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