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

KHTML

khtmlview.cpp

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

KHTML

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

kdelibs

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