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