From 39aff7ccefc90164390a97164419c0610ee0f360 Mon Sep 17 00:00:00 2001 From: Andrea Diamantini Date: Tue, 5 Jun 2012 09:30:27 +0200 Subject: kwebapp improvements - added password widget - improved contextual menus - added rekonq statusbar messages There are a lot of changes here, but they are quite safe as the code is somewhat duplicated by the original classes in rekonq I know the situation is suboptimal, but we need to wait for next development period to properly fix it --- kwebapp/CMakeLists.txt | 13 ++- kwebapp/kwebmain.cpp | 71 ++++++++----- kwebapp/rekonqview.cpp | 270 ++++++++++++++++++++++++++++++++++++++++++++++ kwebapp/rekonqview.h | 83 +++++++++++++++ kwebapp/walletbar.cpp | 105 ++++++++++++++++++ kwebapp/walletbar.h | 63 +++++++++++ kwebapp/webpage.cpp | 61 ++++++----- kwebapp/webpage.h | 46 ++++---- kwebapp/websnap.cpp | 166 +++++++++++++++++++++++++++++ kwebapp/websnap.h | 121 +++++++++++++++++++++ kwebapp/webview.cpp | 282 ++++++++++++++++++++++++++++++++++++++++--------- kwebapp/webview.h | 65 ++++++++---- 12 files changed, 1191 insertions(+), 155 deletions(-) create mode 100644 kwebapp/rekonqview.cpp create mode 100644 kwebapp/rekonqview.h create mode 100644 kwebapp/walletbar.cpp create mode 100644 kwebapp/walletbar.h create mode 100644 kwebapp/websnap.cpp create mode 100644 kwebapp/websnap.h diff --git a/kwebapp/CMakeLists.txt b/kwebapp/CMakeLists.txt index dda4616d..990897eb 100644 --- a/kwebapp/CMakeLists.txt +++ b/kwebapp/CMakeLists.txt @@ -1,14 +1,17 @@ set( kwebapp_SRCS + rekonqview.cpp + walletbar.cpp webview.cpp webpage.cpp + websnap.cpp kwebmain.cpp ) -include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${QT4_INCLUDES} - ${KDE4_INCLUDES} - +include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${QT4_INCLUDES} + ${KDE4_INCLUDES} ) diff --git a/kwebapp/kwebmain.cpp b/kwebapp/kwebmain.cpp index 639d1533..a0848946 100644 --- a/kwebapp/kwebmain.cpp +++ b/kwebapp/kwebmain.cpp @@ -1,44 +1,54 @@ -/* - * This file is part of the KDE project. - * Copyright (C) 2011 by Andrea Diamantini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ -#include "webview.h" +// Local Includes +#include "rekonqview.h" -#include - -#include -#include +// KDE Includes +#include +#include +#include +#include +#include +// Qt Includes +#include #include -#include + static const char description[] = I18N_NOOP("Web Application Viewer"); -static const char version[] = "0.1"; +static const char version[] = "0.2"; + int main(int argc, char **argv) { KAboutData about("kwebapp", 0, ki18n("kwebapp"), version, ki18n(description), - KAboutData::License_GPL, ki18n("(C) 2011 Andrea Diamantini"), KLocalizedString(), 0, "adjam7@gmail.com"); + KAboutData::License_GPL, ki18n("(C) 2011-2012 Andrea Diamantini"), KLocalizedString(), 0, "adjam7@gmail.com"); about.addAuthor(ki18n("Andrea Diamantini"), KLocalizedString(), "adjam7@gmail.com"); KCmdLineArgs::init(argc, argv, &about); @@ -48,6 +58,8 @@ int main(int argc, char **argv) KApplication app; + QWebSettings::setIconDatabasePath(KStandardDirs::locateLocal("cache", "kwebapp.favicons/")); + qDebug() << "ICON PATH: " << KStandardDirs::locateLocal("cache", "kwebapp.favicons/"); KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); if (args->count() != 1) { @@ -55,7 +67,8 @@ int main(int argc, char **argv) return 0; } - WebView *widg = new WebView(QUrl::fromUserInput(args->arg(0))); + RekonqView *widg = new RekonqView(); + widg->loadUrl(KUrl(QUrl::fromUserInput(args->arg(0)))); widg->show(); args->clear(); diff --git a/kwebapp/rekonqview.cpp b/kwebapp/rekonqview.cpp new file mode 100644 index 00000000..b737bc11 --- /dev/null +++ b/kwebapp/rekonqview.cpp @@ -0,0 +1,270 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + + +// Self Includes +#include "rekonqview.h" +#include "rekonqview.moc" + +// Local Includes +#include "walletbar.h" +#include "webpage.h" + +// KDE Includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt Includes +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +RekonqView::RekonqView(QWidget *parent) + : QWidget(parent) + , m_webView(0) + , m_popup(new QLabel(this)) + , m_hidePopupTimer(new QTimer(this)) + +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + + l->addWidget(view()); + view()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + // fix focus handling + setFocusProxy(view()); + + KWebWallet *wallet = page()->wallet(); + + if (wallet) + { + connect(wallet, SIGNAL(saveFormDataRequested(QString, QUrl)), + this, SLOT(createWalletBar(QString, QUrl))); + } + + connect(page(), SIGNAL(linkHovered(QString, QString, QString)), this, SLOT(notifyMessage(QString))); + + // setting popup notification + m_popup->setAutoFillBackground(true); + m_popup->setMargin(4); + m_popup->raise(); + m_popup->hide(); + + connect(m_hidePopupTimer, SIGNAL(timeout()), m_popup, SLOT(hide())); + + // signal && slots + connect(view(), SIGNAL(iconChanged()), this, SLOT(setIcon())); + connect(view(), SIGNAL(titleChanged(QString)), this, SLOT(setTitle(QString))); + +} + + +RekonqView::~RekonqView() +{ + m_walletBar.clear(); + + delete m_webView; +} + + +WebView *RekonqView::view() +{ + if (!m_webView) + { + m_webView = new WebView(this); + } + return m_webView; +} + + +WebPage *RekonqView::page() +{ + return view()->page(); +} + + +KUrl RekonqView::url() +{ +// if (page() && page()->isOnRekonqPage()) +// { +// return page()->loadingUrl(); +// } + + return view()->url(); +} + + +void RekonqView::setTitle(const QString &t) +{ + setWindowTitle(t); +} + + +void RekonqView::setIcon() +{ + setWindowIcon(view()->icon()); +} + + +void RekonqView::createWalletBar(const QString &key, const QUrl &url) +{ + // check if the url is in the wallet blacklist + QString urlString = url.toString(); + + KSharedConfig::Ptr config = KSharedConfig::openConfig("rekonqrc", KConfig::SimpleConfig, "config"); + KConfigGroup group1(config, "misc"); + QStringList blackList = group1.readEntry("walletBlackList", QStringList()); + if (blackList.contains(urlString)) + return; + + KWebWallet *wallet = page()->wallet(); + + KConfigGroup group2(config, "Privacy"); + bool passwordSavingEnabled = group2.readEntry("passwordSavingEnabled", false); + + if (!passwordSavingEnabled) + { + wallet->rejectSaveFormDataRequest(key); + return; + } + + if (m_walletBar.isNull()) + { + m_walletBar = new WalletBar(this); + m_walletBar.data()->onSaveFormData(key, url); + qobject_cast(layout())->insertWidget(0, m_walletBar.data()); + m_walletBar.data()->animatedShow(); + } + else + { + disconnect(wallet); + qobject_cast(layout())->insertWidget(0, m_walletBar.data()); + m_walletBar.data()->animatedShow(); + } + + connect(m_walletBar.data(), SIGNAL(saveFormDataAccepted(QString)), + wallet, SLOT(acceptSaveFormDataRequest(QString)), Qt::UniqueConnection); + connect(m_walletBar.data(), SIGNAL(saveFormDataRejected(QString)), + wallet, SLOT(rejectSaveFormDataRequest(QString)), Qt::UniqueConnection); +} + + +bool RekonqView::hasRSSInfo() +{ + QWebElementCollection col = page()->mainFrame()->findAllElements("link[type=\"application/rss+xml\"]"); + col.append(page()->mainFrame()->findAllElements("link[type=\"application/atom+xml\"]")); + if (col.count() != 0) + return true; + + return false; +} + + +void RekonqView::loadUrl(const KUrl& url) +{ + if (url.isEmpty()) + return; + + if (!url.isValid()) + { + KMessageBox::error(0, i18n("Malformed URL:\n%1", url.url(KUrl::RemoveTrailingSlash))); + return; + } + + view()->load(url); +} + + +void RekonqView::notifyMessage(const QString &msg) +{ + // deleting popus if empty msgs + if (msg.isEmpty()) + { + m_hidePopupTimer->start(250); + return; + } + + m_hidePopupTimer->stop(); + m_hidePopupTimer->start(500); + + QString msgToShow = Qt::escape(msg); + + const int margin = 4; + const int halfWidth = width() / 2; + + // Set Popup size + QFontMetrics fm = m_popup->fontMetrics(); + QSize labelSize(fm.width(msgToShow) + 2 * margin, fm.height() + 2 * margin); + + if (labelSize.width() > halfWidth) + labelSize.setWidth(halfWidth); + + m_popup->setFixedSize(labelSize); + m_popup->setText(fm.elidedText(msgToShow, Qt::ElideMiddle, labelSize.width() - 2 * margin)); + + // NOTE: while currentFrame should NEVER be null + // we are checking here its existence cause of bug:264187 + if (!page() || !page()->currentFrame()) + return; + + const bool horizontalScrollbarIsVisible = page()->currentFrame()->scrollBarMaximum(Qt::Horizontal); + const bool verticalScrollbarIsVisible = page()->currentFrame()->scrollBarMaximum(Qt::Vertical); + const bool actionBarsVisible = false; //FIXME m_findBar->isVisible() || m_zoomBar->isVisible(); + + const int scrollbarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent); + const int hScrollbarSize = horizontalScrollbarIsVisible ? scrollbarExtent : 0; + const int vScrollbarSize = verticalScrollbarIsVisible ? scrollbarExtent : 0; + + const QPoint mousePos = mapFromGlobal(QCursor::pos()); + const QPoint bottomPoint = geometry().bottomLeft(); + + int y = bottomPoint.y() + 1 - 2 * m_popup->height() - hScrollbarSize; // +1 because bottom() returns top() + height() - 1, see QRect doku + int x = QRect(QPoint(0, y), labelSize).contains(mousePos) || actionBarsVisible + ? width() - labelSize.width() - vScrollbarSize + : 0; + + m_popup->move(x, y); + m_popup->show(); +} diff --git a/kwebapp/rekonqview.h b/kwebapp/rekonqview.h new file mode 100644 index 00000000..770c468a --- /dev/null +++ b/kwebapp/rekonqview.h @@ -0,0 +1,83 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + + +#ifndef REKONQ_VIEW_H +#define REKONQ_VIEW_H + + +// Local Includes +#include "webview.h" + +// Qt Includes +#include + +// Forward Declarations +class WalletBar; + +class WebPage; + +class QLabel; +class QTimer; + + +class RekonqView : public QWidget +{ + Q_OBJECT + +public: + explicit RekonqView(QWidget *parent = 0); + ~RekonqView(); + + WebView *view(); + WebPage *page(); + + KUrl url(); + + bool hasRSSInfo(); + +public Q_SLOTS: + void loadUrl(const KUrl& url); + +private Q_SLOTS: + void setTitle(const QString &); + void setIcon(); + + void createWalletBar(const QString &, const QUrl &); + void notifyMessage(const QString &msg); + +Q_SIGNALS: + void loadProgressing(); + +private: + WebView *m_webView; + + QWeakPointer m_walletBar; + + QLabel *m_popup; + QTimer *m_hidePopupTimer; +}; + +#endif diff --git a/kwebapp/walletbar.cpp b/kwebapp/walletbar.cpp new file mode 100644 index 00000000..36a97578 --- /dev/null +++ b/kwebapp/walletbar.cpp @@ -0,0 +1,105 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + + +// Self Includes +#include "walletbar.h" +#include "walletbar.moc" + +// KDE Includes +#include +#include +#include +#include + +// Qt Includes +#include + + +WalletBar::WalletBar(QWidget *parent) + : KMessageWidget(parent) +{ + setMessageType(KMessageWidget::Warning); + + QSize sz = size(); + sz.setWidth(qobject_cast(parent)->size().width()); + resize(sz); + + setCloseButtonVisible(false); + + QAction *rememberAction = new QAction(KIcon("document-save"), i18n("Remember"), this); + connect(rememberAction, SIGNAL(triggered(bool)), this, SLOT(rememberData())); + addAction(rememberAction); + + QAction *neverHereAction = new QAction(KIcon("process-stop"), i18n("Never for This Site"), this); + connect(neverHereAction, SIGNAL(triggered(bool)), this, SLOT(neverRememberData())); + addAction(neverHereAction); + + QAction *notNowAction = new QAction(KIcon("dialog-cancel"), i18n("Not Now"), this); + connect(notNowAction, SIGNAL(triggered(bool)), this, SLOT(notNowRememberData())); + addAction(notNowAction); +} + + +void WalletBar::rememberData() +{ + emit saveFormDataAccepted(m_key); + + animatedHide(); + deleteLater(); +} + + +void WalletBar::neverRememberData() +{ + // add url to the blacklist + KSharedConfig::Ptr config = KSharedConfig::openConfig("rekonqrc", KConfig::SimpleConfig, "config"); + KConfigGroup group(config, "misc"); + QStringList list = group.readEntry("walletBlackList", QStringList()); + list << m_url.toString(); + group.writeEntry("walletBlackList", list); + config->sync(); + + notNowRememberData(); +} + + +void WalletBar::notNowRememberData() +{ + emit saveFormDataRejected(m_key); + + animatedHide(); + deleteLater(); +} + + + +void WalletBar::onSaveFormData(const QString &key, const QUrl &url) +{ + setText(i18n("Do you want rekonq to remember the password on %1?", url.host())); + + m_key = key; + m_url = url; +} diff --git a/kwebapp/walletbar.h b/kwebapp/walletbar.h new file mode 100644 index 00000000..094dec0e --- /dev/null +++ b/kwebapp/walletbar.h @@ -0,0 +1,63 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + + +#ifndef WALLET_BAR_H +#define WALLET_BAR_H + + +// KDE Includes +#include + +// Qt Includes +#include +#include + + +class WalletBar : public KMessageWidget +{ + Q_OBJECT + +public: + WalletBar(QWidget *parent); + +private Q_SLOTS: + void rememberData(); + void neverRememberData(); + void notNowRememberData(); + +public Q_SLOTS: + void onSaveFormData(const QString &, const QUrl &); + +Q_SIGNALS: + void saveFormDataAccepted(const QString &); + void saveFormDataRejected(const QString &); + +private: + QString m_key; + QUrl m_url; +}; + +#endif // WALLET_BAR_H diff --git a/kwebapp/webpage.cpp b/kwebapp/webpage.cpp index f1f3c38d..cdca10bd 100644 --- a/kwebapp/webpage.cpp +++ b/kwebapp/webpage.cpp @@ -1,23 +1,27 @@ -/* - * This file is part of the KDE project. - * Copyright (C) 2011 by Andrea Diamantini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ // Self Includes @@ -33,21 +37,22 @@ WebPage::WebPage(QObject *parent) : KWebPage(parent) - , _selfLoading(false) + , _selfLoading(true) { connect(this, SIGNAL(loadFinished(bool)), this, SLOT(disableSelfLoading())); + + connect(this, SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(downloadResponse(QNetworkReply*))); + connect(this, SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequest(QNetworkRequest))); } bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) { - if (_selfLoading) - { - return KWebPage::acceptNavigationRequest(frame, request, type); - } - - (void)new KRun(request.url(), view(), 0); - return false; + return KWebPage::acceptNavigationRequest(frame, request, type); + + // FIXME +// (void)new KRun(request.url(), view(), 0); +// return false; } diff --git a/kwebapp/webpage.h b/kwebapp/webpage.h index fd8c88f1..33d06a31 100644 --- a/kwebapp/webpage.h +++ b/kwebapp/webpage.h @@ -1,23 +1,27 @@ -/* - * This file is part of the KDE project. - * Copyright (C) 2011 by Andrea Diamantini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ #ifndef _WEB_PAGE_H @@ -45,7 +49,7 @@ protected: private: bool _selfLoading; - + }; #endif // _WEB_PAGE_H diff --git a/kwebapp/websnap.cpp b/kwebapp/websnap.cpp new file mode 100644 index 00000000..830d37e1 --- /dev/null +++ b/kwebapp/websnap.cpp @@ -0,0 +1,166 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 Nokia Corporation +* Copyright (C) 2009-2012 by Andrea Diamantini +* Copyright (C) 2010 by Matthieu Gicquel +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + + +// Self Includes +#include "websnap.h" +#include "websnap.moc" + +// KDE Includes +#include + +// Qt Includes +#include +#include + +#include + +#include +#include + +#include +#include + + +WebSnap::WebSnap(const KUrl& url, QObject *parent) + : QObject(parent) + , m_url(url) +{ + // this to not register websnap history + m_page.settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); + + // this to not let this page open other windows + m_page.settings()->setAttribute(QWebSettings::PluginsEnabled, false); + m_page.settings()->setAttribute(QWebSettings::JavascriptEnabled, false); + + connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(saveResult(bool))); + + QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection); +} + + +WebSnap::~WebSnap() +{ + m_page.action(QWebPage::Stop)->trigger(); + m_page.deleteLater(); +} + + +void WebSnap::load() +{ + m_page.mainFrame()->load(m_url); +} + + + +QPixmap WebSnap::render(const QWebPage &page, int w, int h) +{ + // create the page image + QPixmap pageImage = QPixmap(w, h); + pageImage.fill(Qt::transparent); + + // render it + QPainter p(&pageImage); + page.mainFrame()->render(&p, QWebFrame::ContentsLayer); + p.end(); + + return pageImage; +} + + +// NOTE +// to render page preview in a safe way, you CANNOT work with scrollbars! +// In fact, disabling temporarily them DOES NOT work without reloading a page +// that is something we CANNOT do. +QPixmap WebSnap::renderPagePreview(const QWebPage &page, int w, int h) +{ + // store actual viewportsize + QSize oldSize = page.viewportSize(); + + // prepare page + // NOTE: I saw some sites with strange CMS and with absurd content size width (eg: 8584553) + // This usually leads setViewportSize to crash :( + // So, ensure renderWidth is no more than 2000. + int renderWidth = page.mainFrame()->contentsSize().width(); + if (renderWidth > 2000) + renderWidth = 2000; + int renderHeight = renderWidth * ((0.0 + h) / w); + + page.setViewportSize(QSize(renderWidth, renderHeight)); + + // consider scrollbars and render the page + bool verticalScrollBarActive = !page.mainFrame()->scrollBarGeometry(Qt::Vertical).isEmpty(); + if (verticalScrollBarActive) + renderWidth -= 15; + + bool horizontalScrollBarActive = !page.mainFrame()->scrollBarGeometry(Qt::Horizontal).isEmpty(); + if (horizontalScrollBarActive) + renderHeight -= 15; + + QPixmap pageImage = WebSnap::render(page, renderWidth, renderHeight); + + // resize image + pageImage = pageImage.scaled(w, h, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + + // restore page state + page.setViewportSize(oldSize); + + return pageImage; +} + + +QString WebSnap::imagePathFromUrl(const KUrl &url) +{ + QUrl temp = QUrl(url.url()); + QByteArray name = temp.toEncoded(QUrl::RemoveScheme | QUrl::RemoveUserInfo | QUrl::StripTrailingSlash); + + QByteArray hashedName = QCryptographicHash::hash(name, QCryptographicHash::Md5).toHex(); + + return KStandardDirs::locateLocal("cache", QString("thumbs/") + hashedName + ".png", true); +} + + +void WebSnap::saveResult(bool ok) +{ + if (ok) + { + QPixmap image = renderPagePreview(m_page, defaultWidth, defaultHeight); + QString path = imagePathFromUrl(m_url); + QFile::remove(path); + image.save(path); + } + + emit snapDone(ok); + + this->deleteLater(); +} + + +bool WebSnap::existsImage(const KUrl &u) +{ + return QFile::exists(imagePathFromUrl(u)); +} diff --git a/kwebapp/websnap.h b/kwebapp/websnap.h new file mode 100644 index 00000000..0584ce00 --- /dev/null +++ b/kwebapp/websnap.h @@ -0,0 +1,121 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 Nokia Corporation +* Copyright (C) 2009-2012 by Andrea Diamantini +* Copyright (C) 2010 by Matthieu Gicquel +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + + +#ifndef WEB_SNAP_H +#define WEB_SNAP_H + + +// KDE Includes +#include + +// Qt Includes +#include +#include + +// Forward Declarations +class QPixmap; + +/** + * This class is used in many classes of rekonq to produce an image + * based on the site corresponding to the url passed as argument. + * It also cached the images to not retrieve them every time :) + * + * Heavily based on Graphics-Dojo WebSnap example (thanks!) + * + * We use this in the following rekonq classes: + * + * - TabBar class: to show a tab preview (given a page, you show AND save an image) + * - PreviewSelector class: to save new favorite selection (given a page, you show AND save an image) + * + * - NewTabPage class: to show the favorites page "preview" (given an url, you show AND save an image) + * + */ + +class WebSnap : public QObject +{ + Q_OBJECT + +public: + /** + * Creates a WebSnap object. It will load the url in one WebPage + * and snap an image from it. + * + * @param url the url to load + * @param parent the object parent + */ + explicit WebSnap(const KUrl &url, QObject *parent = 0); + + ~WebSnap(); + + /** + * Snaps a pixmap of size w * h from a page + * + * @param page the page to snap + * @param w the image width + * @param h the image height + * + * @return the pixmap snapped from the page + */ + static QPixmap renderPagePreview(const QWebPage &page, int w = defaultWidth, int h = defaultHeight); + + /** + * Guess the local path where the image for the url provided + * should be + * + * @param url the url to guess snap path + * + * @return the local path of the url snap + */ + static QString imagePathFromUrl(const KUrl &url); + + /** + * Determines if a snap exists for that url + * + */ + static bool existsImage(const KUrl &url); + + +private Q_SLOTS: + void saveResult(bool ok = true); + void load(); + +Q_SIGNALS: + void snapDone(bool ok); + +private: + // Constants + static const int defaultWidth = 200; + static const int defaultHeight = 150; + QWebPage m_page; + KUrl m_url; + + //render a preview: common part of renderPagePreview() and renderTabPreview() + static QPixmap render(const QWebPage &page, int w, int h); +}; + +#endif // WEB_SNAP_H diff --git a/kwebapp/webview.cpp b/kwebapp/webview.cpp index 55889a8a..782c98d9 100644 --- a/kwebapp/webview.cpp +++ b/kwebapp/webview.cpp @@ -1,21 +1,27 @@ -/*************************************************************************** - * Copyright (C) 2011-2012 by Andrea Diamantini * - * * - * 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 . * - ***************************************************************************/ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ // Self Includes @@ -36,6 +42,8 @@ #include #include #include +#include +#include // Qt Includes #include @@ -45,40 +53,31 @@ #include #include +// Defines +#define QL1S(x) QLatin1String(x) -WebView::WebView(const QUrl &url, QWidget *parent) + +WebView::WebView(QWidget *parent) : KWebView(parent) + , m_page(0) { page()->setForwardUnsupportedContent(true); - connect(page(), SIGNAL(unsupportedContent(QNetworkReply*)), page(), SLOT(downloadResponse(QNetworkReply*))); - connect(page(), SIGNAL(downloadRequested(QNetworkRequest)), page(), SLOT(downloadRequest(QNetworkRequest))); connect(this, SIGNAL(linkShiftClicked(KUrl)), page(), SLOT(downloadUrl(KUrl))); - QWebSettings::setIconDatabasePath(KStandardDirs::locateLocal("cache", "kwebapp.favicons")); - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(titleChanged(QString)), this, SLOT(setTitle(QString))); - connect(this, SIGNAL(iconChanged()), this, SLOT(setIcon())); connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(menuRequested(QPoint))); - - const QString iconPath = KStandardDirs::locateLocal("cache" , "favicons/" , true) + url.host() + "_WEBAPPICON.png"; - setWindowIcon(QIcon(iconPath)); - - // last... - load(url); } -void WebView::setTitle(const QString &t) +WebPage *WebView::page() { - setWindowTitle(t); -} - - -void WebView::setIcon() -{ - setWindowIcon(icon()); + if (!m_page) + { + m_page = new WebPage(this); + setPage(m_page); + } + return m_page; } @@ -89,30 +88,203 @@ void WebView::menuRequested(const QPoint &pos) KMenu menu(this); QAction *a; - // is a link? - if (!result.linkUrl().isEmpty()) + KAction *sendByMailAction = new KAction(this); + sendByMailAction->setIcon(KIcon("mail-send")); + connect(sendByMailAction, SIGNAL(triggered(bool)), this, SLOT(sendByMail())); + + KAction *openInDefaultBrowserAction = new KAction(KIcon("window-new"), i18n("Open in default browser"), this); + connect(openInDefaultBrowserAction, SIGNAL(triggered(bool)), this, SLOT(openLinkInDefaultBrowser())); + + // Choose right context + int resultHit = 0; + if (result.linkUrl().isEmpty()) + resultHit = WebView::EmptySelection; + else + resultHit = WebView::LinkSelection; + + if (!result.pixmap().isNull()) + resultHit |= WebView::ImageSelection; + + if (result.isContentSelected()) + resultHit = WebView::TextSelection; + + // ----------------------------------------------------------- + // Ok, let's start filling up the menu... + + // is content editable? Add PASTE + if (result.isContentEditable()) { - a = new KAction(KIcon("window-new"), i18n("Open in default browser"), this); - a->setData(result.linkUrl()); - connect(a, SIGNAL(triggered(bool)), this, SLOT(openLinkInDefaultBrowser())); - menu.addAction(a); + menu.addAction(pageAction(KWebPage::Paste)); + menu.addSeparator(); + } + + + // EMPTY PAGE ACTIONS ---------------------------------------- + if (resultHit == WebView::EmptySelection) + { + // send by mail: page url + sendByMailAction->setData(page()->currentFrame()->url()); + sendByMailAction->setText(i18n("Share page url")); + + // navigation + QWebHistory *history = page()->history(); + if (history->canGoBack()) + { + menu.addAction(pageAction(KWebPage::Back)); + } + + if (history->canGoForward()) + { + menu.addAction(pageAction(KWebPage::Forward)); + } + + menu.addAction(pageAction(KWebPage::Reload)); + + menu.addSeparator(); + + // Page Actions + menu.addAction(pageAction(KWebPage::SelectAll)); menu.addAction(pageAction(KWebPage::DownloadLinkToDisk)); + + } + + // LINK ACTIONS ------------------------------------------ + if (resultHit & WebView::LinkSelection) + { + // send by mail: link url + sendByMailAction->setData(result.linkUrl()); + sendByMailAction->setText(i18n("Share link")); + + openInDefaultBrowserAction->setData(result.linkUrl()); + menu.addAction(openInDefaultBrowserAction); + + menu.addSeparator(); + + a = pageAction(KWebPage::DownloadLinkToDisk); + menu.addAction(a); menu.addAction(pageAction(KWebPage::CopyLinkToClipboard)); + } + + // IMAGE ACTION ----------------------------------------- + if (resultHit & WebView::ImageSelection) + { + // send by mail: image url + sendByMailAction->setData(result.imageUrl()); + sendByMailAction->setText(i18n("Share image link")); + menu.addSeparator(); + + a = new KAction(KIcon("view-preview"), i18n("&View Image"), this); + a->setData(result.imageUrl()); + connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), + this, SLOT(viewImage(Qt::MouseButtons, Qt::KeyboardModifiers))); + menu.addAction(a); + + menu.addAction(pageAction(KWebPage::DownloadImageToDisk)); + + a = new KAction(KIcon("view-media-visualization"), i18n("&Copy Image Location"), this); + a->setData(result.imageUrl()); + connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(slotCopyImageLocation())); + menu.addAction(a); + } - if (history()->canGoBack()) + // ACTIONS FOR TEXT SELECTION ---------------------------- + if (resultHit & WebView::TextSelection) { - menu.addAction(pageAction(KWebPage::Back)); + // send by mail: text + sendByMailAction->setData(selectedText()); + sendByMailAction->setText(i18n("Share selected text")); + + if (result.isContentEditable()) + { + // actions for text selected in field + menu.addAction(pageAction(KWebPage::Cut)); + } + + a = pageAction(KWebPage::Copy); + if (!result.linkUrl().isEmpty()) + a->setText(i18n("Copy Text")); //for link + else + a->setText(i18n("Copy")); + menu.addAction(a); + + if (selectedText().contains('.') && selectedText().indexOf('.') < selectedText().length() + && !selectedText().trimmed().contains(" ") + ) + { + QString text = selectedText(); + text = text.trimmed(); + KUrl urlLikeText(text); + if (urlLikeText.isValid()) + { + QString truncatedUrl = text; + const int maxTextSize = 18; + if (truncatedUrl.length() > maxTextSize) + { + const int truncateSize = 15; + truncatedUrl.truncate(truncateSize); + truncatedUrl += QL1S("..."); + } + + openInDefaultBrowserAction->setData(QUrl(urlLikeText)); + menu.addAction(openInDefaultBrowserAction); + + menu.addSeparator(); + } + } + +// // Default SearchEngine +// KService::Ptr defaultEngine = SearchEngine::defaultEngine(); +// if (defaultEngine) // check if a default engine is set +// { +// a = new KAction(i18nc("Search selected text with the default search engine", "Search with %1", defaultEngine->name()), this); +// a->setIcon(rApp->iconManager()->iconForUrl(SearchEngine::buildQuery(defaultEngine, ""))); +// a->setData(defaultEngine->entryPath()); +// connect(a, SIGNAL(triggered(bool)), this, SLOT(search())); +// menu.addAction(a); +// } + + // All favourite ones + KActionMenu *searchMenu = new KActionMenu(KIcon("edit-find"), i18nc("@title:menu", "Search"), this); + +// Q_FOREACH(const KService::Ptr & engine, SearchEngine::favorites()) +// { +// a = new KAction(i18nc("@item:inmenu Search, %1 = search engine", "With %1", engine->name()), this); +// a->setIcon(rApp->iconManager()->iconForUrl(SearchEngine::buildQuery(engine, ""))); +// a->setData(engine->entryPath()); +// connect(a, SIGNAL(triggered(bool)), this, SLOT(search())); +// searchMenu->addAction(a); +// } + +// a = new KAction(KIcon("edit-find"), i18n("On Current Page"), this); +// connect(a, SIGNAL(triggered()), rApp->mainWindow(), SLOT(findSelectedText())); +// searchMenu->addAction(a); + + if (!searchMenu->menu()->isEmpty()) + { + menu.addAction(searchMenu); + } } - if (history()->canGoBack()) + // DEFAULT ACTIONs (on the bottom) ----------------------- + menu.addSeparator(); + if (resultHit & WebView::LinkSelection) { - menu.addAction(pageAction(KWebPage::Forward)); + a = new KAction(KIcon("bookmark-new"), i18n("&Bookmark link"), this); + a->setData(result.linkUrl()); + connect(a, SIGNAL(triggered(bool)), this, SLOT(bookmarkLink())); + menu.addAction(a); } + else + { + a = new KAction(KIcon("bookmark-new"), i18n("&Add Bookmark"), this); + connect(a, SIGNAL(triggered(bool)), this, SLOT(bookmarkCurrentPage())); + menu.addAction(a); + } + menu.addAction(sendByMailAction); - menu.addAction(pageAction(KWebPage::Reload)); menu.exec(mapToGlobal(pos)); } @@ -125,3 +297,13 @@ void WebView::openLinkInDefaultBrowser() (void)new KRun(u, this, 0); } + + +void WebView::sendByMail() +{ + KAction *a = qobject_cast(sender()); + QString url = a->data().toString(); + + KToolInvocation::invokeMailer("", "", "", "", url); +} + diff --git a/kwebapp/webview.h b/kwebapp/webview.h index 1d5aba66..5cf6fcfe 100644 --- a/kwebapp/webview.h +++ b/kwebapp/webview.h @@ -1,21 +1,28 @@ -/*************************************************************************** - * Copyright (C) 2011-2012 by Andrea Diamantini * - * * - * 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 . * - ***************************************************************************/ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini +* +* +* 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) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* 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, see . +* +* ============================================================ */ + #ifndef WEB_VIEW_H #define WEB_VIEW_H @@ -34,15 +41,29 @@ class WebView : public KWebView { Q_OBJECT - + public: - explicit WebView(const QUrl &url, QWidget *parent = 0); + + enum ContextType + { + EmptySelection = 0x00000000, + LinkSelection = 0x00000001, + ImageSelection = 0x00000010, + TextSelection = 0x00000100 + }; + + explicit WebView(QWidget *parent = 0); + + WebPage *page(); private Q_SLOTS: - void setTitle(const QString &); - void setIcon(); void menuRequested(const QPoint &); void openLinkInDefaultBrowser(); + + void sendByMail(); + +private: + WebPage *m_page; }; #endif // WEB_VIEW_H -- cgit v1.2.1