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