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