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