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

KHTML

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

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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