• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KHTML

khtmlview.cpp

Go to the documentation of this file.
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  *                     2003-2008 Apple Computer, Inc.
00009  *                     2008 Allan Sandfeld Jensen <kde@carewolf.com>
00010  *                     2006-2008 Germain Garand <germain@ebooksfrance.org>
00011  *
00012  * This library is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Library General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 2 of the License, or (at your option) any later version.
00016  *
00017  * This library is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  * Library General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU Library General Public License
00023  * along with this library; see the file COPYING.LIB.  If not, write to
00024  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00025  * Boston, MA 02110-1301, USA.
00026  */
00027 
00028 
00029 #include "khtmlview.h"
00030 
00031 #include "khtmlview.moc"
00032 
00033 #include "khtml_part.h"
00034 #include "khtml_events.h"
00035 #ifdef Q_WS_X11
00036 #include <qx11info_x11.h>
00037 #endif
00038 
00039 #include "html/html_documentimpl.h"
00040 #include "html/html_inlineimpl.h"
00041 #include "html/html_formimpl.h"
00042 #include "html/htmltokenizer.h"
00043 #include "editing/editor.h"
00044 #include "rendering/render_arena.h"
00045 #include "rendering/render_canvas.h"
00046 #include "rendering/render_frames.h"
00047 #include "rendering/render_replaced.h"
00048 #include "rendering/render_form.h"
00049 #include "rendering/render_layer.h"
00050 #include "rendering/render_line.h"
00051 #include "rendering/render_table.h"
00052 // removeme
00053 #define protected public
00054 #include "rendering/render_text.h"
00055 #undef protected
00056 #include "xml/dom2_eventsimpl.h"
00057 #include "css/cssstyleselector.h"
00058 #include "css/csshelper.h"
00059 #include "misc/htmlhashes.h"
00060 #include "misc/helper.h"
00061 #include "misc/loader.h"
00062 #include "khtml_settings.h"
00063 #include "khtml_printsettings.h"
00064 
00065 #include "khtmlpart_p.h"
00066 
00067 #include <kcursor.h>
00068 #include <kdebug.h>
00069 #include <kglobalsettings.h>
00070 #include <kdialog.h>
00071 #include <kiconloader.h>
00072 #include <klocale.h>
00073 #include <knotification.h>
00074 #include <kdeprintdialog.h>
00075 #include <kconfig.h>
00076 #include <kstandarddirs.h>
00077 #include <kstandardshortcut.h>
00078 #include <kstringhandler.h>
00079 #include <kconfiggroup.h>
00080 
00081 #include <QtGui/QBitmap>
00082 #include <QtGui/QLabel>
00083 #include <QtCore/QObject>
00084 #include <QtGui/QPainter>
00085 #include <QtCore/QHash>
00086 #include <QtGui/QToolTip>
00087 #include <QtCore/QString>
00088 #include <QtGui/QTextDocument>
00089 #include <QtCore/QTimer>
00090 #include <QtCore/QAbstractEventDispatcher>
00091 #include <QtCore/QVector>
00092 #include <QtGui/QAbstractScrollArea>
00093 #include <QtGui/QPrinter>
00094 #include <QtGui/QPrintDialog>
00095 
00096 //#define DEBUG_FLICKER
00097 
00098 #include <limits.h>
00099 #ifdef Q_WS_X11
00100 #include <X11/Xlib.h>
00101 #include <fixx11h.h>
00102 #elif defined(Q_WS_WIN)
00103 #include <windows.h>
00104 #endif
00105 
00106 #if 0
00107 namespace khtml {
00108     void dumpLineBoxes(RenderFlow *flow);
00109 }
00110 #endif
00111 
00112 using namespace DOM;
00113 using namespace khtml;
00114 
00115 #ifndef NDEBUG
00116 static const int sFirstLayoutDelay = 760;
00117 static const int sParsingLayoutsInterval = 420;
00118 static const int sLayoutAttemptDelay = 400;
00119 #else
00120 static const int sFirstLayoutDelay = 540;
00121 static const int sParsingLayoutsInterval = 360;
00122 static const int sLayoutAttemptDelay = 340;
00123 #endif
00124 static const int sLayoutAttemptIncrement = 20;
00125 static const int sParsingLayoutsIncrement = 60;
00126 
00127 static const int sSmoothScrollTime = 140;
00128 static const int sSmoothScrollTick = 14;
00129 static const int sSmoothScrollMinStaticPixels = 320*200;
00130 
00131 static const int sMaxMissedDeadlines = 12;
00132 static const int sWayTooMany = -1;
00133 
00134 class KHTMLViewPrivate {
00135     friend class KHTMLView;
00136 public:
00137 
00138     enum PseudoFocusNodes {
00139     PFNone,
00140     PFTop,
00141     PFBottom
00142     };
00143 
00144     enum StaticBackgroundState {
00145          SBNone = 0,
00146          SBPartial,
00147          SBFull
00148     };
00149 
00150     enum CompletedState {
00151         CSNone = 0,
00152         CSFull,
00153         CSActionPending
00154     };
00155 
00156     KHTMLViewPrivate(KHTMLView* v)
00157         : underMouse( 0 ), underMouseNonShared( 0 ), oldUnderMouse( 0 )
00158     {
00159         postponed_autorepeat = NULL;
00160         scrollingFromWheelTimerId = 0;
00161         smoothScrollMode = KHTMLView::SSMWhenEfficient;
00162 
00163         reset();
00164         vpolicy = Qt::ScrollBarAsNeeded;
00165     hpolicy = Qt::ScrollBarAsNeeded;
00166         formCompletions=0;
00167         prevScrollbarVisible = true;
00168 
00169         possibleTripleClick = false;
00170         emitCompletedAfterRepaint = CSNone;
00171         cursorIconWidget = 0;
00172         cursorIconType   = KHTMLView::LINK_NORMAL;
00173         m_mouseScrollTimer = 0;
00174         m_mouseScrollIndicator = 0;
00175         contentsX = 0;
00176         contentsY = 0;
00177         view = v;
00178     }
00179     ~KHTMLViewPrivate()
00180     {
00181         delete formCompletions;
00182         delete postponed_autorepeat;
00183         if (underMouse)
00184         underMouse->deref();
00185         if (underMouseNonShared)
00186         underMouseNonShared->deref();
00187         if (oldUnderMouse)
00188             oldUnderMouse->deref();
00189 
00190         delete cursorIconWidget;
00191         delete m_mouseScrollTimer;
00192         delete m_mouseScrollIndicator;
00193     }
00194     void reset()
00195     {
00196         if (underMouse)
00197         underMouse->deref();
00198     underMouse = 0;
00199         if (underMouseNonShared)
00200         underMouseNonShared->deref();
00201     underMouseNonShared = 0;
00202     if (oldUnderMouse)
00203         oldUnderMouse->deref();
00204         oldUnderMouse = 0;
00205         linkPressed = false;
00206         staticWidget = SBNone;
00207         fixedObjectsCount = 0;
00208         staticObjectsCount = 0;
00209     tabMovePending = false;
00210     lastTabbingDirection = true;
00211     pseudoFocusNode = PFNone;
00212     zoomLevel = 100;
00213 #ifndef KHTML_NO_SCROLLBARS
00214         //We don't turn off the toolbars here
00215     //since if the user turns them
00216     //off, then chances are they want them turned
00217     //off always - even after a reset.
00218 #else
00219         vpolicy = ScrollBarAlwaysOff;
00220         hpolicy = ScrollBarAlwaysOff;
00221 #endif
00222         scrollBarMoved = false;
00223         contentsMoving = false;
00224         ignoreWheelEvents = false;
00225         scrollingFromWheel = QPoint(-1,-1);
00226     borderX = 30;
00227     borderY = 30;
00228     dx = dy = ddx = ddy = rdx = rdy = dddx = dddy = 0;
00229         paged = false;
00230     clickX = -1;
00231     clickY = -1;
00232     clickCount = 0;
00233     isDoubleClick = false;
00234     scrollingSelf = false;
00235         delete postponed_autorepeat;
00236         postponed_autorepeat = NULL;
00237     layoutTimerId = 0;
00238         repaintTimerId = 0;
00239         scrollTimerId = 0;
00240         scrollSuspended = false;
00241         scrollSuspendPreActivate = false;
00242         smoothScrolling = false;
00243         smoothScrollModeIsDefault = true;
00244         shouldSmoothScroll = false;
00245         smoothScrollMissedDeadlines = 0;
00246         hasFrameset = false;
00247         complete = false;
00248         firstLayoutPending = true;
00249         firstRepaintPending = true;
00250         needsFullRepaint = true;
00251         dirtyLayout = false;
00252         layoutSchedulingEnabled = true;
00253         painting = false;
00254         layoutCounter = 0;
00255         layoutAttemptCounter = 0;
00256         scheduledLayoutCounter = 0;
00257         updateRegion = QRegion();
00258         m_dialogsAllowed = true;
00259 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00260         typeAheadActivated = false;
00261 #endif // KHTML_NO_TYPE_AHEAD_FIND
00262     accessKeysActivated = false;
00263     accessKeysPreActivate = false;
00264 
00265         // the view might have been built before the part it will be assigned to,
00266         // so exceptionally, we need to directly ref/deref KHTMLGlobal to
00267         // account for this transitory case.
00268         KHTMLGlobal::ref();
00269         accessKeysEnabled = KHTMLGlobal::defaultHTMLSettings()->accessKeysEnabled();
00270         KHTMLGlobal::deref();
00271 
00272         emitCompletedAfterRepaint = CSNone;
00273         m_mouseEventsTarget = 0;
00274         m_clipHolder = 0;
00275     }
00276     void newScrollTimer(QWidget *view, int tid)
00277     {
00278         //kDebug(6000) << "newScrollTimer timer " << tid;
00279         view->killTimer(scrollTimerId);
00280         scrollTimerId = tid;
00281         scrollSuspended = false;
00282     }
00283     enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
00284 
00285     void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
00286     {
00287         static const struct { int msec, pixels; } timings [] = {
00288             {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
00289             {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
00290         };
00291         if (!scrollTimerId ||
00292             (static_cast<int>(scrollDirection) != direction &&
00293              (static_cast<int>(scrollDirection) != oppositedir || scrollSuspended))) {
00294             scrollTiming = 6;
00295             scrollBy = timings[scrollTiming].pixels;
00296             scrollDirection = direction;
00297             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00298         } else if (scrollDirection == direction &&
00299                    timings[scrollTiming+1].msec && !scrollSuspended) {
00300             scrollBy = timings[++scrollTiming].pixels;
00301             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00302         } else if (scrollDirection == oppositedir) {
00303             if (scrollTiming) {
00304                 scrollBy = timings[--scrollTiming].pixels;
00305                 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00306             }
00307         }
00308         scrollSuspended = false;
00309     }
00310 
00311     bool haveZoom() const { return zoomLevel != 100; }
00312 
00313     void startScrolling()
00314     {
00315         smoothScrolling = true;
00316         smoothScrollTimer.start(sSmoothScrollTick);
00317         shouldSmoothScroll = false;
00318     }
00319 
00320     void stopScrolling()
00321     {
00322         smoothScrollTimer.stop();
00323         dx = dy = 0;
00324         ddx = ddy = 0;
00325         rdx = rdy = 0;
00326         dddx = dddy = 0;
00327         updateContentsXY();
00328         smoothScrolling = false;
00329         shouldSmoothScroll = false;
00330     }
00331 
00332     void updateContentsXY()
00333     {
00334         contentsX = QApplication::isRightToLeft() ?
00335                         view->horizontalScrollBar()->maximum()-view->horizontalScrollBar()->value() : view->horizontalScrollBar()->value();
00336         contentsY = view->verticalScrollBar()->value();
00337     }
00338 
00339     void scrollExternalWidgets(int dx, int dy)
00340     {
00341         if (visibleWidgets.isEmpty())
00342             return;
00343 
00344         QHashIterator<void*, QWidget*> it(visibleWidgets);
00345         while (it.hasNext()) {
00346             it.next();
00347             it.value()->move( it.value()->pos() + QPoint(dx, dy) );
00348         }
00349     }
00350 
00351     NodeImpl *underMouse;
00352     NodeImpl *underMouseNonShared;
00353     NodeImpl *oldUnderMouse;
00354 
00355     // Do not adjust bitfield enums sizes.
00356     // They are oversized because they are signed on some platforms.
00357     bool tabMovePending:1;
00358     bool lastTabbingDirection:1;
00359     PseudoFocusNodes pseudoFocusNode:3;
00360     bool scrollBarMoved:1;
00361     bool contentsMoving:1;
00362 
00363     Qt::ScrollBarPolicy vpolicy;
00364     Qt::ScrollBarPolicy hpolicy;
00365     bool prevScrollbarVisible:1;
00366     bool linkPressed:1;
00367     bool ignoreWheelEvents:1;
00368     StaticBackgroundState staticWidget: 3;
00369     int staticObjectsCount;
00370     int fixedObjectsCount;
00371 
00372     int zoomLevel;
00373     int borderX, borderY;
00374     int dx, dy, ddx, ddy, rdx, rdy, dddx, dddy;
00375     KConfig *formCompletions;
00376 
00377     int clickX, clickY, clickCount;
00378     bool isDoubleClick;
00379 
00380     bool paged;
00381 
00382     bool scrollingSelf;
00383     int contentsX, contentsY;
00384     int layoutTimerId;
00385     QKeyEvent* postponed_autorepeat;
00386 
00387     int repaintTimerId;
00388     int scrollTimerId;
00389     int scrollTiming;
00390     int scrollBy;
00391     ScrollDirection scrollDirection     :3;
00392     bool scrollSuspended            :1;
00393     bool scrollSuspendPreActivate       :1;
00394     KHTMLView::SmoothScrollingMode smoothScrollMode :3;
00395     bool smoothScrolling                          :1;
00396     bool smoothScrollModeIsDefault                :1;
00397     bool shouldSmoothScroll                       :1;
00398     bool hasFrameset                              :1;
00399     bool complete               :1;
00400     bool firstLayoutPending         :1;
00401     bool firstRepaintPending                    :1;
00402     bool layoutSchedulingEnabled        :1;
00403     bool needsFullRepaint           :1;
00404     bool painting               :1;
00405     bool possibleTripleClick            :1;
00406     bool dirtyLayout                           :1;
00407     bool m_dialogsAllowed           :1;
00408     short smoothScrollMissedDeadlines;
00409     int layoutCounter;
00410     int layoutAttemptCounter;
00411     int scheduledLayoutCounter;
00412     QRegion updateRegion;
00413     QTimer smoothScrollTimer;
00414     QTime smoothScrollStopwatch;
00415     QHash<void*, QWidget*> visibleWidgets;
00416 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00417     QString findString;
00418     QTimer timer;
00419     bool findLinksOnly;
00420     bool typeAheadActivated;
00421 #endif // KHTML_NO_TYPE_AHEAD_FIND
00422     bool accessKeysEnabled;
00423     bool accessKeysActivated;
00424     bool accessKeysPreActivate;
00425     CompletedState emitCompletedAfterRepaint;
00426 
00427     QLabel*               cursorIconWidget;
00428     KHTMLView::LinkCursor cursorIconType;
00429 
00430     // scrolling activated by MMB
00431     short m_mouseScroll_byX;
00432     short m_mouseScroll_byY;
00433     QPoint scrollingFromWheel;
00434     int scrollingFromWheelTimerId;
00435     QTimer *m_mouseScrollTimer;
00436     QWidget *m_mouseScrollIndicator;
00437     QPointer<QWidget> m_mouseEventsTarget;
00438     QStack<QRegion>* m_clipHolder;
00439     KHTMLView* view;
00440 };
00441 
00442 #ifndef QT_NO_TOOLTIP
00443 
00453 static bool findImageMapRect(HTMLImageElementImpl *img, const QPoint &scrollOfs,
00454             const QPoint &p, QRect &r, QString &s)
00455 {
00456     HTMLMapElementImpl* map;
00457     if (img && img->document()->isHTMLDocument() &&
00458         (map = static_cast<HTMLDocumentImpl*>(img->document())->getMap(img->imageMap()))) {
00459         RenderObject::NodeInfo info(true, false);
00460         RenderObject *rend = img->renderer();
00461         int ax, ay;
00462         if (!rend || !rend->absolutePosition(ax, ay))
00463             return false;
00464         // we're a client side image map
00465         bool inside = map->mapMouseEvent(p.x() - ax + scrollOfs.x(),
00466                 p.y() - ay + scrollOfs.y(), rend->contentWidth(),
00467                 rend->contentHeight(), info);
00468         if (inside && info.URLElement()) {
00469             HTMLAreaElementImpl *area = static_cast<HTMLAreaElementImpl *>(info.URLElement());
00470             Q_ASSERT(area->id() == ID_AREA);
00471             s = area->getAttribute(ATTR_TITLE).string();
00472             QRegion reg = area->cachedRegion();
00473             if (!s.isEmpty() && !reg.isEmpty()) {
00474                 r = reg.boundingRect();
00475                 r.translate(ax, ay);
00476                 return true;
00477             }
00478         }
00479     }
00480     return false;
00481 }
00482 
00483 bool KHTMLView::event( QEvent* e )
00484 {
00485     switch ( e->type() ) {
00486     case QEvent::ToolTip: {
00487         QHelpEvent *he = static_cast<QHelpEvent*>(e);
00488         QPoint     p   = he->pos();
00489 
00490         DOM::NodeImpl *node = d->underMouseNonShared;
00491         QRect region;
00492         while ( node ) {
00493             if ( node->isElementNode() ) {
00494                 DOM::ElementImpl *e = static_cast<DOM::ElementImpl*>( node );
00495                 QRect r;
00496                 QString s;
00497                 bool found = false;
00498                 // for images, check if it is part of a client-side image map,
00499                 // and query the <area>s' title attributes, too
00500                 if (e->id() == ID_IMG && !e->getAttribute( ATTR_USEMAP ).isEmpty()) {
00501                     found = findImageMapRect(static_cast<HTMLImageElementImpl *>(e),
00502                                 viewportToContents(QPoint(0, 0)), p, r, s);
00503                 }
00504                 if (!found) {
00505                     s = e->getAttribute( ATTR_TITLE ).string();
00506                     r = node->getRect();
00507                 }
00508                 region |= QRect( contentsToViewport( r.topLeft() ), r.size() );
00509                 if ( !s.isEmpty() ) {
00510                     QToolTip::showText( he->globalPos(),
00511                         Qt::convertFromPlainText( s, Qt::WhiteSpaceNormal ),
00512                         widget(), region );
00513                     break;
00514                 }
00515             }
00516             node = node->parentNode();
00517         }
00518         // Qt makes tooltip events happen nearly immediately when a preceding one was processed in the past few seconds.
00519         // We don't want that feature to apply to web tootlips however, as it clashes with dhtml menus.
00520         // So we'll just pretend we did not process that event.
00521         return false;
00522     }
00523 
00524     case QEvent::DragEnter:
00525     case QEvent::DragMove:
00526     case QEvent::DragLeave:
00527     case QEvent::Drop:
00528       // In Qt4, one needs to both call accept() on the DND event and return
00529       // true on ::event for the candidate widget for the drop to be possible.
00530       // Apps hosting us, such as konq, can do the former but not the later.
00531       // We will do the second bit, as it's a no-op unless someone else explicitly
00532       // accepts the event. We need to skip the scrollarea to do that,
00533       // since it will just skip the events, both killing the drop, and
00534       // not permitting us to forward it up the part hiearchy in our dragEnterEvent,
00535       // etc. handlers
00536       return QWidget::event(e);
00537     case QEvent::StyleChange:
00538     case QEvent::LayoutRequest: {
00539          updateScrollBars();
00540          return QAbstractScrollArea::event(e);
00541     }
00542     case QEvent::PaletteChange:
00543       slotPaletteChanged();
00544       return QScrollArea::event(e);
00545     default:
00546       return QScrollArea::event(e);
00547     }
00548 }
00549 #endif
00550 
00551 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent )
00552     : QScrollArea( parent ), d( new KHTMLViewPrivate( this ) )
00553 {
00554     m_medium = "screen";
00555 
00556     m_part = part;
00557 
00558     QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
00559     QScrollArea::setHorizontalScrollBarPolicy(d->hpolicy);
00560 
00561 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00562     connect(&d->timer, SIGNAL(timeout()), this, SLOT(findTimeout()));
00563 #endif // KHTML_NO_TYPE_AHEAD_FIND
00564 
00565     init();
00566     widget()->setMouseTracking(true);
00567 }
00568 
00569 KHTMLView::~KHTMLView()
00570 {
00571     closeChildDialogs();
00572     if (m_part)
00573     {
00574         DOM::DocumentImpl *doc = m_part->xmlDocImpl();
00575         if (doc)
00576             doc->detach();
00577     }
00578     delete d;
00579 }
00580 
00581 void KHTMLView::setPart(KHTMLPart *part)
00582 {
00583     assert(part && !m_part);
00584     m_part = part;
00585 }
00586 
00587 void KHTMLView::init()
00588 {
00589     // Do not access the part here. It might not be fully constructed.
00590 
00591     setFrameStyle(QFrame::NoFrame);
00592     setFocusPolicy(Qt::StrongFocus);
00593     viewport()->setFocusProxy(this);
00594 
00595     _marginWidth = -1; // undefined
00596     _marginHeight = -1;
00597     _width = 0;
00598     _height = 0;
00599 
00600     installEventFilter(this);
00601 
00602     setAcceptDrops(true);
00603     if (!widget())
00604         setWidget( new QWidget(this) );
00605     widget()->setAttribute( Qt::WA_NoSystemBackground );
00606 
00607     // Do *not* remove this attribute frivolously.
00608     // You might not notice a change of behaviour in Debug builds
00609     // but removing opaque events will make QWidget::scroll fail horribly
00610     // in Release builds.
00611     widget()->setAttribute( Qt::WA_OpaquePaintEvent );
00612 
00613     verticalScrollBar()->setCursor( Qt::ArrowCursor );
00614     horizontalScrollBar()->setCursor( Qt::ArrowCursor );
00615 
00616     connect(&d->smoothScrollTimer, SIGNAL(timeout()), this, SLOT(scrollTick()));
00617 }
00618 
00619 void KHTMLView::resizeContentsToViewport()
00620 {
00621     QSize s = viewport()->size();
00622     resizeContents(s.width(), s.height());
00623 }
00624 
00625 
00626 // called by KHTMLPart::clear()
00627 void KHTMLView::clear()
00628 {
00629 #ifndef KHTML_NO_TYPE_AHEAD_FIND
00630     if( d->typeAheadActivated )
00631         findTimeout();
00632 #endif
00633     if (d->accessKeysEnabled && d->accessKeysActivated)
00634         accessKeysTimeout();
00635     viewport()->unsetCursor();
00636     if ( d->cursorIconWidget )
00637         d->cursorIconWidget->hide();
00638     if (d->smoothScrolling)
00639         d->stopScrolling();
00640     d->reset();
00641     QAbstractEventDispatcher::instance()->unregisterTimers(this);
00642     emit cleared();
00643 
00644     QScrollArea::setHorizontalScrollBarPolicy(d->hpolicy);
00645     QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
00646     verticalScrollBar()->setEnabled( false );
00647     horizontalScrollBar()->setEnabled( false );
00648 
00649 }
00650 
00651 void KHTMLView::hideEvent(QHideEvent* e)
00652 {
00653     QScrollArea::hideEvent(e);
00654     if ( m_part && m_part->xmlDocImpl() )
00655         m_part->xmlDocImpl()->docLoader()->pauseAnimations();
00656 }
00657 
00658 void KHTMLView::showEvent(QShowEvent* e)
00659 {
00660     QScrollArea::showEvent(e);
00661     if ( m_part && m_part->xmlDocImpl() )
00662         m_part->xmlDocImpl()->docLoader()->resumeAnimations();
00663 }
00664 
00665 void KHTMLView::setMouseEventsTarget( QWidget* w )
00666 {
00667     d->m_mouseEventsTarget = w;
00668 }
00669 
00670 QWidget* KHTMLView::mouseEventsTarget() const
00671 {
00672     return d->m_mouseEventsTarget;
00673 }
00674 
00675 void KHTMLView::setClipHolder( QStack<QRegion>* ch )
00676 {
00677     d->m_clipHolder = ch;
00678 }
00679 
00680 QStack<QRegion>* KHTMLView::clipHolder() const
00681 {
00682     return d->m_clipHolder;
00683 }
00684 
00685 int KHTMLView::contentsWidth() const
00686 {
00687     return widget() ? widget()->width() : 0;
00688 }
00689 
00690 int KHTMLView::contentsHeight() const
00691 {
00692     return widget() ? widget()->height() : 0;
00693 }
00694 
00695 void KHTMLView::resizeContents(int w, int h)
00696 {
00697     if (!widget())
00698         return;
00699     widget()->resize(w, h);
00700     if (!widget()->isVisible())
00701         updateScrollBars();
00702 }
00703 
00704 int KHTMLView::contentsX() const
00705 {
00706     return d->contentsX;
00707 }
00708 
00709 int KHTMLView::contentsY() const
00710 {
00711     return d->contentsY;
00712 }
00713 
00714 int KHTMLView::visibleWidth() const
00715 {
00716     if (m_kwp->isRedirected()) {
00717         // our RenderWidget knows better
00718         if (RenderWidget* rw = m_kwp->renderWidget()) {
00719             int ret = rw->width()-rw->paddingLeft()-rw->paddingRight()-rw->borderLeft()-rw->borderRight();
00720             if (verticalScrollBar()->isVisible()) {
00721                 ret -= verticalScrollBar()->sizeHint().width();
00722                 ret = qMax(0, ret);
00723             }
00724             return ret;
00725         }
00726     }
00727     return viewport()->width();
00728 }
00729 
00730 int KHTMLView::visibleHeight() const
00731 {
00732     if (m_kwp->isRedirected()) {
00733         // our RenderWidget knows better
00734         if (RenderWidget* rw = m_kwp->renderWidget()) {
00735             int ret = rw->height()-rw->paddingBottom()-rw->paddingTop()-rw->borderTop()-rw->borderBottom();
00736             if (horizontalScrollBar()->isVisible()) {
00737                 ret -= horizontalScrollBar()->sizeHint().height();
00738                 ret = qMax(0, ret);
00739             }
00740             return ret;
00741         }
00742     }
00743     return viewport()->height();
00744 }
00745 
00746 void KHTMLView::setContentsPos( int x, int y)
00747 {
00748    horizontalScrollBar()->setValue( QApplication::isRightToLeft() ?
00749                            horizontalScrollBar()->maximum()-x : x );
00750    verticalScrollBar()->setValue( y );
00751 }
00752 
00753 void KHTMLView::scrollBy(int x, int y)
00754 {
00755    if (d->scrollTimerId)
00756        d->newScrollTimer(this, 0);
00757    horizontalScrollBar()->setValue( horizontalScrollBar()->value()+x );
00758    verticalScrollBar()->setValue( verticalScrollBar()->value()+y );
00759 }
00760 
00761 QPoint KHTMLView::contentsToViewport(const QPoint& p) const
00762 {
00763     return QPoint(p.x()-contentsX(), p.y()-contentsY());
00764 }
00765 
00766 void KHTMLView::contentsToViewport(int x, int y, int& cx, int& cy) const
00767 {
00768     QPoint p(x,y);
00769     p = contentsToViewport(p);
00770     cx = p.x();
00771     cy = p.y();
00772 }
00773 
00774 QPoint KHTMLView::viewportToContents(const QPoint& p) const
00775 {
00776     return QPoint(p.x()+contentsX(), p.y()+contentsY());
00777 }
00778 
00779 void KHTMLView::viewportToContents(int x, int y, int& cx, int& cy) const
00780 {
00781     QPoint p(x,y);
00782     p = viewportToContents(p);
00783     cx = p.x();
00784     cy = p.y();
00785 }
00786 
00787 void KHTMLView::updateContents(int x, int y, int w, int h)
00788 {
00789     applyTransforms(x, y, w, h);
00790     if (m_kwp->isRedirected()) {
00791         QPoint off = m_kwp->absolutePos();
00792         KHTMLView* pview = m_part->parentPart()->view();
00793         pview->updateContents(x+off.x(), y+off.y(), w, h);
00794     } else
00795         widget()->update(x, y, w, h);
00796 }
00797 
00798 void KHTMLView::updateContents( const QRect& r )
00799 {
00800     updateContents( r.x(), r.y(), r.width(), r.height() );
00801 }
00802 
00803 void KHTMLView::repaintContents(int x, int y, int w, int h)
00804 {
00805     applyTransforms(x, y, w, h);
00806     if (m_kwp->isRedirected()) {
00807         QPoint off = m_kwp->absolutePos();
00808         KHTMLView* pview = m_part->parentPart()->view();
00809         pview->repaintContents(x+off.x(), y+off.y(), w, h);
00810     } else
00811         widget()->repaint(x, y, w, h);
00812 }
00813 
00814 void KHTMLView::repaintContents( const QRect& r )
00815 {
00816     repaintContents( r.x(), r.y(), r.width(), r.height() );
00817 }
00818 
00819 void KHTMLView::applyTransforms( int& x, int& y, int& w, int& h) const
00820 {
00821     if (d->haveZoom()) {
00822         const int z = d->zoomLevel;
00823         x = x*z/100;
00824         y = y*z/100;
00825         w = w*z/100;
00826         h = h*z/100;
00827     }
00828     x -= contentsX();
00829     y -= contentsY();
00830 }
00831 
00832 void KHTMLView::revertTransforms( int& x, int& y, int& w, int& h) const
00833 {
00834     x += contentsX();
00835     y += contentsY();
00836     if (d->haveZoom()) {
00837         const int z = d->zoomLevel;
00838         x = x*100/z;
00839         y = y*100/z;
00840         w = w*100/z;
00841         h = h*100/z;
00842     }
00843 }
00844 
00845 void KHTMLView::revertTransforms( int& x, int& y ) const
00846 {
00847     int dummy = 0;
00848     revertTransforms(x, y, dummy, dummy);
00849 }
00850 
00851 void KHTMLView::resizeEvent (QResizeEvent* /*e*/)
00852 {
00853     updateScrollBars();
00854 
00855     // If we didn't load anything, make white area as big as the view
00856     if (!m_part->xmlDocImpl())
00857         resizeContentsToViewport();
00858 
00859     // Viewport-dependent media queries may cause us to need completely different style information.
00860     if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->styleSelector()->affectedByViewportChange()) {
00861          m_part->xmlDocImpl()->updateStyleSelector();
00862     }
00863 
00864     if (d->layoutSchedulingEnabled)
00865         layout();
00866 
00867     QApplication::sendPostedEvents(viewport(), QEvent::Paint);
00868 
00869     if ( m_part && m_part->xmlDocImpl() ) {
00870         if (m_part->parentPart()) {
00871             // sub-frame : queue the resize event until our toplevel is done layouting
00872             khtml::ChildFrame *cf = m_part->parentPart()->frame( m_part );
00873             cf->m_partContainerElement->postResizeEvent();
00874         } else {
00875             // toplevel : dispatch sub-frames'resize events before our own
00876             HTMLPartContainerElementImpl::sendPostedResizeEvents();
00877             m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
00878         }
00879     }
00880 }
00881 
00882 void KHTMLView::paintEvent( QPaintEvent *e )
00883 {
00884     QPainter p(widget());
00885 
00886     QRect r = e->rect();
00887     QRect v(contentsX(), contentsY(), visibleWidth(), visibleHeight());
00888     QPoint off(contentsX(),contentsY());
00889     p.translate(-off);
00890     r.translate(off);
00891 
00892     r = r.intersect(v);
00893 
00894     if (!r.isValid() || r.isEmpty()) return;
00895 
00896     if (d->haveZoom()) {
00897         p.scale( d->zoomLevel/100., d->zoomLevel/100.);
00898 
00899         r.setX(r.x()*100/d->zoomLevel);
00900         r.setY(r.y()*100/d->zoomLevel);
00901         r.setWidth(r.width()*100/d->zoomLevel);
00902         r.setHeight(r.height()*100/d->zoomLevel);
00903         r.adjust(-1,-1,1,1);
00904     }
00905     p.setClipRect(r);
00906 
00907     int ex = r.x();
00908     int ey = r.y();
00909     int ew = r.width();
00910     int eh = r.height();
00911 
00912     if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
00913         p.fillRect(ex, ey, ew, eh, palette().brush(QPalette::Active, QPalette::Base));
00914         return;
00915     } else if ( d->complete && static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
00916         // an external update request happens while we have a layout scheduled
00917         unscheduleRelayout();
00918         layout();
00919     } else if (m_part->xmlDocImpl()->tokenizer()) {
00920         m_part->xmlDocImpl()->tokenizer()->setNormalYeldDelay();
00921     }
00922 
00923     if (d->painting) {
00924         kDebug( 6000 ) << "WARNING: paintEvent reentered! ";
00925         kDebug( 6000 ) << kBacktrace();
00926         return;
00927     }
00928     d->painting = true;
00929 
00930     m_part->xmlDocImpl()->renderer()->layer()->paint(&p, r);
00931 
00932     if (d->hasFrameset) {
00933         NodeImpl *body = static_cast<HTMLDocumentImpl*>(m_part->xmlDocImpl())->body();
00934         if(body && body->renderer() && body->id() == ID_FRAMESET)
00935             static_cast<RenderFrameSet*>(body->renderer())->paintFrameSetRules(&p, r);
00936         else
00937             d->hasFrameset = false;
00938     }
00939 
00940     khtml::DrawContentsEvent event( &p, ex, ey, ew, eh );
00941     QApplication::sendEvent( m_part, &event );
00942 
00943     if (d->contentsMoving && !d->smoothScrolling && widget()->underMouse()) {
00944         QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, widget()->mapFromGlobal( QCursor::pos() ),
00945                                               Qt::NoButton, Qt::NoButton, Qt::NoModifier );
00946         QApplication::postEvent(widget(), tempEvent);
00947     }
00948 
00949     d->painting = false;
00950     d->firstRepaintPending = false;
00951 }
00952 
00953 void KHTMLView::setMarginWidth(int w)
00954 {
00955     // make it update the rendering area when set
00956     _marginWidth = w;
00957 }
00958 
00959 void KHTMLView::setMarginHeight(int h)
00960 {
00961     // make it update the rendering area when set
00962     _marginHeight = h;
00963 }
00964 
00965 void KHTMLView::layout()
00966 {
00967     if( m_part && m_part->xmlDocImpl() ) {
00968         DOM::DocumentImpl *document = m_part->xmlDocImpl();
00969 
00970         khtml::RenderCanvas* canvas = static_cast<khtml::RenderCanvas *>(document->renderer());
00971         if ( !canvas ) return;
00972 
00973         d->layoutSchedulingEnabled=false;
00974         d->dirtyLayout = true;
00975 
00976         // the reference object for the overflow property on canvas
00977         RenderObject * ref = 0;
00978         RenderObject* root = document->documentElement() ? document->documentElement()->renderer() : 0;
00979 
00980         if (document->isHTMLDocument()) {
00981              NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
00982              if(body && body->renderer() && body->id() == ID_FRAMESET) {
00983                  QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00984                  QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00985                  body->renderer()->setNeedsLayout(true);
00986                  d->hasFrameset = true;
00987              }
00988              else if (root) // only apply body's overflow to canvas if root has a visible overflow
00989                      ref = (!body || root->style()->hidesOverflow()) ? root : body->renderer();
00990         } else {
00991             ref = root;
00992         }
00993         if (ref) {
00994             if( ref->style()->overflowX() == OHIDDEN ) {
00995                 if (d->hpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00996             } else if (ref->style()->overflowX() == OSCROLL ) {
00997                 if (d->hpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00998             } else if (horizontalScrollBarPolicy() != d->hpolicy) {
00999                 QScrollArea::setHorizontalScrollBarPolicy(d->hpolicy);
01000             }
01001             if ( ref->style()->overflowY() == OHIDDEN ) {
01002                 if (d->vpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01003             } else if (ref->style()->overflowY() == OSCROLL ) {
01004                 if (d->vpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
01005             } else if (verticalScrollBarPolicy() != d->vpolicy) {
01006                 QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
01007             }
01008         }
01009         d->needsFullRepaint = d->firstLayoutPending;
01010         if (_height !=  visibleHeight() || _width != visibleWidth()) {;
01011             d->needsFullRepaint = true;
01012             _height = visibleHeight();
01013             _width = visibleWidth();
01014         }
01015 
01016         canvas->layout();
01017 
01018         emit finishedLayout();
01019         if (d->firstLayoutPending) {
01020             // make sure firstLayoutPending is set to false now in case this layout
01021             // wasn't scheduled
01022             d->firstLayoutPending = false;
01023             verticalScrollBar()->setEnabled( true );
01024             horizontalScrollBar()->setEnabled( true );
01025         }
01026         d->layoutCounter++;
01027 
01028         if (d->accessKeysEnabled && d->accessKeysActivated) {
01029             emit hideAccessKeys();
01030             displayAccessKeys();
01031         }
01032     }
01033     else
01034        _width = visibleWidth();
01035 
01036     if (d->layoutTimerId)
01037         killTimer(d->layoutTimerId);
01038     d->layoutTimerId = 0;
01039     d->layoutSchedulingEnabled=true;
01040 }
01041 
01042 void KHTMLView::closeChildDialogs()
01043 {
01044     QList<QDialog *> dlgs = findChildren<QDialog *>();
01045     foreach (QDialog *dlg, dlgs)
01046     {
01047         KDialog* dlgbase = dynamic_cast<KDialog*>( dlg );
01048         if ( dlgbase ) {
01049             if ( dlgbase->testAttribute( Qt::WA_ShowModal ) ) {
01050                 kDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase;
01051                 // close() ends up calling QButton::animateClick, which isn't immediate
01052                 // we need something the exits the event loop immediately (#49068)
01053                 dlgbase->reject();
01054             }
01055         }
01056         else
01057         {
01058             kWarning() << "closeChildDialogs: not a KDialog! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg);
01059             static_cast<QWidget*>(dlg)->hide();
01060         }
01061     }
01062     d->m_dialogsAllowed = false;
01063 }
01064 
01065 bool KHTMLView::dialogsAllowed() {
01066     bool allowed = d->m_dialogsAllowed;
01067     KHTMLPart* p = m_part->parentPart();
01068     if (p && p->view())
01069         allowed &= p->view()->dialogsAllowed();
01070     return allowed;
01071 }
01072 
01073 void KHTMLView::closeEvent( QCloseEvent* ev )
01074 {
01075     closeChildDialogs();
01076     QScrollArea::closeEvent( ev );
01077 }
01078 
01079 void KHTMLView::setZoomLevel(int percent)
01080 {
01081     percent = percent < 20 ? 20 : (percent > 800 ? 800 : percent);
01082     int oldpercent = d->zoomLevel;
01083     d->zoomLevel = percent;
01084     if (percent != oldpercent) {
01085         if (d->layoutSchedulingEnabled)
01086             layout();
01087         widget()->update();
01088     }
01089 }
01090 
01091 int KHTMLView::zoomLevel() const
01092 {
01093     return d->zoomLevel;
01094 }
01095 
01096 void KHTMLView::setSmoothScrollingMode( SmoothScrollingMode m )
01097 {
01098     d->smoothScrollMode = m;
01099     d->smoothScrollModeIsDefault = false;
01100     if (d->smoothScrolling && !m)
01101         d->stopScrolling();
01102 }
01103 
01104 void KHTMLView::setSmoothScrollingModeDefault( SmoothScrollingMode m )
01105 {
01106     // check for manual override
01107     if (!d->smoothScrollModeIsDefault)
01108         return;
01109     d->smoothScrollMode = m;
01110     if (d->smoothScrolling && !m)
01111         d->stopScrolling();
01112 }
01113 
01114 KHTMLView::SmoothScrollingMode KHTMLView::smoothScrollingMode( ) const
01115 {
01116     return d->smoothScrollMode;
01117 }
01118 
01119 //
01120 // Event Handling
01121 //
01123 
01124 void KHTMLView::mousePressEvent( QMouseEvent *_mouse )
01125 {
01126     if (!m_part->xmlDocImpl()) return;
01127     if (d->possibleTripleClick && ( _mouse->button() & Qt::MouseButtonMask ) == Qt::LeftButton)
01128     {
01129         mouseDoubleClickEvent( _mouse ); // it handles triple clicks too
01130         return;
01131     }
01132 
01133     int xm = _mouse->x();
01134     int ym = _mouse->y();
01135     revertTransforms(xm, ym);
01136 
01137     // kDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()-contentsX()<<"/"<<_mouse->y()-contentsY()<<"), contents=(" << xm << "/" << ym << ")\n";
01138 
01139     d->isDoubleClick = false;
01140 
01141     DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MousePress );
01142     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
01143 
01144     //kDebug(6000) << "innerNode="<<mev.innerNode.nodeName().string();
01145 
01146     if ( (_mouse->button() == Qt::MidButton) &&
01147           !m_part->d->m_bOpenMiddleClick && !d->m_mouseScrollTimer &&
01148           mev.url.isNull() && (mev.innerNode.elementId() != ID_INPUT) ) {
01149         QPoint point = mapFromGlobal( _mouse->globalPos() );
01150 
01151         d->m_mouseScroll_byX = 0;
01152         d->m_mouseScroll_byY = 0;
01153 
01154         d->m_mouseScrollTimer = new QTimer( this );
01155         connect( d->m_mouseScrollTimer, SIGNAL(timeout()), this, SLOT(slotMouseScrollTimer()) );
01156 
01157         if ( !d->m_mouseScrollIndicator ) {
01158             QPixmap pixmap( 48, 48 ), icon;
01159             pixmap.fill( QColor( qRgba( 127, 127, 127, 127 ) ) );
01160 
01161             QPainter p( &pixmap );
01162             QStyleOption option;
01163 
01164             option.rect.setRect( 16, 0, 16, 16 );
01165             QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowUp, &option, &p );
01166             option.rect.setRect( 0, 16, 16, 16 );
01167             QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowLeft, &option, &p );
01168             option.rect.setRect( 16, 32, 16, 16 );
01169             QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowDown, &option, &p );
01170             option.rect.setRect( 32, 16, 16, 16 );
01171             QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowRight, &option, &p );
01172             p.drawEllipse( 23, 23, 2, 2 );
01173 
01174             d->m_mouseScrollIndicator = new QWidget( this );
01175             d->m_mouseScrollIndicator->setFixedSize( 48, 48 );
01176             QPalette palette;
01177             palette.setBrush( d->m_mouseScrollIndicator->backgroundRole(), QBrush( pixmap ) );
01178             d->m_mouseScrollIndicator->setPalette( palette );
01179         }
01180         d->m_mouseScrollIndicator->move( point.x()-24, point.y()-24 );
01181 
01182         bool hasHorBar = visibleWidth() < contentsWidth();
01183         bool hasVerBar = visibleHeight() < contentsHeight();
01184 
01185         KConfigGroup cg( KGlobal::config(), "HTML Settings" );
01186         if ( cg.readEntry( "ShowMouseScrollIndicator", true ) ) {
01187             d->m_mouseScrollIndicator->show();
01188             d->m_mouseScrollIndicator->unsetCursor();
01189 
01190             QBitmap mask = d->m_mouseScrollIndicator->palette().brush(d->m_mouseScrollIndicator->backgroundRole()).texture().createHeuristicMask( true );
01191 
01192         if ( hasHorBar && !hasVerBar ) {
01193                 QBitmap bm( 16, 16 );
01194                 bm.clear();
01195                 QPainter painter( &mask );
01196                 painter.drawPixmap( QRectF( 16, 0, bm.width(), bm.height() ), bm, bm.rect() );
01197                 painter.drawPixmap( QRectF( 16, 32, bm.width(), bm.height() ), bm, bm.rect() );
01198                 d->m_mouseScrollIndicator->setCursor( Qt::SizeHorCursor );
01199             }
01200             else if ( !hasHorBar && hasVerBar ) {
01201                 QBitmap bm( 16, 16 );
01202                 bm.clear();
01203                 QPainter painter( &mask );
01204                 painter.drawPixmap( QRectF( 0, 16, bm.width(), bm.height() ), bm, bm.rect() );
01205                 painter.drawPixmap( QRectF( 32, 16, bm.width(), bm.height() ), bm, bm.rect() );
01206                 d->m_mouseScrollIndicator->setCursor( Qt::SizeVerCursor );
01207             }
01208             else
01209                 d->m_mouseScrollIndicator->setCursor( Qt::SizeAllCursor );
01210 
01211             d->m_mouseScrollIndicator->setMask( mask );
01212         }
01213         else {
01214             if ( hasHorBar && !hasVerBar )
01215                 viewport()->setCursor( Qt::SizeHorCursor );
01216             else if ( !hasHorBar && hasVerBar )
01217                 viewport()->setCursor( Qt::SizeVerCursor );
01218             else
01219                 viewport()->setCursor( Qt::SizeAllCursor );
01220         }
01221 
01222         return;
01223     }
01224     else if ( d->m_mouseScrollTimer ) {
01225         delete d->m_mouseScrollTimer;
01226         d->m_mouseScrollTimer = 0;
01227 
01228         if ( d->m_mouseScrollIndicator )
01229             d->m_mouseScrollIndicator->hide();
01230     }
01231 
01232     if (d->clickCount > 0 &&
01233         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
01234         d->clickCount++;
01235     else {
01236         d->clickCount = 1;
01237         d->clickX = xm;
01238         d->clickY = ym;
01239     }
01240 
01241     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
01242                                            d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
01243 
01244     if (!swallowEvent) {
01245     emit m_part->nodeActivated(mev.innerNode);
01246 
01247     khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
01248         QApplication::sendEvent( m_part, &event );
01249         // we might be deleted after this
01250     }
01251 }
01252 
01253 void KHTMLView::mouseDoubleClickEvent( QMouseEvent *_mouse )
01254 {
01255     if(!m_part->xmlDocImpl()) return;
01256 
01257     int xm = _mouse->x();
01258     int ym = _mouse->y();
01259     revertTransforms(xm, ym);
01260 
01261     // kDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym;
01262 
01263     d->isDoubleClick = true;
01264 
01265     DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseDblClick );
01266     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
01267 
01268     // We do the same thing as mousePressEvent() here, since the DOM does not treat
01269     // single and double-click events as separate (only the detail, i.e. number of clicks differs)
01270     if (d->clickCount > 0 &&
01271         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
01272     d->clickCount++;
01273     else { // shouldn't happen, if Qt has the same criterias for double clicks.
01274     d->clickCount = 1;
01275     d->clickX = xm;
01276     d->clickY = ym;
01277     }
01278     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
01279                                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
01280 
01281     if (!swallowEvent) {
01282     khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
01283     QApplication::sendEvent( m_part, &event );
01284     }
01285 
01286     d->possibleTripleClick=true;
01287     QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
01288 }
01289 
01290 void KHTMLView::tripleClickTimeout()
01291 {
01292     d->possibleTripleClick = false;
01293     d->clickCount = 0;
01294 }
01295 
01296 static bool targetOpensNewWindow(KHTMLPart *part, QString target)
01297 {
01298     if (!target.isEmpty() && (target.toLower() != "_top") &&
01299        (target.toLower() != "_self") && (target.toLower() != "_parent")) {
01300         if (target.toLower() == "_blank")
01301             return true;
01302         else {
01303             while (part->parentPart())
01304                 part = part->parentPart();
01305             if (!part->frameExists(target))
01306                 return true;
01307         }
01308     }
01309     return false;
01310 }
01311 
01312 void KHTMLView::mouseMoveEvent( QMouseEvent * _mouse )
01313 {
01314     if ( d->m_mouseScrollTimer ) {
01315         QPoint point = mapFromGlobal( _mouse->globalPos() );
01316 
01317         int deltaX = point.x() - d->m_mouseScrollIndicator->x() - 24;
01318         int deltaY = point.y() - d->m_mouseScrollIndicator->y() - 24;
01319 
01320         (deltaX > 0) ? d->m_mouseScroll_byX = 1 : d->m_mouseScroll_byX = -1;
01321         (deltaY > 0) ? d->m_mouseScroll_byY = 1 : d->m_mouseScroll_byY = -1;
01322 
01323         double adX = qAbs(deltaX)/30.0;
01324         double adY = qAbs(deltaY)/30.0;
01325 
01326         d->m_mouseScroll_byX = qMax(qMin(d->m_mouseScroll_byX * int(adX*adX), SHRT_MAX), SHRT_MIN);
01327         d->m_mouseScroll_byY = qMax(qMin(d->m_mouseScroll_byY * int(adY*adY), SHRT_MAX), SHRT_MIN);
01328 
01329         if (d->m_mouseScroll_byX == 0 && d->m_mouseScroll_byY == 0) {
01330             d->m_mouseScrollTimer->stop();
01331         }
01332         else if (!d->m_mouseScrollTimer->isActive()) {
01333             d->m_mouseScrollTimer->start( 20 );
01334         }
01335     }
01336 
01337     if(!m_part->xmlDocImpl()) return;
01338 
01339     int xm = _mouse->x();
01340     int ym = _mouse->y();
01341     revertTransforms(xm, ym);
01342 
01343     DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseMove );
01344     // Do not modify :hover/:active state while mouse is pressed.
01345     m_part->xmlDocImpl()->prepareMouseEvent( _mouse->buttons() /*readonly ?*/, xm, ym, &mev );
01346 
01347     // kDebug(6000) << "mouse move: " << _mouse->pos()
01348     //        << " button " << _mouse->button()
01349     //        << " state " << _mouse->state() << endl;
01350 
01351     DOM::NodeImpl* target = mev.innerNode.handle();
01352     DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
01353 
01354     // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
01355     if (d->m_mouseEventsTarget && fn && fn->renderer() && fn->renderer()->isWidget())
01356        target = fn;
01357 
01358     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,target,mev.innerNonSharedNode.handle(),false,
01359                                            0,_mouse,true,DOM::NodeImpl::MouseMove);
01360 
01361     if (d->clickCount > 0 &&
01362         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
01363     d->clickCount = 0;  // moving the mouse outside the threshold invalidates the click
01364     }
01365 
01366     khtml::RenderObject* r = target ? target->renderer() : 0;
01367     bool setCursor = true;
01368     bool forceDefault = false;
01369     if (r && r->isWidget()) { 
01370         RenderWidget* rw = static_cast<RenderWidget*>(r);
01371         KHTMLWidget* kw = qobject_cast<KHTMLView*>(rw->widget())? dynamic_cast<KHTMLWidget*>(rw->widget()) : 0;
01372         if (kw && kw->m_kwp->isRedirected())
01373             setCursor = false;
01374         else if (QLineEdit* le = qobject_cast<QLineEdit*>(rw->widget())) {
01375             QList<QWidget*> wl = qFindChildren<QWidget *>( le, "KHTMLLineEditButton" );
01376             // force arrow cursor above lineedit clear button
01377             foreach (QWidget*w, wl) {
01378                 if (w->underMouse()) {
01379                     forceDefault = true;
01380                     break;
01381                 }
01382             }
01383         }
01384     }
01385     khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
01386     QCursor c;
01387     LinkCursor linkCursor = LINK_NORMAL;
01388     switch (!forceDefault ? (style ? style->cursor() : CURSOR_AUTO) : CURSOR_DEFAULT) {
01389     case CURSOR_AUTO:
01390         if ( r && r->isText() && !r->isPointInsideSelection(xm, ym, m_part->caret()) )
01391             c = QCursor(Qt::IBeamCursor);
01392         if ( mev.url.length() && m_part->settings()->changeCursor() ) {
01393             c = m_part->urlCursor();
01394         if (mev.url.string().startsWith("mailto:") && mev.url.string().indexOf('@')>0)
01395               linkCursor = LINK_MAILTO;
01396             else
01397               if ( targetOpensNewWindow( m_part, mev.target.string() ) )
01398             linkCursor = LINK_NEWWINDOW;
01399         }
01400 
01401         if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
01402             c = QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
01403 
01404         break;
01405     case CURSOR_CROSS:
01406         c = QCursor(Qt::CrossCursor);
01407         break;
01408     case CURSOR_POINTER:
01409         c = m_part->urlCursor();
01410     if (mev.url.string().startsWith("mailto:") && mev.url.string().indexOf('@')>0)
01411           linkCursor = LINK_MAILTO;
01412         else
01413           if ( targetOpensNewWindow( m_part, mev.target.string() ) )
01414         linkCursor = LINK_NEWWINDOW;
01415         break;
01416     case CURSOR_PROGRESS:
01417         c = QCursor(Qt::BusyCursor); // working_cursor
01418         break;
01419     case CURSOR_MOVE:
01420     case CURSOR_ALL_SCROLL:
01421         c = QCursor(Qt::SizeAllCursor);
01422         break;
01423     case CURSOR_E_RESIZE:
01424     case CURSOR_W_RESIZE:
01425     case CURSOR_EW_RESIZE:
01426         c = QCursor(Qt::SizeHorCursor);
01427         break;
01428     case CURSOR_N_RESIZE:
01429     case CURSOR_S_RESIZE:
01430     case CURSOR_NS_RESIZE:
01431         c = QCursor(Qt::SizeVerCursor);
01432         break;
01433     case CURSOR_NE_RESIZE:
01434     case CURSOR_SW_RESIZE:
01435     case CURSOR_NESW_RESIZE:
01436         c = QCursor(Qt::SizeBDiagCursor);
01437         break;
01438     case CURSOR_NW_RESIZE:
01439     case CURSOR_SE_RESIZE:
01440     case CURSOR_NWSE_RESIZE:
01441         c = QCursor(Qt::SizeFDiagCursor);
01442         break;
01443     case CURSOR_TEXT:
01444         c = QCursor(Qt::IBeamCursor);
01445         break;
01446     case CURSOR_WAIT:
01447         c = QCursor(Qt::WaitCursor);
01448         break;
01449     case CURSOR_HELP:
01450         c = QCursor(Qt::WhatsThisCursor);
01451         break;
01452     case CURSOR_DEFAULT:
01453         break;
01454     case CURSOR_NONE:
01455     case CURSOR_NOT_ALLOWED:
01456         c = QCursor(Qt::ForbiddenCursor);
01457         break;
01458     case CURSOR_ROW_RESIZE:
01459         c = QCursor(Qt::SplitVCursor);
01460         break;
01461     case CURSOR_COL_RESIZE:
01462         c = QCursor(Qt::SplitHCursor);
01463         break;
01464     case CURSOR_VERTICAL_TEXT:
01465     case CURSOR_CONTEXT_MENU:
01466     case CURSOR_NO_DROP:
01467     case CURSOR_CELL:
01468     case CURSOR_COPY:
01469     case CURSOR_ALIAS:
01470         c = QCursor(Qt::ArrowCursor);
01471         break;
01472     }
01473 
01474     if (!setCursor && style && style->cursor() != CURSOR_AUTO)
01475         setCursor = true;
01476 
01477     QWidget* vp = viewport();
01478     for (KHTMLPart* p = m_part; p; p = p->parentPart())
01479         if (!p->parentPart())
01480             vp = p->view()->viewport();
01481     if ( setCursor && vp->cursor().handle() != c.handle() ) {
01482         if( c.shape() == Qt::ArrowCursor) {
01483             for (KHTMLPart* p = m_part; p; p = p->parentPart())
01484                 p->view()->viewport()->unsetCursor();
01485         }
01486         else {
01487             vp->setCursor( c );
01488         }
01489     }
01490 
01491     if ( linkCursor!=LINK_NORMAL && isVisible() && hasFocus() ) {
01492 #ifdef Q_WS_X11
01493 
01494         if( !d->cursorIconWidget ) {
01495 #ifdef Q_WS_X11
01496             d->cursorIconWidget = new QLabel( 0, Qt::X11BypassWindowManagerHint );
01497             XSetWindowAttributes attr;
01498             attr.save_under = True;
01499             XChangeWindowAttributes( QX11Info::display(), d->cursorIconWidget->winId(), CWSaveUnder, &attr );
01500 #else
01501             d->cursorIconWidget = new QLabel( NULL, NULL );
01502             //TODO
01503 #endif
01504         }
01505 
01506         // Update the pixmap if need be.
01507         if (linkCursor != d->cursorIconType) {
01508             d->cursorIconType = linkCursor;
01509             QString cursorIcon;
01510             switch (linkCursor)
01511             {
01512               case LINK_MAILTO:     cursorIcon = "mail-message-new"; break;
01513               case LINK_NEWWINDOW:  cursorIcon = "window-new";       break;
01514               default:              cursorIcon = "dialog-error";     break;
01515             }
01516 
01517             QPixmap icon_pixmap = KHTMLGlobal::iconLoader()->loadIcon( cursorIcon, KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(), 0, true );
01518 
01519             d->cursorIconWidget->resize( icon_pixmap.width(), icon_pixmap.height());
01520             d->cursorIconWidget->setMask( icon_pixmap.createMaskFromColor(Qt::transparent));
01521             d->cursorIconWidget->setPixmap( icon_pixmap);
01522             d->cursorIconWidget->update();
01523         }
01524 
01525         QPoint c_pos = QCursor::pos();
01526         d->cursorIconWidget->move( c_pos.x() + 15, c_pos.y() + 15 );
01527 #ifdef Q_WS_X11
01528         XRaiseWindow( QX11Info::display(), d->cursorIconWidget->winId());
01529         QApplication::flush();
01530 #elif defined(Q_WS_WIN)
01531         SetWindowPos( d->cursorIconWidget->winId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
01532 #else
01533         //TODO?
01534 #endif
01535         d->cursorIconWidget->show();
01536 #endif
01537     }
01538     else if ( d->cursorIconWidget )
01539         d->cursorIconWidget->hide();
01540 
01541     if (r && r->isWidget()) {
01542     _mouse->ignore();
01543     }
01544 
01545     if (!swallowEvent) {
01546         khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
01547         QApplication::sendEvent( m_part, &event );
01548     }
01549 }
01550 
01551 void KHTMLView::mouseReleaseEvent( QMouseEvent * _mouse )
01552 {
01553     bool swallowEvent = false;
01554 
01555     int xm = _mouse->x();
01556     int ym = _mouse->y();
01557     revertTransforms(xm, ym);
01558 
01559     DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseRelease );
01560 
01561     if ( m_part->xmlDocImpl() )
01562     {
01563         m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
01564 
01565         DOM::NodeImpl* target = mev.innerNode.handle();
01566         DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
01567 
01568         // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
01569         if (d->m_mouseEventsTarget && fn && fn->renderer() && fn->renderer()->isWidget())
01570             target = fn;
01571 
01572         swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,target,mev.innerNonSharedNode.handle(),true,
01573                                           d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
01574 
01575         // clear our sticky event target on any mouseRelease event
01576         if (d->m_mouseEventsTarget)
01577             d->m_mouseEventsTarget = 0;
01578 
01579         if (d->clickCount > 0 &&
01580             QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
01581             QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
01582                            _mouse->pos(), _mouse->button(), _mouse->buttons(), _mouse->modifiers());
01583             dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
01584                                d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
01585         }
01586 
01587         khtml::RenderObject* r = target ? target->renderer() : 0;
01588         if (r && r->isWidget())
01589             _mouse->ignore();
01590     }
01591 
01592     if (!swallowEvent) {
01593     khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
01594     QApplication::sendEvent( m_part, &event );
01595     }
01596 }
01597 
01598 // returns true if event should be swallowed
01599 bool KHTMLView::dispatchKeyEvent( QKeyEvent *_ke )
01600 {
01601     if (!m_part->xmlDocImpl())
01602         return false;
01603     // Pressing and releasing a key should generate keydown, keypress and keyup events
01604     // Holding it down should generated keydown, keypress (repeatedly) and keyup events
01605     // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
01606     // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
01607     // of the Qt events shouldn't be passed to DOM, but it should be still filtered
01608     // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
01609     // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
01610     // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
01611     // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
01612     // The solution is to filter out and postpone the Qt autorepeat keyrelease until
01613     // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
01614     // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
01615     // again, and here it will be ignored.
01616     //
01617     //  Qt:      Press      | Release(autorepeat) Press(autorepeat) etc. |   Release
01618     //  DOM:   Down + Press |      (nothing)           Press             |     Up
01619 
01620     // It's also possible to get only Releases. E.g. the release of alt-tab,
01621     // or when the keypresses get captured by an accel.
01622 
01623     if( _ke == d->postponed_autorepeat ) // replayed event
01624     {
01625         return false;
01626     }
01627 
01628     if( _ke->type() == QEvent::KeyPress )
01629     {
01630         if( !_ke->isAutoRepeat())
01631         {
01632             bool ret = dispatchKeyEventHelper( _ke, false ); // keydown
01633             // don't send keypress even if keydown was blocked, like IE (and unlike Mozilla)
01634             if( !ret && dispatchKeyEventHelper( _ke, true )) // keypress
01635                 ret = true;
01636             return ret;
01637         }
01638         else // autorepeat
01639         {
01640             bool ret = dispatchKeyEventHelper( _ke, true ); // keypress
01641             if( !ret && d->postponed_autorepeat )
01642                 keyPressEvent( d->postponed_autorepeat );
01643             delete d->postponed_autorepeat;
01644             d->postponed_autorepeat = NULL;
01645             return ret;
01646         }
01647     }
01648     else // QEvent::KeyRelease
01649     {
01650         // Discard postponed "autorepeat key-release" events that didn't see
01651         // a keypress after them (e.g. due to QAccel)
01652         if ( d->postponed_autorepeat ) {
01653             delete d->postponed_autorepeat;
01654             d->postponed_autorepeat = 0;
01655         }
01656 
01657         if( !_ke->isAutoRepeat()) {
01658             return dispatchKeyEventHelper( _ke, false ); // keyup
01659         }
01660         else
01661         {
01662             d->postponed_autorepeat = new QKeyEvent( _ke->type(), _ke->key(), _ke->modifiers(),
01663                 _ke->text(), _ke->isAutoRepeat(), _ke->count());
01664             if( _ke->isAccepted())
01665                 d->postponed_autorepeat->accept();
01666             else
01667                 d->postponed_autorepeat->ignore();
01668             return true;
01669         }
01670     }
01671 }
01672 
01673 // returns true if event should be swallowed
01674 bool KHTMLView::dispatchKeyEventHelper( QKeyEvent *_ke, bool keypress )
01675 {
01676     DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
01677     if (keyNode) {
01678         return keyNode->dispatchKeyEvent(_ke, keypress);
01679     } else { // no focused node, send to document
01680         return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
01681     }
01682 }
01683 
01684 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
01685 {
01686 #ifndef KHTML_NO_TYPE_AHEAD_FIND
01687     if(d->typeAheadActivated)
01688     {
01689         // type-ahead find aka find-as-you-type
01690         if(_ke->key() == Qt::Key_Backspace)
01691         {
01692             d->findString = d->findString.left(d->findString.length() - 1);
01693 
01694             if(!d->findString.isEmpty())
01695             {
01696                 findAhead(false);
01697             }
01698             else
01699             {
01700                 findTimeout();
01701             }
01702 
01703             d->timer.setSingleShot(true);
01704             d->timer.start(3000);
01705             _ke->accept();
01706             return;
01707         }
01708         else if(_ke->key() == Qt::Key_Escape)
01709         {
01710             findTimeout();
01711 
01712             _ke->accept();
01713             return;
01714         }
01715         else if(_ke->key() == Qt::Key_Space || !_ke->text().trimmed().isEmpty())
01716         {
01717             d->findString += _ke->text();
01718 
01719             findAhead(true);
01720 
01721             d->timer.setSingleShot(true);
01722             d->timer.start(3000);
01723             _ke->accept();
01724             return;
01725         }
01726     }
01727 #endif // KHTML_NO_TYPE_AHEAD_FIND
01728 
01729     // If CTRL was hit, be prepared for access keys
01730     if (d->accessKeysEnabled && _ke->key() == Qt::Key_Control && !(_ke->modifiers() & ~Qt::ControlModifier) && !d->accessKeysActivated)
01731     {
01732         d->accessKeysPreActivate=true;
01733         _ke->accept();
01734         return;
01735     }
01736 
01737     if (_ke->key() == Qt::Key_Shift && !(_ke->modifiers() & ~Qt::ShiftModifier))
01738         d->scrollSuspendPreActivate=true;
01739 
01740     // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
01741     // may eat the event
01742 
01743     if (d->accessKeysEnabled && d->accessKeysActivated)
01744     {
01745         int state = ( _ke->modifiers() & ( Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier ));
01746         if ( state==0 || state==Qt::ShiftModifier) {
01747     if (_ke->key() != Qt::Key_Shift) accessKeysTimeout();
01748         handleAccessKey( _ke );
01749         _ke->accept();
01750         return;
01751         }
01752     accessKeysTimeout();
01753     }
01754 
01755     if ( dispatchKeyEvent( _ke )) {
01756         // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
01757         _ke->accept();
01758         return;
01759     }
01760 
01761     int offs = (viewport()->height() < 30) ? viewport()->height() : 30; // ### ??
01762     if (_ke->modifiers() & Qt::ShiftModifier)
01763       switch(_ke->key())
01764         {
01765         case Qt::Key_Space:
01766             verticalScrollBar()->setValue( verticalScrollBar()->value() -viewport()->height() + offs );
01767             if(d->scrollSuspended)
01768                 d->newScrollTimer(this, 0);
01769             break;
01770 
01771         case Qt::Key_Down:
01772         case Qt::Key_J:
01773             d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
01774             break;
01775 
01776         case Qt::Key_Up:
01777         case Qt::Key_K:
01778             d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
01779             break;
01780 
01781         case Qt::Key_Left:
01782         case Qt::Key_H:
01783             d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
01784             break;
01785 
01786         case Qt::Key_Right:
01787         case Qt::Key_L:
01788             d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
01789             break;
01790         }
01791     else
01792         switch ( _ke->key() )
01793         {
01794         case Qt::Key_Down:
01795         case Qt::Key_J:
01796             if (!d->scrollTimerId || d->scrollSuspended)
01797                 verticalScrollBar()->setValue( verticalScrollBar()->value()+10 );
01798             if (d->scrollTimerId)
01799                 d->newScrollTimer(this, 0);
01800             break;
01801 
01802         case Qt::Key_Space:
01803         case Qt::Key_PageDown:
01804         d->shouldSmoothScroll = true;
01805             verticalScrollBar()->setValue( verticalScrollBar()->value() +viewport()->height() - offs );
01806             if(d->scrollSuspended)
01807                 d->newScrollTimer(this, 0);
01808             break;
01809 
01810         case Qt::Key_Up:
01811         case Qt::Key_K:
01812             if (!d->scrollTimerId || d->scrollSuspended)
01813                 verticalScrollBar()->setValue( verticalScrollBar()->value()-10 );
01814             if (d->scrollTimerId)
01815                 d->newScrollTimer(this, 0);
01816             break;
01817 
01818         case Qt::Key_PageUp:
01819         d->shouldSmoothScroll = true;
01820             verticalScrollBar()->setValue( verticalScrollBar()->value() -viewport()->height() + offs );
01821             if(d->scrollSuspended)
01822                 d->newScrollTimer(this, 0);
01823             break;
01824         case Qt::Key_Right:
01825         case Qt::Key_L:
01826             if (!d->scrollTimerId || d->scrollSuspended)
01827                  horizontalScrollBar()->setValue( horizontalScrollBar()->value()+10 );
01828             if (d->scrollTimerId)
01829                 d->newScrollTimer(this, 0);
01830             break;
01831 
01832         case Qt::Key_Left:
01833         case Qt::Key_H:
01834             if (!d->scrollTimerId || d->scrollSuspended)
01835                 horizontalScrollBar()->setValue( horizontalScrollBar()->value()-10 );
01836             if (d->scrollTimerId)
01837                 d->newScrollTimer(this, 0);
01838             break;
01839         case Qt::Key_Enter:
01840         case Qt::Key_Return:
01841         // ### FIXME:
01842         // or even better to HTMLAnchorElementImpl::event()
01843             if (m_part->xmlDocImpl()) {
01844         NodeImpl *n = m_part->xmlDocImpl()->focusNode();
01845         if (n)
01846             n->setActive();
01847         }
01848             break;
01849         case Qt::Key_Home:
01850             verticalScrollBar()->setValue( 0 );
01851             horizontalScrollBar()->setValue( 0 );
01852             if(d->scrollSuspended)
01853                 d->newScrollTimer(this, 0);
01854             break;
01855         case Qt::Key_End:
01856             verticalScrollBar()->setValue( contentsHeight() - visibleHeight() );
01857             if(d->scrollSuspended)
01858                 d->newScrollTimer(this, 0);
01859             break;
01860         case Qt::Key_Shift:
01861             // what are you doing here?
01862         _ke->ignore();
01863             return;
01864         default:
01865             if (d->scrollTimerId)
01866                 d->newScrollTimer(this, 0);
01867         _ke->ignore();
01868             return;
01869         }
01870 
01871     _ke->accept();
01872 }
01873 
01874 void KHTMLView::findTimeout()
01875 {
01876 #ifndef KHTML_NO_TYPE_AHEAD_FIND
01877     d->typeAheadActivated = false;
01878     d->findString = "";
01879     m_part->setStatusBarText(i18n("Find stopped."), KHTMLPart::BarDefaultText);
01880     m_part->enableFindAheadActions( true );
01881 #endif // KHTML_NO_TYPE_AHEAD_FIND
01882 }
01883 
01884 #ifndef KHTML_NO_TYPE_AHEAD_FIND
01885 void KHTMLView::startFindAhead( bool linksOnly )
01886 {
01887     if( linksOnly )
01888     {
01889         d->findLinksOnly = true;
01890         m_part->setStatusBarText(i18n("Starting -- find links as you type"),
01891                                  KHTMLPart::BarDefaultText);
01892     }
01893     else
01894     {
01895         d->findLinksOnly = false;
01896         m_part->setStatusBarText(i18n("Starting -- find text as you type"),
01897                                  KHTMLPart::BarDefaultText);
01898     }
01899 
01900     m_part->findTextBegin();
01901     d->typeAheadActivated = true;
01902         // disable, so that the shortcut ( / or ' by default ) doesn't interfere
01903     m_part->enableFindAheadActions( false );
01904     d->timer.setSingleShot(true);
01905     d->timer.start(3000);
01906 }
01907 
01908 void KHTMLView::findAhead(bool increase)
01909 {
01910     QString status;
01911     QString text = d->findString.toLower();
01912 
01913     if(d->findLinksOnly)
01914     {
01915         m_part->findText(d->findString, KHTMLPart::FindNoPopups |
01916                          KHTMLPart::FindLinksOnly, this);
01917         if(m_part->findTextNext())
01918         {
01919             status = i18n("Link found: \"%1\".", Qt::escape(text));
01920         }
01921         else
01922         {
01923             if(increase) KNotification::beep();
01924             status = i18n("Link not found: \"%1\".", Qt::escape(text));
01925         }
01926     }
01927     else
01928     {
01929         m_part->findText(d->findString, KHTMLPart::FindNoPopups, this);
01930         if(m_part->findTextNext())
01931         {
01932             status = i18n("Text found: \"%1\".", Qt::escape(text));
01933         }
01934         else
01935         {
01936             if(increase) KNotification::beep();
01937             status = i18n("Text not found: \"%1\".", Qt::escape(text));
01938         }
01939     }
01940 
01941     // Note: we need to escape -twice-: the above just escape for i18n, now we need to do it for Qt, too.
01942     m_part->setStatusBarText(Qt::escape(status), KHTMLPart::BarDefaultText);
01943 }
01944 
01945 void KHTMLView::updateFindAheadTimeout()
01946 {
01947     if( d->typeAheadActivated ) {
01948         d->timer.setSingleShot( true );
01949         d->timer.start( 3000 );
01950     }
01951 }
01952 
01953 #endif // KHTML_NO_TYPE_AHEAD_FIND
01954 
01955 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
01956 {
01957 #ifndef KHTML_NO_TYPE_AHEAD_FIND
01958     if(d->typeAheadActivated) {
01959         _ke->accept();
01960         return;
01961     }
01962 #endif
01963 
01964     if( d->scrollSuspendPreActivate && _ke->key() != Qt::Key_Shift )
01965         d->scrollSuspendPreActivate = false;
01966     if( _ke->key() == Qt::Key_Shift && d->scrollSuspendPreActivate && !(_ke->modifiers() & Qt::ShiftModifier))
01967         if (d->scrollTimerId) {
01968                 d->scrollSuspended = !d->scrollSuspended;
01969                 if (d->scrollSuspended)
01970                     d->stopScrolling();
01971         }
01972 
01973     if (d->accessKeysEnabled)
01974     {
01975         if (d->accessKeysPreActivate && _ke->key() != Qt::Key_Control)
01976             d->accessKeysPreActivate=false;
01977         if (d->accessKeysPreActivate && !(_ke->modifiers() & Qt::ControlModifier))
01978         {
01979         displayAccessKeys();
01980         m_part->setStatusBarText(i18n("Access Keys activated"),KHTMLPart::BarOverrideText);
01981         d->accessKeysActivated = true;
01982         d->accessKeysPreActivate = false;
01983             _ke->accept();
01984             return;
01985         }
01986     else if (d->accessKeysActivated)
01987         {
01988             accessKeysTimeout();
01989             _ke->accept();
01990             return;
01991         }
01992     }
01993 
01994     // Send keyup event
01995     if ( dispatchKeyEvent( _ke ) )
01996     {
01997         _ke->accept();
01998         return;
01999     }
02000 
02001     QScrollArea::keyReleaseEvent(_ke);
02002 }
02003 
02004 bool KHTMLView::focusNextPrevChild( bool next )
02005 {
02006     // Now try to find the next child
02007     if (m_part->xmlDocImpl() && focusNextPrevNode(next))
02008     {
02009     if (m_part->xmlDocImpl()->focusNode())
02010         kDebug() << "focusNode.name: "
02011               << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
02012     return true; // focus node found
02013     }
02014 
02015     // If we get here, pass tabbing control up to the next/previous child in our parent
02016     d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
02017     if (m_part->parentPart() && m_part->parentPart()->view())
02018         return m_part->parentPart()->view()->focusNextPrevChild(next);
02019 
02020     return QWidget::focusNextPrevChild(next);
02021 }
02022 
02023 void KHTMLView::doAutoScroll()
02024 {
02025     QPoint pos = QCursor::pos();
02026     QPoint off;
02027     KHTMLView* v = m_kwp->isRedirected() ? m_kwp->rootViewPos(off) : this;
02028     pos = v->viewport()->mapFromGlobal( pos );
02029     pos -= off;
02030     int xm, ym;
02031     viewportToContents(pos.x(), pos.y(), xm, ym); // ###
02032 
02033     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
02034     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
02035          (pos.x() < 0) || (pos.x() > visibleWidth()) )
02036     {
02037         ensureVisible( xm, ym, 0, 5 );
02038 
02039 #ifndef KHTML_NO_SELECTION
02040         // extend the selection while scrolling
02041     DOM::Node innerNode;
02042     if (m_part->isExtendingSelection()) {
02043             RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
02044             m_part->xmlDocImpl()->renderer()->layer()
02045                 ->nodeAtPoint(renderInfo, xm, ym);
02046             innerNode = renderInfo.innerNode();
02047     }/*end if*/
02048 
02049         if (innerNode.handle() && innerNode.handle()->renderer()
02050              && innerNode.handle()->renderer()->shouldSelect()) {
02051             m_part->extendSelectionTo(xm, ym, innerNode);
02052         }/*end if*/
02053 #endif // KHTML_NO_SELECTION
02054     }
02055 }
02056 
02057 // KHTML defines its own stacking order for any object and thus takes
02058 // control of widget painting whenever it can. This is called "redirection".
02059 //
02060 // Redirected widgets are placed off screen. When they are declared as a child of our view (ChildPolished event),
02061 // an event filter is installed, so as to catch any paint event and translate them as update() of the view's main widget.
02062 //
02063 // Painting also happens spontaneously within widgets. In this case, the widget would update() parts of itself.
02064 // While this ordinarily results in a paintEvent being schedduled, it is not the case with off screen widgets.
02065 // Thus update() is monitored by using the mechanism that deffers any update call happening during a paint event,
02066 // transforming it into a posted UpdateLater event. Hence the need to set Qt::WA_WState_InPaintEvent on redirected widgets.
02067 //
02068 // Once the UpdateLater event has been received, Qt::WA_WState_InPaintEvent is removed and the process continues
02069 // with the update of the corresponding rect on the view. That in turn will make our painting subsystem render()
02070 // the widget at the correct stacking position.
02071 //
02072 // For non-redirected (e.g. external) widgets, z-order is honoured through masking. cf.RenderLayer::updateWidgetMasks
02073 
02074 static void handleWidget(QWidget* w, KHTMLView* view, bool recurse=true)
02075 {
02076     if (w->isWindow())
02077         return;
02078 
02079     if (!qobject_cast<QFrame*>(w))
02080     w->setAttribute( Qt::WA_NoSystemBackground );
02081 
02082     w->setAttribute(Qt::WA_WState_InPaintEvent);
02083     w->setAttribute(Qt::WA_OpaquePaintEvent);
02084     w->installEventFilter(view);
02085 
02086     if (!recurse)
02087         return;
02088     if (qobject_cast<KHTMLView*>(w)) {
02089         handleWidget(static_cast<KHTMLView*>(w)->widget(), view, false);
02090         handleWidget(static_cast<KHTMLView*>(w)->horizontalScrollBar(), view, false);
02091         handleWidget(static_cast<KHTMLView*>(w)->verticalScrollBar(), view, false);
02092         return;
02093     }
02094 
02095     QObjectList children = w->children();
02096     foreach (QObject* object, children) {
02097     QWidget *widget = qobject_cast<QWidget*>(object);
02098     if (widget)
02099         handleWidget(widget, view);
02100     }
02101 }
02102 
02103 class KHTMLBackingStoreHackWidget : public QWidget
02104 {
02105 public:
02106     void publicEvent(QEvent *e)
02107     {
02108         QWidget::event(e);
02109     }
02110 };
02111 
02112 bool  KHTMLView::viewportEvent ( QEvent * e )
02113 {
02114     switch (e->type()) {
02115       // those must not be dispatched to the specialized handlers
02116       // as widgetEvent() already took care of that
02117       case QEvent::MouseButtonPress:
02118       case QEvent::MouseButtonRelease:
02119       case QEvent::MouseButtonDblClick:
02120       case QEvent::MouseMove:
02121 #ifndef QT_NO_WHEELEVENT
02122       case QEvent::Wheel:
02123 #endif
02124       case QEvent::ContextMenu:
02125       case QEvent::DragEnter:
02126       case QEvent::DragMove:
02127       case QEvent::DragLeave:
02128       case QEvent::Drop:
02129         return false;
02130       case QEvent::Paint: {
02131           QRect r = static_cast<QPaintEvent*>(e)->rect();
02132           r.setX(r.x() +contentsX());
02133           r.setY(r.y() +contentsY());
02134           QPaintEvent pe(r);
02135           paintEvent(&pe);
02136           return true;
02137       }
02138       default:
02139         break;
02140     }
02141     return QScrollArea::viewportEvent(e);
02142 }
02143 
02144 static void setInPaintEventFlag(QWidget* w, bool b = true, bool recurse=true)
02145 {
02146       w->setAttribute(Qt::WA_WState_InPaintEvent, b);
02147 
02148       if (!recurse)
02149           return;
02150       if (qobject_cast<KHTMLView*>(w)) {
02151           setInPaintEventFlag(static_cast<KHTMLView*>(w)->widget(), b, false);
02152           setInPaintEventFlag(static_cast<KHTMLView*>(w)->horizontalScrollBar(), b, false);
02153           setInPaintEventFlag(static_cast<KHTMLView*>(w)->verticalScrollBar(), b, false);
02154           return;
02155       }
02156 
02157       foreach(QObject* cw, w->children()) {
02158           if (cw->isWidgetType() && ! static_cast<QWidget*>(cw)->isWindow()
02159                                  && !(static_cast<QWidget*>(cw)->windowModality() & Qt::ApplicationModal)) {
02160               setInPaintEventFlag(static_cast<QWidget*>(cw), b);
02161           }
02162       }
02163 }
02164 
02165 bool KHTMLView::eventFilter(QObject *o, QEvent *e)
02166 {
02167     if ( e->type() == QEvent::ShortcutOverride ) {
02168     QKeyEvent* ke = (QKeyEvent*) e;
02169     if (m_part->isEditable() || m_part->isCaretMode()
02170         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
02171         && m_part->xmlDocImpl()->focusNode()->isContentEditable())) {
02172         if ( (ke->modifiers() & Qt::ControlModifier) || (ke->modifiers() & Qt::ShiftModifier) ) {
02173         switch ( ke->key() ) {
02174         case Qt::Key_Left:
02175         case Qt::Key_Right:
02176         case Qt::Key_Up:
02177         case Qt::Key_Down:
02178         case Qt::Key_Home:
02179         case Qt::Key_End:
02180             ke->accept();
02181             return true;
02182         default:
02183             break;
02184         }
02185         }
02186     }
02187     }
02188 
02189     if ( e->type() == QEvent::Leave ) {
02190       if ( d->cursorIconWidget )
02191         d->cursorIconWidget->hide();
02192       m_part->resetHoverText();
02193     }
02194 
02195     QWidget *view = widget();
02196     if (o == view) {
02197         if (widgetEvent(e))
02198             return true;
02199         else if (e->type() == QEvent::Resize) {
02200             updateScrollBars();
02201             return false;
02202         }
02203     } else if (o->isWidgetType()) {
02204     QWidget *v = static_cast<QWidget *>(o);
02205         QWidget *c = v;
02206     while (v && v != view) {
02207             c = v;
02208         v = v->parentWidget();
02209     }
02210     KHTMLWidget* k = dynamic_cast<KHTMLWidget*>(c);
02211     if (v && k && k->m_kwp->isRedirected()) {
02212         bool block = false;
02213         bool isUpdate = false;
02214         QWidget *w = static_cast<QWidget *>(o);
02215         switch(e->type()) {
02216         case QEvent::UpdateRequest: {
02217                 // implicitly call qt_syncBackingStore(w)
02218                 static_cast<KHTMLBackingStoreHackWidget *>(w)->publicEvent(e);
02219                 block = true;
02220                 break;
02221             }
02222             case QEvent::UpdateLater:
02223                 isUpdate = true;
02224                 // no break;
02225         case QEvent::Paint:
02226         if (!allowWidgetPaintEvents) {
02227             // eat the event. Like this we can control exactly when the widget
02228             // gets repainted.
02229             block = true;
02230             int x = 0, y = 0;
02231                     QWidget *v = w;
02232                     while (v && v->parentWidget() != view) {
02233                         x += v->x();
02234                         y += v->y();
02235                         v = v->parentWidget();
02236                     }
02237 
02238                     QPoint ap = k->m_kwp->absolutePos();
02239             x += ap.x();
02240             y += ap.y();
02241 
02242             QRect pr = isUpdate ? static_cast<QUpdateLaterEvent*>(e)->region().boundingRect() : static_cast<QPaintEvent*>(e)->rect();
02243                     bool asap = !d->contentsMoving && qobject_cast<QAbstractScrollArea*>(c);
02244 
02245                     if (isUpdate) {
02246                         setInPaintEventFlag(w, false);
02247                         if (asap)
02248                             w->repaint(static_cast<QUpdateLaterEvent*>(e)->region());
02249                         else
02250                             w->update(static_cast<QUpdateLaterEvent*>(e)->region());
02251                         setInPaintEventFlag(w);
02252                     }
02253 
02254             // QScrollView needs fast repaints
02255             if ( asap && !isUpdate && !d->painting && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer() &&
02256                  !static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
02257                 repaintContents(x + pr.x(), y + pr.y(),
02258                                             pr.width(), pr.height()+1); // ### investigate that +1 (shows up when
02259                                                                         // updating e.g a textarea's blinking cursor)
02260                     } else if (!d->painting) {
02261                 scheduleRepaint(x + pr.x(), y + pr.y(),
02262                     pr.width(), pr.height()+1, asap);
02263                     }
02264         }
02265         break;
02266         case QEvent::MouseMove:
02267         case QEvent::MouseButtonPress:
02268         case QEvent::MouseButtonRelease:
02269         case QEvent::MouseButtonDblClick: {
02270 
02271         if (0 && w->parentWidget() == view && !qobject_cast<QScrollBar*>(w) && !::qobject_cast<QScrollBar *>(w)) {
02272             QMouseEvent *me = static_cast<QMouseEvent *>(e);
02273             QPoint pt = w->mapTo( view, me->pos());
02274             QMouseEvent me2(me->type(), pt, me->button(), me->buttons(), me->modifiers());
02275 
02276             if (e->type() == QEvent::MouseMove)
02277             mouseMoveEvent(&me2);
02278             else if(e->type() == QEvent::MouseButtonPress)
02279             mousePressEvent(&me2);
02280             else if(e->type() == QEvent::MouseButtonRelease)
02281             mouseReleaseEvent(&me2);
02282             else
02283             mouseDoubleClickEvent(&me2);
02284             block = true;
02285                 }
02286         break;
02287         }
02288         case QEvent::KeyPress:
02289         case QEvent::KeyRelease:
02290         if (w->parentWidget() == view && !qobject_cast<QScrollBar*>(w)) {
02291             QKeyEvent *ke = static_cast<QKeyEvent *>(e);
02292             if (e->type() == QEvent::KeyPress)
02293             keyPressEvent(ke);
02294             else
02295             keyReleaseEvent(ke);
02296             block = true;
02297         }
02298 
02299                 if (qobject_cast<KUrlRequester*>(w->parentWidget()) &&
02300             e->type() == QEvent::KeyPress) {
02301             // Since keypress events on the upload widget will
02302             // be forwarded to the lineedit anyway,
02303             // block the original copy at this level to prevent
02304             // double-emissions of events it doesn't accept
02305             e->ignore();
02306             block = true;
02307         }
02308 
02309         break;
02310             case QEvent::FocusIn:
02311             case QEvent::FocusOut:
02312                 block = true;
02313                 break;
02314         default:
02315         break;
02316         }
02317         if (block) {
02318         //qDebug("eating event");
02319         return true;
02320         }
02321     }
02322     }
02323 
02324 //    kDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type();
02325     return QScrollArea::eventFilter(o, e);
02326 }
02327 
02328 bool KHTMLView::widgetEvent(QEvent* e)
02329 {
02330     switch (e->type()) {
02331       case QEvent::MouseButtonPress:
02332       case QEvent::MouseButtonRelease:
02333       case QEvent::MouseButtonDblClick:
02334       case QEvent::MouseMove:
02335       case QEvent::Paint:
02336 #ifndef QT_NO_WHEELEVENT
02337       case QEvent::Wheel:
02338 #endif
02339       case QEvent::ContextMenu:
02340       case QEvent::DragEnter:
02341       case QEvent::DragMove:
02342       case QEvent::DragLeave:
02343       case QEvent::Drop:
02344         return QFrame::event(e);
02345       case QEvent::ChildPolished: {
02346         // we need to install an event filter on all children of the widget() to
02347         // be able to get correct stacking of children within the document.
02348         QObject *c = static_cast<QChildEvent *>(e)->child();
02349         if (c->isWidgetType()) {
02350             QWidget *w = static_cast<QWidget *>(c);
02351         // don't install the event filter on toplevels
02352         if (!(w->windowFlags() & Qt::Window) && !(w->windowModality() & Qt::ApplicationModal)) {
02353             KHTMLWidget* k = dynamic_cast<KHTMLWidget*>(w);
02354             if (k && k->m_kwp->isRedirected()) {
02355                 w->unsetCursor();
02356             handleWidget(w, this);
02357                 }
02358             }
02359         }
02360         break;
02361       }
02362       case QEvent::Move: {
02363           if (static_cast<QMoveEvent*>(e)->pos() != QPoint(0,0)) {
02364               widget()->move(0,0);
02365               updateScrollBars();
02366               return true;
02367           }
02368           break;
02369       }
02370       default:
02371         break;
02372     }
02373     return false;
02374 }
02375 
02376 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
02377 {
02378     return d->underMouse;
02379 }
02380 
02381 DOM::NodeImpl *KHTMLView::nonSharedNodeUnderMouse() const
02382 {
02383     return d->underMouseNonShared;
02384 }
02385 
02386 bool KHTMLView::scrollTo(const QRect &bounds)
02387 {
02388     d->scrollingSelf = true; // so scroll events get ignored
02389 
02390     int x, y, xe, ye;
02391     x = bounds.left();
02392     y = bounds.top();
02393     xe = bounds.right();
02394     ye = bounds.bottom();
02395 
02396     //kDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y;
02397 
02398     int deltax;
02399     int deltay;
02400 
02401     int curHeight = visibleHeight();
02402     int curWidth = visibleWidth();
02403 
02404     if (ye-y>curHeight-d->borderY)
02405     ye  = y + curHeight - d->borderY;
02406 
02407     if (xe-x>curWidth-d->borderX)
02408     xe = x + curWidth - d->borderX;
02409 
02410     // is xpos of target left of the view's border?
02411     if (x < contentsX() + d->borderX )
02412             deltax = x - contentsX() - d->borderX;
02413     // is xpos of target right of the view's right border?
02414     else if (xe + d->borderX > contentsX() + curWidth)
02415             deltax = xe + d->borderX - ( contentsX() + curWidth );
02416     else
02417         deltax = 0;
02418 
02419     // is ypos of target above upper border?
02420     if (y < contentsY() + d->borderY)
02421             deltay = y - contentsY() - d->borderY;
02422     // is ypos of target below lower border?
02423     else if (ye + d->borderY > contentsY() + curHeight)
02424             deltay = ye + d->borderY - ( contentsY() + curHeight );
02425     else
02426         deltay = 0;
02427 
02428     int maxx = curWidth-d->borderX;
02429     int maxy = curHeight-d->borderY;
02430 
02431     int scrollX, scrollY;
02432 
02433     scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
02434     scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
02435 
02436     if (contentsX() + scrollX < 0)
02437     scrollX = -contentsX();
02438     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
02439     scrollX = contentsWidth() - visibleWidth() - contentsX();
02440 
02441     if (contentsY() + scrollY < 0)
02442     scrollY = -contentsY();
02443     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
02444     scrollY = contentsHeight() - visibleHeight() - contentsY();
02445 
02446     horizontalScrollBar()->setValue( horizontalScrollBar()->value()+scrollX );
02447     verticalScrollBar()->setValue( verticalScrollBar()->value()+scrollY );
02448 
02449     d->scrollingSelf = false;
02450 
02451     if ( (abs(deltax)<=maxx) && (abs(deltay)<=maxy) )
02452     return true;
02453     else return false;
02454 
02455 }
02456 
02457 bool KHTMLView::focusNextPrevNode(bool next)
02458 {
02459     // Sets the focus node of the document to be the node after (or if
02460     // next is false, before) the current focus node.  Only nodes that
02461     // are selectable (i.e. for which isFocusable() returns true) are
02462     // taken into account, and the order used is that specified in the
02463     // HTML spec (see DocumentImpl::nextFocusNode() and
02464     // DocumentImpl::previousFocusNode() for details).
02465 
02466     DocumentImpl *doc = m_part->xmlDocImpl();
02467     NodeImpl *oldFocusNode = doc->focusNode();
02468 
02469     // See whether we're in the middle of a detach, or hiding of the
02470     // widget. In this case, we will just clear focus, being careful not to emit events
02471     // or update rendering. Doing this also prevents the code below from going bonkers with
02472     // oldFocusNode not actually being focusable, etc.
02473     if (oldFocusNode) {
02474     if ((oldFocusNode->renderer() && !oldFocusNode->renderer()->parent())
02475           || !oldFocusNode->isTabFocusable()) {
02476         doc->quietResetFocus();
02477         return true;
02478     }
02479     }
02480 
02481 #if 1
02482     // If the user has scrolled the document, then instead of picking
02483     // the next focusable node in the document, use the first one that
02484     // is within the visible area (if possible).
02485     if (d->scrollBarMoved)
02486     {
02487     NodeImpl *toFocus;
02488     if (next)
02489         toFocus = doc->nextFocusNode(oldFocusNode);
02490     else
02491         toFocus = doc->previousFocusNode(oldFocusNode);
02492 
02493     if (!toFocus && oldFocusNode) {
02494         if (next)
02495         toFocus = doc->nextFocusNode(NULL);
02496         else
02497         toFocus = doc->previousFocusNode(NULL);
02498     }
02499 
02500     while (toFocus && toFocus != oldFocusNode)
02501     {
02502 
02503         QRect focusNodeRect = toFocus->getRect();
02504         if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
02505         (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
02506         {
02507             QRect r = toFocus->getRect();
02508             ensureVisible( r.right(), r.bottom());
02509             ensureVisible( r.left(), r.top());
02510             d->scrollBarMoved = false;
02511             d->tabMovePending = false;
02512             d->lastTabbingDirection = next;
02513             d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
02514             m_part->xmlDocImpl()->setFocusNode(toFocus);
02515             Node guard(toFocus);
02516             if (!toFocus->hasOneRef() )
02517             {
02518             emit m_part->nodeActivated(Node(toFocus));
02519             }
02520             return true;
02521         }
02522         }
02523         if (next)
02524         toFocus = doc->nextFocusNode(toFocus);
02525         else
02526         toFocus = doc->previousFocusNode(toFocus);
02527 
02528         if (!toFocus && oldFocusNode)
02529         {
02530         if (next)
02531         {
02532             toFocus = doc->nextFocusNode(NULL);
02533         }
02534         else
02535         {
02536             toFocus = doc->previousFocusNode(NULL);
02537         }
02538         }
02539     }
02540 
02541     d->scrollBarMoved = false;
02542     }
02543 #endif
02544 
02545     if (!oldFocusNode && d->pseudoFocusNode == KHTMLViewPrivate::PFNone)
02546     {
02547     ensureVisible(contentsX(), next?0:contentsHeight());
02548     d->scrollBarMoved = false;
02549     d->pseudoFocusNode = next?KHTMLViewPrivate::PFTop:KHTMLViewPrivate::PFBottom;
02550     return true;
02551     }
02552 
02553     NodeImpl *newFocusNode = NULL;
02554 
02555     if (d->tabMovePending && next != d->lastTabbingDirection)
02556     {
02557     //kDebug ( 6000 ) << " tab move pending and tabbing direction changed!\n";
02558     newFocusNode = oldFocusNode;
02559     }
02560     else if (next)
02561     {
02562     if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFTop )
02563         newFocusNode = doc->nextFocusNode(oldFocusNode);
02564     }
02565     else
02566     {
02567     if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFBottom )
02568         newFocusNode = doc->previousFocusNode(oldFocusNode);
02569     }
02570 
02571     bool targetVisible = false;
02572     if (!newFocusNode)
02573     {
02574     if ( next )
02575     {
02576         targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight()-d->borderY,0,0));
02577     }
02578     else
02579     {
02580         targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,d->borderY,0,0));
02581     }
02582     }
02583     else
02584     {
02585         // if it's an editable element, activate the caret
02586         if (!m_part->isCaretMode() && newFocusNode->isContentEditable()) {
02587             kDebug(6200) << "show caret! fn: " << newFocusNode->nodeName().string() << endl;
02588             m_part->clearCaretRectIfNeeded();
02589             m_part->d->editor_context.m_selection.moveTo(Position(newFocusNode, 0L));
02590             m_part->setCaretVisible(true);
02591         } else {
02592            m_part->setCaretVisible(false);
02593            kDebug(6200) << "hide caret! fn: " << newFocusNode->nodeName().string() << endl;
02594     }
02595         m_part->notifySelectionChanged();
02596 
02597     targetVisible = scrollTo(newFocusNode->getRect());
02598     }
02599 
02600     if (targetVisible)
02601     {
02602     //kDebug ( 6000 ) << " target reached.\n";
02603     d->tabMovePending = false;
02604 
02605     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
02606     if (newFocusNode)
02607     {
02608         Node guard(newFocusNode);
02609         if (!newFocusNode->hasOneRef() )
02610         {
02611         emit m_part->nodeActivated(Node(newFocusNode));
02612         }
02613         return true;
02614     }
02615     else
02616     {
02617         d->pseudoFocusNode = next?KHTMLViewPrivate::PFBottom:KHTMLViewPrivate::PFTop;
02618         return false;
02619     }
02620     }
02621     else
02622     {
02623     if (!d->tabMovePending)
02624         d->lastTabbingDirection = next;
02625     d->tabMovePending = true;
02626     return true;
02627     }
02628 }
02629 
02630 void KHTMLView::displayAccessKeys()
02631 {
02632     QVector< QChar > taken;
02633     displayAccessKeys( NULL, this, taken, false );
02634     displayAccessKeys( NULL, this, taken, true );
02635 }
02636 
02637 void KHTMLView::displayAccessKeys( KHTMLView* caller, KHTMLView* origview, QVector< QChar >& taken, bool use_fallbacks )
02638 {
02639     QMap< ElementImpl*, QChar > fallbacks;
02640     if( use_fallbacks )
02641         fallbacks = buildFallbackAccessKeys();
02642     for( NodeImpl* n = m_part->xmlDocImpl(); n != NULL; n = n->traverseNextNode()) {
02643         if( n->isElementNode()) {
02644             ElementImpl* en = static_cast< ElementImpl* >( n );
02645             DOMString s = en->getAttribute( ATTR_ACCESSKEY );
02646             QString accesskey;
02647             if( s.length() == 1 ) {
02648                 QChar a = s.string()[ 0 ].toUpper();
02649                 if( qFind( taken.begin(), taken.end(), a ) == taken.end()) // !contains
02650                     accesskey = a;
02651             }
02652             if( accesskey.isNull() && fallbacks.contains( en )) {
02653                 QChar a = fallbacks[ en ].toUpper();
02654                 if( qFind( taken.begin(), taken.end(), a ) == taken.end()) // !contains
02655                     accesskey = QString( "<qt><i>" ) + a + "</i></qt>";
02656             }
02657             if( !accesskey.isNull()) {
02658             QRect rec=en->getRect();
02659             QLabel *lab=new QLabel(accesskey,viewport());
02660             lab->setAttribute(Qt::WA_DeleteOnClose);
02661             connect( origview, SIGNAL(hideAccessKeys()), lab, SLOT(close()) );
02662             connect( this, SIGNAL(repaintAccessKeys()), lab, SLOT(repaint()));
02663             lab->setPalette(QToolTip::palette());
02664             lab->setLineWidth(2);
02665             lab->setFrameStyle(QFrame::Box | QFrame::Plain);
02666             lab->setMargin(3);
02667             lab->adjustSize();
02668             lab->setParent( widget() );
02669         lab->setAutoFillBackground(true);
02670             lab->move(
02671             qMin(rec.left()+rec.width()/2 - contentsX(), contentsWidth() - lab->width()),
02672             qMin(rec.top()+rec.height()/2 - contentsY(), contentsHeight() - lab->height()));
02673             lab->show();
02674                 taken.append( accesskey[ 0 ] );
02675         }
02676         }
02677     }
02678     if( use_fallbacks )
02679         return;
02680 
02681     QList<KParts::ReadOnlyPart*> frames = m_part->frames();
02682     foreach( KParts::ReadOnlyPart* cur, frames ) {
02683         if( !qobject_cast<KHTMLPart*>(cur) )
02684             continue;
02685         KHTMLPart* part = static_cast< KHTMLPart* >( cur );
02686         if( part->view() && part->view() != caller )
02687             part->view()->displayAccessKeys( this, origview, taken, use_fallbacks );
02688     }
02689 
02690     // pass up to the parent
02691     if (m_part->parentPart() && m_part->parentPart()->view()
02692         && m_part->parentPart()->view() != caller)
02693         m_part->parentPart()->view()->displayAccessKeys( this, origview, taken, use_fallbacks );
02694 }
02695 
02696 bool KHTMLView::isScrollingFromMouseWheel() const
02697 {
02698     return d->scrollingFromWheel != QPoint(-1,-1);
02699 }
02700 
02701 void KHTMLView::accessKeysTimeout()
02702 {
02703 d->accessKeysActivated=false;
02704 d->accessKeysPreActivate = false;
02705 m_part->setStatusBarText(QString(), KHTMLPart::BarOverrideText);
02706 emit hideAccessKeys();
02707 }
02708 
02709 // Handling of the HTML accesskey attribute.
02710 bool KHTMLView::handleAccessKey( const QKeyEvent* ev )
02711 {
02712 // Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
02713 // but this code must act as if the modifiers weren't pressed
02714     QChar c;
02715     if( ev->key() >= Qt::Key_A && ev->key() <= Qt::Key_Z )
02716         c = 'A' + ev->key() - Qt::Key_A;
02717     else if( ev->key() >= Qt::Key_0 && ev->key() <= Qt::Key_9 )
02718         c = '0' + ev->key() - Qt::Key_0;
02719     else {
02720         // TODO fake XKeyEvent and XLookupString ?
02721         // This below seems to work e.g. for eacute though.
02722         if( ev->text().length() == 1 )
02723             c = ev->text()[ 0 ];
02724     }
02725     if( c.isNull())
02726         return false;
02727     return focusNodeWithAccessKey( c );
02728 }
02729 
02730 bool KHTMLView::focusNodeWithAccessKey( QChar c, KHTMLView* caller )
02731 {
02732     DocumentImpl *doc = m_part->xmlDocImpl();
02733     if( !doc )
02734         return false;
02735     ElementImpl* node = doc->findAccessKeyElement( c );
02736     if( !node ) {
02737         QList<KParts::ReadOnlyPart*> frames = m_part->frames();
02738         foreach( KParts::ReadOnlyPart* cur, frames ) {
02739             if( !qobject_cast<KHTMLPart*>(cur) )
02740                 continue;
02741             KHTMLPart* part = static_cast< KHTMLPart* >( cur );
02742             if( part->view() && part->view() != caller
02743                 && part->view()->focusNodeWithAccessKey( c, this ))
02744                 return true;
02745         }
02746         // pass up to the parent
02747         if (m_part->parentPart() && m_part->parentPart()->view()
02748             && m_part->parentPart()->view() != caller
02749             && m_part->parentPart()->view()->focusNodeWithAccessKey( c, this ))
02750             return true;
02751         if( caller == NULL ) { // the active frame (where the accesskey was pressed)
02752             const QMap< ElementImpl*, QChar > fallbacks = buildFallbackAccessKeys();
02753             for( QMap< ElementImpl*, QChar >::ConstIterator it = fallbacks.begin();
02754                  it != fallbacks.end();
02755                  ++it )
02756                 if( *it == c ) {
02757                     node = it.key();
02758                     break;
02759                 }
02760         }
02761         if( node == NULL )
02762             return false;
02763     }
02764 
02765     // Scroll the view as necessary to ensure that the new focus node is visible
02766 
02767     QRect r = node->getRect();
02768     ensureVisible( r.right(), r.bottom());
02769     ensureVisible( r.left(), r.top());
02770 
02771     Node guard( node );
02772     if( node->isFocusable()) {
02773     if (node->id()==ID_LABEL) {
02774         // if Accesskey is a label, give focus to the label's referrer.
02775         node=static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl* >( node )->getFormElement());
02776         if (!node) return true;
02777             guard = node;
02778     }
02779         // Set focus node on the document
02780 #ifdef __GNUC__
02781 #warning "port QFocusEvent::setReason( QFocusEvent::Shortcut ); to qt4"
02782 #endif
02783         //QFocusEvent::setReason( QFocusEvent::Shortcut );
02784         m_part->xmlDocImpl()->setFocusNode(node);
02785 #ifdef __GNUC__
02786 #warning "port QFocusEvent::resetReason(); to qt4"
02787 #endif
02788         //QFocusEvent::resetReason();
02789         if( node != NULL && node->hasOneRef()) // deleted, only held by guard
02790             return true;
02791         emit m_part->nodeActivated(Node(node));
02792         if( node != NULL && node->hasOneRef())
02793             return true;
02794     }
02795 
02796     switch( node->id()) {
02797         case ID_A:
02798             static_cast< HTMLAnchorElementImpl* >( node )->click();
02799           break;
02800         case ID_INPUT:
02801             static_cast< HTMLInputElementImpl* >( node )->click();
02802           break;
02803         case ID_BUTTON:
02804             static_cast< HTMLButtonElementImpl* >( node )->click();
02805           break;
02806         case ID_AREA:
02807             static_cast< HTMLAreaElementImpl* >( node )->click();
02808           break;
02809         case ID_TEXTAREA:
02810       break; // just focusing it is enough
02811         case ID_LEGEND:
02812             // TODO
02813           break;
02814     }
02815     return true;
02816 }
02817 
02818 static QString getElementText( NodeImpl* start, bool after )
02819 {
02820     QString ret;             // nextSibling(), to go after e.g. </select>
02821     for( NodeImpl* n = after ? start->nextSibling() : start->traversePreviousNode();
02822          n != NULL;
02823          n = after ? n->traverseNextNode() : n->traversePreviousNode()) {
02824         if( n->isTextNode()) {
02825             if( after )
02826                 ret += static_cast< TextImpl* >( n )->toString().string();
02827             else
02828                 ret.prepend( static_cast< TextImpl* >( n )->toString().string());
02829         } else {
02830             switch( n->id()) {
02831                 case ID_A:
02832                 case ID_FONT:
02833                 case ID_TT:
02834                 case ID_U:
02835                 case ID_B:
02836                 case ID_I:
02837                 case ID_S:
02838                 case ID_STRIKE:
02839                 case ID_BIG:
02840                 case ID_SMALL:
02841                 case ID_EM:
02842                 case ID_STRONG:
02843                 case ID_DFN:
02844                 case ID_CODE:
02845                 case ID_SAMP:
02846                 case ID_KBD:
02847                 case ID_VAR:
02848                 case ID_CITE:
02849                 case ID_ABBR:
02850                 case ID_ACRONYM:
02851                 case ID_SUB:
02852                 case ID_SUP:
02853                 case ID_SPAN:
02854                 case ID_NOBR:
02855                 case ID_WBR:
02856                     break;
02857                 case ID_TD:
02858                     if( ret.trimmed().isEmpty())
02859                         break;
02860                     // fall through
02861                 default:
02862                     return ret.simplified();
02863             }
02864         }
02865     }
02866     return ret.simplified();
02867 }
02868 
02869 static QMap< NodeImpl*, QString > buildLabels( NodeImpl* start )
02870 {
02871     QMap< NodeImpl*, QString > ret;
02872     for( NodeImpl* n = start;
02873          n != NULL;
02874          n = n->traverseNextNode()) {
02875         if( n->id() == ID_LABEL ) {
02876             HTMLLabelElementImpl* label = static_cast< HTMLLabelElementImpl* >( n );
02877             NodeImpl* labelfor = label->getFormElement();
02878             if( labelfor )
02879                 ret[ labelfor ] = label->innerText().string().simplified();
02880         }
02881     }
02882     return ret;
02883 }
02884 
02885 namespace khtml {
02886 struct AccessKeyData {
02887     ElementImpl* element;
02888     QString text;
02889     QString url;
02890     int priority; // 10(highest) - 0(lowest)
02891 };
02892 }
02893 
02894 QMap< ElementImpl*, QChar > KHTMLView::buildFallbackAccessKeys() const
02895 {
02896     // build a list of all possible candidate elements that could use an accesskey
02897     QLinkedList< AccessKeyData > data; // Note: this has to be a list type that keep iterators valid
02898                                        // when other entries are removed
02899     QMap< NodeImpl*, QString > labels = buildLabels( m_part->xmlDocImpl());
02900     for( NodeImpl* n = m_part->xmlDocImpl();
02901          n != NULL;
02902          n = n->traverseNextNode()) {
02903         if( n->isElementNode()) {
02904             ElementImpl* element = static_cast< ElementImpl* >( n );
02905             if( element->getAttribute( ATTR_ACCESSKEY ).length() == 1 )
02906                 continue; // has accesskey set, ignore
02907             if( element->renderer() == NULL )
02908                 continue; // not visible
02909             QString text;
02910             QString url;
02911             int priority = 0;
02912             bool ignore = false;
02913             bool text_after = false;
02914             bool text_before = false;
02915             switch( element->id()) {
02916                 case ID_A:
02917                     url = khtml::parseURL(element->getAttribute(ATTR_HREF)).string();
02918                     if( url.isEmpty()) // doesn't have href, it's only an anchor
02919                         continue;
02920                     text = static_cast< HTMLElementImpl* >( element )->innerText().string().simplified();
02921                     priority = 2;
02922                     break;
02923                 case ID_INPUT: {
02924                     HTMLInputElementImpl* in = static_cast< HTMLInputElementImpl* >( element );
02925                     switch( in->inputType()) {
02926                         case HTMLInputElementImpl::SUBMIT:
02927                             text = in->value().string();
02928                             if( text.isEmpty())
02929                                 text = i18n( "Submit" );
02930                             priority = 7;
02931                             break;
02932                         case HTMLInputElementImpl::IMAGE:
02933                             text = in->altText().string();
02934                             priority = 7;
02935                             break;
02936                         case HTMLInputElementImpl::BUTTON:
02937                             text = in->value().string();
02938                             priority = 5;
02939                             break;
02940                         case HTMLInputElementImpl::RESET:
02941                             text = in->value().string();
02942                             if( text.isEmpty())
02943                                 text = i18n( "Reset" );
02944                             priority = 5;
02945                             break;
02946                         case HTMLInputElementImpl::HIDDEN:
02947                             ignore = true;
02948                             break;
02949                         case HTMLInputElementImpl::CHECKBOX:
02950                         case HTMLInputElementImpl::RADIO:
02951                             text_after = true;
02952                             priority = 5;
02953                             break;
02954                         case HTMLInputElementImpl::TEXT:
02955                         case HTMLInputElementImpl::PASSWORD:
02956                         case HTMLInputElementImpl::FILE:
02957                             text_before = true;
02958                             priority = 5;
02959                             break;
02960                         default:
02961                             priority = 5;
02962                             break;
02963                     }
02964                     break;
02965                 }
02966                 case ID_BUTTON:
02967                     text = static_cast< HTMLElementImpl* >( element )->innerText().string().simplified();
02968                     switch( static_cast< HTMLButtonElementImpl* >( element )->buttonType()) {
02969                         case HTMLButtonElementImpl::SUBMIT:
02970                             if( text.isEmpty())
02971                                 text = i18n( "Submit" );
02972                             priority = 7;
02973                             break;
02974                         case HTMLButtonElementImpl::RESET:
02975                             if( text.isEmpty())
02976                                 text = i18n( "Reset" );
02977                             priority = 5;
02978                             break;
02979                         default:
02980                             priority = 5;
02981                             break;
02982                     }
02983                     break;
02984                 case ID_SELECT: // these don't have accesskey attribute, but quick access may be handy
02985                     text_before = true;
02986                     text_after = true;
02987                     priority = 5;
02988                     break;
02989                 case ID_FRAME:
02990                     ignore = true;
02991                     break;
02992                 default:
02993                     ignore = !element->isFocusable();
02994                     priority = 2;
02995                     break;
02996             }
02997             if( ignore )
02998                 continue;
02999             if( text.isNull() && labels.contains( element ))
03000                 text = labels[ element ];
03001             if( text.isNull() && text_before )
03002                 text = getElementText( element, false );
03003             if( text.isNull() && text_after )
03004                 text = getElementText( element, true );
03005             text = text.trimmed();
03006             // increase priority of items which have explicitly specified accesskeys in the config
03007             const QList< QPair< QString, QChar > > priorities
03008                 = m_part->settings()->fallbackAccessKeysAssignments();
03009             for( QList< QPair< QString, QChar > >::ConstIterator it = priorities.begin();
03010                  it != priorities.end();
03011                  ++it ) {
03012                 if( text == (*it).first )
03013                     priority = 10;
03014             }
03015             AccessKeyData tmp = { element, text, url, priority };
03016             data.append( tmp );
03017         }
03018     }
03019 
03020     QList< QChar > keys;
03021     for( char c = 'A'; c <= 'Z'; ++c )
03022         keys << c;
03023     for( char c = '0'; c <= '9'; ++c )
03024         keys << c;
03025     for( NodeImpl* n = m_part->xmlDocImpl();
03026          n != NULL;
03027          n = n->traverseNextNode()) {
03028         if( n->isElementNode()) {
03029             ElementImpl* en = static_cast< ElementImpl* >( n );
03030             DOMString s = en->getAttribute( ATTR_ACCESSKEY );
03031             if( s.length() == 1 ) {
03032                 QChar c = s.string()[ 0 ].toUpper();
03033                 keys.removeAll( c ); // remove manually assigned accesskeys
03034             }
03035         }
03036     }
03037 
03038     QMap< ElementImpl*, QChar > ret;
03039     for( int priority = 10; priority >= 0; --priority ) {
03040         for( QLinkedList< AccessKeyData >::Iterator it = data.begin();
03041              it != data.end();
03042              ) {
03043             if( (*it).priority != priority ) {
03044                 ++it;
03045                 continue;
03046             }
03047             if( keys.isEmpty())
03048                 break;
03049             QString text = (*it).text;
03050             QChar key;
03051             if( key.isNull() && !text.isEmpty()) {
03052                 const QList< QPair< QString, QChar > > priorities
03053                     = m_part->settings()->fallbackAccessKeysAssignments();
03054                 for( QList< QPair< QString, QChar > >::ConstIterator it = priorities.begin();
03055                      it != priorities.end();
03056                      ++it )
03057                     if( text == (*it).first && keys.contains( (*it).second )) {
03058                         key = (*it).second;
03059                         break;
03060                     }
03061             }
03062             // try first to select the first character as the accesskey,
03063             // then first character of the following words,
03064             // and then simply the first free character
03065             if( key.isNull() && !text.isEmpty()) {
03066                 const QStringList words = text.split( ' ' );
03067                 for( QStringList::ConstIterator it = words.begin();
03068                      it != words.end();
03069                      ++it ) {
03070                     if( keys.contains( (*it)[ 0 ].toUpper())) {
03071                         key = (*it)[ 0 ].toUpper();
03072                         break;
03073                     }
03074                 }
03075             }
03076             if( key.isNull() && !text.isEmpty()) {
03077                 for( int i = 0; i < text.length(); ++i ) {
03078                     if( keys.contains( text[ i ].toUpper())) {
03079                         key = text[ i ].toUpper();
03080                         break;
03081                     }
03082                 }
03083             }
03084             if( key.isNull())
03085                 key = keys.front();
03086             ret[ (*it).element ] = key;
03087             keys.removeAll( key );
03088             QString url = (*it).url;
03089             it = data.erase( it );
03090             // assign the same accesskey also to other elements pointing to the same url
03091             if( !url.isEmpty() && !url.startsWith( "javascript:", Qt::CaseInsensitive )) {
03092                 for( QLinkedList< AccessKeyData >::Iterator it2 = data.begin();
03093                      it2 != data.end();
03094                      ) {
03095                     if( (*it2).url == url ) {
03096                         ret[ (*it2).element ] = key;
03097                         if( it == it2 )
03098                             ++it;
03099                         it2 = data.erase( it2 );
03100                     } else
03101                         ++it2;
03102                 }
03103             }
03104         }
03105     }
03106     return ret;
03107 }
03108 
03109 void KHTMLView::setMediaType( const QString &medium )
03110 {
03111     m_medium = medium;
03112 }
03113 
03114 QString KHTMLView::mediaType() const
03115 {
03116     return m_medium;
03117 }
03118 
03119 bool KHTMLView::pagedMode() const
03120 {
03121     return d->paged;
03122 }
03123 
03124 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
03125 {
03126     if (vis) {
03127         d->visibleWidgets.insert(w, w->widget());
03128     }
03129     else
03130         d->visibleWidgets.remove(w);
03131 }
03132 
03133 bool KHTMLView::needsFullRepaint() const
03134 {
03135     return d->needsFullRepaint;
03136 }
03137 
03138 namespace {
03139    class QPointerDeleter
03140    {
03141    public:
03142        explicit QPointerDeleter(QObject* o) : obj(o) {}
03143        ~QPointerDeleter() { delete obj; }
03144    private:
03145        const QPointer<QObject> obj; 
03146    }; 
03147 }
03148 
03149 void KHTMLView::print(bool quick)
03150 {
03151     if(!m_part->xmlDocImpl()) return;
03152     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
03153     if(!root) return;
03154 
03155     QPointer<KHTMLPrintSettings> printSettings(new KHTMLPrintSettings); //XXX: doesn't save settings between prints like this
03156 
03157     // read print settings
03158     KSharedConfigPtr config = KGlobal::config();
03159     KConfigGroup group(config, "KHTML Print Settings");
03160     printSettings->setprintFriendly(group.readEntry("PrintFriendly", true));
03161     printSettings->setprintImages(group.readEntry("PrintImages", true));
03162     printSettings->setprintHeader(group.readEntry("PrintHeader", true));
03163 
03164     const QPointerDeleter settingsDeleter(printSettings); //the printdialog takes ownership of the settings widget, thus this workaround to avoid double deletion
03165     QPrinter printer;
03166     QPointer<QPrintDialog> dialog = KdePrint::createPrintDialog(&printer, QList<QWidget*>() << printSettings, this);
03167     dialog->setOption( QAbstractPrintDialog::PrintPageRange, false);
03168     const QPointerDeleter dialogDeleter(dialog);
03169 
03170     QString docname = m_part->xmlDocImpl()->URL().prettyUrl();
03171     if ( !docname.isEmpty() )
03172         docname = KStringHandler::csqueeze(docname, 80);
03173 
03174     if(quick || (dialog->exec() && dialog)) { /*'this' and thus dialog might have been deleted while exec()!*/
03175         // write HTML settings
03176         KSharedConfigPtr config = KGlobal::config();
03177         KConfigGroup group(config, "KHTML Print Settings");
03178         group.writeEntry("PrintFriendly", printSettings->printFriendly());
03179         group.writeEntry("PrintImages", printSettings->printImages());
03180         group.writeEntry("PrintHeader", printSettings->printHeader());
03181 
03182         viewport()->setCursor( Qt::WaitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
03183         // set up KPrinter
03184         printer.setFullPage(false);
03185         printer.setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
03186         printer.setDocName(docname);
03187 
03188         QPainter *p = new QPainter;
03189         p->begin( &printer );
03190         khtml::setPrintPainter( p );
03191 
03192         m_part->xmlDocImpl()->setPaintDevice( &printer );
03193         QString oldMediaType = mediaType();
03194         setMediaType( "print" );
03195         // We ignore margin settings for html and body when printing
03196         // and use the default margins from the print-system
03197         // (In Qt 3.0.x the default margins are hardcoded in Qt)
03198         m_part->xmlDocImpl()->setPrintStyleSheet( printSettings->printFriendly() ?
03199                                                   "* { background-image: none !important;"
03200                                                   "    background-color: white !important;"
03201                                                   "    color: black !important; }"
03202                           "body { margin: 0px !important; }"
03203                           "html { margin: 0px !important; }" :
03204                           "body { margin: 0px !important; }"
03205                           "html { margin: 0px !important; }"
03206                           );
03207 
03208         kDebug(6000) << "printing: physical page width = " << printer.width()
03209                       << " height = " << printer.height() << endl;
03210         root->setStaticMode(true);
03211         root->setPagedMode(true);
03212         root->setWidth(printer.width());
03213 //         root->setHeight(printer.height());
03214         root->setPageTop(0);
03215         root->setPageBottom(0);
03216         d->paged = true;
03217 
03218         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(printer.logicalDpiY(), 100);
03219         m_part->xmlDocImpl()->updateStyleSelector();
03220         root->setPrintImages(printSettings->printImages());
03221         root->makePageBreakAvoidBlocks();
03222 
03223         root->setNeedsLayoutAndMinMaxRecalc();
03224         root->layout();
03225 
03226         // check sizes ask for action.. (scale or clip)
03227 
03228         bool printHeader = printSettings->printHeader();
03229 
03230         int headerHeight = 0;
03231         QFont headerFont("Sans Serif", 8);
03232 
03233         QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),KLocale::ShortDate);
03234         QString headerMid = docname;
03235         QString headerRight;
03236 
03237         if (printHeader)
03238         {
03239            p->setFont(headerFont);
03240            headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
03241         }
03242 
03243         // ok. now print the pages.
03244         kDebug(6000) << "printing: html page width = " << root->docWidth()
03245                       << " height = " << root->docHeight() << endl;
03246         kDebug(6000) << "printing: margins left = " << printer.pageRect().left() - printer.paperRect().left()
03247                       << " top = " << printer.pageRect().top() - printer.paperRect().top() << endl;
03248         kDebug(6000) << "printing: paper width = " << printer.width()
03249                       << " height = " << printer.height() << endl;
03250         // if the width is too large to fit on the paper we just scale
03251         // the whole thing.
03252         int pageWidth = printer.width();
03253         int pageHeight = printer.height();
03254         p->setClipRect(0,0, pageWidth, pageHeight);
03255 
03256         pageHeight -= headerHeight;
03257 
03258         bool scalePage = false;
03259         double scale = 0.0;
03260 #ifndef QT_NO_TRANSFORMATIONS
03261         if(root->docWidth() > printer.width()) {
03262             scalePage = true;
03263             scale = ((double) printer.width())/((double) root->docWidth());
03264             pageHeight = (int) (pageHeight/scale);
03265             pageWidth = (int) (pageWidth/scale);
03266             headerHeight = (int) (headerHeight/scale);
03267         }
03268 #endif
03269         kDebug(6000) << "printing: scaled html width = " << pageWidth
03270                       << " height = " << pageHeight << endl;
03271 
03272         root->setHeight(pageHeight);
03273         root->setPageBottom(pageHeight);
03274         root->setNeedsLayout(true);
03275         root->layoutIfNeeded();
03276 //         m_part->slotDebugRenderTree();
03277 
03278         // Squeeze header to make it it on the page.
03279         if (printHeader)
03280         {
03281             int available_width = printer.width() - 10 -
03282                 2 * qMax(p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
03283                          p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
03284             if (available_width < 150)
03285                available_width = 150;
03286             int mid_width;
03287             int squeeze = 120;
03288             do {
03289                 headerMid = KStringHandler::csqueeze(docname, squeeze);
03290                 mid_width = p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
03291                 squeeze -= 10;
03292             } while (mid_width > available_width);
03293         }
03294 
03295         int top = 0;
03296         int bottom = 0;
03297         int page = 1;
03298         while(top < root->docHeight()) {
03299             if(top > 0) printer.newPage();
03300             p->save();
03301             p->setClipRect(0, 0, pageWidth, headerHeight);
03302             if (printHeader)
03303             {
03304                 int dy = p->fontMetrics().lineSpacing();
03305                 p->setPen(Qt::black);
03306                 p->setFont(headerFont);
03307 
03308                 headerRight = QString("#%1").arg(page);
03309 
03310                 p->drawText(0, 0, printer.width(), dy, Qt::AlignLeft, headerLeft);
03311                 p->drawText(0, 0, printer.width(), dy, Qt::AlignHCenter, headerMid);
03312                 p->drawText(0, 0, printer.width(), dy, Qt::AlignRight, headerRight);
03313             }
03314 
03315 #ifndef QT_NO_TRANSFORMATIONS
03316             if (scalePage)
03317                 p->scale(scale, scale);
03318 #endif
03319             p->restore();
03320             p->translate(0, headerHeight-top);
03321 
03322             bottom = top+pageHeight;
03323 
03324             root->setPageTop(top);
03325             root->setPageBottom(bottom);
03326             root->setPageNumber(page);
03327 
03328             root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
03329             kDebug(6000) << "printed: page " << page <<" bottom At = " << bottom;
03330 
03331             top = bottom;
03332             p->resetTransform();
03333             page++;
03334         }
03335 
03336         p->end();
03337         delete p;
03338 
03339         // and now reset the layout to the usual one...
03340         root->setPagedMode(false);
03341         root->setStaticMode(false);
03342         d->paged = false;
03343         khtml::setPrintPainter( 0 );
03344         setMediaType( oldMediaType );
03345         m_part->xmlDocImpl()->setPaintDevice( this );
03346         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->logicalDpiY(), m_part->fontScaleFactor());
03347         m_part->xmlDocImpl()->updateStyleSelector();
03348         viewport()->unsetCursor();
03349     }
03350 }
03351 
03352 void KHTMLView::slotPaletteChanged()
03353 {
03354     if(!m_part->xmlDocImpl()) return;
03355     DOM::DocumentImpl *document = m_part->xmlDocImpl();
03356     if (!document->isHTMLDocument()) return;
03357     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
03358     if(!root) return;
03359     root->style()->resetPalette();
03360     NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
03361     if(!body) return;
03362     body->setChanged(true);
03363     body->recalcStyle( NodeImpl::Force );
03364 }
03365 
03366 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
03367 {
03368     if(!m_part->xmlDocImpl()) return;
03369     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
03370     if(!root) return;
03371     d->firstRepaintPending = false;
03372 
03373     QPaintDevice* opd = m_part->xmlDocImpl()->paintDevice();
03374     m_part->xmlDocImpl()->setPaintDevice(p->device());
03375     root->setPagedMode(true);
03376     root->setStaticMode(true);
03377     root->setWidth(rc.width());
03378 
03379     // save()
03380     QRegion creg = p->clipRegion();
03381     QTransform t = p->worldTransform();
03382     QRect w = p->window();
03383     QRect v = p->viewport();
03384     bool vte = p->viewTransformEnabled();
03385     bool wme = p->worldMatrixEnabled();
03386 
03387     p->setClipRect(rc);
03388     p->translate(rc.left(), rc.top());
03389     double scale = ((double) rc.width()/(double) root->docWidth());
03390     int height = (int) ((double) rc.height() / scale);
03391 #ifndef QT_NO_TRANSFORMATIONS
03392     p->scale(scale, scale);
03393 #endif
03394     root->setPageTop(yOff);
03395     root->setPageBottom(yOff+height);
03396 
03397     root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
03398     if (more)
03399         *more = yOff + height < root->docHeight();
03400 
03401     // restore()
03402     p->setWorldTransform(t);
03403     p->setWindow(w);
03404     p->setViewport(v);
03405     p->setViewTransformEnabled( vte );
03406     p->setWorldMatrixEnabled( wme );
03407     if (!creg.isEmpty())
03408         p->setClipRegion( creg );
03409     else
03410         p->setClipRegion(QRegion(), Qt::NoClip);
03411 
03412     root->setPagedMode(false);
03413     root->setStaticMode(false);
03414     m_part->xmlDocImpl()->setPaintDevice( opd );
03415 }
03416 
03417 void KHTMLView::render(QPainter* p, const QRect& r, const QPoint& off)
03418 {
03419     d->firstRepaintPending = false;
03420     QRect clip(off.x()+r.x(), off.y()+r.y(),r.width(),r.height());
03421     if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
03422         p->fillRect(clip, palette().brush(QPalette::Active, QPalette::Base));
03423         return;
03424     }
03425     QPaintDevice* opd = m_part->xmlDocImpl()->paintDevice();
03426     m_part->xmlDocImpl()->setPaintDevice(p->device());
03427 
03428     // save()
03429     QRegion creg = p->clipRegion();
03430     QTransform t = p->worldTransform();
03431     QRect w = p->window();
03432     QRect v = p->viewport();
03433     bool vte = p->viewTransformEnabled();
03434     bool wme = p->worldMatrixEnabled();
03435 
03436     p->setClipRect(clip);
03437     QRect rect = r.translated(contentsX(),contentsY());
03438     p->translate(off.x()-contentsX(), off.y()-contentsY());
03439 
03440     m_part->xmlDocImpl()->renderer()->layer()->paint(p, rect);
03441 
03442     // restore()
03443     p->setWorldTransform(t);
03444     p->setWindow(w);
03445     p->setViewport(v);
03446     p->setViewTransformEnabled( vte );
03447     p->setWorldMatrixEnabled( wme );
03448     if (!creg.isEmpty())
03449         p->setClipRegion( creg );
03450     else
03451         p->setClipRegion(QRegion(), Qt::NoClip);
03452 
03453     m_part->xmlDocImpl()->setPaintDevice( opd );
03454 }
03455 
03456 void KHTMLView::setHasStaticBackground(bool partial)
03457 {
03458     // full static iframe is irreversible for now
03459     if (d->staticWidget == KHTMLViewPrivate::SBFull && m_kwp->isRedirected())
03460         return;
03461 
03462     d->staticWidget = partial ?
03463                           KHTMLViewPrivate::SBPartial : KHTMLViewPrivate::SBFull;
03464 }
03465 
03466 void KHTMLView::setHasNormalBackground()
03467 {
03468     // full static iframe is irreversible for now
03469     if (d->staticWidget == KHTMLViewPrivate::SBFull && m_kwp->isRedirected())
03470         return;
03471 
03472     d->staticWidget = KHTMLViewPrivate::SBNone;
03473 }
03474 
03475 void KHTMLView::addStaticObject(bool fixed)
03476 {
03477     if (fixed)
03478         d->fixedObjectsCount++;
03479     else
03480         d->staticObjectsCount++;
03481 
03482     setHasStaticBackground( true /*partial*/ );
03483 }
03484 
03485 void KHTMLView::removeStaticObject(bool fixed)
03486 {
03487     if (fixed)
03488         d->fixedObjectsCount--;
03489     else
03490         d->staticObjectsCount--;
03491 
03492     assert( d->fixedObjectsCount >= 0 && d->staticObjectsCount >= 0 );
03493 
03494     if (!d->staticObjectsCount && !d->fixedObjectsCount)
03495         setHasNormalBackground();
03496     else
03497         setHasStaticBackground( true /*partial*/ );
03498 }
03499 
03500 void KHTMLView::setVerticalScrollBarPolicy( Qt::ScrollBarPolicy policy )
03501 {
03502 #ifndef KHTML_NO_SCROLLBARS
03503     d->vpolicy = policy;
03504     QScrollArea::setVerticalScrollBarPolicy(policy);
03505 #else
03506     Q_UNUSED( policy );
03507 #endif
03508 }
03509 
03510 void KHTMLView::setHorizontalScrollBarPolicy( Qt::ScrollBarPolicy policy )
03511 {
03512 #ifndef KHTML_NO_SCROLLBARS
03513     d->hpolicy = policy;
03514     QScrollArea::setHorizontalScrollBarPolicy(policy);
03515 #else
03516     Q_UNUSED( policy );
03517 #endif
03518 }
03519 
03520 void KHTMLView::restoreScrollBar()
03521 {
03522     int ow = visibleWidth();
03523     QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
03524     if (visibleWidth() != ow)
03525         layout();
03526     d->prevScrollbarVisible = verticalScrollBar()->isVisible();
03527 }
03528 
03529 QStringList KHTMLView::formCompletionItems(const QString &name) const
03530 {
03531     if (!m_part->settings()->isFormCompletionEnabled())
03532         return QStringList();
03533     if (!d->formCompletions)
03534         d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
03535     return d->formCompletions->group("").readEntry(name, QStringList());
03536 }
03537 
03538 void KHTMLView::clearCompletionHistory(const QString& name)
03539 {
03540     if (!d->formCompletions)
03541     {
03542         d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
03543     }
03544     d->formCompletions->group("").writeEntry(name, "");
03545     d->formCompletions->sync();
03546 }
03547 
03548 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
03549 {
03550     if (!m_part->settings()->isFormCompletionEnabled())
03551         return;
03552     // don't store values that are all numbers or just numbers with
03553     // dashes or spaces as those are likely credit card numbers or
03554     // something similar
03555     bool cc_number(true);
03556     for ( int i = 0; i < value.length(); ++i)
03557     {
03558       QChar c(value[i]);
03559       if (!c.isNumber() && c != '-' && !c.isSpace())
03560       {
03561         cc_number = false;
03562         break;
03563       }
03564     }
03565     if (cc_number)
03566       return;
03567     QStringList items = formCompletionItems(name);
03568     if (!items.contains(value))
03569         items.prepend(value);
03570     while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
03571         items.erase(items.isEmpty() ? items.end() : --items.end());
03572     d->formCompletions->group("").writeEntry(name, items);
03573 }
03574 
03575 void KHTMLView::addNonPasswordStorableSite(const QString& host)
03576 {
03577     if (!d->formCompletions) {
03578         d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
03579     }
03580 
03581     KConfigGroup cg( d->formCompletions, "NonPasswordStorableSites");
03582     QStringList sites = cg.readEntry("Sites", QStringList());
03583     sites.append(host);
03584     cg.writeEntry("Sites", sites);
03585     cg.sync();
03586 }
03587 
03588 
03589 void KHTMLView::delNonPasswordStorableSite(const QString& host)
03590 {
03591     if (!d->formCompletions) {
03592         d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
03593     }
03594 
03595     KConfigGroup cg( d->formCompletions, "NonPasswordStorableSites");
03596     QStringList sites = cg.readEntry("Sites", QStringList());
03597     sites.removeOne(host);
03598     cg.writeEntry("Sites", sites);
03599     cg.sync();
03600 }
03601 
03602 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
03603 {
03604     if (!d->formCompletions) {
03605         d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
03606     }
03607     QStringList sites =  d->formCompletions->group( "NonPasswordStorableSites" ).readEntry("Sites", QStringList());
03608     return (sites.indexOf(host) != -1);
03609 }
03610 
03611 // returns true if event should be swallowed
03612 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
03613                    DOM::NodeImpl *targetNodeNonShared, bool cancelable,
03614                    int detail,QMouseEvent *_mouse, bool setUnder,
03615                    int mouseEventType, int orient)
03616 {
03617     // if the target node is a text node, dispatch on the parent node - rdar://4196646 (and #76948)
03618     if (targetNode && targetNode->isTextNode())
03619         targetNode = targetNode->parentNode();
03620 
03621     if (d->underMouse)
03622     d->underMouse->deref();
03623     d->underMouse = targetNode;
03624     if (d->underMouse)
03625     d->underMouse->ref();
03626 
03627     if (d->underMouseNonShared)
03628     d->underMouseNonShared->deref();
03629     d->underMouseNonShared = targetNodeNonShared;
03630     if (d->underMouseNonShared)
03631     d->underMouseNonShared->ref();
03632 
03633     bool isWheelEvent = (mouseEventType == DOM::NodeImpl::MouseWheel);
03634 
03635     int exceptioncode = 0;
03636     int pageX = _mouse->x();
03637     int pageY = _mouse->y();
03638     revertTransforms(pageX, pageY);
03639     int clientX = pageX - contentsX();
03640     int clientY = pageY - contentsY();
03641     int screenX = _mouse->globalX();
03642     int screenY = _mouse->globalY();
03643     int button = -1;
03644     switch (_mouse->button()) {
03645     case Qt::LeftButton:
03646         button = 0;
03647         break;
03648     case Qt::MidButton:
03649         button = 1;
03650         break;
03651     case Qt::RightButton:
03652         button = 2;
03653         break;
03654     default:
03655         break;
03656     }
03657     if (d->accessKeysEnabled && d->accessKeysPreActivate && button!=-1)
03658         d->accessKeysPreActivate=false;
03659 
03660     bool ctrlKey = (_mouse->modifiers() & Qt::ControlModifier);
03661     bool altKey = (_mouse->modifiers() & Qt::AltModifier);
03662     bool shiftKey = (_mouse->modifiers() & Qt::ShiftModifier);
03663     bool metaKey = (_mouse->modifiers() & Qt::MetaModifier);
03664 
03665     // mouseout/mouseover
03666     if (setUnder && d->oldUnderMouse != targetNode) {
03667         if (d->oldUnderMouse && d->oldUnderMouse->document() != m_part->xmlDocImpl()) {
03668             d->oldUnderMouse->deref();
03669             d->oldUnderMouse = 0;
03670         }
03671         // send mouseout event to the old node
03672         if (d->oldUnderMouse) {
03673         // send mouseout event to the old node
03674             MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
03675                             true,true,m_part->xmlDocImpl()->defaultView(),
03676                             0,screenX,screenY,clientX,clientY,pageX, pageY,
03677                             ctrlKey,altKey,shiftKey,metaKey,
03678                             button,targetNode);
03679             me->ref();
03680             d->oldUnderMouse->dispatchEvent(me,exceptioncode,true);
03681             me->deref();
03682         }
03683         // send mouseover event to the new node
03684     if (targetNode) {
03685         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
03686                             true,true,m_part->xmlDocImpl()->defaultView(),
03687                             0,screenX,screenY,clientX,clientY,pageX, pageY,
03688                             ctrlKey,altKey,shiftKey,metaKey,
03689                             button,d->oldUnderMouse);
03690 
03691             me->ref();
03692             targetNode->dispatchEvent(me,exceptioncode,true);
03693         me->deref();
03694     }
03695     if (d->oldUnderMouse)
03696         d->oldUnderMouse->deref();
03697         d->oldUnderMouse = targetNode;
03698         if (d->oldUnderMouse)
03699             d->oldUnderMouse->ref();
03700     }
03701 
03702     bool swallowEvent = false;
03703 
03704     if (targetNode) {
03705     // if the target node is a disabled widget, we don't want any full-blown mouse events
03706     if (targetNode->isGenericFormElement()
03707          && static_cast<HTMLGenericFormElementImpl*>(targetNode)->disabled())
03708         return true;
03709 
03710         // send the actual event
03711         bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
03712                           _mouse->type() == QEvent::MouseButtonDblClick );
03713         MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
03714                         true,cancelable,m_part->xmlDocImpl()->defaultView(),
03715                         detail,screenX,screenY,clientX,clientY,pageX, pageY,
03716                         ctrlKey,altKey,shiftKey,metaKey,
03717                         button,0, isWheelEvent ? 0 : _mouse, dblclick,
03718                         isWheelEvent ? static_cast<MouseEventImpl::Orientation>(orient) : MouseEventImpl::ONone );
03719         me->ref();
03720         if ( !d->m_mouseEventsTarget && RenderLayer::gScrollBar && eventId == EventImpl::MOUSEDOWN_EVENT )
03721             // button is pressed inside a layer scrollbar, so make it the target for future mousemove events until released
03722             d->m_mouseEventsTarget = RenderLayer::gScrollBar;
03723         if ( d->m_mouseEventsTarget && qobject_cast<QScrollBar*>(d->m_mouseEventsTarget) &&
03724              dynamic_cast<KHTMLWidget*>(static_cast<QWidget*>(d->m_mouseEventsTarget)) ) {
03725             // we have a sticky mouse event target and it is a layer's scrollbar. Forward events manually.
03726             // ### should use the dom
03727             KHTMLWidget*w = dynamic_cast<KHTMLWidget*>(static_cast<QWidget*>(d->m_mouseEventsTarget));
03728             QPoint p = w->m_kwp->absolutePos();
03729             QMouseEvent fw(_mouse->type(), QPoint(pageX, pageY)-p, _mouse->button(), _mouse->buttons(), _mouse->modifiers());
03730             static_cast<RenderWidget::EventPropagator *>(static_cast<QWidget*>(d->m_mouseEventsTarget))->sendEvent(&fw);
03731             if (_mouse->type() == QMouseEvent::MouseButtonPress && _mouse->button() == Qt::RightButton) {
03732                 QContextMenuEvent cme(QContextMenuEvent::Mouse, p);
03733                 static_cast<RenderWidget::EventPropagator *>(static_cast<QWidget*>(d->m_mouseEventsTarget))->sendEvent(&cme);
03734                 d->m_mouseEventsTarget = 0;
03735             }
03736             swallowEvent = true;
03737         } else {
03738             targetNode->dispatchEvent(me,exceptioncode,true);
03739         bool defaultHandled = me->defaultHandled();
03740             if (defaultHandled || me->defaultPrevented())
03741                 swallowEvent = true;
03742         }
03743         if (eventId == EventImpl::MOUSEDOWN_EVENT && !me->defaultPrevented()) {
03744             // Focus should be shifted on mouse down, not on a click.  -dwh
03745             // Blur current focus node when a link/button is clicked; this
03746             // is expected by some sites that rely on onChange handlers running
03747             // from form fields before the button click is processed.
03748             DOM::NodeImpl* nodeImpl = targetNode;
03749             for ( ; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode())
03750                 {}
03751             if (nodeImpl && nodeImpl->isMouseFocusable())
03752                 m_part->xmlDocImpl()->setFocusNode(nodeImpl);
03753             else if (!nodeImpl || !nodeImpl->focused())
03754                 m_part->xmlDocImpl()->setFocusNode(0);
03755         }
03756         me->deref();
03757     }
03758 
03759     return swallowEvent;
03760 }
03761 
03762 void KHTMLView::setIgnoreWheelEvents( bool e )
03763 {
03764     d->ignoreWheelEvents = e;
03765 }
03766 
03767 #ifndef QT_NO_WHEELEVENT
03768 
03769 void KHTMLView::wheelEvent(QWheelEvent* e)
03770 {
03771     // check if we should reset the state of the indicator describing if
03772     // we are currently scrolling the view as a result of wheel events
03773     if (d->scrollingFromWheel != QPoint(-1,-1) && d->scrollingFromWheel != QCursor::pos())
03774         d->scrollingFromWheel = d->scrollingFromWheelTimerId ? QCursor::pos() : QPoint(-1,-1);
03775 
03776     if (d->accessKeysEnabled && d->accessKeysPreActivate) d->accessKeysPreActivate=false;
03777 
03778     if ( ( e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier )
03779     {
03780         emit zoomView( - e->delta() );
03781         e->accept();
03782     }
03783     else if (d->firstLayoutPending)
03784     {
03785         e->accept();
03786     }
03787     else if( !m_kwp->isRedirected() &&
03788              (   (e->orientation() == Qt::Vertical &&
03789                    ((d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
03790                      || (e->delta() > 0 && contentsY() <= 0)
03791                      || (e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())))
03792               ||
03793                  (e->orientation() == Qt::Horizontal &&
03794                     ((d->ignoreWheelEvents && !horizontalScrollBar()->isVisible())
03795                      || (e->delta() > 0 && contentsX() <=0)
03796                      || (e->delta() < 0 && contentsX() >= contentsWidth() - visibleWidth()))))
03797             && m_part->parentPart())
03798     {
03799         if ( m_part->parentPart()->view() )
03800             m_part->parentPart()->view()->wheelEvent( e );
03801         e->ignore();
03802     }
03803     else
03804     {
03805         int xm = e->x();
03806         int ym = e->y();
03807         revertTransforms(xm, ym);
03808 
03809         DOM::NodeImpl::MouseEvent mev( e->buttons(), DOM::NodeImpl::MouseWheel );
03810         m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
03811 
03812         MouseEventImpl::Orientation o = MouseEventImpl::OVertical;
03813         if (e->orientation() == Qt::Horizontal)
03814             o = MouseEventImpl::OHorizontal;
03815 
03816         QMouseEvent _mouse(QEvent::MouseMove, e->pos(), Qt::NoButton, e->buttons(), e->modifiers());
03817         bool swallow = dispatchMouseEvent(EventImpl::KHTML_MOUSEWHEEL_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),
03818                                                true,-e->delta()/40,&_mouse,true,DOM::NodeImpl::MouseWheel,o);
03819 
03820         if (swallow)
03821             return;
03822 
03823         d->scrollBarMoved = true;
03824         d->scrollingFromWheel = QCursor::pos();
03825         if (d->smoothScrollMode != SSMDisabled)
03826             d->shouldSmoothScroll = true;
03827         if (d->scrollingFromWheelTimerId)
03828             killTimer(d->scrollingFromWheelTimerId);
03829         d->scrollingFromWheelTimerId = startTimer(400);
03830 
03831         if (m_part->parentPart()) {
03832             // don't propagate if we are a sub-frame and our scrollbars are already at end of range
03833             bool h = (static_cast<QWheelEvent*>(e)->orientation() == Qt::Horizontal);
03834             bool d = (static_cast<QWheelEvent*>(e)->delta() < 0);
03835             QScrollBar* hsb = horizontalScrollBar();
03836             QScrollBar* vsb = verticalScrollBar();
03837             if ( (h && ((d && hsb->value() == hsb->maximum()) || (!d && hsb->value() == hsb->minimum()))) ||
03838                 (!h && ((d && vsb->value() == vsb->maximum()) || (!d && vsb->value() == vsb->minimum()))) ) {
03839                 e->accept();
03840                 return;
03841             }
03842         }
03843         QScrollArea::wheelEvent( e );
03844     }
03845 
03846 }
03847 #endif
03848 
03849 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
03850 {
03851     // Still overridden for BC reasons only...
03852     QScrollArea::dragEnterEvent( ev );
03853 }
03854 
03855 void KHTMLView::dropEvent( QDropEvent *ev )
03856 {
03857     // Still overridden for BC reasons only...
03858     QScrollArea::dropEvent( ev );
03859 }
03860 
03861 void KHTMLView::focusInEvent( QFocusEvent *e )
03862 {
03863     DOM::NodeImpl* fn = m_part->xmlDocImpl() ? m_part->xmlDocImpl()->focusNode() : 0;
03864 #ifndef KHTML_NO_TYPE_AHEAD_FIND
03865     if (!fn || m_part->isCaretMode())
03866         m_part->enableFindAheadActions( true );
03867 #endif
03868     if (fn && fn->renderer() && fn->renderer()->isWidget() &&
03869         (e->reason() != Qt::MouseFocusReason) &&
03870         static_cast<khtml::RenderWidget*>(fn->renderer())->widget())
03871         static_cast<khtml::RenderWidget*>(fn->renderer())->widget()->setFocus();
03872     m_part->setSelectionVisible();
03873     QScrollArea::focusInEvent( e );
03874 }
03875 
03876 void KHTMLView::focusOutEvent( QFocusEvent *e )
03877 {
03878     if (m_part) {
03879         m_part->stopAutoScroll();
03880         m_part->setSelectionVisible(false);
03881     }
03882 
03883 #ifndef KHTML_NO_TYPE_AHEAD_FIND
03884     if(d->typeAheadActivated)
03885     {
03886         findTimeout();
03887     }
03888     if (m_part)
03889         m_part->enableFindAheadActions( false );
03890 #endif // KHTML_NO_TYPE_AHEAD_FIND
03891 
03892     if ( d->cursorIconWidget )
03893         d->cursorIconWidget->hide();
03894 
03895     QScrollArea::focusOutEvent( e );
03896 }
03897 
03898 void KHTMLView::scrollContentsBy( int dx, int dy )
03899 {
03900     if (!dx && !dy) return;
03901 
03902     if ( !d->firstLayoutPending && !d->complete && m_part->xmlDocImpl() &&
03903           d->layoutSchedulingEnabled) {
03904         // contents scroll while we are not complete: we need to check our layout *now*
03905         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>( m_part->xmlDocImpl()->renderer() );
03906         if (root && root->needsLayout()) {
03907             unscheduleRelayout();
03908             layout();
03909         }
03910     }
03911 
03912     if ( d->shouldSmoothScroll && d->smoothScrollMode != SSMDisabled && m_part->xmlDocImpl() &&
03913           m_part->xmlDocImpl()->renderer() && (d->smoothScrollMode != SSMWhenEfficient || d->smoothScrollMissedDeadlines != sWayTooMany)) {
03914 
03915         bool doSmoothScroll = (!d->staticWidget || d->smoothScrollMode == SSMEnabled);
03916 
03917         int numStaticPixels = 0;
03918         QRegion r = static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->staticRegion();
03919 
03920         // only do smooth scrolling if static region is relatively small
03921         if (!doSmoothScroll && d->staticWidget == KHTMLViewPrivate::SBPartial && r.rects().size() <= 10) {
03922             foreach(QRect rr, r.rects())
03923                 numStaticPixels += rr.width()*rr.height();
03924             if ((numStaticPixels < sSmoothScrollMinStaticPixels) || (numStaticPixels*8 < visibleWidth()*visibleHeight()))
03925                 doSmoothScroll = true;
03926         }
03927         if (doSmoothScroll) {
03928             setupSmoothScrolling(dx, dy);
03929             return;
03930         }
03931     }
03932 
03933     if (!d->scrollingSelf) {
03934         d->scrollBarMoved = true;
03935         d->contentsMoving = true;
03936         // ensure quick reset of contentsMoving flag
03937         scheduleRepaint(0, 0, 0, 0);
03938     }
03939 
03940     if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->documentElement()) {
03941         // ### FIXME: there is something wrong with this event.
03942         // With a capturing listener on document and window, window's should fire first, then document's.
03943         // Also, this doesn't work: <body onload="document.onscroll=function() {alert('ok')}"><div style=height:2000>
03944         m_part->xmlDocImpl()->documentElement()->dispatchWindowEvent(EventImpl::SCROLL_EVENT, false, false);
03945     }
03946 
03947     if (QApplication::isRightToLeft())
03948         dx = -dx;
03949 
03950     if (!d->smoothScrolling) {
03951         d->updateContentsXY();
03952     } else {
03953         d->contentsX -= dx;
03954         d->contentsY -= dy;
03955     }
03956     if (widget()->pos() != QPoint(0,0)) {
03957          kDebug(6000) << "Static widget wasn't positioned at (0,0). This should NOT happen. Please report this event to developers.";
03958          kDebug(6000) <<  kBacktrace();
03959          widget()->move(0,0);
03960     }
03961 
03962     QWidget *w = widget();
03963     QPoint off;
03964     if (m_kwp->isRedirected()) {
03965         // This is a redirected sub frame. Translate to root view context
03966         KHTMLView* v = m_kwp->rootViewPos( off );
03967         if (v)
03968             w = v->widget();
03969         off = viewport()->mapTo(this, off);
03970     }
03971 
03972     if ( d->staticWidget ) {
03973 
03974         // now remove from view the external widgets that must have completely
03975         // disappeared after dx/dy scroll delta is effective
03976         if (!d->visibleWidgets.isEmpty())
03977             checkExternalWidgetsPosition();
03978 
03979         if ( d->staticWidget == KHTMLViewPrivate::SBPartial
03980                                 && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer() ) {
03981             // static objects might be selectively repainted, like stones in flowing water
03982             QRegion r = static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->staticRegion();
03983             r.translate( -contentsX(), -contentsY());
03984             QVector<QRect> ar = r.rects();
03985 
03986             for (int i = 0; i < ar.size() ; ++i) {
03987                 widget()->update( ar[i] );
03988             }
03989             r = QRegion(QRect(0, 0, visibleWidth(), visibleHeight())) - r;
03990             ar = r.rects();
03991             for (int i = 0; i < ar.size() ; ++i) {
03992                 w->scroll( dx, dy, ar[i].translated(off) );
03993             }
03994             d->scrollExternalWidgets(dx, dy);
03995         } else {
03996             // we can't avoid a full update
03997             widget()->update();
03998         }
03999         return;
04000     }
04001 
04002     if (m_kwp->isRedirected()) {
04003         const QRect rect(off.x(), off.y(), visibleWidth() * d->zoomLevel / 100, visibleHeight() * d->zoomLevel / 100);
04004         w->scroll(dx, dy, rect);
04005         if (d->zoomLevel != 100) {
04006             w->update(rect); // without this update we are getting bad rendering when an iframe is zoomed in
04007         }
04008     }  else {
04009         widget()->scroll(dx, dy, widget()->rect() & viewport()->rect());
04010     }
04011 
04012     d->scrollExternalWidgets(dx, dy);
04013 }
04014 
04015 void KHTMLView::setupSmoothScrolling(int dx, int dy)
04016 {
04017     // full scroll is remaining scroll plus new scroll
04018     d->dx = d->dx + dx;
04019     d->dy = d->dy + dy;
04020 
04021     if (d->dx == 0 && d->dy == 0) return;
04022 
04023     int steps = sSmoothScrollTime/sSmoothScrollTick;
04024 
04025     // average step size (stored in 1/16 px/step)
04026     d->ddx = (d->dx*16)/(steps+1);
04027     d->ddy = (d->dy*16)/(steps+1);
04028 
04029     if (abs(d->ddx) < 64 && abs(d->ddy) < 64) {
04030     // Don't move slower than average 4px/step in minimum one direction
04031     if (d->ddx > 0) d->ddx = qMax(d->ddx, 64);
04032     if (d->ddy > 0) d->ddy = qMax(d->ddy, 64);
04033     if (d->ddx < 0) d->ddx = qMin(d->ddx, -64);
04034     if (d->ddy < 0) d->ddy = qMin(d->ddy, -64);
04035     // This means fewer than normal steps
04036     steps = qMax(d->ddx ? (d->dx*16)/d->ddx : 0, d->ddy ? (d->dy*16)/d->ddy : 0);
04037     if (steps < 1) steps = 1;
04038     d->ddx = (d->dx*16)/(steps+1);
04039     d->ddy = (d->dy*16)/(steps+1);
04040     }
04041 
04042     // step size starts at double average speed and ends at 0
04043     d->ddx *= 2;
04044     d->ddy *= 2;
04045 
04046     // deacceleration speed
04047     d->dddx = (d->ddx+1)/steps;
04048     d->dddy = (d->ddy+1)/steps;
04049 
04050     if (!d->smoothScrolling) {
04051         d->startScrolling();
04052         scrollTick();
04053     }
04054     d->smoothScrollStopwatch.start();
04055 }
04056 
04057 void KHTMLView::scrollTick() {
04058     if (d->dx == 0 && d->dy == 0) {
04059         d->stopScrolling();
04060         return;
04061     }
04062 
04063     // step size + remaining partial step
04064     int tddx = d->ddx + d->rdx;
04065     int tddy = d->ddy + d->rdy;
04066 
04067     // don't go under 1px/step
04068     if (tddx > 0 && tddx < 16) tddx = 16;
04069     if (tddy > 0 && tddy < 16) tddy = 16;
04070     if (tddx < 0 && tddx > -16) tddx = -16;
04071     if (tddy < 0 && tddy > -16) tddy = -16;
04072 
04073     // full pixel steps to scroll in this step
04074     int ddx = tddx / 16;
04075     int ddy = tddy / 16;
04076     // remaining partial step (this is especially needed for 1.x sized steps)
04077     d->rdx = tddx % 16;
04078     d->rdy = tddy % 16;
04079 
04080     // limit step to requested scrolling distance
04081     if (abs(ddx) > abs(d->dx)) ddx = d->dx;
04082     if (abs(ddy) > abs(d->dy)) ddy = d->dy;
04083 
04084     // Don't stop if deaccelerated too fast
04085     if (!ddx) ddx = d->dx;
04086     if (!ddy) ddy = d->dy;
04087 
04088     // update remaining scroll
04089     d->dx -= ddx;
04090     d->dy -= ddy;
04091 
04092     d->shouldSmoothScroll = false;
04093     scrollContentsBy(ddx, ddy);
04094 
04095     // only consider decelerating if we aren't too far behind schedule
04096     if (d->smoothScrollStopwatch.elapsed() < 2*sSmoothScrollTick) { 
04097         // update scrolling speed
04098         int dddx = d->dddx;
04099         int dddy = d->dddy;
04100         // don't change direction
04101         if (abs(dddx) > abs(d->ddx)) dddx = d->ddx;
04102         if (abs(dddy) > abs(d->ddy)) dddy = d->ddy;
04103 
04104         d->ddx -= dddx;
04105         d->ddy -= dddy;
04106         d->smoothScrollMissedDeadlines = 0;
04107     } else {
04108         if (d->smoothScrollMissedDeadlines != sWayTooMany && 
04109                 (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->parsing())) {
04110             d->smoothScrollMissedDeadlines++;
04111             if (d->smoothScrollMissedDeadlines >= sMaxMissedDeadlines) {
04112                 // we missed many deadlines in a row!
04113                 // time to signal we had enough..
04114                 d->smoothScrollMissedDeadlines = sWayTooMany;
04115             }
04116         }
04117     }
04118     d->smoothScrollStopwatch.start();
04119 }
04120 
04121 
04122 void KHTMLView::addChild(QWidget * child, int x, int y)
04123 {
04124     if (!child)
04125         return;
04126 
04127     if (child->parent() != widget())
04128         child->setParent( widget() );
04129 
04130     // ### handle pseudo-zooming of non-redirected widgets (e.g. just resize'em)
04131 
04132     child->move(x-contentsX(), y-contentsY());
04133 }
04134 
04135 void KHTMLView::timerEvent ( QTimerEvent *e )
04136 {
04137 //    kDebug() << "timer event " << e->timerId();
04138     if ( e->timerId() == d->scrollTimerId ) {
04139         if( d->scrollSuspended )
04140             return;
04141         switch (d->scrollDirection) {
04142             case KHTMLViewPrivate::ScrollDown:
04143                 if (contentsY() + visibleHeight () >= contentsHeight())
04144                     d->newScrollTimer(this, 0);
04145                 else
04146                     verticalScrollBar()->setValue( verticalScrollBar()->value() +d->scrollBy );
04147                 break;
04148             case KHTMLViewPrivate::ScrollUp:
04149                 if (contentsY() <= 0)
04150                     d->newScrollTimer(this, 0);
04151                 else
04152                     verticalScrollBar()->setValue( verticalScrollBar()->value() -d->scrollBy );
04153                 break;
04154             case KHTMLViewPrivate::ScrollRight:
04155                 if (contentsX() + visibleWidth () >= contentsWidth())
04156                     d->newScrollTimer(this, 0);
04157                 else
04158                     horizontalScrollBar()->setValue( horizontalScrollBar()->value() +d->scrollBy );
04159                 break;
04160             case KHTMLViewPrivate::ScrollLeft:
04161                 if (contentsX() <= 0)
04162                     d->newScrollTimer(this, 0);
04163                 else
04164                     horizontalScrollBar()->setValue( horizontalScrollBar()->value() -d->scrollBy );
04165                 break;
04166         }
04167         return;
04168     }
04169     else if ( e->timerId() == d->scrollingFromWheelTimerId ) {
04170         killTimer( d->scrollingFromWheelTimerId );
04171         d->scrollingFromWheelTimerId = 0;
04172     } else if ( e->timerId() == d->layoutTimerId ) {
04173         if (d->firstLayoutPending && d->layoutAttemptCounter < 4
04174                            && (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->readyForLayout())) {
04175             d->layoutAttemptCounter++;
04176             killTimer(d->layoutTimerId);
04177             d->layoutTimerId = 0;
04178             scheduleRelayout();
04179             return;
04180         }
04181         layout();
04182         d->scheduledLayoutCounter++;
04183         if (d->firstLayoutPending) {
04184             d->firstLayoutPending = false;
04185             verticalScrollBar()->setEnabled( true );
04186             horizontalScrollBar()->setEnabled( true );
04187         }
04188     }
04189 
04190     d->contentsMoving = false;
04191     if( m_part->xmlDocImpl() ) {
04192     DOM::DocumentImpl *document = m_part->xmlDocImpl();
04193     khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
04194 
04195     if ( root && root->needsLayout() ) {
04196         if (d->repaintTimerId)
04197             killTimer(d->repaintTimerId);
04198         d->repaintTimerId = 0;
04199         scheduleRelayout();
04200         return;
04201     }
04202     }
04203 
04204     if (d->repaintTimerId)
04205         killTimer(d->repaintTimerId);
04206     d->repaintTimerId = 0;
04207 
04208     QRect updateRegion;
04209     const QVector<QRect> rects = d->updateRegion.rects();
04210 
04211     d->updateRegion = QRegion();
04212 
04213     if ( rects.size() )
04214         updateRegion = rects[0];
04215 
04216     for ( int i = 1; i < rects.size(); ++i ) {
04217         QRect newRegion = updateRegion.unite(rects[i]);
04218         if (2*newRegion.height() > 3*updateRegion.height() )
04219         {
04220             repaintContents( updateRegion );
04221             updateRegion = rects[i];
04222         }
04223         else
04224             updateRegion = newRegion;
04225     }
04226 
04227     if ( !updateRegion.isNull() )
04228         repaintContents( updateRegion );
04229 
04230     // As widgets can only be accurately positioned during painting, every layout might
04231     // dissociate a widget from its RenderWidget. E.g: if a RenderWidget was visible before layout, but the layout
04232     // pushed it out of the viewport, it will not be repainted, and consequently it's associated widget won't be repositioned.
04233     // Thus we need to check each supposedly 'visible' widget at the end of layout, and remove it in case it's no more in sight.
04234 
04235     if (d->dirtyLayout && !d->visibleWidgets.isEmpty())
04236         checkExternalWidgetsPosition();
04237 
04238     d->dirtyLayout = false;
04239 
04240     emit repaintAccessKeys();
04241     if (d->emitCompletedAfterRepaint) {
04242         bool full = d->emitCompletedAfterRepaint == KHTMLViewPrivate::CSFull;
04243         d->emitCompletedAfterRepaint = KHTMLViewPrivate::CSNone;
04244         if ( full )
04245             emit m_part->completed();
04246         else
04247             emit m_part->completed(true);
04248     }
04249 }
04250 
04251 void KHTMLView::checkExternalWidgetsPosition()
04252 {
04253     QWidget* w;
04254     QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
04255     QList<RenderWidget*> toRemove;
04256     QHashIterator<void*, QWidget*> it(d->visibleWidgets);
04257     while (it.hasNext()) {
04258         int xp = 0, yp = 0;
04259         it.next();
04260         RenderWidget* rw = static_cast<RenderWidget*>( it.key() );
04261         if (!rw->absolutePosition(xp, yp) ||
04262             !visibleRect.intersects(QRect(xp, yp, it.value()->width(), it.value()->height())))
04263             toRemove.append(rw);
04264     }
04265     foreach (RenderWidget* r, toRemove)
04266         if ( (w = d->visibleWidgets.take(r) ) )
04267             w->move( 0, -500000);
04268 }
04269 
04270 void KHTMLView::scheduleRelayout(khtml::RenderObject * /*clippedObj*/)
04271 {
04272     if (!d->layoutSchedulingEnabled || d->layoutTimerId)
04273         return;
04274 
04275     int time = 0;
04276     if (d->firstLayoutPending) {
04277         // Any repaint happening while we have no content blanks the viewport ("white flash").
04278         // Hence the need to delay the first layout as much as we can.
04279         // Only if the document gets stuck for too long in incomplete state will we allow the blanking.
04280         time = d->layoutAttemptCounter ?
04281                sLayoutAttemptDelay + sLayoutAttemptIncrement*d->layoutAttemptCounter : sFirstLayoutDelay;
04282     } else if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()) {
04283         // Delay between successive layouts in parsing mode.
04284         // Increment reflects the decaying importance of visual feedback over time.
04285         time = qMin(2000, sParsingLayoutsInterval + d->scheduledLayoutCounter*sParsingLayoutsIncrement);
04286     }
04287     d->layoutTimerId = startTimer( time );
04288 }
04289 
04290 void KHTMLView::unscheduleRelayout()
04291 {
04292     if (!d->layoutTimerId)
04293         return;
04294 
04295     killTimer(d->layoutTimerId);
04296     d->layoutTimerId = 0;
04297 }
04298 
04299 void KHTMLView::unscheduleRepaint()
04300 {
04301     if (!d->repaintTimerId)
04302         return;
04303 
04304     killTimer(d->repaintTimerId);
04305     d->repaintTimerId = 0;
04306 }
04307 
04308 void KHTMLView::scheduleRepaint(int x, int y, int w, int h, bool asap)
04309 {
04310     bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
04311 
04312 //     kDebug() << "parsing " << parsing;
04313 //     kDebug() << "complete " << d->complete;
04314 
04315     int time = parsing && !d->firstLayoutPending ? 150 : (!asap ? ( !d->complete ? 80 : 20 ) : 0);
04316 
04317 #ifdef DEBUG_FLICKER
04318     QPainter p;
04319     p.begin( viewport() );
04320 
04321     int vx, vy;
04322     contentsToViewport( x, y, vx, vy );
04323     p.fillRect( vx, vy, w, h, Qt::red );
04324     p.end();
04325 #endif
04326 
04327     d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
04328 
04329     if (asap && !parsing)
04330         unscheduleRepaint();
04331 
04332     if ( !d->repaintTimerId )
04333         d->repaintTimerId = startTimer( time );
04334 
04335 //     kDebug() << "starting timer " << time;
04336 }
04337 
04338 void KHTMLView::complete( bool pendingAction )
04339 {
04340 //     kDebug() << "KHTMLView::complete()";
04341 
04342     d->complete = true;
04343 
04344     // is there a relayout pending?
04345     if (d->layoutTimerId)
04346     {
04347 //         kDebug() << "requesting relayout now";
04348         // do it now
04349         killTimer(d->layoutTimerId);
04350         d->layoutTimerId = startTimer( 0 );
04351         d->emitCompletedAfterRepaint = pendingAction ?
04352             KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
04353     }
04354 
04355     // is there a repaint pending?
04356     if (d->repaintTimerId)
04357     {
04358 //         kDebug() << "requesting repaint now";
04359         // do it now
04360         killTimer(d->repaintTimerId);
04361         d->repaintTimerId = startTimer( 0 );
04362         d->emitCompletedAfterRepaint = pendingAction ?
04363             KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
04364     }
04365 
04366     if (!d->emitCompletedAfterRepaint)
04367     {
04368         if (!pendingAction)
04369         emit m_part->completed();
04370         else
04371             emit m_part->completed(true);
04372     }
04373 
04374 }
04375 
04376 void KHTMLView::updateScrollBars()
04377 {
04378     const QWidget *view = widget();
04379     if (!view)
04380         return;
04381 
04382     QSize p = viewport()->size();
04383     QSize m = maximumViewportSize();
04384 
04385     if (m.expandedTo(view->size()) == m)
04386         p = m; // no scroll bars needed
04387 
04388     QSize v = view->size();
04389     horizontalScrollBar()->setRange(0, v.width() - p.width());
04390     horizontalScrollBar()->setPageStep(p.width());
04391     verticalScrollBar()->setRange(0, v.height() - p.height());
04392     verticalScrollBar()->setPageStep(p.height());
04393     if (!d->smoothScrolling) {
04394         d->updateContentsXY();
04395     }
04396 }
04397 
04398 void KHTMLView::slotMouseScrollTimer()
04399 {
04400      horizontalScrollBar()->setValue( horizontalScrollBar()->value() +d->m_mouseScroll_byX );
04401      verticalScrollBar()->setValue( verticalScrollBar()->value() +d->m_mouseScroll_byY);
04402 }
04403 
04404 
04405 static DOM::Position positionOfLineBoundary(const DOM::Position &pos, bool toEnd)
04406 {
04407     Selection sel = pos;
04408     sel.expandUsingGranularity(Selection::LINE);
04409     return toEnd ? sel.end() : sel.start();
04410 }
04411 
04412 inline static DOM::Position positionOfLineBegin(const DOM::Position &pos)
04413 {
04414     return positionOfLineBoundary(pos, false);
04415 }
04416 
04417 inline static DOM::Position positionOfLineEnd(const DOM::Position &pos)
04418 {
04419     return positionOfLineBoundary(pos, true);
04420 }
04421 
04422 bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
04423 {
04424   EditorContext *ec = &m_part->d->editor_context;
04425   Selection &caret = ec->m_selection;
04426   Position old_pos = caret.caretPos();
04427   Position pos = old_pos;
04428   bool recalcXPos = true;
04429   bool handled = true;
04430 
04431   bool ctrl = _ke->modifiers() & Qt::ControlModifier;
04432   bool shift = _ke->modifiers() & Qt::ShiftModifier;
04433 
04434   switch(_ke->key()) {
04435 
04436     // -- Navigational keys
04437     case Qt::Key_Down:
04438       pos = old_pos.nextLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
04439       recalcXPos = false;
04440       break;
04441 
04442     case Qt::Key_Up:
04443       pos = old_pos.previousLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
04444       recalcXPos = false;
04445       break;
04446 
04447     case Qt::Key_Left:
04448       pos = ctrl ? old_pos.previousWordPosition() : old_pos.previousCharacterPosition();
04449       break;
04450 
04451     case Qt::Key_Right:
04452       pos = ctrl ? old_pos.nextWordPosition() : old_pos.nextCharacterPosition();
04453       break;
04454 
04455     case Qt::Key_PageDown:
04456 //       moveCaretNextPage(); ###
04457       break;
04458 
04459     case Qt::Key_PageUp:
04460 //       moveCaretPrevPage(); ###
04461       break;
04462 
04463     case Qt::Key_Home:
04464       if (ctrl)
04465         /*moveCaretToDocumentBoundary(false)*/; // ###
04466       else
04467         pos = positionOfLineBegin(old_pos);
04468       break;
04469 
04470     case Qt::Key_End:
04471       if (ctrl)
04472         /*moveCaretToDocumentBoundary(true)*/; // ###
04473       else
04474         pos = positionOfLineEnd(old_pos);
04475       break;
04476 
04477     default:
04478       handled = false;
04479 
04480   }/*end switch*/
04481 
04482   if (pos != old_pos) {
04483     m_part->clearCaretRectIfNeeded();
04484 
04485     caret.moveTo(shift ? caret.nonCaretPos() : pos, pos);
04486     int old_x = caret.xPosForVerticalArrowNavigation(Selection::CARETPOS);
04487 
04488     m_part->selectionLayoutChanged();
04489 
04490     // restore old x-position to prevent recalculation
04491     if (!recalcXPos)
04492       m_part->d->editor_context.m_xPosForVerticalArrowNavigation = old_x;
04493 
04494     m_part->emitCaretPositionChanged(pos);
04495     // ### check when to emit it
04496     m_part->notifySelectionChanged();
04497 
04498   }
04499 
04500   if (handled) _ke->accept();
04501   return handled;
04502 }
04503 
04504 #undef DEBUG_CARETMODE

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal