00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#include "khtmlview.moc"
00027
00028
#include "khtmlview.h"
00029
00030
#include "khtml_part.h"
00031
#include "khtml_events.h"
00032
00033
#include "html/html_documentimpl.h"
00034
#include "html/html_inlineimpl.h"
00035
#include "html/html_formimpl.h"
00036
#include "rendering/render_arena.h"
00037
#include "rendering/render_canvas.h"
00038
#include "rendering/render_frames.h"
00039
#include "rendering/render_replaced.h"
00040
#include "rendering/render_layer.h"
00041
#include "rendering/render_line.h"
00042
#include "rendering/render_table.h"
00043
00044
#define protected public
00045
#include "rendering/render_text.h"
00046
#undef protected
00047
#include "xml/dom2_eventsimpl.h"
00048
#include "css/cssstyleselector.h"
00049
#include "misc/htmlhashes.h"
00050
#include "misc/helper.h"
00051
#include "khtml_settings.h"
00052
#include "khtml_printsettings.h"
00053
00054
#include "khtmlpart_p.h"
00055
00056
#ifndef KHTML_NO_CARET
00057
#include "khtml_caret_p.h"
00058
#include "xml/dom2_rangeimpl.h"
00059
#endif
00060
00061
#include <kcursor.h>
00062
#include <ksimpleconfig.h>
00063
#include <kstringhandler.h>
00064
#include <kstandarddirs.h>
00065
#include <kprinter.h>
00066
#include <klocale.h>
00067
00068
#include <qtooltip.h>
00069
#include <qpainter.h>
00070
#include <qpaintdevicemetrics.h>
00071
#include <qstylesheet.h>
00072
#include <kapplication.h>
00073
00074
#include <kimageio.h>
00075
#include <kdebug.h>
00076
#include <kurldrag.h>
00077
#include <qobjectlist.h>
00078
#include <qtimer.h>
00079
#include <kdialogbase.h>
00080
#include <qptrdict.h>
00081
00082
00083
00084
00085
00086
00087
00088
#define PAINT_BUFFER_HEIGHT 128
00089
00090
using namespace DOM;
00091
using namespace khtml;
00092
class KHTMLToolTip;
00093
00094
#ifndef QT_NO_TOOLTIP
00095
00096
class KHTMLToolTip :
public QToolTip
00097 {
00098
public:
00099 KHTMLToolTip(
KHTMLView *view, KHTMLViewPrivate* vp) :
QToolTip(view->viewport())
00100 {
00101 m_view = view;
00102 m_viewprivate = vp;
00103 };
00104
00105
protected:
00106
virtual void maybeTip(
const QPoint &);
00107
00108
private:
00109
KHTMLView *m_view;
00110 KHTMLViewPrivate* m_viewprivate;
00111 };
00112
00113
#endif
00114
00115
class KHTMLViewPrivate {
00116
friend class KHTMLToolTip;
00117
public:
00118 KHTMLViewPrivate()
00119 : underMouse( 0 )
00120 {
00121
#ifndef KHTML_NO_CARET
00122
m_caretViewContext = 0;
00123 m_editorContext = 0;
00124
#endif // KHTML_NO_CARET
00125
postponed_autorepeat = NULL;
00126 reset();
00127 tp=0;
00128 paintBuffer=0;
00129 vertPaintBuffer=0;
00130 formCompletions=0;
00131 prevScrollbarVisible =
true;
00132 tooltip = 0;
00133 possibleTripleClick =
false;
00134 }
00135 ~KHTMLViewPrivate()
00136 {
00137
delete formCompletions;
00138
delete tp; tp = 0;
00139
delete paintBuffer; paintBuffer =0;
00140
delete vertPaintBuffer;
00141
delete postponed_autorepeat;
00142
if (underMouse)
00143 underMouse->deref();
00144
delete tooltip;
00145
#ifndef KHTML_NO_CARET
00146
delete m_caretViewContext;
00147
delete m_editorContext;
00148
#endif // KHTML_NO_CARET
00149
}
00150
void reset()
00151 {
00152
if (underMouse)
00153 underMouse->deref();
00154 underMouse = 0;
00155 linkPressed =
false;
00156 useSlowRepaints =
false;
00157 originalNode = 0;
00158 borderTouched =
false;
00159
#ifndef KHTML_NO_SCROLLBARS
00160
vmode = QScrollView::Auto;
00161 hmode = QScrollView::Auto;
00162
#else
00163
vmode = QScrollView::AlwaysOff;
00164 hmode = QScrollView::AlwaysOff;
00165
#endif
00166
#ifdef DEBUG_PIXEL
00167
timer.start();
00168 pixelbooth = 0;
00169 repaintbooth = 0;
00170
#endif
00171
scrollBarMoved =
false;
00172 ignoreWheelEvents =
false;
00173 borderX = 30;
00174 borderY = 30;
00175 clickX = -1;
00176 clickY = -1;
00177 prevMouseX = -1;
00178 prevMouseY = -1;
00179 clickCount = 0;
00180 isDoubleClick =
false;
00181 scrollingSelf =
false;
00182
delete postponed_autorepeat;
00183 postponed_autorepeat = NULL;
00184 layoutTimerId = 0;
00185 repaintTimerId = 0;
00186 scrollTimerId = 0;
00187 scrollSuspended =
false;
00188 complete =
false;
00189 firstRelayout =
true;
00190 dirtyLayout =
false;
00191 layoutSchedulingEnabled =
true;
00192 updateRegion =
QRegion();
00193 m_dialogsAllowed =
true;
00194
#ifndef KHTML_NO_CARET
00195
if (m_caretViewContext) {
00196 m_caretViewContext->caretMoved =
false;
00197 m_caretViewContext->keyReleasePending =
false;
00198 }
00199
#endif // KHTML_NO_CARET
00200
}
00201
void newScrollTimer(
QWidget *view,
int tid)
00202 {
00203
00204 view->killTimer(scrollTimerId);
00205 scrollTimerId = tid;
00206 scrollSuspended =
false;
00207 }
00208
enum ScrollDirection { ScrollLeft, ScrollRight, ScrollUp, ScrollDown };
00209
00210
void adjustScroller(
QWidget *view, ScrollDirection direction, ScrollDirection oppositedir)
00211 {
00212
static const struct {
int msec, pixels; } timings [] = {
00213 {320,1}, {224,1}, {160,1}, {112,1}, {80,1}, {56,1}, {40,1},
00214 {28,1}, {20,1}, {20,2}, {20,3}, {20,4}, {20,6}, {20,8}, {0,0}
00215 };
00216
if (!scrollTimerId ||
00217 (scrollDirection != direction &&
00218 (scrollDirection != oppositedir || scrollSuspended))) {
00219 scrollTiming = 6;
00220 scrollBy = timings[scrollTiming].pixels;
00221 scrollDirection = direction;
00222 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00223 }
else if (scrollDirection == direction &&
00224 timings[scrollTiming+1].msec && !scrollSuspended) {
00225 scrollBy = timings[++scrollTiming].pixels;
00226 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00227 }
else if (scrollDirection == oppositedir) {
00228
if (scrollTiming) {
00229 scrollBy = timings[--scrollTiming].pixels;
00230 newScrollTimer(view, view->startTimer(timings[scrollTiming].msec));
00231 }
00232 }
00233 scrollSuspended =
false;
00234 }
00235
00236
#ifndef KHTML_NO_CARET
00237
00240 CaretViewContext *caretViewContext() {
00241
if (!m_caretViewContext) m_caretViewContext =
new CaretViewContext();
00242
return m_caretViewContext;
00243 }
00247
EditorContext *editorContext() {
00248
if (!m_editorContext) m_editorContext =
new EditorContext();
00249
return m_editorContext;
00250 }
00251
#endif // KHTML_NO_CARET
00252
00253
#ifdef DEBUG_PIXEL
00254
QTime timer;
00255
unsigned int pixelbooth;
00256
unsigned int repaintbooth;
00257
#endif
00258
00259
QPainter *tp;
00260
QPixmap *paintBuffer;
00261
QPixmap *vertPaintBuffer;
00262 NodeImpl *underMouse;
00263
00264
00265 NodeImpl *originalNode;
00266
00267
bool borderTouched:1;
00268
bool borderStart:1;
00269
bool scrollBarMoved:1;
00270
00271 QScrollView::ScrollBarMode vmode;
00272 QScrollView::ScrollBarMode hmode;
00273
bool prevScrollbarVisible;
00274
bool linkPressed;
00275
bool useSlowRepaints;
00276
bool ignoreWheelEvents;
00277
00278
int borderX, borderY;
00279
KSimpleConfig *formCompletions;
00280
00281
int clickX, clickY, clickCount;
00282
bool isDoubleClick;
00283
00284
int prevMouseX, prevMouseY;
00285
bool scrollingSelf;
00286
int layoutTimerId;
00287
QKeyEvent* postponed_autorepeat;
00288
00289
int repaintTimerId;
00290
int scrollTimerId;
00291
bool scrollSuspended;
00292
int scrollTiming;
00293
int scrollBy;
00294 ScrollDirection scrollDirection;
00295
bool complete;
00296
bool firstRelayout;
00297
bool layoutSchedulingEnabled;
00298
bool possibleTripleClick;
00299
bool dirtyLayout;
00300
bool m_dialogsAllowed;
00301
QRegion updateRegion;
00302 KHTMLToolTip *tooltip;
00303
QPtrDict<QWidget> visibleWidgets;
00304
#ifndef KHTML_NO_CARET
00305
CaretViewContext *m_caretViewContext;
00306
EditorContext *m_editorContext;
00307
#endif // KHTML_NO_CARET
00308
};
00309
00310
#ifndef QT_NO_TOOLTIP
00311
00312
void KHTMLToolTip::maybeTip(
const QPoint& )
00313 {
00314 DOM::NodeImpl *node = m_viewprivate->underMouse;
00315
QRect region;
00316
while ( node ) {
00317
if ( node->isElementNode() ) {
00318
QString s = static_cast<DOM::ElementImpl*>( node )->getAttribute( ATTR_TITLE ).string();
00319 region |=
QRect( m_view->contentsToViewport( node->getRect().topLeft() ), node->getRect().size() );
00320
if ( !s.isEmpty() ) {
00321 tip( region, QStyleSheet::convertFromPlainText( s, QStyleSheetItem::WhiteSpaceNormal ) );
00322
break;
00323 }
00324 }
00325 node = node->parentNode();
00326 }
00327 }
00328
#endif
00329
00330 KHTMLView::KHTMLView(
KHTMLPart *part,
QWidget *parent,
const char *name)
00331 :
QScrollView( parent, name, WResizeNoErase | WRepaintNoErase )
00332 {
00333 m_medium =
"screen";
00334
00335 m_part = part;
00336 d =
new KHTMLViewPrivate;
00337 QScrollView::setVScrollBarMode(d->vmode);
00338 QScrollView::setHScrollBarMode(d->hmode);
00339 connect(kapp, SIGNAL(kdisplayPaletteChanged()),
this, SLOT(slotPaletteChanged()));
00340 connect(
this, SIGNAL(contentsMoving(
int,
int)),
this, SLOT(slotScrollBarMoved()));
00341
00342
00343 enableClipper(
true);
00344
00345 static_cast<KHTMLView *>(static_cast<QWidget *>(viewport()))->setWFlags(WPaintUnclipped);
00346
00347 setResizePolicy(Manual);
00348 viewport()->setMouseTracking(
true);
00349 viewport()->setBackgroundMode(NoBackground);
00350
00351
KImageIO::registerFormats();
00352
00353
#ifndef QT_NO_TOOLTIP
00354
d->tooltip =
new KHTMLToolTip(
this, d );
00355
#endif
00356
00357 init();
00358
00359 viewport()->show();
00360 }
00361
00362 KHTMLView::~KHTMLView()
00363 {
00364 closeChildDialogs();
00365
if (m_part)
00366 {
00367
00368
00369 DOM::DocumentImpl *doc = m_part->
xmlDocImpl();
00370
if (doc)
00371 doc->detach();
00372 }
00373
delete d; d = 0;
00374 }
00375
00376
void KHTMLView::init()
00377 {
00378
if(!d->paintBuffer) d->paintBuffer =
new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
00379
if(!d->vertPaintBuffer)
00380 d->vertPaintBuffer =
new QPixmap(10, PAINT_BUFFER_HEIGHT);
00381
if(!d->tp) d->tp =
new QPainter();
00382
00383 setFocusPolicy(QWidget::StrongFocus);
00384 viewport()->setFocusProxy(
this);
00385
00386 _marginWidth = -1;
00387 _marginHeight = -1;
00388 _width = 0;
00389 _height = 0;
00390
00391 installEventFilter(
this);
00392
00393 setAcceptDrops(
true);
00394
QSize s = viewportSize(4095, 4095);
00395 resizeContents(s.width(), s.height());
00396 }
00397
00398
void KHTMLView::clear()
00399 {
00400
00401 setStaticBackground(
true);
00402
#ifndef KHTML_NO_CARET
00403
if (!m_part->
isCaretMode() && !m_part->
isEditable()) caretOff();
00404
#endif
00405
00406 d->reset();
00407 killTimers();
00408 emit cleared();
00409
00410 QScrollView::setHScrollBarMode(d->hmode);
00411 QScrollView::setVScrollBarMode(d->vmode);
00412 }
00413
00414
void KHTMLView::hideEvent(
QHideEvent* e)
00415 {
00416 QScrollView::hideEvent(e);
00417 }
00418
00419
void KHTMLView::showEvent(
QShowEvent* e)
00420 {
00421 QScrollView::showEvent(e);
00422 }
00423
00424
void KHTMLView::resizeEvent (
QResizeEvent* e)
00425 {
00426
int dw = e->oldSize().width() - e->size().width();
00427
int dh = e->oldSize().height() - e->size().height();
00428
00429
00430
00431 dw = dw>0 ? kMax(0, contentsWidth()-dw) : contentsWidth();
00432 dh = dh>0 ? kMax(0, contentsHeight()-dh) : contentsHeight();
00433
00434 resizeContents(dw, dh);
00435 QScrollView::resizeEvent(e);
00436
00437
if ( m_part && m_part->
xmlDocImpl() )
00438 m_part->
xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT,
false,
false );
00439 }
00440
00441
void KHTMLView::viewportResizeEvent (
QResizeEvent* e)
00442 {
00443 QScrollView::viewportResizeEvent(e);
00444
00445
00446
00447
00448
if (d->layoutSchedulingEnabled)
00449
layout();
00450
#ifndef KHTML_NO_CARET
00451
else {
00452 hideCaret();
00453 recalcAndStoreCaretPos();
00454 showCaret();
00455 }
00456
#endif
00457
00458 KApplication::sendPostedEvents(viewport(), QEvent::Paint);
00459 }
00460
00461
00462
void KHTMLView::drawContents(
QPainter*)
00463 {
00464 }
00465
00466
void KHTMLView::drawContents(
QPainter *p,
int ex,
int ey,
int ew,
int eh )
00467 {
00468
#ifdef DEBUG_PIXEL
00469
00470
if ( d->timer.elapsed() > 5000 ) {
00471 qDebug(
"drawed %d pixels in %d repaints the last %d milliseconds",
00472 d->pixelbooth, d->repaintbooth, d->timer.elapsed() );
00473 d->timer.restart();
00474 d->pixelbooth = 0;
00475 d->repaintbooth = 0;
00476 }
00477 d->pixelbooth += ew*eh;
00478 d->repaintbooth++;
00479
#endif
00480
00481
00482
if(!m_part || !m_part->
xmlDocImpl() || !m_part->
xmlDocImpl()->renderer()) {
00483 p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00484
return;
00485 }
00486
00487
QPoint pt = contentsToViewport(
QPoint(ex, ey));
00488
QRegion cr =
QRect(pt.x(), pt.y(), ew, eh);
00489
00490
for (
QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
00491
QWidget *w = it.current();
00492 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
00493
QScrollView *sv = ::qt_cast<QScrollView *>(w);
00494
if (sv || !rw->isFormElement()) {
00495
00496
int x, y;
00497 rw->absolutePosition(x, y);
00498 contentsToViewport(x, y, x, y);
00499 cr -= QRect(x, y, rw->width(), rw->height());
00500 }
00501 }
00502
00503
#if 0
00504
00505
00506
if (cr.isEmpty())
00507
return;
00508
#endif
00509
00510
#ifndef DEBUG_NO_PAINT_BUFFER
00511
p->setClipRegion(cr);
00512
00513
if (eh > PAINT_BUFFER_HEIGHT && ew <= 10) {
00514
if ( d->vertPaintBuffer->height() < visibleHeight() )
00515 d->vertPaintBuffer->resize(10, visibleHeight());
00516 d->tp->begin(d->vertPaintBuffer);
00517 d->tp->translate(-ex, -ey);
00518 d->tp->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00519 m_part->
xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey, ew, eh));
00520 d->tp->end();
00521 p->drawPixmap(ex, ey, *d->vertPaintBuffer, 0, 0, ew, eh);
00522 }
00523
else {
00524
if ( d->paintBuffer->width() < visibleWidth() )
00525 d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
00526
00527
int py=0;
00528
while (py < eh) {
00529
int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
00530 d->tp->begin(d->paintBuffer);
00531 d->tp->translate(-ex, -ey-py);
00532 d->tp->fillRect(ex, ey+py, ew, ph, palette().active().brush(QColorGroup::Base));
00533 m_part->
xmlDocImpl()->renderer()->layer()->paint(d->tp, QRect(ex, ey+py, ew, ph));
00534 d->tp->end();
00535
00536 p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
00537 py += PAINT_BUFFER_HEIGHT;
00538 }
00539 }
00540
#else // !DEBUG_NO_PAINT_BUFFER
00541
static int cnt=0;
00542 ex = contentsX(); ey = contentsY();
00543 ew = visibleWidth(); eh = visibleHeight();
00544 QRect pr(ex,ey,ew,eh);
00545
kdDebug() <<
"[" << ++cnt <<
"]" <<
" clip region: " << pr <<
endl;
00546
00547
00548 p->fillRect(ex, ey, ew, eh, palette().active().brush(QColorGroup::Base));
00549 m_part->
xmlDocImpl()->renderer()->layer()->paint(p, pr);
00550
#endif // DEBUG_NO_PAINT_BUFFER
00551
00552
#ifndef KHTML_NO_CARET
00553
if (d->m_caretViewContext && d->m_caretViewContext->visible) {
00554 QRect pos(d->m_caretViewContext->x, d->m_caretViewContext->y,
00555 d->m_caretViewContext->width, d->m_caretViewContext->height);
00556
if (pos.intersects(QRect(ex, ey, ew, eh))) {
00557 p->setRasterOp(XorROP);
00558 p->setPen(white);
00559
if (pos.width() == 1)
00560 p->drawLine(pos.topLeft(), pos.bottomRight());
00561
else {
00562 p->fillRect(pos, white);
00563 }
00564 }
00565 }
00566
#endif // KHTML_NO_CARET
00567
00568
00569
00570
00571 khtml::DrawContentsEvent
event( p, ex, ey, ew, eh );
00572 QApplication::sendEvent( m_part, &event );
00573
00574 }
00575
00576 void KHTMLView::setMarginWidth(
int w)
00577 {
00578
00579 _marginWidth = w;
00580 }
00581
00582
void KHTMLView::setMarginHeight(
int h)
00583 {
00584
00585 _marginHeight = h;
00586 }
00587
00588 void KHTMLView::layout()
00589 {
00590
if( m_part && m_part->
xmlDocImpl() ) {
00591 DOM::DocumentImpl *document = m_part->
xmlDocImpl();
00592
00593 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
00594
if ( !root )
return;
00595
00596 d->layoutSchedulingEnabled=
false;
00597
00598
if (document->isHTMLDocument()) {
00599 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
00600
if(body && body->renderer() && body->id() == ID_FRAMESET) {
00601 QScrollView::setVScrollBarMode(AlwaysOff);
00602 QScrollView::setHScrollBarMode(AlwaysOff);
00603 body->renderer()->setLayouted(
false);
00604
00605
00606
00607
00608 }
00609
else if (!d->tooltip)
00610 d->tooltip =
new KHTMLToolTip(
this, d );
00611 }
00612
00613 _height = visibleHeight();
00614 _width = visibleWidth();
00615
00616
00617 root->setMinMaxKnown(
false);
00618 root->setLayouted(
false);
00619 root->layout();
00620
00621 emit finishedLayout();
00622
#ifndef KHTML_NO_CARET
00623
hideCaret();
00624
if ((m_part->
isCaretMode() || m_part->
isEditable())
00625 && !d->complete && d->m_caretViewContext
00626 && !d->m_caretViewContext->caretMoved) {
00627 initCaret();
00628 }
else {
00629 recalcAndStoreCaretPos();
00630 showCaret();
00631 }
00632
#endif
00633
root->repaint();
00634
00635 }
00636
else
00637 _width = visibleWidth();
00638
00639 killTimer(d->layoutTimerId);
00640 d->layoutTimerId = 0;
00641 d->layoutSchedulingEnabled=
true;
00642 }
00643
00644
void KHTMLView::closeChildDialogs()
00645 {
00646
QObjectList *dlgs = queryList(
"QDialog");
00647
for (
QObject *dlg = dlgs->first(); dlg; dlg = dlgs->next())
00648 {
00649
KDialogBase* dlgbase = dynamic_cast<KDialogBase *>( dlg );
00650
if ( dlgbase ) {
00651
kdDebug(6000) <<
"closeChildDialogs: closing dialog " << dlgbase <<
endl;
00652
00653
00654 dlgbase->
cancel();
00655 }
00656
else
00657 {
00658
kdWarning() <<
"closeChildDialogs: not a KDialogBase! Don't use QDialogs in KDE! " << static_cast<QWidget*>(dlg) <<
endl;
00659 static_cast<QWidget*>(dlg)->hide();
00660 }
00661 }
00662
delete dlgs;
00663 d->m_dialogsAllowed =
false;
00664 }
00665
00666
bool KHTMLView::dialogsAllowed() {
00667
bool allowed = d->m_dialogsAllowed;
00668
KHTMLPart* p = m_part->
parentPart();
00669
if (p && p->
view())
00670 allowed &= p->
view()->
dialogsAllowed();
00671
return allowed;
00672 }
00673
00674
void KHTMLView::closeEvent(
QCloseEvent* ev )
00675 {
00676 closeChildDialogs();
00677 QScrollView::closeEvent( ev );
00678 }
00679
00680
00681
00682
00684
00685
void KHTMLView::viewportMousePressEvent(
QMouseEvent *_mouse )
00686 {
00687
if(!m_part->
xmlDocImpl())
return;
00688
if (d->possibleTripleClick)
00689 {
00690 viewportMouseDoubleClickEvent( _mouse );
00691
return;
00692 }
00693
00694
int xm, ym;
00695 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00696
00697
00698
00699 d->isDoubleClick =
false;
00700
00701 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
00702 m_part->
xmlDocImpl()->prepareMouseEvent(
false, xm, ym, &mev );
00703
00704
if (d->clickCount > 0 &&
00705
QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00706 d->clickCount++;
00707
else {
00708 d->clickCount = 1;
00709 d->clickX = xm;
00710 d->clickY = ym;
00711 }
00712
00713
bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),
true,
00714 d->clickCount,_mouse,
true,DOM::NodeImpl::MousePress);
00715
00716 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00717
if (r && r->isWidget())
00718 _mouse->ignore();
00719
00720
if (!swallowEvent) {
00721 emit m_part->
nodeActivated(mev.innerNode);
00722
00723 khtml::MousePressEvent
event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00724 QApplication::sendEvent( m_part, &event );
00725
00726 }
00727 }
00728
00729
void KHTMLView::viewportMouseDoubleClickEvent(
QMouseEvent *_mouse )
00730 {
00731
if(!m_part->
xmlDocImpl())
return;
00732
00733
int xm, ym;
00734 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00735
00736
kdDebug( 6000 ) <<
"mouseDblClickEvent: x=" << xm <<
", y=" << ym <<
endl;
00737
00738 d->isDoubleClick =
true;
00739
00740 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
00741 m_part->
xmlDocImpl()->prepareMouseEvent(
false, xm, ym, &mev );
00742
00743
00744
00745
if (d->clickCount > 0 &&
00746
QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
00747 d->clickCount++;
00748
else {
00749 d->clickCount = 1;
00750 d->clickX = xm;
00751 d->clickY = ym;
00752 }
00753
bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),
true,
00754 d->clickCount,_mouse,
true,DOM::NodeImpl::MouseDblClick);
00755
00756 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00757
if (r && r->isWidget())
00758 _mouse->ignore();
00759
00760
if (!swallowEvent) {
00761 khtml::MouseDoubleClickEvent
event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode, d->clickCount );
00762 QApplication::sendEvent( m_part, &event );
00763 }
00764
00765 d->possibleTripleClick=
true;
00766 QTimer::singleShot(QApplication::doubleClickInterval(),
this,SLOT(tripleClickTimeout()));
00767 }
00768
00769
void KHTMLView::tripleClickTimeout()
00770 {
00771 d->possibleTripleClick =
false;
00772 d->clickCount = 0;
00773 }
00774
00775
static inline void forwardPeripheralEvent(khtml::RenderWidget* r,
QMouseEvent* me,
int x,
int y)
00776 {
00777
int absx = 0;
00778
int absy = 0;
00779 r->absolutePosition(absx, absy);
00780
QPoint p(x-absx, y-absy);
00781
QMouseEvent fw(me->type(), p, me->button(), me->state());
00782
QWidget* w = r->widget();
00783
if(w)
00784 static_cast<khtml::RenderWidget::EventPropagator*>(w)->sendEvent(&fw);
00785 }
00786
00787
void KHTMLView::viewportMouseMoveEvent(
QMouseEvent * _mouse )
00788 {
00789
00790
if(!m_part->
xmlDocImpl())
return;
00791
00792
int xm, ym;
00793 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00794
00795 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
00796
00797 m_part->
xmlDocImpl()->prepareMouseEvent( _mouse->state() & Qt::MouseButtonMask , xm, ym, &mev );
00798
00799
00800
00801
00802
00803
bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),
false,
00804 0,_mouse,
true,DOM::NodeImpl::MouseMove);
00805
00806
if (d->clickCount > 0 &&
00807
QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
00808 d->clickCount = 0;
00809 }
00810
00811
00812 m_part->
executeScheduledScript();
00813
00814 DOM::NodeImpl* fn = m_part->
xmlDocImpl()->focusNode();
00815
if (fn && fn != mev.innerNode.handle() &&
00816 fn->renderer() && fn->renderer()->isWidget()) {
00817 forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00818 }
00819
00820 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00821 khtml::RenderStyle* style = (r && r->style()) ? r->style() : 0;
00822
QCursor c;
00823
switch ( style ? style->cursor() : CURSOR_AUTO) {
00824
case CURSOR_AUTO:
00825
if ( r && r->isText() )
00826 c =
KCursor::ibeamCursor();
00827
00828
if ( mev.url.length() && m_part->
settings()->
changeCursor() )
00829 c = m_part->
urlCursor();
00830
00831
if (r && r->isFrameSet() && !static_cast<RenderFrameSet*>(r)->noResize())
00832 c =
QCursor(static_cast<RenderFrameSet*>(r)->cursorShape());
00833
00834
break;
00835
case CURSOR_CROSS:
00836 c =
KCursor::crossCursor();
00837
break;
00838
case CURSOR_POINTER:
00839 c = m_part->
urlCursor();
00840
break;
00841
case CURSOR_PROGRESS:
00842 c =
KCursor::workingCursor();
00843
break;
00844
case CURSOR_MOVE:
00845 c =
KCursor::sizeAllCursor();
00846
break;
00847
case CURSOR_E_RESIZE:
00848
case CURSOR_W_RESIZE:
00849 c =
KCursor::sizeHorCursor();
00850
break;
00851
case CURSOR_N_RESIZE:
00852
case CURSOR_S_RESIZE:
00853 c =
KCursor::sizeVerCursor();
00854
break;
00855
case CURSOR_NE_RESIZE:
00856
case CURSOR_SW_RESIZE:
00857 c =
KCursor::sizeBDiagCursor();
00858
break;
00859
case CURSOR_NW_RESIZE:
00860
case CURSOR_SE_RESIZE:
00861 c =
KCursor::sizeFDiagCursor();
00862
break;
00863
case CURSOR_TEXT:
00864 c =
KCursor::ibeamCursor();
00865
break;
00866
case CURSOR_WAIT:
00867 c =
KCursor::waitCursor();
00868
break;
00869
case CURSOR_HELP:
00870 c =
KCursor::whatsThisCursor();
00871
break;
00872
case CURSOR_DEFAULT:
00873
break;
00874 }
00875
00876
if ( viewport()->cursor().handle() != c.handle() ) {
00877
if( c.handle() ==
KCursor::arrowCursor().handle()) {
00878
for (
KHTMLPart* p = m_part; p; p = p->
parentPart())
00879 p->
view()->viewport()->unsetCursor();
00880 }
00881
else {
00882 viewport()->setCursor( c );
00883 }
00884 }
00885
if (r && r->isWidget()) {
00886 _mouse->ignore();
00887 }
00888
00889
00890 d->prevMouseX = xm;
00891 d->prevMouseY = ym;
00892
00893
if (!swallowEvent) {
00894 khtml::MouseMoveEvent
event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00895 QApplication::sendEvent( m_part, &event );
00896 }
00897 }
00898
00899
void KHTMLView::viewportMouseReleaseEvent(
QMouseEvent * _mouse )
00900 {
00901
if ( !m_part->
xmlDocImpl() )
return;
00902
00903
int xm, ym;
00904 viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
00905
00906 DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
00907 m_part->
xmlDocImpl()->prepareMouseEvent(
false, xm, ym, &mev );
00908
00909
bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),
true,
00910 d->clickCount,_mouse,
false,DOM::NodeImpl::MouseRelease);
00911
00912
if (d->clickCount > 0 &&
00913
QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) {
00914
QMouseEvent me(d->isDoubleClick ? QEvent::MouseButtonDblClick : QEvent::MouseButtonRelease,
00915 _mouse->pos(), _mouse->button(), _mouse->state());
00916 dispatchMouseEvent(EventImpl::CLICK_EVENT, mev.innerNode.handle(),
true,
00917 d->clickCount, &me,
true, DOM::NodeImpl::MouseRelease);
00918 }
00919
00920 DOM::NodeImpl* fn = m_part->
xmlDocImpl()->focusNode();
00921
if (fn && fn != mev.innerNode.handle() &&
00922 fn->renderer() && fn->renderer()->isWidget()) {
00923 forwardPeripheralEvent(static_cast<khtml::RenderWidget*>(fn->renderer()), _mouse, xm, ym);
00924 }
00925
00926 khtml::RenderObject* r = mev.innerNode.handle() ? mev.innerNode.handle()->renderer() : 0;
00927
if (r && r->isWidget())
00928 _mouse->ignore();
00929
00930
if (!swallowEvent) {
00931 khtml::MouseReleaseEvent
event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
00932 QApplication::sendEvent( m_part, &event );
00933 }
00934 }
00935
00936
00937
bool KHTMLView::dispatchKeyEvent(
QKeyEvent *_ke )
00938 {
00939
if (!m_part->
xmlDocImpl())
00940
return false;
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
if( _ke == d->postponed_autorepeat )
00962 {
00963
return false;
00964 }
00965
00966
if( _ke->type() == QEvent::KeyPress )
00967 {
00968
if( !_ke->isAutoRepeat())
00969 {
00970
bool ret = dispatchKeyEventHelper( _ke,
false );
00971
if( dispatchKeyEventHelper( _ke,
true ))
00972 ret =
true;
00973
return ret;
00974 }
00975
else
00976 {
00977
bool ret = dispatchKeyEventHelper( _ke,
true );
00978
if( !ret && d->postponed_autorepeat )
00979 keyPressEvent( d->postponed_autorepeat );
00980
delete d->postponed_autorepeat;
00981 d->postponed_autorepeat = NULL;
00982
return ret;
00983 }
00984 }
00985
else
00986 {
00987
00988
00989
if ( d->postponed_autorepeat ) {
00990
delete d->postponed_autorepeat;
00991 d->postponed_autorepeat = 0;
00992 }
00993
00994
if( !_ke->isAutoRepeat()) {
00995
return dispatchKeyEventHelper( _ke,
false );
00996 }
00997
else
00998 {
00999 d->postponed_autorepeat =
new QKeyEvent( _ke->type(), _ke->key(), _ke->ascii(), _ke->state(),
01000 _ke->text(), _ke->isAutoRepeat(), _ke->count());
01001
if( _ke->isAccepted())
01002 d->postponed_autorepeat->accept();
01003
else
01004 d->postponed_autorepeat->ignore();
01005
return true;
01006 }
01007 }
01008 }
01009
01010
01011
bool KHTMLView::dispatchKeyEventHelper(
QKeyEvent *_ke,
bool keypress )
01012 {
01013 DOM::NodeImpl* keyNode = m_part->
xmlDocImpl()->focusNode();
01014
if (keyNode) {
01015
return keyNode->dispatchKeyEvent(_ke, keypress);
01016 }
else {
01017
return m_part->
xmlDocImpl()->dispatchKeyEvent(_ke, keypress);
01018 }
01019 }
01020
01021
void KHTMLView::keyPressEvent(
QKeyEvent *_ke )
01022 {
01023
01024
#ifndef KHTML_NO_CARET
01025
if (m_part->
isEditable() || m_part->
isCaretMode()
01026 || (m_part->
xmlDocImpl() && m_part->
xmlDocImpl()->focusNode()
01027 && m_part->
xmlDocImpl()->focusNode()->contentEditable())) {
01028 d->caretViewContext()->keyReleasePending =
true;
01029 caretKeyPressEvent(_ke);
01030
return;
01031 }
01032
#endif // KHTML_NO_CARET
01033
01034
01035
01036
if( handleAccessKey( _ke )) {
01037 _ke->accept();
01038
return;
01039 }
01040
01041
if ( dispatchKeyEvent( _ke )) {
01042
01043 _ke->accept();
01044
return;
01045 }
01046
01047
int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
01048
if (_ke->state() & Qt::ShiftButton)
01049
switch(_ke->key())
01050 {
01051
case Key_Space:
01052
if ( d->vmode == QScrollView::AlwaysOff )
01053 _ke->accept();
01054
else {
01055 scrollBy( 0, -clipper()->height() - offs );
01056
if(d->scrollSuspended)
01057 d->newScrollTimer(
this, 0);
01058 }
01059
break;
01060
01061
case Key_Down:
01062
case Key_J:
01063 d->adjustScroller(
this, KHTMLViewPrivate::ScrollDown, KHTMLViewPrivate::ScrollUp);
01064
break;
01065
01066
case Key_Up:
01067
case Key_K:
01068 d->adjustScroller(
this, KHTMLViewPrivate::ScrollUp, KHTMLViewPrivate::ScrollDown);
01069
break;
01070
01071
case Key_Left:
01072
case Key_H:
01073 d->adjustScroller(
this, KHTMLViewPrivate::ScrollLeft, KHTMLViewPrivate::ScrollRight);
01074
break;
01075
01076
case Key_Right:
01077
case Key_L:
01078 d->adjustScroller(
this, KHTMLViewPrivate::ScrollRight, KHTMLViewPrivate::ScrollLeft);
01079
break;
01080 }
01081
else
01082
switch ( _ke->key() )
01083 {
01084
case Key_Down:
01085
case Key_J:
01086
if ( d->vmode == QScrollView::AlwaysOff )
01087 _ke->accept();
01088
else {
01089
if (!d->scrollTimerId || d->scrollSuspended)
01090 scrollBy( 0, 10 );
01091
if (d->scrollTimerId)
01092 d->newScrollTimer(
this, 0);
01093 }
01094
break;
01095
01096
case Key_Space:
01097
case Key_Next:
01098
if ( d->vmode == QScrollView::AlwaysOff )
01099 _ke->accept();
01100
else {
01101 scrollBy( 0, clipper()->height() - offs );
01102
if(d->scrollSuspended)
01103 d->newScrollTimer(
this, 0);
01104 }
01105
break;
01106
01107
case Key_Up:
01108
case Key_K:
01109
if ( d->vmode == QScrollView::AlwaysOff )
01110 _ke->accept();
01111
else {
01112
if (!d->scrollTimerId || d->scrollSuspended)
01113 scrollBy( 0, -10 );
01114
if (d->scrollTimerId)
01115 d->newScrollTimer(
this, 0);
01116 }
01117
break;
01118
01119
case Key_Prior:
01120
if ( d->vmode == QScrollView::AlwaysOff )
01121 _ke->accept();
01122
else {
01123 scrollBy( 0, -clipper()->height() + offs );
01124
if(d->scrollSuspended)
01125 d->newScrollTimer(
this, 0);
01126 }
01127
break;
01128
case Key_Right:
01129
case Key_L:
01130
if ( d->hmode == QScrollView::AlwaysOff )
01131 _ke->accept();
01132
else {
01133
if (!d->scrollTimerId || d->scrollSuspended)
01134 scrollBy( 10, 0 );
01135
if (d->scrollTimerId)
01136 d->newScrollTimer(
this, 0);
01137 }
01138
break;
01139
case Key_Left:
01140
case Key_H:
01141
if ( d->hmode == QScrollView::AlwaysOff )
01142 _ke->accept();
01143
else {
01144
if (!d->scrollTimerId || d->scrollSuspended)
01145 scrollBy( -10, 0 );
01146
if (d->scrollTimerId)
01147 d->newScrollTimer(
this, 0);
01148 }
01149
break;
01150
case Key_Enter:
01151
case Key_Return:
01152
01153
01154
if (m_part->
xmlDocImpl()) {
01155 NodeImpl *n = m_part->
xmlDocImpl()->focusNode();
01156
if (n)
01157 n->setActive();
01158 d->originalNode = n;
01159 }
01160
break;
01161
case Key_Home:
01162
if ( d->vmode == QScrollView::AlwaysOff )
01163 _ke->accept();
01164
else {
01165 setContentsPos( 0, 0 );
01166
if(d->scrollSuspended)
01167 d->newScrollTimer(
this, 0);
01168 }
01169
break;
01170
case Key_End:
01171
if ( d->vmode == QScrollView::AlwaysOff )
01172 _ke->accept();
01173
else {
01174 setContentsPos( 0, contentsHeight() - visibleHeight() );
01175
if(d->scrollSuspended)
01176 d->newScrollTimer(
this, 0);
01177 }
01178
break;
01179
case Key_Shift:
01180
01181 _ke->ignore();
01182
return;
01183
case Key_Control:
01184
if (d->scrollTimerId)
01185 d->scrollSuspended = !d->scrollSuspended;
01186
break;
01187
default:
01188
if (d->scrollTimerId)
01189 d->newScrollTimer(
this, 0);
01190 _ke->ignore();
01191
return;
01192 }
01193 _ke->accept();
01194 }
01195
01196
void KHTMLView::keyReleaseEvent(
QKeyEvent *_ke)
01197 {
01198
if (d->m_caretViewContext && d->m_caretViewContext->keyReleasePending) {
01199
01200 d->m_caretViewContext->keyReleasePending =
false;
01201
return;
01202 }
01203
01204
01205
if ( dispatchKeyEvent( _ke ) )
01206 {
01207 _ke->accept();
01208
return;
01209 }
01210 QScrollView::keyReleaseEvent(_ke);
01211 }
01212
01213
void KHTMLView::contentsContextMenuEvent (
QContextMenuEvent * )
01214 {
01215
01216
#if 0
01217
if (!m_part->
xmlDocImpl())
return;
01218
int xm = _ce->x();
01219
int ym = _ce->y();
01220
01221 DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove );
01222 m_part->
xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
01223
01224 NodeImpl *targetNode = mev.innerNode.handle();
01225
if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
01226
int absx = 0;
01227
int absy = 0;
01228 targetNode->renderer()->absolutePosition(absx,absy);
01229
QPoint pos(xm-absx,ym-absy);
01230
01231
QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
01232
QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
01233 setIgnoreEvents(
true);
01234 QApplication::sendEvent(w,&cme);
01235 setIgnoreEvents(
false);
01236 }
01237
#endif
01238
}
01239
01240
bool KHTMLView::focusNextPrevChild(
bool next )
01241 {
01242
01243
if (m_part->
xmlDocImpl()) {
01244 focusNextPrevNode(next);
01245
if (m_part->
xmlDocImpl()->focusNode() != 0) {
01246
kdDebug() <<
"focusNode.name: "
01247 << m_part->
xmlDocImpl()->focusNode()->nodeName().string() <<
endl;
01248
return true;
01249 }
01250 }
01251
01252
01253
if (m_part->
parentPart() && m_part->
parentPart()->
view())
01254
return m_part->
parentPart()->
view()->
focusNextPrevChild(next);
01255
01256
return QWidget::focusNextPrevChild(next);
01257 }
01258
01259
void KHTMLView::doAutoScroll()
01260 {
01261
QPoint pos = QCursor::pos();
01262 pos = viewport()->mapFromGlobal( pos );
01263
01264
int xm, ym;
01265 viewportToContents(pos.x(), pos.y(), xm, ym);
01266
01267 pos =
QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
01268
if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
01269 (pos.x() < 0) || (pos.x() > visibleWidth()) )
01270 {
01271 ensureVisible( xm, ym, 0, 5 );
01272
01273
#ifndef KHTML_NO_SELECTION
01274
01275
DOM::Node innerNode;
01276
if (m_part->
isExtendingSelection()) {
01277 RenderObject::NodeInfo renderInfo(
true,
false);
01278 m_part->
xmlDocImpl()->renderer()->layer()
01279 ->nodeAtPoint(renderInfo, xm, ym);
01280 innerNode = renderInfo.innerNode();
01281 }
01282
01283
if (innerNode.
handle() && innerNode.
handle()->renderer()) {
01284
int absX, absY;
01285 innerNode.
handle()->renderer()->absolutePosition(absX, absY);
01286
01287 m_part->
extendSelectionTo(xm, ym, absX, absY, innerNode);
01288 }
01289
#endif // KHTML_NO_SELECTION
01290
}
01291 }
01292
01293
01294
class HackWidget :
public QWidget
01295 {
01296
public:
01297
inline void setNoErase() { setWFlags(getWFlags()|WRepaintNoErase); }
01298 };
01299
01300
bool KHTMLView::eventFilter(
QObject *o,
QEvent *e)
01301 {
01302
if ( e->type() == QEvent::AccelOverride ) {
01303
QKeyEvent* ke = (
QKeyEvent*) e;
01304
01305
if (m_part->
isEditable() || m_part->
isCaretMode()
01306 || (m_part->
xmlDocImpl() && m_part->
xmlDocImpl()->focusNode()
01307 && m_part->
xmlDocImpl()->focusNode()->contentEditable())) {
01308
01309
if ( (ke->state() & ControlButton) || (ke->state() & ShiftButton) ) {
01310
switch ( ke->key() ) {
01311
case Key_Left:
01312
case Key_Right:
01313
case Key_Up:
01314
case Key_Down:
01315
case Key_Home:
01316
case Key_End:
01317 ke->accept();
01318
01319
return true;
01320
default:
01321
break;
01322 }
01323 }
01324 }
01325 }
01326
01327
QWidget *view = viewport();
01328
01329
if (o == view) {
01330
01331
01332
if(e->type() == QEvent::ChildInserted) {
01333
QObject *c = static_cast<QChildEvent *>(e)->child();
01334
if (c->isWidgetType()) {
01335
QWidget *w = static_cast<QWidget *>(c);
01336
01337
if (w->parentWidget(
true) == view) {
01338
if (!strcmp(w->name(),
"__khtml")) {
01339 w->installEventFilter(
this);
01340 w->unsetCursor();
01341 w->setBackgroundMode( QWidget::NoBackground );
01342 static_cast<HackWidget *>(w)->setNoErase();
01343
if (w->children()) {
01344
QObjectListIterator it(*w->children());
01345
for (; it.current(); ++it) {
01346
QWidget *widget = ::qt_cast<QWidget *>(it.current());
01347
if (widget && !widget->isTopLevel()
01348 && !::qt_cast<QScrollView *>(widget)) {
01349 widget->setBackgroundMode( QWidget::NoBackground );
01350 static_cast<HackWidget *>(widget)->setNoErase();
01351 widget->installEventFilter(
this);
01352 }
01353 }
01354 }
01355 }
01356 }
01357 }
01358 }
01359 }
else if (o->isWidgetType()) {
01360
QWidget *v = static_cast<QWidget *>(o);
01361
QWidget *c = v;
01362
while (v && v != view) {
01363 c = v;
01364 v = v->parentWidget(
true);
01365 }
01366
01367
if (v && !strcmp(c->name(),
"__khtml")) {
01368
bool block =
false;
01369
QWidget *w = static_cast<QWidget *>(o);
01370
switch(e->type()) {
01371
case QEvent::Paint:
01372
if (!allowWidgetPaintEvents) {
01373
01374
01375 block =
true;
01376
int x = 0, y = 0;
01377
QWidget *v = w;
01378
while (v && v != view) {
01379 x += v->x();
01380 y += v->y();
01381 v = v->parentWidget();
01382 }
01383 viewportToContents( x, y, x, y );
01384
QPaintEvent *pe = static_cast<QPaintEvent *>(e);
01385 scheduleRepaint(x + pe->rect().x(), y + pe->rect().y(),
01386 pe->rect().width(), pe->rect().height());
01387 }
01388
break;
01389
case QEvent::MouseMove:
01390
case QEvent::MouseButtonPress:
01391
case QEvent::MouseButtonRelease:
01392
case QEvent::MouseButtonDblClick: {
01393
if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01394
QMouseEvent *me = static_cast<QMouseEvent *>(e);
01395
QPoint pt = (me->pos() + w->pos());
01396
QMouseEvent me2(me->type(), pt, me->button(), me->state());
01397
01398
if (e->type() == QEvent::MouseMove)
01399 viewportMouseMoveEvent(&me2);
01400
else if(e->type() == QEvent::MouseButtonPress)
01401 viewportMousePressEvent(&me2);
01402
else if(e->type() == QEvent::MouseButtonRelease)
01403 viewportMouseReleaseEvent(&me2);
01404
else
01405 viewportMouseDoubleClickEvent(&me2);
01406 block =
true;
01407 }
01408
break;
01409 }
01410
case QEvent::KeyPress:
01411
case QEvent::KeyRelease:
01412
if (w->parentWidget() == view && !::qt_cast<QScrollBar *>(w)) {
01413
QKeyEvent *ke = static_cast<QKeyEvent *>(e);
01414
if (e->type() == QEvent::KeyPress)
01415 keyPressEvent(ke);
01416
else
01417 keyReleaseEvent(ke);
01418 block =
true;
01419 }
01420
default:
01421
break;
01422 }
01423
if (block) {
01424
01425
return true;
01426 }
01427 }
01428 }
01429
01430
01431
return QScrollView::eventFilter(o, e);
01432 }
01433
01434
01435 DOM::NodeImpl *KHTMLView::nodeUnderMouse()
const
01436
{
01437
return d->underMouse;
01438 }
01439
01440
bool KHTMLView::scrollTo(
const QRect &bounds)
01441 {
01442 d->scrollingSelf =
true;
01443
01444
int x, y, xe, ye;
01445 x = bounds.left();
01446 y = bounds.top();
01447 xe = bounds.right();
01448 ye = bounds.bottom();
01449
01450
01451
01452
int deltax;
01453
int deltay;
01454
01455
int curHeight = visibleHeight();
01456
int curWidth = visibleWidth();
01457
01458
if (ye-y>curHeight-d->borderY)
01459 ye = y + curHeight - d->borderY;
01460
01461
if (xe-x>curWidth-d->borderX)
01462 xe = x + curWidth - d->borderX;
01463
01464
01465
if (x < contentsX() + d->borderX )
01466 deltax = x - contentsX() - d->borderX;
01467
01468
else if (xe + d->borderX > contentsX() + curWidth)
01469 deltax = xe + d->borderX - ( contentsX() + curWidth );
01470
else
01471 deltax = 0;
01472
01473
01474
if (y < contentsY() + d->borderY)
01475 deltay = y - contentsY() - d->borderY;
01476
01477
else if (ye + d->borderY > contentsY() + curHeight)
01478 deltay = ye + d->borderY - ( contentsY() + curHeight );
01479
else
01480 deltay = 0;
01481
01482
int maxx = curWidth-d->borderX;
01483
int maxy = curHeight-d->borderY;
01484
01485
int scrollX,scrollY;
01486
01487 scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
01488 scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
01489
01490
if (contentsX() + scrollX < 0)
01491 scrollX = -contentsX();
01492
else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
01493 scrollX = contentsWidth() - visibleWidth() - contentsX();
01494
01495
if (contentsY() + scrollY < 0)
01496 scrollY = -contentsY();
01497
else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
01498 scrollY = contentsHeight() - visibleHeight() - contentsY();
01499
01500 scrollBy(scrollX, scrollY);
01501
01502
01503
01504
01505
if (scrollX<0)
01506 scrollX=-scrollX;
01507
if (scrollY<0)
01508 scrollY=-scrollY;
01509
01510 d->scrollingSelf =
false;
01511
01512
if ( (scrollX!=maxx) && (scrollY!=maxy) )
01513
return true;
01514
else return false;
01515
01516 }
01517
01518
void KHTMLView::focusNextPrevNode(
bool next)
01519 {
01520
01521
01522
01523
01524
01525 DocumentImpl *doc = m_part->
xmlDocImpl();
01526 NodeImpl *oldFocusNode = doc->focusNode();
01527 NodeImpl *newFocusNode;
01528
01529
01530
if (
next)
01531 newFocusNode = doc->nextFocusNode(oldFocusNode);
01532
else
01533 newFocusNode = doc->previousFocusNode(oldFocusNode);
01534
01535
01536
01537
if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
01538
01539
kdDebug(6000) <<
" searching for visible link" <<
endl;
01540
01541
bool visible =
false;
01542 NodeImpl *toFocus = newFocusNode;
01543
while (!visible && toFocus) {
01544 QRect focusNodeRect = toFocus->getRect();
01545
if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
01546 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
01547
01548 visible =
true;
01549 }
01550
else {
01551
01552
if (
next)
01553 toFocus = doc->nextFocusNode(toFocus);
01554
else
01555 toFocus = doc->previousFocusNode(toFocus);
01556 }
01557 }
01558
01559
if (toFocus)
01560 newFocusNode = toFocus;
01561 }
01562
01563 d->scrollBarMoved =
false;
01564
01565
if (!newFocusNode)
01566 {
01567
01568
if (
next)
01569 scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
01570
else
01571 scrollTo(QRect(contentsX()+visibleWidth()/2,0,0,0));
01572 }
01573
else
01574
01575 {
01576
#ifndef KHTML_NO_CARET
01577
01578
if (!m_part->
isCaretMode() && !m_part->
isEditable()
01579 && newFocusNode->contentEditable()) {
01580 d->caretViewContext();
01581 moveCaretTo(newFocusNode, 0L,
true);
01582 }
else {
01583 caretOff();
01584 }
01585
#endif // KHTML_NO_CARET
01586
01587
if (oldFocusNode)
01588 {
01589
if (!scrollTo(newFocusNode->getRect()))
01590
return;
01591 }
01592
else
01593 {
01594 ensureVisible(contentsX(), next?0:contentsHeight());
01595
01596 }
01597
01598 }
01599
01600
01601
Node guard(newFocusNode);
01602 m_part->
xmlDocImpl()->setFocusNode(newFocusNode);
01603
if( newFocusNode != NULL && newFocusNode->hasOneRef())
01604
return;
01605 emit m_part->
nodeActivated(
Node(newFocusNode));
01606 }
01607
01608
01609
bool KHTMLView::handleAccessKey(
const QKeyEvent* ev )
01610 {
01611
const int mods = Qt::AltButton | Qt::ControlButton;
01612
if( ( ev->state() & mods ) != mods )
01613
return false;
01614
01615
01616
QChar c;
01617
if( ev->key() >= Key_A && ev->key() <= Key_Z )
01618 c =
'A' + ev->key() - Key_A;
01619
else if( ev->key() >= Key_0 && ev->key() <= Key_9 )
01620 c =
'0' + ev->key() - Key_0;
01621
else {
01622
01623
01624
if( ev->text().length() == 1 )
01625 c = ev->text()[ 0 ];
01626 }
01627
if( c.isNull())
01628
return false;
01629
return focusNodeWithAccessKey( c );
01630 }
01631
01632
bool KHTMLView::focusNodeWithAccessKey(
QChar c,
KHTMLView* caller )
01633 {
01634 DocumentImpl *doc = m_part->
xmlDocImpl();
01635
if( !doc )
01636
return false;
01637 ElementImpl* node = doc->findAccessKeyElement( c );
01638
if( !node ) {
01639
QPtrList<KParts::ReadOnlyPart> frames = m_part->
frames();
01640
for(
QPtrListIterator<KParts::ReadOnlyPart> it( frames );
01641 it != NULL;
01642 ++it ) {
01643
if( !(*it)->inherits(
"KHTMLPart" ))
01644
continue;
01645
KHTMLPart*
part = static_cast< KHTMLPart* >( *it );
01646
if( part->
view() && part->
view() != caller
01647 && part->
view()->
focusNodeWithAccessKey( c,
this ))
01648
return true;
01649 }
01650
01651
if (m_part->
parentPart() && m_part->
parentPart()->
view()
01652 && m_part->
parentPart()->
view() != caller )
01653
return m_part->
parentPart()->
view()->
focusNodeWithAccessKey( c,
this );
01654
return false;
01655 }
01656
01657
01658
#ifndef KHTML_NO_CARET
01659
01660
if (!m_part->
isCaretMode() && !m_part->
isEditable()
01661 && node->contentEditable()) {
01662 d->caretViewContext();
01663 moveCaretTo(node, 0L,
true);
01664 }
else {
01665 caretOff();
01666 }
01667
#endif // KHTML_NO_CARET
01668
01669 QRect r = node->getRect();
01670 ensureVisible( r.right(), r.bottom());
01671 ensureVisible( r.left(), r.top());
01672
01673
Node guard( node );
01674
if( node->isSelectable()) {
01675
01676 m_part->
xmlDocImpl()->setFocusNode(node);
01677
if( node != NULL && node->hasOneRef())
01678
return true;
01679 emit m_part->
nodeActivated(
Node(node));
01680
if( node != NULL && node->hasOneRef())
01681
return true;
01682 }
01683
switch( node->id()) {
01684
case ID_A:
01685 static_cast< HTMLAnchorElementImpl* >( node )->click();
01686
break;
01687
case ID_INPUT:
01688 static_cast< HTMLInputElementImpl* >( node )->click();
01689
break;
01690
case ID_BUTTON:
01691 static_cast< HTMLButtonElementImpl* >( node )->click();
01692
break;
01693
case ID_AREA:
01694 static_cast< HTMLAreaElementImpl* >( node )->click();
01695
break;
01696
case ID_LABEL:
01697
01698
break;
01699
case ID_TEXTAREA:
01700
break;
01701
case ID_LEGEND:
01702
01703
break;
01704 }
01705
return true;
01706 }
01707
01708
void KHTMLView::setMediaType(
const QString &medium )
01709 {
01710 m_medium = medium;
01711 }
01712
01713
QString KHTMLView::mediaType()
const
01714
{
01715
return m_medium;
01716 }
01717
01718
void KHTMLView::setWidgetVisible(RenderWidget* w,
bool vis)
01719 {
01720
if (vis) {
01721 d->visibleWidgets.replace(w, w->widget());
01722 }
01723
else
01724 d->visibleWidgets.remove(w);
01725 }
01726
01727 void KHTMLView::print()
01728 {
01729
print(
false );
01730 }
01731
01732 void KHTMLView::print(
bool quick)
01733 {
01734
if(!m_part->
xmlDocImpl())
return;
01735 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->
xmlDocImpl()->renderer());
01736
if(!root)
return;
01737
01738
01739 KPrinter *printer =
new KPrinter(
true, QPrinter::PrinterResolution);
01740 printer->addDialogPage(
new KHTMLPrintSettings());
01741
QString docname = m_part->
xmlDocImpl()->URL().prettyURL();
01742
if ( !docname.isEmpty() )
01743 docname = KStringHandler::csqueeze(docname, 80);
01744
if(quick || printer->setup(
this, i18n(
"Print %1").arg(docname))) {
01745 viewport()->setCursor( waitCursor );
01746
01747 printer->setFullPage(
false);
01748 printer->setCreator(
QString(
"KDE %1.%2.%3 HTML Library").arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE));
01749 printer->setDocName(docname);
01750
01751
QPainter *p =
new QPainter;
01752 p->begin( printer );
01753 khtml::setPrintPainter( p );
01754
01755 m_part->
xmlDocImpl()->setPaintDevice( printer );
01756
QString oldMediaType = mediaType();
01757 setMediaType(
"print" );
01758
01759
01760
01761 m_part->
xmlDocImpl()->setPrintStyleSheet( printer->option(
"app-khtml-printfriendly") ==
"true" ?
01762
"* { background-image: none !important;"
01763
" background-color: white !important;"
01764
" color: black !important; }"
01765
"body { margin: 0px !important; }"
01766
"html { margin: 0px !important; }" :
01767
"body { margin: 0px !important; }"
01768
"html { margin: 0px !important; }"
01769 );
01770
01771
QPaintDeviceMetrics metrics( printer );
01772
01773
01774
01775
01776
01777
01778
kdDebug(6000) <<
"printing: physical page width = " << metrics.width()
01779 <<
" height = " << metrics.height() <<
endl;
01780 root->setPrintingMode(
true);
01781 root->setWidth(metrics.width());
01782
01783 m_part->
xmlDocImpl()->styleSelector()->computeFontSizes(&metrics, 100);
01784 m_part->
xmlDocImpl()->updateStyleSelector();
01785 root->setPrintImages( printer->option(
"app-khtml-printimages") ==
"true");
01786 root->setMinMaxKnown(
false );
01787 root->setLayouted(
false );
01788 root->layout();
01789 khtml::RenderWidget::flushWidgetResizes();
01790
01791
bool printHeader = (printer->option(
"app-khtml-printheader") ==
"true");
01792
01793
int headerHeight = 0;
01794
QFont headerFont(
"helvetica", 8);
01795
01796
QString headerLeft =
KGlobal::locale()->
formatDate(QDate::currentDate(),
true);
01797
QString headerMid = docname;
01798
QString headerRight;
01799
01800
if (printHeader)
01801 {
01802 p->setFont(headerFont);
01803 headerHeight = (p->fontMetrics().lineSpacing() * 3) / 2;
01804 }
01805
01806
01807
kdDebug(6000) <<
"printing: html page width = " << root->docWidth()
01808 <<
" height = " << root->docHeight() <<
endl;
01809
kdDebug(6000) <<
"printing: margins left = " << printer->margins().width()
01810 <<
" top = " << printer->margins().height() <<
endl;
01811
kdDebug(6000) <<
"printing: paper width = " << metrics.width()
01812 <<
" height = " << metrics.height() <<
endl;
01813
01814
01815
int pageHeight = metrics.height();
01816
int pageWidth = metrics.width();
01817 p->setClipRect(0,0, pageWidth, pageHeight);
01818
01819 pageHeight -= headerHeight;
01820
01821
bool scalePage =
false;
01822
double scale = 0.0;
01823
#ifndef QT_NO_TRANSFORMATIONS
01824
if(root->docWidth() > metrics.width()) {
01825 scalePage =
true;
01826 scale = ((
double) metrics.width())/((
double) root->docWidth());
01827 pageHeight = (
int) (pageHeight/scale);
01828 pageWidth = (
int) (pageWidth/scale);
01829 headerHeight = (
int) (headerHeight/scale);
01830 }
01831
#endif
01832
kdDebug(6000) <<
"printing: scaled html width = " << pageWidth
01833 <<
" height = " << pageHeight <<
endl;
01834
01835
01836
if (printHeader)
01837 {
01838
int available_width = metrics.width() - 10 -
01839 2 * kMax(p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerLeft).width(),
01840 p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerRight).width());
01841
if (available_width < 150)
01842 available_width = 150;
01843
int mid_width;
01844
int squeeze = 120;
01845
do {
01846 headerMid = KStringHandler::csqueeze(docname, squeeze);
01847 mid_width = p->boundingRect(0, 0, metrics.width(), p->fontMetrics().lineSpacing(), Qt::AlignLeft, headerMid).width();
01848 squeeze -= 10;
01849 }
while (mid_width > available_width);
01850 }
01851
01852
int top = 0;
01853
int page = 1;
01854
while(top < root->docHeight()) {
01855
if(top > 0) printer->newPage();
01856
if (printHeader)
01857 {
01858
int dy = p->fontMetrics().lineSpacing();
01859 p->setPen(Qt::black);
01860 p->setFont(headerFont);
01861
01862 headerRight =
QString(
"#%1").arg(page);
01863
01864 p->drawText(0, 0, metrics.width(), dy, Qt::AlignLeft, headerLeft);
01865 p->drawText(0, 0, metrics.width(), dy, Qt::AlignHCenter, headerMid);
01866 p->drawText(0, 0, metrics.width(), dy, Qt::AlignRight, headerRight);
01867 }
01868
01869
#ifndef QT_NO_TRANSFORMATIONS
01870
if (scalePage)
01871 p->
scale(scale, scale);
01872
#endif
01873
p->
translate(0, headerHeight-top);
01874
01875 root->setTruncatedAt(top+pageHeight);
01876
01877 root->layer()->paint(p, QRect(0, top, pageWidth, pageHeight));
01878
if (top + pageHeight >= root->docHeight())
01879
break;
01880
01881 top = root->truncatedAt();
01882 p->resetXForm();
01883 page++;
01884 }
01885
01886 p->end();
01887
delete p;
01888
01889
01890 root->setPrintingMode(
false);
01891 khtml::setPrintPainter( 0 );
01892 setMediaType( oldMediaType );
01893 m_part->
xmlDocImpl()->setPaintDevice(
this );
01894 m_part->
xmlDocImpl()->styleSelector()->computeFontSizes(m_part->
xmlDocImpl()->paintDeviceMetrics(), m_part->
zoomFactor());
01895 m_part->
xmlDocImpl()->updateStyleSelector();
01896 viewport()->unsetCursor();
01897 }
01898
delete printer;
01899 }
01900
01901
void KHTMLView::slotPaletteChanged()
01902 {
01903
if(!m_part->
xmlDocImpl())
return;
01904 DOM::DocumentImpl *document = m_part->
xmlDocImpl();
01905
if (!document->isHTMLDocument())
return;
01906 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
01907
if(!root)
return;
01908 root->style()->resetPalette();
01909 NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
01910
if(!body)
return;
01911 body->setChanged(
true);
01912 body->recalcStyle( NodeImpl::Force );
01913 }
01914
01915
void KHTMLView::paint(
QPainter *p,
const QRect &rc,
int yOff,
bool *more)
01916 {
01917
if(!m_part->
xmlDocImpl())
return;
01918 khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->
xmlDocImpl()->renderer());
01919
if(!root)
return;
01920
01921 m_part->
xmlDocImpl()->setPaintDevice(p->device());
01922 root->setPrintingMode(
true);
01923 root->setWidth(rc.width());
01924
01925 p->save();
01926 p->setClipRect(rc);
01927 p->
translate(rc.left(), rc.top());
01928
double scale = ((
double) rc.width()/(
double) root->docWidth());
01929
int height = (
int) ((
double) rc.height() / scale);
01930
#ifndef QT_NO_TRANSFORMATIONS
01931
p->
scale(scale, scale);
01932
#endif
01933
01934 root->layer()->paint(p, QRect(0, yOff, root->docWidth(), height));
01935
if (more)
01936 *more = yOff + height < root->docHeight();
01937 p->restore();
01938
01939 root->setPrintingMode(
false);
01940 m_part->
xmlDocImpl()->setPaintDevice(
this );
01941 }
01942
01943
01944
void KHTMLView::useSlowRepaints()
01945 {
01946 d->useSlowRepaints =
true;
01947 setStaticBackground(
true);
01948 }
01949
01950
01951 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
01952 {
01953
#ifndef KHTML_NO_SCROLLBARS
01954
d->vmode = mode;
01955 QScrollView::setVScrollBarMode(mode);
01956
#else
01957
Q_UNUSED( mode );
01958
#endif
01959
}
01960
01961 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
01962 {
01963
#ifndef KHTML_NO_SCROLLBARS
01964
d->hmode = mode;
01965 QScrollView::setHScrollBarMode(mode);
01966
#else
01967
Q_UNUSED( mode );
01968
#endif
01969
}
01970
01971
void KHTMLView::restoreScrollBar()
01972 {
01973
int ow = visibleWidth();
01974 QScrollView::setVScrollBarMode(d->vmode);
01975
if (visibleWidth() != ow)
01976
layout();
01977 d->prevScrollbarVisible = verticalScrollBar()->isVisible();
01978 }
01979
01980
QStringList KHTMLView::formCompletionItems(
const QString &name)
const
01981
{
01982
if (!m_part->
settings()->
isFormCompletionEnabled())
01983
return QStringList();
01984
if (!d->formCompletions)
01985 d->formCompletions =
new KSimpleConfig(
locateLocal(
"data",
"khtml/formcompletions"));
01986
return d->formCompletions->readListEntry(name);
01987 }
01988
01989
void KHTMLView::clearCompletionHistory(
const QString& name)
01990 {
01991
if (!d->formCompletions)
01992 {
01993 d->formCompletions =
new KSimpleConfig(
locateLocal(
"data",
"khtml/formcompletions"));
01994 }
01995 d->formCompletions->writeEntry(name,
"");
01996 d->formCompletions->sync();
01997 }
01998
01999
void KHTMLView::addFormCompletionItem(
const QString &name,
const QString &value)
02000 {
02001
if (!m_part->
settings()->
isFormCompletionEnabled())
02002
return;
02003
02004
02005
02006
bool cc_number(
true);
02007
for (
unsigned int i = 0; i < value.length(); ++i)
02008 {
02009
QChar c(value[i]);
02010
if (!c.isNumber() && c !=
'-' && !c.isSpace())
02011 {
02012 cc_number =
false;
02013
break;
02014 }
02015 }
02016
if (cc_number)
02017
return;
02018
QStringList items = formCompletionItems(name);
02019
if (!items.contains(value))
02020 items.prepend(value);
02021
while ((
int)items.count() > m_part->
settings()->
maxFormCompletionItems())
02022 items.remove(items.fromLast());
02023 d->formCompletions->writeEntry(name, items);
02024 }
02025
02026
void KHTMLView::addNonPasswordStorableSite(
const QString& host)
02027 {
02028
if (!d->formCompletions) {
02029 d->formCompletions =
new KSimpleConfig(
locateLocal(
"data",
"khtml/formcompletions"));
02030 }
02031
02032 d->formCompletions->setGroup(
"NonPasswordStorableSites");
02033
QStringList sites = d->formCompletions->readListEntry(
"Sites");
02034 sites.append(host);
02035 d->formCompletions->writeEntry(
"Sites", sites);
02036 d->formCompletions->sync();
02037 d->formCompletions->setGroup(QString::null);
02038 }
02039
02040
bool KHTMLView::nonPasswordStorableSite(
const QString& host)
const
02041
{
02042
if (!d->formCompletions) {
02043 d->formCompletions =
new KSimpleConfig(
locateLocal(
"data",
"khtml/formcompletions"));
02044 }
02045 d->formCompletions->setGroup(
"NonPasswordStorableSites");
02046
QStringList sites = d->formCompletions->readListEntry(
"Sites");
02047 d->formCompletions->setGroup(QString::null);
02048
02049
return (sites.find(host) != sites.end());
02050 }
02051
02052
02053
bool KHTMLView::dispatchMouseEvent(
int eventId, DOM::NodeImpl *targetNode,
bool cancelable,
02054
int detail,
QMouseEvent *_mouse,
bool setUnder,
02055
int mouseEventType)
02056 {
02057
if (d->underMouse)
02058 d->underMouse->deref();
02059 d->underMouse = targetNode;
02060
if (d->underMouse)
02061 d->underMouse->ref();
02062
02063
int exceptioncode = 0;
02064
int pageX = 0;
02065
int pageY = 0;
02066 viewportToContents(_mouse->x(), _mouse->y(), pageX, pageY);
02067
int clientX = pageX - contentsX();
02068
int clientY = pageY - contentsY();
02069
int screenX = _mouse->globalX();
02070
int screenY = _mouse->globalY();
02071
int button = -1;
02072
switch (_mouse->button()) {
02073
case LeftButton:
02074 button = 0;
02075
break;
02076
case MidButton:
02077 button = 1;
02078
break;
02079
case RightButton:
02080 button = 2;
02081
break;
02082
default:
02083
break;
02084 }
02085
bool ctrlKey = (_mouse->state() & ControlButton);
02086
bool altKey = (_mouse->state() & AltButton);
02087
bool shiftKey = (_mouse->state() & ShiftButton);
02088
bool metaKey = (_mouse->state() & MetaButton);
02089
02090
02091
if (setUnder && (d->prevMouseX != pageX || d->prevMouseY != pageY)) {
02092
02093
02094
02095 NodeImpl *oldUnder = 0;
02096
if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
02097 NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
02098 m_part->
xmlDocImpl()->prepareMouseEvent(
true, d->prevMouseX, d->prevMouseY, &mev );
02099 oldUnder = mev.innerNode.handle();
02100 }
02101
02102
if (oldUnder != targetNode) {
02103
02104
if (oldUnder){
02105 oldUnder->ref();
02106 MouseEventImpl *me =
new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
02107
true,
true,m_part->
xmlDocImpl()->defaultView(),
02108 0,screenX,screenY,clientX,clientY,pageX, pageY,
02109 ctrlKey,altKey,shiftKey,metaKey,
02110 button,targetNode);
02111 me->ref();
02112 oldUnder->dispatchEvent(me,exceptioncode,
true);
02113 me->deref();
02114 }
02115
02116
02117
if (targetNode) {
02118 MouseEventImpl *me =
new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
02119
true,
true,m_part->
xmlDocImpl()->defaultView(),
02120 0,screenX,screenY,clientX,clientY,pageX, pageY,
02121 ctrlKey,altKey,shiftKey,metaKey,
02122 button,oldUnder);
02123
02124 me->ref();
02125 targetNode->dispatchEvent(me,exceptioncode,
true);
02126 me->deref();
02127 }
02128
02129
if (oldUnder)
02130 oldUnder->deref();
02131 }
02132 }
02133
02134
bool swallowEvent =
false;
02135
02136
if (targetNode) {
02137
02138
bool dblclick = ( eventId == EventImpl::CLICK_EVENT &&
02139 _mouse->type() == QEvent::MouseButtonDblClick );
02140 MouseEventImpl *me =
new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
02141
true,cancelable,m_part->
xmlDocImpl()->defaultView(),
02142 detail,screenX,screenY,clientX,clientY,pageX, pageY,
02143 ctrlKey,altKey,shiftKey,metaKey,
02144 button,0, _mouse, dblclick );
02145 me->ref();
02146 targetNode->dispatchEvent(me,exceptioncode,
true);
02147
if (me->defaultHandled() || me->defaultPrevented())
02148 swallowEvent =
true;
02149 me->deref();
02150
02151
if (eventId == EventImpl::MOUSEDOWN_EVENT) {
02152
if (targetNode->isSelectable())
02153 m_part->
xmlDocImpl()->setFocusNode(targetNode);
02154
else
02155 m_part->
xmlDocImpl()->setFocusNode(0);
02156 }
02157 }
02158
02159
return swallowEvent;
02160 }
02161
02162
void KHTMLView::setIgnoreWheelEvents(
bool e )
02163 {
02164 d->ignoreWheelEvents = e;
02165 }
02166
02167
#ifndef QT_NO_WHEELEVENT
02168
02169
void KHTMLView::viewportWheelEvent(
QWheelEvent* e)
02170 {
02171
if ( ( e->state() & ControlButton) == ControlButton )
02172 {
02173 emit zoomView( - e->delta() );
02174 e->accept();
02175 }
02176
else if ( ( (d->ignoreWheelEvents && !verticalScrollBar()->isVisible())
02177 || e->delta() > 0 && contentsY() <= 0
02178 || e->delta() < 0 && contentsY() >= contentsHeight() - visibleHeight())
02179 && m_part->
parentPart() ) {
02180
kdDebug(6000) <<
this <<
" cz " << contentsY() <<
" ch " << contentsHeight() <<
" vh " << visibleHeight() <<
endl;
02181
if ( m_part->
parentPart()->
view() )
02182 m_part->
parentPart()->
view()->wheelEvent( e );
02183
kdDebug(6000) <<
"sent" <<
endl;
02184 e->ignore();
02185 }
02186
else if ( d->vmode == QScrollView::AlwaysOff ) {
02187 e->accept();
02188 }
02189
else {
02190 d->scrollBarMoved =
true;
02191 QScrollView::viewportWheelEvent( e );
02192
02193
QMouseEvent *tempEvent =
new QMouseEvent( QEvent::MouseMove,
QPoint(-1,-1),
QPoint(-1,-1), Qt::NoButton, e->state() );
02194 emit viewportMouseMoveEvent ( tempEvent );
02195
delete tempEvent;
02196 }
02197
02198 }
02199
#endif
02200
02201
void KHTMLView::dragEnterEvent(
QDragEnterEvent* ev )
02202 {
02203
02204
02205
02206
if ( m_part->
parentPart() )
02207 {
02208 QApplication::sendEvent(m_part->
parentPart()->
widget(), ev);
02209
return;
02210 }
02211 QScrollView::dragEnterEvent( ev );
02212 }
02213
02214
void KHTMLView::dropEvent(
QDropEvent *ev )
02215 {
02216
02217
02218
02219
if ( m_part->
parentPart() )
02220 {
02221 QApplication::sendEvent(m_part->
parentPart()->
widget(), ev);
02222
return;
02223 }
02224 QScrollView::dropEvent( ev );
02225 }
02226
02227
void KHTMLView::focusInEvent(
QFocusEvent *e )
02228 {
02229
#ifndef KHTML_NO_CARET
02230
02231
02232
if (d->m_caretViewContext &&
02233 d->m_caretViewContext->freqTimerId == -1 &&
02234 m_part->
xmlDocImpl()) {
02235 NodeImpl *caretNode = m_part->
xmlDocImpl()->focusNode();
02236
if (m_part->
isCaretMode()
02237 || m_part->
isEditable()
02238 || (caretNode && caretNode->renderer()
02239 && caretNode->renderer()->style()->userInput()
02240 == UI_ENABLED)) {
02241 d->m_caretViewContext->freqTimerId = startTimer(500);
02242 d->m_caretViewContext->visible =
true;
02243 }
02244 }
02245 showCaret();
02246
#endif // KHTML_NO_CARET
02247
QScrollView::focusInEvent( e );
02248 }
02249
02250
void KHTMLView::focusOutEvent(
QFocusEvent *e )
02251 {
02252
if(m_part) m_part->
stopAutoScroll();
02253
02254
#ifndef KHTML_NO_CARET
02255
if (d->m_caretViewContext) {
02256
switch (d->m_caretViewContext->displayNonFocused) {
02257
case KHTMLPart::CaretInvisible:
02258 hideCaret();
02259
break;
02260
case KHTMLPart::CaretVisible: {
02261 killTimer(d->m_caretViewContext->freqTimerId);
02262 d->m_caretViewContext->freqTimerId = -1;
02263 NodeImpl *caretNode = m_part->
xmlDocImpl()->focusNode();
02264
if (!d->m_caretViewContext->visible && (m_part->
isCaretMode()
02265 || m_part->
isEditable()
02266 || (caretNode && caretNode->renderer()
02267 && caretNode->renderer()->style()->userInput()
02268 == UI_ENABLED))) {
02269 d->m_caretViewContext->visible =
true;
02270 showCaret(
true);
02271 }
02272
break;
02273 }
02274
case KHTMLPart::CaretBlink:
02275
02276
break;
02277 }
02278 }
02279
#endif // KHTML_NO_CARET
02280
QScrollView::focusOutEvent( e );
02281 }
02282
02283
void KHTMLView::slotScrollBarMoved()
02284 {
02285
if (!d->scrollingSelf)
02286 d->scrollBarMoved =
true;
02287 }
02288
02289
void KHTMLView::timerEvent (
QTimerEvent *e )
02290 {
02291
02292
if ( e->timerId() == d->scrollTimerId ) {
02293
if( d->scrollSuspended )
02294
return;
02295
switch (d->scrollDirection) {
02296
case KHTMLViewPrivate::ScrollDown:
02297
if (contentsY() + visibleHeight () >= contentsHeight())
02298 d->newScrollTimer(
this, 0);
02299
else
02300 scrollBy( 0, d->scrollBy );
02301
break;
02302
case KHTMLViewPrivate::ScrollUp:
02303
if (contentsY() <= 0)
02304 d->newScrollTimer(
this, 0);
02305
else
02306 scrollBy( 0, -d->scrollBy );
02307
break;
02308
case KHTMLViewPrivate::ScrollRight:
02309
if (contentsX() + visibleWidth () >= contentsWidth())
02310 d->newScrollTimer(
this, 0);
02311
else
02312 scrollBy( d->scrollBy, 0 );
02313
break;
02314
case KHTMLViewPrivate::ScrollLeft:
02315
if (contentsX() <= 0)
02316 d->newScrollTimer(
this, 0);
02317
else
02318 scrollBy( -d->scrollBy, 0 );
02319
break;
02320 }
02321
return;
02322 }
02323
else if ( e->timerId() == d->layoutTimerId ) {
02324 d->firstRelayout =
false;
02325 d->dirtyLayout =
true;
02326
layout();
02327 }
02328
#ifndef KHTML_NO_CARET
02329
else if (d->m_caretViewContext
02330 && e->timerId() == d->m_caretViewContext->freqTimerId) {
02331 d->m_caretViewContext->visible = !d->m_caretViewContext->visible;
02332
if (d->m_caretViewContext->displayed) {
02333 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02334 d->m_caretViewContext->width,
02335 d->m_caretViewContext->height);
02336 }
02337
02338
02339
return;
02340 }
02341
#endif
02342
02343
if( m_part->
xmlDocImpl() ) {
02344 DOM::DocumentImpl *document = m_part->
xmlDocImpl();
02345 khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
02346
02347
if ( root && !root->layouted() ) {
02348 killTimer(d->repaintTimerId);
02349 d->repaintTimerId = 0;
02350 scheduleRelayout();
02351
return;
02352 }
02353 }
02354
02355 setStaticBackground(d->useSlowRepaints);
02356
02357
02358 killTimer(d->repaintTimerId);
02359 d->repaintTimerId = 0;
02360
02361
QRegion updateRegion;
02362
QMemArray<QRect> rects = d->updateRegion.rects();
02363
02364 d->updateRegion =
QRegion();
02365
02366
if ( rects.size() )
02367 updateRegion = rects[0];
02368
02369
for (
unsigned i = 1; i < rects.size(); ++i ) {
02370 QRect obR = updateRegion.boundingRect();
02371
QRegion newRegion = updateRegion.unite(rects[i]);
02372
if (2*newRegion.boundingRect().height() > 3*obR.height() )
02373 {
02374 repaintContents( obR );
02375 updateRegion = rects[i];
02376 }
02377
else
02378 updateRegion = newRegion;
02379 }
02380
02381
if ( !updateRegion.isNull() )
02382 repaintContents( updateRegion.boundingRect() );
02383
02384
if (d->dirtyLayout && !d->visibleWidgets.isEmpty()) {
02385
QWidget* w;
02386 d->dirtyLayout =
false;
02387
02388 QRect visibleRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
02389
QPtrList<RenderWidget> toRemove;
02390
for (
QPtrDictIterator<QWidget> it(d->visibleWidgets); it.current(); ++it) {
02391
int xp = 0, yp = 0;
02392 w = it.current();
02393 RenderWidget* rw = static_cast<RenderWidget*>( it.currentKey() );
02394
if (!rw->absolutePosition(xp, yp) ||
02395 !visibleRect.intersects(QRect(xp, yp, w->width(), w->height())))
02396 toRemove.append(rw);
02397 }
02398
for (RenderWidget* r = toRemove.first(); r; r = toRemove.next())
02399
if ( (w = d->visibleWidgets.take(r) ) )
02400 addChild(w, 0, -500000);
02401 }
02402 }
02403
02404
void KHTMLView::scheduleRelayout(khtml::RenderObject * )
02405 {
02406
if (!d->layoutSchedulingEnabled || d->layoutTimerId)
02407
return;
02408
02409 d->layoutTimerId = startTimer( m_part->
xmlDocImpl() && m_part->
xmlDocImpl()->parsing()
02410 ? 1000 : 0 );
02411 }
02412
02413
void KHTMLView::unscheduleRelayout()
02414 {
02415
if (!d->layoutTimerId)
02416
return;
02417
02418 killTimer(d->layoutTimerId);
02419 d->layoutTimerId = 0;
02420 }
02421
02422
void KHTMLView::unscheduleRepaint()
02423 {
02424
if (!d->repaintTimerId)
02425
return;
02426
02427 killTimer(d->repaintTimerId);
02428 d->repaintTimerId = 0;
02429 }
02430
02431
void KHTMLView::scheduleRepaint(
int x,
int y,
int w,
int h)
02432 {
02433
bool parsing = !m_part->
xmlDocImpl() || m_part->
xmlDocImpl()->parsing();
02434
02435
02436
02437
02438
int time = parsing ? 300 : ( !d->complete ? 100 : 20 );
02439
02440
#ifdef DEBUG_FLICKER
02441
QPainter p;
02442 p.begin( viewport() );
02443
02444
int vx, vy;
02445 contentsToViewport( x, y, vx, vy );
02446 p.fillRect( vx, vy, w, h, Qt::red );
02447 p.end();
02448
#endif
02449
02450 d->updateRegion = d->updateRegion.unite(QRect(x,y,w,h));
02451
02452
if ( !d->repaintTimerId )
02453 d->repaintTimerId = startTimer( time );
02454
02455
02456 }
02457
02458
void KHTMLView::complete()
02459 {
02460
02461
02462 d->complete =
true;
02463
02464
02465
if (d->layoutTimerId)
02466 {
02467
02468
02469 killTimer(d->layoutTimerId);
02470 d->layoutTimerId = startTimer( 0 );
02471 }
02472
02473
02474
if (d->repaintTimerId)
02475 {
02476
02477
02478 killTimer(d->repaintTimerId);
02479 d->repaintTimerId = startTimer( 20 );
02480 }
02481 }
02482
02483
#ifndef KHTML_NO_CARET
02484
02485
02486
02487
02488
#include "khtml_caret.cpp"
02489
02490
void KHTMLView::initCaret(
bool keepSelection)
02491 {
02492
#if DEBUG_CARETMODE > 0
02493
kdDebug(6200) <<
"begin initCaret" <<
endl;
02494
#endif
02495
02496
if (m_part->
xmlDocImpl()) {
02497 d->caretViewContext();
02498
bool cmoved = d->m_caretViewContext->caretMoved;
02499
if (m_part->
d->caretNode().isNull()) {
02500
02501 m_part->
d->caretNode() = m_part->
document();
02502 m_part->
d->caretOffset() = 0L;
02503
02504
02505
02506
if (!m_part->
d->caretNode().handle()->renderer())
return;
02507 }
02508
02509
02510
02511 moveCaretTo(m_part->
d->caretNode().handle(), m_part->
d->caretOffset(), !keepSelection);
02512
02513
02514 d->m_caretViewContext->caretMoved = cmoved;
02515 }
02516
#if DEBUG_CARETMODE > 0
02517
kdDebug(6200) <<
"end initCaret" <<
endl;
02518
#endif
02519
}
02520
02521
bool KHTMLView::caretOverrides()
const
02522
{
02523
bool cm = m_part->
isCaretMode();
02524
bool dm = m_part->
isEditable();
02525
return cm && !dm ?
false
02526 : (dm || m_part->
d->caretNode().handle()->contentEditable())
02527 && d->editorContext()->override;
02528 }
02529
02530
void KHTMLView::ensureNodeHasFocus(NodeImpl *node)
02531 {
02532
if (m_part->
isCaretMode() || m_part->
isEditable())
return;
02533
if (node->focused())
return;
02534
02535
02536 NodeImpl *firstAncestor = 0;
02537
while (node) {
02538
if (node->renderer()
02539 && node->renderer()->style()->userInput() != UI_ENABLED)
02540
break;
02541 firstAncestor = node;
02542 node = node->parentNode();
02543 }
02544
02545
if (!node) firstAncestor = 0;
02546
02547 DocumentImpl *doc = m_part->
xmlDocImpl();
02548
02549
if (!firstAncestor && doc->focusNode() && doc->focusNode()->renderer()
02550 && doc->focusNode()->renderer()->isWidget())
02551
return;
02552
02553
02554
#if DEBUG_CARETMODE > 1
02555
kdDebug(6200) <<
k_funcinfo <<
"firstAncestor " << firstAncestor <<
": "
02556 << (firstAncestor ? firstAncestor->nodeName().string() :
QString::null) <<
endl;
02557
#endif
02558
doc->setFocusNode(firstAncestor);
02559 emit m_part->
nodeActivated(
Node(firstAncestor));
02560 }
02561
02562
void KHTMLView::recalcAndStoreCaretPos(InlineBox *hintBox)
02563 {
02564
if (!m_part || m_part->
d->caretNode().isNull())
return;
02565 d->caretViewContext();
02566 NodeImpl *caretNode = m_part->
d->caretNode().handle();
02567
#if DEBUG_CARETMODE > 0
02568
kdDebug(6200) <<
"recalcAndStoreCaretPos: caretNode=" << caretNode << (caretNode ?
" "+caretNode->nodeName().string() :
QString::null) << " r
@" << caretNode->renderer() << (caretNode->renderer() && caretNode->renderer()->isText() ? " \"" +
QConstString(static_cast<RenderText *>(caretNode->renderer())->str->s, kMin(static_cast<RenderText *>(caretNode->renderer())->str->l, 15u)).string() + "\"" :
QString::null) <<
endl;
02569
#endif
02570
caretNode->getCaret(m_part->
d->caretOffset(),
02571 caretOverrides(),
02572 d->m_caretViewContext->x, d->m_caretViewContext->y,
02573 d->m_caretViewContext->width,
02574 d->m_caretViewContext->height);
02575
02576
if (hintBox && d->m_caretViewContext->x == -1) {
02577
#if DEBUG_CARETMODE > 1
02578
kdDebug(6200) <<
"using hint inline box coordinates" <<
endl;
02579
#endif
02580
RenderObject *r = caretNode->renderer();
02581
const QFontMetrics &fm = r->style()->fontMetrics();
02582
int absx, absy;
02583 r->containingBlock()->absolutePosition(absx, absy,
02584
false);
02585 d->m_caretViewContext->x = absx + hintBox->xPos();
02586 d->m_caretViewContext->y = absy + hintBox->yPos()
02587 + hintBox->baseline() - fm.ascent();
02588 d->m_caretViewContext->width = 1;
02589
02590
02591 d->m_caretViewContext->height = fm.height();
02592 }
02593
02594
#if DEBUG_CARETMODE > 4
02595
02596
#endif
02597
#if DEBUG_CARETMODE > 0
02598
kdDebug(6200) <<
"caret: ofs="<<m_part->
d->caretOffset()<<
" "
02599 <<
" x="<<d->m_caretViewContext->x<<
" y="<<d->m_caretViewContext->y
02600 <<
" h="<<d->m_caretViewContext->height<<
endl;
02601
#endif
02602
}
02603
02604
void KHTMLView::caretOn()
02605 {
02606
if (d->m_caretViewContext) {
02607 killTimer(d->m_caretViewContext->freqTimerId);
02608
02609
if (hasFocus() || d->m_caretViewContext->displayNonFocused
02610 == KHTMLPart::CaretBlink) {
02611 d->m_caretViewContext->freqTimerId = startTimer(500);
02612 }
else {
02613 d->m_caretViewContext->freqTimerId = -1;
02614 }
02615
02616 d->m_caretViewContext->visible =
true;
02617
if ((d->m_caretViewContext->displayed = (hasFocus()
02618 || d->m_caretViewContext->displayNonFocused
02619 != KHTMLPart::CaretInvisible))) {
02620 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02621 d->m_caretViewContext->width,
02622 d->m_caretViewContext->height);
02623 }
02624
02625 }
02626 }
02627
02628
void KHTMLView::caretOff()
02629 {
02630
if (d->m_caretViewContext) {
02631 killTimer(d->m_caretViewContext->freqTimerId);
02632 d->m_caretViewContext->freqTimerId = -1;
02633 d->m_caretViewContext->displayed =
false;
02634
if (d->m_caretViewContext->visible) {
02635 d->m_caretViewContext->visible =
false;
02636 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02637 d->m_caretViewContext->width,
02638 d->m_caretViewContext->height);
02639 }
02640
02641 }
02642 }
02643
02644
void KHTMLView::showCaret(
bool forceRepaint)
02645 {
02646
if (d->m_caretViewContext) {
02647 d->m_caretViewContext->displayed =
true;
02648
if (d->m_caretViewContext->visible) {
02649
if (!forceRepaint) {
02650 updateContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02651 d->m_caretViewContext->width,
02652 d->m_caretViewContext->height);
02653 }
else {
02654 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02655 d->m_caretViewContext->width,
02656 d->m_caretViewContext->height);
02657 }
02658 }
02659
02660 }
02661 }
02662
02663
bool KHTMLView::foldSelectionToCaret(NodeImpl *startNode,
long startOffset,
02664 NodeImpl *endNode,
long endOffset)
02665 {
02666 m_part->
d->m_selectionStart = m_part->
d->m_selectionEnd = m_part->
d->caretNode();
02667 m_part->
d->m_startOffset = m_part->
d->m_endOffset = m_part->
d->caretOffset();
02668 m_part->
d->m_extendAtEnd =
true;
02669
02670
bool folded = startNode != endNode || startOffset != endOffset;
02671
02672
02673
if (folded) {
02674 m_part->
xmlDocImpl()->clearSelection();
02675 }
02676
02677
return folded;
02678 }
02679
02680
void KHTMLView::hideCaret()
02681 {
02682
if (d->m_caretViewContext) {
02683
if (d->m_caretViewContext->visible) {
02684
02685 d->m_caretViewContext->visible =
false;
02686
02687
02688 repaintContents(d->m_caretViewContext->x, d->m_caretViewContext->y,
02689 d->m_caretViewContext->width,
02690 d->m_caretViewContext->height);
02691 d->m_caretViewContext->visible =
true;
02692 }
02693 d->m_caretViewContext->displayed =
false;
02694
02695 }
02696 }
02697
02698
int KHTMLView::caretDisplayPolicyNonFocused()
const
02699
{
02700
if (d->m_caretViewContext)
02701
return d->m_caretViewContext->displayNonFocused;
02702
else
02703
return KHTMLPart::CaretInvisible;
02704 }
02705
02706
void KHTMLView::setCaretDisplayPolicyNonFocused(
int policy)
02707 {
02708 d->caretViewContext();
02709
02710 d->m_caretViewContext->displayNonFocused = (
KHTMLPart::CaretDisplayPolicy)policy;
02711
02712
02713
if (!hasFocus()) {
02714
switch (d->m_caretViewContext->displayNonFocused) {
02715
case KHTMLPart::CaretInvisible:
02716 hideCaret();
02717
break;
02718
case KHTMLPart::CaretBlink:
02719
if (d->m_caretViewContext->freqTimerId != -1)
break;
02720 d->m_caretViewContext->freqTimerId = startTimer(500);
02721
02722
case KHTMLPart::CaretVisible:
02723 d->m_caretViewContext->displayed =
true;
02724 showCaret();
02725
break;
02726 }
02727 }
02728 }
02729
02730
bool KHTMLView::placeCaret(InlineBox *hintBox)
02731 {
02732 CaretViewContext *cv = d->caretViewContext();
02733 caretOff();
02734 NodeImpl *caretNode = m_part->
d->caretNode().handle();
02735
02736
if (!caretNode || !caretNode->renderer())
return false;
02737 ensureNodeHasFocus(caretNode);
02738
if (m_part->
isCaretMode() || m_part->
isEditable()
02739 || caretNode->renderer()->style()->userInput() == UI_ENABLED) {
02740 recalcAndStoreCaretPos(hintBox);
02741
02742 cv->origX = cv->x;
02743
02744 caretOn();
02745
return true;
02746 }
02747
return false;
02748 }
02749
02750
void KHTMLView::ensureCaretVisible()
02751 {
02752 CaretViewContext *cv = d->m_caretViewContext;
02753
if (!cv)
return;
02754 ensureVisible(cv->x, cv->y, cv->width, cv->height);
02755 d->scrollBarMoved =
false;
02756 }
02757
02758
bool KHTMLView::extendSelection(NodeImpl *oldStartSel,
long oldStartOfs,
02759 NodeImpl *oldEndSel,
long oldEndOfs)
02760 {
02761
bool changed =
false;
02762
if (m_part->
d->m_selectionStart == m_part->
d->m_selectionEnd
02763 && m_part->
d->m_startOffset == m_part->
d->m_endOffset) {
02764 changed = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02765 m_part->
d->m_extendAtEnd =
true;
02766 }
else do {
02767 changed = m_part->
d->m_selectionStart.handle() != oldStartSel
02768 || m_part->
d->m_startOffset != oldStartOfs
02769 || m_part->
d->m_selectionEnd.handle() != oldEndSel
02770 || m_part->
d->m_endOffset != oldEndOfs;
02771
if (!changed)
break;
02772
02773
02774 NodeImpl *startNode;
02775
long startOffset;
02776
if (m_part->
d->m_extendAtEnd) {
02777 startNode = m_part->
d->m_selectionStart.handle();
02778 startOffset = m_part->
d->m_startOffset;
02779 }
else {
02780 startNode = m_part->
d->m_selectionEnd.handle();
02781 startOffset = m_part->
d->m_endOffset;
02782 m_part->
d->m_selectionEnd = m_part->
d->m_selectionStart;
02783 m_part->
d->m_endOffset = m_part->
d->m_startOffset;
02784 }
02785
02786
bool swapNeeded =
false;
02787
if (!m_part->
d->m_selectionEnd.isNull() && startNode) {
02788 swapNeeded = RangeImpl::compareBoundaryPoints(startNode, startOffset,
02789 m_part->
d->m_selectionEnd.handle(),
02790 m_part->
d->m_endOffset) >= 0;
02791 }
02792
02793 m_part->
d->m_selectionStart = startNode;
02794 m_part->
d->m_startOffset = startOffset;
02795
02796
if (swapNeeded) {
02797 m_part->
xmlDocImpl()->setSelection(m_part->
d->m_selectionEnd.handle(),
02798 m_part->
d->m_endOffset, m_part->
d->m_selectionStart.handle(),
02799 m_part->
d->m_startOffset);
02800 }
else {
02801 m_part->
xmlDocImpl()->setSelection(m_part->
d->m_selectionStart.handle(),
02802 m_part->
d->m_startOffset, m_part->
d->m_selectionEnd.handle(),
02803 m_part->
d->m_endOffset);
02804 }
02805 }
while(
false);
02806
return changed;
02807 }
02808
02809
void KHTMLView::updateSelection(NodeImpl *oldStartSel,
long oldStartOfs,
02810 NodeImpl *oldEndSel,
long oldEndOfs)
02811 {
02812
if (m_part->
d->m_selectionStart == m_part->
d->m_selectionEnd
02813 && m_part->
d->m_startOffset == m_part->
d->m_endOffset) {
02814
if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs)) {
02815 m_part->
emitSelectionChanged();
02816 }
02817 m_part->
d->m_extendAtEnd =
true;
02818 }
else {
02819
02820
if (!m_part->
d->m_selectionEnd.isNull() && !m_part->
d->m_selectionEnd.isNull()) {
02821
bool swapNeeded = RangeImpl::compareBoundaryPoints(
02822 m_part->
d->m_selectionStart.handle(), m_part->
d->m_startOffset,
02823 m_part->
d->m_selectionEnd.handle(), m_part->
d->m_endOffset) >= 0;
02824
if (swapNeeded) {
02825
DOM::Node tmpNode = m_part->
d->m_selectionStart;
02826
long tmpOffset = m_part->
d->m_startOffset;
02827 m_part->
d->m_selectionStart = m_part->
d->m_selectionEnd;
02828 m_part->
d->m_startOffset = m_part->
d->m_endOffset;
02829 m_part->
d->m_selectionEnd = tmpNode;
02830 m_part->
d->m_endOffset = tmpOffset;
02831 m_part->
d->m_startBeforeEnd =
true;
02832 m_part->
d->m_extendAtEnd = !m_part->
d->m_extendAtEnd;
02833 }
02834 }
02835
02836 m_part->
xmlDocImpl()->setSelection(m_part->
d->m_selectionStart.handle(),
02837 m_part->
d->m_startOffset, m_part->
d->m_selectionEnd.handle(),
02838 m_part->
d->m_endOffset);
02839 m_part->
emitSelectionChanged();
02840 }
02841 }
02842
02843
void KHTMLView::caretKeyPressEvent(
QKeyEvent *_ke)
02844 {
02845 NodeImpl *oldStartSel = m_part->
d->m_selectionStart.handle();
02846
long oldStartOfs = m_part->
d->m_startOffset;
02847 NodeImpl *oldEndSel = m_part->
d->m_selectionEnd.handle();
02848
long oldEndOfs = m_part->
d->m_endOffset;
02849
02850 NodeImpl *oldCaretNode = m_part->
d->caretNode().handle();
02851
long oldOffset = m_part->
d->caretOffset();
02852
02853
bool ctrl = _ke->state() & ControlButton;
02854
02855
02856
switch(_ke->key()) {
02857
case Key_Space:
02858
break;
02859
02860
case Key_Down:
02861 moveCaretNextLine(1);
02862
break;
02863
02864
case Key_Up:
02865 moveCaretPrevLine(1);
02866
break;
02867
02868
case Key_Left:
02869 moveCaretBy(
false, ctrl ? CaretByWord : CaretByCharacter, 1);
02870
break;
02871
02872
case Key_Right:
02873 moveCaretBy(
true, ctrl ? CaretByWord : CaretByCharacter, 1);
02874
break;
02875
02876
case Key_Next:
02877 moveCaretNextPage();
02878
break;
02879
02880
case Key_Prior:
02881 moveCaretPrevPage();
02882
break;
02883
02884
case Key_Home:
02885
if (ctrl)
02886 moveCaretToDocumentBoundary(
false);
02887
else
02888 moveCaretToLineBegin();
02889
break;
02890
02891
case Key_End:
02892
if (ctrl)
02893 moveCaretToDocumentBoundary(
true);
02894
else
02895 moveCaretToLineEnd();
02896
break;
02897
02898 }
02899
02900
if ((m_part->
d->caretNode().handle() != oldCaretNode
02901 || m_part->
d->caretOffset() != oldOffset)
02902
02903 && !m_part->
d->caretNode().isNull()) {
02904
02905 d->m_caretViewContext->caretMoved =
true;
02906
02907
if (_ke->state() & ShiftButton) {
02908 updateSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02909 }
else {
02910
if (foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs))
02911 m_part->
emitSelectionChanged();
02912 }
02913
02914 m_part->
emitCaretPositionChanged(m_part->
d->caretNode(), m_part->
d->caretOffset());
02915 }
02916
02917 _ke->accept();
02918 }
02919
02920
bool KHTMLView::moveCaretTo(NodeImpl *node,
long offset,
bool clearSel)
02921 {
02922 sanitizeCaretState(node, offset);
02923
if (!node)
return false;
02924
02925
02926
02927
02928 RenderArena arena;
02929 RenderFlow *cb;
02930 InlineBox *box = 0;
02931 findFlowBox(node, offset, &arena, cb, &box);
02932
if (box && box->object() != node->renderer()) {
02933
if (box->object()->element()) {
02934 node = box->object()->element();
02935 offset = node->minOffset();
02936
#if DEBUG_CARETMODE > 1
02937
kdDebug(6200) <<
"set new node " << node->nodeName().string() <<
"@" << node <<
endl;
02938
#endif
02939
}
else {
02940
02941 box = 0;
02942
kdError(6200) <<
"Box contains no node! Crash imminent" <<
endl;
02943 }
02944 }
02945
02946 NodeImpl *oldStartSel = m_part->
d->m_selectionStart.handle();
02947
long oldStartOfs = m_part->
d->m_startOffset;
02948 NodeImpl *oldEndSel = m_part->
d->m_selectionEnd.handle();
02949
long oldEndOfs = m_part->
d->m_endOffset;
02950
02951
02952
bool posChanged = m_part->
d->caretNode().handle() != node
02953 || m_part->
d->caretOffset() != offset;
02954
bool selChanged =
false;
02955
02956 m_part->
d->caretNode() = node;
02957 m_part->
d->caretOffset() = offset;
02958
if (clearSel || !oldStartSel || !oldEndSel) {
02959 selChanged = foldSelectionToCaret(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02960 }
else {
02961
02962
02963 selChanged = extendSelection(oldStartSel, oldStartOfs, oldEndSel, oldEndOfs);
02964
02965
02966 }
02967
02968 d->caretViewContext()->caretMoved =
true;
02969
02970
bool visible_caret = placeCaret(box);
02971
02972
02973
02974
02975
if (posChanged) {
02976 m_part->
emitCaretPositionChanged(visible_caret ? node : 0, offset);
02977 }
02978
02979
return selChanged;
02980 }
02981
02982
void KHTMLView::moveCaretByLine(
bool next,
int count)
02983 {
02984
02985
02986
Node &caretNodeRef = m_part->
d->caretNode();
02987
if (caretNodeRef.
isNull())
return;
02988
02989 NodeImpl *caretNode = caretNodeRef.
handle();
02990
02991
long offset = m_part->
d->caretOffset();
02992
02993 CaretViewContext *cv = d->caretViewContext();
02994
02995 LinearDocument ld(m_part, caretNode, offset);
02996
02997 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
02998
02999
03000
while (count > 0 && it != ld.end() && it != ld.preBegin()) {
03001 count--;
03002
if (
next) ++it;
else --it;
03003 }
03004
03005
03006
if (it == ld.end() || it == ld.preBegin())
return;
03007
03008
int x, absx, absy;
03009 InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
03010
03011 placeCaretOnLine(caretBox, x, absx, absy);
03012 }
03013
03014
void KHTMLView::placeCaretOnLine(InlineBox *caretBox,
int x,
int absx,
int absy)
03015 {
03016
03017
if (!caretBox)
return;
03018
03019 RenderObject *caretRender = caretBox->object();
03020 NodeImpl *caretNode = caretRender->element();
03021
03022
#if DEBUG_CARETMODE > 0
03023
kdDebug(6200) <<
"got valid caretBox " << caretBox <<
endl;
03024
kdDebug(6200) <<
"xPos: " << caretBox->xPos() <<
" yPos: " << caretBox->yPos()
03025 <<
" width: " << caretBox->width() <<
" height: " << caretBox->height() <<
endl;
03026
if (caretBox->isInlineTextBox()) {
kdDebug(6200) <<
"contains \"" <<
QString(((RenderText *)((InlineTextBox *)caretBox)->object())->str->s + ((InlineTextBox *)caretBox)->m_start, ((InlineTextBox *)caretBox)->m_len) <<
"\"" <<
endl;}
03027
#endif
03028
03029
int caretHeight = caretBox->height();
03030
bool isText = caretBox->isInlineTextBox();
03031
int yOfs = 0;
03032
if (isText) {
03033
03034 RenderText *t = static_cast<RenderText *>(caretRender);
03035
const QFontMetrics &fm = t->metrics(caretBox->m_firstLine);
03036 caretHeight = fm.height();
03037 yOfs = caretBox->baseline() - fm.ascent();
03038 }
03039
03040 caretOff();
03041
03042
03043 m_part->
d->caretNode() = caretNode;
03044
long &offset = m_part->
d->caretOffset();
03045
03046
03047 d->m_caretViewContext->y = caretBox->yPos() + yOfs;
03048 d->m_caretViewContext->height = caretHeight;
03049 d->m_caretViewContext->width = 1;
03050
03051
int xPos = caretBox->xPos();
03052
int caretBoxWidth = caretBox->width();
03053
03054
03055
if (x <= xPos) {
03056 d->m_caretViewContext->x = xPos;
03057 offset = caretBox->minOffset();
03058
03059 }
else if (x > xPos && x <= xPos + caretBoxWidth) {
03060
if (isText) {
03061 offset = static_cast<InlineTextBox *>(caretBox)->offsetForPoint(x,
03062 d->m_caretViewContext->x);
03063
#if DEBUG_CARETMODE > 2
03064
kdDebug(6200) <<
"deviation from origX " << d->m_caretViewContext->x - x <<
endl;
03065
#endif
03066
}
else {
03067
if (xPos + caretBoxWidth - x < x - xPos) {
03068 d->m_caretViewContext->x = xPos + caretBoxWidth;
03069 offset = caretNode ? caretNode->maxOffset() : 1;
03070 }
else {
03071 d->m_caretViewContext->x = xPos;
03072 offset = caretNode ? caretNode->minOffset() : 0;
03073 }
03074 }
03075 }
else {
03076 d->m_caretViewContext->x = xPos + caretBoxWidth;
03077 offset = caretBox->maxOffset();
03078 }
03079
#if DEBUG_CARETMODE > 0
03080
kdDebug(6200) <<
"new offset: " << offset <<
endl;
03081
#endif
03082
03083 d->m_caretViewContext->x += absx;
03084 d->m_caretViewContext->y += absy;
03085
03086 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03087 d->m_caretViewContext->width, d->m_caretViewContext->height);
03088 d->scrollBarMoved =
false;
03089
03090 ensureNodeHasFocus(caretNode);
03091 caretOn();
03092 }
03093
03094
void KHTMLView::moveCaretToLineBoundary(
bool end)
03095 {
03096
03097
03098
Node &caretNodeRef = m_part->
d->caretNode();
03099
if (caretNodeRef.
isNull())
return;
03100
03101 NodeImpl *caretNode = caretNodeRef.
handle();
03102
03103
long offset = m_part->
d->caretOffset();
03104
03105 LinearDocument ld(m_part, caretNode, offset);
03106
03107 EditableLineIterator it = ld.current();
03108
if (it == ld.end())
return;
03109
03110 EditableInlineBoxIterator fbit(it, end);
03111 InlineBox *b = *fbit;
03112 Q_ASSERT(b);
03113
03114 RenderObject *cb = (*it)->object();
03115
int absx, absy;
03116
03117
if (cb) cb->absolutePosition(absx,absy);
03118
else absx = absy = 0;
03119
03120
int x = b->xPos() + (
end ? b->width() : 0);
03121 d->m_caretViewContext->origX = absx + x;
03122 placeCaretOnLine(b, x, absx, absy);
03123 }
03124
03125
void KHTMLView::moveCaretToDocumentBoundary(
bool end)
03126 {
03127
03128
03129
Node &caretNodeRef = m_part->
d->caretNode();
03130
if (caretNodeRef.
isNull())
return;
03131
03132 NodeImpl *caretNode = caretNodeRef.
handle();
03133
03134
long offset = m_part->
d->caretOffset();
03135
03136 LinearDocument ld(m_part, caretNode, offset);
03137
03138 EditableLineIterator it(end ? ld.preEnd() : ld.begin(),
end);
03139
if (it == ld.end() || it == ld.preBegin())
return;
03140
03141 EditableInlineBoxIterator fbit = it;
03142 InlineBox *b = *fbit;
03143 Q_ASSERT(b);
03144
03145 RenderObject *cb = (*it)->object();
03146
int absx, absy;
03147
03148
if (cb) cb->absolutePosition(absx, absy);
03149
else absx = absy = 0;
03150
03151
int x = b->xPos();
03152 d->m_caretViewContext->origX = absx + x;
03153 placeCaretOnLine(b, x, absx, absy);
03154 }
03155
03156
void KHTMLView::moveCaretBy(
bool next, CaretMovement cmv,
int count)
03157 {
03158
if (!m_part)
return;
03159
03160
03161
Node &caretNodeRef = m_part->
d->caretNode();
03162
if (caretNodeRef.
isNull())
return;
03163
03164 NodeImpl *caretNode = caretNodeRef.
handle();
03165
03166
long &offset = m_part->
d->caretOffset();
03167
03168 LinearDocument ld(m_part, caretNode, offset);
03169
03170 EditableCharacterIterator it(&ld);
03171 InlineBox *hintBox = it.box();
03172
while (it.node() && count > 0) {
03173 count--;
03174
if (cmv == CaretByCharacter) {
03175
if (
next) ++it;
03176
else --it;
03177 }
else if (cmv == CaretByWord) {
03178
if (
next) moveItToNextWord(it);
03179
else moveItToPrevWord(it);
03180 }
03181 }
03182
if (it.node()) {
03183 caretNodeRef = it.node();
03184 offset = it.offset();
03185 hintBox = it.box();
03186
#if DEBUG_CARETMODE > 2
03187
kdDebug(6200) <<
"set by valid node. offset: " << offset <<
endl;
03188
#endif
03189
}
else {
03190 offset =
next ? caretNode->maxOffset() : caretNode->minOffset();
03191
#if DEBUG_CARETMODE > 0
03192
kdDebug(6200) <<
"set by INvalid node. offset: " << offset <<
endl;
03193
#endif
03194
}
03195 placeCaretOnChar(hintBox);
03196 }
03197
03198
void KHTMLView::placeCaretOnChar(InlineBox *hintBox)
03199 {
03200 caretOff();
03201 recalcAndStoreCaretPos(hintBox);
03202 ensureVisible(d->m_caretViewContext->x, d->m_caretViewContext->y,
03203 d->m_caretViewContext->width, d->m_caretViewContext->height);
03204 d->m_caretViewContext->origX = d->m_caretViewContext->x;
03205 d->scrollBarMoved =
false;
03206
#if DEBUG_CARETMODE > 3
03207
03208
#endif
03209
ensureNodeHasFocus(m_part->
d->caretNode().handle());
03210 caretOn();
03211 }
03212
03213
void KHTMLView::moveCaretByPage(
bool next)
03214 {
03215
03216
03217
Node &caretNodeRef = m_part->
d->caretNode();
03218
if (caretNodeRef.
isNull())
return;
03219
03220 NodeImpl *caretNode = caretNodeRef.
handle();
03221
03222
long offset = m_part->
d->caretOffset();
03223
03224
int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
03225
03226
int mindist = clipper()->height() - offs;
03227
03228 CaretViewContext *cv = d->caretViewContext();
03229
03230
03231 LinearDocument ld(m_part, caretNode, offset);
03232
03233 ErgonomicEditableLineIterator it(ld.current(), cv->origX);
03234
03235 moveIteratorByPage(ld, it, mindist, next);
03236
03237
int x, absx, absy;
03238 InlineBox *caretBox = nearestInlineBox(it, d->m_caretViewContext, x, absx, absy);
03239
03240 placeCaretOnLine(caretBox, x, absx, absy);
03241 }
03242
03243
void KHTMLView::moveCaretPrevWord()
03244 {
03245 moveCaretBy(
false, CaretByWord, 1);
03246 }
03247
03248
void KHTMLView::moveCaretNextWord()
03249 {
03250 moveCaretBy(
true, CaretByWord, 1);
03251 }
03252
03253
void KHTMLView::moveCaretPrevLine(
int n)
03254 {
03255 moveCaretByLine(
false, n);
03256 }
03257
03258
void KHTMLView::moveCaretNextLine(
int n)
03259 {
03260 moveCaretByLine(
true, n);
03261 }
03262
03263
void KHTMLView::moveCaretPrevPage()
03264 {
03265 moveCaretByPage(
false);
03266 }
03267
03268
void KHTMLView::moveCaretNextPage()
03269 {
03270 moveCaretByPage(
true);
03271 }
03272
03273
void KHTMLView::moveCaretToLineBegin()
03274 {
03275 moveCaretToLineBoundary(
false);
03276 }
03277
03278
void KHTMLView::moveCaretToLineEnd()
03279 {
03280 moveCaretToLineBoundary(
true);
03281 }
03282
03283
#endif // KHTML_NO_CARET
03284
03285
#undef DEBUG_CARETMODE