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,
01939 KMIN(rec.left()+rec.width()/2, contentsWidth() - lab->width()),
01940 KMIN(rec.top()+rec.height()/2, contentsHeight() - lab->height()));
01941 showChild(lab);
01942 }
01943 }
01944 }
01945 }
01946
01947 void KHTMLView::accessKeysTimeout()
01948 {
01949 d->accessKeysActivated=false;
01950 d->accessKeysPreActivate = false;
01951 m_part->setStatusBarText(QString::null, KHTMLPart::BarOverrideText);
01952 emit hideAccessKeys();
01953 }
01954
01955
01956 bool KHTMLView::handleAccessKey( const QKeyEvent* ev )
01957 {
01958
01959
01960 QChar c;
01961 if( ev->key() >= Key_A && ev->key() <= Key_Z )
01962 c = 'A' + ev->key() - Key_A;
01963 else if( ev->key() >= Key_0 && ev->key() <= Key_9 )
01964 c = '0' + ev->key() - Key_0;
01965 else {
01966
01967
01968 if( ev->text().length() == 1 )
01969 c = ev->text()[ 0 ];
01970 }
01971 if( c.isNull())
01972 return false;
01973 return focusNodeWithAccessKey( c );
01974 }
01975
01976 bool KHTMLView::focusNodeWithAccessKey( QChar c, KHTMLView* caller )
01977 {
01978 DocumentImpl *doc = m_part->xmlDocImpl();
01979 if( !doc )
01980 return false;
01981 ElementImpl* node = doc->findAccessKeyElement( c );
01982 if( !node ) {
01983 QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
01984 for( QPtrListIterator<KParts::ReadOnlyPart> it( frames );
01985 it != NULL;
01986 ++it ) {
01987 if( !(*it)->inherits( "KHTMLPart" ))
01988 continue;
01989 KHTMLPart* part = static_cast< KHTMLPart* >( *it );
01990 if( part->view() && part->view() != caller
01991 && part->view()->focusNodeWithAccessKey( c, this ))
01992 return true;
01993 }
01994
01995 if (m_part->parentPart() && m_part->parentPart()->view()
01996 && m_part->parentPart()->view() != caller )
01997 return m_part->parentPart()->view()->focusNodeWithAccessKey( c, this );
01998 return false;
01999 }
02000
02001
02002 #ifndef KHTML_NO_CARET
02003
02004 if (!m_part->isCaretMode() && !m_part->isEditable()
02005 && node->contentEditable()) {
02006 d->caretViewContext();
02007 moveCaretTo(node, 0L, true);
02008 } else {
02009 caretOff();
02010 }
02011 #endif // KHTML_NO_CARET
02012
02013 QRect r = node->getRect();
02014 ensureVisible( r.right(), r.bottom());
02015 ensureVisible( r.left(), r.top());
02016
02017 Node guard( node );
02018 if( node->isSelectable()) {
02019 if (node->id()==ID_LABEL) {
02020
02021 node=static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl* >( node )->getFormElement());
02022 if (!node) return true;
02023 guard = node;
02024 }
02025
02026 m_part->xmlDocImpl()->setFocusNode(node);
02027 if( node != NULL && node->hasOneRef())
02028 return true;
02029 emit m_part->nodeActivated(Node(node));
02030 if( node != NULL && node->hasOneRef())
02031 return true;
02032 }
02033
02034 switch( node->id()) {
02035 case ID_A:
02036 static_cast< HTMLAnchorElementImpl* >( node )->click();
02037 break;
02038 case ID_INPUT:
02039 static_cast< HTMLInputElementImpl* >( node )->click();
02040 break;
02041 case ID_BUTTON:
02042 static_cast< HTMLButtonElementImpl* >( node )->click();
02043 break;
02044 case ID_AREA:
02045 static_cast< HTMLAreaElementImpl* >( node )->click();
02046 break;
02047 case ID_TEXTAREA:
02048 break;
02049 case ID_LEGEND:
02050
02051 break;
02052 }
02053 return true;
02054 }
02055
02056 void KHTMLView::setMediaType( const QString &medium )
02057 {
02058 m_medium = medium;
02059 }
02060
02061 QString KHTMLView::mediaType() const
02062 {
02063 return m_medium;
02064 }
02065
02066 void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
02067 {
02068 if (vis) {
02069 d->visibleWidgets.replace(w, w->widget());
02070 }
02071 else
02072 d->visibleWidgets.remove(w);
02073 }
02074
02075 void KHTMLView::print()
02076 {
02077 print( false );
02078 }
02079
02080 void KHTMLView::print(bool quick)
02081 {
02082 if(!m_part->xmlDocImpl()) return;
02083 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
02084 if(!root) return;
02085
02086
02087 KPrinter *printer = new KPrinter(true, QPrinter::PrinterResolution);
02088 printer->addDialogPage(new KHTMLPrintSettings());
02089 QString docname = m_part->xmlDocImpl()->URL().prettyURL();
02090 if ( !docname.isEmpty() )
02091 docname = KStringHandler::csqueeze(docname, 80);
02092 if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
02093 viewport()->setCursor( waitCursor );
02094
02095 printer->setFullPage(false);
02096 printer->setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
02097 printer->setDocName(docname);
02098
02099 QPainter *p = new QPainter;
02100 p->begin( printer );
02101 khtml::setPrintPainter( p );
02102
02103 m_part->xmlDocImpl()->setPaintDevice( printer );
02104 QString oldMediaType = mediaType();
02105 setMediaType( "print" );
02106
02107
02108
02109 m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
02110 "* { background-image: none !important;"
02111 " background-color: white !important;"
02112 " color: black !important; }"
02113 "body { margin: 0px !important; }"
02114 "html { margin: 0px !important; }" :
02115 "body { margin: 0px !important; }"
02116 "html { margin: 0px !important; }"
02117 );
02118
02119 QPaintDeviceMetrics metrics( printer );
02120
02121
02122
02123
02124
02125
02126 kdDebug(6000) << "printing: physical page width = " << metrics.width()
02127 << " height = " << metrics.height() << endl;
02128 root->setPrintingMode(true);
02129 root->setWidth(metrics.width());
02130
02131 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
02132 m_part->xmlDocImpl()->updateStyleSelector();
02133 root->setPrintImages( printer->option("app-khtml-printimages") == "true");
02134 root->setMinMaxKnown( false );
02135 root->setLayouted( false );
02136 root->layout();
02137 khtml::RenderWidget::flushWidgetResizes();
02138
02139 bool printHeader = (printer->option("app-khtml-printheader") == "true");
02140
02141 int headerHeight = 0;
02142 QFont headerFont("helvetica", 8);
02143
02144 QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),true);
02145 QString headerMid = docname;
02146 QString headerRight;
02147
02148 if (printHeader)
02149 {
02150 p->setFont(headerFont);
02151 headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
02152 }
02153
02154
02155 kdDebug(6000) << "printing: html page width = " << root->docWidth()
02156 << " height = " << root->docHeight() << endl;
02157 kdDebug(6000) << "printing: margins left = " << printer->margins().width()
02158 << " top = " << printer->margins().height() << endl;
02159 kdDebug(6000) << "printing: paper width = " << metrics.width()
02160 << " height = " << metrics.height() << endl;
02161
02162
02163 int pageHeight = metrics.height();
02164 int pageWidth = metrics.width();
02165 p->setClipRect(0,0, pageWidth, pageHeight);
02166
02167 pageHeight -= headerHeight;
02168
02169 bool scalePage = false;
02170 double scale = 0.0;
02171 #ifndef QT_NO_TRANSFORMATIONS
02172 if(root->docWidth() > metrics.width()) {
02173 scalePage = true;
02174 scale = ((double) metrics.width())/((double) root->docWidth());
02175 pageHeight = (int) (pageHeight/scale);
02176 pageWidth = (int) (pageWidth/scale);
02177 headerHeight = (int) (headerHeight/scale);
02178 }
02179 #endif
02180 kdDebug(6000) << "printing: scaled html width = " << pageWidth
02181 << " height = " << pageHeight << endl;
02182
02183
02184 if (printHeader)
02185 {
02186 int available_width = metrics.width() - 10 -
02187 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
02188 p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
02189 if (available_width < 150)
02190 available_width = 150;
02191 int mid_width;
02192 int squeeze = 120;
02193 do {
02194 headerMid = KStringHandler::csqueeze(docname, squeeze);
02195 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
02196 squeeze -= 10;
02197 } while (mid_width > available_width);
02198 }
02199
02200 int top = 0;
02201 int page = 1;
02202 while(top < root->docHeight()) {
02203 if(top > 0) printer->newPage();
02204 if (printHeader)
02205 {
02206 int dy = p->fontMetrics().lineSpacing();
02207 p->setPen(Qt::black);
02208 p->setFont(headerFont);
02209
02210 headerRight = QString("#%1").arg(page);
02211
02212 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
02213 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
02214 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
02215 }
02216
02217 #ifndef QT_NO_TRANSFORMATIONS
02218 if (scalePage)
02219 p->scale(scale, scale);
02220 #endif
02221 p->translate(0, headerHeight-top);
02222
02223 root->setTruncatedAt(top+pageHeight);
02224
02225 root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
02226 if (top + pageHeight >= root->docHeight())
02227 break;
02228
02229 top = root->truncatedAt();
02230 p->resetXForm();
02231 page++;
02232 }
02233
02234 p->end();
02235 delete p;
02236
02237
02238 root->setPrintingMode(false);
02239 khtml::setPrintPainter( 0 );
02240 setMediaType( oldMediaType );
02241 m_part->xmlDocImpl()->setPaintDevice( this );
02242 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
02243 m_part->xmlDocImpl()->updateStyleSelector();
02244 viewport()->unsetCursor();
02245 }
02246 delete printer;
02247 }
02248
02249 void KHTMLView::slotPaletteChanged()
02250 {
02251 if(!m_part->xmlDocImpl()) return;
02252 DOM::DocumentImpl *document = m_part->xmlDocImpl();
02253 if (!document->isHTMLDocument()) return;
02254 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
02255 if(!root) return;
02256 root->style()->resetPalette();
02257 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
02258 if(!body) return;
02259 body->setChanged(true);
02260 body->recalcStyle( NodeImpl::Force );
02261 }
02262
02263 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
02264 {
02265 if(!m_part->xmlDocImpl()) return;
02266 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
02267 if(!root) return;
02268
02269 m_part->xmlDocImpl()->setPaintDevice(p->device());
02270 root->setPrintingMode(true);
02271 root->setWidth(rc.width());
02272
02273 p->save();
02274 p->setClipRect(rc);
02275 p->translate(rc.left(), rc.top());
02276 double scale = ((double) rc.width()/(double) root->docWidth());
02277 int height = (int) ((double) rc.height() / scale);
02278 #ifndef QT_NO_TRANSFORMATIONS
02279 p->scale(scale, scale);
02280 #endif
02281
02282 root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
02283 if (more)
02284 *more = yOff + height < root->docHeight();
02285 p->restore();
02286
02287 root->setPrintingMode(false);
02288 m_part->xmlDocImpl()->setPaintDevice( this );
02289 }
02290
02291
02292 void KHTMLView::useSlowRepaints()
02293 {
02294 d->useSlowRepaints = true;
02295 setStaticBackground(true);
02296 }
02297
02298
02299 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
02300 {
02301 #ifndef KHTML_NO_SCROLLBARS
02302 d->vmode = mode;
02303 QScrollView::setVScrollBarMode(mode);
02304 #else
02305 Q_UNUSED( mode );
02306 #endif
02307 }
02308
02309 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
02310 {
02311 #ifndef KHTML_NO_SCROLLBARS
02312 d->hmode = mode;
02313 QScrollView::setHScrollBarMode(mode);
02314 #else
02315 Q_UNUSED( mode );
02316 #endif
02317 }
02318
02319 void KHTMLView::restoreScrollBar()
02320 {
02321 int ow = visibleWidth();
02322 QScrollView::setVScrollBarMode(d->vmode);
02323 if (visibleWidth() != ow)
02324 layout();
02325 d->prevScrollbarVisible = verticalScrollBar()->isVisible();
02326 }
02327
02328 QStringList KHTMLView::formCompletionItems(const QString &name) const
02329 {
02330 if (!m_part->settings()->isFormCompletionEnabled())
02331 return QStringList();
02332 if (!d->formCompletions)
02333 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02334 return d->formCompletions->readListEntry(name);
02335 }
02336
02337 void KHTMLView::clearCompletionHistory(const QString& name)
02338 {
02339 if (!d->formCompletions)
02340 {
02341 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02342 }
02343 d->formCompletions->writeEntry(name, "");
02344 d->formCompletions->sync();
02345 }
02346
02347 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
02348 {
02349 if (!m_part->settings()->isFormCompletionEnabled())
02350 return;
02351
02352
02353
02354 bool cc_number(true);
02355 for (unsigned int i = 0; i < value.length(); ++i)
02356 {
02357 QChar c(value[i]);
02358 if (!c.isNumber() && c != '-' && !c.isSpace())
02359 {
02360 cc_number = false;
02361 break;
02362 }
02363 }
02364 if (cc_number)
02365 return;
02366 QStringList items = formCompletionItems(name);
02367 if (!items.contains(value))
02368 items.prepend(value);
02369 while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
02370 items.remove(items.fromLast());
02371 d->formCompletions->writeEntry(name, items);
02372 }
02373
02374 void KHTMLView::addNonPasswordStorableSite(const QString& host)
02375 {
02376 if (!d->formCompletions) {
02377 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02378 }
02379
02380 d->formCompletions->setGroup("NonPasswordStorableSites");
02381 QStringList sites = d->formCompletions->readListEntry("Sites");
02382 sites.append(host);
02383 d->formCompletions->writeEntry("Sites", sites);
02384 d->formCompletions->sync();
02385 d->formCompletions->setGroup(QString::null);
02386 }
02387
02388 bool KHTMLView::nonPasswordStorableSite(const QString& host) const
02389 {
02390 if (!d->formCompletions) {
02391 d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
02392 }
02393 d->formCompletions->setGroup("NonPasswordStorableSites");
02394 QStringList sites = d->formCompletions->readListEntry("Sites");
02395 d->formCompletions->setGroup(QString::null);
02396
02397 return (sites.find(host) != sites.end());
02398 }
02399
02400
02401 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
02402 DOM::NodeImpl *targetNodeNonShared, bool cancelable,
02403 int detail,QMouseEvent *_mouse, bool setUnder,
02404 int mouseEventType)
02405 {
02406 if (d->underMouse)
02407 d->underMouse->deref();
02408 d->underMouse = targetNode;
02409 if (d->underMouse)
02410 d->underMouse->ref();
02411
02412 if (d->underMouseNonShared)
02413 d->underMouseNonShared->deref();
02414 d->underMouseNonShared = targetNodeNonShared;
02415 if (d->underMouseNonShared)
02416 d->underMouseNonShared->ref();
02417
02418 int exceptioncode = 0;
02419 int pageX = 0;
02420 int pageY = 0;
02421 viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
02422 int clientX = pageX - contentsX();
02423 int clientY = pageY - contentsY();
02424 int screenX = _mouse->globalX();
02425 int screenY = _mouse->globalY();
02426 int button = -1;
02427 switch (_mouse->button()) {
02428 case LeftButton:
02429 button = 0;
02430 break;
02431 case MidButton:
02432 button = 1;
02433 break;
02434 case RightButton:
02435 button = 2;
02436 break;
02437 default:
02438 break;
02439 }
02440 if (d->accessKeysPreActivate && button!=-1)
02441 d->accessKeysPreActivate=false;
02442
02443 bool ctrlKey = (_mouse->state() & ControlButton);
02444 bool altKey = (_mouse->state() & AltButton);
02445 bool shiftKey = (_mouse->state() & ShiftButton);
02446 bool metaKey = (_mouse->state() & MetaButton);
02447
02448
02449 if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
02450
02451
02452
02453 NodeImpl *oldUnder = 0;
02454 if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
02455 NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
02456 m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
02457 oldUnder = mev.innerNode.handle();
02458 }
02459
02460 if (oldUnder != targetNode) {
02461
02462 if (oldUnder){
02463 oldUnder->ref();
02464 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
02465 true,true,m_part->xmlDocImpl()->defaultView(),
02466 0,screenX,screenY,clientX,clientY,pageX, pageY,
02467 ctrlKey,altKey,shiftKey,metaKey,
02468 button,targetNode);
02469 me->ref();
02470 oldUnder->dispatchEvent(me,exceptioncode,true);
02471 me->deref();
02472 }
02473
02474
02475 if (targetNode) {
02476 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
02477 true,true,m_part->xmlDocImpl()->defaultView(),
02478 0,screenX,screenY,clientX,clientY,pageX, pageY,
02479 ctrlKey,altKey,shiftKey,metaKey,
02480 button,oldUnder);
02481
02482 me->ref();
02483 targetNode->dispatchEvent(me,exceptioncode,true);
02484 me->deref();
02485 }
02486
02487 if (oldUnder)
02488 oldUnder->deref();
02489 }
02490 }
02491
02492 bool swallowEvent = false;
02493
02494 if (targetNode) {
02495
02496 bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
02497 _mouse->type() == QEvent::MouseButtonDblClick );
02498 MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
02499 true,cancelable,m_part->xmlDocImpl()->defaultView(),
02500 detail,screenX,screenY,clientX,clientY,pageX, pageY,
02501 ctrlKey,altKey,shiftKey,metaKey,
02502 button,0, _mouse, dblclick );
02503 me->ref();
02504 targetNode->dispatchEvent(me,exceptioncode,true);
02505 if (me->defaultHandled() || me->defaultPrevented())
02506 swallowEvent = true;
02507 me->deref();
02508
02509 if (eventId == EventImpl::MOUSEDOWN_EVENT) {
02510 if (targetNode->isSelectable())
02511 m_part->xmlDocImpl()->setFocusNode(targetNode);
02512 else
02513 m_part->xmlDocImpl()->setFocusNode(0);
02514 }
02515 }
02516
02517 return swallowEvent;
02518 }
02519
02520 void KHTMLView::setIgnoreWheelEvents( bool e )
02521 {
02522 d->ignoreWheelEvents = e;
02523 }
02524
02525 #ifndef QT_NO_WHEELEVENT
02526
02527 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
02528 {
02529 if (d->accessKeysPreActivate) d->accessKeysPreActivate=false;
02530
02531 if ( ( e->state() & ControlButton) == ControlButton )
02532 {
02533 emit zoomView( - e->delta() );
02534 e->accept();
02535 }
02536 else if ( ( (d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
02537 || e->delta() > 0 && contentsY() <= 0
02538 || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())
02539 && m_part->parentPart() ) {
02540 kdDebug(6000) << this << " cz " << contentsY() << " ch " << contentsHeight() << " vh " << visibleHeight() << endl;
02541 if ( m_part->parentPart()->view() )
02542 m_part->parentPart()->view()->wheelEvent( e );
02543 kdDebug(6000) << "sent" << endl;
02544 e->ignore();
02545 }
02546 else if ( d->vmode == QScrollView::AlwaysOff ) {
02547 e->accept();
02548 }
02549 else {
02550 d->scrollBarMoved = true;
02551 QScrollView::viewportWheelEvent( e );
02552
02553 QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, QPoint(-1,-1), QPoint(-1,-1), Qt::NoButton, e->state() );
02554 emit viewportMouseMoveEvent ( tempEvent );
02555 delete tempEvent;
02556 }
02557
02558 }
02559 #endif
02560
02561 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
02562 {
02563
02564
02565
02566 if ( m_part->parentPart() )
02567 {
02568 QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02569 return;
02570 }
02571 QScrollView::dragEnterEvent( ev );
02572 }
02573
02574 void KHTMLView::dropEvent( QDropEvent *ev )
02575 {
02576
02577
02578
02579 if ( m_part->parentPart() )
02580 {
02581 QApplication::sendEvent(m_part->parentPart()->widget(), ev);
02582 return;
02583 }
02584 QScrollView::dropEvent( ev );
02585 }
02586
02587 void KHTMLView::focusInEvent( QFocusEvent *e )
02588 {
02589 #ifndef KHTML_NO_CARET
02590
02591
02592 if (d->m_caretViewContext &&
02593 d->m_caretViewContext->freqTimerId == -1 &&
02594 m_part->xmlDocImpl()) {
02595 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02596 if (m_part->isCaretMode()
02597 || m_part->isEditable()
02598 || (caretNode && caretNode->renderer()
02599 && caretNode->renderer()->style()->userInput()
02600 == UI_ENABLED)) {
02601 d->m_caretViewContext->freqTimerId = startTimer(500);
02602 d->m_caretViewContext->visible = true;
02603 }
02604 }
02605 showCaret();
02606 #endif // KHTML_NO_CARET
02607 QScrollView::focusInEvent( e );
02608 }
02609
02610 void KHTMLView::focusOutEvent( QFocusEvent *e )
02611 {
02612 if(m_part) m_part->stopAutoScroll();
02613
02614 #ifndef KHTML_NO_TYPE_AHEAD_FIND
02615 if(d->typeAheadActivated)
02616 {
02617 findTimeout();
02618 }
02619 #endif // KHTML_NO_TYPE_AHEAD_FIND
02620
02621 #ifndef KHTML_NO_CARET
02622 if (d->m_caretViewContext) {
02623 switch (d->m_caretViewContext->displayNonFocused) {
02624 case KHTMLPart::CaretInvisible:
02625 hideCaret();
02626 break;
02627 case KHTMLPart::CaretVisible: {
02628 killTimer(d->m_caretViewContext->freqTimerId);
02629 d->m_caretViewContext->freqTimerId = -1;
02630 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
02631 if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
02632 || m_part->isEditable()
02633 || (caretNode && caretNode->renderer()
02634 && caretNode->renderer()->style()->userInput()
02635 == UI_ENABLED))) {
02636 d->m_caretViewContext->visible = true;
02637 showCaret(true);
02638 }
02639 break;
02640 }
02641 case KHTMLPart::CaretBlink:
02642
02643 break;
02644 }
02645 }
02646 #endif // KHTML_NO_CARET
02647 QScrollView::focusOutEvent( e );
02648 }
02649
02650 void KHTMLView::slotScrollBarMoved()
02651 {
02652 if (!d->scrollingSelf)
02653 d->scrollBarMoved = true;
02654 }
02655
02656 void KHTMLView::timerEvent ( QTimerEvent *e )
02657 {
02658
02659 if ( e->timerId() == d->scrollTimerId ) {
02660 if( d->scrollSuspended )
02661 return;
02662 switch (d->scrollDirection) {
02663 case KHTMLViewPrivate::ScrollDown:
02664 if (contentsY() + visibleHeight () >= contentsHeight())
02665 d->newScrollTimer(this, 0);
02666 else
02667 scrollBy( 0, d->scrollBy );
02668 break;
02669 case KHTMLViewPrivate::ScrollUp:
02670 if (contentsY() <= 0)
02671 d->newScrollTimer(this, 0);
02672 else
02673 scrollBy( 0, -d->scrollBy );
02674 break;
02675 case KHTMLViewPrivate::ScrollRight:
02676 if (contentsX() + visibleWidth () >= contentsWidth())
02677 d->newScrollTimer(this, 0);
02678 else
02679 scrollBy( d->scrollBy, 0 );
02680 break;
02681 case KHTMLViewPrivate::ScrollLeft:
02682 if (contentsX() <= 0)
02683 d->newScrollTimer(this, 0);
02684 else
02685 scrollBy( -d->scrollBy, 0 );
02686 break;
02687 }
02688 return;
02689 }
02690 else if ( e->timerId() == d->layoutTimerId ) {
02691 d->firstRelayout = false;
02692 d->dirtyLayout = true;
02693 layout();
02694 }
02695 #ifndef KHTML_NO_CARET
02696 else if (d->m_caretViewContext
02697 && e->timerId() == d->m_caretViewContext->freqTimerId) {
02698 d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
02699 if (d->m_caretViewContext->displayed) {
02700 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02701 d->m_caretViewContext->width,
02702 d->m_caretViewContext->height);
02703 }
02704
02705
02706 return;
02707 }
02708 #endif
02709
02710 if( m_part->xmlDocImpl() ) {
02711 DOM::DocumentImpl *document = m_part->xmlDocImpl();
02712 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
02713
02714 if ( root && !root->layouted() ) {
02715 killTimer(d->repaintTimerId);
02716 d->repaintTimerId = 0;
02717 scheduleRelayout();
02718 return;
02719 }
02720 }
02721
02722 setStaticBackground(d->useSlowRepaints);
02723
02724
02725 killTimer(d->repaintTimerId);
02726 d->repaintTimerId = 0;
02727
02728 QRegion updateRegion;
02729 QMemArray<QRect> rects = d->updateRegion.rects();
02730
02731 d->updateRegion = QRegion();
02732
02733 if ( rects.size() )
02734 updateRegion = rects[0];
02735
02736 for ( unsigned i = 1; i < rects.size(); ++i ) {
02737 QRect obR = updateRegion.boundingRect();
02738 QRegion newRegion = updateRegion.unite(rects[i]);
02739 if (2*newRegion.boundingRect().height() > 3*obR.height() )
02740 {
02741 repaintContents( obR );
02742 updateRegion = rects[i];
02743 }
02744 else
02745 updateRegion = newRegion;
02746 }
02747
02748 if ( !updateRegion.isNull() )
02749 repaintContents( updateRegion.boundingRect() );
02750
02751 if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
02752 QWidget* w;
02753 d->dirtyLayout = false;
02754
02755 QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02756 QPtrList<RenderWidget> toRemove;
02757 for (QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
02758 int xp = 0, yp = 0;
02759 w = it.current();
02760 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
02761 if (!rw->absolutePosition(xp, yp) ||
02762 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
02763 toRemove.append(rw);
02764 }
02765 for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
02766 if ( (w = d->visibleWidgets.take(r) ) )
02767 addChild(w, 0, -500000);
02768 }
02769 if (d->accessKeysActivated) emit repaintAccessKeys();
02770 }
02771
02772 void KHTMLView::scheduleRelayout(khtml::RenderObject * )
02773 {
02774 if (!d->layoutSchedulingEnabled || d->layoutTimerId)
02775 return;
02776
02777 d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
02778 ? 1000 : 0 );
02779 }
02780
02781 void KHTMLView::unscheduleRelayout()
02782 {
02783 if (!d->layoutTimerId)
02784 return;
02785
02786 killTimer(d->layoutTimerId);
02787 d->layoutTimerId = 0;
02788 }
02789
02790 void KHTMLView::unscheduleRepaint()
02791 {
02792 if (!d->repaintTimerId)
02793 return;
02794
02795 killTimer(d->repaintTimerId);
02796 d->repaintTimerId = 0;
02797 }
02798
02799 void KHTMLView::scheduleRepaint(int x, int y, int w, int h)
02800 {
02801 bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
02802
02803
02804
02805
02806 int time = parsing ? 300 : ( !d->complete ? 100 : 20 );
02807
02808 #ifdef DEBUG_FLICKER
02809 QPainter p;
02810 p.begin( viewport() );
02811
02812 int vx, vy;
02813 contentsToViewport( x, y, vx, vy );
02814 p.fillRect( vx, vy, w, h, Qt::red );
02815 p.end();
02816 #endif
02817
02818 d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
02819
02820 if ( !d->repaintTimerId )
02821 d->repaintTimerId = startTimer( time );
02822
02823
02824 }
02825
02826 void KHTMLView::complete()
02827 {
02828
02829
02830 d->complete = true;
02831
02832
02833 if (d->layoutTimerId)
02834 {
02835
02836
02837 killTimer(d->layoutTimerId);
02838 d->layoutTimerId = startTimer( 0 );
02839 }
02840
02841
02842 if (d->repaintTimerId)
02843 {
02844
02845
02846 killTimer(d->repaintTimerId);
02847 d->repaintTimerId = startTimer( 20 );
02848 }
02849 }
02850
02851 #ifndef KHTML_NO_CARET
02852
02853
02854
02855
02856 #include "khtml_caret.cpp"
02857
02858 void KHTMLView::initCaret(bool keepSelection)
02859 {
02860 #if DEBUG_CARETMODE > 0
02861 kdDebug(6200) << "begin initCaret" << endl;
02862 #endif
02863
02864 if (m_part->xmlDocImpl()) {
02865 #if 0
02866 ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
02867 if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
02868 #endif
02869 d->caretViewContext();
02870 bool cmoved = d->m_caretViewContext->caretMoved;
02871 if (m_part->d->caretNode().isNull()) {
02872
02873 m_part->d->caretNode() = m_part->document();
02874 m_part->d->caretOffset() = 0L;
02875
02876
02877
02878 if (!m_part->d->caretNode().handle()->renderer()) return;
02879 }
02880
02881
02882
02883 moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
02884
02885
02886 d->m_caretViewContext->caretMoved = cmoved;
02887 }
02888 #if DEBUG_CARETMODE > 0
02889 kdDebug(6200) << "end initCaret" << endl;
02890 #endif
02891 }
02892
02893 bool KHTMLView::caretOverrides() const
02894 {
02895 bool cm = m_part->isCaretMode();
02896 bool dm = m_part->isEditable();
02897 return cm && !dm ? false
02898 : (dm || m_part->d->caretNode().handle()->contentEditable())
02899 && d->editorContext()->override;
02900 }
02901
02902 void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
02903 {
02904 if (m_part->isCaretMode() || m_part->isEditable()) return;
02905 if (node->focused()) return;
02906
02907
02908 NodeImpl *firstAncestor = 0;
02909 while (node) {
02910 if (node->renderer()
02911 && node->renderer()->style()->userInput() != UI_ENABLED)
02912 break;
02913 firstAncestor = node;
02914 node = node->parentNode();
02915 }
02916
02917 if (!node) firstAncestor = 0;
02918
02919 DocumentImpl *doc = m_part->xmlDocImpl();
02920
02921 if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
02922 && doc->focusNode()->renderer()->isWidget())
02923 return;
02924
02925
02926 #if DEBUG_CARETMODE > 1
02927 kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
02928 << (firstAncestor ? firstAncestor->nodeName().string() : QString::null) << endl;
02929 #endif
02930 doc->setFocusNode(firstAncestor);
02931 emit m_part->nodeActivated(Node(firstAncestor));
02932 }
02933
02934 void KHTMLView::recalcAndStoreCaretPos(CaretBox *hintBox)
02935 {
02936 if (!m_part || m_part->d->caretNode().isNull()) return;
02937 d->caretViewContext();
02938 NodeImpl *caretNode = m_part->d->caretNode().handle();
02939 #if DEBUG_CARETMODE > 0
02940 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;
02941 #endif
02942 caretNode->getCaret(m_part->d->caretOffset(), caretOverrides(),
02943 d->m_caretViewContext->x, d->m_caretViewContext->y,
02944 d->m_caretViewContext->width,
02945 d->m_caretViewContext->height);
02946
02947 if (hintBox && d->m_caretViewContext->x == -1) {
02948 #if DEBUG_CARETMODE > 1
02949 kdDebug(6200) << "using hint inline box coordinates" << endl;
02950 #endif
02951 RenderObject *r = caretNode->renderer();
02952 const QFontMetrics &fm = r->style()->fontMetrics();
02953 int absx, absy;
02954 r->containingBlock()->absolutePosition(absx, absy,
02955 false);
02956 d->m_caretViewContext->x = absx + hintBox->xPos();
02957 d->m_caretViewContext->y = absy + hintBox->yPos();
02958
02959 d->m_caretViewContext->width = 1;
02960
02961
02962 d->m_caretViewContext->height = fm.height();
02963 }
02964
02965 #if DEBUG_CARETMODE > 4
02966
02967 #endif
02968 #if DEBUG_CARETMODE > 0
02969 kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
02970 <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
02971 <<" h="<<d->m_caretViewContext->height<<endl;
02972 #endif
02973 }
02974
02975 void KHTMLView::caretOn()
02976 {
02977 if (d->m_caretViewContext) {
02978 killTimer(d->m_caretViewContext->freqTimerId);
02979
02980 if (hasFocus() || d->m_caretViewContext->displayNonFocused
02981 == KHTMLPart::CaretBlink) {
02982 d->m_caretViewContext->freqTimerId = startTimer(500);
02983 } else {
02984 d->m_caretViewContext->freqTimerId = -1;
02985 }
02986
02987 d->m_caretViewContext->visible = true;
02988 if ((d->m_caretViewContext->displayed = (hasFocus()
02989 || d->m_caretViewContext->displayNonFocused
02990 != KHTMLPart::CaretInvisible))) {
02991 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02992 d->m_caretViewContext->width,
02993 d->m_caretViewContext->height);
02994 }
02995
02996 }
02997 }
02998
02999 void KHTMLView::caretOff()
03000 {
03001 if (d->m_caretViewContext) {
03002 killTimer(d->m_caretViewContext->freqTimerId);
03003 d->m_caretViewContext->freqTimerId = -1;
03004 d->m_caretViewContext->displayed = false;
03005 if (d->m_caretViewContext->visible) {
03006 d->m_caretViewContext->visible = false;
03007 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03008 d->m_caretViewContext->width,
03009 d->m_caretViewContext->height);
03010 }
03011
03012 }
03013 }
03014
03015 void KHTMLView::showCaret(bool forceRepaint)
03016 {
03017 if (d->m_caretViewContext) {
03018 d->m_caretViewContext->displayed = true;
03019 if (d->m_caretViewContext->visible) {
03020 if (!forceRepaint) {
03021 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03022 d->m_caretViewContext->width,
03023 d->m_caretViewContext->height);
03024 } else {
03025 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03026 d->m_caretViewContext->width,
03027 d->m_caretViewContext->height);
03028 }
03029 }
03030
03031 }
03032 }
03033
03034 bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
03035 NodeImpl *endNode, long endOffset)
03036 {
03037 m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
03038 m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
03039 m_part->d->m_extendAtEnd = true;
03040
03041 bool folded = startNode != endNode || startOffset != endOffset;
03042
03043
03044 if (folded) {
03045 m_part->xmlDocImpl()->clearSelection();
03046 }
03047
03048 return folded;
03049 }
03050
03051 void KHTMLView::hideCaret()
03052 {
03053 if (d->m_caretViewContext) {
03054 if (d->m_caretViewContext->visible) {
03055
03056 d->m_caretViewContext->visible = false;
03057
03058
03059 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
03060 d->m_caretViewContext->width,
03061 d->m_caretViewContext->height);
03062 d->m_caretViewContext->visible = true;
03063 }
03064 d->m_caretViewContext->displayed = false;
03065
03066 }
03067 }
03068
03069 int KHTMLView::caretDisplayPolicyNonFocused() const
03070 {
03071 if (d->m_caretViewContext)
03072 return d->m_caretViewContext->displayNonFocused;
03073 else
03074 return KHTMLPart::CaretInvisible;
03075 }
03076
03077 void KHTMLView::setCaretDisplayPolicyNonFocused(int policy)
03078 {
03079 d->caretViewContext();
03080
03081 d->m_caretViewContext->displayNonFocused = (KHTMLPart::CaretDisplayPolicy)policy;
03082
03083
03084 if (!hasFocus()) {
03085 switch (d->m_caretViewContext->displayNonFocused) {
03086 case KHTMLPart::CaretInvisible:
03087 hideCaret();
03088 break;
03089 case KHTMLPart::CaretBlink:
03090 if (d->m_caretViewContext->freqTimerId != -1) break;
03091 d->m_caretViewContext->freqTimerId = startTimer(500);
03092
03093 case KHTMLPart::CaretVisible:
03094 d->m_caretViewContext->displayed = true;
03095 showCaret();
03096 break;
03097 }
03098 }
03099 }
03100
03101 bool KHTMLView::placeCaret(CaretBox *hintBox)
03102 {
03103 CaretViewContext *cv = d->caretViewContext();
03104 caretOff();
03105 NodeImpl *caretNode = m_part->d->caretNode().handle();
03106
03107 if (!caretNode || !caretNode->renderer()) return false;
03108 ensureNodeHasFocus(caretNode);
03109 if (m_part->isCaretMode() || m_part->isEditable()
03110 || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
03111 recalcAndStoreCaretPos(hintBox);
03112
03113 cv->origX = cv->x;
03114
03115 caretOn();
03116 return true;
03117 }
03118 return false;
03119 }
03120
03121 void KHTMLView::ensureCaretVisible()
03122 {
03123 CaretViewContext *cv = d->m_caretViewContext;
03124 if (!cv) return;
03125 ensureVisible(cv->x, cv->y, cv->width, cv->height);
03126 d->scrollBarMoved = false;
03127 }
03128
03129 bool KHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
03130 NodeImpl *oldEndSel, long oldEndOfs)
03131 {
03132 bool changed = false;
03133 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
03134 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
03135 changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03136 m_part->d->m_extendAtEnd = true;
03137 } else do {
03138 changed = m_part->d->m_selectionStart.handle() != oldStartSel
03139 || m_part->d->m_startOffset != oldStartOfs
03140 || m_part->d->m_selectionEnd.handle() != oldEndSel
03141 || m_part->d->m_endOffset != oldEndOfs;
03142 if (!changed) break;
03143
03144
03145 NodeImpl *startNode;
03146 long startOffset;
03147 if (m_part->d->m_extendAtEnd) {
03148 startNode = m_part->d->m_selectionStart.handle();
03149 startOffset = m_part->d->m_startOffset;
03150 } else {
03151 startNode = m_part->d->m_selectionEnd.handle();
03152 startOffset = m_part->d->m_endOffset;
03153 m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
03154 m_part->d->m_endOffset = m_part->d->m_startOffset;
03155 m_part->d->m_extendAtEnd = true;
03156 }
03157
03158 bool swapNeeded = false;
03159 if (!m_part->d->m_selectionEnd.isNull() && startNode) {
03160 swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
03161 m_part->d->m_selectionEnd.handle(),
03162 m_part->d->m_endOffset) >= 0;
03163 }
03164
03165 m_part->d->m_selectionStart = startNode;
03166 m_part->d->m_startOffset = startOffset;
03167
03168 if (swapNeeded) {
03169 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
03170 m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
03171 m_part->d->m_startOffset);
03172 } else {
03173 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
03174 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
03175 m_part->d->m_endOffset);
03176 }
03177 } while(false);
03178 return changed;
03179 }
03180
03181 void KHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
03182 NodeImpl *oldEndSel, long oldEndOfs)
03183 {
03184 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
03185 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
03186 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
03187 m_part->emitSelectionChanged();
03188 }
03189 m_part->d->m_extendAtEnd = true;
03190 } else {
03191
03192 if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
03193 bool swapNeeded = RangeImpl::compareBoundaryPoints(
03194 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
03195 m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
03196 if (swapNeeded) {
03197 DOM::Node tmpNode = m_part->d->m_selectionStart;
03198 long tmpOffset = m_part->d->m_startOffset;
03199 m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
03200 m_part->d->m_startOffset = m_part->d->m_endOffset;
03201 m_part->d->m_selectionEnd = tmpNode;
03202 m_part->d->m_endOffset = tmpOffset;
03203 m_part->d->m_startBeforeEnd = true;
03204 m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
03205 }
03206 }
03207
03208 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
03209 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
03210 m_part->d->m_endOffset);
03211 m_part->emitSelectionChanged();
03212 }
03213 }
03214
03215 void KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
03216 {
03217 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
03218 long oldStartOfs = m_part->d->m_startOffset;
03219 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
03220 long oldEndOfs = m_part->d->m_endOffset;
03221
03222 NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
03223 long oldOffset = m_part->d->caretOffset();
03224
03225 bool ctrl = _ke->state() & ControlButton;
03226
03227
03228 switch(_ke->key()) {
03229 case Key_Space:
03230 break;
03231
03232 case Key_Down:
03233 moveCaretNextLine(1);
03234 break;
03235
03236 case Key_Up:
03237 moveCaretPrevLine(1);
03238 break;
03239
03240 case Key_Left:
03241 moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
03242 break;
03243
03244 case Key_Right:
03245 moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
03246 break;
03247
03248 case Key_Next:
03249 moveCaretNextPage();
03250 break;
03251
03252 case Key_Prior:
03253 moveCaretPrevPage();
03254 break;
03255
03256 case Key_Home:
03257 if (ctrl)
03258 moveCaretToDocumentBoundary(false);
03259 else
03260 moveCaretToLineBegin();
03261 break;
03262
03263 case Key_End:
03264 if (ctrl)
03265 moveCaretToDocumentBoundary(true);
03266 else
03267 moveCaretToLineEnd();
03268 break;
03269
03270 }
03271
03272 if ((m_part->d->caretNode().handle() != oldCaretNode
03273 || m_part->d->caretOffset() != oldOffset)
03274
03275 && !m_part->d->caretNode().isNull()) {
03276
03277 d->m_caretViewContext->caretMoved = true;
03278
03279 if (_ke->state() & ShiftButton) {
03280 updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03281 } else {
03282 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
03283 m_part->emitSelectionChanged();
03284 }
03285
03286 m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
03287 }
03288
03289 _ke->accept();
03290 }
03291
03292 bool KHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
03293 {
03294 if (!node) return false;
03295 ElementImpl *baseElem = determineBaseElement(node);
03296 RenderFlow *base = static_cast<RenderFlow *>(baseElem ? baseElem->renderer() : 0);
03297 if (!node) return false;
03298
03299
03300
03301
03302 CaretBoxLineDeleter cblDeleter;
03303
03304 long r_ofs;
03305 CaretBoxIterator cbit;
03306 CaretBoxLine *cbl = findCaretBoxLine(node, offset, &cblDeleter, base, r_ofs, cbit);
03307 if(!cbl) {
03308 kdWarning() << "KHTMLView::moveCaretTo - findCaretBoxLine() returns NULL" << endl;
03309 return false;
03310 }
03311
03312 #if DEBUG_CARETMODE > 3
03313 if (cbl) kdDebug(6200) << cbl->information() << endl;
03314 #endif
03315 CaretBox *box = *cbit;
03316 if (cbit != cbl->end() && box->object() != node->renderer()) {
03317 if (box->object()->element()) {
03318 mapRenderPosToDOMPos(box->object(), r_ofs, box->isOutside(),
03319 box->isOutsideEnd(), node, offset);
03320
03321 #if DEBUG_CARETMODE > 1
03322 kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
03323 #endif
03324 } else {
03325
03326 box = 0;
03327 kdError(6200) << "Box contains no node! Crash imminent" << endl;
03328 }
03329 }
03330
03331 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
03332 long oldStartOfs = m_part->d->m_startOffset;
03333 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
03334 long oldEndOfs = m_part->d->m_endOffset;
03335
03336
03337 bool posChanged = m_part->d->caretNode().handle() != node
03338 || m_part->d->caretOffset() != offset;
03339 bool selChanged = false;
03340
03341 m_part->d->caretNode() = node;
03342 m_part->d->caretOffset() = offset;
03343 if (clearSel || !oldStartSel || !oldEndSel) {
03344 selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03345 } else {
03346
03347
03348 selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
03349
03350
03351 }
03352
03353 d->caretViewContext()->caretMoved = true;
03354
03355 bool visible_caret = placeCaret(box);
03356
03357
03358
03359
03360 if (posChanged) {
03361 m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
03362 }
03363
03364 return selChanged;
03365 }
03366
03367 void KHTMLView::moveCaretByLine(bool next, int count)
03368 {
03369 Node &caretNodeRef = m_part->d->caretNode();
03370 if (caretNodeRef.isNull()) return;
03371
03372 NodeImpl *caretNode = caretNodeRef.handle();
03373
03374 long offset = m_part->d->caretOffset();
03375
03376 CaretViewContext *cv = d->caretViewContext();
03377
03378 ElementImpl *baseElem = determineBaseElement(caretNode);
03379 LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
03380
03381 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03382
03383
03384 while (count > 0 && it != ld.end() && it != ld.preBegin()) {
03385 count--;
03386 if (next) ++it; else --it;
03387 }
03388
03389
03390 if (it == ld.end() || it == ld.preBegin()) return;
03391
03392 int x, absx, absy;
03393 CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
03394
03395 placeCaretOnLine(caretBox, x, absx, absy);
03396 }
03397
03398 void KHTMLView::placeCaretOnLine(CaretBox *caretBox, int x, int absx, int absy)
03399 {
03400
03401 if (!caretBox) return;
03402
03403 RenderObject *caretRender = caretBox->object();
03404
03405 #if DEBUG_CARETMODE > 0
03406 kdDebug(6200) << "got valid caretBox " << caretBox << endl;
03407 kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
03408 << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
03409 InlineTextBox *tb = static_cast<InlineTextBox *>(caretBox->inlineBox());
03410 if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << QString(static_cast<RenderText *>(tb->object())->str->s + tb->m_start, tb->m_len) << "\"" << endl;}
03411 #endif
03412
03413 int caretHeight = caretBox->height();
03414 bool isText = caretBox->isInlineTextBox();
03415 int yOfs = 0;
03416 if (isText) {
03417
03418 RenderText *t = static_cast<RenderText *>(caretRender);
03419 const QFontMetrics &fm = t->metrics(caretBox->inlineBox()->m_firstLine);
03420 caretHeight = fm.height();
03421 yOfs = caretBox->inlineBox()->baseline() - fm.ascent();
03422 }
03423
03424 caretOff();
03425
03426
03427 NodeImpl *caretNode;
03428 long &offset = m_part->d->caretOffset();
03429 mapRenderPosToDOMPos(caretRender, offset, caretBox->isOutside(),
03430 caretBox->isOutsideEnd(), caretNode, offset);
03431
03432
03433 d->m_caretViewContext->y = caretBox->yPos() + yOfs;
03434 d->m_caretViewContext->height = caretHeight;
03435 d->m_caretViewContext->width = 1;
03436
03437 int xPos = caretBox->xPos();
03438 int caretBoxWidth = caretBox->width();
03439 d->m_caretViewContext->x = xPos;
03440
03441 if (!caretBox->isOutside()) {
03442
03443 long r_ofs = 0;
03444 if (x <= xPos) {
03445 r_ofs = caretBox->minOffset();
03446
03447 } else if (x > xPos && x <= xPos + caretBoxWidth) {
03448 if (isText) {
03449 r_ofs = static_cast<InlineTextBox *>(caretBox->inlineBox())
03450 ->offsetForPoint(x, d->m_caretViewContext->x);
03451 #if DEBUG_CARETMODE > 2
03452 kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
03453 #endif
03454 #if 0
03455 } else {
03456 if (xPos + caretBoxWidth - x < x - xPos) {
03457 d->m_caretViewContext->x = xPos + caretBoxWidth;
03458 r_ofs = caretNode ? caretNode->maxOffset() : 1;
03459 } else {
03460 d->m_caretViewContext->x = xPos;
03461 r_ofs = caretNode ? caretNode->minOffset() : 0;
03462 }
03463 #endif
03464 }
03465 } else {
03466 d->m_caretViewContext->x = xPos + caretBoxWidth;
03467 r_ofs = caretBox->maxOffset();
03468 }
03469 offset = r_ofs;
03470 }
03471 #if DEBUG_CARETMODE > 0
03472 kdDebug(6200) << "new offset: " << offset << endl;
03473 #endif
03474
03475 m_part->d->caretNode() = caretNode;
03476 m_part->d->caretOffset() = offset;
03477
03478 d->m_caretViewContext->x += absx;
03479 d->m_caretViewContext->y += absy;
03480
03481 #if DEBUG_CARETMODE > 1
03482 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;
03483 #endif
03484
03485 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03486 d->m_caretViewContext->width, d->m_caretViewContext->height);
03487 d->scrollBarMoved = false;
03488
03489 ensureNodeHasFocus(caretNode);
03490 caretOn();
03491 }
03492
03493 void KHTMLView::moveCaretToLineBoundary(bool end)
03494 {
03495 Node &caretNodeRef = m_part->d->caretNode();
03496 if (caretNodeRef.isNull()) return;
03497
03498 NodeImpl *caretNode = caretNodeRef.handle();
03499
03500 long offset = m_part->d->caretOffset();
03501
03502 ElementImpl *baseElem = determineBaseElement(caretNode);
03503 LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
03504
03505 EditableLineIterator it = ld.current();
03506 if (it == ld.end()) return;
03507
03508 EditableCaretBoxIterator fbit(it, end);
03509 Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
03510 CaretBox *b = *fbit;
03511
03512 RenderObject *cb = b->containingBlock();
03513 int absx, absy;
03514
03515 if (cb) cb->absolutePosition(absx,absy);
03516 else absx = absy = 0;
03517
03518 int x = b->xPos() + (end && !b->isOutside() ? b->width() : 0);
03519 d->m_caretViewContext->origX = absx + x;
03520 placeCaretOnLine(b, x, absx, absy);
03521 }
03522
03523 void KHTMLView::moveCaretToDocumentBoundary(bool end)
03524 {
03525 Node &caretNodeRef = m_part->d->caretNode();
03526 if (caretNodeRef.isNull()) return;
03527
03528 NodeImpl *caretNode = caretNodeRef.handle();
03529
03530 long offset = m_part->d->caretOffset();
03531
03532 ElementImpl *baseElem = determineBaseElement(caretNode);
03533 LinearDocument ld(m_part, caretNode, offset, IndicatedFlows, baseElem);
03534
03535 EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
03536 if (it == ld.end() || it == ld.preBegin()) return;
03537
03538 EditableCaretBoxIterator fbit = it;
03539 Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
03540 CaretBox *b = *fbit;
03541
03542 RenderObject *cb = (*it)->containingBlock();
03543 int absx, absy;
03544
03545 if (cb) cb->absolutePosition(absx, absy);
03546 else absx = absy = 0;
03547
03548 int x = b->xPos();
03549 d->m_caretViewContext->origX = absx + x;
03550 placeCaretOnLine(b, x, absx, absy);
03551 }
03552
03553 void KHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
03554 {
03555 if (!m_part) return;
03556 Node &caretNodeRef = m_part->d->caretNode();
03557 if (caretNodeRef.isNull()) return;
03558
03559 NodeImpl *caretNode = caretNodeRef.handle();
03560
03561 long &offset = m_part->d->caretOffset();
03562
03563 ElementImpl *baseElem = determineBaseElement(caretNode);
03564 CaretAdvancePolicy advpol = cmv != CaretByWord ? IndicatedFlows : LeafsOnly;
03565 LinearDocument ld(m_part, caretNode, offset, advpol, baseElem);
03566
03567 EditableCharacterIterator it(&ld);
03568 while (!it.isEnd() && count > 0) {
03569 count--;
03570 if (cmv == CaretByCharacter) {
03571 if (next) ++it;
03572 else --it;
03573 } else if (cmv == CaretByWord) {
03574 if (next) moveItToNextWord(it);
03575 else moveItToPrevWord(it);
03576 }
03577
03578 }
03579 CaretBox *hintBox = 0;
03580 if (!it.isEnd()) {
03581 NodeImpl *node = caretNodeRef.handle();
03582 hintBox = it.caretBox();
03583
03584
03585 mapRenderPosToDOMPos(it.renderer(), it.offset(), hintBox->isOutside(),
03586 hintBox->isOutsideEnd(), node, offset);
03587
03588 caretNodeRef = node;
03589 #if DEBUG_CARETMODE > 2
03590 kdDebug(6200) << "set by valid node " << node << " " << (node?node->nodeName().string():QString::null) << " offset: " << offset << endl;
03591 #endif
03592 } else {
03593 offset = next ? caretNode->maxOffset() : caretNode->minOffset();
03594 #if DEBUG_CARETMODE > 0
03595 kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
03596 #endif
03597 }
03598 placeCaretOnChar(hintBox);
03599 }
03600
03601 void KHTMLView::placeCaretOnChar(CaretBox *hintBox)
03602 {
03603 caretOff();
03604 recalcAndStoreCaretPos(hintBox);
03605 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03606 d->m_caretViewContext->width, d->m_caretViewContext->height);
03607 d->m_caretViewContext->origX = d->m_caretViewContext->x;
03608 d->scrollBarMoved = false;
03609 #if DEBUG_CARETMODE > 3
03610
03611 #endif
03612 ensureNodeHasFocus(m_part->d->caretNode().handle());
03613 caretOn();
03614 }
03615
03616 void KHTMLView::moveCaretByPage(bool next)
03617 {
03618 Node &caretNodeRef = m_part->d->caretNode();
03619
03620 NodeImpl *caretNode = caretNodeRef.handle();
03621
03622 long offset = m_part->d->caretOffset();
03623
03624 int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
03625
03626 int mindist = clipper()->height() - offs;
03627
03628 CaretViewContext *cv = d->caretViewContext();
03629
03630
03631 ElementImpl *baseElem = determineBaseElement(caretNode);
03632 LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
03633
03634 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03635
03636 moveIteratorByPage(ld, it, mindist, next);
03637
03638 int x, absx, absy;
03639 CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
03640
03641 placeCaretOnLine(caretBox, x, absx, absy);
03642 }
03643
03644 void KHTMLView::moveCaretPrevWord()
03645 {
03646 moveCaretBy(false, CaretByWord, 1);
03647 }
03648
03649 void KHTMLView::moveCaretNextWord()
03650 {
03651 moveCaretBy(true, CaretByWord, 1);
03652 }
03653
03654 void KHTMLView::moveCaretPrevLine(int n)
03655 {
03656 moveCaretByLine(false, n);
03657 }
03658
03659 void KHTMLView::moveCaretNextLine(int n)
03660 {
03661 moveCaretByLine(true, n);
03662 }
03663
03664 void KHTMLView::moveCaretPrevPage()
03665 {
03666 moveCaretByPage(false);
03667 }
03668
03669 void KHTMLView::moveCaretNextPage()
03670 {
03671 moveCaretByPage(true);
03672 }
03673
03674 void KHTMLView::moveCaretToLineBegin()
03675 {
03676 moveCaretToLineBoundary(false);
03677 }
03678
03679 void KHTMLView::moveCaretToLineEnd()
03680 {
03681 moveCaretToLineBoundary(true);
03682 }
03683
03684 #endif // KHTML_NO_CARET
03685
03686 #undef DEBUG_CARETMODE