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