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