khtml Library API Documentation

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 Dirk Mueller <mueller@kde.org>
00007  *                     2003 Leo Savernik <l.savernik@aon.at>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Library General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Library General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Library General Public License
00020  * along with this library; see the file COPYING.LIB.  If not, write to
00021  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00022  * Boston, MA 02111-1307, USA.
00023  */
00024 
00025 
00026 #include "khtmlview.moc"
00027 
00028 #include "khtmlview.h"
00029 
00030 #include "khtml_part.h"
00031 #include "khtml_events.h"
00032 
00033 #include "html/html_documentimpl.h"
00034 #include "html/html_inlineimpl.h"
00035 #include "rendering/render_arena.h"
00036 #include "rendering/render_canvas.h"
00037 #include "rendering/render_frames.h"
00038 #include "rendering/render_replaced.h"
00039 #include "rendering/render_layer.h"
00040 #include "rendering/render_line.h"
00041 #include "rendering/render_table.h"
00042 // removeme
00043 #define protected public
00044 #include "rendering/render_text.h"
00045 #undef protected
00046 #include "xml/dom2_eventsimpl.h"
00047 #include "css/cssstyleselector.h"
00048 #include "misc/htmlhashes.h"
00049 #include "misc/helper.h"
00050 #include "khtml_settings.h"
00051 #include "khtml_printsettings.h"
00052 
00053 #include "khtmlpart_p.h"
00054 
00055 #ifndef KHTML_NO_CARET
00056 #include "khtml_caret_p.h"
00057 #include "xml/dom2_rangeimpl.h"
00058 #endif
00059 
00060 #include <kcursor.h>
00061 #include <ksimpleconfig.h>
00062 #include <kstringhandler.h>
00063 #include <kstandarddirs.h>
00064 #include <kprinter.h>
00065 #include <klocale.h>
00066 
00067 #include <qtooltip.h>
00068 #include <qpainter.h>
00069 #include <qpaintdevicemetrics.h>
00070 #include <qstylesheet.h>
00071 #include <kapplication.h>
00072 
00073 #include <kimageio.h>
00074 #include <kdebug.h>
00075 #include <kurldrag.h>
00076 #include <qobjectlist.h>
00077 #include <qtimer.h>
00078 #include <kdialogbase.h>
00079 #include <qptrdict.h>
00080 
00081 //#define DEBUG_NO_PAINT_BUFFER
00082 
00083 #define PAINT_BUFFER_HEIGHT 128
00084 
00085 using namespace DOM;
00086 using namespace khtml;
00087 class KHTMLToolTip;
00088 
00089 #ifndef QT_NO_TOOLTIP
00090 
00091 class KHTMLToolTip : public QToolTip
00092 {
00093 public:
00094     KHTMLToolTip(KHTMLView *view,  KHTMLViewPrivate* vp) : QToolTip(view->viewport())
00095     {
00096         m_view = view;
00097         m_viewprivate = vp;
00098     };
00099 
00100 protected:
00101     virtual void maybeTip(const QPoint &);
00102 
00103 private:
00104     KHTMLView *m_view;
00105     KHTMLViewPrivate* m_viewprivate;
00106 };
00107 
00108 #endif
00109 
00110 class KHTMLViewPrivate {
00111     friend class KHTMLToolTip;
00112 public:
00113     KHTMLViewPrivate()
00114         : underMouse( 0 )
00115     {
00116 #ifndef KHTML_NO_CARET
00117     m_caretViewContext = 0;
00118     m_editorContext = 0;
00119 #endif // KHTML_NO_CARET
00120         postponed_autorepeat = NULL;
00121         reset();
00122         tp=0;
00123         paintBuffer=0;
00124         vertPaintBuffer=0;
00125         formCompletions=0;
00126         prevScrollbarVisible = true;
00127     tooltip = 0;
00128         possibleTripleClick = false;
00129     }
00130     ~KHTMLViewPrivate()
00131     {
00132         delete formCompletions;
00133         delete tp; tp = 0;
00134         delete paintBuffer; paintBuffer =0;
00135         delete vertPaintBuffer;
00136         delete postponed_autorepeat;
00137         if (underMouse)
00138         underMouse->deref();
00139     delete tooltip;
00140 #ifndef KHTML_NO_CARET
00141     delete m_caretViewContext;
00142     delete m_editorContext;
00143 #endif // KHTML_NO_CARET
00144     }
00145     void reset()
00146     {
00147         if (underMouse)
00148         underMouse->deref();
00149     underMouse = 0;
00150         linkPressed = false;
00151         useSlowRepaints = false;
00152         originalNode = 0;
00153     borderTouched = false;
00154 #ifndef KHTML_NO_SCROLLBARS
00155         vmode = QScrollView::Auto;
00156         hmode = QScrollView::Auto;
00157 #else
00158         vmode = QScrollView::AlwaysOff;
00159         hmode = QScrollView::AlwaysOff;
00160 #endif
00161         scrollBarMoved = false;
00162         ignoreWheelEvents = false;
00163     borderX = 30;
00164     borderY = 30;
00165     clickX = -1;
00166     clickY = -1;
00167         prevMouseX = -1;
00168         prevMouseY = -1;
00169     clickCount = 0;
00170     isDoubleClick = false;
00171     scrollingSelf = false;
00172         delete postponed_autorepeat;
00173         postponed_autorepeat = NULL;
00174     layoutTimerId = 0;
00175         repaintTimerId = 0;
00176         scrollTimerId = 0;
00177         complete = false;
00178         firstRelayout = true;
00179         dirtyLayout = false;
00180         layoutSchedulingEnabled = true;
00181         updateRect = QRect();
00182         m_dialogsAllowed = true;
00183 #ifndef KHTML_NO_CARET
00184         if (m_caretViewContext) {
00185           m_caretViewContext->caretMoved = false;
00186       m_caretViewContext->keyReleasePending = false;
00187         }/*end if*/
00188 #endif // KHTML_NO_CARET
00189     }
00190     void newScrollTimer(QWidget *view, int tid)
00191     {
00192         //kdDebug(6000) << "newScrollTimer timer " << tid << endl;
00193         view->killTimer(scrollTimerId);
00194         scrollTimerId = tid;
00195     }
00196     enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
00197 
00198     void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
00199     {
00200         static const struct { int msec, pixels; } timings [] = {
00201             {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
00202             {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
00203         };
00204         if (!scrollTimerId ||
00205             (scrollDirection != direction &&
00206              scrollDirection != oppositedir)) {
00207             scrollTiming = 6;
00208             scrollBy = timings[scrollTiming].pixels;
00209             scrollDirection = direction;
00210             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00211         } else if (scrollDirection == direction &&
00212                    timings[scrollTiming+1].msec) {
00213             scrollBy = timings[++scrollTiming].pixels;
00214             newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00215         } else if (scrollDirection == oppositedir) {
00216             if (scrollTiming) {
00217                 scrollBy = timings[--scrollTiming].pixels;
00218                 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00219             }
00220         }
00221     }
00222 
00223 #ifndef KHTML_NO_CARET
00224 
00227     CaretViewContext *caretViewContext() {
00228       if (!m_caretViewContext) m_caretViewContext = new CaretViewContext();
00229       return m_caretViewContext;
00230     }
00234     EditorContext *editorContext() {
00235       if (!m_editorContext) m_editorContext = new EditorContext();
00236       return m_editorContext;
00237     }
00238 #endif // KHTML_NO_CARET
00239 
00240     QPainter *tp;
00241     QPixmap  *paintBuffer;
00242     QPixmap  *vertPaintBuffer;
00243     NodeImpl *underMouse;
00244 
00245     // the node that was selected when enter was pressed
00246     NodeImpl *originalNode;
00247 
00248     bool borderTouched:1;
00249     bool borderStart:1;
00250     bool scrollBarMoved:1;
00251 
00252     QScrollView::ScrollBarMode vmode;
00253     QScrollView::ScrollBarMode hmode;
00254     bool prevScrollbarVisible;
00255     bool linkPressed;
00256     bool useSlowRepaints;
00257     bool ignoreWheelEvents;
00258 
00259     int borderX, borderY;
00260     KSimpleConfig *formCompletions;
00261 
00262     int clickX, clickY, clickCount;
00263     bool isDoubleClick;
00264 
00265     int prevMouseX, prevMouseY;
00266     bool scrollingSelf;
00267     int layoutTimerId;
00268     QKeyEvent* postponed_autorepeat;
00269 
00270     int repaintTimerId;
00271     int scrollTimerId;
00272     int scrollTiming;
00273     int scrollBy;
00274     ScrollDirection scrollDirection;
00275     bool complete;
00276     bool firstRelayout;
00277     bool layoutSchedulingEnabled;
00278     bool possibleTripleClick;
00279     bool dirtyLayout;
00280     bool m_dialogsAllowed;
00281     QRect updateRect;
00282     KHTMLToolTip *tooltip;
00283     QPtrDict<QWidget> visibleWidgets;
00284 #ifndef KHTML_NO_CARET
00285     CaretViewContext *m_caretViewContext;
00286     EditorContext *m_editorContext;
00287 #endif // KHTML_NO_CARET
00288 };
00289 
00290 #ifndef QT_NO_TOOLTIP
00291 
00292 void KHTMLToolTip::maybeTip(const QPoint& /*p*/)
00293 {
00294     DOM::NodeImpl *node = m_viewprivate->underMouse;
00295     QRect region;
00296     while ( node ) {
00297         if ( node->isElementNode() ) {
00298             QString s = static_cast<DOM::ElementImpl*>( node )->getAttribute( ATTR_TITLE ).string();
00299             region |= QRect( m_view->contentsToViewport( node->getRect().topLeft() ), node->getRect().size() );
00300             if ( !s.isEmpty() ) {
00301                 tip( region, QStyleSheet::convertFromPlainText( s, QStyleSheetItem::WhiteSpaceNormal ) );
00302                 break;
00303             }
00304         }
00305         node = node->parentNode();
00306     }
00307 }
00308 #endif
00309 
00310 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name)
00311     : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase )
00312 {
00313     m_medium = "screen";
00314 
00315     m_part = part;
00316     d = new KHTMLViewPrivate;
00317     QScrollView::setVScrollBarMode(d->vmode);
00318     QScrollView::setHScrollBarMode(d->hmode);
00319     connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged()));
00320     connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
00321 
00322     // initialize QScrollView
00323     enableClipper(true);
00324     // hack to get unclipped painting on the viewport.
00325     static_cast<KHTMLView *>(static_cast<QWidget *>(viewport()))->setWFlags(WPaintUnclipped);
00326 
00327     setResizePolicy(Manual);
00328     viewport()->setMouseTracking(true);
00329     viewport()->setBackgroundMode(NoBackground);
00330 
00331     KImageIO::registerFormats();
00332 
00333 #ifndef QT_NO_TOOLTIP
00334     d->tooltip = new KHTMLToolTip( this, d );
00335 #endif
00336 
00337     init();
00338 
00339     viewport()->show();
00340 }
00341 
00342 KHTMLView::~KHTMLView()
00343 {
00344     closeChildDialogs();
00345     if (m_part)
00346     {
00347         //WABA: Is this Ok? Do I need to deref it as well?
00348         //Does this need to be done somewhere else?
00349         DOM::DocumentImpl *doc = m_part->xmlDocImpl();
00350         if (doc)
00351             doc->detach();
00352     }
00353     delete d; d = 0;
00354 }
00355 
00356 void KHTMLView::init()
00357 {
00358     if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
00359     if(!d->vertPaintBuffer)
00360         d->vertPaintBuffer = new QPixmap(10, PAINT_BUFFER_HEIGHT);
00361     if(!d->tp) d->tp = new QPainter();
00362 
00363     setFocusPolicy(QWidget::StrongFocus);
00364     viewport()->setFocusProxy(this);
00365 
00366     _marginWidth = -1; // undefined
00367     _marginHeight = -1;
00368     _width = 0;
00369     _height = 0;
00370 
00371     installEventFilter(this);
00372 
00373     setAcceptDrops(true);
00374     QSize s = viewportSize(4095, 4095);
00375     resizeContents(s.width(), s.height());
00376 }
00377 
00378 void KHTMLView::clear()
00379 {
00380     // work around QScrollview's unbelievable bugginess
00381     setStaticBackground(true);
00382 #ifndef KHTML_NO_CARET
00383     if (!m_part->isCaretMode() && !m_part->isEditable()) caretOff();
00384 #endif
00385 
00386     d->reset();
00387     killTimers();
00388     emit cleared();
00389 
00390     QScrollView::setHScrollBarMode(d->hmode);
00391     QScrollView::setVScrollBarMode(d->vmode);
00392 }
00393 
00394 void KHTMLView::hideEvent(QHideEvent* e)
00395 {
00396     QScrollView::hideEvent(e);
00397 }
00398 
00399 void KHTMLView::showEvent(QShowEvent* e)
00400 {
00401     QScrollView::showEvent(e);
00402 }
00403 
00404 void KHTMLView::resizeEvent (QResizeEvent* e)
00405 {
00406     QScrollView::resizeEvent(e);
00407 
00408     if ( m_part && m_part->xmlDocImpl() )
00409         m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
00410 }
00411 
00412 void KHTMLView::viewportResizeEvent (QResizeEvent* e)
00413 {
00414     QScrollView::viewportResizeEvent(e);
00415 
00416     //int w = visibleWidth();
00417     //int h = visibleHeight();
00418 
00419     if (d->layoutSchedulingEnabled)
00420         layout();
00421 #ifndef KHTML_NO_CARET
00422     else {
00423         hideCaret();
00424         recalcAndStoreCaretPos();
00425     showCaret();
00426     }/*end if*/
00427 #endif
00428 
00429     KApplication::sendPostedEvents(viewport(), QEvent::Paint);
00430 }
00431 
00432 // this is to get rid of a compiler virtual overload mismatch warning. do not remove
00433 void KHTMLView::drawContents( QPainter*)
00434 {
00435 }
00436 
00437 void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
00438 {
00439 //     kdDebug( 6000 ) << "drawContents this="<< this <<" x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl;
00440     if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
00441         p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00442         return;
00443     }
00444 //    QRect dbg_paint_rect(ex,ey,ew,eh);
00445 
00446     QPoint pt = contentsToViewport(QPoint(ex, ey));
00447     QRegion cr = QRect(pt.x(), pt.y(), ew, eh);
00448 //     kdDebug(6000) << "clip rect: " << QRect(pt.x(), pt.y(), ew, eh) << endl;
00449     for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
00450     QWidget *w = it.current();
00451     RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
00452     QScrollView *sv = ::qt_cast<QScrollView *>(w);
00453     if (sv || !rw->isFormElement()) {
00454 //      kdDebug(6000) << "    removing scrollview " << sv;
00455         int x, y;
00456         rw->absolutePosition(x, y);
00457         contentsToViewport(x, y, x, y);
00458         cr -= QRect(x, y, rw->width(), rw->height());
00459     }
00460     }
00461     if (cr.isEmpty())
00462     return;
00463 
00464 #ifndef DEBUG_NO_PAINT_BUFFER
00465     p->setClipRegion(cr);
00466 
00467     if (eh > PAINT_BUFFER_HEIGHT && ew <= 10) {
00468         if ( d->vertPaintBuffer->height() < visibleHeight() )
00469             d->vertPaintBuffer->resize(10, visibleHeight());
00470         d->tp->begin(d->vertPaintBuffer);
00471         d->tp->translate(-ex, -ey);
00472         d->tp->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00473         m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey, ew, eh));
00474         d->tp->end();
00475     p->drawPixmap(ex, ey, *d->vertPaintBuffer, 0, 0, ew, eh);
00476     }
00477     else {
00478         if ( d->paintBuffer->width() < visibleWidth() )
00479             d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
00480 
00481         int py=0;
00482         while (py < eh) {
00483             int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
00484             d->tp->begin(d->paintBuffer);
00485             d->tp->translate(-ex, -ey-py);
00486             d->tp->fillRect(ex, ey+py, ew, ph, palette().active().brush(QColorGroup::Base));
00487             m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey+py, ew, ph));
00488 #ifdef BOX_DEBUG
00489             if (m_part->xmlDocImpl()->focusNode())
00490             {
00491                 d->tp->setBrush(Qt::NoBrush);
00492                 d->tp->drawRect(m_part->xmlDocImpl()->focusNode()->getRect());
00493             }
00494 #endif
00495             d->tp->end();
00496 
00497         p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
00498             py += PAINT_BUFFER_HEIGHT;
00499         }
00500     }
00501 #else // !DEBUG_NO_PAINT_BUFFER
00502 static int cnt=0;
00503     ex = contentsX(); ey = contentsY();
00504     ew = visibleWidth(); eh = visibleHeight();
00505     kdDebug() << "[" << ++cnt << "]" << " clip region: " << QRect(ex,ey,ew,eh) << endl;
00506 //  p->setClipRegion(QRect(0,0,ew,eh));
00507 //        p->translate(-ex, -ey);
00508         p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00509         m_part->xmlDocImpl()->renderer()->layer()->paint(p, ex, ey, ew, eh, 0, 0);
00510 #endif // DEBUG_NO_PAINT_BUFFER
00511 
00512 #ifndef KHTML_NO_CARET
00513     if (d->m_caretViewContext && d->m_caretViewContext->visible) {
00514         QRect pos(d->m_caretViewContext->x, d->m_caretViewContext->y,
00515         d->m_caretViewContext->width, d->m_caretViewContext->height);
00516         if (pos.intersects(QRect(ex, ey, ew, eh))) {
00517             p->setRasterOp(XorROP);
00518         p->setPen(white);
00519         if (pos.width() == 1)
00520               p->drawLine(pos.topLeft(), pos.bottomRight());
00521         else {
00522           p->fillRect(pos, white);
00523         }/*end if*/
00524     }/*end if*/
00525     }/*end if*/
00526 #endif // KHTML_NO_CARET
00527 
00528 //    p->setPen(QPen(magenta,0,DashDotDotLine));
00529 //    p->drawRect(dbg_paint_rect);
00530 
00531     khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
00532     QApplication::sendEvent( m_part, &event );
00533 
00534 }
00535 
00536 void KHTMLView::setMarginWidth(int w)
00537 {
00538     // make it update the rendering area when set
00539     _marginWidth = w;
00540 }
00541 
00542 void KHTMLView::setMarginHeight(int h)
00543 {
00544     // make it update the rendering area when set
00545     _marginHeight = h;
00546 }
00547 
00548 void KHTMLView::layout()
00549 {
00550     d->layoutSchedulingEnabled=false;
00551 
00552     if( m_part && m_part->xmlDocImpl() ) {
00553         DOM::DocumentImpl *document = m_part->xmlDocImpl();
00554 
00555         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
00556         if ( !root ) return;
00557 
00558          if (document->isHTMLDocument()) {
00559              NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
00560              if(body && body->renderer() && body->id() == ID_FRAMESET) {
00561                  QScrollView::setVScrollBarMode(AlwaysOff);
00562                  QScrollView::setHScrollBarMode(AlwaysOff);
00563                  body->renderer()->setLayouted(false);
00564 //                  if (d->tooltip) {
00565 //                      delete d->tooltip;
00566 //                      d->tooltip = 0;
00567 //                  }
00568              }
00569              else if (!d->tooltip)
00570                  d->tooltip = new KHTMLToolTip( this, d );
00571          }
00572 
00573         _height = visibleHeight();
00574         _width = visibleWidth();
00575         //QTime qt;
00576         //qt.start();
00577         root->setMinMaxKnown(false);
00578         root->setLayouted(false);
00579         root->layout();
00580 #ifndef KHTML_NO_CARET
00581         hideCaret();
00582         if ((m_part->isCaretMode() || m_part->isEditable())
00583             && !d->complete && d->m_caretViewContext
00584                 && !d->m_caretViewContext->caretMoved) {
00585             initCaret();
00586         } else {
00587         recalcAndStoreCaretPos();
00588         showCaret();
00589         }/*end if*/
00590 #endif
00591     root->repaint();
00592         //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
00593     }
00594     else
00595        _width = visibleWidth();
00596 
00597     killTimer(d->layoutTimerId);
00598     d->layoutTimerId = 0;
00599     d->layoutSchedulingEnabled=true;
00600 }
00601 
00602 void KHTMLView::closeChildDialogs()
00603 {
00604     QObjectList *dlgs = queryList("QDialog");
00605     for (QObject *dlg = dlgs->first(); dlg; dlg = dlgs->next())
00606     {
00607         KDialogBase* dlgbase = dynamic_cast<KDialogBase *>( dlg );
00608         if ( dlgbase ) {
00609             kdDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase << endl;
00610             // close() ends up calling QButton::animateClick, which isn't immediate
00611             // we need something the exits the event loop immediately (#49068)
00612             dlgbase->cancel();
00613         }
00614         else
00615         {
00616             kdWarning() << "closeChildDialogs: not a KDialogBase! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg) << endl;
00617             static_cast<QWidget*>(dlg)->hide();
00618         }
00619     }
00620     delete dlgs;
00621     d->m_dialogsAllowed = false;
00622 }
00623 
00624 bool KHTMLView::dialogsAllowed() {
00625     bool allowed = d->m_dialogsAllowed;
00626     KHTMLPart* p = m_part->parentPart();
00627     if (p && p->view())
00628         allowed &= p->view()->dialogsAllowed();
00629     return allowed;
00630 }
00631 
00632 void KHTMLView::closeEvent( QCloseEvent* ev )
00633 {
00634     closeChildDialogs();
00635     QScrollView::closeEvent( ev );
00636 }
00637 
00638 //
00639 // Event Handling
00640 //
00642 
00643 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
00644 {
00645     if(!m_part->xmlDocImpl()) return;
00646     if (d->possibleTripleClick)
00647     {
00648         viewportMouseDoubleClickEvent( _mouse ); // it handles triple clicks too
00649         return;
00650     }
00651 
00652     int xm, ym;
00653     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00654 
00655     //kdDebug( 6000 ) << "\nmousePressEvent: x=" << xm << ", y=" << ym << endl;
00656 
00657     d->isDoubleClick = false;
00658 
00659     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
00660     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00661 
00662     if (d->clickCount > 0 &&
00663         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00664     d->clickCount++;
00665     else {
00666     d->clickCount = 1;
00667     d->clickX = xm;
00668     d->clickY = ym;
00669     }
00670 
00671     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
00672                                            d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
00673     if (mev.innerNode.handle())
00674     mev.innerNode.handle()->setPressed();
00675 
00676     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00677     if (r && r->isWidget())
00678     _mouse->ignore();
00679 
00680     if (!swallowEvent) {
00681     emit m_part->nodeActivated(mev.innerNode);
00682 
00683     khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00684         QApplication::sendEvent( m_part, &event );
00685         // we might be deleted after this
00686     }
00687 }
00688 
00689 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
00690 {
00691     if(!m_part->xmlDocImpl()) return;
00692 
00693     int xm, ym;
00694     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00695 
00696     kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
00697 
00698     d->isDoubleClick = true;
00699 
00700     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
00701     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00702 
00703     // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat
00704     // single and double-click events as separate (only the detail, i.e. number of clicks differs)
00705     if (d->clickCount > 0 &&
00706         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00707     d->clickCount++;
00708     else { // shouldn't happen, if Qt has the same criterias for double clicks.
00709     d->clickCount = 1;
00710     d->clickX = xm;
00711     d->clickY = ym;
00712     }
00713     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
00714                                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
00715 
00716     if (mev.innerNode.handle())
00717     mev.innerNode.handle()->setPressed();
00718 
00719     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00720     if (r && r->isWidget())
00721     _mouse->ignore();
00722 
00723     if (!swallowEvent) {
00724     khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
00725     QApplication::sendEvent( m_part, &event );
00726     }
00727 
00728     d->possibleTripleClick=true;
00729     QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
00730 }
00731 
00732 void KHTMLView::tripleClickTimeout()
00733 {
00734     d->possibleTripleClick = false;
00735     d->clickCount = 0;
00736 }
00737 
00738 static inline void forwardPeripheralEvent(khtml::RenderWidget* r, QMouseEvent* me, int x, int y)
00739 {
00740     int absx = 0;
00741     int absy = 0;
00742     r->absolutePosition(absx, absy);
00743     QPoint p(x-absx, y-absy);
00744     QMouseEvent fw(me->type(), p, me->button(), me->state());
00745     QWidget* w = r->widget();
00746     if(w)
00747         static_cast<khtml::RenderWidget::EventPropagator*>(w)->sendEvent(&fw);
00748 }
00749 
00750 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
00751 {
00752 
00753     if(!m_part->xmlDocImpl()) return;
00754 
00755     int xm, ym;
00756     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00757 
00758     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
00759     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00760 
00761 //     kdDebug(6000) << "mouse move: " << _mouse->pos()
00762 //        << " button " << _mouse->button()
00763 //        << " state " << _mouse->state() << endl;
00764 
00765     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),false,
00766                                            0,_mouse,true,DOM::NodeImpl::MouseMove);
00767 
00768     if (d->clickCount > 0 &&
00769         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
00770     d->clickCount = 0;  // moving the mouse outside the threshold invalidates the click
00771     }
00772 
00773     // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
00774     m_part->executeScheduledScript();
00775 
00776     DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
00777     if (fn && fn != mev.innerNode.handle() &&
00778         fn->renderer() && fn->renderer()->isWidget()) {
00779         forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00780     }
00781 
00782     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00783     khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
00784     QCursor c;
00785     switch ( style ? style->cursor() : CURSOR_AUTO) {
00786     case CURSOR_AUTO:
00787         if ( mev.url.length() && m_part->settings()->changeCursor() )
00788             c = m_part->urlCursor();
00789 
00790         if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
00791             c = QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
00792 
00793         break;
00794     case CURSOR_CROSS:
00795         c = KCursor::crossCursor();
00796         break;
00797     case CURSOR_POINTER:
00798         c = m_part->urlCursor();
00799         break;
00800     case CURSOR_PROGRESS:
00801         c = KCursor::workingCursor();
00802         break;
00803     case CURSOR_MOVE:
00804         c = KCursor::sizeAllCursor();
00805         break;
00806     case CURSOR_E_RESIZE:
00807     case CURSOR_W_RESIZE:
00808         c = KCursor::sizeHorCursor();
00809         break;
00810     case CURSOR_N_RESIZE:
00811     case CURSOR_S_RESIZE:
00812         c = KCursor::sizeVerCursor();
00813         break;
00814     case CURSOR_NE_RESIZE:
00815     case CURSOR_SW_RESIZE:
00816         c = KCursor::sizeBDiagCursor();
00817         break;
00818     case CURSOR_NW_RESIZE:
00819     case CURSOR_SE_RESIZE:
00820         c = KCursor::sizeFDiagCursor();
00821         break;
00822     case CURSOR_TEXT:
00823         c = KCursor::ibeamCursor();
00824         break;
00825     case CURSOR_WAIT:
00826         c = KCursor::waitCursor();
00827         break;
00828     case CURSOR_HELP:
00829         c = KCursor::whatsThisCursor();
00830         break;
00831     case CURSOR_DEFAULT:
00832         break;
00833     }
00834 
00835     if ( viewport()->cursor().handle() != c.handle() ) {
00836         if( c.handle() == KCursor::arrowCursor().handle()) {
00837             for (KHTMLPart* p = m_part; p; p = p->parentPart())
00838                 p->view()->viewport()->unsetCursor();
00839         }
00840         else {
00841             viewport()->setCursor( c );
00842     }
00843     }
00844     if (r && r->isWidget()) {
00845     _mouse->ignore();
00846     }
00847 
00848 
00849     d->prevMouseX = xm;
00850     d->prevMouseY = ym;
00851 
00852     if (!swallowEvent) {
00853         khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00854         QApplication::sendEvent( m_part, &event );
00855     }
00856 }
00857 
00858 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
00859 {
00860     if ( !m_part->xmlDocImpl() ) return;
00861 
00862     int xm, ym;
00863     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00864 
00865     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
00866     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
00867 
00868     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true,
00869                                            d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
00870 
00871     if (d->clickCount > 0 &&
00872         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
00873     QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
00874                _mouse->pos(), _mouse->button(), _mouse->state());
00875     dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),true,
00876                            d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
00877     }
00878 
00879     if (mev.innerNode.handle())
00880     mev.innerNode.handle()->setPressed(false);
00881 
00882     DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
00883     if (fn && fn != mev.innerNode.handle() &&
00884         fn->renderer() && fn->renderer()->isWidget()) {
00885         forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00886     }
00887 
00888     khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00889     if (r && r->isWidget())
00890     _mouse->ignore();
00891 
00892     if (!swallowEvent) {
00893     khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00894     QApplication::sendEvent( m_part, &event );
00895     }
00896 }
00897 
00898 // returns true if event should be swallowed
00899 bool KHTMLView::dispatchKeyEvent( QKeyEvent *_ke )
00900 {
00901     if (!m_part->xmlDocImpl())
00902         return false;
00903     // Pressing and releasing a key should generate keydown, keypress and keyup events
00904     // Holding it down should generated keydown, keypress (repeatedly) and keyup events
00905     // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
00906     // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
00907     // of the Qt events shouldn't be passed to DOM, but it should be still filtered
00908     // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
00909     // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
00910     // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
00911     // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
00912     // The solution is to filter out and postpone the Qt autorepeat keyrelease until
00913     // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
00914     // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
00915     // again, and here it will be ignored.
00916     //
00917     //  Qt:      Press      | Release(autorepeat) Press(autorepeat) etc. |   Release
00918     //  DOM:   Down + Press |      (nothing)           Press             |     Up
00919 
00920     // It's also possible to get only Releases. E.g. the release of alt-tab,
00921     // or when the keypresses get captured by an accel.
00922 
00923     if( _ke == d->postponed_autorepeat ) // replayed event
00924     {
00925         return false;
00926     }
00927 
00928     if( _ke->type() == QEvent::KeyPress )
00929     {
00930         if( !_ke->isAutoRepeat())
00931         {
00932             bool ret = dispatchKeyEventHelper( _ke, false ); // keydown
00933             if( dispatchKeyEventHelper( _ke, true )) // keypress
00934                 ret = true;
00935             return ret;
00936         }
00937         else // autorepeat
00938         {
00939             bool ret = dispatchKeyEventHelper( _ke, true ); // keypress
00940             if( !ret && d->postponed_autorepeat )
00941                 keyPressEvent( d->postponed_autorepeat );
00942             delete d->postponed_autorepeat;
00943             d->postponed_autorepeat = NULL;
00944             return ret;
00945         }
00946     }
00947     else // QEvent::KeyRelease
00948     {
00949         // Discard postponed "autorepeat key-release" events that didn't see
00950         // a keypress after them (e.g. due to QAccel)
00951         if ( d->postponed_autorepeat ) {
00952             delete d->postponed_autorepeat;
00953             d->postponed_autorepeat = 0;
00954         }
00955 
00956         if( !_ke->isAutoRepeat()) {
00957             return dispatchKeyEventHelper( _ke, false ); // keyup
00958         }
00959         else
00960         {
00961             d->postponed_autorepeat = new QKeyEvent( _ke->type(), _ke->key(), _ke->ascii(), _ke->state(),
00962                 _ke->text(), _ke->isAutoRepeat(), _ke->count());
00963             if( _ke->isAccepted())
00964                 d->postponed_autorepeat->accept();
00965             else
00966                 d->postponed_autorepeat->ignore();
00967             return true;
00968         }
00969     }
00970 }
00971 
00972 // returns true if event should be swallowed
00973 bool KHTMLView::dispatchKeyEventHelper( QKeyEvent *_ke, bool keypress )
00974 {
00975     DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
00976     if (keyNode) {
00977         return keyNode->dispatchKeyEvent(_ke, keypress);
00978     } else { // no focused node, send to document
00979         return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
00980     }
00981 }
00982 
00983 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
00984 {
00985 
00986 #ifndef KHTML_NO_CARET
00987     if (m_part->isEditable() || m_part->isCaretMode()
00988         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
00989         && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
00990       d->caretViewContext()->keyReleasePending = true;
00991       caretKeyPressEvent(_ke);
00992       return;
00993     }
00994 #endif // KHTML_NO_CARET
00995 
00996     if ( dispatchKeyEvent( _ke )) {
00997         // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
00998         _ke->accept();
00999         return;
01000     }
01001 
01002     int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
01003     if (_ke->state() & Qt::ShiftButton)
01004       switch(_ke->key())
01005         {
01006         case Key_Space:
01007             if ( d->vmode == QScrollView::AlwaysOff )
01008                 _ke->accept();
01009             else
01010                 scrollBy( 0, -clipper()->height() - offs );
01011             break;
01012 
01013         case Key_Down:
01014         case Key_J:
01015             d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
01016             break;
01017 
01018         case Key_Up:
01019         case Key_K:
01020             d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
01021             break;
01022 
01023         case Key_Left:
01024         case Key_H:
01025             d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
01026             break;
01027 
01028         case Key_Right:
01029         case Key_L:
01030             d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
01031             break;
01032         }
01033     else
01034         switch ( _ke->key() )
01035         {
01036         case Key_Down:
01037         case Key_J:
01038             if ( d->vmode == QScrollView::AlwaysOff )
01039                 _ke->accept();
01040             else {
01041                 if (d->scrollTimerId)
01042                     d->newScrollTimer(this, 0);
01043                 else
01044                     scrollBy( 0, 10 );
01045             }
01046             break;
01047 
01048         case Key_Space:
01049         case Key_Next:
01050             if ( d->vmode == QScrollView::AlwaysOff )
01051                 _ke->accept();
01052             else
01053                 scrollBy( 0, clipper()->height() - offs );
01054             break;
01055 
01056         case Key_Up:
01057         case Key_K:
01058             if ( d->vmode == QScrollView::AlwaysOff )
01059                 _ke->accept();
01060             else {
01061                 if (d->scrollTimerId)
01062                     d->newScrollTimer(this, 0);
01063                 else
01064                     scrollBy( 0, -10 );
01065             }
01066             break;
01067 
01068         case Key_Prior:
01069             if ( d->vmode == QScrollView::AlwaysOff )
01070                 _ke->accept();
01071             else
01072                 scrollBy( 0, -clipper()->height() + offs );
01073             break;
01074         case Key_Right:
01075         case Key_L:
01076             if ( d->hmode == QScrollView::AlwaysOff )
01077                 _ke->accept();
01078             else {
01079                 if (d->scrollTimerId)
01080                     d->newScrollTimer(this, 0);
01081                 else
01082                     scrollBy( 10, 0 );
01083             }
01084             break;
01085         case Key_Left:
01086         case Key_H:
01087             if ( d->hmode == QScrollView::AlwaysOff )
01088                 _ke->accept();
01089             else {
01090                 if (d->scrollTimerId)
01091                     d->newScrollTimer(this, 0);
01092                 else
01093                     scrollBy( -10, 0 );
01094             }
01095             break;
01096         case Key_Enter:
01097         case Key_Return:
01098         // ### FIXME:
01099         // move this code to HTMLAnchorElementImpl::setPressed(false),
01100         // or even better to HTMLAnchorElementImpl::event()
01101             if (m_part->xmlDocImpl()) {
01102         NodeImpl *n = m_part->xmlDocImpl()->focusNode();
01103         if (n)
01104             n->setActive();
01105         d->originalNode = n;
01106         }
01107             break;
01108         case Key_Home:
01109             if ( d->vmode == QScrollView::AlwaysOff )
01110                 _ke->accept();
01111             else
01112                 setContentsPos( 0, 0 );
01113             break;
01114         case Key_End:
01115             if ( d->vmode == QScrollView::AlwaysOff )
01116                 _ke->accept();
01117             else
01118                 setContentsPos( 0, contentsHeight() - visibleHeight() );
01119             break;
01120         case Key_Shift:
01121             // what are you doing here?
01122         _ke->ignore();
01123             return;
01124         default:
01125             if (d->scrollTimerId)
01126                 d->newScrollTimer(this, 0);
01127         _ke->ignore();
01128             return;
01129         }
01130     _ke->accept();
01131 }
01132 
01133 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
01134 {
01135     if (d->m_caretViewContext && d->m_caretViewContext->keyReleasePending) {
01136         //caretKeyReleaseEvent(_ke);
01137     d->m_caretViewContext->keyReleasePending = false;
01138     return;
01139     }
01140 
01141     // Send keyup event
01142     if ( dispatchKeyEvent( _ke ) )
01143     {
01144         _ke->accept();
01145         return;
01146     }
01147     QScrollView::keyReleaseEvent(_ke);
01148 }
01149 
01150 void KHTMLView::contentsContextMenuEvent ( QContextMenuEvent * /*ce*/ )
01151 {
01152 // ### what kind of c*** is that ?
01153 #if 0
01154     if (!m_part->xmlDocImpl()) return;
01155     int xm = _ce->x();
01156     int ym = _ce->y();
01157 
01158     DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove ); // ### not a mouse event!
01159     m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
01160 
01161     NodeImpl *targetNode = mev.innerNode.handle();
01162     if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
01163         int absx = 0;
01164         int absy = 0;
01165         targetNode->renderer()->absolutePosition(absx,absy);
01166         QPoint pos(xm-absx,ym-absy);
01167 
01168         QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
01169         QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
01170         setIgnoreEvents(true);
01171         QApplication::sendEvent(w,&cme);
01172         setIgnoreEvents(false);
01173     }
01174 #endif
01175 }
01176 
01177 bool KHTMLView::focusNextPrevChild( bool next )
01178 {
01179     // Now try to find the next child
01180     if (m_part->xmlDocImpl()) {
01181         focusNextPrevNode(next);
01182         if (m_part->xmlDocImpl()->focusNode() != 0) {
01183       kdDebug() << "focusNode.name: "
01184       << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
01185             return true; // focus node found
01186         }
01187     }
01188 
01189     // If we get here, there is no next/previous child to go to, so pass up to the next/previous child in our parent
01190     if (m_part->parentPart() && m_part->parentPart()->view())
01191         return m_part->parentPart()->view()->focusNextPrevChild(next);
01192 
01193     return QWidget::focusNextPrevChild(next);
01194 }
01195 
01196 void KHTMLView::doAutoScroll()
01197 {
01198     QPoint pos = QCursor::pos();
01199     pos = viewport()->mapFromGlobal( pos );
01200 
01201     int xm, ym;
01202     viewportToContents(pos.x(), pos.y(), xm, ym);
01203 
01204     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
01205     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
01206          (pos.x() < 0) || (pos.x() > visibleWidth()) )
01207     {
01208         ensureVisible( xm, ym, 0, 5 );
01209 
01210 #ifndef KHTML_NO_SELECTION
01211         // extend the selection while scrolling
01212     DOM::Node innerNode;
01213     if (m_part->isExtendingSelection()) {
01214             RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
01215             m_part->xmlDocImpl()->renderer()->layer()
01216                 ->nodeAtPoint(renderInfo, xm, ym);
01217             innerNode = renderInfo.innerNode();
01218     }/*end if*/
01219 
01220         if (innerNode.handle() && innerNode.handle()->renderer()) {
01221             int absX, absY;
01222             innerNode.handle()->renderer()->absolutePosition(absX, absY);
01223 
01224             m_part->extendSelectionTo(xm, ym, absX, absY, innerNode);
01225         }/*end if*/
01226 #endif // KHTML_NO_SELECTION
01227     }
01228 }
01229 
01230 
01231 class HackWidget : public QWidget
01232 {
01233  public:
01234     inline void setNoErase() { setWFlags(getWFlags()|WRepaintNoErase); }
01235 };
01236 
01237 bool KHTMLView::eventFilter(QObject *o, QEvent *e)
01238 {
01239     if ( e->type() == QEvent::AccelOverride ) {
01240     QKeyEvent* ke = (QKeyEvent*) e;
01241 //kdDebug(6200) << "QEvent::AccelOverride" << endl;
01242     if (m_part->isEditable() || m_part->isCaretMode()
01243         || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
01244         && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
01245 //kdDebug(6200) << "editable/navigable" << endl;
01246         if ( (ke->state() & ControlButton) || (ke->state() & ShiftButton) ) {
01247         switch ( ke->key() ) {
01248         case Key_Left:
01249         case Key_Right:
01250         case Key_Up:
01251         case Key_Down:
01252         case Key_Home:
01253         case Key_End:
01254             ke->accept();
01255 //kdDebug(6200) << "eaten" << endl;
01256             return true;
01257         default:
01258             break;
01259         }
01260         }
01261     }
01262     }
01263 
01264     QWidget *view = viewport();
01265 
01266     if (o == view) {
01267     // we need to install an event filter on all children of the viewport to
01268     // be able to get correct stacking of children within the document.
01269     if(e->type() == QEvent::ChildInserted) {
01270         QObject *c = static_cast<QChildEvent *>(e)->child();
01271         if (c->isWidgetType()) {
01272         QWidget *w = static_cast<QWidget *>(c);
01273         // don't install the event filter on toplevels
01274         if (w->parentWidget(true) == view) {
01275             if (!strcmp(w->name(), "__khtml")) {
01276             w->installEventFilter(this);
01277             w->unsetCursor();
01278             w->setBackgroundMode( QWidget::NoBackground );
01279             static_cast<HackWidget *>(w)->setNoErase();
01280             if (w->children()) {
01281                 QObjectListIterator it(*w->children());
01282                 for (; it.current(); ++it) {
01283                 QWidget *widget = ::qt_cast<QWidget *>(it.current());
01284                 if (widget && !widget->isTopLevel()
01285                     && !::qt_cast<QScrollView *>(widget)) {
01286                     widget->setBackgroundMode( QWidget::NoBackground );
01287                     static_cast<HackWidget *>(widget)->setNoErase();
01288                     widget->installEventFilter(this);
01289                 }
01290                 }
01291             }
01292             }
01293         }
01294         }
01295     }
01296     } else if (o->isWidgetType()) {
01297     QWidget *v = static_cast<QWidget *>(o);
01298         QWidget *c = v;
01299     while (v && v != view) {
01300             c = v;
01301         v = v->parentWidget(true);
01302     }
01303 
01304     if (v && !strcmp(c->name(), "__khtml")) {
01305         bool block = false;
01306         QWidget *w = static_cast<QWidget *>(o);
01307         switch(e->type()) {
01308         case QEvent::Paint:
01309         if (!allowWidgetPaintEvents) {
01310             // eat the event. Like this we can control exactly when the widget
01311             // get's repainted.
01312             block = true;
01313             int x = 0, y = 0;
01314             QWidget *v = w;
01315             while (v && v != view) {
01316             x += v->x();
01317             y += v->y();
01318             v = v->parentWidget();
01319             }
01320             viewportToContents( x, y, x, y );
01321             QPaintEvent *pe = static_cast<QPaintEvent *>(e);
01322             scheduleRepaint(x + pe->rect().x(), y + pe->rect().y(),
01323                     pe->rect().width(), pe->rect().height());
01324         }
01325         break;
01326         case QEvent::MouseMove:
01327         case QEvent::MouseButtonPress:
01328         case QEvent::MouseButtonRelease:
01329         case QEvent::MouseButtonDblClick: {
01330         if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01331             QMouseEvent *me = static_cast<QMouseEvent *>(e);
01332             QPoint pt = (me->pos() + w->pos());
01333             QMouseEvent me2(me->type(), pt, me->button(), me->state());
01334 
01335             if (e->type() == QEvent::MouseMove)
01336             viewportMouseMoveEvent(&me2);
01337             else if(e->type() == QEvent::MouseButtonPress)
01338             viewportMousePressEvent(&me2);
01339             else if(e->type() == QEvent::MouseButtonRelease)
01340             viewportMouseReleaseEvent(&me2);
01341             else
01342             viewportMouseDoubleClickEvent(&me2);
01343             block = true;
01344                 }
01345         break;
01346         }
01347         case QEvent::KeyPress:
01348         case QEvent::KeyRelease:
01349         if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01350             QKeyEvent *ke = static_cast<QKeyEvent *>(e);
01351             if (e->type() == QEvent::KeyPress)
01352             keyPressEvent(ke);
01353             else
01354             keyReleaseEvent(ke);
01355             block = true;
01356         }
01357         default:
01358         break;
01359         }
01360         if (block) {
01361         //qDebug("eating event");
01362         return true;
01363         }
01364     }
01365     }
01366 
01367 //    kdDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type() << endl;
01368     return QScrollView::eventFilter(o, e);
01369 }
01370 
01371 
01372 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
01373 {
01374     return d->underMouse;
01375 }
01376 
01377 bool KHTMLView::scrollTo(const QRect &bounds)
01378 {
01379     d->scrollingSelf = true; // so scroll events get ignored
01380 
01381     int x, y, xe, ye;
01382     x = bounds.left();
01383     y = bounds.top();
01384     xe = bounds.right();
01385     ye = bounds.bottom();
01386 
01387     //kdDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y<<endl;
01388 
01389     int deltax;
01390     int deltay;
01391 
01392     int curHeight = visibleHeight();
01393     int curWidth = visibleWidth();
01394 
01395     if (ye-y>curHeight-d->borderY)
01396     ye  = y + curHeight - d->borderY;
01397 
01398     if (xe-x>curWidth-d->borderX)
01399     xe = x + curWidth - d->borderX;
01400 
01401     // is xpos of target left of the view's border?
01402     if (x < contentsX() + d->borderX )
01403             deltax = x - contentsX() - d->borderX;
01404     // is xpos of target right of the view's right border?
01405     else if (xe + d->borderX > contentsX() + curWidth)
01406             deltax = xe + d->borderX - ( contentsX() + curWidth );
01407     else
01408         deltax = 0;
01409 
01410     // is ypos of target above upper border?
01411     if (y < contentsY() + d->borderY)
01412             deltay = y - contentsY() - d->borderY;
01413     // is ypos of target below lower border?
01414     else if (ye + d->borderY > contentsY() + curHeight)
01415             deltay = ye + d->borderY - ( contentsY() + curHeight );
01416     else
01417         deltay = 0;
01418 
01419     int maxx = curWidth-d->borderX;
01420     int maxy = curHeight-d->borderY;
01421 
01422     int scrollX,scrollY;
01423 
01424     scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
01425     scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
01426 
01427     if (contentsX() + scrollX < 0)
01428     scrollX = -contentsX();
01429     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
01430     scrollX = contentsWidth() - visibleWidth() - contentsX();
01431 
01432     if (contentsY() + scrollY < 0)
01433     scrollY = -contentsY();
01434     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
01435     scrollY = contentsHeight() - visibleHeight() - contentsY();
01436 
01437     scrollBy(scrollX, scrollY);
01438 
01439 
01440 
01441     // generate abs(scroll.)
01442     if (scrollX<0)
01443         scrollX=-scrollX;
01444     if (scrollY<0)
01445         scrollY=-scrollY;
01446 
01447     d->scrollingSelf = false;
01448 
01449     if ( (scrollX!=maxx) && (scrollY!=maxy) )
01450     return true;
01451     else return false;
01452 
01453 }
01454 
01455 void KHTMLView::focusNextPrevNode(bool next)
01456 {
01457     // Sets the focus node of the document to be the node after (or if next is false, before) the current focus node.
01458     // Only nodes that are selectable (i.e. for which isSelectable() returns true) are taken into account, and the order
01459     // used is that specified in the HTML spec (see DocumentImpl::nextFocusNode() and DocumentImpl::previousFocusNode()
01460     // for details).
01461 
01462     DocumentImpl *doc = m_part->xmlDocImpl();
01463     NodeImpl *oldFocusNode = doc->focusNode();
01464     NodeImpl *newFocusNode;
01465 
01466     // Find the next/previous node from the current one
01467     if (next)
01468         newFocusNode = doc->nextFocusNode(oldFocusNode);
01469     else
01470         newFocusNode = doc->previousFocusNode(oldFocusNode);
01471 
01472     // If there was previously no focus node and the user has scrolled the document, then instead of picking the first
01473     // focusable node in the document, use the first one that lies within the visible area (if possible).
01474     if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
01475 
01476       kdDebug(6000) << " searching for visible link" << endl;
01477 
01478         bool visible = false;
01479         NodeImpl *toFocus = newFocusNode;
01480         while (!visible && toFocus) {
01481             QRect focusNodeRect = toFocus->getRect();
01482             if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
01483                 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
01484                 // toFocus is visible in the contents area
01485                 visible = true;
01486             }
01487             else {
01488                 // toFocus is _not_ visible in the contents area, pick the next node
01489                 if (next)
01490                     toFocus = doc->nextFocusNode(toFocus);
01491                 else
01492                     toFocus = doc->previousFocusNode(toFocus);
01493             }
01494         }
01495 
01496         if (toFocus)
01497             newFocusNode = toFocus;
01498     }
01499 
01500     d->scrollBarMoved = false;
01501 
01502     if (!newFocusNode)
01503       {
01504         // No new focus node, scroll to bottom or top depending on next
01505         if (next)
01506             scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
01507         else
01508             scrollTo(QRect(contentsX()+visibleWidth()/2,0,0,0));
01509     }
01510     else
01511     // Scroll the view as necessary to ensure that the new focus node is visible
01512     {
01513 #ifndef KHTML_NO_CARET
01514         // if it's an editable element, activate the caret
01515         if (!m_part->isCaretMode() && !m_part->isEditable()
01516         && newFocusNode->contentEditable()) {
01517         d->caretViewContext();
01518         moveCaretTo(newFocusNode, 0L, true);
01519         } else {
01520         caretOff();
01521     }
01522 #endif // KHTML_NO_CARET
01523 
01524       if (oldFocusNode)
01525     {
01526       if (!scrollTo(newFocusNode->getRect()))
01527         return;
01528     }
01529       else
01530     {
01531       ensureVisible(contentsX(), next?0:contentsHeight());
01532       //return;
01533     }
01534 
01535     }
01536 
01537     // Set focus node on the document
01538     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
01539     emit m_part->nodeActivated(Node(newFocusNode));
01540 }
01541 
01542 void KHTMLView::setMediaType( const QString &medium )
01543 {
01544     m_medium = medium;
01545 }
01546 
01547 QString KHTMLView::mediaType() const
01548 {
01549     return m_medium;
01550 }
01551 
01552 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
01553 {
01554     if (vis) {
01555         d->visibleWidgets.replace(w, w->widget());
01556     }
01557     else
01558         d->visibleWidgets.remove(w);
01559 }
01560 
01561 void KHTMLView::print()
01562 {
01563     print( false );
01564 }
01565 
01566 void KHTMLView::print(bool quick)
01567 {
01568     if(!m_part->xmlDocImpl()) return;
01569     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
01570     if(!root) return;
01571 
01572     // this only works on Unix - we assume 72dpi
01573     KPrinter *printer = new KPrinter(true, QPrinter::PrinterResolution);
01574     printer->addDialogPage(new KHTMLPrintSettings());
01575     QString docname = m_part->xmlDocImpl()->URL().prettyURL();
01576     if ( !docname.isEmpty() )
01577         docname = KStringHandler::csqueeze(docname, 80);
01578     if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
01579         viewport()->setCursor( waitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
01580         // set up KPrinter
01581         printer->setFullPage(false);
01582         printer->setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
01583         printer->setDocName(docname);
01584 
01585         QPainter *p = new QPainter;
01586         p->begin( printer );
01587         khtml::setPrintPainter( p );
01588 
01589         m_part->xmlDocImpl()->setPaintDevice( printer );
01590         QString oldMediaType = mediaType();
01591         setMediaType( "print" );
01592         // We ignore margin settings for html and body when printing
01593         // and use the default margins from the print-system
01594         // (In Qt 3.0.x the default margins are hardcoded in Qt)
01595         m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
01596                                                   "* { background-image: none !important;"
01597                                                   "    background-color: white !important;"
01598                                                   "    color: black !important; }"
01599                           "body { margin: 0px !important; }"
01600                           "html { margin: 0px !important; }" :
01601                           "body { margin: 0px !important; }"
01602                           "html { margin: 0px !important; }"
01603                           );
01604 
01605         QPaintDeviceMetrics metrics( printer );
01606 
01607         // this is a simple approximation... we layout the document
01608         // according to the width of the page, then just cut
01609         // pages without caring about the content. We should do better
01610         // in the future, but for the moment this is better than no
01611         // printing support
01612         kdDebug(6000) << "printing: physical page width = " << metrics.width()
01613                       << " height = " << metrics.height() << endl;
01614         root->setPrintingMode(true);
01615         root->setWidth(metrics.width());
01616 
01617         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
01618         m_part->xmlDocImpl()->updateStyleSelector();
01619         root->setPrintImages( printer->option("app-khtml-printimages") == "true");
01620         root->setMinMaxKnown( false );
01621         root->setLayouted( false );
01622         root->layout();
01623 
01624         bool printHeader = (printer->option("app-khtml-printheader") == "true");
01625 
01626         int headerHeight = 0;
01627         QFont headerFont("helvetica", 8);
01628 
01629         QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),true);
01630         QString headerMid = docname;
01631         QString headerRight;
01632 
01633         if (printHeader)
01634         {
01635            p->setFont(headerFont);
01636            headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
01637         }
01638 
01639         // ok. now print the pages.
01640         kdDebug(6000) << "printing: html page width = " << root->docWidth()
01641                       << " height = " << root->docHeight() << endl;
01642         kdDebug(6000) << "printing: margins left = " << printer->margins().width()
01643                       << " top = " << printer->margins().height() << endl;
01644         kdDebug(6000) << "printing: paper width = " << metrics.width()
01645                       << " height = " << metrics.height() << endl;
01646         // if the width is too large to fit on the paper we just scale
01647         // the whole thing.
01648         int pageHeight = metrics.height();
01649         int pageWidth = metrics.width();
01650         p->setClipRect(0,0, pageWidth, pageHeight);
01651 
01652         pageHeight -= headerHeight;
01653 
01654         bool scalePage = false;
01655         double scale = 0.0;
01656 #ifndef QT_NO_TRANSFORMATIONS
01657         if(root->docWidth() > metrics.width()) {
01658             scalePage = true;
01659             scale = ((double) metrics.width())/((double) root->docWidth());
01660             pageHeight = (int) (pageHeight/scale);
01661             pageWidth = (int) (pageWidth/scale);
01662             headerHeight = (int) (headerHeight/scale);
01663         }
01664 #endif
01665         kdDebug(6000) << "printing: scaled html width = " << pageWidth
01666                       << " height = " << pageHeight << endl;
01667 
01668         // Squeeze header to make it it on the page.
01669         if (printHeader)
01670         {
01671             int available_width = metrics.width() - 10 -
01672                 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
01673                          p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
01674             if (available_width < 150)
01675                available_width = 150;
01676             int mid_width;
01677             int squeeze = 120;
01678             do {
01679                 headerMid = KStringHandler::csqueeze(docname, squeeze);
01680                 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
01681                 squeeze -= 10;
01682             } while (mid_width > available_width);
01683         }
01684 
01685         int top = 0;
01686         int page = 1;
01687         while(top < root->docHeight()) {
01688             if(top > 0) printer->newPage();
01689             if (printHeader)
01690             {
01691                 int dy = p->fontMetrics().lineSpacing();
01692                 p->setPen(Qt::black);
01693                 p->setFont(headerFont);
01694 
01695                 headerRight = QString("#%1").arg(page);
01696 
01697                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
01698                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
01699                 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
01700             }
01701 
01702 #ifndef QT_NO_TRANSFORMATIONS
01703             if (scalePage)
01704                 p->scale(scale, scale);
01705 #endif
01706             p->translate(0, headerHeight-top);
01707 
01708             root->setTruncatedAt(top+pageHeight);
01709 
01710             root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
01711             if (top + pageHeight >= root->docHeight())
01712                 break; // Stop if we have printed everything
01713 
01714             top = root->truncatedAt();
01715             p->resetXForm();
01716             page++;
01717         }
01718 
01719         p->end();
01720         delete p;
01721 
01722         // and now reset the layout to the usual one...
01723         root->setPrintingMode(false);
01724         khtml::setPrintPainter( 0 );
01725         setMediaType( oldMediaType );
01726         m_part->xmlDocImpl()->setPaintDevice( this );
01727         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
01728         m_part->xmlDocImpl()->updateStyleSelector();
01729         viewport()->unsetCursor();
01730     }
01731     delete printer;
01732 }
01733 
01734 void KHTMLView::slotPaletteChanged()
01735 {
01736     if(!m_part->xmlDocImpl()) return;
01737     DOM::DocumentImpl *document = m_part->xmlDocImpl();
01738     if (!document->isHTMLDocument()) return;
01739     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
01740     if(!root) return;
01741     root->style()->resetPalette();
01742     NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
01743     if(!body) return;
01744     body->setChanged(true);
01745     body->recalcStyle( NodeImpl::Force );
01746 }
01747 
01748 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
01749 {
01750     if(!m_part->xmlDocImpl()) return;
01751     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
01752     if(!root) return;
01753 
01754     m_part->xmlDocImpl()->setPaintDevice(p->device());
01755     root->setPrintingMode(true);
01756     root->setWidth(rc.width());
01757 
01758     p->save();
01759     p->setClipRect(rc);
01760     p->translate(rc.left(), rc.top());
01761     double scale = ((double) rc.width()/(double) root->docWidth());
01762     int height = (int) ((double) rc.height() / scale);
01763 #ifndef QT_NO_TRANSFORMATIONS
01764     p->scale(scale, scale);
01765 #endif
01766 
01767     root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
01768     if (more)
01769         *more = yOff + height < root->docHeight();
01770     p->restore();
01771 
01772     root->setPrintingMode(false);
01773     m_part->xmlDocImpl()->setPaintDevice( this );
01774 }
01775 
01776 
01777 void KHTMLView::useSlowRepaints()
01778 {
01779     kdDebug(0) << "slow repaints requested" << endl;
01780     d->useSlowRepaints = true;
01781     setStaticBackground(true);
01782 }
01783 
01784 
01785 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
01786 {
01787 #ifndef KHTML_NO_SCROLLBARS
01788     d->vmode = mode;
01789     QScrollView::setVScrollBarMode(mode);
01790 #else
01791     Q_UNUSED( mode );
01792 #endif
01793 }
01794 
01795 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
01796 {
01797 #ifndef KHTML_NO_SCROLLBARS
01798     d->hmode = mode;
01799     QScrollView::setHScrollBarMode(mode);
01800 #else
01801     Q_UNUSED( mode );
01802 #endif
01803 }
01804 
01805 void KHTMLView::restoreScrollBar()
01806 {
01807     int ow = visibleWidth();
01808     QScrollView::setVScrollBarMode(d->vmode);
01809     if (visibleWidth() != ow)
01810         layout();
01811     d->prevScrollbarVisible = verticalScrollBar()->isVisible();
01812 }
01813 
01814 QStringList KHTMLView::formCompletionItems(const QString &name) const
01815 {
01816     if (!m_part->settings()->isFormCompletionEnabled())
01817         return QStringList();
01818     if (!d->formCompletions)
01819         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01820     return d->formCompletions->readListEntry(name);
01821 }
01822 
01823 void KHTMLView::clearCompletionHistory(const QString& name)
01824 {
01825     if (!d->formCompletions)
01826     {
01827         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01828     }
01829     d->formCompletions->writeEntry(name, "");
01830     d->formCompletions->sync();
01831 }
01832 
01833 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
01834 {
01835     if (!m_part->settings()->isFormCompletionEnabled())
01836         return;
01837     // don't store values that are all numbers or just numbers with
01838     // dashes or spaces as those are likely credit card numbers or
01839     // something similar
01840     bool cc_number(true);
01841     for (unsigned int i = 0; i < value.length(); ++i)
01842     {
01843       QChar c(value[i]);
01844       if (!c.isNumber() && c != '-' && !c.isSpace())
01845       {
01846         cc_number = false;
01847         break;
01848       }
01849     }
01850     if (cc_number)
01851       return;
01852     QStringList items = formCompletionItems(name);
01853     if (!items.contains(value))
01854         items.prepend(value);
01855     while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
01856         items.remove(items.fromLast());
01857     d->formCompletions->writeEntry(name, items);
01858 }
01859 
01860 void KHTMLView::addNonPasswordStorableSite(const QString& host)
01861 {
01862     if (!d->formCompletions) {
01863         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01864     }
01865 
01866     d->formCompletions->setGroup("NonPasswordStorableSites");
01867     QStringList sites = d->formCompletions->readListEntry("Sites");
01868     sites.append(host);
01869     d->formCompletions->writeEntry("Sites", sites);
01870     d->formCompletions->sync();
01871     d->formCompletions->setGroup(QString::null);//reset
01872 }
01873 
01874 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
01875 {
01876     if (!d->formCompletions) {
01877         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
01878     }
01879     d->formCompletions->setGroup("NonPasswordStorableSites");
01880     QStringList sites =  d->formCompletions->readListEntry("Sites");
01881     d->formCompletions->setGroup(QString::null);//reset
01882 
01883     return (sites.find(host) != sites.end());
01884 }
01885 
01886 // returns true if event should be swallowed
01887 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable,
01888                    int detail,QMouseEvent *_mouse, bool setUnder,
01889                    int mouseEventType)
01890 {
01891     if (d->underMouse)
01892     d->underMouse->deref();
01893     d->underMouse = targetNode;
01894     if (d->underMouse)
01895     d->underMouse->ref();
01896 
01897     int exceptioncode = 0;
01898     int mx, my;
01899     viewportToContents(_mouse->x(), _mouse->y(), mx, my);
01900     // clientX and clientY are in viewport coordinates
01901     // At least the JS code wants event.[xy]/event.client[XY] to be in viewport coords.
01902     // [that's not the same as _mouse->[xy](), since we use the clipper]
01903     int clientX = mx - contentsX();
01904     int clientY = my - contentsY();
01905     int screenX = _mouse->globalX();
01906     int screenY = _mouse->globalY();
01907     int button = -1;
01908     switch (_mouse->button()) {
01909     case LeftButton:
01910         button = 0;
01911         break;
01912     case MidButton:
01913         button = 1;
01914         break;
01915     case RightButton:
01916         button = 2;
01917         break;
01918     default:
01919         break;
01920     }
01921     bool ctrlKey = (_mouse->state() & ControlButton);
01922     bool altKey = (_mouse->state() & AltButton);
01923     bool shiftKey = (_mouse->state() & ShiftButton);
01924     bool metaKey = (_mouse->state() & MetaButton);
01925 
01926     // mouseout/mouseover
01927     if (setUnder && (d->prevMouseX != mx || d->prevMouseY != my)) {
01928 
01929         // ### this code sucks. we should save the oldUnder instead of calculating
01930         // it again. calculating is expensive! (Dirk)
01931         NodeImpl *oldUnder = 0;
01932     if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
01933         NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
01934         m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
01935         oldUnder = mev.innerNode.handle();
01936     }
01937 //  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());
01938     if (oldUnder != targetNode) {
01939         // send mouseout event to the old node
01940         if (oldUnder){
01941         oldUnder->ref();
01942         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
01943                             true,true,m_part->xmlDocImpl()->defaultView(),
01944                             0,screenX,screenY,clientX,clientY,
01945                             ctrlKey,altKey,shiftKey,metaKey,
01946                             button,targetNode);
01947         me->ref();
01948         oldUnder->dispatchEvent(me,exceptioncode,true);
01949         me->deref();
01950         }
01951 
01952         // send mouseover event to the new node
01953         if (targetNode) {
01954         MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
01955                             true,true,m_part->xmlDocImpl()->defaultView(),
01956                             0,screenX,screenY,clientX,clientY,
01957                             ctrlKey,altKey,shiftKey,metaKey,
01958                             button,oldUnder);
01959 
01960         me->ref();
01961         targetNode->dispatchEvent(me,exceptioncode,true);
01962         me->deref();
01963         }
01964 
01965             if (oldUnder)
01966                 oldUnder->deref();
01967         }
01968     }
01969 
01970     bool swallowEvent = false;
01971 
01972     if (targetNode) {
01973         // send the actual event
01974         bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
01975                           _mouse->type() == QEvent::MouseButtonDblClick );
01976         MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
01977                         true,cancelable,m_part->xmlDocImpl()->defaultView(),
01978                         detail,screenX,screenY,clientX,clientY,
01979                         ctrlKey,altKey,shiftKey,metaKey,
01980                         button,0, _mouse, dblclick );
01981         me->ref();
01982         targetNode->dispatchEvent(me,exceptioncode,true);
01983         if (me->defaultHandled() || me->defaultPrevented())
01984             swallowEvent = true;
01985         me->deref();
01986 
01987         if (eventId == EventImpl::MOUSEDOWN_EVENT) {
01988             if (targetNode->isSelectable())
01989                 m_part->xmlDocImpl()->setFocusNode(targetNode);
01990             else
01991                 m_part->xmlDocImpl()->setFocusNode(0);
01992         }
01993     }
01994 
01995     return swallowEvent;
01996 }
01997 
01998 void KHTMLView::setIgnoreWheelEvents( bool e )
01999 {
02000     d->ignoreWheelEvents = e;
02001 }
02002 
02003 #ifndef QT_NO_WHEELEVENT
02004 
02005 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
02006 {
02007     if ( ( e->state() & ControlButton) == ControlButton )
02008     {
02009         emit zoomView( - e->delta() );
02010         e->accept();
02011     }
02012     else if ( ( (d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
02013                 || e->delta() > 0 && contentsY() <= 0
02014                         || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())
02015                 && m_part->parentPart() ) {
02016        kdDebug(6000) << this << " cz " << contentsY() << " ch " << contentsHeight() << " vh " << visibleHeight() << endl;
02017         if ( m_part->parentPart()->view() )
02018             m_part->parentPart()->view()->wheelEvent( e );
02019         kdDebug(6000) << "sent" << endl;
02020         e->ignore();
02021     }
02022     else if ( d->vmode == QScrollView::AlwaysOff ) {
02023         e->accept();
02024     }
02025     else {
02026         d->scrollBarMoved = true;
02027         QScrollView::viewportWheelEvent( e );
02028 
02029         QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, QPoint(-1,-1), QPoint(-1,-1), Qt::NoButton, e->state() );
02030         emit viewportMouseMoveEvent ( tempEvent );
02031         delete tempEvent;
02032     }
02033 
02034 }
02035 #endif
02036 
02037 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
02038 {
02039     // Handle drops onto frames (#16820)
02040     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
02041     // in e.g. kmail, so not handled here).
02042     if ( m_part->parentPart() )
02043     {
02044         QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02045     return;
02046     }
02047     QScrollView::dragEnterEvent( ev );
02048 }
02049 
02050 void KHTMLView::dropEvent( QDropEvent *ev )
02051 {
02052     // Handle drops onto frames (#16820)
02053     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
02054     // in e.g. kmail, so not handled here).
02055     if ( m_part->parentPart() )
02056     {
02057         QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02058     return;
02059     }
02060     QScrollView::dropEvent( ev );
02061 }
02062 
02063 void KHTMLView::focusInEvent( QFocusEvent *e )
02064 {
02065 #ifndef KHTML_NO_CARET
02066     // Restart blink frequency timer if it has been killed, but only on
02067     // editable nodes
02068     if (d->m_caretViewContext &&
02069         d->m_caretViewContext->freqTimerId == -1 &&
02070         m_part->xmlDocImpl()) {
02071         NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02072         if (m_part->isCaretMode()
02073         || m_part->isEditable()
02074             || (caretNode && caretNode->renderer()
02075             && caretNode->renderer()->style()->userInput()
02076                 == UI_ENABLED)) {
02077             d->m_caretViewContext->freqTimerId = startTimer(500);
02078         d->m_caretViewContext->visible = true;
02079         }/*end if*/
02080     }/*end if*/
02081     showCaret();
02082 #endif // KHTML_NO_CARET
02083     QScrollView::focusInEvent( e );
02084 }
02085 
02086 void KHTMLView::focusOutEvent( QFocusEvent *e )
02087 {
02088     if(m_part) m_part->stopAutoScroll();
02089 
02090 #ifndef KHTML_NO_CARET
02091     if (d->m_caretViewContext) {
02092         switch (d->m_caretViewContext->displayNonFocused) {
02093     case KHTMLPart::CaretInvisible:
02094             hideCaret();
02095         break;
02096     case KHTMLPart::CaretVisible: {
02097         killTimer(d->m_caretViewContext->freqTimerId);
02098         d->m_caretViewContext->freqTimerId = -1;
02099             NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02100         if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
02101         || m_part->isEditable()
02102             || (caretNode && caretNode->renderer()
02103             && caretNode->renderer()->style()->userInput()
02104                 == UI_ENABLED))) {
02105             d->m_caretViewContext->visible = true;
02106             showCaret(true);
02107         }/*end if*/
02108         break;
02109     }
02110     case KHTMLPart::CaretBlink:
02111         // simply leave as is
02112         break;
02113     }/*end switch*/
02114     }/*end if*/
02115 #endif // KHTML_NO_CARET
02116     QScrollView::focusOutEvent( e );
02117 }
02118 
02119 void KHTMLView::slotScrollBarMoved()
02120 {
02121     if (!d->scrollingSelf)
02122         d->scrollBarMoved = true;
02123 }
02124 
02125 void KHTMLView::timerEvent ( QTimerEvent *e )
02126 {
02127 //    kdDebug() << "timer event " << e->timerId() << endl;
02128     if ( e->timerId() == d->scrollTimerId ) {
02129         switch (d->scrollDirection) {
02130             case KHTMLViewPrivate::ScrollDown:
02131                 if (contentsY() + visibleHeight () >= contentsHeight())
02132                     d->newScrollTimer(this, 0);
02133                 else
02134                     scrollBy( 0, d->scrollBy );
02135                 break;
02136             case KHTMLViewPrivate::ScrollUp:
02137                 if (contentsY() <= 0)
02138                     d->newScrollTimer(this, 0);
02139                 else
02140                     scrollBy( 0, -d->scrollBy );
02141                 break;
02142             case KHTMLViewPrivate::ScrollRight:
02143                 if (contentsX() + visibleWidth () >= contentsWidth())
02144                     d->newScrollTimer(this, 0);
02145                 else
02146                     scrollBy( d->scrollBy, 0 );
02147                 break;
02148             case KHTMLViewPrivate::ScrollLeft:
02149                 if (contentsX() <= 0)
02150                     d->newScrollTimer(this, 0);
02151                 else
02152                     scrollBy( -d->scrollBy, 0 );
02153                 break;
02154         }
02155         return;
02156     }
02157     else if ( e->timerId() == d->layoutTimerId ) {
02158         d->firstRelayout = false;
02159         d->dirtyLayout = true;
02160         layout();
02161     }
02162 #ifndef KHTML_NO_CARET
02163     else if (d->m_caretViewContext
02164              && e->timerId() == d->m_caretViewContext->freqTimerId) {
02165         d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
02166     if (d->m_caretViewContext->displayed) {
02167         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02168             d->m_caretViewContext->width,
02169             d->m_caretViewContext->height);
02170     }/*end if*/
02171 //  if (d->m_caretViewContext->visible) cout << "|" << flush;
02172 //  else cout << "°" << flush;
02173     return;
02174     }
02175 #endif
02176 
02177     if( m_part->xmlDocImpl() ) {
02178     DOM::DocumentImpl *document = m_part->xmlDocImpl();
02179     khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
02180 
02181     if ( root && !root->layouted() ) {
02182         killTimer(d->repaintTimerId);
02183         d->repaintTimerId = 0;
02184         scheduleRelayout();
02185         return;
02186     }
02187     }
02188 
02189     setStaticBackground(d->useSlowRepaints);
02190 
02191 //        kdDebug() << "scheduled repaint "<< d->repaintTimerId  << endl;
02192     killTimer(d->repaintTimerId);
02193     d->repaintTimerId = 0;
02194 
02195     updateContents( d->updateRect );
02196     d->updateRect = QRect();
02197 
02198     if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
02199         QWidget* w;
02200         d->dirtyLayout = false;
02201 
02202         QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02203         QPtrList<RenderWidget> toRemove;
02204         for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
02205             int xp = 0, yp = 0;
02206             w = it.current();
02207             RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
02208             if (!rw->absolutePosition(xp, yp) ||
02209                 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
02210                 toRemove.append(rw);
02211         }
02212         for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
02213             if ( (w = d->visibleWidgets.take(r) ) )
02214                 addChild(w, 0, -500000);
02215     }
02216 }
02217 
02218 void KHTMLView::scheduleRelayout(khtml::RenderObject * /*clippedObj*/)
02219 {
02220     if (!d->layoutSchedulingEnabled || d->layoutTimerId)
02221         return;
02222 
02223     d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
02224                              ? 1000 : 0 );
02225 }
02226 
02227 void KHTMLView::unscheduleRelayout()
02228 {
02229     if (!d->layoutTimerId)
02230         return;
02231 
02232     killTimer(d->layoutTimerId);
02233     d->layoutTimerId = 0;
02234 }
02235 
02236 void KHTMLView::unscheduleRepaint()
02237 {
02238     if (!d->repaintTimerId)
02239         return;
02240 
02241     killTimer(d->repaintTimerId);
02242     d->repaintTimerId = 0;
02243 }
02244 
02245 void KHTMLView::scheduleRepaint(int x, int y, int w, int h)
02246 {
02247     bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
02248 
02249 //     kdDebug() << "parsing " << parsing << endl;
02250 //     kdDebug() << "complete " << d->complete << endl;
02251 
02252     int time;
02253 
02254     // if complete...
02255     if (d->complete)
02256         // ...repaint immediately
02257         time = 20;
02258     else
02259     {
02260         if (parsing)
02261             // not complete and still parsing
02262             time = 300;
02263         else
02264             // not complete, not parsing, extend the timer if it exists
02265             // otherwise, repaint immediately
02266             time = d->repaintTimerId ? 400 : 20;
02267     }
02268 
02269     if (d->repaintTimerId) {
02270         killTimer(d->repaintTimerId);
02271         d->updateRect = d->updateRect.unite(QRect(x,y,w,h));
02272     } else
02273         d->updateRect = QRect(x,y,w,h);
02274 
02275 //  kdDebug(6000) << "scheduled repaint for " << d->updateRect << endl;
02276     d->repaintTimerId = startTimer( time );
02277 
02278 //     kdDebug() << "starting timer " << time << endl;
02279 }
02280 
02281 void KHTMLView::complete()
02282 {
02283 //     kdDebug() << "KHTMLView::complete()" << endl;
02284 
02285     d->complete = true;
02286 
02287     // is there a relayout pending?
02288     if (d->layoutTimerId)
02289     {
02290 //         kdDebug() << "requesting relayout now" << endl;
02291         // do it now
02292         killTimer(d->layoutTimerId);
02293         d->layoutTimerId = startTimer( 0 );
02294     }
02295 
02296     // is there a repaint pending?
02297     if (d->repaintTimerId)
02298     {
02299 //         kdDebug() << "requesting repaint now" << endl;
02300         // do it now
02301         killTimer(d->repaintTimerId);
02302         d->repaintTimerId = startTimer( 20 );
02303     }
02304 }
02305 
02306 #ifndef KHTML_NO_CARET
02307 
02308 // ### the dependencies on static functions are a nightmare. just be
02309 // hacky and include the implementation here. Clean me up, please.
02310 
02311 #include "khtml_caret.cpp"
02312 
02313 void KHTMLView::initCaret(bool keepSelection)
02314 {
02315 #if DEBUG_CARETMODE > 0
02316   kdDebug(6200) << "begin initCaret" << endl;
02317 #endif
02318   // save caretMoved state as moveCaretTo changes it
02319   if (m_part->xmlDocImpl()) {
02320     d->caretViewContext();
02321     bool cmoved = d->m_caretViewContext->caretMoved;
02322     if (m_part->d->caretNode().isNull()) {
02323       // set to document, position will be sanitized anyway
02324       m_part->d->caretNode() = m_part->document();
02325       m_part->d->caretOffset() = 0L;
02326       // This sanity check is necessary for the not so unlikely case that
02327       // setEditable or setCaretMode is called before any render objects have
02328       // been created.
02329       if (!m_part->d->caretNode().handle()->renderer()) return;
02330     }/*end if*/
02331 //    kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
02332 //          << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
02333     // ### does not repaint the selection on keepSelection!=false
02334     moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
02335 //    kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
02336 //          << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
02337     d->m_caretViewContext->caretMoved = cmoved;
02338   }/*end if*/
02339 #if DEBUG_CARETMODE > 0
02340   kdDebug(6200) << "end initCaret" << endl;
02341 #endif
02342 }
02343 
02344 bool KHTMLView::caretOverrides() const
02345 {
02346     bool cm = m_part->isCaretMode();
02347     bool dm = m_part->isEditable();
02348     return cm && !dm ? false
02349         : (dm || m_part->d->caretNode().handle()->contentEditable())
02350       && d->editorContext()->override;
02351 }
02352 
02353 void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
02354 {
02355   if (m_part->isCaretMode() || m_part->isEditable()) return;
02356   if (node->focused()) return;
02357 
02358   // Find first ancestor whose "user-input" is "enabled"
02359   NodeImpl *firstAncestor = 0;
02360   while (node) {
02361     if (node->renderer()
02362        && node->renderer()->style()->userInput() != UI_ENABLED)
02363       break;
02364     firstAncestor = node;
02365     node = node->parentNode();
02366   }/*wend*/
02367 
02368   if (!node) firstAncestor = 0;
02369 
02370   DocumentImpl *doc = m_part->xmlDocImpl();
02371   // ensure that embedded widgets don't lose their focus
02372   if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
02373     && doc->focusNode()->renderer()->isWidget())
02374     return;
02375 
02376   // Set focus node on the document
02377 #if DEBUG_CARETMODE > 1
02378   kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
02379     << (firstAncestor ? firstAncestor->nodeName().string() : QString::null) << endl;
02380 #endif
02381   doc->setFocusNode(firstAncestor);
02382   emit m_part->nodeActivated(Node(firstAncestor));
02383 }
02384 
02385 void KHTMLView::recalcAndStoreCaretPos(InlineBox *hintBox)
02386 {
02387     if (!m_part || m_part->d->caretNode().isNull()) return;
02388     d->caretViewContext();
02389     NodeImpl *caretNode = m_part->d->caretNode().handle();
02390 #if DEBUG_CARETMODE > 0
02391   kdDebug(6200) << "recalcAndStoreCaretPos: caretNode=" << caretNode << (caretNode ? " "+caretNode->nodeName().string() : QString::null) << " r@" << caretNode->renderer() << (caretNode->renderer() && caretNode->renderer()->isText() ? " \"" + QConstString(static_cast<RenderText *>(caretNode->renderer())->str->s, kMin(static_cast<RenderText *>(caretNode->renderer())->str->l, 15u)).string() + "\"" : QString::null) << endl;
02392 #endif
02393     caretNode->getCaret(m_part->d->caretOffset(),
02394                 caretOverrides(),
02395             d->m_caretViewContext->x, d->m_caretViewContext->y,
02396         d->m_caretViewContext->width,
02397         d->m_caretViewContext->height);
02398 
02399     if (hintBox && d->m_caretViewContext->x == -1) {
02400 #if DEBUG_CARETMODE > 1
02401         kdDebug(6200) << "using hint inline box coordinates" << endl;
02402 #endif
02403     RenderObject *r = caretNode->renderer();
02404     const QFontMetrics &fm = r->style()->fontMetrics();
02405         int absx, absy;
02406     r->containingBlock()->absolutePosition(absx, absy,
02407                         false); // ### what about fixed?
02408     d->m_caretViewContext->x = absx + hintBox->xPos();
02409     d->m_caretViewContext->y = absy + hintBox->yPos()
02410                 + hintBox->baseline() - fm.ascent();
02411     d->m_caretViewContext->width = 1;
02412     // ### firstline not regarded. But I think it can be safely neglected
02413     // as hint boxes are only used for empty lines.
02414     d->m_caretViewContext->height = fm.height();
02415     }/*end if*/
02416 
02417 #if DEBUG_CARETMODE > 4
02418 //    kdDebug(6200) << "freqTimerId: "<<d->m_caretViewContext->freqTimerId<<endl;
02419 #endif
02420 #if DEBUG_CARETMODE > 0
02421     kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
02422         <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
02423     <<" h="<<d->m_caretViewContext->height<<endl;
02424 #endif
02425 }
02426 
02427 void KHTMLView::caretOn()
02428 {
02429     if (d->m_caretViewContext) {
02430         killTimer(d->m_caretViewContext->freqTimerId);
02431 
02432     if (hasFocus() || d->m_caretViewContext->displayNonFocused
02433             == KHTMLPart::CaretBlink) {
02434             d->m_caretViewContext->freqTimerId = startTimer(500);
02435     } else {
02436         d->m_caretViewContext->freqTimerId = -1;
02437     }/*end if*/
02438 
02439         d->m_caretViewContext->visible = true;
02440         if ((d->m_caretViewContext->displayed = (hasFocus()
02441         || d->m_caretViewContext->displayNonFocused
02442             != KHTMLPart::CaretInvisible))) {
02443         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02444                 d->m_caretViewContext->width,
02445             d->m_caretViewContext->height);
02446     }/*end if*/
02447 //        kdDebug(6200) << "caret on" << endl;
02448     }/*end if*/
02449 }
02450 
02451 void KHTMLView::caretOff()
02452 {
02453     if (d->m_caretViewContext) {
02454         killTimer(d->m_caretViewContext->freqTimerId);
02455     d->m_caretViewContext->freqTimerId = -1;
02456         d->m_caretViewContext->displayed = false;
02457         if (d->m_caretViewContext->visible) {
02458             d->m_caretViewContext->visible = false;
02459         updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02460                 d->m_caretViewContext->width,
02461                 d->m_caretViewContext->height);
02462     }/*end if*/
02463 //        kdDebug(6200) << "caret off" << endl;
02464     }/*end if*/
02465 }
02466 
02467 void KHTMLView::showCaret(bool forceRepaint)
02468 {
02469     if (d->m_caretViewContext) {
02470         d->m_caretViewContext->displayed = true;
02471         if (d->m_caretViewContext->visible) {
02472         if (!forceRepaint) {
02473             updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02474                 d->m_caretViewContext->width,
02475             d->m_caretViewContext->height);
02476             } else {
02477             repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02478                 d->m_caretViewContext->width,
02479                 d->m_caretViewContext->height);
02480         }/*end if*/
02481     }/*end if*/
02482 //        kdDebug(6200) << "caret shown" << endl;
02483     }/*end if*/
02484 }
02485 
02486 bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
02487                     NodeImpl *endNode, long endOffset)
02488 {
02489   m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
02490   m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
02491   m_part->d->m_extendAtEnd = true;
02492 
02493   bool folded = startNode != endNode || startOffset != endOffset;
02494 
02495   // Only clear the selection if there has been one.
02496   if (folded) {
02497     m_part->xmlDocImpl()->clearSelection();
02498   }/*end if*/
02499 
02500   return folded;
02501 }
02502 
02503 void KHTMLView::hideCaret()
02504 {
02505     if (d->m_caretViewContext) {
02506         if (d->m_caretViewContext->visible) {
02507 //            kdDebug(6200) << "redraw caret hidden" << endl;
02508         d->m_caretViewContext->visible = false;
02509         // force repaint, otherwise the event won't be handled
02510         // before the focus leaves the window
02511         repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02512                 d->m_caretViewContext->width,
02513                 d->m_caretViewContext->height);
02514         d->m_caretViewContext->visible = true;
02515     }/*end if*/
02516         d->m_caretViewContext->displayed = false;
02517 //        kdDebug(6200) << "caret hidden" << endl;
02518     }/*end if*/
02519 }
02520 
02521 int KHTMLView::caretDisplayPolicyNonFocused() const
02522 {
02523   if (d->m_caretViewContext)
02524     return d->m_caretViewContext->displayNonFocused;
02525   else
02526     return KHTMLPart::CaretInvisible;
02527 }
02528 
02529 void KHTMLView::setCaretDisplayPolicyNonFocused(int policy)
02530 {
02531   d->caretViewContext();
02532 //  int old = d->m_caretViewContext->displayNonFocused;
02533   d->m_caretViewContext->displayNonFocused = (KHTMLPart::CaretDisplayPolicy)policy;
02534 
02535   // make change immediately take effect if not focused
02536   if (!hasFocus()) {
02537     switch (d->m_caretViewContext->displayNonFocused) {
02538       case KHTMLPart::CaretInvisible:
02539         hideCaret();
02540     break;
02541       case KHTMLPart::CaretBlink:
02542     if (d->m_caretViewContext->freqTimerId != -1) break;
02543     d->m_caretViewContext->freqTimerId = startTimer(500);
02544     // fall through
02545       case KHTMLPart::CaretVisible:
02546         d->m_caretViewContext->displayed = true;
02547         showCaret();
02548     break;
02549     }/*end switch*/
02550   }/*end if*/
02551 }
02552 
02553 bool KHTMLView::placeCaret(InlineBox *hintBox)
02554 {
02555   CaretViewContext *cv = d->caretViewContext();
02556   caretOff();
02557   NodeImpl *caretNode = m_part->d->caretNode().handle();
02558   // ### why is it sometimes null?
02559   if (!caretNode || !caretNode->renderer()) return false;
02560   ensureNodeHasFocus(caretNode);
02561   if (m_part->isCaretMode() || m_part->isEditable()
02562      || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
02563     recalcAndStoreCaretPos(hintBox);
02564 
02565     cv->origX = cv->x;
02566 
02567     caretOn();
02568     return true;
02569   }/*end if*/
02570   return false;
02571 }
02572 
02573 void KHTMLView::ensureCaretVisible()
02574 {
02575   CaretViewContext *cv = d->m_caretViewContext;
02576   if (!cv) return;
02577   ensureVisible(cv->x, cv->y, cv->width, cv->height);
02578   d->scrollBarMoved = false;
02579 }
02580 
02581 bool KHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
02582                 NodeImpl *oldEndSel, long oldEndOfs)
02583 {
02584   bool changed = false;
02585   if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
02586       && m_part->d->m_startOffset == m_part->d->m_endOffset) {
02587     changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02588     m_part->d->m_extendAtEnd = true;
02589   } else do {
02590     changed = m_part->d->m_selectionStart.handle() != oldStartSel
02591             || m_part->d->m_startOffset != oldStartOfs
02592         || m_part->d->m_selectionEnd.handle() != oldEndSel
02593         || m_part->d->m_endOffset != oldEndOfs;
02594     if (!changed) break;
02595 
02596     // determine start position -- caret position is always at end.
02597     NodeImpl *startNode;
02598     long startOffset;
02599     if (m_part->d->m_extendAtEnd) {
02600       startNode = m_part->d->m_selectionStart.handle();
02601       startOffset = m_part->d->m_startOffset;
02602     } else {
02603       startNode = m_part->d->m_selectionEnd.handle();
02604       startOffset = m_part->d->m_endOffset;
02605       m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
02606       m_part->d->m_endOffset = m_part->d->m_startOffset;
02607     }/*end if*/
02608 
02609     bool swapNeeded = false;
02610     if (!m_part->d->m_selectionEnd.isNull() && startNode) {
02611       swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
02612                 m_part->d->m_selectionEnd.handle(),
02613             m_part->d->m_endOffset) >= 0;
02614     }/*end if*/
02615 
02616     m_part->d->m_selectionStart = startNode;
02617     m_part->d->m_startOffset = startOffset;
02618 
02619     if (swapNeeded) {
02620       m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
02621         m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
02622         m_part->d->m_startOffset);
02623     } else {
02624       m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
02625         m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
02626         m_part->d->m_endOffset);
02627     }/*end if*/
02628   } while(false);/*end if*/
02629   return changed;
02630 }
02631 
02632 void KHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
02633                 NodeImpl *oldEndSel, long oldEndOfs)
02634 {
02635   if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
02636       && m_part->d->m_startOffset == m_part->d->m_endOffset) {
02637     if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
02638       m_part->emitSelectionChanged();
02639     }/*end if*/
02640     m_part->d->m_extendAtEnd = true;
02641   } else {
02642     // check if the extending end has passed the immobile end
02643     if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
02644       bool swapNeeded = RangeImpl::compareBoundaryPoints(
02645                 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
02646             m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
02647       if (swapNeeded) {
02648         DOM::Node tmpNode = m_part->d->m_selectionStart;
02649         long tmpOffset = m_part->d->m_startOffset;
02650         m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
02651         m_part->d->m_startOffset = m_part->d->m_endOffset;
02652         m_part->d->m_selectionEnd = tmpNode;
02653         m_part->d->m_endOffset = tmpOffset;
02654         m_part->d->m_startBeforeEnd = true;
02655         m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
02656       }/*end if*/
02657     }/*end if*/
02658 
02659     m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
02660         m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
02661         m_part->d->m_endOffset);
02662     m_part->emitSelectionChanged();
02663   }/*end if*/
02664 }
02665 
02666 void KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
02667 {
02668   NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
02669   long oldStartOfs = m_part->d->m_startOffset;
02670   NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
02671   long oldEndOfs = m_part->d->m_endOffset;
02672 
02673   NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
02674   long oldOffset = m_part->d->caretOffset();
02675 
02676   bool ctrl = _ke->state() & ControlButton;
02677 
02678 // FIXME: this is that widely indented because I will write ifs around it.
02679       switch(_ke->key()) {
02680         case Key_Space:
02681           break;
02682 
02683         case Key_Down:
02684       moveCaretNextLine(1);
02685           break;
02686 
02687         case Key_Up:
02688       moveCaretPrevLine(1);
02689           break;
02690 
02691         case Key_Left:
02692       moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
02693           break;
02694 
02695         case Key_Right:
02696       moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
02697           break;
02698 
02699         case Key_Next:
02700       moveCaretNextPage();
02701           break;
02702 
02703         case Key_Prior:
02704       moveCaretPrevPage();
02705           break;
02706 
02707         case Key_Home:
02708       if (ctrl)
02709         moveCaretToDocumentBoundary(false);
02710       else
02711         moveCaretToLineBegin();
02712           break;
02713 
02714         case Key_End:
02715       if (ctrl)
02716         moveCaretToDocumentBoundary(true);
02717       else
02718         moveCaretToLineEnd();
02719           break;
02720 
02721       }/*end switch*/
02722 
02723   if ((m_part->d->caretNode().handle() != oldCaretNode
02724     || m_part->d->caretOffset() != oldOffset)
02725     // node should never be null, but faulty conditions may cause it to be
02726     && !m_part->d->caretNode().isNull()) {
02727 
02728     d->m_caretViewContext->caretMoved = true;
02729 
02730     if (_ke->state() & ShiftButton) {   // extend selection
02731       updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02732     } else {            // clear any selection
02733       if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
02734         m_part->emitSelectionChanged();
02735     }/*end if*/
02736 
02737     m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
02738   }/*end if*/
02739 
02740   _ke->accept();
02741 }
02742 
02743 bool KHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
02744 {
02745   sanitizeCaretState(node, offset);
02746   if (!node) return false;
02747 
02748   // need to find out the node's inline box. If there is none, this function
02749   // will snap to the next node that has one. This is necessary to make the
02750   // caret visible in any case.
02751   RenderArena arena;
02752   RenderFlow *cb;
02753   InlineBox *box = 0;
02754   findFlowBox(node, offset, &arena, cb, &box);
02755   if (box && box->object() != node->renderer()) {
02756     if (box->object()->element()) {
02757       node = box->object()->element();
02758       offset = node->minOffset();
02759 #if DEBUG_CARETMODE > 1
02760       kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
02761 #endif
02762     } else {    // box has no associated element -> do not use
02763       // this case should actually never happen.
02764       box = 0;
02765       kdError(6200) << "Box contains no node! Crash imminent" << endl;
02766     }/*end if*/
02767   }
02768 
02769   NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
02770   long oldStartOfs = m_part->d->m_startOffset;
02771   NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
02772   long oldEndOfs = m_part->d->m_endOffset;
02773 
02774   // test for position change
02775   bool posChanged = m_part->d->caretNode().handle() != node
02776         || m_part->d->caretOffset() != offset;
02777   bool selChanged = false;
02778 
02779   m_part->d->caretNode() = node;
02780   m_part->d->caretOffset() = offset;
02781   if (clearSel || !oldStartSel || !oldEndSel) {
02782     selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02783   } else {
02784     //kdDebug(6200) << "moveToCaret: extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
02785     //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;
02786     selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02787     //kdDebug(6200) << "after extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
02788     //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;
02789   }/*end if*/
02790 
02791   d->caretViewContext()->caretMoved = true;
02792 
02793   bool visible_caret = placeCaret(box);
02794 
02795   // FIXME: if the old position was !visible_caret, and the new position is
02796   // also, then two caretPositionChanged signals with a null Node are
02797   // emitted in series.
02798   if (posChanged) {
02799     m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
02800   }/*end if*/
02801 
02802   return selChanged;
02803 }
02804 
02805 void KHTMLView::moveCaretByLine(bool next, int count)
02806 {
02807   // FIXME: what if the node is removed whilst we access it?
02808   // Current solution: bail out
02809   Node &caretNodeRef = m_part->d->caretNode();
02810   if (caretNodeRef.isNull()) return;
02811 
02812   NodeImpl *caretNode = caretNodeRef.handle();
02813 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
02814   long offset = m_part->d->caretOffset();
02815 
02816   CaretViewContext *cv = d->caretViewContext();
02817 
02818   LinearDocument ld(m_part, caretNode, offset);
02819 
02820   ErgonomicEditableLineIterator it(ld.current(), cv->origX);
02821 
02822   // move count lines vertically
02823   while (count > 0 && it != ld.end() && it != ld.preBegin()) {
02824     count--;
02825     if (next) ++it; else --it;
02826   }/*wend*/
02827 
02828   // Nothing? Then leave everything as is.
02829   if (it == ld.end() || it == ld.preBegin()) return;
02830 
02831   int x, absx, absy;
02832   InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
02833 
02834   placeCaretOnLine(caretBox, x, absx, absy);
02835 }
02836 
02837 void KHTMLView::placeCaretOnLine(InlineBox *caretBox, int x, int absx, int absy)
02838 {
02839   // paranoia sanity check
02840   if (!caretBox) return;
02841 
02842   RenderObject *caretRender = caretBox->object();
02843   NodeImpl *caretNode = caretRender->element();
02844 
02845 #if DEBUG_CARETMODE > 0
02846   kdDebug(6200) << "got valid caretBox " << caretBox << endl;
02847   kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
02848         << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
02849   if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << QString(((RenderText *)((InlineTextBox *)caretBox)->object())->str->s + ((InlineTextBox *)caretBox)->m_start, ((InlineTextBox *)caretBox)->m_len) << "\"" << endl;}
02850 #endif
02851   // inquire height of caret
02852   int caretHeight = caretBox->height();
02853   bool isText = caretBox->isInlineTextBox();
02854   int yOfs = 0;     // y-offset for text nodes
02855   if (isText) {
02856     // text boxes need extrawurst
02857     RenderText *t = static_cast<RenderText *>(caretRender);
02858     const QFontMetrics &fm = t->metrics(caretBox->m_firstLine);
02859     caretHeight = fm.height();
02860     yOfs = caretBox->baseline() - fm.ascent();
02861   }/*end if*/
02862 
02863   caretOff();
02864 
02865   // set new caret node
02866   m_part->d->caretNode() = caretNode;
02867   long &offset = m_part->d->caretOffset();
02868 
02869   // set all variables not needing special treatment
02870   d->m_caretViewContext->y = caretBox->yPos() + yOfs;
02871   d->m_caretViewContext->height = caretHeight;
02872   d->m_caretViewContext->width = 1; // FIXME: regard override
02873 
02874   int xPos = caretBox->xPos();
02875   int caretBoxWidth = caretBox->width();
02876 
02877   // before or at beginning of inline box -> place at beginning
02878   if (x <= xPos) {
02879     d->m_caretViewContext->x = xPos;
02880     offset = caretBox->minOffset();
02881   // somewhere within this block
02882   } else if (x > xPos && x <= xPos + caretBoxWidth) {
02883     if (isText) { // find out where exactly
02884       offset = static_cast<InlineTextBox *>(caretBox)->offsetForPoint(x,
02885             d->m_caretViewContext->x);
02886 #if DEBUG_CARETMODE > 2
02887       kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
02888 #endif
02889     } else {    // snap to nearest end
02890       if (xPos + caretBoxWidth - x < x - xPos) {
02891         d->m_caretViewContext->x = xPos + caretBoxWidth;
02892         offset = caretNode ? caretNode->maxOffset() : 1;
02893       } else {
02894         d->m_caretViewContext->x = xPos;
02895         offset = caretNode ? caretNode->minOffset() : 0;
02896       }/*end if*/
02897     }/*end if*/
02898   } else {      // after the inline box -> place at end
02899     d->m_caretViewContext->x = xPos + caretBoxWidth;
02900     offset = caretBox->maxOffset();
02901   }/*end if*/
02902 #if DEBUG_CARETMODE > 0
02903       kdDebug(6200) << "new offset: " << offset << endl;
02904 #endif
02905 
02906   d->m_caretViewContext->x += absx;
02907   d->m_caretViewContext->y += absy;
02908 
02909   ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
02910     d->m_caretViewContext->width, d->m_caretViewContext->height);
02911   d->scrollBarMoved = false;
02912 
02913   ensureNodeHasFocus(caretNode);
02914   caretOn();
02915 }
02916 
02917 void KHTMLView::moveCaretToLineBoundary(bool end)
02918 {
02919   // FIXME: what if the node is removed whilst we access it?
02920   // Current solution: bail out
02921   Node &caretNodeRef = m_part->d->caretNode();
02922   if (caretNodeRef.isNull()) return;
02923 
02924   NodeImpl *caretNode = caretNodeRef.handle();
02925 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
02926   long offset = m_part->d->caretOffset();
02927 
02928   LinearDocument ld(m_part, caretNode, offset);
02929 
02930   EditableLineIterator it = ld.current();
02931   if (it == ld.end()) return;   // should not happen, but who knows
02932 
02933   EditableInlineBoxIterator fbit(it, end);
02934   InlineBox *b = *fbit;
02935   Q_ASSERT(b);
02936 
02937   RenderObject *cb = (*it)->object();
02938   int absx, absy;
02939 
02940   if (cb) cb->absolutePosition(absx,absy);
02941   else absx = absy = 0;
02942 
02943   int x = b->xPos() + (end ? b->width() : 0);
02944   d->m_caretViewContext->origX = absx + x;
02945   placeCaretOnLine(b, x, absx, absy);
02946 }
02947 
02948 void KHTMLView::moveCaretToDocumentBoundary(bool end)
02949 {
02950   // FIXME: what if the node is removed whilst we access it?
02951   // Current solution: bail out
02952   Node &caretNodeRef = m_part->d->caretNode();
02953   if (caretNodeRef.isNull()) return;
02954 
02955   NodeImpl *caretNode = caretNodeRef.handle();
02956 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
02957   long offset = m_part->d->caretOffset();
02958 
02959   LinearDocument ld(m_part, caretNode, offset);
02960 
02961   EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
02962   if (it == ld.end() || it == ld.preBegin()) return;    // should not happen, but who knows
02963 
02964   EditableInlineBoxIterator fbit = it;
02965   InlineBox *b = *fbit;
02966   Q_ASSERT(b);
02967 
02968   RenderObject *cb = (*it)->object();
02969   int absx, absy;
02970 
02971   if (cb) cb->absolutePosition(absx, absy);
02972   else absx = absy = 0;
02973 
02974   int x = b->xPos()/* + (end ? b->width() : 0) reactivate for rtl*/;
02975   d->m_caretViewContext->origX = absx + x;
02976   placeCaretOnLine(b, x, absx, absy);
02977 }
02978 
02979 void KHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
02980 {
02981   if (!m_part) return;
02982   // FIXME: what if the node is removed whilst we access it?
02983   // Current solution: bail out
02984   Node &caretNodeRef = m_part->d->caretNode();
02985   if (caretNodeRef.isNull()) return;
02986 
02987   NodeImpl *caretNode = caretNodeRef.handle();
02988 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
02989   long &offset = m_part->d->caretOffset();
02990 
02991   LinearDocument ld(m_part, caretNode, offset);
02992 
02993   EditableCharacterIterator it(&ld);
02994   InlineBox *hintBox = it.box();
02995   while (it.node() && count > 0) {
02996     count--;
02997     if (cmv == CaretByCharacter) {
02998       if (next) ++it;
02999       else --it;
03000     } else if (cmv == CaretByWord) {
03001       if (next) moveItToNextWord(it);
03002       else moveItToPrevWord(it);
03003     }/*end if*/
03004   }/*wend*/
03005   if (it.node()) {
03006     caretNodeRef = it.node();
03007     offset = it.offset();
03008     hintBox = it.box();
03009 #if DEBUG_CARETMODE > 2
03010     kdDebug(6200) << "set by valid node. offset: " << offset << endl;
03011 #endif
03012   } else {
03013     offset = next ? caretNode->maxOffset() : caretNode->minOffset();
03014 #if DEBUG_CARETMODE > 0
03015     kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
03016 #endif
03017   }/*end if*/
03018   placeCaretOnChar(hintBox);
03019 }
03020 
03021 void KHTMLView::placeCaretOnChar(InlineBox *hintBox)
03022 {
03023   caretOff();
03024   recalcAndStoreCaretPos(hintBox);
03025   ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03026     d->m_caretViewContext->width, d->m_caretViewContext->height);
03027   d->m_caretViewContext->origX = d->m_caretViewContext->x;
03028   d->scrollBarMoved = false;
03029 #if DEBUG_CARETMODE > 3
03030   //if (caretNode->isTextNode())  kdDebug(6200) << "text[0] = " << (int)*((TextImpl *)caretNode)->data().unicode() << " text :\"" << ((TextImpl *)caretNode)->data().string() << "\"" << endl;
03031 #endif
03032   ensureNodeHasFocus(m_part->d->caretNode().handle());
03033   caretOn();
03034 }
03035 
03036 void KHTMLView::moveCaretByPage(bool next)
03037 {
03038   // FIXME: what if the node is removed whilst we access it?
03039   // Current solution: bail out
03040   Node &caretNodeRef = m_part->d->caretNode();
03041   if (caretNodeRef.isNull()) return;
03042 
03043   NodeImpl *caretNode = caretNodeRef.handle();
03044 //  kdDebug(6200) << ": caretNode=" << caretNode << endl;
03045   long offset = m_part->d->caretOffset();
03046 
03047   int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
03048   // Minimum distance the caret must be moved
03049   int mindist = clipper()->height() - offs;
03050 
03051   CaretViewContext *cv = d->caretViewContext();
03052 //  int y = cv->y;      // we always measure the top border
03053 
03054   LinearDocument ld(m_part, caretNode, offset);
03055 
03056   ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03057 
03058   moveIteratorByPage(ld, it, mindist, next);
03059 
03060   int x, absx, absy;
03061   InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
03062 
03063   placeCaretOnLine(caretBox, x, absx, absy);
03064 }
03065 
03066 void KHTMLView::moveCaretPrevWord()
03067 {
03068   moveCaretBy(false, CaretByWord, 1);
03069 }
03070 
03071 void KHTMLView::moveCaretNextWord()
03072 {
03073   moveCaretBy(true, CaretByWord, 1);
03074 }
03075 
03076 void KHTMLView::moveCaretPrevLine(int n)
03077 {
03078   moveCaretByLine(false, n);
03079 }
03080 
03081 void KHTMLView::moveCaretNextLine(int n)
03082 {
03083   moveCaretByLine(true, n);
03084 }
03085 
03086 void KHTMLView::moveCaretPrevPage()
03087 {
03088   moveCaretByPage(false);
03089 }
03090 
03091 void KHTMLView::moveCaretNextPage()
03092 {
03093   moveCaretByPage(true);
03094 }
03095 
03096 void KHTMLView::moveCaretToLineBegin()
03097 {
03098   moveCaretToLineBoundary(false);
03099 }
03100 
03101 void KHTMLView::moveCaretToLineEnd()
03102 {
03103   moveCaretToLineBoundary(true);
03104 }
03105 
03106 #endif // KHTML_NO_CARET
03107 
03108 #undef DEBUG_CARETMODE
KDE Logo
This file is part of the documentation for khtml Library Version 3.2.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Feb 4 12:37:20 2004 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2003