• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • khtml
 

khtml

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

khtml

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

khtml

Skip menu "khtml"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for khtml by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |