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