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 QRect r = node->getRect();
01659 ensureVisible( r.right(), r.bottom());
01660 ensureVisible( r.left(), r.top());
01661
01662 Node guard( node );
01663 if( node->isSelectable()) {
01664
01665 m_part->xmlDocImpl()->setFocusNode(node);
01666 if( node != NULL && node->hasOneRef())
01667 return true;
01668 emit m_part->nodeActivated(Node(node));
01669 if( node != NULL && node->hasOneRef())
01670 return true;
01671 }
01672 switch( node->id()) {
01673 case ID_A:
01674 static_cast< HTMLAnchorElementImpl* >( node )->click();
01675 break;
01676 case ID_INPUT:
01677 static_cast< HTMLInputElementImpl* >( node )->click();
01678 break;
01679 case ID_BUTTON:
01680 static_cast< HTMLButtonElementImpl* >( node )->click();
01681 break;
01682 case ID_AREA:
01683 static_cast< HTMLAreaElementImpl* >( node )->click();
01684 break;
01685 case ID_LABEL:
01686
01687 break;
01688 case ID_TEXTAREA:
01689 break;
01690 case ID_LEGEND:
01691
01692 break;
01693 }
01694 return true;
01695 }
01696
01697 void KHTMLView::setMediaType( const QString &medium )
01698 {
01699 m_medium = medium;
01700 }
01701
01702 QString KHTMLView::mediaType() const
01703 {
01704 return m_medium;
01705 }
01706
01707 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
01708 {
01709 if (vis) {
01710 d->visibleWidgets.replace(w, w->widget());
01711 }
01712 else
01713 d->visibleWidgets.remove(w);
01714 }
01715
01716 void KHTMLView::print()
01717 {
01718 print( false );
01719 }
01720
01721 void KHTMLView::print(bool quick)
01722 {
01723 if(!m_part->xmlDocImpl()) return;
01724 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
01725 if(!root) return;
01726
01727
01728 KPrinter *printer = new KPrinter(true, QPrinter::PrinterResolution);
01729 printer->addDialogPage(new KHTMLPrintSettings());
01730 QString docname = m_part->xmlDocImpl()->URL().prettyURL();
01731 if ( !docname.isEmpty() )
01732 docname = KStringHandler::csqueeze(docname, 80);
01733 if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
01734 viewport()->setCursor( waitCursor );
01735
01736 printer->setFullPage(false);
01737 printer->setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
01738 printer->setDocName(docname);
01739
01740 QPainter *p = new QPainter;
01741 p->begin( printer );
01742 khtml::setPrintPainter( p );
01743
01744 m_part->xmlDocImpl()->setPaintDevice( printer );
01745 QString oldMediaType = mediaType();
01746 setMediaType( "print" );
01747
01748
01749
01750 m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
01751 "* { background-image: none !important;"
01752 " background-color: white !important;"
01753 " color: black !important; }"
01754 "body { margin: 0px !important; }"
01755 "html { margin: 0px !important; }" :
01756 "body { margin: 0px !important; }"
01757 "html { margin: 0px !important; }"
01758 );
01759
01760 QPaintDeviceMetrics metrics( printer );
01761
01762
01763
01764
01765
01766
01767 kdDebug(6000) << "printing: physical page width = " << metrics.width()
01768 << " height = " << metrics.height() << endl;
01769 root->setPrintingMode(true);
01770 root->setWidth(metrics.width());
01771
01772 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
01773 m_part->xmlDocImpl()->updateStyleSelector();
01774 root->setPrintImages( printer->option("app-khtml-printimages") == "true");
01775 root->setMinMaxKnown( false );
01776 root->setLayouted( false );
01777 root->layout();
01778 khtml::RenderWidget::flushWidgetResizes();
01779
01780 bool printHeader = (printer->option("app-khtml-printheader") == "true");
01781
01782 int headerHeight = 0;
01783 QFont headerFont("helvetica", 8);
01784
01785 QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),true);
01786 QString headerMid = docname;
01787 QString headerRight;
01788
01789 if (printHeader)
01790 {
01791 p->setFont(headerFont);
01792 headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
01793 }
01794
01795
01796 kdDebug(6000) << "printing: html page width = " << root->docWidth()
01797 << " height = " << root->docHeight() << endl;
01798 kdDebug(6000) << "printing: margins left = " << printer->margins().width()
01799 << " top = " << printer->margins().height() << endl;
01800 kdDebug(6000) << "printing: paper width = " << metrics.width()
01801 << " height = " << metrics.height() << endl;
01802
01803
01804 int pageHeight = metrics.height();
01805 int pageWidth = metrics.width();
01806 p->setClipRect(0,0, pageWidth, pageHeight);
01807
01808 pageHeight -= headerHeight;
01809
01810 bool scalePage = false;
01811 double scale = 0.0;
01812 #ifndef QT_NO_TRANSFORMATIONS
01813 if(root->docWidth() > metrics.width()) {
01814 scalePage = true;
01815 scale = ((double) metrics.width())/((double) root->docWidth());
01816 pageHeight = (int) (pageHeight/scale);
01817 pageWidth = (int) (pageWidth/scale);
01818 headerHeight = (int) (headerHeight/scale);
01819 }
01820 #endif
01821 kdDebug(6000) << "printing: scaled html width = " << pageWidth
01822 << " height = " << pageHeight << endl;
01823
01824
01825 if (printHeader)
01826 {
01827 int available_width = metrics.width() - 10 -
01828 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
01829 p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
01830 if (available_width < 150)
01831 available_width = 150;
01832 int mid_width;
01833 int squeeze = 120;
01834 do {
01835 headerMid = KStringHandler::csqueeze(docname, squeeze);
01836 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
01837 squeeze -= 10;
01838 } while (mid_width > available_width);
01839 }
01840
01841 int top = 0;
01842 int page = 1;
01843 while(top < root->docHeight()) {
01844 if(top > 0) printer->newPage();
01845 if (printHeader)
01846 {
01847 int dy = p->fontMetrics().lineSpacing();
01848 p->setPen(Qt::black);
01849 p->setFont(headerFont);
01850
01851 headerRight = QString("#%1").arg(page);
01852
01853 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
01854 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
01855 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
01856 }
01857
01858 #ifndef QT_NO_TRANSFORMATIONS
01859 if (scalePage)
01860 p->scale(scale, scale);
01861 #endif
01862 p->translate(0, headerHeight-top);
01863
01864 root->setTruncatedAt(top+pageHeight);
01865
01866 root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
01867 if (top + pageHeight >= root->docHeight())
01868 break;
01869
01870 top = root->truncatedAt();
01871 p->resetXForm();
01872 page++;
01873 }
01874
01875 p->end();
01876 delete p;
01877
01878
01879 root->setPrintingMode(false);
01880 khtml::setPrintPainter( 0 );
01881 setMediaType( oldMediaType );
01882 m_part->xmlDocImpl()->setPaintDevice( this );
01883 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
01884 m_part->xmlDocImpl()->updateStyleSelector();
01885 viewport()->unsetCursor();
01886 }
01887 delete printer;
01888 }
01889
01890 void KHTMLView::slotPaletteChanged()
01891 {
01892 if(!m_part->xmlDocImpl()) return;
01893 DOM::DocumentImpl *document = m_part->xmlDocImpl();
01894 if (!document->isHTMLDocument()) return;
01895 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
01896 if(!root) return;
01897 root->style()->resetPalette();
01898 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
01899 if(!body) return;
01900 body->setChanged(true);
01901 body->recalcStyle( NodeImpl::Force );
01902 }
01903
01904 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
01905 {
01906 if(!m_part->xmlDocImpl()) return;
01907 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
01908 if(!root) return;
01909
01910 m_part->xmlDocImpl()->setPaintDevice(p->device());
01911 root->setPrintingMode(true);
01912 root->setWidth(rc.width());
01913
01914 p->save();
01915 p->setClipRect(rc);
01916 p->translate(rc.left(), rc.top());
01917 double scale = ((double) rc.width()/(double) root->docWidth());
01918 int height = (int) ((double) rc.height() / scale);
01919 #ifndef QT_NO_TRANSFORMATIONS
01920 p->scale(scale, scale);
01921 #endif
01922
01923 root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
01924 if (more)
01925 *more = yOff + height < root->docHeight();
01926 p->restore();
01927
01928 root->setPrintingMode(false);
01929 m_part->xmlDocImpl()->setPaintDevice( this );
01930 }
01931
01932
01933 void KHTMLView::useSlowRepaints()
01934 {
01935 d->useSlowRepaints = true;
01936 setStaticBackground(true);
01937 }
01938
01939
01940 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
01941 {
01942 #ifndef KHTML_NO_SCROLLBARS
01943 d->vmode = mode;
01944 QScrollView::setVScrollBarMode(mode);
01945 #else
01946 Q_UNUSED( mode );
01947 #endif
01948 }
01949
01950 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
01951 {
01952 #ifndef KHTML_NO_SCROLLBARS
01953 d->hmode = mode;
01954 QScrollView::setHScrollBarMode(mode);
01955 #else
01956 Q_UNUSED( mode );
01957 #endif
01958 }
01959
01960 void KHTMLView::restoreScrollBar()
01961 {
01962 int ow = visibleWidth();
01963 QScrollView::setVScrollBarMode(d->vmode);
01964 if (visibleWidth() != ow)
01965 layout();
01966 d->prevScrollbarVisible = verticalScrollBar()->isVisible();
01967 }
01968
01969 QStringList KHTMLView::formCompletionItems(const QString &name) const
01970 {
01971 if (!m_part->settings()->isFormCompletionEnabled())
01972 return QStringList();
01973 if (!d->formCompletions)
01974 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01975 return d->formCompletions->readListEntry(name);
01976 }
01977
01978 void KHTMLView::clearCompletionHistory(const QString& name)
01979 {
01980 if (!d->formCompletions)
01981 {
01982 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01983 }
01984 d->formCompletions->writeEntry(name, "");
01985 d->formCompletions->sync();
01986 }
01987
01988 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
01989 {
01990 if (!m_part->settings()->isFormCompletionEnabled())
01991 return;
01992
01993
01994
01995 bool cc_number(true);
01996 for (unsigned int i = 0; i < value.length(); ++i)
01997 {
01998 QChar c(value[i]);
01999 if (!c.isNumber() && c != '-' && !c.isSpace())
02000 {
02001 cc_number = false;
02002 break;
02003 }
02004 }
02005 if (cc_number)
02006 return;
02007 QStringList items = formCompletionItems(name);
02008 if (!items.contains(value))
02009 items.prepend(value);
02010 while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
02011 items.remove(items.fromLast());
02012 d->formCompletions->writeEntry(name, items);
02013 }
02014
02015 void KHTMLView::addNonPasswordStorableSite(const QString& host)
02016 {
02017 if (!d->formCompletions) {
02018 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02019 }
02020
02021 d->formCompletions->setGroup("NonPasswordStorableSites");
02022 QStringList sites = d->formCompletions->readListEntry("Sites");
02023 sites.append(host);
02024 d->formCompletions->writeEntry("Sites", sites);
02025 d->formCompletions->sync();
02026 d->formCompletions->setGroup(QString::null);
02027 }
02028
02029 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
02030 {
02031 if (!d->formCompletions) {
02032 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02033 }
02034 d->formCompletions->setGroup("NonPasswordStorableSites");
02035 QStringList sites = d->formCompletions->readListEntry("Sites");
02036 d->formCompletions->setGroup(QString::null);
02037
02038 return (sites.find(host) != sites.end());
02039 }
02040
02041
02042 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable,
02043 int detail,QMouseEvent *_mouse, bool setUnder,
02044 int mouseEventType)
02045 {
02046 if (d->underMouse)
02047 d->underMouse->deref();
02048 d->underMouse = targetNode;
02049 if (d->underMouse)
02050 d->underMouse->ref();
02051
02052 int exceptioncode = 0;
02053 int pageX = 0;
02054 int pageY = 0;
02055 viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
02056 int clientX = pageX - contentsX();
02057 int clientY = pageY - contentsY();
02058 int screenX = _mouse->globalX();
02059 int screenY = _mouse->globalY();
02060 int button = -1;
02061 switch (_mouse->button()) {
02062 case LeftButton:
02063 button = 0;
02064 break;
02065 case MidButton:
02066 button = 1;
02067 break;
02068 case RightButton:
02069 button = 2;
02070 break;
02071 default:
02072 break;
02073 }
02074 bool ctrlKey = (_mouse->state() & ControlButton);
02075 bool altKey = (_mouse->state() & AltButton);
02076 bool shiftKey = (_mouse->state() & ShiftButton);
02077 bool metaKey = (_mouse->state() & MetaButton);
02078
02079
02080 if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
02081
02082
02083
02084 NodeImpl *oldUnder = 0;
02085 if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
02086 NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
02087 m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
02088 oldUnder = mev.innerNode.handle();
02089 }
02090
02091 if (oldUnder != targetNode) {
02092
02093 if (oldUnder){
02094 oldUnder->ref();
02095 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
02096 true,true,m_part->xmlDocImpl()->defaultView(),
02097 0,screenX,screenY,clientX,clientY,pageX, pageY,
02098 ctrlKey,altKey,shiftKey,metaKey,
02099 button,targetNode);
02100 me->ref();
02101 oldUnder->dispatchEvent(me,exceptioncode,true);
02102 me->deref();
02103 }
02104
02105
02106 if (targetNode) {
02107 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
02108 true,true,m_part->xmlDocImpl()->defaultView(),
02109 0,screenX,screenY,clientX,clientY,pageX, pageY,
02110 ctrlKey,altKey,shiftKey,metaKey,
02111 button,oldUnder);
02112
02113 me->ref();
02114 targetNode->dispatchEvent(me,exceptioncode,true);
02115 me->deref();
02116 }
02117
02118 if (oldUnder)
02119 oldUnder->deref();
02120 }
02121 }
02122
02123 bool swallowEvent = false;
02124
02125 if (targetNode) {
02126
02127 bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
02128 _mouse->type() == QEvent::MouseButtonDblClick );
02129 MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
02130 true,cancelable,m_part->xmlDocImpl()->defaultView(),
02131 detail,screenX,screenY,clientX,clientY,pageX, pageY,
02132 ctrlKey,altKey,shiftKey,metaKey,
02133 button,0, _mouse, dblclick );
02134 me->ref();
02135 targetNode->dispatchEvent(me,exceptioncode,true);
02136 if (me->defaultHandled() || me->defaultPrevented())
02137 swallowEvent = true;
02138 me->deref();
02139
02140 if (eventId == EventImpl::MOUSEDOWN_EVENT) {
02141 if (targetNode->isSelectable())
02142 m_part->xmlDocImpl()->setFocusNode(targetNode);
02143 else
02144 m_part->xmlDocImpl()->setFocusNode(0);
02145 }
02146 }
02147
02148 return swallowEvent;
02149 }
02150
02151 void KHTMLView::setIgnoreWheelEvents( bool e )
02152 {
02153 d->ignoreWheelEvents = e;
02154 }
02155
02156 #ifndef QT_NO_WHEELEVENT
02157
02158 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
02159 {
02160 if ( ( e->state() & ControlButton) == ControlButton )
02161 {
02162 emit zoomView( - e->delta() );
02163 e->accept();
02164 }
02165 else if ( ( (d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
02166 || e->delta() > 0 && contentsY() <= 0
02167 || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())
02168 && m_part->parentPart() ) {
02169 kdDebug(6000) << this << " cz " << contentsY() << " ch " << contentsHeight() << " vh " << visibleHeight() << endl;
02170 if ( m_part->parentPart()->view() )
02171 m_part->parentPart()->view()->wheelEvent( e );
02172 kdDebug(6000) << "sent" << endl;
02173 e->ignore();
02174 }
02175 else if ( d->vmode == QScrollView::AlwaysOff ) {
02176 e->accept();
02177 }
02178 else {
02179 d->scrollBarMoved = true;
02180 QScrollView::viewportWheelEvent( e );
02181
02182 QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, QPoint(-1,-1), QPoint(-1,-1), Qt::NoButton, e->state() );
02183 emit viewportMouseMoveEvent ( tempEvent );
02184 delete tempEvent;
02185 }
02186
02187 }
02188 #endif
02189
02190 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
02191 {
02192
02193
02194
02195 if ( m_part->parentPart() )
02196 {
02197 QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02198 return;
02199 }
02200 QScrollView::dragEnterEvent( ev );
02201 }
02202
02203 void KHTMLView::dropEvent( QDropEvent *ev )
02204 {
02205
02206
02207
02208 if ( m_part->parentPart() )
02209 {
02210 QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02211 return;
02212 }
02213 QScrollView::dropEvent( ev );
02214 }
02215
02216 void KHTMLView::focusInEvent( QFocusEvent *e )
02217 {
02218 #ifndef KHTML_NO_CARET
02219
02220
02221 if (d->m_caretViewContext &&
02222 d->m_caretViewContext->freqTimerId == -1 &&
02223 m_part->xmlDocImpl()) {
02224 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02225 if (m_part->isCaretMode()
02226 || m_part->isEditable()
02227 || (caretNode && caretNode->renderer()
02228 && caretNode->renderer()->style()->userInput()
02229 == UI_ENABLED)) {
02230 d->m_caretViewContext->freqTimerId = startTimer(500);
02231 d->m_caretViewContext->visible = true;
02232 }
02233 }
02234 showCaret();
02235 #endif // KHTML_NO_CARET
02236 QScrollView::focusInEvent( e );
02237 }
02238
02239 void KHTMLView::focusOutEvent( QFocusEvent *e )
02240 {
02241 if(m_part) m_part->stopAutoScroll();
02242
02243 #ifndef KHTML_NO_CARET
02244 if (d->m_caretViewContext) {
02245 switch (d->m_caretViewContext->displayNonFocused) {
02246 case KHTMLPart::CaretInvisible:
02247 hideCaret();
02248 break;
02249 case KHTMLPart::CaretVisible: {
02250 killTimer(d->m_caretViewContext->freqTimerId);
02251 d->m_caretViewContext->freqTimerId = -1;
02252 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02253 if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
02254 || m_part->isEditable()
02255 || (caretNode && caretNode->renderer()
02256 && caretNode->renderer()->style()->userInput()
02257 == UI_ENABLED))) {
02258 d->m_caretViewContext->visible = true;
02259 showCaret(true);
02260 }
02261 break;
02262 }
02263 case KHTMLPart::CaretBlink:
02264
02265 break;
02266 }
02267 }
02268 #endif // KHTML_NO_CARET
02269 QScrollView::focusOutEvent( e );
02270 }
02271
02272 void KHTMLView::slotScrollBarMoved()
02273 {
02274 if (!d->scrollingSelf)
02275 d->scrollBarMoved = true;
02276 }
02277
02278 void KHTMLView::timerEvent ( QTimerEvent *e )
02279 {
02280
02281 if ( e->timerId() == d->scrollTimerId ) {
02282 if( d->scrollSuspended )
02283 return;
02284 switch (d->scrollDirection) {
02285 case KHTMLViewPrivate::ScrollDown:
02286 if (contentsY() + visibleHeight () >= contentsHeight())
02287 d->newScrollTimer(this, 0);
02288 else
02289 scrollBy( 0, d->scrollBy );
02290 break;
02291 case KHTMLViewPrivate::ScrollUp:
02292 if (contentsY() <= 0)
02293 d->newScrollTimer(this, 0);
02294 else
02295 scrollBy( 0, -d->scrollBy );
02296 break;
02297 case KHTMLViewPrivate::ScrollRight:
02298 if (contentsX() + visibleWidth () >= contentsWidth())
02299 d->newScrollTimer(this, 0);
02300 else
02301 scrollBy( d->scrollBy, 0 );
02302 break;
02303 case KHTMLViewPrivate::ScrollLeft:
02304 if (contentsX() <= 0)
02305 d->newScrollTimer(this, 0);
02306 else
02307 scrollBy( -d->scrollBy, 0 );
02308 break;
02309 }
02310 return;
02311 }
02312 else if ( e->timerId() == d->layoutTimerId ) {
02313 d->firstRelayout = false;
02314 d->dirtyLayout = true;
02315 layout();
02316 }
02317 #ifndef KHTML_NO_CARET
02318 else if (d->m_caretViewContext
02319 && e->timerId() == d->m_caretViewContext->freqTimerId) {
02320 d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
02321 if (d->m_caretViewContext->displayed) {
02322 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02323 d->m_caretViewContext->width,
02324 d->m_caretViewContext->height);
02325 }
02326
02327
02328 return;
02329 }
02330 #endif
02331
02332 if( m_part->xmlDocImpl() ) {
02333 DOM::DocumentImpl *document = m_part->xmlDocImpl();
02334 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
02335
02336 if ( root && !root->layouted() ) {
02337 killTimer(d->repaintTimerId);
02338 d->repaintTimerId = 0;
02339 scheduleRelayout();
02340 return;
02341 }
02342 }
02343
02344 setStaticBackground(d->useSlowRepaints);
02345
02346
02347 killTimer(d->repaintTimerId);
02348 d->repaintTimerId = 0;
02349
02350 QRegion updateRegion;
02351 QMemArray<QRect> rects = d->updateRegion.rects();
02352
02353 d->updateRegion = QRegion();
02354
02355 if ( rects.size() )
02356 updateRegion = rects[0];
02357
02358 for ( unsigned i = 1; i < rects.size(); ++i ) {
02359 QRect obR = updateRegion.boundingRect();
02360 QRegion newRegion = updateRegion.unite(rects[i]);
02361 if (2*newRegion.boundingRect().height() > 3*obR.height() )
02362 {
02363 repaintContents( obR );
02364 updateRegion = rects[i];
02365 }
02366 else
02367 updateRegion = newRegion;
02368 }
02369
02370 if ( !updateRegion.isNull() )
02371 repaintContents( updateRegion.boundingRect() );
02372
02373 if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
02374 QWidget* w;
02375 d->dirtyLayout = false;
02376
02377 QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02378 QPtrList<RenderWidget> toRemove;
02379 for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
02380 int xp = 0, yp = 0;
02381 w = it.current();
02382 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
02383 if (!rw->absolutePosition(xp, yp) ||
02384 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
02385 toRemove.append(rw);
02386 }
02387 for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
02388 if ( (w = d->visibleWidgets.take(r) ) )
02389 addChild(w, 0, -500000);
02390 }
02391 }
02392
02393 void KHTMLView::scheduleRelayout(khtml::RenderObject * )
02394 {
02395 if (!d->layoutSchedulingEnabled || d->layoutTimerId)
02396 return;
02397
02398 d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
02399 ? 1000 : 0 );
02400 }
02401
02402 void KHTMLView::unscheduleRelayout()
02403 {
02404 if (!d->layoutTimerId)
02405 return;
02406
02407 killTimer(d->layoutTimerId);
02408 d->layoutTimerId = 0;
02409 }
02410
02411 void KHTMLView::unscheduleRepaint()
02412 {
02413 if (!d->repaintTimerId)
02414 return;
02415
02416 killTimer(d->repaintTimerId);
02417 d->repaintTimerId = 0;
02418 }
02419
02420 void KHTMLView::scheduleRepaint(int x, int y, int w, int h)
02421 {
02422 bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
02423
02424
02425
02426
02427 int time = parsing ? 300 : ( !d->complete ? 100 : 20 );
02428
02429 #ifdef DEBUG_FLICKER
02430 QPainter p;
02431 p.begin( viewport() );
02432
02433 int vx, vy;
02434 contentsToViewport( x, y, vx, vy );
02435 p.fillRect( vx, vy, w, h, Qt::red );
02436 p.end();
02437 #endif
02438
02439 d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
02440
02441 if ( !d->repaintTimerId )
02442 d->repaintTimerId = startTimer( time );
02443
02444
02445 }
02446
02447 void KHTMLView::complete()
02448 {
02449
02450
02451 d->complete = true;
02452
02453
02454 if (d->layoutTimerId)
02455 {
02456
02457
02458 killTimer(d->layoutTimerId);
02459 d->layoutTimerId = startTimer( 0 );
02460 }
02461
02462
02463 if (d->repaintTimerId)
02464 {
02465
02466
02467 killTimer(d->repaintTimerId);
02468 d->repaintTimerId = startTimer( 20 );
02469 }
02470 }
02471
02472 #ifndef KHTML_NO_CARET
02473
02474
02475
02476
02477 #include "khtml_caret.cpp"
02478
02479 void KHTMLView::initCaret(bool keepSelection)
02480 {
02481 #if DEBUG_CARETMODE > 0
02482 kdDebug(6200) << "begin initCaret" << endl;
02483 #endif
02484
02485 if (m_part->xmlDocImpl()) {
02486 d->caretViewContext();
02487 bool cmoved = d->m_caretViewContext->caretMoved;
02488 if (m_part->d->caretNode().isNull()) {
02489
02490 m_part->d->caretNode() = m_part->document();
02491 m_part->d->caretOffset() = 0L;
02492
02493
02494
02495 if (!m_part->d->caretNode().handle()->renderer()) return;
02496 }
02497
02498
02499
02500 moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
02501
02502
02503 d->m_caretViewContext->caretMoved = cmoved;
02504 }
02505 #if DEBUG_CARETMODE > 0
02506 kdDebug(6200) << "end initCaret" << endl;
02507 #endif
02508 }
02509
02510 bool KHTMLView::caretOverrides() const
02511 {
02512 bool cm = m_part->isCaretMode();
02513 bool dm = m_part->isEditable();
02514 return cm && !dm ? false
02515 : (dm || m_part->d->caretNode().handle()->contentEditable())
02516 && d->editorContext()->override;
02517 }
02518
02519 void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
02520 {
02521 if (m_part->isCaretMode() || m_part->isEditable()) return;
02522 if (node->focused()) return;
02523
02524
02525 NodeImpl *firstAncestor = 0;
02526 while (node) {
02527 if (node->renderer()
02528 && node->renderer()->style()->userInput() != UI_ENABLED)
02529 break;
02530 firstAncestor = node;
02531 node = node->parentNode();
02532 }
02533
02534 if (!node) firstAncestor = 0;
02535
02536 DocumentImpl *doc = m_part->xmlDocImpl();
02537
02538 if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
02539 && doc->focusNode()->renderer()->isWidget())
02540 return;
02541
02542
02543 #if DEBUG_CARETMODE > 1
02544 kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
02545 << (firstAncestor ? firstAncestor->nodeName().string() : QString::null) << endl;
02546 #endif
02547 doc->setFocusNode(firstAncestor);
02548 emit m_part->nodeActivated(Node(firstAncestor));
02549 }
02550
02551 void KHTMLView::recalcAndStoreCaretPos(InlineBox *hintBox)
02552 {
02553 if (!m_part || m_part->d->caretNode().isNull()) return;
02554 d->caretViewContext();
02555 NodeImpl *caretNode = m_part->d->caretNode().handle();
02556 #if DEBUG_CARETMODE > 0
02557 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;
02558 #endif
02559 caretNode->getCaret(m_part->d->caretOffset(),
02560 caretOverrides(),
02561 d->m_caretViewContext->x, d->m_caretViewContext->y,
02562 d->m_caretViewContext->width,
02563 d->m_caretViewContext->height);
02564
02565 if (hintBox && d->m_caretViewContext->x == -1) {
02566 #if DEBUG_CARETMODE > 1
02567 kdDebug(6200) << "using hint inline box coordinates" << endl;
02568 #endif
02569 RenderObject *r = caretNode->renderer();
02570 const QFontMetrics &fm = r->style()->fontMetrics();
02571 int absx, absy;
02572 r->containingBlock()->absolutePosition(absx, absy,
02573 false);
02574 d->m_caretViewContext->x = absx + hintBox->xPos();
02575 d->m_caretViewContext->y = absy + hintBox->yPos()
02576 + hintBox->baseline() - fm.ascent();
02577 d->m_caretViewContext->width = 1;
02578
02579
02580 d->m_caretViewContext->height = fm.height();
02581 }
02582
02583 #if DEBUG_CARETMODE > 4
02584
02585 #endif
02586 #if DEBUG_CARETMODE > 0
02587 kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
02588 <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
02589 <<" h="<<d->m_caretViewContext->height<<endl;
02590 #endif
02591 }
02592
02593 void KHTMLView::caretOn()
02594 {
02595 if (d->m_caretViewContext) {
02596 killTimer(d->m_caretViewContext->freqTimerId);
02597
02598 if (hasFocus() || d->m_caretViewContext->displayNonFocused
02599 == KHTMLPart::CaretBlink) {
02600 d->m_caretViewContext->freqTimerId = startTimer(500);
02601 } else {
02602 d->m_caretViewContext->freqTimerId = -1;
02603 }
02604
02605 d->m_caretViewContext->visible = true;
02606 if ((d->m_caretViewContext->displayed = (hasFocus()
02607 || d->m_caretViewContext->displayNonFocused
02608 != KHTMLPart::CaretInvisible))) {
02609 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02610 d->m_caretViewContext->width,
02611 d->m_caretViewContext->height);
02612 }
02613
02614 }
02615 }
02616
02617 void KHTMLView::caretOff()
02618 {
02619 if (d->m_caretViewContext) {
02620 killTimer(d->m_caretViewContext->freqTimerId);
02621 d->m_caretViewContext->freqTimerId = -1;
02622 d->m_caretViewContext->displayed = false;
02623 if (d->m_caretViewContext->visible) {
02624 d->m_caretViewContext->visible = false;
02625 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02626 d->m_caretViewContext->width,
02627 d->m_caretViewContext->height);
02628 }
02629
02630 }
02631 }
02632
02633 void KHTMLView::showCaret(bool forceRepaint)
02634 {
02635 if (d->m_caretViewContext) {
02636 d->m_caretViewContext->displayed = true;
02637 if (d->m_caretViewContext->visible) {
02638 if (!forceRepaint) {
02639 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02640 d->m_caretViewContext->width,
02641 d->m_caretViewContext->height);
02642 } else {
02643 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02644 d->m_caretViewContext->width,
02645 d->m_caretViewContext->height);
02646 }
02647 }
02648
02649 }
02650 }
02651
02652 bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
02653 NodeImpl *endNode, long endOffset)
02654 {
02655 m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
02656 m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
02657 m_part->d->m_extendAtEnd = true;
02658
02659 bool folded = startNode != endNode || startOffset != endOffset;
02660
02661
02662 if (folded) {
02663 m_part->xmlDocImpl()->clearSelection();
02664 }
02665
02666 return folded;
02667 }
02668
02669 void KHTMLView::hideCaret()
02670 {
02671 if (d->m_caretViewContext) {
02672 if (d->m_caretViewContext->visible) {
02673
02674 d->m_caretViewContext->visible = false;
02675
02676
02677 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02678 d->m_caretViewContext->width,
02679 d->m_caretViewContext->height);
02680 d->m_caretViewContext->visible = true;
02681 }
02682 d->m_caretViewContext->displayed = false;
02683
02684 }
02685 }
02686
02687 int KHTMLView::caretDisplayPolicyNonFocused() const
02688 {
02689 if (d->m_caretViewContext)
02690 return d->m_caretViewContext->displayNonFocused;
02691 else
02692 return KHTMLPart::CaretInvisible;
02693 }
02694
02695 void KHTMLView::setCaretDisplayPolicyNonFocused(int policy)
02696 {
02697 d->caretViewContext();
02698
02699 d->m_caretViewContext->displayNonFocused = (KHTMLPart::CaretDisplayPolicy)policy;
02700
02701
02702 if (!hasFocus()) {
02703 switch (d->m_caretViewContext->displayNonFocused) {
02704 case KHTMLPart::CaretInvisible:
02705 hideCaret();
02706 break;
02707 case KHTMLPart::CaretBlink:
02708 if (d->m_caretViewContext->freqTimerId != -1) break;
02709 d->m_caretViewContext->freqTimerId = startTimer(500);
02710
02711 case KHTMLPart::CaretVisible:
02712 d->m_caretViewContext->displayed = true;
02713 showCaret();
02714 break;
02715 }
02716 }
02717 }
02718
02719 bool KHTMLView::placeCaret(InlineBox *hintBox)
02720 {
02721 CaretViewContext *cv = d->caretViewContext();
02722 caretOff();
02723 NodeImpl *caretNode = m_part->d->caretNode().handle();
02724
02725 if (!caretNode || !caretNode->renderer()) return false;
02726 ensureNodeHasFocus(caretNode);
02727 if (m_part->isCaretMode() || m_part->isEditable()
02728 || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
02729 recalcAndStoreCaretPos(hintBox);
02730
02731 cv->origX = cv->x;
02732
02733 caretOn();
02734 return true;
02735 }
02736 return false;
02737 }
02738
02739 void KHTMLView::ensureCaretVisible()
02740 {
02741 CaretViewContext *cv = d->m_caretViewContext;
02742 if (!cv) return;
02743 ensureVisible(cv->x, cv->y, cv->width, cv->height);
02744 d->scrollBarMoved = false;
02745 }
02746
02747 bool KHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
02748 NodeImpl *oldEndSel, long oldEndOfs)
02749 {
02750 bool changed = false;
02751 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
02752 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
02753 changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02754 m_part->d->m_extendAtEnd = true;
02755 } else do {
02756 changed = m_part->d->m_selectionStart.handle() != oldStartSel
02757 || m_part->d->m_startOffset != oldStartOfs
02758 || m_part->d->m_selectionEnd.handle() != oldEndSel
02759 || m_part->d->m_endOffset != oldEndOfs;
02760 if (!changed) break;
02761
02762
02763 NodeImpl *startNode;
02764 long startOffset;
02765 if (m_part->d->m_extendAtEnd) {
02766 startNode = m_part->d->m_selectionStart.handle();
02767 startOffset = m_part->d->m_startOffset;
02768 } else {
02769 startNode = m_part->d->m_selectionEnd.handle();
02770 startOffset = m_part->d->m_endOffset;
02771 m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
02772 m_part->d->m_endOffset = m_part->d->m_startOffset;
02773 }
02774
02775 bool swapNeeded = false;
02776 if (!m_part->d->m_selectionEnd.isNull() && startNode) {
02777 swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
02778 m_part->d->m_selectionEnd.handle(),
02779 m_part->d->m_endOffset) >= 0;
02780 }
02781
02782 m_part->d->m_selectionStart = startNode;
02783 m_part->d->m_startOffset = startOffset;
02784
02785 if (swapNeeded) {
02786 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
02787 m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
02788 m_part->d->m_startOffset);
02789 } else {
02790 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
02791 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
02792 m_part->d->m_endOffset);
02793 }
02794 } while(false);
02795 return changed;
02796 }
02797
02798 void KHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
02799 NodeImpl *oldEndSel, long oldEndOfs)
02800 {
02801 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
02802 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
02803 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
02804 m_part->emitSelectionChanged();
02805 }
02806 m_part->d->m_extendAtEnd = true;
02807 } else {
02808
02809 if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
02810 bool swapNeeded = RangeImpl::compareBoundaryPoints(
02811 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
02812 m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
02813 if (swapNeeded) {
02814 DOM::Node tmpNode = m_part->d->m_selectionStart;
02815 long tmpOffset = m_part->d->m_startOffset;
02816 m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
02817 m_part->d->m_startOffset = m_part->d->m_endOffset;
02818 m_part->d->m_selectionEnd = tmpNode;
02819 m_part->d->m_endOffset = tmpOffset;
02820 m_part->d->m_startBeforeEnd = true;
02821 m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
02822 }
02823 }
02824
02825 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
02826 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
02827 m_part->d->m_endOffset);
02828 m_part->emitSelectionChanged();
02829 }
02830 }
02831
02832 void KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
02833 {
02834 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
02835 long oldStartOfs = m_part->d->m_startOffset;
02836 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
02837 long oldEndOfs = m_part->d->m_endOffset;
02838
02839 NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
02840 long oldOffset = m_part->d->caretOffset();
02841
02842 bool ctrl = _ke->state() & ControlButton;
02843
02844
02845 switch(_ke->key()) {
02846 case Key_Space:
02847 break;
02848
02849 case Key_Down:
02850 moveCaretNextLine(1);
02851 break;
02852
02853 case Key_Up:
02854 moveCaretPrevLine(1);
02855 break;
02856
02857 case Key_Left:
02858 moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
02859 break;
02860
02861 case Key_Right:
02862 moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
02863 break;
02864
02865 case Key_Next:
02866 moveCaretNextPage();
02867 break;
02868
02869 case Key_Prior:
02870 moveCaretPrevPage();
02871 break;
02872
02873 case Key_Home:
02874 if (ctrl)
02875 moveCaretToDocumentBoundary(false);
02876 else
02877 moveCaretToLineBegin();
02878 break;
02879
02880 case Key_End:
02881 if (ctrl)
02882 moveCaretToDocumentBoundary(true);
02883 else
02884 moveCaretToLineEnd();
02885 break;
02886
02887 }
02888
02889 if ((m_part->d->caretNode().handle() != oldCaretNode
02890 || m_part->d->caretOffset() != oldOffset)
02891
02892 && !m_part->d->caretNode().isNull()) {
02893
02894 d->m_caretViewContext->caretMoved = true;
02895
02896 if (_ke->state() & ShiftButton) {
02897 updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02898 } else {
02899 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
02900 m_part->emitSelectionChanged();
02901 }
02902
02903 m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
02904 }
02905
02906 _ke->accept();
02907 }
02908
02909 bool KHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
02910 {
02911 sanitizeCaretState(node, offset);
02912 if (!node) return false;
02913
02914
02915
02916
02917 RenderArena arena;
02918 RenderFlow *cb;
02919 InlineBox *box = 0;
02920 findFlowBox(node, offset, &arena, cb, &box);
02921 if (box && box->object() != node->renderer()) {
02922 if (box->object()->element()) {
02923 node = box->object()->element();
02924 offset = node->minOffset();
02925 #if DEBUG_CARETMODE > 1
02926 kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
02927 #endif
02928 } else {
02929
02930 box = 0;
02931 kdError(6200) << "Box contains no node! Crash imminent" << endl;
02932 }
02933 }
02934
02935 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
02936 long oldStartOfs = m_part->d->m_startOffset;
02937 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
02938 long oldEndOfs = m_part->d->m_endOffset;
02939
02940
02941 bool posChanged = m_part->d->caretNode().handle() != node
02942 || m_part->d->caretOffset() != offset;
02943 bool selChanged = false;
02944
02945 m_part->d->caretNode() = node;
02946 m_part->d->caretOffset() = offset;
02947 if (clearSel || !oldStartSel || !oldEndSel) {
02948 selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02949 } else {
02950
02951
02952 selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02953
02954
02955 }
02956
02957 d->caretViewContext()->caretMoved = true;
02958
02959 bool visible_caret = placeCaret(box);
02960
02961
02962
02963
02964 if (posChanged) {
02965 m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
02966 }
02967
02968 return selChanged;
02969 }
02970
02971 void KHTMLView::moveCaretByLine(bool next, int count)
02972 {
02973
02974
02975 Node &caretNodeRef = m_part->d->caretNode();
02976 if (caretNodeRef.isNull()) return;
02977
02978 NodeImpl *caretNode = caretNodeRef.handle();
02979
02980 long offset = m_part->d->caretOffset();
02981
02982 CaretViewContext *cv = d->caretViewContext();
02983
02984 LinearDocument ld(m_part, caretNode, offset);
02985
02986 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
02987
02988
02989 while (count > 0 && it != ld.end() && it != ld.preBegin()) {
02990 count--;
02991 if (next) ++it; else --it;
02992 }
02993
02994
02995 if (it == ld.end() || it == ld.preBegin()) return;
02996
02997 int x, absx, absy;
02998 InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
02999
03000 placeCaretOnLine(caretBox, x, absx, absy);
03001 }
03002
03003 void KHTMLView::placeCaretOnLine(InlineBox *caretBox, int x, int absx, int absy)
03004 {
03005
03006 if (!caretBox) return;
03007
03008 RenderObject *caretRender = caretBox->object();
03009 NodeImpl *caretNode = caretRender->element();
03010
03011 #if DEBUG_CARETMODE > 0
03012 kdDebug(6200) << "got valid caretBox " << caretBox << endl;
03013 kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
03014 << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
03015 if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << QString(((RenderText *)((InlineTextBox *)caretBox)->object())->str->s + ((InlineTextBox *)caretBox)->m_start, ((InlineTextBox *)caretBox)->m_len) << "\"" << endl;}
03016 #endif
03017
03018 int caretHeight = caretBox->height();
03019 bool isText = caretBox->isInlineTextBox();
03020 int yOfs = 0;
03021 if (isText) {
03022
03023 RenderText *t = static_cast<RenderText *>(caretRender);
03024 const QFontMetrics &fm = t->metrics(caretBox->m_firstLine);
03025 caretHeight = fm.height();
03026 yOfs = caretBox->baseline() - fm.ascent();
03027 }
03028
03029 caretOff();
03030
03031
03032 m_part->d->caretNode() = caretNode;
03033 long &offset = m_part->d->caretOffset();
03034
03035
03036 d->m_caretViewContext->y = caretBox->yPos() + yOfs;
03037 d->m_caretViewContext->height = caretHeight;
03038 d->m_caretViewContext->width = 1;
03039
03040 int xPos = caretBox->xPos();
03041 int caretBoxWidth = caretBox->width();
03042
03043
03044 if (x <= xPos) {
03045 d->m_caretViewContext->x = xPos;
03046 offset = caretBox->minOffset();
03047
03048 } else if (x > xPos && x <= xPos + caretBoxWidth) {
03049 if (isText) {
03050 offset = static_cast<InlineTextBox *>(caretBox)->offsetForPoint(x,
03051 d->m_caretViewContext->x);
03052 #if DEBUG_CARETMODE > 2
03053 kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
03054 #endif
03055 } else {
03056 if (xPos + caretBoxWidth - x < x - xPos) {
03057 d->m_caretViewContext->x = xPos + caretBoxWidth;
03058 offset = caretNode ? caretNode->maxOffset() : 1;
03059 } else {
03060 d->m_caretViewContext->x = xPos;
03061 offset = caretNode ? caretNode->minOffset() : 0;
03062 }
03063 }
03064 } else {
03065 d->m_caretViewContext->x = xPos + caretBoxWidth;
03066 offset = caretBox->maxOffset();
03067 }
03068 #if DEBUG_CARETMODE > 0
03069 kdDebug(6200) << "new offset: " << offset << endl;
03070 #endif
03071
03072 d->m_caretViewContext->x += absx;
03073 d->m_caretViewContext->y += absy;
03074
03075 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03076 d->m_caretViewContext->width, d->m_caretViewContext->height);
03077 d->scrollBarMoved = false;
03078
03079 ensureNodeHasFocus(caretNode);
03080 caretOn();
03081 }
03082
03083 void KHTMLView::moveCaretToLineBoundary(bool end)
03084 {
03085
03086
03087 Node &caretNodeRef = m_part->d->caretNode();
03088 if (caretNodeRef.isNull()) return;
03089
03090 NodeImpl *caretNode = caretNodeRef.handle();
03091
03092 long offset = m_part->d->caretOffset();
03093
03094 LinearDocument ld(m_part, caretNode, offset);
03095
03096 EditableLineIterator it = ld.current();
03097 if (it == ld.end()) return;
03098
03099 EditableInlineBoxIterator fbit(it, end);
03100 InlineBox *b = *fbit;
03101 Q_ASSERT(b);
03102
03103 RenderObject *cb = (*it)->object();
03104 int absx, absy;
03105
03106 if (cb) cb->absolutePosition(absx,absy);
03107 else absx = absy = 0;
03108
03109 int x = b->xPos() + (end ? b->width() : 0);
03110 d->m_caretViewContext->origX = absx + x;
03111 placeCaretOnLine(b, x, absx, absy);
03112 }
03113
03114 void KHTMLView::moveCaretToDocumentBoundary(bool end)
03115 {
03116
03117
03118 Node &caretNodeRef = m_part->d->caretNode();
03119 if (caretNodeRef.isNull()) return;
03120
03121 NodeImpl *caretNode = caretNodeRef.handle();
03122
03123 long offset = m_part->d->caretOffset();
03124
03125 LinearDocument ld(m_part, caretNode, offset);
03126
03127 EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
03128 if (it == ld.end() || it == ld.preBegin()) return;
03129
03130 EditableInlineBoxIterator fbit = it;
03131 InlineBox *b = *fbit;
03132 Q_ASSERT(b);
03133
03134 RenderObject *cb = (*it)->object();
03135 int absx, absy;
03136
03137 if (cb) cb->absolutePosition(absx, absy);
03138 else absx = absy = 0;
03139
03140 int x = b->xPos();
03141 d->m_caretViewContext->origX = absx + x;
03142 placeCaretOnLine(b, x, absx, absy);
03143 }
03144
03145 void KHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
03146 {
03147 if (!m_part) return;
03148
03149
03150 Node &caretNodeRef = m_part->d->caretNode();
03151 if (caretNodeRef.isNull()) return;
03152
03153 NodeImpl *caretNode = caretNodeRef.handle();
03154
03155 long &offset = m_part->d->caretOffset();
03156
03157 LinearDocument ld(m_part, caretNode, offset);
03158
03159 EditableCharacterIterator it(&ld);
03160 InlineBox *hintBox = it.box();
03161 while (it.node() && count > 0) {
03162 count--;
03163 if (cmv == CaretByCharacter) {
03164 if (next) ++it;
03165 else --it;
03166 } else if (cmv == CaretByWord) {
03167 if (next) moveItToNextWord(it);
03168 else moveItToPrevWord(it);
03169 }
03170 }
03171 if (it.node()) {
03172 caretNodeRef = it.node();
03173 offset = it.offset();
03174 hintBox = it.box();
03175 #if DEBUG_CARETMODE > 2
03176 kdDebug(6200) << "set by valid node. offset: " << offset << endl;
03177 #endif
03178 } else {
03179 offset = next ? caretNode->maxOffset() : caretNode->minOffset();
03180 #if DEBUG_CARETMODE > 0
03181 kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
03182 #endif
03183 }
03184 placeCaretOnChar(hintBox);
03185 }
03186
03187 void KHTMLView::placeCaretOnChar(InlineBox *hintBox)
03188 {
03189 caretOff();
03190 recalcAndStoreCaretPos(hintBox);
03191 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03192 d->m_caretViewContext->width, d->m_caretViewContext->height);
03193 d->m_caretViewContext->origX = d->m_caretViewContext->x;
03194 d->scrollBarMoved = false;
03195 #if DEBUG_CARETMODE > 3
03196
03197 #endif
03198 ensureNodeHasFocus(m_part->d->caretNode().handle());
03199 caretOn();
03200 }
03201
03202 void KHTMLView::moveCaretByPage(bool next)
03203 {
03204
03205
03206 Node &caretNodeRef = m_part->d->caretNode();
03207 if (caretNodeRef.isNull()) return;
03208
03209 NodeImpl *caretNode = caretNodeRef.handle();
03210
03211 long offset = m_part->d->caretOffset();
03212
03213 int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
03214
03215 int mindist = clipper()->height() - offs;
03216
03217 CaretViewContext *cv = d->caretViewContext();
03218
03219
03220 LinearDocument ld(m_part, caretNode, offset);
03221
03222 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03223
03224 moveIteratorByPage(ld, it, mindist, next);
03225
03226 int x, absx, absy;
03227 InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
03228
03229 placeCaretOnLine(caretBox, x, absx, absy);
03230 }
03231
03232 void KHTMLView::moveCaretPrevWord()
03233 {
03234 moveCaretBy(false, CaretByWord, 1);
03235 }
03236
03237 void KHTMLView::moveCaretNextWord()
03238 {
03239 moveCaretBy(true, CaretByWord, 1);
03240 }
03241
03242 void KHTMLView::moveCaretPrevLine(int n)
03243 {
03244 moveCaretByLine(false, n);
03245 }
03246
03247 void KHTMLView::moveCaretNextLine(int n)
03248 {
03249 moveCaretByLine(true, n);
03250 }
03251
03252 void KHTMLView::moveCaretPrevPage()
03253 {
03254 moveCaretByPage(false);
03255 }
03256
03257 void KHTMLView::moveCaretNextPage()
03258 {
03259 moveCaretByPage(true);
03260 }
03261
03262 void KHTMLView::moveCaretToLineBegin()
03263 {
03264 moveCaretToLineBoundary(false);
03265 }
03266
03267 void KHTMLView::moveCaretToLineEnd()
03268 {
03269 moveCaretToLineBoundary(true);
03270 }
03271
03272 #endif // KHTML_NO_CARET
03273
03274 #undef DEBUG_CARETMODE