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