00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "khtmlview.moc"
00027
00028 #include "khtmlview.h"
00029
00030 #include "khtml_part.h"
00031 #include "khtml_events.h"
00032
00033 #include "html/html_documentimpl.h"
00034 #include "html/html_inlineimpl.h"
00035 #include "html/html_formimpl.h"
00036 #include "rendering/render_arena.h"
00037 #include "rendering/render_canvas.h"
00038 #include "rendering/render_frames.h"
00039 #include "rendering/render_replaced.h"
00040 #include "rendering/render_layer.h"
00041 #include "rendering/render_line.h"
00042 #include "rendering/render_table.h"
00043
00044 #define protected public
00045 #include "rendering/render_text.h"
00046 #undef protected
00047 #include "xml/dom2_eventsimpl.h"
00048 #include "css/cssstyleselector.h"
00049 #include "misc/htmlhashes.h"
00050 #include "misc/helper.h"
00051 #include "khtml_settings.h"
00052 #include "khtml_printsettings.h"
00053
00054 #include "khtmlpart_p.h"
00055
00056 #ifndef KHTML_NO_CARET
00057 #include "khtml_caret_p.h"
00058 #include "xml/dom2_rangeimpl.h"
00059 #endif
00060
00061 #include <kcursor.h>
00062 #include <ksimpleconfig.h>
00063 #include <kstringhandler.h>
00064 #include <kstandarddirs.h>
00065 #include <kprinter.h>
00066 #include <klocale.h>
00067
00068 #include <qtooltip.h>
00069 #include <qpainter.h>
00070 #include <qpaintdevicemetrics.h>
00071 #include <qstylesheet.h>
00072 #include <kapplication.h>
00073
00074 #include <kimageio.h>
00075 #include <kdebug.h>
00076 #include <kurldrag.h>
00077 #include <qobjectlist.h>
00078 #include <qtimer.h>
00079 #include <kdialogbase.h>
00080 #include <qptrdict.h>
00081
00082
00083
00084
00085
00086
00087
00088 #define PAINT_BUFFER_HEIGHT 128
00089
00090 using namespace DOM;
00091 using namespace khtml;
00092 class KHTMLToolTip;
00093
00094 #ifndef QT_NO_TOOLTIP
00095
00096 class KHTMLToolTip : public QToolTip
00097 {
00098 public:
00099 KHTMLToolTip(KHTMLView *view, KHTMLViewPrivate* vp) : QToolTip(view->viewport())
00100 {
00101 m_view = view;
00102 m_viewprivate = vp;
00103 };
00104
00105 protected:
00106 virtual void maybeTip(const QPoint &);
00107
00108 private:
00109 KHTMLView *m_view;
00110 KHTMLViewPrivate* m_viewprivate;
00111 };
00112
00113 #endif
00114
00115 class KHTMLViewPrivate {
00116 friend class KHTMLToolTip;
00117 public:
00118 KHTMLViewPrivate()
00119 : underMouse( 0 )
00120 {
00121 #ifndef KHTML_NO_CARET
00122 m_caretViewContext = 0;
00123 m_editorContext = 0;
00124 #endif // KHTML_NO_CARET
00125 postponed_autorepeat = NULL;
00126 reset();
00127 tp=0;
00128 paintBuffer=0;
00129 vertPaintBuffer=0;
00130 formCompletions=0;
00131 prevScrollbarVisible = true;
00132 tooltip = 0;
00133 possibleTripleClick = false;
00134 }
00135 ~KHTMLViewPrivate()
00136 {
00137 delete formCompletions;
00138 delete tp; tp = 0;
00139 delete paintBuffer; paintBuffer =0;
00140 delete vertPaintBuffer;
00141 delete postponed_autorepeat;
00142 if (underMouse)
00143 underMouse->deref();
00144 delete tooltip;
00145 #ifndef KHTML_NO_CARET
00146 delete m_caretViewContext;
00147 delete m_editorContext;
00148 #endif // KHTML_NO_CARET
00149 }
00150 void reset()
00151 {
00152 if (underMouse)
00153 underMouse->deref();
00154 underMouse = 0;
00155 linkPressed = false;
00156 useSlowRepaints = false;
00157 originalNode = 0;
00158 borderTouched = false;
00159 #ifndef KHTML_NO_SCROLLBARS
00160 vmode = QScrollView::Auto;
00161 hmode = QScrollView::Auto;
00162 #else
00163 vmode = QScrollView::AlwaysOff;
00164 hmode = QScrollView::AlwaysOff;
00165 #endif
00166 #ifdef DEBUG_PIXEL
00167 timer.start();
00168 pixelbooth = 0;
00169 repaintbooth = 0;
00170 #endif
00171 scrollBarMoved = false;
00172 ignoreWheelEvents = false;
00173 borderX = 30;
00174 borderY = 30;
00175 clickX = -1;
00176 clickY = -1;
00177 prevMouseX = -1;
00178 prevMouseY = -1;
00179 clickCount = 0;
00180 isDoubleClick = false;
00181 scrollingSelf = false;
00182 delete postponed_autorepeat;
00183 postponed_autorepeat = NULL;
00184 layoutTimerId = 0;
00185 repaintTimerId = 0;
00186 scrollTimerId = 0;
00187 scrollSuspended = false;
00188 complete = false;
00189 firstRelayout = true;
00190 dirtyLayout = false;
00191 layoutSchedulingEnabled = true;
00192 updateRegion = QRegion();
00193 m_dialogsAllowed = true;
00194 #ifndef KHTML_NO_CARET
00195 if (m_caretViewContext) {
00196 m_caretViewContext->caretMoved = false;
00197 m_caretViewContext->keyReleasePending = false;
00198 }
00199 #endif // KHTML_NO_CARET
00200 }
00201 void newScrollTimer(QWidget *view, int tid)
00202 {
00203
00204 view->killTimer(scrollTimerId);
00205 scrollTimerId = tid;
00206 scrollSuspended = false;
00207 }
00208 enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
00209
00210 void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
00211 {
00212 static const struct { int msec, pixels; } timings [] = {
00213 {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
00214 {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
00215 };
00216 if (!scrollTimerId ||
00217 (scrollDirection != direction &&
00218 (scrollDirection != oppositedir || scrollSuspended))) {
00219 scrollTiming = 6;
00220 scrollBy = timings[scrollTiming].pixels;
00221 scrollDirection = direction;
00222 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00223 } else if (scrollDirection == direction &&
00224 timings[scrollTiming+1].msec && !scrollSuspended) {
00225 scrollBy = timings[++scrollTiming].pixels;
00226 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00227 } else if (scrollDirection == oppositedir) {
00228 if (scrollTiming) {
00229 scrollBy = timings[--scrollTiming].pixels;
00230 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00231 }
00232 }
00233 scrollSuspended = false;
00234 }
00235
00236 #ifndef KHTML_NO_CARET
00237
00240 CaretViewContext *caretViewContext() {
00241 if (!m_caretViewContext) m_caretViewContext = new CaretViewContext();
00242 return m_caretViewContext;
00243 }
00247 EditorContext *editorContext() {
00248 if (!m_editorContext) m_editorContext = new EditorContext();
00249 return m_editorContext;
00250 }
00251 #endif // KHTML_NO_CARET
00252
00253 #ifdef DEBUG_PIXEL
00254 QTime timer;
00255 unsigned int pixelbooth;
00256 unsigned int repaintbooth;
00257 #endif
00258
00259 QPainter *tp;
00260 QPixmap *paintBuffer;
00261 QPixmap *vertPaintBuffer;
00262 NodeImpl *underMouse;
00263
00264
00265 NodeImpl *originalNode;
00266
00267 bool borderTouched:1;
00268 bool borderStart:1;
00269 bool scrollBarMoved:1;
00270
00271 QScrollView::ScrollBarMode vmode;
00272 QScrollView::ScrollBarMode hmode;
00273 bool prevScrollbarVisible;
00274 bool linkPressed;
00275 bool useSlowRepaints;
00276 bool ignoreWheelEvents;
00277
00278 int borderX, borderY;
00279 KSimpleConfig *formCompletions;
00280
00281 int clickX, clickY, clickCount;
00282 bool isDoubleClick;
00283
00284 int prevMouseX, prevMouseY;
00285 bool scrollingSelf;
00286 int layoutTimerId;
00287 QKeyEvent* postponed_autorepeat;
00288
00289 int repaintTimerId;
00290 int scrollTimerId;
00291 bool scrollSuspended;
00292 int scrollTiming;
00293 int scrollBy;
00294 ScrollDirection scrollDirection;
00295 bool complete;
00296 bool firstRelayout;
00297 bool layoutSchedulingEnabled;
00298 bool possibleTripleClick;
00299 bool dirtyLayout;
00300 bool m_dialogsAllowed;
00301 QRegion updateRegion;
00302 KHTMLToolTip *tooltip;
00303 QPtrDict<QWidget> visibleWidgets;
00304 #ifndef KHTML_NO_CARET
00305 CaretViewContext *m_caretViewContext;
00306 EditorContext *m_editorContext;
00307 #endif // KHTML_NO_CARET
00308 };
00309
00310 #ifndef QT_NO_TOOLTIP
00311
00312 void KHTMLToolTip::maybeTip(const QPoint& )
00313 {
00314 DOM::NodeImpl *node = m_viewprivate->underMouse;
00315 QRect region;
00316 while ( node ) {
00317 if ( node->isElementNode() ) {
00318 QString s = static_cast<DOM::ElementImpl*>( node )->getAttribute( ATTR_TITLE ).string();
00319 region |= QRect( m_view->contentsToViewport( node->getRect().topLeft() ), node->getRect().size() );
00320 if ( !s.isEmpty() ) {
00321 tip( region, QStyleSheet::convertFromPlainText( s, QStyleSheetItem::WhiteSpaceNormal ) );
00322 break;
00323 }
00324 }
00325 node = node->parentNode();
00326 }
00327 }
00328 #endif
00329
00330 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name)
00331 : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase )
00332 {
00333 m_medium = "screen";
00334
00335 m_part = part;
00336 d = new KHTMLViewPrivate;
00337 QScrollView::setVScrollBarMode(d->vmode);
00338 QScrollView::setHScrollBarMode(d->hmode);
00339 connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged()));
00340 connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
00341
00342
00343 enableClipper(true);
00344
00345 static_cast<KHTMLView *>(static_cast<QWidget *>(viewport()))->setWFlags(WPaintUnclipped);
00346
00347 setResizePolicy(Manual);
00348 viewport()->setMouseTracking(true);
00349 viewport()->setBackgroundMode(NoBackground);
00350
00351 KImageIO::registerFormats();
00352
00353 #ifndef QT_NO_TOOLTIP
00354 d->tooltip = new KHTMLToolTip( this, d );
00355 #endif
00356
00357 init();
00358
00359 viewport()->show();
00360 }
00361
00362 KHTMLView::~KHTMLView()
00363 {
00364 closeChildDialogs();
00365 if (m_part)
00366 {
00367
00368
00369 DOM::DocumentImpl *doc = m_part->xmlDocImpl();
00370 if (doc)
00371 doc->detach();
00372 }
00373 delete d; d = 0;
00374 }
00375
00376 void KHTMLView::init()
00377 {
00378 if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
00379 if(!d->vertPaintBuffer)
00380 d->vertPaintBuffer = new QPixmap(10, PAINT_BUFFER_HEIGHT);
00381 if(!d->tp) d->tp = new QPainter();
00382
00383 setFocusPolicy(QWidget::StrongFocus);
00384 viewport()->setFocusProxy(this);
00385
00386 _marginWidth = -1;
00387 _marginHeight = -1;
00388 _width = 0;
00389 _height = 0;
00390
00391 installEventFilter(this);
00392
00393 setAcceptDrops(true);
00394 QSize s = viewportSize(4095, 4095);
00395 resizeContents(s.width(), s.height());
00396 }
00397
00398 void KHTMLView::clear()
00399 {
00400
00401 setStaticBackground(true);
00402 #ifndef KHTML_NO_CARET
00403 if (!m_part->isCaretMode() && !m_part->isEditable()) caretOff();
00404 #endif
00405
00406 d->reset();
00407 killTimers();
00408 emit cleared();
00409
00410 QScrollView::setHScrollBarMode(d->hmode);
00411 QScrollView::setVScrollBarMode(d->vmode);
00412 }
00413
00414 void KHTMLView::hideEvent(QHideEvent* e)
00415 {
00416 QScrollView::hideEvent(e);
00417 }
00418
00419 void KHTMLView::showEvent(QShowEvent* e)
00420 {
00421 QScrollView::showEvent(e);
00422 }
00423
00424 void KHTMLView::resizeEvent (QResizeEvent* e)
00425 {
00426 QScrollView::resizeEvent(e);
00427
00428 if ( m_part && m_part->xmlDocImpl() )
00429 m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
00430 }
00431
00432 void KHTMLView::viewportResizeEvent (QResizeEvent* e)
00433 {
00434 QScrollView::viewportResizeEvent(e);
00435
00436
00437
00438
00439 if (d->layoutSchedulingEnabled)
00440 layout();
00441 #ifndef KHTML_NO_CARET
00442 else {
00443 hideCaret();
00444 recalcAndStoreCaretPos();
00445 showCaret();
00446 }
00447 #endif
00448
00449 KApplication::sendPostedEvents(viewport(), QEvent::Paint);
00450 }
00451
00452
00453 void KHTMLView::drawContents( QPainter*)
00454 {
00455 }
00456
00457 void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
00458 {
00459 #ifdef DEBUG_PIXEL
00460
00461 if ( d->timer.elapsed() > 5000 ) {
00462 qDebug( "drawed %d pixels in %d repaints the last %d milliseconds",
00463 d->pixelbooth, d->repaintbooth, d->timer.elapsed() );
00464 d->timer.restart();
00465 d->pixelbooth = 0;
00466 d->repaintbooth = 0;
00467 }
00468 d->pixelbooth += ew*eh;
00469 d->repaintbooth++;
00470 #endif
00471
00472
00473 if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
00474 p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00475 return;
00476 }
00477
00478 QPoint pt = contentsToViewport(QPoint(ex, ey));
00479 QRegion cr = QRect(pt.x(), pt.y(), ew, eh);
00480
00481 for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
00482 QWidget *w = it.current();
00483 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
00484 QScrollView *sv = ::qt_cast<QScrollView *>(w);
00485 if (sv || !rw->isFormElement()) {
00486
00487 int x, y;
00488 rw->absolutePosition(x, y);
00489 contentsToViewport(x, y, x, y);
00490 cr -= QRect(x, y, rw->width(), rw->height());
00491 }
00492 }
00493
00494 #if 0
00495
00496
00497 if (cr.isEmpty())
00498 return;
00499 #endif
00500
00501 #ifndef DEBUG_NO_PAINT_BUFFER
00502 p->setClipRegion(cr);
00503
00504 if (eh > PAINT_BUFFER_HEIGHT && ew <= 10) {
00505 if ( d->vertPaintBuffer->height() < visibleHeight() )
00506 d->vertPaintBuffer->resize(10, visibleHeight());
00507 d->tp->begin(d->vertPaintBuffer);
00508 d->tp->translate(-ex, -ey);
00509 d->tp->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00510 m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey, ew, eh));
00511 d->tp->end();
00512 p->drawPixmap(ex, ey, *d->vertPaintBuffer, 0, 0, ew, eh);
00513 }
00514 else {
00515 if ( d->paintBuffer->width() < visibleWidth() )
00516 d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
00517
00518 int py=0;
00519 while (py < eh) {
00520 int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
00521 d->tp->begin(d->paintBuffer);
00522 d->tp->translate(-ex, -ey-py);
00523 d->tp->fillRect(ex, ey+py, ew, ph, palette().active().brush(QColorGroup::Base));
00524 m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey+py, ew, ph));
00525 d->tp->end();
00526
00527 p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
00528 py += PAINT_BUFFER_HEIGHT;
00529 }
00530 }
00531 #else // !DEBUG_NO_PAINT_BUFFER
00532 static int cnt=0;
00533 ex = contentsX(); ey = contentsY();
00534 ew = visibleWidth(); eh = visibleHeight();
00535 QRect pr(ex,ey,ew,eh);
00536 kdDebug() << "[" << ++cnt << "]" << " clip region: " << pr << endl;
00537
00538
00539 p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00540 m_part->xmlDocImpl()->renderer()->layer()->paint(p, pr);
00541 #endif // DEBUG_NO_PAINT_BUFFER
00542
00543 #ifndef KHTML_NO_CARET
00544 if (d->m_caretViewContext && d->m_caretViewContext->visible) {
00545 QRect pos(d->m_caretViewContext->x, d->m_caretViewContext->y,
00546 d->m_caretViewContext->width, d->m_caretViewContext->height);
00547 if (pos.intersects(QRect(ex, ey, ew, eh))) {
00548 p->setRasterOp(XorROP);
00549 p->setPen(white);
00550 if (pos.width() == 1)
00551 p->drawLine(pos.topLeft(), pos.bottomRight());
00552 else {
00553 p->fillRect(pos, white);
00554 }
00555 }
00556 }
00557 #endif // KHTML_NO_CARET
00558
00559
00560
00561
00562 khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
00563 QApplication::sendEvent( m_part, &event );
00564
00565 }
00566
00567 void KHTMLView::setMarginWidth(int w)
00568 {
00569
00570 _marginWidth = w;
00571 }
00572
00573 void KHTMLView::setMarginHeight(int h)
00574 {
00575
00576 _marginHeight = h;
00577 }
00578
00579 void KHTMLView::layout()
00580 {
00581 if( m_part && m_part->xmlDocImpl() ) {
00582 DOM::DocumentImpl *document = m_part->xmlDocImpl();
00583
00584 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
00585 if ( !root ) return;
00586
00587 d->layoutSchedulingEnabled=false;
00588
00589 if (document->isHTMLDocument()) {
00590 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
00591 if(body && body->renderer() && body->id() == ID_FRAMESET) {
00592 QScrollView::setVScrollBarMode(AlwaysOff);
00593 QScrollView::setHScrollBarMode(AlwaysOff);
00594 body->renderer()->setLayouted(false);
00595
00596
00597
00598
00599 }
00600 else if (!d->tooltip)
00601 d->tooltip = new KHTMLToolTip( this, d );
00602 }
00603
00604 _height = visibleHeight();
00605 _width = visibleWidth();
00606
00607
00608 root->setMinMaxKnown(false);
00609 root->setLayouted(false);
00610 root->layout();
00611 #ifndef KHTML_NO_CARET
00612 hideCaret();
00613 if ((m_part->isCaretMode() || m_part->isEditable())
00614 && !d->complete && d->m_caretViewContext
00615 && !d->m_caretViewContext->caretMoved) {
00616 initCaret();
00617 } else {
00618 recalcAndStoreCaretPos();
00619 showCaret();
00620 }
00621 #endif
00622 root->repaint();
00623
00624 }
00625 else
00626 _width = visibleWidth();
00627
00628 killTimer(d->layoutTimerId);
00629 d->layoutTimerId = 0;
00630 d->layoutSchedulingEnabled=true;
00631 }
00632
00633 void KHTMLView::closeChildDialogs()
00634 {
00635 QObjectList *dlgs = queryList("QDialog");
00636 for (QObject *dlg = dlgs->first(); dlg; dlg = dlgs->next())
00637 {
00638 KDialogBase* dlgbase = dynamic_cast<KDialogBase *>( dlg );
00639 if ( dlgbase ) {
00640 kdDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase << endl;
00641
00642
00643 dlgbase->cancel();
00644 }
00645 else
00646 {
00647 kdWarning() << "closeChildDialogs: not a KDialogBase! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg) << endl;
00648 static_cast<QWidget*>(dlg)->hide();
00649 }
00650 }
00651 delete dlgs;
00652 d->m_dialogsAllowed = false;
00653 }
00654
00655 bool KHTMLView::dialogsAllowed() {
00656 bool allowed = d->m_dialogsAllowed;
00657 KHTMLPart* p = m_part->parentPart();
00658 if (p && p->view())
00659 allowed &= p->view()->dialogsAllowed();
00660 return allowed;
00661 }
00662
00663 void KHTMLView::closeEvent( QCloseEvent* ev )
00664 {
00665 closeChildDialogs();
00666 QScrollView::closeEvent( ev );
00667 }
00668
00669
00670
00671
00673
00674 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
00675 {
00676 if(!m_part->xmlDocImpl()) return;
00677 if (d->possibleTripleClick)
00678 {
00679 viewportMouseDoubleClickEvent( _mouse );
00680 return;
00681 }
00682
00683 int xm, ym;
00684 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00685
00686
00687
00688 d->isDoubleClick = false;
00689
00690 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
00691 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00692
00693 if (d->clickCount > 0 &&
00694 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00695 d->clickCount++;
00696 else {
00697 d->clickCount = 1;
00698 d->clickX = xm;
00699 d->clickY = ym;
00700 }
00701
00702 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
00703 d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
00704
00705 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00706 if (r && r->isWidget())
00707 _mouse->ignore();
00708
00709 if (!swallowEvent) {
00710 emit m_part->nodeActivated(mev.innerNode);
00711
00712 khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00713 QApplication::sendEvent( m_part, &event );
00714
00715 }
00716 }
00717
00718 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
00719 {
00720 if(!m_part->xmlDocImpl()) return;
00721
00722 int xm, ym;
00723 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00724
00725 kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
00726
00727 d->isDoubleClick = true;
00728
00729 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
00730 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00731
00732
00733
00734 if (d->clickCount > 0 &&
00735 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00736 d->clickCount++;
00737 else {
00738 d->clickCount = 1;
00739 d->clickX = xm;
00740 d->clickY = ym;
00741 }
00742 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
00743 d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
00744
00745 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00746 if (r && r->isWidget())
00747 _mouse->ignore();
00748
00749 if (!swallowEvent) {
00750 khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
00751 QApplication::sendEvent( m_part, &event );
00752 }
00753
00754 d->possibleTripleClick=true;
00755 QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
00756 }
00757
00758 void KHTMLView::tripleClickTimeout()
00759 {
00760 d->possibleTripleClick = false;
00761 d->clickCount = 0;
00762 }
00763
00764 static inline void forwardPeripheralEvent(khtml::RenderWidget* r, QMouseEvent* me, int x, int y)
00765 {
00766 int absx = 0;
00767 int absy = 0;
00768 r->absolutePosition(absx, absy);
00769 QPoint p(x-absx, y-absy);
00770 QMouseEvent fw(me->type(), p, me->button(), me->state());
00771 QWidget* w = r->widget();
00772 if(w)
00773 static_cast<khtml::RenderWidget::EventPropagator*>(w)->sendEvent(&fw);
00774 }
00775
00776 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
00777 {
00778
00779 if(!m_part->xmlDocImpl()) return;
00780
00781 int xm, ym;
00782 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00783
00784 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
00785
00786 m_part->xmlDocImpl()->prepareMouseEvent( _mouse->state() & Qt::MouseButtonMask , xm, ym, &mev );
00787
00788
00789
00790
00791
00792 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),false,
00793 0,_mouse,true,DOM::NodeImpl::MouseMove);
00794
00795 if (d->clickCount > 0 &&
00796 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
00797 d->clickCount = 0;
00798 }
00799
00800
00801 m_part->executeScheduledScript();
00802
00803 DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
00804 if (fn && fn != mev.innerNode.handle() &&
00805 fn->renderer() && fn->renderer()->isWidget()) {
00806 forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00807 }
00808
00809 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00810 khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
00811 QCursor c;
00812 switch ( style ? style->cursor() : CURSOR_AUTO) {
00813 case CURSOR_AUTO:
00814 if ( r && r->isText() )
00815 c = KCursor::ibeamCursor();
00816
00817 if ( mev.url.length() && m_part->settings()->changeCursor() )
00818 c = m_part->urlCursor();
00819
00820 if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
00821 c = QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
00822
00823 break;
00824 case CURSOR_CROSS:
00825 c = KCursor::crossCursor();
00826 break;
00827 case CURSOR_POINTER:
00828 c = m_part->urlCursor();
00829 break;
00830 case CURSOR_PROGRESS:
00831 c = KCursor::workingCursor();
00832 break;
00833 case CURSOR_MOVE:
00834 c = KCursor::sizeAllCursor();
00835 break;
00836 case CURSOR_E_RESIZE:
00837 case CURSOR_W_RESIZE:
00838 c = KCursor::sizeHorCursor();
00839 break;
00840 case CURSOR_N_RESIZE:
00841 case CURSOR_S_RESIZE:
00842 c = KCursor::sizeVerCursor();
00843 break;
00844 case CURSOR_NE_RESIZE:
00845 case CURSOR_SW_RESIZE:
00846 c = KCursor::sizeBDiagCursor();
00847 break;
00848 case CURSOR_NW_RESIZE:
00849 case CURSOR_SE_RESIZE:
00850 c = KCursor::sizeFDiagCursor();
00851 break;
00852 case CURSOR_TEXT:
00853 c = KCursor::ibeamCursor();
00854 break;
00855 case CURSOR_WAIT:
00856 c = KCursor::waitCursor();
00857 break;
00858 case CURSOR_HELP:
00859 c = KCursor::whatsThisCursor();
00860 break;
00861 case CURSOR_DEFAULT:
00862 break;
00863 }
00864
00865 if ( viewport()->cursor().handle() != c.handle() ) {
00866 if( c.handle() == KCursor::arrowCursor().handle()) {
00867 for (KHTMLPart* p = m_part; p; p = p->parentPart())
00868 p->view()->viewport()->unsetCursor();
00869 }
00870 else {
00871 viewport()->setCursor( c );
00872 }
00873 }
00874 if (r && r->isWidget()) {
00875 _mouse->ignore();
00876 }
00877
00878
00879 d->prevMouseX = xm;
00880 d->prevMouseY = ym;
00881
00882 if (!swallowEvent) {
00883 khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00884 QApplication::sendEvent( m_part, &event );
00885 }
00886 }
00887
00888 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
00889 {
00890 if ( !m_part->xmlDocImpl() ) return;
00891
00892 int xm, ym;
00893 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00894
00895 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
00896 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00897
00898 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true,
00899 d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
00900
00901 if (d->clickCount > 0 &&
00902 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
00903 QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
00904 _mouse->pos(), _mouse->button(), _mouse->state());
00905 dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),true,
00906 d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
00907 }
00908
00909 DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
00910 if (fn && fn != mev.innerNode.handle() &&
00911 fn->renderer() && fn->renderer()->isWidget()) {
00912 forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00913 }
00914
00915 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00916 if (r && r->isWidget())
00917 _mouse->ignore();
00918
00919 if (!swallowEvent) {
00920 khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00921 QApplication::sendEvent( m_part, &event );
00922 }
00923 }
00924
00925
00926 bool KHTMLView::dispatchKeyEvent( QKeyEvent *_ke )
00927 {
00928 if (!m_part->xmlDocImpl())
00929 return false;
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 if( _ke == d->postponed_autorepeat )
00951 {
00952 return false;
00953 }
00954
00955 if( _ke->type() == QEvent::KeyPress )
00956 {
00957 if( !_ke->isAutoRepeat())
00958 {
00959 bool ret = dispatchKeyEventHelper( _ke, false );
00960 if( dispatchKeyEventHelper( _ke, true ))
00961 ret = true;
00962 return ret;
00963 }
00964 else
00965 {
00966 bool ret = dispatchKeyEventHelper( _ke, true );
00967 if( !ret && d->postponed_autorepeat )
00968 keyPressEvent( d->postponed_autorepeat );
00969 delete d->postponed_autorepeat;
00970 d->postponed_autorepeat = NULL;
00971 return ret;
00972 }
00973 }
00974 else
00975 {
00976
00977
00978 if ( d->postponed_autorepeat ) {
00979 delete d->postponed_autorepeat;
00980 d->postponed_autorepeat = 0;
00981 }
00982
00983 if( !_ke->isAutoRepeat()) {
00984 return dispatchKeyEventHelper( _ke, false );
00985 }
00986 else
00987 {
00988 d->postponed_autorepeat = new QKeyEvent( _ke->type(), _ke->key(), _ke->ascii(), _ke->state(),
00989 _ke->text(), _ke->isAutoRepeat(), _ke->count());
00990 if( _ke->isAccepted())
00991 d->postponed_autorepeat->accept();
00992 else
00993 d->postponed_autorepeat->ignore();
00994 return true;
00995 }
00996 }
00997 }
00998
00999
01000 bool KHTMLView::dispatchKeyEventHelper( QKeyEvent *_ke, bool keypress )
01001 {
01002 DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
01003 if (keyNode) {
01004 return keyNode->dispatchKeyEvent(_ke, keypress);
01005 } else {
01006 return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
01007 }
01008 }
01009
01010 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
01011 {
01012
01013 #ifndef KHTML_NO_CARET
01014 if (m_part->isEditable() || m_part->isCaretMode()
01015 || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
01016 && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
01017 d->caretViewContext()->keyReleasePending = true;
01018 caretKeyPressEvent(_ke);
01019 return;
01020 }
01021 #endif // KHTML_NO_CARET
01022
01023
01024
01025 if( handleAccessKey( _ke )) {
01026 _ke->accept();
01027 return;
01028 }
01029
01030 if ( dispatchKeyEvent( _ke )) {
01031
01032 _ke->accept();
01033 return;
01034 }
01035
01036 int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
01037 if (_ke->state() & Qt::ShiftButton)
01038 switch(_ke->key())
01039 {
01040 case Key_Space:
01041 if ( d->vmode == QScrollView::AlwaysOff )
01042 _ke->accept();
01043 else {
01044 scrollBy( 0, -clipper()->height() - offs );
01045 if(d->scrollSuspended)
01046 d->newScrollTimer(this, 0);
01047 }
01048 break;
01049
01050 case Key_Down:
01051 case Key_J:
01052 d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
01053 break;
01054
01055 case Key_Up:
01056 case Key_K:
01057 d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
01058 break;
01059
01060 case Key_Left:
01061 case Key_H:
01062 d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
01063 break;
01064
01065 case Key_Right:
01066 case Key_L:
01067 d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
01068 break;
01069 }
01070 else
01071 switch ( _ke->key() )
01072 {
01073 case Key_Down:
01074 case Key_J:
01075 if ( d->vmode == QScrollView::AlwaysOff )
01076 _ke->accept();
01077 else {
01078 if (!d->scrollTimerId || d->scrollSuspended)
01079 scrollBy( 0, 10 );
01080 if (d->scrollTimerId)
01081 d->newScrollTimer(this, 0);
01082 }
01083 break;
01084
01085 case Key_Space:
01086 case Key_Next:
01087 if ( d->vmode == QScrollView::AlwaysOff )
01088 _ke->accept();
01089 else {
01090 scrollBy( 0, clipper()->height() - offs );
01091 if(d->scrollSuspended)
01092 d->newScrollTimer(this, 0);
01093 }
01094 break;
01095
01096 case Key_Up:
01097 case Key_K:
01098 if ( d->vmode == QScrollView::AlwaysOff )
01099 _ke->accept();
01100 else {
01101 if (!d->scrollTimerId || d->scrollSuspended)
01102 scrollBy( 0, -10 );
01103 if (d->scrollTimerId)
01104 d->newScrollTimer(this, 0);
01105 }
01106 break;
01107
01108 case Key_Prior:
01109 if ( d->vmode == QScrollView::AlwaysOff )
01110 _ke->accept();
01111 else {
01112 scrollBy( 0, -clipper()->height() + offs );
01113 if(d->scrollSuspended)
01114 d->newScrollTimer(this, 0);
01115 }
01116 break;
01117 case Key_Right:
01118 case Key_L:
01119 if ( d->hmode == QScrollView::AlwaysOff )
01120 _ke->accept();
01121 else {
01122 if (!d->scrollTimerId || d->scrollSuspended)
01123 scrollBy( 10, 0 );
01124 if (d->scrollTimerId)
01125 d->newScrollTimer(this, 0);
01126 }
01127 break;
01128 case Key_Left:
01129 case Key_H:
01130 if ( d->hmode == QScrollView::AlwaysOff )
01131 _ke->accept();
01132 else {
01133 if (!d->scrollTimerId || d->scrollSuspended)
01134 scrollBy( -10, 0 );
01135 if (d->scrollTimerId)
01136 d->newScrollTimer(this, 0);
01137 }
01138 break;
01139 case Key_Enter:
01140 case Key_Return:
01141
01142
01143 if (m_part->xmlDocImpl()) {
01144 NodeImpl *n = m_part->xmlDocImpl()->focusNode();
01145 if (n)
01146 n->setActive();
01147 d->originalNode = n;
01148 }
01149 break;
01150 case Key_Home:
01151 if ( d->vmode == QScrollView::AlwaysOff )
01152 _ke->accept();
01153 else {
01154 setContentsPos( 0, 0 );
01155 if(d->scrollSuspended)
01156 d->newScrollTimer(this, 0);
01157 }
01158 break;
01159 case Key_End:
01160 if ( d->vmode == QScrollView::AlwaysOff )
01161 _ke->accept();
01162 else {
01163 setContentsPos( 0, contentsHeight() - visibleHeight() );
01164 if(d->scrollSuspended)
01165 d->newScrollTimer(this, 0);
01166 }
01167 break;
01168 case Key_Shift:
01169
01170 _ke->ignore();
01171 return;
01172 case Key_Control:
01173 if (d->scrollTimerId)
01174 d->scrollSuspended = !d->scrollSuspended;
01175 break;
01176 default:
01177 if (d->scrollTimerId)
01178 d->newScrollTimer(this, 0);
01179 _ke->ignore();
01180 return;
01181 }
01182 _ke->accept();
01183 }
01184
01185 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
01186 {
01187 if (d->m_caretViewContext && d->m_caretViewContext->keyReleasePending) {
01188
01189 d->m_caretViewContext->keyReleasePending = false;
01190 return;
01191 }
01192
01193
01194 if ( dispatchKeyEvent( _ke ) )
01195 {
01196 _ke->accept();
01197 return;
01198 }
01199 QScrollView::keyReleaseEvent(_ke);
01200 }
01201
01202 void KHTMLView::contentsContextMenuEvent ( QContextMenuEvent * )
01203 {
01204
01205 #if 0
01206 if (!m_part->xmlDocImpl()) return;
01207 int xm = _ce->x();
01208 int ym = _ce->y();
01209
01210 DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove );
01211 m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
01212
01213 NodeImpl *targetNode = mev.innerNode.handle();
01214 if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
01215 int absx = 0;
01216 int absy = 0;
01217 targetNode->renderer()->absolutePosition(absx,absy);
01218 QPoint pos(xm-absx,ym-absy);
01219
01220 QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
01221 QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
01222 setIgnoreEvents(true);
01223 QApplication::sendEvent(w,&cme);
01224 setIgnoreEvents(false);
01225 }
01226 #endif
01227 }
01228
01229 bool KHTMLView::focusNextPrevChild( bool next )
01230 {
01231
01232 if (m_part->xmlDocImpl()) {
01233 focusNextPrevNode(next);
01234 if (m_part->xmlDocImpl()->focusNode() != 0) {
01235 kdDebug() << "focusNode.name: "
01236 << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
01237 return true;
01238 }
01239 }
01240
01241
01242 if (m_part->parentPart() && m_part->parentPart()->view())
01243 return m_part->parentPart()->view()->focusNextPrevChild(next);
01244
01245 return QWidget::focusNextPrevChild(next);
01246 }
01247
01248 void KHTMLView::doAutoScroll()
01249 {
01250 QPoint pos = QCursor::pos();
01251 pos = viewport()->mapFromGlobal( pos );
01252
01253 int xm, ym;
01254 viewportToContents(pos.x(), pos.y(), xm, ym);
01255
01256 pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
01257 if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
01258 (pos.x() < 0) || (pos.x() > visibleWidth()) )
01259 {
01260 ensureVisible( xm, ym, 0, 5 );
01261
01262 #ifndef KHTML_NO_SELECTION
01263
01264 DOM::Node innerNode;
01265 if (m_part->isExtendingSelection()) {
01266 RenderObject::NodeInfo renderInfo(true, false);
01267 m_part->xmlDocImpl()->renderer()->layer()
01268 ->nodeAtPoint(renderInfo, xm, ym);
01269 innerNode = renderInfo.innerNode();
01270 }
01271
01272 if (innerNode.handle() && innerNode.handle()->renderer()) {
01273 int absX, absY;
01274 innerNode.handle()->renderer()->absolutePosition(absX, absY);
01275
01276 m_part->extendSelectionTo(xm, ym, absX, absY, innerNode);
01277 }
01278 #endif // KHTML_NO_SELECTION
01279 }
01280 }
01281
01282
01283 class HackWidget : public QWidget
01284 {
01285 public:
01286 inline void setNoErase() { setWFlags(getWFlags()|WRepaintNoErase); }
01287 };
01288
01289 bool KHTMLView::eventFilter(QObject *o, QEvent *e)
01290 {
01291 if ( e->type() == QEvent::AccelOverride ) {
01292 QKeyEvent* ke = (QKeyEvent*) e;
01293
01294 if (m_part->isEditable() || m_part->isCaretMode()
01295 || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
01296 && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
01297
01298 if ( (ke->state() & ControlButton) || (ke->state() & ShiftButton) ) {
01299 switch ( ke->key() ) {
01300 case Key_Left:
01301 case Key_Right:
01302 case Key_Up:
01303 case Key_Down:
01304 case Key_Home:
01305 case Key_End:
01306 ke->accept();
01307
01308 return true;
01309 default:
01310 break;
01311 }
01312 }
01313 }
01314 }
01315
01316 QWidget *view = viewport();
01317
01318 if (o == view) {
01319
01320
01321 if(e->type() == QEvent::ChildInserted) {
01322 QObject *c = static_cast<QChildEvent *>(e)->child();
01323 if (c->isWidgetType()) {
01324 QWidget *w = static_cast<QWidget *>(c);
01325
01326 if (w->parentWidget(true) == view) {
01327 if (!strcmp(w->name(), "__khtml")) {
01328 w->installEventFilter(this);
01329 w->unsetCursor();
01330 w->setBackgroundMode( QWidget::NoBackground );
01331 static_cast<HackWidget *>(w)->setNoErase();
01332 if (w->children()) {
01333 QObjectListIterator it(*w->children());
01334 for (; it.current(); ++it) {
01335 QWidget *widget = ::qt_cast<QWidget *>(it.current());
01336 if (widget && !widget->isTopLevel()
01337 && !::qt_cast<QScrollView *>(widget)) {
01338 widget->setBackgroundMode( QWidget::NoBackground );
01339 static_cast<HackWidget *>(widget)->setNoErase();
01340 widget->installEventFilter(this);
01341 }
01342 }
01343 }
01344 }
01345 }
01346 }
01347 }
01348 } else if (o->isWidgetType()) {
01349 QWidget *v = static_cast<QWidget *>(o);
01350 QWidget *c = v;
01351 while (v && v != view) {
01352 c = v;
01353 v = v->parentWidget(true);
01354 }
01355
01356 if (v && !strcmp(c->name(), "__khtml")) {
01357 bool block = false;
01358 QWidget *w = static_cast<QWidget *>(o);
01359 switch(e->type()) {
01360 case QEvent::Paint:
01361 if (!allowWidgetPaintEvents) {
01362
01363
01364 block = true;
01365 int x = 0, y = 0;
01366 QWidget *v = w;
01367 while (v && v != view) {
01368 x += v->x();
01369 y += v->y();
01370 v = v->parentWidget();
01371 }
01372 viewportToContents( x, y, x, y );
01373 QPaintEvent *pe = static_cast<QPaintEvent *>(e);
01374 scheduleRepaint(x + pe->rect().x(), y + pe->rect().y(),
01375 pe->rect().width(), pe->rect().height());
01376 }
01377 break;
01378 case QEvent::MouseMove:
01379 case QEvent::MouseButtonPress:
01380 case QEvent::MouseButtonRelease:
01381 case QEvent::MouseButtonDblClick: {
01382 if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01383 QMouseEvent *me = static_cast<QMouseEvent *>(e);
01384 QPoint pt = (me->pos() + w->pos());
01385 QMouseEvent me2(me->type(), pt, me->button(), me->state());
01386
01387 if (e->type() == QEvent::MouseMove)
01388 viewportMouseMoveEvent(&me2);
01389 else if(e->type() == QEvent::MouseButtonPress)
01390 viewportMousePressEvent(&me2);
01391 else if(e->type() == QEvent::MouseButtonRelease)
01392 viewportMouseReleaseEvent(&me2);
01393 else
01394 viewportMouseDoubleClickEvent(&me2);
01395 block = true;
01396 }
01397 break;
01398 }
01399 case QEvent::KeyPress:
01400 case QEvent::KeyRelease:
01401 if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01402 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
01403 if (e->type() == QEvent::KeyPress)
01404 keyPressEvent(ke);
01405 else
01406 keyReleaseEvent(ke);
01407 block = true;
01408 }
01409 default:
01410 break;
01411 }
01412 if (block) {
01413
01414 return true;
01415 }
01416 }
01417 }
01418
01419
01420 return QScrollView::eventFilter(o, e);
01421 }
01422
01423
01424 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
01425 {
01426 return d->underMouse;
01427 }
01428
01429 bool KHTMLView::scrollTo(const QRect &bounds)
01430 {
01431 d->scrollingSelf = true;
01432
01433 int x, y, xe, ye;
01434 x = bounds.left();
01435 y = bounds.top();
01436 xe = bounds.right();
01437 ye = bounds.bottom();
01438
01439
01440
01441 int deltax;
01442 int deltay;
01443
01444 int curHeight = visibleHeight();
01445 int curWidth = visibleWidth();
01446
01447 if (ye-y>curHeight-d->borderY)
01448 ye = y + curHeight - d->borderY;
01449
01450 if (xe-x>curWidth-d->borderX)
01451 xe = x + curWidth - d->borderX;
01452
01453
01454 if (x < contentsX() + d->borderX )
01455 deltax = x - contentsX() - d->borderX;
01456
01457 else if (xe + d->borderX > contentsX() + curWidth)
01458 deltax = xe + d->borderX - ( contentsX() + curWidth );
01459 else
01460 deltax = 0;
01461
01462
01463 if (y < contentsY() + d->borderY)
01464 deltay = y - contentsY() - d->borderY;
01465
01466 else if (ye + d->borderY > contentsY() + curHeight)
01467 deltay = ye + d->borderY - ( contentsY() + curHeight );
01468 else
01469 deltay = 0;
01470
01471 int maxx = curWidth-d->borderX;
01472 int maxy = curHeight-d->borderY;
01473
01474 int scrollX,scrollY;
01475
01476 scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
01477 scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
01478
01479 if (contentsX() + scrollX < 0)
01480 scrollX = -contentsX();
01481 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
01482 scrollX = contentsWidth() - visibleWidth() - contentsX();
01483
01484 if (contentsY() + scrollY < 0)
01485 scrollY = -contentsY();
01486 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
01487 scrollY = contentsHeight() - visibleHeight() - contentsY();
01488
01489 scrollBy(scrollX, scrollY);
01490
01491
01492
01493
01494 if (scrollX<0)
01495 scrollX=-scrollX;
01496 if (scrollY<0)
01497 scrollY=-scrollY;
01498
01499 d->scrollingSelf = false;
01500
01501 if ( (scrollX!=maxx) && (scrollY!=maxy) )
01502 return true;
01503 else return false;
01504
01505 }
01506
01507 void KHTMLView::focusNextPrevNode(bool next)
01508 {
01509
01510
01511
01512
01513
01514 DocumentImpl *doc = m_part->xmlDocImpl();
01515 NodeImpl *oldFocusNode = doc->focusNode();
01516 NodeImpl *newFocusNode;
01517
01518
01519 if (next)
01520 newFocusNode = doc->nextFocusNode(oldFocusNode);
01521 else
01522 newFocusNode = doc->previousFocusNode(oldFocusNode);
01523
01524
01525
01526 if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
01527
01528 kdDebug(6000) << " searching for visible link" << endl;
01529
01530 bool visible = false;
01531 NodeImpl *toFocus = newFocusNode;
01532 while (!visible && toFocus) {
01533 QRect focusNodeRect = toFocus->getRect();
01534 if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
01535 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
01536
01537 visible = true;
01538 }
01539 else {
01540
01541 if (next)
01542 toFocus = doc->nextFocusNode(toFocus);
01543 else
01544 toFocus = doc->previousFocusNode(toFocus);
01545 }
01546 }
01547
01548 if (toFocus)
01549 newFocusNode = toFocus;
01550 }
01551
01552 d->scrollBarMoved = false;
01553
01554 if (!newFocusNode)
01555 {
01556
01557 if (next)
01558 scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
01559 else
01560 scrollTo(QRect(contentsX()+visibleWidth()/2,0,0,0));
01561 }
01562 else
01563
01564 {
01565 #ifndef KHTML_NO_CARET
01566
01567 if (!m_part->isCaretMode() && !m_part->isEditable()
01568 && newFocusNode->contentEditable()) {
01569 d->caretViewContext();
01570 moveCaretTo(newFocusNode, 0L, true);
01571 } else {
01572 caretOff();
01573 }
01574 #endif // KHTML_NO_CARET
01575
01576 if (oldFocusNode)
01577 {
01578 if (!scrollTo(newFocusNode->getRect()))
01579 return;
01580 }
01581 else
01582 {
01583 ensureVisible(contentsX(), next?0:contentsHeight());
01584
01585 }
01586
01587 }
01588
01589
01590 Node guard(newFocusNode);
01591 m_part->xmlDocImpl()->setFocusNode(newFocusNode);
01592 if( newFocusNode != NULL && newFocusNode->hasOneRef())
01593 return;
01594 emit m_part->nodeActivated(Node(newFocusNode));
01595 }
01596
01597
01598 bool KHTMLView::handleAccessKey( const QKeyEvent* ev )
01599 {
01600 const int mods = Qt::AltButton | Qt::ControlButton;
01601 if( ( ev->state() & mods ) != mods )
01602 return false;
01603
01604
01605 QChar c;
01606 if( ev->key() >= Key_A && ev->key() <= Key_Z )
01607 c = 'A' + ev->key() - Key_A;
01608 else if( ev->key() >= Key_0 && ev->key() <= Key_9 )
01609 c = '0' + ev->key() - Key_0;
01610 else {
01611
01612
01613 if( ev->text().length() == 1 )
01614 c = ev->text()[ 0 ];
01615 }
01616 if( c.isNull())
01617 return false;
01618 return focusNodeWithAccessKey( c );
01619 }
01620
01621 bool KHTMLView::focusNodeWithAccessKey( QChar c, KHTMLView* caller )
01622 {
01623 DocumentImpl *doc = m_part->xmlDocImpl();
01624 if( !doc )
01625 return false;
01626 ElementImpl* node = doc->findAccessKeyElement( c );
01627 if( !node ) {
01628 QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
01629 for( QPtrListIterator<KParts::ReadOnlyPart> it( frames );
01630 it != NULL;
01631 ++it ) {
01632 if( !(*it)->inherits( "KHTMLPart" ))
01633 continue;
01634 KHTMLPart* part = static_cast< KHTMLPart* >( *it );
01635 if( part->view() && part->view() != caller
01636 && part->view()->focusNodeWithAccessKey( c, this ))
01637 return true;
01638 }
01639
01640 if (m_part->parentPart() && m_part->parentPart()->view()
01641 && m_part->parentPart()->view() != caller )
01642 return m_part->parentPart()->view()->focusNodeWithAccessKey( c, this );
01643 return false;
01644 }
01645
01646
01647 #ifndef KHTML_NO_CARET
01648
01649 if (!m_part->isCaretMode() && !m_part->isEditable()
01650 && node->contentEditable()) {
01651 d->caretViewContext();
01652 moveCaretTo(node, 0L, true);
01653 } else {
01654 caretOff();
01655 }
01656 #endif // KHTML_NO_CARET
01657
01658 if (!scrollTo(node->getRect()))
01659 return true;
01660
01661 Node guard( node );
01662 if( node->isSelectable()) {
01663
01664 m_part->xmlDocImpl()->setFocusNode(node);
01665 if( node != NULL && node->hasOneRef())
01666 return true;
01667 emit m_part->nodeActivated(Node(node));
01668 if( node != NULL && node->hasOneRef())
01669 return true;
01670 }
01671 switch( node->id()) {
01672 case ID_A:
01673 static_cast< HTMLAnchorElementImpl* >( node )->click();
01674 break;
01675 case ID_INPUT:
01676 static_cast< HTMLInputElementImpl* >( node )->click();
01677 break;
01678 case ID_BUTTON:
01679 static_cast< HTMLButtonElementImpl* >( node )->click();
01680 break;
01681 case ID_AREA:
01682 static_cast< HTMLAreaElementImpl* >( node )->click();
01683 break;
01684 case ID_LABEL:
01685
01686 break;
01687 case ID_TEXTAREA:
01688 break;
01689 case ID_LEGEND:
01690
01691 break;
01692 }
01693 return true;
01694 }
01695
01696 void KHTMLView::setMediaType( const QString &medium )
01697 {
01698 m_medium = medium;
01699 }
01700
01701 QString KHTMLView::mediaType() const
01702 {
01703 return m_medium;
01704 }
01705
01706 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
01707 {
01708 if (vis) {
01709 d->visibleWidgets.replace(w, w->widget());
01710 }
01711 else
01712 d->visibleWidgets.remove(w);
01713 }
01714
01715 void KHTMLView::print()
01716 {
01717 print( false );
01718 }
01719
01720 void KHTMLView::print(bool quick)
01721 {
01722 if(!m_part->xmlDocImpl()) return;
01723 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
01724 if(!root) return;
01725
01726
01727 KPrinter *printer = new KPrinter(true, QPrinter::PrinterResolution);
01728 printer->addDialogPage(new KHTMLPrintSettings());
01729 QString docname = m_part->xmlDocImpl()->URL().prettyURL();
01730 if ( !docname.isEmpty() )
01731 docname = KStringHandler::csqueeze(docname, 80);
01732 if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
01733 viewport()->setCursor( waitCursor );
01734
01735 printer->setFullPage(false);
01736 printer->setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
01737 printer->setDocName(docname);
01738
01739 QPainter *p = new QPainter;
01740 p->begin( printer );
01741 khtml::setPrintPainter( p );
01742
01743 m_part->xmlDocImpl()->setPaintDevice( printer );
01744 QString oldMediaType = mediaType();
01745 setMediaType( "print" );
01746
01747
01748
01749 m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
01750 "* { background-image: none !important;"
01751 " background-color: white !important;"
01752 " color: black !important; }"
01753 "body { margin: 0px !important; }"
01754 "html { margin: 0px !important; }" :
01755 "body { margin: 0px !important; }"
01756 "html { margin: 0px !important; }"
01757 );
01758
01759 QPaintDeviceMetrics metrics( printer );
01760
01761
01762
01763
01764
01765
01766 kdDebug(6000) << "printing: physical page width = " << metrics.width()
01767 << " height = " << metrics.height() << endl;
01768 root->setPrintingMode(true);
01769 root->setWidth(metrics.width());
01770
01771 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
01772 m_part->xmlDocImpl()->updateStyleSelector();
01773 root->setPrintImages( printer->option("app-khtml-printimages") == "true");
01774 root->setMinMaxKnown( false );
01775 root->setLayouted( false );
01776 root->layout();
01777
01778 bool printHeader = (printer->option("app-khtml-printheader") == "true");
01779
01780 int headerHeight = 0;
01781 QFont headerFont("helvetica", 8);
01782
01783 QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),true);
01784 QString headerMid = docname;
01785 QString headerRight;
01786
01787 if (printHeader)
01788 {
01789 p->setFont(headerFont);
01790 headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
01791 }
01792
01793
01794 kdDebug(6000) << "printing: html page width = " << root->docWidth()
01795 << " height = " << root->docHeight() << endl;
01796 kdDebug(6000) << "printing: margins left = " << printer->margins().width()
01797 << " top = " << printer->margins().height() << endl;
01798 kdDebug(6000) << "printing: paper width = " << metrics.width()
01799 << " height = " << metrics.height() << endl;
01800
01801
01802 int pageHeight = metrics.height();
01803 int pageWidth = metrics.width();
01804 p->setClipRect(0,0, pageWidth, pageHeight);
01805
01806 pageHeight -= headerHeight;
01807
01808 bool scalePage = false;
01809 double scale = 0.0;
01810 #ifndef QT_NO_TRANSFORMATIONS
01811 if(root->docWidth() > metrics.width()) {
01812 scalePage = true;
01813 scale = ((double) metrics.width())/((double) root->docWidth());
01814 pageHeight = (int) (pageHeight/scale);
01815 pageWidth = (int) (pageWidth/scale);
01816 headerHeight = (int) (headerHeight/scale);
01817 }
01818 #endif
01819 kdDebug(6000) << "printing: scaled html width = " << pageWidth
01820 << " height = " << pageHeight << endl;
01821
01822
01823 if (printHeader)
01824 {
01825 int available_width = metrics.width() - 10 -
01826 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
01827 p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
01828 if (available_width < 150)
01829 available_width = 150;
01830 int mid_width;
01831 int squeeze = 120;
01832 do {
01833 headerMid = KStringHandler::csqueeze(docname, squeeze);
01834 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
01835 squeeze -= 10;
01836 } while (mid_width > available_width);
01837 }
01838
01839 int top = 0;
01840 int page = 1;
01841 while(top < root->docHeight()) {
01842 if(top > 0) printer->newPage();
01843 if (printHeader)
01844 {
01845 int dy = p->fontMetrics().lineSpacing();
01846 p->setPen(Qt::black);
01847 p->setFont(headerFont);
01848
01849 headerRight = QString("#%1").arg(page);
01850
01851 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
01852 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
01853 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
01854 }
01855
01856 #ifndef QT_NO_TRANSFORMATIONS
01857 if (scalePage)
01858 p->scale(scale, scale);
01859 #endif
01860 p->translate(0, headerHeight-top);
01861
01862 root->setTruncatedAt(top+pageHeight);
01863
01864 root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
01865 if (top + pageHeight >= root->docHeight())
01866 break;
01867
01868 top = root->truncatedAt();
01869 p->resetXForm();
01870 page++;
01871 }
01872
01873 p->end();
01874 delete p;
01875
01876
01877 root->setPrintingMode(false);
01878 khtml::setPrintPainter( 0 );
01879 setMediaType( oldMediaType );
01880 m_part->xmlDocImpl()->setPaintDevice( this );
01881 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
01882 m_part->xmlDocImpl()->updateStyleSelector();
01883 viewport()->unsetCursor();
01884 }
01885 delete printer;
01886 }
01887
01888 void KHTMLView::slotPaletteChanged()
01889 {
01890 if(!m_part->xmlDocImpl()) return;
01891 DOM::DocumentImpl *document = m_part->xmlDocImpl();
01892 if (!document->isHTMLDocument()) return;
01893 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
01894 if(!root) return;
01895 root->style()->resetPalette();
01896 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
01897 if(!body) return;
01898 body->setChanged(true);
01899 body->recalcStyle( NodeImpl::Force );
01900 }
01901
01902 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
01903 {
01904 if(!m_part->xmlDocImpl()) return;
01905 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
01906 if(!root) return;
01907
01908 m_part->xmlDocImpl()->setPaintDevice(p->device());
01909 root->setPrintingMode(true);
01910 root->setWidth(rc.width());
01911
01912 p->save();
01913 p->setClipRect(rc);
01914 p->translate(rc.left(), rc.top());
01915 double scale = ((double) rc.width()/(double) root->docWidth());
01916 int height = (int) ((double) rc.height() / scale);
01917 #ifndef QT_NO_TRANSFORMATIONS
01918 p->scale(scale, scale);
01919 #endif
01920
01921 root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
01922 if (more)
01923 *more = yOff + height < root->docHeight();
01924 p->restore();
01925
01926 root->setPrintingMode(false);
01927 m_part->xmlDocImpl()->setPaintDevice( this );
01928 }
01929
01930
01931 void KHTMLView::useSlowRepaints()
01932 {
01933 d->useSlowRepaints = true;
01934 setStaticBackground(true);
01935 }
01936
01937
01938 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
01939 {
01940 #ifndef KHTML_NO_SCROLLBARS
01941 d->vmode = mode;
01942 QScrollView::setVScrollBarMode(mode);
01943 #else
01944 Q_UNUSED( mode );
01945 #endif
01946 }
01947
01948 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
01949 {
01950 #ifndef KHTML_NO_SCROLLBARS
01951 d->hmode = mode;
01952 QScrollView::setHScrollBarMode(mode);
01953 #else
01954 Q_UNUSED( mode );
01955 #endif
01956 }
01957
01958 void KHTMLView::restoreScrollBar()
01959 {
01960 int ow = visibleWidth();
01961 QScrollView::setVScrollBarMode(d->vmode);
01962 if (visibleWidth() != ow)
01963 layout();
01964 d->prevScrollbarVisible = verticalScrollBar()->isVisible();
01965 }
01966
01967 QStringList KHTMLView::formCompletionItems(const QString &name) const
01968 {
01969 if (!m_part->settings()->isFormCompletionEnabled())
01970 return QStringList();
01971 if (!d->formCompletions)
01972 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01973 return d->formCompletions->readListEntry(name);
01974 }
01975
01976 void KHTMLView::clearCompletionHistory(const QString& name)
01977 {
01978 if (!d->formCompletions)
01979 {
01980 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01981 }
01982 d->formCompletions->writeEntry(name, "");
01983 d->formCompletions->sync();
01984 }
01985
01986 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
01987 {
01988 if (!m_part->settings()->isFormCompletionEnabled())
01989 return;
01990
01991
01992
01993 bool cc_number(true);
01994 for (unsigned int i = 0; i < value.length(); ++i)
01995 {
01996 QChar c(value[i]);
01997 if (!c.isNumber() && c != '-' && !c.isSpace())
01998 {
01999 cc_number = false;
02000 break;
02001 }
02002 }
02003 if (cc_number)
02004 return;
02005 QStringList items = formCompletionItems(name);
02006 if (!items.contains(value))
02007 items.prepend(value);
02008 while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
02009 items.remove(items.fromLast());
02010 d->formCompletions->writeEntry(name, items);
02011 }
02012
02013 void KHTMLView::addNonPasswordStorableSite(const QString& host)
02014 {
02015 if (!d->formCompletions) {
02016 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02017 }
02018
02019 d->formCompletions->setGroup("NonPasswordStorableSites");
02020 QStringList sites = d->formCompletions->readListEntry("Sites");
02021 sites.append(host);
02022 d->formCompletions->writeEntry("Sites", sites);
02023 d->formCompletions->sync();
02024 d->formCompletions->setGroup(QString::null);
02025 }
02026
02027 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
02028 {
02029 if (!d->formCompletions) {
02030 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02031 }
02032 d->formCompletions->setGroup("NonPasswordStorableSites");
02033 QStringList sites = d->formCompletions->readListEntry("Sites");
02034 d->formCompletions->setGroup(QString::null);
02035
02036 return (sites.find(host) != sites.end());
02037 }
02038
02039
02040 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable,
02041 int detail,QMouseEvent *_mouse, bool setUnder,
02042 int mouseEventType)
02043 {
02044 if (d->underMouse)
02045 d->underMouse->deref();
02046 d->underMouse = targetNode;
02047 if (d->underMouse)
02048 d->underMouse->ref();
02049
02050 int exceptioncode = 0;
02051 int pageX = 0;
02052 int pageY = 0;
02053 viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
02054 int clientX = pageX - contentsX();
02055 int clientY = pageY - contentsY();
02056 int screenX = _mouse->globalX();
02057 int screenY = _mouse->globalY();
02058 int button = -1;
02059 switch (_mouse->button()) {
02060 case LeftButton:
02061 button = 0;
02062 break;
02063 case MidButton:
02064 button = 1;
02065 break;
02066 case RightButton:
02067 button = 2;
02068 break;
02069 default:
02070 break;
02071 }
02072 bool ctrlKey = (_mouse->state() & ControlButton);
02073 bool altKey = (_mouse->state() & AltButton);
02074 bool shiftKey = (_mouse->state() & ShiftButton);
02075 bool metaKey = (_mouse->state() & MetaButton);
02076
02077
02078 if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
02079
02080
02081
02082 NodeImpl *oldUnder = 0;
02083 if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
02084 NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
02085 m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
02086 oldUnder = mev.innerNode.handle();
02087 }
02088
02089 if (oldUnder != targetNode) {
02090
02091 if (oldUnder){
02092 oldUnder->ref();
02093 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
02094 true,true,m_part->xmlDocImpl()->defaultView(),
02095 0,screenX,screenY,clientX,clientY,pageX, pageY,
02096 ctrlKey,altKey,shiftKey,metaKey,
02097 button,targetNode);
02098 me->ref();
02099 oldUnder->dispatchEvent(me,exceptioncode,true);
02100 me->deref();
02101 }
02102
02103
02104 if (targetNode) {
02105 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
02106 true,true,m_part->xmlDocImpl()->defaultView(),
02107 0,screenX,screenY,clientX,clientY,pageX, pageY,
02108 ctrlKey,altKey,shiftKey,metaKey,
02109 button,oldUnder);
02110
02111 me->ref();
02112 targetNode->dispatchEvent(me,exceptioncode,true);
02113 me->deref();
02114 }
02115
02116 if (oldUnder)
02117 oldUnder->deref();
02118 }
02119 }
02120
02121 bool swallowEvent = false;
02122
02123 if (targetNode) {
02124
02125 bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
02126 _mouse->type() == QEvent::MouseButtonDblClick );
02127 MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
02128 true,cancelable,m_part->xmlDocImpl()->defaultView(),
02129 detail,screenX,screenY,clientX,clientY,pageX, pageY,
02130 ctrlKey,altKey,shiftKey,metaKey,
02131 button,0, _mouse, dblclick );
02132 me->ref();
02133 targetNode->dispatchEvent(me,exceptioncode,true);
02134 if (me->defaultHandled() || me->defaultPrevented())
02135 swallowEvent = true;
02136 me->deref();
02137
02138 if (eventId == EventImpl::MOUSEDOWN_EVENT) {
02139 if (targetNode->isSelectable())
02140 m_part->xmlDocImpl()->setFocusNode(targetNode);
02141 else
02142 m_part->xmlDocImpl()->setFocusNode(0);
02143 }
02144 }
02145
02146 return swallowEvent;
02147 }
02148
02149 void KHTMLView::setIgnoreWheelEvents( bool e )
02150 {
02151 d->ignoreWheelEvents = e;
02152 }
02153
02154 #ifndef QT_NO_WHEELEVENT
02155
02156 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
02157 {
02158 if ( ( e->state() & ControlButton) == ControlButton )
02159 {
02160 emit zoomView( - e->delta() );
02161 e->accept();
02162 }
02163 else if ( ( (d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
02164 || e->delta() > 0 && contentsY() <= 0
02165 || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())
02166 && m_part->parentPart() ) {
02167 kdDebug(6000) << this << " cz " << contentsY() << " ch " << contentsHeight() << " vh " << visibleHeight() << endl;
02168 if ( m_part->parentPart()->view() )
02169 m_part->parentPart()->view()->wheelEvent( e );
02170 kdDebug(6000) << "sent" << endl;
02171 e->ignore();
02172 }
02173 else if ( d->vmode == QScrollView::AlwaysOff ) {
02174 e->accept();
02175 }
02176 else {
02177 d->scrollBarMoved = true;
02178 QScrollView::viewportWheelEvent( e );
02179
02180 QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, QPoint(-1,-1), QPoint(-1,-1), Qt::NoButton, e->state() );
02181 emit viewportMouseMoveEvent ( tempEvent );
02182 delete tempEvent;
02183 }
02184
02185 }
02186 #endif
02187
02188 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
02189 {
02190
02191
02192
02193 if ( m_part->parentPart() )
02194 {
02195 QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02196 return;
02197 }
02198 QScrollView::dragEnterEvent( ev );
02199 }
02200
02201 void KHTMLView::dropEvent( QDropEvent *ev )
02202 {
02203
02204
02205
02206 if ( m_part->parentPart() )
02207 {
02208 QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02209 return;
02210 }
02211 QScrollView::dropEvent( ev );
02212 }
02213
02214 void KHTMLView::focusInEvent( QFocusEvent *e )
02215 {
02216 #ifndef KHTML_NO_CARET
02217
02218
02219 if (d->m_caretViewContext &&
02220 d->m_caretViewContext->freqTimerId == -1 &&
02221 m_part->xmlDocImpl()) {
02222 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02223 if (m_part->isCaretMode()
02224 || m_part->isEditable()
02225 || (caretNode && caretNode->renderer()
02226 && caretNode->renderer()->style()->userInput()
02227 == UI_ENABLED)) {
02228 d->m_caretViewContext->freqTimerId = startTimer(500);
02229 d->m_caretViewContext->visible = true;
02230 }
02231 }
02232 showCaret();
02233 #endif // KHTML_NO_CARET
02234 QScrollView::focusInEvent( e );
02235 }
02236
02237 void KHTMLView::focusOutEvent( QFocusEvent *e )
02238 {
02239 if(m_part) m_part->stopAutoScroll();
02240
02241 #ifndef KHTML_NO_CARET
02242 if (d->m_caretViewContext) {
02243 switch (d->m_caretViewContext->displayNonFocused) {
02244 case KHTMLPart::CaretInvisible:
02245 hideCaret();
02246 break;
02247 case KHTMLPart::CaretVisible: {
02248 killTimer(d->m_caretViewContext->freqTimerId);
02249 d->m_caretViewContext->freqTimerId = -1;
02250 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02251 if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
02252 || m_part->isEditable()
02253 || (caretNode && caretNode->renderer()
02254 && caretNode->renderer()->style()->userInput()
02255 == UI_ENABLED))) {
02256 d->m_caretViewContext->visible = true;
02257 showCaret(true);
02258 }
02259 break;
02260 }
02261 case KHTMLPart::CaretBlink:
02262
02263 break;
02264 }
02265 }
02266 #endif // KHTML_NO_CARET
02267 QScrollView::focusOutEvent( e );
02268 }
02269
02270 void KHTMLView::slotScrollBarMoved()
02271 {
02272 if (!d->scrollingSelf)
02273 d->scrollBarMoved = true;
02274 }
02275
02276 void KHTMLView::timerEvent ( QTimerEvent *e )
02277 {
02278
02279 if ( e->timerId() == d->scrollTimerId ) {
02280 if( d->scrollSuspended )
02281 return;
02282 switch (d->scrollDirection) {
02283 case KHTMLViewPrivate::ScrollDown:
02284 if (contentsY() + visibleHeight () >= contentsHeight())
02285 d->newScrollTimer(this, 0);
02286 else
02287 scrollBy( 0, d->scrollBy );
02288 break;
02289 case KHTMLViewPrivate::ScrollUp:
02290 if (contentsY() <= 0)
02291 d->newScrollTimer(this, 0);
02292 else
02293 scrollBy( 0, -d->scrollBy );
02294 break;
02295 case KHTMLViewPrivate::ScrollRight:
02296 if (contentsX() + visibleWidth () >= contentsWidth())
02297 d->newScrollTimer(this, 0);
02298 else
02299 scrollBy( d->scrollBy, 0 );
02300 break;
02301 case KHTMLViewPrivate::ScrollLeft:
02302 if (contentsX() <= 0)
02303 d->newScrollTimer(this, 0);
02304 else
02305 scrollBy( -d->scrollBy, 0 );
02306 break;
02307 }
02308 return;
02309 }
02310 else if ( e->timerId() == d->layoutTimerId ) {
02311 d->firstRelayout = false;
02312 d->dirtyLayout = true;
02313 layout();
02314 }
02315 #ifndef KHTML_NO_CARET
02316 else if (d->m_caretViewContext
02317 && e->timerId() == d->m_caretViewContext->freqTimerId) {
02318 d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
02319 if (d->m_caretViewContext->displayed) {
02320 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02321 d->m_caretViewContext->width,
02322 d->m_caretViewContext->height);
02323 }
02324
02325
02326 return;
02327 }
02328 #endif
02329
02330 if( m_part->xmlDocImpl() ) {
02331 DOM::DocumentImpl *document = m_part->xmlDocImpl();
02332 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
02333
02334 if ( root && !root->layouted() ) {
02335 killTimer(d->repaintTimerId);
02336 d->repaintTimerId = 0;
02337 scheduleRelayout();
02338 return;
02339 }
02340 }
02341
02342 setStaticBackground(d->useSlowRepaints);
02343
02344
02345 killTimer(d->repaintTimerId);
02346 d->repaintTimerId = 0;
02347
02348 QRegion updateRegion;
02349 QMemArray<QRect> rects = d->updateRegion.rects();
02350
02351 d->updateRegion = QRegion();
02352
02353 if ( rects.size() )
02354 updateRegion = rects[0];
02355
02356 for ( unsigned i = 1; i < rects.size(); ++i ) {
02357 QRect obR = updateRegion.boundingRect();
02358 QRegion newRegion = updateRegion.unite(rects[i]);
02359 if (2*newRegion.boundingRect().height() > 3*obR.height() )
02360 {
02361 repaintContents( obR );
02362 updateRegion = rects[i];
02363 }
02364 else
02365 updateRegion = newRegion;
02366 }
02367
02368 if ( !updateRegion.isNull() )
02369 repaintContents( updateRegion.boundingRect() );
02370
02371 if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
02372 QWidget* w;
02373 d->dirtyLayout = false;
02374
02375 QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02376 QPtrList<RenderWidget> toRemove;
02377 for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
02378 int xp = 0, yp = 0;
02379 w = it.current();
02380 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
02381 if (!rw->absolutePosition(xp, yp) ||
02382 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
02383 toRemove.append(rw);
02384 }
02385 for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
02386 if ( (w = d->visibleWidgets.take(r) ) )
02387 addChild(w, 0, -500000);
02388 }
02389 }
02390
02391 void KHTMLView::scheduleRelayout(khtml::RenderObject * )
02392 {
02393 if (!d->layoutSchedulingEnabled || d->layoutTimerId)
02394 return;
02395
02396 d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
02397 ? 1000 : 0 );
02398 }
02399
02400 void KHTMLView::unscheduleRelayout()
02401 {
02402 if (!d->layoutTimerId)
02403 return;
02404
02405 killTimer(d->layoutTimerId);
02406 d->layoutTimerId = 0;
02407 }
02408
02409 void KHTMLView::unscheduleRepaint()
02410 {
02411 if (!d->repaintTimerId)
02412 return;
02413
02414 killTimer(d->repaintTimerId);
02415 d->repaintTimerId = 0;
02416 }
02417
02418 void KHTMLView::scheduleRepaint(int x, int y, int w, int h)
02419 {
02420 bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
02421
02422
02423
02424
02425 int time = parsing ? 300 : ( !d->complete ? 100 : 20 );
02426
02427 #ifdef DEBUG_FLICKER
02428 QPainter p;
02429 p.begin( viewport() );
02430
02431 int vx, vy;
02432 contentsToViewport( x, y, vx, vy );
02433 p.fillRect( vx, vy, w, h, Qt::red );
02434 p.end();
02435 #endif
02436
02437 d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
02438
02439 if ( !d->repaintTimerId )
02440 d->repaintTimerId = startTimer( time );
02441
02442
02443 }
02444
02445 void KHTMLView::complete()
02446 {
02447
02448
02449 d->complete = true;
02450
02451
02452 if (d->layoutTimerId)
02453 {
02454
02455
02456 killTimer(d->layoutTimerId);
02457 d->layoutTimerId = startTimer( 0 );
02458 }
02459
02460
02461 if (d->repaintTimerId)
02462 {
02463
02464
02465 killTimer(d->repaintTimerId);
02466 d->repaintTimerId = startTimer( 20 );
02467 }
02468 }
02469
02470 #ifndef KHTML_NO_CARET
02471
02472
02473
02474
02475 #include "khtml_caret.cpp"
02476
02477 void KHTMLView::initCaret(bool keepSelection)
02478 {
02479 #if DEBUG_CARETMODE > 0
02480 kdDebug(6200) << "begin initCaret" << endl;
02481 #endif
02482
02483 if (m_part->xmlDocImpl()) {
02484 d->caretViewContext();
02485 bool cmoved = d->m_caretViewContext->caretMoved;
02486 if (m_part->d->caretNode().isNull()) {
02487
02488 m_part->d->caretNode() = m_part->document();
02489 m_part->d->caretOffset() = 0L;
02490
02491
02492
02493 if (!m_part->d->caretNode().handle()->renderer()) return;
02494 }
02495
02496
02497
02498 moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
02499
02500
02501 d->m_caretViewContext->caretMoved = cmoved;
02502 }
02503 #if DEBUG_CARETMODE > 0
02504 kdDebug(6200) << "end initCaret" << endl;
02505 #endif
02506 }
02507
02508 bool KHTMLView::caretOverrides() const
02509 {
02510 bool cm = m_part->isCaretMode();
02511 bool dm = m_part->isEditable();
02512 return cm && !dm ? false
02513 : (dm || m_part->d->caretNode().handle()->contentEditable())
02514 && d->editorContext()->override;
02515 }
02516
02517 void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
02518 {
02519 if (m_part->isCaretMode() || m_part->isEditable()) return;
02520 if (node->focused()) return;
02521
02522
02523 NodeImpl *firstAncestor = 0;
02524 while (node) {
02525 if (node->renderer()
02526 && node->renderer()->style()->userInput() != UI_ENABLED)
02527 break;
02528 firstAncestor = node;
02529 node = node->parentNode();
02530 }
02531
02532 if (!node) firstAncestor = 0;
02533
02534 DocumentImpl *doc = m_part->xmlDocImpl();
02535
02536 if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
02537 && doc->focusNode()->renderer()->isWidget())
02538 return;
02539
02540
02541 #if DEBUG_CARETMODE > 1
02542 kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
02543 << (firstAncestor ? firstAncestor->nodeName().string() : QString::null) << endl;
02544 #endif
02545 doc->setFocusNode(firstAncestor);
02546 emit m_part->nodeActivated(Node(firstAncestor));
02547 }
02548
02549 void KHTMLView::recalcAndStoreCaretPos(InlineBox *hintBox)
02550 {
02551 if (!m_part || m_part->d->caretNode().isNull()) return;
02552 d->caretViewContext();
02553 NodeImpl *caretNode = m_part->d->caretNode().handle();
02554 #if DEBUG_CARETMODE > 0
02555 kdDebug(6200) << "recalcAndStoreCaretPos: caretNode=" << caretNode << (caretNode ? " "+caretNode->nodeName().string() : QString::null) << " r@" << caretNode->renderer() << (caretNode->renderer() && caretNode->renderer()->isText() ? " \"" + QConstString(static_cast<RenderText *>(caretNode->renderer())->str->s, kMin(static_cast<RenderText *>(caretNode->renderer())->str->l, 15u)).string() + "\"" : QString::null) << endl;
02556 #endif
02557 caretNode->getCaret(m_part->d->caretOffset(),
02558 caretOverrides(),
02559 d->m_caretViewContext->x, d->m_caretViewContext->y,
02560 d->m_caretViewContext->width,
02561 d->m_caretViewContext->height);
02562
02563 if (hintBox && d->m_caretViewContext->x == -1) {
02564 #if DEBUG_CARETMODE > 1
02565 kdDebug(6200) << "using hint inline box coordinates" << endl;
02566 #endif
02567 RenderObject *r = caretNode->renderer();
02568 const QFontMetrics &fm = r->style()->fontMetrics();
02569 int absx, absy;
02570 r->containingBlock()->absolutePosition(absx, absy,
02571 false);
02572 d->m_caretViewContext->x = absx + hintBox->xPos();
02573 d->m_caretViewContext->y = absy + hintBox->yPos()
02574 + hintBox->baseline() - fm.ascent();
02575 d->m_caretViewContext->width = 1;
02576
02577
02578 d->m_caretViewContext->height = fm.height();
02579 }
02580
02581 #if DEBUG_CARETMODE > 4
02582
02583 #endif
02584 #if DEBUG_CARETMODE > 0
02585 kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
02586 <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
02587 <<" h="<<d->m_caretViewContext->height<<endl;
02588 #endif
02589 }
02590
02591 void KHTMLView::caretOn()
02592 {
02593 if (d->m_caretViewContext) {
02594 killTimer(d->m_caretViewContext->freqTimerId);
02595
02596 if (hasFocus() || d->m_caretViewContext->displayNonFocused
02597 == KHTMLPart::CaretBlink) {
02598 d->m_caretViewContext->freqTimerId = startTimer(500);
02599 } else {
02600 d->m_caretViewContext->freqTimerId = -1;
02601 }
02602
02603 d->m_caretViewContext->visible = true;
02604 if ((d->m_caretViewContext->displayed = (hasFocus()
02605 || d->m_caretViewContext->displayNonFocused
02606 != KHTMLPart::CaretInvisible))) {
02607 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02608 d->m_caretViewContext->width,
02609 d->m_caretViewContext->height);
02610 }
02611
02612 }
02613 }
02614
02615 void KHTMLView::caretOff()
02616 {
02617 if (d->m_caretViewContext) {
02618 killTimer(d->m_caretViewContext->freqTimerId);
02619 d->m_caretViewContext->freqTimerId = -1;
02620 d->m_caretViewContext->displayed = false;
02621 if (d->m_caretViewContext->visible) {
02622 d->m_caretViewContext->visible = false;
02623 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02624 d->m_caretViewContext->width,
02625 d->m_caretViewContext->height);
02626 }
02627
02628 }
02629 }
02630
02631 void KHTMLView::showCaret(bool forceRepaint)
02632 {
02633 if (d->m_caretViewContext) {
02634 d->m_caretViewContext->displayed = true;
02635 if (d->m_caretViewContext->visible) {
02636 if (!forceRepaint) {
02637 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02638 d->m_caretViewContext->width,
02639 d->m_caretViewContext->height);
02640 } else {
02641 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02642 d->m_caretViewContext->width,
02643 d->m_caretViewContext->height);
02644 }
02645 }
02646
02647 }
02648 }
02649
02650 bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
02651 NodeImpl *endNode, long endOffset)
02652 {
02653 m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
02654 m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
02655 m_part->d->m_extendAtEnd = true;
02656
02657 bool folded = startNode != endNode || startOffset != endOffset;
02658
02659
02660 if (folded) {
02661 m_part->xmlDocImpl()->clearSelection();
02662 }
02663
02664 return folded;
02665 }
02666
02667 void KHTMLView::hideCaret()
02668 {
02669 if (d->m_caretViewContext) {
02670 if (d->m_caretViewContext->visible) {
02671
02672 d->m_caretViewContext->visible = false;
02673
02674
02675 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02676 d->m_caretViewContext->width,
02677 d->m_caretViewContext->height);
02678 d->m_caretViewContext->visible = true;
02679 }
02680 d->m_caretViewContext->displayed = false;
02681
02682 }
02683 }
02684
02685 int KHTMLView::caretDisplayPolicyNonFocused() const
02686 {
02687 if (d->m_caretViewContext)
02688 return d->m_caretViewContext->displayNonFocused;
02689 else
02690 return KHTMLPart::CaretInvisible;
02691 }
02692
02693 void KHTMLView::setCaretDisplayPolicyNonFocused(int policy)
02694 {
02695 d->caretViewContext();
02696
02697 d->m_caretViewContext->displayNonFocused = (KHTMLPart::CaretDisplayPolicy)policy;
02698
02699
02700 if (!hasFocus()) {
02701 switch (d->m_caretViewContext->displayNonFocused) {
02702 case KHTMLPart::CaretInvisible:
02703 hideCaret();
02704 break;
02705 case KHTMLPart::CaretBlink:
02706 if (d->m_caretViewContext->freqTimerId != -1) break;
02707 d->m_caretViewContext->freqTimerId = startTimer(500);
02708
02709 case KHTMLPart::CaretVisible:
02710 d->m_caretViewContext->displayed = true;
02711 showCaret();
02712 break;
02713 }
02714 }
02715 }
02716
02717 bool KHTMLView::placeCaret(InlineBox *hintBox)
02718 {
02719 CaretViewContext *cv = d->caretViewContext();
02720 caretOff();
02721 NodeImpl *caretNode = m_part->d->caretNode().handle();
02722
02723 if (!caretNode || !caretNode->renderer()) return false;
02724 ensureNodeHasFocus(caretNode);
02725 if (m_part->isCaretMode() || m_part->isEditable()
02726 || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
02727 recalcAndStoreCaretPos(hintBox);
02728
02729 cv->origX = cv->x;
02730
02731 caretOn();
02732 return true;
02733 }
02734 return false;
02735 }
02736
02737 void KHTMLView::ensureCaretVisible()
02738 {
02739 CaretViewContext *cv = d->m_caretViewContext;
02740 if (!cv) return;
02741 ensureVisible(cv->x, cv->y, cv->width, cv->height);
02742 d->scrollBarMoved = false;
02743 }
02744
02745 bool KHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
02746 NodeImpl *oldEndSel, long oldEndOfs)
02747 {
02748 bool changed = false;
02749 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
02750 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
02751 changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02752 m_part->d->m_extendAtEnd = true;
02753 } else do {
02754 changed = m_part->d->m_selectionStart.handle() != oldStartSel
02755 || m_part->d->m_startOffset != oldStartOfs
02756 || m_part->d->m_selectionEnd.handle() != oldEndSel
02757 || m_part->d->m_endOffset != oldEndOfs;
02758 if (!changed) break;
02759
02760
02761 NodeImpl *startNode;
02762 long startOffset;
02763 if (m_part->d->m_extendAtEnd) {
02764 startNode = m_part->d->m_selectionStart.handle();
02765 startOffset = m_part->d->m_startOffset;
02766 } else {
02767 startNode = m_part->d->m_selectionEnd.handle();
02768 startOffset = m_part->d->m_endOffset;
02769 m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
02770 m_part->d->m_endOffset = m_part->d->m_startOffset;
02771 }
02772
02773 bool swapNeeded = false;
02774 if (!m_part->d->m_selectionEnd.isNull() && startNode) {
02775 swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
02776 m_part->d->m_selectionEnd.handle(),
02777 m_part->d->m_endOffset) >= 0;
02778 }
02779
02780 m_part->d->m_selectionStart = startNode;
02781 m_part->d->m_startOffset = startOffset;
02782
02783 if (swapNeeded) {
02784 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
02785 m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
02786 m_part->d->m_startOffset);
02787 } else {
02788 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
02789 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
02790 m_part->d->m_endOffset);
02791 }
02792 } while(false);
02793 return changed;
02794 }
02795
02796 void KHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
02797 NodeImpl *oldEndSel, long oldEndOfs)
02798 {
02799 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
02800 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
02801 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
02802 m_part->emitSelectionChanged();
02803 }
02804 m_part->d->m_extendAtEnd = true;
02805 } else {
02806
02807 if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
02808 bool swapNeeded = RangeImpl::compareBoundaryPoints(
02809 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
02810 m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
02811 if (swapNeeded) {
02812 DOM::Node tmpNode = m_part->d->m_selectionStart;
02813 long tmpOffset = m_part->d->m_startOffset;
02814 m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
02815 m_part->d->m_startOffset = m_part->d->m_endOffset;
02816 m_part->d->m_selectionEnd = tmpNode;
02817 m_part->d->m_endOffset = tmpOffset;
02818 m_part->d->m_startBeforeEnd = true;
02819 m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
02820 }
02821 }
02822
02823 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
02824 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
02825 m_part->d->m_endOffset);
02826 m_part->emitSelectionChanged();
02827 }
02828 }
02829
02830 void KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
02831 {
02832 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
02833 long oldStartOfs = m_part->d->m_startOffset;
02834 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
02835 long oldEndOfs = m_part->d->m_endOffset;
02836
02837 NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
02838 long oldOffset = m_part->d->caretOffset();
02839
02840 bool ctrl = _ke->state() & ControlButton;
02841
02842
02843 switch(_ke->key()) {
02844 case Key_Space:
02845 break;
02846
02847 case Key_Down:
02848 moveCaretNextLine(1);
02849 break;
02850
02851 case Key_Up:
02852 moveCaretPrevLine(1);
02853 break;
02854
02855 case Key_Left:
02856 moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
02857 break;
02858
02859 case Key_Right:
02860 moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
02861 break;
02862
02863 case Key_Next:
02864 moveCaretNextPage();
02865 break;
02866
02867 case Key_Prior:
02868 moveCaretPrevPage();
02869 break;
02870
02871 case Key_Home:
02872 if (ctrl)
02873 moveCaretToDocumentBoundary(false);
02874 else
02875 moveCaretToLineBegin();
02876 break;
02877
02878 case Key_End:
02879 if (ctrl)
02880 moveCaretToDocumentBoundary(true);
02881 else
02882 moveCaretToLineEnd();
02883 break;
02884
02885 }
02886
02887 if ((m_part->d->caretNode().handle() != oldCaretNode
02888 || m_part->d->caretOffset() != oldOffset)
02889
02890 && !m_part->d->caretNode().isNull()) {
02891
02892 d->m_caretViewContext->caretMoved = true;
02893
02894 if (_ke->state() & ShiftButton) {
02895 updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02896 } else {
02897 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
02898 m_part->emitSelectionChanged();
02899 }
02900
02901 m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
02902 }
02903
02904 _ke->accept();
02905 }
02906
02907 bool KHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
02908 {
02909 sanitizeCaretState(node, offset);
02910 if (!node) return false;
02911
02912
02913
02914
02915 RenderArena arena;
02916 RenderFlow *cb;
02917 InlineBox *box = 0;
02918 findFlowBox(node, offset, &arena, cb, &box);
02919 if (box && box->object() != node->renderer()) {
02920 if (box->object()->element()) {
02921 node = box->object()->element();
02922 offset = node->minOffset();
02923 #if DEBUG_CARETMODE > 1
02924 kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
02925 #endif
02926 } else {
02927
02928 box = 0;
02929 kdError(6200) << "Box contains no node! Crash imminent" << endl;
02930 }
02931 }
02932
02933 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
02934 long oldStartOfs = m_part->d->m_startOffset;
02935 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
02936 long oldEndOfs = m_part->d->m_endOffset;
02937
02938
02939 bool posChanged = m_part->d->caretNode().handle() != node
02940 || m_part->d->caretOffset() != offset;
02941 bool selChanged = false;
02942
02943 m_part->d->caretNode() = node;
02944 m_part->d->caretOffset() = offset;
02945 if (clearSel || !oldStartSel || !oldEndSel) {
02946 selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02947 } else {
02948
02949
02950 selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02951
02952
02953 }
02954
02955 d->caretViewContext()->caretMoved = true;
02956
02957 bool visible_caret = placeCaret(box);
02958
02959
02960
02961
02962 if (posChanged) {
02963 m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
02964 }
02965
02966 return selChanged;
02967 }
02968
02969 void KHTMLView::moveCaretByLine(bool next, int count)
02970 {
02971
02972
02973 Node &caretNodeRef = m_part->d->caretNode();
02974 if (caretNodeRef.isNull()) return;
02975
02976 NodeImpl *caretNode = caretNodeRef.handle();
02977
02978 long offset = m_part->d->caretOffset();
02979
02980 CaretViewContext *cv = d->caretViewContext();
02981
02982 LinearDocument ld(m_part, caretNode, offset);
02983
02984 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
02985
02986
02987 while (count > 0 && it != ld.end() && it != ld.preBegin()) {
02988 count--;
02989 if (next) ++it; else --it;
02990 }
02991
02992
02993 if (it == ld.end() || it == ld.preBegin()) return;
02994
02995 int x, absx, absy;
02996 InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
02997
02998 placeCaretOnLine(caretBox, x, absx, absy);
02999 }
03000
03001 void KHTMLView::placeCaretOnLine(InlineBox *caretBox, int x, int absx, int absy)
03002 {
03003
03004 if (!caretBox) return;
03005
03006 RenderObject *caretRender = caretBox->object();
03007 NodeImpl *caretNode = caretRender->element();
03008
03009 #if DEBUG_CARETMODE > 0
03010 kdDebug(6200) << "got valid caretBox " << caretBox << endl;
03011 kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
03012 << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
03013 if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << QString(((RenderText *)((InlineTextBox *)caretBox)->object())->str->s + ((InlineTextBox *)caretBox)->m_start, ((InlineTextBox *)caretBox)->m_len) << "\"" << endl;}
03014 #endif
03015
03016 int caretHeight = caretBox->height();
03017 bool isText = caretBox->isInlineTextBox();
03018 int yOfs = 0;
03019 if (isText) {
03020
03021 RenderText *t = static_cast<RenderText *>(caretRender);
03022 const QFontMetrics &fm = t->metrics(caretBox->m_firstLine);
03023 caretHeight = fm.height();
03024 yOfs = caretBox->baseline() - fm.ascent();
03025 }
03026
03027 caretOff();
03028
03029
03030 m_part->d->caretNode() = caretNode;
03031 long &offset = m_part->d->caretOffset();
03032
03033
03034 d->m_caretViewContext->y = caretBox->yPos() + yOfs;
03035 d->m_caretViewContext->height = caretHeight;
03036 d->m_caretViewContext->width = 1;
03037
03038 int xPos = caretBox->xPos();
03039 int caretBoxWidth = caretBox->width();
03040
03041
03042 if (x <= xPos) {
03043 d->m_caretViewContext->x = xPos;
03044 offset = caretBox->minOffset();
03045
03046 } else if (x > xPos && x <= xPos + caretBoxWidth) {
03047 if (isText) {
03048 offset = static_cast<InlineTextBox *>(caretBox)->offsetForPoint(x,
03049 d->m_caretViewContext->x);
03050 #if DEBUG_CARETMODE > 2
03051 kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
03052 #endif
03053 } else {
03054 if (xPos + caretBoxWidth - x < x - xPos) {
03055 d->m_caretViewContext->x = xPos + caretBoxWidth;
03056 offset = caretNode ? caretNode->maxOffset() : 1;
03057 } else {
03058 d->m_caretViewContext->x = xPos;
03059 offset = caretNode ? caretNode->minOffset() : 0;
03060 }
03061 }
03062 } else {
03063 d->m_caretViewContext->x = xPos + caretBoxWidth;
03064 offset = caretBox->maxOffset();
03065 }
03066 #if DEBUG_CARETMODE > 0
03067 kdDebug(6200) << "new offset: " << offset << endl;
03068 #endif
03069
03070 d->m_caretViewContext->x += absx;
03071 d->m_caretViewContext->y += absy;
03072
03073 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03074 d->m_caretViewContext->width, d->m_caretViewContext->height);
03075 d->scrollBarMoved = false;
03076
03077 ensureNodeHasFocus(caretNode);
03078 caretOn();
03079 }
03080
03081 void KHTMLView::moveCaretToLineBoundary(bool end)
03082 {
03083
03084
03085 Node &caretNodeRef = m_part->d->caretNode();
03086 if (caretNodeRef.isNull()) return;
03087
03088 NodeImpl *caretNode = caretNodeRef.handle();
03089
03090 long offset = m_part->d->caretOffset();
03091
03092 LinearDocument ld(m_part, caretNode, offset);
03093
03094 EditableLineIterator it = ld.current();
03095 if (it == ld.end()) return;
03096
03097 EditableInlineBoxIterator fbit(it, end);
03098 InlineBox *b = *fbit;
03099 Q_ASSERT(b);
03100
03101 RenderObject *cb = (*it)->object();
03102 int absx, absy;
03103
03104 if (cb) cb->absolutePosition(absx,absy);
03105 else absx = absy = 0;
03106
03107 int x = b->xPos() + (end ? b->width() : 0);
03108 d->m_caretViewContext->origX = absx + x;
03109 placeCaretOnLine(b, x, absx, absy);
03110 }
03111
03112 void KHTMLView::moveCaretToDocumentBoundary(bool end)
03113 {
03114
03115
03116 Node &caretNodeRef = m_part->d->caretNode();
03117 if (caretNodeRef.isNull()) return;
03118
03119 NodeImpl *caretNode = caretNodeRef.handle();
03120
03121 long offset = m_part->d->caretOffset();
03122
03123 LinearDocument ld(m_part, caretNode, offset);
03124
03125 EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
03126 if (it == ld.end() || it == ld.preBegin()) return;
03127
03128 EditableInlineBoxIterator fbit = it;
03129 InlineBox *b = *fbit;
03130 Q_ASSERT(b);
03131
03132 RenderObject *cb = (*it)->object();
03133 int absx, absy;
03134
03135 if (cb) cb->absolutePosition(absx, absy);
03136 else absx = absy = 0;
03137
03138 int x = b->xPos();
03139 d->m_caretViewContext->origX = absx + x;
03140 placeCaretOnLine(b, x, absx, absy);
03141 }
03142
03143 void KHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
03144 {
03145 if (!m_part) return;
03146
03147
03148 Node &caretNodeRef = m_part->d->caretNode();
03149 if (caretNodeRef.isNull()) return;
03150
03151 NodeImpl *caretNode = caretNodeRef.handle();
03152
03153 long &offset = m_part->d->caretOffset();
03154
03155 LinearDocument ld(m_part, caretNode, offset);
03156
03157 EditableCharacterIterator it(&ld);
03158 InlineBox *hintBox = it.box();
03159 while (it.node() && count > 0) {
03160 count--;
03161 if (cmv == CaretByCharacter) {
03162 if (next) ++it;
03163 else --it;
03164 } else if (cmv == CaretByWord) {
03165 if (next) moveItToNextWord(it);
03166 else moveItToPrevWord(it);
03167 }
03168 }
03169 if (it.node()) {
03170 caretNodeRef = it.node();
03171 offset = it.offset();
03172 hintBox = it.box();
03173 #if DEBUG_CARETMODE > 2
03174 kdDebug(6200) << "set by valid node. offset: " << offset << endl;
03175 #endif
03176 } else {
03177 offset = next ? caretNode->maxOffset() : caretNode->minOffset();
03178 #if DEBUG_CARETMODE > 0
03179 kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
03180 #endif
03181 }
03182 placeCaretOnChar(hintBox);
03183 }
03184
03185 void KHTMLView::placeCaretOnChar(InlineBox *hintBox)
03186 {
03187 caretOff();
03188 recalcAndStoreCaretPos(hintBox);
03189 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03190 d->m_caretViewContext->width, d->m_caretViewContext->height);
03191 d->m_caretViewContext->origX = d->m_caretViewContext->x;
03192 d->scrollBarMoved = false;
03193 #if DEBUG_CARETMODE > 3
03194
03195 #endif
03196 ensureNodeHasFocus(m_part->d->caretNode().handle());
03197 caretOn();
03198 }
03199
03200 void KHTMLView::moveCaretByPage(bool next)
03201 {
03202
03203
03204 Node &caretNodeRef = m_part->d->caretNode();
03205 if (caretNodeRef.isNull()) return;
03206
03207 NodeImpl *caretNode = caretNodeRef.handle();
03208
03209 long offset = m_part->d->caretOffset();
03210
03211 int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
03212
03213 int mindist = clipper()->height() - offs;
03214
03215 CaretViewContext *cv = d->caretViewContext();
03216
03217
03218 LinearDocument ld(m_part, caretNode, offset);
03219
03220 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03221
03222 moveIteratorByPage(ld, it, mindist, next);
03223
03224 int x, absx, absy;
03225 InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
03226
03227 placeCaretOnLine(caretBox, x, absx, absy);
03228 }
03229
03230 void KHTMLView::moveCaretPrevWord()
03231 {
03232 moveCaretBy(false, CaretByWord, 1);
03233 }
03234
03235 void KHTMLView::moveCaretNextWord()
03236 {
03237 moveCaretBy(true, CaretByWord, 1);
03238 }
03239
03240 void KHTMLView::moveCaretPrevLine(int n)
03241 {
03242 moveCaretByLine(false, n);
03243 }
03244
03245 void KHTMLView::moveCaretNextLine(int n)
03246 {
03247 moveCaretByLine(true, n);
03248 }
03249
03250 void KHTMLView::moveCaretPrevPage()
03251 {
03252 moveCaretByPage(false);
03253 }
03254
03255 void KHTMLView::moveCaretNextPage()
03256 {
03257 moveCaretByPage(true);
03258 }
03259
03260 void KHTMLView::moveCaretToLineBegin()
03261 {
03262 moveCaretToLineBoundary(false);
03263 }
03264
03265 void KHTMLView::moveCaretToLineEnd()
03266 {
03267 moveCaretToLineBoundary(true);
03268 }
03269
03270 #endif // KHTML_NO_CARET
03271
03272 #undef DEBUG_CARETMODE