Index: trunk/kdelibs/khtml/khtmlview.cpp =================================================================== --- trunk/kdelibs/khtml/khtmlview.cpp (revision 121401) +++ trunk/kdelibs/khtml/khtmlview.cpp (revision 121402) @@ -1,1235 +1,1238 @@ /* This file is part of the KDE project * * Copyright (C) 1998, 1999 Torben Weis * 1999 Lars Knoll * 1999 Antti Koivisto * 2000 Dirk Mueller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "khtmlview.moc" #include "khtml_part.h" #include "khtml_events.h" #include "html/html_documentimpl.h" #include "html/html_inlineimpl.h" #include "rendering/render_object.h" #include "rendering/render_root.h" #include "rendering/render_style.h" #include "xml/dom2_eventsimpl.h" #include "misc/htmlhashes.h" #include "misc/helper.h" #include "khtml_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PAINT_BUFFER_HEIGHT 128 using namespace DOM; using namespace khtml; class KHTMLToolTip; class KHTMLViewPrivate { friend class KHTMLToolTip; public: KHTMLViewPrivate() { underMouse = 0; reset(); tp=0; paintBuffer=0; formCompletions=0; prevScrollbarVisible = true; } ~KHTMLViewPrivate() { delete formCompletions; delete tp; tp = 0; delete paintBuffer; paintBuffer =0; if (underMouse) underMouse->deref(); } void reset() { if (underMouse) underMouse->deref(); underMouse = 0; linkPressed = false; useSlowRepaints = false; originalNode = 0; borderTouched = false; #ifndef KHTML_NO_SCROLLBARS vmode = QScrollView::Auto; hmode = QScrollView::Auto; #else vmode = QScrollView::AlwaysOff; hmode = QScrollView::AlwaysOff; #endif scrollBarMoved = false; ignoreWheelEvents = false; borderX = 30; borderY = 30; clickX = -1; clickY = -1; prevMouseX = -1; prevMouseY = -1; clickCount = 0; isDoubleClick = false; } QPainter *tp; QPixmap *paintBuffer; NodeImpl *underMouse; // the node that was selected when enter was pressed ElementImpl *originalNode; bool borderTouched:1; bool borderStart:1; bool scrollBarMoved:1; QScrollView::ScrollBarMode vmode; QScrollView::ScrollBarMode hmode; bool prevScrollbarVisible; bool linkPressed; bool useSlowRepaints; bool ignoreWheelEvents; int borderX, borderY; KSimpleConfig *formCompletions; int clickX, clickY, clickCount; bool isDoubleClick; int prevMouseX, prevMouseY; }; #ifndef QT_NO_TOOLTIP class KHTMLToolTip : public QToolTip { public: KHTMLToolTip(KHTMLView *view, KHTMLViewPrivate* vp) : QToolTip(view->viewport()) { m_view = view; m_viewprivate = vp; }; protected: virtual void maybeTip(const QPoint &); private: KHTMLView *m_view; KHTMLViewPrivate* m_viewprivate; }; void KHTMLToolTip::maybeTip(const QPoint& /*p*/) { DOM::NodeImpl *node = m_viewprivate->underMouse; while ( node ) { if ( node->isElementNode() ) { QString s = static_cast( node )->getAttribute( ATTR_TITLE ).string(); if ( !s.isEmpty() ) { QRect r( m_view->contentsToViewport( node->getRect().topLeft() ), node->getRect().size() ); tip( r, s ); } break; } node = node->parentNode(); } } #endif KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name) : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase ) { m_medium = "screen"; m_part = part; d = new KHTMLViewPrivate; QScrollView::setVScrollBarMode(d->vmode); QScrollView::setHScrollBarMode(d->hmode); connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged())); connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved())); // initialize QScrollview enableClipper(true); viewport()->setMouseTracking(true); viewport()->setBackgroundMode(NoBackground); KImageIO::registerFormats(); viewport()->setCursor(arrowCursor); #ifndef QT_NO_TOOLTIP ( void ) new KHTMLToolTip( this, d ); #endif init(); viewport()->show(); } KHTMLView::~KHTMLView() { if (m_part) { //WABA: Is this Ok? Do I need to deref it as well? //Does this need to be done somewhere else? DOM::DocumentImpl *doc = m_part->xmlDocImpl(); if (doc) doc->detach(); } delete d; d = 0; } void KHTMLView::init() { if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT); if(!d->tp) d->tp = new QPainter(); setFocusPolicy(QWidget::StrongFocus); viewport()->setFocusPolicy( QWidget::WheelFocus ); viewport()->setFocusProxy(this); _marginWidth = -1; // undefined _marginHeight = -1; _width = 0; _height = 0; setAcceptDrops(true); resizeContents(visibleWidth(), visibleHeight()); } void KHTMLView::clear() { viewport()->erase(); if(d->useSlowRepaints) setStaticBackground(false); d->reset(); emit cleared(); QScrollView::setHScrollBarMode(d->hmode); if (d->vmode==Auto) QScrollView::setVScrollBarMode(d->prevScrollbarVisible?AlwaysOn:Auto); else QScrollView::setVScrollBarMode(d->vmode); resizeContents(visibleWidth(), visibleHeight()); } void KHTMLView::hideEvent(QHideEvent* e) { // viewport()->setBackgroundMode(PaletteBase); QScrollView::hideEvent(e); } void KHTMLView::showEvent(QShowEvent* e) { // viewport()->setBackgroundMode(NoBackground); QScrollView::showEvent(e); } void KHTMLView::resizeEvent (QResizeEvent* e) { QScrollView::resizeEvent(e); int w = visibleWidth(); int h = visibleHeight(); layout(); // this is to make sure we get the right width even if the scrolbar has dissappeared // due to the size change. if(visibleHeight() != h || visibleWidth() != w) layout(); KApplication::sendPostedEvents(viewport(), QEvent::Paint); } void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh ) { if(!m_part->xmlDocImpl()) { p->fillRect(ex, ey, ew, eh, palette().normal().brush(QColorGroup::Base)); return; } //kdDebug( 6000 ) << "drawContents x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl; if ( d->paintBuffer->width() < visibleWidth() ) d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT); int py=0; while (py < eh) { int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT; d->tp->begin(d->paintBuffer); d->tp->translate(-ex, -ey-py); d->tp->fillRect(ex, ey+py, ew, ph, palette().normal().brush(QColorGroup::Base)); m_part->xmlDocImpl()->renderer()->print(d->tp, ex, ey+py, ew, ph, 0, 0); #ifdef BOX_DEBUG if (m_part->xmlDocImpl()->focusNode()) { d->tp->setBrush(Qt::NoBrush); d->tp->drawRect(m_part->xmlDocImpl()->focusNode()->getRect()); } #endif d->tp->end(); p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph); py += PAINT_BUFFER_HEIGHT; } khtml::DrawContentsEvent event( p, ex, ey, ew, eh ); QApplication::sendEvent( m_part, &event ); } void KHTMLView::layout(bool) { //### take care of frmaes (hide scrollbars,...) if( m_part->xmlDocImpl() ) { DOM::DocumentImpl *document = m_part->xmlDocImpl(); khtml::RenderRoot* root = static_cast(document->renderer()); if ( !root ) return; if (document->isHTMLDocument()) { NodeImpl *body = static_cast(document)->body(); if(body && body->renderer() && body->id() == ID_FRAMESET) { QScrollView::setVScrollBarMode(AlwaysOff); QScrollView::setHScrollBarMode(AlwaysOff); _width = visibleWidth(); body->renderer()->setLayouted(false); body->renderer()->layout(); root->layout(); return; } } _height = visibleHeight(); _width = visibleWidth(); //QTime qt; //qt.start(); root->layout(); //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl; } else { _width = visibleWidth(); } } // // Event Handling // ///////////////// void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse ) { if(!m_part->xmlDocImpl()) return; int xm, ym; viewportToContents(_mouse->x(), _mouse->y(), xm, ym); //kdDebug( 6000 ) << "\nmousePressEvent: x=" << xm << ", y=" << ym << endl; // Make this frame the active one // ### need some visual indication for the active frame. /* ### use PartManager (Simon) if ( _isFrame && !_isSelected ) { kdDebug( 6000 ) << "activating frame!" << endl; topView()->setFrameSelected(this); }*/ d->isDoubleClick = false; DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress ); m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, 0, 0, &mev ); if (d->clickCount > 0 && d->clickX == xm && d->clickY == ym) // ### support mouse threshold d->clickCount++; else { d->clickCount = 1; d->clickX = xm; d->clickY = ym; } dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true, d->clickCount,_mouse,true,DOM::NodeImpl::MousePress); if (mev.innerNode.handle()) mev.innerNode.handle()->setPressed(); khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.innerNode ); event.setNodePos( mev.nodeAbsX, mev.nodeAbsY ); QApplication::sendEvent( m_part, &event ); emit m_part->nodeActivated(mev.innerNode); } void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse ) { if(!m_part->xmlDocImpl()) return; int xm, ym; viewportToContents(_mouse->x(), _mouse->y(), xm, ym); //kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl; d->isDoubleClick = true; DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick ); m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, 0, 0, &mev ); // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat // single and double-click events as separate (only the detail, i.e. number of clicks differs) // In other words an even detail value for a mouse click event means a double click, and an // odd detail value means a single click if (d->clickCount > 0 && d->clickX == xm && d->clickY == ym) // ### support mouse threshold d->clickCount++; else { d->clickCount = 1; d->clickX = xm; d->clickY = ym; } dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true, d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick); if (mev.innerNode.handle()) mev.innerNode.handle()->setPressed(); khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.innerNode ); event.setNodePos( mev.nodeAbsX, mev.nodeAbsY ); QApplication::sendEvent( m_part, &event ); // ### //if ( url.length() ) //emit doubleClick( url.string(), _mouse->button() ); } void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse ) { if(!m_part->xmlDocImpl()) return; int xm, ym; viewportToContents(_mouse->x(), _mouse->y(), xm, ym); DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove ); m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, 0, 0, &mev ); dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),false, 0,_mouse,true,DOM::NodeImpl::MouseMove); if (d->clickCount > 0 && QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) { d->clickCount = 0; // moving the mouse outside the threshold invalidates the click } // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events m_part->executeScheduledScript(); QCursor c = KCursor::arrowCursor(); if ( !mev.innerNode.isNull() && mev.innerNode.handle()->style() ) { khtml::RenderStyle* style = mev.innerNode.handle()->style(); if ((style->cursor() == CURSOR_AUTO) && (style->cursorImage()) && !(style->cursorImage()->pixmap().isNull())) { /* First of all it works: Check out http://www.iam.unibe.ch/~schlpbch/cursor.html * * But, I don't know what exactly we have to do here: rescale to 32*32, change to monochrome.. */ //kdDebug( 6000 ) << "using custom cursor" << endl; const QPixmap p = style->cursorImage()->pixmap(); // ### fix c = QCursor(p); } else { switch ( style->cursor() ) { case CURSOR_AUTO: if ( mev.url.length() && const_cast(m_part->settings())->changeCursor() ) c = m_part->urlCursor(); break; case CURSOR_CROSS: c = KCursor::crossCursor(); break; case CURSOR_POINTER: c = m_part->urlCursor(); break; case CURSOR_MOVE: c = KCursor::sizeAllCursor(); break; case CURSOR_E_RESIZE: case CURSOR_W_RESIZE: c = KCursor::sizeHorCursor(); break; case CURSOR_N_RESIZE: case CURSOR_S_RESIZE: c = KCursor::sizeVerCursor(); break; case CURSOR_NE_RESIZE: case CURSOR_SW_RESIZE: c = KCursor::sizeBDiagCursor(); break; case CURSOR_NW_RESIZE: case CURSOR_SE_RESIZE: c = KCursor::sizeFDiagCursor(); break; case CURSOR_TEXT: c = KCursor::ibeamCursor(); break; case CURSOR_WAIT: c = KCursor::waitCursor(); break; case CURSOR_HELP: c = KCursor::whatsThisCursor(); break; case CURSOR_DEFAULT: break; } } } QWidget *vp = viewport(); if ( vp->cursor().handle() != c.handle() ) vp->setCursor( c ); d->prevMouseX = xm; d->prevMouseY = ym; khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.innerNode ); event.setNodePos( mev.nodeAbsX, mev.nodeAbsY ); QApplication::sendEvent( m_part, &event ); } void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse ) { if ( !m_part->xmlDocImpl() ) return; int xm, ym; viewportToContents(_mouse->x(), _mouse->y(), xm, ym); //kdDebug( 6000 ) << "\nmouseReleaseEvent: x=" << xm << ", y=" << ym << endl; DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease ); m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, 0, 0, &mev ); dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true, d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease); if (d->clickCount > 0 && QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()) dispatchMouseEvent(EventImpl::CLICK_EVENT,mev.innerNode.handle(),true, d->clickCount,_mouse,true,DOM::NodeImpl::MouseRelease); if (mev.innerNode.handle()) mev.innerNode.handle()->setPressed(false); khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.innerNode ); event.setNodePos( mev.nodeAbsX, mev.nodeAbsY ); QApplication::sendEvent( m_part, &event ); } void KHTMLView::keyPressEvent( QKeyEvent *_ke ) { if (m_part->xmlDocImpl()) { ElementImpl *e = m_part->xmlDocImpl()->focusNode(); if (e && e->dispatchKeyEvent(_ke)) { //kdDebug(6010)<<"KHTMLView: key press event accepted by DOM."<accept(); return; } } int offs = (clipper()->height() < 30) ? clipper()->height() : 30; if (_ke->state()&ShiftButton) switch(_ke->key()) { case Key_Space: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( 0, -clipper()->height() - offs ); break; } else switch ( _ke->key() ) { case Key_Down: case Key_J: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( 0, 10 ); break; case Key_Space: case Key_Next: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( 0, clipper()->height() - offs ); break; case Key_Up: case Key_K: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( 0, -10 ); break; case Key_Prior: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( 0, -clipper()->height() + offs ); break; case Key_Right: case Key_L: if ( d->hmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( 10, 0 ); break; case Key_Left: case Key_H: if ( d->hmode == QScrollView::AlwaysOff ) _ke->accept(); else scrollBy( -10, 0 ); break; case Key_Enter: case Key_Return: // ### FIXME: // move this code to HTMLAnchorElementImpl::setPressed(false), // or even better to HTMLAnchorElementImpl::event() if (m_part->xmlDocImpl()) { ElementImpl *e = m_part->xmlDocImpl()->focusNode(); if (e) e->setActive(); d->originalNode = e; } break; case Key_Home: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else setContentsPos( 0, 0 ); break; case Key_End: if ( d->vmode == QScrollView::AlwaysOff ) _ke->accept(); else setContentsPos( 0, contentsHeight() - visibleHeight() ); break; default: _ke->ignore(); return; } _ke->accept(); } void KHTMLView::keyReleaseEvent(QKeyEvent *_ke) { if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode() && m_part->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke)) _ke->accept(); } bool KHTMLView::focusNextPrevChild( bool next ) { if (focusWidget()!=this) setFocus(); if (m_part->xmlDocImpl() && gotoLink(next)) return true; if (m_part->parentPart() && m_part->parentPart()->view()) return m_part->parentPart()->view()->focusNextPrevChild(next); m_part->overURL(QString(), 0); return QWidget::focusNextPrevChild(next); } void KHTMLView::doAutoScroll() { QPoint pos = QCursor::pos(); pos = viewport()->mapFromGlobal( pos ); int xm, ym; viewportToContents(pos.x(), pos.y(), xm, ym); pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y()); if ( (pos.y() < 0) || (pos.y() > visibleHeight()) || (pos.x() < 0) || (pos.x() > visibleWidth()) ) { ensureVisible( xm, ym, 0, 5 ); } } DOM::NodeImpl *KHTMLView::nodeUnderMouse() const { return d->underMouse; } bool KHTMLView::scrollTo(const QRect &bounds) { int x, y, xe, ye; x = bounds.left(); y = bounds.top(); xe = bounds.right(); ye = bounds.bottom(); //kdDebug(6000)<<"scrolling coords: x="<getRect(); if (nextRect.top() < contentsY() || nextRect.bottom() > contentsY()+visibleHeight()) return true; } } } if (!currentNode && d->borderStart != forward) nextTarget = 0; QRect nextRect; if (nextTarget) nextRect = nextTarget->getRect(); else nextRect = QRect(contentsX()+visibleWidth()/2, (forward?contentsHeight():0), 0, 0); // kdDebug(6000)<<"scrolling to dest ("<xmlDocImpl()->focusNode()) m_part->xmlDocImpl()->setFocusNode(0); d->borderTouched = false; return false; } else { HTMLAnchorElementImpl *anchor = 0; if ( ( nextTarget->id() == ID_A || nextTarget->id() == ID_AREA ) ) anchor = static_cast( nextTarget ); if (anchor && !anchor->areaHref().isNull()) m_part->overURL(anchor->areaHref().string(), 0); else m_part->overURL(QString(), 0); //kdDebug(6000)<<"reached link:"<nodeName().string()<xmlDocImpl()->setFocusNode(nextTarget); emit m_part->nodeActivated(Node(nextTarget)); } } return true; } void KHTMLView::setMediaType( const QString &medium ) { m_medium = medium; } QString KHTMLView::mediaType() const { return m_medium; } void KHTMLView::print() { if(!m_part->xmlDocImpl()) return; khtml::RenderRoot *root = static_cast(m_part->xmlDocImpl()->renderer()); if(!root) return; KPrinter *printer = new KPrinter; if(printer->setup(this)) { QApplication::setOverrideCursor( waitCursor ); // set up KPrinter printer->setFullPage(false); printer->setCreator("KDE 3.0 HTML Library"); QString docname = m_part->xmlDocImpl()->URL(); if ( !docname.isEmpty() ) printer->setDocName(docname); QPainter *p = new QPainter; p->begin( printer ); khtml::setPrintPainter( p ); m_part->xmlDocImpl()->setPaintDevice( printer ); QString oldMediaType = mediaType(); setMediaType( "print" ); QPaintDeviceMetrics metrics( printer ); // this is a simple approximation... we layout the document // according to the width of the page, then just cut // pages without caring about the content. We should do better // in the future, but for the moment this is better than no // printing support kdDebug(6000) << "printing: physical page width = " << metrics.width() << " height = " << metrics.height() << endl; root->setPrintingMode(true); root->setWidth(metrics.width()); QValueList oldSizes = m_part->fontSizes(); const int printFontSizes[] = { 6, 7, 8, 10, 12, 14, 18, 24, 28, 34, 40, 48, 56, 68, 82, 100, 0 }; QValueList fontSizes; for ( int i = 0; printFontSizes[i] != 0; i++ ) fontSizes << printFontSizes[ i ]; m_part->setFontSizes(fontSizes); m_part->xmlDocImpl()->applyChanges(); root->updateSize(); // ok. now print the pages. kdDebug(6000) << "printing: html page width = " << root->docWidth() << " height = " << root->docHeight() << endl; kdDebug(6000) << "printing: margins left = " << printer->margins().width() << " top = " << printer->margins().height() << endl; kdDebug(6000) << "printing: paper width = " << metrics.width() << " height = " << metrics.height() << endl; // if the width is too large to fit on the paper we just scale // the whole thing. int pageHeight = metrics.height(); int pageWidth = metrics.width(); // We print the bottom 'overlap' units again at the top of the next page. int overlap = 30; p->setClipRect(0,0, pageWidth, pageHeight); if(root->docWidth() > metrics.width()) { double scale = ((double) metrics.width())/((double) root->docWidth()); #ifndef QT_NO_TRANSFORMATIONS p->scale(scale, scale); #endif pageHeight = (int) (pageHeight/scale); pageWidth = (int) (pageWidth/scale); overlap = (int) (overlap/scale); } kdDebug(6000) << "printing: scaled html width = " << pageWidth << " height = " << pageHeight << endl; int top = 0; while(top < root->docHeight()) { if(top > 0) printer->newPage(); root->print(p, 0, top, pageWidth, pageHeight, 0, 0); p->translate(0,-(pageHeight-overlap)); if (top + pageHeight >= root->docHeight()) break; // Stop if we have printed everything top += (pageHeight-overlap); } p->end(); delete p; // and now reset the layout to the usual one... root->setPrintingMode(false); khtml::setPrintPainter( 0 ); setMediaType( oldMediaType ); m_part->xmlDocImpl()->setPaintDevice( this ); m_part->setFontSizes(oldSizes); m_part->xmlDocImpl()->applyChanges(); QApplication::restoreOverrideCursor(); } delete printer; } void KHTMLView::slotPaletteChanged() { if(!m_part->xmlDocImpl()) return; DOM::DocumentImpl *document = m_part->xmlDocImpl(); if (!document->isHTMLDocument()) return; khtml::RenderRoot *root = static_cast(document->renderer()); if(!root) return; root->style()->resetPalette(); NodeImpl *body = static_cast(document)->body(); if(!body) return; body->setChanged(true); body->applyChanges(); } void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more) { if(!m_part->xmlDocImpl()) return; khtml::RenderRoot *root = static_cast(m_part->xmlDocImpl()->renderer()); if(!root) return; m_part->xmlDocImpl()->setPaintDevice(p->device()); root->setPrintingMode(true); root->setWidth(rc.width()); p->save(); p->setClipRect(rc); p->translate(rc.left(), rc.top()); double scale = ((double) rc.width()/(double) root->docWidth()); int height = (int) ((double) rc.height() / scale); #ifndef QT_NO_TRANSFORMATIONS p->scale(scale, scale); #endif root->print(p, 0, yOff, root->docWidth(), height, 0, 0); if (more) *more = yOff + height < root->docHeight(); p->restore(); root->setPrintingMode(false); m_part->xmlDocImpl()->setPaintDevice( this ); } void KHTMLView::useSlowRepaints() { kdDebug(0) << "slow repaints requested" << endl; d->useSlowRepaints = true; setStaticBackground(true); } void KHTMLView::setVScrollBarMode ( ScrollBarMode mode ) { #ifndef KHTML_NO_SCROLLBARS d->vmode = mode; QScrollView::setVScrollBarMode(mode); #else Q_UNUSED( mode ); #endif } void KHTMLView::setHScrollBarMode ( ScrollBarMode mode ) { #ifndef KHTML_NO_SCROLLBARS d->hmode = mode; QScrollView::setHScrollBarMode(mode); #else Q_UNUSED( mode ); #endif } void KHTMLView::restoreScrollBar ( ) { int ow = visibleWidth(); QScrollView::setVScrollBarMode(d->vmode); if (visibleWidth() != ow) { layout(); updateContents(contentsX(),contentsY(),visibleWidth(),visibleHeight()); } d->prevScrollbarVisible = verticalScrollBar()->isVisible(); } QStringList KHTMLView::formCompletionItems(const QString &name) const { if (!m_part->settings()->isFormCompletionEnabled()) return QStringList(); if (!d->formCompletions) d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions")); return d->formCompletions->readListEntry(name); } void KHTMLView::addFormCompletionItem(const QString &name, const QString &value) { if (!m_part->settings()->isFormCompletionEnabled()) return; // don't store values that are all numbers or just numbers with // dashes or spaces as those are likely credit card numbers or // something similar bool cc_number(true); for (unsigned int i = 0; i < value.length(); ++i) { QChar c(value[i]); if (!c.isNumber() && c != '-' && !c.isSpace()) { cc_number = false; break; } } if (cc_number) return; QStringList items = formCompletionItems(name); if (!items.contains(value)) items.prepend(value); while ((int)items.count() > m_part->settings()->maxFormCompletionItems()) items.remove(items.fromLast()); d->formCompletions->writeEntry(name, items); } void KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable, int detail,QMouseEvent *_mouse, bool setUnder, int mouseEventType) { if (d->underMouse) d->underMouse->deref(); d->underMouse = targetNode; if (d->underMouse) d->underMouse->ref(); int exceptioncode; int clientX, clientY; viewportToContents(_mouse->x(), _mouse->y(), clientX, clientY); int screenX = _mouse->globalX(); int screenY = _mouse->globalY(); int button = -1; switch (_mouse->button()) { case LeftButton: button = 0; break; case MidButton: button = 1; break; case RightButton: button = 2; break; default: break; } bool ctrlKey = (_mouse->state() & ControlButton); bool altKey = (_mouse->state() & AltButton); bool shiftKey = (_mouse->state() & ShiftButton); bool metaKey = false; // ### qt support? // mouseout/mouseover if (setUnder && (d->prevMouseX != clientX || d->prevMouseY != clientY)) { NodeImpl *oldUnder = 0; if (d->prevMouseX >= 0 && d->prevMouseY >= 0) { NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast(mouseEventType)); m_part->xmlDocImpl()->prepareMouseEvent( d->prevMouseX, d->prevMouseY, 0, 0, &mev ); oldUnder = mev.innerNode.handle(); } if (oldUnder != targetNode) { // send mouseout event to the old node if (oldUnder){ oldUnder->ref(); MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT, true,true,m_part->xmlDocImpl()->defaultView(), 0,screenX,screenY,clientX,clientY, ctrlKey,altKey,shiftKey,metaKey, button,targetNode); me->ref(); oldUnder->dispatchEvent(me,exceptioncode); me->deref(); } // send mouseover event to the new node if (targetNode) { MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT, true,true,m_part->xmlDocImpl()->defaultView(), 0,screenX,screenY,clientX,clientY, ctrlKey,altKey,shiftKey,metaKey, button,oldUnder); me->ref(); targetNode->dispatchEvent(me,exceptioncode); me->deref(); } if (oldUnder) oldUnder->deref(); } } if (targetNode) { // send the actual event MouseEventImpl *me = new MouseEventImpl(static_cast(eventId), true,cancelable,m_part->xmlDocImpl()->defaultView(), detail,screenX,screenY,clientX,clientY, ctrlKey,altKey,shiftKey,metaKey, button,0); me->ref(); targetNode->dispatchEvent(me,exceptioncode); bool defaultHandled = me->defaultHandled(); me->deref(); // special case for HTML click & ondblclick handler if (eventId == EventImpl::CLICK_EVENT) { me = new MouseEventImpl(d->isDoubleClick ? EventImpl::KHTML_DBLCLICK_EVENT : EventImpl::KHTML_CLICK_EVENT, true,cancelable,m_part->xmlDocImpl()->defaultView(), detail,screenX,screenY,clientX,clientY, ctrlKey,altKey,shiftKey,metaKey, button,0); me->ref(); if (defaultHandled) me->setDefaultHandled(); targetNode->dispatchEvent(me,exceptioncode); me->deref(); } } } void KHTMLView::setIgnoreWheelEvents( bool e ) { d->ignoreWheelEvents = e; } +#ifndef QT_NO_WHEELEVENT + void KHTMLView::viewportWheelEvent(QWheelEvent* e) { if ( d->ignoreWheelEvents && !verticalScrollBar()->isVisible() && m_part->parentPart() ) { if ( m_part->parentPart()->view() ) m_part->parentPart()->view()->wheelEvent( e ); e->ignore(); } else if ( d->vmode == QScrollView::AlwaysOff ) { e->accept(); } else { d->scrollBarMoved = true; QScrollView::viewportWheelEvent( e ); } } +#endif void KHTMLView::focusOutEvent( QFocusEvent *e ) { m_part->stopAutoScroll(); QScrollView::focusOutEvent( e ); } void KHTMLView::slotScrollBarMoved() { d->scrollBarMoved = true; } Index: trunk/kdelibs/khtml/khtmlview.h =================================================================== --- trunk/kdelibs/khtml/khtmlview.h (revision 121401) +++ trunk/kdelibs/khtml/khtmlview.h (revision 121402) @@ -1,244 +1,246 @@ /* This file is part of the KDE project Copyright (C) 1997 Martin Jones (mjones@kde.org) (C) 1998 Waldo Bastian (bastian@kde.org) (C) 1998, 1999 Torben Weis (weis@kde.org) (C) 1999 Lars Knoll (knoll@kde.org) (C) 1999 Antti Koivisto (koivisto@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef KHTML_H #define KHTML_H // qt includes and classes #include class QPainter; class QRect; namespace DOM { class HTMLDocumentImpl; class ElementImpl; class HTMLElementImpl; class HTMLTitleElementImpl; class HTMLGenericFormElementImpl; class HTMLFormElementImpl; class Range; class NodeImpl; class CSSProperty; }; namespace khtml { class RenderObject; class RenderRoot; class RenderStyle; class RenderLineEdit; class RenderPartObject; void applyRule(RenderStyle *style, DOM::CSSProperty *prop, DOM::ElementImpl *e); }; class KHTMLPart; class KHTMLViewPrivate; /** * Renders and displays HTML in a @ref QScrollView. * * Suitable for use as an application's main view. **/ class KHTMLView : public QScrollView { Q_OBJECT friend class DOM::HTMLDocumentImpl; friend class DOM::HTMLElementImpl; friend class DOM::HTMLTitleElementImpl; friend class KHTMLPart; friend class khtml::RenderRoot; friend class DOM::HTMLGenericFormElementImpl; friend class DOM::HTMLFormElementImpl; friend class khtml::RenderLineEdit; friend class khtml::RenderPartObject; friend void khtml::applyRule(khtml::RenderStyle *style, DOM::CSSProperty *prop, DOM::ElementImpl *e); public: /** * Constructs a KHTMLView. */ KHTMLView( KHTMLPart *part, QWidget *parent, const char *name=0 ); virtual ~KHTMLView(); /** * Returns a pointer to the KHTMLPart that is * rendering the page. **/ KHTMLPart *part() const { return m_part; } int frameWidth() const { return _width; } /** * Sets a margin in x direction. */ void setMarginWidth(int x) { _marginWidth = x; } /** * Returns the margin width. * * A return value of -1 means the default value will be used. */ int marginWidth() const { return _marginWidth; } /* * Sets a margin in y direction. */ void setMarginHeight(int y) { _marginHeight = y; } /** * Returns the margin height. * * A return value of -1 means the default value will be used. */ int marginHeight() { return _marginHeight; } /** * Sets verticals scrollbar mode. Reimplemented for internal reasons. */ virtual void setVScrollBarMode ( ScrollBarMode mode ); /** * Sets horizontal scrollbar mode. Reimplemented for internal reasons. */ virtual void setHScrollBarMode ( ScrollBarMode mode ); /** * Overrides the scrollbar mode. */ void forceHScrollBarMode( ScrollBarMode mode ); - + /** * Overrides the scrollbar mode. */ void forceVScrollBarMode( ScrollBarMode mode ); /** * Prints the HTML document. */ void print(); /** * Paints the HTML document to a QPainter. * The document will be scaled to match the width of * rc and clipped to fit in the height. * yOff determines the vertical offset in the document to start with. * more, if nonzero will be set to true if the documents extends * beyond the rc or false if everything below yOff was painted. **/ void paint(QPainter *p, const QRect &rc, int yOff = 0, bool *more = 0); void layout(bool force = false); /** * Get/set the CSS Media Type. * * Media type is set to "screen" for on-screen rendering and "print" * during printing. Other media types lack the proper support in the * renderer and are not activated. The DOM tree and the parser itself, * however, properly handle other media types. To make them actually work * you only need to enable the media type in the view and if necessary * add the media type dependent changes to the renderer. */ void setMediaType( const QString &medium ); QString mediaType() const; signals: void cleared(); protected: void clear(); virtual void resizeEvent ( QResizeEvent * event ); virtual void showEvent ( QShowEvent * ); virtual void hideEvent ( QHideEvent *); virtual bool focusNextPrevChild( bool next ); virtual void drawContents ( QPainter * p, int clipx, int clipy, int clipw, int cliph ); virtual void viewportMousePressEvent( QMouseEvent * ); virtual void focusOutEvent( QFocusEvent * ); virtual void viewportMouseDoubleClickEvent( QMouseEvent * ); virtual void viewportMouseMoveEvent(QMouseEvent *); virtual void viewportMouseReleaseEvent(QMouseEvent *); +#ifndef QT_NO_WHEELEVENT virtual void viewportWheelEvent(QWheelEvent*); +#endif void keyPressEvent( QKeyEvent *_ke ); void keyReleaseEvent ( QKeyEvent *_ke ); void doAutoScroll(); protected slots: void slotPaletteChanged(); void slotScrollBarMoved(); private: /** * move the view towards the given rectangle be up to one page. * return true if reached. */ bool scrollTo(const QRect &); /** * move the view towards the next node * or the last node from this one. */ bool gotoLink(bool); /** * @internal */ bool gotoLinkInternal(bool); void useSlowRepaints(); void setIgnoreWheelEvents(bool e); void init(); DOM::NodeImpl *nodeUnderMouse() const; void restoreScrollBar(); QStringList formCompletionItems(const QString &name) const; void addFormCompletionItem(const QString &name, const QString &value); void dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable, int detail,QMouseEvent *_mouse, bool setUnder, int mouseEventType); // ------------------------------------- member variables ------------------------------------ private: int _width; int _height; int _marginWidth; int _marginHeight; KHTMLPart *m_part; KHTMLViewPrivate *d; QString m_medium; // media type }; #endif