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