1 /* This file is part of the KDE project
3 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 * 1999 Lars Knoll <knoll@kde.org>
5 * 1999 Antti Koivisto <koivisto@kde.org>
6 * 2000-2004 Dirk Mueller <mueller@kde.org>
7 * 2003 Leo Savernik <l.savernik@aon.at>
8 * 2003-2008 Apple Computer, Inc.
9 * 2008 Allan Sandfeld Jensen <kde@carewolf.com>
10 * 2006-2008 Germain Garand <germain@ebooksfrance.org>
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
29 #include "khtmlview.h"
31 #include "khtmlview.moc"
33 #include "khtml_part.h"
34 #include "khtml_events.h"
36 #include <qx11info_x11.h>
39 #include "html/html_documentimpl.h"
40 #include "html/html_inlineimpl.h"
41 #include "html/html_formimpl.h"
42 #include "html/htmltokenizer.h"
43 #include "editing/editor.h"
44 #include "rendering/render_arena.h"
45 #include "rendering/render_canvas.h"
46 #include "rendering/render_frames.h"
47 #include "rendering/render_replaced.h"
48 #include "rendering/render_form.h"
49 #include "rendering/render_layer.h"
50 #include "rendering/render_line.h"
51 #include "rendering/render_table.h"
53 #define protected public
54 #include "rendering/render_text.h"
56 #include "xml/dom2_eventsimpl.h"
57 #include "css/cssstyleselector.h"
58 #include "css/csshelper.h"
59 #include "misc/htmlhashes.h"
60 #include "misc/helper.h"
61 #include "misc/loader.h"
62 #include "khtml_settings.h"
63 #include "khtml_printsettings.h"
65 #include "khtmlpart_p.h"
69 #include <kglobalsettings.h>
71 #include <kiconloader.h>
73 #include <knotification.h>
74 #include <kdeprintdialog.h>
76 #include <kstandarddirs.h>
77 #include <kstandardshortcut.h>
78 #include <kstringhandler.h>
79 #include <kconfiggroup.h>
81 #include <QtGui/QBitmap>
82 #include <QtGui/QLabel>
83 #include <QtCore/QObject>
84 #include <QtGui/QPainter>
85 #include <QtCore/QHash>
86 #include <QtGui/QToolTip>
87 #include <QtCore/QString>
88 #include <QtGui/QTextDocument>
89 #include <QtCore/QTimer>
90 #include <QtCore/QAbstractEventDispatcher>
91 #include <QtCore/QVector>
92 #include <QtGui/QAbstractScrollArea>
93 #include <QtGui/QPrinter>
94 #include <QtGui/QPrintDialog>
96 //#define DEBUG_FLICKER
100 #include <X11/Xlib.h>
102 #elif defined(Q_WS_WIN)
108 void dumpLineBoxes(RenderFlow
*flow
);
113 using namespace khtml
;
116 static const int sFirstLayoutDelay
= 760;
117 static const int sParsingLayoutsInterval
= 420;
118 static const int sLayoutAttemptDelay
= 400;
120 static const int sFirstLayoutDelay
= 540;
121 static const int sParsingLayoutsInterval
= 360;
122 static const int sLayoutAttemptDelay
= 340;
124 static const int sLayoutAttemptIncrement
= 20;
125 static const int sParsingLayoutsIncrement
= 60;
127 static const int sSmoothScrollTime
= 140;
128 static const int sSmoothScrollTick
= 14;
129 static const int sSmoothScrollMinStaticPixels
= 320*200;
131 class KHTMLViewPrivate
{
132 friend class KHTMLView
;
135 enum PseudoFocusNodes
{
141 enum StaticBackgroundState
{
147 enum CompletedState
{
153 KHTMLViewPrivate(KHTMLView
* v
)
154 : underMouse( 0 ), underMouseNonShared( 0 ), oldUnderMouse( 0 )
156 postponed_autorepeat
= NULL
;
157 scrollingFromWheelTimerId
= 0;
158 smoothScrollMode
= KHTMLView::SSMWhenEfficient
;
160 vpolicy
= Qt::ScrollBarAsNeeded
;
161 hpolicy
= Qt::ScrollBarAsNeeded
;
163 prevScrollbarVisible
= true;
165 possibleTripleClick
= false;
166 emitCompletedAfterRepaint
= CSNone
;
167 cursorIconWidget
= 0;
168 cursorIconType
= KHTMLView::LINK_NORMAL
;
169 m_mouseScrollTimer
= 0;
170 m_mouseScrollIndicator
= 0;
177 delete formCompletions
;
178 delete postponed_autorepeat
;
181 if (underMouseNonShared
)
182 underMouseNonShared
->deref();
184 oldUnderMouse
->deref();
186 delete cursorIconWidget
;
187 delete m_mouseScrollTimer
;
188 delete m_mouseScrollIndicator
;
195 if (underMouseNonShared
)
196 underMouseNonShared
->deref();
197 underMouseNonShared
= 0;
199 oldUnderMouse
->deref();
202 staticWidget
= SBNone
;
203 fixedObjectsCount
= 0;
204 staticObjectsCount
= 0;
205 tabMovePending
= false;
206 lastTabbingDirection
= true;
207 pseudoFocusNode
= PFNone
;
209 #ifndef KHTML_NO_SCROLLBARS
210 //We don't turn off the toolbars here
211 //since if the user turns them
212 //off, then chances are they want them turned
213 //off always - even after a reset.
215 vpolicy
= ScrollBarAlwaysOff
;
216 hpolicy
= ScrollBarAlwaysOff
;
218 scrollBarMoved
= false;
219 contentsMoving
= false;
220 ignoreWheelEvents
= false;
221 scrollingFromWheel
= QPoint(-1,-1);
224 dx
= dy
= ddx
= ddy
= rdx
= rdy
= dddx
= dddy
= 0;
229 isDoubleClick
= false;
230 scrollingSelf
= false;
231 delete postponed_autorepeat
;
232 postponed_autorepeat
= NULL
;
236 scrollSuspended
= false;
237 scrollSuspendPreActivate
= false;
238 smoothScrolling
= false;
239 smoothScrollModeIsDefault
= true;
240 shouldSmoothScroll
= false;
243 firstLayoutPending
= true;
244 firstRepaintPending
= true;
245 needsFullRepaint
= true;
247 layoutSchedulingEnabled
= true;
250 layoutAttemptCounter
= 0;
251 scheduledLayoutCounter
= 0;
252 updateRegion
= QRegion();
253 m_dialogsAllowed
= true;
254 #ifndef KHTML_NO_TYPE_AHEAD_FIND
255 typeAheadActivated
= false;
256 #endif // KHTML_NO_TYPE_AHEAD_FIND
257 accessKeysActivated
= false;
258 accessKeysPreActivate
= false;
260 // the view might have been built before the part it will be assigned to,
261 // so exceptionally, we need to directly ref/deref KHTMLGlobal to
262 // account for this transitory case.
264 accessKeysEnabled
= KHTMLGlobal::defaultHTMLSettings()->accessKeysEnabled();
265 KHTMLGlobal::deref();
267 emitCompletedAfterRepaint
= CSNone
;
268 m_mouseEventsTarget
= 0;
271 void newScrollTimer(QWidget
*view
, int tid
)
273 //kDebug(6000) << "newScrollTimer timer " << tid;
274 view
->killTimer(scrollTimerId
);
276 scrollSuspended
= false;
278 enum ScrollDirection
{ ScrollLeft
, ScrollRight
, ScrollUp
, ScrollDown
};
280 void adjustScroller(QWidget
*view
, ScrollDirection direction
, ScrollDirection oppositedir
)
282 static const struct { int msec
, pixels
; } timings
[] = {
283 {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
284 {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
286 if (!scrollTimerId
||
287 (static_cast<int>(scrollDirection
) != direction
&&
288 (static_cast<int>(scrollDirection
) != oppositedir
|| scrollSuspended
))) {
290 scrollBy
= timings
[scrollTiming
].pixels
;
291 scrollDirection
= direction
;
292 newScrollTimer(view
, view
->startTimer(timings
[scrollTiming
].msec
));
293 } else if (scrollDirection
== direction
&&
294 timings
[scrollTiming
+1].msec
&& !scrollSuspended
) {
295 scrollBy
= timings
[++scrollTiming
].pixels
;
296 newScrollTimer(view
, view
->startTimer(timings
[scrollTiming
].msec
));
297 } else if (scrollDirection
== oppositedir
) {
299 scrollBy
= timings
[--scrollTiming
].pixels
;
300 newScrollTimer(view
, view
->startTimer(timings
[scrollTiming
].msec
));
303 scrollSuspended
= false;
306 bool haveZoom() const { return zoomLevel
!= 100; }
308 void startScrolling()
310 smoothScrolling
= true;
311 smoothScrollTimer
.start(sSmoothScrollTick
);
312 shouldSmoothScroll
= false;
317 smoothScrollTimer
.stop();
323 smoothScrolling
= false;
324 shouldSmoothScroll
= false;
327 void updateContentsXY()
329 contentsX
= QApplication::isRightToLeft() ?
330 view
->horizontalScrollBar()->maximum()-view
->horizontalScrollBar()->value() : view
->horizontalScrollBar()->value();
331 contentsY
= view
->verticalScrollBar()->value();
334 void scrollExternalWidgets(int dx
, int dy
)
336 if (visibleWidgets
.isEmpty())
339 QHashIterator
<void*, QWidget
*> it(visibleWidgets
);
340 while (it
.hasNext()) {
342 it
.value()->move( it
.value()->pos() + QPoint(dx
, dy
) );
346 NodeImpl
*underMouse
;
347 NodeImpl
*underMouseNonShared
;
348 NodeImpl
*oldUnderMouse
;
350 // Do not adjust bitfield enums sizes.
351 // They are oversized because they are signed on some platforms.
352 bool tabMovePending
:1;
353 bool lastTabbingDirection
:1;
354 PseudoFocusNodes pseudoFocusNode
:3;
355 bool scrollBarMoved
:1;
356 bool contentsMoving
:1;
358 Qt::ScrollBarPolicy vpolicy
;
359 Qt::ScrollBarPolicy hpolicy
;
360 bool prevScrollbarVisible
:1;
362 bool ignoreWheelEvents
:1;
363 StaticBackgroundState staticWidget
: 3;
364 int staticObjectsCount
;
365 int fixedObjectsCount
;
368 int borderX
, borderY
;
369 int dx
, dy
, ddx
, ddy
, rdx
, rdy
, dddx
, dddy
;
370 KConfig
*formCompletions
;
372 int clickX
, clickY
, clickCount
;
378 int contentsX
, contentsY
;
380 QKeyEvent
* postponed_autorepeat
;
386 ScrollDirection scrollDirection
:3;
387 bool scrollSuspended
:1;
388 bool scrollSuspendPreActivate
:1;
389 KHTMLView::SmoothScrollingMode smoothScrollMode
:3;
390 bool smoothScrolling
:1;
391 bool smoothScrollModeIsDefault
:1;
392 bool shouldSmoothScroll
:1;
395 bool firstLayoutPending
:1;
396 bool firstRepaintPending
:1;
397 bool layoutSchedulingEnabled
:1;
398 bool needsFullRepaint
:1;
400 bool possibleTripleClick
:1;
402 bool m_dialogsAllowed
:1;
404 int layoutAttemptCounter
;
405 int scheduledLayoutCounter
;
406 QRegion updateRegion
;
407 QTimer smoothScrollTimer
;
408 QTime smoothScrollStopwatch
;
409 QHash
<void*, QWidget
*> visibleWidgets
;
410 #ifndef KHTML_NO_TYPE_AHEAD_FIND
414 bool typeAheadActivated
;
415 #endif // KHTML_NO_TYPE_AHEAD_FIND
416 bool accessKeysEnabled
;
417 bool accessKeysActivated
;
418 bool accessKeysPreActivate
;
419 CompletedState emitCompletedAfterRepaint
;
421 QLabel
* cursorIconWidget
;
422 KHTMLView::LinkCursor cursorIconType
;
424 // scrolling activated by MMB
425 short m_mouseScroll_byX
;
426 short m_mouseScroll_byY
;
427 QPoint scrollingFromWheel
;
428 int scrollingFromWheelTimerId
;
429 QTimer
*m_mouseScrollTimer
;
430 QWidget
*m_mouseScrollIndicator
;
431 QPointer
<QWidget
> m_mouseEventsTarget
;
432 QStack
<QRegion
>* m_clipHolder
;
436 #ifndef QT_NO_TOOLTIP
438 /** calculates the client-side image map rectangle for the given image element
439 * @param img image element
440 * @param scrollOfs scroll offset of viewport in content coordinates
441 * @param p position to be probed in viewport coordinates
442 * @param r returns the bounding rectangle in content coordinates
443 * @param s returns the title string
444 * @return true if an appropriate area was found -- only in this case r and
445 * s are valid, false otherwise
447 static bool findImageMapRect(HTMLImageElementImpl
*img
, const QPoint
&scrollOfs
,
448 const QPoint
&p
, QRect
&r
, QString
&s
)
450 HTMLMapElementImpl
* map
;
451 if (img
&& img
->document()->isHTMLDocument() &&
452 (map
= static_cast<HTMLDocumentImpl
*>(img
->document())->getMap(img
->imageMap()))) {
453 RenderObject::NodeInfo
info(true, false);
454 RenderObject
*rend
= img
->renderer();
456 if (!rend
|| !rend
->absolutePosition(ax
, ay
))
458 // we're a client side image map
459 bool inside
= map
->mapMouseEvent(p
.x() - ax
+ scrollOfs
.x(),
460 p
.y() - ay
+ scrollOfs
.y(), rend
->contentWidth(),
461 rend
->contentHeight(), info
);
462 if (inside
&& info
.URLElement()) {
463 HTMLAreaElementImpl
*area
= static_cast<HTMLAreaElementImpl
*>(info
.URLElement());
464 Q_ASSERT(area
->id() == ID_AREA
);
465 s
= area
->getAttribute(ATTR_TITLE
).string();
466 QRegion reg
= area
->cachedRegion();
467 if (!s
.isEmpty() && !reg
.isEmpty()) {
468 r
= reg
.boundingRect();
477 bool KHTMLView::event( QEvent
* e
)
479 switch ( e
->type() ) {
480 case QEvent::ToolTip
: {
481 QHelpEvent
*he
= static_cast<QHelpEvent
*>(e
);
482 QPoint p
= he
->pos();
484 DOM::NodeImpl
*node
= d
->underMouseNonShared
;
487 if ( node
->isElementNode() ) {
488 DOM::ElementImpl
*e
= static_cast<DOM::ElementImpl
*>( node
);
492 // for images, check if it is part of a client-side image map,
493 // and query the <area>s' title attributes, too
494 if (e
->id() == ID_IMG
&& !e
->getAttribute( ATTR_USEMAP
).isEmpty()) {
495 found
= findImageMapRect(static_cast<HTMLImageElementImpl
*>(e
),
496 viewportToContents(QPoint(0, 0)), p
, r
, s
);
499 s
= e
->getAttribute( ATTR_TITLE
).string();
502 region
|= QRect( contentsToViewport( r
.topLeft() ), r
.size() );
503 if ( !s
.isEmpty() ) {
504 QToolTip::showText( viewport()->mapToGlobal(region
.bottomLeft()),
505 Qt::convertFromPlainText( s
, Qt::WhiteSpaceNormal
) );
509 node
= node
->parentNode();
514 case QEvent::DragEnter
:
515 case QEvent::DragMove
:
516 case QEvent::DragLeave
:
518 // In Qt4, one needs to both call accept() on the DND event and return
519 // true on ::event for the candidate widget for the drop to be possible.
520 // Apps hosting us, such as konq, can do the former but not the later.
521 // We will do the second bit, as it's a no-op unless someone else explicitly
522 // accepts the event. We need to skip the scrollarea to do that,
523 // since it will just skip the events, both killing the drop, and
524 // not permitting us to forward it up the part hiearchy in our dragEnterEvent,
526 return QWidget::event(e
);
527 case QEvent::StyleChange
:
528 case QEvent::LayoutRequest
: {
530 return QAbstractScrollArea::event(e
);
532 case QEvent::PaletteChange
:
533 slotPaletteChanged();
534 return QScrollArea::event(e
);
536 return QScrollArea::event(e
);
541 KHTMLView::KHTMLView( KHTMLPart
*part
, QWidget
*parent
)
542 : QScrollArea( parent
), d( new KHTMLViewPrivate( this ) )
548 QScrollArea::setVerticalScrollBarPolicy(d
->vpolicy
);
549 QScrollArea::setHorizontalScrollBarPolicy(d
->hpolicy
);
551 #ifndef KHTML_NO_TYPE_AHEAD_FIND
552 connect(&d
->timer
, SIGNAL(timeout()), this, SLOT(findTimeout()));
553 #endif // KHTML_NO_TYPE_AHEAD_FIND
556 widget()->setMouseTracking(true);
559 KHTMLView::~KHTMLView()
564 DOM::DocumentImpl
*doc
= m_part
->xmlDocImpl();
571 void KHTMLView::setPart(KHTMLPart
*part
)
573 assert(part
&& !m_part
);
577 void KHTMLView::init()
579 // Do not access the part here. It might not be fully constructed.
581 setFrameStyle(QFrame::NoFrame
);
582 setFocusPolicy(Qt::StrongFocus
);
583 viewport()->setFocusProxy(this);
585 _marginWidth
= -1; // undefined
590 installEventFilter(this);
592 setAcceptDrops(true);
594 setWidget( new QWidget(this) );
595 widget()->setAttribute( Qt::WA_NoSystemBackground
);
597 verticalScrollBar()->setCursor( Qt::ArrowCursor
);
598 horizontalScrollBar()->setCursor( Qt::ArrowCursor
);
600 connect(&d
->smoothScrollTimer
, SIGNAL(timeout()), this, SLOT(scrollTick()));
603 void KHTMLView::resizeContentsToViewport()
605 QSize s
= viewport()->size();
606 resizeContents(s
.width(), s
.height());
610 // called by KHTMLPart::clear()
611 void KHTMLView::clear()
613 #ifndef KHTML_NO_TYPE_AHEAD_FIND
614 if( d
->typeAheadActivated
)
617 if (d
->accessKeysEnabled
&& d
->accessKeysActivated
)
619 viewport()->unsetCursor();
620 if ( d
->cursorIconWidget
)
621 d
->cursorIconWidget
->hide();
622 if (d
->smoothScrolling
)
625 QAbstractEventDispatcher::instance()->unregisterTimers(this);
628 QScrollArea::setHorizontalScrollBarPolicy(d
->hpolicy
);
629 QScrollArea::setVerticalScrollBarPolicy(d
->vpolicy
);
630 verticalScrollBar()->setEnabled( false );
631 horizontalScrollBar()->setEnabled( false );
635 void KHTMLView::hideEvent(QHideEvent
* e
)
637 QScrollArea::hideEvent(e
);
638 if ( m_part
&& m_part
->xmlDocImpl() )
639 m_part
->xmlDocImpl()->docLoader()->pauseAnimations();
642 void KHTMLView::showEvent(QShowEvent
* e
)
644 QScrollArea::showEvent(e
);
645 if ( m_part
&& m_part
->xmlDocImpl() )
646 m_part
->xmlDocImpl()->docLoader()->resumeAnimations();
649 void KHTMLView::setMouseEventsTarget( QWidget
* w
)
651 d
->m_mouseEventsTarget
= w
;
654 QWidget
* KHTMLView::mouseEventsTarget() const
656 return d
->m_mouseEventsTarget
;
659 void KHTMLView::setClipHolder( QStack
<QRegion
>* ch
)
661 d
->m_clipHolder
= ch
;
664 QStack
<QRegion
>* KHTMLView::clipHolder() const
666 return d
->m_clipHolder
;
669 int KHTMLView::contentsWidth() const
671 return widget() ? widget()->width() : 0;
674 int KHTMLView::contentsHeight() const
676 return widget() ? widget()->height() : 0;
679 void KHTMLView::resizeContents(int w
, int h
)
683 widget()->resize(w
, h
);
684 if (!widget()->isVisible())
688 int KHTMLView::contentsX() const
693 int KHTMLView::contentsY() const
698 int KHTMLView::visibleWidth() const
700 if (m_kwp
->isRedirected()) {
701 // our RenderWidget knows better
702 if (RenderWidget
* rw
= m_kwp
->renderWidget()) {
703 int ret
= rw
->width()-rw
->paddingLeft()-rw
->paddingRight()-rw
->borderLeft()-rw
->borderRight();
704 if (verticalScrollBar()->isVisible()) {
705 ret
-= verticalScrollBar()->sizeHint().width();
711 return viewport()->width();
714 int KHTMLView::visibleHeight() const
716 if (m_kwp
->isRedirected()) {
717 // our RenderWidget knows better
718 if (RenderWidget
* rw
= m_kwp
->renderWidget()) {
719 int ret
= rw
->height()-rw
->paddingBottom()-rw
->paddingTop()-rw
->borderTop()-rw
->borderBottom();
720 if (horizontalScrollBar()->isVisible()) {
721 ret
-= horizontalScrollBar()->sizeHint().height();
727 return viewport()->height();
730 void KHTMLView::setContentsPos( int x
, int y
)
732 horizontalScrollBar()->setValue( QApplication::isRightToLeft() ?
733 horizontalScrollBar()->maximum()-x
: x
);
734 verticalScrollBar()->setValue( y
);
737 void KHTMLView::scrollBy(int x
, int y
)
739 horizontalScrollBar()->setValue( horizontalScrollBar()->value()+x
);
740 verticalScrollBar()->setValue( verticalScrollBar()->value()+y
);
743 QPoint
KHTMLView::contentsToViewport(const QPoint
& p
) const
745 return QPoint(p
.x()-contentsX(), p
.y()-contentsY());
748 void KHTMLView::contentsToViewport(int x
, int y
, int& cx
, int& cy
) const
751 p
= contentsToViewport(p
);
756 QPoint
KHTMLView::viewportToContents(const QPoint
& p
) const
758 return QPoint(p
.x()+contentsX(), p
.y()+contentsY());
761 void KHTMLView::viewportToContents(int x
, int y
, int& cx
, int& cy
) const
764 p
= viewportToContents(p
);
769 void KHTMLView::updateContents(int x
, int y
, int w
, int h
)
771 applyTransforms(x
, y
, w
, h
);
772 if (m_kwp
->isRedirected()) {
773 QPoint off
= m_kwp
->absolutePos();
774 KHTMLView
* pview
= m_part
->parentPart()->view();
775 pview
->updateContents(x
+off
.x(), y
+off
.y(), w
, h
);
777 widget()->update(x
, y
, w
, h
);
780 void KHTMLView::updateContents( const QRect
& r
)
782 updateContents( r
.x(), r
.y(), r
.width(), r
.height() );
785 void KHTMLView::repaintContents(int x
, int y
, int w
, int h
)
787 applyTransforms(x
, y
, w
, h
);
788 if (m_kwp
->isRedirected()) {
789 QPoint off
= m_kwp
->absolutePos();
790 KHTMLView
* pview
= m_part
->parentPart()->view();
791 pview
->repaintContents(x
+off
.x(), y
+off
.y(), w
, h
);
793 widget()->repaint(x
, y
, w
, h
);
796 void KHTMLView::repaintContents( const QRect
& r
)
798 repaintContents( r
.x(), r
.y(), r
.width(), r
.height() );
801 void KHTMLView::applyTransforms( int& x
, int& y
, int& w
, int& h
) const
804 const int z
= d
->zoomLevel
;
814 void KHTMLView::revertTransforms( int& x
, int& y
, int& w
, int& h
) const
819 const int z
= d
->zoomLevel
;
827 void KHTMLView::revertTransforms( int& x
, int& y
) const
830 revertTransforms(x
, y
, dummy
, dummy
);
833 void KHTMLView::resizeEvent (QResizeEvent
* /*e*/)
837 // If we didn't load anything, make white area as big as the view
838 if (!m_part
->xmlDocImpl())
839 resizeContentsToViewport();
841 // Viewport-dependent media queries may cause us to need completely different style information.
842 if (m_part
->xmlDocImpl() && m_part
->xmlDocImpl()->styleSelector()->affectedByViewportChange()) {
843 m_part
->xmlDocImpl()->updateStyleSelector();
846 if (d
->layoutSchedulingEnabled
)
849 QApplication::sendPostedEvents(viewport(), QEvent::Paint
);
851 if ( m_part
&& m_part
->xmlDocImpl() ) {
852 if (m_part
->parentPart()) {
853 // sub-frame : queue the resize event until our toplevel is done layouting
854 khtml::ChildFrame
*cf
= m_part
->parentPart()->frame( m_part
);
855 cf
->m_partContainerElement
->postResizeEvent();
857 // toplevel : dispatch sub-frames'resize events before our own
858 HTMLPartContainerElementImpl::sendPostedResizeEvents();
859 m_part
->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT
, false, false );
864 void KHTMLView::paintEvent( QPaintEvent
*e
)
866 QPainter
p(widget());
869 QRect
v(contentsX(), contentsY(), visibleWidth(), visibleHeight());
870 QPoint
off(contentsX(),contentsY());
876 if (!r
.isValid() || r
.isEmpty()) return;
879 p
.scale( d
->zoomLevel
/100., d
->zoomLevel
/100.);
881 r
.setX(r
.x()*100/d
->zoomLevel
);
882 r
.setY(r
.y()*100/d
->zoomLevel
);
883 r
.setWidth(r
.width()*100/d
->zoomLevel
);
884 r
.setHeight(r
.height()*100/d
->zoomLevel
);
894 if(!m_part
|| !m_part
->xmlDocImpl() || !m_part
->xmlDocImpl()->renderer()) {
895 p
.fillRect(ex
, ey
, ew
, eh
, palette().brush(QPalette::Active
, QPalette::Base
));
897 } else if ( d
->complete
&& static_cast<RenderCanvas
*>(m_part
->xmlDocImpl()->renderer())->needsLayout() ) {
898 // an external update request happens while we have a layout scheduled
899 unscheduleRelayout();
901 } else if (m_part
->xmlDocImpl()->tokenizer()) {
902 m_part
->xmlDocImpl()->tokenizer()->setNormalYeldDelay();
906 kDebug( 6000 ) << "WARNING: paintEvent reentered! ";
907 kDebug( 6000 ) << kBacktrace();
912 m_part
->xmlDocImpl()->renderer()->layer()->paint(&p
, r
);
914 if (d
->hasFrameset
) {
915 NodeImpl
*body
= static_cast<HTMLDocumentImpl
*>(m_part
->xmlDocImpl())->body();
916 if(body
&& body
->renderer() && body
->id() == ID_FRAMESET
)
917 static_cast<RenderFrameSet
*>(body
->renderer())->paintFrameSetRules(&p
, r
);
919 d
->hasFrameset
= false;
922 khtml::DrawContentsEvent
event( &p
, ex
, ey
, ew
, eh
);
923 QApplication::sendEvent( m_part
, &event
);
925 if (d
->contentsMoving
&& !d
->smoothScrolling
&& widget()->underMouse()) {
926 QMouseEvent
*tempEvent
= new QMouseEvent( QEvent::MouseMove
, widget()->mapFromGlobal( QCursor::pos() ),
927 Qt::NoButton
, Qt::NoButton
, Qt::NoModifier
);
928 QApplication::postEvent(widget(), tempEvent
);
932 d
->firstRepaintPending
= false;
935 void KHTMLView::setMarginWidth(int w
)
937 // make it update the rendering area when set
941 void KHTMLView::setMarginHeight(int h
)
943 // make it update the rendering area when set
947 void KHTMLView::layout()
949 if( m_part
&& m_part
->xmlDocImpl() ) {
950 DOM::DocumentImpl
*document
= m_part
->xmlDocImpl();
952 khtml::RenderCanvas
* canvas
= static_cast<khtml::RenderCanvas
*>(document
->renderer());
953 if ( !canvas
) return;
955 d
->layoutSchedulingEnabled
=false;
956 d
->dirtyLayout
= true;
958 // the reference object for the overflow property on canvas
959 RenderObject
* ref
= 0;
960 RenderObject
* root
= document
->documentElement() ? document
->documentElement()->renderer() : 0;
962 if (document
->isHTMLDocument()) {
963 NodeImpl
*body
= static_cast<HTMLDocumentImpl
*>(document
)->body();
964 if(body
&& body
->renderer() && body
->id() == ID_FRAMESET
) {
965 QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
966 QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
967 body
->renderer()->setNeedsLayout(true);
968 d
->hasFrameset
= true;
970 else if (root
) // only apply body's overflow to canvas if root has a visible overflow
971 ref
= (!body
|| root
->style()->hidesOverflow()) ? root
: body
->renderer();
976 if( ref
->style()->overflowX() == OHIDDEN
) {
977 if (d
->hpolicy
== Qt::ScrollBarAsNeeded
) QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
978 } else if (ref
->style()->overflowX() == OSCROLL
) {
979 if (d
->hpolicy
== Qt::ScrollBarAsNeeded
) QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn
);
980 } else if (horizontalScrollBarPolicy() != d
->hpolicy
) {
981 QScrollArea::setHorizontalScrollBarPolicy(d
->hpolicy
);
983 if ( ref
->style()->overflowY() == OHIDDEN
) {
984 if (d
->vpolicy
== Qt::ScrollBarAsNeeded
) QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
985 } else if (ref
->style()->overflowY() == OSCROLL
) {
986 if (d
->vpolicy
== Qt::ScrollBarAsNeeded
) QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn
);
987 } else if (verticalScrollBarPolicy() != d
->vpolicy
) {
988 QScrollArea::setVerticalScrollBarPolicy(d
->vpolicy
);
991 d
->needsFullRepaint
= d
->firstLayoutPending
;
992 if (_height
!= visibleHeight() || _width
!= visibleWidth()) {;
993 d
->needsFullRepaint
= true;
994 _height
= visibleHeight();
995 _width
= visibleWidth();
1000 emit
finishedLayout();
1001 if (d
->firstLayoutPending
) {
1002 // make sure firstLayoutPending is set to false now in case this layout
1004 d
->firstLayoutPending
= false;
1005 verticalScrollBar()->setEnabled( true );
1006 horizontalScrollBar()->setEnabled( true );
1010 if (d
->accessKeysEnabled
&& d
->accessKeysActivated
) {
1011 emit
hideAccessKeys();
1012 displayAccessKeys();
1016 _width
= visibleWidth();
1018 if (d
->layoutTimerId
)
1019 killTimer(d
->layoutTimerId
);
1020 d
->layoutTimerId
= 0;
1021 d
->layoutSchedulingEnabled
=true;
1024 void KHTMLView::closeChildDialogs()
1026 QList
<QDialog
*> dlgs
= findChildren
<QDialog
*>();
1027 foreach (QDialog
*dlg
, dlgs
)
1029 KDialog
* dlgbase
= dynamic_cast<KDialog
*>( dlg
);
1031 if ( dlgbase
->testAttribute( Qt::WA_ShowModal
) ) {
1032 kDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase
;
1033 // close() ends up calling QButton::animateClick, which isn't immediate
1034 // we need something the exits the event loop immediately (#49068)
1040 kWarning() << "closeChildDialogs: not a KDialog! Don't use QDialogs in KDE! " << static_cast<QWidget
*>(dlg
);
1041 static_cast<QWidget
*>(dlg
)->hide();
1044 d
->m_dialogsAllowed
= false;
1047 bool KHTMLView::dialogsAllowed() {
1048 bool allowed
= d
->m_dialogsAllowed
;
1049 KHTMLPart
* p
= m_part
->parentPart();
1051 allowed
&= p
->view()->dialogsAllowed();
1055 void KHTMLView::closeEvent( QCloseEvent
* ev
)
1057 closeChildDialogs();
1058 QScrollArea::closeEvent( ev
);
1061 void KHTMLView::setZoomLevel(int percent
)
1063 percent
= percent
< 20 ? 20 : (percent
> 800 ? 800 : percent
);
1064 int oldpercent
= d
->zoomLevel
;
1065 d
->zoomLevel
= percent
;
1066 if (percent
!= oldpercent
) {
1067 if (d
->layoutSchedulingEnabled
)
1073 int KHTMLView::zoomLevel() const
1075 return d
->zoomLevel
;
1078 void KHTMLView::setSmoothScrollingMode( SmoothScrollingMode m
)
1080 d
->smoothScrollMode
= m
;
1081 d
->smoothScrollModeIsDefault
= false;
1082 if (d
->smoothScrolling
&& !m
)
1086 void KHTMLView::setSmoothScrollingModeDefault( SmoothScrollingMode m
)
1088 // check for manual override
1089 if (!d
->smoothScrollModeIsDefault
)
1091 d
->smoothScrollMode
= m
;
1092 if (d
->smoothScrolling
&& !m
)
1096 KHTMLView::SmoothScrollingMode
KHTMLView::smoothScrollingMode( ) const
1098 return d
->smoothScrollMode
;
1106 void KHTMLView::mousePressEvent( QMouseEvent
*_mouse
)
1108 if (!m_part
->xmlDocImpl()) return;
1109 if (d
->possibleTripleClick
&& ( _mouse
->button() & Qt::MouseButtonMask
) == Qt::LeftButton
)
1111 mouseDoubleClickEvent( _mouse
); // it handles triple clicks too
1115 int xm
= _mouse
->x();
1116 int ym
= _mouse
->y();
1117 revertTransforms(xm
, ym
);
1119 // kDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()-contentsX()<<"/"<<_mouse->y()-contentsY()<<"), contents=(" << xm << "/" << ym << ")\n";
1121 d
->isDoubleClick
= false;
1123 DOM::NodeImpl::MouseEvent
mev( _mouse
->buttons(), DOM::NodeImpl::MousePress
);
1124 m_part
->xmlDocImpl()->prepareMouseEvent( false, xm
, ym
, &mev
);
1126 //kDebug(6000) << "innerNode="<<mev.innerNode.nodeName().string();
1128 if ( (_mouse
->button() == Qt::MidButton
) &&
1129 !m_part
->d
->m_bOpenMiddleClick
&& !d
->m_mouseScrollTimer
&&
1130 mev
.url
.isNull() && (mev
.innerNode
.elementId() != ID_INPUT
) ) {
1131 QPoint point
= mapFromGlobal( _mouse
->globalPos() );
1133 d
->m_mouseScroll_byX
= 0;
1134 d
->m_mouseScroll_byY
= 0;
1136 d
->m_mouseScrollTimer
= new QTimer( this );
1137 connect( d
->m_mouseScrollTimer
, SIGNAL(timeout()), this, SLOT(slotMouseScrollTimer()) );
1139 if ( !d
->m_mouseScrollIndicator
) {
1140 QPixmap
pixmap( 48, 48 ), icon
;
1141 pixmap
.fill( QColor( qRgba( 127, 127, 127, 127 ) ) );
1143 QPainter
p( &pixmap
);
1144 QStyleOption option
;
1146 option
.rect
.setRect( 16, 0, 16, 16 );
1147 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowUp
, &option
, &p
);
1148 option
.rect
.setRect( 0, 16, 16, 16 );
1149 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowLeft
, &option
, &p
);
1150 option
.rect
.setRect( 16, 32, 16, 16 );
1151 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowDown
, &option
, &p
);
1152 option
.rect
.setRect( 32, 16, 16, 16 );
1153 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowRight
, &option
, &p
);
1154 p
.drawEllipse( 23, 23, 2, 2 );
1156 d
->m_mouseScrollIndicator
= new QWidget( this );
1157 d
->m_mouseScrollIndicator
->setFixedSize( 48, 48 );
1159 palette
.setBrush( d
->m_mouseScrollIndicator
->backgroundRole(), QBrush( pixmap
) );
1160 d
->m_mouseScrollIndicator
->setPalette( palette
);
1162 d
->m_mouseScrollIndicator
->move( point
.x()-24, point
.y()-24 );
1164 bool hasHorBar
= visibleWidth() < contentsWidth();
1165 bool hasVerBar
= visibleHeight() < contentsHeight();
1167 KConfigGroup
cg( KGlobal::config(), "HTML Settings" );
1168 if ( cg
.readEntry( "ShowMouseScrollIndicator", true ) ) {
1169 d
->m_mouseScrollIndicator
->show();
1170 d
->m_mouseScrollIndicator
->unsetCursor();
1172 QBitmap mask
= d
->m_mouseScrollIndicator
->palette().brush(d
->m_mouseScrollIndicator
->backgroundRole()).texture().createHeuristicMask( true );
1174 if ( hasHorBar
&& !hasVerBar
) {
1175 QBitmap
bm( 16, 16 );
1177 QPainter
painter( &mask
);
1178 painter
.drawPixmap( QRectF( 16, 0, bm
.width(), bm
.height() ), bm
, bm
.rect() );
1179 painter
.drawPixmap( QRectF( 16, 32, bm
.width(), bm
.height() ), bm
, bm
.rect() );
1180 d
->m_mouseScrollIndicator
->setCursor( Qt::SizeHorCursor
);
1182 else if ( !hasHorBar
&& hasVerBar
) {
1183 QBitmap
bm( 16, 16 );
1185 QPainter
painter( &mask
);
1186 painter
.drawPixmap( QRectF( 0, 16, bm
.width(), bm
.height() ), bm
, bm
.rect() );
1187 painter
.drawPixmap( QRectF( 32, 16, bm
.width(), bm
.height() ), bm
, bm
.rect() );
1188 d
->m_mouseScrollIndicator
->setCursor( Qt::SizeVerCursor
);
1191 d
->m_mouseScrollIndicator
->setCursor( Qt::SizeAllCursor
);
1193 d
->m_mouseScrollIndicator
->setMask( mask
);
1196 if ( hasHorBar
&& !hasVerBar
)
1197 viewport()->setCursor( Qt::SizeHorCursor
);
1198 else if ( !hasHorBar
&& hasVerBar
)
1199 viewport()->setCursor( Qt::SizeVerCursor
);
1201 viewport()->setCursor( Qt::SizeAllCursor
);
1206 else if ( d
->m_mouseScrollTimer
) {
1207 delete d
->m_mouseScrollTimer
;
1208 d
->m_mouseScrollTimer
= 0;
1210 if ( d
->m_mouseScrollIndicator
)
1211 d
->m_mouseScrollIndicator
->hide();
1214 if (d
->clickCount
> 0 &&
1215 QPoint(d
->clickX
-xm
,d
->clickY
-ym
).manhattanLength() <= QApplication::startDragDistance())
1223 bool swallowEvent
= dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT
,mev
.innerNode
.handle(),mev
.innerNonSharedNode
.handle(),true,
1224 d
->clickCount
,_mouse
,true,DOM::NodeImpl::MousePress
);
1226 if (!swallowEvent
) {
1227 emit m_part
->nodeActivated(mev
.innerNode
);
1229 khtml::MousePressEvent
event( _mouse
, xm
, ym
, mev
.url
, mev
.target
, mev
.innerNode
);
1230 QApplication::sendEvent( m_part
, &event
);
1231 // we might be deleted after this
1235 void KHTMLView::mouseDoubleClickEvent( QMouseEvent
*_mouse
)
1237 if(!m_part
->xmlDocImpl()) return;
1239 int xm
= _mouse
->x();
1240 int ym
= _mouse
->y();
1241 revertTransforms(xm
, ym
);
1243 // kDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym;
1245 d
->isDoubleClick
= true;
1247 DOM::NodeImpl::MouseEvent
mev( _mouse
->buttons(), DOM::NodeImpl::MouseDblClick
);
1248 m_part
->xmlDocImpl()->prepareMouseEvent( false, xm
, ym
, &mev
);
1250 // We do the same thing as mousePressEvent() here, since the DOM does not treat
1251 // single and double-click events as separate (only the detail, i.e. number of clicks differs)
1252 if (d
->clickCount
> 0 &&
1253 QPoint(d
->clickX
-xm
,d
->clickY
-ym
).manhattanLength() <= QApplication::startDragDistance())
1255 else { // shouldn't happen, if Qt has the same criterias for double clicks.
1260 bool swallowEvent
= dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT
,mev
.innerNode
.handle(),mev
.innerNonSharedNode
.handle(),true,
1261 d
->clickCount
,_mouse
,true,DOM::NodeImpl::MouseDblClick
);
1263 if (!swallowEvent
) {
1264 khtml::MouseDoubleClickEvent
event( _mouse
, xm
, ym
, mev
.url
, mev
.target
, mev
.innerNode
, d
->clickCount
);
1265 QApplication::sendEvent( m_part
, &event
);
1268 d
->possibleTripleClick
=true;
1269 QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
1272 void KHTMLView::tripleClickTimeout()
1274 d
->possibleTripleClick
= false;
1278 static bool targetOpensNewWindow(KHTMLPart
*part
, QString target
)
1280 if (!target
.isEmpty() && (target
.toLower() != "_top") &&
1281 (target
.toLower() != "_self") && (target
.toLower() != "_parent")) {
1282 if (target
.toLower() == "_blank")
1285 while (part
->parentPart())
1286 part
= part
->parentPart();
1287 if (!part
->frameExists(target
))
1294 void KHTMLView::mouseMoveEvent( QMouseEvent
* _mouse
)
1296 if ( d
->m_mouseScrollTimer
) {
1297 QPoint point
= mapFromGlobal( _mouse
->globalPos() );
1299 int deltaX
= point
.x() - d
->m_mouseScrollIndicator
->x() - 24;
1300 int deltaY
= point
.y() - d
->m_mouseScrollIndicator
->y() - 24;
1302 (deltaX
> 0) ? d
->m_mouseScroll_byX
= 1 : d
->m_mouseScroll_byX
= -1;
1303 (deltaY
> 0) ? d
->m_mouseScroll_byY
= 1 : d
->m_mouseScroll_byY
= -1;
1305 double adX
= qAbs(deltaX
)/30.0;
1306 double adY
= qAbs(deltaY
)/30.0;
1308 d
->m_mouseScroll_byX
= qMax(qMin(d
->m_mouseScroll_byX
* int(adX
*adX
), SHRT_MAX
), SHRT_MIN
);
1309 d
->m_mouseScroll_byY
= qMax(qMin(d
->m_mouseScroll_byY
* int(adY
*adY
), SHRT_MAX
), SHRT_MIN
);
1311 if (d
->m_mouseScroll_byX
== 0 && d
->m_mouseScroll_byY
== 0) {
1312 d
->m_mouseScrollTimer
->stop();
1314 else if (!d
->m_mouseScrollTimer
->isActive()) {
1315 d
->m_mouseScrollTimer
->start( 20 );
1319 if(!m_part
->xmlDocImpl()) return;
1321 int xm
= _mouse
->x();
1322 int ym
= _mouse
->y();
1323 revertTransforms(xm
, ym
);
1325 DOM::NodeImpl::MouseEvent
mev( _mouse
->buttons(), DOM::NodeImpl::MouseMove
);
1326 // Do not modify :hover/:active state while mouse is pressed.
1327 m_part
->xmlDocImpl()->prepareMouseEvent( _mouse
->buttons() /*readonly ?*/, xm
, ym
, &mev
);
1329 // kDebug(6000) << "mouse move: " << _mouse->pos()
1330 // << " button " << _mouse->button()
1331 // << " state " << _mouse->state() << endl;
1333 DOM::NodeImpl
* target
= mev
.innerNode
.handle();
1334 DOM::NodeImpl
* fn
= m_part
->xmlDocImpl()->focusNode();
1336 // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
1337 if (d
->m_mouseEventsTarget
&& fn
&& fn
->renderer() && fn
->renderer()->isWidget())
1340 bool swallowEvent
= dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT
,target
,mev
.innerNonSharedNode
.handle(),false,
1341 0,_mouse
,true,DOM::NodeImpl::MouseMove
);
1343 if (d
->clickCount
> 0 &&
1344 QPoint(d
->clickX
-xm
,d
->clickY
-ym
).manhattanLength() > QApplication::startDragDistance()) {
1345 d
->clickCount
= 0; // moving the mouse outside the threshold invalidates the click
1348 khtml::RenderObject
* r
= target
? target
->renderer() : 0;
1349 bool setCursor
= true;
1350 if (r
&& r
->isWidget()) {
1351 RenderWidget
* rw
= static_cast<RenderWidget
*>(r
);
1352 KHTMLWidget
* kw
= qobject_cast
<KHTMLView
*>(rw
->widget())? dynamic_cast<KHTMLWidget
*>(rw
->widget()) : 0;
1353 if (kw
&& kw
->m_kwp
->isRedirected())
1356 khtml::RenderStyle
* style
= (r
&& r
->style()) ? r
->style() : 0;
1358 LinkCursor linkCursor
= LINK_NORMAL
;
1359 switch ( style
? style
->cursor() : CURSOR_AUTO
) {
1361 if ( r
&& r
->isText() && !r
->isPointInsideSelection(xm
, ym
, m_part
->caret()) )
1362 c
= QCursor(Qt::IBeamCursor
);
1363 if ( mev
.url
.length() && m_part
->settings()->changeCursor() ) {
1364 c
= m_part
->urlCursor();
1365 if (mev
.url
.string().startsWith("mailto:") && mev
.url
.string().indexOf('@')>0)
1366 linkCursor
= LINK_MAILTO
;
1368 if ( targetOpensNewWindow( m_part
, mev
.target
.string() ) )
1369 linkCursor
= LINK_NEWWINDOW
;
1372 if (r
&& r
->isFrameSet() && !static_cast<RenderFrameSet
*>(r
)->noResize())
1373 c
= QCursor(static_cast<RenderFrameSet
*>(r
)->cursorShape());
1377 c
= QCursor(Qt::CrossCursor
);
1379 case CURSOR_POINTER
:
1380 c
= m_part
->urlCursor();
1381 if (mev
.url
.string().startsWith("mailto:") && mev
.url
.string().indexOf('@')>0)
1382 linkCursor
= LINK_MAILTO
;
1384 if ( targetOpensNewWindow( m_part
, mev
.target
.string() ) )
1385 linkCursor
= LINK_NEWWINDOW
;
1387 case CURSOR_PROGRESS
:
1388 c
= QCursor(Qt::BusyCursor
); // working_cursor
1391 case CURSOR_ALL_SCROLL
:
1392 c
= QCursor(Qt::SizeAllCursor
);
1394 case CURSOR_E_RESIZE
:
1395 case CURSOR_W_RESIZE
:
1396 case CURSOR_EW_RESIZE
:
1397 c
= QCursor(Qt::SizeHorCursor
);
1399 case CURSOR_N_RESIZE
:
1400 case CURSOR_S_RESIZE
:
1401 case CURSOR_NS_RESIZE
:
1402 c
= QCursor(Qt::SizeVerCursor
);
1404 case CURSOR_NE_RESIZE
:
1405 case CURSOR_SW_RESIZE
:
1406 case CURSOR_NESW_RESIZE
:
1407 c
= QCursor(Qt::SizeBDiagCursor
);
1409 case CURSOR_NW_RESIZE
:
1410 case CURSOR_SE_RESIZE
:
1411 case CURSOR_NWSE_RESIZE
:
1412 c
= QCursor(Qt::SizeFDiagCursor
);
1415 c
= QCursor(Qt::IBeamCursor
);
1418 c
= QCursor(Qt::WaitCursor
);
1421 c
= QCursor(Qt::WhatsThisCursor
);
1423 case CURSOR_DEFAULT
:
1426 case CURSOR_NOT_ALLOWED
:
1427 c
= QCursor(Qt::ForbiddenCursor
);
1429 case CURSOR_ROW_RESIZE
:
1430 c
= QCursor(Qt::SplitVCursor
);
1432 case CURSOR_COL_RESIZE
:
1433 c
= QCursor(Qt::SplitHCursor
);
1435 case CURSOR_VERTICAL_TEXT
:
1436 case CURSOR_CONTEXT_MENU
:
1437 case CURSOR_NO_DROP
:
1441 c
= QCursor(Qt::ArrowCursor
);
1445 if (!setCursor
&& style
&& style
->cursor() != CURSOR_AUTO
)
1448 QWidget
* vp
= viewport();
1449 for (KHTMLPart
* p
= m_part
; p
; p
= p
->parentPart())
1450 if (!p
->parentPart())
1451 vp
= p
->view()->viewport();
1452 if ( setCursor
&& vp
->cursor().handle() != c
.handle() ) {
1453 if( c
.shape() == Qt::ArrowCursor
) {
1454 for (KHTMLPart
* p
= m_part
; p
; p
= p
->parentPart())
1455 p
->view()->viewport()->unsetCursor();
1462 if ( linkCursor
!=LINK_NORMAL
&& isVisible() && hasFocus() ) {
1465 if( !d
->cursorIconWidget
) {
1467 d
->cursorIconWidget
= new QLabel( 0, Qt::X11BypassWindowManagerHint
);
1468 XSetWindowAttributes attr
;
1469 attr
.save_under
= True
;
1470 XChangeWindowAttributes( QX11Info::display(), d
->cursorIconWidget
->winId(), CWSaveUnder
, &attr
);
1472 d
->cursorIconWidget
= new QLabel( NULL
, NULL
);
1477 // Update the pixmap if need be.
1478 if (linkCursor
!= d
->cursorIconType
) {
1479 d
->cursorIconType
= linkCursor
;
1483 case LINK_MAILTO
: cursorIcon
= "mail-message-new"; break;
1484 case LINK_NEWWINDOW
: cursorIcon
= "window-new"; break;
1485 default: cursorIcon
= "dialog-error"; break;
1488 QPixmap icon_pixmap
= KHTMLGlobal::iconLoader()->loadIcon( cursorIcon
, KIconLoader::Small
, 0, KIconLoader::DefaultState
, QStringList(), 0, true );
1490 d
->cursorIconWidget
->resize( icon_pixmap
.width(), icon_pixmap
.height());
1491 d
->cursorIconWidget
->setMask( icon_pixmap
.createMaskFromColor(Qt::transparent
));
1492 d
->cursorIconWidget
->setPixmap( icon_pixmap
);
1493 d
->cursorIconWidget
->update();
1496 QPoint c_pos
= QCursor::pos();
1497 d
->cursorIconWidget
->move( c_pos
.x() + 15, c_pos
.y() + 15 );
1499 XRaiseWindow( QX11Info::display(), d
->cursorIconWidget
->winId());
1500 QApplication::flush();
1501 #elif defined(Q_WS_WIN)
1502 SetWindowPos( d
->cursorIconWidget
->winId(), HWND_TOP
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
1506 d
->cursorIconWidget
->show();
1509 else if ( d
->cursorIconWidget
)
1510 d
->cursorIconWidget
->hide();
1512 if (r
&& r
->isWidget()) {
1516 if (!swallowEvent
) {
1517 khtml::MouseMoveEvent
event( _mouse
, xm
, ym
, mev
.url
, mev
.target
, mev
.innerNode
);
1518 QApplication::sendEvent( m_part
, &event
);
1522 void KHTMLView::mouseReleaseEvent( QMouseEvent
* _mouse
)
1524 bool swallowEvent
= false;
1526 int xm
= _mouse
->x();
1527 int ym
= _mouse
->y();
1528 revertTransforms(xm
, ym
);
1530 DOM::NodeImpl::MouseEvent
mev( _mouse
->buttons(), DOM::NodeImpl::MouseRelease
);
1532 if ( m_part
->xmlDocImpl() )
1534 m_part
->xmlDocImpl()->prepareMouseEvent( false, xm
, ym
, &mev
);
1536 DOM::NodeImpl
* target
= mev
.innerNode
.handle();
1537 DOM::NodeImpl
* fn
= m_part
->xmlDocImpl()->focusNode();
1539 // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
1540 if (d
->m_mouseEventsTarget
&& fn
&& fn
->renderer() && fn
->renderer()->isWidget())
1543 swallowEvent
= dispatchMouseEvent(EventImpl::MOUSEUP_EVENT
,target
,mev
.innerNonSharedNode
.handle(),true,
1544 d
->clickCount
,_mouse
,false,DOM::NodeImpl::MouseRelease
);
1546 // clear our sticky event target on any mouseRelease event
1547 if (d
->m_mouseEventsTarget
)
1548 d
->m_mouseEventsTarget
= 0;
1550 if (d
->clickCount
> 0 &&
1551 QPoint(d
->clickX
-xm
,d
->clickY
-ym
).manhattanLength() <= QApplication::startDragDistance()) {
1552 QMouseEvent
me(d
->isDoubleClick
? QEvent::MouseButtonDblClick
: QEvent::MouseButtonRelease
,
1553 _mouse
->pos(), _mouse
->button(), _mouse
->buttons(), _mouse
->modifiers());
1554 dispatchMouseEvent(EventImpl::CLICK_EVENT
, mev
.innerNode
.handle(),mev
.innerNonSharedNode
.handle(),true,
1555 d
->clickCount
, &me
, true, DOM::NodeImpl::MouseRelease
);
1558 khtml::RenderObject
* r
= target
? target
->renderer() : 0;
1559 if (r
&& r
->isWidget())
1563 if (!swallowEvent
) {
1564 khtml::MouseReleaseEvent
event( _mouse
, xm
, ym
, mev
.url
, mev
.target
, mev
.innerNode
);
1565 QApplication::sendEvent( m_part
, &event
);
1569 // returns true if event should be swallowed
1570 bool KHTMLView::dispatchKeyEvent( QKeyEvent
*_ke
)
1572 if (!m_part
->xmlDocImpl())
1574 // Pressing and releasing a key should generate keydown, keypress and keyup events
1575 // Holding it down should generated keydown, keypress (repeatedly) and keyup events
1576 // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
1577 // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
1578 // of the Qt events shouldn't be passed to DOM, but it should be still filtered
1579 // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
1580 // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
1581 // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
1582 // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
1583 // The solution is to filter out and postpone the Qt autorepeat keyrelease until
1584 // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
1585 // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
1586 // again, and here it will be ignored.
1588 // Qt: Press | Release(autorepeat) Press(autorepeat) etc. | Release
1589 // DOM: Down + Press | (nothing) Press | Up
1591 // It's also possible to get only Releases. E.g. the release of alt-tab,
1592 // or when the keypresses get captured by an accel.
1594 if( _ke
== d
->postponed_autorepeat
) // replayed event
1599 if( _ke
->type() == QEvent::KeyPress
)
1601 if( !_ke
->isAutoRepeat())
1603 bool ret
= dispatchKeyEventHelper( _ke
, false ); // keydown
1604 // don't send keypress even if keydown was blocked, like IE (and unlike Mozilla)
1605 if( !ret
&& dispatchKeyEventHelper( _ke
, true )) // keypress
1611 bool ret
= dispatchKeyEventHelper( _ke
, true ); // keypress
1612 if( !ret
&& d
->postponed_autorepeat
)
1613 keyPressEvent( d
->postponed_autorepeat
);
1614 delete d
->postponed_autorepeat
;
1615 d
->postponed_autorepeat
= NULL
;
1619 else // QEvent::KeyRelease
1621 // Discard postponed "autorepeat key-release" events that didn't see
1622 // a keypress after them (e.g. due to QAccel)
1623 if ( d
->postponed_autorepeat
) {
1624 delete d
->postponed_autorepeat
;
1625 d
->postponed_autorepeat
= 0;
1628 if( !_ke
->isAutoRepeat()) {
1629 return dispatchKeyEventHelper( _ke
, false ); // keyup
1633 d
->postponed_autorepeat
= new QKeyEvent( _ke
->type(), _ke
->key(), _ke
->modifiers(),
1634 _ke
->text(), _ke
->isAutoRepeat(), _ke
->count());
1635 if( _ke
->isAccepted())
1636 d
->postponed_autorepeat
->accept();
1638 d
->postponed_autorepeat
->ignore();
1644 // returns true if event should be swallowed
1645 bool KHTMLView::dispatchKeyEventHelper( QKeyEvent
*_ke
, bool keypress
)
1647 DOM::NodeImpl
* keyNode
= m_part
->xmlDocImpl()->focusNode();
1649 return keyNode
->dispatchKeyEvent(_ke
, keypress
);
1650 } else { // no focused node, send to document
1651 return m_part
->xmlDocImpl()->dispatchKeyEvent(_ke
, keypress
);
1655 void KHTMLView::keyPressEvent( QKeyEvent
*_ke
)
1657 #ifndef KHTML_NO_TYPE_AHEAD_FIND
1658 if(d
->typeAheadActivated
)
1660 // type-ahead find aka find-as-you-type
1661 if(_ke
->key() == Qt::Key_Backspace
)
1663 d
->findString
= d
->findString
.left(d
->findString
.length() - 1);
1665 if(!d
->findString
.isEmpty())
1674 d
->timer
.setSingleShot(true);
1675 d
->timer
.start(3000);
1679 else if(_ke
->key() == Qt::Key_Escape
)
1686 else if(_ke
->key() == Qt::Key_Space
|| !_ke
->text().trimmed().isEmpty())
1688 d
->findString
+= _ke
->text();
1692 d
->timer
.setSingleShot(true);
1693 d
->timer
.start(3000);
1698 #endif // KHTML_NO_TYPE_AHEAD_FIND
1700 // If CTRL was hit, be prepared for access keys
1701 if (d
->accessKeysEnabled
&& _ke
->key() == Qt::Key_Control
&& !(_ke
->modifiers() & ~Qt::ControlModifier
) && !d
->accessKeysActivated
)
1703 d
->accessKeysPreActivate
=true;
1708 if (_ke
->key() == Qt::Key_Shift
&& !(_ke
->modifiers() & ~Qt::ShiftModifier
))
1709 d
->scrollSuspendPreActivate
=true;
1711 // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
1712 // may eat the event
1714 if (d
->accessKeysEnabled
&& d
->accessKeysActivated
)
1716 int state
= ( _ke
->modifiers() & ( Qt::ShiftModifier
| Qt::ControlModifier
| Qt::AltModifier
| Qt::MetaModifier
));
1717 if ( state
==0 || state
==Qt::ShiftModifier
) {
1718 if (_ke
->key() != Qt::Key_Shift
) accessKeysTimeout();
1719 handleAccessKey( _ke
);
1723 accessKeysTimeout();
1726 if ( dispatchKeyEvent( _ke
)) {
1727 // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
1732 int offs
= (viewport()->height() < 30) ? viewport()->height() : 30; // ### ??
1733 if (_ke
->modifiers() & Qt::ShiftModifier
)
1737 verticalScrollBar()->setValue( verticalScrollBar()->value() -viewport()->height() + offs
);
1738 if(d
->scrollSuspended
)
1739 d
->newScrollTimer(this, 0);
1744 d
->adjustScroller(this, KHTMLViewPrivate::ScrollDown
, KHTMLViewPrivate::ScrollUp
);
1749 d
->adjustScroller(this, KHTMLViewPrivate::ScrollUp
, KHTMLViewPrivate::ScrollDown
);
1754 d
->adjustScroller(this, KHTMLViewPrivate::ScrollLeft
, KHTMLViewPrivate::ScrollRight
);
1759 d
->adjustScroller(this, KHTMLViewPrivate::ScrollRight
, KHTMLViewPrivate::ScrollLeft
);
1763 switch ( _ke
->key() )
1767 if (!d
->scrollTimerId
|| d
->scrollSuspended
)
1768 verticalScrollBar()->setValue( verticalScrollBar()->value()+10 );
1769 if (d
->scrollTimerId
)
1770 d
->newScrollTimer(this, 0);
1774 case Qt::Key_PageDown
:
1775 d
->shouldSmoothScroll
= true;
1776 verticalScrollBar()->setValue( verticalScrollBar()->value() +viewport()->height() - offs
);
1777 if(d
->scrollSuspended
)
1778 d
->newScrollTimer(this, 0);
1783 if (!d
->scrollTimerId
|| d
->scrollSuspended
)
1784 verticalScrollBar()->setValue( verticalScrollBar()->value()-10 );
1785 if (d
->scrollTimerId
)
1786 d
->newScrollTimer(this, 0);
1789 case Qt::Key_PageUp
:
1790 d
->shouldSmoothScroll
= true;
1791 verticalScrollBar()->setValue( verticalScrollBar()->value() -viewport()->height() + offs
);
1792 if(d
->scrollSuspended
)
1793 d
->newScrollTimer(this, 0);
1797 if (!d
->scrollTimerId
|| d
->scrollSuspended
)
1798 horizontalScrollBar()->setValue( horizontalScrollBar()->value()+10 );
1799 if (d
->scrollTimerId
)
1800 d
->newScrollTimer(this, 0);
1805 if (!d
->scrollTimerId
|| d
->scrollSuspended
)
1806 horizontalScrollBar()->setValue( horizontalScrollBar()->value()-10 );
1807 if (d
->scrollTimerId
)
1808 d
->newScrollTimer(this, 0);
1811 case Qt::Key_Return
:
1813 // or even better to HTMLAnchorElementImpl::event()
1814 if (m_part
->xmlDocImpl()) {
1815 NodeImpl
*n
= m_part
->xmlDocImpl()->focusNode();
1821 verticalScrollBar()->setValue( 0 );
1822 horizontalScrollBar()->setValue( 0 );
1823 if(d
->scrollSuspended
)
1824 d
->newScrollTimer(this, 0);
1827 verticalScrollBar()->setValue( contentsHeight() - visibleHeight() );
1828 if(d
->scrollSuspended
)
1829 d
->newScrollTimer(this, 0);
1832 // what are you doing here?
1836 if (d
->scrollTimerId
)
1837 d
->newScrollTimer(this, 0);
1845 void KHTMLView::findTimeout()
1847 #ifndef KHTML_NO_TYPE_AHEAD_FIND
1848 d
->typeAheadActivated
= false;
1850 m_part
->setStatusBarText(i18n("Find stopped."), KHTMLPart::BarDefaultText
);
1851 m_part
->enableFindAheadActions( true );
1852 #endif // KHTML_NO_TYPE_AHEAD_FIND
1855 #ifndef KHTML_NO_TYPE_AHEAD_FIND
1856 void KHTMLView::startFindAhead( bool linksOnly
)
1860 d
->findLinksOnly
= true;
1861 m_part
->setStatusBarText(i18n("Starting -- find links as you type"),
1862 KHTMLPart::BarDefaultText
);
1866 d
->findLinksOnly
= false;
1867 m_part
->setStatusBarText(i18n("Starting -- find text as you type"),
1868 KHTMLPart::BarDefaultText
);
1871 m_part
->findTextBegin();
1872 d
->typeAheadActivated
= true;
1873 // disable, so that the shortcut ( / or ' by default ) doesn't interfere
1874 m_part
->enableFindAheadActions( false );
1875 d
->timer
.setSingleShot(true);
1876 d
->timer
.start(3000);
1879 void KHTMLView::findAhead(bool increase
)
1882 QString text
= d
->findString
.toLower();
1884 if(d
->findLinksOnly
)
1886 m_part
->findText(d
->findString
, KHTMLPart::FindNoPopups
|
1887 KHTMLPart::FindLinksOnly
, this);
1888 if(m_part
->findTextNext())
1890 status
= i18n("Link found: \"%1\".", Qt::escape(text
));
1894 if(increase
) KNotification::beep();
1895 status
= i18n("Link not found: \"%1\".", Qt::escape(text
));
1900 m_part
->findText(d
->findString
, KHTMLPart::FindNoPopups
, this);
1901 if(m_part
->findTextNext())
1903 status
= i18n("Text found: \"%1\".", Qt::escape(text
));
1907 if(increase
) KNotification::beep();
1908 status
= i18n("Text not found: \"%1\".", Qt::escape(text
));
1912 // Note: we need to escape -twice-: the above just escape for i18n, now we need to do it for Qt, too.
1913 m_part
->setStatusBarText(Qt::escape(status
), KHTMLPart::BarDefaultText
);
1916 void KHTMLView::updateFindAheadTimeout()
1918 if( d
->typeAheadActivated
) {
1919 d
->timer
.setSingleShot( true );
1920 d
->timer
.start( 3000 );
1924 #endif // KHTML_NO_TYPE_AHEAD_FIND
1926 void KHTMLView::keyReleaseEvent(QKeyEvent
*_ke
)
1928 #ifndef KHTML_NO_TYPE_AHEAD_FIND
1929 if(d
->typeAheadActivated
) {
1935 if( d
->scrollSuspendPreActivate
&& _ke
->key() != Qt::Key_Shift
)
1936 d
->scrollSuspendPreActivate
= false;
1937 if( _ke
->key() == Qt::Key_Shift
&& d
->scrollSuspendPreActivate
&& !(_ke
->modifiers() & Qt::ShiftModifier
))
1938 if (d
->scrollTimerId
) {
1939 d
->scrollSuspended
= !d
->scrollSuspended
;
1940 if (d
->scrollSuspended
)
1944 if (d
->accessKeysEnabled
)
1946 if (d
->accessKeysPreActivate
&& _ke
->key() != Qt::Key_Control
)
1947 d
->accessKeysPreActivate
=false;
1948 if (d
->accessKeysPreActivate
&& !(_ke
->modifiers() & Qt::ControlModifier
))
1950 displayAccessKeys();
1951 m_part
->setStatusBarText(i18n("Access Keys activated"),KHTMLPart::BarOverrideText
);
1952 d
->accessKeysActivated
= true;
1953 d
->accessKeysPreActivate
= false;
1957 else if (d
->accessKeysActivated
)
1959 accessKeysTimeout();
1966 if ( dispatchKeyEvent( _ke
) )
1972 QScrollArea::keyReleaseEvent(_ke
);
1975 bool KHTMLView::focusNextPrevChild( bool next
)
1977 // Now try to find the next child
1978 if (m_part
->xmlDocImpl() && focusNextPrevNode(next
))
1980 if (m_part
->xmlDocImpl()->focusNode())
1981 kDebug() << "focusNode.name: "
1982 << m_part
->xmlDocImpl()->focusNode()->nodeName().string() << endl
;
1983 return true; // focus node found
1986 // If we get here, pass tabbing control up to the next/previous child in our parent
1987 d
->pseudoFocusNode
= KHTMLViewPrivate::PFNone
;
1988 if (m_part
->parentPart() && m_part
->parentPart()->view())
1989 return m_part
->parentPart()->view()->focusNextPrevChild(next
);
1991 return QWidget::focusNextPrevChild(next
);
1994 void KHTMLView::doAutoScroll()
1996 QPoint pos
= QCursor::pos();
1998 KHTMLView
* v
= m_kwp
->isRedirected() ? m_kwp
->rootViewPos(off
) : this;
1999 pos
= v
->viewport()->mapFromGlobal( pos
);
2002 viewportToContents(pos
.x(), pos
.y(), xm
, ym
); // ###
2004 pos
= QPoint(pos
.x() - viewport()->x(), pos
.y() - viewport()->y());
2005 if ( (pos
.y() < 0) || (pos
.y() > visibleHeight()) ||
2006 (pos
.x() < 0) || (pos
.x() > visibleWidth()) )
2008 ensureVisible( xm
, ym
, 0, 5 );
2010 #ifndef KHTML_NO_SELECTION
2011 // extend the selection while scrolling
2012 DOM::Node innerNode
;
2013 if (m_part
->isExtendingSelection()) {
2014 RenderObject::NodeInfo
renderInfo(true/*readonly*/, false/*active*/);
2015 m_part
->xmlDocImpl()->renderer()->layer()
2016 ->nodeAtPoint(renderInfo
, xm
, ym
);
2017 innerNode
= renderInfo
.innerNode();
2020 if (innerNode
.handle() && innerNode
.handle()->renderer()
2021 && innerNode
.handle()->renderer()->shouldSelect()) {
2022 m_part
->extendSelectionTo(xm
, ym
, innerNode
);
2024 #endif // KHTML_NO_SELECTION
2028 // KHTML defines its own stacking order for any object and thus takes
2029 // control of widget painting whenever it can. This is called "redirection".
2031 // Redirected widgets are placed off screen. When they are declared as a child of our view (ChildPolished event),
2032 // an event filter is installed, so as to catch any paint event and translate them as update() of the view's main widget.
2034 // Painting also happens spontaneously within widgets. In this case, the widget would update() parts of itself.
2035 // While this ordinarily results in a paintEvent being schedduled, it is not the case with off screen widgets.
2036 // Thus update() is monitored by using the mechanism that deffers any update call happening during a paint event,
2037 // transforming it into a posted UpdateLater event. Hence the need to set Qt::WA_WState_InPaintEvent on redirected widgets.
2039 // Once the UpdateLater event has been received, Qt::WA_WState_InPaintEvent is removed and the process continues
2040 // with the update of the corresponding rect on the view. That in turn will make our painting subsystem render()
2041 // the widget at the correct stacking position.
2043 // For non-redirected (e.g. external) widgets, z-order is honoured through masking. cf.RenderLayer::updateWidgetMasks
2045 static void handleWidget(QWidget
* w
, KHTMLView
* view
, bool recurse
=true)
2050 if (!qobject_cast
<QFrame
*>(w
))
2051 w
->setAttribute( Qt::WA_NoSystemBackground
);
2053 w
->setAttribute(Qt::WA_WState_InPaintEvent
);
2054 w
->setAttribute(Qt::WA_OpaquePaintEvent
);
2055 w
->installEventFilter(view
);
2059 if (qobject_cast
<KHTMLView
*>(w
)) {
2060 handleWidget(static_cast<KHTMLView
*>(w
)->widget(), view
, false);
2061 handleWidget(static_cast<KHTMLView
*>(w
)->horizontalScrollBar(), view
, false);
2062 handleWidget(static_cast<KHTMLView
*>(w
)->verticalScrollBar(), view
, false);
2066 QObjectList children
= w
->children();
2067 foreach (QObject
* object
, children
) {
2068 QWidget
*widget
= qobject_cast
<QWidget
*>(object
);
2070 handleWidget(widget
, view
);
2074 class KHTMLBackingStoreHackWidget
: public QWidget
2077 void publicEvent(QEvent
*e
)
2083 bool KHTMLView::viewportEvent ( QEvent
* e
)
2085 switch (e
->type()) {
2086 // those must not be dispatched to the specialized handlers
2087 // as widgetEvent() already took care of that
2088 case QEvent::MouseButtonPress
:
2089 case QEvent::MouseButtonRelease
:
2090 case QEvent::MouseButtonDblClick
:
2091 case QEvent::MouseMove
:
2092 #ifndef QT_NO_WHEELEVENT
2095 case QEvent::ContextMenu
:
2096 case QEvent::DragEnter
:
2097 case QEvent::DragMove
:
2098 case QEvent::DragLeave
:
2101 case QEvent::Paint
: {
2102 QRect r
= static_cast<QPaintEvent
*>(e
)->rect();
2103 r
.setX(r
.x() +contentsX());
2104 r
.setY(r
.y() +contentsY());
2112 return QScrollArea::viewportEvent(e
);
2115 static void setInPaintEventFlag(QWidget
* w
, bool b
= true, bool recurse
=true)
2117 w
->setAttribute(Qt::WA_WState_InPaintEvent
, b
);
2121 if (qobject_cast
<KHTMLView
*>(w
)) {
2122 setInPaintEventFlag(static_cast<KHTMLView
*>(w
)->widget(), b
, false);
2123 setInPaintEventFlag(static_cast<KHTMLView
*>(w
)->horizontalScrollBar(), b
, false);
2124 setInPaintEventFlag(static_cast<KHTMLView
*>(w
)->verticalScrollBar(), b
, false);
2128 foreach(QObject
* cw
, w
->children()) {
2129 if (cw
->isWidgetType() && ! static_cast<QWidget
*>(cw
)->isWindow()
2130 && !(static_cast<QWidget
*>(cw
)->windowModality() & Qt::ApplicationModal
)) {
2131 setInPaintEventFlag(static_cast<QWidget
*>(cw
), b
);
2136 bool KHTMLView::eventFilter(QObject
*o
, QEvent
*e
)
2138 if ( e
->type() == QEvent::ShortcutOverride
) {
2139 QKeyEvent
* ke
= (QKeyEvent
*) e
;
2140 if (m_part
->isEditable() || m_part
->isCaretMode()
2141 || (m_part
->xmlDocImpl() && m_part
->xmlDocImpl()->focusNode()
2142 && m_part
->xmlDocImpl()->focusNode()->isContentEditable())) {
2143 if ( (ke
->modifiers() & Qt::ControlModifier
) || (ke
->modifiers() & Qt::ShiftModifier
) ) {
2144 switch ( ke
->key() ) {
2160 if ( e
->type() == QEvent::Leave
) {
2161 if ( d
->cursorIconWidget
)
2162 d
->cursorIconWidget
->hide();
2163 m_part
->resetHoverText();
2166 QWidget
*view
= widget();
2170 else if (e
->type() == QEvent::Resize
) {
2174 } else if (o
->isWidgetType()) {
2175 QWidget
*v
= static_cast<QWidget
*>(o
);
2177 while (v
&& v
!= view
) {
2179 v
= v
->parentWidget();
2181 KHTMLWidget
* k
= dynamic_cast<KHTMLWidget
*>(c
);
2182 if (v
&& k
&& k
->m_kwp
->isRedirected()) {
2184 bool isUpdate
= false;
2185 QWidget
*w
= static_cast<QWidget
*>(o
);
2187 case QEvent::UpdateRequest
: {
2188 // implicitly call qt_syncBackingStore(w)
2189 static_cast<KHTMLBackingStoreHackWidget
*>(w
)->publicEvent(e
);
2193 case QEvent::UpdateLater
:
2197 if (!allowWidgetPaintEvents
) {
2198 // eat the event. Like this we can control exactly when the widget
2203 while (v
&& v
->parentWidget() != view
) {
2206 v
= v
->parentWidget();
2209 QPoint ap
= k
->m_kwp
->absolutePos();
2213 QRect pr
= isUpdate
? static_cast<QUpdateLaterEvent
*>(e
)->region().boundingRect() : static_cast<QPaintEvent
*>(e
)->rect();
2214 bool asap
= !d
->contentsMoving
&& qobject_cast
<QAbstractScrollArea
*>(c
);
2217 setInPaintEventFlag(w
, false);
2219 w
->repaint(static_cast<QUpdateLaterEvent
*>(e
)->region());
2221 w
->update(static_cast<QUpdateLaterEvent
*>(e
)->region());
2222 setInPaintEventFlag(w
);
2225 // QScrollView needs fast repaints
2226 if ( asap
&& !isUpdate
&& !d
->painting
&& m_part
->xmlDocImpl() && m_part
->xmlDocImpl()->renderer() &&
2227 !static_cast<khtml::RenderCanvas
*>(m_part
->xmlDocImpl()->renderer())->needsLayout() ) {
2228 repaintContents(x
+ pr
.x(), y
+ pr
.y(),
2229 pr
.width(), pr
.height()+1); // ### investigate that +1 (shows up when
2230 // updating e.g a textarea's blinking cursor)
2231 } else if (!d
->painting
) {
2232 scheduleRepaint(x
+ pr
.x(), y
+ pr
.y(),
2233 pr
.width(), pr
.height()+1, asap
);
2237 case QEvent::MouseMove
:
2238 case QEvent::MouseButtonPress
:
2239 case QEvent::MouseButtonRelease
:
2240 case QEvent::MouseButtonDblClick
: {
2242 if (0 && w
->parentWidget() == view
&& !qobject_cast
<QScrollBar
*>(w
) && !::qobject_cast
<QScrollBar
*>(w
)) {
2243 QMouseEvent
*me
= static_cast<QMouseEvent
*>(e
);
2244 QPoint pt
= w
->mapTo( view
, me
->pos());
2245 QMouseEvent
me2(me
->type(), pt
, me
->button(), me
->buttons(), me
->modifiers());
2247 if (e
->type() == QEvent::MouseMove
)
2248 mouseMoveEvent(&me2
);
2249 else if(e
->type() == QEvent::MouseButtonPress
)
2250 mousePressEvent(&me2
);
2251 else if(e
->type() == QEvent::MouseButtonRelease
)
2252 mouseReleaseEvent(&me2
);
2254 mouseDoubleClickEvent(&me2
);
2259 case QEvent::KeyPress
:
2260 case QEvent::KeyRelease
:
2261 if (w
->parentWidget() == view
&& !qobject_cast
<QScrollBar
*>(w
)) {
2262 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(e
);
2263 if (e
->type() == QEvent::KeyPress
)
2266 keyReleaseEvent(ke
);
2270 case QEvent::FocusIn
:
2271 case QEvent::FocusOut
:
2278 //qDebug("eating event");
2284 // kDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type();
2285 return QScrollArea::eventFilter(o
, e
);
2288 bool KHTMLView::widgetEvent(QEvent
* e
)
2290 switch (e
->type()) {
2291 case QEvent::MouseButtonPress
:
2292 case QEvent::MouseButtonRelease
:
2293 case QEvent::MouseButtonDblClick
:
2294 case QEvent::MouseMove
:
2296 #ifndef QT_NO_WHEELEVENT
2299 case QEvent::ContextMenu
:
2300 case QEvent::DragEnter
:
2301 case QEvent::DragMove
:
2302 case QEvent::DragLeave
:
2304 return QFrame::event(e
);
2305 case QEvent::ChildPolished
: {
2306 // we need to install an event filter on all children of the widget() to
2307 // be able to get correct stacking of children within the document.
2308 QObject
*c
= static_cast<QChildEvent
*>(e
)->child();
2309 if (c
->isWidgetType()) {
2310 QWidget
*w
= static_cast<QWidget
*>(c
);
2311 // don't install the event filter on toplevels
2312 if (!(w
->windowFlags() & Qt::Window
) && !(w
->windowModality() & Qt::ApplicationModal
)) {
2313 KHTMLWidget
* k
= dynamic_cast<KHTMLWidget
*>(w
);
2314 if (k
&& k
->m_kwp
->isRedirected()) {
2316 handleWidget(w
, this);
2321 case QEvent::Move
: {
2322 if (static_cast<QMoveEvent
*>(e
)->pos() != QPoint(0,0)) {
2323 widget()->move(0,0);
2334 DOM::NodeImpl
*KHTMLView::nodeUnderMouse() const
2336 return d
->underMouse
;
2339 DOM::NodeImpl
*KHTMLView::nonSharedNodeUnderMouse() const
2341 return d
->underMouseNonShared
;
2344 bool KHTMLView::scrollTo(const QRect
&bounds
)
2346 d
->scrollingSelf
= true; // so scroll events get ignored
2351 xe
= bounds
.right();
2352 ye
= bounds
.bottom();
2354 //kDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y;
2359 int curHeight
= visibleHeight();
2360 int curWidth
= visibleWidth();
2362 if (ye
-y
>curHeight
-d
->borderY
)
2363 ye
= y
+ curHeight
- d
->borderY
;
2365 if (xe
-x
>curWidth
-d
->borderX
)
2366 xe
= x
+ curWidth
- d
->borderX
;
2368 // is xpos of target left of the view's border?
2369 if (x
< contentsX() + d
->borderX
)
2370 deltax
= x
- contentsX() - d
->borderX
;
2371 // is xpos of target right of the view's right border?
2372 else if (xe
+ d
->borderX
> contentsX() + curWidth
)
2373 deltax
= xe
+ d
->borderX
- ( contentsX() + curWidth
);
2377 // is ypos of target above upper border?
2378 if (y
< contentsY() + d
->borderY
)
2379 deltay
= y
- contentsY() - d
->borderY
;
2380 // is ypos of target below lower border?
2381 else if (ye
+ d
->borderY
> contentsY() + curHeight
)
2382 deltay
= ye
+ d
->borderY
- ( contentsY() + curHeight
);
2386 int maxx
= curWidth
-d
->borderX
;
2387 int maxy
= curHeight
-d
->borderY
;
2389 int scrollX
, scrollY
;
2391 scrollX
= deltax
> 0 ? (deltax
> maxx
? maxx
: deltax
) : deltax
== 0 ? 0 : (deltax
>-maxx
? deltax
: -maxx
);
2392 scrollY
= deltay
> 0 ? (deltay
> maxy
? maxy
: deltay
) : deltay
== 0 ? 0 : (deltay
>-maxy
? deltay
: -maxy
);
2394 if (contentsX() + scrollX
< 0)
2395 scrollX
= -contentsX();
2396 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX
)
2397 scrollX
= contentsWidth() - visibleWidth() - contentsX();
2399 if (contentsY() + scrollY
< 0)
2400 scrollY
= -contentsY();
2401 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY
)
2402 scrollY
= contentsHeight() - visibleHeight() - contentsY();
2404 horizontalScrollBar()->setValue( horizontalScrollBar()->value()+scrollX
);
2405 verticalScrollBar()->setValue( verticalScrollBar()->value()+scrollY
);
2407 d
->scrollingSelf
= false;
2409 if ( (abs(deltax
)<=maxx
) && (abs(deltay
)<=maxy
) )
2415 bool KHTMLView::focusNextPrevNode(bool next
)
2417 // Sets the focus node of the document to be the node after (or if
2418 // next is false, before) the current focus node. Only nodes that
2419 // are selectable (i.e. for which isFocusable() returns true) are
2420 // taken into account, and the order used is that specified in the
2421 // HTML spec (see DocumentImpl::nextFocusNode() and
2422 // DocumentImpl::previousFocusNode() for details).
2424 DocumentImpl
*doc
= m_part
->xmlDocImpl();
2425 NodeImpl
*oldFocusNode
= doc
->focusNode();
2427 // See whether we're in the middle of a detach, or hiding of the
2428 // widget. In this case, we will just clear focus, being careful not to emit events
2429 // or update rendering. Doing this also prevents the code below from going bonkers with
2430 // oldFocusNode not actually being focusable, etc.
2432 if ((oldFocusNode
->renderer() && !oldFocusNode
->renderer()->parent())
2433 || !oldFocusNode
->isTabFocusable()) {
2434 doc
->quietResetFocus();
2440 // If the user has scrolled the document, then instead of picking
2441 // the next focusable node in the document, use the first one that
2442 // is within the visible area (if possible).
2443 if (d
->scrollBarMoved
)
2447 toFocus
= doc
->nextFocusNode(oldFocusNode
);
2449 toFocus
= doc
->previousFocusNode(oldFocusNode
);
2451 if (!toFocus
&& oldFocusNode
) {
2453 toFocus
= doc
->nextFocusNode(NULL
);
2455 toFocus
= doc
->previousFocusNode(NULL
);
2458 while (toFocus
&& toFocus
!= oldFocusNode
)
2461 QRect focusNodeRect
= toFocus
->getRect();
2462 if ((focusNodeRect
.left() > contentsX()) && (focusNodeRect
.right() < contentsX() + visibleWidth()) &&
2463 (focusNodeRect
.top() > contentsY()) && (focusNodeRect
.bottom() < contentsY() + visibleHeight())) {
2465 QRect r
= toFocus
->getRect();
2466 ensureVisible( r
.right(), r
.bottom());
2467 ensureVisible( r
.left(), r
.top());
2468 d
->scrollBarMoved
= false;
2469 d
->tabMovePending
= false;
2470 d
->lastTabbingDirection
= next
;
2471 d
->pseudoFocusNode
= KHTMLViewPrivate::PFNone
;
2472 m_part
->xmlDocImpl()->setFocusNode(toFocus
);
2473 Node
guard(toFocus
);
2474 if (!toFocus
->hasOneRef() )
2476 emit m_part
->nodeActivated(Node(toFocus
));
2482 toFocus
= doc
->nextFocusNode(toFocus
);
2484 toFocus
= doc
->previousFocusNode(toFocus
);
2486 if (!toFocus
&& oldFocusNode
)
2490 toFocus
= doc
->nextFocusNode(NULL
);
2494 toFocus
= doc
->previousFocusNode(NULL
);
2499 d
->scrollBarMoved
= false;
2503 if (!oldFocusNode
&& d
->pseudoFocusNode
== KHTMLViewPrivate::PFNone
)
2505 ensureVisible(contentsX(), next
?0:contentsHeight());
2506 d
->scrollBarMoved
= false;
2507 d
->pseudoFocusNode
= next
?KHTMLViewPrivate::PFTop
:KHTMLViewPrivate::PFBottom
;
2511 NodeImpl
*newFocusNode
= NULL
;
2513 if (d
->tabMovePending
&& next
!= d
->lastTabbingDirection
)
2515 //kDebug ( 6000 ) << " tab move pending and tabbing direction changed!\n";
2516 newFocusNode
= oldFocusNode
;
2520 if (oldFocusNode
|| d
->pseudoFocusNode
== KHTMLViewPrivate::PFTop
)
2521 newFocusNode
= doc
->nextFocusNode(oldFocusNode
);
2525 if (oldFocusNode
|| d
->pseudoFocusNode
== KHTMLViewPrivate::PFBottom
)
2526 newFocusNode
= doc
->previousFocusNode(oldFocusNode
);
2529 bool targetVisible
= false;
2534 targetVisible
= scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight()-d
->borderY
,0,0));
2538 targetVisible
= scrollTo(QRect(contentsX()+visibleWidth()/2,d
->borderY
,0,0));
2543 // if it's an editable element, activate the caret
2544 if (!m_part
->isCaretMode() && newFocusNode
->isContentEditable()) {
2545 kDebug(6200) << "show caret! fn: " << newFocusNode
->nodeName().string() << endl
;
2546 m_part
->clearCaretRectIfNeeded();
2547 m_part
->d
->editor_context
.m_selection
.moveTo(Position(newFocusNode
, 0L));
2548 m_part
->setCaretVisible(true);
2550 m_part
->setCaretVisible(false);
2551 kDebug(6200) << "hide caret! fn: " << newFocusNode
->nodeName().string() << endl
;
2553 m_part
->notifySelectionChanged();
2555 targetVisible
= scrollTo(newFocusNode
->getRect());
2560 //kDebug ( 6000 ) << " target reached.\n";
2561 d
->tabMovePending
= false;
2563 m_part
->xmlDocImpl()->setFocusNode(newFocusNode
);
2566 Node
guard(newFocusNode
);
2567 if (!newFocusNode
->hasOneRef() )
2569 emit m_part
->nodeActivated(Node(newFocusNode
));
2575 d
->pseudoFocusNode
= next
?KHTMLViewPrivate::PFBottom
:KHTMLViewPrivate::PFTop
;
2581 if (!d
->tabMovePending
)
2582 d
->lastTabbingDirection
= next
;
2583 d
->tabMovePending
= true;
2588 void KHTMLView::displayAccessKeys()
2590 QVector
< QChar
> taken
;
2591 displayAccessKeys( NULL
, this, taken
, false );
2592 displayAccessKeys( NULL
, this, taken
, true );
2595 void KHTMLView::displayAccessKeys( KHTMLView
* caller
, KHTMLView
* origview
, QVector
< QChar
>& taken
, bool use_fallbacks
)
2597 QMap
< ElementImpl
*, QChar
> fallbacks
;
2599 fallbacks
= buildFallbackAccessKeys();
2600 for( NodeImpl
* n
= m_part
->xmlDocImpl(); n
!= NULL
; n
= n
->traverseNextNode()) {
2601 if( n
->isElementNode()) {
2602 ElementImpl
* en
= static_cast< ElementImpl
* >( n
);
2603 DOMString s
= en
->getAttribute( ATTR_ACCESSKEY
);
2605 if( s
.length() == 1 ) {
2606 QChar a
= s
.string()[ 0 ].toUpper();
2607 if( qFind( taken
.begin(), taken
.end(), a
) == taken
.end()) // !contains
2610 if( accesskey
.isNull() && fallbacks
.contains( en
)) {
2611 QChar a
= fallbacks
[ en
].toUpper();
2612 if( qFind( taken
.begin(), taken
.end(), a
) == taken
.end()) // !contains
2613 accesskey
= QString( "<qt><i>" ) + a
+ "</i></qt>";
2615 if( !accesskey
.isNull()) {
2616 QRect rec
=en
->getRect();
2617 QLabel
*lab
=new QLabel(accesskey
,viewport());
2618 lab
->setAttribute(Qt::WA_DeleteOnClose
);
2619 connect( origview
, SIGNAL(hideAccessKeys()), lab
, SLOT(close()) );
2620 connect( this, SIGNAL(repaintAccessKeys()), lab
, SLOT(repaint()));
2621 lab
->setPalette(QToolTip::palette());
2622 lab
->setLineWidth(2);
2623 lab
->setFrameStyle(QFrame::Box
| QFrame::Plain
);
2626 lab
->setParent( widget() );
2627 lab
->setAutoFillBackground(true);
2629 qMin(rec
.left()+rec
.width()/2 - contentsX(), contentsWidth() - lab
->width()),
2630 qMin(rec
.top()+rec
.height()/2 - contentsY(), contentsHeight() - lab
->height()));
2632 taken
.append( accesskey
[ 0 ] );
2639 QList
<KParts::ReadOnlyPart
*> frames
= m_part
->frames();
2640 foreach( KParts::ReadOnlyPart
* cur
, frames
) {
2641 if( !qobject_cast
<KHTMLPart
*>(cur
) )
2643 KHTMLPart
* part
= static_cast< KHTMLPart
* >( cur
);
2644 if( part
->view() && part
->view() != caller
)
2645 part
->view()->displayAccessKeys( this, origview
, taken
, use_fallbacks
);
2648 // pass up to the parent
2649 if (m_part
->parentPart() && m_part
->parentPart()->view()
2650 && m_part
->parentPart()->view() != caller
)
2651 m_part
->parentPart()->view()->displayAccessKeys( this, origview
, taken
, use_fallbacks
);
2654 bool KHTMLView::isScrollingFromMouseWheel() const
2656 return d
->scrollingFromWheel
!= QPoint(-1,-1);
2659 void KHTMLView::accessKeysTimeout()
2661 d
->accessKeysActivated
=false;
2662 d
->accessKeysPreActivate
= false;
2663 m_part
->setStatusBarText(QString(), KHTMLPart::BarOverrideText
);
2664 emit
hideAccessKeys();
2667 // Handling of the HTML accesskey attribute.
2668 bool KHTMLView::handleAccessKey( const QKeyEvent
* ev
)
2670 // Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
2671 // but this code must act as if the modifiers weren't pressed
2673 if( ev
->key() >= Qt::Key_A
&& ev
->key() <= Qt::Key_Z
)
2674 c
= 'A' + ev
->key() - Qt::Key_A
;
2675 else if( ev
->key() >= Qt::Key_0
&& ev
->key() <= Qt::Key_9
)
2676 c
= '0' + ev
->key() - Qt::Key_0
;
2678 // TODO fake XKeyEvent and XLookupString ?
2679 // This below seems to work e.g. for eacute though.
2680 if( ev
->text().length() == 1 )
2681 c
= ev
->text()[ 0 ];
2685 return focusNodeWithAccessKey( c
);
2688 bool KHTMLView::focusNodeWithAccessKey( QChar c
, KHTMLView
* caller
)
2690 DocumentImpl
*doc
= m_part
->xmlDocImpl();
2693 ElementImpl
* node
= doc
->findAccessKeyElement( c
);
2695 QList
<KParts::ReadOnlyPart
*> frames
= m_part
->frames();
2696 foreach( KParts::ReadOnlyPart
* cur
, frames
) {
2697 if( !qobject_cast
<KHTMLPart
*>(cur
) )
2699 KHTMLPart
* part
= static_cast< KHTMLPart
* >( cur
);
2700 if( part
->view() && part
->view() != caller
2701 && part
->view()->focusNodeWithAccessKey( c
, this ))
2704 // pass up to the parent
2705 if (m_part
->parentPart() && m_part
->parentPart()->view()
2706 && m_part
->parentPart()->view() != caller
2707 && m_part
->parentPart()->view()->focusNodeWithAccessKey( c
, this ))
2709 if( caller
== NULL
) { // the active frame (where the accesskey was pressed)
2710 const QMap
< ElementImpl
*, QChar
> fallbacks
= buildFallbackAccessKeys();
2711 for( QMap
< ElementImpl
*, QChar
>::ConstIterator it
= fallbacks
.begin();
2712 it
!= fallbacks
.end();
2723 // Scroll the view as necessary to ensure that the new focus node is visible
2725 QRect r
= node
->getRect();
2726 ensureVisible( r
.right(), r
.bottom());
2727 ensureVisible( r
.left(), r
.top());
2730 if( node
->isFocusable()) {
2731 if (node
->id()==ID_LABEL
) {
2732 // if Accesskey is a label, give focus to the label's referrer.
2733 node
=static_cast<ElementImpl
*>(static_cast< HTMLLabelElementImpl
* >( node
)->getFormElement());
2734 if (!node
) return true;
2737 // Set focus node on the document
2739 #warning "port QFocusEvent::setReason( QFocusEvent::Shortcut ); to qt4"
2741 //QFocusEvent::setReason( QFocusEvent::Shortcut );
2742 m_part
->xmlDocImpl()->setFocusNode(node
);
2744 #warning "port QFocusEvent::resetReason(); to qt4"
2746 //QFocusEvent::resetReason();
2747 if( node
!= NULL
&& node
->hasOneRef()) // deleted, only held by guard
2749 emit m_part
->nodeActivated(Node(node
));
2750 if( node
!= NULL
&& node
->hasOneRef())
2754 switch( node
->id()) {
2756 static_cast< HTMLAnchorElementImpl
* >( node
)->click();
2759 static_cast< HTMLInputElementImpl
* >( node
)->click();
2762 static_cast< HTMLButtonElementImpl
* >( node
)->click();
2765 static_cast< HTMLAreaElementImpl
* >( node
)->click();
2768 break; // just focusing it is enough
2776 static QString
getElementText( NodeImpl
* start
, bool after
)
2778 QString ret
; // nextSibling(), to go after e.g. </select>
2779 for( NodeImpl
* n
= after
? start
->nextSibling() : start
->traversePreviousNode();
2781 n
= after
? n
->traverseNextNode() : n
->traversePreviousNode()) {
2782 if( n
->isTextNode()) {
2784 ret
+= static_cast< TextImpl
* >( n
)->toString().string();
2786 ret
.prepend( static_cast< TextImpl
* >( n
)->toString().string());
2816 if( ret
.trimmed().isEmpty())
2820 return ret
.simplified();
2824 return ret
.simplified();
2827 static QMap
< NodeImpl
*, QString
> buildLabels( NodeImpl
* start
)
2829 QMap
< NodeImpl
*, QString
> ret
;
2830 for( NodeImpl
* n
= start
;
2832 n
= n
->traverseNextNode()) {
2833 if( n
->id() == ID_LABEL
) {
2834 HTMLLabelElementImpl
* label
= static_cast< HTMLLabelElementImpl
* >( n
);
2835 NodeImpl
* labelfor
= label
->getFormElement();
2837 ret
[ labelfor
] = label
->innerText().string().simplified();
2844 struct AccessKeyData
{
2845 ElementImpl
* element
;
2848 int priority
; // 10(highest) - 0(lowest)
2852 QMap
< ElementImpl
*, QChar
> KHTMLView::buildFallbackAccessKeys() const
2854 // build a list of all possible candidate elements that could use an accesskey
2855 QLinkedList
< AccessKeyData
> data
; // Note: this has to be a list type that keep iterators valid
2856 // when other entries are removed
2857 QMap
< NodeImpl
*, QString
> labels
= buildLabels( m_part
->xmlDocImpl());
2858 for( NodeImpl
* n
= m_part
->xmlDocImpl();
2860 n
= n
->traverseNextNode()) {
2861 if( n
->isElementNode()) {
2862 ElementImpl
* element
= static_cast< ElementImpl
* >( n
);
2863 if( element
->getAttribute( ATTR_ACCESSKEY
).length() == 1 )
2864 continue; // has accesskey set, ignore
2865 if( element
->renderer() == NULL
)
2866 continue; // not visible
2870 bool ignore
= false;
2871 bool text_after
= false;
2872 bool text_before
= false;
2873 switch( element
->id()) {
2875 url
= khtml::parseURL(element
->getAttribute(ATTR_HREF
)).string();
2876 if( url
.isEmpty()) // doesn't have href, it's only an anchor
2878 text
= static_cast< HTMLElementImpl
* >( element
)->innerText().string().simplified();
2882 HTMLInputElementImpl
* in
= static_cast< HTMLInputElementImpl
* >( element
);
2883 switch( in
->inputType()) {
2884 case HTMLInputElementImpl::SUBMIT
:
2885 text
= in
->value().string();
2887 text
= i18n( "Submit" );
2890 case HTMLInputElementImpl::IMAGE
:
2891 text
= in
->altText().string();
2894 case HTMLInputElementImpl::BUTTON
:
2895 text
= in
->value().string();
2898 case HTMLInputElementImpl::RESET
:
2899 text
= in
->value().string();
2901 text
= i18n( "Reset" );
2904 case HTMLInputElementImpl::HIDDEN
:
2907 case HTMLInputElementImpl::CHECKBOX
:
2908 case HTMLInputElementImpl::RADIO
:
2912 case HTMLInputElementImpl::TEXT
:
2913 case HTMLInputElementImpl::PASSWORD
:
2914 case HTMLInputElementImpl::FILE:
2925 text
= static_cast< HTMLElementImpl
* >( element
)->innerText().string().simplified();
2926 switch( static_cast< HTMLButtonElementImpl
* >( element
)->buttonType()) {
2927 case HTMLButtonElementImpl::SUBMIT
:
2929 text
= i18n( "Submit" );
2932 case HTMLButtonElementImpl::RESET
:
2934 text
= i18n( "Reset" );
2942 case ID_SELECT
: // these don't have accesskey attribute, but quick access may be handy
2951 ignore
= !element
->isFocusable();
2957 if( text
.isNull() && labels
.contains( element
))
2958 text
= labels
[ element
];
2959 if( text
.isNull() && text_before
)
2960 text
= getElementText( element
, false );
2961 if( text
.isNull() && text_after
)
2962 text
= getElementText( element
, true );
2963 text
= text
.trimmed();
2964 // increase priority of items which have explicitly specified accesskeys in the config
2965 const QList
< QPair
< QString
, QChar
> > priorities
2966 = m_part
->settings()->fallbackAccessKeysAssignments();
2967 for( QList
< QPair
< QString
, QChar
> >::ConstIterator it
= priorities
.begin();
2968 it
!= priorities
.end();
2970 if( text
== (*it
).first
)
2973 AccessKeyData tmp
= { element
, text
, url
, priority
};
2978 QList
< QChar
> keys
;
2979 for( char c
= 'A'; c
<= 'Z'; ++c
)
2981 for( char c
= '0'; c
<= '9'; ++c
)
2983 for( NodeImpl
* n
= m_part
->xmlDocImpl();
2985 n
= n
->traverseNextNode()) {
2986 if( n
->isElementNode()) {
2987 ElementImpl
* en
= static_cast< ElementImpl
* >( n
);
2988 DOMString s
= en
->getAttribute( ATTR_ACCESSKEY
);
2989 if( s
.length() == 1 ) {
2990 QChar c
= s
.string()[ 0 ].toUpper();
2991 keys
.removeAll( c
); // remove manually assigned accesskeys
2996 QMap
< ElementImpl
*, QChar
> ret
;
2997 for( int priority
= 10; priority
>= 0; --priority
) {
2998 for( QLinkedList
< AccessKeyData
>::Iterator it
= data
.begin();
3001 if( (*it
).priority
!= priority
) {
3007 QString text
= (*it
).text
;
3009 if( key
.isNull() && !text
.isEmpty()) {
3010 const QList
< QPair
< QString
, QChar
> > priorities
3011 = m_part
->settings()->fallbackAccessKeysAssignments();
3012 for( QList
< QPair
< QString
, QChar
> >::ConstIterator it
= priorities
.begin();
3013 it
!= priorities
.end();
3015 if( text
== (*it
).first
&& keys
.contains( (*it
).second
)) {
3020 // try first to select the first character as the accesskey,
3021 // then first character of the following words,
3022 // and then simply the first free character
3023 if( key
.isNull() && !text
.isEmpty()) {
3024 const QStringList words
= text
.split( ' ' );
3025 for( QStringList::ConstIterator it
= words
.begin();
3028 if( keys
.contains( (*it
)[ 0 ].toUpper())) {
3029 key
= (*it
)[ 0 ].toUpper();
3034 if( key
.isNull() && !text
.isEmpty()) {
3035 for( int i
= 0; i
< text
.length(); ++i
) {
3036 if( keys
.contains( text
[ i
].toUpper())) {
3037 key
= text
[ i
].toUpper();
3044 ret
[ (*it
).element
] = key
;
3045 keys
.removeAll( key
);
3046 QString url
= (*it
).url
;
3047 it
= data
.erase( it
);
3048 // assign the same accesskey also to other elements pointing to the same url
3049 if( !url
.isEmpty() && !url
.startsWith( "javascript:", Qt::CaseInsensitive
)) {
3050 for( QLinkedList
< AccessKeyData
>::Iterator it2
= data
.begin();
3053 if( (*it2
).url
== url
) {
3054 ret
[ (*it2
).element
] = key
;
3057 it2
= data
.erase( it2
);
3067 void KHTMLView::setMediaType( const QString
&medium
)
3072 QString
KHTMLView::mediaType() const
3077 bool KHTMLView::pagedMode() const
3082 void KHTMLView::setWidgetVisible(RenderWidget
* w
, bool vis
)
3085 d
->visibleWidgets
.insert(w
, w
->widget());
3088 d
->visibleWidgets
.remove(w
);
3091 bool KHTMLView::needsFullRepaint() const
3093 return d
->needsFullRepaint
;
3097 class QPointerDeleter
3100 explicit QPointerDeleter(QObject
* o
) : obj(o
) {}
3101 ~QPointerDeleter() { delete obj
; }
3103 const QPointer
<QObject
> obj
;
3107 void KHTMLView::print(bool quick
)
3109 if(!m_part
->xmlDocImpl()) return;
3110 khtml::RenderCanvas
*root
= static_cast<khtml::RenderCanvas
*>(m_part
->xmlDocImpl()->renderer());
3113 QPointer
<KHTMLPrintSettings
> printSettings(new KHTMLPrintSettings
); //XXX: doesn't save settings between prints like this
3114 const QPointerDeleter
settingsDeleter(printSettings
); //the printdialog takes ownership of the settings widget, thus this workaround to avoid double deletion
3116 QPointer
<QPrintDialog
> dialog
= KdePrint::createPrintDialog(&printer
, QList
<QWidget
*>() << printSettings
, this);
3117 const QPointerDeleter
dialogDeleter(dialog
);
3119 QString docname
= m_part
->xmlDocImpl()->URL().prettyUrl();
3120 if ( !docname
.isEmpty() )
3121 docname
= KStringHandler::csqueeze(docname
, 80);
3123 if(quick
|| (dialog
->exec() && dialog
)) { /*'this' and thus dialog might have been deleted while exec()!*/
3124 viewport()->setCursor( Qt::WaitCursor
); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
3126 printer
.setFullPage(false);
3127 printer
.setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR
).arg(KDE_VERSION_MINOR
).arg(KDE_VERSION_RELEASE
));
3128 printer
.setDocName(docname
);
3130 QPainter
*p
= new QPainter
;
3131 p
->begin( &printer
);
3132 khtml::setPrintPainter( p
);
3134 m_part
->xmlDocImpl()->setPaintDevice( &printer
);
3135 QString oldMediaType
= mediaType();
3136 setMediaType( "print" );
3137 // We ignore margin settings for html and body when printing
3138 // and use the default margins from the print-system
3139 // (In Qt 3.0.x the default margins are hardcoded in Qt)
3140 m_part
->xmlDocImpl()->setPrintStyleSheet( printSettings
->printFriendly() ?
3141 "* { background-image: none !important;"
3142 " background-color: white !important;"
3143 " color: black !important; }"
3144 "body { margin: 0px !important; }"
3145 "html { margin: 0px !important; }" :
3146 "body { margin: 0px !important; }"
3147 "html { margin: 0px !important; }"
3150 kDebug(6000) << "printing: physical page width = " << printer
.width()
3151 << " height = " << printer
.height() << endl
;
3152 root
->setStaticMode(true);
3153 root
->setPagedMode(true);
3154 root
->setWidth(printer
.width());
3155 // root->setHeight(printer.height());
3156 root
->setPageTop(0);
3157 root
->setPageBottom(0);
3160 m_part
->xmlDocImpl()->styleSelector()->computeFontSizes(printer
.logicalDpiY(), 100);
3161 m_part
->xmlDocImpl()->updateStyleSelector();
3162 root
->setPrintImages(printSettings
->printImages());
3163 root
->makePageBreakAvoidBlocks();
3165 root
->setNeedsLayoutAndMinMaxRecalc();
3168 // check sizes ask for action.. (scale or clip)
3170 bool printHeader
= printSettings
->printHeader();
3172 int headerHeight
= 0;
3173 QFont
headerFont("Sans Serif", 8);
3175 QString headerLeft
= KGlobal::locale()->formatDate(QDate::currentDate(),KLocale::ShortDate
);
3176 QString headerMid
= docname
;
3177 QString headerRight
;
3181 p
->setFont(headerFont
);
3182 headerHeight
= (p
->fontMetrics().lineSpacing() * 3) / 2;
3185 // ok. now print the pages.
3186 kDebug(6000) << "printing: html page width = " << root
->docWidth()
3187 << " height = " << root
->docHeight() << endl
;
3188 kDebug(6000) << "printing: margins left = " << printer
.pageRect().left() - printer
.paperRect().left()
3189 << " top = " << printer
.pageRect().top() - printer
.paperRect().top() << endl
;
3190 kDebug(6000) << "printing: paper width = " << printer
.width()
3191 << " height = " << printer
.height() << endl
;
3192 // if the width is too large to fit on the paper we just scale
3194 int pageWidth
= printer
.width();
3195 int pageHeight
= printer
.height();
3196 p
->setClipRect(0,0, pageWidth
, pageHeight
);
3198 pageHeight
-= headerHeight
;
3200 bool scalePage
= false;
3202 #ifndef QT_NO_TRANSFORMATIONS
3203 if(root
->docWidth() > printer
.width()) {
3205 scale
= ((double) printer
.width())/((double) root
->docWidth());
3206 pageHeight
= (int) (pageHeight
/scale
);
3207 pageWidth
= (int) (pageWidth
/scale
);
3208 headerHeight
= (int) (headerHeight
/scale
);
3211 kDebug(6000) << "printing: scaled html width = " << pageWidth
3212 << " height = " << pageHeight
<< endl
;
3214 root
->setHeight(pageHeight
);
3215 root
->setPageBottom(pageHeight
);
3216 root
->setNeedsLayout(true);
3217 root
->layoutIfNeeded();
3218 // m_part->slotDebugRenderTree();
3220 // Squeeze header to make it it on the page.
3223 int available_width
= printer
.width() - 10 -
3224 2 * qMax(p
->boundingRect(0, 0, printer
.width(), p
->fontMetrics().lineSpacing(), Qt::AlignLeft
, headerLeft
).width(),
3225 p
->boundingRect(0, 0, printer
.width(), p
->fontMetrics().lineSpacing(), Qt::AlignLeft
, headerRight
).width());
3226 if (available_width
< 150)
3227 available_width
= 150;
3231 headerMid
= KStringHandler::csqueeze(docname
, squeeze
);
3232 mid_width
= p
->boundingRect(0, 0, printer
.width(), p
->fontMetrics().lineSpacing(), Qt::AlignLeft
, headerMid
).width();
3234 } while (mid_width
> available_width
);
3240 while(top
< root
->docHeight()) {
3241 if(top
> 0) printer
.newPage();
3243 p
->setClipRect(0, 0, pageWidth
, headerHeight
);
3246 int dy
= p
->fontMetrics().lineSpacing();
3247 p
->setPen(Qt::black
);
3248 p
->setFont(headerFont
);
3250 headerRight
= QString("#%1").arg(page
);
3252 p
->drawText(0, 0, printer
.width(), dy
, Qt::AlignLeft
, headerLeft
);
3253 p
->drawText(0, 0, printer
.width(), dy
, Qt::AlignHCenter
, headerMid
);
3254 p
->drawText(0, 0, printer
.width(), dy
, Qt::AlignRight
, headerRight
);
3257 #ifndef QT_NO_TRANSFORMATIONS
3259 p
->scale(scale
, scale
);
3262 p
->translate(0, headerHeight
-top
);
3264 bottom
= top
+pageHeight
;
3266 root
->setPageTop(top
);
3267 root
->setPageBottom(bottom
);
3268 root
->setPageNumber(page
);
3270 root
->layer()->paint(p
, QRect(0, top
, pageWidth
, pageHeight
));
3271 kDebug(6000) << "printed: page " << page
<<" bottom At = " << bottom
;
3274 p
->resetTransform();
3281 // and now reset the layout to the usual one...
3282 root
->setPagedMode(false);
3283 root
->setStaticMode(false);
3285 khtml::setPrintPainter( 0 );
3286 setMediaType( oldMediaType
);
3287 m_part
->xmlDocImpl()->setPaintDevice( this );
3288 m_part
->xmlDocImpl()->styleSelector()->computeFontSizes(m_part
->xmlDocImpl()->logicalDpiY(), m_part
->fontScaleFactor());
3289 m_part
->xmlDocImpl()->updateStyleSelector();
3290 viewport()->unsetCursor();
3294 void KHTMLView::slotPaletteChanged()
3296 if(!m_part
->xmlDocImpl()) return;
3297 DOM::DocumentImpl
*document
= m_part
->xmlDocImpl();
3298 if (!document
->isHTMLDocument()) return;
3299 khtml::RenderCanvas
*root
= static_cast<khtml::RenderCanvas
*>(document
->renderer());
3301 root
->style()->resetPalette();
3302 NodeImpl
*body
= static_cast<HTMLDocumentImpl
*>(document
)->body();
3304 body
->setChanged(true);
3305 body
->recalcStyle( NodeImpl::Force
);
3308 void KHTMLView::paint(QPainter
*p
, const QRect
&rc
, int yOff
, bool *more
)
3310 if(!m_part
->xmlDocImpl()) return;
3311 khtml::RenderCanvas
*root
= static_cast<khtml::RenderCanvas
*>(m_part
->xmlDocImpl()->renderer());
3313 d
->firstRepaintPending
= false;
3315 QPaintDevice
* opd
= m_part
->xmlDocImpl()->paintDevice();
3316 m_part
->xmlDocImpl()->setPaintDevice(p
->device());
3317 root
->setPagedMode(true);
3318 root
->setStaticMode(true);
3319 root
->setWidth(rc
.width());
3322 QRegion creg
= p
->clipRegion();
3323 QTransform t
= p
->worldTransform();
3324 QRect w
= p
->window();
3325 QRect v
= p
->viewport();
3326 bool vte
= p
->viewTransformEnabled();
3327 bool wme
= p
->worldMatrixEnabled();
3330 p
->translate(rc
.left(), rc
.top());
3331 double scale
= ((double) rc
.width()/(double) root
->docWidth());
3332 int height
= (int) ((double) rc
.height() / scale
);
3333 #ifndef QT_NO_TRANSFORMATIONS
3334 p
->scale(scale
, scale
);
3336 root
->setPageTop(yOff
);
3337 root
->setPageBottom(yOff
+height
);
3339 root
->layer()->paint(p
, QRect(0, yOff
, root
->docWidth(), height
));
3341 *more
= yOff
+ height
< root
->docHeight();
3344 p
->setWorldTransform(t
);
3347 p
->setViewTransformEnabled( vte
);
3348 p
->setWorldMatrixEnabled( wme
);
3349 if (!creg
.isEmpty())
3350 p
->setClipRegion( creg
);
3352 p
->setClipRegion(QRegion(), Qt::NoClip
);
3354 root
->setPagedMode(false);
3355 root
->setStaticMode(false);
3356 m_part
->xmlDocImpl()->setPaintDevice( opd
);
3359 void KHTMLView::render(QPainter
* p
, const QRect
& r
, const QPoint
& off
)
3361 d
->firstRepaintPending
= false;
3362 QRect
clip(off
.x()+r
.x(), off
.y()+r
.y(),r
.width(),r
.height());
3363 if(!m_part
|| !m_part
->xmlDocImpl() || !m_part
->xmlDocImpl()->renderer()) {
3364 p
->fillRect(clip
, palette().brush(QPalette::Active
, QPalette::Base
));
3367 QPaintDevice
* opd
= m_part
->xmlDocImpl()->paintDevice();
3368 m_part
->xmlDocImpl()->setPaintDevice(p
->device());
3371 QRegion creg
= p
->clipRegion();
3372 QTransform t
= p
->worldTransform();
3373 QRect w
= p
->window();
3374 QRect v
= p
->viewport();
3375 bool vte
= p
->viewTransformEnabled();
3376 bool wme
= p
->worldMatrixEnabled();
3378 p
->setClipRect(clip
);
3379 QRect rect
= r
.translated(contentsX(),contentsY());
3380 p
->translate(off
.x()-contentsX(), off
.y()-contentsY());
3382 m_part
->xmlDocImpl()->renderer()->layer()->paint(p
, rect
);
3385 p
->setWorldTransform(t
);
3388 p
->setViewTransformEnabled( vte
);
3389 p
->setWorldMatrixEnabled( wme
);
3390 if (!creg
.isEmpty())
3391 p
->setClipRegion( creg
);
3393 p
->setClipRegion(QRegion(), Qt::NoClip
);
3395 m_part
->xmlDocImpl()->setPaintDevice( opd
);
3398 void KHTMLView::setHasStaticBackground(bool partial
)
3400 // full static iframe is irreversible for now
3401 if (d
->staticWidget
== KHTMLViewPrivate::SBFull
&& m_kwp
->isRedirected())
3404 d
->staticWidget
= partial
?
3405 KHTMLViewPrivate::SBPartial
: KHTMLViewPrivate::SBFull
;
3408 void KHTMLView::setHasNormalBackground()
3410 // full static iframe is irreversible for now
3411 if (d
->staticWidget
== KHTMLViewPrivate::SBFull
&& m_kwp
->isRedirected())
3414 d
->staticWidget
= KHTMLViewPrivate::SBNone
;
3417 void KHTMLView::addStaticObject(bool fixed
)
3420 d
->fixedObjectsCount
++;
3422 d
->staticObjectsCount
++;
3424 setHasStaticBackground( true /*partial*/ );
3427 void KHTMLView::removeStaticObject(bool fixed
)
3430 d
->fixedObjectsCount
--;
3432 d
->staticObjectsCount
--;
3434 assert( d
->fixedObjectsCount
>= 0 && d
->staticObjectsCount
>= 0 );
3436 if (!d
->staticObjectsCount
&& !d
->fixedObjectsCount
)
3437 setHasNormalBackground();
3439 setHasStaticBackground( true /*partial*/ );
3442 void KHTMLView::setVerticalScrollBarPolicy( Qt::ScrollBarPolicy policy
)
3444 #ifndef KHTML_NO_SCROLLBARS
3445 d
->vpolicy
= policy
;
3446 QScrollArea::setVerticalScrollBarPolicy(policy
);
3452 void KHTMLView::setHorizontalScrollBarPolicy( Qt::ScrollBarPolicy policy
)
3454 #ifndef KHTML_NO_SCROLLBARS
3455 d
->hpolicy
= policy
;
3456 QScrollArea::setHorizontalScrollBarPolicy(policy
);
3462 void KHTMLView::restoreScrollBar()
3464 int ow
= visibleWidth();
3465 QScrollArea::setVerticalScrollBarPolicy(d
->vpolicy
);
3466 if (visibleWidth() != ow
)
3468 d
->prevScrollbarVisible
= verticalScrollBar()->isVisible();
3471 QStringList
KHTMLView::formCompletionItems(const QString
&name
) const
3473 if (!m_part
->settings()->isFormCompletionEnabled())
3474 return QStringList();
3475 if (!d
->formCompletions
)
3476 d
->formCompletions
= new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3477 return d
->formCompletions
->group("").readEntry(name
, QStringList());
3480 void KHTMLView::clearCompletionHistory(const QString
& name
)
3482 if (!d
->formCompletions
)
3484 d
->formCompletions
= new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3486 d
->formCompletions
->group("").writeEntry(name
, "");
3487 d
->formCompletions
->sync();
3490 void KHTMLView::addFormCompletionItem(const QString
&name
, const QString
&value
)
3492 if (!m_part
->settings()->isFormCompletionEnabled())
3494 // don't store values that are all numbers or just numbers with
3495 // dashes or spaces as those are likely credit card numbers or
3496 // something similar
3497 bool cc_number(true);
3498 for ( int i
= 0; i
< value
.length(); ++i
)
3501 if (!c
.isNumber() && c
!= '-' && !c
.isSpace())
3509 QStringList items
= formCompletionItems(name
);
3510 if (!items
.contains(value
))
3511 items
.prepend(value
);
3512 while ((int)items
.count() > m_part
->settings()->maxFormCompletionItems())
3513 items
.erase(items
.isEmpty() ? items
.end() : --items
.end());
3514 d
->formCompletions
->group("").writeEntry(name
, items
);
3517 void KHTMLView::addNonPasswordStorableSite(const QString
& host
)
3519 if (!d
->formCompletions
) {
3520 d
->formCompletions
= new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3523 KConfigGroup
cg( d
->formCompletions
, "NonPasswordStorableSites");
3524 QStringList sites
= cg
.readEntry("Sites", QStringList());
3526 cg
.writeEntry("Sites", sites
);
3530 bool KHTMLView::nonPasswordStorableSite(const QString
& host
) const
3532 if (!d
->formCompletions
) {
3533 d
->formCompletions
= new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3535 QStringList sites
= d
->formCompletions
->group( "NonPasswordStorableSites" ).readEntry("Sites", QStringList());
3536 return (sites
.indexOf(host
) != -1);
3539 // returns true if event should be swallowed
3540 bool KHTMLView::dispatchMouseEvent(int eventId
, DOM::NodeImpl
*targetNode
,
3541 DOM::NodeImpl
*targetNodeNonShared
, bool cancelable
,
3542 int detail
,QMouseEvent
*_mouse
, bool setUnder
,
3543 int mouseEventType
, int orient
)
3545 // if the target node is a text node, dispatch on the parent node - rdar://4196646 (and #76948)
3546 if (targetNode
&& targetNode
->isTextNode())
3547 targetNode
= targetNode
->parentNode();
3550 d
->underMouse
->deref();
3551 d
->underMouse
= targetNode
;
3553 d
->underMouse
->ref();
3555 if (d
->underMouseNonShared
)
3556 d
->underMouseNonShared
->deref();
3557 d
->underMouseNonShared
= targetNodeNonShared
;
3558 if (d
->underMouseNonShared
)
3559 d
->underMouseNonShared
->ref();
3561 bool isWheelEvent
= (mouseEventType
== DOM::NodeImpl::MouseWheel
);
3563 int exceptioncode
= 0;
3564 int pageX
= _mouse
->x();
3565 int pageY
= _mouse
->y();
3566 revertTransforms(pageX
, pageY
);
3567 int clientX
= pageX
- contentsX();
3568 int clientY
= pageY
- contentsY();
3569 int screenX
= _mouse
->globalX();
3570 int screenY
= _mouse
->globalY();
3572 switch (_mouse
->button()) {
3573 case Qt::LeftButton
:
3579 case Qt::RightButton
:
3585 if (d
->accessKeysEnabled
&& d
->accessKeysPreActivate
&& button
!=-1)
3586 d
->accessKeysPreActivate
=false;
3588 bool ctrlKey
= (_mouse
->modifiers() & Qt::ControlModifier
);
3589 bool altKey
= (_mouse
->modifiers() & Qt::AltModifier
);
3590 bool shiftKey
= (_mouse
->modifiers() & Qt::ShiftModifier
);
3591 bool metaKey
= (_mouse
->modifiers() & Qt::MetaModifier
);
3593 // mouseout/mouseover
3594 if (setUnder
&& d
->oldUnderMouse
!= targetNode
) {
3595 if (d
->oldUnderMouse
&& d
->oldUnderMouse
->document() != m_part
->xmlDocImpl()) {
3596 d
->oldUnderMouse
->deref();
3597 d
->oldUnderMouse
= 0;
3599 // send mouseout event to the old node
3600 if (d
->oldUnderMouse
) {
3601 // send mouseout event to the old node
3602 MouseEventImpl
*me
= new MouseEventImpl(EventImpl::MOUSEOUT_EVENT
,
3603 true,true,m_part
->xmlDocImpl()->defaultView(),
3604 0,screenX
,screenY
,clientX
,clientY
,pageX
, pageY
,
3605 ctrlKey
,altKey
,shiftKey
,metaKey
,
3608 d
->oldUnderMouse
->dispatchEvent(me
,exceptioncode
,true);
3611 // send mouseover event to the new node
3613 MouseEventImpl
*me
= new MouseEventImpl(EventImpl::MOUSEOVER_EVENT
,
3614 true,true,m_part
->xmlDocImpl()->defaultView(),
3615 0,screenX
,screenY
,clientX
,clientY
,pageX
, pageY
,
3616 ctrlKey
,altKey
,shiftKey
,metaKey
,
3617 button
,d
->oldUnderMouse
);
3620 targetNode
->dispatchEvent(me
,exceptioncode
,true);
3623 if (d
->oldUnderMouse
)
3624 d
->oldUnderMouse
->deref();
3625 d
->oldUnderMouse
= targetNode
;
3626 if (d
->oldUnderMouse
)
3627 d
->oldUnderMouse
->ref();
3630 bool swallowEvent
= false;
3633 // if the target node is a disabled widget, we don't want any full-blown mouse events
3634 if (targetNode
->isGenericFormElement()
3635 && static_cast<HTMLGenericFormElementImpl
*>(targetNode
)->disabled())
3638 // send the actual event
3639 bool dblclick
= ( eventId
== EventImpl::CLICK_EVENT
&&
3640 _mouse
->type() == QEvent::MouseButtonDblClick
);
3641 MouseEventImpl
*me
= new MouseEventImpl(static_cast<EventImpl::EventId
>(eventId
),
3642 true,cancelable
,m_part
->xmlDocImpl()->defaultView(),
3643 detail
,screenX
,screenY
,clientX
,clientY
,pageX
, pageY
,
3644 ctrlKey
,altKey
,shiftKey
,metaKey
,
3645 button
,0, isWheelEvent
? 0 : _mouse
, dblclick
,
3646 isWheelEvent
? static_cast<MouseEventImpl::Orientation
>(orient
) : MouseEventImpl::ONone
);
3648 if ( !d
->m_mouseEventsTarget
&& RenderLayer::gScrollBar
&& eventId
== EventImpl::MOUSEDOWN_EVENT
)
3649 // button is pressed inside a layer scrollbar, so make it the target for future mousemove events until released
3650 d
->m_mouseEventsTarget
= RenderLayer::gScrollBar
;
3651 if ( d
->m_mouseEventsTarget
&& qobject_cast
<QScrollBar
*>(d
->m_mouseEventsTarget
) &&
3652 dynamic_cast<KHTMLWidget
*>(static_cast<QWidget
*>(d
->m_mouseEventsTarget
)) ) {
3653 // we have a sticky mouse event target and it is a layer's scrollbar. Forward events manually.
3654 // ### should use the dom
3655 KHTMLWidget
*w
= dynamic_cast<KHTMLWidget
*>(static_cast<QWidget
*>(d
->m_mouseEventsTarget
));
3656 QPoint p
= w
->m_kwp
->absolutePos();
3657 QMouseEvent
fw(_mouse
->type(), QPoint(pageX
, pageY
)-p
, _mouse
->button(), _mouse
->buttons(), _mouse
->modifiers());
3658 static_cast<RenderWidget::EventPropagator
*>(static_cast<QWidget
*>(d
->m_mouseEventsTarget
))->sendEvent(&fw
);
3659 if (_mouse
->type() == QMouseEvent::MouseButtonPress
&& _mouse
->button() == Qt::RightButton
) {
3660 QContextMenuEvent
cme(QContextMenuEvent::Mouse
, p
);
3661 static_cast<RenderWidget::EventPropagator
*>(static_cast<QWidget
*>(d
->m_mouseEventsTarget
))->sendEvent(&cme
);
3662 d
->m_mouseEventsTarget
= 0;
3664 swallowEvent
= true;
3666 targetNode
->dispatchEvent(me
,exceptioncode
,true);
3667 bool defaultHandled
= me
->defaultHandled();
3668 if (defaultHandled
|| me
->defaultPrevented())
3669 swallowEvent
= true;
3673 if (eventId
== EventImpl::MOUSEDOWN_EVENT
) {
3674 // Focus should be shifted on mouse down, not on a click. -dwh
3675 // Blur current focus node when a link/button is clicked; this
3676 // is expected by some sites that rely on onChange handlers running
3677 // from form fields before the button click is processed.
3678 DOM::NodeImpl
* nodeImpl
= targetNode
;
3679 for ( ; nodeImpl
&& !nodeImpl
->isFocusable(); nodeImpl
= nodeImpl
->parentNode())
3681 if (nodeImpl
&& nodeImpl
->isMouseFocusable())
3682 m_part
->xmlDocImpl()->setFocusNode(nodeImpl
);
3683 else if (!nodeImpl
|| !nodeImpl
->focused())
3684 m_part
->xmlDocImpl()->setFocusNode(0);
3688 return swallowEvent
;
3691 void KHTMLView::setIgnoreWheelEvents( bool e
)
3693 d
->ignoreWheelEvents
= e
;
3696 #ifndef QT_NO_WHEELEVENT
3698 void KHTMLView::wheelEvent(QWheelEvent
* e
)
3700 // check if we should reset the state of the indicator describing if
3701 // we are currently scrolling the view as a result of wheel events
3702 if (d
->scrollingFromWheel
!= QPoint(-1,-1) && d
->scrollingFromWheel
!= QCursor::pos())
3703 d
->scrollingFromWheel
= d
->scrollingFromWheelTimerId
? QCursor::pos() : QPoint(-1,-1);
3705 if (d
->accessKeysEnabled
&& d
->accessKeysPreActivate
) d
->accessKeysPreActivate
=false;
3707 if ( ( e
->modifiers() & Qt::ControlModifier
) == Qt::ControlModifier
)
3709 emit
zoomView( - e
->delta() );
3712 else if (d
->firstLayoutPending
)
3716 else if( !m_kwp
->isRedirected() &&
3717 ( (e
->orientation() == Qt::Vertical
&&
3718 ((d
->ignoreWheelEvents
&& !verticalScrollBar()->isVisible())
3719 || (e
->delta() > 0 && contentsY() <= 0)
3720 || (e
->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())))
3722 (e
->orientation() == Qt::Horizontal
&&
3723 ((d
->ignoreWheelEvents
&& !horizontalScrollBar()->isVisible())
3724 || (e
->delta() > 0 && contentsX() <=0)
3725 || (e
->delta() < 0 && contentsX() >= contentsWidth() - visibleWidth()))))
3726 && m_part
->parentPart())
3728 if ( m_part
->parentPart()->view() )
3729 m_part
->parentPart()->view()->wheelEvent( e
);
3736 revertTransforms(xm
, ym
);
3738 DOM::NodeImpl::MouseEvent
mev( e
->buttons(), DOM::NodeImpl::MouseWheel
);
3739 m_part
->xmlDocImpl()->prepareMouseEvent( false, xm
, ym
, &mev
);
3741 MouseEventImpl::Orientation o
= MouseEventImpl::OVertical
;
3742 if (e
->orientation() == Qt::Horizontal
)
3743 o
= MouseEventImpl::OHorizontal
;
3745 QMouseEvent
_mouse(QEvent::MouseMove
, QPoint(xm
,ym
), Qt::NoButton
, e
->buttons(), e
->modifiers());
3746 bool swallow
= dispatchMouseEvent(EventImpl::KHTML_MOUSEWHEEL_EVENT
,mev
.innerNode
.handle(),mev
.innerNonSharedNode
.handle(),
3747 true,-e
->delta()/40,&_mouse
,true,DOM::NodeImpl::MouseWheel
,o
);
3752 d
->scrollBarMoved
= true;
3753 d
->scrollingFromWheel
= QCursor::pos();
3754 if (d
->smoothScrollMode
!= SSMDisabled
)
3755 d
->shouldSmoothScroll
= true;
3756 if (d
->scrollingFromWheelTimerId
)
3757 killTimer(d
->scrollingFromWheelTimerId
);
3758 d
->scrollingFromWheelTimerId
= startTimer(400);
3760 if (m_part
->parentPart()) {
3761 // don't propagate if we are a sub-frame and our scrollbars are already at end of range
3762 bool h
= (static_cast<QWheelEvent
*>(e
)->orientation() == Qt::Horizontal
);
3763 bool d
= (static_cast<QWheelEvent
*>(e
)->delta() < 0);
3764 QScrollBar
* hsb
= horizontalScrollBar();
3765 QScrollBar
* vsb
= verticalScrollBar();
3766 if ( (h
&& ((d
&& hsb
->value() == hsb
->maximum()) || (!d
&& hsb
->value() == hsb
->minimum()))) ||
3767 (!h
&& ((d
&& vsb
->value() == vsb
->maximum()) || (!d
&& vsb
->value() == vsb
->minimum()))) ) {
3772 QScrollArea::wheelEvent( e
);
3778 void KHTMLView::dragEnterEvent( QDragEnterEvent
* ev
)
3780 // Still overridden for BC reasons only...
3781 QScrollArea::dragEnterEvent( ev
);
3784 void KHTMLView::dropEvent( QDropEvent
*ev
)
3786 // Still overridden for BC reasons only...
3787 QScrollArea::dropEvent( ev
);
3790 void KHTMLView::focusInEvent( QFocusEvent
*e
)
3792 DOM::NodeImpl
* fn
= m_part
->xmlDocImpl() ? m_part
->xmlDocImpl()->focusNode() : 0;
3793 #ifndef KHTML_NO_TYPE_AHEAD_FIND
3794 if (!fn
|| m_part
->isCaretMode())
3795 m_part
->enableFindAheadActions( true );
3797 if (fn
&& fn
->renderer() && fn
->renderer()->isWidget() &&
3798 (e
->reason() != Qt::MouseFocusReason
) &&
3799 static_cast<khtml::RenderWidget
*>(fn
->renderer())->widget())
3800 static_cast<khtml::RenderWidget
*>(fn
->renderer())->widget()->setFocus();
3801 m_part
->setSelectionVisible();
3802 QScrollArea::focusInEvent( e
);
3805 void KHTMLView::focusOutEvent( QFocusEvent
*e
)
3808 m_part
->stopAutoScroll();
3809 m_part
->setSelectionVisible(false);
3812 #ifndef KHTML_NO_TYPE_AHEAD_FIND
3813 if(d
->typeAheadActivated
)
3818 m_part
->enableFindAheadActions( false );
3819 #endif // KHTML_NO_TYPE_AHEAD_FIND
3821 if ( d
->cursorIconWidget
)
3822 d
->cursorIconWidget
->hide();
3824 QScrollArea::focusOutEvent( e
);
3827 void KHTMLView::scrollContentsBy( int dx
, int dy
)
3829 if (!dx
&& !dy
) return;
3831 if ( !d
->firstLayoutPending
&& !d
->complete
&& m_part
->xmlDocImpl() &&
3832 d
->layoutSchedulingEnabled
) {
3833 // contents scroll while we are not complete: we need to check our layout *now*
3834 khtml::RenderCanvas
* root
= static_cast<khtml::RenderCanvas
*>( m_part
->xmlDocImpl()->renderer() );
3835 if (root
&& root
->needsLayout()) {
3836 unscheduleRelayout();
3841 if ( d
->shouldSmoothScroll
&& d
->smoothScrollMode
!= SSMDisabled
&& m_part
->xmlDocImpl() &&
3842 m_part
->xmlDocImpl()->renderer()) {
3844 bool doSmoothScroll
= (!d
->staticWidget
|| d
->smoothScrollMode
== SSMEnabled
);
3846 int numStaticPixels
= 0;
3847 QRegion r
= static_cast<RenderCanvas
*>(m_part
->xmlDocImpl()->renderer())->staticRegion();
3849 // only do smooth scrolling if static region is relatively small
3850 if (!doSmoothScroll
&& d
->staticWidget
== KHTMLViewPrivate::SBPartial
&& r
.rects().size() <= 10) {
3851 foreach(QRect rr
, r
.rects())
3852 numStaticPixels
+= rr
.width()*rr
.height();
3853 if ((numStaticPixels
< sSmoothScrollMinStaticPixels
) || (numStaticPixels
*8 < visibleWidth()*visibleHeight()))
3854 doSmoothScroll
= true;
3856 if (doSmoothScroll
) {
3857 setupSmoothScrolling(dx
, dy
);
3862 if (!d
->scrollingSelf
) {
3863 d
->scrollBarMoved
= true;
3864 d
->contentsMoving
= true;
3865 // ensure quick reset of contentsMoving flag
3866 scheduleRepaint(0, 0, 0, 0);
3869 if (m_part
->xmlDocImpl() && m_part
->xmlDocImpl()->documentElement()) {
3870 // ### FIXME: there is something wrong with this event.
3871 // With a capturing listener on document and window, window's should fire first, then document's.
3872 // Also, this doesn't work: <body onload="document.onscroll=function() {alert('ok')}"><div style=height:2000>
3873 m_part
->xmlDocImpl()->documentElement()->dispatchWindowEvent(EventImpl::SCROLL_EVENT
, false, false);
3876 if (QApplication::isRightToLeft())
3879 if (!d
->smoothScrolling
) {
3880 d
->updateContentsXY();
3885 if (widget()->pos() != QPoint(0,0)) {
3886 kDebug(6000) << "Static widget wasn't positioned at (0,0). This should NOT happen. Please report this event to developers.";
3887 kDebug(6000) << kBacktrace();
3888 widget()->move(0,0);
3891 QWidget
*w
= widget();
3893 if (m_kwp
->isRedirected()) {
3894 // This is a redirected sub frame. Translate to root view context
3895 KHTMLView
* v
= m_kwp
->rootViewPos( off
);
3898 off
= viewport()->mapTo(this, off
);
3901 if ( d
->staticWidget
) {
3903 // now remove from view the external widgets that must have completely
3904 // disappeared after dx/dy scroll delta is effective
3905 if (!d
->visibleWidgets
.isEmpty())
3906 checkExternalWidgetsPosition();
3908 if ( d
->staticWidget
== KHTMLViewPrivate::SBPartial
3909 && m_part
->xmlDocImpl() && m_part
->xmlDocImpl()->renderer() ) {
3910 // static objects might be selectively repainted, like stones in flowing water
3911 QRegion r
= static_cast<RenderCanvas
*>(m_part
->xmlDocImpl()->renderer())->staticRegion();
3912 r
.translate( -contentsX(), -contentsY());
3913 QVector
<QRect
> ar
= r
.rects();
3915 for (int i
= 0; i
< ar
.size() ; ++i
) {
3916 widget()->update( ar
[i
] );
3918 r
= QRegion(QRect(0, 0, visibleWidth(), visibleHeight())) - r
;
3920 for (int i
= 0; i
< ar
.size() ; ++i
) {
3921 w
->scroll( dx
, dy
, ar
[i
].translated(off
) );
3923 d
->scrollExternalWidgets(dx
, dy
);
3925 // we can't avoid a full update
3931 if (m_kwp
->isRedirected()) {
3932 const QRect
rect(off
.x(), off
.y(), visibleWidth() * d
->zoomLevel
/ 100, visibleHeight() * d
->zoomLevel
/ 100);
3933 w
->scroll(dx
, dy
, rect
);
3934 if (d
->zoomLevel
!= 100) {
3935 w
->update(rect
); // without this update we are getting bad rendering when an iframe is zoomed in
3938 widget()->scroll(dx
, dy
, widget()->rect() & viewport()->rect());
3941 d
->scrollExternalWidgets(dx
, dy
);
3944 void KHTMLView::setupSmoothScrolling(int dx
, int dy
)
3946 // full scroll is remaining scroll plus new scroll
3950 if (d
->dx
== 0 && d
->dy
== 0) return;
3952 int steps
= sSmoothScrollTime
/sSmoothScrollTick
;
3954 // average step size (stored in 1/16 px/step)
3955 d
->ddx
= (d
->dx
*16)/(steps
+1);
3956 d
->ddy
= (d
->dy
*16)/(steps
+1);
3958 if (abs(d
->ddx
) < 64 && abs(d
->ddy
) < 64) {
3959 // Don't move slower than average 4px/step in minimum one direction
3960 if (d
->ddx
> 0) d
->ddx
= qMax(d
->ddx
, 64);
3961 if (d
->ddy
> 0) d
->ddy
= qMax(d
->ddy
, 64);
3962 if (d
->ddx
< 0) d
->ddx
= qMin(d
->ddx
, -64);
3963 if (d
->ddy
< 0) d
->ddy
= qMin(d
->ddy
, -64);
3964 // This means fewer than normal steps
3965 steps
= qMax(d
->ddx
? (d
->dx
*16)/d
->ddx
: 0, d
->ddy
? (d
->dy
*16)/d
->ddy
: 0);
3966 if (steps
< 1) steps
= 1;
3967 d
->ddx
= (d
->dx
*16)/(steps
+1);
3968 d
->ddy
= (d
->dy
*16)/(steps
+1);
3971 // step size starts at double average speed and ends at 0
3975 // deacceleration speed
3976 d
->dddx
= (d
->ddx
+1)/steps
;
3977 d
->dddy
= (d
->ddy
+1)/steps
;
3979 if (!d
->smoothScrolling
) {
3980 d
->startScrolling();
3983 d
->smoothScrollStopwatch
.start();
3986 void KHTMLView::scrollTick() {
3987 if (d
->dx
== 0 && d
->dy
== 0) {
3992 // step size + remaining partial step
3993 int tddx
= d
->ddx
+ d
->rdx
;
3994 int tddy
= d
->ddy
+ d
->rdy
;
3996 // don't go under 1px/step
3997 if (tddx
> 0 && tddx
< 16) tddx
= 16;
3998 if (tddy
> 0 && tddy
< 16) tddy
= 16;
3999 if (tddx
< 0 && tddx
> -16) tddx
= -16;
4000 if (tddy
< 0 && tddy
> -16) tddy
= -16;
4002 // full pixel steps to scroll in this step
4003 int ddx
= tddx
/ 16;
4004 int ddy
= tddy
/ 16;
4005 // remaining partial step (this is especially needed for 1.x sized steps)
4009 // limit step to requested scrolling distance
4010 if (abs(ddx
) > abs(d
->dx
)) ddx
= d
->dx
;
4011 if (abs(ddy
) > abs(d
->dy
)) ddy
= d
->dy
;
4013 // Don't stop if deaccelerated too fast
4014 if (!ddx
) ddx
= d
->dx
;
4015 if (!ddy
) ddy
= d
->dy
;
4017 // update remaining scroll
4021 d
->shouldSmoothScroll
= false;
4022 scrollContentsBy(ddx
, ddy
);
4024 // only consider decelerating if we aren't too far behind schedule
4025 if (d
->smoothScrollStopwatch
.elapsed() < 2*sSmoothScrollTick
) {
4026 // update scrolling speed
4029 // don't change direction
4030 if (abs(dddx
) > abs(d
->ddx
)) dddx
= d
->ddx
;
4031 if (abs(dddy
) > abs(d
->ddy
)) dddy
= d
->ddy
;
4036 d
->smoothScrollStopwatch
.start();
4040 void KHTMLView::addChild(QWidget
* child
, int x
, int y
)
4045 if (child
->parent() != widget())
4046 child
->setParent( widget() );
4048 // ### handle pseudo-zooming of non-redirected widgets (e.g. just resize'em)
4050 child
->move(x
-contentsX(), y
-contentsY());
4053 void KHTMLView::timerEvent ( QTimerEvent
*e
)
4055 // kDebug() << "timer event " << e->timerId();
4056 if ( e
->timerId() == d
->scrollTimerId
) {
4057 if( d
->scrollSuspended
)
4059 switch (d
->scrollDirection
) {
4060 case KHTMLViewPrivate::ScrollDown
:
4061 if (contentsY() + visibleHeight () >= contentsHeight())
4062 d
->newScrollTimer(this, 0);
4064 verticalScrollBar()->setValue( verticalScrollBar()->value() +d
->scrollBy
);
4066 case KHTMLViewPrivate::ScrollUp
:
4067 if (contentsY() <= 0)
4068 d
->newScrollTimer(this, 0);
4070 verticalScrollBar()->setValue( verticalScrollBar()->value() -d
->scrollBy
);
4072 case KHTMLViewPrivate::ScrollRight
:
4073 if (contentsX() + visibleWidth () >= contentsWidth())
4074 d
->newScrollTimer(this, 0);
4076 horizontalScrollBar()->setValue( horizontalScrollBar()->value() +d
->scrollBy
);
4078 case KHTMLViewPrivate::ScrollLeft
:
4079 if (contentsX() <= 0)
4080 d
->newScrollTimer(this, 0);
4082 horizontalScrollBar()->setValue( horizontalScrollBar()->value() -d
->scrollBy
);
4087 else if ( e
->timerId() == d
->scrollingFromWheelTimerId
) {
4088 killTimer( d
->scrollingFromWheelTimerId
);
4089 d
->scrollingFromWheelTimerId
= 0;
4090 } else if ( e
->timerId() == d
->layoutTimerId
) {
4091 if (d
->firstLayoutPending
&& d
->layoutAttemptCounter
< 4
4092 && (!m_part
->xmlDocImpl() || !m_part
->xmlDocImpl()->readyForLayout())) {
4093 d
->layoutAttemptCounter
++;
4094 killTimer(d
->layoutTimerId
);
4095 d
->layoutTimerId
= 0;
4100 d
->scheduledLayoutCounter
++;
4101 if (d
->firstLayoutPending
) {
4102 d
->firstLayoutPending
= false;
4103 verticalScrollBar()->setEnabled( true );
4104 horizontalScrollBar()->setEnabled( true );
4108 d
->contentsMoving
= false;
4109 if( m_part
->xmlDocImpl() ) {
4110 DOM::DocumentImpl
*document
= m_part
->xmlDocImpl();
4111 khtml::RenderCanvas
* root
= static_cast<khtml::RenderCanvas
*>(document
->renderer());
4113 if ( root
&& root
->needsLayout() ) {
4114 if (d
->repaintTimerId
)
4115 killTimer(d
->repaintTimerId
);
4116 d
->repaintTimerId
= 0;
4122 if (d
->repaintTimerId
)
4123 killTimer(d
->repaintTimerId
);
4124 d
->repaintTimerId
= 0;
4127 const QVector
<QRect
> rects
= d
->updateRegion
.rects();
4129 d
->updateRegion
= QRegion();
4132 updateRegion
= rects
[0];
4134 for ( int i
= 1; i
< rects
.size(); ++i
) {
4135 QRect newRegion
= updateRegion
.unite(rects
[i
]);
4136 if (2*newRegion
.height() > 3*updateRegion
.height() )
4138 repaintContents( updateRegion
);
4139 updateRegion
= rects
[i
];
4142 updateRegion
= newRegion
;
4145 if ( !updateRegion
.isNull() )
4146 repaintContents( updateRegion
);
4148 // As widgets can only be accurately positioned during painting, every layout might
4149 // dissociate a widget from its RenderWidget. E.g: if a RenderWidget was visible before layout, but the layout
4150 // pushed it out of the viewport, it will not be repainted, and consequently it's associated widget won't be repositioned.
4151 // Thus we need to check each supposedly 'visible' widget at the end of layout, and remove it in case it's no more in sight.
4153 if (d
->dirtyLayout
&& !d
->visibleWidgets
.isEmpty())
4154 checkExternalWidgetsPosition();
4156 d
->dirtyLayout
= false;
4158 emit
repaintAccessKeys();
4159 if (d
->emitCompletedAfterRepaint
) {
4160 bool full
= d
->emitCompletedAfterRepaint
== KHTMLViewPrivate::CSFull
;
4161 d
->emitCompletedAfterRepaint
= KHTMLViewPrivate::CSNone
;
4163 emit m_part
->completed();
4165 emit m_part
->completed(true);
4169 void KHTMLView::checkExternalWidgetsPosition()
4172 QRect
visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
4173 QList
<RenderWidget
*> toRemove
;
4174 QHashIterator
<void*, QWidget
*> it(d
->visibleWidgets
);
4175 while (it
.hasNext()) {
4178 RenderWidget
* rw
= static_cast<RenderWidget
*>( it
.key() );
4179 if (!rw
->absolutePosition(xp
, yp
) ||
4180 !visibleRect
.intersects(QRect(xp
, yp
, it
.value()->width(), it
.value()->height())))
4181 toRemove
.append(rw
);
4183 foreach (RenderWidget
* r
, toRemove
)
4184 if ( (w
= d
->visibleWidgets
.take(r
) ) )
4185 w
->move( 0, -500000);
4188 void KHTMLView::scheduleRelayout(khtml::RenderObject
* /*clippedObj*/)
4190 if (!d
->layoutSchedulingEnabled
|| d
->layoutTimerId
)
4194 if (d
->firstLayoutPending
) {
4195 // Any repaint happening while we have no content blanks the viewport ("white flash").
4196 // Hence the need to delay the first layout as much as we can.
4197 // Only if the document gets stuck for too long in incomplete state will we allow the blanking.
4198 time
= d
->layoutAttemptCounter
?
4199 sLayoutAttemptDelay
+ sLayoutAttemptIncrement
*d
->layoutAttemptCounter
: sFirstLayoutDelay
;
4200 } else if (m_part
->xmlDocImpl() && m_part
->xmlDocImpl()->parsing()) {
4201 // Delay between successive layouts in parsing mode.
4202 // Increment reflects the decaying importance of visual feedback over time.
4203 time
= qMin(2000, sParsingLayoutsInterval
+ d
->scheduledLayoutCounter
*sParsingLayoutsIncrement
);
4205 d
->layoutTimerId
= startTimer( time
);
4208 void KHTMLView::unscheduleRelayout()
4210 if (!d
->layoutTimerId
)
4213 killTimer(d
->layoutTimerId
);
4214 d
->layoutTimerId
= 0;
4217 void KHTMLView::unscheduleRepaint()
4219 if (!d
->repaintTimerId
)
4222 killTimer(d
->repaintTimerId
);
4223 d
->repaintTimerId
= 0;
4226 void KHTMLView::scheduleRepaint(int x
, int y
, int w
, int h
, bool asap
)
4228 bool parsing
= !m_part
->xmlDocImpl() || m_part
->xmlDocImpl()->parsing();
4230 // kDebug() << "parsing " << parsing;
4231 // kDebug() << "complete " << d->complete;
4233 int time
= parsing
&& !d
->firstLayoutPending
? 150 : (!asap
? ( !d
->complete
? 80 : 20 ) : 0);
4235 #ifdef DEBUG_FLICKER
4237 p
.begin( viewport() );
4240 contentsToViewport( x
, y
, vx
, vy
);
4241 p
.fillRect( vx
, vy
, w
, h
, Qt::red
);
4245 d
->updateRegion
= d
->updateRegion
.unite(QRect(x
,y
,w
,h
));
4247 if (asap
&& !parsing
)
4248 unscheduleRepaint();
4250 if ( !d
->repaintTimerId
)
4251 d
->repaintTimerId
= startTimer( time
);
4253 // kDebug() << "starting timer " << time;
4256 void KHTMLView::complete( bool pendingAction
)
4258 // kDebug() << "KHTMLView::complete()";
4262 // is there a relayout pending?
4263 if (d
->layoutTimerId
)
4265 // kDebug() << "requesting relayout now";
4267 killTimer(d
->layoutTimerId
);
4268 d
->layoutTimerId
= startTimer( 0 );
4269 d
->emitCompletedAfterRepaint
= pendingAction
?
4270 KHTMLViewPrivate::CSActionPending
: KHTMLViewPrivate::CSFull
;
4273 // is there a repaint pending?
4274 if (d
->repaintTimerId
)
4276 // kDebug() << "requesting repaint now";
4278 killTimer(d
->repaintTimerId
);
4279 d
->repaintTimerId
= startTimer( 0 );
4280 d
->emitCompletedAfterRepaint
= pendingAction
?
4281 KHTMLViewPrivate::CSActionPending
: KHTMLViewPrivate::CSFull
;
4284 if (!d
->emitCompletedAfterRepaint
)
4287 emit m_part
->completed();
4289 emit m_part
->completed(true);
4294 void KHTMLView::updateScrollBars()
4296 const QWidget
*view
= widget();
4300 QSize p
= viewport()->size();
4301 QSize m
= maximumViewportSize();
4303 if (m
.expandedTo(view
->size()) == m
)
4304 p
= m
; // no scroll bars needed
4306 QSize v
= view
->size();
4307 horizontalScrollBar()->setRange(0, v
.width() - p
.width());
4308 horizontalScrollBar()->setPageStep(p
.width());
4309 verticalScrollBar()->setRange(0, v
.height() - p
.height());
4310 verticalScrollBar()->setPageStep(p
.height());
4311 if (!d
->smoothScrolling
) {
4312 d
->updateContentsXY();
4316 void KHTMLView::slotMouseScrollTimer()
4318 horizontalScrollBar()->setValue( horizontalScrollBar()->value() +d
->m_mouseScroll_byX
);
4319 verticalScrollBar()->setValue( verticalScrollBar()->value() +d
->m_mouseScroll_byY
);
4323 static DOM::Position
positionOfLineBoundary(const DOM::Position
&pos
, bool toEnd
)
4325 Selection sel
= pos
;
4326 sel
.expandUsingGranularity(Selection::LINE
);
4327 return toEnd
? sel
.end() : sel
.start();
4330 inline static DOM::Position
positionOfLineBegin(const DOM::Position
&pos
)
4332 return positionOfLineBoundary(pos
, false);
4335 inline static DOM::Position
positionOfLineEnd(const DOM::Position
&pos
)
4337 return positionOfLineBoundary(pos
, true);
4340 bool KHTMLView::caretKeyPressEvent(QKeyEvent
*_ke
)
4342 EditorContext
*ec
= &m_part
->d
->editor_context
;
4343 Selection
&caret
= ec
->m_selection
;
4344 Position old_pos
= caret
.caretPos();
4345 Position pos
= old_pos
;
4346 bool recalcXPos
= true;
4347 bool handled
= true;
4349 bool ctrl
= _ke
->modifiers() & Qt::ControlModifier
;
4350 bool shift
= _ke
->modifiers() & Qt::ShiftModifier
;
4352 switch(_ke
->key()) {
4354 // -- Navigational keys
4356 pos
= old_pos
.nextLinePosition(caret
.xPosForVerticalArrowNavigation(Selection::EXTENT
));
4361 pos
= old_pos
.previousLinePosition(caret
.xPosForVerticalArrowNavigation(Selection::EXTENT
));
4366 pos
= ctrl
? old_pos
.previousWordPosition() : old_pos
.previousCharacterPosition();
4370 pos
= ctrl
? old_pos
.nextWordPosition() : old_pos
.nextCharacterPosition();
4373 case Qt::Key_PageDown
:
4374 // moveCaretNextPage(); ###
4377 case Qt::Key_PageUp
:
4378 // moveCaretPrevPage(); ###
4383 /*moveCaretToDocumentBoundary(false)*/; // ###
4385 pos
= positionOfLineBegin(old_pos
);
4390 /*moveCaretToDocumentBoundary(true)*/; // ###
4392 pos
= positionOfLineEnd(old_pos
);
4400 if (pos
!= old_pos
) {
4401 m_part
->clearCaretRectIfNeeded();
4403 caret
.moveTo(shift
? caret
.nonCaretPos() : pos
, pos
);
4404 int old_x
= caret
.xPosForVerticalArrowNavigation(Selection::CARETPOS
);
4406 m_part
->selectionLayoutChanged();
4408 // restore old x-position to prevent recalculation
4410 m_part
->d
->editor_context
.m_xPosForVerticalArrowNavigation
= old_x
;
4412 m_part
->emitCaretPositionChanged(pos
);
4413 // ### check when to emit it
4414 m_part
->notifySelectionChanged();
4418 if (handled
) _ke
->accept();
4422 #undef DEBUG_CARETMODE