• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KHTML

  • khtml
khtmlview.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 *
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>
11 *
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.
16 *
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.
21 *
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.
26 */
27
28
29#include "khtmlview.h"
30
31#include "khtmlview.moc"
32
33#include "khtml_part.h"
34#include "khtml_events.h"
35#ifdef Q_WS_X11
36#include <qx11info_x11.h>
37#endif
38
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"
52// removeme
53#define protected public
54#include "rendering/render_text.h"
55#undef protected
56#include "xml/dom2_eventsimpl.h"
57#include "css/cssstyleselector.h"
58#include "misc/loader.h"
59#include "khtml_settings.h"
60#include "khtml_printsettings.h"
61
62#include "khtmlpart_p.h"
63
64#include <kcursor.h>
65#include <kdebug.h>
66#include <kglobalsettings.h>
67#include <kdialog.h>
68#include <kiconloader.h>
69#include <klocale.h>
70#include <knotification.h>
71#include <kdeprintdialog.h>
72#include <kconfig.h>
73#include <kstandarddirs.h>
74#include <kstandardshortcut.h>
75#include <kstringhandler.h>
76#include <kconfiggroup.h>
77
78#include <QtGui/QBitmap>
79#include <QtGui/QLabel>
80#include <QtCore/QObject>
81#include <QtGui/QPainter>
82#include <QtCore/QHash>
83#include <QtGui/QToolTip>
84#include <QtCore/QString>
85#include <QtGui/QTextDocument>
86#include <QtCore/QTimer>
87#include <QtCore/QAbstractEventDispatcher>
88#include <QtCore/QVector>
89#include <QtGui/QAbstractScrollArea>
90#include <QtGui/QPrinter>
91#include <QtGui/QPrintDialog>
92
93//#define DEBUG_FLICKER
94
95#include <limits.h>
96#ifdef Q_WS_X11
97#include <X11/Xlib.h>
98#include <fixx11h.h>
99#elif defined(Q_WS_WIN)
100#include <windows.h>
101#endif
102
103#if 0
104namespace khtml {
105 void dumpLineBoxes(RenderFlow *flow);
106}
107#endif
108
109using namespace DOM;
110using namespace khtml;
111
112#ifndef NDEBUG
113static const int sFirstLayoutDelay = 520;
114static const int sParsingLayoutsInterval = 380;
115static const int sLayoutAttemptDelay = 300;
116#else
117static const int sFirstLayoutDelay = 280;
118static const int sParsingLayoutsInterval = 320;
119static const int sLayoutAttemptDelay = 200;
120#endif
121static const int sLayoutAttemptIncrement = 20;
122static const int sParsingLayoutsIncrement = 60;
123
124static const int sSmoothScrollTime = 128;
125static const int sSmoothScrollTick = 16;
126static const int sSmoothScrollMinStaticPixels = 320*200;
127
128static const int sMaxMissedDeadlines = 12;
129static const int sWayTooMany = -1;
130
131class KHTMLViewPrivate {
132 friend class KHTMLView;
133public:
134
135 enum PseudoFocusNodes {
136 PFNone,
137 PFTop,
138 PFBottom
139 };
140
141 enum StaticBackgroundState {
142 SBNone = 0,
143 SBPartial,
144 SBFull
145 };
146
147 enum CompletedState {
148 CSNone = 0,
149 CSFull,
150 CSActionPending
151 };
152
153 KHTMLViewPrivate(KHTMLView* v)
154 : underMouse( 0 ), underMouseNonShared( 0 ), oldUnderMouse( 0 )
155 {
156 postponed_autorepeat = NULL;
157 scrollingFromWheelTimerId = 0;
158 smoothScrollMode = KHTMLView::SSMWhenEfficient;
159
160 reset();
161 vpolicy = Qt::ScrollBarAsNeeded;
162 hpolicy = Qt::ScrollBarAsNeeded;
163 formCompletions=0;
164 prevScrollbarVisible = true;
165
166 possibleTripleClick = false;
167 emitCompletedAfterRepaint = CSNone;
168 cursorIconWidget = 0;
169 cursorIconType = KHTMLView::LINK_NORMAL;
170 m_mouseScrollTimer = 0;
171 m_mouseScrollIndicator = 0;
172 contentsX = 0;
173 contentsY = 0;
174 view = v;
175 }
176 ~KHTMLViewPrivate()
177 {
178 delete formCompletions;
179 delete postponed_autorepeat;
180 if (underMouse)
181 underMouse->deref();
182 if (underMouseNonShared)
183 underMouseNonShared->deref();
184 if (oldUnderMouse)
185 oldUnderMouse->deref();
186
187 delete cursorIconWidget;
188 delete m_mouseScrollTimer;
189 delete m_mouseScrollIndicator;
190 }
191 void reset()
192 {
193 if (underMouse)
194 underMouse->deref();
195 underMouse = 0;
196 if (underMouseNonShared)
197 underMouseNonShared->deref();
198 underMouseNonShared = 0;
199 if (oldUnderMouse)
200 oldUnderMouse->deref();
201 oldUnderMouse = 0;
202 linkPressed = false;
203 staticWidget = SBNone;
204 fixedObjectsCount = 0;
205 staticObjectsCount = 0;
206 tabMovePending = false;
207 lastTabbingDirection = true;
208 pseudoFocusNode = PFNone;
209 zoomLevel = 100;
210#ifndef KHTML_NO_SCROLLBARS
211 //We don't turn off the toolbars here
212 //since if the user turns them
213 //off, then chances are they want them turned
214 //off always - even after a reset.
215#else
216 vpolicy = ScrollBarAlwaysOff;
217 hpolicy = ScrollBarAlwaysOff;
218#endif
219 scrollBarMoved = false;
220 contentsMoving = false;
221 ignoreWheelEvents = false;
222 scrollingFromWheel = QPoint(-1,-1);
223 borderX = 30;
224 borderY = 30;
225 steps = 0;
226 dx = dy = 0;
227 paged = false;
228 clickX = -1;
229 clickY = -1;
230 clickCount = 0;
231 isDoubleClick = false;
232 scrollingSelf = false;
233 delete postponed_autorepeat;
234 postponed_autorepeat = NULL;
235 layoutTimerId = 0;
236 repaintTimerId = 0;
237 scrollTimerId = 0;
238 scrollSuspended = false;
239 scrollSuspendPreActivate = false;
240 smoothScrolling = false;
241 smoothScrollModeIsDefault = true;
242 shouldSmoothScroll = false;
243 smoothScrollMissedDeadlines = 0;
244 hasFrameset = false;
245 complete = false;
246 firstLayoutPending = true;
247#ifdef SPEED_DEBUG
248 firstRepaintPending = true;
249#endif
250 needsFullRepaint = true;
251 dirtyLayout = false;
252 layoutSchedulingEnabled = true;
253 painting = false;
254 layoutCounter = 0;
255 layoutAttemptCounter = 0;
256 scheduledLayoutCounter = 0;
257 updateRegion = QRegion();
258 m_dialogsAllowed = true;
259 accessKeysActivated = false;
260 accessKeysPreActivate = false;
261
262 // the view might have been built before the part it will be assigned to,
263 // so exceptionally, we need to directly ref/deref KHTMLGlobal to
264 // account for this transitory case.
265 KHTMLGlobal::ref();
266 accessKeysEnabled = KHTMLGlobal::defaultHTMLSettings()->accessKeysEnabled();
267 KHTMLGlobal::deref();
268
269 emitCompletedAfterRepaint = CSNone;
270 m_mouseEventsTarget = 0;
271 m_clipHolder = 0;
272 }
273 void newScrollTimer(QWidget *view, int tid)
274 {
275 //kDebug(6000) << "newScrollTimer timer " << tid;
276 view->killTimer(scrollTimerId);
277 scrollTimerId = tid;
278 scrollSuspended = false;
279 }
280 enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
281
282 void adjustScroller(QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
283 {
284 static const struct { int msec, pixels; } timings [] = {
285 {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
286 {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
287 };
288 if (!scrollTimerId ||
289 (static_cast<int>(scrollDirection) != direction &&
290 (static_cast<int>(scrollDirection) != oppositedir || scrollSuspended))) {
291 scrollTiming = 6;
292 scrollBy = timings[scrollTiming].pixels;
293 scrollDirection = direction;
294 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
295 } else if (scrollDirection == direction &&
296 timings[scrollTiming+1].msec && !scrollSuspended) {
297 scrollBy = timings[++scrollTiming].pixels;
298 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
299 } else if (scrollDirection == oppositedir) {
300 if (scrollTiming) {
301 scrollBy = timings[--scrollTiming].pixels;
302 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
303 }
304 }
305 scrollSuspended = false;
306 }
307
308 bool haveZoom() const { return zoomLevel != 100; }
309
310 void startScrolling()
311 {
312 smoothScrolling = true;
313 smoothScrollTimer.start(sSmoothScrollTick);
314 shouldSmoothScroll = false;
315 }
316
317 void stopScrolling()
318 {
319 smoothScrollTimer.stop();
320 dx = dy = 0;
321 steps = 0;
322 updateContentsXY();
323 smoothScrolling = false;
324 shouldSmoothScroll = false;
325 }
326
327 void updateContentsXY()
328 {
329 contentsX = QApplication::isRightToLeft() ?
330 view->horizontalScrollBar()->maximum()-view->horizontalScrollBar()->value() : view->horizontalScrollBar()->value();
331 contentsY = view->verticalScrollBar()->value();
332 }
333 void scrollAccessKeys(int dx, int dy)
334 {
335 QList<QLabel*> wl = qFindChildren<QLabel*>(view->widget(), "KHTMLAccessKey");
336 foreach(QLabel* w, wl) {
337 w->move( w->pos() + QPoint(dx, dy) );
338 }
339 }
340 void scrollExternalWidgets(int dx, int dy)
341 {
342 if (visibleWidgets.isEmpty())
343 return;
344
345 QHashIterator<void*, QWidget*> it(visibleWidgets);
346 while (it.hasNext()) {
347 it.next();
348 it.value()->move( it.value()->pos() + QPoint(dx, dy) );
349 }
350 }
351
352 NodeImpl *underMouse;
353 NodeImpl *underMouseNonShared;
354 NodeImpl *oldUnderMouse;
355
356 // Do not adjust bitfield enums sizes.
357 // They are oversized because they are signed on some platforms.
358 bool tabMovePending:1;
359 bool lastTabbingDirection:1;
360 PseudoFocusNodes pseudoFocusNode:3;
361 bool scrollBarMoved:1;
362 bool contentsMoving:1;
363
364 Qt::ScrollBarPolicy vpolicy;
365 Qt::ScrollBarPolicy hpolicy;
366 bool prevScrollbarVisible:1;
367 bool linkPressed:1;
368 bool ignoreWheelEvents:1;
369 StaticBackgroundState staticWidget: 3;
370 int staticObjectsCount;
371 int fixedObjectsCount;
372
373 int zoomLevel;
374 int borderX, borderY;
375 int dx, dy;
376 int steps;
377 KConfig *formCompletions;
378
379 int clickX, clickY, clickCount;
380 bool isDoubleClick;
381
382 bool paged;
383
384 bool scrollingSelf;
385 int contentsX, contentsY;
386 int layoutTimerId;
387 QKeyEvent* postponed_autorepeat;
388
389 int repaintTimerId;
390 int scrollTimerId;
391 int scrollTiming;
392 int scrollBy;
393 ScrollDirection scrollDirection :3;
394 bool scrollSuspended :1;
395 bool scrollSuspendPreActivate :1;
396 KHTMLView::SmoothScrollingMode smoothScrollMode :3;
397 bool smoothScrolling :1;
398 bool smoothScrollModeIsDefault :1;
399 bool shouldSmoothScroll :1;
400 bool hasFrameset :1;
401 bool complete :1;
402 bool firstLayoutPending :1;
403#ifdef SPEED_DEBUG
404 bool firstRepaintPending :1;
405#endif
406 bool layoutSchedulingEnabled :1;
407 bool needsFullRepaint :1;
408 bool painting :1;
409 bool possibleTripleClick :1;
410 bool dirtyLayout :1;
411 bool m_dialogsAllowed :1;
412 short smoothScrollMissedDeadlines;
413 int layoutCounter;
414 int layoutAttemptCounter;
415 int scheduledLayoutCounter;
416 QRegion updateRegion;
417 QTimer smoothScrollTimer;
418 QTime smoothScrollStopwatch;
419 QHash<void*, QWidget*> visibleWidgets;
420 bool accessKeysEnabled;
421 bool accessKeysActivated;
422 bool accessKeysPreActivate;
423 CompletedState emitCompletedAfterRepaint;
424
425 QLabel* cursorIconWidget;
426 KHTMLView::LinkCursor cursorIconType;
427
428 // scrolling activated by MMB
429 short m_mouseScroll_byX;
430 short m_mouseScroll_byY;
431 QPoint scrollingFromWheel;
432 int scrollingFromWheelTimerId;
433 QTimer *m_mouseScrollTimer;
434 QWidget *m_mouseScrollIndicator;
435 QPointer<QWidget> m_mouseEventsTarget;
436 QStack<QRegion>* m_clipHolder;
437 KHTMLView* view;
438};
439
440#ifndef QT_NO_TOOLTIP
441
451static bool findImageMapRect(HTMLImageElementImpl *img, const QPoint &scrollOfs,
452 const QPoint &p, QRect &r, QString &s)
453{
454 HTMLMapElementImpl* map;
455 if (img && img->document()->isHTMLDocument() &&
456 (map = static_cast<HTMLDocumentImpl*>(img->document())->getMap(img->imageMap()))) {
457 RenderObject::NodeInfo info(true, false);
458 RenderObject *rend = img->renderer();
459 int ax, ay;
460 if (!rend || !rend->absolutePosition(ax, ay))
461 return false;
462 // we're a client side image map
463 bool inside = map->mapMouseEvent(p.x() - ax + scrollOfs.x(),
464 p.y() - ay + scrollOfs.y(), rend->contentWidth(),
465 rend->contentHeight(), info);
466 if (inside && info.URLElement()) {
467 HTMLAreaElementImpl *area = static_cast<HTMLAreaElementImpl *>(info.URLElement());
468 Q_ASSERT(area->id() == ID_AREA);
469 s = area->getAttribute(ATTR_TITLE).string();
470 QRegion reg = area->cachedRegion();
471 if (!s.isEmpty() && !reg.isEmpty()) {
472 r = reg.boundingRect();
473 r.translate(ax, ay);
474 return true;
475 }
476 }
477 }
478 return false;
479}
480
481bool KHTMLView::event( QEvent* e )
482{
483 switch ( e->type() ) {
484 case QEvent::ToolTip: {
485 QHelpEvent *he = static_cast<QHelpEvent*>(e);
486 QPoint p = he->pos();
487
488 DOM::NodeImpl *node = d->underMouseNonShared;
489 QRect region;
490 while ( node ) {
491 if ( node->isElementNode() ) {
492 DOM::ElementImpl *e = static_cast<DOM::ElementImpl*>( node );
493 QRect r;
494 QString s;
495 bool found = false;
496 // for images, check if it is part of a client-side image map,
497 // and query the <area>s' title attributes, too
498 if (e->id() == ID_IMG && !e->getAttribute( ATTR_USEMAP ).isEmpty()) {
499 found = findImageMapRect(static_cast<HTMLImageElementImpl *>(e),
500 viewportToContents(QPoint(0, 0)), p, r, s);
501 }
502 if (!found) {
503 s = e->getAttribute(ATTR_TITLE).string().trimmed();
504 r = node->getRect();
505 }
506 region |= QRect( contentsToViewport( r.topLeft() ), r.size() );
507 if ( !s.isEmpty() ) {
508 QToolTip::showText( he->globalPos(),
509 Qt::convertFromPlainText( s, Qt::WhiteSpaceNormal ),
510 widget(), region );
511 break;
512 }
513 }
514 node = node->parentNode();
515 }
516 // Qt makes tooltip events happen nearly immediately when a preceding one was processed in the past few seconds.
517 // We don't want that feature to apply to web tootlips however, as it clashes with dhtml menus.
518 // So we'll just pretend we did not process that event.
519 return false;
520 }
521
522 case QEvent::DragEnter:
523 case QEvent::DragMove:
524 case QEvent::DragLeave:
525 case QEvent::Drop:
526 // In Qt4, one needs to both call accept() on the DND event and return
527 // true on ::event for the candidate widget for the drop to be possible.
528 // Apps hosting us, such as konq, can do the former but not the later.
529 // We will do the second bit, as it's a no-op unless someone else explicitly
530 // accepts the event. We need to skip the scrollarea to do that,
531 // since it will just skip the events, both killing the drop, and
532 // not permitting us to forward it up the part hiearchy in our dragEnterEvent,
533 // etc. handlers
534 return QWidget::event(e);
535 case QEvent::StyleChange:
536 case QEvent::LayoutRequest: {
537 updateScrollBars();
538 return QAbstractScrollArea::event(e);
539 }
540 case QEvent::PaletteChange:
541 slotPaletteChanged();
542 return QScrollArea::event(e);
543 default:
544 return QScrollArea::event(e);
545 }
546}
547#endif
548
549KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent )
550 : QScrollArea( parent ), d( new KHTMLViewPrivate( this ) )
551{
552 m_medium = "screen";
553
554 m_part = part;
555
556 QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
557 QScrollArea::setHorizontalScrollBarPolicy(d->hpolicy);
558
559 init();
560 widget()->setMouseTracking(true);
561}
562
563KHTMLView::~KHTMLView()
564{
565 closeChildDialogs();
566 if (m_part)
567 {
568 DOM::DocumentImpl *doc = m_part->xmlDocImpl();
569 if (doc)
570 doc->detach();
571 }
572 delete d;
573}
574
575void KHTMLView::setPart(KHTMLPart *part)
576{
577 assert(part && !m_part);
578 m_part = part;
579}
580
581void KHTMLView::init()
582{
583 // Do not access the part here. It might not be fully constructed.
584
585 setFrameStyle(QFrame::NoFrame);
586 setFocusPolicy(Qt::StrongFocus);
587 viewport()->setFocusProxy(this);
588
589 _marginWidth = -1; // undefined
590 _marginHeight = -1;
591 _width = 0;
592 _height = 0;
593
594 installEventFilter(this);
595
596 setAcceptDrops(true);
597 if (!widget())
598 setWidget( new QWidget(this) );
599 widget()->setAttribute( Qt::WA_NoSystemBackground );
600
601 // Do *not* remove this attribute frivolously.
602 // You might not notice a change of behaviour in Debug builds
603 // but removing opaque events will make QWidget::scroll fail horribly
604 // in Release builds.
605 widget()->setAttribute( Qt::WA_OpaquePaintEvent );
606
607 verticalScrollBar()->setCursor( Qt::ArrowCursor );
608 horizontalScrollBar()->setCursor( Qt::ArrowCursor );
609
610 connect(&d->smoothScrollTimer, SIGNAL(timeout()), this, SLOT(scrollTick()));
611}
612
613void KHTMLView::resizeContentsToViewport()
614{
615 QSize s = viewport()->size();
616 resizeContents(s.width(), s.height());
617}
618
619
620// called by KHTMLPart::clear()
621void KHTMLView::clear()
622{
623 if (d->accessKeysEnabled && d->accessKeysActivated)
624 accessKeysTimeout();
625 viewport()->unsetCursor();
626 if ( d->cursorIconWidget )
627 d->cursorIconWidget->hide();
628 if (d->smoothScrolling)
629 d->stopScrolling();
630 d->reset();
631 QAbstractEventDispatcher::instance()->unregisterTimers(this);
632 emit cleared();
633
634 QScrollArea::setHorizontalScrollBarPolicy(d->hpolicy);
635 QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
636 verticalScrollBar()->setEnabled( false );
637 horizontalScrollBar()->setEnabled( false );
638
639}
640
641void KHTMLView::hideEvent(QHideEvent* e)
642{
643 QScrollArea::hideEvent(e);
644}
645
646void KHTMLView::showEvent(QShowEvent* e)
647{
648 QScrollArea::showEvent(e);
649}
650
651void KHTMLView::setMouseEventsTarget( QWidget* w )
652{
653 d->m_mouseEventsTarget = w;
654}
655
656QWidget* KHTMLView::mouseEventsTarget() const
657{
658 return d->m_mouseEventsTarget;
659}
660
661void KHTMLView::setClipHolder( QStack<QRegion>* ch )
662{
663 d->m_clipHolder = ch;
664}
665
666QStack<QRegion>* KHTMLView::clipHolder() const
667{
668 return d->m_clipHolder;
669}
670
671int KHTMLView::contentsWidth() const
672{
673 return widget() ? widget()->width() : 0;
674}
675
676int KHTMLView::contentsHeight() const
677{
678 return widget() ? widget()->height() : 0;
679}
680
681void KHTMLView::resizeContents(int w, int h)
682{
683 if (!widget())
684 return;
685 widget()->resize(w, h);
686 if (!widget()->isVisible())
687 updateScrollBars();
688}
689
690int KHTMLView::contentsX() const
691{
692 return d->contentsX;
693}
694
695int KHTMLView::contentsY() const
696{
697 return d->contentsY;
698}
699
700int KHTMLView::visibleWidth() const
701{
702 if (m_kwp->isRedirected()) {
703 // our RenderWidget knows better
704 if (RenderWidget* rw = m_kwp->renderWidget()) {
705 int ret = rw->width()-rw->paddingLeft()-rw->paddingRight()-rw->borderLeft()-rw->borderRight();
706 if (verticalScrollBar()->isVisible()) {
707 ret -= verticalScrollBar()->sizeHint().width();
708 ret = qMax(0, ret);
709 }
710 return ret;
711 }
712 }
713 return viewport()->width();
714}
715
716int KHTMLView::visibleHeight() const
717{
718 if (m_kwp->isRedirected()) {
719 // our RenderWidget knows better
720 if (RenderWidget* rw = m_kwp->renderWidget()) {
721 int ret = rw->height()-rw->paddingBottom()-rw->paddingTop()-rw->borderTop()-rw->borderBottom();
722 if (horizontalScrollBar()->isVisible()) {
723 ret -= horizontalScrollBar()->sizeHint().height();
724 ret = qMax(0, ret);
725 }
726 return ret;
727 }
728 }
729 return viewport()->height();
730}
731
732void KHTMLView::setContentsPos( int x, int y)
733{
734 horizontalScrollBar()->setValue( QApplication::isRightToLeft() ?
735 horizontalScrollBar()->maximum()-x : x );
736 verticalScrollBar()->setValue( y );
737}
738
739void KHTMLView::scrollBy(int x, int y)
740{
741 if (d->scrollTimerId)
742 d->newScrollTimer(this, 0);
743 horizontalScrollBar()->setValue( horizontalScrollBar()->value()+x );
744 verticalScrollBar()->setValue( verticalScrollBar()->value()+y );
745}
746
747QPoint KHTMLView::contentsToViewport(const QPoint& p) const
748{
749 return QPoint(p.x()-contentsX(), p.y()-contentsY());
750}
751
752void KHTMLView::contentsToViewport(int x, int y, int& cx, int& cy) const
753{
754 QPoint p(x,y);
755 p = contentsToViewport(p);
756 cx = p.x();
757 cy = p.y();
758}
759
760QPoint KHTMLView::viewportToContents(const QPoint& p) const
761{
762 return QPoint(p.x()+contentsX(), p.y()+contentsY());
763}
764
765void KHTMLView::viewportToContents(int x, int y, int& cx, int& cy) const
766{
767 QPoint p(x,y);
768 p = viewportToContents(p);
769 cx = p.x();
770 cy = p.y();
771}
772
773void KHTMLView::updateContents(int x, int y, int w, int h)
774{
775 applyTransforms(x, y, w, h);
776 if (m_kwp->isRedirected()) {
777 QPoint off = m_kwp->absolutePos();
778 KHTMLView* pview = m_part->parentPart()->view();
779 pview->updateContents(x+off.x(), y+off.y(), w, h);
780 } else
781 widget()->update(x, y, w, h);
782}
783
784void KHTMLView::updateContents( const QRect& r )
785{
786 updateContents( r.x(), r.y(), r.width(), r.height() );
787}
788
789void KHTMLView::repaintContents(int x, int y, int w, int h)
790{
791 applyTransforms(x, y, w, h);
792 if (m_kwp->isRedirected()) {
793 QPoint off = m_kwp->absolutePos();
794 KHTMLView* pview = m_part->parentPart()->view();
795 pview->repaintContents(x+off.x(), y+off.y(), w, h);
796 } else
797 widget()->repaint(x, y, w, h);
798}
799
800void KHTMLView::repaintContents( const QRect& r )
801{
802 repaintContents( r.x(), r.y(), r.width(), r.height() );
803}
804
805void KHTMLView::applyTransforms( int& x, int& y, int& w, int& h) const
806{
807 if (d->haveZoom()) {
808 const int z = d->zoomLevel;
809 x = x*z/100;
810 y = y*z/100;
811 w = w*z/100;
812 h = h*z/100;
813 }
814 x -= contentsX();
815 y -= contentsY();
816}
817
818void KHTMLView::revertTransforms( int& x, int& y, int& w, int& h) const
819{
820 x += contentsX();
821 y += contentsY();
822 if (d->haveZoom()) {
823 const int z = d->zoomLevel;
824 x = x*100/z;
825 y = y*100/z;
826 w = w*100/z;
827 h = h*100/z;
828 }
829}
830
831void KHTMLView::revertTransforms( int& x, int& y ) const
832{
833 int dummy = 0;
834 revertTransforms(x, y, dummy, dummy);
835}
836
837void KHTMLView::resizeEvent (QResizeEvent* /*e*/)
838{
839 updateScrollBars();
840
841 // If we didn't load anything, make white area as big as the view
842 if (!m_part->xmlDocImpl())
843 resizeContentsToViewport();
844
845 // Viewport-dependent media queries may cause us to need completely different style information.
846 if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->styleSelector()->affectedByViewportChange()) {
847 m_part->xmlDocImpl()->updateStyleSelector();
848 }
849
850 if (d->layoutSchedulingEnabled)
851 layout();
852
853 QApplication::sendPostedEvents(viewport(), QEvent::Paint);
854
855 if ( m_part && m_part->xmlDocImpl() ) {
856 if (m_part->parentPart()) {
857 // sub-frame : queue the resize event until our toplevel is done layouting
858 khtml::ChildFrame *cf = m_part->parentPart()->frame( m_part );
859 if (cf && !cf->m_partContainerElement.isNull())
860 cf->m_partContainerElement.data()->postResizeEvent();
861 } else {
862 // toplevel : dispatch sub-frames'resize events before our own
863 HTMLPartContainerElementImpl::sendPostedResizeEvents();
864 m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
865 }
866 }
867}
868
869void KHTMLView::paintEvent( QPaintEvent *e )
870{
871 QRect r = e->rect();
872 QRect v(contentsX(), contentsY(), visibleWidth(), visibleHeight());
873 QPoint off(contentsX(),contentsY());
874 r.translate(off);
875 r = r.intersect(v);
876 if (!r.isValid() || r.isEmpty()) return;
877
878 QPainter p(widget());
879 p.translate(-off);
880
881 if (d->haveZoom()) {
882 p.scale( d->zoomLevel/100., d->zoomLevel/100.);
883
884 r.setX(r.x()*100/d->zoomLevel);
885 r.setY(r.y()*100/d->zoomLevel);
886 r.setWidth(r.width()*100/d->zoomLevel);
887 r.setHeight(r.height()*100/d->zoomLevel);
888 r.adjust(-1,-1,1,1);
889 }
890 p.setClipRect(r);
891
892 int ex = r.x();
893 int ey = r.y();
894 int ew = r.width();
895 int eh = r.height();
896
897 if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
898 p.fillRect(ex, ey, ew, eh, palette().brush(QPalette::Active, QPalette::Base));
899 return;
900 } else if ( d->complete && static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
901 // an external update request happens while we have a layout scheduled
902 unscheduleRelayout();
903 layout();
904 } else if (m_part->xmlDocImpl()->tokenizer()) {
905 m_part->xmlDocImpl()->tokenizer()->setNormalYieldDelay();
906 }
907
908 if (d->painting) {
909 kDebug( 6000 ) << "WARNING: paintEvent reentered! ";
910 kDebug( 6000 ) << kBacktrace();
911 return;
912 }
913 d->painting = true;
914
915 m_part->xmlDocImpl()->renderer()->layer()->paint(&p, r);
916
917 if (d->hasFrameset) {
918 NodeImpl *body = static_cast<HTMLDocumentImpl*>(m_part->xmlDocImpl())->body();
919 if(body && body->renderer() && body->id() == ID_FRAMESET)
920 static_cast<RenderFrameSet*>(body->renderer())->paintFrameSetRules(&p, r);
921 else
922 d->hasFrameset = false;
923 }
924
925 khtml::DrawContentsEvent event( &p, ex, ey, ew, eh );
926 QApplication::sendEvent( m_part, &event );
927
928 if (d->contentsMoving && !d->smoothScrolling && widget()->underMouse()) {
929 QMouseEvent *tempEvent = new QMouseEvent( QEvent::MouseMove, widget()->mapFromGlobal( QCursor::pos() ),
930 Qt::NoButton, Qt::NoButton, Qt::NoModifier );
931 QApplication::postEvent(widget(), tempEvent);
932 }
933#ifdef SPEED_DEBUG
934 if (d->firstRepaintPending && !m_part->parentPart()) {
935 kDebug(6080) << "FIRST PAINT:" << m_part->d->m_parsetime.elapsed();
936 }
937 d->firstRepaintPending = false;
938#endif
939 d->painting = false;
940}
941
942void KHTMLView::setMarginWidth(int w)
943{
944 // make it update the rendering area when set
945 _marginWidth = w;
946}
947
948void KHTMLView::setMarginHeight(int h)
949{
950 // make it update the rendering area when set
951 _marginHeight = h;
952}
953
954void KHTMLView::layout()
955{
956 if( m_part && m_part->xmlDocImpl() ) {
957 DOM::DocumentImpl *document = m_part->xmlDocImpl();
958
959 khtml::RenderCanvas* canvas = static_cast<khtml::RenderCanvas *>(document->renderer());
960 if ( !canvas ) return;
961
962 d->layoutSchedulingEnabled=false;
963 d->dirtyLayout = true;
964
965 // the reference object for the overflow property on canvas
966 RenderObject * ref = 0;
967 RenderObject* root = document->documentElement() ? document->documentElement()->renderer() : 0;
968
969 if (document->isHTMLDocument()) {
970 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
971 if(body && body->renderer() && body->id() == ID_FRAMESET) {
972 QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
973 QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
974 body->renderer()->setNeedsLayout(true);
975 d->hasFrameset = true;
976 }
977 else if (root) // only apply body's overflow to canvas if root has a visible overflow
978 ref = (!body || root->style()->hidesOverflow()) ? root : body->renderer();
979 } else {
980 ref = root;
981 }
982 if (ref) {
983 if( ref->style()->overflowX() == OHIDDEN ) {
984 if (d->hpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
985 } else if (ref->style()->overflowX() == OSCROLL ) {
986 if (d->hpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
987 } else if (horizontalScrollBarPolicy() != d->hpolicy) {
988 QScrollArea::setHorizontalScrollBarPolicy(d->hpolicy);
989 }
990 if ( ref->style()->overflowY() == OHIDDEN ) {
991 if (d->vpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
992 } else if (ref->style()->overflowY() == OSCROLL ) {
993 if (d->vpolicy == Qt::ScrollBarAsNeeded) QScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
994 } else if (verticalScrollBarPolicy() != d->vpolicy) {
995 QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
996 }
997 }
998 d->needsFullRepaint = d->firstLayoutPending;
999 if (_height != visibleHeight() || _width != visibleWidth()) {;
1000 d->needsFullRepaint = true;
1001 _height = visibleHeight();
1002 _width = visibleWidth();
1003 }
1004
1005 canvas->layout();
1006
1007 emit finishedLayout();
1008 if (d->firstLayoutPending) {
1009 // make sure firstLayoutPending is set to false now in case this layout
1010 // wasn't scheduled
1011 d->firstLayoutPending = false;
1012 verticalScrollBar()->setEnabled( true );
1013 horizontalScrollBar()->setEnabled( true );
1014 }
1015 d->layoutCounter++;
1016
1017 if (d->accessKeysEnabled && d->accessKeysActivated) {
1018 emit hideAccessKeys();
1019 displayAccessKeys();
1020 }
1021 }
1022 else
1023 _width = visibleWidth();
1024
1025 if (d->layoutTimerId)
1026 killTimer(d->layoutTimerId);
1027 d->layoutTimerId = 0;
1028 d->layoutSchedulingEnabled=true;
1029}
1030
1031void KHTMLView::closeChildDialogs()
1032{
1033 QList<QDialog *> dlgs = findChildren<QDialog *>();
1034 foreach (QDialog *dlg, dlgs)
1035 {
1036 KDialog* dlgbase = dynamic_cast<KDialog*>( dlg );
1037 if ( dlgbase ) {
1038 if ( dlgbase->testAttribute( Qt::WA_ShowModal ) ) {
1039 kDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase;
1040 // close() ends up calling QButton::animateClick, which isn't immediate
1041 // we need something the exits the event loop immediately (#49068)
1042 dlgbase->reject();
1043 }
1044 }
1045 else
1046 {
1047 kWarning() << "closeChildDialogs: not a KDialog! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg);
1048 static_cast<QWidget*>(dlg)->hide();
1049 }
1050 }
1051 d->m_dialogsAllowed = false;
1052}
1053
1054bool KHTMLView::dialogsAllowed() {
1055 bool allowed = d->m_dialogsAllowed;
1056 KHTMLPart* p = m_part->parentPart();
1057 if (p && p->view())
1058 allowed &= p->view()->dialogsAllowed();
1059 return allowed;
1060}
1061
1062void KHTMLView::closeEvent( QCloseEvent* ev )
1063{
1064 closeChildDialogs();
1065 QScrollArea::closeEvent( ev );
1066}
1067
1068void KHTMLView::setZoomLevel(int percent)
1069{
1070 percent = percent < 20 ? 20 : (percent > 800 ? 800 : percent);
1071 int oldpercent = d->zoomLevel;
1072 d->zoomLevel = percent;
1073 if (percent != oldpercent) {
1074 if (d->layoutSchedulingEnabled)
1075 layout();
1076 widget()->update();
1077 }
1078}
1079
1080int KHTMLView::zoomLevel() const
1081{
1082 return d->zoomLevel;
1083}
1084
1085void KHTMLView::setSmoothScrollingMode( SmoothScrollingMode m )
1086{
1087 d->smoothScrollMode = m;
1088 d->smoothScrollModeIsDefault = false;
1089 if (d->smoothScrolling && !m)
1090 d->stopScrolling();
1091}
1092
1093void KHTMLView::setSmoothScrollingModeDefault( SmoothScrollingMode m )
1094{
1095 // check for manual override
1096 if (!d->smoothScrollModeIsDefault)
1097 return;
1098 d->smoothScrollMode = m;
1099 if (d->smoothScrolling && !m)
1100 d->stopScrolling();
1101}
1102
1103KHTMLView::SmoothScrollingMode KHTMLView::smoothScrollingMode( ) const
1104{
1105 return d->smoothScrollMode;
1106}
1107
1108//
1109// Event Handling
1110//
1112
1113void KHTMLView::mousePressEvent( QMouseEvent *_mouse )
1114{
1115 if (!m_part->xmlDocImpl()) return;
1116 if (d->possibleTripleClick && ( _mouse->button() & Qt::MouseButtonMask ) == Qt::LeftButton)
1117 {
1118 mouseDoubleClickEvent( _mouse ); // it handles triple clicks too
1119 return;
1120 }
1121
1122 int xm = _mouse->x();
1123 int ym = _mouse->y();
1124 revertTransforms(xm, ym);
1125
1126 // kDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()-contentsX()<<"/"<<_mouse->y()-contentsY()<<"), contents=(" << xm << "/" << ym << ")\n";
1127
1128 d->isDoubleClick = false;
1129
1130 DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MousePress );
1131 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1132
1133 //kDebug(6000) << "innerNode="<<mev.innerNode.nodeName().string();
1134
1135 if ( (_mouse->button() == Qt::MidButton) &&
1136 !m_part->d->m_bOpenMiddleClick && !d->m_mouseScrollTimer &&
1137 mev.url.isNull() && (mev.innerNode.elementId() != ID_INPUT) ) {
1138 QPoint point = mapFromGlobal( _mouse->globalPos() );
1139
1140 d->m_mouseScroll_byX = 0;
1141 d->m_mouseScroll_byY = 0;
1142
1143 d->m_mouseScrollTimer = new QTimer( this );
1144 connect( d->m_mouseScrollTimer, SIGNAL(timeout()), this, SLOT(slotMouseScrollTimer()) );
1145
1146 if ( !d->m_mouseScrollIndicator ) {
1147 QPixmap pixmap( 48, 48 ), icon;
1148 pixmap.fill( QColor( qRgba( 127, 127, 127, 127 ) ) );
1149
1150 QPainter p( &pixmap );
1151 QStyleOption option;
1152
1153 option.rect.setRect( 16, 0, 16, 16 );
1154 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowUp, &option, &p );
1155 option.rect.setRect( 0, 16, 16, 16 );
1156 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowLeft, &option, &p );
1157 option.rect.setRect( 16, 32, 16, 16 );
1158 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowDown, &option, &p );
1159 option.rect.setRect( 32, 16, 16, 16 );
1160 QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowRight, &option, &p );
1161 p.drawEllipse( 23, 23, 2, 2 );
1162
1163 d->m_mouseScrollIndicator = new QWidget( this );
1164 d->m_mouseScrollIndicator->setFixedSize( 48, 48 );
1165 QPalette palette;
1166 palette.setBrush( d->m_mouseScrollIndicator->backgroundRole(), QBrush( pixmap ) );
1167 d->m_mouseScrollIndicator->setPalette( palette );
1168 }
1169 d->m_mouseScrollIndicator->move( point.x()-24, point.y()-24 );
1170
1171 bool hasHorBar = visibleWidth() < contentsWidth();
1172 bool hasVerBar = visibleHeight() < contentsHeight();
1173
1174 KConfigGroup cg( KGlobal::config(), "HTML Settings" );
1175 if ( cg.readEntry( "ShowMouseScrollIndicator", true ) ) {
1176 d->m_mouseScrollIndicator->show();
1177 d->m_mouseScrollIndicator->unsetCursor();
1178
1179 QBitmap mask = d->m_mouseScrollIndicator->palette().brush(d->m_mouseScrollIndicator->backgroundRole()).texture().createHeuristicMask( true );
1180
1181 if ( hasHorBar && !hasVerBar ) {
1182 QBitmap bm( 16, 16 );
1183 bm.clear();
1184 QPainter painter( &mask );
1185 painter.drawPixmap( QRectF( 16, 0, bm.width(), bm.height() ), bm, bm.rect() );
1186 painter.drawPixmap( QRectF( 16, 32, bm.width(), bm.height() ), bm, bm.rect() );
1187 d->m_mouseScrollIndicator->setCursor( Qt::SizeHorCursor );
1188 }
1189 else if ( !hasHorBar && hasVerBar ) {
1190 QBitmap bm( 16, 16 );
1191 bm.clear();
1192 QPainter painter( &mask );
1193 painter.drawPixmap( QRectF( 0, 16, bm.width(), bm.height() ), bm, bm.rect() );
1194 painter.drawPixmap( QRectF( 32, 16, bm.width(), bm.height() ), bm, bm.rect() );
1195 d->m_mouseScrollIndicator->setCursor( Qt::SizeVerCursor );
1196 }
1197 else
1198 d->m_mouseScrollIndicator->setCursor( Qt::SizeAllCursor );
1199
1200 d->m_mouseScrollIndicator->setMask( mask );
1201 }
1202 else {
1203 if ( hasHorBar && !hasVerBar )
1204 viewport()->setCursor( Qt::SizeHorCursor );
1205 else if ( !hasHorBar && hasVerBar )
1206 viewport()->setCursor( Qt::SizeVerCursor );
1207 else
1208 viewport()->setCursor( Qt::SizeAllCursor );
1209 }
1210
1211 return;
1212 }
1213 else if ( d->m_mouseScrollTimer ) {
1214 delete d->m_mouseScrollTimer;
1215 d->m_mouseScrollTimer = 0;
1216
1217 if ( d->m_mouseScrollIndicator )
1218 d->m_mouseScrollIndicator->hide();
1219 }
1220
1221 if (d->clickCount > 0 &&
1222 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
1223 d->clickCount++;
1224 else {
1225 d->clickCount = 1;
1226 d->clickX = xm;
1227 d->clickY = ym;
1228 }
1229
1230 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1231 d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
1232
1233 if (!swallowEvent) {
1234 emit m_part->nodeActivated(mev.innerNode);
1235
1236 khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1237 QApplication::sendEvent( m_part, &event );
1238 // we might be deleted after this
1239 }
1240}
1241
1242void KHTMLView::mouseDoubleClickEvent( QMouseEvent *_mouse )
1243{
1244 if(!m_part->xmlDocImpl()) return;
1245
1246 int xm = _mouse->x();
1247 int ym = _mouse->y();
1248 revertTransforms(xm, ym);
1249
1250 // kDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym;
1251
1252 d->isDoubleClick = true;
1253
1254 DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseDblClick );
1255 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1256
1257 // We do the same thing as mousePressEvent() here, since the DOM does not treat
1258 // single and double-click events as separate (only the detail, i.e. number of clicks differs)
1259 if (d->clickCount > 0 &&
1260 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
1261 d->clickCount++;
1262 else { // shouldn't happen, if Qt has the same criterias for double clicks.
1263 d->clickCount = 1;
1264 d->clickX = xm;
1265 d->clickY = ym;
1266 }
1267 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1268 d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
1269
1270 if (!swallowEvent) {
1271 khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
1272 QApplication::sendEvent( m_part, &event );
1273 }
1274
1275 d->possibleTripleClick=true;
1276 QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
1277}
1278
1279void KHTMLView::tripleClickTimeout()
1280{
1281 d->possibleTripleClick = false;
1282 d->clickCount = 0;
1283}
1284
1285static bool targetOpensNewWindow(KHTMLPart *part, QString target)
1286{
1287 if (!target.isEmpty() && (target.toLower() != "_top") &&
1288 (target.toLower() != "_self") && (target.toLower() != "_parent")) {
1289 if (target.toLower() == "_blank")
1290 return true;
1291 else {
1292 while (part->parentPart())
1293 part = part->parentPart();
1294 if (!part->frameExists(target))
1295 return true;
1296 }
1297 }
1298 return false;
1299}
1300
1301void KHTMLView::mouseMoveEvent( QMouseEvent * _mouse )
1302{
1303 if ( d->m_mouseScrollTimer ) {
1304 QPoint point = mapFromGlobal( _mouse->globalPos() );
1305
1306 int deltaX = point.x() - d->m_mouseScrollIndicator->x() - 24;
1307 int deltaY = point.y() - d->m_mouseScrollIndicator->y() - 24;
1308
1309 (deltaX > 0) ? d->m_mouseScroll_byX = 1 : d->m_mouseScroll_byX = -1;
1310 (deltaY > 0) ? d->m_mouseScroll_byY = 1 : d->m_mouseScroll_byY = -1;
1311
1312 double adX = qAbs(deltaX)/30.0;
1313 double adY = qAbs(deltaY)/30.0;
1314
1315 d->m_mouseScroll_byX = qMax(qMin(d->m_mouseScroll_byX * int(adX*adX), SHRT_MAX), SHRT_MIN);
1316 d->m_mouseScroll_byY = qMax(qMin(d->m_mouseScroll_byY * int(adY*adY), SHRT_MAX), SHRT_MIN);
1317
1318 if (d->m_mouseScroll_byX == 0 && d->m_mouseScroll_byY == 0) {
1319 d->m_mouseScrollTimer->stop();
1320 }
1321 else if (!d->m_mouseScrollTimer->isActive()) {
1322 d->m_mouseScrollTimer->start( 20 );
1323 }
1324 }
1325
1326 if(!m_part->xmlDocImpl()) return;
1327
1328 int xm = _mouse->x();
1329 int ym = _mouse->y();
1330 revertTransforms(xm, ym);
1331
1332 DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseMove );
1333 // Do not modify :hover/:active state while mouse is pressed.
1334 m_part->xmlDocImpl()->prepareMouseEvent( _mouse->buttons() /*readonly ?*/, xm, ym, &mev );
1335
1336 // kDebug(6000) << "mouse move: " << _mouse->pos()
1337 // << " button " << _mouse->button()
1338 // << " state " << _mouse->state() << endl;
1339
1340 DOM::NodeImpl* target = mev.innerNode.handle();
1341 DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
1342
1343 // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
1344 if (d->m_mouseEventsTarget && fn && fn->renderer() && fn->renderer()->isWidget())
1345 target = fn;
1346
1347 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,target,mev.innerNonSharedNode.handle(),false,
1348 0,_mouse,true,DOM::NodeImpl::MouseMove);
1349
1350 if (d->clickCount > 0 &&
1351 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
1352 d->clickCount = 0; // moving the mouse outside the threshold invalidates the click
1353 }
1354
1355 khtml::RenderObject* r = target ? target->renderer() : 0;
1356 bool setCursor = true;
1357 bool forceDefault = false;
1358 if (r && r->isWidget()) {
1359 RenderWidget* rw = static_cast<RenderWidget*>(r);
1360 KHTMLWidget* kw = qobject_cast<KHTMLView*>(rw->widget())? dynamic_cast<KHTMLWidget*>(rw->widget()) : 0;
1361 if (kw && kw->m_kwp->isRedirected())
1362 setCursor = false;
1363 else if (QLineEdit* le = qobject_cast<QLineEdit*>(rw->widget())) {
1364 QList<QWidget*> wl = qFindChildren<QWidget *>( le, "KLineEditButton" );
1365 // force arrow cursor above lineedit clear button
1366 foreach (QWidget*w, wl) {
1367 if (w->underMouse()) {
1368 forceDefault = true;
1369 break;
1370 }
1371 }
1372 }
1373 else if (QTextEdit* te = qobject_cast<QTextEdit*>(rw->widget())) {
1374 if (te->verticalScrollBar()->underMouse() || te->horizontalScrollBar()->underMouse())
1375 forceDefault = true;
1376 }
1377 }
1378 khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
1379 QCursor c;
1380 LinkCursor linkCursor = LINK_NORMAL;
1381 switch (!forceDefault ? (style ? style->cursor() : CURSOR_AUTO) : CURSOR_DEFAULT) {
1382 case CURSOR_AUTO:
1383 if ( r && r->isText() && ((m_part->d->m_bMousePressed && m_part->d->editor_context.m_beganSelectingText) ||
1384 !r->isPointInsideSelection(xm, ym, m_part->caret())) )
1385 c = QCursor(Qt::IBeamCursor);
1386 if ( mev.url.length() && m_part->settings()->changeCursor() ) {
1387 c = m_part->urlCursor();
1388 if (mev.url.string().startsWith("mailto:") && mev.url.string().indexOf('@')>0)
1389 linkCursor = LINK_MAILTO;
1390 else
1391 if ( targetOpensNewWindow( m_part, mev.target.string() ) )
1392 linkCursor = LINK_NEWWINDOW;
1393 }
1394
1395 if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
1396 c = QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
1397
1398 break;
1399 case CURSOR_CROSS:
1400 c = QCursor(Qt::CrossCursor);
1401 break;
1402 case CURSOR_POINTER:
1403 c = m_part->urlCursor();
1404 if (mev.url.string().startsWith("mailto:") && mev.url.string().indexOf('@')>0)
1405 linkCursor = LINK_MAILTO;
1406 else
1407 if ( targetOpensNewWindow( m_part, mev.target.string() ) )
1408 linkCursor = LINK_NEWWINDOW;
1409 break;
1410 case CURSOR_PROGRESS:
1411 c = QCursor(Qt::BusyCursor); // working_cursor
1412 break;
1413 case CURSOR_MOVE:
1414 case CURSOR_ALL_SCROLL:
1415 c = QCursor(Qt::SizeAllCursor);
1416 break;
1417 case CURSOR_E_RESIZE:
1418 case CURSOR_W_RESIZE:
1419 case CURSOR_EW_RESIZE:
1420 c = QCursor(Qt::SizeHorCursor);
1421 break;
1422 case CURSOR_N_RESIZE:
1423 case CURSOR_S_RESIZE:
1424 case CURSOR_NS_RESIZE:
1425 c = QCursor(Qt::SizeVerCursor);
1426 break;
1427 case CURSOR_NE_RESIZE:
1428 case CURSOR_SW_RESIZE:
1429 case CURSOR_NESW_RESIZE:
1430 c = QCursor(Qt::SizeBDiagCursor);
1431 break;
1432 case CURSOR_NW_RESIZE:
1433 case CURSOR_SE_RESIZE:
1434 case CURSOR_NWSE_RESIZE:
1435 c = QCursor(Qt::SizeFDiagCursor);
1436 break;
1437 case CURSOR_TEXT:
1438 c = QCursor(Qt::IBeamCursor);
1439 break;
1440 case CURSOR_WAIT:
1441 c = QCursor(Qt::WaitCursor);
1442 break;
1443 case CURSOR_HELP:
1444 c = QCursor(Qt::WhatsThisCursor);
1445 break;
1446 case CURSOR_DEFAULT:
1447 break;
1448 case CURSOR_NONE:
1449 case CURSOR_NOT_ALLOWED:
1450 c = QCursor(Qt::ForbiddenCursor);
1451 break;
1452 case CURSOR_ROW_RESIZE:
1453 c = QCursor(Qt::SplitVCursor);
1454 break;
1455 case CURSOR_COL_RESIZE:
1456 c = QCursor(Qt::SplitHCursor);
1457 break;
1458 case CURSOR_VERTICAL_TEXT:
1459 case CURSOR_CONTEXT_MENU:
1460 case CURSOR_NO_DROP:
1461 case CURSOR_CELL:
1462 case CURSOR_COPY:
1463 case CURSOR_ALIAS:
1464 c = QCursor(Qt::ArrowCursor);
1465 break;
1466 }
1467
1468 if (!setCursor && style && style->cursor() != CURSOR_AUTO)
1469 setCursor = true;
1470
1471 QWidget* vp = viewport();
1472 for (KHTMLPart* p = m_part; p; p = p->parentPart())
1473 if (!p->parentPart())
1474 vp = p->view()->viewport();
1475 if ( setCursor && vp->cursor().handle() != c.handle() ) {
1476 if( c.shape() == Qt::ArrowCursor) {
1477 for (KHTMLPart* p = m_part; p; p = p->parentPart())
1478 p->view()->viewport()->unsetCursor();
1479 }
1480 else {
1481 vp->setCursor( c );
1482 }
1483 }
1484
1485 if ( linkCursor!=LINK_NORMAL && isVisible() && hasFocus() ) {
1486#ifdef Q_WS_X11
1487
1488 if( !d->cursorIconWidget ) {
1489#ifdef Q_WS_X11
1490 d->cursorIconWidget = new QLabel( 0, Qt::X11BypassWindowManagerHint );
1491 XSetWindowAttributes attr;
1492 attr.save_under = True;
1493 XChangeWindowAttributes( QX11Info::display(), d->cursorIconWidget->winId(), CWSaveUnder, &attr );
1494#else
1495 d->cursorIconWidget = new QLabel( NULL, NULL );
1496 //TODO
1497#endif
1498 }
1499
1500 // Update the pixmap if need be.
1501 if (linkCursor != d->cursorIconType) {
1502 d->cursorIconType = linkCursor;
1503 QString cursorIcon;
1504 switch (linkCursor)
1505 {
1506 case LINK_MAILTO: cursorIcon = "mail-message-new"; break;
1507 case LINK_NEWWINDOW: cursorIcon = "window-new"; break;
1508 default: cursorIcon = "dialog-error"; break;
1509 }
1510
1511 QPixmap icon_pixmap = KHTMLGlobal::iconLoader()->loadIcon( cursorIcon, KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(), 0, true );
1512
1513 d->cursorIconWidget->resize( icon_pixmap.width(), icon_pixmap.height());
1514 d->cursorIconWidget->setMask( icon_pixmap.createMaskFromColor(Qt::transparent));
1515 d->cursorIconWidget->setPixmap( icon_pixmap);
1516 d->cursorIconWidget->update();
1517 }
1518
1519 QPoint c_pos = QCursor::pos();
1520 d->cursorIconWidget->move( c_pos.x() + 15, c_pos.y() + 15 );
1521#ifdef Q_WS_X11
1522 XRaiseWindow( QX11Info::display(), d->cursorIconWidget->winId());
1523 QApplication::flush();
1524#elif defined(Q_WS_WIN)
1525 SetWindowPos( d->cursorIconWidget->winId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
1526#else
1527 //TODO?
1528#endif
1529 d->cursorIconWidget->show();
1530#endif
1531 }
1532 else if ( d->cursorIconWidget )
1533 d->cursorIconWidget->hide();
1534
1535 if (r && r->isWidget()) {
1536 _mouse->ignore();
1537 }
1538
1539 if (!swallowEvent) {
1540 khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1541 QApplication::sendEvent( m_part, &event );
1542 }
1543}
1544
1545void KHTMLView::mouseReleaseEvent( QMouseEvent * _mouse )
1546{
1547 bool swallowEvent = false;
1548
1549 int xm = _mouse->x();
1550 int ym = _mouse->y();
1551 revertTransforms(xm, ym);
1552
1553 DOM::NodeImpl::MouseEvent mev( _mouse->buttons(), DOM::NodeImpl::MouseRelease );
1554
1555 if ( m_part->xmlDocImpl() )
1556 {
1557 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1558
1559 DOM::NodeImpl* target = mev.innerNode.handle();
1560 DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
1561
1562 // a widget may be the real target of this event (e.g. if a scrollbar's slider is being moved)
1563 if (d->m_mouseEventsTarget && fn && fn->renderer() && fn->renderer()->isWidget())
1564 target = fn;
1565
1566 swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,target,mev.innerNonSharedNode.handle(),true,
1567 d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
1568
1569 // clear our sticky event target on any mouseRelease event
1570 if (d->m_mouseEventsTarget)
1571 d->m_mouseEventsTarget = 0;
1572
1573 if (d->clickCount > 0 &&
1574 QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
1575 QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
1576 _mouse->pos(), _mouse->button(), _mouse->buttons(), _mouse->modifiers());
1577 dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1578 d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
1579 }
1580
1581 khtml::RenderObject* r = target ? target->renderer() : 0;
1582 if (r && r->isWidget())
1583 _mouse->ignore();
1584 }
1585
1586 if (!swallowEvent) {
1587 khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1588 QApplication::sendEvent( m_part, &event );
1589 }
1590}
1591
1592// returns true if event should be swallowed
1593bool KHTMLView::dispatchKeyEvent( QKeyEvent *_ke )
1594{
1595 if (!m_part->xmlDocImpl())
1596 return false;
1597 // Pressing and releasing a key should generate keydown, keypress and keyup events
1598 // Holding it down should generated keydown, keypress (repeatedly) and keyup events
1599 // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
1600 // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
1601 // of the Qt events shouldn't be passed to DOM, but it should be still filtered
1602 // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
1603 // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
1604 // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
1605 // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
1606 // The solution is to filter out and postpone the Qt autorepeat keyrelease until
1607 // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
1608 // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
1609 // again, and here it will be ignored.
1610 //
1611 // Qt: Press | Release(autorepeat) Press(autorepeat) etc. | Release
1612 // DOM: Down + Press | (nothing) Press | Up
1613
1614 // It's also possible to get only Releases. E.g. the release of alt-tab,
1615 // or when the keypresses get captured by an accel.
1616
1617 if( _ke == d->postponed_autorepeat ) // replayed event
1618 {
1619 return false;
1620 }
1621
1622 if( _ke->type() == QEvent::KeyPress )
1623 {
1624 if( !_ke->isAutoRepeat())
1625 {
1626 bool ret = dispatchKeyEventHelper( _ke, false ); // keydown
1627 // don't send keypress even if keydown was blocked, like IE (and unlike Mozilla)
1628 if( !ret && dispatchKeyEventHelper( _ke, true )) // keypress
1629 ret = true;
1630 return ret;
1631 }
1632 else // autorepeat
1633 {
1634 bool ret = dispatchKeyEventHelper( _ke, true ); // keypress
1635 if( !ret && d->postponed_autorepeat )
1636 keyPressEvent( d->postponed_autorepeat );
1637 delete d->postponed_autorepeat;
1638 d->postponed_autorepeat = NULL;
1639 return ret;
1640 }
1641 }
1642 else // QEvent::KeyRelease
1643 {
1644 // Discard postponed "autorepeat key-release" events that didn't see
1645 // a keypress after them (e.g. due to QAccel)
1646 delete d->postponed_autorepeat;
1647 d->postponed_autorepeat = 0;
1648
1649 if( !_ke->isAutoRepeat()) {
1650 return dispatchKeyEventHelper( _ke, false ); // keyup
1651 }
1652 else
1653 {
1654 d->postponed_autorepeat = new QKeyEvent( _ke->type(), _ke->key(), _ke->modifiers(),
1655 _ke->text(), _ke->isAutoRepeat(), _ke->count());
1656 if( _ke->isAccepted())
1657 d->postponed_autorepeat->accept();
1658 else
1659 d->postponed_autorepeat->ignore();
1660 return true;
1661 }
1662 }
1663}
1664
1665// returns true if event should be swallowed
1666bool KHTMLView::dispatchKeyEventHelper( QKeyEvent *_ke, bool keypress )
1667{
1668 DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
1669 if (keyNode) {
1670 return keyNode->dispatchKeyEvent(_ke, keypress);
1671 } else { // no focused node, send to document
1672 return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
1673 }
1674}
1675
1676void KHTMLView::keyPressEvent( QKeyEvent *_ke )
1677{
1678 // If CTRL was hit, be prepared for access keys
1679 if (d->accessKeysEnabled && _ke->key() == Qt::Key_Control && !(_ke->modifiers() & ~Qt::ControlModifier) && !d->accessKeysActivated)
1680 {
1681 d->accessKeysPreActivate=true;
1682 _ke->accept();
1683 return;
1684 }
1685
1686 if (_ke->key() == Qt::Key_Shift && !(_ke->modifiers() & ~Qt::ShiftModifier))
1687 d->scrollSuspendPreActivate=true;
1688
1689 // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
1690 // may eat the event
1691
1692 if (d->accessKeysEnabled && d->accessKeysActivated)
1693 {
1694 int state = ( _ke->modifiers() & ( Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier ));
1695 if ( state==0 || state==Qt::ShiftModifier ) {
1696 if (_ke->key() != Qt::Key_Shift)
1697 accessKeysTimeout();
1698 handleAccessKey( _ke );
1699 _ke->accept();
1700 return;
1701 }
1702 accessKeysTimeout();
1703 _ke->accept();
1704 return;
1705 }
1706
1707 if ( dispatchKeyEvent( _ke )) {
1708 // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
1709 _ke->accept();
1710 return;
1711 }
1712
1713 int offs = (viewport()->height() < 30) ? viewport()->height() : 30; // ### ??
1714 if (_ke->modifiers() & Qt::ShiftModifier)
1715 switch(_ke->key())
1716 {
1717 case Qt::Key_Space:
1718 verticalScrollBar()->setValue( verticalScrollBar()->value() -viewport()->height() + offs );
1719 if(d->scrollSuspended)
1720 d->newScrollTimer(this, 0);
1721 break;
1722
1723 case Qt::Key_Down:
1724 case Qt::Key_J:
1725 d->adjustScroller(this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
1726 break;
1727
1728 case Qt::Key_Up:
1729 case Qt::Key_K:
1730 d->adjustScroller(this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
1731 break;
1732
1733 case Qt::Key_Left:
1734 case Qt::Key_H:
1735 d->adjustScroller(this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
1736 break;
1737
1738 case Qt::Key_Right:
1739 case Qt::Key_L:
1740 d->adjustScroller(this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
1741 break;
1742 }
1743 else
1744 switch ( _ke->key() )
1745 {
1746 case Qt::Key_Down:
1747 case Qt::Key_J:
1748 if (!d->scrollTimerId || d->scrollSuspended)
1749 verticalScrollBar()->setValue( verticalScrollBar()->value()+10 );
1750 if (d->scrollTimerId)
1751 d->newScrollTimer(this, 0);
1752 break;
1753
1754 case Qt::Key_Space:
1755 case Qt::Key_PageDown:
1756 d->shouldSmoothScroll = true;
1757 verticalScrollBar()->setValue( verticalScrollBar()->value() +viewport()->height() - offs );
1758 if(d->scrollSuspended)
1759 d->newScrollTimer(this, 0);
1760 break;
1761
1762 case Qt::Key_Up:
1763 case Qt::Key_K:
1764 if (!d->scrollTimerId || d->scrollSuspended)
1765 verticalScrollBar()->setValue( verticalScrollBar()->value()-10 );
1766 if (d->scrollTimerId)
1767 d->newScrollTimer(this, 0);
1768 break;
1769
1770 case Qt::Key_PageUp:
1771 d->shouldSmoothScroll = true;
1772 verticalScrollBar()->setValue( verticalScrollBar()->value() -viewport()->height() + offs );
1773 if(d->scrollSuspended)
1774 d->newScrollTimer(this, 0);
1775 break;
1776 case Qt::Key_Right:
1777 case Qt::Key_L:
1778 if (!d->scrollTimerId || d->scrollSuspended)
1779 horizontalScrollBar()->setValue( horizontalScrollBar()->value()+10 );
1780 if (d->scrollTimerId)
1781 d->newScrollTimer(this, 0);
1782 break;
1783
1784 case Qt::Key_Left:
1785 case Qt::Key_H:
1786 if (!d->scrollTimerId || d->scrollSuspended)
1787 horizontalScrollBar()->setValue( horizontalScrollBar()->value()-10 );
1788 if (d->scrollTimerId)
1789 d->newScrollTimer(this, 0);
1790 break;
1791 case Qt::Key_Enter:
1792 case Qt::Key_Return:
1793 // ### FIXME:
1794 // or even better to HTMLAnchorElementImpl::event()
1795 if (m_part->xmlDocImpl()) {
1796 NodeImpl *n = m_part->xmlDocImpl()->focusNode();
1797 if (n)
1798 n->setActive();
1799 }
1800 break;
1801 case Qt::Key_Home:
1802 verticalScrollBar()->setValue( 0 );
1803 horizontalScrollBar()->setValue( 0 );
1804 if(d->scrollSuspended)
1805 d->newScrollTimer(this, 0);
1806 break;
1807 case Qt::Key_End:
1808 verticalScrollBar()->setValue( contentsHeight() - visibleHeight() );
1809 if(d->scrollSuspended)
1810 d->newScrollTimer(this, 0);
1811 break;
1812 case Qt::Key_Shift:
1813 // what are you doing here?
1814 _ke->ignore();
1815 return;
1816 default:
1817 if (d->scrollTimerId)
1818 d->newScrollTimer(this, 0);
1819 _ke->ignore();
1820 return;
1821 }
1822
1823 _ke->accept();
1824}
1825
1826void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
1827{
1828 if( d->scrollSuspendPreActivate && _ke->key() != Qt::Key_Shift )
1829 d->scrollSuspendPreActivate = false;
1830 if( _ke->key() == Qt::Key_Shift && d->scrollSuspendPreActivate && !(_ke->modifiers() & Qt::ShiftModifier))
1831 if (d->scrollTimerId) {
1832 d->scrollSuspended = !d->scrollSuspended;
1833 if (d->scrollSuspended)
1834 d->stopScrolling();
1835 }
1836
1837 if (d->accessKeysEnabled)
1838 {
1839 if (d->accessKeysPreActivate && _ke->key() != Qt::Key_Control)
1840 d->accessKeysPreActivate=false;
1841 if (d->accessKeysPreActivate && !(_ke->modifiers() & Qt::ControlModifier))
1842 {
1843 displayAccessKeys();
1844 m_part->setStatusBarText(i18n("Access Keys activated"),KHTMLPart::BarOverrideText);
1845 d->accessKeysActivated = true;
1846 d->accessKeysPreActivate = false;
1847 _ke->accept();
1848 return;
1849 }
1850 else if (d->accessKeysActivated)
1851 {
1852 accessKeysTimeout();
1853 _ke->accept();
1854 return;
1855 }
1856 }
1857
1858 // Send keyup event
1859 if ( dispatchKeyEvent( _ke ) )
1860 {
1861 _ke->accept();
1862 return;
1863 }
1864
1865 QScrollArea::keyReleaseEvent(_ke);
1866}
1867
1868bool KHTMLView::focusNextPrevChild( bool next )
1869{
1870 // Now try to find the next child
1871 if (m_part->xmlDocImpl() && focusNextPrevNode(next))
1872 {
1873 if (m_part->xmlDocImpl()->focusNode())
1874 kDebug() << "focusNode.name: "
1875 << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
1876 return true; // focus node found
1877 }
1878
1879 // If we get here, pass tabbing control up to the next/previous child in our parent
1880 d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
1881 if (m_part->parentPart() && m_part->parentPart()->view())
1882 return m_part->parentPart()->view()->focusNextPrevChild(next);
1883
1884 return QWidget::focusNextPrevChild(next);
1885}
1886
1887void KHTMLView::doAutoScroll()
1888{
1889 QPoint pos = QCursor::pos();
1890 QPoint off;
1891 KHTMLView* v = m_kwp->isRedirected() ? m_kwp->rootViewPos(off) : this;
1892 pos = v->viewport()->mapFromGlobal( pos );
1893 pos -= off;
1894 int xm, ym;
1895 viewportToContents(pos.x(), pos.y(), xm, ym); // ###
1896
1897 pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
1898 if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
1899 (pos.x() < 0) || (pos.x() > visibleWidth()) )
1900 {
1901 ensureVisible( xm, ym, 0, 5 );
1902
1903#ifndef KHTML_NO_SELECTION
1904 // extend the selection while scrolling
1905 DOM::Node innerNode;
1906 if (m_part->isExtendingSelection()) {
1907 RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
1908 m_part->xmlDocImpl()->renderer()->layer()
1909 ->nodeAtPoint(renderInfo, xm, ym);
1910 innerNode = renderInfo.innerNode();
1911 }/*end if*/
1912
1913 if (innerNode.handle() && innerNode.handle()->renderer()
1914 && innerNode.handle()->renderer()->shouldSelect()) {
1915 m_part->extendSelectionTo(xm, ym, innerNode);
1916 }/*end if*/
1917#endif // KHTML_NO_SELECTION
1918 }
1919}
1920
1921// KHTML defines its own stacking order for any object and thus takes
1922// control of widget painting whenever it can. This is called "redirection".
1923//
1924// Redirected widgets are placed off screen. When they are declared as a child of our view (ChildPolished event),
1925// an event filter is installed, so as to catch any paint event and translate them as update() of the view's main widget.
1926//
1927// Painting also happens spontaneously within widgets. In this case, the widget would update() parts of itself.
1928// While this ordinarily results in a paintEvent being schedduled, it is not the case with off screen widgets.
1929// Thus update() is monitored by using the mechanism that deffers any update call happening during a paint event,
1930// transforming it into a posted UpdateLater event. Hence the need to set Qt::WA_WState_InPaintEvent on redirected widgets.
1931//
1932// Once the UpdateLater event has been received, Qt::WA_WState_InPaintEvent is removed and the process continues
1933// with the update of the corresponding rect on the view. That in turn will make our painting subsystem render()
1934// the widget at the correct stacking position.
1935//
1936// For non-redirected (e.g. external) widgets, z-order is honoured through masking. cf.RenderLayer::updateWidgetMasks
1937
1938static void handleWidget(QWidget* w, KHTMLView* view, bool recurse=true)
1939{
1940 if (w->isWindow())
1941 return;
1942
1943 if (!qobject_cast<QFrame*>(w))
1944 w->setAttribute( Qt::WA_NoSystemBackground );
1945
1946 w->setAttribute(Qt::WA_WState_InPaintEvent);
1947
1948 if (!(w->objectName() == "KLineEditButton"))
1949 w->setAttribute(Qt::WA_OpaquePaintEvent);
1950
1951 w->installEventFilter(view);
1952
1953 if (!recurse)
1954 return;
1955 if (qobject_cast<KHTMLView*>(w)) {
1956 handleWidget(static_cast<KHTMLView*>(w)->widget(), view, false);
1957 handleWidget(static_cast<KHTMLView*>(w)->horizontalScrollBar(), view, false);
1958 handleWidget(static_cast<KHTMLView*>(w)->verticalScrollBar(), view, false);
1959 return;
1960 }
1961
1962 QObjectList children = w->children();
1963 foreach (QObject* object, children) {
1964 QWidget *widget = qobject_cast<QWidget*>(object);
1965 if (widget)
1966 handleWidget(widget, view);
1967 }
1968}
1969
1970class KHTMLBackingStoreHackWidget : public QWidget
1971{
1972public:
1973 void publicEvent(QEvent *e)
1974 {
1975 QWidget::event(e);
1976 }
1977};
1978
1979bool KHTMLView::viewportEvent ( QEvent * e )
1980{
1981 switch (e->type()) {
1982 // those must not be dispatched to the specialized handlers
1983 // as widgetEvent() already took care of that
1984 case QEvent::MouseButtonPress:
1985 case QEvent::MouseButtonRelease:
1986 case QEvent::MouseButtonDblClick:
1987 case QEvent::MouseMove:
1988#ifndef QT_NO_WHEELEVENT
1989 case QEvent::Wheel:
1990#endif
1991 case QEvent::ContextMenu:
1992 case QEvent::DragEnter:
1993 case QEvent::DragMove:
1994 case QEvent::DragLeave:
1995 case QEvent::Drop:
1996 return false;
1997 default:
1998 break;
1999 }
2000 return QScrollArea::viewportEvent(e);
2001}
2002
2003static void setInPaintEventFlag(QWidget* w, bool b = true, bool recurse=true)
2004{
2005 w->setAttribute(Qt::WA_WState_InPaintEvent, b);
2006
2007 if (!recurse)
2008 return;
2009 if (qobject_cast<KHTMLView*>(w)) {
2010 setInPaintEventFlag(static_cast<KHTMLView*>(w)->widget(), b, false);
2011 setInPaintEventFlag(static_cast<KHTMLView*>(w)->horizontalScrollBar(), b, false);
2012 setInPaintEventFlag(static_cast<KHTMLView*>(w)->verticalScrollBar(), b, false);
2013 return;
2014 }
2015
2016 foreach(QObject* cw, w->children()) {
2017 if (cw->isWidgetType() && ! static_cast<QWidget*>(cw)->isWindow()
2018 && !(static_cast<QWidget*>(cw)->windowModality() & Qt::ApplicationModal)) {
2019 setInPaintEventFlag(static_cast<QWidget*>(cw), b);
2020 }
2021 }
2022}
2023
2024bool KHTMLView::eventFilter(QObject *o, QEvent *e)
2025{
2026 if ( e->type() == QEvent::ShortcutOverride ) {
2027 QKeyEvent* ke = (QKeyEvent*) e;
2028 if (m_part->isEditable() || m_part->isCaretMode()
2029 || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
2030 && m_part->xmlDocImpl()->focusNode()->isContentEditable())) {
2031 if ( (ke->modifiers() & Qt::ControlModifier) || (ke->modifiers() & Qt::ShiftModifier) ) {
2032 switch ( ke->key() ) {
2033 case Qt::Key_Left:
2034 case Qt::Key_Right:
2035 case Qt::Key_Up:
2036 case Qt::Key_Down:
2037 case Qt::Key_Home:
2038 case Qt::Key_End:
2039 ke->accept();
2040 return true;
2041 default:
2042 break;
2043 }
2044 }
2045 }
2046 }
2047
2048 if ( e->type() == QEvent::Leave ) {
2049 if ( d->cursorIconWidget )
2050 d->cursorIconWidget->hide();
2051 m_part->resetHoverText();
2052 }
2053
2054 QWidget *view = widget();
2055 if (o == view) {
2056 if (widgetEvent(e))
2057 return true;
2058 else if (e->type() == QEvent::Resize) {
2059 updateScrollBars();
2060 return false;
2061 }
2062 } else if (o->isWidgetType()) {
2063 QWidget *v = static_cast<QWidget *>(o);
2064 QWidget *c = v;
2065 while (v && v != view) {
2066 c = v;
2067 v = v->parentWidget();
2068 }
2069 KHTMLWidget* k = dynamic_cast<KHTMLWidget*>(c);
2070 if (v && k && k->m_kwp->isRedirected()) {
2071 bool block = false;
2072 bool isUpdate = false;
2073 QWidget *w = static_cast<QWidget *>(o);
2074 switch(e->type()) {
2075 case QEvent::UpdateRequest: {
2076 // implicitly call qt_syncBackingStore(w)
2077 static_cast<KHTMLBackingStoreHackWidget *>(w)->publicEvent(e);
2078 block = true;
2079 break;
2080 }
2081 case QEvent::UpdateLater:
2082 isUpdate = true;
2083 // no break;
2084 case QEvent::Paint:
2085 if (!allowWidgetPaintEvents) {
2086 // eat the event. Like this we can control exactly when the widget
2087 // gets repainted.
2088 block = true;
2089 int x = 0, y = 0;
2090 QWidget *v = w;
2091 while (v && v->parentWidget() != view) {
2092 x += v->x();
2093 y += v->y();
2094 v = v->parentWidget();
2095 }
2096
2097 QPoint ap = k->m_kwp->absolutePos();
2098 x += ap.x();
2099 y += ap.y();
2100
2101 QRect pr = isUpdate ? static_cast<QUpdateLaterEvent*>(e)->region().boundingRect() : static_cast<QPaintEvent*>(e)->rect();
2102 bool asap = !d->contentsMoving && qobject_cast<QAbstractScrollArea*>(c);
2103
2104 if (isUpdate) {
2105 setInPaintEventFlag(w, false);
2106 if (asap)
2107 w->repaint(static_cast<QUpdateLaterEvent*>(e)->region());
2108 else
2109 w->update(static_cast<QUpdateLaterEvent*>(e)->region());
2110 setInPaintEventFlag(w);
2111 }
2112
2113 // QScrollView needs fast repaints
2114 if ( asap && !isUpdate && !d->painting && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer() &&
2115 !static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
2116 repaintContents(x + pr.x(), y + pr.y(),
2117 pr.width(), pr.height()+1); // ### investigate that +1 (shows up when
2118 // updating e.g a textarea's blinking cursor)
2119 } else if (!d->painting) {
2120 scheduleRepaint(x + pr.x(), y + pr.y(),
2121 pr.width(), pr.height()+1, asap);
2122 }
2123 }
2124 break;
2125 case QEvent::MouseMove:
2126 case QEvent::MouseButtonPress:
2127 case QEvent::MouseButtonRelease:
2128 case QEvent::MouseButtonDblClick: {
2129
2130 if (0 && w->parentWidget() == view && !qobject_cast<QScrollBar*>(w) && !::qobject_cast<QScrollBar *>(w)) {
2131 QMouseEvent *me = static_cast<QMouseEvent *>(e);
2132 QPoint pt = w->mapTo( view, me->pos());
2133 QMouseEvent me2(me->type(), pt, me->button(), me->buttons(), me->modifiers());
2134
2135 if (e->type() == QEvent::MouseMove)
2136 mouseMoveEvent(&me2);
2137 else if(e->type() == QEvent::MouseButtonPress)
2138 mousePressEvent(&me2);
2139 else if(e->type() == QEvent::MouseButtonRelease)
2140 mouseReleaseEvent(&me2);
2141 else
2142 mouseDoubleClickEvent(&me2);
2143 block = true;
2144 }
2145 break;
2146 }
2147 case QEvent::KeyPress:
2148 case QEvent::KeyRelease:
2149 if (w->parentWidget() == view && !qobject_cast<QScrollBar*>(w)) {
2150 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
2151 if (e->type() == QEvent::KeyPress) {
2152 keyPressEvent(ke);
2153 ke->accept();
2154 } else{
2155 keyReleaseEvent(ke);
2156 ke->accept();
2157 }
2158 block = true;
2159 }
2160
2161 if (qobject_cast<KUrlRequester*>(w->parentWidget()) &&
2162 e->type() == QEvent::KeyPress) {
2163 // Since keypress events on the upload widget will
2164 // be forwarded to the lineedit anyway,
2165 // block the original copy at this level to prevent
2166 // double-emissions of events it doesn't accept
2167 e->ignore();
2168 block = true;
2169 }
2170
2171 break;
2172 case QEvent::FocusIn:
2173 case QEvent::FocusOut: {
2174 QPoint dummy;
2175 KHTMLView* root = m_kwp->rootViewPos(dummy);
2176 if (!root)
2177 root = this;
2178 block = static_cast<QFocusEvent*>(e)->reason() != Qt::MouseFocusReason || root->underMouse();
2179 break;
2180 }
2181 default:
2182 break;
2183 }
2184 if (block) {
2185 //qDebug("eating event");
2186 return true;
2187 }
2188 }
2189 }
2190
2191// kDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type();
2192 return QScrollArea::eventFilter(o, e);
2193}
2194
2195bool KHTMLView::widgetEvent(QEvent* e)
2196{
2197 switch (e->type()) {
2198 case QEvent::MouseButtonPress:
2199 case QEvent::MouseButtonRelease:
2200 case QEvent::MouseButtonDblClick:
2201 case QEvent::MouseMove:
2202 case QEvent::Paint:
2203#ifndef QT_NO_WHEELEVENT
2204 case QEvent::Wheel:
2205#endif
2206 case QEvent::ContextMenu:
2207 case QEvent::DragEnter:
2208 case QEvent::DragMove:
2209 case QEvent::DragLeave:
2210 case QEvent::Drop:
2211 return QFrame::event(e);
2212 case QEvent::ChildPolished: {
2213 // we need to install an event filter on all children of the widget() to
2214 // be able to get correct stacking of children within the document.
2215 QObject *c = static_cast<QChildEvent *>(e)->child();
2216 if (c->isWidgetType()) {
2217 QWidget *w = static_cast<QWidget *>(c);
2218 // don't install the event filter on toplevels
2219 if (!(w->windowFlags() & Qt::Window) && !(w->windowModality() & Qt::ApplicationModal)) {
2220 KHTMLWidget* k = dynamic_cast<KHTMLWidget*>(w);
2221 if (k && k->m_kwp->isRedirected()) {
2222 w->unsetCursor();
2223 handleWidget(w, this);
2224 }
2225 }
2226 }
2227 break;
2228 }
2229 case QEvent::Move: {
2230 if (static_cast<QMoveEvent*>(e)->pos() != QPoint(0,0)) {
2231 widget()->move(0,0);
2232 updateScrollBars();
2233 return true;
2234 }
2235 break;
2236 }
2237 default:
2238 break;
2239 }
2240 return false;
2241}
2242
2243bool KHTMLView::hasLayoutPending()
2244{
2245 return d->layoutTimerId && !d->firstLayoutPending;
2246}
2247
2248DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
2249{
2250 return d->underMouse;
2251}
2252
2253DOM::NodeImpl *KHTMLView::nonSharedNodeUnderMouse() const
2254{
2255 return d->underMouseNonShared;
2256}
2257
2258bool KHTMLView::scrollTo(const QRect &bounds)
2259{
2260 d->scrollingSelf = true; // so scroll events get ignored
2261
2262 int x, y, xe, ye;
2263 x = bounds.left();
2264 y = bounds.top();
2265 xe = bounds.right();
2266 ye = bounds.bottom();
2267
2268 //kDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y;
2269
2270 int deltax;
2271 int deltay;
2272
2273 int curHeight = visibleHeight();
2274 int curWidth = visibleWidth();
2275
2276 if (ye-y>curHeight-d->borderY)
2277 ye = y + curHeight - d->borderY;
2278
2279 if (xe-x>curWidth-d->borderX)
2280 xe = x + curWidth - d->borderX;
2281
2282 // is xpos of target left of the view's border?
2283 if (x < contentsX() + d->borderX )
2284 deltax = x - contentsX() - d->borderX;
2285 // is xpos of target right of the view's right border?
2286 else if (xe + d->borderX > contentsX() + curWidth)
2287 deltax = xe + d->borderX - ( contentsX() + curWidth );
2288 else
2289 deltax = 0;
2290
2291 // is ypos of target above upper border?
2292 if (y < contentsY() + d->borderY)
2293 deltay = y - contentsY() - d->borderY;
2294 // is ypos of target below lower border?
2295 else if (ye + d->borderY > contentsY() + curHeight)
2296 deltay = ye + d->borderY - ( contentsY() + curHeight );
2297 else
2298 deltay = 0;
2299
2300 int maxx = curWidth-d->borderX;
2301 int maxy = curHeight-d->borderY;
2302
2303 int scrollX, scrollY;
2304
2305 scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
2306 scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
2307
2308 if (contentsX() + scrollX < 0)
2309 scrollX = -contentsX();
2310 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
2311 scrollX = contentsWidth() - visibleWidth() - contentsX();
2312
2313 if (contentsY() + scrollY < 0)
2314 scrollY = -contentsY();
2315 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
2316 scrollY = contentsHeight() - visibleHeight() - contentsY();
2317
2318 horizontalScrollBar()->setValue( horizontalScrollBar()->value()+scrollX );
2319 verticalScrollBar()->setValue( verticalScrollBar()->value()+scrollY );
2320
2321 d->scrollingSelf = false;
2322
2323 if ( (abs(deltax)<=maxx) && (abs(deltay)<=maxy) )
2324 return true;
2325 else return false;
2326
2327}
2328
2329bool KHTMLView::focusNextPrevNode(bool next)
2330{
2331 // Sets the focus node of the document to be the node after (or if
2332 // next is false, before) the current focus node. Only nodes that
2333 // are selectable (i.e. for which isFocusable() returns true) are
2334 // taken into account, and the order used is that specified in the
2335 // HTML spec (see DocumentImpl::nextFocusNode() and
2336 // DocumentImpl::previousFocusNode() for details).
2337
2338 DocumentImpl *doc = m_part->xmlDocImpl();
2339 NodeImpl *oldFocusNode = doc->focusNode();
2340
2341 // See whether we're in the middle of a detach, or hiding of the
2342 // widget. In this case, we will just clear focus, being careful not to emit events
2343 // or update rendering. Doing this also prevents the code below from going bonkers with
2344 // oldFocusNode not actually being focusable, etc.
2345 if (oldFocusNode) {
2346 if ((oldFocusNode->renderer() && !oldFocusNode->renderer()->parent())
2347 || !oldFocusNode->isTabFocusable()) {
2348 doc->quietResetFocus();
2349 return true;
2350 }
2351 }
2352
2353#if 1
2354 // If the user has scrolled the document, then instead of picking
2355 // the next focusable node in the document, use the first one that
2356 // is within the visible area (if possible).
2357 if (d->scrollBarMoved)
2358 {
2359 NodeImpl *toFocus;
2360 if (next)
2361 toFocus = doc->nextFocusNode(oldFocusNode);
2362 else
2363 toFocus = doc->previousFocusNode(oldFocusNode);
2364
2365 if (!toFocus && oldFocusNode) {
2366 if (next)
2367 toFocus = doc->nextFocusNode(NULL);
2368 else
2369 toFocus = doc->previousFocusNode(NULL);
2370 }
2371
2372 while (toFocus && toFocus != oldFocusNode)
2373 {
2374
2375 QRect focusNodeRect = toFocus->getRect();
2376 if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
2377 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
2378 {
2379 QRect r = toFocus->getRect();
2380 ensureVisible( r.right(), r.bottom());
2381 ensureVisible( r.left(), r.top());
2382 d->scrollBarMoved = false;
2383 d->tabMovePending = false;
2384 d->lastTabbingDirection = next;
2385 d->pseudoFocusNode = KHTMLViewPrivate::PFNone;
2386 m_part->xmlDocImpl()->setFocusNode(toFocus);
2387 Node guard(toFocus);
2388 if (!toFocus->hasOneRef() )
2389 {
2390 emit m_part->nodeActivated(Node(toFocus));
2391 }
2392 return true;
2393 }
2394 }
2395 if (next)
2396 toFocus = doc->nextFocusNode(toFocus);
2397 else
2398 toFocus = doc->previousFocusNode(toFocus);
2399
2400 if (!toFocus && oldFocusNode)
2401 {
2402 if (next)
2403 {
2404 toFocus = doc->nextFocusNode(NULL);
2405 }
2406 else
2407 {
2408 toFocus = doc->previousFocusNode(NULL);
2409 }
2410 }
2411 }
2412
2413 d->scrollBarMoved = false;
2414 }
2415#endif
2416
2417 if (!oldFocusNode && d->pseudoFocusNode == KHTMLViewPrivate::PFNone)
2418 {
2419 ensureVisible(contentsX(), next?0:contentsHeight());
2420 d->scrollBarMoved = false;
2421 d->pseudoFocusNode = next?KHTMLViewPrivate::PFTop:KHTMLViewPrivate::PFBottom;
2422 return true;
2423 }
2424
2425 NodeImpl *newFocusNode = NULL;
2426
2427 if (d->tabMovePending && next != d->lastTabbingDirection)
2428 {
2429 //kDebug ( 6000 ) << " tab move pending and tabbing direction changed!\n";
2430 newFocusNode = oldFocusNode;
2431 }
2432 else if (next)
2433 {
2434 if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFTop )
2435 newFocusNode = doc->nextFocusNode(oldFocusNode);
2436 }
2437 else
2438 {
2439 if (oldFocusNode || d->pseudoFocusNode == KHTMLViewPrivate::PFBottom )
2440 newFocusNode = doc->previousFocusNode(oldFocusNode);
2441 }
2442
2443 bool targetVisible = false;
2444 if (!newFocusNode)
2445 {
2446 if ( next )
2447 {
2448 targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight()-d->borderY,0,0));
2449 }
2450 else
2451 {
2452 targetVisible = scrollTo(QRect(contentsX()+visibleWidth()/2,d->borderY,0,0));
2453 }
2454 }
2455 else
2456 {
2457 // if it's an editable element, activate the caret
2458 if (!m_part->isCaretMode() && newFocusNode->isContentEditable()) {
2459 kDebug(6200) << "show caret! fn: " << newFocusNode->nodeName().string() << endl;
2460 m_part->clearCaretRectIfNeeded();
2461 m_part->d->editor_context.m_selection.moveTo(Position(newFocusNode, 0L));
2462 m_part->setCaretVisible(true);
2463 } else {
2464 m_part->setCaretVisible(false);
2465 kDebug(6200) << "hide caret! fn: " << newFocusNode->nodeName().string() << endl;
2466 }
2467 m_part->notifySelectionChanged();
2468
2469 targetVisible = scrollTo(newFocusNode->getRect());
2470 }
2471
2472 if (targetVisible)
2473 {
2474 //kDebug ( 6000 ) << " target reached.\n";
2475 d->tabMovePending = false;
2476
2477 m_part->xmlDocImpl()->setFocusNode(newFocusNode);
2478 if (newFocusNode)
2479 {
2480 Node guard(newFocusNode);
2481 if (!newFocusNode->hasOneRef() )
2482 {
2483 emit m_part->nodeActivated(Node(newFocusNode));
2484 }
2485 return true;
2486 }
2487 else
2488 {
2489 d->pseudoFocusNode = next?KHTMLViewPrivate::PFBottom:KHTMLViewPrivate::PFTop;
2490 return false;
2491 }
2492 }
2493 else
2494 {
2495 if (!d->tabMovePending)
2496 d->lastTabbingDirection = next;
2497 d->tabMovePending = true;
2498 return true;
2499 }
2500}
2501
2502void KHTMLView::displayAccessKeys()
2503{
2504 QVector< QChar > taken;
2505 displayAccessKeys( NULL, this, taken, false );
2506 displayAccessKeys( NULL, this, taken, true );
2507}
2508
2509void KHTMLView::displayAccessKeys( KHTMLView* caller, KHTMLView* origview, QVector< QChar >& taken, bool use_fallbacks )
2510{
2511 QMap< ElementImpl*, QChar > fallbacks;
2512 if( use_fallbacks )
2513 fallbacks = buildFallbackAccessKeys();
2514 for( NodeImpl* n = m_part->xmlDocImpl(); n != NULL; n = n->traverseNextNode()) {
2515 if( n->isElementNode()) {
2516 ElementImpl* en = static_cast< ElementImpl* >( n );
2517 DOMString s = en->getAttribute( ATTR_ACCESSKEY );
2518 QString accesskey;
2519 if( s.length() == 1 ) {
2520 QChar a = s.string()[ 0 ].toUpper();
2521 if( qFind( taken.begin(), taken.end(), a ) == taken.end()) // !contains
2522 accesskey = a;
2523 }
2524 if( accesskey.isNull() && fallbacks.contains( en )) {
2525 QChar a = fallbacks[ en ].toUpper();
2526 if( qFind( taken.begin(), taken.end(), a ) == taken.end()) // !contains
2527 accesskey = QString( "<qt><i>" ) + a + "</i></qt>";
2528 }
2529 if( !accesskey.isNull()) {
2530 QRect rec=en->getRect();
2531 QLabel *lab=new QLabel(accesskey,widget());
2532 lab->setAttribute(Qt::WA_DeleteOnClose);
2533 lab->setObjectName("KHTMLAccessKey");
2534 connect( origview, SIGNAL(hideAccessKeys()), lab, SLOT(close()) );
2535 connect( this, SIGNAL(repaintAccessKeys()), lab, SLOT(repaint()));
2536 lab->setPalette(QToolTip::palette());
2537 lab->setLineWidth(2);
2538 lab->setFrameStyle(QFrame::Box | QFrame::Plain);
2539 lab->setMargin(3);
2540 lab->adjustSize();
2541 lab->setParent( widget() );
2542 lab->setAutoFillBackground(true);
2543 lab->move(
2544 qMin(rec.left()+rec.width()/2 - contentsX(), contentsWidth() - lab->width()),
2545 qMin(rec.top()+rec.height()/2 - contentsY(), contentsHeight() - lab->height()));
2546 lab->show();
2547 taken.append( accesskey[ 0 ] );
2548 }
2549 }
2550 }
2551 if( use_fallbacks )
2552 return;
2553
2554 QList<KParts::ReadOnlyPart*> frames = m_part->frames();
2555 foreach( KParts::ReadOnlyPart* cur, frames ) {
2556 if( !qobject_cast<KHTMLPart*>(cur) )
2557 continue;
2558 KHTMLPart* part = static_cast< KHTMLPart* >( cur );
2559 if( part->view() && part->view() != caller )
2560 part->view()->displayAccessKeys( this, origview, taken, use_fallbacks );
2561 }
2562
2563 // pass up to the parent
2564 if (m_part->parentPart() && m_part->parentPart()->view()
2565 && m_part->parentPart()->view() != caller)
2566 m_part->parentPart()->view()->displayAccessKeys( this, origview, taken, use_fallbacks );
2567}
2568
2569bool KHTMLView::isScrollingFromMouseWheel() const
2570{
2571 return d->scrollingFromWheel != QPoint(-1,-1);
2572}
2573
2574void KHTMLView::accessKeysTimeout()
2575{
2576 d->accessKeysActivated=false;
2577 d->accessKeysPreActivate = false;
2578 m_part->setStatusBarText(QString(), KHTMLPart::BarOverrideText);
2579 emit hideAccessKeys();
2580}
2581
2582// Handling of the HTML accesskey attribute.
2583bool KHTMLView::handleAccessKey( const QKeyEvent* ev )
2584{
2585// Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
2586// but this code must act as if the modifiers weren't pressed
2587 QChar c;
2588 if( ev->key() >= Qt::Key_A && ev->key() <= Qt::Key_Z )
2589 c = 'A' + ev->key() - Qt::Key_A;
2590 else if( ev->key() >= Qt::Key_0 && ev->key() <= Qt::Key_9 )
2591 c = '0' + ev->key() - Qt::Key_0;
2592 else {
2593 // TODO fake XKeyEvent and XLookupString ?
2594 // This below seems to work e.g. for eacute though.
2595 if( ev->text().length() == 1 )
2596 c = ev->text()[ 0 ];
2597 }
2598 if( c.isNull())
2599 return false;
2600 return focusNodeWithAccessKey( c );
2601}
2602
2603bool KHTMLView::focusNodeWithAccessKey( QChar c, KHTMLView* caller )
2604{
2605 DocumentImpl *doc = m_part->xmlDocImpl();
2606 if( !doc )
2607 return false;
2608 ElementImpl* node = doc->findAccessKeyElement( c );
2609 if( !node ) {
2610 QList<KParts::ReadOnlyPart*> frames = m_part->frames();
2611 foreach( KParts::ReadOnlyPart* cur, frames ) {
2612 if( !qobject_cast<KHTMLPart*>(cur) )
2613 continue;
2614 KHTMLPart* part = static_cast< KHTMLPart* >( cur );
2615 if( part->view() && part->view() != caller
2616 && part->view()->focusNodeWithAccessKey( c, this ))
2617 return true;
2618 }
2619 // pass up to the parent
2620 if (m_part->parentPart() && m_part->parentPart()->view()
2621 && m_part->parentPart()->view() != caller
2622 && m_part->parentPart()->view()->focusNodeWithAccessKey( c, this ))
2623 return true;
2624 if( caller == NULL ) { // the active frame (where the accesskey was pressed)
2625 const QMap< ElementImpl*, QChar > fallbacks = buildFallbackAccessKeys();
2626 for( QMap< ElementImpl*, QChar >::ConstIterator it = fallbacks.begin();
2627 it != fallbacks.end();
2628 ++it )
2629 if( *it == c ) {
2630 node = it.key();
2631 break;
2632 }
2633 }
2634 if( node == NULL )
2635 return false;
2636 }
2637
2638 // Scroll the view as necessary to ensure that the new focus node is visible
2639
2640 QRect r = node->getRect();
2641 ensureVisible( r.right(), r.bottom());
2642 ensureVisible( r.left(), r.top());
2643
2644 Node guard( node );
2645 if( node->isFocusable()) {
2646 if (node->id()==ID_LABEL) {
2647 // if Accesskey is a label, give focus to the label's referrer.
2648 node=static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl* >( node )->getFormElement());
2649 if (!node) return true;
2650 guard = node;
2651 }
2652 // Set focus node on the document
2653 m_part->xmlDocImpl()->setFocusNode(node);
2654
2655 if( node != NULL && node->hasOneRef()) // deleted, only held by guard
2656 return true;
2657 emit m_part->nodeActivated(Node(node));
2658 if( node != NULL && node->hasOneRef())
2659 return true;
2660 }
2661
2662 switch( node->id()) {
2663 case ID_A:
2664 static_cast< HTMLAnchorElementImpl* >( node )->click();
2665 break;
2666 case ID_INPUT:
2667 static_cast< HTMLInputElementImpl* >( node )->click();
2668 break;
2669 case ID_BUTTON:
2670 static_cast< HTMLButtonElementImpl* >( node )->click();
2671 break;
2672 case ID_AREA:
2673 static_cast< HTMLAreaElementImpl* >( node )->click();
2674 break;
2675 case ID_TEXTAREA:
2676 break; // just focusing it is enough
2677 case ID_LEGEND:
2678 // TODO
2679 break;
2680 }
2681 return true;
2682}
2683
2684static QString getElementText( NodeImpl* start, bool after )
2685{
2686 QString ret; // nextSibling(), to go after e.g. </select>
2687 for( NodeImpl* n = after ? start->nextSibling() : start->traversePreviousNode();
2688 n != NULL;
2689 n = after ? n->traverseNextNode() : n->traversePreviousNode()) {
2690 if( n->isTextNode()) {
2691 if( after )
2692 ret += static_cast< TextImpl* >( n )->toString().string();
2693 else
2694 ret.prepend( static_cast< TextImpl* >( n )->toString().string());
2695 } else {
2696 switch( n->id()) {
2697 case ID_A:
2698 case ID_FONT:
2699 case ID_TT:
2700 case ID_U:
2701 case ID_B:
2702 case ID_I:
2703 case ID_S:
2704 case ID_STRIKE:
2705 case ID_BIG:
2706 case ID_SMALL:
2707 case ID_EM:
2708 case ID_STRONG:
2709 case ID_DFN:
2710 case ID_CODE:
2711 case ID_SAMP:
2712 case ID_KBD:
2713 case ID_VAR:
2714 case ID_CITE:
2715 case ID_ABBR:
2716 case ID_ACRONYM:
2717 case ID_SUB:
2718 case ID_SUP:
2719 case ID_SPAN:
2720 case ID_NOBR:
2721 case ID_WBR:
2722 break;
2723 case ID_TD:
2724 if( ret.trimmed().isEmpty())
2725 break;
2726 // fall through
2727 default:
2728 return ret.simplified();
2729 }
2730 }
2731 }
2732 return ret.simplified();
2733}
2734
2735static QMap< NodeImpl*, QString > buildLabels( NodeImpl* start )
2736{
2737 QMap< NodeImpl*, QString > ret;
2738 for( NodeImpl* n = start;
2739 n != NULL;
2740 n = n->traverseNextNode()) {
2741 if( n->id() == ID_LABEL ) {
2742 HTMLLabelElementImpl* label = static_cast< HTMLLabelElementImpl* >( n );
2743 NodeImpl* labelfor = label->getFormElement();
2744 if( labelfor )
2745 ret[ labelfor ] = label->innerText().string().simplified();
2746 }
2747 }
2748 return ret;
2749}
2750
2751namespace khtml {
2752struct AccessKeyData {
2753 ElementImpl* element;
2754 QString text;
2755 QString url;
2756 int priority; // 10(highest) - 0(lowest)
2757};
2758}
2759
2760QMap< ElementImpl*, QChar > KHTMLView::buildFallbackAccessKeys() const
2761{
2762 // build a list of all possible candidate elements that could use an accesskey
2763 QLinkedList< AccessKeyData > data; // Note: this has to be a list type that keep iterators valid
2764 // when other entries are removed
2765 QMap< NodeImpl*, QString > labels = buildLabels( m_part->xmlDocImpl());
2766 QMap< QString, QChar > hrefs;
2767
2768 for( NodeImpl* n = m_part->xmlDocImpl();
2769 n != NULL;
2770 n = n->traverseNextNode()) {
2771 if( n->isElementNode()) {
2772 ElementImpl* element = static_cast< ElementImpl* >( n );
2773 if( element->renderer() == NULL )
2774 continue; // not visible
2775 QString text;
2776 QString url;
2777 int priority = 0;
2778 bool ignore = false;
2779 bool text_after = false;
2780 bool text_before = false;
2781 switch( element->id()) {
2782 case ID_A:
2783 url = element->getAttribute(ATTR_HREF).parsedUrl().string();
2784 if( url.isEmpty()) // doesn't have href, it's only an anchor
2785 continue;
2786 text = static_cast< HTMLElementImpl* >( element )->innerText().string().simplified();
2787 priority = 2;
2788 break;
2789 case ID_INPUT: {
2790 HTMLInputElementImpl* in = static_cast< HTMLInputElementImpl* >( element );
2791 switch( in->inputType()) {
2792 case HTMLInputElementImpl::SUBMIT:
2793 text = in->value().string();
2794 if( text.isEmpty())
2795 text = i18n( "Submit" );
2796 priority = 7;
2797 break;
2798 case HTMLInputElementImpl::IMAGE:
2799 text = in->altText().string();
2800 priority = 7;
2801 break;
2802 case HTMLInputElementImpl::BUTTON:
2803 text = in->value().string();
2804 priority = 5;
2805 break;
2806 case HTMLInputElementImpl::RESET:
2807 text = in->value().string();
2808 if( text.isEmpty())
2809 text = i18n( "Reset" );
2810 priority = 5;
2811 break;
2812 case HTMLInputElementImpl::HIDDEN:
2813 ignore = true;
2814 break;
2815 case HTMLInputElementImpl::CHECKBOX:
2816 case HTMLInputElementImpl::RADIO:
2817 text_after = true;
2818 priority = 5;
2819 break;
2820 case HTMLInputElementImpl::TEXT:
2821 case HTMLInputElementImpl::PASSWORD:
2822 case HTMLInputElementImpl::FILE:
2823 text_before = true;
2824 priority = 5;
2825 break;
2826 default:
2827 priority = 5;
2828 break;
2829 }
2830 break;
2831 }
2832 case ID_BUTTON:
2833 text = static_cast< HTMLElementImpl* >( element )->innerText().string().simplified();
2834 switch( static_cast< HTMLButtonElementImpl* >( element )->buttonType()) {
2835 case HTMLButtonElementImpl::SUBMIT:
2836 if( text.isEmpty())
2837 text = i18n( "Submit" );
2838 priority = 7;
2839 break;
2840 case HTMLButtonElementImpl::RESET:
2841 if( text.isEmpty())
2842 text = i18n( "Reset" );
2843 priority = 5;
2844 break;
2845 default:
2846 priority = 5;
2847 break;
2848 }
2849 break;
2850 case ID_SELECT: // these don't have accesskey attribute, but quick access may be handy
2851 text_before = true;
2852 text_after = true;
2853 priority = 5;
2854 break;
2855 case ID_FRAME:
2856 ignore = true;
2857 break;
2858 default:
2859 ignore = !element->isFocusable();
2860 priority = 2;
2861 break;
2862 }
2863 if( ignore )
2864 continue;
2865
2866 // build map of manually assigned accesskeys and their targets
2867 DOMString akey = element->getAttribute( ATTR_ACCESSKEY );
2868 if( akey.length() == 1 ) {
2869 hrefs[url] = akey.string()[ 0 ].toUpper();
2870 continue; // has accesskey set, ignore
2871 }
2872 if( text.isNull() && labels.contains( element ))
2873 text = labels[ element ];
2874 if( text.isNull() && text_before )
2875 text = getElementText( element, false );
2876 if( text.isNull() && text_after )
2877 text = getElementText( element, true );
2878 text = text.trimmed();
2879 // increase priority of items which have explicitly specified accesskeys in the config
2880 const QList< QPair< QString, QChar > > priorities
2881 = m_part->settings()->fallbackAccessKeysAssignments();
2882 for( QList< QPair< QString, QChar > >::ConstIterator it = priorities.begin();
2883 it != priorities.end();
2884 ++it ) {
2885 if( text == (*it).first )
2886 priority = 10;
2887 }
2888 AccessKeyData tmp = { element, text, url, priority };
2889 data.append( tmp );
2890 }
2891 }
2892
2893 QList< QChar > keys;
2894 for( char c = 'A'; c <= 'Z'; ++c )
2895 keys << c;
2896 for( char c = '0'; c <= '9'; ++c )
2897 keys << c;
2898 for( NodeImpl* n = m_part->xmlDocImpl();
2899 n != NULL;
2900 n = n->traverseNextNode()) {
2901 if( n->isElementNode()) {
2902 ElementImpl* en = static_cast< ElementImpl* >( n );
2903 DOMString s = en->getAttribute( ATTR_ACCESSKEY );
2904 if( s.length() == 1 ) {
2905 QChar c = s.string()[ 0 ].toUpper();
2906 keys.removeAll( c ); // remove manually assigned accesskeys
2907 }
2908 }
2909 }
2910
2911 QMap< ElementImpl*, QChar > ret;
2912 for( int priority = 10; priority >= 0; --priority ) {
2913 for( QLinkedList< AccessKeyData >::Iterator it = data.begin();
2914 it != data.end();
2915 ) {
2916 if( (*it).priority != priority ) {
2917 ++it;
2918 continue;
2919 }
2920 if( keys.isEmpty())
2921 break;
2922 QString text = (*it).text;
2923 QChar key;
2924 const QString url = (*it).url;
2925 // an identical link already has an accesskey assigned
2926 if( hrefs.contains( url ) ) {
2927 it = data.erase( it );
2928 continue;
2929 }
2930 if( !text.isEmpty()) {
2931 const QList< QPair< QString, QChar > > priorities
2932 = m_part->settings()->fallbackAccessKeysAssignments();
2933 for( QList< QPair< QString, QChar > >::ConstIterator it = priorities.begin();
2934 it != priorities.end();
2935 ++it )
2936 if( text == (*it).first && keys.contains( (*it).second )) {
2937 key = (*it).second;
2938 break;
2939 }
2940 }
2941 // try first to select the first character as the accesskey,
2942 // then first character of the following words,
2943 // and then simply the first free character
2944 if( key.isNull() && !text.isEmpty()) {
2945 const QStringList words = text.split( ' ' );
2946 for( QStringList::ConstIterator it = words.begin();
2947 it != words.end();
2948 ++it ) {
2949 if( keys.contains( (*it)[ 0 ].toUpper())) {
2950 key = (*it)[ 0 ].toUpper();
2951 break;
2952 }
2953 }
2954 }
2955 if( key.isNull() && !text.isEmpty()) {
2956 for( int i = 0; i < text.length(); ++i ) {
2957 if( keys.contains( text[ i ].toUpper())) {
2958 key = text[ i ].toUpper();
2959 break;
2960 }
2961 }
2962 }
2963 if( key.isNull())
2964 key = keys.front();
2965 ret[ (*it).element ] = key;
2966 keys.removeAll( key );
2967 it = data.erase( it );
2968 // assign the same accesskey also to other elements pointing to the same url
2969 if( !url.isEmpty() && !url.startsWith( "javascript:", Qt::CaseInsensitive )) {
2970 for( QLinkedList< AccessKeyData >::Iterator it2 = data.begin();
2971 it2 != data.end();
2972 ) {
2973 if( (*it2).url == url ) {
2974 ret[ (*it2).element ] = key;
2975 if( it == it2 )
2976 ++it;
2977 it2 = data.erase( it2 );
2978 } else
2979 ++it2;
2980 }
2981 }
2982 }
2983 }
2984 return ret;
2985}
2986
2987void KHTMLView::setMediaType( const QString &medium )
2988{
2989 m_medium = medium;
2990}
2991
2992QString KHTMLView::mediaType() const
2993{
2994 return m_medium;
2995}
2996
2997bool KHTMLView::pagedMode() const
2998{
2999 return d->paged;
3000}
3001
3002void KHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
3003{
3004 if (vis) {
3005 d->visibleWidgets.insert(w, w->widget());
3006 }
3007 else
3008 d->visibleWidgets.remove(w);
3009}
3010
3011bool KHTMLView::needsFullRepaint() const
3012{
3013 return d->needsFullRepaint;
3014}
3015
3016namespace {
3017 class QPointerDeleter
3018 {
3019 public:
3020 explicit QPointerDeleter(QObject* o) : obj(o) {}
3021 ~QPointerDeleter() { delete obj; }
3022 private:
3023 const QPointer<QObject> obj;
3024 };
3025}
3026
3027void KHTMLView::print(bool quick)
3028{
3029 if(!m_part->xmlDocImpl()) return;
3030 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
3031 if(!root) return;
3032
3033 QPointer<KHTMLPrintSettings> printSettings(new KHTMLPrintSettings); //XXX: doesn't save settings between prints like this
3034 const QPointerDeleter settingsDeleter(printSettings); //the printdialog takes ownership of the settings widget, thus this workaround to avoid double deletion
3035 QPrinter printer;
3036 QPointer<QPrintDialog> dialog = KdePrint::createPrintDialog(&printer, KdePrint::SystemSelectsPages, QList<QWidget*>() << printSettings.data(), this);
3037
3038 const QPointerDeleter dialogDeleter(dialog);
3039
3040 QString docname = m_part->xmlDocImpl()->URL().prettyUrl();
3041 if ( !docname.isEmpty() )
3042 docname = KStringHandler::csqueeze(docname, 80);
3043
3044 if(quick || (dialog->exec() && dialog)) { /*'this' and thus dialog might have been deleted while exec()!*/
3045 viewport()->setCursor( Qt::WaitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
3046 // set up KPrinter
3047 printer.setFullPage(false);
3048 printer.setCreator(QString("KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
3049 printer.setDocName(docname);
3050
3051 QPainter *p = new QPainter;
3052 p->begin( &printer );
3053 khtml::setPrintPainter( p );
3054
3055 m_part->xmlDocImpl()->setPaintDevice( &printer );
3056 QString oldMediaType = mediaType();
3057 setMediaType( "print" );
3058 // We ignore margin settings for html and body when printing
3059 // and use the default margins from the print-system
3060 // (In Qt 3.0.x the default margins are hardcoded in Qt)
3061 m_part->xmlDocImpl()->setPrintStyleSheet( printSettings->printFriendly() ?
3062 "* { background-image: none !important;"
3063 " background-color: white !important;"
3064 " color: black !important; }"
3065 "body { margin: 0px !important; }"
3066 "html { margin: 0px !important; }" :
3067 "body { margin: 0px !important; }"
3068 "html { margin: 0px !important; }"
3069 );
3070
3071 kDebug(6000) << "printing: physical page width = " << printer.width()
3072 << " height = " << printer.height() << endl;
3073 root->setStaticMode(true);
3074 root->setPagedMode(true);
3075 root->setWidth(printer.width());
3076// root->setHeight(printer.height());
3077 root->setPageTop(0);
3078 root->setPageBottom(0);
3079 d->paged = true;
3080
3081 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(printer.logicalDpiY(), 100);
3082 m_part->xmlDocImpl()->updateStyleSelector();
3083 root->setPrintImages(printSettings->printImages());
3084 root->makePageBreakAvoidBlocks();
3085
3086 root->setNeedsLayoutAndMinMaxRecalc();
3087 root->layout();
3088
3089 // check sizes ask for action.. (scale or clip)
3090
3091 bool printHeader = printSettings->printHeader();
3092
3093 int headerHeight = 0;
3094 QFont headerFont("Sans Serif", 8);
3095
3096 QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(),KLocale::ShortDate);
3097 QString headerMid = docname;
3098 QString headerRight;
3099
3100 if (printHeader)
3101 {
3102 p->setFont(headerFont);
3103 headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
3104 }
3105
3106 // ok. now print the pages.
3107 kDebug(6000) << "printing: html page width = " << root->docWidth()
3108 << " height = " << root->docHeight() << endl;
3109 kDebug(6000) << "printing: margins left = " << printer.pageRect().left() - printer.paperRect().left()
3110 << " top = " << printer.pageRect().top() - printer.paperRect().top() << endl;
3111 kDebug(6000) << "printing: paper width = " << printer.width()
3112 << " height = " << printer.height() << endl;
3113 // if the width is too large to fit on the paper we just scale
3114 // the whole thing.
3115 int pageWidth = printer.width();
3116 int pageHeight = printer.height();
3117 p->setClipRect(0,0, pageWidth, pageHeight);
3118
3119 pageHeight -= headerHeight;
3120
3121#ifndef QT_NO_TRANSFORMATIONS
3122 bool scalePage = false;
3123 double scale = 0.0;
3124 if(root->docWidth() > printer.width()) {
3125 scalePage = true;
3126 scale = ((double) printer.width())/((double) root->docWidth());
3127 pageHeight = (int) (pageHeight/scale);
3128 pageWidth = (int) (pageWidth/scale);
3129 headerHeight = (int) (headerHeight/scale);
3130 }
3131#endif
3132 kDebug(6000) << "printing: scaled html width = " << pageWidth
3133 << " height = " << pageHeight << endl;
3134
3135 root->setHeight(pageHeight);
3136 root->setPageBottom(pageHeight);
3137 root->setNeedsLayout(true);
3138 root->layoutIfNeeded();
3139// m_part->slotDebugRenderTree();
3140
3141 // Squeeze header to make it it on the page.
3142 if (printHeader)
3143 {
3144 int available_width = printer.width() - 10 -
3145 2 * qMax(p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
3146 p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
3147 if (available_width < 150)
3148 available_width = 150;
3149 int mid_width;
3150 int squeeze = 120;
3151 do {
3152 headerMid = KStringHandler::csqueeze(docname, squeeze);
3153 mid_width = p->boundingRect(0, 0, printer.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
3154 squeeze -= 10;
3155 } while (mid_width > available_width);
3156 }
3157
3158 int top = 0;
3159 int bottom = 0;
3160 int page = 1;
3161 while(top < root->docHeight()) {
3162 if(top > 0) printer.newPage();
3163#ifndef QT_NO_TRANSFORMATIONS
3164 if (scalePage)
3165 p->scale(scale, scale);
3166#endif
3167 p->save();
3168 p->setClipRect(0, 0, pageWidth, headerHeight);
3169 if (printHeader)
3170 {
3171 int dy = p->fontMetrics().lineSpacing();
3172 p->setPen(Qt::black);
3173 p->setFont(headerFont);
3174
3175 headerRight = QString("#%1").arg(page);
3176
3177 p->drawText(0, 0, printer.width(), dy, Qt::AlignLeft, headerLeft);
3178 p->drawText(0, 0, printer.width(), dy, Qt::AlignHCenter, headerMid);
3179 p->drawText(0, 0, printer.width(), dy, Qt::AlignRight, headerRight);
3180 }
3181
3182 p->restore();
3183 p->translate(0, headerHeight-top);
3184
3185 bottom = top+pageHeight;
3186
3187 root->setPageTop(top);
3188 root->setPageBottom(bottom);
3189 root->setPageNumber(page);
3190
3191 root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
3192 kDebug(6000) << "printed: page " << page <<" bottom At = " << bottom;
3193
3194 top = bottom;
3195 p->resetTransform();
3196 page++;
3197 }
3198
3199 p->end();
3200 delete p;
3201
3202 // and now reset the layout to the usual one...
3203 root->setPagedMode(false);
3204 root->setStaticMode(false);
3205 d->paged = false;
3206 khtml::setPrintPainter( 0 );
3207 setMediaType( oldMediaType );
3208 m_part->xmlDocImpl()->setPaintDevice( this );
3209 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->logicalDpiY(), m_part->fontScaleFactor());
3210 m_part->xmlDocImpl()->updateStyleSelector();
3211 viewport()->unsetCursor();
3212 }
3213}
3214
3215void KHTMLView::slotPaletteChanged()
3216{
3217 if(!m_part->xmlDocImpl()) return;
3218 DOM::DocumentImpl *document = m_part->xmlDocImpl();
3219 if (!document->isHTMLDocument()) return;
3220 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
3221 if(!root) return;
3222 root->style()->resetPalette();
3223 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
3224 if(!body) return;
3225 body->setChanged(true);
3226 body->recalcStyle( NodeImpl::Force );
3227}
3228
3229void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
3230{
3231 if(!m_part->xmlDocImpl()) return;
3232 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
3233 if(!root) return;
3234#ifdef SPEED_DEBUG
3235 d->firstRepaintPending = false;
3236#endif
3237
3238 QPaintDevice* opd = m_part->xmlDocImpl()->paintDevice();
3239 m_part->xmlDocImpl()->setPaintDevice(p->device());
3240 root->setPagedMode(true);
3241 root->setStaticMode(true);
3242 root->setWidth(rc.width());
3243
3244 // save()
3245 QRegion creg = p->clipRegion();
3246 QTransform t = p->worldTransform();
3247 QRect w = p->window();
3248 QRect v = p->viewport();
3249 bool vte = p->viewTransformEnabled();
3250 bool wme = p->worldMatrixEnabled();
3251
3252 p->setClipRect(rc);
3253 p->translate(rc.left(), rc.top());
3254 double scale = ((double) rc.width()/(double) root->docWidth());
3255 int height = (int) ((double) rc.height() / scale);
3256#ifndef QT_NO_TRANSFORMATIONS
3257 p->scale(scale, scale);
3258#endif
3259 root->setPageTop(yOff);
3260 root->setPageBottom(yOff+height);
3261
3262 root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
3263 if (more)
3264 *more = yOff + height < root->docHeight();
3265
3266 // restore()
3267 p->setWorldTransform(t);
3268 p->setWindow(w);
3269 p->setViewport(v);
3270 p->setViewTransformEnabled( vte );
3271 p->setWorldMatrixEnabled( wme );
3272 if (!creg.isEmpty())
3273 p->setClipRegion( creg );
3274 else
3275 p->setClipRegion(QRegion(), Qt::NoClip);
3276
3277 root->setPagedMode(false);
3278 root->setStaticMode(false);
3279 m_part->xmlDocImpl()->setPaintDevice( opd );
3280}
3281
3282void KHTMLView::render(QPainter* p, const QRect& r, const QPoint& off)
3283{
3284#ifdef SPEED_DEBUG
3285 d->firstRepaintPending = false;
3286#endif
3287 QRect clip(off.x()+r.x(), off.y()+r.y(),r.width(),r.height());
3288 if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
3289 p->fillRect(clip, palette().brush(QPalette::Active, QPalette::Base));
3290 return;
3291 }
3292 QPaintDevice* opd = m_part->xmlDocImpl()->paintDevice();
3293 m_part->xmlDocImpl()->setPaintDevice(p->device());
3294
3295 // save()
3296 QRegion creg = p->clipRegion();
3297 QTransform t = p->worldTransform();
3298 QRect w = p->window();
3299 QRect v = p->viewport();
3300 bool vte = p->viewTransformEnabled();
3301 bool wme = p->worldMatrixEnabled();
3302
3303 p->setClipRect(clip);
3304 QRect rect = r.translated(contentsX(),contentsY());
3305 p->translate(off.x()-contentsX(), off.y()-contentsY());
3306
3307 m_part->xmlDocImpl()->renderer()->layer()->paint(p, rect);
3308
3309 // restore()
3310 p->setWorldTransform(t);
3311 p->setWindow(w);
3312 p->setViewport(v);
3313 p->setViewTransformEnabled( vte );
3314 p->setWorldMatrixEnabled( wme );
3315 if (!creg.isEmpty())
3316 p->setClipRegion( creg );
3317 else
3318 p->setClipRegion(QRegion(), Qt::NoClip);
3319
3320 m_part->xmlDocImpl()->setPaintDevice( opd );
3321}
3322
3323void KHTMLView::setHasStaticBackground(bool partial)
3324{
3325 // full static iframe is irreversible for now
3326 if (d->staticWidget == KHTMLViewPrivate::SBFull && m_kwp->isRedirected())
3327 return;
3328
3329 d->staticWidget = partial ?
3330 KHTMLViewPrivate::SBPartial : KHTMLViewPrivate::SBFull;
3331}
3332
3333void KHTMLView::setHasNormalBackground()
3334{
3335 // full static iframe is irreversible for now
3336 if (d->staticWidget == KHTMLViewPrivate::SBFull && m_kwp->isRedirected())
3337 return;
3338
3339 d->staticWidget = KHTMLViewPrivate::SBNone;
3340}
3341
3342void KHTMLView::addStaticObject(bool fixed)
3343{
3344 if (fixed)
3345 d->fixedObjectsCount++;
3346 else
3347 d->staticObjectsCount++;
3348
3349 setHasStaticBackground( true /*partial*/ );
3350}
3351
3352void KHTMLView::removeStaticObject(bool fixed)
3353{
3354 if (fixed)
3355 d->fixedObjectsCount--;
3356 else
3357 d->staticObjectsCount--;
3358
3359 assert( d->fixedObjectsCount >= 0 && d->staticObjectsCount >= 0 );
3360
3361 if (!d->staticObjectsCount && !d->fixedObjectsCount)
3362 setHasNormalBackground();
3363 else
3364 setHasStaticBackground( true /*partial*/ );
3365}
3366
3367void KHTMLView::setVerticalScrollBarPolicy( Qt::ScrollBarPolicy policy )
3368{
3369#ifndef KHTML_NO_SCROLLBARS
3370 d->vpolicy = policy;
3371 QScrollArea::setVerticalScrollBarPolicy(policy);
3372#else
3373 Q_UNUSED( policy );
3374#endif
3375}
3376
3377void KHTMLView::setHorizontalScrollBarPolicy( Qt::ScrollBarPolicy policy )
3378{
3379#ifndef KHTML_NO_SCROLLBARS
3380 d->hpolicy = policy;
3381 QScrollArea::setHorizontalScrollBarPolicy(policy);
3382#else
3383 Q_UNUSED( policy );
3384#endif
3385}
3386
3387void KHTMLView::restoreScrollBar()
3388{
3389 int ow = visibleWidth();
3390 QScrollArea::setVerticalScrollBarPolicy(d->vpolicy);
3391 if (visibleWidth() != ow)
3392 layout();
3393 d->prevScrollbarVisible = verticalScrollBar()->isVisible();
3394}
3395
3396QStringList KHTMLView::formCompletionItems(const QString &name) const
3397{
3398 if (!m_part->settings()->isFormCompletionEnabled())
3399 return QStringList();
3400 if (!d->formCompletions)
3401 d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3402 return d->formCompletions->group("").readEntry(name, QStringList());
3403}
3404
3405void KHTMLView::clearCompletionHistory(const QString& name)
3406{
3407 if (!d->formCompletions)
3408 {
3409 d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3410 }
3411 d->formCompletions->group("").writeEntry(name, "");
3412 d->formCompletions->sync();
3413}
3414
3415void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
3416{
3417 if (!m_part->settings()->isFormCompletionEnabled())
3418 return;
3419 // don't store values that are all numbers or just numbers with
3420 // dashes or spaces as those are likely credit card numbers or
3421 // something similar
3422 bool cc_number(true);
3423 for ( int i = 0; i < value.length(); ++i)
3424 {
3425 QChar c(value[i]);
3426 if (!c.isNumber() && c != '-' && !c.isSpace())
3427 {
3428 cc_number = false;
3429 break;
3430 }
3431 }
3432 if (cc_number)
3433 return;
3434 QStringList items = formCompletionItems(name);
3435 if (!items.contains(value))
3436 items.prepend(value);
3437 while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
3438 items.erase(items.isEmpty() ? items.end() : --items.end());
3439 d->formCompletions->group("").writeEntry(name, items);
3440}
3441
3442void KHTMLView::addNonPasswordStorableSite(const QString& host)
3443{
3444 if (!d->formCompletions) {
3445 d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3446 }
3447
3448 KConfigGroup cg( d->formCompletions, "NonPasswordStorableSites");
3449 QStringList sites = cg.readEntry("Sites", QStringList());
3450 sites.append(host);
3451 cg.writeEntry("Sites", sites);
3452 cg.sync();
3453}
3454
3455
3456void KHTMLView::delNonPasswordStorableSite(const QString& host)
3457{
3458 if (!d->formCompletions) {
3459 d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3460 }
3461
3462 KConfigGroup cg( d->formCompletions, "NonPasswordStorableSites");
3463 QStringList sites = cg.readEntry("Sites", QStringList());
3464 sites.removeOne(host);
3465 cg.writeEntry("Sites", sites);
3466 cg.sync();
3467}
3468
3469bool KHTMLView::nonPasswordStorableSite(const QString& host) const
3470{
3471 if (!d->formCompletions) {
3472 d->formCompletions = new KConfig(KStandardDirs::locateLocal("data", "khtml/formcompletions"));
3473 }
3474 QStringList sites = d->formCompletions->group( "NonPasswordStorableSites" ).readEntry("Sites", QStringList());
3475 return (sites.indexOf(host) != -1);
3476}
3477
3478// returns true if event should be swallowed
3479bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
3480 DOM::NodeImpl *targetNodeNonShared, bool cancelable,
3481 int detail,QMouseEvent *_mouse, bool setUnder,
3482 int mouseEventType, int orient)
3483{
3484 // if the target node is a text node, dispatch on the parent node - rdar://4196646 (and #76948)
3485 if (targetNode && targetNode->isTextNode())
3486 targetNode = targetNode->parentNode();
3487
3488 if (d->underMouse)
3489 d->underMouse->deref();
3490 d->underMouse = targetNode;
3491 if (d->underMouse)
3492 d->underMouse->ref();
3493
3494 if (d->underMouseNonShared)
3495 d->underMouseNonShared->deref();
3496 d->underMouseNonShared = targetNodeNonShared;
3497 if (d->underMouseNonShared)
3498 d->underMouseNonShared->ref();
3499
3500 bool isWheelEvent = (mouseEventType == DOM::NodeImpl::MouseWheel);
3501
3502 int exceptioncode = 0;
3503 int pageX = _mouse->x();
3504 int pageY = _mouse->y();
3505 revertTransforms(pageX, pageY);
3506 int clientX = pageX - contentsX();
3507 int clientY = pageY - contentsY();
3508 int screenX = _mouse->globalX();
3509 int screenY = _mouse->globalY();
3510 int button = -1;
3511 switch (_mouse->button()) {
3512 case Qt::LeftButton:
3513 button = 0;
3514 break;
3515 case Qt::MidButton:
3516 button = 1;
3517 break;
3518 case Qt::RightButton:
3519 button = 2;
3520 break;
3521 default:
3522 break;
3523 }
3524 if (d->accessKeysEnabled && d->accessKeysPreActivate && button!=-1)
3525 d->accessKeysPreActivate=false;
3526
3527 bool ctrlKey = (_mouse->modifiers() & Qt::ControlModifier);
3528 bool altKey = (_mouse->modifiers() & Qt::AltModifier);
3529 bool shiftKey = (_mouse->modifiers() & Qt::ShiftModifier);
3530 bool metaKey = (_mouse->modifiers() & Qt::MetaModifier);
3531
3532 // mouseout/mouseover
3533 if (setUnder && d->oldUnderMouse != targetNode) {
3534 if (d->oldUnderMouse && d->oldUnderMouse->document() != m_part->xmlDocImpl()) {
3535 d->oldUnderMouse->deref();
3536 d->oldUnderMouse = 0;
3537 }
3538 // send mouseout event to the old node
3539 if (d->oldUnderMouse) {
3540 // send mouseout event to the old node
3541 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
3542 true,true,m_part->xmlDocImpl()->defaultView(),
3543 0,screenX,screenY,clientX,clientY,pageX, pageY,
3544 ctrlKey,altKey,shiftKey,metaKey,
3545 button,targetNode);
3546 me->ref();
3547 d->oldUnderMouse->dispatchEvent(me,exceptioncode,true);
3548 me->deref();
3549 }
3550 // send mouseover event to the new node
3551 if (targetNode) {
3552 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
3553 true,true,m_part->xmlDocImpl()->defaultView(),
3554 0,screenX,screenY,clientX,clientY,pageX, pageY,
3555 ctrlKey,altKey,shiftKey,metaKey,
3556 button,d->oldUnderMouse);
3557
3558 me->ref();
3559 targetNode->dispatchEvent(me,exceptioncode,true);
3560 me->deref();
3561 }
3562 if (d->oldUnderMouse)
3563 d->oldUnderMouse->deref();
3564 d->oldUnderMouse = targetNode;
3565 if (d->oldUnderMouse)
3566 d->oldUnderMouse->ref();
3567 }
3568
3569 bool swallowEvent = false;
3570
3571 if (targetNode) {
3572 // if the target node is a disabled widget, we don't want any full-blown mouse events
3573 if (targetNode->isGenericFormElement()
3574 && static_cast<HTMLGenericFormElementImpl*>(targetNode)->disabled())
3575 return true;
3576
3577 // send the actual event
3578 bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
3579 _mouse->type() == QEvent::MouseButtonDblClick );
3580 MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
3581 true,cancelable,m_part->xmlDocImpl()->defaultView(),
3582 detail,screenX,screenY,clientX,clientY,pageX, pageY,
3583 ctrlKey,altKey,shiftKey,metaKey,
3584 button,0, isWheelEvent ? 0 : _mouse, dblclick,
3585 isWheelEvent ? static_cast<MouseEventImpl::Orientation>(orient) : MouseEventImpl::ONone );
3586 me->ref();
3587 if ( !d->m_mouseEventsTarget && RenderLayer::gScrollBar && eventId == EventImpl::MOUSEDOWN_EVENT )
3588 // button is pressed inside a layer scrollbar, so make it the target for future mousemove events until released
3589 d->m_mouseEventsTarget = RenderLayer::gScrollBar;
3590 if ( d->m_mouseEventsTarget && qobject_cast<QScrollBar*>(d->m_mouseEventsTarget) &&
3591 dynamic_cast<KHTMLWidget*>(static_cast<QWidget*>(d->m_mouseEventsTarget)) ) {
3592 // we have a sticky mouse event target and it is a layer's scrollbar. Forward events manually.
3593 // ### should use the dom
3594 KHTMLWidget*w = dynamic_cast<KHTMLWidget*>(static_cast<QWidget*>(d->m_mouseEventsTarget));
3595 QPoint p = w->m_kwp->absolutePos();
3596 QMouseEvent fw(_mouse->type(), QPoint(pageX, pageY)-p, _mouse->button(), _mouse->buttons(), _mouse->modifiers());
3597 static_cast<RenderWidget::EventPropagator *>(static_cast<QWidget*>(d->m_mouseEventsTarget))->sendEvent(&fw);
3598 if (_mouse->type() == QMouseEvent::MouseButtonPress && _mouse->button() == Qt::RightButton) {
3599 QContextMenuEvent cme(QContextMenuEvent::Mouse, p);
3600 static_cast<RenderWidget::EventPropagator *>(static_cast<QWidget*>(d->m_mouseEventsTarget))->sendEvent(&cme);
3601 d->m_mouseEventsTarget = 0;
3602 }
3603 swallowEvent = true;
3604 } else {
3605 targetNode->dispatchEvent(me,exceptioncode,true);
3606 bool defaultHandled = me->defaultHandled();
3607 if (defaultHandled || me->defaultPrevented())
3608 swallowEvent = true;
3609 }
3610 if (eventId == EventImpl::MOUSEDOWN_EVENT && !me->defaultPrevented()) {
3611 // Focus should be shifted on mouse down, not on a click. -dwh
3612 // Blur current focus node when a link/button is clicked; this
3613 // is expected by some sites that rely on onChange handlers running
3614 // from form fields before the button click is processed.
3615 DOM::NodeImpl* nodeImpl = targetNode;
3616 for ( ; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode())
3617 {}
3618 if (nodeImpl && nodeImpl->isMouseFocusable())
3619 m_part->xmlDocImpl()->setFocusNode(nodeImpl);
3620 else if (!nodeImpl || !nodeImpl->focused())
3621 m_part->xmlDocImpl()->setFocusNode(0);
3622 }
3623 me->deref();
3624 }
3625
3626 return swallowEvent;
3627}
3628
3629void KHTMLView::setIgnoreWheelEvents( bool e )
3630{
3631 d->ignoreWheelEvents = e;
3632}
3633
3634#ifndef QT_NO_WHEELEVENT
3635
3636void KHTMLView::wheelEvent(QWheelEvent* e)
3637{
3638 // check if we should reset the state of the indicator describing if
3639 // we are currently scrolling the view as a result of wheel events
3640 if (d->scrollingFromWheel != QPoint(-1,-1) && d->scrollingFromWheel != QCursor::pos())
3641 d->scrollingFromWheel = d->scrollingFromWheelTimerId ? QCursor::pos() : QPoint(-1,-1);
3642
3643 if (d->accessKeysEnabled && d->accessKeysPreActivate) d->accessKeysPreActivate=false;
3644
3645 if ( ( e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier )
3646 {
3647 emit zoomView( - e->delta() );
3648 e->accept();
3649 }
3650 else if (d->firstLayoutPending)
3651 {
3652 e->accept();
3653 }
3654 else if( !m_kwp->isRedirected() &&
3655 ( (e->orientation() == Qt::Vertical &&
3656 ((d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
3657 || (e->delta() > 0 && contentsY() <= 0)
3658 || (e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())))
3659 ||
3660 (e->orientation() == Qt::Horizontal &&
3661 ((d->ignoreWheelEvents && !horizontalScrollBar()->isVisible())
3662 || (e->delta() > 0 && contentsX() <=0)
3663 || (e->delta() < 0 && contentsX() >= contentsWidth() - visibleWidth()))))
3664 && m_part->parentPart())
3665 {
3666 if ( m_part->parentPart()->view() )
3667 m_part->parentPart()->view()->wheelEvent( e );
3668 e->ignore();
3669 }
3670 else
3671 {
3672 int xm = e->x();
3673 int ym = e->y();
3674 revertTransforms(xm, ym);
3675
3676 DOM::NodeImpl::MouseEvent mev( e->buttons(), DOM::NodeImpl::MouseWheel );
3677 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
3678
3679 MouseEventImpl::Orientation o = MouseEventImpl::OVertical;
3680 if (e->orientation() == Qt::Horizontal)
3681 o = MouseEventImpl::OHorizontal;
3682
3683 QMouseEvent _mouse(QEvent::MouseMove, e->pos(), Qt::NoButton, e->buttons(), e->modifiers());
3684 bool swallow = dispatchMouseEvent(EventImpl::KHTML_MOUSEWHEEL_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),
3685 true,-e->delta()/40,&_mouse,true,DOM::NodeImpl::MouseWheel,o);
3686
3687 if (swallow)
3688 return;
3689
3690 d->scrollBarMoved = true;
3691 d->scrollingFromWheel = QCursor::pos();
3692 if (d->smoothScrollMode != SSMDisabled)
3693 d->shouldSmoothScroll = true;
3694 if (d->scrollingFromWheelTimerId)
3695 killTimer(d->scrollingFromWheelTimerId);
3696 d->scrollingFromWheelTimerId = startTimer(400);
3697
3698 if (m_part->parentPart()) {
3699 // don't propagate if we are a sub-frame and our scrollbars are already at end of range
3700 bool h = (static_cast<QWheelEvent*>(e)->orientation() == Qt::Horizontal);
3701 bool d = (static_cast<QWheelEvent*>(e)->delta() < 0);
3702 QScrollBar* hsb = horizontalScrollBar();
3703 QScrollBar* vsb = verticalScrollBar();
3704 if ( (h && ((d && hsb->value() == hsb->maximum()) || (!d && hsb->value() == hsb->minimum()))) ||
3705 (!h && ((d && vsb->value() == vsb->maximum()) || (!d && vsb->value() == vsb->minimum()))) ) {
3706 e->accept();
3707 return;
3708 }
3709 }
3710 QScrollArea::wheelEvent( e );
3711 }
3712
3713}
3714#endif
3715
3716void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
3717{
3718 // Still overridden for BC reasons only...
3719 QScrollArea::dragEnterEvent( ev );
3720}
3721
3722void KHTMLView::dropEvent( QDropEvent *ev )
3723{
3724 // Still overridden for BC reasons only...
3725 QScrollArea::dropEvent( ev );
3726}
3727
3728void KHTMLView::focusInEvent( QFocusEvent *e )
3729{
3730 DOM::NodeImpl* fn = m_part->xmlDocImpl() ? m_part->xmlDocImpl()->focusNode() : 0;
3731 if (fn && fn->renderer() && fn->renderer()->isWidget() &&
3732 (e->reason() != Qt::MouseFocusReason) &&
3733 static_cast<khtml::RenderWidget*>(fn->renderer())->widget())
3734 static_cast<khtml::RenderWidget*>(fn->renderer())->widget()->setFocus();
3735 m_part->setSelectionVisible();
3736 QScrollArea::focusInEvent( e );
3737}
3738
3739void KHTMLView::focusOutEvent( QFocusEvent *e )
3740{
3741 if (m_part) {
3742 m_part->stopAutoScroll();
3743 m_part->setSelectionVisible(false);
3744 }
3745
3746 if ( d->cursorIconWidget )
3747 d->cursorIconWidget->hide();
3748
3749 QScrollArea::focusOutEvent( e );
3750}
3751
3752void KHTMLView::scrollContentsBy( int dx, int dy )
3753{
3754 if (!dx && !dy) return;
3755
3756 if ( !d->firstLayoutPending && !d->complete && m_part->xmlDocImpl() &&
3757 d->layoutSchedulingEnabled) {
3758 // contents scroll while we are not complete: we need to check our layout *now*
3759 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>( m_part->xmlDocImpl()->renderer() );
3760 if (root && root->needsLayout()) {
3761 unscheduleRelayout();
3762 layout();
3763 }
3764 }
3765
3766 if ( d->shouldSmoothScroll && d->smoothScrollMode != SSMDisabled && m_part->xmlDocImpl() &&
3767 m_part->xmlDocImpl()->renderer() && (d->smoothScrollMode != SSMWhenEfficient || d->smoothScrollMissedDeadlines != sWayTooMany)) {
3768
3769 bool doSmoothScroll = (!d->staticWidget || d->smoothScrollMode == SSMEnabled);
3770
3771 int numStaticPixels = 0;
3772 QRegion r = static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->staticRegion();
3773
3774 // only do smooth scrolling if static region is relatively small
3775 if (!doSmoothScroll && d->staticWidget == KHTMLViewPrivate::SBPartial && r.rects().size() <= 10) {
3776 foreach(const QRect &rr, r.rects())
3777 numStaticPixels += rr.width()*rr.height();
3778 if ((numStaticPixels < sSmoothScrollMinStaticPixels) || (numStaticPixels*8 < visibleWidth()*visibleHeight()))
3779 doSmoothScroll = true;
3780 }
3781 if (doSmoothScroll) {
3782 setupSmoothScrolling(dx, dy);
3783 return;
3784 }
3785 }
3786
3787 if ( underMouse() && QToolTip::isVisible() )
3788 QToolTip::hideText();
3789
3790 if (!d->scrollingSelf) {
3791 d->scrollBarMoved = true;
3792 d->contentsMoving = true;
3793 // ensure quick reset of contentsMoving flag
3794 scheduleRepaint(0, 0, 0, 0);
3795 }
3796
3797 if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->documentElement()) {
3798 m_part->xmlDocImpl()->documentElement()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false);
3799 }
3800
3801 if (QApplication::isRightToLeft())
3802 dx = -dx;
3803
3804 if (!d->smoothScrolling) {
3805 d->updateContentsXY();
3806 } else {
3807 d->contentsX -= dx;
3808 d->contentsY -= dy;
3809 }
3810 if (widget()->pos() != QPoint(0,0)) {
3811 kDebug(6000) << "Static widget wasn't positioned at (0,0). This should NOT happen. Please report this event to developers.";
3812 kDebug(6000) << kBacktrace();
3813 widget()->move(0,0);
3814 }
3815
3816 QWidget *w = widget();
3817 QPoint off;
3818 if (m_kwp->isRedirected()) {
3819 // This is a redirected sub frame. Translate to root view context
3820 KHTMLView* v = m_kwp->rootViewPos( off );
3821 if (v)
3822 w = v->widget();
3823 off = viewport()->mapTo(this, off);
3824 }
3825
3826 if ( d->staticWidget ) {
3827
3828 // now remove from view the external widgets that must have completely
3829 // disappeared after dx/dy scroll delta is effective
3830 if (!d->visibleWidgets.isEmpty())
3831 checkExternalWidgetsPosition();
3832
3833 if ( d->staticWidget == KHTMLViewPrivate::SBPartial
3834 && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer() ) {
3835 // static objects might be selectively repainted, like stones in flowing water
3836 QRegion r = static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->staticRegion();
3837 r.translate( -contentsX(), -contentsY());
3838 QVector<QRect> ar = r.rects();
3839
3840 for (int i = 0; i < ar.size() ; ++i) {
3841 widget()->update( ar[i] );
3842 }
3843 r = QRegion(QRect(0, 0, visibleWidth(), visibleHeight())) - r;
3844 ar = r.rects();
3845 for (int i = 0; i < ar.size() ; ++i) {
3846 w->scroll( dx, dy, ar[i].translated(off) );
3847 }
3848 d->scrollExternalWidgets(dx, dy);
3849 } else {
3850 // we can't avoid a full update
3851 widget()->update();
3852 }
3853 if (d->accessKeysActivated)
3854 d->scrollAccessKeys(dx, dy);
3855
3856 return;
3857 }
3858
3859 if (m_kwp->isRedirected()) {
3860 const QRect rect(off.x(), off.y(), visibleWidth() * d->zoomLevel / 100, visibleHeight() * d->zoomLevel / 100);
3861 w->scroll(dx, dy, rect);
3862 if (d->zoomLevel != 100) {
3863 w->update(rect); // without this update we are getting bad rendering when an iframe is zoomed in
3864 }
3865 } else {
3866 widget()->scroll(dx, dy, widget()->rect() & viewport()->rect());
3867 }
3868
3869 d->scrollExternalWidgets(dx, dy);
3870 if (d->accessKeysActivated)
3871 d->scrollAccessKeys(dx, dy);
3872}
3873
3874void KHTMLView::setupSmoothScrolling(int dx, int dy)
3875{
3876 // old or minimum speed
3877 int ddx = qMax(d->steps ? abs(d->dx)/d->steps : 0,3);
3878 int ddy = qMax(d->steps ? abs(d->dy)/d->steps : 0,3);
3879
3880 // full scroll is remaining scroll plus new scroll
3881 d->dx = d->dx + dx;
3882 d->dy = d->dy + dy;
3883
3884 if (d->dx == 0 && d->dy == 0) {
3885 d->stopScrolling();
3886 return;
3887 }
3888
3889 d->steps = (sSmoothScrollTime-1)/sSmoothScrollTick + 1;
3890
3891 if (qMax(abs(d->dx), abs(d->dy)) / d->steps < qMax(ddx,ddy)) {
3892 // Don't move slower than average 4px/step in minimum one direction
3893 // This means fewer than normal steps
3894 d->steps = qMax((abs(d->dx)+ddx-1)/ddx, (abs(d->dy)+ddy-1)/ddy);
3895 if (d->steps < 1) d->steps = 1;
3896 }
3897
3898 d->smoothScrollStopwatch.start();
3899 if (!d->smoothScrolling) {
3900 d->startScrolling();
3901 scrollTick();
3902 }
3903}
3904
3905void KHTMLView::scrollTick() {
3906 if (d->dx == 0 && d->dy == 0) {
3907 d->stopScrolling();
3908 return;
3909 }
3910
3911 if (d->steps < 1) d->steps = 1;
3912 int takesteps = d->smoothScrollStopwatch.restart() / sSmoothScrollTick;
3913 int scroll_x = 0;
3914 int scroll_y = 0;
3915 if (takesteps < 1) takesteps = 1;
3916 if (takesteps > d->steps) takesteps = d->steps;
3917 for(int i = 0; i < takesteps; i++) {
3918 int ddx = (d->dx / (d->steps+1)) * 2;
3919 int ddy = (d->dy / (d->steps+1)) * 2;
3920
3921 // limit step to requested scrolling distance
3922 if (abs(ddx) > abs(d->dx)) ddx = d->dx;
3923 if (abs(ddy) > abs(d->dy)) ddy = d->dy;
3924
3925 // update remaining scroll
3926 d->dx -= ddx;
3927 d->dy -= ddy;
3928 scroll_x += ddx;
3929 scroll_y += ddy;
3930 d->steps--;
3931 }
3932
3933 d->shouldSmoothScroll = false;
3934 scrollContentsBy(scroll_x, scroll_y);
3935
3936 if (takesteps < 2) {
3937 d->smoothScrollMissedDeadlines = 0;
3938 } else {
3939 if (d->smoothScrollMissedDeadlines != sWayTooMany &&
3940 (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->parsing())) {
3941 d->smoothScrollMissedDeadlines++;
3942 if (d->smoothScrollMissedDeadlines >= sMaxMissedDeadlines) {
3943 // we missed many deadlines in a row!
3944 // time to signal we had enough..
3945 d->smoothScrollMissedDeadlines = sWayTooMany;
3946 }
3947 }
3948 }
3949}
3950
3951
3952void KHTMLView::addChild(QWidget * child, int x, int y)
3953{
3954 if (!child)
3955 return;
3956
3957 if (child->parent() != widget())
3958 child->setParent( widget() );
3959
3960 // ### handle pseudo-zooming of non-redirected widgets (e.g. just resize'em)
3961
3962 child->move(x-contentsX(), y-contentsY());
3963}
3964
3965void KHTMLView::timerEvent ( QTimerEvent *e )
3966{
3967// kDebug() << "timer event " << e->timerId();
3968 if ( e->timerId() == d->scrollTimerId ) {
3969 if( d->scrollSuspended )
3970 return;
3971 switch (d->scrollDirection) {
3972 case KHTMLViewPrivate::ScrollDown:
3973 if (contentsY() + visibleHeight () >= contentsHeight())
3974 d->newScrollTimer(this, 0);
3975 else
3976 verticalScrollBar()->setValue( verticalScrollBar()->value() +d->scrollBy );
3977 break;
3978 case KHTMLViewPrivate::ScrollUp:
3979 if (contentsY() <= 0)
3980 d->newScrollTimer(this, 0);
3981 else
3982 verticalScrollBar()->setValue( verticalScrollBar()->value() -d->scrollBy );
3983 break;
3984 case KHTMLViewPrivate::ScrollRight:
3985 if (contentsX() + visibleWidth () >= contentsWidth())
3986 d->newScrollTimer(this, 0);
3987 else
3988 horizontalScrollBar()->setValue( horizontalScrollBar()->value() +d->scrollBy );
3989 break;
3990 case KHTMLViewPrivate::ScrollLeft:
3991 if (contentsX() <= 0)
3992 d->newScrollTimer(this, 0);
3993 else
3994 horizontalScrollBar()->setValue( horizontalScrollBar()->value() -d->scrollBy );
3995 break;
3996 }
3997 return;
3998 }
3999 else if ( e->timerId() == d->scrollingFromWheelTimerId ) {
4000 killTimer( d->scrollingFromWheelTimerId );
4001 d->scrollingFromWheelTimerId = 0;
4002 } else if ( e->timerId() == d->layoutTimerId ) {
4003 if (d->firstLayoutPending && d->layoutAttemptCounter < 4
4004 && (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->readyForLayout())) {
4005 d->layoutAttemptCounter++;
4006 killTimer(d->layoutTimerId);
4007 d->layoutTimerId = 0;
4008 scheduleRelayout();
4009 return;
4010 }
4011 layout();
4012 d->scheduledLayoutCounter++;
4013 if (d->firstLayoutPending) {
4014 d->firstLayoutPending = false;
4015 verticalScrollBar()->setEnabled( true );
4016 horizontalScrollBar()->setEnabled( true );
4017 }
4018 }
4019
4020 d->contentsMoving = false;
4021 if( m_part->xmlDocImpl() ) {
4022 DOM::DocumentImpl *document = m_part->xmlDocImpl();
4023 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
4024
4025 if ( root && root->needsLayout() ) {
4026 if (d->repaintTimerId)
4027 killTimer(d->repaintTimerId);
4028 d->repaintTimerId = 0;
4029 scheduleRelayout();
4030 return;
4031 }
4032 }
4033
4034 if (d->repaintTimerId)
4035 killTimer(d->repaintTimerId);
4036 d->repaintTimerId = 0;
4037
4038 QRect updateRegion;
4039 const QVector<QRect> rects = d->updateRegion.rects();
4040
4041 d->updateRegion = QRegion();
4042
4043 if ( rects.size() )
4044 updateRegion = rects[0];
4045
4046 for ( int i = 1; i < rects.size(); ++i ) {
4047 QRect newRegion = updateRegion.unite(rects[i]);
4048 if (2*newRegion.height() > 3*updateRegion.height() )
4049 {
4050 repaintContents( updateRegion );
4051 updateRegion = rects[i];
4052 }
4053 else
4054 updateRegion = newRegion;
4055 }
4056
4057 if ( !updateRegion.isNull() )
4058 repaintContents( updateRegion );
4059
4060 // As widgets can only be accurately positioned during painting, every layout might
4061 // dissociate a widget from its RenderWidget. E.g: if a RenderWidget was visible before layout, but the layout
4062 // pushed it out of the viewport, it will not be repainted, and consequently it's associated widget won't be repositioned.
4063 // 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.
4064
4065 if (d->dirtyLayout && !d->visibleWidgets.isEmpty())
4066 checkExternalWidgetsPosition();
4067
4068 d->dirtyLayout = false;
4069
4070 emit repaintAccessKeys();
4071 if (d->emitCompletedAfterRepaint) {
4072 bool full = d->emitCompletedAfterRepaint == KHTMLViewPrivate::CSFull;
4073 d->emitCompletedAfterRepaint = KHTMLViewPrivate::CSNone;
4074 if ( full )
4075 emit m_part->completed();
4076 else
4077 emit m_part->completed(true);
4078 }
4079}
4080
4081void KHTMLView::checkExternalWidgetsPosition()
4082{
4083 QWidget* w;
4084 QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
4085 QList<RenderWidget*> toRemove;
4086 QHashIterator<void*, QWidget*> it(d->visibleWidgets);
4087 while (it.hasNext()) {
4088 int xp = 0, yp = 0;
4089 it.next();
4090 RenderWidget* rw = static_cast<RenderWidget*>( it.key() );
4091 if (!rw->absolutePosition(xp, yp) ||
4092 !visibleRect.intersects(QRect(xp, yp, it.value()->width(), it.value()->height())))
4093 toRemove.append(rw);
4094 }
4095 foreach (RenderWidget* r, toRemove)
4096 if ( (w = d->visibleWidgets.take(r) ) )
4097 w->move( 0, -500000);
4098}
4099
4100void KHTMLView::scheduleRelayout(khtml::RenderObject * /*clippedObj*/)
4101{
4102 if (!d->layoutSchedulingEnabled || d->layoutTimerId)
4103 return;
4104
4105 int time = 0;
4106 if (d->firstLayoutPending) {
4107 // Any repaint happening while we have no content blanks the viewport ("white flash").
4108 // Hence the need to delay the first layout as much as we can.
4109 // Only if the document gets stuck for too long in incomplete state will we allow the blanking.
4110 time = d->layoutAttemptCounter ?
4111 sLayoutAttemptDelay + sLayoutAttemptIncrement*d->layoutAttemptCounter : sFirstLayoutDelay;
4112 } else if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()) {
4113 // Delay between successive layouts in parsing mode.
4114 // Increment reflects the decaying importance of visual feedback over time.
4115 time = qMin(2000, sParsingLayoutsInterval + d->scheduledLayoutCounter*sParsingLayoutsIncrement);
4116 }
4117 d->layoutTimerId = startTimer( time );
4118}
4119
4120void KHTMLView::unscheduleRelayout()
4121{
4122 if (!d->layoutTimerId)
4123 return;
4124
4125 killTimer(d->layoutTimerId);
4126 d->layoutTimerId = 0;
4127}
4128
4129void KHTMLView::unscheduleRepaint()
4130{
4131 if (!d->repaintTimerId)
4132 return;
4133
4134 killTimer(d->repaintTimerId);
4135 d->repaintTimerId = 0;
4136}
4137
4138void KHTMLView::scheduleRepaint(int x, int y, int w, int h, bool asap)
4139{
4140 bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
4141
4142// kDebug() << "parsing " << parsing;
4143// kDebug() << "complete " << d->complete;
4144
4145 int time = parsing && !d->firstLayoutPending ? 150 : (!asap ? ( !d->complete ? 80 : 20 ) : 0);
4146
4147#ifdef DEBUG_FLICKER
4148 QPainter p;
4149 p.begin( viewport() );
4150
4151 int vx, vy;
4152 contentsToViewport( x, y, vx, vy );
4153 p.fillRect( vx, vy, w, h, Qt::red );
4154 p.end();
4155#endif
4156
4157 d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
4158
4159 if (asap && !parsing)
4160 unscheduleRepaint();
4161
4162 if ( !d->repaintTimerId )
4163 d->repaintTimerId = startTimer( time );
4164
4165// kDebug() << "starting timer " << time;
4166}
4167
4168void KHTMLView::complete( bool pendingAction )
4169{
4170// kDebug() << "KHTMLView::complete()";
4171
4172 d->complete = true;
4173
4174 // is there a relayout pending?
4175 if (d->layoutTimerId)
4176 {
4177// kDebug() << "requesting relayout now";
4178 // do it now
4179 killTimer(d->layoutTimerId);
4180 d->layoutTimerId = startTimer( 0 );
4181 d->emitCompletedAfterRepaint = pendingAction ?
4182 KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
4183 }
4184
4185 // is there a repaint pending?
4186 if (d->repaintTimerId)
4187 {
4188// kDebug() << "requesting repaint now";
4189 // do it now
4190 killTimer(d->repaintTimerId);
4191 d->repaintTimerId = startTimer( 0 );
4192 d->emitCompletedAfterRepaint = pendingAction ?
4193 KHTMLViewPrivate::CSActionPending : KHTMLViewPrivate::CSFull;
4194 }
4195
4196 if (!d->emitCompletedAfterRepaint)
4197 {
4198 if (!pendingAction)
4199 emit m_part->completed();
4200 else
4201 emit m_part->completed(true);
4202 }
4203
4204}
4205
4206void KHTMLView::updateScrollBars()
4207{
4208 const QWidget *view = widget();
4209 if (!view)
4210 return;
4211
4212 QSize p = viewport()->size();
4213 QSize m = maximumViewportSize();
4214
4215 if (m.expandedTo(view->size()) == m)
4216 p = m; // no scroll bars needed
4217
4218 QSize v = view->size();
4219 horizontalScrollBar()->setRange(0, v.width() - p.width());
4220 horizontalScrollBar()->setPageStep(p.width());
4221 verticalScrollBar()->setRange(0, v.height() - p.height());
4222 verticalScrollBar()->setPageStep(p.height());
4223 if (!d->smoothScrolling) {
4224 d->updateContentsXY();
4225 }
4226}
4227
4228void KHTMLView::slotMouseScrollTimer()
4229{
4230 horizontalScrollBar()->setValue( horizontalScrollBar()->value() +d->m_mouseScroll_byX );
4231 verticalScrollBar()->setValue( verticalScrollBar()->value() +d->m_mouseScroll_byY);
4232}
4233
4234
4235static DOM::Position positionOfLineBoundary(const DOM::Position &pos, bool toEnd)
4236{
4237 Selection sel = pos;
4238 sel.expandUsingGranularity(Selection::LINE);
4239 return toEnd ? sel.end() : sel.start();
4240}
4241
4242inline static DOM::Position positionOfLineBegin(const DOM::Position &pos)
4243{
4244 return positionOfLineBoundary(pos, false);
4245}
4246
4247inline static DOM::Position positionOfLineEnd(const DOM::Position &pos)
4248{
4249 return positionOfLineBoundary(pos, true);
4250}
4251
4252bool KHTMLView::caretKeyPressEvent(QKeyEvent *_ke)
4253{
4254 EditorContext *ec = &m_part->d->editor_context;
4255 Selection &caret = ec->m_selection;
4256 Position old_pos = caret.caretPos();
4257 Position pos = old_pos;
4258 bool recalcXPos = true;
4259 bool handled = true;
4260
4261 bool ctrl = _ke->modifiers() & Qt::ControlModifier;
4262 bool shift = _ke->modifiers() & Qt::ShiftModifier;
4263
4264 switch(_ke->key()) {
4265
4266 // -- Navigational keys
4267 case Qt::Key_Down:
4268 pos = old_pos.nextLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
4269 recalcXPos = false;
4270 break;
4271
4272 case Qt::Key_Up:
4273 pos = old_pos.previousLinePosition(caret.xPosForVerticalArrowNavigation(Selection::EXTENT));
4274 recalcXPos = false;
4275 break;
4276
4277 case Qt::Key_Left:
4278 pos = ctrl ? old_pos.previousWordPosition() : old_pos.previousCharacterPosition();
4279 break;
4280
4281 case Qt::Key_Right:
4282 pos = ctrl ? old_pos.nextWordPosition() : old_pos.nextCharacterPosition();
4283 break;
4284
4285 case Qt::Key_PageDown:
4286// moveCaretNextPage(); ###
4287 break;
4288
4289 case Qt::Key_PageUp:
4290// moveCaretPrevPage(); ###
4291 break;
4292
4293 case Qt::Key_Home:
4294 if (ctrl)
4295 /*moveCaretToDocumentBoundary(false)*/; // ###
4296 else
4297 pos = positionOfLineBegin(old_pos);
4298 break;
4299
4300 case Qt::Key_End:
4301 if (ctrl)
4302 /*moveCaretToDocumentBoundary(true)*/; // ###
4303 else
4304 pos = positionOfLineEnd(old_pos);
4305 break;
4306
4307 default:
4308 handled = false;
4309
4310 }/*end switch*/
4311
4312 if (pos != old_pos) {
4313 m_part->clearCaretRectIfNeeded();
4314
4315 caret.moveTo(shift ? caret.nonCaretPos() : pos, pos);
4316 int old_x = caret.xPosForVerticalArrowNavigation(Selection::CARETPOS);
4317
4318 m_part->selectionLayoutChanged();
4319
4320 // restore old x-position to prevent recalculation
4321 if (!recalcXPos)
4322 m_part->d->editor_context.m_xPosForVerticalArrowNavigation = old_x;
4323
4324 m_part->emitCaretPositionChanged(pos);
4325 // ### check when to emit it
4326 m_part->notifySelectionChanged();
4327
4328 }
4329
4330 if (handled) _ke->accept();
4331 return handled;
4332}
4333
4334#undef DEBUG_CARETMODE
DOM::DOMString
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
DOM::DOMString::length
uint length() const
Definition: dom_string.cpp:185
DOM::DOMString::string
QString string() const
Definition: dom_string.cpp:236
DOM::Node
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:271
DOM::Node::handle
NodeImpl * handle() const
Definition: dom_node.h:925
KConfigGroup
KConfigGroup::readEntry
QString readEntry(const char *key, const char *aDefault=0) const
KConfig
KDialog
KHTMLGlobal::iconLoader
static KIconLoader * iconLoader()
Definition: khtml_global.cpp:227
KHTMLGlobal::defaultHTMLSettings
static KHTMLSettings * defaultHTMLSettings()
Definition: khtml_global.cpp:237
KHTMLPartPrivate::editor_context
khtml::EditorContext editor_context
Definition: khtmlpart_p.h:371
KHTMLPartPrivate::m_parsetime
QTime m_parsetime
Definition: khtmlpart_p.h:313
KHTMLPartPrivate::m_bMousePressed
bool m_bMousePressed
Definition: khtmlpart_p.h:367
KHTMLPartPrivate::m_bOpenMiddleClick
bool m_bOpenMiddleClick
Definition: khtmlpart_p.h:254
KHTMLPart
This class is khtml's main class.
Definition: khtml_part.h:207
KHTMLPart::view
KHTMLView * view() const
Returns a pointer to the HTML document's view.
Definition: khtml_part.cpp:1059
KHTMLPart::isEditable
bool isEditable() const
Returns true if the document is editable, false otherwise.
Definition: khtml_part.cpp:2904
KHTMLPart::parentPart
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
Definition: khtml_part.cpp:5356
KHTMLPart::nodeActivated
void nodeActivated(const DOM::Node &)
This signal is emitted when an element retrieves the keyboard focus.
KHTMLPart::setCaretVisible
void setCaretVisible(bool show)
Sets the visibility of the caret.
Definition: khtml_part.cpp:2952
KHTMLPart::begin
virtual void begin(const KUrl &url=KUrl(), int xOffset=0, int yOffset=0)
Clears the widget and prepares it for new content.
Definition: khtml_part.cpp:1993
KHTMLPart::settings
const KHTMLSettings * settings() const
Definition: khtml_part.cpp:2508
KHTMLPart::frames
QList< KParts::ReadOnlyPart * > frames() const
Definition: khtml_part.cpp:6046
KHTMLPart::fontScaleFactor
int fontScaleFactor() const
Returns the current font scale factor.
Definition: khtml_part.cpp:5886
KHTMLPart::isCaretMode
bool isCaretMode() const
Returns whether caret mode is on/off.
Definition: khtml_part.cpp:2884
KHTMLPart::urlCursor
QCursor urlCursor() const
Returns the cursor which is used when the cursor is on a link.
Definition: khtml_part.cpp:2788
KHTMLPart::frameExists
bool frameExists(const QString &frameName)
Returns whether a frame with the specified name is exists or not.
Definition: khtml_part.cpp:5314
KHTMLPrintSettings
Definition: khtml_printsettings.h:28
KHTMLSettings::maxFormCompletionItems
int maxFormCompletionItems() const
Definition: khtml_settings.cpp:1089
KHTMLSettings::fallbackAccessKeysAssignments
QList< QPair< QString, QChar > > fallbackAccessKeysAssignments() const
Definition: khtml_settings.cpp:1178
KHTMLSettings::isFormCompletionEnabled
bool isFormCompletionEnabled() const
Definition: khtml_settings.cpp:1084
KHTMLSettings::accessKeysEnabled
bool accessKeysEnabled() const
Definition: khtml_settings.cpp:818
KHTMLSettings::changeCursor
bool changeCursor() const
Definition: khtml_settings.cpp:327
KHTMLView
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:93
KHTMLView::slotPaletteChanged
void slotPaletteChanged()
Definition: khtmlview.cpp:3215
KHTMLView::closeEvent
virtual void closeEvent(QCloseEvent *)
Definition: khtmlview.cpp:1062
KHTMLView::addChild
void addChild(QWidget *child, int dx, int dy)
Definition: khtmlview.cpp:3952
KHTMLView::repaintContents
void repaintContents(const QRect &r)
Requests an immediate repaint of the content area.
Definition: khtmlview.cpp:800
KHTMLView::part
KHTMLPart * part() const
Returns a pointer to the KHTMLPart that is rendering the page.
Definition: khtmlview.h:135
KHTMLView::contentsWidth
int contentsWidth() const
Returns the contents area's width.
Definition: khtmlview.cpp:671
KHTMLView::finishedLayout
void finishedLayout()
This signal is used for internal layouting.
KHTMLView::repaintAccessKeys
void repaintAccessKeys()
KHTMLView::resizeEvent
virtual void resizeEvent(QResizeEvent *event)
Definition: khtmlview.cpp:837
KHTMLView::displayAccessKeys
void displayAccessKeys()
Display all accesskeys in small tooltips.
Definition: khtmlview.cpp:2502
KHTMLView::mousePressEvent
virtual void mousePressEvent(QMouseEvent *)
Definition: khtmlview.cpp:1113
KHTMLView::focusOutEvent
virtual void focusOutEvent(QFocusEvent *)
Definition: khtmlview.cpp:3739
KHTMLView::setContentsPos
void setContentsPos(int x, int y)
Place the contents area point x/y at the top left of the viewport.
Definition: khtmlview.cpp:732
KHTMLView::setMarginHeight
void setMarginHeight(int y)
Definition: khtmlview.cpp:948
KHTMLView::dropEvent
virtual void dropEvent(QDropEvent *)
Definition: khtmlview.cpp:3722
KHTMLView::clear
void clear()
Definition: khtmlview.cpp:621
KHTMLView::focusInEvent
virtual void focusInEvent(QFocusEvent *)
Definition: khtmlview.cpp:3728
KHTMLView::widgetEvent
virtual bool widgetEvent(QEvent *)
Definition: khtmlview.cpp:2195
KHTMLView::~KHTMLView
virtual ~KHTMLView()
Definition: khtmlview.cpp:563
KHTMLView::keyPressEvent
void keyPressEvent(QKeyEvent *_ke)
Definition: khtmlview.cpp:1676
KHTMLView::scrollContentsBy
virtual void scrollContentsBy(int dx, int dy)
Definition: khtmlview.cpp:3752
KHTMLView::setZoomLevel
void setZoomLevel(int percent)
Apply a zoom level to the content area.
Definition: khtmlview.cpp:1068
KHTMLView::dragEnterEvent
virtual void dragEnterEvent(QDragEnterEvent *)
Definition: khtmlview.cpp:3716
KHTMLView::focusNextPrevChild
virtual bool focusNextPrevChild(bool next)
Definition: khtmlview.cpp:1868
KHTMLView::setSmoothScrollingModeDefault
void setSmoothScrollingModeDefault(SmoothScrollingMode m)
Definition: khtmlview.cpp:1093
KHTMLView::event
virtual bool event(QEvent *event)
Definition: khtmlview.cpp:481
KHTMLView::hideAccessKeys
void hideAccessKeys()
KHTMLView::cleared
void cleared()
KHTMLView::timerEvent
void timerEvent(QTimerEvent *)
Definition: khtmlview.cpp:3965
KHTMLView::KHTMLView
KHTMLView(KHTMLPart *part, QWidget *parent)
Constructs a KHTMLView.
Definition: khtmlview.cpp:549
KHTMLView::setMarginWidth
void setMarginWidth(int x)
Sets a margin in x direction.
Definition: khtmlview.cpp:942
KHTMLView::layout
void layout()
ensure the display is up to date
Definition: khtmlview.cpp:954
KHTMLView::mouseDoubleClickEvent
virtual void mouseDoubleClickEvent(QMouseEvent *)
Definition: khtmlview.cpp:1242
KHTMLView::resizeContents
virtual void resizeContents(int w, int h)
Resize the contents area.
Definition: khtmlview.cpp:681
KHTMLView::setSmoothScrollingMode
void setSmoothScrollingMode(SmoothScrollingMode m)
Set the smooth scrolling mode.
Definition: khtmlview.cpp:1085
KHTMLView::setHorizontalScrollBarPolicy
virtual void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
Sets horizontal scrollbar mode.
Definition: khtmlview.cpp:3377
KHTMLView::contentsX
int contentsX() const
Returns the x coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:690
KHTMLView::viewportEvent
virtual bool viewportEvent(QEvent *e)
Definition: khtmlview.cpp:1979
KHTMLView::paintEvent
virtual void paintEvent(QPaintEvent *)
Definition: khtmlview.cpp:869
KHTMLView::zoomView
void zoomView(int)
KHTMLView::contentsY
int contentsY() const
Returns the y coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:695
KHTMLView::wheelEvent
virtual void wheelEvent(QWheelEvent *)
Definition: khtmlview.cpp:3636
KHTMLView::zoomLevel
int zoomLevel() const
Retrieve the current zoom level.
Definition: khtmlview.cpp:1080
KHTMLView::showEvent
virtual void showEvent(QShowEvent *)
Definition: khtmlview.cpp:646
KHTMLView::hideEvent
virtual void hideEvent(QHideEvent *)
Definition: khtmlview.cpp:641
KHTMLView::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *)
Definition: khtmlview.cpp:1545
KHTMLView::setVerticalScrollBarPolicy
virtual void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
Sets vertical scrollbar mode.
Definition: khtmlview.cpp:3367
KHTMLView::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *)
Definition: khtmlview.cpp:1301
KHTMLView::visibleWidth
int visibleWidth() const
Returns the width of the viewport.
Definition: khtmlview.cpp:700
KHTMLView::SmoothScrollingMode
SmoothScrollingMode
Smooth Scrolling Mode enumeration.
Definition: khtmlview.h:305
KHTMLView::SSMDisabled
@ SSMDisabled
Definition: khtmlview.h:305
KHTMLView::SSMEnabled
@ SSMEnabled
Definition: khtmlview.h:305
KHTMLView::SSMWhenEfficient
@ SSMWhenEfficient
Definition: khtmlview.h:305
KHTMLView::print
void print(bool quick=false)
Prints the HTML document.
Definition: khtmlview.cpp:3027
KHTMLView::keyReleaseEvent
void keyReleaseEvent(QKeyEvent *_ke)
Definition: khtmlview.cpp:1826
KHTMLView::viewportToContents
QPoint viewportToContents(const QPoint &p) const
Returns a point translated to contents area coordinates.
Definition: khtmlview.cpp:760
KHTMLView::eventFilter
virtual bool eventFilter(QObject *, QEvent *)
Definition: khtmlview.cpp:2024
KHTMLView::smoothScrollingMode
SmoothScrollingMode smoothScrollingMode() const
Retrieve the current smooth scrolling mode.
Definition: khtmlview.cpp:1103
KHTMLView::contentsHeight
int contentsHeight() const
Returns the contents area's height.
Definition: khtmlview.cpp:676
KHTMLView::scrollBy
void scrollBy(int x, int y)
Scrolls the content area by a given amount.
Definition: khtmlview.cpp:739
KHTMLView::updateContents
void updateContents(const QRect &r)
Requests an update of the content area.
Definition: khtmlview.cpp:784
KHTMLView::doAutoScroll
void doAutoScroll()
Definition: khtmlview.cpp:1887
KHTMLView::visibleHeight
int visibleHeight() const
Returns the height of the viewport.
Definition: khtmlview.cpp:716
KHTMLView::contentsToViewport
QPoint contentsToViewport(const QPoint &p) const
Returns a point translated to viewport coordinates.
Definition: khtmlview.cpp:747
KIconLoader::Small
Small
KIconLoader::DefaultState
DefaultState
KIconLoader::loadIcon
QPixmap loadIcon(const QString &name, KIconLoader::Group group, int size=0, int state=KIconLoader::DefaultState, const QStringList &overlays=QStringList(), QString *path_store=0L, bool canReturnNull=false) const
KLocale::formatDate
QString formatDate(const QDate &date, DateFormat format=LongDate) const
KLocale::ShortDate
ShortDate
KParts::ReadOnlyPart
KParts::ReadOnlyPart::completed
void completed()
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, bool createDir, const KComponentData &cData=KGlobal::mainComponent())
QCursor
QDialog
QEvent
QHash
QLabel
QLineEdit
QList
QMap
QObject
QPair
QScrollArea
QStack
Definition: khtmlview.h:37
QTextEdit
QVector
Definition: khtmlview.h:36
QWidget
khtml::ChildFrame
Definition: khtml_childframe_p.h:41
khtml::ChildFrame::m_partContainerElement
QWeakPointer< DOM::HTMLPartContainerElementImpl > m_partContainerElement
Definition: khtml_childframe_p.h:49
khtml::DrawContentsEvent
Definition: khtml_events.h:131
khtml::KHTMLWidget
Definition: khtmlview.h:71
khtml::KHTMLWidget::m_kwp
KHTMLWidgetPrivate * m_kwp
Definition: khtmlview.h:75
khtml::MouseDoubleClickEvent
Definition: khtml_events.h:80
khtml::MouseMoveEvent
Definition: khtml_events.h:101
khtml::MousePressEvent
Definition: khtml_events.h:64
khtml::MouseReleaseEvent
Definition: khtml_events.h:116
assert
#define assert(x)
Definition: editor.cpp:43
editor.h
fixx11h.h
kDebug
#define kDebug
kWarning
#define kWarning
mask
#define mask
kconfig.h
kconfiggroup.h
kcursor.h
kdebug.h
kdeprintdialog.h
kdialog.h
kglobalsettings.h
khtml_events.h
khtml_part.h
khtml_printsettings.h
khtml_settings.h
d
#define d
Definition: khtmlfind.cpp:42
khtmlpart_p.h
sParsingLayoutsInterval
static const int sParsingLayoutsInterval
Definition: khtmlview.cpp:114
getElementText
static QString getElementText(NodeImpl *start, bool after)
Definition: khtmlview.cpp:2684
sSmoothScrollTick
static const int sSmoothScrollTick
Definition: khtmlview.cpp:125
targetOpensNewWindow
static bool targetOpensNewWindow(KHTMLPart *part, QString target)
Definition: khtmlview.cpp:1285
sWayTooMany
static const int sWayTooMany
Definition: khtmlview.cpp:129
positionOfLineBegin
static DOM::Position positionOfLineBegin(const DOM::Position &pos)
Definition: khtmlview.cpp:4242
sMaxMissedDeadlines
static const int sMaxMissedDeadlines
Definition: khtmlview.cpp:128
positionOfLineBoundary
static DOM::Position positionOfLineBoundary(const DOM::Position &pos, bool toEnd)
Definition: khtmlview.cpp:4235
handleWidget
static void handleWidget(QWidget *w, KHTMLView *view, bool recurse=true)
Definition: khtmlview.cpp:1938
positionOfLineEnd
static DOM::Position positionOfLineEnd(const DOM::Position &pos)
Definition: khtmlview.cpp:4247
sSmoothScrollMinStaticPixels
static const int sSmoothScrollMinStaticPixels
Definition: khtmlview.cpp:126
buildLabels
static QMap< NodeImpl *, QString > buildLabels(NodeImpl *start)
Definition: khtmlview.cpp:2735
sLayoutAttemptIncrement
static const int sLayoutAttemptIncrement
Definition: khtmlview.cpp:121
findImageMapRect
static bool findImageMapRect(HTMLImageElementImpl *img, const QPoint &scrollOfs, const QPoint &p, QRect &r, QString &s)
calculates the client-side image map rectangle for the given image element
Definition: khtmlview.cpp:451
sSmoothScrollTime
static const int sSmoothScrollTime
Definition: khtmlview.cpp:124
sParsingLayoutsIncrement
static const int sParsingLayoutsIncrement
Definition: khtmlview.cpp:122
setInPaintEventFlag
static void setInPaintEventFlag(QWidget *w, bool b=true, bool recurse=true)
Definition: khtmlview.cpp:2003
sFirstLayoutDelay
static const int sFirstLayoutDelay
Definition: khtmlview.cpp:113
sLayoutAttemptDelay
static const int sLayoutAttemptDelay
Definition: khtmlview.cpp:115
khtmlview.h
kiconloader.h
timeout
int timeout
klocale.h
i18n
QString i18n(const char *text)
knotification.h
kstandarddirs.h
kstandardshortcut.h
kstringhandler.h
DOM
This library provides a full-featured HTML parser and widget.
Definition: design.h:55
KGlobal::locale
KLocale * locale()
ref
void ref()
KGlobal::config
KSharedConfigPtr config()
next
KAction * next(const QObject *recvr, const char *slot, QObject *parent)
close
KAction * close(const QObject *recvr, const char *slot, QObject *parent)
reset
KGuiItem reset()
label
QString label(StandardShortcut id)
KStringHandler::csqueeze
QString csqueeze(const QString &str, int maxlen=40)
installEventFilter
void installEventFilter(QWidget *filter)
KdePrint::createPrintDialog
QPrintDialog * createPrintDialog(QPrinter *printer, const QList< QWidget * > &customTabs, QWidget *parent=0)
KdePrint::SystemSelectsPages
SystemSelectsPages
khtml
if
if(!yymsg) yymsg
khtml::EditorContext
Contextual information about the caret and the built-in editor.
Definition: editing_p.h:38
khtml::EditorContext::m_beganSelectingText
bool m_beganSelectingText
Definition: editing_p.h:52
khtml::EditorContext::m_selection
DOM::Selection m_selection
Definition: editing_p.h:44
khtml::EditorContext::m_xPosForVerticalArrowNavigation
int m_xPosForVerticalArrowNavigation
Definition: editing_p.h:59
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal