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