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