| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# khtmlview.cpp

    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 Apple Computer, Inc.
    00009  *
    00010  * This library is free software; you can redistribute it and/or
    00011  * modify it under the terms of the GNU Library General Public
    00012  * License as published by the Free Software Foundation; either
    00013  * version 2 of the License, or (at your option) any later version.
    00014  *
    00015  * This library is distributed in the hope that it will be useful,
    00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00018  * Library General Public License for more details.
    00019  *
    00020  * You should have received a copy of the GNU Library General Public License
    00021  * along with this library; see the file COPYING.LIB.  If not, write to
    00022  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00023  * Boston, MA 02111-1307, USA.
    00024  */
    00025
    00026
    00027 #include "khtmlview.moc"
    00028
    00029 #include "khtmlview.h"
    00030
    00031 #include "khtml_part.h"
    00032 #include "khtml_events.h"
    00033
    00034 #include "html/html_documentimpl.h"
    00035 #include "html/html_inlineimpl.h"
    00036 #include "html/html_formimpl.h"
    00037 #include "rendering/render_arena.h"
    00038 #include "rendering/render_canvas.h"
    00039 #include "rendering/render_frames.h"
    00040 #include "rendering/render_replaced.h"
    00041 #include "rendering/render_layer.h"
    00042 #include "rendering/render_line.h"
    00043 #include "rendering/render_table.h"
    00044 // removeme
    00045 #define protected public
    00046 #include "rendering/render_text.h"
    00047 #undef protected
    00048 #include "xml/dom2_eventsimpl.h"
    00049 #include "css/cssstyleselector.h"
    00050 #include "misc/htmlhashes.h"
    00051 #include "misc/helper.h"
    00052 #include "khtml_settings.h"
    00053 #include "khtml_printsettings.h"
    00054
    00055 #include "khtmlpart_p.h"
    00056
    00057 #ifndef KHTML_NO_CARET
    00058 #include "khtml_caret_p.h"
    00059 #include "xml/dom2_rangeimpl.h"
    00060 #endif
    00061
    00062 #include <kapplication.h>
    00063 #include <kcursor.h>
    00064 #include <kdebug.h>
    00065 #include <kdialogbase.h>
    00066 #include <kiconloader.h>
    00067 #include <kimageio.h>
    00068 #include <klocale.h>
    00069 #include <knotifyclient.h>
    00070 #include <kprinter.h>
    00071 #include <ksimpleconfig.h>
    00072 #include <kstandarddirs.h>
    00073 #include <kstdaccel.h>
    00074 #include <kstringhandler.h>
    00075 #include <kurldrag.h>
    00076
    00077 #include <qbitmap.h>
    00078 #include <qlabel.h>
    00079 #include <qobjectlist.h>
    00080 #include <qpaintdevicemetrics.h>
    00081 #include <qpainter.h>
    00082 #include <qptrdict.h>
    00083 #include <qtooltip.h>
    00084 #include <qstring.h>
    00085 #include <qstylesheet.h>
    00086 #include <qtimer.h>
    00087
    00088 //#define DEBUG_NO_PAINT_BUFFER
    00089
    00090 //#define DEBUG_FLICKER
    00091
    00092 //#define DEBUG_PIXEL
    00093
    00094 #include <X11/Xlib.h>
    00095 #include <fixx11h.h>
    00096
    00097 #define PAINT_BUFFER_HEIGHT 128
    00098
    00099 #if 0
    00100 namespace khtml {
    00101     void dumpLineBoxes(RenderFlow *flow);
    00102 }
    00103 #endif
    00104
    00105 using namespace DOM;
    00106 using namespace khtml;
    00107 class KHTMLToolTip;
    00108
    00109
    00110 #ifndef QT_NO_TOOLTIP
    00111
    00112 class KHTMLToolTip : public QToolTip
    00113 {
    00114 public:
    00115     KHTMLToolTip(KHTMLView *view,  KHTMLViewPrivate* vp) : QToolTip(view->viewport())
    00116     {
    00117         m_view = view;
    00118         m_viewprivate = vp;
    00119     };
    00120
    00121 protected:
    00122     virtual void maybeTip(const QPoint &);
    00123
    00124 private:
    00125     KHTMLView *m_view;
    00126     KHTMLViewPrivate* m_viewprivate;
    00127 };
    00128
    00129 #endif
    00130
    00131 class KHTMLViewPrivate {
    00132     friend class KHTMLToolTip;
    00133 public:
    00134
    00135     enum PseudoFocusNodes {
    00136     PFNone,
    00137     PFTop,
    00138     PFBottom
    00139     };
    00140
    00141     enum CompletedState {
    00142         CSNone = 0,
    00143         CSFull,
    00144         CSActionPending
    00145     };
    00146
    00147     KHTMLViewPrivate()
    00148         : underMouse( 0 ), underMouseNonShared( 0 )
    00149     {
    00150 #ifndef KHTML_NO_CARET
    00151     m_caretViewContext = 0;
    00152     m_editorContext = 0;
    00153 #endif // KHTML_NO_CARET
    00154         postponed_autorepeat = NULL;
    00155         reset();
    00156         vmode = QScrollView::Auto;
    00157     hmode = QScrollView::Auto;
    00158         tp=0;
    00159         paintBuffer=0;
    00160         vertPaintBuffer=0;
    00161         formCompletions=0;
    00162         prevScrollbarVisible = true;
    00163     tooltip = 0;
    00164         possibleTripleClick = false;
    00165         emitCompletedAfterRepaint = CSNone;
    00166     cursor_icon_widget = NULL;
    00167         m_mouseScrollTimer = 0;
    00168         m_mouseScrollIndicator = 0;
    00169     }
    00170     ~KHTMLViewPrivate()
    00171     {
    00172         delete formCompletions;
    00173         delete tp; tp = 0;
    00174         delete paintBuffer; paintBuffer =0;
    00175         delete vertPaintBuffer;
    00176         delete postponed_autorepeat;
    00177         if (underMouse)
    00178         underMouse->deref();
    00179         if (underMouseNonShared)
    00180         underMouseNonShared->deref();
    00181     delete tooltip;
    00182 #ifndef KHTML_NO_CARET
    00183     delete m_caretViewContext;
    00184     delete m_editorContext;
    00185 #endif // KHTML_NO_CARET
    00186         delete cursor_icon_widget;
    00187         delete m_mouseScrollTimer;
    00188         delete m_mouseScrollIndicator;
    00189     }
    00190     void reset()
    00191     {
    00192         if (underMouse)
    00193         underMouse->deref();
    00194     underMouse = 0;
    00195         if (underMouseNonShared)
    00196         underMouseNonShared->deref();
    00197     underMouseNonShared = 0;
    00198         linkPressed = false;
    00199         useSlowRepaints = false;
    00200     tabMovePending = false;
    00201     lastTabbingDirection = true;
    00202     pseudoFocusNode = PFNone;
    00203 #ifndef KHTML_NO_SCROLLBARS
    00204         //We don't turn off the toolbars here
    00205     //since if the user turns them
    00206     //off, then chances are they want them turned
    00207     //off always - even after a reset.
    00208 #else
    00209         vmode = QScrollView::AlwaysOff;
    00210         hmode = QScrollView::AlwaysOff;
    00211 #endif
    00212 #ifdef DEBUG_PIXEL
    00213         timer.start();
    00214         pixelbooth = 0;
    00215         repaintbooth = 0;
    00216 #endif
    00217         scrollBarMoved = false;
    00218         contentsMoving = false;
    00219         ignoreWheelEvents = false;
    00220     borderX = 30;
    00221     borderY = 30;
    00222     clickX = -1;
    00223     clickY = -1;
    00224         prevMouseX = -1;
    00225         prevMouseY = -1;
    00226     clickCount = 0;
    00227     isDoubleClick = false;
    00228     scrollingSelf = false;
    00229         delete postponed_autorepeat;
    00230         postponed_autorepeat = NULL;
    00231     layoutTimerId = 0;
    00232         repaintTimerId = 0;
    00233         scrollTimerId = 0;
    00234         scrollSuspended = false;
    00235         scrollSuspendPreActivate = false;
    00236         complete = false;
    00237         firstRelayout = true;
    00238         needsFullRepaint = true;
    00239         dirtyLayout = false;
    00240         layoutSchedulingEnabled = true;
    00241         painting = false;
    00242         updateRegion = QRegion();
    00243         m_dialogsAllowed = true;
    00244 #ifndef KHTML_NO_CARET
    00245         if (m_caretViewContext) {
    00246           m_caretViewContext->caretMoved = false;
    00247       m_caretViewContext->keyReleasePending = false;
    00248         }/*end if*/
    00249 #endif // KHTML_NO_CARET
    00250 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    00251         typeAheadActivated = false;
    00252 #endif // KHTML_NO_TYPE_AHEAD_FIND
    00253     accessKeysActivated = false;
    00254     accessKeysPreActivate = false;
    00255         emitCompletedAfterRepaint = CSNone;
    00256     }
    00257     void newScrollTimer(QWidget *view, int tid)
    00258     {
    00259         //kdDebug(6000) << "newScrollTimer timer " << tid << endl;
    00260         view->killTimer(scrollTimerId);
    00261         scrollTimerId = tid;
    00262         scrollSuspended = false;
    00263     }
    00264     enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
    00265
    00266     void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
    00267     {
    00268         static const struct { int msec, pixels; } timings [] = {
    00269             {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
    00270             {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
    00271         };
    00272         if (!scrollTimerId ||
    00273             (scrollDirection != direction &&
    00274              (scrollDirection != oppositedir || scrollSuspended))) {
    00275             scrollTiming = 6;
    00276             scrollBy = timings[scrollTiming].pixels;
    00277             scrollDirection = direction;
    00278             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
    00279         } else if (scrollDirection == direction &&
    00280                    timings[scrollTiming+1].msec && !scrollSuspended) {
    00281             scrollBy = timings[++scrollTiming].pixels;
    00282             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
    00283         } else if (scrollDirection == oppositedir) {
    00284             if (scrollTiming) {
    00285                 scrollBy = timings[--scrollTiming].pixels;
    00286                 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
    00287             }
    00288         }
    00289         scrollSuspended = false;
    00290     }
    00291
    00292 #ifndef KHTML_NO_CARET
    00293
    00296     CaretViewContext *caretViewContext() {
    00297       if (!m_caretViewContext) m_caretViewContext = new CaretViewContext();
    00298       return m_caretViewContext;
    00299     }
    00303     EditorContext *editorContext() {
    00304       if (!m_editorContext) m_editorContext = new EditorContext();
    00305       return m_editorContext;
    00306     }
    00307 #endif // KHTML_NO_CARET
    00308
    00309 #ifdef DEBUG_PIXEL
    00310     QTime timer;
    00311     unsigned int pixelbooth;
    00312     unsigned int repaintbooth;
    00313 #endif
    00314
    00315     QPainter *tp;
    00316     QPixmap  *paintBuffer;
    00317     QPixmap  *vertPaintBuffer;
    00318     NodeImpl *underMouse;
    00319     NodeImpl *underMouseNonShared;
    00320
    00321     bool tabMovePending:1;
    00322     bool lastTabbingDirection:1;
    00323     PseudoFocusNodes pseudoFocusNode:2;
    00324     bool scrollBarMoved:1;
    00325     bool contentsMoving:1;
    00326
    00327     QScrollView::ScrollBarMode vmode;
    00328     QScrollView::ScrollBarMode hmode;
    00329     bool prevScrollbarVisible:1;
    00330     bool linkPressed:1;
    00331     bool useSlowRepaints:1;
    00332     bool ignoreWheelEvents:1;
    00333
    00334     int borderX, borderY;
    00335     KSimpleConfig *formCompletions;
    00336
    00337     int clickX, clickY, clickCount;
    00338     bool isDoubleClick;
    00339
    00340     int prevMouseX, prevMouseY;
    00341     bool scrollingSelf;
    00342     int layoutTimerId;
    00343     QKeyEvent* postponed_autorepeat;
    00344
    00345     int repaintTimerId;
    00346     int scrollTimerId;
    00347     int scrollTiming;
    00348     int scrollBy;
    00349     ScrollDirection scrollDirection     :2;
    00350     bool scrollSuspended            :1;
    00351     bool scrollSuspendPreActivate       :1;
    00352     bool complete               :1;
    00353     bool firstRelayout              :1;
    00354     bool layoutSchedulingEnabled        :1;
    00355     bool needsFullRepaint           :1;
    00356     bool painting               :1;
    00357     bool possibleTripleClick            :1;
    00358     bool dirtyLayout                :1;
    00359     bool m_dialogsAllowed           :1;
    00360     QRegion updateRegion;
    00361     KHTMLToolTip *tooltip;
    00362     QPtrDict<QWidget> visibleWidgets;
    00363 #ifndef KHTML_NO_CARET
    00364     CaretViewContext *m_caretViewContext;
    00365     EditorContext *m_editorContext;
    00366 #endif // KHTML_NO_CARET
    00367 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    00368     QString findString;
    00369     QTimer timer;
    00370     bool findLinksOnly;
    00371     bool typeAheadActivated;
    00372 #endif // KHTML_NO_TYPE_AHEAD_FIND
    00373     bool accessKeysActivated;
    00374     bool accessKeysPreActivate;
    00375     CompletedState emitCompletedAfterRepaint;
    00376
    00377     QWidget* cursor_icon_widget;
    00378
    00379     // scrolling activated by MMB
    00380     int m_mouseScroll_byX : 4;
    00381     int m_mouseScroll_byY : 4;
    00382     QTimer *m_mouseScrollTimer;
    00383     QWidget *m_mouseScrollIndicator;
    00384 };
    00385
    00386 #ifndef QT_NO_TOOLTIP
    00387
    00397 static bool findImageMapRect(HTMLImageElementImpl *img, const QPoint &scrollOfs,
    00398             const QPoint &p, QRect &r, QString &s)
    00399 {
    00400     HTMLMapElementImpl* map;
    00401     if (img && img->getDocument()->isHTMLDocument() &&
    00402         (map = static_cast<HTMLDocumentImpl*>(img->getDocument())->getMap(img->imageMap()))) {
    00403         RenderObject::NodeInfo info(true, false);
    00404         RenderObject *rend = img->renderer();
    00405         int ax, ay;
    00406         if (!rend || !rend->absolutePosition(ax, ay))
    00407             return false;
    00408         // we're a client side image map
    00409         bool inside = map->mapMouseEvent(p.x() - ax + scrollOfs.x(),
    00410                 p.y() - ay + scrollOfs.y(), rend->contentWidth(),
    00411                 rend->contentHeight(), info);
    00412         if (inside && info.URLElement()) {
    00413             HTMLAreaElementImpl *area = static_cast<HTMLAreaElementImpl *>(info.URLElement());
    00414             Q_ASSERT(area->id() == ID_AREA);
    00415             s = area->getAttribute(ATTR_TITLE).string();
    00416             QRegion reg = area->cachedRegion();
    00417             if (!s.isEmpty() && !reg.isEmpty()) {
    00418                 r = reg.boundingRect();
    00419                 r.moveBy(ax, ay);
    00420                 return true;
    00421             }
    00422         }
    00423     }
    00424     return false;
    00425 }
    00426
    00427 void KHTMLToolTip::maybeTip(const QPoint& p)
    00428 {
    00429     DOM::NodeImpl *node = m_viewprivate->underMouseNonShared;
    00430     QRect region;
    00431     while ( node ) {
    00432         if ( node->isElementNode() ) {
    00433             DOM::ElementImpl *e = static_cast<DOM::ElementImpl*>( node );
    00434             QRect r;
    00435             QString s;
    00436             bool found = false;
    00437             // for images, check if it is part of a client-side image map,
    00438             // and query the <area>s' title attributes, too
    00439             if (e->id() == ID_IMG && !e->getAttribute( ATTR_USEMAP ).isEmpty()) {
    00440                 found = findImageMapRect(static_cast<HTMLImageElementImpl *>(e),
    00441                             m_view->viewportToContents(QPoint(0, 0)), p, r, s);
    00442             }
    00443             if (!found) {
    00444                 s = e->getAttribute( ATTR_TITLE ).string();
    00445                 r = node->getRect();
    00446             }
    00447             region |= QRect( m_view->contentsToViewport( r.topLeft() ), r.size() );
    00448             if ( !s.isEmpty() ) {
    00449                 tip( region, QStyleSheet::convertFromPlainText( s, QStyleSheetItem::WhiteSpaceNormal ) );
    00450                 break;
    00451             }
    00452         }
    00453         node = node->parentNode();
    00454     }
    00455 }
    00456 #endif
    00457
    00458 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name)
    00459     : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase )
    00460 {
    00461     m_medium = "screen";
    00462
    00463     m_part = part;
    00464     d = new KHTMLViewPrivate;
    00465     QScrollView::setVScrollBarMode(d->vmode);
    00466     QScrollView::setHScrollBarMode(d->hmode);
    00467     connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged()));
    00468     connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
    00469
    00470     // initialize QScrollView
    00471     enableClipper(true);
    00472     // hack to get unclipped painting on the viewport.
    00473     static_cast<KHTMLView *>(static_cast<QWidget *>(viewport()))->setWFlags(WPaintUnclipped);
    00474
    00475     setResizePolicy(Manual);
    00476     viewport()->setMouseTracking(true);
    00477     viewport()->setBackgroundMode(NoBackground);
    00478
    00479     KImageIO::registerFormats();
    00480
    00481 #ifndef QT_NO_TOOLTIP
    00482     d->tooltip = new KHTMLToolTip( this, d );
    00483 #endif
    00484
    00485 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    00486     connect(&d->timer, SIGNAL(timeout()), this, SLOT(findTimeout()));
    00487 #endif // KHTML_NO_TYPE_AHEAD_FIND
    00488
    00489     init();
    00490
    00491     viewport()->show();
    00492 }
    00493
    00494 KHTMLView::~KHTMLView()
    00495 {
    00496     closeChildDialogs();
    00497     if (m_part)
    00498     {
    00499         //WABA: Is this Ok? Do I need to deref it as well?
    00500         //Does this need to be done somewhere else?
    00501         DOM::DocumentImpl *doc = m_part->xmlDocImpl();
    00502         if (doc)
    00503             doc->detach();
    00504     }
    00505     delete d; d = 0;
    00506 }
    00507
    00508 void KHTMLView::init()
    00509 {
    00510     if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
    00511     if(!d->vertPaintBuffer)
    00512         d->vertPaintBuffer = new QPixmap(10, PAINT_BUFFER_HEIGHT);
    00513     if(!d->tp) d->tp = new QPainter();
    00514
    00515     setFocusPolicy(QWidget::StrongFocus);
    00516     viewport()->setFocusProxy(this);
    00517
    00518     _marginWidth = -1; // undefined
    00519     _marginHeight = -1;
    00520     _width = 0;
    00521     _height = 0;
    00522
    00523     installEventFilter(this);
    00524
    00525     setAcceptDrops(true);
    00526     QSize s = viewportSize(4095, 4095);
    00527     resizeContents(s.width(), s.height());
    00528 }
    00529
    00530 void KHTMLView::clear()
    00531 {
    00532     // work around QScrollview's unbelievable bugginess
    00533     setStaticBackground(true);
    00534 #ifndef KHTML_NO_CARET
    00535     if (!m_part->isCaretMode() && !m_part->isEditable()) caretOff();
    00536 #endif
    00537
    00538     if( d->typeAheadActivated )
    00539         findTimeout();
    00540     if (d->accessKeysActivated)
    00541         accessKeysTimeout();
    00542     viewport()->unsetCursor();
    00543     if ( d->cursor_icon_widget )
    00544         d->cursor_icon_widget->hide();
    00545     d->reset();
    00546     killTimers();
    00547     emit cleared();
    00548
    00549     QScrollView::setHScrollBarMode(d->hmode);
    00550     QScrollView::setVScrollBarMode(d->vmode);
    00551     verticalScrollBar()->setEnabled( false );
    00552     horizontalScrollBar()->setEnabled( false );
    00553 }
    00554
    00555 void KHTMLView::hideEvent(QHideEvent* e)
    00556 {
    00557     QScrollView::hideEvent(e);
    00558 }
    00559
    00560 void KHTMLView::showEvent(QShowEvent* e)
    00561 {
    00562     QScrollView::showEvent(e);
    00563 }
    00564
    00565 void KHTMLView::resizeEvent (QResizeEvent* e)
    00566 {
    00567     int dw = e->oldSize().width() - e->size().width();
    00568     int dh = e->oldSize().height() - e->size().height();
    00569
    00570     // if we are shrinking the view, don't allow the content to overflow
    00571     // before the layout occurs - we don't know if we need scrollbars yet
    00572     dw = dw>0 ? kMax(0, contentsWidth()-dw) : contentsWidth();
    00573     dh = dh>0 ? kMax(0, contentsHeight()-dh) : contentsHeight();
    00574
    00575     resizeContents(dw, dh);
    00576
    00577     QScrollView::resizeEvent(e);
    00578
    00579     if ( m_part && m_part->xmlDocImpl() )
    00580         m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
    00581 }
    00582
    00583 void KHTMLView::viewportResizeEvent (QResizeEvent* e)
    00584 {
    00585     QScrollView::viewportResizeEvent(e);
    00586
    00587     //int w = visibleWidth();
    00588     //int h = visibleHeight();
    00589
    00590     if (d->layoutSchedulingEnabled)
    00591         layout();
    00592 #ifndef KHTML_NO_CARET
    00593     else {
    00594         hideCaret();
    00595         recalcAndStoreCaretPos();
    00596     showCaret();
    00597     }/*end if*/
    00598 #endif
    00599
    00600     KApplication::sendPostedEvents(viewport(), QEvent::Paint);
    00601 }
    00602
    00603 // this is to get rid of a compiler virtual overload mismatch warning. do not remove
    00604 void KHTMLView::drawContents( QPainter*)
    00605 {
    00606 }
    00607
    00608 void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
    00609 {
    00610 #ifdef DEBUG_PIXEL
    00611
    00612     if ( d->timer.elapsed() > 5000 ) {
    00613         qDebug( "drawed %d pixels in %d repaints the last %d milliseconds",
    00614                 d->pixelbooth, d->repaintbooth,  d->timer.elapsed() );
    00615         d->timer.restart();
    00616         d->pixelbooth = 0;
    00617         d->repaintbooth = 0;
    00618     }
    00619     d->pixelbooth += ew*eh;
    00620     d->repaintbooth++;
    00621 #endif
    00622
    00623     //kdDebug( 6000 ) << "drawContents this="<< this <<" x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl;
    00624     if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
    00625         p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
    00626         return;
    00627     } else if ( d->complete && static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
    00628         // an external update request happens while we have a layout scheduled
    00629         unscheduleRelayout();
    00630         layout();
    00631     }
    00632
    00633     if (d->painting) {
    00634         kdDebug( 6000 ) << "WARNING: drawContents reentered! " << endl;
    00635         return;
    00636     }
    00637     d->painting = true;
    00638
    00639     QPoint pt = contentsToViewport(QPoint(ex, ey));
    00640     QRegion cr = QRect(pt.x(), pt.y(), ew, eh);
    00641     //kdDebug(6000) << "clip rect: " << QRect(pt.x(), pt.y(), ew, eh) << endl;
    00642     for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
    00643     QWidget *w = it.current();
    00644     RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
    00645         if (strcmp(w->name(), "__khtml")) {
    00646             int x, y;
    00647             rw->absolutePosition(x, y);
    00648             contentsToViewport(x, y, x, y);
    00649             cr -= QRect(x, y, rw->width(), rw->height());
    00650         }
    00651     }
    00652
    00653 #if 0
    00654     // this is commonly the case with framesets. we still do
    00655     // want to paint them, otherwise the widgets don't get placed.
    00656     if (cr.isEmpty()) {
    00657         d->painting = false;
    00658     return;
    00659     }
    00660 #endif
    00661
    00662 #ifndef DEBUG_NO_PAINT_BUFFER
    00663     p->setClipRegion(cr);
    00664
    00665     if (eh > PAINT_BUFFER_HEIGHT && ew <= 10) {
    00666         if ( d->vertPaintBuffer->height() < visibleHeight() )
    00667             d->vertPaintBuffer->resize(10, visibleHeight());
    00668         d->tp->begin(d->vertPaintBuffer);
    00669         d->tp->translate(-ex, -ey);
    00670         d->tp->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
    00671         m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey, ew, eh));
    00672         d->tp->end();
    00673     p->drawPixmap(ex, ey, *d->vertPaintBuffer, 0, 0, ew, eh);
    00674     }
    00675     else {
    00676         if ( d->paintBuffer->width() < visibleWidth() )
    00677             d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
    00678
    00679         int py=0;
    00680         while (py < eh) {
    00681             int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
    00682             d->tp->begin(d->paintBuffer);
    00683             d->tp->translate(-ex, -ey-py);
    00684             d->tp->fillRect(ex, ey+py, ew, ph, palette().active().brush(QColorGroup::Base));
    00685             m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey+py, ew, ph));
    00686             d->tp->end();
    00687
    00688         p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
    00689             py += PAINT_BUFFER_HEIGHT;
    00690         }
    00691     }
    00692 #else // !DEBUG_NO_PAINT_BUFFER
    00693 static int cnt=0;
    00694     ex = contentsX(); ey = contentsY();
    00695     ew = visibleWidth(); eh = visibleHeight();
    00696     QRect pr(ex,ey,ew,eh);
    00697     kdDebug() << "[" << ++cnt << "]" << " clip region: " << pr << endl;
    00698 //  p->setClipRegion(QRect(0,0,ew,eh));
    00699 //        p->translate(-ex, -ey);
    00700         p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
    00701         m_part->xmlDocImpl()->renderer()->layer()->paint(p, pr);
    00702 #endif // DEBUG_NO_PAINT_BUFFER
    00703
    00704 #ifndef KHTML_NO_CARET
    00705     if (d->m_caretViewContext && d->m_caretViewContext->visible) {
    00706         QRect pos(d->m_caretViewContext->x, d->m_caretViewContext->y,
    00707         d->m_caretViewContext->width, d->m_caretViewContext->height);
    00708         if (pos.intersects(QRect(ex, ey, ew, eh))) {
    00709             p->setRasterOp(XorROP);
    00710         p->setPen(white);
    00711         if (pos.width() == 1)
    00712               p->drawLine(pos.topLeft(), pos.bottomRight());
    00713         else {
    00714           p->fillRect(pos, white);
    00715         }/*end if*/
    00716     }/*end if*/
    00717     }/*end if*/
    00718 #endif // KHTML_NO_CARET
    00719
    00720 //    p->setPen(QPen(magenta,0,DashDotDotLine));
    00721 //    p->drawRect(dbg_paint_rect);
    00722
    00723     khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
    00724     QApplication::sendEvent( m_part, &event );
    00725
    00726     d->painting = false;
    00727 }
    00728
    00729 void KHTMLView::setMarginWidth(int w)
    00730 {
    00731     // make it update the rendering area when set
    00732     _marginWidth = w;
    00733 }
    00734
    00735 void KHTMLView::setMarginHeight(int h)
    00736 {
    00737     // make it update the rendering area when set
    00738     _marginHeight = h;
    00739 }
    00740
    00741 void KHTMLView::layout()
    00742 {
    00743     if( m_part && m_part->xmlDocImpl() ) {
    00744         DOM::DocumentImpl *document = m_part->xmlDocImpl();
    00745
    00746         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
    00747         if ( !root ) return;
    00748
    00749         d->layoutSchedulingEnabled=false;
    00750
    00751         if (document->isHTMLDocument()) {
    00752              NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
    00753              if(body && body->renderer() && body->id() == ID_FRAMESET) {
    00754                  QScrollView::setVScrollBarMode(AlwaysOff);
    00755                  QScrollView::setHScrollBarMode(AlwaysOff);
    00756                  body->renderer()->setNeedsLayout(true);
    00757 //                  if (d->tooltip) {
    00758 //                      delete d->tooltip;
    00759 //                      d->tooltip = 0;
    00760 //                  }
    00761              }
    00762              else if (!d->tooltip)
    00763                  d->tooltip = new KHTMLToolTip( this, d );
    00764         }
    00765         d->needsFullRepaint = d->firstRelayout;
    00766         if (_height !=  visibleHeight() || _width != visibleWidth()) {;
    00767             d->needsFullRepaint = true;
    00768             _height = visibleHeight();
    00769             _width = visibleWidth();
    00770         }
    00771         //QTime qt;
    00772         //qt.start();
    00773         root->layout();
    00774
    00775         emit finishedLayout();
    00776         if (d->firstRelayout) {
    00777             // make sure firstRelayout is set to false now in case this layout
    00778             // wasn't scheduled
    00779             d->firstRelayout = false;
    00780             verticalScrollBar()->setEnabled( true );
    00781             horizontalScrollBar()->setEnabled( true );
    00782         }
    00783 #if 0
    00784     ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
    00785     if (listitem) kdDebug(6000) << "after layout, before repaint" << endl;
    00786     if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
    00787 #endif
    00788 #ifndef KHTML_NO_CARET
    00789         hideCaret();
    00790         if ((m_part->isCaretMode() || m_part->isEditable())
    00791             && !d->complete && d->m_caretViewContext
    00792                 && !d->m_caretViewContext->caretMoved) {
    00793             initCaret();
    00794         } else {
    00795         recalcAndStoreCaretPos();
    00796         showCaret();
    00797         }/*end if*/
    00798 #endif
    00799         if (d->accessKeysActivated) {
    00800             emit hideAccessKeys();
    00801             displayAccessKeys();
    00802         }
    00803         //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
    00804     }
    00805     else
    00806        _width = visibleWidth();
    00807
    00808     killTimer(d->layoutTimerId);
    00809     d->layoutTimerId = 0;
    00810     d->layoutSchedulingEnabled=true;
    00811 }
    00812
    00813 void KHTMLView::closeChildDialogs()
    00814 {
    00815     QObjectList *dlgs = queryList("QDialog");
    00816     for (QObject *dlg = dlgs->first(); dlg; dlg = dlgs->next())
    00817     {
    00818         KDialogBase* dlgbase = dynamic_cast<KDialogBase *>( dlg );
    00819         if ( dlgbase ) {
    00820             if ( dlgbase->testWFlags( WShowModal ) ) {
    00821                 kdDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase << endl;
    00822                 // close() ends up calling QButton::animateClick, which isn't immediate
    00823                 // we need something the exits the event loop immediately (#49068)
    00824                 dlgbase->cancel();
    00825             }
    00826         }
    00827         else
    00828         {
    00829             kdWarning() << "closeChildDialogs: not a KDialogBase! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg) << endl;
    00830             static_cast<QWidget*>(dlg)->hide();
    00831         }
    00832     }
    00833     delete dlgs;
    00834     d->m_dialogsAllowed = false;
    00835 }
    00836
    00837 bool KHTMLView::dialogsAllowed() {
    00838     bool allowed = d->m_dialogsAllowed;
    00839     KHTMLPart* p = m_part->parentPart();
    00840     if (p && p->view())
    00841         allowed &= p->view()->dialogsAllowed();
    00842     return allowed;
    00843 }
    00844
    00845 void KHTMLView::closeEvent( QCloseEvent* ev )
    00846 {
    00847     closeChildDialogs();
    00848     QScrollView::closeEvent( ev );
    00849 }
    00850
    00851 //
    00852 // Event Handling
    00853 //
    00855
    00856 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
    00857 {
    00858     if (!m_part->xmlDocImpl()) return;
    00859     if (d->possibleTripleClick && ( _mouse->button() & MouseButtonMask ) == LeftButton)
    00860     {
    00861         viewportMouseDoubleClickEvent( _mouse ); // it handles triple clicks too
    00862         return;
    00863     }
    00864
    00865     int xm, ym;
    00866     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
    00867     //kdDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()<<"/"<<_mouse->y()<<"), contents=(" << xm << "/" << ym << ")\n";
    00868
    00869     d->isDoubleClick = false;
    00870
    00871     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
    00872     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
    00873
    00874     //kdDebug(6000) << "innerNode="<<mev.innerNode.nodeName().string()<<endl;
    00875
    00876     if ( (_mouse->button() == MidButton) &&
    00877           !m_part->d->m_bOpenMiddleClick && !d->m_mouseScrollTimer &&
    00878           mev.url.isNull() && (mev.innerNode.elementId() != ID_INPUT) ) {
    00879         QPoint point = mapFromGlobal( _mouse->globalPos() );
    00880
    00881         d->m_mouseScroll_byX = 0;
    00882         d->m_mouseScroll_byY = 0;
    00883
    00884         d->m_mouseScrollTimer = new QTimer( this );
    00885         connect( d->m_mouseScrollTimer, SIGNAL(timeout()), this, SLOT(slotMouseScrollTimer()) );
    00886
    00887         if ( !d->m_mouseScrollIndicator ) {
    00888             QPixmap pixmap, icon;
    00889             pixmap.resize( 48, 48 );
    00890             pixmap.fill( QColor( qRgba( 127, 127, 127, 127 ) ) );
    00891
    00892             QPainter p( &pixmap );
    00893             icon = KGlobal::iconLoader()->loadIcon( "1uparrow", KIcon::Small );
    00894             p.drawPixmap( 16, 0, icon );
    00895             icon = KGlobal::iconLoader()->loadIcon( "1leftarrow", KIcon::Small );
    00896             p.drawPixmap( 0, 16, icon );
    00897             icon = KGlobal::iconLoader()->loadIcon( "1downarrow", KIcon::Small );
    00898             p.drawPixmap( 16, 32,icon  );
    00899             icon = KGlobal::iconLoader()->loadIcon( "1rightarrow", KIcon::Small );
    00900             p.drawPixmap( 32, 16, icon );
    00901             p.drawEllipse( 23, 23, 2, 2 );
    00902
    00903             d->m_mouseScrollIndicator = new QWidget( this, 0 );
    00904             d->m_mouseScrollIndicator->setFixedSize( 48, 48 );
    00905             d->m_mouseScrollIndicator->setPaletteBackgroundPixmap( pixmap );
    00906         }
    00907         d->m_mouseScrollIndicator->move( point.x()-24, point.y()-24 );
    00908
    00909         bool hasHorBar = visibleWidth() < contentsWidth();
    00910         bool hasVerBar = visibleHeight() < contentsHeight();
    00911
    00912         KConfig *config = KGlobal::config();
    00913         KConfigGroupSaver saver( config, "HTML Settings" );
    00914         if ( config->readBoolEntry( "ShowMouseScrollIndicator", true ) ) {
    00915             d->m_mouseScrollIndicator->show();
    00916             d->m_mouseScrollIndicator->unsetCursor();
    00917
    00918             QBitmap mask = d->m_mouseScrollIndicator->paletteBackgroundPixmap()->createHeuristicMask( true );
    00919
    00920         if ( hasHorBar && !hasVerBar ) {
    00921                 QBitmap bm( 16, 16, true );
    00922                 bitBlt( &mask, 16,  0, &bm, 0, 0, -1, -1 );
    00923                 bitBlt( &mask, 16, 32, &bm, 0, 0, -1, -1 );
    00924                 d->m_mouseScrollIndicator->setCursor( KCursor::SizeHorCursor );
    00925             }
    00926             else if ( !hasHorBar && hasVerBar ) {
    00927                 QBitmap bm( 16, 16, true );
    00928                 bitBlt( &mask,  0, 16, &bm, 0, 0, -1, -1 );
    00929                 bitBlt( &mask, 32, 16, &bm, 0, 0, -1, -1 );
    00930                 d->m_mouseScrollIndicator->setCursor( KCursor::SizeVerCursor );
    00931             }
    00932             else
    00933                 d->m_mouseScrollIndicator->setCursor( KCursor::SizeAllCursor );
    00934
    00935             d->m_mouseScrollIndicator->setMask( mask );
    00936         }
    00937         else {
    00938             if ( hasHorBar && !hasVerBar )
    00939                 viewport()->setCursor( KCursor::SizeHorCursor );
    00940             else if ( !hasHorBar && hasVerBar )
    00941                 viewport()->setCursor( KCursor::SizeVerCursor );
    00942             else
    00943                 viewport()->setCursor( KCursor::SizeAllCursor );
    00944         }
    00945
    00946         return;
    00947     }
    00948     else if ( d->m_mouseScrollTimer ) {
    00949         delete d->m_mouseScrollTimer;
    00950         d->m_mouseScrollTimer = 0;
    00951
    00952         if ( d->m_mouseScrollIndicator )
    00953             d->m_mouseScrollIndicator->hide();
    00954     }
    00955
    00956     d->clickCount = 1;
    00957     d->clickX = xm;
    00958     d->clickY = ym;
    00959
    00960     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
    00961                                            d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
    00962
    00963     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
    00964     if (r && r->isWidget())
    00965     _mouse->ignore();
    00966
    00967     if (!swallowEvent) {
    00968     emit m_part->nodeActivated(mev.innerNode);
    00969
    00970     khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
    00971         QApplication::sendEvent( m_part, &event );
    00972         // we might be deleted after this
    00973     }
    00974 }
    00975
    00976 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
    00977 {
    00978     if(!m_part->xmlDocImpl()) return;
    00979
    00980     int xm, ym;
    00981     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
    00982
    00983     kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
    00984
    00985     d->isDoubleClick = true;
    00986
    00987     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
    00988     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
    00989
    00990     // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat
    00991     // single and double-click events as separate (only the detail, i.e. number of clicks differs)
    00992     if (d->clickCount > 0 &&
    00993         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
    00994     d->clickCount++;
    00995     else { // shouldn't happen, if Qt has the same criterias for double clicks.
    00996     d->clickCount = 1;
    00997     d->clickX = xm;
    00998     d->clickY = ym;
    00999     }
    01000     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
    01001                                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
    01002
    01003     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
    01004     if (r && r->isWidget())
    01005     _mouse->ignore();
    01006
    01007     if (!swallowEvent) {
    01008     khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
    01009     QApplication::sendEvent( m_part, &event );
    01010     }
    01011
    01012     d->possibleTripleClick=true;
    01013     QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
    01014 }
    01015
    01016 void KHTMLView::tripleClickTimeout()
    01017 {
    01018     d->possibleTripleClick = false;
    01019     d->clickCount = 0;
    01020 }
    01021
    01022 static inline void forwardPeripheralEvent(khtml::RenderWidget* r, QMouseEvent* me, int x, int y)
    01023 {
    01024     int absx = 0;
    01025     int absy = 0;
    01026     r->absolutePosition(absx, absy);
    01027     QPoint p(x-absx, y-absy);
    01028     QMouseEvent fw(me->type(), p, me->button(), me->state());
    01029     QWidget* w = r->widget();
    01030     if(w)
    01031         static_cast<khtml::RenderWidget::EventPropagator*>(w)->sendEvent(&fw);
    01032 }
    01033
    01034 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
    01035 {
    01036     if ( d->m_mouseScrollTimer ) {
    01037         QPoint point = mapFromGlobal( _mouse->globalPos() );
    01038
    01039         int deltaX = point.x() - d->m_mouseScrollIndicator->x() - 24;
    01040         int deltaY = point.y() - d->m_mouseScrollIndicator->y() - 24;
    01041
    01042         (deltaX > 0) ? d->m_mouseScroll_byX = 1 : d->m_mouseScroll_byX = -1;
    01043         (deltaY > 0) ? d->m_mouseScroll_byY = 1 : d->m_mouseScroll_byY = -1;
    01044
    01045         int adX = abs( deltaX );
    01046         int adY = abs( deltaY );
    01047
    01048         if (adX > 100) d->m_mouseScroll_byX *= 7;
    01049         else if (adX > 75) d->m_mouseScroll_byX *= 4;
    01050         else if (adX > 50) d->m_mouseScroll_byX *= 2;
    01051         else if (adX > 25) d->m_mouseScroll_byX *= 1;
    01052         else d->m_mouseScroll_byX = 0;
    01053
    01054         if (adY > 100) d->m_mouseScroll_byY *= 7;
    01055         else if (adY > 75) d->m_mouseScroll_byY *= 4;
    01056         else if (adY > 50) d->m_mouseScroll_byY *= 2;
    01057         else if (adY > 25) d->m_mouseScroll_byY *= 1;
    01058         else d->m_mouseScroll_byY = 0;
    01059
    01060         if (d->m_mouseScroll_byX == 0 && d->m_mouseScroll_byY == 0) {
    01061             d->m_mouseScrollTimer->stop();
    01062         }
    01063         else if (!d->m_mouseScrollTimer->isActive()) {
    01064             d->m_mouseScrollTimer->changeInterval( 20 );
    01065         }
    01066     }
    01067
    01068     if(!m_part->xmlDocImpl()) return;
    01069
    01070     int xm, ym;
    01071     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
    01072
    01073     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
    01074     // Do not modify :hover/:active state while mouse is pressed.
    01075     m_part->xmlDocImpl()->prepareMouseEvent( _mouse->state() & Qt::MouseButtonMask /*readonly ?*/, xm, ym, &mev );
    01076
    01077 //     kdDebug(6000) << "mouse move: " << _mouse->pos()
    01078 //        << " button " << _mouse->button()
    01079 //        << " state " << _mouse->state() << endl;
    01080
    01081     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),false,
    01082                                            0,_mouse,true,DOM::NodeImpl::MouseMove);
    01083
    01084     if (d->clickCount > 0 &&
    01085         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
    01086     d->clickCount = 0;  // moving the mouse outside the threshold invalidates the click
    01087     }
    01088
    01089     // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
    01090     m_part->executeScheduledScript();
    01091
    01092     DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
    01093     if (fn && fn != mev.innerNode.handle() &&
    01094         fn->renderer() && fn->renderer()->isWidget()) {
    01095         forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
    01096     }
    01097
    01098     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
    01099     khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
    01100     QCursor c;
    01101     bool mailtoCursor = false;
    01102     switch ( style ? style->cursor() : CURSOR_AUTO) {
    01103     case CURSOR_AUTO:
    01104         if ( r && r->isText() )
    01105             c = KCursor::ibeamCursor();
    01106         if ( mev.url.length() && m_part->settings()->changeCursor() ) {
    01107             c = m_part->urlCursor();
    01108         if (mev.url.string().startsWith("mailto:") && mev.url.string().find('@')>0)
    01109                 mailtoCursor = true;
    01110         }
    01111
    01112         if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
    01113             c = QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
    01114
    01115         break;
    01116     case CURSOR_CROSS:
    01117         c = KCursor::crossCursor();
    01118         break;
    01119     case CURSOR_POINTER:
    01120         c = m_part->urlCursor();
    01121     if (mev.url.string().startsWith("mailto:") && mev.url.string().find('@')>0)
    01122             mailtoCursor = true;
    01123         break;
    01124     case CURSOR_PROGRESS:
    01125         c = KCursor::workingCursor();
    01126         break;
    01127     case CURSOR_MOVE:
    01128         c = KCursor::sizeAllCursor();
    01129         break;
    01130     case CURSOR_E_RESIZE:
    01131     case CURSOR_W_RESIZE:
    01132         c = KCursor::sizeHorCursor();
    01133         break;
    01134     case CURSOR_N_RESIZE:
    01135     case CURSOR_S_RESIZE:
    01136         c = KCursor::sizeVerCursor();
    01137         break;
    01138     case CURSOR_NE_RESIZE:
    01139     case CURSOR_SW_RESIZE:
    01140         c = KCursor::sizeBDiagCursor();
    01141         break;
    01142     case CURSOR_NW_RESIZE:
    01143     case CURSOR_SE_RESIZE:
    01144         c = KCursor::sizeFDiagCursor();
    01145         break;
    01146     case CURSOR_TEXT:
    01147         c = KCursor::ibeamCursor();
    01148         break;
    01149     case CURSOR_WAIT:
    01150         c = KCursor::waitCursor();
    01151         break;
    01152     case CURSOR_HELP:
    01153         c = KCursor::whatsThisCursor();
    01154         break;
    01155     case CURSOR_DEFAULT:
    01156         break;
    01157     }
    01158
    01159     if ( viewport()->cursor().handle() != c.handle() ) {
    01160         if( c.handle() == KCursor::arrowCursor().handle()) {
    01161             for (KHTMLPart* p = m_part; p; p = p->parentPart())
    01162                 p->view()->viewport()->unsetCursor();
    01163         }
    01164         else {
    01165             viewport()->setCursor( c );
    01166         }
    01167     }
    01168
    01169     if ( mailtoCursor && isVisible() && hasFocus() ) {
    01170         if( !d->cursor_icon_widget ) {
    01171             QPixmap icon_pixmap = KGlobal::iconLoader()->loadIcon( "mail_generic", KIcon::Small, 0, KIcon::DefaultState, 0, true );
    01172             d->cursor_icon_widget = new QWidget( NULL, NULL, WX11BypassWM );
    01173             XSetWindowAttributes attr;
    01174             attr.save_under = True;
    01175             XChangeWindowAttributes( qt_xdisplay(), d->cursor_icon_widget->winId(), CWSaveUnder, &attr );
    01176             d->cursor_icon_widget->resize( icon_pixmap.width(), icon_pixmap.height());
    01177             if( icon_pixmap.mask() )
    01178                 d->cursor_icon_widget->setMask( *icon_pixmap.mask());
    01179             else
    01180                 d->cursor_icon_widget->clearMask();
    01181             d->cursor_icon_widget->setBackgroundPixmap( icon_pixmap );
    01182             d->cursor_icon_widget->erase();
    01183         }
    01184         QPoint c_pos = QCursor::pos();
    01185         d->cursor_icon_widget->move( c_pos.x() + 15, c_pos.y() + 15 );
    01186         XRaiseWindow( qt_xdisplay(), d->cursor_icon_widget->winId());
    01187         QApplication::flushX();
    01188         d->cursor_icon_widget->show();
    01189     }
    01190     else if ( d->cursor_icon_widget )
    01191         d->cursor_icon_widget->hide();
    01192
    01193     if (r && r->isWidget()) {
    01194     _mouse->ignore();
    01195     }
    01196
    01197
    01198     d->prevMouseX = xm;
    01199     d->prevMouseY = ym;
    01200
    01201     if (!swallowEvent) {
    01202         khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
    01203         QApplication::sendEvent( m_part, &event );
    01204     }
    01205 }
    01206
    01207 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
    01208 {
    01209     bool swallowEvent = false;
    01210     int xm, ym;
    01211     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
    01212     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
    01213
    01214     if ( m_part->xmlDocImpl() )
    01215     {
    01216         m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
    01217
    01218         swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
    01219                                           d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
    01220
    01221         if (d->clickCount > 0 &&
    01222             QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
    01223             QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
    01224                            _mouse->pos(), _mouse->button(), _mouse->state());
    01225             dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
    01226                                d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
    01227         }
    01228
    01229         DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
    01230         if (fn && fn != mev.innerNode.handle() &&
    01231             fn->renderer() && fn->renderer()->isWidget() &&
    01232             _mouse->button() != MidButton) {
    01233             forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
    01234         }
    01235
    01236         khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
    01237         if (r && r->isWidget())
    01238             _mouse->ignore();
    01239     }
    01240
    01241     if (!swallowEvent) {
    01242     khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
    01243     QApplication::sendEvent( m_part, &event );
    01244     }
    01245 }
    01246
    01247 // returns true if event should be swallowed
    01248 bool KHTMLView::dispatchKeyEvent( QKeyEvent *_ke )
    01249 {
    01250     if (!m_part->xmlDocImpl())
    01251         return false;
    01252     // Pressing and releasing a key should generate keydown, keypress and keyup events
    01253     // Holding it down should generated keydown, keypress (repeatedly) and keyup events
    01254     // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
    01255     // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
    01256     // of the Qt events shouldn't be passed to DOM, but it should be still filtered
    01257     // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
    01258     // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
    01259     // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
    01260     // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
    01261     // The solution is to filter out and postpone the Qt autorepeat keyrelease until
    01262     // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
    01263     // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
    01264     // again, and here it will be ignored.
    01265     //
    01266     //  Qt:      Press      | Release(autorepeat) Press(autorepeat) etc. |   Release
    01267     //  DOM:   Down + Press |      (nothing)           Press             |     Up
    01268
    01269     // It's also possible to get only Releases. E.g. the release of alt-tab,
    01270     // or when the keypresses get captured by an accel.
    01271
    01272     if( _ke == d->postponed_autorepeat ) // replayed event
    01273     {
    01274         return false;
    01275     }
    01276
    01277     if( _ke->type() == QEvent::KeyPress )
    01278     {
    01279         if( !_ke->isAutoRepeat())
    01280         {
    01281             bool ret = dispatchKeyEventHelper( _ke, false ); // keydown
    01282             if( dispatchKeyEventHelper( _ke, true )) // keypress
    01283                 ret = true;
    01284             return ret;
    01285         }
    01286         else // autorepeat
    01287         {
    01288             bool ret = dispatchKeyEventHelper( _ke, true ); // keypress
    01289             if( !ret && d->postponed_autorepeat )
    01290                 keyPressEvent( d->postponed_autorepeat );
    01291             delete d->postponed_autorepeat;
    01292             d->postponed_autorepeat = NULL;
    01293             return ret;
    01294         }
    01295     }
    01296     else // QEvent::KeyRelease
    01297     {
    01298         // Discard postponed "autorepeat key-release" events that didn't see
    01299         // a keypress after them (e.g. due to QAccel)
    01300         if ( d->postponed_autorepeat ) {
    01301             delete d->postponed_autorepeat;
    01302             d->postponed_autorepeat = 0;
    01303         }
    01304
    01305         if( !_ke->isAutoRepeat()) {
    01306             return dispatchKeyEventHelper( _ke, false ); // keyup
    01307         }
    01308         else
    01309         {
    01310             d->postponed_autorepeat = new QKeyEvent( _ke->type(), _ke->key(), _ke->ascii(), _ke->state(),
    01311                 _ke->text(), _ke->isAutoRepeat(), _ke->count());
    01312             if( _ke->isAccepted())
    01313                 d->postponed_autorepeat->accept();
    01314             else
    01315                 d->postponed_autorepeat->ignore();
    01316             return true;
    01317         }
    01318     }
    01319 }
    01320
    01321 // returns true if event should be swallowed
    01322 bool KHTMLView::dispatchKeyEventHelper( QKeyEvent *_ke, bool keypress )
    01323 {
    01324     DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
    01325     if (keyNode) {
    01326         return keyNode->dispatchKeyEvent(_ke, keypress);
    01327     } else { // no focused node, send to document
    01328         return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
    01329     }
    01330 }
    01331
    01332 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
    01333 {
    01334 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    01335     if(d->typeAheadActivated)
    01336     {
    01337         // type-ahead find aka find-as-you-type
    01338         if(_ke->key() == Key_BackSpace)
    01339         {
    01340             d->findString = d->findString.left(d->findString.length() - 1);
    01341
    01342             if(!d->findString.isEmpty())
    01343             {
    01344                 findAhead(false);
    01345             }
    01346             else
    01347             {
    01348                 findTimeout();
    01349             }
    01350
    01351             d->timer.start(3000, true);
    01352             _ke->accept();
    01353             return;
    01354         }
    01355         else if(_ke->key() == Key_Escape)
    01356         {
    01357             findTimeout();
    01358
    01359             _ke->accept();
    01360             return;
    01361         }
    01362         else if(_ke->key() == Key_Space || !_ke->text().stripWhiteSpace().isEmpty())
    01363         {
    01364             d->findString += _ke->text();
    01365
    01366             findAhead(true);
    01367
    01368             d->timer.start(3000, true);
    01369             _ke->accept();
    01370             return;
    01371         }
    01372     }
    01373 #endif // KHTML_NO_TYPE_AHEAD_FIND
    01374
    01375 #ifndef KHTML_NO_CARET
    01376     if (m_part->isEditable() || m_part->isCaretMode()
    01377         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
    01378         && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
    01379       d->caretViewContext()->keyReleasePending = true;
    01380       caretKeyPressEvent(_ke);
    01381       return;
    01382     }
    01383 #endif // KHTML_NO_CARET
    01384
    01385     // If CTRL was hit, be prepared for access keys
    01386     if (_ke->key() == Key_Control && _ke->state()==0 && !d->accessKeysActivated) d->accessKeysPreActivate=true;
    01387
    01388     if (_ke->key() == Key_Shift && _ke->state()==0)
    01389         d->scrollSuspendPreActivate=true;
    01390
    01391     // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
    01392     // may eat the event
    01393
    01394     if (d->accessKeysActivated)
    01395     {
    01396         if (_ke->state()==0 || _ke->state()==ShiftButton) {
    01397     if (_ke->key() != Key_Shift) accessKeysTimeout();
    01398         handleAccessKey( _ke );
    01399         _ke->accept();
    01400         return;
    01401         }
    01402     accessKeysTimeout();
    01403     }
    01404
    01405     if ( dispatchKeyEvent( _ke )) {
    01406         // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
    01407         _ke->accept();
    01408         return;
    01409     }
    01410
    01411 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    01412     if((_ke->key() == '\'' || _ke->key() == '/') && !d->typeAheadActivated)
    01413     {
    01414         if(_ke->key() == '\'')
    01415         {
    01416             d->findLinksOnly = true;
    01417             m_part->setStatusBarText(i18n("Starting -- find links as you type"),
    01418                                      KHTMLPart::BarDefaultText);
    01419         }
    01420         else if(_ke->key() == '/')
    01421         {
    01422             d->findLinksOnly = false;
    01423             m_part->setStatusBarText(i18n("Starting -- find text as you type"),
    01424                                      KHTMLPart::BarDefaultText);
    01425         }
    01426
    01427         m_part->findTextBegin();
    01428         d->typeAheadActivated = true;
    01429         d->timer.start(3000, true);
    01430         _ke->accept();
    01431         return;
    01432     }
    01433 #endif // KHTML_NO_TYPE_AHEAD_FIND
    01434
    01435     int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
    01436     if (_ke->state() & Qt::ShiftButton)
    01437       switch(_ke->key())
    01438         {
    01439         case Key_Space:
    01440             if ( d->vmode == QScrollView::AlwaysOff )
    01441                 _ke->accept();
    01442             else {
    01443                 scrollBy( 0, -clipper()->height() - offs );
    01444                 if(d->scrollSuspended)
    01445                     d->newScrollTimer(this, 0);
    01446             }
    01447             break;
    01448
    01449         case Key_Down:
    01450         case Key_J:
    01451             d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
    01452             break;
    01453
    01454         case Key_Up:
    01455         case Key_K:
    01456             d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
    01457             break;
    01458
    01459         case Key_Left:
    01460         case Key_H:
    01461             d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
    01462             break;
    01463
    01464         case Key_Right:
    01465         case Key_L:
    01466             d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
    01467             break;
    01468         }
    01469     else
    01470         switch ( _ke->key() )
    01471         {
    01472         case Key_Down:
    01473         case Key_J:
    01474             if ( d->vmode == QScrollView::AlwaysOff )
    01475                 _ke->accept();
    01476             else {
    01477                 if (!d->scrollTimerId || d->scrollSuspended)
    01478                     scrollBy( 0, 10 );
    01479                 if (d->scrollTimerId)
    01480                     d->newScrollTimer(this, 0);
    01481             }
    01482             break;
    01483
    01484         case Key_Space:
    01485         case Key_Next:
    01486             if ( d->vmode == QScrollView::AlwaysOff )
    01487                 _ke->accept();
    01488             else {
    01489                 scrollBy( 0, clipper()->height() - offs );
    01490                 if(d->scrollSuspended)
    01491                     d->newScrollTimer(this, 0);
    01492             }
    01493             break;
    01494
    01495         case Key_Up:
    01496         case Key_K:
    01497             if ( d->vmode == QScrollView::AlwaysOff )
    01498                 _ke->accept();
    01499             else {
    01500                 if (!d->scrollTimerId || d->scrollSuspended)
    01501                     scrollBy( 0, -10 );
    01502                 if (d->scrollTimerId)
    01503                     d->newScrollTimer(this, 0);
    01504             }
    01505             break;
    01506
    01507         case Key_Prior:
    01508             if ( d->vmode == QScrollView::AlwaysOff )
    01509                 _ke->accept();
    01510             else {
    01511                 scrollBy( 0, -clipper()->height() + offs );
    01512                 if(d->scrollSuspended)
    01513                     d->newScrollTimer(this, 0);
    01514             }
    01515             break;
    01516         case Key_Right:
    01517         case Key_L:
    01518             if ( d->hmode == QScrollView::AlwaysOff )
    01519                 _ke->accept();
    01520             else {
    01521                 if (!d->scrollTimerId || d->scrollSuspended)
    01522                     scrollBy( 10, 0 );
    01523                 if (d->scrollTimerId)
    01524                     d->newScrollTimer(this, 0);
    01525             }
    01526             break;
    01527         case Key_Left:
    01528         case Key_H:
    01529             if ( d->hmode == QScrollView::AlwaysOff )
    01530                 _ke->accept();
    01531             else {
    01532                 if (!d->scrollTimerId || d->scrollSuspended)
    01533                     scrollBy( -10, 0 );
    01534                 if (d->scrollTimerId)
    01535                     d->newScrollTimer(this, 0);
    01536             }
    01537             break;
    01538         case Key_Enter:
    01539         case Key_Return:
    01540         // ### FIXME:
    01541         // or even better to HTMLAnchorElementImpl::event()
    01542             if (m_part->xmlDocImpl()) {
    01543         NodeImpl *n = m_part->xmlDocImpl()->focusNode();
    01544         if (n)
    01545             n->setActive();
    01546         }
    01547             break;
    01548         case Key_Home:
    01549             if ( d->vmode == QScrollView::AlwaysOff )
    01550                 _ke->accept();
    01551             else {
    01552                 setContentsPos( 0, 0 );
    01553                 if(d->scrollSuspended)
    01554                     d->newScrollTimer(this, 0);
    01555             }
    01556             break;
    01557         case Key_End:
    01558             if ( d->vmode == QScrollView::AlwaysOff )
    01559                 _ke->accept();
    01560             else {
    01561                 setContentsPos( 0, contentsHeight() - visibleHeight() );
    01562                 if(d->scrollSuspended)
    01563                     d->newScrollTimer(this, 0);
    01564             }
    01565             break;
    01566         case Key_Shift:
    01567             // what are you doing here?
    01568         _ke->ignore();
    01569             return;
    01570         default:
    01571             if (d->scrollTimerId)
    01572                 d->newScrollTimer(this, 0);
    01573         _ke->ignore();
    01574             return;
    01575         }
    01576
    01577     _ke->accept();
    01578 }
    01579
    01580 void KHTMLView::findTimeout()
    01581 {
    01582 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    01583     d->typeAheadActivated = false;
    01584     d->findString = "";
    01585     m_part->setStatusBarText(i18n("Find stopped."), KHTMLPart::BarDefaultText);
    01586 #endif // KHTML_NO_TYPE_AHEAD_FIND
    01587 }
    01588
    01589 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    01590 void KHTMLView::findAhead(bool increase)
    01591 {
    01592     QString status;
    01593
    01594     if(d->findLinksOnly)
    01595     {
    01596         m_part->findText(d->findString, KHTMLPart::FindNoPopups |
    01597                          KHTMLPart::FindLinksOnly, this);
    01598         if(m_part->findTextNext())
    01599         {
    01600             status = i18n("Link found: \"%1\".");
    01601         }
    01602         else
    01603         {
    01604             if(increase) KNotifyClient::beep();
    01605             status = i18n("Link not found: \"%1\".");
    01606         }
    01607     }
    01608     else
    01609     {
    01610         m_part->findText(d->findString, KHTMLPart::FindNoPopups, this);
    01611         if(m_part->findTextNext())
    01612         {
    01613             status = i18n("Text found: \"%1\".");
    01614         }
    01615         else
    01616         {
    01617             if(increase) KNotifyClient::beep();
    01618             status = i18n("Text not found: \"%1\".");
    01619         }
    01620     }
    01621
    01622     m_part->setStatusBarText(status.arg(d->findString.lower()),
    01623                              KHTMLPart::BarDefaultText);
    01624 }
    01625
    01626 void KHTMLView::updateFindAheadTimeout()
    01627 {
    01628     if( d->typeAheadActivated )
    01629         d->timer.start( 3000, true );
    01630 }
    01631
    01632 #endif // KHTML_NO_TYPE_AHEAD_FIND
    01633
    01634 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
    01635 {
    01636     if (d->m_caretViewContext && d->m_caretViewContext->keyReleasePending) {
    01637         //caretKeyReleaseEvent(_ke);
    01638     d->m_caretViewContext->keyReleasePending = false;
    01639     return;
    01640     }
    01641
    01642     if (d->accessKeysPreActivate && _ke->key() != Key_Control) d->accessKeysPreActivate=false;
    01643     if (_ke->key() == Key_Control &&  d->accessKeysPreActivate && _ke->state() == Qt::ControlButton && !(KApplication::keyboardMouseState() & Qt::ControlButton))
    01644     {
    01645         displayAccessKeys();
    01646         m_part->setStatusBarText(i18n("Access Keys activated"),KHTMLPart::BarOverrideText);
    01647         d->accessKeysActivated = true;
    01648         d->accessKeysPreActivate = false;
    01649     }
    01650     else if (d->accessKeysActivated) accessKeysTimeout();
    01651
    01652     if( d->scrollSuspendPreActivate && _ke->key() != Key_Shift )
    01653         d->scrollSuspendPreActivate = false;
    01654     if( _ke->key() == Key_Shift && d->scrollSuspendPreActivate && _ke->state() == Qt::ShiftButton
    01655         && !(KApplication::keyboardMouseState() & Qt::ShiftButton))
    01656         if (d->scrollTimerId)
    01657                 d->scrollSuspended = !d->scrollSuspended;
    01658
    01659     // Send keyup event
    01660     if ( dispatchKeyEvent( _ke ) )
    01661     {
    01662         _ke->accept();
    01663         return;
    01664     }
    01665
    01666     QScrollView::keyReleaseEvent(_ke);
    01667 }
    01668
    01669 void KHTMLView::contentsContextMenuEvent ( QContextMenuEvent * /*ce*/ )
    01670 {
    01671 // ### what kind of c*** is that ?
    01672 #if 0
    01673     if (!m_part->xmlDocImpl()) return;
    01674     int xm = _ce->x();
    01675     int ym = _ce->y();
    01676
    01677     DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove ); // ### not a mouse event!
    01678     m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
    01679
    01680     NodeImpl *targetNode = mev.innerNode.handle();
    01681     if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
    01682         int absx = 0;
    01683         int absy = 0;
    01684         targetNode->renderer()->absolutePosition(absx,absy);
    01685         QPoint pos(xm-absx,ym-absy);
    01686
    01687         QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
    01688         QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
    01689         setIgnoreEvents(true);
    01690         QApplication::sendEvent(w,&cme);
    01691         setIgnoreEvents(false);
    01692     }
    01693 #endif
    01694 }
    01695
    01696 bool KHTMLView::focusNextPrevChild( bool next )
    01697 {
    01698     // Now try to find the next child
    01699     if (m_part->xmlDocImpl() && focusNextPrevNode(next))
    01700     {
    01701     if (m_part->xmlDocImpl()->focusNode())
    01702         kdDebug() << "focusNode.name: "
    01703               << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
    01704     return true; // focus node found
    01705     }
    01706
    01707     // If we get here, pass tabbing control up to the next/previous child in our parent
    01708     d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
    01709     if (m_part->parentPart() && m_part->parentPart()->view())
    01710         return m_part->parentPart()->view()->focusNextPrevChild(next);
    01711
    01712     return QWidget::focusNextPrevChild(next);
    01713 }
    01714
    01715 void KHTMLView::doAutoScroll()
    01716 {
    01717     QPoint pos = QCursor::pos();
    01718     pos = viewport()->mapFromGlobal( pos );
    01719
    01720     int xm, ym;
    01721     viewportToContents(pos.x(), pos.y(), xm, ym);
    01722
    01723     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
    01724     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
    01725          (pos.x() < 0) || (pos.x() > visibleWidth()) )
    01726     {
    01727         ensureVisible( xm, ym, 0, 5 );
    01728
    01729 #ifndef KHTML_NO_SELECTION
    01730         // extend the selection while scrolling
    01731     DOM::Node innerNode;
    01732     if (m_part->isExtendingSelection()) {
    01733             RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
    01734             m_part->xmlDocImpl()->renderer()->layer()
    01735                 ->nodeAtPoint(renderInfo, xm, ym);
    01736             innerNode = renderInfo.innerNode();
    01737     }/*end if*/
    01738
    01739         if (innerNode.handle() && innerNode.handle()->renderer()) {
    01740             int absX, absY;
    01741             innerNode.handle()->renderer()->absolutePosition(absX, absY);
    01742
    01743             m_part->extendSelectionTo(xm, ym, absX, absY, innerNode);
    01744         }/*end if*/
    01745 #endif // KHTML_NO_SELECTION
    01746     }
    01747 }
    01748
    01749
    01750 class HackWidget : public QWidget
    01751 {
    01752  public:
    01753     inline void setNoErase() { setWFlags(getWFlags()|WRepaintNoErase); }
    01754 };
    01755
    01756 bool KHTMLView::eventFilter(QObject *o, QEvent *e)
    01757 {
    01758     if ( e->type() == QEvent::AccelOverride ) {
    01759     QKeyEvent* ke = (QKeyEvent*) e;
    01760 //kdDebug(6200) << "QEvent::AccelOverride" << endl;
    01761     if (m_part->isEditable() || m_part->isCaretMode()
    01762         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
    01763         && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
    01764 //kdDebug(6200) << "editable/navigable" << endl;
    01765         if ( (ke->state() & ControlButton) || (ke->state() & ShiftButton) ) {
    01766         switch ( ke->key() ) {
    01767         case Key_Left:
    01768         case Key_Right:
    01769         case Key_Up:
    01770         case Key_Down:
    01771         case Key_Home:
    01772         case Key_End:
    01773             ke->accept();
    01774 //kdDebug(6200) << "eaten" << endl;
    01775             return true;
    01776         default:
    01777             break;
    01778         }
    01779         }
    01780     }
    01781     }
    01782
    01783     if ( e->type() == QEvent::Leave && d->cursor_icon_widget )
    01784         d->cursor_icon_widget->hide();
    01785
    01786     QWidget *view = viewport();
    01787
    01788     if (o == view) {
    01789     // we need to install an event filter on all children of the viewport to
    01790     // be able to get correct stacking of children within the document.
    01791     if(e->type() == QEvent::ChildInserted) {
    01792         QObject *c = static_cast<QChildEvent *>(e)->child();
    01793         if (c->isWidgetType()) {
    01794         QWidget *w = static_cast<QWidget *>(c);
    01795         // don't install the event filter on toplevels
    01796         if (w->parentWidget(true) == view) {
    01797             if (!strcmp(w->name(), "__khtml")) {
    01798             w->installEventFilter(this);
    01799             w->unsetCursor();
    01800             if (!::qt_cast<QFrame*>(w))
    01801                 w->setBackgroundMode( QWidget::NoBackground );
    01802             static_cast<HackWidget *>(w)->setNoErase();
    01803             if (w->children()) {
    01804                 QObjectListIterator it(*w->children());
    01805                 for (; it.current(); ++it) {
    01806                 QWidget *widget = ::qt_cast<QWidget *>(it.current());
    01807                 if (widget && !widget->isTopLevel()) {
    01808                     if (!::qt_cast<QFrame*>(w))
    01809                         widget->setBackgroundMode( QWidget::NoBackground );
    01810                     static_cast<HackWidget *>(widget)->setNoErase();
    01811                     widget->installEventFilter(this);
    01812                 }
    01813                 }
    01814             }
    01815             }
    01816         }
    01817         }
    01818     }
    01819     } else if (o->isWidgetType()) {
    01820     QWidget *v = static_cast<QWidget *>(o);
    01821         QWidget *c = v;
    01822     while (v && v != view) {
    01823             c = v;
    01824         v = v->parentWidget(true);
    01825     }
    01826
    01827     if (v && !strcmp(c->name(), "__khtml")) {
    01828         bool block = false;
    01829         QWidget *w = static_cast<QWidget *>(o);
    01830         switch(e->type()) {
    01831         case QEvent::Paint:
    01832         if (!allowWidgetPaintEvents) {
    01833             // eat the event. Like this we can control exactly when the widget
    01834             // get's repainted.
    01835             block = true;
    01836             int x = 0, y = 0;
    01837             QWidget *v = w;
    01838             while (v && v != view) {
    01839             x += v->x();
    01840             y += v->y();
    01841             v = v->parentWidget();
    01842             }
    01843             viewportToContents( x, y, x, y );
    01844             QPaintEvent *pe = static_cast<QPaintEvent *>(e);
    01845             bool asap = !d->contentsMoving && ::qt_cast<QScrollView *>(c);
    01846
    01847             // QScrollView needs fast repaints
    01848             if ( asap && !d->painting && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer() &&
    01849                  !static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
    01850                 repaintContents(x + pe->rect().x(), y + pe->rect().y(),
    01851                                             pe->rect().width(), pe->rect().height(), true);
    01852                     } else {
    01853                 scheduleRepaint(x + pe->rect().x(), y + pe->rect().y(),
    01854                     pe->rect().width(), pe->rect().height(), asap);
    01855                     }
    01856         }
    01857         break;
    01858         case QEvent::MouseMove:
    01859         case QEvent::MouseButtonPress:
    01860         case QEvent::MouseButtonRelease:
    01861         case QEvent::MouseButtonDblClick: {
    01862         if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
    01863             QMouseEvent *me = static_cast<QMouseEvent *>(e);
    01864             QPoint pt = (me->pos() + w->pos());
    01865             QMouseEvent me2(me->type(), pt, me->button(), me->state());
    01866
    01867             if (e->type() == QEvent::MouseMove)
    01868             viewportMouseMoveEvent(&me2);
    01869             else if(e->type() == QEvent::MouseButtonPress)
    01870             viewportMousePressEvent(&me2);
    01871             else if(e->type() == QEvent::MouseButtonRelease)
    01872             viewportMouseReleaseEvent(&me2);
    01873             else
    01874             viewportMouseDoubleClickEvent(&me2);
    01875             block = true;
    01876                 }
    01877         break;
    01878         }
    01879         case QEvent::KeyPress:
    01880         case QEvent::KeyRelease:
    01881         if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
    01882             QKeyEvent *ke = static_cast<QKeyEvent *>(e);
    01883             if (e->type() == QEvent::KeyPress)
    01884             keyPressEvent(ke);
    01885             else
    01886             keyReleaseEvent(ke);
    01887             block = true;
    01888         }
    01889         default:
    01890         break;
    01891         }
    01892         if (block) {
    01893         //qDebug("eating event");
    01894         return true;
    01895         }
    01896     }
    01897     }
    01898
    01899 //    kdDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type() << endl;
    01900     return QScrollView::eventFilter(o, e);
    01901 }
    01902
    01903
    01904 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
    01905 {
    01906     return d->underMouse;
    01907 }
    01908
    01909 DOM::NodeImpl *KHTMLView::nonSharedNodeUnderMouse() const
    01910 {
    01911     return d->underMouseNonShared;
    01912 }
    01913
    01914 bool KHTMLView::scrollTo(const QRect &bounds)
    01915 {
    01916     d->scrollingSelf = true; // so scroll events get ignored
    01917
    01918     int x, y, xe, ye;
    01919     x = bounds.left();
    01920     y = bounds.top();
    01921     xe = bounds.right();
    01922     ye = bounds.bottom();
    01923
    01924     //kdDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y<<endl;
    01925
    01926     int deltax;
    01927     int deltay;
    01928
    01929     int curHeight = visibleHeight();
    01930     int curWidth = visibleWidth();
    01931
    01932     if (ye-y>curHeight-d->borderY)
    01933     ye  = y + curHeight - d->borderY;
    01934
    01935     if (xe-x>curWidth-d->borderX)
    01936     xe = x + curWidth - d->borderX;
    01937
    01938     // is xpos of target left of the view's border?
    01939     if (x < contentsX() + d->borderX )
    01940             deltax = x - contentsX() - d->borderX;
    01941     // is xpos of target right of the view's right border?
    01942     else if (xe + d->borderX > contentsX() + curWidth)
    01943             deltax = xe + d->borderX - ( contentsX() + curWidth );
    01944     else
    01945         deltax = 0;
    01946
    01947     // is ypos of target above upper border?
    01948     if (y < contentsY() + d->borderY)
    01949             deltay = y - contentsY() - d->borderY;
    01950     // is ypos of target below lower border?
    01951     else if (ye + d->borderY > contentsY() + curHeight)
    01952             deltay = ye + d->borderY - ( contentsY() + curHeight );
    01953     else
    01954         deltay = 0;
    01955
    01956     int maxx = curWidth-d->borderX;
    01957     int maxy = curHeight-d->borderY;
    01958
    01959     int scrollX,scrollY;
    01960
    01961     scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
    01962     scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
    01963
    01964     if (contentsX() + scrollX < 0)
    01965     scrollX = -contentsX();
    01966     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
    01967     scrollX = contentsWidth() - visibleWidth() - contentsX();
    01968
    01969     if (contentsY() + scrollY < 0)
    01970     scrollY = -contentsY();
    01971     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
    01972     scrollY = contentsHeight() - visibleHeight() - contentsY();
    01973
    01974     scrollBy(scrollX, scrollY);
    01975
    01976     d->scrollingSelf = false;
    01977
    01978     if ( (abs(deltax)<=maxx) && (abs(deltay)<=maxy) )
    01979     return true;
    01980     else return false;
    01981
    01982 }
    01983
    01984 bool KHTMLView::focusNextPrevNode(bool next)
    01985 {
    01986     // Sets the focus node of the document to be the node after (or if
    01987     // next is false, before) the current focus node.  Only nodes that
    01988     // are selectable (i.e. for which isFocusable() returns true) are
    01989     // taken into account, and the order used is that specified in the
    01990     // HTML spec (see DocumentImpl::nextFocusNode() and
    01991     // DocumentImpl::previousFocusNode() for details).
    01992
    01993     DocumentImpl *doc = m_part->xmlDocImpl();
    01994     NodeImpl *oldFocusNode = doc->focusNode();
    01995
    01996 #if 1
    01997     // If the user has scrolled the document, then instead of picking
    01998     // the next focusable node in the document, use the first one that
    01999     // is within the visible area (if possible).
    02000     if (d->scrollBarMoved)
    02001     {
    02002     NodeImpl *toFocus;
    02003     if (next)
    02004         toFocus = doc->nextFocusNode(oldFocusNode);
    02005     else
    02006         toFocus = doc->previousFocusNode(oldFocusNode);
    02007
    02008     if (!toFocus && oldFocusNode)
    02009         if (next)
    02010         toFocus = doc->nextFocusNode(NULL);
    02011         else
    02012         toFocus = doc->previousFocusNode(NULL);
    02013
    02014     while (toFocus && toFocus != oldFocusNode)
    02015     {
    02016
    02017         QRect focusNodeRect = toFocus->getRect();
    02018         if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
    02019         (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
    02020         {
    02021             QRect r = toFocus->getRect();
    02022             ensureVisible( r.right(), r.bottom());
    02023             ensureVisible( r.left(), r.top());
    02024             d->scrollBarMoved = false;
    02025             d->tabMovePending = false;
    02026             d->lastTabbingDirection = next;
    02027             d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
    02028             m_part->xmlDocImpl()->setFocusNode(toFocus);
    02029             Node guard(toFocus);
    02030             if (!toFocus->hasOneRef() )
    02031             {
    02032             emit m_part->nodeActivated(Node(toFocus));
    02033             }
    02034             return true;
    02035         }
    02036         }
    02037         if (next)
    02038         toFocus = doc->nextFocusNode(toFocus);
    02039         else
    02040         toFocus = doc->previousFocusNode(toFocus);
    02041
    02042         if (!toFocus && oldFocusNode)
    02043         if (next)
    02044             toFocus = doc->nextFocusNode(NULL);
    02045         else
    02046             toFocus = doc->previousFocusNode(NULL);
    02047     }
    02048
    02049     d->scrollBarMoved = false;
    02050     }
    02051 #endif
    02052
    02053     if (!oldFocusNode && d->pseudoFocusNode == KHTMLViewPrivate::PFNone)
    02054     {
    02055     ensureVisible(contentsX(), next?0:contentsHeight());
    02056     d->scrollBarMoved = false;
    02057     d->pseudoFocusNode = next?KHTMLViewPrivate::PFTop:KHTMLViewPrivate::PFBottom;
    02058     return true;
    02059     }
    02060
    02061     NodeImpl *newFocusNode = NULL;
    02062
    02063     if (d->tabMovePending && next != d->lastTabbingDirection)
    02064     {
    02065     //kdDebug ( 6000 ) << " tab move pending and tabbing direction changed!\n";
    02066     newFocusNode = oldFocusNode;
    02067     }
    02068     else if (next)
    02069     {
    02070     if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFTop )
    02071         newFocusNode = doc->nextFocusNode(oldFocusNode);
    02072     }
    02073     else
    02074     {
    02075     if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFBottom )
    02076         newFocusNode = doc->previousFocusNode(oldFocusNode);
    02077     }
    02078
    02079     bool targetVisible = false;
    02080     if (!newFocusNode)
    02081     {
    02082     if ( next )
    02083     {
    02084         targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight()-d->borderY,0,0));
    02085     }
    02086     else
    02087     {
    02088         targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,d->borderY,0,0));
    02089     }
    02090     }
    02091     else
    02092     {
    02093 #ifndef KHTML_NO_CARET
    02094         // if it's an editable element, activate the caret
    02095         if (!m_part->isCaretMode() && !m_part->isEditable()
    02096         && newFocusNode->contentEditable()) {
    02097         d->caretViewContext();
    02098         moveCaretTo(newFocusNode, 0L, true);
    02099         } else {
    02100         caretOff();
    02101     }
    02102 #endif // KHTML_NO_CARET
    02103
    02104     targetVisible = scrollTo(newFocusNode->getRect());
    02105     }
    02106
    02107     if (targetVisible)
    02108     {
    02109     //kdDebug ( 6000 ) << " target reached.\n";
    02110     d->tabMovePending = false;
    02111
    02112     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
    02113     if (newFocusNode)
    02114     {
    02115         Node guard(newFocusNode);
    02116         if (!newFocusNode->hasOneRef() )
    02117         {
    02118         emit m_part->nodeActivated(Node(newFocusNode));
    02119         }
    02120         return true;
    02121     }
    02122     else
    02123     {
    02124         d->pseudoFocusNode = next?KHTMLViewPrivate::PFBottom:KHTMLViewPrivate::PFTop;
    02125         return false;
    02126     }
    02127     }
    02128     else
    02129     {
    02130     if (!d->tabMovePending)
    02131         d->lastTabbingDirection = next;
    02132     d->tabMovePending = true;
    02133     return true;
    02134     }
    02135 }
    02136
    02137 void KHTMLView::displayAccessKeys()
    02138 {
    02139     for( NodeImpl* n = m_part->xmlDocImpl(); n != NULL; n = n->traverseNextNode()) {
    02140         if( n->isElementNode()) {
    02141             ElementImpl* en = static_cast< ElementImpl* >( n );
    02142             DOMString s = en->getAttribute( ATTR_ACCESSKEY );
    02143             if( s.length() == 1) {
    02144             QRect rec=en->getRect();
    02145             QLabel *lab=new QLabel(s.string(),viewport(),0,Qt::WDestructiveClose);
    02146             connect( this, SIGNAL(hideAccessKeys()), lab, SLOT(close()) );
    02147             connect( this, SIGNAL(repaintAccessKeys()), lab, SLOT(repaint()));
    02148             lab->setPalette(QToolTip::palette());
    02149             lab->setLineWidth(2);
    02150             lab->setFrameStyle(QFrame::Box | QFrame::Plain);
    02151             lab->setMargin(3);
    02152             lab->adjustSize();
    02153             addChild(lab,
    02154                     KMIN(rec.left()+rec.width()/2, contentsWidth() - lab->width()),
    02155                     KMIN(rec.top()+rec.height()/2, contentsHeight() - lab->height()));
    02156             showChild(lab);
    02157         }
    02158         }
    02159     }
    02160 }
    02161
    02162 void KHTMLView::accessKeysTimeout()
    02163 {
    02164 d->accessKeysActivated=false;
    02165 d->accessKeysPreActivate = false;
    02166 m_part->setStatusBarText(QString::null, KHTMLPart::BarOverrideText);
    02167 emit hideAccessKeys();
    02168 }
    02169
    02170 // Handling of the HTML accesskey attribute.
    02171 bool KHTMLView::handleAccessKey( const QKeyEvent* ev )
    02172 {
    02173 // Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
    02174 // but this code must act as if the modifiers weren't pressed
    02175     QChar c;
    02176     if( ev->key() >= Key_A && ev->key() <= Key_Z )
    02177         c = 'A' + ev->key() - Key_A;
    02178     else if( ev->key() >= Key_0 && ev->key() <= Key_9 )
    02179         c = '0' + ev->key() - Key_0;
    02180     else {
    02181         // TODO fake XKeyEvent and XLookupString ?
    02182         // This below seems to work e.g. for eacute though.
    02183         if( ev->text().length() == 1 )
    02184             c = ev->text()[ 0 ];
    02185     }
    02186     if( c.isNull())
    02187         return false;
    02188     return focusNodeWithAccessKey( c );
    02189 }
    02190
    02191 bool KHTMLView::focusNodeWithAccessKey( QChar c, KHTMLView* caller )
    02192 {
    02193     DocumentImpl *doc = m_part->xmlDocImpl();
    02194     if( !doc )
    02195         return false;
    02196     ElementImpl* node = doc->findAccessKeyElement( c );
    02197     if( !node ) {
    02198         QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
    02199         for( QPtrListIterator<KParts::ReadOnlyPart> it( frames );
    02200              it != NULL;
    02201              ++it ) {
    02202             if( !(*it)->inherits( "KHTMLPart" ))
    02203                 continue;
    02204             KHTMLPart* part = static_cast< KHTMLPart* >( *it );
    02205             if( part->view() && part->view() != caller
    02206                 && part->view()->focusNodeWithAccessKey( c, this ))
    02207                 return true;
    02208         }
    02209         // pass up to the parent
    02210         if (m_part->parentPart() && m_part->parentPart()->view()
    02211             && m_part->parentPart()->view() != caller )
    02212             return m_part->parentPart()->view()->focusNodeWithAccessKey( c, this );
    02213         return false;
    02214     }
    02215
    02216     // Scroll the view as necessary to ensure that the new focus node is visible
    02217 #ifndef KHTML_NO_CARET
    02218     // if it's an editable element, activate the caret
    02219     if (!m_part->isCaretMode() && !m_part->isEditable()
    02220     && node->contentEditable()) {
    02221         d->caretViewContext();
    02222         moveCaretTo(node, 0L, true);
    02223     } else {
    02224         caretOff();
    02225     }
    02226 #endif // KHTML_NO_CARET
    02227
    02228     QRect r = node->getRect();
    02229     ensureVisible( r.right(), r.bottom());
    02230     ensureVisible( r.left(), r.top());
    02231
    02232     Node guard( node );
    02233     if( node->isFocusable()) {
    02234     if (node->id()==ID_LABEL) {
    02235         // if Accesskey is a label, give focus to the label's referrer.
    02236         node=static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl* >( node )->getFormElement());
    02237         if (!node) return true;
    02238             guard = node;
    02239     }
    02240         // Set focus node on the document
    02241         m_part->xmlDocImpl()->setFocusNode(node);
    02242         if( node != NULL && node->hasOneRef()) // deleted, only held by guard
    02243             return true;
    02244         emit m_part->nodeActivated(Node(node));
    02245         if( node != NULL && node->hasOneRef())
    02246             return true;
    02247     }
    02248
    02249     switch( node->id()) {
    02250         case ID_A:
    02251             static_cast< HTMLAnchorElementImpl* >( node )->click();
    02252           break;
    02253         case ID_INPUT:
    02254             static_cast< HTMLInputElementImpl* >( node )->click();
    02255           break;
    02256         case ID_BUTTON:
    02257             static_cast< HTMLButtonElementImpl* >( node )->click();
    02258           break;
    02259         case ID_AREA:
    02260             static_cast< HTMLAreaElementImpl* >( node )->click();
    02261           break;
    02262         case ID_TEXTAREA:
    02263       break; // just focusing it is enough
    02264         case ID_LEGEND:
    02265             // TODO
    02266           break;
    02267     }
    02268     return true;
    02269 }
    02270
    02271 void KHTMLView::setMediaType( const QString &medium )
    02272 {
    02273     m_medium = medium;
    02274 }
    02275
    02276 QString KHTMLView::mediaType() const
    02277 {
    02278     return m_medium;
    02279 }
    02280
    02281 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
    02282 {
    02283     if (vis) {
    02284         d->visibleWidgets.replace(w, w->widget());
    02285     }
    02286     else
    02287         d->visibleWidgets.remove(w);
    02288 }
    02289
    02290 bool KHTMLView::needsFullRepaint() const
    02291 {
    02292     return d->needsFullRepaint;
    02293 }
    02294
    02295 void KHTMLView::print()
    02296 {
    02297     print( false );
    02298 }
    02299
    02300 void KHTMLView::print(bool quick)
    02301 {
    02302     if(!m_part->xmlDocImpl()) return;
    02303     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
    02304     if(!root) return;
    02305
    02306     // this only works on Unix - we assume 72dpi
    02307     KPrinter *printer = new KPrinter(true, QPrinter::PrinterResolution);
    02308     printer->addDialogPage(new KHTMLPrintSettings());
    02309     QString docname = m_part->xmlDocImpl()->URL().prettyURL();
    02310     if ( !docname.isEmpty() )
    02311         docname = KStringHandler::csqueeze(docname, 80);
    02312     if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
    02313         viewport()->setCursor( waitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
    02314         // set up KPrinter
    02315         printer->setFullPage(false);
    02316         printer->setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
    02317         printer->setDocName(docname);
    02318
    02319         QPainter *p = new QPainter;
    02320         p->begin( printer );
    02321         khtml::setPrintPainter( p );
    02322
    02323         m_part->xmlDocImpl()->setPaintDevice( printer );
    02324         QString oldMediaType = mediaType();
    02325         setMediaType( "print" );
    02326         // We ignore margin settings for html and body when printing
    02327         // and use the default margins from the print-system
    02328         // (In Qt 3.0.x the default margins are hardcoded in Qt)
    02329         m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
    02330                                                   "* { background-image: none !important;"
    02331                                                   "    background-color: white !important;"
    02332                                                   "    color: black !important; }"
    02333                           "body { margin: 0px !important; }"
    02334                           "html { margin: 0px !important; }" :
    02335                           "body { margin: 0px !important; }"
    02336                           "html { margin: 0px !important; }"
    02337                           );
    02338
    02339         QPaintDeviceMetrics metrics( printer );
    02340
    02341         // this is a simple approximation... we layout the document
    02342         // according to the width of the page, then just cut
    02343         // pages without caring about the content. We should do better
    02344         // in the future, but for the moment this is better than no
    02345         // printing support
    02346         kdDebug(6000) << "printing: physical page width = " << metrics.width()
    02347                       << " height = " << metrics.height() << endl;
    02348         root->setPrintingMode(true);
    02349         root->setWidth(metrics.width());
    02350
    02351         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
    02352         m_part->xmlDocImpl()->updateStyleSelector();
    02353         root->setPrintImages( printer->option("app-khtml-printimages") == "true");
    02354         root->setNeedsLayoutAndMinMaxRecalc();
    02355         root->layout();
    02356         khtml::RenderWidget::flushWidgetResizes(); // make sure widgets have their final size
    02357
    02358         bool printHeader = (printer->option("app-khtml-printheader") == "true");
    02359
    02360         int headerHeight = 0;
    02361         QFont headerFont("helvetica", 8);
    02362
    02363         QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),true);
    02364         QString headerMid = docname;
    02365         QString headerRight;
    02366
    02367         if (printHeader)
    02368         {
    02369            p->setFont(headerFont);
    02370            headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
    02371         }
    02372
    02373         // ok. now print the pages.
    02374         kdDebug(6000) << "printing: html page width = " << root->docWidth()
    02375                       << " height = " << root->docHeight() << endl;
    02376         kdDebug(6000) << "printing: margins left = " << printer->margins().width()
    02377                       << " top = " << printer->margins().height() << endl;
    02378         kdDebug(6000) << "printing: paper width = " << metrics.width()
    02379                       << " height = " << metrics.height() << endl;
    02380         // if the width is too large to fit on the paper we just scale
    02381         // the whole thing.
    02382         int pageHeight = metrics.height();
    02383         int pageWidth = metrics.width();
    02384         p->setClipRect(0,0, pageWidth, pageHeight);
    02385
    02386         pageHeight -= headerHeight;
    02387
    02388         bool scalePage = false;
    02389         double scale = 0.0;
    02390 #ifndef QT_NO_TRANSFORMATIONS
    02391         if(root->docWidth() > metrics.width()) {
    02392             scalePage = true;
    02393             scale = ((double) metrics.width())/((double) root->docWidth());
    02394             pageHeight = (int) (pageHeight/scale);
    02395             pageWidth = (int) (pageWidth/scale);
    02396             headerHeight = (int) (headerHeight/scale);
    02397         }
    02398 #endif
    02399         kdDebug(6000) << "printing: scaled html width = " << pageWidth
    02400                       << " height = " << pageHeight << endl;
    02401
    02402         // Squeeze header to make it it on the page.
    02403         if (printHeader)
    02404         {
    02405             int available_width = metrics.width() - 10 -
    02406                 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
    02407                          p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
    02408             if (available_width < 150)
    02409                available_width = 150;
    02410             int mid_width;
    02411             int squeeze = 120;
    02412             do {
    02413                 headerMid = KStringHandler::csqueeze(docname, squeeze);
    02414                 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
    02415                 squeeze -= 10;
    02416             } while (mid_width > available_width);
    02417         }
    02418
    02419         int top = 0;
    02420         int page = 1;
    02421         int bottom = 0;
    02422         int oldbottom = 0;
    02423         while(top < root->docHeight()) {
    02424             if(top > 0) printer->newPage();
    02425             if (printHeader)
    02426             {
    02427                 int dy = p->fontMetrics().lineSpacing();
    02428                 p->setPen(Qt::black);
    02429                 p->setFont(headerFont);
    02430
    02431                 headerRight = QString("#%1").arg(page);
    02432
    02433                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
    02434                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
    02435                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
    02436             }
    02437
    02438 #ifndef QT_NO_TRANSFORMATIONS
    02439             if (scalePage)
    02440                 p->scale(scale, scale);
    02441 #endif
    02442             p->translate(0, headerHeight-top);
    02443
    02444             oldbottom = top+pageHeight;
    02445             root->setTruncatedAt(oldbottom);
    02446
    02447             root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
    02448             bottom = root->bestTruncatedAt();
    02449             kdDebug(6000) << "printed: page " << page <<" truncatedAt = " << oldbottom
    02450                           << " bestTruncatedAt = " << bottom << endl;
    02451             if (bottom == 0) bottom = oldbottom;
    02452
    02453             if (bottom >= root->docHeight())
    02454                 break; // Stop if we have printed everything
    02455
    02456             top = bottom;
    02457             p->resetXForm();
    02458             page++;
    02459         }
    02460
    02461         p->end();
    02462         delete p;
    02463
    02464         // and now reset the layout to the usual one...
    02465         root->setPrintingMode(false);
    02466         khtml::setPrintPainter( 0 );
    02467         setMediaType( oldMediaType );
    02468         m_part->xmlDocImpl()->setPaintDevice( this );
    02469         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
    02470         m_part->xmlDocImpl()->updateStyleSelector();
    02471         viewport()->unsetCursor();
    02472     }
    02473     delete printer;
    02474 }
    02475
    02476 void KHTMLView::slotPaletteChanged()
    02477 {
    02478     if(!m_part->xmlDocImpl()) return;
    02479     DOM::DocumentImpl *document = m_part->xmlDocImpl();
    02480     if (!document->isHTMLDocument()) return;
    02481     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
    02482     if(!root) return;
    02483     root->style()->resetPalette();
    02484     NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
    02485     if(!body) return;
    02486     body->setChanged(true);
    02487     body->recalcStyle( NodeImpl::Force );
    02488 }
    02489
    02490 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
    02491 {
    02492     if(!m_part->xmlDocImpl()) return;
    02493     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
    02494     if(!root) return;
    02495
    02496     m_part->xmlDocImpl()->setPaintDevice(p->device());
    02497     root->setPrintingMode(true);
    02498     root->setWidth(rc.width());
    02499
    02500     p->save();
    02501     p->setClipRect(rc);
    02502     p->translate(rc.left(), rc.top());
    02503     double scale = ((double) rc.width()/(double) root->docWidth());
    02504     int height = (int) ((double) rc.height() / scale);
    02505 #ifndef QT_NO_TRANSFORMATIONS
    02506     p->scale(scale, scale);
    02507 #endif
    02508
    02509     root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
    02510     if (more)
    02511         *more = yOff + height < root->docHeight();
    02512     p->restore();
    02513
    02514     root->setPrintingMode(false);
    02515     m_part->xmlDocImpl()->setPaintDevice( this );
    02516 }
    02517
    02518
    02519 void KHTMLView::useSlowRepaints()
    02520 {
    02521     d->useSlowRepaints = true;
    02522     setStaticBackground(true);
    02523 }
    02524
    02525
    02526 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
    02527 {
    02528 #ifndef KHTML_NO_SCROLLBARS
    02529     d->vmode = mode;
    02530     QScrollView::setVScrollBarMode(mode);
    02531 #else
    02532     Q_UNUSED( mode );
    02533 #endif
    02534 }
    02535
    02536 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
    02537 {
    02538 #ifndef KHTML_NO_SCROLLBARS
    02539     d->hmode = mode;
    02540     QScrollView::setHScrollBarMode(mode);
    02541 #else
    02542     Q_UNUSED( mode );
    02543 #endif
    02544 }
    02545
    02546 void KHTMLView::restoreScrollBar()
    02547 {
    02548     int ow = visibleWidth();
    02549     QScrollView::setVScrollBarMode(d->vmode);
    02550     if (visibleWidth() != ow)
    02551         layout();
    02552     d->prevScrollbarVisible = verticalScrollBar()->isVisible();
    02553 }
    02554
    02555 QStringList KHTMLView::formCompletionItems(const QString &name) const
    02556 {
    02557     if (!m_part->settings()->isFormCompletionEnabled())
    02558         return QStringList();
    02559     if (!d->formCompletions)
    02560         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
    02561     return d->formCompletions->readListEntry(name);
    02562 }
    02563
    02564 void KHTMLView::clearCompletionHistory(const QString& name)
    02565 {
    02566     if (!d->formCompletions)
    02567     {
    02568         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
    02569     }
    02570     d->formCompletions->writeEntry(name, "");
    02571     d->formCompletions->sync();
    02572 }
    02573
    02574 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
    02575 {
    02576     if (!m_part->settings()->isFormCompletionEnabled())
    02577         return;
    02578     // don't store values that are all numbers or just numbers with
    02579     // dashes or spaces as those are likely credit card numbers or
    02580     // something similar
    02581     bool cc_number(true);
    02582     for (unsigned int i = 0; i < value.length(); ++i)
    02583     {
    02584       QChar c(value[i]);
    02585       if (!c.isNumber() && c != '-' && !c.isSpace())
    02586       {
    02587         cc_number = false;
    02588         break;
    02589       }
    02590     }
    02591     if (cc_number)
    02592       return;
    02593     QStringList items = formCompletionItems(name);
    02594     if (!items.contains(value))
    02595         items.prepend(value);
    02596     while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
    02597         items.remove(items.fromLast());
    02598     d->formCompletions->writeEntry(name, items);
    02599 }
    02600
    02601 void KHTMLView::addNonPasswordStorableSite(const QString& host)
    02602 {
    02603     if (!d->formCompletions) {
    02604         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
    02605     }
    02606
    02607     d->formCompletions->setGroup("NonPasswordStorableSites");
    02608     QStringList sites = d->formCompletions->readListEntry("Sites");
    02609     sites.append(host);
    02610     d->formCompletions->writeEntry("Sites", sites);
    02611     d->formCompletions->sync();
    02612     d->formCompletions->setGroup(QString::null);//reset
    02613 }
    02614
    02615 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
    02616 {
    02617     if (!d->formCompletions) {
    02618         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
    02619     }
    02620     d->formCompletions->setGroup("NonPasswordStorableSites");
    02621     QStringList sites =  d->formCompletions->readListEntry("Sites");
    02622     d->formCompletions->setGroup(QString::null);//reset
    02623
    02624     return (sites.find(host) != sites.end());
    02625 }
    02626
    02627 // returns true if event should be swallowed
    02628 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
    02629                    DOM::NodeImpl *targetNodeNonShared, bool cancelable,
    02630                    int detail,QMouseEvent *_mouse, bool setUnder,
    02631                    int mouseEventType)
    02632 {
    02633     if (d->underMouse)
    02634     d->underMouse->deref();
    02635     d->underMouse = targetNode;
    02636     if (d->underMouse)
    02637     d->underMouse->ref();
    02638
    02639     if (d->underMouseNonShared)
    02640     d->underMouseNonShared->deref();
    02641     d->underMouseNonShared = targetNodeNonShared;
    02642     if (d->underMouseNonShared)
    02643     d->underMouseNonShared->ref();
    02644
    02645     int exceptioncode = 0;
    02646     int pageX = 0;
    02647     int pageY = 0;
    02648     viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
    02649     int clientX = pageX - contentsX();
    02650     int clientY = pageY - contentsY();
    02651     int screenX = _mouse->globalX();
    02652     int screenY = _mouse->globalY();
    02653     int button = -1;
    02654     switch (_mouse->button()) {
    02655     case LeftButton:
    02656         button = 0;
    02657         break;
    02658     case MidButton:
    02659         button = 1;
    02660         break;
    02661     case RightButton:
    02662         button = 2;
    02663         break;
    02664     default:
    02665         break;
    02666     }
    02667     if (d->accessKeysPreActivate && button!=-1)
    02668         d->accessKeysPreActivate=false;
    02669
    02670     bool ctrlKey = (_mouse->state() & ControlButton);
    02671     bool altKey = (_mouse->state() & AltButton);
    02672     bool shiftKey = (_mouse->state() & ShiftButton);
    02673     bool metaKey = (_mouse->state() & MetaButton);
    02674
    02675     // mouseout/mouseover
    02676     if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
    02677
    02678         // ### this code sucks. we should save the oldUnder instead of calculating
    02679         // it again. calculating is expensive! (Dirk)
    02680         NodeImpl *oldUnder = 0;
    02681     if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
    02682         NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
    02683         m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
    02684         oldUnder = mev.innerNode.handle();
    02685     }
    02686 //  qDebug("oldunder=%p (%s), target=%p (%s) x/y=%d/%d", oldUnder, oldUnder ? oldUnder->renderer()->renderName() : 0, targetNode,  targetNode ? targetNode->renderer()->renderName() : 0, _mouse->x(), _mouse->y());
    02687     if (oldUnder != targetNode) {
    02688         // send mouseout event to the old node
    02689         if (oldUnder){
    02690         oldUnder->ref();
    02691         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
    02692                             true,true,m_part->xmlDocImpl()->defaultView(),
    02693                             0,screenX,screenY,clientX,clientY,pageX, pageY,
    02694                             ctrlKey,altKey,shiftKey,metaKey,
    02695                             button,targetNode);
    02696         me->ref();
    02697         oldUnder->dispatchEvent(me,exceptioncode,true);
    02698         me->deref();
    02699         }
    02700
    02701         // send mouseover event to the new node
    02702         if (targetNode) {
    02703         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
    02704                             true,true,m_part->xmlDocImpl()->defaultView(),
    02705                             0,screenX,screenY,clientX,clientY,pageX, pageY,
    02706                             ctrlKey,altKey,shiftKey,metaKey,
    02707                             button,oldUnder);
    02708
    02709         me->ref();
    02710         targetNode->dispatchEvent(me,exceptioncode,true);
    02711         me->deref();
    02712         }
    02713
    02714             if (oldUnder)
    02715                 oldUnder->deref();
    02716         }
    02717     }
    02718
    02719     bool swallowEvent = false;
    02720
    02721     if (targetNode) {
    02722         // send the actual event
    02723         bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
    02724                           _mouse->type() == QEvent::MouseButtonDblClick );
    02725         MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
    02726                         true,cancelable,m_part->xmlDocImpl()->defaultView(),
    02727                         detail,screenX,screenY,clientX,clientY,pageX, pageY,
    02728                         ctrlKey,altKey,shiftKey,metaKey,
    02729                         button,0, _mouse, dblclick );
    02730         me->ref();
    02731         targetNode->dispatchEvent(me,exceptioncode,true);
    02732         if (me->defaultHandled() || me->defaultPrevented())
    02733             swallowEvent = true;
    02734         me->deref();
    02735
    02736         if (eventId == EventImpl::MOUSEDOWN_EVENT) {
    02737             // Focus should be shifted on mouse down, not on a click.  -dwh
    02738             // Blur current focus node when a link/button is clicked; this
    02739             // is expected by some sites that rely on onChange handlers running
    02740             // from form fields before the button click is processed.
    02741             DOM::NodeImpl* nodeImpl = targetNode;
    02742             for ( ; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode());
    02743             if (nodeImpl && nodeImpl->isMouseFocusable())
    02744                 m_part->xmlDocImpl()->setFocusNode(nodeImpl);
    02745             else if (!nodeImpl || !nodeImpl->focused())
    02746                 m_part->xmlDocImpl()->setFocusNode(0);
    02747         }
    02748     }
    02749
    02750     return swallowEvent;
    02751 }
    02752
    02753 void KHTMLView::setIgnoreWheelEvents( bool e )
    02754 {
    02755     d->ignoreWheelEvents = e;
    02756 }
    02757
    02758 #ifndef QT_NO_WHEELEVENT
    02759
    02760 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
    02761 {
    02762     if (d->accessKeysPreActivate) d->accessKeysPreActivate=false;
    02763
    02764     if ( ( e->state() & ControlButton) == ControlButton )
    02765     {
    02766         emit zoomView( - e->delta() );
    02767         e->accept();
    02768     }
    02769     else if (d->firstRelayout)
    02770     {
    02771         e->accept();
    02772     }
    02773     else if( (   (e->orientation() == Vertical &&
    02774                    ((d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
    02775                      || e->delta() > 0 && contentsY() <= 0
    02776                      || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight()))
    02777               ||
    02778                  (e->orientation() == Horizontal &&
    02779                     ((d->ignoreWheelEvents && !horizontalScrollBar()->isVisible())
    02780                      || e->delta() > 0 && contentsX() <=0
    02781                      || e->delta() < 0 && contentsX() >= contentsWidth() - visibleWidth())))
    02782             && m_part->parentPart())
    02783     {
    02784         if ( m_part->parentPart()->view() )
    02785             m_part->parentPart()->view()->wheelEvent( e );
    02786         e->ignore();
    02787     }
    02788     else if ( (e->orientation() == Vertical && d->vmode == QScrollView::AlwaysOff) ||
    02789               (e->orientation() == Horizontal && d->hmode == QScrollView::AlwaysOff) )
    02790     {
    02791         e->accept();
    02792     }
    02793     else
    02794     {
    02795         d->scrollBarMoved = true;
    02796         QScrollView::viewportWheelEvent( e );
    02797
    02798         QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, QPoint(-1,-1), QPoint(-1,-1), Qt::NoButton, e->state() );
    02799         emit viewportMouseMoveEvent ( tempEvent );
    02800         delete tempEvent;
    02801     }
    02802
    02803 }
    02804 #endif
    02805
    02806 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
    02807 {
    02808     // Handle drops onto frames (#16820)
    02809     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
    02810     // in e.g. kmail, so not handled here).
    02811     if ( m_part->parentPart() )
    02812     {
    02813         QApplication::sendEvent(m_part->parentPart()->widget(), ev);
    02814     return;
    02815     }
    02816     QScrollView::dragEnterEvent( ev );
    02817 }
    02818
    02819 void KHTMLView::dropEvent( QDropEvent *ev )
    02820 {
    02821     // Handle drops onto frames (#16820)
    02822     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
    02823     // in e.g. kmail, so not handled here).
    02824     if ( m_part->parentPart() )
    02825     {
    02826         QApplication::sendEvent(m_part->parentPart()->widget(), ev);
    02827     return;
    02828     }
    02829     QScrollView::dropEvent( ev );
    02830 }
    02831
    02832 void KHTMLView::focusInEvent( QFocusEvent *e )
    02833 {
    02834     DOM::NodeImpl* fn = m_part->xmlDocImpl() ? m_part->xmlDocImpl()->focusNode() : 0;
    02835     if (fn && fn->renderer() && fn->renderer()->isWidget() &&
    02836         (e->reason() != QFocusEvent::Mouse) &&
    02837         static_cast<khtml::RenderWidget*>(fn->renderer())->widget())
    02838         static_cast<khtml::RenderWidget*>(fn->renderer())->widget()->setFocus();
    02839 #ifndef KHTML_NO_CARET
    02840     // Restart blink frequency timer if it has been killed, but only on
    02841     // editable nodes
    02842     if (d->m_caretViewContext &&
    02843         d->m_caretViewContext->freqTimerId == -1 &&
    02844         fn) {
    02845         if (m_part->isCaretMode()
    02846         || m_part->isEditable()
    02847             || (fn && fn->renderer()
    02848             && fn->renderer()->style()->userInput()
    02849                 == UI_ENABLED)) {
    02850             d->m_caretViewContext->freqTimerId = startTimer(500);
    02851         d->m_caretViewContext->visible = true;
    02852         }/*end if*/
    02853     }/*end if*/
    02854     showCaret();
    02855 #endif // KHTML_NO_CARET
    02856     QScrollView::focusInEvent( e );
    02857 }
    02858
    02859 void KHTMLView::focusOutEvent( QFocusEvent *e )
    02860 {
    02861     if(m_part) m_part->stopAutoScroll();
    02862
    02863 #ifndef KHTML_NO_TYPE_AHEAD_FIND
    02864     if(d->typeAheadActivated)
    02865     {
    02866         findTimeout();
    02867     }
    02868 #endif // KHTML_NO_TYPE_AHEAD_FIND
    02869
    02870 #ifndef KHTML_NO_CARET
    02871     if (d->m_caretViewContext) {
    02872         switch (d->m_caretViewContext->displayNonFocused) {
    02873     case KHTMLPart::CaretInvisible:
    02874             hideCaret();
    02875         break;
    02876     case KHTMLPart::CaretVisible: {
    02877         killTimer(d->m_caretViewContext->freqTimerId);
    02878         d->m_caretViewContext->freqTimerId = -1;
    02879             NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
    02880         if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
    02881         || m_part->isEditable()
    02882             || (caretNode && caretNode->renderer()
    02883             && caretNode->renderer()->style()->userInput()
    02884                 == UI_ENABLED))) {
    02885             d->m_caretViewContext->visible = true;
    02886             showCaret(true);
    02887         }/*end if*/
    02888         break;
    02889     }
    02890     case KHTMLPart::CaretBlink:
    02891         // simply leave as is
    02892         break;
    02893     }/*end switch*/
    02894     }/*end if*/
    02895 #endif // KHTML_NO_CARET
    02896
    02897     if ( d->cursor_icon_widget )
    02898         d->cursor_icon_widget->hide();
    02899
    02900     QScrollView::focusOutEvent( e );
    02901 }
    02902
    02903 void KHTMLView::slotScrollBarMoved()
    02904 {
    02905     if ( !d->firstRelayout && !d->complete && m_part->xmlDocImpl() &&
    02906           d->layoutSchedulingEnabled) {
    02907         // contents scroll while we are not complete: we need to check our layout *now*
    02908         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>( m_part->xmlDocImpl()->renderer() );
    02909         if (root && root->needsLayout()) {
    02910             unscheduleRelayout();
    02911             layout();
    02912         }
    02913     }
    02914     if (!d->scrollingSelf) {
    02915         d->scrollBarMoved = true;
    02916         d->contentsMoving = true;
    02917         // ensure quick reset of contentsMoving flag
    02918         scheduleRepaint(0, 0, 0, 0);
    02919     }
    02920 }
    02921
    02922 void KHTMLView::timerEvent ( QTimerEvent *e )
    02923 {
    02924 //    kdDebug() << "timer event " << e->timerId() << endl;
    02925     if ( e->timerId() == d->scrollTimerId ) {
    02926         if( d->scrollSuspended )
    02927             return;
    02928         switch (d->scrollDirection) {
    02929             case KHTMLViewPrivate::ScrollDown:
    02930                 if (contentsY() + visibleHeight () >= contentsHeight())
    02931                     d->newScrollTimer(this, 0);
    02932                 else
    02933                     scrollBy( 0, d->scrollBy );
    02934                 break;
    02935             case KHTMLViewPrivate::ScrollUp:
    02936                 if (contentsY() <= 0)
    02937                     d->newScrollTimer(this, 0);
    02938                 else
    02939                     scrollBy( 0, -d->scrollBy );
    02940                 break;
    02941             case KHTMLViewPrivate::ScrollRight:
    02942                 if (contentsX() + visibleWidth () >= contentsWidth())
    02943                     d->newScrollTimer(this, 0);
    02944                 else
    02945                     scrollBy( d->scrollBy, 0 );
    02946                 break;
    02947             case KHTMLViewPrivate::ScrollLeft:
    02948                 if (contentsX() <= 0)
    02949                     d->newScrollTimer(this, 0);
    02950                 else
    02951                     scrollBy( -d->scrollBy, 0 );
    02952                 break;
    02953         }
    02954         return;
    02955     }
    02956     else if ( e->timerId() == d->layoutTimerId ) {
    02957         d->dirtyLayout = true;
    02958         layout();
    02959         if (d->firstRelayout) {
    02960             d->firstRelayout = false;
    02961             verticalScrollBar()->setEnabled( true );
    02962             horizontalScrollBar()->setEnabled( true );
    02963         }
    02964     }
    02965 #ifndef KHTML_NO_CARET
    02966     else if (d->m_caretViewContext
    02967              && e->timerId() == d->m_caretViewContext->freqTimerId) {
    02968         d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
    02969     if (d->m_caretViewContext->displayed) {
    02970         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
    02971             d->m_caretViewContext->width,
    02972             d->m_caretViewContext->height);
    02973     }/*end if*/
    02974 //  if (d->m_caretViewContext->visible) cout << "|" << flush;
    02975 //  else cout << "" << flush;
    02976     return;
    02977     }
    02978 #endif
    02979
    02980     d->contentsMoving = false;
    02981     if( m_part->xmlDocImpl() ) {
    02982     DOM::DocumentImpl *document = m_part->xmlDocImpl();
    02983     khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
    02984
    02985     if ( root && root->needsLayout() ) {
    02986         killTimer(d->repaintTimerId);
    02987         d->repaintTimerId = 0;
    02988         scheduleRelayout();
    02989         return;
    02990     }
    02991     }
    02992
    02993     setStaticBackground(d->useSlowRepaints);
    02994
    02995 //        kdDebug() << "scheduled repaint "<< d->repaintTimerId  << endl;
    02996     killTimer(d->repaintTimerId);
    02997     d->repaintTimerId = 0;
    02998
    02999     QRegion updateRegion;
    03000     QMemArray<QRect> rects = d->updateRegion.rects();
    03001
    03002     d->updateRegion = QRegion();
    03003
    03004     if ( rects.size() )
    03005         updateRegion = rects[0];
    03006
    03007     for ( unsigned i = 1; i < rects.size(); ++i ) {
    03008         QRect obR = updateRegion.boundingRect();
    03009         QRegion newRegion = updateRegion.unite(rects[i]);
    03010         if (2*newRegion.boundingRect().height() > 3*obR.height() )
    03011         {
    03012             repaintContents( obR );
    03013             updateRegion = rects[i];
    03014         }
    03015         else
    03016             updateRegion = newRegion;
    03017     }
    03018
    03019     if ( !updateRegion.isNull() )
    03020         repaintContents( updateRegion.boundingRect() );
    03021
    03022     if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
    03023         QWidget* w;
    03024         d->dirtyLayout = false;
    03025
    03026         QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
    03027         QPtrList<RenderWidget> toRemove;
    03028         for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
    03029             int xp = 0, yp = 0;
    03030             w = it.current();
    03031             RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
    03032             if (!rw->absolutePosition(xp, yp) ||
    03033                 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
    03034                 toRemove.append(rw);
    03035         }
    03036         for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
    03037             if ( (w = d->visibleWidgets.take(r) ) )
    03038                 addChild(w, 0, -500000);
    03039     }
    03040     if (d->accessKeysActivated) emit repaintAccessKeys();
    03041     if (d->emitCompletedAfterRepaint) {
    03042         if (d->emitCompletedAfterRepaint == KHTMLViewPrivate::CSFull)
    03043             emit m_part->completed();
    03044         else
    03045             emit m_part->completed(true);
    03046         d->emitCompletedAfterRepaint = KHTMLViewPrivate::CSNone;
    03047     }
    03048 }
    03049
    03050 void KHTMLView::scheduleRelayout(khtml::RenderObject * /*clippedObj*/)
    03051 {
    03052     if (!d->layoutSchedulingEnabled || d->layoutTimerId)
    03053         return;
    03054
    03055     d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
    03056                              ? 1000 : 0 );
    03057 }
    03058
    03059 void KHTMLView::unscheduleRelayout()
    03060 {
    03061     if (!d->layoutTimerId)
    03062         return;
    03063
    03064     killTimer(d->layoutTimerId);
    03065     d->layoutTimerId = 0;
    03066 }
    03067
    03068 void KHTMLView::unscheduleRepaint()
    03069 {
    03070     if (!d->repaintTimerId)
    03071         return;
    03072
    03073     killTimer(d->repaintTimerId);
    03074     d->repaintTimerId = 0;
    03075 }
    03076
    03077 void KHTMLView::scheduleRepaint(int x, int y, int w, int h, bool asap)
    03078 {
    03079     bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
    03080
    03081 //     kdDebug() << "parsing " << parsing << endl;
    03082 //     kdDebug() << "complete " << d->complete << endl;
    03083
    03084     int time = parsing ? 300 : (!asap ? ( !d->complete ? 100 : 20 ) : 0);
    03085
    03086 #ifdef DEBUG_FLICKER
    03087     QPainter p;
    03088     p.begin( viewport() );
    03089
    03090     int vx, vy;
    03091     contentsToViewport( x, y, vx, vy );
    03092     p.fillRect( vx, vy, w, h, Qt::red );
    03093     p.end();
    03094 #endif
    03095
    03096     d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
    03097
    03098     if (asap && !parsing)
    03099         unscheduleRelayout();
    03100
    03101     if ( !d->repaintTimerId )
    03102         d->repaintTimerId = startTimer( time );
    03103
    03104 //     kdDebug() << "starting timer " << time << endl;
    03105 }
    03106
    03107 void KHTMLView::complete( bool pendingAction )
    03108 {
    03109 //     kdDebug() << "KHTMLView::complete()" << endl;
    03110
    03111     d->complete = true;
    03112
    03113     // is there a relayout pending?
    03114     if (d->layoutTimerId)
    03115     {
    03116 //         kdDebug() << "requesting relayout now" << endl;
    03117         // do it now
    03118         killTimer(d->layoutTimerId);
    03119         d->layoutTimerId = startTimer( 0 );
    03120         d->emitCompletedAfterRepaint = pendingAction ?
    03121             KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
    03122     }
    03123
    03124     // is there a repaint pending?
    03125     if (d->repaintTimerId)
    03126     {
    03127 //         kdDebug() << "requesting repaint now" << endl;
    03128         // do it now
    03129         killTimer(d->repaintTimerId);
    03130         d->repaintTimerId = startTimer( 20 );
    03131         d->emitCompletedAfterRepaint = pendingAction ?
    03132             KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
    03133     }
    03134
    03135     if (!d->emitCompletedAfterRepaint)
    03136     {
    03137         if (!pendingAction)
    03138         emit m_part->completed();
    03139         else
    03140             emit m_part->completed(true);
    03141     }
    03142
    03143 }
    03144
    03145 void KHTMLView::slotMouseScrollTimer()
    03146 {
    03147     scrollBy( d->m_mouseScroll_byX, d->m_mouseScroll_byY );
    03148 }
    03149
    03150 #ifndef KHTML_NO_CARET
    03151
    03152 // ### the dependencies on static functions are a nightmare. just be
    03153 // hacky and include the implementation here. Clean me up, please.
    03154
    03155 #include "khtml_caret.cpp"
    03156
    03157 void KHTMLView::initCaret(bool keepSelection)
    03158 {
    03159 #if DEBUG_CARETMODE > 0
    03160   kdDebug(6200) << "begin initCaret" << endl;
    03161 #endif
    03162   // save caretMoved state as moveCaretTo changes it
    03163   if (m_part->xmlDocImpl()) {
    03164 #if 0
    03165     ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
    03166     if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
    03167 #endif
    03168     d->caretViewContext();
    03169     bool cmoved = d->m_caretViewContext->caretMoved;
    03170     if (m_part->d->caretNode().isNull()) {
    03171       // set to document, position will be sanitized anyway
    03172       m_part->d->caretNode() = m_part->document();
    03173       m_part->d->caretOffset() = 0L;
    03174       // This sanity check is necessary for the not so unlikely case that
    03175       // setEditable or setCaretMode is called before any render objects have
    03176       // been created.
    03177       if (!m_part->d->caretNode().handle()->renderer()) return;
    03178     }/*end if*/
    03179 //    kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
    03180 //          << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
    03181     // ### does not repaint the selection on keepSelection!=false
    03182     moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
    03183 //    kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
    03184 //          << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
    03185     d->m_caretViewContext->caretMoved = cmoved;
    03186   }/*end if*/
    03187 #if DEBUG_CARETMODE > 0
    03188   kdDebug(6200) << "end initCaret" << endl;
    03189 #endif
    03190 }
    03191
    03192 bool KHTMLView::caretOverrides() const
    03193 {
    03194     bool cm = m_part->isCaretMode();
    03195     bool dm = m_part->isEditable();
    03196     return cm && !dm ? false
    03197         : (dm || m_part->d->caretNode().handle()->contentEditable())
    03198       && d->editorContext()->override;
    03199 }
    03200
    03201 void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
    03202 {
    03203   if (m_part->isCaretMode() || m_part->isEditable()) return;
    03204   if (node->focused()) return;
    03205
    03206   // Find first ancestor whose "user-input" is "enabled"
    03207   NodeImpl *firstAncestor = 0;
    03208   while (node) {
    03209     if (node->renderer()
    03210        && node->renderer()->style()->userInput() != UI_ENABLED)
    03211       break;
    03212     firstAncestor = node;
    03213     node = node->parentNode();
    03214   }/*wend*/
    03215
    03216   if (!node) firstAncestor = 0;
    03217
    03218   DocumentImpl *doc = m_part->xmlDocImpl();
    03219   // ensure that embedded widgets don't lose their focus
    03220   if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
    03221     && doc->focusNode()->renderer()->isWidget())
    03222     return;
    03223
    03224   // Set focus node on the document
    03225 #if DEBUG_CARETMODE > 1
    03226   kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
    03227     << (firstAncestor ? firstAncestor->nodeName().string() : QString::null) << endl;
    03228 #endif
    03229   doc->setFocusNode(firstAncestor);
    03230   emit m_part->nodeActivated(Node(firstAncestor));
    03231 }
    03232
    03233 void KHTMLView::recalcAndStoreCaretPos(CaretBox *hintBox)
    03234 {
    03235     if (!m_part || m_part->d->caretNode().isNull()) return;
    03236     d->caretViewContext();
    03237     NodeImpl *caretNode = m_part->d->caretNode().handle();
    03238 #if DEBUG_CARETMODE > 0
    03239   kdDebug(6200) << "recalcAndStoreCaretPos: caretNode=" << caretNode << (caretNode ? " "+caretNode->nodeName().string() : QString::null) << " r@" << caretNode->renderer() << (caretNode->renderer() && caretNode->renderer()->isText() ? " \"" + QConstString(static_cast<RenderText *>(caretNode->renderer())->str->s, kMin(static_cast<RenderText *>(caretNode->renderer())->str->l, 15u)).string() + "\"" : QString::null) << endl;
    03240 #endif
    03241     caretNode->getCaret(m_part->d->caretOffset(), caretOverrides(),
    03242             d->m_caretViewContext->x, d->m_caretViewContext->y,
    03243         d->m_caretViewContext->width,
    03244         d->m_caretViewContext->height);
    03245
    03246     if (hintBox && d->m_caretViewContext->x == -1) {
    03247 #if DEBUG_CARETMODE > 1
    03248         kdDebug(6200) << "using hint inline box coordinates" << endl;
    03249 #endif
    03250     RenderObject *r = caretNode->renderer();
    03251     const QFontMetrics &fm = r->style()->fontMetrics();
    03252         int absx, absy;
    03253     r->containingBlock()->absolutePosition(absx, absy,
    03254                         false); // ### what about fixed?
    03255     d->m_caretViewContext->x = absx + hintBox->xPos();
    03256     d->m_caretViewContext->y = absy + hintBox->yPos();
    03257 //              + hintBox->baseline() - fm.ascent();
    03258     d->m_caretViewContext->width = 1;
    03259     // ### firstline not regarded. But I think it can be safely neglected
    03260     // as hint boxes are only used for empty lines.
    03261     d->m_caretViewContext->height = fm.height();
    03262     }/*end if*/
    03263
    03264 #if DEBUG_CARETMODE > 4
    03265 //    kdDebug(6200) << "freqTimerId: "<<d->m_caretViewContext->freqTimerId<<endl;
    03266 #endif
    03267 #if DEBUG_CARETMODE > 0
    03268     kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
    03269         <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
    03270     <<" h="<<d->m_caretViewContext->height<<endl;
    03271 #endif
    03272 }
    03273
    03274 void KHTMLView::caretOn()
    03275 {
    03276     if (d->m_caretViewContext) {
    03277         killTimer(d->m_caretViewContext->freqTimerId);
    03278
    03279     if (hasFocus() || d->m_caretViewContext->displayNonFocused
    03280             == KHTMLPart::CaretBlink) {
    03281             d->m_caretViewContext->freqTimerId = startTimer(500);
    03282     } else {
    03283         d->m_caretViewContext->freqTimerId = -1;
    03284     }/*end if*/
    03285
    03286         d->m_caretViewContext->visible = true;
    03287         if ((d->m_caretViewContext->displayed = (hasFocus()
    03288         || d->m_caretViewContext->displayNonFocused
    03289             != KHTMLPart::CaretInvisible))) {
    03290         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03291                 d->m_caretViewContext->width,
    03292             d->m_caretViewContext->height);
    03293     }/*end if*/
    03294 //        kdDebug(6200) << "caret on" << endl;
    03295     }/*end if*/
    03296 }
    03297
    03298 void KHTMLView::caretOff()
    03299 {
    03300     if (d->m_caretViewContext) {
    03301         killTimer(d->m_caretViewContext->freqTimerId);
    03302     d->m_caretViewContext->freqTimerId = -1;
    03303         d->m_caretViewContext->displayed = false;
    03304         if (d->m_caretViewContext->visible) {
    03305             d->m_caretViewContext->visible = false;
    03306         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03307                 d->m_caretViewContext->width,
    03308                 d->m_caretViewContext->height);
    03309     }/*end if*/
    03310 //        kdDebug(6200) << "caret off" << endl;
    03311     }/*end if*/
    03312 }
    03313
    03314 void KHTMLView::showCaret(bool forceRepaint)
    03315 {
    03316     if (d->m_caretViewContext) {
    03317         d->m_caretViewContext->displayed = true;
    03318         if (d->m_caretViewContext->visible) {
    03319         if (!forceRepaint) {
    03320             updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03321                 d->m_caretViewContext->width,
    03322             d->m_caretViewContext->height);
    03323             } else {
    03324             repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03325                 d->m_caretViewContext->width,
    03326                 d->m_caretViewContext->height);
    03327         }/*end if*/
    03328     }/*end if*/
    03329 //        kdDebug(6200) << "caret shown" << endl;
    03330     }/*end if*/
    03331 }
    03332
    03333 bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
    03334                     NodeImpl *endNode, long endOffset)
    03335 {
    03336   m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
    03337   m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
    03338   m_part->d->m_extendAtEnd = true;
    03339
    03340   bool folded = startNode != endNode || startOffset != endOffset;
    03341
    03342   // Only clear the selection if there has been one.
    03343   if (folded) {
    03344     m_part->xmlDocImpl()->clearSelection();
    03345   }/*end if*/
    03346
    03347   return folded;
    03348 }
    03349
    03350 void KHTMLView::hideCaret()
    03351 {
    03352     if (d->m_caretViewContext) {
    03353         if (d->m_caretViewContext->visible) {
    03354 //            kdDebug(6200) << "redraw caret hidden" << endl;
    03355         d->m_caretViewContext->visible = false;
    03356         // force repaint, otherwise the event won't be handled
    03357         // before the focus leaves the window
    03358         repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03359                 d->m_caretViewContext->width,
    03360                 d->m_caretViewContext->height);
    03361         d->m_caretViewContext->visible = true;
    03362     }/*end if*/
    03363         d->m_caretViewContext->displayed = false;
    03364 //        kdDebug(6200) << "caret hidden" << endl;
    03365     }/*end if*/
    03366 }
    03367
    03368 int KHTMLView::caretDisplayPolicyNonFocused() const
    03369 {
    03370   if (d->m_caretViewContext)
    03371     return d->m_caretViewContext->displayNonFocused;
    03372   else
    03373     return KHTMLPart::CaretInvisible;
    03374 }
    03375
    03376 void KHTMLView::setCaretDisplayPolicyNonFocused(int policy)
    03377 {
    03378   d->caretViewContext();
    03379 //  int old = d->m_caretViewContext->displayNonFocused;
    03380   d->m_caretViewContext->displayNonFocused = (KHTMLPart::CaretDisplayPolicy)policy;
    03381
    03382   // make change immediately take effect if not focused
    03383   if (!hasFocus()) {
    03384     switch (d->m_caretViewContext->displayNonFocused) {
    03385       case KHTMLPart::CaretInvisible:
    03386         hideCaret();
    03387     break;
    03388       case KHTMLPart::CaretBlink:
    03389     if (d->m_caretViewContext->freqTimerId != -1) break;
    03390     d->m_caretViewContext->freqTimerId = startTimer(500);
    03391     // fall through
    03392       case KHTMLPart::CaretVisible:
    03393         d->m_caretViewContext->displayed = true;
    03394         showCaret();
    03395     break;
    03396     }/*end switch*/
    03397   }/*end if*/
    03398 }
    03399
    03400 bool KHTMLView::placeCaret(CaretBox *hintBox)
    03401 {
    03402   CaretViewContext *cv = d->caretViewContext();
    03403   caretOff();
    03404   NodeImpl *caretNode = m_part->d->caretNode().handle();
    03405   // ### why is it sometimes null?
    03406   if (!caretNode || !caretNode->renderer()) return false;
    03407   ensureNodeHasFocus(caretNode);
    03408   if (m_part->isCaretMode() || m_part->isEditable()
    03409      || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
    03410     recalcAndStoreCaretPos(hintBox);
    03411
    03412     cv->origX = cv->x;
    03413
    03414     caretOn();
    03415     return true;
    03416   }/*end if*/
    03417   return false;
    03418 }
    03419
    03420 void KHTMLView::ensureCaretVisible()
    03421 {
    03422   CaretViewContext *cv = d->m_caretViewContext;
    03423   if (!cv) return;
    03424   ensureVisible(cv->x, cv->y, cv->width, cv->height);
    03425   d->scrollBarMoved = false;
    03426 }
    03427
    03428 bool KHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
    03429                 NodeImpl *oldEndSel, long oldEndOfs)
    03430 {
    03431   bool changed = false;
    03432   if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
    03433       && m_part->d->m_startOffset == m_part->d->m_endOffset) {
    03434     changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
    03435     m_part->d->m_extendAtEnd = true;
    03436   } else do {
    03437     changed = m_part->d->m_selectionStart.handle() != oldStartSel
    03438             || m_part->d->m_startOffset != oldStartOfs
    03439         || m_part->d->m_selectionEnd.handle() != oldEndSel
    03440         || m_part->d->m_endOffset != oldEndOfs;
    03441     if (!changed) break;
    03442
    03443     // determine start position -- caret position is always at end.
    03444     NodeImpl *startNode;
    03445     long startOffset;
    03446     if (m_part->d->m_extendAtEnd) {
    03447       startNode = m_part->d->m_selectionStart.handle();
    03448       startOffset = m_part->d->m_startOffset;
    03449     } else {
    03450       startNode = m_part->d->m_selectionEnd.handle();
    03451       startOffset = m_part->d->m_endOffset;
    03452       m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
    03453       m_part->d->m_endOffset = m_part->d->m_startOffset;
    03454       m_part->d->m_extendAtEnd = true;
    03455     }/*end if*/
    03456
    03457     bool swapNeeded = false;
    03458     if (!m_part->d->m_selectionEnd.isNull() && startNode) {
    03459       swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
    03460                 m_part->d->m_selectionEnd.handle(),
    03461             m_part->d->m_endOffset) >= 0;
    03462     }/*end if*/
    03463
    03464     m_part->d->m_selectionStart = startNode;
    03465     m_part->d->m_startOffset = startOffset;
    03466
    03467     if (swapNeeded) {
    03468       m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
    03469         m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
    03470         m_part->d->m_startOffset);
    03471     } else {
    03472       m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
    03473         m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
    03474         m_part->d->m_endOffset);
    03475     }/*end if*/
    03476   } while(false);/*end if*/
    03477   return changed;
    03478 }
    03479
    03480 void KHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
    03481                 NodeImpl *oldEndSel, long oldEndOfs)
    03482 {
    03483   if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
    03484       && m_part->d->m_startOffset == m_part->d->m_endOffset) {
    03485     if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
    03486       m_part->emitSelectionChanged();
    03487     }/*end if*/
    03488     m_part->d->m_extendAtEnd = true;
    03489   } else {
    03490     // check if the extending end has passed the immobile end
    03491     if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
    03492       bool swapNeeded = RangeImpl::compareBoundaryPoints(
    03493                 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
    03494             m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
    03495       if (swapNeeded) {
    03496         DOM::Node tmpNode = m_part->d->m_selectionStart;
    03497         long tmpOffset = m_part->d->m_startOffset;
    03498         m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
    03499         m_part->d->m_startOffset = m_part->d->m_endOffset;
    03500         m_part->d->m_selectionEnd = tmpNode;
    03501         m_part->d->m_endOffset = tmpOffset;
    03502         m_part->d->m_startBeforeEnd = true;
    03503         m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
    03504       }/*end if*/
    03505     }/*end if*/
    03506
    03507     m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
    03508         m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
    03509         m_part->d->m_endOffset);
    03510     m_part->emitSelectionChanged();
    03511   }/*end if*/
    03512 }
    03513
    03514 void KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
    03515 {
    03516   NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
    03517   long oldStartOfs = m_part->d->m_startOffset;
    03518   NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
    03519   long oldEndOfs = m_part->d->m_endOffset;
    03520
    03521   NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
    03522   long oldOffset = m_part->d->caretOffset();
    03523
    03524   bool ctrl = _ke->state() & ControlButton;
    03525
    03526 // FIXME: this is that widely indented because I will write ifs around it.
    03527       switch(_ke->key()) {
    03528         case Key_Space:
    03529           break;
    03530
    03531         case Key_Down:
    03532       moveCaretNextLine(1);
    03533           break;
    03534
    03535         case Key_Up:
    03536       moveCaretPrevLine(1);
    03537           break;
    03538
    03539         case Key_Left:
    03540       moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
    03541           break;
    03542
    03543         case Key_Right:
    03544       moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
    03545           break;
    03546
    03547         case Key_Next:
    03548       moveCaretNextPage();
    03549           break;
    03550
    03551         case Key_Prior:
    03552       moveCaretPrevPage();
    03553           break;
    03554
    03555         case Key_Home:
    03556       if (ctrl)
    03557         moveCaretToDocumentBoundary(false);
    03558       else
    03559         moveCaretToLineBegin();
    03560           break;
    03561
    03562         case Key_End:
    03563       if (ctrl)
    03564         moveCaretToDocumentBoundary(true);
    03565       else
    03566         moveCaretToLineEnd();
    03567           break;
    03568
    03569       }/*end switch*/
    03570
    03571   if ((m_part->d->caretNode().handle() != oldCaretNode
    03572     || m_part->d->caretOffset() != oldOffset)
    03573     // node should never be null, but faulty conditions may cause it to be
    03574     && !m_part->d->caretNode().isNull()) {
    03575
    03576     d->m_caretViewContext->caretMoved = true;
    03577
    03578     if (_ke->state() & ShiftButton) {   // extend selection
    03579       updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
    03580     } else {            // clear any selection
    03581       if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
    03582         m_part->emitSelectionChanged();
    03583     }/*end if*/
    03584
    03585     m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
    03586   }/*end if*/
    03587
    03588   _ke->accept();
    03589 }
    03590
    03591 bool KHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
    03592 {
    03593   if (!node) return false;
    03594   ElementImpl *baseElem = determineBaseElement(node);
    03595   RenderFlow *base = static_cast<RenderFlow *>(baseElem ? baseElem->renderer() : 0);
    03596   if (!node) return false;
    03597
    03598   // need to find out the node's inline box. If there is none, this function
    03599   // will snap to the next node that has one. This is necessary to make the
    03600   // caret visible in any case.
    03601   CaretBoxLineDeleter cblDeleter;
    03602 //   RenderBlock *cb;
    03603   long r_ofs;
    03604   CaretBoxIterator cbit;
    03605   CaretBoxLine *cbl = findCaretBoxLine(node, offset, &cblDeleter, base, r_ofs, cbit);
    03606   if(!cbl) {
    03607       kdWarning() << "KHTMLView::moveCaretTo - findCaretBoxLine() returns NULL" << endl;
    03608       return false;
    03609   }
    03610
    03611 #if DEBUG_CARETMODE > 3
    03612   if (cbl) kdDebug(6200) << cbl->information() << endl;
    03613 #endif
    03614   CaretBox *box = *cbit;
    03615   if (cbit != cbl->end() && box->object() != node->renderer()) {
    03616     if (box->object()->element()) {
    03617       mapRenderPosToDOMPos(box->object(), r_ofs, box->isOutside(),
    03618                 box->isOutsideEnd(), node, offset);
    03619       //if (!outside) offset = node->minOffset();
    03620 #if DEBUG_CARETMODE > 1
    03621       kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
    03622 #endif
    03623     } else {    // box has no associated element -> do not use
    03624       // this case should actually never happen.
    03625       box = 0;
    03626       kdError(6200) << "Box contains no node! Crash imminent" << endl;
    03627     }/*end if*/
    03628   }
    03629
    03630   NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
    03631   long oldStartOfs = m_part->d->m_startOffset;
    03632   NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
    03633   long oldEndOfs = m_part->d->m_endOffset;
    03634
    03635   // test for position change
    03636   bool posChanged = m_part->d->caretNode().handle() != node
    03637         || m_part->d->caretOffset() != offset;
    03638   bool selChanged = false;
    03639
    03640   m_part->d->caretNode() = node;
    03641   m_part->d->caretOffset() = offset;
    03642   if (clearSel || !oldStartSel || !oldEndSel) {
    03643     selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
    03644   } else {
    03645     //kdDebug(6200) << "moveToCaret: extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
    03646     //kdDebug(6200) << "selection: start(" << m_part->d->m_selectionStart.handle() << "," << m_part->d->m_startOffset << "), end(" << m_part->d->m_selectionEnd.handle() << "," << m_part->d->m_endOffset << "), caret(" << m_part->d->caretNode().handle() << "," << m_part->d->caretOffset() << ")" << endl;
    03647     selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
    03648     //kdDebug(6200) << "after extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
    03649     //kdDebug(6200) << "selection: start(" << m_part->d->m_selectionStart.handle() << "," << m_part->d->m_startOffset << "), end(" << m_part->d->m_selectionEnd.handle() << "," << m_part->d->m_endOffset << "), caret(" << m_part->d->caretNode().handle() << "," << m_part->d->caretOffset() << ")" << endl;
    03650   }/*end if*/
    03651
    03652   d->caretViewContext()->caretMoved = true;
    03653
    03654   bool visible_caret = placeCaret(box);
    03655
    03656   // FIXME: if the old position was !visible_caret, and the new position is
    03657   // also, then two caretPositionChanged signals with a null Node are
    03658   // emitted in series.
    03659   if (posChanged) {
    03660     m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
    03661   }/*end if*/
    03662
    03663   return selChanged;
    03664 }
    03665
    03666 void KHTMLView::moveCaretByLine(bool next, int count)
    03667 {
    03668   Node &caretNodeRef = m_part->d->caretNode();
    03669   if (caretNodeRef.isNull()) return;
    03670
    03671   NodeImpl *caretNode = caretNodeRef.handle();
    03672 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
    03673   long offset = m_part->d->caretOffset();
    03674
    03675   CaretViewContext *cv = d->caretViewContext();
    03676
    03677   ElementImpl *baseElem = determineBaseElement(caretNode);
    03678   LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
    03679
    03680   ErgonomicEditableLineIterator it(ld.current(), cv->origX);
    03681
    03682   // move count lines vertically
    03683   while (count > 0 && it != ld.end() && it != ld.preBegin()) {
    03684     count--;
    03685     if (next) ++it; else --it;
    03686   }/*wend*/
    03687
    03688   // Nothing? Then leave everything as is.
    03689   if (it == ld.end() || it == ld.preBegin()) return;
    03690
    03691   int x, absx, absy;
    03692   CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
    03693
    03694   placeCaretOnLine(caretBox, x, absx, absy);
    03695 }
    03696
    03697 void KHTMLView::placeCaretOnLine(CaretBox *caretBox, int x, int absx, int absy)
    03698 {
    03699   // paranoia sanity check
    03700   if (!caretBox) return;
    03701
    03702   RenderObject *caretRender = caretBox->object();
    03703
    03704 #if DEBUG_CARETMODE > 0
    03705   kdDebug(6200) << "got valid caretBox " << caretBox << endl;
    03706   kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
    03707         << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
    03708   InlineTextBox *tb = static_cast<InlineTextBox *>(caretBox->inlineBox());
    03709   if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << QString(static_cast<RenderText *>(tb->object())->str->s + tb->m_start, tb->m_len) << "\"" << endl;}
    03710 #endif
    03711   // inquire height of caret
    03712   int caretHeight = caretBox->height();
    03713   bool isText = caretBox->isInlineTextBox();
    03714   int yOfs = 0;     // y-offset for text nodes
    03715   if (isText) {
    03716     // text boxes need extrawurst
    03717     RenderText *t = static_cast<RenderText *>(caretRender);
    03718     const QFontMetrics &fm = t->metrics(caretBox->inlineBox()->m_firstLine);
    03719     caretHeight = fm.height();
    03720     yOfs = caretBox->inlineBox()->baseline() - fm.ascent();
    03721   }/*end if*/
    03722
    03723   caretOff();
    03724
    03725   // set new caret node
    03726   NodeImpl *caretNode;
    03727   long &offset = m_part->d->caretOffset();
    03728   mapRenderPosToDOMPos(caretRender, offset, caretBox->isOutside(),
    03729         caretBox->isOutsideEnd(), caretNode, offset);
    03730
    03731   // set all variables not needing special treatment
    03732   d->m_caretViewContext->y = caretBox->yPos() + yOfs;
    03733   d->m_caretViewContext->height = caretHeight;
    03734   d->m_caretViewContext->width = 1; // FIXME: regard override
    03735
    03736   int xPos = caretBox->xPos();
    03737   int caretBoxWidth = caretBox->width();
    03738   d->m_caretViewContext->x = xPos;
    03739
    03740   if (!caretBox->isOutside()) {
    03741     // before or at beginning of inline box -> place at beginning
    03742     long r_ofs = 0;
    03743     if (x <= xPos) {
    03744       r_ofs = caretBox->minOffset();
    03745   // somewhere within this block
    03746     } else if (x > xPos && x <= xPos + caretBoxWidth) {
    03747       if (isText) { // find out where exactly
    03748         r_ofs = static_cast<InlineTextBox *>(caretBox->inlineBox())
    03749             ->offsetForPoint(x, d->m_caretViewContext->x);
    03750 #if DEBUG_CARETMODE > 2
    03751         kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
    03752 #endif
    03753 #if 0
    03754       } else {  // snap to nearest end
    03755         if (xPos + caretBoxWidth - x < x - xPos) {
    03756           d->m_caretViewContext->x = xPos + caretBoxWidth;
    03757           r_ofs = caretNode ? caretNode->maxOffset() : 1;
    03758         } else {
    03759           d->m_caretViewContext->x = xPos;
    03760           r_ofs = caretNode ? caretNode->minOffset() : 0;
    03761         }/*end if*/
    03762 #endif
    03763       }/*end if*/
    03764     } else {        // after the inline box -> place at end
    03765       d->m_caretViewContext->x = xPos + caretBoxWidth;
    03766       r_ofs = caretBox->maxOffset();
    03767     }/*end if*/
    03768     offset = r_ofs;
    03769   }/*end if*/
    03770 #if DEBUG_CARETMODE > 0
    03771       kdDebug(6200) << "new offset: " << offset << endl;
    03772 #endif
    03773
    03774   m_part->d->caretNode() = caretNode;
    03775   m_part->d->caretOffset() = offset;
    03776
    03777   d->m_caretViewContext->x += absx;
    03778   d->m_caretViewContext->y += absy;
    03779
    03780 #if DEBUG_CARETMODE > 1
    03781     kdDebug(6200) << "new caret position: x " << d->m_caretViewContext->x << " y " << d->m_caretViewContext->y << " w " << d->m_caretViewContext->width << " h " << d->m_caretViewContext->height << " absx " << absx << " absy " << absy << endl;
    03782 #endif
    03783
    03784   ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03785     d->m_caretViewContext->width, d->m_caretViewContext->height);
    03786   d->scrollBarMoved = false;
    03787
    03788   ensureNodeHasFocus(caretNode);
    03789   caretOn();
    03790 }
    03791
    03792 void KHTMLView::moveCaretToLineBoundary(bool end)
    03793 {
    03794   Node &caretNodeRef = m_part->d->caretNode();
    03795   if (caretNodeRef.isNull()) return;
    03796
    03797   NodeImpl *caretNode = caretNodeRef.handle();
    03798 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
    03799   long offset = m_part->d->caretOffset();
    03800
    03801   ElementImpl *baseElem = determineBaseElement(caretNode);
    03802   LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
    03803
    03804   EditableLineIterator it = ld.current();
    03805   if (it == ld.end()) return;   // should not happen, but who knows
    03806
    03807   EditableCaretBoxIterator fbit(it, end);
    03808   Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
    03809   CaretBox *b = *fbit;
    03810
    03811   RenderObject *cb = b->containingBlock();
    03812   int absx, absy;
    03813
    03814   if (cb) cb->absolutePosition(absx,absy);
    03815   else absx = absy = 0;
    03816
    03817   int x = b->xPos() + (end && !b->isOutside() ? b->width() : 0);
    03818   d->m_caretViewContext->origX = absx + x;
    03819   placeCaretOnLine(b, x, absx, absy);
    03820 }
    03821
    03822 void KHTMLView::moveCaretToDocumentBoundary(bool end)
    03823 {
    03824   Node &caretNodeRef = m_part->d->caretNode();
    03825   if (caretNodeRef.isNull()) return;
    03826
    03827   NodeImpl *caretNode = caretNodeRef.handle();
    03828 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
    03829   long offset = m_part->d->caretOffset();
    03830
    03831   ElementImpl *baseElem = determineBaseElement(caretNode);
    03832   LinearDocument ld(m_part, caretNode, offset, IndicatedFlows, baseElem);
    03833
    03834   EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
    03835   if (it == ld.end() || it == ld.preBegin()) return;    // should not happen, but who knows
    03836
    03837   EditableCaretBoxIterator fbit = it;
    03838   Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
    03839   CaretBox *b = *fbit;
    03840
    03841   RenderObject *cb = (*it)->containingBlock();
    03842   int absx, absy;
    03843
    03844   if (cb) cb->absolutePosition(absx, absy);
    03845   else absx = absy = 0;
    03846
    03847   int x = b->xPos()/* + (end ? b->width() : 0) reactivate for rtl*/;
    03848   d->m_caretViewContext->origX = absx + x;
    03849   placeCaretOnLine(b, x, absx, absy);
    03850 }
    03851
    03852 void KHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
    03853 {
    03854   if (!m_part) return;
    03855   Node &caretNodeRef = m_part->d->caretNode();
    03856   if (caretNodeRef.isNull()) return;
    03857
    03858   NodeImpl *caretNode = caretNodeRef.handle();
    03859 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
    03860   long &offset = m_part->d->caretOffset();
    03861
    03862   ElementImpl *baseElem = determineBaseElement(caretNode);
    03863   CaretAdvancePolicy advpol = cmv != CaretByWord ? IndicatedFlows : LeafsOnly;
    03864   LinearDocument ld(m_part, caretNode, offset, advpol, baseElem);
    03865
    03866   EditableCharacterIterator it(&ld);
    03867   while (!it.isEnd() && count > 0) {
    03868     count--;
    03869     if (cmv == CaretByCharacter) {
    03870       if (next) ++it;
    03871       else --it;
    03872     } else if (cmv == CaretByWord) {
    03873       if (next) moveItToNextWord(it);
    03874       else moveItToPrevWord(it);
    03875     }/*end if*/
    03876 //kdDebug(6200) << "movecaret" << endl;
    03877   }/*wend*/
    03878   CaretBox *hintBox = 0;    // make gcc uninit warning disappear
    03879   if (!it.isEnd()) {
    03880     NodeImpl *node = caretNodeRef.handle();
    03881     hintBox = it.caretBox();
    03882 //kdDebug(6200) << "hintBox = " << hintBox << endl;
    03883 //kdDebug(6200) << " outside " << hintBox->isOutside() << " outsideEnd " << hintBox->isOutsideEnd() << " r " << it.renderer() << " ofs " << it.offset() << " cb " << hintBox->containingBlock() << endl;
    03884     mapRenderPosToDOMPos(it.renderer(), it.offset(), hintBox->isOutside(),
    03885             hintBox->isOutsideEnd(), node, offset);
    03886 //kdDebug(6200) << "mapRTD" << endl;
    03887     caretNodeRef = node;
    03888 #if DEBUG_CARETMODE > 2
    03889     kdDebug(6200) << "set by valid node " << node << " " << (node?node->nodeName().string():QString::null) << " offset: " << offset << endl;
    03890 #endif
    03891   } else {
    03892     offset = next ? caretNode->maxOffset() : caretNode->minOffset();
    03893 #if DEBUG_CARETMODE > 0
    03894     kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
    03895 #endif
    03896   }/*end if*/
    03897   placeCaretOnChar(hintBox);
    03898 }
    03899
    03900 void KHTMLView::placeCaretOnChar(CaretBox *hintBox)
    03901 {
    03902   caretOff();
    03903   recalcAndStoreCaretPos(hintBox);
    03904   ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
    03905     d->m_caretViewContext->width, d->m_caretViewContext->height);
    03906   d->m_caretViewContext->origX = d->m_caretViewContext->x;
    03907   d->scrollBarMoved = false;
    03908 #if DEBUG_CARETMODE > 3
    03909   //if (caretNode->isTextNode())  kdDebug(6200) << "text[0] = " << (int)*((TextImpl *)caretNode)->data().unicode() << " text :\"" << ((TextImpl *)caretNode)->data().string() << "\"" << endl;
    03910 #endif
    03911   ensureNodeHasFocus(m_part->d->caretNode().handle());
    03912   caretOn();
    03913 }
    03914
    03915 void KHTMLView::moveCaretByPage(bool next)
    03916 {
    03917   Node &caretNodeRef = m_part->d->caretNode();
    03918
    03919   NodeImpl *caretNode = caretNodeRef.handle();
    03920 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
    03921   long offset = m_part->d->caretOffset();
    03922
    03923   int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
    03924   // Minimum distance the caret must be moved
    03925   int mindist = clipper()->height() - offs;
    03926
    03927   CaretViewContext *cv = d->caretViewContext();
    03928 //  int y = cv->y;      // we always measure the top border
    03929
    03930   ElementImpl *baseElem = determineBaseElement(caretNode);
    03931   LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
    03932
    03933   ErgonomicEditableLineIterator it(ld.current(), cv->origX);
    03934
    03935   moveIteratorByPage(ld, it, mindist, next);
    03936
    03937   int x, absx, absy;
    03938   CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
    03939
    03940   placeCaretOnLine(caretBox, x, absx, absy);
    03941 }
    03942
    03943 void KHTMLView::moveCaretPrevWord()
    03944 {
    03945   moveCaretBy(false, CaretByWord, 1);
    03946 }
    03947
    03948 void KHTMLView::moveCaretNextWord()
    03949 {
    03950   moveCaretBy(true, CaretByWord, 1);
    03951 }
    03952
    03953 void KHTMLView::moveCaretPrevLine(int n)
    03954 {
    03955   moveCaretByLine(false, n);
    03956 }
    03957
    03958 void KHTMLView::moveCaretNextLine(int n)
    03959 {
    03960   moveCaretByLine(true, n);
    03961 }
    03962
    03963 void KHTMLView::moveCaretPrevPage()
    03964 {
    03965   moveCaretByPage(false);
    03966 }
    03967
    03968 void KHTMLView::moveCaretNextPage()
    03969 {
    03970   moveCaretByPage(true);
    03971 }
    03972
    03973 void KHTMLView::moveCaretToLineBegin()
    03974 {
    03975   moveCaretToLineBoundary(false);
    03976 }
    03977
    03978 void KHTMLView::moveCaretToLineEnd()
    03979 {
    03980   moveCaretToLineBoundary(true);
    03981 }
    03982
    03983 #endif // KHTML_NO_CARET
    03984
    03985 #undef DEBUG_CARETMODE

This file is part of the documentation for khtml Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:33:16 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003