khtml Library API Documentation

khtmlview.cpp

00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00004  *                     1999 Lars Knoll <knoll@kde.org>
00005  *                     1999 Antti Koivisto <koivisto@kde.org>
00006  *                     2000-2004 Dirk Mueller <mueller@kde.org>
00007  *                     2003 Leo Savernik <l.savernik@aon.at>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Library General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Library General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Library General Public License
00020  * along with this library; see the file COPYING.LIB.  If not, write to
00021  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00022  * Boston, MA 02111-1307, USA.
00023  */
00024 
00025 
00026 #include "khtmlview.moc"
00027 
00028 #include "khtmlview.h"
00029 
00030 #include "khtml_part.h"
00031 #include "khtml_events.h"
00032 
00033 #include "html/html_documentimpl.h"
00034 #include "html/html_inlineimpl.h"
00035 #include "html/html_formimpl.h"
00036 #include "rendering/render_arena.h"
00037 #include "rendering/render_canvas.h"
00038 #include "rendering/render_frames.h"
00039 #include "rendering/render_replaced.h"
00040 #include "rendering/render_layer.h"
00041 #include "rendering/render_line.h"
00042 #include "rendering/render_table.h"
00043 // removeme
00044 #define protected public
00045 #include "rendering/render_text.h"
00046 #undef protected
00047 #include "xml/dom2_eventsimpl.h"
00048 #include "css/cssstyleselector.h"
00049 #include "misc/htmlhashes.h"
00050 #include "misc/helper.h"
00051 #include "khtml_settings.h"
00052 #include "khtml_printsettings.h"
00053 
00054 #include "khtmlpart_p.h"
00055 
00056 #ifndef KHTML_NO_CARET
00057 #include "khtml_caret_p.h"
00058 #include "xml/dom2_rangeimpl.h"
00059 #endif
00060 
00061 #include <kcursor.h>
00062 #include <knotifyclient.h>
00063 #include <ksimpleconfig.h>
00064 #include <kstringhandler.h>
00065 #include <kstandarddirs.h>
00066 #include <kprinter.h>
00067 #include <klocale.h>
00068 #include <kstdaccel.h>
00069 
00070 #include <qtooltip.h>
00071 #include <qpainter.h>
00072 #include <qlabel.h>
00073 #include <qpaintdevicemetrics.h>
00074 #include <qstylesheet.h>
00075 #include <kapplication.h>
00076 
00077 #include <kimageio.h>
00078 #include <kdebug.h>
00079 #include <kurldrag.h>
00080 #include <qobjectlist.h>
00081 #include <qtimer.h>
00082 #include <kdialogbase.h>
00083 #include <qptrdict.h>
00084 
00085 
00086 //#define DEBUG_NO_PAINT_BUFFER
00087 
00088 //#define DEBUG_FLICKER
00089 
00090 //#define DEBUG_PIXEL
00091 
00092 #define PAINT_BUFFER_HEIGHT 128
00093 
00094 #if 0
00095 namespace khtml {
00096     void dumpLineBoxes(RenderFlow *flow);
00097 }
00098 #endif
00099 
00100 using namespace DOM;
00101 using namespace khtml;
00102 class KHTMLToolTip;
00103 
00104 
00105 #ifndef QT_NO_TOOLTIP
00106 
00107 class KHTMLToolTip : public QToolTip
00108 {
00109 public:
00110     KHTMLToolTip(KHTMLView *view,  KHTMLViewPrivate* vp) : QToolTip(view->viewport())
00111     {
00112         m_view = view;
00113         m_viewprivate = vp;
00114     };
00115     
00116 protected:
00117     virtual void maybeTip(const QPoint &);
00118 
00119 private:
00120     KHTMLView *m_view;
00121     KHTMLViewPrivate* m_viewprivate;
00122 };
00123 
00124 #endif
00125 
00126 class KHTMLViewPrivate {
00127     friend class KHTMLToolTip;
00128 public:
00129 
00130     enum PseudoFocusNodes {
00131     PFNone,
00132     PFTop,
00133     PFBottom
00134     };
00135 
00136     KHTMLViewPrivate()
00137         : underMouse( 0 ), underMouseNonShared( 0 )
00138     {
00139 #ifndef KHTML_NO_CARET
00140     m_caretViewContext = 0;
00141     m_editorContext = 0;
00142 #endif // KHTML_NO_CARET
00143         postponed_autorepeat = NULL;
00144         reset();
00145         tp=0;
00146         paintBuffer=0;
00147         vertPaintBuffer=0;
00148         formCompletions=0;
00149         prevScrollbarVisible = true;
00150     tooltip = 0;
00151         possibleTripleClick = false;
00152     }
00153     ~KHTMLViewPrivate()
00154     {
00155         delete formCompletions;
00156         delete tp; tp = 0;
00157         delete paintBuffer; paintBuffer =0;
00158         delete vertPaintBuffer;
00159         delete postponed_autorepeat;
00160         if (underMouse)
00161         underMouse->deref();
00162         if (underMouseNonShared)
00163         underMouseNonShared->deref();
00164     delete tooltip;
00165 #ifndef KHTML_NO_CARET
00166     delete m_caretViewContext;
00167     delete m_editorContext;
00168 #endif // KHTML_NO_CARET
00169     }
00170     void reset()
00171     {
00172         if (underMouse)
00173         underMouse->deref();
00174     underMouse = 0;
00175         if (underMouseNonShared)
00176         underMouseNonShared->deref();
00177     underMouseNonShared = 0;
00178         linkPressed = false;
00179         useSlowRepaints = false;
00180     tabMovePending = false;
00181     lastTabbingDirection = true;
00182     pseudoFocusNode = PFNone;
00183 #ifndef KHTML_NO_SCROLLBARS
00184         vmode = QScrollView::Auto;
00185         hmode = QScrollView::Auto;
00186 #else
00187         vmode = QScrollView::AlwaysOff;
00188         hmode = QScrollView::AlwaysOff;
00189 #endif
00190 #ifdef DEBUG_PIXEL
00191         timer.start();
00192         pixelbooth = 0;
00193         repaintbooth = 0;
00194 #endif
00195         scrollBarMoved = false;
00196         ignoreWheelEvents = false;
00197     borderX = 30;
00198     borderY = 30;
00199     clickX = -1;
00200     clickY = -1;
00201         prevMouseX = -1;
00202         prevMouseY = -1;
00203     clickCount = 0;
00204     isDoubleClick = false;
00205     scrollingSelf = false;
00206         delete postponed_autorepeat;
00207         postponed_autorepeat = NULL;
00208     layoutTimerId = 0;
00209         repaintTimerId = 0;
00210         scrollTimerId = 0;
00211         scrollSuspended = false;
00212         scrollSuspendPreActivate = false;
00213         complete = false;
00214         firstRelayout = true;
00215         dirtyLayout = false;
00216         layoutSchedulingEnabled = true;
00217         updateRegion = QRegion();
00218         m_dialogsAllowed = true;
00219 #ifndef KHTML_NO_CARET
00220         if (m_caretViewContext) {
00221           m_caretViewContext->caretMoved = false;
00222       m_caretViewContext->keyReleasePending = false;
00223         }/*end if*/
00224 #endif // KHTML_NO_CARET
00225 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00226         typeAheadActivated = false;
00227 #endif // KHTML_NO_TYPE_AHEAD_FIND
00228     accessKeysActivated = false;
00229     accessKeysPreActivate = false;
00230     }
00231     void newScrollTimer(QWidget *view, int tid)
00232     {
00233         //kdDebug(6000) << "newScrollTimer timer " << tid << endl;
00234         view->killTimer(scrollTimerId);
00235         scrollTimerId = tid;
00236         scrollSuspended = false;
00237     }
00238     enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
00239 
00240     void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
00241     {
00242         static const struct { int msec, pixels; } timings [] = {
00243             {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
00244             {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
00245         };
00246         if (!scrollTimerId ||
00247             (scrollDirection != direction &&
00248              (scrollDirection != oppositedir || scrollSuspended))) {
00249             scrollTiming = 6;
00250             scrollBy = timings[scrollTiming].pixels;
00251             scrollDirection = direction;
00252             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00253         } else if (scrollDirection == direction &&
00254                    timings[scrollTiming+1].msec && !scrollSuspended) {
00255             scrollBy = timings[++scrollTiming].pixels;
00256             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00257         } else if (scrollDirection == oppositedir) {
00258             if (scrollTiming) {
00259                 scrollBy = timings[--scrollTiming].pixels;
00260                 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00261             }
00262         }
00263         scrollSuspended = false;
00264     }
00265 
00266 #ifndef KHTML_NO_CARET
00267 
00270     CaretViewContext *caretViewContext() {
00271       if (!m_caretViewContext) m_caretViewContext = new CaretViewContext();
00272       return m_caretViewContext;
00273     }
00277     EditorContext *editorContext() {
00278       if (!m_editorContext) m_editorContext = new EditorContext();
00279       return m_editorContext;
00280     }
00281 #endif // KHTML_NO_CARET
00282 
00283 #ifdef DEBUG_PIXEL
00284     QTime timer;
00285     unsigned int pixelbooth;
00286     unsigned int repaintbooth;
00287 #endif
00288 
00289     QPainter *tp;
00290     QPixmap  *paintBuffer;
00291     QPixmap  *vertPaintBuffer;
00292     NodeImpl *underMouse;
00293     NodeImpl *underMouseNonShared;
00294 
00295     bool tabMovePending:1;
00296     bool lastTabbingDirection:1;
00297     PseudoFocusNodes pseudoFocusNode:2;
00298     bool scrollBarMoved:1;
00299 
00300     QScrollView::ScrollBarMode vmode;
00301     QScrollView::ScrollBarMode hmode;
00302     bool prevScrollbarVisible;
00303     bool linkPressed;
00304     bool useSlowRepaints;
00305     bool ignoreWheelEvents;
00306 
00307     int borderX, borderY;
00308     KSimpleConfig *formCompletions;
00309 
00310     int clickX, clickY, clickCount;
00311     bool isDoubleClick;
00312 
00313     int prevMouseX, prevMouseY;
00314     bool scrollingSelf;
00315     int layoutTimerId;
00316     QKeyEvent* postponed_autorepeat;
00317 
00318     int repaintTimerId;
00319     int scrollTimerId;
00320     bool scrollSuspended;
00321     bool scrollSuspendPreActivate;
00322     int scrollTiming;
00323     int scrollBy;
00324     ScrollDirection scrollDirection;
00325     bool complete;
00326     bool firstRelayout;
00327     bool layoutSchedulingEnabled;
00328     bool possibleTripleClick;
00329     bool dirtyLayout;
00330     bool m_dialogsAllowed;
00331     QRegion updateRegion;
00332     KHTMLToolTip *tooltip;
00333     QPtrDict<QWidget> visibleWidgets;
00334 #ifndef KHTML_NO_CARET
00335     CaretViewContext *m_caretViewContext;
00336     EditorContext *m_editorContext;
00337 #endif // KHTML_NO_CARET
00338 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00339     QString findString;
00340     QTimer timer;
00341     bool findLinksOnly;
00342     bool typeAheadActivated;
00343 #endif // KHTML_NO_TYPE_AHEAD_FIND
00344     bool accessKeysActivated;
00345     bool accessKeysPreActivate;
00346 };
00347 
00348 #ifndef QT_NO_TOOLTIP
00349 
00359 static bool findImageMapRect(HTMLImageElementImpl *img, const QPoint &scrollOfs,
00360             const QPoint &p, QRect &r, QString &s)
00361 {
00362     HTMLMapElementImpl* map;
00363     if (img && img->getDocument()->isHTMLDocument() &&
00364         (map = static_cast<HTMLDocumentImpl*>(img->getDocument())->getMap(img->imageMap()))) {
00365         RenderObject::NodeInfo info(true, false);
00366         RenderObject *rend = img->renderer();
00367         int ax, ay;
00368         if (!rend || !rend->absolutePosition(ax, ay))
00369             return false;
00370         // we're a client side image map
00371         bool inside = map->mapMouseEvent(p.x() - ax + scrollOfs.x(),
00372                 p.y() - ay + scrollOfs.y(), rend->contentWidth(),
00373                 rend->contentHeight(), info);
00374         if (inside && info.URLElement()) {
00375             HTMLAreaElementImpl *area = static_cast<HTMLAreaElementImpl *>(info.URLElement());
00376             Q_ASSERT(area->id() == ID_AREA);
00377             s = area->getAttribute(ATTR_TITLE).string();
00378             QRegion reg = area->cachedRegion();
00379             if (!s.isEmpty() && !reg.isEmpty()) {
00380                 r = reg.boundingRect();
00381                 r.moveBy(ax, ay);
00382                 return true;
00383             }
00384         }
00385     }
00386     return false;
00387 }
00388 
00389 void KHTMLToolTip::maybeTip(const QPoint& p)
00390 {
00391     DOM::NodeImpl *node = m_viewprivate->underMouseNonShared;
00392     QRect region;
00393     while ( node ) {
00394         if ( node->isElementNode() ) {
00395             DOM::ElementImpl *e = static_cast<DOM::ElementImpl*>( node );
00396             QRect r;
00397             QString s;
00398             bool found = false;
00399             // for images, check if it is part of a client-side image map,
00400             // and query the <area>s' title attributes, too
00401             if (e->id() == ID_IMG && !e->getAttribute( ATTR_USEMAP ).isEmpty()) {
00402                 found = findImageMapRect(static_cast<HTMLImageElementImpl *>(e),
00403                             m_view->viewportToContents(QPoint(0, 0)), p, r, s);
00404             }
00405             if (!found) {
00406                 s = e->getAttribute( ATTR_TITLE ).string();
00407                 r = node->getRect();
00408             }
00409             region |= QRect( m_view->contentsToViewport( r.topLeft() ), r.size() );
00410             if ( !s.isEmpty() ) {
00411                 tip( region, QStyleSheet::convertFromPlainText( s, QStyleSheetItem::WhiteSpaceNormal ) );
00412                 break;
00413             }
00414         }
00415         node = node->parentNode();
00416     }
00417 }
00418 #endif
00419 
00420 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name)
00421     : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase )
00422 {
00423     m_medium = "screen";
00424 
00425     m_part = part;
00426     d = new KHTMLViewPrivate;
00427     QScrollView::setVScrollBarMode(d->vmode);
00428     QScrollView::setHScrollBarMode(d->hmode);
00429     connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged()));
00430     connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
00431 
00432     // initialize QScrollView
00433     enableClipper(true);
00434     // hack to get unclipped painting on the viewport.
00435     static_cast<KHTMLView *>(static_cast<QWidget *>(viewport()))->setWFlags(WPaintUnclipped);
00436 
00437     setResizePolicy(Manual);
00438     viewport()->setMouseTracking(true);
00439     viewport()->setBackgroundMode(NoBackground);
00440 
00441     KImageIO::registerFormats();
00442 
00443 #ifndef QT_NO_TOOLTIP
00444     d->tooltip = new KHTMLToolTip( this, d );
00445 #endif
00446 
00447 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00448     connect(&d->timer, SIGNAL(timeout()), this, SLOT(findTimeout()));
00449 #endif // KHTML_NO_TYPE_AHEAD_FIND
00450 
00451     init();
00452 
00453     viewport()->show();
00454 }
00455 
00456 KHTMLView::~KHTMLView()
00457 {
00458     closeChildDialogs();
00459     if (m_part)
00460     {
00461         //WABA: Is this Ok? Do I need to deref it as well?
00462         //Does this need to be done somewhere else?
00463         DOM::DocumentImpl *doc = m_part->xmlDocImpl();
00464         if (doc)
00465             doc->detach();
00466     }
00467     delete d; d = 0;
00468 }
00469 
00470 void KHTMLView::init()
00471 {
00472     if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
00473     if(!d->vertPaintBuffer)
00474         d->vertPaintBuffer = new QPixmap(10, PAINT_BUFFER_HEIGHT);
00475     if(!d->tp) d->tp = new QPainter();
00476 
00477     setFocusPolicy(QWidget::StrongFocus);
00478     viewport()->setFocusProxy(this);
00479 
00480     _marginWidth = -1; // undefined
00481     _marginHeight = -1;
00482     _width = 0;
00483     _height = 0;
00484 
00485     installEventFilter(this);
00486 
00487     setAcceptDrops(true);
00488     QSize s = viewportSize(4095, 4095);
00489     resizeContents(s.width(), s.height());
00490 }
00491 
00492 void KHTMLView::clear()
00493 {
00494     // work around QScrollview's unbelievable bugginess
00495     setStaticBackground(true);
00496 #ifndef KHTML_NO_CARET
00497     if (!m_part->isCaretMode() && !m_part->isEditable()) caretOff();
00498 #endif
00499 
00500     if( d->typeAheadActivated )
00501         findTimeout();
00502     if (d->accessKeysActivated)
00503         accessKeysTimeout();
00504     d->reset();
00505     killTimers();
00506     emit cleared();
00507 
00508     QScrollView::setHScrollBarMode(d->hmode);
00509     QScrollView::setVScrollBarMode(d->vmode);
00510 }
00511 
00512 void KHTMLView::hideEvent(QHideEvent* e)
00513 {
00514     QScrollView::hideEvent(e);
00515 }
00516 
00517 void KHTMLView::showEvent(QShowEvent* e)
00518 {
00519     QScrollView::showEvent(e);
00520 }
00521 
00522 void KHTMLView::resizeEvent (QResizeEvent* e)
00523 {
00524     int dw = e->oldSize().width() - e->size().width();
00525     int dh = e->oldSize().height() - e->size().height();
00526 
00527     // if we are shrinking the view, don't allow the content to overflow
00528     // before the layout occurs - we don't know if we need scrollbars yet
00529     dw = dw>0 ? kMax(0, contentsWidth()-dw) : contentsWidth();
00530     dh = dh>0 ? kMax(0, contentsHeight()-dh) : contentsHeight();
00531 
00532     resizeContents(dw, dh);
00533 
00534     QScrollView::resizeEvent(e);
00535 
00536     if ( m_part && m_part->xmlDocImpl() )
00537         m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
00538 }
00539 
00540 void KHTMLView::viewportResizeEvent (QResizeEvent* e)
00541 {
00542     QScrollView::viewportResizeEvent(e);
00543 
00544     //int w = visibleWidth();
00545     //int h = visibleHeight();
00546 
00547     if (d->layoutSchedulingEnabled)
00548         layout();
00549 #ifndef KHTML_NO_CARET
00550     else {
00551         hideCaret();
00552         recalcAndStoreCaretPos();
00553     showCaret();
00554     }/*end if*/
00555 #endif
00556 
00557     KApplication::sendPostedEvents(viewport(), QEvent::Paint);
00558 }
00559 
00560 // this is to get rid of a compiler virtual overload mismatch warning. do not remove
00561 void KHTMLView::drawContents( QPainter*)
00562 {
00563 }
00564 
00565 void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
00566 {
00567 #ifdef DEBUG_PIXEL
00568 
00569     if ( d->timer.elapsed() > 5000 ) {
00570         qDebug( "drawed %d pixels in %d repaints the last %d milliseconds",
00571                 d->pixelbooth, d->repaintbooth,  d->timer.elapsed() );
00572         d->timer.restart();
00573         d->pixelbooth = 0;
00574         d->repaintbooth = 0;
00575     }
00576     d->pixelbooth += ew*eh;
00577     d->repaintbooth++;
00578 #endif
00579 
00580     //kdDebug( 6000 ) << "drawContents this="<< this <<" x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl;
00581     if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
00582         p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00583         return;
00584     }
00585 
00586     QPoint pt = contentsToViewport(QPoint(ex, ey));
00587     QRegion cr = QRect(pt.x(), pt.y(), ew, eh);
00588 //     kdDebug(6000) << "clip rect: " << QRect(pt.x(), pt.y(), ew, eh) << endl;
00589     for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
00590     QWidget *w = it.current();
00591     RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
00592     QScrollView *sv = ::qt_cast<QScrollView *>(w);
00593     if (sv || !rw->isFormElement()) {
00594 //      kdDebug(6000) << "    removing scrollview " << sv;
00595         int x, y;
00596         rw->absolutePosition(x, y);
00597         contentsToViewport(x, y, x, y);
00598         cr -= QRect(x, y, rw->width(), rw->height());
00599     }
00600     }
00601 
00602 #if 0
00603     // this is commonly the case with framesets. we still do
00604     // want to paint them, otherwise the widgets don't get placed.
00605     if (cr.isEmpty())
00606     return;
00607 #endif
00608 
00609 #ifndef DEBUG_NO_PAINT_BUFFER
00610     p->setClipRegion(cr);
00611 
00612     if (eh > PAINT_BUFFER_HEIGHT && ew <= 10) {
00613         if ( d->vertPaintBuffer->height() < visibleHeight() )
00614             d->vertPaintBuffer->resize(10, visibleHeight());
00615         d->tp->begin(d->vertPaintBuffer);
00616         d->tp->translate(-ex, -ey);
00617         d->tp->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00618         m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey, ew, eh));
00619         d->tp->end();
00620     p->drawPixmap(ex, ey, *d->vertPaintBuffer, 0, 0, ew, eh);
00621     }
00622     else {
00623         if ( d->paintBuffer->width() < visibleWidth() )
00624             d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
00625 
00626         int py=0;
00627         while (py < eh) {
00628             int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
00629             d->tp->begin(d->paintBuffer);
00630             d->tp->translate(-ex, -ey-py);
00631             d->tp->fillRect(ex, ey+py, ew, ph, palette().active().brush(QColorGroup::Base));
00632             m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey+py, ew, ph));
00633             d->tp->end();
00634 
00635         p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
00636             py += PAINT_BUFFER_HEIGHT;
00637         }
00638     }
00639 #else // !DEBUG_NO_PAINT_BUFFER
00640 static int cnt=0;
00641     ex = contentsX(); ey = contentsY();
00642     ew = visibleWidth(); eh = visibleHeight();
00643     QRect pr(ex,ey,ew,eh);
00644     kdDebug() << "[" << ++cnt << "]" << " clip region: " << pr << endl;
00645 //  p->setClipRegion(QRect(0,0,ew,eh));
00646 //        p->translate(-ex, -ey);
00647         p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00648         m_part->xmlDocImpl()->renderer()->layer()->paint(p, pr);
00649 #endif // DEBUG_NO_PAINT_BUFFER
00650 
00651 #ifndef KHTML_NO_CARET
00652     if (d->m_caretViewContext && d->m_caretViewContext->visible) {
00653         QRect pos(d->m_caretViewContext->x, d->m_caretViewContext->y,
00654         d->m_caretViewContext->width, d->m_caretViewContext->height);
00655         if (pos.intersects(QRect(ex, ey, ew, eh))) {
00656             p->setRasterOp(XorROP);
00657         p->setPen(white);
00658         if (pos.width() == 1)
00659               p->drawLine(pos.topLeft(), pos.bottomRight());
00660         else {
00661           p->fillRect(pos, white);
00662         }/*end if*/
00663     }/*end if*/
00664     }/*end if*/
00665 #endif // KHTML_NO_CARET
00666 
00667 //    p->setPen(QPen(magenta,0,DashDotDotLine));
00668 //    p->drawRect(dbg_paint_rect);
00669 
00670     khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
00671     QApplication::sendEvent( m_part, &event );
00672 
00673 }
00674 
00675 void KHTMLView::setMarginWidth(int w)
00676 {
00677     // make it update the rendering area when set
00678     _marginWidth = w;
00679 }
00680 
00681 void KHTMLView::setMarginHeight(int h)
00682 {
00683     // make it update the rendering area when set
00684     _marginHeight = h;
00685 }
00686 
00687 void KHTMLView::layout()
00688 {
00689     if( m_part && m_part->xmlDocImpl() ) {
00690         DOM::DocumentImpl *document = m_part->xmlDocImpl();
00691 
00692         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
00693         if ( !root ) return;
00694 
00695         d->layoutSchedulingEnabled=false;
00696 
00697         if (document->isHTMLDocument()) {
00698              NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
00699              if(body && body->renderer() && body->id() == ID_FRAMESET) {
00700                  QScrollView::setVScrollBarMode(AlwaysOff);
00701                  QScrollView::setHScrollBarMode(AlwaysOff);
00702                  body->renderer()->setLayouted(false);
00703 //                  if (d->tooltip) {
00704 //                      delete d->tooltip;
00705 //                      d->tooltip = 0;
00706 //                  }
00707              }
00708              else if (!d->tooltip)
00709                  d->tooltip = new KHTMLToolTip( this, d );
00710         }
00711 
00712         _height = visibleHeight();
00713         _width = visibleWidth();
00714         //QTime qt;
00715         //qt.start();
00716         root->setMinMaxKnown(false);
00717         root->setLayouted(false);
00718         root->layout();
00719 
00720         emit finishedLayout();
00721 #if 0
00722     ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
00723     if (listitem) kdDebug(6000) << "after layout, before repaint" << endl;
00724     if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
00725 #endif
00726 #ifndef KHTML_NO_CARET
00727         hideCaret();
00728         if ((m_part->isCaretMode() || m_part->isEditable())
00729             && !d->complete && d->m_caretViewContext
00730                 && !d->m_caretViewContext->caretMoved) {
00731             initCaret();
00732         } else {
00733         recalcAndStoreCaretPos();
00734         showCaret();
00735         }/*end if*/
00736 #endif
00737     root->repaint();
00738         if (d->accessKeysActivated) {
00739             emit hideAccessKeys();
00740             displayAccessKeys();
00741         }
00742         //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
00743     }
00744     else
00745        _width = visibleWidth();
00746 
00747     killTimer(d->layoutTimerId);
00748     d->layoutTimerId = 0;
00749     d->layoutSchedulingEnabled=true;
00750 }
00751 
00752 void KHTMLView::closeChildDialogs()
00753 {
00754     QObjectList *dlgs = queryList("QDialog");
00755     for (QObject *dlg = dlgs->first(); dlg; dlg = dlgs->next())
00756     {
00757         KDialogBase* dlgbase = dynamic_cast<KDialogBase *>( dlg );
00758         if ( dlgbase ) {
00759             kdDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase << endl;
00760             // close() ends up calling QButton::animateClick, which isn't immediate
00761             // we need something the exits the event loop immediately (#49068)
00762             dlgbase->cancel();
00763         }
00764         else
00765         {
00766             kdWarning() << "closeChildDialogs: not a KDialogBase! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg) << endl;
00767             static_cast<QWidget*>(dlg)->hide();
00768         }
00769     }
00770     delete dlgs;
00771     d->m_dialogsAllowed = false;
00772 }
00773 
00774 bool KHTMLView::dialogsAllowed() {
00775     bool allowed = d->m_dialogsAllowed;
00776     KHTMLPart* p = m_part->parentPart();
00777     if (p && p->view())
00778         allowed &= p->view()->dialogsAllowed();
00779     return allowed;
00780 }
00781 
00782 void KHTMLView::closeEvent( QCloseEvent* ev )
00783 {
00784     closeChildDialogs();
00785     QScrollView::closeEvent( ev );
00786 }
00787 
00788 //
00789 // Event Handling
00790 //
00792 
00793 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
00794 {
00795     if(!m_part->xmlDocImpl()) return;
00796     if (d->possibleTripleClick)
00797     {
00798         viewportMouseDoubleClickEvent( _mouse ); // it handles triple clicks too
00799         return;
00800     }
00801 
00802     int xm, ym;
00803     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00804     //kdDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()<<"/"<<_mouse->y()<<"), contents=(" << xm << "/" << ym << ")\n";
00805 
00806     d->isDoubleClick = false;
00807 
00808     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
00809     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00810 
00811     //kdDebug(6000) << "innerNode="<<mev.innerNode.nodeName().string()<<endl;
00812 
00813     if (d->clickCount > 0 &&
00814         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00815     d->clickCount++;
00816     else {
00817     d->clickCount = 1;
00818     d->clickX = xm;
00819     d->clickY = ym;
00820     }
00821 
00822     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
00823                                            d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
00824 
00825     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00826     if (r && r->isWidget())
00827     _mouse->ignore();
00828 
00829     if (!swallowEvent) {
00830     emit m_part->nodeActivated(mev.innerNode);
00831 
00832     khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00833         QApplication::sendEvent( m_part, &event );
00834         // we might be deleted after this
00835     }
00836 }
00837 
00838 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
00839 {
00840     if(!m_part->xmlDocImpl()) return;
00841 
00842     int xm, ym;
00843     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00844 
00845     kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
00846 
00847     d->isDoubleClick = true;
00848 
00849     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
00850     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00851 
00852     // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat
00853     // single and double-click events as separate (only the detail, i.e. number of clicks differs)
00854     if (d->clickCount > 0 &&
00855         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00856     d->clickCount++;
00857     else { // shouldn't happen, if Qt has the same criterias for double clicks.
00858     d->clickCount = 1;
00859     d->clickX = xm;
00860     d->clickY = ym;
00861     }
00862     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
00863                                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
00864 
00865     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00866     if (r && r->isWidget())
00867     _mouse->ignore();
00868 
00869     if (!swallowEvent) {
00870     khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
00871     QApplication::sendEvent( m_part, &event );
00872     }
00873 
00874     d->possibleTripleClick=true;
00875     QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
00876 }
00877 
00878 void KHTMLView::tripleClickTimeout()
00879 {
00880     d->possibleTripleClick = false;
00881     d->clickCount = 0;
00882 }
00883 
00884 static inline void forwardPeripheralEvent(khtml::RenderWidget* r, QMouseEvent* me, int x, int y)
00885 {
00886     int absx = 0;
00887     int absy = 0;
00888     r->absolutePosition(absx, absy);
00889     QPoint p(x-absx, y-absy);
00890     QMouseEvent fw(me->type(), p, me->button(), me->state());
00891     QWidget* w = r->widget();
00892     if(w)
00893         static_cast<khtml::RenderWidget::EventPropagator*>(w)->sendEvent(&fw);
00894 }
00895 
00896 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
00897 {
00898 
00899     if(!m_part->xmlDocImpl()) return;
00900 
00901     int xm, ym;
00902     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00903 
00904     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
00905     // Do not modify :hover/:active state while mouse is pressed.
00906     m_part->xmlDocImpl()->prepareMouseEvent( _mouse->state() & Qt::MouseButtonMask /*readonly ?*/, xm, ym, &mev );
00907 
00908 //     kdDebug(6000) << "mouse move: " << _mouse->pos()
00909 //        << " button " << _mouse->button()
00910 //        << " state " << _mouse->state() << endl;
00911 
00912     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),false,
00913                                            0,_mouse,true,DOM::NodeImpl::MouseMove);
00914 
00915     if (d->clickCount > 0 &&
00916         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
00917     d->clickCount = 0;  // moving the mouse outside the threshold invalidates the click
00918     }
00919 
00920     // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
00921     m_part->executeScheduledScript();
00922 
00923     DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
00924     if (fn && fn != mev.innerNode.handle() &&
00925         fn->renderer() && fn->renderer()->isWidget()) {
00926         forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00927     }
00928 
00929     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00930     khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
00931     QCursor c;
00932     switch ( style ? style->cursor() : CURSOR_AUTO) {
00933     case CURSOR_AUTO:
00934         if ( r && r->isText() )
00935             c = KCursor::ibeamCursor();
00936 
00937         if ( mev.url.length() && m_part->settings()->changeCursor() )
00938             c = m_part->urlCursor();
00939 
00940         if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
00941             c = QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
00942 
00943         break;
00944     case CURSOR_CROSS:
00945         c = KCursor::crossCursor();
00946         break;
00947     case CURSOR_POINTER:
00948         c = m_part->urlCursor();
00949         break;
00950     case CURSOR_PROGRESS:
00951         c = KCursor::workingCursor();
00952         break;
00953     case CURSOR_MOVE:
00954         c = KCursor::sizeAllCursor();
00955         break;
00956     case CURSOR_E_RESIZE:
00957     case CURSOR_W_RESIZE:
00958         c = KCursor::sizeHorCursor();
00959         break;
00960     case CURSOR_N_RESIZE:
00961     case CURSOR_S_RESIZE:
00962         c = KCursor::sizeVerCursor();
00963         break;
00964     case CURSOR_NE_RESIZE:
00965     case CURSOR_SW_RESIZE:
00966         c = KCursor::sizeBDiagCursor();
00967         break;
00968     case CURSOR_NW_RESIZE:
00969     case CURSOR_SE_RESIZE:
00970         c = KCursor::sizeFDiagCursor();
00971         break;
00972     case CURSOR_TEXT:
00973         c = KCursor::ibeamCursor();
00974         break;
00975     case CURSOR_WAIT:
00976         c = KCursor::waitCursor();
00977         break;
00978     case CURSOR_HELP:
00979         c = KCursor::whatsThisCursor();
00980         break;
00981     case CURSOR_DEFAULT:
00982         break;
00983     }
00984 
00985     if ( viewport()->cursor().handle() != c.handle() ) {
00986         if( c.handle() == KCursor::arrowCursor().handle()) {
00987             for (KHTMLPart* p = m_part; p; p = p->parentPart())
00988                 p->view()->viewport()->unsetCursor();
00989         }
00990         else {
00991             viewport()->setCursor( c );
00992     }
00993     }
00994     if (r && r->isWidget()) {
00995     _mouse->ignore();
00996     }
00997 
00998 
00999     d->prevMouseX = xm;
01000     d->prevMouseY = ym;
01001 
01002     if (!swallowEvent) {
01003         khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
01004         QApplication::sendEvent( m_part, &event );
01005     }
01006 }
01007 
01008 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
01009 {
01010     if ( !m_part->xmlDocImpl() ) return;
01011 
01012     int xm, ym;
01013     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
01014 
01015     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
01016     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
01017 
01018     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
01019                                            d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
01020 
01021     if (d->clickCount > 0 &&
01022         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
01023     QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
01024                _mouse->pos(), _mouse->button(), _mouse->state());
01025     dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
01026                            d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
01027     }
01028 
01029     DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
01030     if (fn && fn != mev.innerNode.handle() &&
01031         fn->renderer() && fn->renderer()->isWidget()) {
01032         forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
01033     }
01034 
01035     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
01036     if (r && r->isWidget())
01037     _mouse->ignore();
01038 
01039     if (!swallowEvent) {
01040     khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
01041     QApplication::sendEvent( m_part, &event );
01042     }
01043 }
01044 
01045 // returns true if event should be swallowed
01046 bool KHTMLView::dispatchKeyEvent( QKeyEvent *_ke )
01047 {
01048     if (!m_part->xmlDocImpl())
01049         return false;
01050     // Pressing and releasing a key should generate keydown, keypress and keyup events
01051     // Holding it down should generated keydown, keypress (repeatedly) and keyup events
01052     // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
01053     // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
01054     // of the Qt events shouldn't be passed to DOM, but it should be still filtered
01055     // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
01056     // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
01057     // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
01058     // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
01059     // The solution is to filter out and postpone the Qt autorepeat keyrelease until
01060     // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
01061     // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
01062     // again, and here it will be ignored.
01063     //
01064     //  Qt:      Press      | Release(autorepeat) Press(autorepeat) etc. |   Release
01065     //  DOM:   Down + Press |      (nothing)           Press             |     Up
01066 
01067     // It's also possible to get only Releases. E.g. the release of alt-tab,
01068     // or when the keypresses get captured by an accel.
01069 
01070     if( _ke == d->postponed_autorepeat ) // replayed event
01071     {
01072         return false;
01073     }
01074 
01075     if( _ke->type() == QEvent::KeyPress )
01076     {
01077         if( !_ke->isAutoRepeat())
01078         {
01079             bool ret = dispatchKeyEventHelper( _ke, false ); // keydown
01080             if( dispatchKeyEventHelper( _ke, true )) // keypress
01081                 ret = true;
01082             return ret;
01083         }
01084         else // autorepeat
01085         {
01086             bool ret = dispatchKeyEventHelper( _ke, true ); // keypress
01087             if( !ret && d->postponed_autorepeat )
01088                 keyPressEvent( d->postponed_autorepeat );
01089             delete d->postponed_autorepeat;
01090             d->postponed_autorepeat = NULL;
01091             return ret;
01092         }
01093     }
01094     else // QEvent::KeyRelease
01095     {
01096         // Discard postponed "autorepeat key-release" events that didn't see
01097         // a keypress after them (e.g. due to QAccel)
01098         if ( d->postponed_autorepeat ) {
01099             delete d->postponed_autorepeat;
01100             d->postponed_autorepeat = 0;
01101         }
01102 
01103         if( !_ke->isAutoRepeat()) {
01104             return dispatchKeyEventHelper( _ke, false ); // keyup
01105         }
01106         else
01107         {
01108             d->postponed_autorepeat = new QKeyEvent( _ke->type(), _ke->key(), _ke->ascii(), _ke->state(),
01109                 _ke->text(), _ke->isAutoRepeat(), _ke->count());
01110             if( _ke->isAccepted())
01111                 d->postponed_autorepeat->accept();
01112             else
01113                 d->postponed_autorepeat->ignore();
01114             return true;
01115         }
01116     }
01117 }
01118 
01119 // returns true if event should be swallowed
01120 bool KHTMLView::dispatchKeyEventHelper( QKeyEvent *_ke, bool keypress )
01121 {
01122     DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
01123     if (keyNode) {
01124         return keyNode->dispatchKeyEvent(_ke, keypress);
01125     } else { // no focused node, send to document
01126         return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
01127     }
01128 }
01129 
01130 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
01131 {
01132 
01133 #ifndef KHTML_NO_CARET
01134     if (m_part->isEditable() || m_part->isCaretMode()
01135         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
01136         && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
01137       d->caretViewContext()->keyReleasePending = true;
01138       caretKeyPressEvent(_ke);
01139       return;
01140     }
01141 #endif // KHTML_NO_CARET
01142 
01143     // If CTRL was hit, be prepared for access keys
01144     if (_ke->key() == Key_Control && _ke->state()==0 && !d->accessKeysActivated) d->accessKeysPreActivate=true;
01145 
01146     if (_ke->key() == Key_Shift && _ke->state()==0)
01147         d->scrollSuspendPreActivate=true;
01148 
01149     // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
01150     // may eat the event
01151 
01152     if (d->accessKeysActivated)
01153     {
01154         if (_ke->state()==0 || _ke->state()==ShiftButton) {
01155     if (_ke->key() != Key_Shift) accessKeysTimeout();
01156         handleAccessKey( _ke );
01157         _ke->accept();
01158         return;
01159         }
01160     accessKeysTimeout();
01161     }
01162 
01163     if ( dispatchKeyEvent( _ke )) {
01164         // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
01165         _ke->accept();
01166         return;
01167     }
01168 
01169 #ifndef KHTML_NO_TYPE_AHEAD_FIND
01170     if(d->typeAheadActivated)
01171     {
01172         // type-ahead find aka find-as-you-type
01173         if(_ke->key() == Key_BackSpace)
01174         {
01175             d->findString = d->findString.left(d->findString.length() - 1);
01176 
01177             if(!d->findString.isEmpty())
01178             {
01179                 findAhead(false);
01180             }
01181             else
01182             {
01183                 findTimeout();
01184             }
01185 
01186             d->timer.start(3000, true);
01187             _ke->accept();
01188             return;
01189         }
01190         else if(_ke->key() == KStdAccel::findNext())
01191         { // part doesn't get this key event because of the keyboard grab
01192             m_part->findTextNext();
01193             d->timer.start(3000, true);
01194             _ke->accept();
01195             return;
01196         }
01197         else if(_ke->key() == Key_Escape)
01198         {
01199             findTimeout();
01200 
01201             _ke->accept();
01202             return;
01203         }
01204         else if(_ke->text().isEmpty() == false)
01205         {
01206             d->findString += _ke->text();
01207 
01208             findAhead(true);
01209 
01210             d->timer.start(3000, true);
01211             _ke->accept();
01212             return;
01213         }
01214     }
01215     else if(_ke->key() == '\'' || _ke->key() == '/')
01216     {
01217         if(_ke->key() == '\'')
01218         {
01219             d->findLinksOnly = true;
01220             m_part->setStatusBarText(i18n("Starting -- find links as you type"),
01221                                      KHTMLPart::BarDefaultText);
01222         }
01223         else if(_ke->key() == '/')
01224         {
01225             d->findLinksOnly = false;
01226             m_part->setStatusBarText(i18n("Starting -- find text as you type"),
01227                                      KHTMLPart::BarDefaultText);
01228         }
01229 
01230         m_part->findTextBegin();
01231         d->typeAheadActivated = true;
01232         d->timer.start(3000, true);
01233         grabKeyboard();
01234         _ke->accept();
01235         return;
01236     }
01237 #endif // KHTML_NO_TYPE_AHEAD_FIND
01238     
01239     int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
01240     if (_ke->state() & Qt::ShiftButton)
01241       switch(_ke->key())
01242         {
01243         case Key_Space:
01244             if ( d->vmode == QScrollView::AlwaysOff )
01245                 _ke->accept();
01246             else {
01247                 scrollBy( 0, -clipper()->height() - offs );
01248                 if(d->scrollSuspended)
01249                     d->newScrollTimer(this, 0);
01250             }
01251             break;
01252 
01253         case Key_Down:
01254         case Key_J:
01255             d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
01256             break;
01257 
01258         case Key_Up:
01259         case Key_K:
01260             d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
01261             break;
01262 
01263         case Key_Left:
01264         case Key_H:
01265             d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
01266             break;
01267 
01268         case Key_Right:
01269         case Key_L:
01270             d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
01271             break;
01272         }
01273     else
01274         switch ( _ke->key() )
01275         {
01276         case Key_Down:
01277         case Key_J:
01278             if ( d->vmode == QScrollView::AlwaysOff )
01279                 _ke->accept();
01280             else {
01281                 if (!d->scrollTimerId || d->scrollSuspended)
01282                     scrollBy( 0, 10 );
01283                 if (d->scrollTimerId)
01284                     d->newScrollTimer(this, 0);
01285             }
01286             break;
01287 
01288         case Key_Space:
01289         case Key_Next:
01290             if ( d->vmode == QScrollView::AlwaysOff )
01291                 _ke->accept();
01292             else {
01293                 scrollBy( 0, clipper()->height() - offs );
01294                 if(d->scrollSuspended)
01295                     d->newScrollTimer(this, 0);
01296             }
01297             break;
01298 
01299         case Key_Up:
01300         case Key_K:
01301             if ( d->vmode == QScrollView::AlwaysOff )
01302                 _ke->accept();
01303             else {
01304                 if (!d->scrollTimerId || d->scrollSuspended)
01305                     scrollBy( 0, -10 );
01306                 if (d->scrollTimerId)
01307                     d->newScrollTimer(this, 0);
01308             }
01309             break;
01310 
01311         case Key_Prior:
01312             if ( d->vmode == QScrollView::AlwaysOff )
01313                 _ke->accept();
01314             else {
01315                 scrollBy( 0, -clipper()->height() + offs );
01316                 if(d->scrollSuspended)
01317                     d->newScrollTimer(this, 0);
01318             }
01319             break;
01320         case Key_Right:
01321         case Key_L:
01322             if ( d->hmode == QScrollView::AlwaysOff )
01323                 _ke->accept();
01324             else {
01325                 if (!d->scrollTimerId || d->scrollSuspended)
01326                     scrollBy( 10, 0 );
01327                 if (d->scrollTimerId)
01328                     d->newScrollTimer(this, 0);
01329             }
01330             break;
01331         case Key_Left:
01332         case Key_H:
01333             if ( d->hmode == QScrollView::AlwaysOff )
01334                 _ke->accept();
01335             else {
01336                 if (!d->scrollTimerId || d->scrollSuspended)
01337                     scrollBy( -10, 0 );
01338                 if (d->scrollTimerId)
01339                     d->newScrollTimer(this, 0);
01340             }
01341             break;
01342         case Key_Enter:
01343         case Key_Return:
01344         // ### FIXME:
01345         // or even better to HTMLAnchorElementImpl::event()
01346             if (m_part->xmlDocImpl()) {
01347         NodeImpl *n = m_part->xmlDocImpl()->focusNode();
01348         if (n)
01349             n->setActive();
01350         }
01351             break;
01352         case Key_Home:
01353             if ( d->vmode == QScrollView::AlwaysOff )
01354                 _ke->accept();
01355             else {
01356                 setContentsPos( 0, 0 );
01357                 if(d->scrollSuspended)
01358                     d->newScrollTimer(this, 0);
01359             }
01360             break;
01361         case Key_End:
01362             if ( d->vmode == QScrollView::AlwaysOff )
01363                 _ke->accept();
01364             else {
01365                 setContentsPos( 0, contentsHeight() - visibleHeight() );
01366                 if(d->scrollSuspended)
01367                     d->newScrollTimer(this, 0);
01368             }
01369             break;
01370         case Key_Shift:
01371             // what are you doing here?
01372         _ke->ignore();
01373             return;
01374         default:
01375             if (d->scrollTimerId)
01376                 d->newScrollTimer(this, 0);
01377         _ke->ignore();
01378             return;
01379         }
01380 
01381     _ke->accept();
01382 }
01383 
01384 #ifndef KHTML_NO_TYPE_AHEAD_FIND
01385 
01386 void KHTMLView::findTimeout()
01387 {
01388     d->typeAheadActivated = false;
01389     d->findString = "";
01390     releaseKeyboard();
01391     m_part->setStatusBarText(i18n("Find stopped."), KHTMLPart::BarDefaultText);
01392 }
01393 
01394 void KHTMLView::findAhead(bool increase)
01395 {
01396     QString status;
01397 
01398     if(d->findLinksOnly)
01399     {
01400         m_part->findText(d->findString, KHTMLPart::FindNoPopups |
01401                          KHTMLPart::FindLinksOnly, this);
01402         if(m_part->findTextNext())
01403         {
01404             status = i18n("Link found: \"%1\".");
01405         }
01406         else
01407         {
01408             if(increase) KNotifyClient::beep();
01409             status = i18n("Link not found: \"%1\".");
01410         }
01411     }
01412     else
01413     {
01414         m_part->findText(d->findString, KHTMLPart::FindNoPopups, this);
01415         if(m_part->findTextNext())
01416         {
01417             status = i18n("Text found: \"%1\".");
01418         }
01419         else
01420         {
01421             if(increase) KNotifyClient::beep();
01422             status = i18n("Text not found: \"%1\".");
01423         }
01424     }
01425 
01426     m_part->setStatusBarText(status.arg(d->findString.lower()),
01427                              KHTMLPart::BarDefaultText);
01428 }
01429 
01430 #endif // KHTML_NO_TYPE_AHEAD_FIND
01431 
01432 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
01433 {
01434     if (d->m_caretViewContext && d->m_caretViewContext->keyReleasePending) {
01435         //caretKeyReleaseEvent(_ke);
01436     d->m_caretViewContext->keyReleasePending = false;
01437     return;
01438     }
01439 
01440     if (d->accessKeysPreActivate && _ke->key() != Key_Control) d->accessKeysPreActivate=false;
01441     if (_ke->key() == Key_Control &&  d->accessKeysPreActivate && _ke->state() == Qt::ControlButton && !(KApplication::keyboardModifiers() & KApplication::ControlModifier))
01442     {
01443         displayAccessKeys();
01444         m_part->setStatusBarText(i18n("Access Keys activated"),KHTMLPart::BarOverrideText);
01445         d->accessKeysActivated = true;
01446         d->accessKeysPreActivate = false;
01447     }
01448     else if (d->accessKeysActivated) accessKeysTimeout();
01449     
01450     if( d->scrollSuspendPreActivate && _ke->key() != Key_Shift )
01451         d->scrollSuspendPreActivate = false;
01452     if( _ke->key() == Key_Shift && d->scrollSuspendPreActivate && _ke->state() == Qt::ShiftButton
01453         && !(KApplication::keyboardModifiers() & KApplication::ShiftModifier))
01454         if (d->scrollTimerId)
01455                 d->scrollSuspended = !d->scrollSuspended;
01456 
01457     // Send keyup event
01458     if ( dispatchKeyEvent( _ke ) )
01459     {
01460         _ke->accept();
01461         return;
01462     }
01463     
01464     QScrollView::keyReleaseEvent(_ke);
01465 }
01466 
01467 void KHTMLView::contentsContextMenuEvent ( QContextMenuEvent * /*ce*/ )
01468 {
01469 // ### what kind of c*** is that ?
01470 #if 0
01471     if (!m_part->xmlDocImpl()) return;
01472     int xm = _ce->x();
01473     int ym = _ce->y();
01474 
01475     DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove ); // ### not a mouse event!
01476     m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
01477 
01478     NodeImpl *targetNode = mev.innerNode.handle();
01479     if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
01480         int absx = 0;
01481         int absy = 0;
01482         targetNode->renderer()->absolutePosition(absx,absy);
01483         QPoint pos(xm-absx,ym-absy);
01484 
01485         QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
01486         QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
01487         setIgnoreEvents(true);
01488         QApplication::sendEvent(w,&cme);
01489         setIgnoreEvents(false);
01490     }
01491 #endif
01492 }
01493 
01494 bool KHTMLView::focusNextPrevChild( bool next )
01495 {
01496     // Now try to find the next child
01497     if (m_part->xmlDocImpl() && focusNextPrevNode(next))
01498     {
01499     if (m_part->xmlDocImpl()->focusNode())
01500         kdDebug() << "focusNode.name: "
01501               << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
01502     return true; // focus node found
01503     }
01504 
01505     // If we get here, pass tabbing control up to the next/previous child in our parent
01506     d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
01507     if (m_part->parentPart() && m_part->parentPart()->view())
01508         return m_part->parentPart()->view()->focusNextPrevChild(next);
01509 
01510     return QWidget::focusNextPrevChild(next);
01511 }
01512 
01513 void KHTMLView::doAutoScroll()
01514 {
01515     QPoint pos = QCursor::pos();
01516     pos = viewport()->mapFromGlobal( pos );
01517 
01518     int xm, ym;
01519     viewportToContents(pos.x(), pos.y(), xm, ym);
01520 
01521     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
01522     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
01523          (pos.x() < 0) || (pos.x() > visibleWidth()) )
01524     {
01525         ensureVisible( xm, ym, 0, 5 );
01526 
01527 #ifndef KHTML_NO_SELECTION
01528         // extend the selection while scrolling
01529     DOM::Node innerNode;
01530     if (m_part->isExtendingSelection()) {
01531             RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
01532             m_part->xmlDocImpl()->renderer()->layer()
01533                 ->nodeAtPoint(renderInfo, xm, ym);
01534             innerNode = renderInfo.innerNode();
01535     }/*end if*/
01536 
01537         if (innerNode.handle() && innerNode.handle()->renderer()) {
01538             int absX, absY;
01539             innerNode.handle()->renderer()->absolutePosition(absX, absY);
01540 
01541             m_part->extendSelectionTo(xm, ym, absX, absY, innerNode);
01542         }/*end if*/
01543 #endif // KHTML_NO_SELECTION
01544     }
01545 }
01546 
01547 
01548 class HackWidget : public QWidget
01549 {
01550  public:
01551     inline void setNoErase() { setWFlags(getWFlags()|WRepaintNoErase); }
01552 };
01553 
01554 bool KHTMLView::eventFilter(QObject *o, QEvent *e)
01555 {
01556     if ( e->type() == QEvent::AccelOverride ) {
01557     QKeyEvent* ke = (QKeyEvent*) e;
01558 //kdDebug(6200) << "QEvent::AccelOverride" << endl;
01559     if (m_part->isEditable() || m_part->isCaretMode()
01560         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
01561         && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
01562 //kdDebug(6200) << "editable/navigable" << endl;
01563         if ( (ke->state() & ControlButton) || (ke->state() & ShiftButton) ) {
01564         switch ( ke->key() ) {
01565         case Key_Left:
01566         case Key_Right:
01567         case Key_Up:
01568         case Key_Down:
01569         case Key_Home:
01570         case Key_End:
01571             ke->accept();
01572 //kdDebug(6200) << "eaten" << endl;
01573             return true;
01574         default:
01575             break;
01576         }
01577         }
01578     }
01579     }
01580 
01581     QWidget *view = viewport();
01582 
01583     if (o == view) {
01584     // we need to install an event filter on all children of the viewport to
01585     // be able to get correct stacking of children within the document.
01586     if(e->type() == QEvent::ChildInserted) {
01587         QObject *c = static_cast<QChildEvent *>(e)->child();
01588         if (c->isWidgetType()) {
01589         QWidget *w = static_cast<QWidget *>(c);
01590         // don't install the event filter on toplevels
01591         if (w->parentWidget(true) == view) {
01592             if (!strcmp(w->name(), "__khtml")) {
01593             w->installEventFilter(this);
01594             w->unsetCursor();
01595             w->setBackgroundMode( QWidget::NoBackground );
01596             static_cast<HackWidget *>(w)->setNoErase();
01597             if (w->children()) {
01598                 QObjectListIterator it(*w->children());
01599                 for (; it.current(); ++it) {
01600                 QWidget *widget = ::qt_cast<QWidget *>(it.current());
01601                 if (widget && !widget->isTopLevel()
01602                     && !::qt_cast<QScrollView *>(widget)) {
01603                     widget->setBackgroundMode( QWidget::NoBackground );
01604                     static_cast<HackWidget *>(widget)->setNoErase();
01605                     widget->installEventFilter(this);
01606                 }
01607                 }
01608             }
01609             }
01610         }
01611         }
01612     }
01613     } else if (o->isWidgetType()) {
01614     QWidget *v = static_cast<QWidget *>(o);
01615         QWidget *c = v;
01616     while (v && v != view) {
01617             c = v;
01618         v = v->parentWidget(true);
01619     }
01620 
01621     if (v && !strcmp(c->name(), "__khtml")) {
01622         bool block = false;
01623         QWidget *w = static_cast<QWidget *>(o);
01624         switch(e->type()) {
01625         case QEvent::Paint:
01626         if (!allowWidgetPaintEvents) {
01627             // eat the event. Like this we can control exactly when the widget
01628             // get's repainted.
01629             block = true;
01630             int x = 0, y = 0;
01631             QWidget *v = w;
01632             while (v && v != view) {
01633             x += v->x();
01634             y += v->y();
01635             v = v->parentWidget();
01636             }
01637             viewportToContents( x, y, x, y );
01638             QPaintEvent *pe = static_cast<QPaintEvent *>(e);
01639             scheduleRepaint(x + pe->rect().x(), y + pe->rect().y(),
01640                     pe->rect().width(), pe->rect().height());
01641         }
01642         break;
01643         case QEvent::MouseMove:
01644         case QEvent::MouseButtonPress:
01645         case QEvent::MouseButtonRelease:
01646         case QEvent::MouseButtonDblClick: {
01647         if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01648             QMouseEvent *me = static_cast<QMouseEvent *>(e);
01649             QPoint pt = (me->pos() + w->pos());
01650             QMouseEvent me2(me->type(), pt, me->button(), me->state());
01651 
01652             if (e->type() == QEvent::MouseMove)
01653             viewportMouseMoveEvent(&me2);
01654             else if(e->type() == QEvent::MouseButtonPress)
01655             viewportMousePressEvent(&me2);
01656             else if(e->type() == QEvent::MouseButtonRelease)
01657             viewportMouseReleaseEvent(&me2);
01658             else
01659             viewportMouseDoubleClickEvent(&me2);
01660             block = true;
01661                 }
01662         break;
01663         }
01664         case QEvent::KeyPress:
01665         case QEvent::KeyRelease:
01666         if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01667             QKeyEvent *ke = static_cast<QKeyEvent *>(e);
01668             if (e->type() == QEvent::KeyPress)
01669             keyPressEvent(ke);
01670             else
01671             keyReleaseEvent(ke);
01672             block = true;
01673         }
01674         default:
01675         break;
01676         }
01677         if (block) {
01678         //qDebug("eating event");
01679         return true;
01680         }
01681     }
01682     }
01683 
01684 //    kdDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type() << endl;
01685     return QScrollView::eventFilter(o, e);
01686 }
01687 
01688 
01689 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
01690 {
01691     return d->underMouse;
01692 }
01693 
01694 DOM::NodeImpl *KHTMLView::nonSharedNodeUnderMouse() const
01695 {
01696     return d->underMouseNonShared;
01697 }
01698 
01699 bool KHTMLView::scrollTo(const QRect &bounds)
01700 {
01701     d->scrollingSelf = true; // so scroll events get ignored
01702 
01703     int x, y, xe, ye;
01704     x = bounds.left();
01705     y = bounds.top();
01706     xe = bounds.right();
01707     ye = bounds.bottom();
01708 
01709     //kdDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y<<endl;
01710 
01711     int deltax;
01712     int deltay;
01713 
01714     int curHeight = visibleHeight();
01715     int curWidth = visibleWidth();
01716 
01717     if (ye-y>curHeight-d->borderY)
01718     ye  = y + curHeight - d->borderY;
01719 
01720     if (xe-x>curWidth-d->borderX)
01721     xe = x + curWidth - d->borderX;
01722 
01723     // is xpos of target left of the view's border?
01724     if (x < contentsX() + d->borderX )
01725             deltax = x - contentsX() - d->borderX;
01726     // is xpos of target right of the view's right border?
01727     else if (xe + d->borderX > contentsX() + curWidth)
01728             deltax = xe + d->borderX - ( contentsX() + curWidth );
01729     else
01730         deltax = 0;
01731 
01732     // is ypos of target above upper border?
01733     if (y < contentsY() + d->borderY)
01734             deltay = y - contentsY() - d->borderY;
01735     // is ypos of target below lower border?
01736     else if (ye + d->borderY > contentsY() + curHeight)
01737             deltay = ye + d->borderY - ( contentsY() + curHeight );
01738     else
01739         deltay = 0;
01740 
01741     int maxx = curWidth-d->borderX;
01742     int maxy = curHeight-d->borderY;
01743 
01744     int scrollX,scrollY;
01745 
01746     scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
01747     scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
01748 
01749     if (contentsX() + scrollX < 0)
01750     scrollX = -contentsX();
01751     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
01752     scrollX = contentsWidth() - visibleWidth() - contentsX();
01753 
01754     if (contentsY() + scrollY < 0)
01755     scrollY = -contentsY();
01756     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
01757     scrollY = contentsHeight() - visibleHeight() - contentsY();
01758 
01759     scrollBy(scrollX, scrollY);
01760 
01761     d->scrollingSelf = false;
01762 
01763     if ( (abs(deltax)<=maxx) && (abs(deltay)<=maxy) )
01764     return true;
01765     else return false;
01766 
01767 }
01768 
01769 bool KHTMLView::focusNextPrevNode(bool next)
01770 {
01771     // Sets the focus node of the document to be the node after (or if
01772     // next is false, before) the current focus node.  Only nodes that
01773     // are selectable (i.e. for which isSelectable() returns true) are
01774     // taken into account, and the order used is that specified in the
01775     // HTML spec (see DocumentImpl::nextFocusNode() and
01776     // DocumentImpl::previousFocusNode() for details).
01777 
01778     DocumentImpl *doc = m_part->xmlDocImpl();
01779     NodeImpl *oldFocusNode = doc->focusNode();
01780 
01781 #if 1
01782     // If the user has scrolled the document, then instead of picking
01783     // the next focusable node in the document, use the first one that
01784     // is within the visible area (if possible).
01785     if (d->scrollBarMoved)
01786     {
01787     NodeImpl *toFocus;
01788     if (next)
01789         toFocus = doc->nextFocusNode(oldFocusNode);
01790     else
01791         toFocus = doc->previousFocusNode(oldFocusNode);
01792 
01793     if (!toFocus && oldFocusNode)
01794         if (next)
01795         toFocus = doc->nextFocusNode(NULL);
01796         else
01797         toFocus = doc->previousFocusNode(NULL);
01798 
01799     while (toFocus && toFocus != oldFocusNode)
01800     {
01801         
01802         QRect focusNodeRect = toFocus->getRect();
01803         if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
01804         (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
01805         {
01806             QRect r = toFocus->getRect();
01807             ensureVisible( r.right(), r.bottom());
01808             ensureVisible( r.left(), r.top());
01809             d->scrollBarMoved = false;
01810             d->tabMovePending = false;
01811             d->lastTabbingDirection = next;
01812             d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
01813             m_part->xmlDocImpl()->setFocusNode(toFocus);
01814             Node guard(toFocus);
01815             if (!toFocus->hasOneRef() )
01816             {
01817             emit m_part->nodeActivated(Node(toFocus));
01818             }
01819             return true;
01820         }
01821         }
01822         if (next)
01823         toFocus = doc->nextFocusNode(toFocus);
01824         else
01825         toFocus = doc->previousFocusNode(toFocus);
01826 
01827         if (!toFocus && oldFocusNode)
01828         if (next)
01829             toFocus = doc->nextFocusNode(NULL);
01830         else
01831             toFocus = doc->previousFocusNode(NULL);
01832     }
01833 
01834     d->scrollBarMoved = false;
01835     }
01836 #endif
01837 
01838     if (!oldFocusNode && d->pseudoFocusNode == KHTMLViewPrivate::PFNone)
01839     {
01840     ensureVisible(contentsX(), next?0:contentsHeight());
01841     d->scrollBarMoved = false;
01842     d->pseudoFocusNode = next?KHTMLViewPrivate::PFTop:KHTMLViewPrivate::PFBottom;
01843     return true;
01844     }
01845 
01846     NodeImpl *newFocusNode = NULL;
01847 
01848     if (d->tabMovePending && next != d->lastTabbingDirection)
01849     {
01850     //kdDebug ( 6000 ) << " tab move pending and tabbing direction changed!\n";
01851     newFocusNode = oldFocusNode;
01852     }
01853     else if (next)
01854     {
01855     if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFTop )
01856         newFocusNode = doc->nextFocusNode(oldFocusNode);
01857     }
01858     else
01859     {
01860     if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFBottom )
01861         newFocusNode = doc->previousFocusNode(oldFocusNode);
01862     }
01863 
01864     bool targetVisible = false;
01865     if (!newFocusNode)
01866     {
01867     if ( next )
01868     {
01869         targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight()-d->borderY,0,0));
01870     }
01871     else
01872     {
01873         targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,d->borderY,0,0));
01874     }
01875     }
01876     else
01877     {
01878 #ifndef KHTML_NO_CARET
01879         // if it's an editable element, activate the caret
01880         if (!m_part->isCaretMode() && !m_part->isEditable()
01881         && newFocusNode->contentEditable()) {
01882         d->caretViewContext();
01883         moveCaretTo(newFocusNode, 0L, true);
01884         } else {
01885         caretOff();
01886     }
01887 #endif // KHTML_NO_CARET
01888 
01889     targetVisible = scrollTo(newFocusNode->getRect());
01890     }
01891 
01892     if (targetVisible)
01893     {
01894     //kdDebug ( 6000 ) << " target reached.\n";
01895     d->tabMovePending = false;
01896 
01897     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
01898     if (newFocusNode)
01899     {
01900         Node guard(newFocusNode);
01901         if (!newFocusNode->hasOneRef() )
01902         {
01903         emit m_part->nodeActivated(Node(newFocusNode));
01904         }
01905         return true;
01906     }
01907     else
01908     {
01909         d->pseudoFocusNode = next?KHTMLViewPrivate::PFBottom:KHTMLViewPrivate::PFTop;
01910         return false;
01911     }
01912     }
01913     else
01914     {
01915     if (!d->tabMovePending)
01916         d->lastTabbingDirection = next;
01917     d->tabMovePending = true;
01918     return true;
01919     }
01920 }
01921 
01922 void KHTMLView::displayAccessKeys()
01923 {
01924     for( NodeImpl* n = m_part->xmlDocImpl(); n != NULL; n = n->traverseNextNode()) {
01925         if( n->isElementNode()) {
01926             ElementImpl* en = static_cast< ElementImpl* >( n );
01927             DOMString s = en->getAttribute( ATTR_ACCESSKEY );
01928             if( s.length() == 1) {      
01929             QRect rec=en->getRect();
01930             QLabel *lab=new QLabel(s.string(),viewport(),0,Qt::WDestructiveClose);
01931             connect( this, SIGNAL(hideAccessKeys()), lab, SLOT(close()) );
01932             connect( this, SIGNAL(repaintAccessKeys()), lab, SLOT(repaint()));
01933             lab->setPalette(QToolTip::palette());
01934             lab->setLineWidth(2);
01935             lab->setFrameStyle(QFrame::Box | QFrame::Plain);
01936             lab->setMargin(3);
01937             lab->adjustSize();
01938             addChild(lab,
01939                     KMIN(rec.left()+rec.width()/2, contentsWidth() - lab->width()),
01940                     KMIN(rec.top()+rec.height()/2, contentsHeight() - lab->height()));
01941             showChild(lab);
01942         }
01943         }
01944     }
01945 }
01946 
01947 void KHTMLView::accessKeysTimeout()
01948 {
01949 d->accessKeysActivated=false;
01950 d->accessKeysPreActivate = false;
01951 m_part->setStatusBarText(QString::null, KHTMLPart::BarOverrideText);
01952 emit hideAccessKeys();
01953 }
01954 
01955 // Handling of the HTML accesskey attribute.
01956 bool KHTMLView::handleAccessKey( const QKeyEvent* ev )
01957 {
01958 // Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
01959 // but this code must act as if the modifiers weren't pressed
01960     QChar c;
01961     if( ev->key() >= Key_A && ev->key() <= Key_Z )
01962         c = 'A' + ev->key() - Key_A;
01963     else if( ev->key() >= Key_0 && ev->key() <= Key_9 )
01964         c = '0' + ev->key() - Key_0;
01965     else {
01966         // TODO fake XKeyEvent and XLookupString ?
01967         // This below seems to work e.g. for eacute though.
01968         if( ev->text().length() == 1 )
01969             c = ev->text()[ 0 ];
01970     }
01971     if( c.isNull())
01972         return false;
01973     return focusNodeWithAccessKey( c );
01974 }
01975 
01976 bool KHTMLView::focusNodeWithAccessKey( QChar c, KHTMLView* caller )
01977 {
01978     DocumentImpl *doc = m_part->xmlDocImpl();
01979     if( !doc )
01980         return false;
01981     ElementImpl* node = doc->findAccessKeyElement( c );
01982     if( !node ) {
01983         QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
01984         for( QPtrListIterator<KParts::ReadOnlyPart> it( frames );
01985              it != NULL;
01986              ++it ) {
01987             if( !(*it)->inherits( "KHTMLPart" ))
01988                 continue;
01989             KHTMLPart* part = static_cast< KHTMLPart* >( *it );
01990             if( part->view() && part->view() != caller
01991                 && part->view()->focusNodeWithAccessKey( c, this ))
01992                 return true;
01993         }
01994         // pass up to the parent
01995         if (m_part->parentPart() && m_part->parentPart()->view()
01996             && m_part->parentPart()->view() != caller )
01997             return m_part->parentPart()->view()->focusNodeWithAccessKey( c, this );
01998         return false;
01999     }
02000 
02001     // Scroll the view as necessary to ensure that the new focus node is visible
02002 #ifndef KHTML_NO_CARET
02003     // if it's an editable element, activate the caret
02004     if (!m_part->isCaretMode() && !m_part->isEditable()
02005     && node->contentEditable()) {
02006         d->caretViewContext();
02007         moveCaretTo(node, 0L, true);
02008     } else {
02009         caretOff();
02010     }
02011 #endif // KHTML_NO_CARET
02012 
02013     QRect r = node->getRect();
02014     ensureVisible( r.right(), r.bottom());
02015     ensureVisible( r.left(), r.top());
02016 
02017     Node guard( node );
02018     if( node->isSelectable()) {
02019     if (node->id()==ID_LABEL) {
02020         // if Accesskey is a label, give focus to the label's referrer.
02021         node=static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl* >( node )->getFormElement());
02022         if (!node) return true;
02023             guard = node;
02024     }
02025         // Set focus node on the document
02026         m_part->xmlDocImpl()->setFocusNode(node);
02027         if( node != NULL && node->hasOneRef()) // deleted, only held by guard
02028             return true;
02029         emit m_part->nodeActivated(Node(node));
02030         if( node != NULL && node->hasOneRef())
02031             return true;
02032     }
02033 
02034     switch( node->id()) {
02035         case ID_A:
02036             static_cast< HTMLAnchorElementImpl* >( node )->click();
02037           break;
02038         case ID_INPUT:
02039             static_cast< HTMLInputElementImpl* >( node )->click();
02040           break;
02041         case ID_BUTTON:
02042             static_cast< HTMLButtonElementImpl* >( node )->click();
02043           break;
02044         case ID_AREA:
02045             static_cast< HTMLAreaElementImpl* >( node )->click();
02046           break;
02047         case ID_TEXTAREA:
02048       break; // just focusing it is enough
02049         case ID_LEGEND:
02050             // TODO
02051           break;
02052     }
02053     return true;
02054 }
02055 
02056 void KHTMLView::setMediaType( const QString &medium )
02057 {
02058     m_medium = medium;
02059 }
02060 
02061 QString KHTMLView::mediaType() const
02062 {
02063     return m_medium;
02064 }
02065 
02066 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
02067 {
02068     if (vis) {
02069         d->visibleWidgets.replace(w, w->widget());
02070     }
02071     else
02072         d->visibleWidgets.remove(w);
02073 }
02074 
02075 void KHTMLView::print()
02076 {
02077     print( false );
02078 }
02079 
02080 void KHTMLView::print(bool quick)
02081 {
02082     if(!m_part->xmlDocImpl()) return;
02083     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
02084     if(!root) return;
02085 
02086     // this only works on Unix - we assume 72dpi
02087     KPrinter *printer = new KPrinter(true, QPrinter::PrinterResolution);
02088     printer->addDialogPage(new KHTMLPrintSettings());
02089     QString docname = m_part->xmlDocImpl()->URL().prettyURL();
02090     if ( !docname.isEmpty() )
02091         docname = KStringHandler::csqueeze(docname, 80);
02092     if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
02093         viewport()->setCursor( waitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
02094         // set up KPrinter
02095         printer->setFullPage(false);
02096         printer->setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
02097         printer->setDocName(docname);
02098 
02099         QPainter *p = new QPainter;
02100         p->begin( printer );
02101         khtml::setPrintPainter( p );
02102 
02103         m_part->xmlDocImpl()->setPaintDevice( printer );
02104         QString oldMediaType = mediaType();
02105         setMediaType( "print" );
02106         // We ignore margin settings for html and body when printing
02107         // and use the default margins from the print-system
02108         // (In Qt 3.0.x the default margins are hardcoded in Qt)
02109         m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
02110                                                   "* { background-image: none !important;"
02111                                                   "    background-color: white !important;"
02112                                                   "    color: black !important; }"
02113                           "body { margin: 0px !important; }"
02114                           "html { margin: 0px !important; }" :
02115                           "body { margin: 0px !important; }"
02116                           "html { margin: 0px !important; }"
02117                           );
02118 
02119         QPaintDeviceMetrics metrics( printer );
02120 
02121         // this is a simple approximation... we layout the document
02122         // according to the width of the page, then just cut
02123         // pages without caring about the content. We should do better
02124         // in the future, but for the moment this is better than no
02125         // printing support
02126         kdDebug(6000) << "printing: physical page width = " << metrics.width()
02127                       << " height = " << metrics.height() << endl;
02128         root->setPrintingMode(true);
02129         root->setWidth(metrics.width());
02130 
02131         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
02132         m_part->xmlDocImpl()->updateStyleSelector();
02133         root->setPrintImages( printer->option("app-khtml-printimages") == "true");
02134         root->setMinMaxKnown( false );
02135         root->setLayouted( false );
02136         root->layout();
02137         khtml::RenderWidget::flushWidgetResizes(); // make sure widgets have their final size
02138 
02139         bool printHeader = (printer->option("app-khtml-printheader") == "true");
02140 
02141         int headerHeight = 0;
02142         QFont headerFont("helvetica", 8);
02143 
02144         QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),true);
02145         QString headerMid = docname;
02146         QString headerRight;
02147 
02148         if (printHeader)
02149         {
02150            p->setFont(headerFont);
02151            headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
02152         }
02153 
02154         // ok. now print the pages.
02155         kdDebug(6000) << "printing: html page width = " << root->docWidth()
02156                       << " height = " << root->docHeight() << endl;
02157         kdDebug(6000) << "printing: margins left = " << printer->margins().width()
02158                       << " top = " << printer->margins().height() << endl;
02159         kdDebug(6000) << "printing: paper width = " << metrics.width()
02160                       << " height = " << metrics.height() << endl;
02161         // if the width is too large to fit on the paper we just scale
02162         // the whole thing.
02163         int pageHeight = metrics.height();
02164         int pageWidth = metrics.width();
02165         p->setClipRect(0,0, pageWidth, pageHeight);
02166 
02167         pageHeight -= headerHeight;
02168 
02169         bool scalePage = false;
02170         double scale = 0.0;
02171 #ifndef QT_NO_TRANSFORMATIONS
02172         if(root->docWidth() > metrics.width()) {
02173             scalePage = true;
02174             scale = ((double) metrics.width())/((double) root->docWidth());
02175             pageHeight = (int) (pageHeight/scale);
02176             pageWidth = (int) (pageWidth/scale);
02177             headerHeight = (int) (headerHeight/scale);
02178         }
02179 #endif
02180         kdDebug(6000) << "printing: scaled html width = " << pageWidth
02181                       << " height = " << pageHeight << endl;
02182 
02183         // Squeeze header to make it it on the page.
02184         if (printHeader)
02185         {
02186             int available_width = metrics.width() - 10 -
02187                 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
02188                          p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
02189             if (available_width < 150)
02190                available_width = 150;
02191             int mid_width;
02192             int squeeze = 120;
02193             do {
02194                 headerMid = KStringHandler::csqueeze(docname, squeeze);
02195                 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
02196                 squeeze -= 10;
02197             } while (mid_width > available_width);
02198         }
02199 
02200         int top = 0;
02201         int page = 1;
02202         while(top < root->docHeight()) {
02203             if(top > 0) printer->newPage();
02204             if (printHeader)
02205             {
02206                 int dy = p->fontMetrics().lineSpacing();
02207                 p->setPen(Qt::black);
02208                 p->setFont(headerFont);
02209 
02210                 headerRight = QString("#%1").arg(page);
02211 
02212                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
02213                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
02214                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
02215             }
02216 
02217 #ifndef QT_NO_TRANSFORMATIONS
02218             if (scalePage)
02219                 p->scale(scale, scale);
02220 #endif
02221             p->translate(0, headerHeight-top);
02222 
02223             root->setTruncatedAt(top+pageHeight);
02224 
02225             root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
02226             if (top + pageHeight >= root->docHeight())
02227                 break; // Stop if we have printed everything
02228 
02229             top = root->truncatedAt();
02230             p->resetXForm();
02231             page++;
02232         }
02233 
02234         p->end();
02235         delete p;
02236 
02237         // and now reset the layout to the usual one...
02238         root->setPrintingMode(false);
02239         khtml::setPrintPainter( 0 );
02240         setMediaType( oldMediaType );
02241         m_part->xmlDocImpl()->setPaintDevice( this );
02242         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
02243         m_part->xmlDocImpl()->updateStyleSelector();
02244         viewport()->unsetCursor();
02245     }
02246     delete printer;
02247 }
02248 
02249 void KHTMLView::slotPaletteChanged()
02250 {
02251     if(!m_part->xmlDocImpl()) return;
02252     DOM::DocumentImpl *document = m_part->xmlDocImpl();
02253     if (!document->isHTMLDocument()) return;
02254     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
02255     if(!root) return;
02256     root->style()->resetPalette();
02257     NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
02258     if(!body) return;
02259     body->setChanged(true);
02260     body->recalcStyle( NodeImpl::Force );
02261 }
02262 
02263 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
02264 {
02265     if(!m_part->xmlDocImpl()) return;
02266     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
02267     if(!root) return;
02268 
02269     m_part->xmlDocImpl()->setPaintDevice(p->device());
02270     root->setPrintingMode(true);
02271     root->setWidth(rc.width());
02272 
02273     p->save();
02274     p->setClipRect(rc);
02275     p->translate(rc.left(), rc.top());
02276     double scale = ((double) rc.width()/(double) root->docWidth());
02277     int height = (int) ((double) rc.height() / scale);
02278 #ifndef QT_NO_TRANSFORMATIONS
02279     p->scale(scale, scale);
02280 #endif
02281 
02282     root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
02283     if (more)
02284         *more = yOff + height < root->docHeight();
02285     p->restore();
02286 
02287     root->setPrintingMode(false);
02288     m_part->xmlDocImpl()->setPaintDevice( this );
02289 }
02290 
02291 
02292 void KHTMLView::useSlowRepaints()
02293 {
02294     d->useSlowRepaints = true;
02295     setStaticBackground(true);
02296 }
02297 
02298 
02299 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
02300 {
02301 #ifndef KHTML_NO_SCROLLBARS
02302     d->vmode = mode;
02303     QScrollView::setVScrollBarMode(mode);
02304 #else
02305     Q_UNUSED( mode );
02306 #endif
02307 }
02308 
02309 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
02310 {
02311 #ifndef KHTML_NO_SCROLLBARS
02312     d->hmode = mode;
02313     QScrollView::setHScrollBarMode(mode);
02314 #else
02315     Q_UNUSED( mode );
02316 #endif
02317 }
02318 
02319 void KHTMLView::restoreScrollBar()
02320 {
02321     int ow = visibleWidth();
02322     QScrollView::setVScrollBarMode(d->vmode);
02323     if (visibleWidth() != ow)
02324         layout();
02325     d->prevScrollbarVisible = verticalScrollBar()->isVisible();
02326 }
02327 
02328 QStringList KHTMLView::formCompletionItems(const QString &name) const
02329 {
02330     if (!m_part->settings()->isFormCompletionEnabled())
02331         return QStringList();
02332     if (!d->formCompletions)
02333         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02334     return d->formCompletions->readListEntry(name);
02335 }
02336 
02337 void KHTMLView::clearCompletionHistory(const QString& name)
02338 {
02339     if (!d->formCompletions)
02340     {
02341         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02342     }
02343     d->formCompletions->writeEntry(name, "");
02344     d->formCompletions->sync();
02345 }
02346 
02347 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
02348 {
02349     if (!m_part->settings()->isFormCompletionEnabled())
02350         return;
02351     // don't store values that are all numbers or just numbers with
02352     // dashes or spaces as those are likely credit card numbers or
02353     // something similar
02354     bool cc_number(true);
02355     for (unsigned int i = 0; i < value.length(); ++i)
02356     {
02357       QChar c(value[i]);
02358       if (!c.isNumber() && c != '-' && !c.isSpace())
02359       {
02360         cc_number = false;
02361         break;
02362       }
02363     }
02364     if (cc_number)
02365       return;
02366     QStringList items = formCompletionItems(name);
02367     if (!items.contains(value))
02368         items.prepend(value);
02369     while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
02370         items.remove(items.fromLast());
02371     d->formCompletions->writeEntry(name, items);
02372 }
02373 
02374 void KHTMLView::addNonPasswordStorableSite(const QString& host)
02375 {
02376     if (!d->formCompletions) {
02377         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02378     }
02379 
02380     d->formCompletions->setGroup("NonPasswordStorableSites");
02381     QStringList sites = d->formCompletions->readListEntry("Sites");
02382     sites.append(host);
02383     d->formCompletions->writeEntry("Sites", sites);
02384     d->formCompletions->sync();
02385     d->formCompletions->setGroup(QString::null);//reset
02386 }
02387 
02388 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
02389 {
02390     if (!d->formCompletions) {
02391         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02392     }
02393     d->formCompletions->setGroup("NonPasswordStorableSites");
02394     QStringList sites =  d->formCompletions->readListEntry("Sites");
02395     d->formCompletions->setGroup(QString::null);//reset
02396 
02397     return (sites.find(host) != sites.end());
02398 }
02399 
02400 // returns true if event should be swallowed
02401 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
02402                    DOM::NodeImpl *targetNodeNonShared, bool cancelable,
02403                    int detail,QMouseEvent *_mouse, bool setUnder,
02404                    int mouseEventType)
02405 {
02406     if (d->underMouse)
02407     d->underMouse->deref();
02408     d->underMouse = targetNode;
02409     if (d->underMouse)
02410     d->underMouse->ref();
02411 
02412     if (d->underMouseNonShared)
02413     d->underMouseNonShared->deref();
02414     d->underMouseNonShared = targetNodeNonShared;
02415     if (d->underMouseNonShared)
02416     d->underMouseNonShared->ref();
02417 
02418     int exceptioncode = 0;
02419     int pageX = 0;
02420     int pageY = 0;
02421     viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
02422     int clientX = pageX - contentsX();
02423     int clientY = pageY - contentsY();
02424     int screenX = _mouse->globalX();
02425     int screenY = _mouse->globalY();
02426     int button = -1;
02427     switch (_mouse->button()) {
02428     case LeftButton:
02429         button = 0;
02430         break;
02431     case MidButton:
02432         button = 1;
02433         break;
02434     case RightButton:
02435         button = 2;
02436         break;
02437     default:
02438         break;
02439     }
02440     if (d->accessKeysPreActivate && button!=-1) 
02441         d->accessKeysPreActivate=false;
02442     
02443     bool ctrlKey = (_mouse->state() & ControlButton);
02444     bool altKey = (_mouse->state() & AltButton);
02445     bool shiftKey = (_mouse->state() & ShiftButton);
02446     bool metaKey = (_mouse->state() & MetaButton);
02447 
02448     // mouseout/mouseover
02449     if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
02450 
02451         // ### this code sucks. we should save the oldUnder instead of calculating
02452         // it again. calculating is expensive! (Dirk)
02453         NodeImpl *oldUnder = 0;
02454     if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
02455         NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
02456         m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
02457         oldUnder = mev.innerNode.handle();
02458     }
02459 //  qDebug("oldunder=%p (%s), target=%p (%s) x/y=%d/%d", oldUnder, oldUnder ? oldUnder->renderer()->renderName() : 0, targetNode,  targetNode ? targetNode->renderer()->renderName() : 0, _mouse->x(), _mouse->y());
02460     if (oldUnder != targetNode) {
02461         // send mouseout event to the old node
02462         if (oldUnder){
02463         oldUnder->ref();
02464         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
02465                             true,true,m_part->xmlDocImpl()->defaultView(),
02466                             0,screenX,screenY,clientX,clientY,pageX, pageY,
02467                             ctrlKey,altKey,shiftKey,metaKey,
02468                             button,targetNode);
02469         me->ref();
02470         oldUnder->dispatchEvent(me,exceptioncode,true);
02471         me->deref();
02472         }
02473 
02474         // send mouseover event to the new node
02475         if (targetNode) {
02476         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
02477                             true,true,m_part->xmlDocImpl()->defaultView(),
02478                             0,screenX,screenY,clientX,clientY,pageX, pageY,
02479                             ctrlKey,altKey,shiftKey,metaKey,
02480                             button,oldUnder);
02481 
02482         me->ref();
02483         targetNode->dispatchEvent(me,exceptioncode,true);
02484         me->deref();
02485         }
02486 
02487             if (oldUnder)
02488                 oldUnder->deref();
02489         }
02490     }
02491 
02492     bool swallowEvent = false;
02493 
02494     if (targetNode) {
02495         // send the actual event
02496         bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
02497                           _mouse->type() == QEvent::MouseButtonDblClick );
02498         MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
02499                         true,cancelable,m_part->xmlDocImpl()->defaultView(),
02500                         detail,screenX,screenY,clientX,clientY,pageX, pageY,
02501                         ctrlKey,altKey,shiftKey,metaKey,
02502                         button,0, _mouse, dblclick );
02503         me->ref();
02504         targetNode->dispatchEvent(me,exceptioncode,true);
02505         if (me->defaultHandled() || me->defaultPrevented())
02506             swallowEvent = true;
02507         me->deref();
02508 
02509         if (eventId == EventImpl::MOUSEDOWN_EVENT) {
02510             if (targetNode->isSelectable())
02511                 m_part->xmlDocImpl()->setFocusNode(targetNode);
02512             else
02513                 m_part->xmlDocImpl()->setFocusNode(0);
02514         }
02515     }
02516 
02517     return swallowEvent;
02518 }
02519 
02520 void KHTMLView::setIgnoreWheelEvents( bool e )
02521 {
02522     d->ignoreWheelEvents = e;
02523 }
02524 
02525 #ifndef QT_NO_WHEELEVENT
02526 
02527 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
02528 {
02529     if (d->accessKeysPreActivate) d->accessKeysPreActivate=false;
02530 
02531     if ( ( e->state() & ControlButton) == ControlButton )
02532     {
02533         emit zoomView( - e->delta() );
02534         e->accept();
02535     }
02536     else if ( ( (d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
02537                 || e->delta() > 0 && contentsY() <= 0
02538                         || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())
02539                 && m_part->parentPart() ) {
02540        kdDebug(6000) << this << " cz " << contentsY() << " ch " << contentsHeight() << " vh " << visibleHeight() << endl;
02541         if ( m_part->parentPart()->view() )
02542             m_part->parentPart()->view()->wheelEvent( e );
02543         kdDebug(6000) << "sent" << endl;
02544         e->ignore();
02545     }
02546     else if ( d->vmode == QScrollView::AlwaysOff ) {
02547         e->accept();
02548     }
02549     else {
02550         d->scrollBarMoved = true;
02551         QScrollView::viewportWheelEvent( e );
02552 
02553         QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, QPoint(-1,-1), QPoint(-1,-1), Qt::NoButton, e->state() );
02554         emit viewportMouseMoveEvent ( tempEvent );
02555         delete tempEvent;
02556     }
02557 
02558 }
02559 #endif
02560 
02561 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
02562 {
02563     // Handle drops onto frames (#16820)
02564     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
02565     // in e.g. kmail, so not handled here).
02566     if ( m_part->parentPart() )
02567     {
02568         QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02569     return;
02570     }
02571     QScrollView::dragEnterEvent( ev );
02572 }
02573 
02574 void KHTMLView::dropEvent( QDropEvent *ev )
02575 {
02576     // Handle drops onto frames (#16820)
02577     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
02578     // in e.g. kmail, so not handled here).
02579     if ( m_part->parentPart() )
02580     {
02581         QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02582     return;
02583     }
02584     QScrollView::dropEvent( ev );
02585 }
02586 
02587 void KHTMLView::focusInEvent( QFocusEvent *e )
02588 {
02589 #ifndef KHTML_NO_CARET
02590     // Restart blink frequency timer if it has been killed, but only on
02591     // editable nodes
02592     if (d->m_caretViewContext &&
02593         d->m_caretViewContext->freqTimerId == -1 &&
02594         m_part->xmlDocImpl()) {
02595         NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02596         if (m_part->isCaretMode()
02597         || m_part->isEditable()
02598             || (caretNode && caretNode->renderer()
02599             && caretNode->renderer()->style()->userInput()
02600                 == UI_ENABLED)) {
02601             d->m_caretViewContext->freqTimerId = startTimer(500);
02602         d->m_caretViewContext->visible = true;
02603         }/*end if*/
02604     }/*end if*/
02605     showCaret();
02606 #endif // KHTML_NO_CARET
02607     QScrollView::focusInEvent( e );
02608 }
02609 
02610 void KHTMLView::focusOutEvent( QFocusEvent *e )
02611 {
02612     if(m_part) m_part->stopAutoScroll();
02613 
02614 #ifndef KHTML_NO_TYPE_AHEAD_FIND
02615     if(d->typeAheadActivated)
02616     {
02617         findTimeout();
02618     }
02619 #endif // KHTML_NO_TYPE_AHEAD_FIND
02620 
02621 #ifndef KHTML_NO_CARET
02622     if (d->m_caretViewContext) {
02623         switch (d->m_caretViewContext->displayNonFocused) {
02624     case KHTMLPart::CaretInvisible:
02625             hideCaret();
02626         break;
02627     case KHTMLPart::CaretVisible: {
02628         killTimer(d->m_caretViewContext->freqTimerId);
02629         d->m_caretViewContext->freqTimerId = -1;
02630             NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02631         if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
02632         || m_part->isEditable()
02633             || (caretNode && caretNode->renderer()
02634             && caretNode->renderer()->style()->userInput()
02635                 == UI_ENABLED))) {
02636             d->m_caretViewContext->visible = true;
02637             showCaret(true);
02638         }/*end if*/
02639         break;
02640     }
02641     case KHTMLPart::CaretBlink:
02642         // simply leave as is
02643         break;
02644     }/*end switch*/
02645     }/*end if*/
02646 #endif // KHTML_NO_CARET
02647     QScrollView::focusOutEvent( e );
02648 }
02649 
02650 void KHTMLView::slotScrollBarMoved()
02651 {
02652     if (!d->scrollingSelf)
02653         d->scrollBarMoved = true;
02654 }
02655 
02656 void KHTMLView::timerEvent ( QTimerEvent *e )
02657 {
02658 //    kdDebug() << "timer event " << e->timerId() << endl;
02659     if ( e->timerId() == d->scrollTimerId ) {
02660         if( d->scrollSuspended )
02661             return;
02662         switch (d->scrollDirection) {
02663             case KHTMLViewPrivate::ScrollDown:
02664                 if (contentsY() + visibleHeight () >= contentsHeight())
02665                     d->newScrollTimer(this, 0);
02666                 else
02667                     scrollBy( 0, d->scrollBy );
02668                 break;
02669             case KHTMLViewPrivate::ScrollUp:
02670                 if (contentsY() <= 0)
02671                     d->newScrollTimer(this, 0);
02672                 else
02673                     scrollBy( 0, -d->scrollBy );
02674                 break;
02675             case KHTMLViewPrivate::ScrollRight:
02676                 if (contentsX() + visibleWidth () >= contentsWidth())
02677                     d->newScrollTimer(this, 0);
02678                 else
02679                     scrollBy( d->scrollBy, 0 );
02680                 break;
02681             case KHTMLViewPrivate::ScrollLeft:
02682                 if (contentsX() <= 0)
02683                     d->newScrollTimer(this, 0);
02684                 else
02685                     scrollBy( -d->scrollBy, 0 );
02686                 break;
02687         }
02688         return;
02689     }
02690     else if ( e->timerId() == d->layoutTimerId ) {
02691         d->firstRelayout = false;
02692         d->dirtyLayout = true;
02693         layout();
02694     }
02695 #ifndef KHTML_NO_CARET
02696     else if (d->m_caretViewContext
02697              && e->timerId() == d->m_caretViewContext->freqTimerId) {
02698         d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
02699     if (d->m_caretViewContext->displayed) {
02700         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02701             d->m_caretViewContext->width,
02702             d->m_caretViewContext->height);
02703     }/*end if*/
02704 //  if (d->m_caretViewContext->visible) cout << "|" << flush;
02705 //  else cout << "" << flush;
02706     return;
02707     }
02708 #endif
02709 
02710     if( m_part->xmlDocImpl() ) {
02711     DOM::DocumentImpl *document = m_part->xmlDocImpl();
02712     khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
02713 
02714     if ( root && !root->layouted() ) {
02715         killTimer(d->repaintTimerId);
02716         d->repaintTimerId = 0;
02717         scheduleRelayout();
02718         return;
02719     }
02720     }
02721 
02722     setStaticBackground(d->useSlowRepaints);
02723 
02724 //        kdDebug() << "scheduled repaint "<< d->repaintTimerId  << endl;
02725     killTimer(d->repaintTimerId);
02726     d->repaintTimerId = 0;
02727 
02728     QRegion updateRegion;
02729     QMemArray<QRect> rects = d->updateRegion.rects();
02730 
02731     d->updateRegion = QRegion();
02732 
02733     if ( rects.size() )
02734         updateRegion = rects[0];
02735 
02736     for ( unsigned i = 1; i < rects.size(); ++i ) {
02737         QRect obR = updateRegion.boundingRect();
02738         QRegion newRegion = updateRegion.unite(rects[i]);
02739         if (2*newRegion.boundingRect().height() > 3*obR.height() )
02740         {
02741             repaintContents( obR );
02742             updateRegion = rects[i];
02743         }
02744         else
02745             updateRegion = newRegion;
02746     }
02747 
02748     if ( !updateRegion.isNull() )
02749         repaintContents( updateRegion.boundingRect() );
02750 
02751     if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
02752         QWidget* w;
02753         d->dirtyLayout = false;
02754 
02755         QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02756         QPtrList<RenderWidget> toRemove;
02757         for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
02758             int xp = 0, yp = 0;
02759             w = it.current();
02760             RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
02761             if (!rw->absolutePosition(xp, yp) ||
02762                 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
02763                 toRemove.append(rw);
02764         }
02765         for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
02766             if ( (w = d->visibleWidgets.take(r) ) )
02767                 addChild(w, 0, -500000);
02768     }
02769     if (d->accessKeysActivated) emit repaintAccessKeys();
02770 }
02771 
02772 void KHTMLView::scheduleRelayout(khtml::RenderObject * /*clippedObj*/)
02773 {
02774     if (!d->layoutSchedulingEnabled || d->layoutTimerId)
02775         return;
02776 
02777     d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
02778                              ? 1000 : 0 );
02779 }
02780 
02781 void KHTMLView::unscheduleRelayout()
02782 {
02783     if (!d->layoutTimerId)
02784         return;
02785 
02786     killTimer(d->layoutTimerId);
02787     d->layoutTimerId = 0;
02788 }
02789 
02790 void KHTMLView::unscheduleRepaint()
02791 {
02792     if (!d->repaintTimerId)
02793         return;
02794 
02795     killTimer(d->repaintTimerId);
02796     d->repaintTimerId = 0;
02797 }
02798 
02799 void KHTMLView::scheduleRepaint(int x, int y, int w, int h)
02800 {
02801     bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
02802 
02803 //     kdDebug() << "parsing " << parsing << endl;
02804 //     kdDebug() << "complete " << d->complete << endl;
02805 
02806     int time = parsing ? 300 : ( !d->complete ? 100 : 20 );
02807 
02808 #ifdef DEBUG_FLICKER
02809     QPainter p;
02810     p.begin( viewport() );
02811 
02812     int vx, vy;
02813     contentsToViewport( x, y, vx, vy );
02814     p.fillRect( vx, vy, w, h, Qt::red );
02815     p.end();
02816 #endif
02817 
02818     d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
02819 
02820     if ( !d->repaintTimerId )
02821         d->repaintTimerId = startTimer( time );
02822 
02823 //     kdDebug() << "starting timer " << time << endl;
02824 }
02825 
02826 void KHTMLView::complete()
02827 {
02828 //     kdDebug() << "KHTMLView::complete()" << endl;
02829 
02830     d->complete = true;
02831 
02832     // is there a relayout pending?
02833     if (d->layoutTimerId)
02834     {
02835 //         kdDebug() << "requesting relayout now" << endl;
02836         // do it now
02837         killTimer(d->layoutTimerId);
02838         d->layoutTimerId = startTimer( 0 );
02839     }
02840 
02841     // is there a repaint pending?
02842     if (d->repaintTimerId)
02843     {
02844 //         kdDebug() << "requesting repaint now" << endl;
02845         // do it now
02846         killTimer(d->repaintTimerId);
02847         d->repaintTimerId = startTimer( 20 );
02848     }
02849 }
02850 
02851 #ifndef KHTML_NO_CARET
02852 
02853 // ### the dependencies on static functions are a nightmare. just be
02854 // hacky and include the implementation here. Clean me up, please.
02855 
02856 #include "khtml_caret.cpp"
02857 
02858 void KHTMLView::initCaret(bool keepSelection)
02859 {
02860 #if DEBUG_CARETMODE > 0
02861   kdDebug(6200) << "begin initCaret" << endl;
02862 #endif
02863   // save caretMoved state as moveCaretTo changes it
02864   if (m_part->xmlDocImpl()) {
02865 #if 0
02866     ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
02867     if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
02868 #endif
02869     d->caretViewContext();
02870     bool cmoved = d->m_caretViewContext->caretMoved;
02871     if (m_part->d->caretNode().isNull()) {
02872       // set to document, position will be sanitized anyway
02873       m_part->d->caretNode() = m_part->document();
02874       m_part->d->caretOffset() = 0L;
02875       // This sanity check is necessary for the not so unlikely case that
02876       // setEditable or setCaretMode is called before any render objects have
02877       // been created.
02878       if (!m_part->d->caretNode().handle()->renderer()) return;
02879     }/*end if*/
02880 //    kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
02881 //          << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
02882     // ### does not repaint the selection on keepSelection!=false
02883     moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
02884 //    kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
02885 //          << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
02886     d->m_caretViewContext->caretMoved = cmoved;
02887   }/*end if*/
02888 #if DEBUG_CARETMODE > 0
02889   kdDebug(6200) << "end initCaret" << endl;
02890 #endif
02891 }
02892 
02893 bool KHTMLView::caretOverrides() const
02894 {
02895     bool cm = m_part->isCaretMode();
02896     bool dm = m_part->isEditable();
02897     return cm && !dm ? false
02898         : (dm || m_part->d->caretNode().handle()->contentEditable())
02899       && d->editorContext()->override;
02900 }
02901 
02902 void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
02903 {
02904   if (m_part->isCaretMode() || m_part->isEditable()) return;
02905   if (node->focused()) return;
02906 
02907   // Find first ancestor whose "user-input" is "enabled"
02908   NodeImpl *firstAncestor = 0;
02909   while (node) {
02910     if (node->renderer()
02911        && node->renderer()->style()->userInput() != UI_ENABLED)
02912       break;
02913     firstAncestor = node;
02914     node = node->parentNode();
02915   }/*wend*/
02916 
02917   if (!node) firstAncestor = 0;
02918 
02919   DocumentImpl *doc = m_part->xmlDocImpl();
02920   // ensure that embedded widgets don't lose their focus
02921   if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
02922     && doc->focusNode()->renderer()->isWidget())
02923     return;
02924 
02925   // Set focus node on the document
02926 #if DEBUG_CARETMODE > 1
02927   kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
02928     << (firstAncestor ? firstAncestor->nodeName().string() : QString::null) << endl;
02929 #endif
02930   doc->setFocusNode(firstAncestor);
02931   emit m_part->nodeActivated(Node(firstAncestor));
02932 }
02933 
02934 void KHTMLView::recalcAndStoreCaretPos(CaretBox *hintBox)
02935 {
02936     if (!m_part || m_part->d->caretNode().isNull()) return;
02937     d->caretViewContext();
02938     NodeImpl *caretNode = m_part->d->caretNode().handle();
02939 #if DEBUG_CARETMODE > 0
02940   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;
02941 #endif
02942     caretNode->getCaret(m_part->d->caretOffset(), caretOverrides(),
02943             d->m_caretViewContext->x, d->m_caretViewContext->y,
02944         d->m_caretViewContext->width,
02945         d->m_caretViewContext->height);
02946 
02947     if (hintBox && d->m_caretViewContext->x == -1) {
02948 #if DEBUG_CARETMODE > 1
02949         kdDebug(6200) << "using hint inline box coordinates" << endl;
02950 #endif
02951     RenderObject *r = caretNode->renderer();
02952     const QFontMetrics &fm = r->style()->fontMetrics();
02953         int absx, absy;
02954     r->containingBlock()->absolutePosition(absx, absy,
02955                         false); // ### what about fixed?
02956     d->m_caretViewContext->x = absx + hintBox->xPos();
02957     d->m_caretViewContext->y = absy + hintBox->yPos();
02958 //              + hintBox->baseline() - fm.ascent();
02959     d->m_caretViewContext->width = 1;
02960     // ### firstline not regarded. But I think it can be safely neglected
02961     // as hint boxes are only used for empty lines.
02962     d->m_caretViewContext->height = fm.height();
02963     }/*end if*/
02964 
02965 #if DEBUG_CARETMODE > 4
02966 //    kdDebug(6200) << "freqTimerId: "<<d->m_caretViewContext->freqTimerId<<endl;
02967 #endif
02968 #if DEBUG_CARETMODE > 0
02969     kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
02970         <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
02971     <<" h="<<d->m_caretViewContext->height<<endl;
02972 #endif
02973 }
02974 
02975 void KHTMLView::caretOn()
02976 {
02977     if (d->m_caretViewContext) {
02978         killTimer(d->m_caretViewContext->freqTimerId);
02979 
02980     if (hasFocus() || d->m_caretViewContext->displayNonFocused
02981             == KHTMLPart::CaretBlink) {
02982             d->m_caretViewContext->freqTimerId = startTimer(500);
02983     } else {
02984         d->m_caretViewContext->freqTimerId = -1;
02985     }/*end if*/
02986 
02987         d->m_caretViewContext->visible = true;
02988         if ((d->m_caretViewContext->displayed = (hasFocus()
02989         || d->m_caretViewContext->displayNonFocused
02990             != KHTMLPart::CaretInvisible))) {
02991         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02992                 d->m_caretViewContext->width,
02993             d->m_caretViewContext->height);
02994     }/*end if*/
02995 //        kdDebug(6200) << "caret on" << endl;
02996     }/*end if*/
02997 }
02998 
02999 void KHTMLView::caretOff()
03000 {
03001     if (d->m_caretViewContext) {
03002         killTimer(d->m_caretViewContext->freqTimerId);
03003     d->m_caretViewContext->freqTimerId = -1;
03004         d->m_caretViewContext->displayed = false;
03005         if (d->m_caretViewContext->visible) {
03006             d->m_caretViewContext->visible = false;
03007         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03008                 d->m_caretViewContext->width,
03009                 d->m_caretViewContext->height);
03010     }/*end if*/
03011 //        kdDebug(6200) << "caret off" << endl;
03012     }/*end if*/
03013 }
03014 
03015 void KHTMLView::showCaret(bool forceRepaint)
03016 {
03017     if (d->m_caretViewContext) {
03018         d->m_caretViewContext->displayed = true;
03019         if (d->m_caretViewContext->visible) {
03020         if (!forceRepaint) {
03021             updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03022                 d->m_caretViewContext->width,
03023             d->m_caretViewContext->height);
03024             } else {
03025             repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03026                 d->m_caretViewContext->width,
03027                 d->m_caretViewContext->height);
03028         }/*end if*/
03029     }/*end if*/
03030 //        kdDebug(6200) << "caret shown" << endl;
03031     }/*end if*/
03032 }
03033 
03034 bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
03035                     NodeImpl *endNode, long endOffset)
03036 {
03037   m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
03038   m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
03039   m_part->d->m_extendAtEnd = true;
03040 
03041   bool folded = startNode != endNode || startOffset != endOffset;
03042 
03043   // Only clear the selection if there has been one.
03044   if (folded) {
03045     m_part->xmlDocImpl()->clearSelection();
03046   }/*end if*/
03047 
03048   return folded;
03049 }
03050 
03051 void KHTMLView::hideCaret()
03052 {
03053     if (d->m_caretViewContext) {
03054         if (d->m_caretViewContext->visible) {
03055 //            kdDebug(6200) << "redraw caret hidden" << endl;
03056         d->m_caretViewContext->visible = false;
03057         // force repaint, otherwise the event won't be handled
03058         // before the focus leaves the window
03059         repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03060                 d->m_caretViewContext->width,
03061                 d->m_caretViewContext->height);
03062         d->m_caretViewContext->visible = true;
03063     }/*end if*/
03064         d->m_caretViewContext->displayed = false;
03065 //        kdDebug(6200) << "caret hidden" << endl;
03066     }/*end if*/
03067 }
03068 
03069 int KHTMLView::caretDisplayPolicyNonFocused() const
03070 {
03071   if (d->m_caretViewContext)
03072     return d->m_caretViewContext->displayNonFocused;
03073   else
03074     return KHTMLPart::CaretInvisible;
03075 }
03076 
03077 void KHTMLView::setCaretDisplayPolicyNonFocused(int policy)
03078 {
03079   d->caretViewContext();
03080 //  int old = d->m_caretViewContext->displayNonFocused;
03081   d->m_caretViewContext->displayNonFocused = (KHTMLPart::CaretDisplayPolicy)policy;
03082 
03083   // make change immediately take effect if not focused
03084   if (!hasFocus()) {
03085     switch (d->m_caretViewContext->displayNonFocused) {
03086       case KHTMLPart::CaretInvisible:
03087         hideCaret();
03088     break;
03089       case KHTMLPart::CaretBlink:
03090     if (d->m_caretViewContext->freqTimerId != -1) break;
03091     d->m_caretViewContext->freqTimerId = startTimer(500);
03092     // fall through
03093       case KHTMLPart::CaretVisible:
03094         d->m_caretViewContext->displayed = true;
03095         showCaret();
03096     break;
03097     }/*end switch*/
03098   }/*end if*/
03099 }
03100 
03101 bool KHTMLView::placeCaret(CaretBox *hintBox)
03102 {
03103   CaretViewContext *cv = d->caretViewContext();
03104   caretOff();
03105   NodeImpl *caretNode = m_part->d->caretNode().handle();
03106   // ### why is it sometimes null?
03107   if (!caretNode || !caretNode->renderer()) return false;
03108   ensureNodeHasFocus(caretNode);
03109   if (m_part->isCaretMode() || m_part->isEditable()
03110      || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
03111     recalcAndStoreCaretPos(hintBox);
03112 
03113     cv->origX = cv->x;
03114 
03115     caretOn();
03116     return true;
03117   }/*end if*/
03118   return false;
03119 }
03120 
03121 void KHTMLView::ensureCaretVisible()
03122 {
03123   CaretViewContext *cv = d->m_caretViewContext;
03124   if (!cv) return;
03125   ensureVisible(cv->x, cv->y, cv->width, cv->height);
03126   d->scrollBarMoved = false;
03127 }
03128 
03129 bool KHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
03130                 NodeImpl *oldEndSel, long oldEndOfs)
03131 {
03132   bool changed = false;
03133   if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
03134       && m_part->d->m_startOffset == m_part->d->m_endOffset) {
03135     changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03136     m_part->d->m_extendAtEnd = true;
03137   } else do {
03138     changed = m_part->d->m_selectionStart.handle() != oldStartSel
03139             || m_part->d->m_startOffset != oldStartOfs
03140         || m_part->d->m_selectionEnd.handle() != oldEndSel
03141         || m_part->d->m_endOffset != oldEndOfs;
03142     if (!changed) break;
03143 
03144     // determine start position -- caret position is always at end.
03145     NodeImpl *startNode;
03146     long startOffset;
03147     if (m_part->d->m_extendAtEnd) {
03148       startNode = m_part->d->m_selectionStart.handle();
03149       startOffset = m_part->d->m_startOffset;
03150     } else {
03151       startNode = m_part->d->m_selectionEnd.handle();
03152       startOffset = m_part->d->m_endOffset;
03153       m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
03154       m_part->d->m_endOffset = m_part->d->m_startOffset;
03155       m_part->d->m_extendAtEnd = true;
03156     }/*end if*/
03157 
03158     bool swapNeeded = false;
03159     if (!m_part->d->m_selectionEnd.isNull() && startNode) {
03160       swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
03161                 m_part->d->m_selectionEnd.handle(),
03162             m_part->d->m_endOffset) >= 0;
03163     }/*end if*/
03164 
03165     m_part->d->m_selectionStart = startNode;
03166     m_part->d->m_startOffset = startOffset;
03167 
03168     if (swapNeeded) {
03169       m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
03170         m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
03171         m_part->d->m_startOffset);
03172     } else {
03173       m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
03174         m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
03175         m_part->d->m_endOffset);
03176     }/*end if*/
03177   } while(false);/*end if*/
03178   return changed;
03179 }
03180 
03181 void KHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
03182                 NodeImpl *oldEndSel, long oldEndOfs)
03183 {
03184   if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
03185       && m_part->d->m_startOffset == m_part->d->m_endOffset) {
03186     if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
03187       m_part->emitSelectionChanged();
03188     }/*end if*/
03189     m_part->d->m_extendAtEnd = true;
03190   } else {
03191     // check if the extending end has passed the immobile end
03192     if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
03193       bool swapNeeded = RangeImpl::compareBoundaryPoints(
03194                 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
03195             m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
03196       if (swapNeeded) {
03197         DOM::Node tmpNode = m_part->d->m_selectionStart;
03198         long tmpOffset = m_part->d->m_startOffset;
03199         m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
03200         m_part->d->m_startOffset = m_part->d->m_endOffset;
03201         m_part->d->m_selectionEnd = tmpNode;
03202         m_part->d->m_endOffset = tmpOffset;
03203         m_part->d->m_startBeforeEnd = true;
03204         m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
03205       }/*end if*/
03206     }/*end if*/
03207 
03208     m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
03209         m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
03210         m_part->d->m_endOffset);
03211     m_part->emitSelectionChanged();
03212   }/*end if*/
03213 }
03214 
03215 void KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
03216 {
03217   NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
03218   long oldStartOfs = m_part->d->m_startOffset;
03219   NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
03220   long oldEndOfs = m_part->d->m_endOffset;
03221 
03222   NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
03223   long oldOffset = m_part->d->caretOffset();
03224 
03225   bool ctrl = _ke->state() & ControlButton;
03226 
03227 // FIXME: this is that widely indented because I will write ifs around it.
03228       switch(_ke->key()) {
03229         case Key_Space:
03230           break;
03231 
03232         case Key_Down:
03233       moveCaretNextLine(1);
03234           break;
03235 
03236         case Key_Up:
03237       moveCaretPrevLine(1);
03238           break;
03239 
03240         case Key_Left:
03241       moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
03242           break;
03243 
03244         case Key_Right:
03245       moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
03246           break;
03247 
03248         case Key_Next:
03249       moveCaretNextPage();
03250           break;
03251 
03252         case Key_Prior:
03253       moveCaretPrevPage();
03254           break;
03255 
03256         case Key_Home:
03257       if (ctrl)
03258         moveCaretToDocumentBoundary(false);
03259       else
03260         moveCaretToLineBegin();
03261           break;
03262 
03263         case Key_End:
03264       if (ctrl)
03265         moveCaretToDocumentBoundary(true);
03266       else
03267         moveCaretToLineEnd();
03268           break;
03269 
03270       }/*end switch*/
03271 
03272   if ((m_part->d->caretNode().handle() != oldCaretNode
03273     || m_part->d->caretOffset() != oldOffset)
03274     // node should never be null, but faulty conditions may cause it to be
03275     && !m_part->d->caretNode().isNull()) {
03276 
03277     d->m_caretViewContext->caretMoved = true;
03278 
03279     if (_ke->state() & ShiftButton) {   // extend selection
03280       updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03281     } else {            // clear any selection
03282       if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
03283         m_part->emitSelectionChanged();
03284     }/*end if*/
03285 
03286     m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
03287   }/*end if*/
03288 
03289   _ke->accept();
03290 }
03291 
03292 bool KHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
03293 {
03294   if (!node) return false;
03295   ElementImpl *baseElem = determineBaseElement(node);
03296   RenderFlow *base = static_cast<RenderFlow *>(baseElem ? baseElem->renderer() : 0);
03297   if (!node) return false;
03298 
03299   // need to find out the node's inline box. If there is none, this function
03300   // will snap to the next node that has one. This is necessary to make the
03301   // caret visible in any case.
03302   CaretBoxLineDeleter cblDeleter;
03303 //   RenderBlock *cb;
03304   long r_ofs;
03305   CaretBoxIterator cbit;
03306   CaretBoxLine *cbl = findCaretBoxLine(node, offset, &cblDeleter, base, r_ofs, cbit);
03307   if(!cbl) {
03308       kdWarning() << "KHTMLView::moveCaretTo - findCaretBoxLine() returns NULL" << endl;
03309       return false;
03310   }
03311 
03312 #if DEBUG_CARETMODE > 3
03313   if (cbl) kdDebug(6200) << cbl->information() << endl;
03314 #endif
03315   CaretBox *box = *cbit;
03316   if (cbit != cbl->end() && box->object() != node->renderer()) {
03317     if (box->object()->element()) {
03318       mapRenderPosToDOMPos(box->object(), r_ofs, box->isOutside(),
03319                 box->isOutsideEnd(), node, offset);
03320       //if (!outside) offset = node->minOffset();
03321 #if DEBUG_CARETMODE > 1
03322       kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
03323 #endif
03324     } else {    // box has no associated element -> do not use
03325       // this case should actually never happen.
03326       box = 0;
03327       kdError(6200) << "Box contains no node! Crash imminent" << endl;
03328     }/*end if*/
03329   }
03330 
03331   NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
03332   long oldStartOfs = m_part->d->m_startOffset;
03333   NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
03334   long oldEndOfs = m_part->d->m_endOffset;
03335 
03336   // test for position change
03337   bool posChanged = m_part->d->caretNode().handle() != node
03338         || m_part->d->caretOffset() != offset;
03339   bool selChanged = false;
03340 
03341   m_part->d->caretNode() = node;
03342   m_part->d->caretOffset() = offset;
03343   if (clearSel || !oldStartSel || !oldEndSel) {
03344     selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03345   } else {
03346     //kdDebug(6200) << "moveToCaret: extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
03347     //kdDebug(6200) << "selection: start(" << m_part->d->m_selectionStart.handle() << "," << m_part->d->m_startOffset << "), end(" << m_part->d->m_selectionEnd.handle() << "," << m_part->d->m_endOffset << "), caret(" << m_part->d->caretNode().handle() << "," << m_part->d->caretOffset() << ")" << endl;
03348     selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03349     //kdDebug(6200) << "after extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
03350     //kdDebug(6200) << "selection: start(" << m_part->d->m_selectionStart.handle() << "," << m_part->d->m_startOffset << "), end(" << m_part->d->m_selectionEnd.handle() << "," << m_part->d->m_endOffset << "), caret(" << m_part->d->caretNode().handle() << "," << m_part->d->caretOffset() << ")" << endl;
03351   }/*end if*/
03352 
03353   d->caretViewContext()->caretMoved = true;
03354 
03355   bool visible_caret = placeCaret(box);
03356 
03357   // FIXME: if the old position was !visible_caret, and the new position is
03358   // also, then two caretPositionChanged signals with a null Node are
03359   // emitted in series.
03360   if (posChanged) {
03361     m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
03362   }/*end if*/
03363 
03364   return selChanged;
03365 }
03366 
03367 void KHTMLView::moveCaretByLine(bool next, int count)
03368 {
03369   Node &caretNodeRef = m_part->d->caretNode();
03370   if (caretNodeRef.isNull()) return;
03371 
03372   NodeImpl *caretNode = caretNodeRef.handle();
03373 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
03374   long offset = m_part->d->caretOffset();
03375 
03376   CaretViewContext *cv = d->caretViewContext();
03377 
03378   ElementImpl *baseElem = determineBaseElement(caretNode);
03379   LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
03380 
03381   ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03382 
03383   // move count lines vertically
03384   while (count > 0 && it != ld.end() && it != ld.preBegin()) {
03385     count--;
03386     if (next) ++it; else --it;
03387   }/*wend*/
03388 
03389   // Nothing? Then leave everything as is.
03390   if (it == ld.end() || it == ld.preBegin()) return;
03391 
03392   int x, absx, absy;
03393   CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
03394 
03395   placeCaretOnLine(caretBox, x, absx, absy);
03396 }
03397 
03398 void KHTMLView::placeCaretOnLine(CaretBox *caretBox, int x, int absx, int absy)
03399 {
03400   // paranoia sanity check
03401   if (!caretBox) return;
03402 
03403   RenderObject *caretRender = caretBox->object();
03404 
03405 #if DEBUG_CARETMODE > 0
03406   kdDebug(6200) << "got valid caretBox " << caretBox << endl;
03407   kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
03408         << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
03409   InlineTextBox *tb = static_cast<InlineTextBox *>(caretBox->inlineBox());
03410   if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << QString(static_cast<RenderText *>(tb->object())->str->s + tb->m_start, tb->m_len) << "\"" << endl;}
03411 #endif
03412   // inquire height of caret
03413   int caretHeight = caretBox->height();
03414   bool isText = caretBox->isInlineTextBox();
03415   int yOfs = 0;     // y-offset for text nodes
03416   if (isText) {
03417     // text boxes need extrawurst
03418     RenderText *t = static_cast<RenderText *>(caretRender);
03419     const QFontMetrics &fm = t->metrics(caretBox->inlineBox()->m_firstLine);
03420     caretHeight = fm.height();
03421     yOfs = caretBox->inlineBox()->baseline() - fm.ascent();
03422   }/*end if*/
03423 
03424   caretOff();
03425 
03426   // set new caret node
03427   NodeImpl *caretNode;
03428   long &offset = m_part->d->caretOffset();
03429   mapRenderPosToDOMPos(caretRender, offset, caretBox->isOutside(),
03430         caretBox->isOutsideEnd(), caretNode, offset);
03431 
03432   // set all variables not needing special treatment
03433   d->m_caretViewContext->y = caretBox->yPos() + yOfs;
03434   d->m_caretViewContext->height = caretHeight;
03435   d->m_caretViewContext->width = 1; // FIXME: regard override
03436 
03437   int xPos = caretBox->xPos();
03438   int caretBoxWidth = caretBox->width();
03439   d->m_caretViewContext->x = xPos;
03440 
03441   if (!caretBox->isOutside()) {
03442     // before or at beginning of inline box -> place at beginning
03443     long r_ofs = 0;
03444     if (x <= xPos) {
03445       r_ofs = caretBox->minOffset();
03446   // somewhere within this block
03447     } else if (x > xPos && x <= xPos + caretBoxWidth) {
03448       if (isText) { // find out where exactly
03449         r_ofs = static_cast<InlineTextBox *>(caretBox->inlineBox())
03450             ->offsetForPoint(x, d->m_caretViewContext->x);
03451 #if DEBUG_CARETMODE > 2
03452         kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
03453 #endif
03454 #if 0
03455       } else {  // snap to nearest end
03456         if (xPos + caretBoxWidth - x < x - xPos) {
03457           d->m_caretViewContext->x = xPos + caretBoxWidth;
03458           r_ofs = caretNode ? caretNode->maxOffset() : 1;
03459         } else {
03460           d->m_caretViewContext->x = xPos;
03461           r_ofs = caretNode ? caretNode->minOffset() : 0;
03462         }/*end if*/
03463 #endif
03464       }/*end if*/
03465     } else {        // after the inline box -> place at end
03466       d->m_caretViewContext->x = xPos + caretBoxWidth;
03467       r_ofs = caretBox->maxOffset();
03468     }/*end if*/
03469     offset = r_ofs;
03470   }/*end if*/
03471 #if DEBUG_CARETMODE > 0
03472       kdDebug(6200) << "new offset: " << offset << endl;
03473 #endif
03474 
03475   m_part->d->caretNode() = caretNode;
03476   m_part->d->caretOffset() = offset;
03477 
03478   d->m_caretViewContext->x += absx;
03479   d->m_caretViewContext->y += absy;
03480 
03481 #if DEBUG_CARETMODE > 1
03482     kdDebug(6200) << "new caret position: x " << d->m_caretViewContext->x << " y " << d->m_caretViewContext->y << " w " << d->m_caretViewContext->width << " h " << d->m_caretViewContext->height << " absx " << absx << " absy " << absy << endl;
03483 #endif
03484 
03485   ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03486     d->m_caretViewContext->width, d->m_caretViewContext->height);
03487   d->scrollBarMoved = false;
03488 
03489   ensureNodeHasFocus(caretNode);
03490   caretOn();
03491 }
03492 
03493 void KHTMLView::moveCaretToLineBoundary(bool end)
03494 {
03495   Node &caretNodeRef = m_part->d->caretNode();
03496   if (caretNodeRef.isNull()) return;
03497 
03498   NodeImpl *caretNode = caretNodeRef.handle();
03499 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
03500   long offset = m_part->d->caretOffset();
03501 
03502   ElementImpl *baseElem = determineBaseElement(caretNode);
03503   LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
03504 
03505   EditableLineIterator it = ld.current();
03506   if (it == ld.end()) return;   // should not happen, but who knows
03507 
03508   EditableCaretBoxIterator fbit(it, end);
03509   Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
03510   CaretBox *b = *fbit;
03511 
03512   RenderObject *cb = b->containingBlock();
03513   int absx, absy;
03514 
03515   if (cb) cb->absolutePosition(absx,absy);
03516   else absx = absy = 0;
03517 
03518   int x = b->xPos() + (end && !b->isOutside() ? b->width() : 0);
03519   d->m_caretViewContext->origX = absx + x;
03520   placeCaretOnLine(b, x, absx, absy);
03521 }
03522 
03523 void KHTMLView::moveCaretToDocumentBoundary(bool end)
03524 {
03525   Node &caretNodeRef = m_part->d->caretNode();
03526   if (caretNodeRef.isNull()) return;
03527 
03528   NodeImpl *caretNode = caretNodeRef.handle();
03529 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
03530   long offset = m_part->d->caretOffset();
03531 
03532   ElementImpl *baseElem = determineBaseElement(caretNode);
03533   LinearDocument ld(m_part, caretNode, offset, IndicatedFlows, baseElem);
03534 
03535   EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
03536   if (it == ld.end() || it == ld.preBegin()) return;    // should not happen, but who knows
03537 
03538   EditableCaretBoxIterator fbit = it;
03539   Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
03540   CaretBox *b = *fbit;
03541 
03542   RenderObject *cb = (*it)->containingBlock();
03543   int absx, absy;
03544 
03545   if (cb) cb->absolutePosition(absx, absy);
03546   else absx = absy = 0;
03547 
03548   int x = b->xPos()/* + (end ? b->width() : 0) reactivate for rtl*/;
03549   d->m_caretViewContext->origX = absx + x;
03550   placeCaretOnLine(b, x, absx, absy);
03551 }
03552 
03553 void KHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
03554 {
03555   if (!m_part) return;
03556   Node &caretNodeRef = m_part->d->caretNode();
03557   if (caretNodeRef.isNull()) return;
03558 
03559   NodeImpl *caretNode = caretNodeRef.handle();
03560 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
03561   long &offset = m_part->d->caretOffset();
03562 
03563   ElementImpl *baseElem = determineBaseElement(caretNode);
03564   CaretAdvancePolicy advpol = cmv != CaretByWord ? IndicatedFlows : LeafsOnly;
03565   LinearDocument ld(m_part, caretNode, offset, advpol, baseElem);
03566 
03567   EditableCharacterIterator it(&ld);
03568   while (!it.isEnd() && count > 0) {
03569     count--;
03570     if (cmv == CaretByCharacter) {
03571       if (next) ++it;
03572       else --it;
03573     } else if (cmv == CaretByWord) {
03574       if (next) moveItToNextWord(it);
03575       else moveItToPrevWord(it);
03576     }/*end if*/
03577 //kdDebug(6200) << "movecaret" << endl;
03578   }/*wend*/
03579   CaretBox *hintBox = 0;    // make gcc uninit warning disappear
03580   if (!it.isEnd()) {
03581     NodeImpl *node = caretNodeRef.handle();
03582     hintBox = it.caretBox();
03583 //kdDebug(6200) << "hintBox = " << hintBox << endl;
03584 //kdDebug(6200) << " outside " << hintBox->isOutside() << " outsideEnd " << hintBox->isOutsideEnd() << " r " << it.renderer() << " ofs " << it.offset() << " cb " << hintBox->containingBlock() << endl;
03585     mapRenderPosToDOMPos(it.renderer(), it.offset(), hintBox->isOutside(),
03586             hintBox->isOutsideEnd(), node, offset);
03587 //kdDebug(6200) << "mapRTD" << endl;
03588     caretNodeRef = node;
03589 #if DEBUG_CARETMODE > 2
03590     kdDebug(6200) << "set by valid node " << node << " " << (node?node->nodeName().string():QString::null) << " offset: " << offset << endl;
03591 #endif
03592   } else {
03593     offset = next ? caretNode->maxOffset() : caretNode->minOffset();
03594 #if DEBUG_CARETMODE > 0
03595     kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
03596 #endif
03597   }/*end if*/
03598   placeCaretOnChar(hintBox);
03599 }
03600 
03601 void KHTMLView::placeCaretOnChar(CaretBox *hintBox)
03602 {
03603   caretOff();
03604   recalcAndStoreCaretPos(hintBox);
03605   ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03606     d->m_caretViewContext->width, d->m_caretViewContext->height);
03607   d->m_caretViewContext->origX = d->m_caretViewContext->x;
03608   d->scrollBarMoved = false;
03609 #if DEBUG_CARETMODE > 3
03610   //if (caretNode->isTextNode())  kdDebug(6200) << "text[0] = " << (int)*((TextImpl *)caretNode)->data().unicode() << " text :\"" << ((TextImpl *)caretNode)->data().string() << "\"" << endl;
03611 #endif
03612   ensureNodeHasFocus(m_part->d->caretNode().handle());
03613   caretOn();
03614 }
03615 
03616 void KHTMLView::moveCaretByPage(bool next)
03617 {
03618   Node &caretNodeRef = m_part->d->caretNode();
03619 
03620   NodeImpl *caretNode = caretNodeRef.handle();
03621 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
03622   long offset = m_part->d->caretOffset();
03623 
03624   int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
03625   // Minimum distance the caret must be moved
03626   int mindist = clipper()->height() - offs;
03627 
03628   CaretViewContext *cv = d->caretViewContext();
03629 //  int y = cv->y;      // we always measure the top border
03630 
03631   ElementImpl *baseElem = determineBaseElement(caretNode);
03632   LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
03633 
03634   ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03635 
03636   moveIteratorByPage(ld, it, mindist, next);
03637 
03638   int x, absx, absy;
03639   CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
03640 
03641   placeCaretOnLine(caretBox, x, absx, absy);
03642 }
03643 
03644 void KHTMLView::moveCaretPrevWord()
03645 {
03646   moveCaretBy(false, CaretByWord, 1);
03647 }
03648 
03649 void KHTMLView::moveCaretNextWord()
03650 {
03651   moveCaretBy(true, CaretByWord, 1);
03652 }
03653 
03654 void KHTMLView::moveCaretPrevLine(int n)
03655 {
03656   moveCaretByLine(false, n);
03657 }
03658 
03659 void KHTMLView::moveCaretNextLine(int n)
03660 {
03661   moveCaretByLine(true, n);
03662 }
03663 
03664 void KHTMLView::moveCaretPrevPage()
03665 {
03666   moveCaretByPage(false);
03667 }
03668 
03669 void KHTMLView::moveCaretNextPage()
03670 {
03671   moveCaretByPage(true);
03672 }
03673 
03674 void KHTMLView::moveCaretToLineBegin()
03675 {
03676   moveCaretToLineBoundary(false);
03677 }
03678 
03679 void KHTMLView::moveCaretToLineEnd()
03680 {
03681   moveCaretToLineBoundary(true);
03682 }
03683 
03684 #endif // KHTML_NO_CARET
03685 
03686 #undef DEBUG_CARETMODE
KDE Logo
This file is part of the documentation for khtml Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Feb 18 15:11:43 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003