/* * Copyright 2009-2011 by Sebastian Kügler * Copyright 2009 by Richard Moore * This program 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, or * (at your option) any later version. * * This program 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 General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kgraphicswebslice.h" #include #include #include #include #include #include #include #include #include struct KGraphicsWebSlicePrivate { QString selector; QRectF sliceGeometry; QRectF originalGeometry; QString loadingText; QTimer* resizeTimer; QSizeF resizeNew; QRectF previewRect; bool previewMode; QColor previewMaskColor; QSize fullContentSize; QWebElementCollection elementCache; QHash selectorGeometry; QRect documentGeometry; }; KGraphicsWebSlice::KGraphicsWebSlice( QGraphicsWidget *parent ) : QGraphicsWebView( parent ) { d = new KGraphicsWebSlicePrivate; d->originalGeometry = QRectF(); d->fullContentSize = QSize(1024,768); d->previewMaskColor = QColor("black"); connect(this, SIGNAL(loadFinished(bool)), this, SLOT(finishedLoading(bool))); d->resizeTimer = new QTimer(this); d->resizeTimer->setInterval(100); d->resizeTimer->setSingleShot(true); d->resizeNew = QSizeF(); connect(d->resizeTimer, SIGNAL(timeout()), SLOT(resizeTimeout())); //resize(300, 300); } KGraphicsWebSlice::~KGraphicsWebSlice() { delete d; } void KGraphicsWebSlice::loadSlice(const QUrl &u, const QString &selector) { if ( d->selector == selector && url() == u) { return; } setElement(selector); if (url() != u) { QGraphicsWebView::load(u); } setZoomFactor(1.0); } void KGraphicsWebSlice::setLoadingText(const QString &html) { d->loadingText = html; } void KGraphicsWebSlice::setElement(const QString &selector) { d->selector = selector; } void KGraphicsWebSlice::setSliceGeometry(const QRectF geo) { d->sliceGeometry = geo; } void KGraphicsWebSlice::finishedLoading(bool ok) { if (!ok) { return; } // Normalize page qDebug() << "loading finished" << ok << ", updating cache then slice or preview"; QWebFrame *frame = page()->mainFrame(); frame->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff ); frame->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff ); page()->setPreferredContentsSize(d->fullContentSize); // Update geometry caches updateElementCache(); // Zoom to slice or preview refresh(); } void KGraphicsWebSlice::refresh() { // TODO: optimize for non-changes if (!d->previewMode) { showSlice(d->selector); } else { showPage(); } } void KGraphicsWebSlice::updateElementCache() { qDebug() << "updateElementCache()"; d->elementCache = page()->mainFrame()->findAllElements("*"); d->documentGeometry = page()->mainFrame()->documentElement().geometry(); foreach(const QWebElement &el, d->elementCache) { d->selectorGeometry[qHash(el.toOuterXml())] = el.geometry(); } } QRectF KGraphicsWebSlice::previewGeometry(const QString &selector) const { return QRectF(page()->mainFrame()->findFirstElement(selector).geometry()); } QRectF KGraphicsWebSlice::sliceGeometry(const QString &selector) const { QWebElement el = page()->mainFrame()->findFirstElement(selector); return d->selectorGeometry.value(qHash(el.toOuterXml())); } void KGraphicsWebSlice::resizeEvent ( QGraphicsSceneResizeEvent * event ) { setTiledBackingStoreFrozen(true); d->resizeNew = event->newSize(); d->resizeTimer->start(); event->accept(); } void KGraphicsWebSlice::resizeTimeout() { QSizeF n = d->resizeNew; // Prevent oopses. if (n.width() > 2400 || n.height() > 2400) { qDebug() << "giant size, what's going on???????" << n.width(); return; } refresh(); setTiledBackingStoreFrozen(false); } void KGraphicsWebSlice::preview(const QString &selector) { if (selector.isEmpty()) { setPreviewMode(false); refresh(); return; } setPreviewMode(true); d->previewRect = previewGeometry(selector); update(); } void KGraphicsWebSlice::setPreviewMode(bool on) { showPage(); if (on && !d->previewMode) { d->previewMode = on; refresh(); } if (!on && d->previewMode) { d->previewMode = on; setZoomFactor(1.0); refresh(); } } void KGraphicsWebSlice::showSlice(const QString &selector) { QRectF r = sliceGeometry(selector); // qDebug() << "area=" << d->documentGeometry << ", viewportSize=" << page()->viewportSize() << ", contentsRect=" << contentsRect().size(); if (!selector.isEmpty() && r.isValid()) { zoom(r); } else if (d->documentGeometry.width() != contentsRect().size().width()) { // Change zoom level only if the current one isn't appropriate // but reset to 1.0 first setZoomFactor(1.0); updateElementCache(); zoom(d->documentGeometry); } } void KGraphicsWebSlice::zoom(const QRectF &area) { if (!area.isValid()) { qDebug() << "invalid zoom area" << area; return; } qreal f = contentsRect().size().width() / qMax((qreal)1.0, area.width()); // size: zoom page if (f > 0.1 && f < 32) { // within sane bounds? setZoomFactor(f); } if (area != sliceGeometry(d->selector)) { qDebug() << "different results."; } // position: move origin according to zoom QPointF viewPosition = area.topLeft(); // We end up positioning too low, so move the new position up a little viewPosition = QPointF(viewPosition.x() * f, (viewPosition.y() * f) - (16 * f)); page()->mainFrame()->setScrollPosition(viewPosition.toPoint()); } void KGraphicsWebSlice::showPage() { qreal zoom = 1.0; QSizeF o = d->documentGeometry.size(); QSizeF s = o; s.scale(contentsRect().size(), Qt::KeepAspectRatio); zoom = s.width() / qMax((qreal)1.0, contentsRect().width()); setZoomFactor(zoom); page()->mainFrame()->setScrollPosition(QPoint(0, 0)); update(); } QPixmap KGraphicsWebSlice::elementPixmap() const { QRectF rect = sliceGeometry(); if (!rect.isValid()) { return QPixmap(); } QPixmap result = QPixmap( rect.size().toSize() ); result.fill( Qt::white ); QPainter painter( &result ); painter.translate( -rect.x(), -rect.y() ); QWebFrame *frame = page()->mainFrame(); frame->render( &painter, QRegion(rect.toRect()) ); return result; } void KGraphicsWebSlice::setPreviewMaskColor(const QColor &color) { d->previewMaskColor = color; if (d->previewMode) { update(); } } void KGraphicsWebSlice::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * widget) { QGraphicsWebView::paint(painter, option, widget); if (!d->previewMode) { return; } d->previewMaskColor.setAlphaF(1.0); painter->setPen(d->previewMaskColor); d->previewMaskColor.setAlphaF(.5); painter->setBrush(d->previewMaskColor); QPainterPath path; path.addRect(boundingRect()); path.addRect(d->previewRect); painter->drawPath(path); //painter->drawRect(d->previewRect); } #include "moc_kgraphicswebslice.cpp"