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