summaryrefslogtreecommitdiff
path: root/src/webtab/webview.cpp
diff options
context:
space:
mode:
authorAndrea Diamantini <adjam7@gmail.com>2012-07-31 23:58:06 +0200
committerAndrea Diamantini <adjam7@gmail.com>2012-12-10 02:48:04 +0100
commitb7b5f23f928ef93abff83b6eadede922c34b355b (patch)
tree53fa667d12922aa3c74f47a61c9041b17e5fdd02 /src/webtab/webview.cpp
parentDownload Manager (diff)
downloadrekonq-b7b5f23f928ef93abff83b6eadede922c34b355b.tar.xz
Copy webtab related files from rekonq repo
NOTE: This change does NOT affect CMakeLists.txt, so that compilation will continue to work as the previous commit. I'm just trying to track changes from original rekonq files...
Diffstat (limited to 'src/webtab/webview.cpp')
-rw-r--r--src/webtab/webview.cpp1273
1 files changed, 1273 insertions, 0 deletions
diff --git a/src/webtab/webview.cpp b/src/webtab/webview.cpp
new file mode 100644
index 00000000..00112d61
--- /dev/null
+++ b/src/webtab/webview.cpp
@@ -0,0 +1,1273 @@
+/* ============================================================
+*
+* This file is a part of the rekonq project
+*
+* Copyright (C) 2008-2012 by Andrea Diamantini <adjam7 at gmail dot com>
+* Copyright (C) 2009-2011 by Lionel Chauvin <megabigbug@yahoo.fr>
+*
+*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* ============================================================ */
+
+
+// Self Includes
+#include "webview.h"
+#include "webview.moc"
+
+// Auto Includes
+#include "rekonq.h"
+
+// Local Includes
+#include "application.h"
+#include "adblockmanager.h"
+#include "bookmarkmanager.h"
+#include "iconmanager.h"
+#include "mainview.h"
+#include "mainwindow.h"
+#include "searchengine.h"
+#include "urlbar.h"
+#include "webpage.h"
+#include "webtab.h"
+
+// KDE Includes
+#include <KAction>
+#include <KActionMenu>
+#include <KLocalizedString>
+#include <KMenu>
+#include <KStandardAction>
+#include <KStandardDirs>
+#include <KToolInvocation>
+
+// Qt Includes
+#include <QFile>
+#include <QTimer>
+
+#include <QClipboard>
+#include <QContextMenuEvent>
+#include <QLabel>
+
+#include <QWebFrame>
+#include <QWebHistory>
+#include <QNetworkRequest>
+
+
+WebView::WebView(QWidget* parent)
+ : KWebView(parent, false)
+ , m_page(0)
+ , m_autoScrollTimer(new QTimer(this))
+ , m_verticalAutoScrollSpeed(0)
+ , m_horizontalAutoScrollSpeed(0)
+ , m_isViewAutoScrolling(false)
+ , m_autoScrollIndicator(QPixmap(KStandardDirs::locate("appdata" , "pics/autoscroll.png")))
+ , m_smoothScrollTimer(new QTimer(this))
+ , m_dy(0)
+ , m_smoothScrollSteps(0)
+ , m_isViewSmoothScrolling(false)
+ , m_accessKeysPressed(false)
+ , m_accessKeysActive(false)
+{
+ // loadUrl signal
+ connect(this, SIGNAL(loadUrl(KUrl, Rekonq::OpenType)), rApp, SLOT(loadUrl(KUrl, Rekonq::OpenType)));
+
+ // Auto scroll timer
+ connect(m_autoScrollTimer, SIGNAL(timeout()), this, SLOT(scrollFrameChanged()));
+ m_autoScrollTimer->setInterval(100);
+
+ // Smooth scroll timer
+ connect(m_smoothScrollTimer, SIGNAL(timeout()), this, SLOT(scrollTick()));
+ m_smoothScrollTimer->setInterval(16);
+
+ connect(this, SIGNAL(iconChanged()), this, SLOT(changeWindowIcon()));
+ connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
+}
+
+
+WebView::~WebView()
+{
+ if (m_isViewSmoothScrolling)
+ stopSmoothScrolling();
+}
+
+
+void WebView::load(const QUrl &url)
+{
+ load(QNetworkRequest(url));
+}
+
+
+void WebView::load(const QNetworkRequest &req, QNetworkAccessManager::Operation op, const QByteArray &body)
+{
+ QNetworkRequest request = req;
+ const QUrl &reqUrl = request.url();
+ if (reqUrl.host() == url().host())
+ {
+ request.setRawHeader(QByteArray("Referer"), url().toEncoded());
+ }
+
+ KWebView::load(request, op, body);
+}
+
+
+void WebView::loadStarted()
+{
+ hideAccessKeys();
+}
+
+
+void WebView::changeWindowIcon()
+{
+ if (ReKonfig::useFavicon())
+ {
+ MainWindow *const mainWindow = rApp->mainWindow();
+ if (url() == mainWindow->currentTab()->url())
+ {
+ const int index = mainWindow->mainView()->currentIndex();
+ mainWindow->changeWindowIcon(index);
+ }
+ }
+}
+
+
+WebPage *WebView::page()
+{
+ if (!m_page)
+ {
+ m_page = new WebPage(this);
+ setPage(m_page);
+ }
+ return m_page;
+}
+
+
+void WebView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QWebHitTestResult result = page()->mainFrame()->hitTestContent(event->pos());
+ MainWindow *mainwindow = rApp->mainWindow();
+
+ KMenu menu(this);
+ QAction *a;
+
+ KAction *inspectAction = new KAction(KIcon("layer-visible-on"), i18n("Inspect Element"), this);
+ connect(inspectAction, SIGNAL(triggered(bool)), this, SLOT(inspect()));
+
+ KAction *sendByMailAction = new KAction(this);
+ sendByMailAction->setIcon(KIcon("mail-send"));
+ connect(sendByMailAction, SIGNAL(triggered(bool)), this, SLOT(sendByMail()));
+
+ // 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())
+ {
+ 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(mainwindow->actionByName("view_redisplay"));
+
+ menu.addSeparator();
+
+ //Frame
+ KActionMenu *frameMenu = new KActionMenu(i18n("Current Frame"), this);
+ frameMenu->addAction(pageAction(KWebPage::OpenFrameInNewWindow));
+
+ a = new KAction(KIcon("document-print-frame"), i18n("Print Frame"), this);
+ connect(a, SIGNAL(triggered()), this, SLOT(printFrame()));
+ frameMenu->addAction(a);
+
+ menu.addAction(frameMenu);
+
+ menu.addSeparator();
+
+ // Page Actions
+ menu.addAction(pageAction(KWebPage::SelectAll));
+
+ menu.addAction(mainwindow->actionByName(KStandardAction::name(KStandardAction::SaveAs)));
+
+ if (!KStandardDirs::findExe("kget").isNull() && ReKonfig::kgetList())
+ {
+ a = new KAction(KIcon("kget"), i18n("List All Links"), this);
+ connect(a, SIGNAL(triggered(bool)), page(), SLOT(downloadAllContentsWithKGet()));
+ menu.addAction(a);
+ }
+
+ menu.addAction(mainwindow->actionByName("page_source"));
+ menu.addAction(inspectAction);
+
+ if (mainwindow->isFullScreen())
+ {
+ menu.addSeparator();
+ menu.addAction(mainwindow->actionByName("fullscreen"));
+ }
+ }
+
+ // LINK ACTIONS -------------------------------------------------------------------
+ if (resultHit & WebView::LinkSelection)
+ {
+ // send by mail: link url
+ sendByMailAction->setData(result.linkUrl());
+ sendByMailAction->setText(i18n("Share link"));
+
+ a = new KAction(KIcon("tab-new"), i18n("Open in New &Tab"), this);
+ a->setData(result.linkUrl());
+ connect(a, SIGNAL(triggered(bool)), this, SLOT(openLinkInNewTab()));
+ menu.addAction(a);
+
+ a = new KAction(KIcon("window-new"), i18n("Open in New &Window"), this);
+ a->setData(result.linkUrl());
+ connect(a, SIGNAL(triggered(bool)), this, SLOT(openLinkInNewWindow()));
+ menu.addAction(a);
+
+ menu.addSeparator();
+
+ // Don't show dots if we are NOT going to ask for download path
+ a = pageAction(KWebPage::DownloadLinkToDisk);
+ if (ReKonfig::askDownloadPath())
+ a->setText(i18n("Save Link..."));
+ else
+ a->setText(i18n("Save Link"));
+
+ menu.addAction(a);
+ menu.addAction(pageAction(KWebPage::CopyLinkToClipboard));
+ }
+
+ // IMAGE ACTIONS ------------------------------------------------------------------
+ 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 (rApp->adblockManager()->isEnabled())
+ {
+ a = new KAction(KIcon("preferences-web-browser-adblock"), i18n("Block image"), this);
+ a->setData(result.imageUrl());
+ connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(blockImage()));
+ menu.addAction(a);
+ }
+ }
+
+ // ACTIONS FOR TEXT SELECTION -----------------------------------------------------
+ if (resultHit & WebView::TextSelection)
+ {
+ // 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("...");
+ }
+ //open selected text url in a new tab
+ QAction * const openInNewTabAction = new KAction(KIcon("tab-new"), i18n("Open '%1' in New Tab", truncatedUrl), this);
+ openInNewTabAction->setData(QUrl(urlLikeText));
+ connect(openInNewTabAction, SIGNAL(triggered(bool)), this, SLOT(openLinkInNewTab()));
+ menu.addAction(openInNewTabAction);
+ //open selected text url in a new window
+ QAction * const openInNewWindowAction = new KAction(KIcon("window-new"), i18n("Open '%1' in New Window", truncatedUrl), this);
+ openInNewWindowAction->setData(QUrl(urlLikeText));
+ connect(openInNewWindowAction, SIGNAL(triggered(bool)), this, SLOT(openLinkInNewWindow()));
+ menu.addAction(openInNewWindowAction);
+ 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);
+ }
+ }
+
+ // DEFAULT ACTIONs (on the bottom) ------------------------------------------------
+ menu.addSeparator();
+ if (resultHit & WebView::LinkSelection)
+ {
+ 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 = mainwindow->actionByName(KStandardAction::name(KStandardAction::AddBookmark));
+ menu.addAction(a);
+ }
+ menu.addAction(sendByMailAction);
+ menu.addAction(inspectAction);
+
+ // finally launch the menu...
+ menu.exec(mapToGlobal(event->pos()));
+}
+
+
+void WebView::mousePressEvent(QMouseEvent *event)
+{
+ if (m_isViewAutoScrolling)
+ {
+ m_verticalAutoScrollSpeed = 0;
+ m_horizontalAutoScrollSpeed = 0;
+ m_autoScrollTimer->stop();
+ m_isViewAutoScrolling = false;
+ update();
+ return;
+ }
+
+ QWebHitTestResult result = page()->mainFrame()->hitTestContent(event->pos());
+ bool weCanDoMiddleClickActions = !result.isContentEditable() && result.linkUrl().isEmpty();
+
+ switch (event->button())
+ {
+ case Qt::XButton1:
+ triggerPageAction(KWebPage::Back);
+ break;
+
+ case Qt::XButton2:
+ triggerPageAction(KWebPage::Forward);
+ break;
+
+ case Qt::MidButton:
+ switch (ReKonfig::middleClickAction())
+ {
+ case 0: // AutoScroll
+ if (weCanDoMiddleClickActions
+ && !m_isViewAutoScrolling
+ && !page()->currentFrame()->scrollBarGeometry(Qt::Horizontal).contains(event->pos())
+ && !page()->currentFrame()->scrollBarGeometry(Qt::Vertical).contains(event->pos()))
+ {
+ if (!page()->currentFrame()->scrollBarGeometry(Qt::Horizontal).isNull()
+ || !page()->currentFrame()->scrollBarGeometry(Qt::Vertical).isNull())
+ {
+ m_clickPos = event->pos();
+ m_isViewAutoScrolling = true;
+ update();
+ }
+ }
+ break;
+
+ case 1: // Load Clipboard URL
+ if (weCanDoMiddleClickActions)
+ {
+ const QString clipboardContent = rApp->clipboard()->text();
+
+ if (clipboardContent.isEmpty())
+ break;
+
+ if (QUrl::fromUserInput(clipboardContent).isValid())
+ loadUrl(clipboardContent, Rekonq::CurrentTab);
+ else // Search with default Engine
+ {
+ KService::Ptr defaultEngine = SearchEngine::defaultEngine();
+ if (defaultEngine) // check if a default engine is set
+ loadUrl(KUrl(SearchEngine::buildQuery(defaultEngine, clipboardContent)), Rekonq::CurrentTab);
+ }
+ }
+ break;
+
+ default: // Do Nothing
+ break;
+ }
+ break;
+
+ default:
+ break;
+ };
+
+ KWebView::mousePressEvent(event);
+}
+
+
+void WebView::mouseMoveEvent(QMouseEvent *event)
+{
+ QPoint mousePos = event->pos();
+
+ if (m_isViewAutoScrolling)
+ {
+ QPoint r = mousePos - m_clickPos;
+ m_horizontalAutoScrollSpeed = r.x() / 2; // you are too fast..
+ m_verticalAutoScrollSpeed = r.y() / 2;
+ if (!m_autoScrollTimer->isActive())
+ m_autoScrollTimer->start();
+
+ return;
+ }
+
+ MainWindow *w = rApp->mainWindow();
+ if (w->isFullScreen())
+ {
+ if (event->pos().y() >= 0 && event->pos().y() <= 4)
+ {
+ w->setWidgetsVisible(true);
+ }
+ else
+ {
+ if (!w->mainView()->currentUrlBar()->hasFocus())
+ w->setWidgetsVisible(false);
+ }
+ }
+ KWebView::mouseMoveEvent(event);
+}
+
+
+void WebView::dropEvent(QDropEvent *event)
+{
+ bool isEditable = page()->frameAt(event->pos())->hitTestContent(event->pos()).isContentEditable();
+ if (event->mimeData()->hasFormat(BookmarkManager::bookmark_mime_type()))
+ {
+ QByteArray addresses = event->mimeData()->data(BookmarkManager::bookmark_mime_type());
+ KBookmark bookmark = rApp->bookmarkManager()->findByAddress(QString::fromLatin1(addresses.data()));
+ if (bookmark.isGroup())
+ {
+ rApp->bookmarkManager()->openFolderinTabs(bookmark.toGroup());
+ }
+ else
+ {
+ emit loadUrl(bookmark.url(), Rekonq::CurrentTab);
+ }
+ }
+ else if (event->mimeData()->hasUrls() && event->source() != this && !isEditable) //dropped links
+ {
+ Q_FOREACH(const QUrl & url, event->mimeData()->urls())
+ {
+ emit loadUrl(url, Rekonq::NewFocusedTab);
+ }
+ }
+ else if (event->mimeData()->hasFormat("text/plain") && event->source() != this && !isEditable) //dropped plain text with url format
+ {
+ QUrl url = QUrl::fromUserInput(event->mimeData()->data("text/plain"));
+
+ if (url.isValid())
+ emit loadUrl(url, Rekonq::NewFocusedTab);
+ }
+ else
+ {
+ KWebView::dropEvent(event);
+ }
+}
+
+
+void WebView::paintEvent(QPaintEvent* event)
+{
+ KWebView::paintEvent(event);
+
+ if (m_isViewAutoScrolling)
+ {
+ QPoint centeredPoint = m_clickPos;
+ centeredPoint.setX(centeredPoint.x() - m_autoScrollIndicator.width() / 2);
+ centeredPoint.setY(centeredPoint.y() - m_autoScrollIndicator.height() / 2);
+
+ QPainter painter(this);
+ painter.setOpacity(0.8);
+ painter.drawPixmap(centeredPoint, m_autoScrollIndicator);
+ }
+}
+
+
+void WebView::search()
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ KService::Ptr engine = KService::serviceByDesktopPath(a->data().toString());
+ KUrl urlSearch = KUrl(SearchEngine::buildQuery(engine, selectedText()));
+
+ emit loadUrl(urlSearch, Rekonq::NewTab);
+}
+
+
+void WebView::printFrame()
+{
+ rApp->mainWindow()->printRequested(page()->currentFrame());
+}
+
+
+void WebView::viewImage(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ KUrl url(a->data().toUrl());
+
+ if (modifiers & Qt::ControlModifier || buttons == Qt::MidButton)
+ {
+ emit loadUrl(url, Rekonq::NewTab);
+ }
+ else
+ {
+ emit loadUrl(url, Rekonq::CurrentTab);
+ }
+}
+
+
+void WebView::slotCopyImageLocation()
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ KUrl imageUrl(a->data().toUrl());
+#ifndef QT_NO_MIMECLIPBOARD
+ // Set it in both the mouse selection and in the clipboard
+ QMimeData* mimeData = new QMimeData;
+ imageUrl.populateMimeData(mimeData);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
+ mimeData = new QMimeData;
+ imageUrl.populateMimeData(mimeData);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
+#else
+ QApplication::clipboard()->setText(imageUrl.url());
+#endif
+}
+
+
+void WebView::openLinkInNewWindow()
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ KUrl url(a->data().toUrl());
+
+ emit loadUrl(url, Rekonq::NewWindow);
+}
+
+
+void WebView::openLinkInNewTab()
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ KUrl url(a->data().toUrl());
+
+ emit loadUrl(url, Rekonq::NewTab);
+}
+
+
+void WebView::bookmarkLink()
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ KUrl url(a->data().toUrl());
+
+ rApp->bookmarkManager()->rootGroup().addBookmark(url.prettyUrl(), url);
+ rApp->bookmarkManager()->emitChanged();
+}
+
+
+void WebView::keyPressEvent(QKeyEvent *event)
+{
+ // If CTRL was hit, be prepared for access keys
+ if (ReKonfig::accessKeysEnabled()
+ && !m_accessKeysActive
+ && event->key() == Qt::Key_Control
+ && !(event->modifiers() & ~Qt::ControlModifier)
+ )
+ {
+ m_accessKeysPressed = true;
+ event->accept();
+ return;
+ }
+
+ const QString tagName = page()->mainFrame()->evaluateJavaScript("document.activeElement.tagName").toString();
+
+ if (event->modifiers() == Qt::ControlModifier)
+ {
+ if (event->key() == Qt::Key_C)
+ {
+ triggerPageAction(KWebPage::Copy);
+ event->accept();
+ return;
+ }
+
+ if (event->key() == Qt::Key_A)
+ {
+ triggerPageAction(KWebPage::SelectAll);
+ event->accept();
+ return;
+ }
+
+ // CTRL + RETURN: open link into another tab
+ if (event->key() == Qt::Key_Return && tagName == QL1S("A"))
+ {
+ KUrl u = KUrl(page()->mainFrame()->evaluateJavaScript("document.activeElement.attributes[\"href\"].value").toString());
+ emit loadUrl(u, Rekonq::NewTab);
+ event->accept();
+ return;
+ }
+ }
+
+ // Auto Scrolling
+ if (event->modifiers() == Qt::ShiftModifier
+ && tagName != QL1S("INPUT")
+ && tagName != QL1S("TEXTAREA")
+ )
+ {
+ // NOTE and FIXME
+ // This check is doabled because it presents strange behavior: QtWebKit check works well in pages like gmail
+ // and fails on sites like g+. The opposite is true for javascript check.
+ // Please, help me finding the right way to check this EVERY TIME.
+ bool isContentEditableQW = page()->mainFrame()->hitTestContent(QCursor::pos()).isContentEditable();
+ bool isContentEditableJS = page()->mainFrame()->evaluateJavaScript("document.activeElement.isContentEditable").toBool();
+
+ if (!isContentEditableQW && !isContentEditableJS)
+ {
+ if (event->key() == Qt::Key_Up)
+ {
+ m_verticalAutoScrollSpeed--;
+ if (!m_autoScrollTimer->isActive())
+ m_autoScrollTimer->start();
+
+ event->accept();
+ return;
+ }
+
+ if (event->key() == Qt::Key_Down)
+ {
+ m_verticalAutoScrollSpeed++;
+ if (!m_autoScrollTimer->isActive())
+ m_autoScrollTimer->start();
+
+ event->accept();
+ return;
+ }
+
+ if (event->key() == Qt::Key_Right)
+ {
+ m_horizontalAutoScrollSpeed++;
+ if (!m_autoScrollTimer->isActive())
+ m_autoScrollTimer->start();
+
+ event->accept();
+ return;
+ }
+
+ if (event->key() == Qt::Key_Left)
+ {
+ m_horizontalAutoScrollSpeed--;
+ if (!m_autoScrollTimer->isActive())
+ m_autoScrollTimer->start();
+
+ event->accept();
+ return;
+ }
+
+ if (m_autoScrollTimer->isActive())
+ {
+ m_autoScrollTimer->stop();
+ event->accept();
+ return;
+ }
+ else
+ {
+ if (m_verticalAutoScrollSpeed || m_horizontalAutoScrollSpeed)
+ {
+ m_autoScrollTimer->start();
+ event->accept();
+ return;
+ }
+ }
+ }
+
+ // if you arrived here, I hope it means SHIFT has been pressed NOT for autoscroll management...
+ }
+
+ if (ReKonfig::accessKeysEnabled() && m_accessKeysActive)
+ {
+ hideAccessKeys();
+ event->accept();
+ return;
+ }
+
+ // vi-like navigation
+ if (ReKonfig::enableViShortcuts())
+ {
+ if (event->modifiers() == Qt::NoModifier
+ && tagName != QL1S("INPUT")
+ && tagName != QL1S("TEXTAREA")
+ )
+ {
+ // See note up!
+ bool isContentEditableQW = page()->mainFrame()->hitTestContent(QCursor::pos()).isContentEditable();
+ bool isContentEditableJS = page()->mainFrame()->evaluateJavaScript("document.activeElement.isContentEditable").toBool();
+
+ if (!isContentEditableQW && !isContentEditableJS)
+ {
+ switch (event->key())
+ {
+ case Qt::Key_J:
+ event->accept();
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
+ break;
+ case Qt::Key_K:
+ event->accept();
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
+ break;
+ case Qt::Key_L:
+ event->accept();
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
+ break;
+ case Qt::Key_H:
+ event->accept();
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ KWebView::keyPressEvent(event);
+}
+
+
+void WebView::keyReleaseEvent(QKeyEvent *event)
+{
+ // access keys management
+ if (ReKonfig::accessKeysEnabled())
+ {
+ if (m_accessKeysPressed && event->key() != Qt::Key_Control)
+ m_accessKeysPressed = false;
+
+ if (m_accessKeysPressed && !(event->modifiers() & Qt::ControlModifier))
+ {
+ kDebug() << "Shotting access keys";
+ QTimer::singleShot(200, this, SLOT(accessKeyShortcut()));
+ event->accept();
+ return;
+ }
+ else
+ {
+ checkForAccessKey(event);
+ kDebug() << "Hiding access keys";
+ hideAccessKeys();
+ event->accept();
+ return;
+ }
+ }
+
+ KWebView::keyReleaseEvent(event);
+}
+
+
+void WebView::wheelEvent(QWheelEvent *event)
+{
+ if (event->orientation() == Qt::Vertical || !ReKonfig::hScrollWheelHistory())
+ {
+ // To let some websites (eg: google maps) to handle wheel events
+ int prevPos = page()->currentFrame()->scrollPosition().y();
+ KWebView::wheelEvent(event);
+ int newPos = page()->currentFrame()->scrollPosition().y();
+
+ // Sync with the zoom slider
+ if (event->modifiers() == Qt::ControlModifier)
+ {
+ // Limits of the slider
+ if (zoomFactor() > 1.9)
+ setZoomFactor(1.9);
+ else if (zoomFactor() < 0.1)
+ setZoomFactor(0.1);
+
+ // Round the factor (Fix slider's end value)
+ int newFactor = zoomFactor() * 10;
+ if ((zoomFactor() * 10 - newFactor) > 0.5)
+ newFactor++;
+
+ emit zoomChanged(newFactor);
+ }
+ else if (ReKonfig::smoothScrolling() && prevPos != newPos)
+ {
+ page()->currentFrame()->setScrollPosition(QPoint(page()->currentFrame()->scrollPosition().x(), prevPos));
+
+ if ((event->delta() > 0) != !m_smoothScrollBottomReached)
+ stopSmoothScrolling();
+
+ if (event->delta() > 0)
+ m_smoothScrollBottomReached = false;
+ else
+ m_smoothScrollBottomReached = true;
+
+
+ setupSmoothScrolling(abs(newPos - prevPos));
+ }
+ }
+ // use horizontal wheel events to go back and forward in tab history
+ else
+ {
+ // left -> go to previous page
+ if (event->delta() > 0)
+ {
+ emit openPreviousInHistory();
+ }
+ // right -> go to next page
+ if (event->delta() < 0)
+ {
+ emit openNextInHistory();
+ }
+ }
+}
+
+
+void WebView::inspect()
+{
+ QAction *a = rApp->mainWindow()->actionByName("web_inspector");
+ if (a && !a->isChecked())
+ a->trigger();
+ pageAction(QWebPage::InspectElement)->trigger();
+}
+
+
+void WebView::scrollFrameChanged()
+{
+ // do the scrolling
+ page()->currentFrame()->scroll(m_horizontalAutoScrollSpeed, m_verticalAutoScrollSpeed);
+
+ // check if we reached the end
+ int y = page()->currentFrame()->scrollPosition().y();
+ if (y == 0 || y == page()->currentFrame()->scrollBarMaximum(Qt::Vertical))
+ m_verticalAutoScrollSpeed = 0;
+
+ int x = page()->currentFrame()->scrollPosition().x();
+ if (x == 0 || x == page()->currentFrame()->scrollBarMaximum(Qt::Horizontal))
+ m_horizontalAutoScrollSpeed = 0;
+}
+
+
+void WebView::setupSmoothScrolling(int posY)
+{
+ int ddy = qMax(m_smoothScrollSteps ? abs(m_dy) / m_smoothScrollSteps : 0, 3);
+
+ m_dy += posY;
+
+ if (m_dy <= 0)
+ {
+ stopSmoothScrolling();
+ return;
+ }
+
+ m_smoothScrollSteps = 8;
+
+ if (m_dy / m_smoothScrollSteps < ddy)
+ {
+ m_smoothScrollSteps = (abs(m_dy) + ddy - 1) / ddy;
+ if (m_smoothScrollSteps < 1)
+ m_smoothScrollSteps = 1;
+ }
+
+ m_smoothScrollTime.start();
+
+ if (!m_isViewSmoothScrolling)
+ {
+ m_isViewSmoothScrolling = true;
+ m_smoothScrollTimer->start();
+ scrollTick();
+ }
+}
+
+
+void WebView::scrollTick()
+{
+ if (m_dy == 0)
+ {
+ stopSmoothScrolling();
+ return;
+ }
+
+ if (m_smoothScrollSteps < 1)
+ m_smoothScrollSteps = 1;
+
+ int takesteps = m_smoothScrollTime.restart() / 16;
+ int scroll_y = 0;
+
+ if (takesteps < 1)
+ takesteps = 1;
+
+ if (takesteps > m_smoothScrollSteps)
+ takesteps = m_smoothScrollSteps;
+
+ for (int i = 0; i < takesteps; i++)
+ {
+ int ddy = (m_dy / (m_smoothScrollSteps + 1)) * 2;
+
+ // limit step to requested scrolling distance
+ if (abs(ddy) > abs(m_dy))
+ ddy = m_dy;
+
+ // update remaining scroll
+ m_dy -= ddy;
+ scroll_y += ddy;
+ m_smoothScrollSteps--;
+ }
+
+ if (m_smoothScrollBottomReached)
+ page()->currentFrame()->scroll(0, scroll_y);
+ else
+ page()->currentFrame()->scroll(0, -scroll_y);
+}
+
+
+void WebView::stopSmoothScrolling()
+{
+ m_smoothScrollTimer->stop();
+ m_dy = 0;
+ m_isViewSmoothScrolling = false;
+}
+
+
+void WebView::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasUrls() || event->mimeData()->hasText())
+ event->acceptProposedAction();
+ else
+ KWebView::dragEnterEvent(event);
+}
+
+
+void WebView::dragMoveEvent(QDragMoveEvent *event)
+{
+ if (event->mimeData()->hasUrls() || event->mimeData()->hasText())
+ event->acceptProposedAction();
+ else
+ KWebView::dragMoveEvent(event);
+}
+
+
+void WebView::hideAccessKeys()
+{
+ if (!m_accessKeyLabels.isEmpty())
+ {
+ for (int i = 0; i < m_accessKeyLabels.count(); ++i)
+ {
+ QLabel *label = m_accessKeyLabels[i];
+ label->hide();
+ label->deleteLater();
+ }
+ m_accessKeyLabels.clear();
+ m_accessKeyNodes.clear();
+ update();
+ }
+}
+
+
+void WebView::showAccessKeys()
+{
+ QStringList supportedElement;
+ supportedElement << QLatin1String("a")
+ << QLatin1String("input")
+ << QLatin1String("area")
+ << QLatin1String("button")
+ << QLatin1String("label")
+ << QLatin1String("legend")
+ << QLatin1String("textarea");
+
+ QList<QChar> unusedKeys;
+ for (char c = 'A'; c <= 'Z'; ++c)
+ unusedKeys << QLatin1Char(c);
+ for (char c = '0'; c <= '9'; ++c)
+ unusedKeys << QLatin1Char(c);
+
+ QRect viewport = QRect(page()->mainFrame()->scrollPosition(), page()->viewportSize());
+ // Priority first goes to elements with accesskey attributes
+ QList<QWebElement> alreadyLabeled;
+ Q_FOREACH(const QString & elementType, supportedElement)
+ {
+ QList<QWebElement> result = page()->mainFrame()->findAllElements(elementType).toList();
+ Q_FOREACH(const QWebElement & element, result)
+ {
+ const QRect geometry = element.geometry();
+ if (geometry.size().isEmpty()
+ || !viewport.contains(geometry.topLeft()))
+ {
+ continue;
+ }
+ QString accessKeyAttribute = element.attribute(QLatin1String("accesskey")).toUpper();
+ if (accessKeyAttribute.isEmpty())
+ continue;
+ QChar accessKey;
+ for (int i = 0; i < accessKeyAttribute.count(); i += 2)
+ {
+ const QChar &possibleAccessKey = accessKeyAttribute[i];
+ if (unusedKeys.contains(possibleAccessKey))
+ {
+ accessKey = possibleAccessKey;
+ break;
+ }
+ }
+ if (accessKey.isNull())
+ {
+ continue;
+ }
+ unusedKeys.removeOne(accessKey);
+ makeAccessKeyLabel(accessKey, element);
+ alreadyLabeled.append(element);
+ }
+ }
+
+ // Pick an access key first from the letters in the text and then from the
+ // list of unused access keys
+ Q_FOREACH(const QString & elementType, supportedElement)
+ {
+ QWebElementCollection result = page()->mainFrame()->findAllElements(elementType);
+ Q_FOREACH(const QWebElement & element, result)
+ {
+ const QRect geometry = element.geometry();
+ if (unusedKeys.isEmpty()
+ || alreadyLabeled.contains(element)
+ || geometry.size().isEmpty()
+ || !viewport.contains(geometry.topLeft()))
+ {
+ continue;
+ }
+ QChar accessKey;
+ QString text = element.toPlainText().toUpper();
+ for (int i = 0; i < text.count(); ++i)
+ {
+ const QChar &c = text.at(i);
+ if (unusedKeys.contains(c))
+ {
+ accessKey = c;
+ break;
+ }
+ }
+ if (accessKey.isNull())
+ accessKey = unusedKeys.takeFirst();
+ unusedKeys.removeOne(accessKey);
+ makeAccessKeyLabel(accessKey, element);
+ }
+ }
+}
+
+
+void WebView::makeAccessKeyLabel(const QChar &accessKey, const QWebElement &element)
+{
+ QLabel *label = new QLabel(this);
+ label->setText(QString(QLatin1String("<qt><b>%1</b>")).arg(accessKey));
+
+ label->setAutoFillBackground(true);
+ label->setFrameStyle(QFrame::Box | QFrame::Plain);
+ QPoint point = element.geometry().center();
+ point -= page()->mainFrame()->scrollPosition();
+ label->move(point);
+ label->show();
+ point.setX(point.x() - label->width() / 2);
+ label->move(point);
+ m_accessKeyLabels.append(label);
+ m_accessKeyNodes[accessKey] = element;
+}
+
+
+bool WebView::checkForAccessKey(QKeyEvent *event)
+{
+ if (m_accessKeyLabels.isEmpty())
+ return false;
+
+ QString text = event->text();
+ if (text.isEmpty())
+ return false;
+ QChar key = text.at(0).toUpper();
+ bool handled = false;
+ if (m_accessKeyNodes.contains(key))
+ {
+ QWebElement element = m_accessKeyNodes[key];
+ QPoint p = element.geometry().center();
+ QWebFrame *frame = element.webFrame();
+ Q_ASSERT(frame);
+ do
+ {
+ p -= frame->scrollPosition();
+ frame = frame->parentFrame();
+ }
+ while (frame && frame != page()->mainFrame());
+ QMouseEvent pevent(QEvent::MouseButtonPress, p, Qt::LeftButton, 0, 0);
+ rApp->sendEvent(this, &pevent);
+ QMouseEvent revent(QEvent::MouseButtonRelease, p, Qt::LeftButton, 0, 0);
+ rApp->sendEvent(this, &revent);
+ handled = true;
+ }
+
+ kDebug() << "checking for access keys: " << handled;
+ return handled;
+}
+
+
+void WebView::accessKeyShortcut()
+{
+ if (!hasFocus()
+ || !m_accessKeysPressed
+ || !ReKonfig::accessKeysEnabled())
+ return;
+ if (m_accessKeyLabels.isEmpty())
+ {
+ showAccessKeys();
+ }
+ else
+ {
+ hideAccessKeys();
+ }
+ m_accessKeysPressed = false;
+}
+
+
+void WebView::sendByMail()
+{
+ KAction *a = qobject_cast<KAction*>(sender());
+ QString url = a->data().toString();
+
+ KToolInvocation::invokeMailer("", "", "", "", url);
+}
+
+
+void WebView::blockImage()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (!action)
+ return;
+
+ QString imageUrl = action->data().toString();
+ rApp->adblockManager()->addCustomRule(imageUrl);
+}
+
+
+void WebView::mouseReleaseEvent(QMouseEvent *event)
+{
+ QWebHitTestResult hitTest = page()->mainFrame()->hitTestContent(event->pos());
+ const QUrl url = hitTest.linkUrl();
+
+ if (!url.isEmpty())
+ {
+ if (event->button() & Qt::MidButton)
+ {
+ if (event->modifiers() & Qt::ShiftModifier)
+ {
+ if (ReKonfig::openNewTabsInBackground())
+ emit loadUrl(url, Rekonq::NewFocusedTab);
+ else
+ emit loadUrl(url, Rekonq::NewBackGroundTab);
+ event->accept();
+ return;
+ }
+
+ emit loadUrl(url, Rekonq::NewTab);
+ event->accept();
+ return;
+ }
+
+ if ((event->button() & Qt::LeftButton) && (event->modifiers() & Qt::ControlModifier))
+ {
+ emit loadUrl(url, Rekonq::NewTab);
+ event->accept();
+ return;
+ }
+
+ if ((event->button() & Qt::LeftButton) && (event->modifiers() & Qt::ShiftModifier))
+ {
+ page()->downloadUrl(url);
+ event->accept();
+ return;
+ }
+ }
+
+ QWebView::mouseReleaseEvent(event);
+}