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