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