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