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