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