• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdehtml
 

tdehtml

  • tdehtml
tdehtmlview.cpp
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-2004 Apple Computer, Inc.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26
27#include "tdehtmlview.moc"
28
29#include "tdehtmlview.h"
30
31#include "tdehtml_part.h"
32#include "tdehtml_events.h"
33
34#include "html/html_documentimpl.h"
35#include "html/html_inlineimpl.h"
36#include "html/html_formimpl.h"
37#include "rendering/render_arena.h"
38#include "rendering/render_canvas.h"
39#include "rendering/render_frames.h"
40#include "rendering/render_replaced.h"
41#include "rendering/render_layer.h"
42#include "rendering/render_line.h"
43#include "rendering/render_table.h"
44// removeme
45#define protected public
46#include "rendering/render_text.h"
47#undef protected
48#include "xml/dom2_eventsimpl.h"
49#include "css/cssstyleselector.h"
50#include "css/csshelper.h"
51#include "misc/htmlhashes.h"
52#include "misc/helper.h"
53#include "misc/loader.h"
54#include "tdehtml_settings.h"
55#include "tdehtml_printsettings.h"
56
57#include "tdehtmlpart_p.h"
58
59#ifndef TDEHTML_NO_CARET
60#include "tdehtml_caret_p.h"
61#include "xml/dom2_rangeimpl.h"
62#endif
63
64#include <tdeapplication.h>
65#include <kcursor.h>
66#include <kdebug.h>
67#include <kdialogbase.h>
68#include <kiconloader.h>
69#include <kimageio.h>
70#include <tdelocale.h>
71#include <knotifyclient.h>
72#include <kprinter.h>
73#include <ksimpleconfig.h>
74#include <tdestandarddirs.h>
75#include <tdestdaccel.h>
76#include <kstringhandler.h>
77#include <kurldrag.h>
78
79#include <tqbitmap.h>
80#include <tqlabel.h>
81#include <tqobjectlist.h>
82#include <tqpaintdevicemetrics.h>
83#include <tqpainter.h>
84#include <tqptrdict.h>
85#include <tqtooltip.h>
86#include <tqstring.h>
87#include <tqstylesheet.h>
88#include <tqtimer.h>
89#include <tqvaluevector.h>
90
91//#define DEBUG_NO_PAINT_BUFFER
92
93//#define DEBUG_FLICKER
94
95//#define DEBUG_PIXEL
96
97#ifdef TQ_WS_X11
98#include <X11/Xlib.h>
99#include <fixx11h.h>
100#endif
101
102#define PAINT_BUFFER_HEIGHT 128
103
104#if 0
105namespace tdehtml {
106 void dumpLineBoxes(RenderFlow *flow);
107}
108#endif
109
110using namespace DOM;
111using namespace tdehtml;
112class TDEHTMLToolTip;
113
114
115#ifndef TQT_NO_TOOLTIP
116
117class TDEHTMLToolTip : public TQToolTip
118{
119public:
120 TDEHTMLToolTip(TDEHTMLView *view, TDEHTMLViewPrivate* vp) : TQToolTip(view->viewport())
121 {
122 m_view = view;
123 m_viewprivate = vp;
124 };
125
126protected:
127 virtual void maybeTip(const TQPoint &);
128
129private:
130 TDEHTMLView *m_view;
131 TDEHTMLViewPrivate* m_viewprivate;
132};
133
134#endif
135
136class TDEHTMLViewPrivate {
137 friend class TDEHTMLToolTip;
138public:
139
140 enum PseudoFocusNodes {
141 PFNone,
142 PFTop,
143 PFBottom
144 };
145
146 enum CompletedState {
147 CSNone = 0,
148 CSFull,
149 CSActionPending
150 };
151
152 TDEHTMLViewPrivate()
153 : underMouse( 0 ), underMouseNonShared( 0 ), visibleWidgets( 107 )
154#ifndef NO_SMOOTH_SCROLL_HACK
155 , dx(0), dy(0), ddx(0), ddy(0), rdx(0), rdy(0), scrolling(false)
156#endif
157 {
158#ifndef TDEHTML_NO_CARET
159 m_caretViewContext = 0;
160 m_editorContext = 0;
161#endif // TDEHTML_NO_CARET
162 postponed_autorepeat = NULL;
163 reset();
164 vmode = TQScrollView::Auto;
165 hmode = TQScrollView::Auto;
166 tp=0;
167 paintBuffer=0;
168 vertPaintBuffer=0;
169 formCompletions=0;
170 prevScrollbarVisible = true;
171 tooltip = 0;
172 possibleTripleClick = false;
173 emitCompletedAfterRepaint = CSNone;
174 cursor_icon_widget = NULL;
175 m_mouseScrollTimer = 0;
176 m_mouseScrollIndicator = 0;
177 }
178 ~TDEHTMLViewPrivate()
179 {
180 delete formCompletions;
181 delete tp; tp = 0;
182 delete paintBuffer; paintBuffer =0;
183 delete vertPaintBuffer;
184 delete postponed_autorepeat;
185 if (underMouse)
186 underMouse->deref();
187 if (underMouseNonShared)
188 underMouseNonShared->deref();
189 delete tooltip;
190#ifndef TDEHTML_NO_CARET
191 delete m_caretViewContext;
192 delete m_editorContext;
193#endif // TDEHTML_NO_CARET
194 delete cursor_icon_widget;
195 delete m_mouseScrollTimer;
196 delete m_mouseScrollIndicator;
197 }
198 void reset()
199 {
200 if (underMouse)
201 underMouse->deref();
202 underMouse = 0;
203 if (underMouseNonShared)
204 underMouseNonShared->deref();
205 underMouseNonShared = 0;
206 linkPressed = false;
207 useSlowRepaints = false;
208 tabMovePending = false;
209 lastTabbingDirection = true;
210 pseudoFocusNode = PFNone;
211#ifndef TDEHTML_NO_SCROLLBARS
212 //We don't turn off the toolbars here
213 //since if the user turns them
214 //off, then chances are they want them turned
215 //off always - even after a reset.
216#else
217 vmode = TQScrollView::AlwaysOff;
218 hmode = TQScrollView::AlwaysOff;
219#endif
220#ifdef DEBUG_PIXEL
221 timer.start();
222 pixelbooth = 0;
223 repaintbooth = 0;
224#endif
225 scrollBarMoved = false;
226 contentsMoving = false;
227 ignoreWheelEvents = false;
228 borderX = 30;
229 borderY = 30;
230 paged = false;
231 clickX = -1;
232 clickY = -1;
233 prevMouseX = -1;
234 prevMouseY = -1;
235 clickCount = 0;
236 isDoubleClick = false;
237 scrollingSelf = false;
238 delete postponed_autorepeat;
239 postponed_autorepeat = NULL;
240 layoutTimerId = 0;
241 repaintTimerId = 0;
242 scrollTimerId = 0;
243 scrollSuspended = false;
244 scrollSuspendPreActivate = false;
245 complete = false;
246 firstRelayout = true;
247 needsFullRepaint = true;
248 dirtyLayout = false;
249 layoutSchedulingEnabled = true;
250 painting = false;
251 updateRegion = TQRegion();
252 m_dialogsAllowed = true;
253#ifndef TDEHTML_NO_CARET
254 if (m_caretViewContext) {
255 m_caretViewContext->caretMoved = false;
256 m_caretViewContext->keyReleasePending = false;
257 }/*end if*/
258#endif // TDEHTML_NO_CARET
259#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
260 typeAheadActivated = false;
261#endif // TDEHTML_NO_TYPE_AHEAD_FIND
262 accessKeysActivated = false;
263 accessKeysPreActivate = false;
264
265 // We ref/deref to ensure defaultHTMLSettings is available
266 TDEHTMLFactory::ref();
267 accessKeysEnabled = TDEHTMLFactory::defaultHTMLSettings()->accessKeysEnabled();
268 TDEHTMLFactory::deref();
269
270 emitCompletedAfterRepaint = CSNone;
271 }
272 void newScrollTimer(TQWidget *view, int tid)
273 {
274 //kdDebug(6000) << "newScrollTimer timer " << tid << endl;
275 view->killTimer(scrollTimerId);
276 scrollTimerId = tid;
277 scrollSuspended = false;
278 }
279 enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
280
281 void adjustScroller(TQWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
282 {
283 static const struct { int msec, pixels; } timings [] = {
284 {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
285 {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
286 };
287 if (!scrollTimerId ||
288 (static_cast<int>(scrollDirection) != direction &&
289 (static_cast<int>(scrollDirection) != oppositedir || scrollSuspended))) {
290 scrollTiming = 6;
291 scrollBy = timings[scrollTiming].pixels;
292 scrollDirection = direction;
293 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
294 } else if (scrollDirection == direction &&
295 timings[scrollTiming+1].msec && !scrollSuspended) {
296 scrollBy = timings[++scrollTiming].pixels;
297 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
298 } else if (scrollDirection == oppositedir) {
299 if (scrollTiming) {
300 scrollBy = timings[--scrollTiming].pixels;
301 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
302 }
303 }
304 scrollSuspended = false;
305 }
306
307#ifndef TDEHTML_NO_CARET
311 CaretViewContext *caretViewContext() {
312 if (!m_caretViewContext) m_caretViewContext = new CaretViewContext();
313 return m_caretViewContext;
314 }
318 EditorContext *editorContext() {
319 if (!m_editorContext) m_editorContext = new EditorContext();
320 return m_editorContext;
321 }
322#endif // TDEHTML_NO_CARET
323
324#ifdef DEBUG_PIXEL
325 TQTime timer;
326 unsigned int pixelbooth;
327 unsigned int repaintbooth;
328#endif
329
330 TQPainter *tp;
331 TQPixmap *paintBuffer;
332 TQPixmap *vertPaintBuffer;
333 NodeImpl *underMouse;
334 NodeImpl *underMouseNonShared;
335
336 bool tabMovePending:1;
337 bool lastTabbingDirection:1;
338 PseudoFocusNodes pseudoFocusNode:2;
339 bool scrollBarMoved:1;
340 bool contentsMoving:1;
341
342 TQScrollView::ScrollBarMode vmode;
343 TQScrollView::ScrollBarMode hmode;
344 bool prevScrollbarVisible:1;
345 bool linkPressed:1;
346 bool useSlowRepaints:1;
347 bool ignoreWheelEvents:1;
348
349 int borderX, borderY;
350 KSimpleConfig *formCompletions;
351
352 bool paged;
353
354 int clickX, clickY, clickCount;
355 bool isDoubleClick;
356
357 int prevMouseX, prevMouseY;
358 bool scrollingSelf;
359 int layoutTimerId;
360 TQKeyEvent* postponed_autorepeat;
361
362 int repaintTimerId;
363 int scrollTimerId;
364 int scrollTiming;
365 int scrollBy;
366 ScrollDirection scrollDirection :2;
367 bool scrollSuspended :1;
368 bool scrollSuspendPreActivate :1;
369 bool complete :1;
370 bool firstRelayout :1;
371 bool layoutSchedulingEnabled :1;
372 bool needsFullRepaint :1;
373 bool painting :1;
374 bool possibleTripleClick :1;
375 bool dirtyLayout :1;
376 bool m_dialogsAllowed :1;
377 TQRegion updateRegion;
378 TDEHTMLToolTip *tooltip;
379 TQPtrDict<TQWidget> visibleWidgets;
380#ifndef TDEHTML_NO_CARET
381 CaretViewContext *m_caretViewContext;
382 EditorContext *m_editorContext;
383#endif // TDEHTML_NO_CARET
384#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
385 TQString findString;
386 TQTimer timer;
387 bool findLinksOnly;
388 bool typeAheadActivated;
389#endif // TDEHTML_NO_TYPE_AHEAD_FIND
390 bool accessKeysEnabled;
391 bool accessKeysActivated;
392 bool accessKeysPreActivate;
393 CompletedState emitCompletedAfterRepaint;
394
395 TQWidget* cursor_icon_widget;
396
397 // scrolling activated by MMB
398 short m_mouseScroll_byX;
399 short m_mouseScroll_byY;
400 TQTimer *m_mouseScrollTimer;
401 TQWidget *m_mouseScrollIndicator;
402#ifndef NO_SMOOTH_SCROLL_HACK
403 TQTimer timer2;
404 int dx;
405 int dy;
406 // Step size * 16 and residual to avoid huge difference between 1px/step and 2px/step
407 int ddx;
408 int ddy;
409 int rdx;
410 int rdy;
411 bool scrolling;
412#endif
413};
414
415#ifndef TQT_NO_TOOLTIP
416
426static bool findImageMapRect(HTMLImageElementImpl *img, const TQPoint &scrollOfs,
427 const TQPoint &p, TQRect &r, TQString &s)
428{
429 HTMLMapElementImpl* map;
430 if (img && img->getDocument()->isHTMLDocument() &&
431 (map = static_cast<HTMLDocumentImpl*>(img->getDocument())->getMap(img->imageMap()))) {
432 RenderObject::NodeInfo info(true, false);
433 RenderObject *rend = img->renderer();
434 int ax, ay;
435 if (!rend || !rend->absolutePosition(ax, ay))
436 return false;
437 // we're a client side image map
438 bool inside = map->mapMouseEvent(p.x() - ax + scrollOfs.x(),
439 p.y() - ay + scrollOfs.y(), rend->contentWidth(),
440 rend->contentHeight(), info);
441 if (inside && info.URLElement()) {
442 HTMLAreaElementImpl *area = static_cast<HTMLAreaElementImpl *>(info.URLElement());
443 Q_ASSERT(area->id() == ID_AREA);
444 s = area->getAttribute(ATTR_TITLE).string();
445 TQRegion reg = area->cachedRegion();
446 if (!s.isEmpty() && !reg.isEmpty()) {
447 r = reg.boundingRect();
448 r.moveBy(ax, ay);
449 return true;
450 }
451 }
452 }
453 return false;
454}
455
456void TDEHTMLToolTip::maybeTip(const TQPoint& p)
457{
458 DOM::NodeImpl *node = m_viewprivate->underMouseNonShared;
459 TQRect region;
460 while ( node ) {
461 if ( node->isElementNode() ) {
462 DOM::ElementImpl *e = static_cast<DOM::ElementImpl*>( node );
463 TQRect r;
464 TQString s;
465 bool found = false;
466 // for images, check if it is part of a client-side image map,
467 // and query the <area>s' title attributes, too
468 if (e->id() == ID_IMG && !e->getAttribute( ATTR_USEMAP ).isEmpty()) {
469 found = findImageMapRect(static_cast<HTMLImageElementImpl *>(e),
470 m_view->viewportToContents(TQPoint(0, 0)), p, r, s);
471 }
472 if (!found) {
473 s = e->getAttribute( ATTR_TITLE ).string();
474 r = node->getRect();
475 }
476 region |= TQRect( m_view->contentsToViewport( r.topLeft() ), r.size() );
477 if ( !s.isEmpty() ) {
478 tip( region, TQStyleSheet::convertFromPlainText( s, TQStyleSheetItem::WhiteSpaceNormal ) );
479 break;
480 }
481 }
482 node = node->parentNode();
483 }
484}
485#endif
486
487TDEHTMLView::TDEHTMLView( TDEHTMLPart *part, TQWidget *parent, const char *name)
488 : TQScrollView( parent, name, (WFlags)(WResizeNoErase | WRepaintNoErase) )
489{
490 m_medium = "screen";
491
492 m_part = part;
493 d = new TDEHTMLViewPrivate;
494 TQScrollView::setVScrollBarMode(d->vmode);
495 TQScrollView::setHScrollBarMode(d->hmode);
496 connect(tdeApp, TQ_SIGNAL(tdedisplayPaletteChanged()), this, TQ_SLOT(slotPaletteChanged()));
497 connect(this, TQ_SIGNAL(contentsMoving(int, int)), this, TQ_SLOT(slotScrollBarMoved()));
498
499 // initialize QScrollView
500 enableClipper(true);
501 // hack to get unclipped painting on the viewport.
502 static_cast<TDEHTMLView *>(viewport())->setWFlags(WPaintUnclipped);
503
504 setResizePolicy(Manual);
505 viewport()->setMouseTracking(true);
506 viewport()->setBackgroundMode(NoBackground);
507
508 KImageIO::registerFormats();
509
510#ifndef TQT_NO_TOOLTIP
511 d->tooltip = new TDEHTMLToolTip( this, d );
512#endif
513
514#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
515 connect(&d->timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(findTimeout()));
516#endif // TDEHTML_NO_TYPE_AHEAD_FIND
517
518 init();
519
520 viewport()->show();
521#ifndef NO_SMOOTH_SCROLL_HACK
522#define timer timer2
523 connect(&d->timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(scrollTick()));
524#undef timer
525#endif
526}
527
528TDEHTMLView::~TDEHTMLView()
529{
530 closeChildDialogs();
531 if (m_part)
532 {
533 //WABA: Is this Ok? Do I need to deref it as well?
534 //Does this need to be done somewhere else?
535 DOM::DocumentImpl *doc = m_part->xmlDocImpl();
536 if (doc)
537 doc->detach();
538 }
539 delete d; d = 0;
540}
541
542void TDEHTMLView::init()
543{
544 if(!d->paintBuffer) d->paintBuffer = new TQPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
545 if(!d->vertPaintBuffer)
546 d->vertPaintBuffer = new TQPixmap(10, PAINT_BUFFER_HEIGHT);
547 if(!d->tp) d->tp = new TQPainter();
548
549 setFocusPolicy(TQWidget::StrongFocus);
550 viewport()->setFocusProxy(this);
551
552 _marginWidth = -1; // undefined
553 _marginHeight = -1;
554 _width = 0;
555 _height = 0;
556
557 installEventFilter(this);
558
559 setAcceptDrops(true);
560 TQSize s = viewportSize(4095, 4095);
561 resizeContents(s.width(), s.height());
562}
563
564void TDEHTMLView::clear()
565{
566 // work around QScrollview's unbelievable bugginess
567 setStaticBackground(true);
568#ifndef TDEHTML_NO_CARET
569 if (!m_part->isCaretMode() && !m_part->isEditable()) caretOff();
570#endif
571
572#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
573 if( d->typeAheadActivated )
574 findTimeout();
575#endif
576 if (d->accessKeysEnabled && d->accessKeysActivated)
577 accessKeysTimeout();
578 viewport()->unsetCursor();
579 if ( d->cursor_icon_widget )
580 d->cursor_icon_widget->hide();
581 d->reset();
582 this->killTimers();
583 emit cleared();
584
585 TQScrollView::setHScrollBarMode(d->hmode);
586 TQScrollView::setVScrollBarMode(d->vmode);
587 verticalScrollBar()->setEnabled( false );
588 horizontalScrollBar()->setEnabled( false );
589}
590
591void TDEHTMLView::hideEvent(TQHideEvent* e)
592{
593 TQScrollView::hideEvent(e);
594 if ( m_part && m_part->xmlDocImpl() )
595 m_part->xmlDocImpl()->docLoader()->pauseAnimations();
596}
597
598void TDEHTMLView::showEvent(TQShowEvent* e)
599{
600 TQScrollView::showEvent(e);
601 if ( m_part && m_part->xmlDocImpl() )
602 m_part->xmlDocImpl()->docLoader()->resumeAnimations();
603}
604
605void TDEHTMLView::resizeEvent (TQResizeEvent* e)
606{
607 int dw = e->oldSize().width() - e->size().width();
608 int dh = e->oldSize().height() - e->size().height();
609
610 // if we are shrinking the view, don't allow the content to overflow
611 // before the layout occurs - we don't know if we need scrollbars yet
612 dw = dw>0 ? kMax(0, contentsWidth()-dw) : contentsWidth();
613 dh = dh>0 ? kMax(0, contentsHeight()-dh) : contentsHeight();
614
615 resizeContents(dw, dh);
616
617 TQScrollView::resizeEvent(e);
618
619 if ( m_part && m_part->xmlDocImpl() )
620 m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
621}
622
623void TDEHTMLView::viewportResizeEvent (TQResizeEvent* e)
624{
625 TQScrollView::viewportResizeEvent(e);
626
627 //int w = visibleWidth();
628 //int h = visibleHeight();
629
630 if (d->layoutSchedulingEnabled)
631 layout();
632#ifndef TDEHTML_NO_CARET
633 else {
634 hideCaret();
635 recalcAndStoreCaretPos();
636 showCaret();
637 }/*end if*/
638#endif
639
640 TDEApplication::sendPostedEvents(viewport(), TQEvent::Paint);
641}
642
643// this is to get rid of a compiler virtual overload mismatch warning. do not remove
644void TDEHTMLView::drawContents( TQPainter*)
645{
646}
647
648void TDEHTMLView::drawContents( TQPainter *p, int ex, int ey, int ew, int eh )
649{
650#ifdef DEBUG_PIXEL
651
652 if ( d->timer.elapsed() > 5000 ) {
653 tqDebug( "drawed %d pixels in %d repaints the last %d milliseconds",
654 d->pixelbooth, d->repaintbooth, d->timer.elapsed() );
655 d->timer.restart();
656 d->pixelbooth = 0;
657 d->repaintbooth = 0;
658 }
659 d->pixelbooth += ew*eh;
660 d->repaintbooth++;
661#endif
662
663 //kdDebug( 6000 ) << "drawContents this="<< this <<" x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl;
664 if(!m_part || !m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
665 p->fillRect(ex, ey, ew, eh, palette().active().brush(TQColorGroup::Base));
666 return;
667 } else if ( d->complete && static_cast<RenderCanvas*>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
668 // an external update request happens while we have a layout scheduled
669 unscheduleRelayout();
670 layout();
671 }
672
673 if (d->painting) {
674 kdDebug( 6000 ) << "WARNING: drawContents reentered! " << endl;
675 return;
676 }
677 d->painting = true;
678
679 TQPoint pt = contentsToViewport(TQPoint(ex, ey));
680 TQRegion cr = TQRect(pt.x(), pt.y(), ew, eh);
681
682 // kdDebug(6000) << "clip rect: " << TQRect(pt.x(), pt.y(), ew, eh) << endl;
683 for (TQPtrDictIterator<TQWidget> it(d->visibleWidgets); it.current(); ++it) {
684 TQWidget *w = it.current();
685 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
686 if (w && rw && !rw->isTDEHTMLWidget()) {
687 int x, y;
688 rw->absolutePosition(x, y);
689 contentsToViewport(x, y, x, y);
690 int pbx = rw->borderLeft()+rw->paddingLeft();
691 int pby = rw->borderTop()+rw->paddingTop();
692 TQRect g = TQRect(x+pbx, y+pby,
693 rw->width()-pbx-rw->borderRight()-rw->paddingRight(),
694 rw->height()-pby-rw->borderBottom()-rw->paddingBottom());
695 if ( !rw->isFrame() && ((g.top() > pt.y()+eh) || (g.bottom() <= pt.y()) ||
696 (g.right() <= pt.x()) || (g.left() > pt.x()+ew) ))
697 continue;
698 RenderLayer* rl = rw->needsMask() ? rw->enclosingStackingContext() : 0;
699 TQRegion mask = rl ? rl->getMask() : TQRegion();
700 if (!mask.isNull()) {
701 TQPoint o(0,0);
702 o = contentsToViewport(o);
703 mask.translate(o.x(),o.y());
704 mask = mask.intersect( TQRect(g.x(),g.y(),g.width(),g.height()) );
705 cr -= mask;
706 } else {
707 cr -= g;
708 }
709 }
710 }
711
712#if 0
713 // this is commonly the case with framesets. we still do
714 // want to paint them, otherwise the widgets don't get placed.
715 if (cr.isEmpty()) {
716 d->painting = false;
717 return;
718 }
719#endif
720
721#ifndef DEBUG_NO_PAINT_BUFFER
722 p->setClipRegion(cr);
723
724 if (eh > PAINT_BUFFER_HEIGHT && ew <= 10) {
725 if ( d->vertPaintBuffer->height() < visibleHeight() )
726 d->vertPaintBuffer->resize(10, visibleHeight());
727 d->tp->begin(d->vertPaintBuffer);
728 d->tp->translate(-ex, -ey);
729 d->tp->fillRect(ex, ey, ew, eh, palette().active().brush(TQColorGroup::Base));
730 m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, TQRect(ex, ey, ew, eh));
731 d->tp->end();
732 p->drawPixmap(ex, ey, *d->vertPaintBuffer, 0, 0, ew, eh);
733 }
734 else {
735 if ( d->paintBuffer->width() < visibleWidth() )
736 d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
737
738 int py=0;
739 while (py < eh) {
740 int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
741 d->tp->begin(d->paintBuffer);
742 d->tp->translate(-ex, -ey-py);
743 d->tp->fillRect(ex, ey+py, ew, ph, palette().active().brush(TQColorGroup::Base));
744 m_part->xmlDocImpl()->renderer()->layer()->paint(d->tp, TQRect(ex, ey+py, ew, ph));
745 d->tp->end();
746
747 p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
748 py += PAINT_BUFFER_HEIGHT;
749 }
750 }
751#else // !DEBUG_NO_PAINT_BUFFER
752static int cnt=0;
753 ex = contentsX(); ey = contentsY();
754 ew = visibleWidth(); eh = visibleHeight();
755 TQRect pr(ex,ey,ew,eh);
756 kdDebug() << "[" << ++cnt << "]" << " clip region: " << pr << endl;
757// p->setClipRegion(TQRect(0,0,ew,eh));
758// p->translate(-ex, -ey);
759 p->fillRect(ex, ey, ew, eh, palette().active().brush(TQColorGroup::Base));
760 m_part->xmlDocImpl()->renderer()->layer()->paint(p, pr);
761#endif // DEBUG_NO_PAINT_BUFFER
762
763#ifndef TDEHTML_NO_CARET
764 if (d->m_caretViewContext && d->m_caretViewContext->visible) {
765 TQRect pos(d->m_caretViewContext->x, d->m_caretViewContext->y,
766 d->m_caretViewContext->width, d->m_caretViewContext->height);
767 if (pos.intersects(TQRect(ex, ey, ew, eh))) {
768 p->setRasterOp(XorROP);
769 p->setPen(white);
770 if (pos.width() == 1)
771 p->drawLine(pos.topLeft(), pos.bottomRight());
772 else {
773 p->fillRect(pos, white);
774 }/*end if*/
775 }/*end if*/
776 }/*end if*/
777#endif // TDEHTML_NO_CARET
778
779// p->setPen(TQPen(magenta,0,DashDotDotLine));
780// p->drawRect(dbg_paint_rect);
781
782 tdehtml::DrawContentsEvent event( p, ex, ey, ew, eh );
783 TQApplication::sendEvent( m_part, &event );
784
785 d->painting = false;
786}
787
788void TDEHTMLView::setMarginWidth(int w)
789{
790 // make it update the rendering area when set
791 _marginWidth = w;
792}
793
794void TDEHTMLView::setMarginHeight(int h)
795{
796 // make it update the rendering area when set
797 _marginHeight = h;
798}
799
800void TDEHTMLView::layout()
801{
802 if( m_part && m_part->xmlDocImpl() ) {
803 DOM::DocumentImpl *document = m_part->xmlDocImpl();
804
805 tdehtml::RenderCanvas* canvas = static_cast<tdehtml::RenderCanvas *>(document->renderer());
806 if ( !canvas ) return;
807
808 d->layoutSchedulingEnabled=false;
809
810 // the reference object for the overflow property on canvas
811 RenderObject * ref = 0;
812 RenderObject* root = document->documentElement() ? document->documentElement()->renderer() : 0;
813
814 if (document->isHTMLDocument()) {
815 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
816 if(body && body->renderer() && body->id() == ID_FRAMESET) {
817 TQScrollView::setVScrollBarMode(AlwaysOff);
818 TQScrollView::setHScrollBarMode(AlwaysOff);
819 body->renderer()->setNeedsLayout(true);
820// if (d->tooltip) {
821// delete d->tooltip;
822// d->tooltip = 0;
823// }
824 }
825 else {
826 if (!d->tooltip)
827 d->tooltip = new TDEHTMLToolTip( this, d );
828 // only apply body's overflow to canvas if root as a visible overflow
829 if (root)
830 ref = (!body || root->style()->hidesOverflow()) ? root : body->renderer();
831 }
832 } else {
833 ref = root;
834 }
835 if (ref) {
836 if( ref->style()->overflowX() == OHIDDEN ) {
837 if (d->hmode == Auto) TQScrollView::setHScrollBarMode(AlwaysOff);
838 } else if (ref->style()->overflowX() == OSCROLL ) {
839 if (d->hmode == Auto) TQScrollView::setHScrollBarMode(AlwaysOn);
840 } else {
841 if (TQScrollView::hScrollBarMode() == AlwaysOff) TQScrollView::setHScrollBarMode(d->hmode);
842 } if ( ref->style()->overflowY() == OHIDDEN ) {
843 if (d->vmode == Auto) TQScrollView::setVScrollBarMode(AlwaysOff);
844 } else if (ref->style()->overflowY() == OSCROLL ) {
845 if (d->vmode == Auto) TQScrollView::setVScrollBarMode(AlwaysOn);
846 } else {
847 if (TQScrollView::vScrollBarMode() == AlwaysOff) TQScrollView::setVScrollBarMode(d->vmode);
848 }
849 }
850 d->needsFullRepaint = d->firstRelayout;
851 if (_height != visibleHeight() || _width != visibleWidth()) {;
852 d->needsFullRepaint = true;
853 _height = visibleHeight();
854 _width = visibleWidth();
855 }
856 //TQTime qt;
857 //qt.start();
858 canvas->layout();
859
860 emit finishedLayout();
861 if (d->firstRelayout) {
862 // make sure firstRelayout is set to false now in case this layout
863 // wasn't scheduled
864 d->firstRelayout = false;
865 verticalScrollBar()->setEnabled( true );
866 horizontalScrollBar()->setEnabled( true );
867 }
868#if 0
869 ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
870 if (listitem) kdDebug(6000) << "after layout, before repaint" << endl;
871 if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
872#endif
873#ifndef TDEHTML_NO_CARET
874 hideCaret();
875 if ((m_part->isCaretMode() || m_part->isEditable())
876 && !d->complete && d->m_caretViewContext
877 && !d->m_caretViewContext->caretMoved) {
878 initCaret();
879 } else {
880 recalcAndStoreCaretPos();
881 showCaret();
882 }/*end if*/
883#endif
884 if (d->accessKeysEnabled && d->accessKeysActivated) {
885 emit hideAccessKeys();
886 displayAccessKeys();
887 }
888 //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
889 }
890 else
891 _width = visibleWidth();
892
893 killTimer(d->layoutTimerId);
894 d->layoutTimerId = 0;
895 d->layoutSchedulingEnabled=true;
896}
897
898void TDEHTMLView::closeChildDialogs()
899{
900 TQObjectList *dlgs = queryList("TQDialog");
901 for (TQObject *dlg = dlgs->first(); dlg; dlg = dlgs->next())
902 {
903 KDialogBase* dlgbase = dynamic_cast<KDialogBase *>( dlg );
904 if ( dlgbase ) {
905 if ( dlgbase->testWFlags( WShowModal ) ) {
906 kdDebug(6000) << "closeChildDialogs: closing dialog " << dlgbase << endl;
907 // close() ends up calling TQButton::animateClick, which isn't immediate
908 // we need something the exits the event loop immediately (#49068)
909 dlgbase->cancel();
910 }
911 }
912 else
913 {
914 kdWarning() << "closeChildDialogs: not a KDialogBase! Don't use QDialogs in KDE! " << static_cast<TQWidget*>(dlg) << endl;
915 static_cast<TQWidget*>(dlg)->hide();
916 }
917 }
918 delete dlgs;
919 d->m_dialogsAllowed = false;
920}
921
922bool TDEHTMLView::dialogsAllowed() {
923 bool allowed = d->m_dialogsAllowed;
924 TDEHTMLPart* p = m_part->parentPart();
925 if (p && p->view())
926 allowed &= p->view()->dialogsAllowed();
927 return allowed;
928}
929
930void TDEHTMLView::closeEvent( TQCloseEvent* ev )
931{
932 closeChildDialogs();
933 TQScrollView::closeEvent( ev );
934}
935
936//
937// Event Handling
938//
940
941void TDEHTMLView::viewportMousePressEvent( TQMouseEvent *_mouse )
942{
943 if (!m_part->xmlDocImpl()) return;
944 if (d->possibleTripleClick && ( _mouse->button() & TQt::MouseButtonMask ) == TQt::LeftButton)
945 {
946 viewportMouseDoubleClickEvent( _mouse ); // it handles triple clicks too
947 return;
948 }
949
950 int xm, ym;
951 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
952 //kdDebug( 6000 ) << "mousePressEvent: viewport=("<<_mouse->x()<<"/"<<_mouse->y()<<"), contents=(" << xm << "/" << ym << ")\n";
953
954 d->isDoubleClick = false;
955
956 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
957 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
958
959 //kdDebug(6000) << "innerNode="<<mev.innerNode.nodeName().string()<<endl;
960
961 if ( (_mouse->button() == TQt::MidButton) &&
962 !m_part->d->m_bOpenMiddleClick && !d->m_mouseScrollTimer &&
963 mev.url.isNull() && (mev.innerNode.elementId() != ID_INPUT) ) {
964 TQPoint point = mapFromGlobal( _mouse->globalPos() );
965
966 d->m_mouseScroll_byX = 0;
967 d->m_mouseScroll_byY = 0;
968
969 d->m_mouseScrollTimer = new TQTimer( this );
970 connect( d->m_mouseScrollTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotMouseScrollTimer()) );
971
972 if ( !d->m_mouseScrollIndicator ) {
973 TQPixmap pixmap, icon;
974 pixmap.resize( 48, 48 );
975 pixmap.fill( TQColor( tqRgba( 127, 127, 127, 127 ) ) );
976
977 TQPainter p( &pixmap );
978 icon = TDEGlobal::iconLoader()->loadIcon( "1uparrow", TDEIcon::Small );
979 p.drawPixmap( 16, 0, icon );
980 icon = TDEGlobal::iconLoader()->loadIcon( "1leftarrow", TDEIcon::Small );
981 p.drawPixmap( 0, 16, icon );
982 icon = TDEGlobal::iconLoader()->loadIcon( "1downarrow", TDEIcon::Small );
983 p.drawPixmap( 16, 32,icon );
984 icon = TDEGlobal::iconLoader()->loadIcon( "1rightarrow", TDEIcon::Small );
985 p.drawPixmap( 32, 16, icon );
986 p.drawEllipse( 23, 23, 2, 2 );
987
988 d->m_mouseScrollIndicator = new TQWidget( this, 0 );
989 d->m_mouseScrollIndicator->setFixedSize( 48, 48 );
990 d->m_mouseScrollIndicator->setPaletteBackgroundPixmap( pixmap );
991 }
992 d->m_mouseScrollIndicator->move( point.x()-24, point.y()-24 );
993
994 bool hasHorBar = visibleWidth() < contentsWidth();
995 bool hasVerBar = visibleHeight() < contentsHeight();
996
997 TDEConfig *config = TDEGlobal::config();
998 TDEConfigGroupSaver saver( config, "HTML Settings" );
999 if ( config->readBoolEntry( "ShowMouseScrollIndicator", true ) ) {
1000 d->m_mouseScrollIndicator->show();
1001 d->m_mouseScrollIndicator->unsetCursor();
1002
1003 TQBitmap mask = d->m_mouseScrollIndicator->paletteBackgroundPixmap()->createHeuristicMask( true );
1004
1005 if ( hasHorBar && !hasVerBar ) {
1006 TQBitmap bm( 16, 16, true );
1007 bitBlt( &mask, 16, 0, &bm, 0, 0, -1, -1 );
1008 bitBlt( &mask, 16, 32, &bm, 0, 0, -1, -1 );
1009 d->m_mouseScrollIndicator->setCursor( KCursor::SizeHorCursor );
1010 }
1011 else if ( !hasHorBar && hasVerBar ) {
1012 TQBitmap bm( 16, 16, true );
1013 bitBlt( &mask, 0, 16, &bm, 0, 0, -1, -1 );
1014 bitBlt( &mask, 32, 16, &bm, 0, 0, -1, -1 );
1015 d->m_mouseScrollIndicator->setCursor( KCursor::SizeVerCursor );
1016 }
1017 else
1018 d->m_mouseScrollIndicator->setCursor( KCursor::SizeAllCursor );
1019
1020 d->m_mouseScrollIndicator->setMask( mask );
1021 }
1022 else {
1023 if ( hasHorBar && !hasVerBar )
1024 viewport()->setCursor( KCursor::SizeHorCursor );
1025 else if ( !hasHorBar && hasVerBar )
1026 viewport()->setCursor( KCursor::SizeVerCursor );
1027 else
1028 viewport()->setCursor( KCursor::SizeAllCursor );
1029 }
1030
1031 return;
1032 }
1033 else if ( d->m_mouseScrollTimer ) {
1034 delete d->m_mouseScrollTimer;
1035 d->m_mouseScrollTimer = 0;
1036
1037 if ( d->m_mouseScrollIndicator )
1038 d->m_mouseScrollIndicator->hide();
1039 }
1040
1041 d->clickCount = 1;
1042 d->clickX = xm;
1043 d->clickY = ym;
1044
1045 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1046 d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
1047
1048 tdehtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
1049 if (r && r->isWidget())
1050 _mouse->ignore();
1051
1052 if (!swallowEvent) {
1053 emit m_part->nodeActivated(mev.innerNode);
1054
1055 tdehtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1056 TQApplication::sendEvent( m_part, &event );
1057 // we might be deleted after this
1058 }
1059}
1060
1061void TDEHTMLView::viewportMouseDoubleClickEvent( TQMouseEvent *_mouse )
1062{
1063 if(!m_part->xmlDocImpl()) return;
1064
1065 int xm, ym;
1066 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
1067
1068 kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
1069
1070 d->isDoubleClick = true;
1071
1072 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
1073 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1074
1075 // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat
1076 // single and double-click events as separate (only the detail, i.e. number of clicks differs)
1077 if (d->clickCount > 0 &&
1078 TQPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= TQApplication::startDragDistance())
1079 d->clickCount++;
1080 else { // shouldn't happen, if Qt has the same criterias for double clicks.
1081 d->clickCount = 1;
1082 d->clickX = xm;
1083 d->clickY = ym;
1084 }
1085 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1086 d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
1087
1088 tdehtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
1089 if (r && r->isWidget())
1090 _mouse->ignore();
1091
1092 if (!swallowEvent) {
1093 tdehtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
1094 TQApplication::sendEvent( m_part, &event );
1095 }
1096
1097 d->possibleTripleClick=true;
1098 TQTimer::singleShot(TQApplication::doubleClickInterval(),this,TQ_SLOT(tripleClickTimeout()));
1099}
1100
1101void TDEHTMLView::tripleClickTimeout()
1102{
1103 d->possibleTripleClick = false;
1104 d->clickCount = 0;
1105}
1106
1107static inline void forwardPeripheralEvent(tdehtml::RenderWidget* r, TQMouseEvent* me, int x, int y)
1108{
1109 int absx = 0;
1110 int absy = 0;
1111 r->absolutePosition(absx, absy);
1112 TQPoint p(x-absx, y-absy);
1113 TQMouseEvent fw(me->type(), p, me->button(), me->state());
1114 TQWidget* w = r->widget();
1115 TQScrollView* sc = ::tqt_cast<TQScrollView*>(w);
1116 if (sc && !::tqt_cast<TQListBox*>(w))
1117 static_cast<tdehtml::RenderWidget::ScrollViewEventPropagator*>(sc)->sendEvent(static_cast<TQEvent*>(&fw));
1118 else if(w)
1119 static_cast<tdehtml::RenderWidget::EventPropagator*>(w)->sendEvent(static_cast<TQEvent*>(&fw));
1120}
1121
1122
1123static bool targetOpensNewWindow(TDEHTMLPart *part, TQString target)
1124{
1125 if (!target.isEmpty() && (target.lower() != "_top") &&
1126 (target.lower() != "_self") && (target.lower() != "_parent")) {
1127 if (target.lower() == "_blank")
1128 return true;
1129 else {
1130 while (part->parentPart())
1131 part = part->parentPart();
1132 if (!part->frameExists(target))
1133 return true;
1134 }
1135 }
1136 return false;
1137}
1138
1139void TDEHTMLView::viewportMouseMoveEvent( TQMouseEvent * _mouse )
1140{
1141 if ( d->m_mouseScrollTimer ) {
1142 TQPoint point = mapFromGlobal( _mouse->globalPos() );
1143
1144 int deltaX = point.x() - d->m_mouseScrollIndicator->x() - 24;
1145 int deltaY = point.y() - d->m_mouseScrollIndicator->y() - 24;
1146
1147 (deltaX > 0) ? d->m_mouseScroll_byX = 1 : d->m_mouseScroll_byX = -1;
1148 (deltaY > 0) ? d->m_mouseScroll_byY = 1 : d->m_mouseScroll_byY = -1;
1149
1150 double adX = TQABS(deltaX)/30.0;
1151 double adY = TQABS(deltaY)/30.0;
1152
1153 d->m_mouseScroll_byX = kMax(kMin(d->m_mouseScroll_byX * int(adX*adX), SHRT_MAX), SHRT_MIN);
1154 d->m_mouseScroll_byY = kMax(kMin(d->m_mouseScroll_byY * int(adY*adY), SHRT_MAX), SHRT_MIN);
1155
1156 if (d->m_mouseScroll_byX == 0 && d->m_mouseScroll_byY == 0) {
1157 d->m_mouseScrollTimer->stop();
1158 }
1159 else if (!d->m_mouseScrollTimer->isActive()) {
1160 d->m_mouseScrollTimer->changeInterval( 20 );
1161 }
1162 }
1163
1164 if(!m_part->xmlDocImpl()) return;
1165
1166 int xm, ym;
1167 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
1168
1169 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
1170 // Do not modify :hover/:active state while mouse is pressed.
1171 m_part->xmlDocImpl()->prepareMouseEvent( _mouse->state() & TQt::MouseButtonMask /*readonly ?*/, xm, ym, &mev );
1172
1173// kdDebug(6000) << "mouse move: " << _mouse->pos()
1174// << " button " << _mouse->button()
1175// << " state " << _mouse->state() << endl;
1176
1177 bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),false,
1178 0,_mouse,true,DOM::NodeImpl::MouseMove);
1179
1180 if (d->clickCount > 0 &&
1181 TQPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > TQApplication::startDragDistance()) {
1182 d->clickCount = 0; // moving the mouse outside the threshold invalidates the click
1183 }
1184
1185 // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
1186 m_part->executeScheduledScript();
1187
1188 DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
1189 if (fn && fn != mev.innerNode.handle() &&
1190 fn->renderer() && fn->renderer()->isWidget()) {
1191 forwardPeripheralEvent(static_cast<tdehtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
1192 }
1193
1194 tdehtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
1195 tdehtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
1196 TQCursor c;
1197 bool mailtoCursor = false;
1198 bool newWindowCursor = false;
1199 switch ( style ? style->cursor() : CURSOR_AUTO) {
1200 case CURSOR_AUTO:
1201 if ( r && r->isText() )
1202 c = KCursor::ibeamCursor();
1203 if ( mev.url.length() && m_part->settings()->changeCursor() ) {
1204 c = m_part->urlCursor();
1205 if (mev.url.string().startsWith("mailto:") && mev.url.string().find('@')>0)
1206 mailtoCursor = true;
1207 else
1208 newWindowCursor = targetOpensNewWindow( m_part, mev.target.string() );
1209 }
1210
1211 if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
1212 c = TQCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
1213
1214 break;
1215 case CURSOR_CROSS:
1216 c = KCursor::crossCursor();
1217 break;
1218 case CURSOR_POINTER:
1219 c = m_part->urlCursor();
1220 if (mev.url.string().startsWith("mailto:") && mev.url.string().find('@')>0)
1221 mailtoCursor = true;
1222 else
1223 newWindowCursor = targetOpensNewWindow( m_part, mev.target.string() );
1224 break;
1225 case CURSOR_PROGRESS:
1226 c = KCursor::workingCursor();
1227 break;
1228 case CURSOR_MOVE:
1229 c = KCursor::sizeAllCursor();
1230 break;
1231 case CURSOR_E_RESIZE:
1232 case CURSOR_W_RESIZE:
1233 c = KCursor::sizeHorCursor();
1234 break;
1235 case CURSOR_N_RESIZE:
1236 case CURSOR_S_RESIZE:
1237 c = KCursor::sizeVerCursor();
1238 break;
1239 case CURSOR_NE_RESIZE:
1240 case CURSOR_SW_RESIZE:
1241 c = KCursor::sizeBDiagCursor();
1242 break;
1243 case CURSOR_NW_RESIZE:
1244 case CURSOR_SE_RESIZE:
1245 c = KCursor::sizeFDiagCursor();
1246 break;
1247 case CURSOR_TEXT:
1248 c = KCursor::ibeamCursor();
1249 break;
1250 case CURSOR_WAIT:
1251 c = KCursor::waitCursor();
1252 break;
1253 case CURSOR_HELP:
1254 c = KCursor::whatsThisCursor();
1255 break;
1256 case CURSOR_DEFAULT:
1257 break;
1258 }
1259
1260 if ( viewport()->cursor().handle() != c.handle() ) {
1261 if( c.handle() == KCursor::arrowCursor().handle()) {
1262 for (TDEHTMLPart* p = m_part; p; p = p->parentPart())
1263 p->view()->viewport()->unsetCursor();
1264 }
1265 else {
1266 viewport()->setCursor( c );
1267 }
1268 }
1269
1270 if ( ( mailtoCursor || newWindowCursor ) && isVisible() && hasFocus() ) {
1271#ifdef TQ_WS_X11
1272 TQPixmap icon_pixmap = TDEGlobal::iconLoader()->loadIcon( mailtoCursor ? "mail_generic" : "window-new", TDEIcon::Small, 0, TDEIcon::DefaultState, 0, true );
1273
1274 if (d->cursor_icon_widget) {
1275 const TQPixmap *pm = d->cursor_icon_widget->backgroundPixmap();
1276 if (!pm || pm->serialNumber()!=icon_pixmap.serialNumber()) {
1277 delete d->cursor_icon_widget;
1278 d->cursor_icon_widget = 0;
1279 }
1280 }
1281
1282 if( !d->cursor_icon_widget ) {
1283 d->cursor_icon_widget = new TQWidget( NULL, NULL, WX11BypassWM );
1284 XSetWindowAttributes attr;
1285 attr.save_under = True;
1286 XChangeWindowAttributes( tqt_xdisplay(), d->cursor_icon_widget->winId(), CWSaveUnder, &attr );
1287 d->cursor_icon_widget->resize( icon_pixmap.width(), icon_pixmap.height());
1288 if( icon_pixmap.mask() )
1289 d->cursor_icon_widget->setMask( *icon_pixmap.mask());
1290 else
1291 d->cursor_icon_widget->clearMask();
1292 d->cursor_icon_widget->setBackgroundPixmap( icon_pixmap );
1293 d->cursor_icon_widget->erase();
1294 }
1295 TQPoint c_pos = TQCursor::pos();
1296 d->cursor_icon_widget->move( c_pos.x() + 15, c_pos.y() + 15 );
1297 XRaiseWindow( tqt_xdisplay(), d->cursor_icon_widget->winId());
1298 TQApplication::flushX();
1299 d->cursor_icon_widget->show();
1300#endif
1301 }
1302 else if ( d->cursor_icon_widget )
1303 d->cursor_icon_widget->hide();
1304
1305 if (r && r->isWidget()) {
1306 _mouse->ignore();
1307 }
1308
1309
1310 d->prevMouseX = xm;
1311 d->prevMouseY = ym;
1312
1313 if (!swallowEvent) {
1314 tdehtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1315 TQApplication::sendEvent( m_part, &event );
1316 }
1317}
1318
1319void TDEHTMLView::viewportMouseReleaseEvent( TQMouseEvent * _mouse )
1320{
1321 bool swallowEvent = false;
1322 int xm, ym;
1323 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
1324 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
1325
1326 if ( m_part->xmlDocImpl() )
1327 {
1328 m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1329
1330 swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1331 d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
1332
1333 if (d->clickCount > 0 &&
1334 TQPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= TQApplication::startDragDistance()) {
1335 TQMouseEvent me(d->isDoubleClick ? TQEvent::MouseButtonDblClick : TQEvent::MouseButtonRelease,
1336 _mouse->pos(), _mouse->button(), _mouse->state());
1337 dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),mev.innerNonSharedNode.handle(),true,
1338 d->clickCount, &me, true, DOM::NodeImpl::MouseRelease);
1339 }
1340
1341 DOM::NodeImpl* fn = m_part->xmlDocImpl()->focusNode();
1342 if (fn && fn != mev.innerNode.handle() &&
1343 fn->renderer() && fn->renderer()->isWidget() &&
1344 _mouse->button() != TQt::MidButton) {
1345 forwardPeripheralEvent(static_cast<tdehtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
1346 }
1347
1348 tdehtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
1349 if (r && r->isWidget())
1350 _mouse->ignore();
1351 }
1352
1353 if (!swallowEvent) {
1354 tdehtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1355 TQApplication::sendEvent( m_part, &event );
1356 }
1357}
1358
1359// returns true if event should be swallowed
1360bool TDEHTMLView::dispatchKeyEvent( TQKeyEvent *_ke )
1361{
1362 if (!m_part->xmlDocImpl())
1363 return false;
1364 // Pressing and releasing a key should generate keydown, keypress and keyup events
1365 // Holding it down should generated keydown, keypress (repeatedly) and keyup events
1366 // The problem here is that Qt generates two autorepeat events (keyrelease+keypress)
1367 // for autorepeating, while DOM wants only one autorepeat event (keypress), so one
1368 // of the Qt events shouldn't be passed to DOM, but it should be still filtered
1369 // out if DOM would filter the autorepeat event. Additional problem is that Qt keyrelease
1370 // events don't have text() set (Qt bug?), so DOM often would ignore the keypress event
1371 // if it was created using Qt keyrelease, but Qt autorepeat keyrelease comes
1372 // before Qt autorepeat keypress (i.e. problem whether to filter it out or not).
1373 // The solution is to filter out and postpone the Qt autorepeat keyrelease until
1374 // the following Qt keypress event comes. If DOM accepts the DOM keypress event,
1375 // the postponed event will be simply discarded. If not, it will be passed to keyPressEvent()
1376 // again, and here it will be ignored.
1377 //
1378 // Qt: Press | Release(autorepeat) Press(autorepeat) etc. | Release
1379 // DOM: Down + Press | (nothing) Press | Up
1380
1381 // It's also possible to get only Releases. E.g. the release of alt-tab,
1382 // or when the keypresses get captured by an accel.
1383
1384 if( _ke == d->postponed_autorepeat ) // replayed event
1385 {
1386 return false;
1387 }
1388
1389 if( _ke->type() == TQEvent::KeyPress )
1390 {
1391 if( !_ke->isAutoRepeat())
1392 {
1393 bool ret = dispatchKeyEventHelper( _ke, false ); // keydown
1394 // don't send keypress even if keydown was blocked, like IE (and unlike Mozilla)
1395 if( !ret && dispatchKeyEventHelper( _ke, true )) // keypress
1396 ret = true;
1397 return ret;
1398 }
1399 else // autorepeat
1400 {
1401 bool ret = dispatchKeyEventHelper( _ke, true ); // keypress
1402 if( !ret && d->postponed_autorepeat )
1403 keyPressEvent( d->postponed_autorepeat );
1404 delete d->postponed_autorepeat;
1405 d->postponed_autorepeat = NULL;
1406 return ret;
1407 }
1408 }
1409 else // TQEvent::KeyRelease
1410 {
1411 // Discard postponed "autorepeat key-release" events that didn't see
1412 // a keypress after them (e.g. due to TQAccel)
1413 if ( d->postponed_autorepeat ) {
1414 delete d->postponed_autorepeat;
1415 d->postponed_autorepeat = 0;
1416 }
1417
1418 if( !_ke->isAutoRepeat()) {
1419 return dispatchKeyEventHelper( _ke, false ); // keyup
1420 }
1421 else
1422 {
1423 d->postponed_autorepeat = new TQKeyEvent( _ke->type(), _ke->key(), _ke->ascii(), _ke->state(),
1424 _ke->text(), _ke->isAutoRepeat(), _ke->count());
1425 if( _ke->isAccepted())
1426 d->postponed_autorepeat->accept();
1427 else
1428 d->postponed_autorepeat->ignore();
1429 return true;
1430 }
1431 }
1432}
1433
1434// returns true if event should be swallowed
1435bool TDEHTMLView::dispatchKeyEventHelper( TQKeyEvent *_ke, bool keypress )
1436{
1437 DOM::NodeImpl* keyNode = m_part->xmlDocImpl()->focusNode();
1438 if (keyNode) {
1439 return keyNode->dispatchKeyEvent(_ke, keypress);
1440 } else { // no focused node, send to document
1441 return m_part->xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
1442 }
1443}
1444
1445void TDEHTMLView::keyPressEvent( TQKeyEvent *_ke )
1446{
1447#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
1448 if(d->typeAheadActivated)
1449 {
1450 // type-ahead find aka find-as-you-type
1451 if(_ke->key() == Key_BackSpace)
1452 {
1453 d->findString = d->findString.left(d->findString.length() - 1);
1454
1455 if(!d->findString.isEmpty())
1456 {
1457 findAhead(false);
1458 }
1459 else
1460 {
1461 findTimeout();
1462 }
1463
1464 d->timer.start(3000, true);
1465 _ke->accept();
1466 return;
1467 }
1468 else if(_ke->key() == Key_Escape)
1469 {
1470 findTimeout();
1471
1472 _ke->accept();
1473 return;
1474 }
1475 else if(_ke->key() == Key_Space || !TQString(_ke->text()).stripWhiteSpace().isEmpty())
1476 {
1477 d->findString += _ke->text();
1478
1479 findAhead(true);
1480
1481 d->timer.start(3000, true);
1482 _ke->accept();
1483 return;
1484 }
1485 }
1486#endif // TDEHTML_NO_TYPE_AHEAD_FIND
1487
1488#ifndef TDEHTML_NO_CARET
1489 if (m_part->isEditable() || m_part->isCaretMode()
1490 || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
1491 && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
1492 d->caretViewContext()->keyReleasePending = true;
1493 caretKeyPressEvent(_ke);
1494 return;
1495 }
1496#endif // TDEHTML_NO_CARET
1497
1498 // If CTRL was hit, be prepared for access keys
1499 if (d->accessKeysEnabled && _ke->key() == Key_Control && _ke->state()==0 && !d->accessKeysActivated)
1500 {
1501 d->accessKeysPreActivate=true;
1502 _ke->accept();
1503 return;
1504 }
1505
1506 if (_ke->key() == Key_Shift && _ke->state()==0)
1507 d->scrollSuspendPreActivate=true;
1508
1509 // accesskey handling needs to be done before dispatching, otherwise e.g. lineedits
1510 // may eat the event
1511
1512 if (d->accessKeysEnabled && d->accessKeysActivated)
1513 {
1514 int state = ( _ke->state() & ( ShiftButton | ControlButton | AltButton | MetaButton ));
1515 if ( state==0 || state==ShiftButton) {
1516 if (_ke->key() != Key_Shift) accessKeysTimeout();
1517 handleAccessKey( _ke );
1518 _ke->accept();
1519 return;
1520 }
1521 accessKeysTimeout();
1522 }
1523
1524 if ( dispatchKeyEvent( _ke )) {
1525 // If either keydown or keypress was accepted by a widget, or canceled by JS, stop here.
1526 _ke->accept();
1527 return;
1528 }
1529
1530 int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
1531 if (_ke->state() & TQt::ShiftButton)
1532 switch(_ke->key())
1533 {
1534 case Key_Space:
1535 scrollBy( 0, -clipper()->height() + offs );
1536 if(d->scrollSuspended)
1537 d->newScrollTimer(this, 0);
1538 break;
1539
1540 case Key_Down:
1541 case Key_J:
1542 d->adjustScroller(this, TDEHTMLViewPrivate::ScrollDown, TDEHTMLViewPrivate::ScrollUp);
1543 break;
1544
1545 case Key_Up:
1546 case Key_K:
1547 d->adjustScroller(this, TDEHTMLViewPrivate::ScrollUp, TDEHTMLViewPrivate::ScrollDown);
1548 break;
1549
1550 case Key_Left:
1551 case Key_H:
1552 d->adjustScroller(this, TDEHTMLViewPrivate::ScrollLeft, TDEHTMLViewPrivate::ScrollRight);
1553 break;
1554
1555 case Key_Right:
1556 case Key_L:
1557 d->adjustScroller(this, TDEHTMLViewPrivate::ScrollRight, TDEHTMLViewPrivate::ScrollLeft);
1558 break;
1559 }
1560 else
1561 switch ( _ke->key() )
1562 {
1563 case Key_Down:
1564 case Key_J:
1565 if (!d->scrollTimerId || d->scrollSuspended)
1566 scrollBy( 0, 10 * _ke->count() );
1567 if (d->scrollTimerId)
1568 d->newScrollTimer(this, 0);
1569 break;
1570
1571 case Key_Space:
1572 case Key_Next:
1573 scrollBy( 0, clipper()->height() - offs );
1574 if(d->scrollSuspended)
1575 d->newScrollTimer(this, 0);
1576 break;
1577
1578 case Key_Up:
1579 case Key_K:
1580 if (!d->scrollTimerId || d->scrollSuspended)
1581 scrollBy( 0, -10 * _ke->count());
1582 if (d->scrollTimerId)
1583 d->newScrollTimer(this, 0);
1584 break;
1585
1586 case Key_Prior:
1587 scrollBy( 0, -clipper()->height() + offs );
1588 if(d->scrollSuspended)
1589 d->newScrollTimer(this, 0);
1590 break;
1591 case Key_Right:
1592 case Key_L:
1593 if (!d->scrollTimerId || d->scrollSuspended)
1594 scrollBy( 10 * _ke->count(), 0 );
1595 if (d->scrollTimerId)
1596 d->newScrollTimer(this, 0);
1597 break;
1598 case Key_Left:
1599 case Key_H:
1600 if (!d->scrollTimerId || d->scrollSuspended)
1601 scrollBy( -10 * _ke->count(), 0 );
1602 if (d->scrollTimerId)
1603 d->newScrollTimer(this, 0);
1604 break;
1605 case Key_Enter:
1606 case Key_Return:
1607 // ### FIXME:
1608 // or even better to HTMLAnchorElementImpl::event()
1609 if (m_part->xmlDocImpl()) {
1610 NodeImpl *n = m_part->xmlDocImpl()->focusNode();
1611 if (n)
1612 n->setActive();
1613 }
1614 break;
1615 case Key_Home:
1616 setContentsPos( 0, 0 );
1617 if(d->scrollSuspended)
1618 d->newScrollTimer(this, 0);
1619 break;
1620 case Key_End:
1621 setContentsPos( 0, contentsHeight() - visibleHeight() );
1622 if(d->scrollSuspended)
1623 d->newScrollTimer(this, 0);
1624 break;
1625 case Key_Shift:
1626 // what are you doing here?
1627 _ke->ignore();
1628 return;
1629 default:
1630 if (d->scrollTimerId)
1631 d->newScrollTimer(this, 0);
1632 _ke->ignore();
1633 return;
1634 }
1635
1636 _ke->accept();
1637}
1638
1639void TDEHTMLView::findTimeout()
1640{
1641#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
1642 d->typeAheadActivated = false;
1643 d->findString = "";
1644 m_part->setStatusBarText(i18n("Find stopped."), TDEHTMLPart::BarDefaultText);
1645 m_part->enableFindAheadActions( true );
1646#endif // TDEHTML_NO_TYPE_AHEAD_FIND
1647}
1648
1649#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
1650void TDEHTMLView::startFindAhead( bool linksOnly )
1651{
1652 if( linksOnly )
1653 {
1654 d->findLinksOnly = true;
1655 m_part->setStatusBarText(i18n("Starting -- find links as you type"),
1656 TDEHTMLPart::BarDefaultText);
1657 }
1658 else
1659 {
1660 d->findLinksOnly = false;
1661 m_part->setStatusBarText(i18n("Starting -- find text as you type"),
1662 TDEHTMLPart::BarDefaultText);
1663 }
1664
1665 m_part->findTextBegin();
1666 d->typeAheadActivated = true;
1667 // disable, so that the shortcut ( / or ' by default ) doesn't interfere
1668 m_part->enableFindAheadActions( false );
1669 d->timer.start(3000, true);
1670}
1671
1672void TDEHTMLView::findAhead(bool increase)
1673{
1674 TQString status;
1675
1676 if(d->findLinksOnly)
1677 {
1678 m_part->findText(d->findString, TDEHTMLPart::FindNoPopups |
1679 TDEHTMLPart::FindLinksOnly, this);
1680 if(m_part->findTextNext())
1681 {
1682 status = i18n("Link found: \"%1\".");
1683 }
1684 else
1685 {
1686 if(increase) KNotifyClient::beep();
1687 status = i18n("Link not found: \"%1\".");
1688 }
1689 }
1690 else
1691 {
1692 m_part->findText(d->findString, TDEHTMLPart::FindNoPopups, this);
1693 if(m_part->findTextNext())
1694 {
1695 status = i18n("Text found: \"%1\".");
1696 }
1697 else
1698 {
1699 if(increase) KNotifyClient::beep();
1700 status = i18n("Text not found: \"%1\".");
1701 }
1702 }
1703
1704 m_part->setStatusBarText(status.arg(d->findString.lower()),
1705 TDEHTMLPart::BarDefaultText);
1706}
1707
1708void TDEHTMLView::updateFindAheadTimeout()
1709{
1710 if( d->typeAheadActivated )
1711 d->timer.start( 3000, true );
1712}
1713
1714#endif // TDEHTML_NO_TYPE_AHEAD_FIND
1715
1716void TDEHTMLView::keyReleaseEvent(TQKeyEvent *_ke)
1717{
1718#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
1719 if(d->typeAheadActivated) {
1720 _ke->accept();
1721 return;
1722 }
1723#endif
1724 if (d->m_caretViewContext && d->m_caretViewContext->keyReleasePending) {
1725 //caretKeyReleaseEvent(_ke);
1726 d->m_caretViewContext->keyReleasePending = false;
1727 return;
1728 }
1729
1730 if( d->scrollSuspendPreActivate && _ke->key() != Key_Shift )
1731 d->scrollSuspendPreActivate = false;
1732 if( _ke->key() == Key_Shift && d->scrollSuspendPreActivate && _ke->state() == TQt::ShiftButton
1733 && !(TDEApplication::keyboardMouseState() & TQt::ShiftButton))
1734 {
1735 if (d->scrollTimerId)
1736 {
1737 d->scrollSuspended = !d->scrollSuspended;
1738#ifndef NO_SMOOTH_SCROLL_HACK
1739 if( d->scrollSuspended )
1740 stopScrolling();
1741#endif
1742 }
1743 }
1744
1745 if (d->accessKeysEnabled)
1746 {
1747 if (d->accessKeysPreActivate && _ke->key() != Key_Control)
1748 d->accessKeysPreActivate=false;
1749 if (d->accessKeysPreActivate && _ke->state() == TQt::ControlButton && !(TDEApplication::keyboardMouseState() & TQt::ControlButton))
1750 {
1751 displayAccessKeys();
1752 m_part->setStatusBarText(i18n("Access Keys activated"),TDEHTMLPart::BarOverrideText);
1753 d->accessKeysActivated = true;
1754 d->accessKeysPreActivate = false;
1755 _ke->accept();
1756 return;
1757 }
1758 else if (d->accessKeysActivated)
1759 {
1760 accessKeysTimeout();
1761 _ke->accept();
1762 return;
1763 }
1764 }
1765
1766 // Send keyup event
1767 if ( dispatchKeyEvent( _ke ) )
1768 {
1769 _ke->accept();
1770 return;
1771 }
1772
1773 TQScrollView::keyReleaseEvent(_ke);
1774}
1775
1776void TDEHTMLView::contentsContextMenuEvent ( TQContextMenuEvent * /*ce*/ )
1777{
1778// ### what kind of c*** is that ?
1779#if 0
1780 if (!m_part->xmlDocImpl()) return;
1781 int xm = _ce->x();
1782 int ym = _ce->y();
1783
1784 DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove ); // ### not a mouse event!
1785 m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
1786
1787 NodeImpl *targetNode = mev.innerNode.handle();
1788 if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
1789 int absx = 0;
1790 int absy = 0;
1791 targetNode->renderer()->absolutePosition(absx,absy);
1792 TQPoint pos(xm-absx,ym-absy);
1793
1794 TQWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
1795 TQContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
1796 setIgnoreEvents(true);
1797 TQApplication::sendEvent(w,&cme);
1798 setIgnoreEvents(false);
1799 }
1800#endif
1801}
1802
1803bool TDEHTMLView::focusNextPrevChild( bool next )
1804{
1805 // Now try to find the next child
1806 if (m_part->xmlDocImpl() && focusNextPrevNode(next))
1807 {
1808 if (m_part->xmlDocImpl()->focusNode())
1809 kdDebug() << "focusNode.name: "
1810 << m_part->xmlDocImpl()->focusNode()->nodeName().string() << endl;
1811 return true; // focus node found
1812 }
1813
1814 // If we get here, pass tabbing control up to the next/previous child in our parent
1815 d->pseudoFocusNode = TDEHTMLViewPrivate::PFNone;
1816 if (m_part->parentPart() && m_part->parentPart()->view())
1817 return m_part->parentPart()->view()->focusNextPrevChild(next);
1818
1819 return TQWidget::focusNextPrevChild(next);
1820}
1821
1822void TDEHTMLView::doAutoScroll()
1823{
1824 TQPoint pos = TQCursor::pos();
1825 pos = viewport()->mapFromGlobal( pos );
1826
1827 int xm, ym;
1828 viewportToContents(pos.x(), pos.y(), xm, ym);
1829
1830 pos = TQPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
1831 if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
1832 (pos.x() < 0) || (pos.x() > visibleWidth()) )
1833 {
1834 ensureVisible( xm, ym, 0, 5 );
1835
1836#ifndef TDEHTML_NO_SELECTION
1837 // extend the selection while scrolling
1838 DOM::Node innerNode;
1839 if (m_part->isExtendingSelection()) {
1840 RenderObject::NodeInfo renderInfo(true/*readonly*/, false/*active*/);
1841 m_part->xmlDocImpl()->renderer()->layer()
1842 ->nodeAtPoint(renderInfo, xm, ym);
1843 innerNode = renderInfo.innerNode();
1844 }/*end if*/
1845
1846 if (innerNode.handle() && innerNode.handle()->renderer()) {
1847 int absX, absY;
1848 innerNode.handle()->renderer()->absolutePosition(absX, absY);
1849
1850 m_part->extendSelectionTo(xm, ym, absX, absY, innerNode);
1851 }/*end if*/
1852#endif // TDEHTML_NO_SELECTION
1853 }
1854}
1855
1856
1857class HackWidget : public TQWidget
1858{
1859 public:
1860 inline void setNoErase() { setWFlags(getWFlags()|WRepaintNoErase); }
1861};
1862
1863bool TDEHTMLView::eventFilter(TQObject *o, TQEvent *e)
1864{
1865 if ( e->type() == TQEvent::AccelOverride ) {
1866 TQKeyEvent* ke = (TQKeyEvent*) e;
1867//kdDebug(6200) << "TQEvent::AccelOverride" << endl;
1868 if (m_part->isEditable() || m_part->isCaretMode()
1869 || (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()
1870 && m_part->xmlDocImpl()->focusNode()->contentEditable())) {
1871//kdDebug(6200) << "editable/navigable" << endl;
1872 if ( (ke->state() & ControlButton) || (ke->state() & ShiftButton) ) {
1873 switch ( ke->key() ) {
1874 case Key_Left:
1875 case Key_Right:
1876 case Key_Up:
1877 case Key_Down:
1878 case Key_Home:
1879 case Key_End:
1880 ke->accept();
1881//kdDebug(6200) << "eaten" << endl;
1882 return true;
1883 default:
1884 break;
1885 }
1886 }
1887 }
1888 }
1889
1890 if ( e->type() == TQEvent::Leave ) {
1891 if ( d->cursor_icon_widget )
1892 d->cursor_icon_widget->hide();
1893 m_part->resetHoverText();
1894 }
1895
1896 TQWidget *view = viewport();
1897
1898 if (o == view) {
1899 // we need to install an event filter on all children of the viewport to
1900 // be able to get correct stacking of children within the document.
1901 if(e->type() == TQEvent::ChildInserted) {
1902 TQObject *c = static_cast<TQChildEvent*>(e)->child();
1903 if (c->isWidgetType()) {
1904 TQWidget *w = static_cast<TQWidget*>(c);
1905 // don't install the event filter on toplevels
1906 if (w->parentWidget(true) == view) {
1907 if (!strcmp(w->name(), "__tdehtml")) {
1908 w->installEventFilter(this);
1909 w->unsetCursor();
1910 if (!::tqt_cast<TQFrame*>(w))
1911 w->setBackgroundMode( TQWidget::NoBackground );
1912 static_cast<HackWidget *>(w)->setNoErase();
1913 if (!w->childrenListObject().isEmpty()) {
1914 TQObjectListIterator it(w->childrenListObject());
1915 for (; it.current(); ++it) {
1916 TQWidget *widget = ::tqt_cast<TQWidget *>(it.current());
1917 if (widget && !widget->isTopLevel()) {
1918 if (!::tqt_cast<TQFrame*>(w))
1919 widget->setBackgroundMode( TQWidget::NoBackground );
1920 static_cast<HackWidget *>(widget)->setNoErase();
1921 widget->installEventFilter(this);
1922 }
1923 }
1924 }
1925 }
1926 }
1927 }
1928 }
1929 } else if (o->isWidgetType()) {
1930 TQWidget *v = static_cast<TQWidget*>(o);
1931 TQWidget *c = v;
1932 while (v && v != view) {
1933 c = v;
1934 v = v->parentWidget(true);
1935 }
1936
1937 if (v && !strcmp(c->name(), "__tdehtml")) {
1938 bool block = false;
1939 TQWidget *w = static_cast<TQWidget*>(o);
1940 switch(e->type()) {
1941 case TQEvent::Paint:
1942 if (!allowWidgetPaintEvents) {
1943 // eat the event. Like this we can control exactly when the widget
1944 // get's repainted.
1945 block = true;
1946 int x = 0, y = 0;
1947 TQWidget *v = w;
1948 while (v && v != view) {
1949 x += v->x();
1950 y += v->y();
1951 v = v->parentWidget();
1952 }
1953 viewportToContents( x, y, x, y );
1954 TQPaintEvent *pe = static_cast<TQPaintEvent*>(e);
1955 bool asap = !d->contentsMoving && ::tqt_cast<TQScrollView *>(c);
1956
1957 // TQScrollView needs fast repaints
1958 if ( asap && !d->painting && m_part->xmlDocImpl() && m_part->xmlDocImpl()->renderer() &&
1959 !static_cast<tdehtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer())->needsLayout() ) {
1960 repaintContents(x + pe->rect().x(), y + pe->rect().y(),
1961 pe->rect().width(), pe->rect().height(), true);
1962 } else {
1963 scheduleRepaint(x + pe->rect().x(), y + pe->rect().y(),
1964 pe->rect().width(), pe->rect().height(), asap);
1965 }
1966 }
1967 break;
1968 case TQEvent::MouseMove:
1969 case TQEvent::MouseButtonPress:
1970 case TQEvent::MouseButtonRelease:
1971 case TQEvent::MouseButtonDblClick: {
1972 if ( (w->parentWidget() == view || ::tqt_cast<TQScrollView*>(c)) && !::tqt_cast<TQScrollBar *>(w)) {
1973 TQMouseEvent *me = static_cast<TQMouseEvent*>(e);
1974 TQPoint pt = w->mapTo( view, me->pos());
1975 TQMouseEvent me2(me->type(), pt, me->button(), me->state());
1976
1977 if (e->type() == TQEvent::MouseMove)
1978 viewportMouseMoveEvent(&me2);
1979 else if(e->type() == TQEvent::MouseButtonPress)
1980 viewportMousePressEvent(&me2);
1981 else if(e->type() == TQEvent::MouseButtonRelease)
1982 viewportMouseReleaseEvent(&me2);
1983 else
1984 viewportMouseDoubleClickEvent(&me2);
1985 block = true;
1986 }
1987 break;
1988 }
1989 case TQEvent::KeyPress:
1990 case TQEvent::KeyRelease:
1991 if (w->parentWidget() == view && !::tqt_cast<TQScrollBar *>(w)) {
1992 TQKeyEvent *ke = static_cast<TQKeyEvent*>(e);
1993 if (e->type() == TQEvent::KeyPress)
1994 keyPressEvent(ke);
1995 else
1996 keyReleaseEvent(ke);
1997 block = true;
1998 }
1999 default:
2000 break;
2001 }
2002 if (block) {
2003 //tqDebug("eating event");
2004 return true;
2005 }
2006 }
2007 }
2008
2009// kdDebug(6000) <<"passing event on to sv event filter object=" << o->className() << " event=" << e->type() << endl;
2010 return TQScrollView::eventFilter(o, e);
2011}
2012
2013
2014DOM::NodeImpl *TDEHTMLView::nodeUnderMouse() const
2015{
2016 return d->underMouse;
2017}
2018
2019DOM::NodeImpl *TDEHTMLView::nonSharedNodeUnderMouse() const
2020{
2021 return d->underMouseNonShared;
2022}
2023
2024bool TDEHTMLView::scrollTo(const TQRect &bounds)
2025{
2026 d->scrollingSelf = true; // so scroll events get ignored
2027
2028 int x, y, xe, ye;
2029 x = bounds.left();
2030 y = bounds.top();
2031 xe = bounds.right();
2032 ye = bounds.bottom();
2033
2034 //kdDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y<<endl;
2035
2036 int deltax;
2037 int deltay;
2038
2039 int curHeight = visibleHeight();
2040 int curWidth = visibleWidth();
2041
2042 if (ye-y>curHeight-d->borderY)
2043 ye = y + curHeight - d->borderY;
2044
2045 if (xe-x>curWidth-d->borderX)
2046 xe = x + curWidth - d->borderX;
2047
2048 // is xpos of target left of the view's border?
2049 if (x < contentsX() + d->borderX )
2050 deltax = x - contentsX() - d->borderX;
2051 // is xpos of target right of the view's right border?
2052 else if (xe + d->borderX > contentsX() + curWidth)
2053 deltax = xe + d->borderX - ( contentsX() + curWidth );
2054 else
2055 deltax = 0;
2056
2057 // is ypos of target above upper border?
2058 if (y < contentsY() + d->borderY)
2059 deltay = y - contentsY() - d->borderY;
2060 // is ypos of target below lower border?
2061 else if (ye + d->borderY > contentsY() + curHeight)
2062 deltay = ye + d->borderY - ( contentsY() + curHeight );
2063 else
2064 deltay = 0;
2065
2066 int maxx = curWidth-d->borderX;
2067 int maxy = curHeight-d->borderY;
2068
2069 int scrollX,scrollY;
2070
2071 scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
2072 scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
2073
2074 if (contentsX() + scrollX < 0)
2075 scrollX = -contentsX();
2076 else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
2077 scrollX = contentsWidth() - visibleWidth() - contentsX();
2078
2079 if (contentsY() + scrollY < 0)
2080 scrollY = -contentsY();
2081 else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
2082 scrollY = contentsHeight() - visibleHeight() - contentsY();
2083
2084 scrollBy(scrollX, scrollY);
2085
2086 d->scrollingSelf = false;
2087
2088 if ( (abs(deltax)<=maxx) && (abs(deltay)<=maxy) )
2089 return true;
2090 else return false;
2091
2092}
2093
2094bool TDEHTMLView::focusNextPrevNode(bool next)
2095{
2096 // Sets the focus node of the document to be the node after (or if
2097 // next is false, before) the current focus node. Only nodes that
2098 // are selectable (i.e. for which isFocusable() returns true) are
2099 // taken into account, and the order used is that specified in the
2100 // HTML spec (see DocumentImpl::nextFocusNode() and
2101 // DocumentImpl::previousFocusNode() for details).
2102
2103 DocumentImpl *doc = m_part->xmlDocImpl();
2104 NodeImpl *oldFocusNode = doc->focusNode();
2105
2106 // See whether we're in the middle of detach. If so, we want to
2107 // clear focus... The document code will be careful to not
2108 // emit events in that case..
2109 if (oldFocusNode && oldFocusNode->renderer() &&
2110 !oldFocusNode->renderer()->parent()) {
2111 doc->setFocusNode(0);
2112 return true;
2113 }
2114
2115#if 1
2116 // If the user has scrolled the document, then instead of picking
2117 // the next focusable node in the document, use the first one that
2118 // is within the visible area (if possible).
2119 if (d->scrollBarMoved)
2120 {
2121 NodeImpl *toFocus;
2122 if (next)
2123 toFocus = doc->nextFocusNode(oldFocusNode);
2124 else
2125 toFocus = doc->previousFocusNode(oldFocusNode);
2126
2127 if (!toFocus && oldFocusNode)
2128 if (next)
2129 toFocus = doc->nextFocusNode(NULL);
2130 else
2131 toFocus = doc->previousFocusNode(NULL);
2132
2133 while (toFocus && toFocus != oldFocusNode)
2134 {
2135
2136 TQRect focusNodeRect = toFocus->getRect();
2137 if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
2138 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
2139 {
2140 TQRect r = toFocus->getRect();
2141 ensureVisible( r.right(), r.bottom());
2142 ensureVisible( r.left(), r.top());
2143 d->scrollBarMoved = false;
2144 d->tabMovePending = false;
2145 d->lastTabbingDirection = next;
2146 d->pseudoFocusNode = TDEHTMLViewPrivate::PFNone;
2147 m_part->xmlDocImpl()->setFocusNode(toFocus);
2148 Node guard(toFocus);
2149 if (!toFocus->hasOneRef() )
2150 {
2151 emit m_part->nodeActivated(Node(toFocus));
2152 }
2153 return true;
2154 }
2155 }
2156 if (next)
2157 toFocus = doc->nextFocusNode(toFocus);
2158 else
2159 toFocus = doc->previousFocusNode(toFocus);
2160
2161 if (!toFocus && oldFocusNode)
2162 if (next)
2163 toFocus = doc->nextFocusNode(NULL);
2164 else
2165 toFocus = doc->previousFocusNode(NULL);
2166 }
2167
2168 d->scrollBarMoved = false;
2169 }
2170#endif
2171
2172 if (!oldFocusNode && d->pseudoFocusNode == TDEHTMLViewPrivate::PFNone)
2173 {
2174 ensureVisible(contentsX(), next?0:contentsHeight());
2175 d->scrollBarMoved = false;
2176 d->pseudoFocusNode = next?TDEHTMLViewPrivate::PFTop:TDEHTMLViewPrivate::PFBottom;
2177 return true;
2178 }
2179
2180 NodeImpl *newFocusNode = NULL;
2181
2182 if (d->tabMovePending && next != d->lastTabbingDirection)
2183 {
2184 //kdDebug ( 6000 ) << " tab move pending and tabbing direction changed!\n";
2185 newFocusNode = oldFocusNode;
2186 }
2187 else if (next)
2188 {
2189 if (oldFocusNode || d->pseudoFocusNode == TDEHTMLViewPrivate::PFTop )
2190 newFocusNode = doc->nextFocusNode(oldFocusNode);
2191 }
2192 else
2193 {
2194 if (oldFocusNode || d->pseudoFocusNode == TDEHTMLViewPrivate::PFBottom )
2195 newFocusNode = doc->previousFocusNode(oldFocusNode);
2196 }
2197
2198 bool targetVisible = false;
2199 if (!newFocusNode)
2200 {
2201 if ( next )
2202 {
2203 targetVisible = scrollTo(TQRect(contentsX()+visibleWidth()/2,contentsHeight()-d->borderY,0,0));
2204 }
2205 else
2206 {
2207 targetVisible = scrollTo(TQRect(contentsX()+visibleWidth()/2,d->borderY,0,0));
2208 }
2209 }
2210 else
2211 {
2212#ifndef TDEHTML_NO_CARET
2213 // if it's an editable element, activate the caret
2214 if (!m_part->isCaretMode() && !m_part->isEditable()
2215 && newFocusNode->contentEditable()) {
2216 d->caretViewContext();
2217 moveCaretTo(newFocusNode, 0L, true);
2218 } else {
2219 caretOff();
2220 }
2221#endif // TDEHTML_NO_CARET
2222
2223 targetVisible = scrollTo(newFocusNode->getRect());
2224 }
2225
2226 if (targetVisible)
2227 {
2228 //kdDebug ( 6000 ) << " target reached.\n";
2229 d->tabMovePending = false;
2230
2231 m_part->xmlDocImpl()->setFocusNode(newFocusNode);
2232 if (newFocusNode)
2233 {
2234 Node guard(newFocusNode);
2235 if (!newFocusNode->hasOneRef() )
2236 {
2237 emit m_part->nodeActivated(Node(newFocusNode));
2238 }
2239 return true;
2240 }
2241 else
2242 {
2243 d->pseudoFocusNode = next?TDEHTMLViewPrivate::PFBottom:TDEHTMLViewPrivate::PFTop;
2244 return false;
2245 }
2246 }
2247 else
2248 {
2249 if (!d->tabMovePending)
2250 d->lastTabbingDirection = next;
2251 d->tabMovePending = true;
2252 return true;
2253 }
2254}
2255
2256void TDEHTMLView::displayAccessKeys()
2257{
2258 TQValueVector< TQChar > taken;
2259 displayAccessKeys( NULL, this, taken, false );
2260 displayAccessKeys( NULL, this, taken, true );
2261}
2262
2263void TDEHTMLView::displayAccessKeys( TDEHTMLView* caller, TDEHTMLView* origview, TQValueVector< TQChar >& taken, bool use_fallbacks )
2264{
2265 TQMap< ElementImpl*, TQChar > fallbacks;
2266 if( use_fallbacks )
2267 fallbacks = buildFallbackAccessKeys();
2268 for( NodeImpl* n = m_part->xmlDocImpl(); n != NULL; n = n->traverseNextNode()) {
2269 if( n->isElementNode()) {
2270 ElementImpl* en = static_cast< ElementImpl* >( n );
2271 DOMString s = en->getAttribute( ATTR_ACCESSKEY );
2272 TQString accesskey;
2273 if( s.length() == 1 ) {
2274 TQChar a = s.string()[ 0 ].upper();
2275 if( tqFind( taken.begin(), taken.end(), a ) == taken.end()) // !contains
2276 accesskey = a;
2277 }
2278 if( accesskey.isNull() && fallbacks.contains( en )) {
2279 TQChar a = fallbacks[ en ].upper();
2280 if( tqFind( taken.begin(), taken.end(), a ) == taken.end()) // !contains
2281 accesskey = TQString( "<qt><i>" ) + a + "</i></qt>";
2282 }
2283 if( !accesskey.isNull()) {
2284 TQRect rec=en->getRect();
2285 TQLabel *lab=new TQLabel(accesskey,viewport(),0,(WFlags)WDestructiveClose);
2286 connect( origview, TQ_SIGNAL(hideAccessKeys()), lab, TQ_SLOT(close()) );
2287 connect( this, TQ_SIGNAL(repaintAccessKeys()), lab, TQ_SLOT(repaint()));
2288 lab->setPalette(TQToolTip::palette());
2289 lab->setLineWidth(2);
2290 lab->setFrameStyle(TQFrame::Box | TQFrame::Plain);
2291 lab->setMargin(3);
2292 lab->adjustSize();
2293 addChild(lab,
2294 KMIN(rec.left()+rec.width()/2, contentsWidth() - lab->width()),
2295 KMIN(rec.top()+rec.height()/2, contentsHeight() - lab->height()));
2296 showChild(lab);
2297 taken.append( accesskey[ 0 ] );
2298 }
2299 }
2300 }
2301 if( use_fallbacks )
2302 return;
2303 TQPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
2304 for( TQPtrListIterator<KParts::ReadOnlyPart> it( frames );
2305 it != NULL;
2306 ++it ) {
2307 if( !(*it)->inherits( "TDEHTMLPart" ))
2308 continue;
2309 TDEHTMLPart* part = static_cast< TDEHTMLPart* >( *it );
2310 if( part->view() && part->view() != caller )
2311 part->view()->displayAccessKeys( this, origview, taken, use_fallbacks );
2312 }
2313 // pass up to the parent
2314 if (m_part->parentPart() && m_part->parentPart()->view()
2315 && m_part->parentPart()->view() != caller)
2316 m_part->parentPart()->view()->displayAccessKeys( this, origview, taken, use_fallbacks );
2317}
2318
2319
2320
2321void TDEHTMLView::accessKeysTimeout()
2322{
2323d->accessKeysActivated=false;
2324d->accessKeysPreActivate = false;
2325m_part->setStatusBarText(TQString::null, TDEHTMLPart::BarOverrideText);
2326emit hideAccessKeys();
2327}
2328
2329// Handling of the HTML accesskey attribute.
2330bool TDEHTMLView::handleAccessKey( const TQKeyEvent* ev )
2331{
2332// Qt interprets the keyevent also with the modifiers, and ev->text() matches that,
2333// but this code must act as if the modifiers weren't pressed
2334 TQChar c;
2335 if( ev->key() >= Key_A && ev->key() <= Key_Z )
2336 c = 'A' + ev->key() - Key_A;
2337 else if( ev->key() >= Key_0 && ev->key() <= Key_9 )
2338 c = '0' + ev->key() - Key_0;
2339 else {
2340 // TODO fake XKeyEvent and XLookupString ?
2341 // This below seems to work e.g. for eacute though.
2342 if( ev->text().length() == 1 )
2343 c = ev->text()[ 0 ];
2344 }
2345 if( c.isNull())
2346 return false;
2347 return focusNodeWithAccessKey( c );
2348}
2349
2350bool TDEHTMLView::focusNodeWithAccessKey( TQChar c, TDEHTMLView* caller )
2351{
2352 DocumentImpl *doc = m_part->xmlDocImpl();
2353 if( !doc )
2354 return false;
2355 ElementImpl* node = doc->findAccessKeyElement( c );
2356 if( !node ) {
2357 TQPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
2358 for( TQPtrListIterator<KParts::ReadOnlyPart> it( frames );
2359 it != NULL;
2360 ++it ) {
2361 if( !(*it)->inherits( "TDEHTMLPart" ))
2362 continue;
2363 TDEHTMLPart* part = static_cast< TDEHTMLPart* >( *it );
2364 if( part->view() && part->view() != caller
2365 && part->view()->focusNodeWithAccessKey( c, this ))
2366 return true;
2367 }
2368 // pass up to the parent
2369 if (m_part->parentPart() && m_part->parentPart()->view()
2370 && m_part->parentPart()->view() != caller
2371 && m_part->parentPart()->view()->focusNodeWithAccessKey( c, this ))
2372 return true;
2373 if( caller == NULL ) { // the active frame (where the accesskey was pressed)
2374 TQMap< ElementImpl*, TQChar > fallbacks = buildFallbackAccessKeys();
2375 for( TQMap< ElementImpl*, TQChar >::ConstIterator it = fallbacks.begin();
2376 it != fallbacks.end();
2377 ++it )
2378 if( *it == c ) {
2379 node = it.key();
2380 break;
2381 }
2382 }
2383 if( node == NULL )
2384 return false;
2385 }
2386
2387 // Scroll the view as necessary to ensure that the new focus node is visible
2388#ifndef TDEHTML_NO_CARET
2389 // if it's an editable element, activate the caret
2390 if (!m_part->isCaretMode() && !m_part->isEditable()
2391 && node->contentEditable()) {
2392 d->caretViewContext();
2393 moveCaretTo(node, 0L, true);
2394 } else {
2395 caretOff();
2396 }
2397#endif // TDEHTML_NO_CARET
2398
2399 TQRect r = node->getRect();
2400 ensureVisible( r.right(), r.bottom());
2401 ensureVisible( r.left(), r.top());
2402
2403 Node guard( node );
2404 if( node->isFocusable()) {
2405 if (node->id()==ID_LABEL) {
2406 // if Accesskey is a label, give focus to the label's referrer.
2407 node=static_cast<ElementImpl *>(static_cast< HTMLLabelElementImpl* >( node )->getFormElement());
2408 if (!node) return true;
2409 guard = node;
2410 }
2411 // Set focus node on the document
2412 TQFocusEvent::setReason( TQFocusEvent::Shortcut );
2413 m_part->xmlDocImpl()->setFocusNode(node);
2414 TQFocusEvent::resetReason();
2415 if( node != NULL && node->hasOneRef()) // deleted, only held by guard
2416 return true;
2417 emit m_part->nodeActivated(Node(node));
2418 if( node != NULL && node->hasOneRef())
2419 return true;
2420 }
2421
2422 switch( node->id()) {
2423 case ID_A:
2424 static_cast< HTMLAnchorElementImpl* >( node )->click();
2425 break;
2426 case ID_INPUT:
2427 static_cast< HTMLInputElementImpl* >( node )->click();
2428 break;
2429 case ID_BUTTON:
2430 static_cast< HTMLButtonElementImpl* >( node )->click();
2431 break;
2432 case ID_AREA:
2433 static_cast< HTMLAreaElementImpl* >( node )->click();
2434 break;
2435 case ID_TEXTAREA:
2436 break; // just focusing it is enough
2437 case ID_LEGEND:
2438 // TODO
2439 break;
2440 }
2441 return true;
2442}
2443
2444static TQString getElementText( NodeImpl* start, bool after )
2445{
2446 TQString ret; // nextSibling(), to go after e.g. </select>
2447 for( NodeImpl* n = after ? start->nextSibling() : start->traversePreviousNode();
2448 n != NULL;
2449 n = after ? n->traverseNextNode() : n->traversePreviousNode()) {
2450 if( n->isTextNode()) {
2451 if( after )
2452 ret += static_cast< TextImpl* >( n )->toString().string();
2453 else
2454 ret.prepend( static_cast< TextImpl* >( n )->toString().string());
2455 } else {
2456 switch( n->id()) {
2457 case ID_A:
2458 case ID_FONT:
2459 case ID_TT:
2460 case ID_U:
2461 case ID_B:
2462 case ID_I:
2463 case ID_S:
2464 case ID_STRIKE:
2465 case ID_BIG:
2466 case ID_SMALL:
2467 case ID_EM:
2468 case ID_STRONG:
2469 case ID_DFN:
2470 case ID_CODE:
2471 case ID_SAMP:
2472 case ID_KBD:
2473 case ID_VAR:
2474 case ID_CITE:
2475 case ID_ABBR:
2476 case ID_ACRONYM:
2477 case ID_SUB:
2478 case ID_SUP:
2479 case ID_SPAN:
2480 case ID_NOBR:
2481 case ID_WBR:
2482 break;
2483 case ID_TD:
2484 if( ret.stripWhiteSpace().isEmpty())
2485 break;
2486 // fall through
2487 default:
2488 return ret.simplifyWhiteSpace();
2489 }
2490 }
2491 }
2492 return ret.simplifyWhiteSpace();
2493}
2494
2495static TQMap< NodeImpl*, TQString > buildLabels( NodeImpl* start )
2496{
2497 TQMap< NodeImpl*, TQString > ret;
2498 for( NodeImpl* n = start;
2499 n != NULL;
2500 n = n->traverseNextNode()) {
2501 if( n->id() == ID_LABEL ) {
2502 HTMLLabelElementImpl* label = static_cast< HTMLLabelElementImpl* >( n );
2503 NodeImpl* labelfor = label->getFormElement();
2504 if( labelfor )
2505 ret[ labelfor ] = label->innerText().string().simplifyWhiteSpace();
2506 }
2507 }
2508 return ret;
2509}
2510
2511namespace tdehtml {
2512struct AccessKeyData {
2513 ElementImpl* element;
2514 TQString text;
2515 TQString url;
2516 int priority; // 10(highest) - 0(lowest)
2517};
2518}
2519
2520TQMap< ElementImpl*, TQChar > TDEHTMLView::buildFallbackAccessKeys() const
2521{
2522 // build a list of all possible candidate elements that could use an accesskey
2523 TQValueList< AccessKeyData > data;
2524 TQMap< NodeImpl*, TQString > labels = buildLabels( m_part->xmlDocImpl());
2525 for( NodeImpl* n = m_part->xmlDocImpl();
2526 n != NULL;
2527 n = n->traverseNextNode()) {
2528 if( n->isElementNode()) {
2529 ElementImpl* element = static_cast< ElementImpl* >( n );
2530 if( element->getAttribute( ATTR_ACCESSKEY ).length() == 1 )
2531 continue; // has accesskey set, ignore
2532 if( element->renderer() == NULL )
2533 continue; // not visible
2534 TQString text;
2535 TQString url;
2536 int priority = 0;
2537 bool ignore = false;
2538 bool text_after = false;
2539 bool text_before = false;
2540 switch( element->id()) {
2541 case ID_A:
2542 url = tdehtml::parseURL(element->getAttribute(ATTR_HREF)).string();
2543 if( url.isEmpty()) // doesn't have href, it's only an anchor
2544 continue;
2545 text = static_cast< HTMLElementImpl* >( element )->innerText().string().simplifyWhiteSpace();
2546 priority = 2;
2547 break;
2548 case ID_INPUT: {
2549 HTMLInputElementImpl* in = static_cast< HTMLInputElementImpl* >( element );
2550 switch( in->inputType()) {
2551 case HTMLInputElementImpl::SUBMIT:
2552 text = in->value().string();
2553 if( text.isEmpty())
2554 text = i18n( "Submit" );
2555 priority = 7;
2556 break;
2557 case HTMLInputElementImpl::IMAGE:
2558 text = in->altText().string();
2559 priority = 7;
2560 break;
2561 case HTMLInputElementImpl::BUTTON:
2562 text = in->value().string();
2563 priority = 5;
2564 break;
2565 case HTMLInputElementImpl::RESET:
2566 text = in->value().string();
2567 if( text.isEmpty())
2568 text = i18n( "Reset" );
2569 priority = 5;
2570 break;
2571 case HTMLInputElementImpl::HIDDEN:
2572 ignore = true;
2573 break;
2574 case HTMLInputElementImpl::CHECKBOX:
2575 case HTMLInputElementImpl::RADIO:
2576 text_after = true;
2577 priority = 5;
2578 break;
2579 case HTMLInputElementImpl::TEXT:
2580 case HTMLInputElementImpl::PASSWORD:
2581 case HTMLInputElementImpl::FILE:
2582 text_before = true;
2583 priority = 5;
2584 break;
2585 default:
2586 priority = 5;
2587 break;
2588 }
2589 break;
2590 }
2591 case ID_BUTTON:
2592 text = static_cast< HTMLElementImpl* >( element )->innerText().string().simplifyWhiteSpace();
2593 switch( static_cast< HTMLButtonElementImpl* >( element )->buttonType()) {
2594 case HTMLButtonElementImpl::SUBMIT:
2595 if( text.isEmpty())
2596 text = i18n( "Submit" );
2597 priority = 7;
2598 break;
2599 case HTMLButtonElementImpl::RESET:
2600 if( text.isEmpty())
2601 text = i18n( "Reset" );
2602 priority = 5;
2603 break;
2604 default:
2605 priority = 5;
2606 break;
2607 break;
2608 }
2609 case ID_SELECT: // these don't have accesskey attribute, but quick access may be handy
2610 text_before = true;
2611 text_after = true;
2612 priority = 5;
2613 break;
2614 case ID_FRAME:
2615 ignore = true;
2616 break;
2617 default:
2618 ignore = !element->isFocusable();
2619 priority = 2;
2620 break;
2621 }
2622 if( ignore )
2623 continue;
2624 if( text.isNull() && labels.contains( element ))
2625 text = labels[ element ];
2626 if( text.isNull() && text_before )
2627 text = getElementText( element, false );
2628 if( text.isNull() && text_after )
2629 text = getElementText( element, true );
2630 text = text.stripWhiteSpace();
2631 // increase priority of items which have explicitly specified accesskeys in the config
2632 TQValueList< TQPair< TQString, TQChar > > priorities
2633 = m_part->settings()->fallbackAccessKeysAssignments();
2634 for( TQValueList< TQPair< TQString, TQChar > >::ConstIterator it = priorities.begin();
2635 it != priorities.end();
2636 ++it ) {
2637 if( text == (*it).first )
2638 priority = 10;
2639 }
2640 AccessKeyData tmp = { element, text, url, priority };
2641 data.append( tmp );
2642 }
2643 }
2644
2645 TQValueList< TQChar > keys;
2646 for( char c = 'A'; c <= 'Z'; ++c )
2647 keys << c;
2648 for( char c = '0'; c <= '9'; ++c )
2649 keys << c;
2650 for( NodeImpl* n = m_part->xmlDocImpl();
2651 n != NULL;
2652 n = n->traverseNextNode()) {
2653 if( n->isElementNode()) {
2654 ElementImpl* en = static_cast< ElementImpl* >( n );
2655 DOMString s = en->getAttribute( ATTR_ACCESSKEY );
2656 if( s.length() == 1 ) {
2657 TQChar c = s.string()[ 0 ].upper();
2658 keys.remove( c ); // remove manually assigned accesskeys
2659 }
2660 }
2661 }
2662
2663 TQMap< ElementImpl*, TQChar > ret;
2664 for( int priority = 10;
2665 priority >= 0;
2666 --priority ) {
2667 for( TQValueList< AccessKeyData >::Iterator it = data.begin();
2668 it != data.end();
2669 ) {
2670 if( (*it).priority != priority ) {
2671 ++it;
2672 continue;
2673 }
2674 if( keys.isEmpty())
2675 break;
2676 TQString text = (*it).text;
2677 TQChar key;
2678 if( key.isNull() && !text.isEmpty()) {
2679 TQValueList< TQPair< TQString, TQChar > > priorities
2680 = m_part->settings()->fallbackAccessKeysAssignments();
2681 for( TQValueList< TQPair< TQString, TQChar > >::ConstIterator it = priorities.begin();
2682 it != priorities.end();
2683 ++it )
2684 if( text == (*it).first && keys.contains( (*it).second )) {
2685 key = (*it).second;
2686 break;
2687 }
2688 }
2689 // try first to select the first character as the accesskey,
2690 // then first character of the following words,
2691 // and then simply the first free character
2692 if( key.isNull() && !text.isEmpty()) {
2693 TQStringList words = TQStringList::split( ' ', text );
2694 for( TQStringList::ConstIterator it = words.begin();
2695 it != words.end();
2696 ++it ) {
2697 if( keys.contains( (*it)[ 0 ].upper())) {
2698 key = (*it)[ 0 ].upper();
2699 break;
2700 }
2701 }
2702 }
2703 if( key.isNull() && !text.isEmpty()) {
2704 for( unsigned int i = 0;
2705 i < text.length();
2706 ++i ) {
2707 if( keys.contains( text[ i ].upper())) {
2708 key = text[ i ].upper();
2709 break;
2710 }
2711 }
2712 }
2713 if( key.isNull())
2714 key = keys.front();
2715 ret[ (*it).element ] = key;
2716 keys.remove( key );
2717 TQString url = (*it).url;
2718 it = data.remove( it );
2719 // assign the same accesskey also to other elements pointing to the same url
2720 if( !url.isEmpty() && !url.startsWith( "javascript:", false )) {
2721 for( TQValueList< AccessKeyData >::Iterator it2 = data.begin();
2722 it2 != data.end();
2723 ) {
2724 if( (*it2).url == url ) {
2725 ret[ (*it2).element ] = key;
2726 if( it == it2 )
2727 ++it;
2728 it2 = data.remove( it2 );
2729 } else
2730 ++it2;
2731 }
2732 }
2733 }
2734 }
2735 return ret;
2736}
2737
2738void TDEHTMLView::setMediaType( const TQString &medium )
2739{
2740 m_medium = medium;
2741}
2742
2743TQString TDEHTMLView::mediaType() const
2744{
2745 return m_medium;
2746}
2747
2748bool TDEHTMLView::pagedMode() const
2749{
2750 return d->paged;
2751}
2752
2753void TDEHTMLView::setWidgetVisible(RenderWidget* w, bool vis)
2754{
2755 if (vis) {
2756 d->visibleWidgets.replace(w, w->widget());
2757 }
2758 else
2759 d->visibleWidgets.remove(w);
2760}
2761
2762bool TDEHTMLView::needsFullRepaint() const
2763{
2764 return d->needsFullRepaint;
2765}
2766
2767void TDEHTMLView::print()
2768{
2769 print( false );
2770}
2771
2772void TDEHTMLView::print(bool quick)
2773{
2774 if(!m_part->xmlDocImpl()) return;
2775 tdehtml::RenderCanvas *root = static_cast<tdehtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
2776 if(!root) return;
2777
2778 KPrinter *printer = new KPrinter(true, TQPrinter::ScreenResolution);
2779 printer->addDialogPage(new TDEHTMLPrintSettings());
2780 TQString docname = m_part->xmlDocImpl()->URL().prettyURL();
2781 if ( !docname.isEmpty() )
2782 docname = KStringHandler::csqueeze(docname, 80);
2783 if(quick || printer->setup(this, i18n("Print %1").arg(docname))) {
2784 viewport()->setCursor( TQt::waitCursor ); // only viewport(), no TQApplication::, otherwise we get the busy cursor in tdeprint's dialogs
2785 // set up KPrinter
2786 printer->setFullPage(false);
2787 printer->setCreator(TQString("TDE %1.%2.%3 HTML Library").arg(TDE_VERSION_MAJOR).arg(TDE_VERSION_MINOR).arg(TDE_VERSION_RELEASE));
2788 printer->setDocName(docname);
2789
2790 TQPainter *p = new TQPainter;
2791 p->begin( printer );
2792 tdehtml::setPrintPainter( p );
2793
2794 m_part->xmlDocImpl()->setPaintDevice( printer );
2795 TQString oldMediaType = mediaType();
2796 setMediaType( "print" );
2797 // We ignore margin settings for html and body when printing
2798 // and use the default margins from the print-system
2799 // (In Qt 3.0.x the default margins are hardcoded in Qt)
2800 m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("app-khtml-printfriendly") == "true" ?
2801 "* { background-image: none !important;"
2802 " background-color: white !important;"
2803 " color: black !important; }"
2804 "body { margin: 0px !important; }"
2805 "html { margin: 0px !important; }" :
2806 "body { margin: 0px !important; }"
2807 "html { margin: 0px !important; }"
2808 );
2809
2810 TQPaintDeviceMetrics metrics( printer );
2811
2812 kdDebug(6000) << "printing: physical page width = " << metrics.width()
2813 << " height = " << metrics.height() << endl;
2814 root->setStaticMode(true);
2815 root->setPagedMode(true);
2816 root->setWidth(metrics.width());
2817// root->setHeight(metrics.height());
2818 root->setPageTop(0);
2819 root->setPageBottom(0);
2820 d->paged = true;
2821
2822 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
2823 m_part->xmlDocImpl()->updateStyleSelector();
2824 root->setPrintImages( printer->option("app-khtml-printimages") == "true");
2825 root->makePageBreakAvoidBlocks();
2826
2827 root->setNeedsLayoutAndMinMaxRecalc();
2828 root->layout();
2829 tdehtml::RenderWidget::flushWidgetResizes(); // make sure widgets have their final size
2830
2831 // check sizes ask for action.. (scale or clip)
2832
2833 bool printHeader = (printer->option("app-khtml-printheader") == "true");
2834
2835 int headerHeight = 0;
2836 TQFont headerFont("Sans Serif", 8);
2837
2838 TQString headerLeft = TDEGlobal::locale()->formatDate(TQDate::currentDate(),true);
2839 TQString headerMid = docname;
2840 TQString headerRight;
2841
2842 if (printHeader)
2843 {
2844 p->setFont(headerFont);
2845 headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
2846 }
2847
2848 // ok. now print the pages.
2849 kdDebug(6000) << "printing: html page width = " << root->docWidth()
2850 << " height = " << root->docHeight() << endl;
2851 kdDebug(6000) << "printing: margins left = " << printer->margins().width()
2852 << " top = " << printer->margins().height() << endl;
2853 kdDebug(6000) << "printing: paper width = " << metrics.width()
2854 << " height = " << metrics.height() << endl;
2855 // if the width is too large to fit on the paper we just scale
2856 // the whole thing.
2857 int pageWidth = metrics.width();
2858 int pageHeight = metrics.height();
2859 p->setClipRect(0,0, pageWidth, pageHeight);
2860
2861 pageHeight -= headerHeight;
2862
2863 bool scalePage = false;
2864 double scale = 0.0;
2865#ifndef TQT_NO_TRANSFORMATIONS
2866 if(root->docWidth() > metrics.width()) {
2867 scalePage = true;
2868 scale = ((double) metrics.width())/((double) root->docWidth());
2869 pageHeight = (int) (pageHeight/scale);
2870 pageWidth = (int) (pageWidth/scale);
2871 headerHeight = (int) (headerHeight/scale);
2872 }
2873#endif
2874 kdDebug(6000) << "printing: scaled html width = " << pageWidth
2875 << " height = " << pageHeight << endl;
2876
2877 root->setHeight(pageHeight);
2878 root->setPageBottom(pageHeight);
2879 root->setNeedsLayout(true);
2880 root->layoutIfNeeded();
2881// m_part->slotDebugRenderTree();
2882
2883 // Squeeze header to make it it on the page.
2884 if (printHeader)
2885 {
2886 int available_width = metrics.width() - 10 -
2887 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), TQt::AlignLeft, headerLeft).width(),
2888 p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), TQt::AlignLeft, headerRight).width());
2889 if (available_width < 150)
2890 available_width = 150;
2891 int mid_width;
2892 int squeeze = 120;
2893 do {
2894 headerMid = KStringHandler::csqueeze(docname, squeeze);
2895 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), TQt::AlignLeft, headerMid).width();
2896 squeeze -= 10;
2897 } while (mid_width > available_width);
2898 }
2899
2900 int top = 0;
2901 int bottom = 0;
2902 int page = 1;
2903 while(top < root->docHeight()) {
2904 if(top > 0) printer->newPage();
2905 p->setClipRect(0, 0, pageWidth, headerHeight, TQPainter::CoordDevice);
2906 if (printHeader)
2907 {
2908 int dy = p->fontMetrics().lineSpacing();
2909 p->setPen(TQt::black);
2910 p->setFont(headerFont);
2911
2912 headerRight = TQString("#%1").arg(page);
2913
2914 p->drawText(0, 0, metrics.width(), dy, TQt::AlignLeft, headerLeft);
2915 p->drawText(0, 0, metrics.width(), dy, TQt::AlignHCenter, headerMid);
2916 p->drawText(0, 0, metrics.width(), dy, TQt::AlignRight, headerRight);
2917 }
2918
2919
2920#ifndef TQT_NO_TRANSFORMATIONS
2921 if (scalePage)
2922 p->scale(scale, scale);
2923#endif
2924
2925 p->setClipRect(0, headerHeight, pageWidth, pageHeight, TQPainter::CoordDevice);
2926 p->translate(0, headerHeight-top);
2927
2928 bottom = top+pageHeight;
2929
2930 root->setPageTop(top);
2931 root->setPageBottom(bottom);
2932 root->setPageNumber(page);
2933
2934 root->layer()->paint(p, TQRect(0, top, pageWidth, pageHeight));
2935// m_part->xmlDocImpl()->renderer()->layer()->paint(p, TQRect(0, top, pageWidth, pageHeight));
2936// root->repaint();
2937// p->flush();
2938 kdDebug(6000) << "printed: page " << page <<" bottom At = " << bottom << endl;
2939
2940 top = bottom;
2941 p->resetXForm();
2942 page++;
2943 }
2944
2945 p->end();
2946 delete p;
2947
2948 // and now reset the layout to the usual one...
2949 root->setPagedMode(false);
2950 root->setStaticMode(false);
2951 d->paged = false;
2952 tdehtml::setPrintPainter( 0 );
2953 setMediaType( oldMediaType );
2954 m_part->xmlDocImpl()->setPaintDevice( this );
2955 m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics(), m_part->zoomFactor());
2956 m_part->xmlDocImpl()->updateStyleSelector();
2957 viewport()->unsetCursor();
2958 }
2959 delete printer;
2960}
2961
2962void TDEHTMLView::slotPaletteChanged()
2963{
2964 if(!m_part->xmlDocImpl()) return;
2965 DOM::DocumentImpl *document = m_part->xmlDocImpl();
2966 if (!document->isHTMLDocument()) return;
2967 tdehtml::RenderCanvas *root = static_cast<tdehtml::RenderCanvas *>(document->renderer());
2968 if(!root) return;
2969 root->style()->resetPalette();
2970 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
2971 if(!body) return;
2972 body->setChanged(true);
2973 body->recalcStyle( NodeImpl::Force );
2974}
2975
2976void TDEHTMLView::paint(TQPainter *p, const TQRect &rc, int yOff, bool *more)
2977{
2978 if(!m_part->xmlDocImpl()) return;
2979 tdehtml::RenderCanvas *root = static_cast<tdehtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
2980 if(!root) return;
2981
2982 m_part->xmlDocImpl()->setPaintDevice(p->device());
2983 root->setPagedMode(true);
2984 root->setStaticMode(true);
2985 root->setWidth(rc.width());
2986
2987 p->save();
2988 p->setClipRect(rc);
2989 p->translate(rc.left(), rc.top());
2990 double scale = ((double) rc.width()/(double) root->docWidth());
2991 int height = (int) ((double) rc.height() / scale);
2992#ifndef TQT_NO_TRANSFORMATIONS
2993 p->scale(scale, scale);
2994#endif
2995 root->setPageTop(yOff);
2996 root->setPageBottom(yOff+height);
2997
2998 root->layer()->paint(p, TQRect(0, yOff, root->docWidth(), height));
2999 if (more)
3000 *more = yOff + height < root->docHeight();
3001 p->restore();
3002
3003 root->setPagedMode(false);
3004 root->setStaticMode(false);
3005 m_part->xmlDocImpl()->setPaintDevice( this );
3006}
3007
3008
3009void TDEHTMLView::useSlowRepaints()
3010{
3011 d->useSlowRepaints = true;
3012 setStaticBackground(true);
3013}
3014
3015
3016void TDEHTMLView::setVScrollBarMode ( ScrollBarMode mode )
3017{
3018#ifndef TDEHTML_NO_SCROLLBARS
3019 d->vmode = mode;
3020 TQScrollView::setVScrollBarMode(mode);
3021#else
3022 Q_UNUSED( mode );
3023#endif
3024}
3025
3026void TDEHTMLView::setHScrollBarMode ( ScrollBarMode mode )
3027{
3028#ifndef TDEHTML_NO_SCROLLBARS
3029 d->hmode = mode;
3030 TQScrollView::setHScrollBarMode(mode);
3031#else
3032 Q_UNUSED( mode );
3033#endif
3034}
3035
3036void TDEHTMLView::restoreScrollBar()
3037{
3038 int ow = visibleWidth();
3039 TQScrollView::setVScrollBarMode(d->vmode);
3040 if (visibleWidth() != ow)
3041 layout();
3042 d->prevScrollbarVisible = verticalScrollBar()->isVisible();
3043}
3044
3045TQStringList TDEHTMLView::formCompletionItems(const TQString &name) const
3046{
3047 if (!m_part->settings()->isFormCompletionEnabled())
3048 return TQStringList();
3049 if (!d->formCompletions)
3050 d->formCompletions = new KSimpleConfig(locateLocal("data", "tdehtml/formcompletions"));
3051 return d->formCompletions->readListEntry(name);
3052}
3053
3054void TDEHTMLView::clearCompletionHistory(const TQString& name)
3055{
3056 if (!d->formCompletions)
3057 {
3058 d->formCompletions = new KSimpleConfig(locateLocal("data", "tdehtml/formcompletions"));
3059 }
3060 d->formCompletions->writeEntry(name, "");
3061 d->formCompletions->sync();
3062}
3063
3064void TDEHTMLView::addFormCompletionItem(const TQString &name, const TQString &value)
3065{
3066 if (!m_part->settings()->isFormCompletionEnabled())
3067 return;
3068 // don't store values that are all numbers or just numbers with
3069 // dashes or spaces as those are likely credit card numbers or
3070 // something similar
3071 bool cc_number(true);
3072 for (unsigned int i = 0; i < value.length(); ++i)
3073 {
3074 TQChar c(value[i]);
3075 if (!c.isNumber() && c != '-' && !c.isSpace())
3076 {
3077 cc_number = false;
3078 break;
3079 }
3080 }
3081 if (cc_number)
3082 return;
3083 TQStringList items = formCompletionItems(name);
3084 if (!items.contains(value))
3085 items.prepend(value);
3086 while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
3087 items.remove(items.fromLast());
3088 d->formCompletions->writeEntry(name, items);
3089}
3090
3091void TDEHTMLView::removeFormCompletionItem(const TQString &name, const TQString &value)
3092{
3093 if (!m_part->settings()->isFormCompletionEnabled())
3094 return;
3095
3096 TQStringList items = formCompletionItems(name);
3097 if (items.remove(value))
3098 d->formCompletions->writeEntry(name, items);
3099}
3100
3101void TDEHTMLView::addNonPasswordStorableSite(const TQString& host)
3102{
3103 if (!d->formCompletions) {
3104 d->formCompletions = new KSimpleConfig(locateLocal("data", "tdehtml/formcompletions"));
3105 }
3106
3107 d->formCompletions->setGroup("NonPasswordStorableSites");
3108 TQStringList sites = d->formCompletions->readListEntry("Sites");
3109 sites.append(host);
3110 d->formCompletions->writeEntry("Sites", sites);
3111 d->formCompletions->sync();
3112 d->formCompletions->setGroup(TQString::null);//reset
3113}
3114
3115bool TDEHTMLView::nonPasswordStorableSite(const TQString& host) const
3116{
3117 if (!d->formCompletions) {
3118 d->formCompletions = new KSimpleConfig(locateLocal("data", "tdehtml/formcompletions"));
3119 }
3120 d->formCompletions->setGroup("NonPasswordStorableSites");
3121 TQStringList sites = d->formCompletions->readListEntry("Sites");
3122 d->formCompletions->setGroup(TQString::null);//reset
3123
3124 return (sites.find(host) != sites.end());
3125}
3126
3127// returns true if event should be swallowed
3128bool TDEHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode,
3129 DOM::NodeImpl *targetNodeNonShared, bool cancelable,
3130 int detail,TQMouseEvent *_mouse, bool setUnder,
3131 int mouseEventType)
3132{
3133 // if the target node is a text node, dispatch on the parent node - rdar://4196646 (and #76948)
3134 if (targetNode && targetNode->isTextNode())
3135 targetNode = targetNode->parentNode();
3136
3137 if (d->underMouse)
3138 d->underMouse->deref();
3139 d->underMouse = targetNode;
3140 if (d->underMouse)
3141 d->underMouse->ref();
3142
3143 if (d->underMouseNonShared)
3144 d->underMouseNonShared->deref();
3145 d->underMouseNonShared = targetNodeNonShared;
3146 if (d->underMouseNonShared)
3147 d->underMouseNonShared->ref();
3148
3149 int exceptioncode = 0;
3150 int pageX = 0;
3151 int pageY = 0;
3152 viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
3153 int clientX = pageX - contentsX();
3154 int clientY = pageY - contentsY();
3155 int screenX = _mouse->globalX();
3156 int screenY = _mouse->globalY();
3157 int button = -1;
3158 switch (_mouse->button()) {
3159 case TQt::LeftButton:
3160 button = 0;
3161 break;
3162 case TQt::MidButton:
3163 button = 1;
3164 break;
3165 case TQt::RightButton:
3166 button = 2;
3167 break;
3168 default:
3169 break;
3170 }
3171 if (d->accessKeysEnabled && d->accessKeysPreActivate && button!=-1)
3172 d->accessKeysPreActivate=false;
3173
3174 bool ctrlKey = (_mouse->state() & ControlButton);
3175 bool altKey = (_mouse->state() & AltButton);
3176 bool shiftKey = (_mouse->state() & ShiftButton);
3177 bool metaKey = (_mouse->state() & MetaButton);
3178
3179 // mouseout/mouseover
3180 if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
3181
3182 // ### this code sucks. we should save the oldUnder instead of calculating
3183 // it again. calculating is expensive! (Dirk)
3184 NodeImpl *oldUnder = 0;
3185 if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
3186 NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
3187 m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
3188 oldUnder = mev.innerNode.handle();
3189
3190 if (oldUnder && oldUnder->isTextNode())
3191 oldUnder = oldUnder->parentNode();
3192 }
3193// tqDebug("oldunder=%p (%s), target=%p (%s) x/y=%d/%d", oldUnder, oldUnder ? oldUnder->renderer()->renderName() : 0, targetNode, targetNode ? targetNode->renderer()->renderName() : 0, _mouse->x(), _mouse->y());
3194 if (oldUnder != targetNode) {
3195 // send mouseout event to the old node
3196 if (oldUnder){
3197 oldUnder->ref();
3198 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
3199 true,true,m_part->xmlDocImpl()->defaultView(),
3200 0,screenX,screenY,clientX,clientY,pageX, pageY,
3201 ctrlKey,altKey,shiftKey,metaKey,
3202 button,targetNode);
3203 me->ref();
3204 oldUnder->dispatchEvent(me,exceptioncode,true);
3205 me->deref();
3206 }
3207
3208 // send mouseover event to the new node
3209 if (targetNode) {
3210 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
3211 true,true,m_part->xmlDocImpl()->defaultView(),
3212 0,screenX,screenY,clientX,clientY,pageX, pageY,
3213 ctrlKey,altKey,shiftKey,metaKey,
3214 button,oldUnder);
3215
3216 me->ref();
3217 targetNode->dispatchEvent(me,exceptioncode,true);
3218 me->deref();
3219 }
3220
3221 if (oldUnder)
3222 oldUnder->deref();
3223 }
3224 }
3225
3226 bool swallowEvent = false;
3227
3228 if (targetNode) {
3229 // send the actual event
3230 bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
3231 _mouse->type() == TQEvent::MouseButtonDblClick );
3232 MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
3233 true,cancelable,m_part->xmlDocImpl()->defaultView(),
3234 detail,screenX,screenY,clientX,clientY,pageX, pageY,
3235 ctrlKey,altKey,shiftKey,metaKey,
3236 button,0, _mouse, dblclick );
3237 me->ref();
3238 targetNode->dispatchEvent(me,exceptioncode,true);
3239 bool defaultHandled = me->defaultHandled();
3240 if (defaultHandled || me->defaultPrevented())
3241 swallowEvent = true;
3242 me->deref();
3243
3244 if (eventId == EventImpl::MOUSEDOWN_EVENT) {
3245 // Focus should be shifted on mouse down, not on a click. -dwh
3246 // Blur current focus node when a link/button is clicked; this
3247 // is expected by some sites that rely on onChange handlers running
3248 // from form fields before the button click is processed.
3249 DOM::NodeImpl* nodeImpl = targetNode;
3250 for ( ; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode());
3251 if (nodeImpl && nodeImpl->isMouseFocusable())
3252 m_part->xmlDocImpl()->setFocusNode(nodeImpl);
3253 else if (!nodeImpl || !nodeImpl->focused())
3254 m_part->xmlDocImpl()->setFocusNode(0);
3255 }
3256 }
3257
3258 return swallowEvent;
3259}
3260
3261void TDEHTMLView::setIgnoreWheelEvents( bool e )
3262{
3263 d->ignoreWheelEvents = e;
3264}
3265
3266#ifndef TQT_NO_WHEELEVENT
3267
3268void TDEHTMLView::viewportWheelEvent(TQWheelEvent* e)
3269{
3270 if (d->accessKeysEnabled && d->accessKeysPreActivate) d->accessKeysPreActivate=false;
3271
3272 if ( ( e->state() & ControlButton) == ControlButton )
3273 {
3274 emit zoomView( - e->delta() );
3275 e->accept();
3276 }
3277 else if (d->firstRelayout)
3278 {
3279 e->accept();
3280 }
3281 else if( ( (e->orientation() == TQt::Vertical &&
3282 ((d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
3283 || e->delta() > 0 && contentsY() <= 0
3284 || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight()))
3285 ||
3286 (e->orientation() == TQt::Horizontal &&
3287 ((d->ignoreWheelEvents && !horizontalScrollBar()->isVisible())
3288 || e->delta() > 0 && contentsX() <=0
3289 || e->delta() < 0 && contentsX() >= contentsWidth() - visibleWidth())))
3290 && m_part->parentPart())
3291 {
3292 if ( m_part->parentPart()->view() )
3293 m_part->parentPart()->view()->wheelEvent( e );
3294 e->ignore();
3295 }
3296 else
3297 {
3298 d->scrollBarMoved = true;
3299#ifndef NO_SMOOTH_SCROLL_HACK
3300 scrollViewWheelEvent( e );
3301#else
3302 TQScrollView::viewportWheelEvent( e );
3303#endif
3304
3305 TQMouseEvent *tempEvent = new TQMouseEvent( TQEvent::MouseMove, TQPoint(-1,-1), TQPoint(-1,-1), TQt::NoButton, e->state() );
3306 emit viewportMouseMoveEvent ( tempEvent );
3307 delete tempEvent;
3308 }
3309
3310}
3311#endif
3312
3313void TDEHTMLView::dragEnterEvent( TQDragEnterEvent* ev )
3314{
3315 // Handle drops onto frames (#16820)
3316 // Drops on the main html part is handled by Konqueror (and shouldn't do anything
3317 // in e.g. kmail, so not handled here).
3318 if ( m_part->parentPart() )
3319 {
3320 TQApplication::sendEvent(m_part->parentPart()->widget(), ev);
3321 return;
3322 }
3323 TQScrollView::dragEnterEvent( ev );
3324}
3325
3326void TDEHTMLView::dropEvent( TQDropEvent *ev )
3327{
3328 // Handle drops onto frames (#16820)
3329 // Drops on the main html part is handled by Konqueror (and shouldn't do anything
3330 // in e.g. kmail, so not handled here).
3331 if ( m_part->parentPart() )
3332 {
3333 TQApplication::sendEvent(m_part->parentPart()->widget(), ev);
3334 return;
3335 }
3336 TQScrollView::dropEvent( ev );
3337}
3338
3339void TDEHTMLView::focusInEvent( TQFocusEvent *e )
3340{
3341#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
3342 m_part->enableFindAheadActions( true );
3343#endif
3344 DOM::NodeImpl* fn = m_part->xmlDocImpl() ? m_part->xmlDocImpl()->focusNode() : 0;
3345 if (fn && fn->renderer() && fn->renderer()->isWidget() &&
3346 (e->reason() != TQFocusEvent::Mouse) &&
3347 static_cast<tdehtml::RenderWidget*>(fn->renderer())->widget())
3348 static_cast<tdehtml::RenderWidget*>(fn->renderer())->widget()->setFocus();
3349#ifndef TDEHTML_NO_CARET
3350 // Restart blink frequency timer if it has been killed, but only on
3351 // editable nodes
3352 if (d->m_caretViewContext &&
3353 d->m_caretViewContext->freqTimerId == -1 &&
3354 fn) {
3355 if (m_part->isCaretMode()
3356 || m_part->isEditable()
3357 || (fn && fn->renderer()
3358 && fn->renderer()->style()->userInput()
3359 == UI_ENABLED)) {
3360 d->m_caretViewContext->freqTimerId = startTimer(500);
3361 d->m_caretViewContext->visible = true;
3362 }/*end if*/
3363 }/*end if*/
3364 showCaret();
3365#endif // TDEHTML_NO_CARET
3366 TQScrollView::focusInEvent( e );
3367}
3368
3369void TDEHTMLView::focusOutEvent( TQFocusEvent *e )
3370{
3371 if(m_part) m_part->stopAutoScroll();
3372
3373#ifndef TDEHTML_NO_TYPE_AHEAD_FIND
3374 if(d->typeAheadActivated)
3375 {
3376 findTimeout();
3377 }
3378 m_part->enableFindAheadActions( false );
3379#endif // TDEHTML_NO_TYPE_AHEAD_FIND
3380
3381#ifndef TDEHTML_NO_CARET
3382 if (d->m_caretViewContext) {
3383 switch (d->m_caretViewContext->displayNonFocused) {
3384 case TDEHTMLPart::CaretInvisible:
3385 hideCaret();
3386 break;
3387 case TDEHTMLPart::CaretVisible: {
3388 killTimer(d->m_caretViewContext->freqTimerId);
3389 d->m_caretViewContext->freqTimerId = -1;
3390 NodeImpl *caretNode = m_part->xmlDocImpl()->focusNode();
3391 if (!d->m_caretViewContext->visible && (m_part->isCaretMode()
3392 || m_part->isEditable()
3393 || (caretNode && caretNode->renderer()
3394 && caretNode->renderer()->style()->userInput()
3395 == UI_ENABLED))) {
3396 d->m_caretViewContext->visible = true;
3397 showCaret(true);
3398 }/*end if*/
3399 break;
3400 }
3401 case TDEHTMLPart::CaretBlink:
3402 // simply leave as is
3403 break;
3404 }/*end switch*/
3405 }/*end if*/
3406#endif // TDEHTML_NO_CARET
3407
3408 if ( d->cursor_icon_widget )
3409 d->cursor_icon_widget->hide();
3410
3411 TQScrollView::focusOutEvent( e );
3412}
3413
3414void TDEHTMLView::slotScrollBarMoved()
3415{
3416 if ( !d->firstRelayout && !d->complete && m_part->xmlDocImpl() &&
3417 d->layoutSchedulingEnabled) {
3418 // contents scroll while we are not complete: we need to check our layout *now*
3419 tdehtml::RenderCanvas* root = static_cast<tdehtml::RenderCanvas *>( m_part->xmlDocImpl()->renderer() );
3420 if (root && root->needsLayout()) {
3421 unscheduleRelayout();
3422 layout();
3423 }
3424 }
3425 if (!d->scrollingSelf) {
3426 d->scrollBarMoved = true;
3427 d->contentsMoving = true;
3428 // ensure quick reset of contentsMoving flag
3429 scheduleRepaint(0, 0, 0, 0);
3430 }
3431
3432 if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->documentElement())
3433 m_part->xmlDocImpl()->documentElement()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false);
3434}
3435
3436void TDEHTMLView::timerEvent ( TQTimerEvent *e )
3437{
3438// kdDebug() << "timer event " << e->timerId() << endl;
3439 if ( e->timerId() == d->scrollTimerId ) {
3440 if( d->scrollSuspended )
3441 return;
3442 switch (d->scrollDirection) {
3443 case TDEHTMLViewPrivate::ScrollDown:
3444 if (contentsY() + visibleHeight () >= contentsHeight())
3445 d->newScrollTimer(this, 0);
3446 else
3447 scrollBy( 0, d->scrollBy );
3448 break;
3449 case TDEHTMLViewPrivate::ScrollUp:
3450 if (contentsY() <= 0)
3451 d->newScrollTimer(this, 0);
3452 else
3453 scrollBy( 0, -d->scrollBy );
3454 break;
3455 case TDEHTMLViewPrivate::ScrollRight:
3456 if (contentsX() + visibleWidth () >= contentsWidth())
3457 d->newScrollTimer(this, 0);
3458 else
3459 scrollBy( d->scrollBy, 0 );
3460 break;
3461 case TDEHTMLViewPrivate::ScrollLeft:
3462 if (contentsX() <= 0)
3463 d->newScrollTimer(this, 0);
3464 else
3465 scrollBy( -d->scrollBy, 0 );
3466 break;
3467 }
3468 return;
3469 }
3470 else if ( e->timerId() == d->layoutTimerId ) {
3471 d->dirtyLayout = true;
3472 layout();
3473 if (d->firstRelayout) {
3474 d->firstRelayout = false;
3475 verticalScrollBar()->setEnabled( true );
3476 horizontalScrollBar()->setEnabled( true );
3477 }
3478 }
3479#ifndef TDEHTML_NO_CARET
3480 else if (d->m_caretViewContext
3481 && e->timerId() == d->m_caretViewContext->freqTimerId) {
3482 d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
3483 if (d->m_caretViewContext->displayed) {
3484 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
3485 d->m_caretViewContext->width,
3486 d->m_caretViewContext->height);
3487 }/*end if*/
3488// if (d->m_caretViewContext->visible) cout << "|" << flush;
3489// else cout << "" << flush;
3490 return;
3491 }
3492#endif
3493
3494 d->contentsMoving = false;
3495 if( m_part->xmlDocImpl() ) {
3496 DOM::DocumentImpl *document = m_part->xmlDocImpl();
3497 tdehtml::RenderCanvas* root = static_cast<tdehtml::RenderCanvas *>(document->renderer());
3498
3499 if ( root && root->needsLayout() ) {
3500 killTimer(d->repaintTimerId);
3501 d->repaintTimerId = 0;
3502 scheduleRelayout();
3503 return;
3504 }
3505 }
3506
3507 setStaticBackground(d->useSlowRepaints);
3508
3509// kdDebug() << "scheduled repaint "<< d->repaintTimerId << endl;
3510 killTimer(d->repaintTimerId);
3511 d->repaintTimerId = 0;
3512
3513 TQRect updateRegion;
3514 TQMemArray<TQRect> rects = d->updateRegion.rects();
3515
3516 d->updateRegion = TQRegion();
3517
3518 if ( rects.size() )
3519 updateRegion = rects[0];
3520
3521 for ( unsigned i = 1; i < rects.size(); ++i ) {
3522 TQRect newRegion = updateRegion.unite(rects[i]);
3523 if (2*newRegion.height() > 3*updateRegion.height() )
3524 {
3525 repaintContents( updateRegion );
3526 updateRegion = rects[i];
3527 }
3528 else
3529 updateRegion = newRegion;
3530 }
3531
3532 if ( !updateRegion.isNull() )
3533 repaintContents( updateRegion );
3534
3535 // As widgets can only be accurately positioned during painting, every layout might
3536 // dissociate a widget from its RenderWidget. E.g: if a RenderWidget was visible before layout, but the layout
3537 // pushed it out of the viewport, it will not be repainted, and consequently it's assocoated widget won't be repositioned!
3538 // Thus we need to check each supposedly 'visible' widget at the end of each layout, and remove it in case it's no more in sight.
3539
3540 if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
3541 TQWidget* w;
3542 d->dirtyLayout = false;
3543
3544 TQRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
3545 TQPtrList<RenderWidget> toRemove;
3546 for (TQPtrDictIterator<TQWidget> it(d->visibleWidgets); it.current(); ++it) {
3547 int xp = 0, yp = 0;
3548 w = it.current();
3549 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
3550 if (!rw->absolutePosition(xp, yp) ||
3551 !visibleRect.intersects(TQRect(xp, yp, w->width(), w->height())))
3552 toRemove.append(rw);
3553 }
3554 for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
3555 if ( (w = d->visibleWidgets.take(r) ) )
3556 addChild(w, 0, -500000);
3557 }
3558
3559 emit repaintAccessKeys();
3560 if (d->emitCompletedAfterRepaint) {
3561 bool full = d->emitCompletedAfterRepaint == TDEHTMLViewPrivate::CSFull;
3562 d->emitCompletedAfterRepaint = TDEHTMLViewPrivate::CSNone;
3563 if ( full )
3564 emit m_part->completed();
3565 else
3566 emit m_part->completed(true);
3567 }
3568}
3569
3570void TDEHTMLView::scheduleRelayout(tdehtml::RenderObject * /*clippedObj*/)
3571{
3572 if (!d->layoutSchedulingEnabled || d->layoutTimerId)
3573 return;
3574
3575 d->layoutTimerId = startTimer( m_part->xmlDocImpl() && m_part->xmlDocImpl()->parsing()
3576 ? 1000 : 0 );
3577}
3578
3579void TDEHTMLView::unscheduleRelayout()
3580{
3581 if (!d->layoutTimerId)
3582 return;
3583
3584 killTimer(d->layoutTimerId);
3585 d->layoutTimerId = 0;
3586}
3587
3588void TDEHTMLView::unscheduleRepaint()
3589{
3590 if (!d->repaintTimerId)
3591 return;
3592
3593 killTimer(d->repaintTimerId);
3594 d->repaintTimerId = 0;
3595}
3596
3597void TDEHTMLView::scheduleRepaint(int x, int y, int w, int h, bool asap)
3598{
3599 bool parsing = !m_part->xmlDocImpl() || m_part->xmlDocImpl()->parsing();
3600
3601// kdDebug() << "parsing " << parsing << endl;
3602// kdDebug() << "complete " << d->complete << endl;
3603
3604 int time = parsing ? 300 : (!asap ? ( !d->complete ? 100 : 20 ) : 0);
3605
3606#ifdef DEBUG_FLICKER
3607 TQPainter p;
3608 p.begin( viewport() );
3609
3610 int vx, vy;
3611 contentsToViewport( x, y, vx, vy );
3612 p.fillRect( vx, vy, w, h, TQt::red );
3613 p.end();
3614#endif
3615
3616 d->updateRegion = d->updateRegion.unite(TQRect(x,y,w,h));
3617
3618 if (asap && !parsing)
3619 unscheduleRepaint();
3620
3621 if ( !d->repaintTimerId )
3622 d->repaintTimerId = startTimer( time );
3623
3624// kdDebug() << "starting timer " << time << endl;
3625}
3626
3627void TDEHTMLView::complete( bool pendingAction )
3628{
3629// kdDebug() << "TDEHTMLView::complete()" << endl;
3630
3631 d->complete = true;
3632
3633 // is there a relayout pending?
3634 if (d->layoutTimerId)
3635 {
3636// kdDebug() << "requesting relayout now" << endl;
3637 // do it now
3638 killTimer(d->layoutTimerId);
3639 d->layoutTimerId = startTimer( 0 );
3640 d->emitCompletedAfterRepaint = pendingAction ?
3641 TDEHTMLViewPrivate::CSActionPending : TDEHTMLViewPrivate::CSFull;
3642 }
3643
3644 // is there a repaint pending?
3645 if (d->repaintTimerId)
3646 {
3647// kdDebug() << "requesting repaint now" << endl;
3648 // do it now
3649 killTimer(d->repaintTimerId);
3650 d->repaintTimerId = startTimer( 20 );
3651 d->emitCompletedAfterRepaint = pendingAction ?
3652 TDEHTMLViewPrivate::CSActionPending : TDEHTMLViewPrivate::CSFull;
3653 }
3654
3655 if (!d->emitCompletedAfterRepaint)
3656 {
3657 if (!pendingAction)
3658 emit m_part->completed();
3659 else
3660 emit m_part->completed(true);
3661 }
3662
3663}
3664
3665void TDEHTMLView::slotMouseScrollTimer()
3666{
3667 scrollBy( d->m_mouseScroll_byX, d->m_mouseScroll_byY );
3668}
3669
3670#ifndef TDEHTML_NO_CARET
3671
3672// ### the dependencies on static functions are a nightmare. just be
3673// hacky and include the implementation here. Clean me up, please.
3674
3675#include "tdehtml_caret.cpp"
3676
3677void TDEHTMLView::initCaret(bool keepSelection)
3678{
3679#if DEBUG_CARETMODE > 0
3680 kdDebug(6200) << "begin initCaret" << endl;
3681#endif
3682 // save caretMoved state as moveCaretTo changes it
3683 if (m_part->xmlDocImpl()) {
3684#if 0
3685 ElementImpl *listitem = m_part->xmlDocImpl()->getElementById("__test_element__");
3686 if (listitem) dumpLineBoxes(static_cast<RenderFlow *>(listitem->renderer()));
3687#endif
3688 d->caretViewContext();
3689 bool cmoved = d->m_caretViewContext->caretMoved;
3690 if (m_part->d->caretNode().isNull()) {
3691 // set to document, position will be sanitized anyway
3692 m_part->d->caretNode() = m_part->document();
3693 m_part->d->caretOffset() = 0L;
3694 // This sanity check is necessary for the not so unlikely case that
3695 // setEditable or setCaretMode is called before any render objects have
3696 // been created.
3697 if (!m_part->d->caretNode().handle()->renderer()) return;
3698 }/*end if*/
3699// kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
3700// << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
3701 // ### does not repaint the selection on keepSelection!=false
3702 moveCaretTo(m_part->d->caretNode().handle(), m_part->d->caretOffset(), !keepSelection);
3703// kdDebug(6200) << "d->m_selectionStart " << m_part->d->m_selectionStart.handle()
3704// << " d->m_selectionEnd " << m_part->d->m_selectionEnd.handle() << endl;
3705 d->m_caretViewContext->caretMoved = cmoved;
3706 }/*end if*/
3707#if DEBUG_CARETMODE > 0
3708 kdDebug(6200) << "end initCaret" << endl;
3709#endif
3710}
3711
3712bool TDEHTMLView::caretOverrides() const
3713{
3714 bool cm = m_part->isCaretMode();
3715 bool dm = m_part->isEditable();
3716 return cm && !dm ? false
3717 : (dm || m_part->d->caretNode().handle()->contentEditable())
3718 && d->editorContext()->override;
3719}
3720
3721void TDEHTMLView::ensureNodeHasFocus(NodeImpl *node)
3722{
3723 if (m_part->isCaretMode() || m_part->isEditable()) return;
3724 if (node->focused()) return;
3725
3726 // Find first ancestor whose "user-input" is "enabled"
3727 NodeImpl *firstAncestor = 0;
3728 while (node) {
3729 if (node->renderer()
3730 && node->renderer()->style()->userInput() != UI_ENABLED)
3731 break;
3732 firstAncestor = node;
3733 node = node->parentNode();
3734 }/*wend*/
3735
3736 if (!node) firstAncestor = 0;
3737
3738 DocumentImpl *doc = m_part->xmlDocImpl();
3739 // ensure that embedded widgets don't lose their focus
3740 if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
3741 && doc->focusNode()->renderer()->isWidget())
3742 return;
3743
3744 // Set focus node on the document
3745#if DEBUG_CARETMODE > 1
3746 kdDebug(6200) << k_funcinfo << "firstAncestor " << firstAncestor << ": "
3747 << (firstAncestor ? firstAncestor->nodeName().string() : TQString::null) << endl;
3748#endif
3749 doc->setFocusNode(firstAncestor);
3750 emit m_part->nodeActivated(Node(firstAncestor));
3751}
3752
3753void TDEHTMLView::recalcAndStoreCaretPos(CaretBox *hintBox)
3754{
3755 if (!m_part || m_part->d->caretNode().isNull()) return;
3756 d->caretViewContext();
3757 NodeImpl *caretNode = m_part->d->caretNode().handle();
3758#if DEBUG_CARETMODE > 0
3759 kdDebug(6200) << "recalcAndStoreCaretPos: caretNode=" << caretNode << (caretNode ? " "+caretNode->nodeName().string() : TQString::null) << " r@" << caretNode->renderer() << (caretNode->renderer() && caretNode->renderer()->isText() ? " \"" + TQConstString(static_cast<RenderText *>(caretNode->renderer())->str->s, kMin(static_cast<RenderText *>(caretNode->renderer())->str->l, 15u)).string() + "\"" : TQString::null) << endl;
3760#endif
3761 caretNode->getCaret(m_part->d->caretOffset(), caretOverrides(),
3762 d->m_caretViewContext->x, d->m_caretViewContext->y,
3763 d->m_caretViewContext->width,
3764 d->m_caretViewContext->height);
3765
3766 if (hintBox && d->m_caretViewContext->x == -1) {
3767#if DEBUG_CARETMODE > 1
3768 kdDebug(6200) << "using hint inline box coordinates" << endl;
3769#endif
3770 RenderObject *r = caretNode->renderer();
3771 const TQFontMetrics &fm = r->style()->fontMetrics();
3772 int absx, absy;
3773 r->containingBlock()->absolutePosition(absx, absy,
3774 false); // ### what about fixed?
3775 d->m_caretViewContext->x = absx + hintBox->xPos();
3776 d->m_caretViewContext->y = absy + hintBox->yPos();
3777// + hintBox->baseline() - fm.ascent();
3778 d->m_caretViewContext->width = 1;
3779 // ### firstline not regarded. But I think it can be safely neglected
3780 // as hint boxes are only used for empty lines.
3781 d->m_caretViewContext->height = fm.height();
3782 }/*end if*/
3783
3784#if DEBUG_CARETMODE > 4
3785// kdDebug(6200) << "freqTimerId: "<<d->m_caretViewContext->freqTimerId<<endl;
3786#endif
3787#if DEBUG_CARETMODE > 0
3788 kdDebug(6200) << "caret: ofs="<<m_part->d->caretOffset()<<" "
3789 <<" x="<<d->m_caretViewContext->x<<" y="<<d->m_caretViewContext->y
3790 <<" h="<<d->m_caretViewContext->height<<endl;
3791#endif
3792}
3793
3794void TDEHTMLView::caretOn()
3795{
3796 if (d->m_caretViewContext) {
3797 killTimer(d->m_caretViewContext->freqTimerId);
3798
3799 if (hasFocus() || d->m_caretViewContext->displayNonFocused
3800 == TDEHTMLPart::CaretBlink) {
3801 d->m_caretViewContext->freqTimerId = startTimer(500);
3802 } else {
3803 d->m_caretViewContext->freqTimerId = -1;
3804 }/*end if*/
3805
3806 d->m_caretViewContext->visible = true;
3807 if ((d->m_caretViewContext->displayed = (hasFocus()
3808 || d->m_caretViewContext->displayNonFocused
3809 != TDEHTMLPart::CaretInvisible))) {
3810 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
3811 d->m_caretViewContext->width,
3812 d->m_caretViewContext->height);
3813 }/*end if*/
3814// kdDebug(6200) << "caret on" << endl;
3815 }/*end if*/
3816}
3817
3818void TDEHTMLView::caretOff()
3819{
3820 if (d->m_caretViewContext) {
3821 killTimer(d->m_caretViewContext->freqTimerId);
3822 d->m_caretViewContext->freqTimerId = -1;
3823 d->m_caretViewContext->displayed = false;
3824 if (d->m_caretViewContext->visible) {
3825 d->m_caretViewContext->visible = false;
3826 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
3827 d->m_caretViewContext->width,
3828 d->m_caretViewContext->height);
3829 }/*end if*/
3830// kdDebug(6200) << "caret off" << endl;
3831 }/*end if*/
3832}
3833
3834void TDEHTMLView::showCaret(bool forceRepaint)
3835{
3836 if (d->m_caretViewContext) {
3837 d->m_caretViewContext->displayed = true;
3838 if (d->m_caretViewContext->visible) {
3839 if (!forceRepaint) {
3840 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
3841 d->m_caretViewContext->width,
3842 d->m_caretViewContext->height);
3843 } else {
3844 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
3845 d->m_caretViewContext->width,
3846 d->m_caretViewContext->height);
3847 }/*end if*/
3848 }/*end if*/
3849// kdDebug(6200) << "caret shown" << endl;
3850 }/*end if*/
3851}
3852
3853bool TDEHTMLView::foldSelectionToCaret(NodeImpl *startNode, long startOffset,
3854 NodeImpl *endNode, long endOffset)
3855{
3856 m_part->d->m_selectionStart = m_part->d->m_selectionEnd = m_part->d->caretNode();
3857 m_part->d->m_startOffset = m_part->d->m_endOffset = m_part->d->caretOffset();
3858 m_part->d->m_extendAtEnd = true;
3859
3860 bool folded = startNode != endNode || startOffset != endOffset;
3861
3862 // Only clear the selection if there has been one.
3863 if (folded) {
3864 m_part->xmlDocImpl()->clearSelection();
3865 }/*end if*/
3866
3867 return folded;
3868}
3869
3870void TDEHTMLView::hideCaret()
3871{
3872 if (d->m_caretViewContext) {
3873 if (d->m_caretViewContext->visible) {
3874// kdDebug(6200) << "redraw caret hidden" << endl;
3875 d->m_caretViewContext->visible = false;
3876 // force repaint, otherwise the event won't be handled
3877 // before the focus leaves the window
3878 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
3879 d->m_caretViewContext->width,
3880 d->m_caretViewContext->height);
3881 d->m_caretViewContext->visible = true;
3882 }/*end if*/
3883 d->m_caretViewContext->displayed = false;
3884// kdDebug(6200) << "caret hidden" << endl;
3885 }/*end if*/
3886}
3887
3888int TDEHTMLView::caretDisplayPolicyNonFocused() const
3889{
3890 if (d->m_caretViewContext)
3891 return d->m_caretViewContext->displayNonFocused;
3892 else
3893 return TDEHTMLPart::CaretInvisible;
3894}
3895
3896void TDEHTMLView::setCaretDisplayPolicyNonFocused(int policy)
3897{
3898 d->caretViewContext();
3899// int old = d->m_caretViewContext->displayNonFocused;
3900 d->m_caretViewContext->displayNonFocused = (TDEHTMLPart::CaretDisplayPolicy)policy;
3901
3902 // make change immediately take effect if not focused
3903 if (!hasFocus()) {
3904 switch (d->m_caretViewContext->displayNonFocused) {
3905 case TDEHTMLPart::CaretInvisible:
3906 hideCaret();
3907 break;
3908 case TDEHTMLPart::CaretBlink:
3909 if (d->m_caretViewContext->freqTimerId != -1) break;
3910 d->m_caretViewContext->freqTimerId = startTimer(500);
3911 // fall through
3912 case TDEHTMLPart::CaretVisible:
3913 d->m_caretViewContext->displayed = true;
3914 showCaret();
3915 break;
3916 }/*end switch*/
3917 }/*end if*/
3918}
3919
3920bool TDEHTMLView::placeCaret(CaretBox *hintBox)
3921{
3922 CaretViewContext *cv = d->caretViewContext();
3923 caretOff();
3924 NodeImpl *caretNode = m_part->d->caretNode().handle();
3925 // ### why is it sometimes null?
3926 if (!caretNode || !caretNode->renderer()) return false;
3927 ensureNodeHasFocus(caretNode);
3928 if (m_part->isCaretMode() || m_part->isEditable()
3929 || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
3930 recalcAndStoreCaretPos(hintBox);
3931
3932 cv->origX = cv->x;
3933
3934 caretOn();
3935 return true;
3936 }/*end if*/
3937 return false;
3938}
3939
3940void TDEHTMLView::ensureCaretVisible()
3941{
3942 CaretViewContext *cv = d->m_caretViewContext;
3943 if (!cv) return;
3944 ensureVisible(cv->x, cv->y, cv->width, cv->height);
3945 d->scrollBarMoved = false;
3946}
3947
3948bool TDEHTMLView::extendSelection(NodeImpl *oldStartSel, long oldStartOfs,
3949 NodeImpl *oldEndSel, long oldEndOfs)
3950{
3951 bool changed = false;
3952 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
3953 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
3954 changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
3955 m_part->d->m_extendAtEnd = true;
3956 } else do {
3957 changed = m_part->d->m_selectionStart.handle() != oldStartSel
3958 || m_part->d->m_startOffset != oldStartOfs
3959 || m_part->d->m_selectionEnd.handle() != oldEndSel
3960 || m_part->d->m_endOffset != oldEndOfs;
3961 if (!changed) break;
3962
3963 // determine start position -- caret position is always at end.
3964 NodeImpl *startNode;
3965 long startOffset;
3966 if (m_part->d->m_extendAtEnd) {
3967 startNode = m_part->d->m_selectionStart.handle();
3968 startOffset = m_part->d->m_startOffset;
3969 } else {
3970 startNode = m_part->d->m_selectionEnd.handle();
3971 startOffset = m_part->d->m_endOffset;
3972 m_part->d->m_selectionEnd = m_part->d->m_selectionStart;
3973 m_part->d->m_endOffset = m_part->d->m_startOffset;
3974 m_part->d->m_extendAtEnd = true;
3975 }/*end if*/
3976
3977 bool swapNeeded = false;
3978 if (!m_part->d->m_selectionEnd.isNull() && startNode) {
3979 swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
3980 m_part->d->m_selectionEnd.handle(),
3981 m_part->d->m_endOffset) >= 0;
3982 }/*end if*/
3983
3984 m_part->d->m_selectionStart = startNode;
3985 m_part->d->m_startOffset = startOffset;
3986
3987 if (swapNeeded) {
3988 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionEnd.handle(),
3989 m_part->d->m_endOffset, m_part->d->m_selectionStart.handle(),
3990 m_part->d->m_startOffset);
3991 } else {
3992 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
3993 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
3994 m_part->d->m_endOffset);
3995 }/*end if*/
3996 } while(false);/*end if*/
3997 return changed;
3998}
3999
4000void TDEHTMLView::updateSelection(NodeImpl *oldStartSel, long oldStartOfs,
4001 NodeImpl *oldEndSel, long oldEndOfs)
4002{
4003 if (m_part->d->m_selectionStart == m_part->d->m_selectionEnd
4004 && m_part->d->m_startOffset == m_part->d->m_endOffset) {
4005 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
4006 m_part->emitSelectionChanged();
4007 }/*end if*/
4008 m_part->d->m_extendAtEnd = true;
4009 } else {
4010 // check if the extending end has passed the immobile end
4011 if (!m_part->d->m_selectionEnd.isNull() && !m_part->d->m_selectionEnd.isNull()) {
4012 bool swapNeeded = RangeImpl::compareBoundaryPoints(
4013 m_part->d->m_selectionStart.handle(), m_part->d->m_startOffset,
4014 m_part->d->m_selectionEnd.handle(), m_part->d->m_endOffset) >= 0;
4015 if (swapNeeded) {
4016 DOM::Node tmpNode = m_part->d->m_selectionStart;
4017 long tmpOffset = m_part->d->m_startOffset;
4018 m_part->d->m_selectionStart = m_part->d->m_selectionEnd;
4019 m_part->d->m_startOffset = m_part->d->m_endOffset;
4020 m_part->d->m_selectionEnd = tmpNode;
4021 m_part->d->m_endOffset = tmpOffset;
4022 m_part->d->m_startBeforeEnd = true;
4023 m_part->d->m_extendAtEnd = !m_part->d->m_extendAtEnd;
4024 }/*end if*/
4025 }/*end if*/
4026
4027 m_part->xmlDocImpl()->setSelection(m_part->d->m_selectionStart.handle(),
4028 m_part->d->m_startOffset, m_part->d->m_selectionEnd.handle(),
4029 m_part->d->m_endOffset);
4030 m_part->emitSelectionChanged();
4031 }/*end if*/
4032}
4033
4034void TDEHTMLView::caretKeyPressEvent(TQKeyEvent *_ke)
4035{
4036 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
4037 long oldStartOfs = m_part->d->m_startOffset;
4038 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
4039 long oldEndOfs = m_part->d->m_endOffset;
4040
4041 NodeImpl *oldCaretNode = m_part->d->caretNode().handle();
4042 long oldOffset = m_part->d->caretOffset();
4043
4044 bool ctrl = _ke->state() & ControlButton;
4045
4046// FIXME: this is that widely indented because I will write ifs around it.
4047 switch(_ke->key()) {
4048 case Key_Space:
4049 break;
4050
4051 case Key_Down:
4052 moveCaretNextLine(1);
4053 break;
4054
4055 case Key_Up:
4056 moveCaretPrevLine(1);
4057 break;
4058
4059 case Key_Left:
4060 moveCaretBy(false, ctrl ? CaretByWord : CaretByCharacter, 1);
4061 break;
4062
4063 case Key_Right:
4064 moveCaretBy(true, ctrl ? CaretByWord : CaretByCharacter, 1);
4065 break;
4066
4067 case Key_Next:
4068 moveCaretNextPage();
4069 break;
4070
4071 case Key_Prior:
4072 moveCaretPrevPage();
4073 break;
4074
4075 case Key_Home:
4076 if (ctrl)
4077 moveCaretToDocumentBoundary(false);
4078 else
4079 moveCaretToLineBegin();
4080 break;
4081
4082 case Key_End:
4083 if (ctrl)
4084 moveCaretToDocumentBoundary(true);
4085 else
4086 moveCaretToLineEnd();
4087 break;
4088
4089 }/*end switch*/
4090
4091 if ((m_part->d->caretNode().handle() != oldCaretNode
4092 || m_part->d->caretOffset() != oldOffset)
4093 // node should never be null, but faulty conditions may cause it to be
4094 && !m_part->d->caretNode().isNull()) {
4095
4096 d->m_caretViewContext->caretMoved = true;
4097
4098 if (_ke->state() & ShiftButton) { // extend selection
4099 updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
4100 } else { // clear any selection
4101 if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
4102 m_part->emitSelectionChanged();
4103 }/*end if*/
4104
4105 m_part->emitCaretPositionChanged(m_part->d->caretNode(), m_part->d->caretOffset());
4106 }/*end if*/
4107
4108 _ke->accept();
4109}
4110
4111bool TDEHTMLView::moveCaretTo(NodeImpl *node, long offset, bool clearSel)
4112{
4113 if (!node) return false;
4114 ElementImpl *baseElem = determineBaseElement(node);
4115 RenderFlow *base = static_cast<RenderFlow *>(baseElem ? baseElem->renderer() : 0);
4116 if (!node) return false;
4117
4118 // need to find out the node's inline box. If there is none, this function
4119 // will snap to the next node that has one. This is necessary to make the
4120 // caret visible in any case.
4121 CaretBoxLineDeleter cblDeleter;
4122// RenderBlock *cb;
4123 long r_ofs;
4124 CaretBoxIterator cbit;
4125 CaretBoxLine *cbl = findCaretBoxLine(node, offset, &cblDeleter, base, r_ofs, cbit);
4126 if(!cbl) {
4127 kdWarning() << "TDEHTMLView::moveCaretTo - findCaretBoxLine() returns NULL" << endl;
4128 return false;
4129 }
4130
4131#if DEBUG_CARETMODE > 3
4132 if (cbl) kdDebug(6200) << cbl->information() << endl;
4133#endif
4134 CaretBox *box = *cbit;
4135 if (cbit != cbl->end() && box->object() != node->renderer()) {
4136 if (box->object()->element()) {
4137 mapRenderPosToDOMPos(box->object(), r_ofs, box->isOutside(),
4138 box->isOutsideEnd(), node, offset);
4139 //if (!outside) offset = node->minOffset();
4140#if DEBUG_CARETMODE > 1
4141 kdDebug(6200) << "set new node " << node->nodeName().string() << "@" << node << endl;
4142#endif
4143 } else { // box has no associated element -> do not use
4144 // this case should actually never happen.
4145 box = 0;
4146 kdError(6200) << "Box contains no node! Crash imminent" << endl;
4147 }/*end if*/
4148 }
4149
4150 NodeImpl *oldStartSel = m_part->d->m_selectionStart.handle();
4151 long oldStartOfs = m_part->d->m_startOffset;
4152 NodeImpl *oldEndSel = m_part->d->m_selectionEnd.handle();
4153 long oldEndOfs = m_part->d->m_endOffset;
4154
4155 // test for position change
4156 bool posChanged = m_part->d->caretNode().handle() != node
4157 || m_part->d->caretOffset() != offset;
4158 bool selChanged = false;
4159
4160 m_part->d->caretNode() = node;
4161 m_part->d->caretOffset() = offset;
4162 if (clearSel || !oldStartSel || !oldEndSel) {
4163 selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
4164 } else {
4165 //kdDebug(6200) << "moveToCaret: extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
4166 //kdDebug(6200) << "selection: start(" << m_part->d->m_selectionStart.handle() << "," << m_part->d->m_startOffset << "), end(" << m_part->d->m_selectionEnd.handle() << "," << m_part->d->m_endOffset << "), caret(" << m_part->d->caretNode().handle() << "," << m_part->d->caretOffset() << ")" << endl;
4167 selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
4168 //kdDebug(6200) << "after extendSelection: m_extendAtEnd " << m_part->d->m_extendAtEnd << endl;
4169 //kdDebug(6200) << "selection: start(" << m_part->d->m_selectionStart.handle() << "," << m_part->d->m_startOffset << "), end(" << m_part->d->m_selectionEnd.handle() << "," << m_part->d->m_endOffset << "), caret(" << m_part->d->caretNode().handle() << "," << m_part->d->caretOffset() << ")" << endl;
4170 }/*end if*/
4171
4172 d->caretViewContext()->caretMoved = true;
4173
4174 bool visible_caret = placeCaret(box);
4175
4176 // FIXME: if the old position was !visible_caret, and the new position is
4177 // also, then two caretPositionChanged signals with a null Node are
4178 // emitted in series.
4179 if (posChanged) {
4180 m_part->emitCaretPositionChanged(visible_caret ? node : 0, offset);
4181 }/*end if*/
4182
4183 return selChanged;
4184}
4185
4186void TDEHTMLView::moveCaretByLine(bool next, int count)
4187{
4188 Node &caretNodeRef = m_part->d->caretNode();
4189 if (caretNodeRef.isNull()) return;
4190
4191 NodeImpl *caretNode = caretNodeRef.handle();
4192// kdDebug(6200) << ": caretNode=" << caretNode << endl;
4193 long offset = m_part->d->caretOffset();
4194
4195 CaretViewContext *cv = d->caretViewContext();
4196
4197 ElementImpl *baseElem = determineBaseElement(caretNode);
4198 LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
4199
4200 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
4201
4202 // move count lines vertically
4203 while (count > 0 && it != ld.end() && it != ld.preBegin()) {
4204 count--;
4205 if (next) ++it; else --it;
4206 }/*wend*/
4207
4208 // Nothing? Then leave everything as is.
4209 if (it == ld.end() || it == ld.preBegin()) return;
4210
4211 int x, absx, absy;
4212 CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
4213
4214 placeCaretOnLine(caretBox, x, absx, absy);
4215}
4216
4217void TDEHTMLView::placeCaretOnLine(CaretBox *caretBox, int x, int absx, int absy)
4218{
4219 // paranoia sanity check
4220 if (!caretBox) return;
4221
4222 RenderObject *caretRender = caretBox->object();
4223
4224#if DEBUG_CARETMODE > 0
4225 kdDebug(6200) << "got valid caretBox " << caretBox << endl;
4226 kdDebug(6200) << "xPos: " << caretBox->xPos() << " yPos: " << caretBox->yPos()
4227 << " width: " << caretBox->width() << " height: " << caretBox->height() << endl;
4228 InlineTextBox *tb = static_cast<InlineTextBox *>(caretBox->inlineBox());
4229 if (caretBox->isInlineTextBox()) { kdDebug(6200) << "contains \"" << TQString(static_cast<RenderText *>(tb->object())->str->s + tb->m_start, tb->m_len) << "\"" << endl;}
4230#endif
4231 // inquire height of caret
4232 int caretHeight = caretBox->height();
4233 bool isText = caretBox->isInlineTextBox();
4234 int yOfs = 0; // y-offset for text nodes
4235 if (isText) {
4236 // text boxes need extrawurst
4237 RenderText *t = static_cast<RenderText *>(caretRender);
4238 const TQFontMetrics &fm = t->metrics(caretBox->inlineBox()->m_firstLine);
4239 caretHeight = fm.height();
4240 yOfs = caretBox->inlineBox()->baseline() - fm.ascent();
4241 }/*end if*/
4242
4243 caretOff();
4244
4245 // set new caret node
4246 NodeImpl *caretNode;
4247 long &offset = m_part->d->caretOffset();
4248 mapRenderPosToDOMPos(caretRender, offset, caretBox->isOutside(),
4249 caretBox->isOutsideEnd(), caretNode, offset);
4250
4251 // set all variables not needing special treatment
4252 d->m_caretViewContext->y = caretBox->yPos() + yOfs;
4253 d->m_caretViewContext->height = caretHeight;
4254 d->m_caretViewContext->width = 1; // FIXME: regard override
4255
4256 int xPos = caretBox->xPos();
4257 int caretBoxWidth = caretBox->width();
4258 d->m_caretViewContext->x = xPos;
4259
4260 if (!caretBox->isOutside()) {
4261 // before or at beginning of inline box -> place at beginning
4262 long r_ofs = 0;
4263 if (x <= xPos) {
4264 r_ofs = caretBox->minOffset();
4265 // somewhere within this block
4266 } else if (x > xPos && x <= xPos + caretBoxWidth) {
4267 if (isText) { // find out where exactly
4268 r_ofs = static_cast<InlineTextBox *>(caretBox->inlineBox())
4269 ->offsetForPoint(x, d->m_caretViewContext->x);
4270#if DEBUG_CARETMODE > 2
4271 kdDebug(6200) << "deviation from origX " << d->m_caretViewContext->x - x << endl;
4272#endif
4273#if 0
4274 } else { // snap to nearest end
4275 if (xPos + caretBoxWidth - x < x - xPos) {
4276 d->m_caretViewContext->x = xPos + caretBoxWidth;
4277 r_ofs = caretNode ? caretNode->maxOffset() : 1;
4278 } else {
4279 d->m_caretViewContext->x = xPos;
4280 r_ofs = caretNode ? caretNode->minOffset() : 0;
4281 }/*end if*/
4282#endif
4283 }/*end if*/
4284 } else { // after the inline box -> place at end
4285 d->m_caretViewContext->x = xPos + caretBoxWidth;
4286 r_ofs = caretBox->maxOffset();
4287 }/*end if*/
4288 offset = r_ofs;
4289 }/*end if*/
4290#if DEBUG_CARETMODE > 0
4291 kdDebug(6200) << "new offset: " << offset << endl;
4292#endif
4293
4294 m_part->d->caretNode() = caretNode;
4295 m_part->d->caretOffset() = offset;
4296
4297 d->m_caretViewContext->x += absx;
4298 d->m_caretViewContext->y += absy;
4299
4300#if DEBUG_CARETMODE > 1
4301 kdDebug(6200) << "new caret position: x " << d->m_caretViewContext->x << " y " << d->m_caretViewContext->y << " w " << d->m_caretViewContext->width << " h " << d->m_caretViewContext->height << " absx " << absx << " absy " << absy << endl;
4302#endif
4303
4304 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
4305 d->m_caretViewContext->width, d->m_caretViewContext->height);
4306 d->scrollBarMoved = false;
4307
4308 ensureNodeHasFocus(caretNode);
4309 caretOn();
4310}
4311
4312void TDEHTMLView::moveCaretToLineBoundary(bool end)
4313{
4314 Node &caretNodeRef = m_part->d->caretNode();
4315 if (caretNodeRef.isNull()) return;
4316
4317 NodeImpl *caretNode = caretNodeRef.handle();
4318// kdDebug(6200) << ": caretNode=" << caretNode << endl;
4319 long offset = m_part->d->caretOffset();
4320
4321 ElementImpl *baseElem = determineBaseElement(caretNode);
4322 LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
4323
4324 EditableLineIterator it = ld.current();
4325 if (it == ld.end()) return; // should not happen, but who knows
4326
4327 EditableCaretBoxIterator fbit(it, end);
4328 Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
4329 CaretBox *b = *fbit;
4330
4331 RenderObject *cb = b->containingBlock();
4332 int absx, absy;
4333
4334 if (cb) cb->absolutePosition(absx,absy);
4335 else absx = absy = 0;
4336
4337 int x = b->xPos() + (end && !b->isOutside() ? b->width() : 0);
4338 d->m_caretViewContext->origX = absx + x;
4339 placeCaretOnLine(b, x, absx, absy);
4340}
4341
4342void TDEHTMLView::moveCaretToDocumentBoundary(bool end)
4343{
4344 Node &caretNodeRef = m_part->d->caretNode();
4345 if (caretNodeRef.isNull()) return;
4346
4347 NodeImpl *caretNode = caretNodeRef.handle();
4348// kdDebug(6200) << ": caretNode=" << caretNode << endl;
4349 long offset = m_part->d->caretOffset();
4350
4351 ElementImpl *baseElem = determineBaseElement(caretNode);
4352 LinearDocument ld(m_part, caretNode, offset, IndicatedFlows, baseElem);
4353
4354 EditableLineIterator it(end ? ld.preEnd() : ld.begin(), end);
4355 if (it == ld.end() || it == ld.preBegin()) return; // should not happen, but who knows
4356
4357 EditableCaretBoxIterator fbit = it;
4358 Q_ASSERT(fbit != (*it)->end() && fbit != (*it)->preBegin());
4359 CaretBox *b = *fbit;
4360
4361 RenderObject *cb = (*it)->containingBlock();
4362 int absx, absy;
4363
4364 if (cb) cb->absolutePosition(absx, absy);
4365 else absx = absy = 0;
4366
4367 int x = b->xPos()/* + (end ? b->width() : 0) reactivate for rtl*/;
4368 d->m_caretViewContext->origX = absx + x;
4369 placeCaretOnLine(b, x, absx, absy);
4370}
4371
4372void TDEHTMLView::moveCaretBy(bool next, CaretMovement cmv, int count)
4373{
4374 if (!m_part) return;
4375 Node &caretNodeRef = m_part->d->caretNode();
4376 if (caretNodeRef.isNull()) return;
4377
4378 NodeImpl *caretNode = caretNodeRef.handle();
4379// kdDebug(6200) << ": caretNode=" << caretNode << endl;
4380 long &offset = m_part->d->caretOffset();
4381
4382 ElementImpl *baseElem = determineBaseElement(caretNode);
4383 CaretAdvancePolicy advpol = cmv != CaretByWord ? IndicatedFlows : LeafsOnly;
4384 LinearDocument ld(m_part, caretNode, offset, advpol, baseElem);
4385
4386 EditableCharacterIterator it(&ld);
4387 while (!it.isEnd() && count > 0) {
4388 count--;
4389 if (cmv == CaretByCharacter) {
4390 if (next) ++it;
4391 else --it;
4392 } else if (cmv == CaretByWord) {
4393 if (next) moveItToNextWord(it);
4394 else moveItToPrevWord(it);
4395 }/*end if*/
4396//kdDebug(6200) << "movecaret" << endl;
4397 }/*wend*/
4398 CaretBox *hintBox = 0; // make gcc uninit warning disappear
4399 if (!it.isEnd()) {
4400 NodeImpl *node = caretNodeRef.handle();
4401 hintBox = it.caretBox();
4402//kdDebug(6200) << "hintBox = " << hintBox << endl;
4403//kdDebug(6200) << " outside " << hintBox->isOutside() << " outsideEnd " << hintBox->isOutsideEnd() << " r " << it.renderer() << " ofs " << it.offset() << " cb " << hintBox->containingBlock() << endl;
4404 mapRenderPosToDOMPos(it.renderer(), it.offset(), hintBox->isOutside(),
4405 hintBox->isOutsideEnd(), node, offset);
4406//kdDebug(6200) << "mapRTD" << endl;
4407 caretNodeRef = node;
4408#if DEBUG_CARETMODE > 2
4409 kdDebug(6200) << "set by valid node " << node << " " << (node?node->nodeName().string():TQString::null) << " offset: " << offset << endl;
4410#endif
4411 } else {
4412 offset = next ? caretNode->maxOffset() : caretNode->minOffset();
4413#if DEBUG_CARETMODE > 0
4414 kdDebug(6200) << "set by INvalid node. offset: " << offset << endl;
4415#endif
4416 }/*end if*/
4417 placeCaretOnChar(hintBox);
4418}
4419
4420void TDEHTMLView::placeCaretOnChar(CaretBox *hintBox)
4421{
4422 caretOff();
4423 recalcAndStoreCaretPos(hintBox);
4424 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
4425 d->m_caretViewContext->width, d->m_caretViewContext->height);
4426 d->m_caretViewContext->origX = d->m_caretViewContext->x;
4427 d->scrollBarMoved = false;
4428#if DEBUG_CARETMODE > 3
4429 //if (caretNode->isTextNode()) kdDebug(6200) << "text[0] = " << (int)*((TextImpl *)caretNode)->data().unicode() << " text :\"" << ((TextImpl *)caretNode)->data().string() << "\"" << endl;
4430#endif
4431 ensureNodeHasFocus(m_part->d->caretNode().handle());
4432 caretOn();
4433}
4434
4435void TDEHTMLView::moveCaretByPage(bool next)
4436{
4437 Node &caretNodeRef = m_part->d->caretNode();
4438 if (caretNodeRef.isNull()) return;
4439
4440 NodeImpl *caretNode = caretNodeRef.handle();
4441// kdDebug(6200) << ": caretNode=" << caretNode << endl;
4442 long offset = m_part->d->caretOffset();
4443
4444 int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
4445 // Minimum distance the caret must be moved
4446 int mindist = clipper()->height() - offs;
4447
4448 CaretViewContext *cv = d->caretViewContext();
4449// int y = cv->y; // we always measure the top border
4450
4451 ElementImpl *baseElem = determineBaseElement(caretNode);
4452 LinearDocument ld(m_part, caretNode, offset, LeafsOnly, baseElem);
4453
4454 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
4455
4456 moveIteratorByPage(ld, it, mindist, next);
4457
4458 int x, absx, absy;
4459 CaretBox *caretBox = nearestCaretBox(it, d->m_caretViewContext, x, absx, absy);
4460
4461 placeCaretOnLine(caretBox, x, absx, absy);
4462}
4463
4464void TDEHTMLView::moveCaretPrevWord()
4465{
4466 moveCaretBy(false, CaretByWord, 1);
4467}
4468
4469void TDEHTMLView::moveCaretNextWord()
4470{
4471 moveCaretBy(true, CaretByWord, 1);
4472}
4473
4474void TDEHTMLView::moveCaretPrevLine(int n)
4475{
4476 moveCaretByLine(false, n);
4477}
4478
4479void TDEHTMLView::moveCaretNextLine(int n)
4480{
4481 moveCaretByLine(true, n);
4482}
4483
4484void TDEHTMLView::moveCaretPrevPage()
4485{
4486 moveCaretByPage(false);
4487}
4488
4489void TDEHTMLView::moveCaretNextPage()
4490{
4491 moveCaretByPage(true);
4492}
4493
4494void TDEHTMLView::moveCaretToLineBegin()
4495{
4496 moveCaretToLineBoundary(false);
4497}
4498
4499void TDEHTMLView::moveCaretToLineEnd()
4500{
4501 moveCaretToLineBoundary(true);
4502}
4503
4504#endif // TDEHTML_NO_CARET
4505
4506#ifndef NO_SMOOTH_SCROLL_HACK
4507#define timer timer2
4508
4509// All scrolls must be completed within 240ms of last keypress
4510static const int SCROLL_TIME = 240;
4511// Each step is 20 ms == 50 frames/second
4512static const int SCROLL_TICK = 20;
4513
4514void TDEHTMLView::scrollBy(int dx, int dy)
4515{
4516 TDEConfigGroup cfg( TDEGlobal::config(), "KDE" );
4517 if( !cfg.readBoolEntry( "SmoothScrolling", false )) {
4518 TQScrollView::scrollBy( dx, dy );
4519 return;
4520 }
4521 // scrolling destination
4522 int full_dx = d->dx + dx;
4523 int full_dy = d->dy + dy;
4524
4525 // scrolling speed
4526 int ddx = 0;
4527 int ddy = 0;
4528
4529 int steps = SCROLL_TIME/SCROLL_TICK;
4530
4531 ddx = (full_dx*16)/steps;
4532 ddy = (full_dy*16)/steps;
4533
4534 // don't go under 1px/step
4535 if (ddx > 0 && ddx < 16) ddx = 16;
4536 if (ddy > 0 && ddy < 16) ddy = 16;
4537 if (ddx < 0 && ddx > -16) ddx = -16;
4538 if (ddy < 0 && ddy > -16) ddy = -16;
4539
4540 d->dx = full_dx;
4541 d->dy = full_dy;
4542 d->ddx = ddx;
4543 d->ddy = ddy;
4544
4545 if (!d->scrolling) {
4546 scrollTick();
4547 startScrolling();
4548 }
4549}
4550
4551void TDEHTMLView::scrollTick() {
4552 if (d->dx == 0 && d->dy == 0) {
4553 stopScrolling();
4554 return;
4555 }
4556
4557 int tddx = d->ddx + d->rdx;
4558 int tddy = d->ddy + d->rdy;
4559
4560 int ddx = tddx / 16;
4561 int ddy = tddy / 16;
4562 d->rdx = tddx % 16;
4563 d->rdy = tddy % 16;
4564
4565 if (d->dx > 0 && ddx > d->dx) ddx = d->dx;
4566 else
4567 if (d->dx < 0 && ddx < d->dx) ddx = d->dx;
4568
4569 if (d->dy > 0 && ddy > d->dy) ddy = d->dy;
4570 else
4571 if (d->dy < 0 && ddy < d->dy) ddy = d->dy;
4572
4573 d->dx -= ddx;
4574 d->dy -= ddy;
4575
4576// TQScrollView::setContentsPos( contentsX() + ddx, contentsY() + ddy);
4577 tdeApp->syncX();
4578 TQScrollView::scrollBy(ddx, ddy);
4579// Unaccelerated X can get seriously overloaded by scrolling and for some reason
4580// will send KeyPress events only infrequently. This should help to reduce
4581// the load.
4582 tdeApp->syncX();
4583}
4584
4585void TDEHTMLView::startScrolling()
4586{
4587 d->scrolling = true;
4588 d->timer.start(SCROLL_TICK, false);
4589}
4590
4591void TDEHTMLView::stopScrolling()
4592{
4593 d->timer.stop();
4594 d->dx = d->dy = 0;
4595 d->scrolling = false;
4596}
4597
4598// Overloaded from TQScrollView and TQScrollBar
4599void TDEHTMLView::scrollViewWheelEvent( TQWheelEvent *e )
4600{
4601 int pageStep = verticalScrollBar()->pageStep();
4602 int lineStep = verticalScrollBar()->lineStep();
4603 int step = TQMIN( TQApplication::wheelScrollLines()*lineStep, pageStep );
4604 if ( ( e->state() & ControlButton ) || ( e->state() & ShiftButton ) )
4605 step = pageStep;
4606
4607 if(e->orientation() == TQt::Horizontal)
4608 scrollBy(-((e->delta()*step)/120), 0);
4609 else if(e->orientation() == TQt::Vertical)
4610 scrollBy(0,-((e->delta()*step)/120));
4611
4612 e->accept();
4613}
4614
4615#undef timer
4616
4617#endif // NO_SMOOTH_SCROLL_HACK
4618
4619#undef DEBUG_CARETMODE
DOM::DOMString
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
DOM::Node
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:275
DOM::Node::isNull
bool isNull() const
tests if this Node is 0.
Definition: dom_node.h:892
KCursor::arrowCursor
static TQCursor arrowCursor()
KCursor::sizeHorCursor
static TQCursor sizeHorCursor()
KCursor::sizeAllCursor
static TQCursor sizeAllCursor()
KCursor::crossCursor
static TQCursor crossCursor()
KCursor::sizeFDiagCursor
static TQCursor sizeFDiagCursor()
KCursor::waitCursor
static TQCursor waitCursor()
KCursor::whatsThisCursor
static TQCursor whatsThisCursor()
KCursor::workingCursor
static TQCursor workingCursor()
KCursor::ibeamCursor
static TQCursor ibeamCursor()
KCursor::sizeVerCursor
static TQCursor sizeVerCursor()
KCursor::sizeBDiagCursor
static TQCursor sizeBDiagCursor()
KDialogBase
KDialogBase::cancel
void cancel()
KParts::Part::widget
virtual TQWidget * widget()
KParts::ReadOnlyPart::completed
void completed()
KSimpleConfig
KStringHandler::csqueeze
static TQString csqueeze(const TQString &str, uint maxlen=40)
TDEApplication::keyboardMouseState
static ButtonState keyboardMouseState()
TDEConfigBase::readBoolEntry
bool readBoolEntry(const TQString &pKey, bool bDefault=false) const
TDEConfigGroupSaver
TDEConfigGroup
TDEConfig
TDEGlobal::iconLoader
static TDEIconLoader * iconLoader()
TDEGlobal::config
static TDEConfig * config()
TDEGlobal::locale
static TDELocale * locale()
KMIN
#define KMIN(a, b)
TDEHTMLPart
This class is tdehtml's main class.
Definition: tdehtml_part.h:184
TDEHTMLPart::document
DOM::Document document() const
Returns a reference to the DOM document.
Definition: tdehtml_part.cpp:859
TDEHTMLPart::CaretDisplayPolicy
CaretDisplayPolicy
Enumeration for displaying the caret.
Definition: tdehtml_part.h:495
TDEHTMLPart::zoomFactor
int zoomFactor() const
Returns the current zoom factor.
Definition: tdehtml_part.cpp:5664
TDEHTMLPart::urlCursor
TQCursor urlCursor() const
Returns the cursor which is used when the cursor is on a link.
Definition: tdehtml_part.cpp:2602
TDEHTMLPart::isCaretMode
bool isCaretMode() const
Returns whether caret mode is on/off.
Definition: tdehtml_part.cpp:2662
TDEHTMLPart::view
TDEHTMLView * view() const
Returns a pointer to the HTML document's view.
Definition: tdehtml_part.cpp:906
TDEHTMLPart::findTextNext
bool findTextNext(const TQString &str, bool forward, bool caseSensitive, bool isRegExp)
Finds the next occurrence of the string or expression.
Definition: tdehtml_part.cpp:2823
TDEHTMLPart::begin
virtual void begin(const KURL &url=KURL(), int xOffset=0, int yOffset=0)
Clears the widget and prepares it for new content.
Definition: tdehtml_part.cpp:1875
TDEHTMLPart::findTextBegin
void findTextBegin()
Initiates a text search.
Definition: tdehtml_part.cpp:2737
TDEHTMLPart::isEditable
bool isEditable() const
Returns true if the document is editable, false otherwise.
Definition: tdehtml_part.cpp:2683
TDEHTMLPart::frameExists
bool frameExists(const TQString &frameName)
Returns whether a frame with the specified name is exists or not.
Definition: tdehtml_part.cpp:5291
TDEHTMLPart::nodeActivated
void nodeActivated(const DOM::Node &)
This signal is emitted when an element retrieves the keyboard focus.
TDEHTMLPart::findText
void findText()
Starts a new search by popping up a dialog asking the user what he wants to search for.
Definition: tdehtml_part.cpp:2996
TDEHTMLPart::parentPart
TDEHTMLPart * parentPart()
Returns a pointer to the parent TDEHTMLPart if the part is a frame in an HTML frameset.
Definition: tdehtml_part.cpp:5321
TDEHTMLView
Renders and displays HTML in a TQScrollView.
Definition: tdehtmlview.h:79
TDEHTMLView::layout
void layout()
ensure the display is up to date
Definition: tdehtmlview.cpp:800
TDEHTMLView::displayAccessKeys
void displayAccessKeys()
Display all accesskeys in small tooltips.
Definition: tdehtmlview.cpp:2256
TDEHTMLView::setVScrollBarMode
virtual void setVScrollBarMode(ScrollBarMode mode)
Sets verticals scrollbar mode.
Definition: tdehtmlview.cpp:3016
TDEHTMLView::print
void print()
Prints the HTML document.
Definition: tdehtmlview.cpp:2767
TDEHTMLView::setMarginWidth
void setMarginWidth(int x)
Sets a margin in x direction.
Definition: tdehtmlview.cpp:788
TDEHTMLView::setHScrollBarMode
virtual void setHScrollBarMode(ScrollBarMode mode)
Sets horizontal scrollbar mode.
Definition: tdehtmlview.cpp:3026
TDEHTMLView::TDEHTMLView
TDEHTMLView(TDEHTMLPart *part, TQWidget *parent, const char *name=0)
Constructs a TDEHTMLView.
Definition: tdehtmlview.cpp:487
TDEHTMLView::part
TDEHTMLPart * part() const
Returns a pointer to the TDEHTMLPart that is rendering the page.
Definition: tdehtmlview.h:113
TDEHTMLView::finishedLayout
void finishedLayout()
This signal is used for internal layouting.
TDEIconLoader::loadIcon
TQPixmap loadIcon(const TQString &name, TDEIcon::Group group, int size=0, int state=TDEIcon::DefaultState, TQString *path_store=0L, bool canReturnNull=false) const
TDEIcon::DefaultState
DefaultState
TDEIcon::Small
Small
TDELocale::formatDate
TQString formatDate(const TQDate &pDate, bool shortFormat=false) const
kdWarning
kdbgstream kdWarning(int area=0)
kdError
kdbgstream kdError(int area=0)
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
locateLocal
TQString locateLocal(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())
DOM
The Document Object Model (DOM) is divided into two parts, the COREDOM core DOM, specifying some core...
Definition: design.h:57
KNotifyClient::event
int event(const TQString &message, const TQString &text=TQString::null) TDE_DEPRECATED
KNotifyClient::beep
void beep(const TQString &reason=TQString::null)
TDEStdAccel::next
const TDEShortcut & next()
TDEStdAccel::key
int key(StdAccel id)
TDEStdAccel::end
const TDEShortcut & end()
TDEStdAccel::close
const TDEShortcut & close()
TDEStdAccel::label
TQString label(StdAccel id)
tdelocale.h

tdehtml

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

tdehtml

Skip menu "tdehtml"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdehtml by doxygen 1.9.4
This website is maintained by Timothy Pearson.