kde-extraapps/kdeplasma-addons/applets/webslice/plasma/webslice.cpp
2015-02-27 11:02:43 +00:00

293 lines
11 KiB
C++

/***************************************************************************
* Copyright 2009-2011 by Sebastian Kugler <sebas@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, 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 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 "webslice.h"
#include <kgraphicswebslice.h>
#include <limits.h>
// Qt
#include <QGraphicsSceneResizeEvent>
#include <QLabel>
#include <QGraphicsLinearLayout>
#include <QWebElement>
#include <QWebFrame>
// KDE
#include <KDebug>
#include <KConfigDialog>
#include <KServiceTypeTrader>
#include <Plasma/Theme>
// Plasma
#include <Plasma/Label>
WebSlice::WebSlice(QObject *parent, const QVariantList &args)
: Plasma::PopupApplet(parent, args),
m_slice(0),
m_url(0)
{
setPopupIcon("internet-web-browser");
setAspectRatioMode(Plasma::IgnoreAspectRatio );
setAcceptDrops(true);
setAcceptsHoverEvents(true);
setMinimumSize(64, 64);
resize(800, 600);
kDebug() << "0";
}
void WebSlice::init()
{
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(pluginName());
const KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet",
constraint);
foreach (const KService::Ptr &service, offers) {
QStringList args = service->property("X-Plasma-Args").toStringList();
if (args.count() >= 1) {
m_url = KUrl(args[0]);
if (args.count() >= 2) {
m_element = args[1];
if (args.count() >= 6) {
m_sliceGeometry = QRectF(args[2].toInt(), args[3].toInt(),
args[4].toInt(), args[5].toInt());
}
}
}
}
void graphicsWidget();
}
WebSlice::~WebSlice ()
{
}
void WebSlice::configChanged()
{
kDebug();
KConfigGroup cg = config();
if (!m_url.isValid() || m_url.isEmpty()) {
m_url = cg.readEntry("url", "http://dot.kde.org/");
m_element = cg.readEntry("element", "#block-views-planetkde-block_1");
// for testing geometry
//m_url = cg.readEntry("url", "http://buienradar.nl/");
//m_sliceGeometry = cg.readEntry("size", QRectF(258, 102, 550, 511));
m_sliceGeometry = cg.readEntry("sliceGeometry", QRectF());
}
setAssociatedApplicationUrls(KUrl::List(m_url));
if (m_slice) {
m_slice->preview();
}
loadSlice(m_url, m_element);
}
QGraphicsWidget* WebSlice::graphicsWidget()
{
if (!m_slice) {
m_widget = new QGraphicsWidget(this);
QGraphicsLinearLayout *l = new QGraphicsLinearLayout(m_widget);
m_widget->setLayout(l);
m_slice = new KGraphicsWebSlice(m_widget);
m_slice->setMaximumSize(contentsRect().size());
//m_slice->show();
updateColors();
//connect(m_slice, SIGNAL(sizeChanged(QSizeF)), this, SLOT(sizeChanged(QSizeF)));
connect(m_slice, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateColors()));
setBusy(true);
m_slice->setLoadingText(i18nc("displayed in the widget while loading", "<h1>Loading...</h1>"));
//m_slice->hide();
l->addItem(m_slice);
kDebug() << "slice set up";
configChanged();
}
return m_widget;
}
void WebSlice::createConfigurationInterface(KConfigDialog *parent)
{
//QLabel *info = new QLabel(parent);
QLabel* info = new QLabel(parent);
info->setWordWrap(true);
info->setTextInteractionFlags(Qt::TextBrowserInteraction);
info->setText(i18n("<p>The Webslice Widget allows you to display a part of a webpage on your desktop or in a panel. The webslice is fully interactive.</p>"
"<p>"
"Specify the URL of the webpage in the URL field."
"In the <em>Element to Show</em> field, fill in a CSS identifier (for example #mybox for elements with the id \"mybox\"). This is the preferred method as it works best with layout changes on the webpage."
"</p>"
"<p>"
"Alternatively, you can specify a rectangle on the webpage to use as slice. Use \"x,y,width,height\" in pixels, for example <em>\"100,80,300,360\"</em>. This method is a fallback for webpages that do not provide enough semantic markup for the above mechanism."
"</p>"
"If both methods (element and geometry) are used, the element will take precedence."));
parent->addPage(info, i18nc("informational page", "Info"), "help-hint");
QWidget *widget = new QWidget(parent);
ui.setupUi(widget);
parent->addPage(widget, i18nc("general config page", "Webpage"), Applet::icon());
connect(ui.loadUrl, SIGNAL(clicked()), this, SLOT(loadUrl()));
connect(ui.elementCombo, SIGNAL(destroyed()), SLOT(disconnectLoadFinished()));
connect(ui.elementCombo, SIGNAL(activated(QString)), this, SLOT(preview(QString)));
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
ui.urlEdit->setText(m_url.toString());
ui.loadUrl->setIcon(KIcon("view-refresh"));
ui.geometryEdit->setText(sliceGeometryToString());
ui.elementCombo->setEditable(true);
updateElements();
preview(m_element);
connect(ui.urlEdit, SIGNAL(userTextChanged(QString)), parent, SLOT(settingsModified()));
connect(ui.loadUrl, SIGNAL(toggled(bool)), parent, SLOT(settingsModified()));
connect(ui.elementCombo, SIGNAL(editTextChanged(QString)), parent, SLOT(settingsModified()));
connect(ui.geometryEdit, SIGNAL(userTextChanged(QString)), parent, SLOT(settingsModified()));
connect(ui.elementCombo, SIGNAL(editTextChanged(QString)), this, SLOT(handleGeometryEdit()));
connect(parent, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this,
SLOT(handleGeometryEdit()));
}
void WebSlice::updateElements()
{
ui.elementCombo->clear();
ui.elementCombo->addItem(m_element, m_element);
ui.elementCombo->addItem(QString("body"), QString("body"));
foreach(const QWebElement el, m_slice->page()->mainFrame()->findAllElements("*")) {
QString elSelector;
QString elAttributeName;
if (el.attributeNames().contains("id")) {
elAttributeName = QString("id");
elSelector = QString("#%1").arg(el.attribute("id")); // according to CSS selector syntax
} else {
/* don't add all elements for now, this really only clutters the combo
elSelector = el.localName();
if (!el.attribute("class").isEmpty()) {
elSelector.append("." + el.attribute("class"));
}
*/
}
// Add Item?
if (!elSelector.isEmpty() && !(el.geometry().size().isNull())) {
ui.elementCombo->addItem(elSelector, elAttributeName);
}
}
}
void WebSlice::disconnectLoadFinished()
{
// we need to prevent the combo from being updated when it's gone
disconnect(m_slice, SIGNAL(loadFinished(bool)), this, SLOT(updateElements()));
m_slice->preview();
}
void WebSlice::preview(const QString &selector)
{
ui.geometryEdit->setText(sliceGeometryToString(selector));
m_slice->preview(selector);
}
void WebSlice::loadUrl()
{
loadSlice(QUrl(ui.urlEdit->text()));
connect(m_slice, SIGNAL(loadFinished(bool)), SLOT(updateElements()));
}
void WebSlice::loadSlice(const QUrl &url, const QString &selector)
{
if (m_slice) {
m_slice->loadSlice(url, selector);
setAssociatedApplicationUrls(KUrl::List(url));
}
}
void WebSlice::configAccepted()
{
if (m_url.toString() != ui.urlEdit->text() ||
m_element != ui.elementCombo->currentText() ||
ui.geometryEdit->text() != sliceGeometryToString()) {
m_url = QUrl(ui.urlEdit->text());
m_element = ui.elementCombo->currentText();
QString geo = ui.geometryEdit->text();
QStringList gel = geo.split(',');
qreal x, y, w, h;
bool ok = true;
if (gel.length() == 4) {
x = (qreal)(gel[0].toDouble(&ok));
y = (qreal)(gel[1].toDouble(&ok));
w = (qreal)(gel[2].toDouble(&ok));
h = (qreal)(gel[3].toDouble(&ok));
if (!ok) {
kWarning() << "a conversion error occurred." << gel;
} else {
m_sliceGeometry = QRectF(x, y, w, h);
config().writeEntry("sliceGeometry", m_sliceGeometry);
}
} else {
if (m_element.isEmpty()) {
kWarning() << "format error, use x,y,w,h" << gel << gel.length();
}
}
KConfigGroup cg = config();
cg.writeEntry("url", m_url.toString());
cg.writeEntry("element", m_element);
if (!m_element.isEmpty()) {
m_sliceGeometry = QRectF();
}
emit configNeedsSaving();
configChanged();
}
}
QString WebSlice::sliceGeometryToString(const QString &selector)
{
QString s = QString("%1,%2,%3,%4").arg(m_slice->sliceGeometry(selector).x()).arg(m_slice->sliceGeometry(selector).y()).arg(m_slice->sliceGeometry(selector).width()).arg(m_slice->sliceGeometry(selector).height());
return s;
}
void WebSlice::loadFinished(bool ok)
{
setBusy(false);
if (!ok) {
return;
}
}
void WebSlice::updateColors()
{
m_slice->setPreviewMaskColor(
Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
}
void WebSlice::handleGeometryEdit()
{
if (ui.elementCombo->currentText().isEmpty()) {
ui.geometryEdit->setEnabled(true);
} else {
ui.geometryEdit->setEnabled(false);
}
}
#include "moc_webslice.cpp"