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