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