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

KDE's Doxygen guidelines are available online.

KHTML

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal