summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Deop <damnshock@gmail.com>2012-01-12 23:46:03 +0100
committerAndrea Diamantini <adjam7@gmail.com>2012-01-12 23:46:03 +0100
commitc89d16a2e9eba8514e263c679faa355b90c59d2e (patch)
tree0e0469c9a1d70bd2ed9c8a0087d90789675daef9
parentLet keys autoscroll work also when middle click use is disabled (diff)
downloadrekonq-c89d16a2e9eba8514e263c679faa355b90c59d2e.tar.xz
Access Keys navigation
Ported access keys navigation system from Arora and adapted to rekonq code. Also (by adjam), get sure access keys are removed on loadStarted REVIEW:103601 REVIEWED-BY: adjam
-rw-r--r--src/rekonq.kcfg3
-rw-r--r--src/settings/settings_general.ui7
-rw-r--r--src/urlbar/bookmarkwidget.cpp3
-rw-r--r--src/urlbar/bookmarkwidget.h1
-rw-r--r--src/webview.cpp215
-rw-r--r--src/webview.h17
6 files changed, 239 insertions, 7 deletions
diff --git a/src/rekonq.kcfg b/src/rekonq.kcfg
index bfaece5f..4c3dec40 100644
--- a/src/rekonq.kcfg
+++ b/src/rekonq.kcfg
@@ -79,6 +79,9 @@
<entry name="enableViShortcuts" type="Bool">
<default>false</default>
</entry>
+ <entry name="accessKeysEnabled" type="Bool">
+ <default>false</default>
+ </entry>
</group>
diff --git a/src/settings/settings_general.ui b/src/settings/settings_general.ui
index 7e250c47..908f1c27 100644
--- a/src/settings/settings_general.ui
+++ b/src/settings/settings_general.ui
@@ -257,6 +257,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="kcfg_accessKeysEnabled">
+ <property name="text">
+ <string>Enable keyboard navigation using the Ctrl key</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/src/urlbar/bookmarkwidget.cpp b/src/urlbar/bookmarkwidget.cpp
index 5ac8d2e6..b36af2bc 100644
--- a/src/urlbar/bookmarkwidget.cpp
+++ b/src/urlbar/bookmarkwidget.cpp
@@ -3,6 +3,7 @@
* This file is a part of the rekonq project
*
* Copyright (C) 2010-2011 by Yoann Laissus <yoann dot laissus at gmail dot com>
+* Copyright (C) 2012 by Andrea Diamantini <adjam7 at gmail dot com>
*
*
* This program is free software; you can redistribute it and/or
@@ -168,7 +169,7 @@ void BookmarkWidget::setupFolderComboBox()
for (KBookmark bookmark = root.first(); !bookmark.isNull(); bookmark = root.next(bookmark))
{
- if(bookmark.isGroup())
+ if (bookmark.isGroup())
{
m_folder->addItem(bookmark.text(), bookmark.address());
}
diff --git a/src/urlbar/bookmarkwidget.h b/src/urlbar/bookmarkwidget.h
index 025077c7..f70fc750 100644
--- a/src/urlbar/bookmarkwidget.h
+++ b/src/urlbar/bookmarkwidget.h
@@ -3,6 +3,7 @@
* This file is a part of the rekonq project
*
* Copyright (C) 2010-2011 by Yoann Laissus <yoann dot laissus at gmail dot com>
+* Copyright (C) 2012 by Andrea Diamantini <adjam7 at gmail dot com>
*
*
* This program is free software; you can redistribute it and/or
diff --git a/src/webview.cpp b/src/webview.cpp
index 8a4cc4ba..da7f802a 100644
--- a/src/webview.cpp
+++ b/src/webview.cpp
@@ -76,6 +76,7 @@ WebView::WebView(QWidget* parent)
, m_smoothScrolling(false)
, m_dy(0)
, m_smoothScrollSteps(0)
+ , m_accessKeysPressed(false)
{
WebPage *page = new WebPage(this);
setPage(page);
@@ -99,6 +100,7 @@ WebView::WebView(QWidget* parent)
m_smoothScrollTimer->setInterval(16);
connect(this, SIGNAL(iconChanged()), this, SLOT(changeWindowIcon()));
+ connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
}
@@ -109,6 +111,12 @@ WebView::~WebView()
}
+void WebView::loadStarted()
+{
+ hideAccessKeys();
+}
+
+
void WebView::changeWindowIcon()
{
if (ReKonfig::useFavicon())
@@ -159,7 +167,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event)
if (result.isContentSelected())
resultHit = WebView::TextSelection;
- // --------------------------------------------------------------------------------------------
+ // --------------------------------------------------------------------------------
// Ok, let's start filling up the menu...
// is content editable? Add PASTE
@@ -169,7 +177,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event)
menu.addSeparator();
}
- // EMPTY PAGE ACTIONS -------------------------------------------------------------------------
+ // EMPTY PAGE ACTIONS -------------------------------------------------------------
if (resultHit == WebView::EmptySelection)
{
// send by mail: page url
@@ -226,7 +234,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event)
}
}
- // LINK ACTIONS -------------------------------------------------------------------------------
+ // LINK ACTIONS -------------------------------------------------------------------
if (resultHit & WebView::LinkSelection)
{
// send by mail: link url
@@ -248,7 +256,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event)
menu.addAction(pageAction(KWebPage::CopyLinkToClipboard));
}
- // IMAGE ACTIONS ------------------------------------------------------------------------------
+ // IMAGE ACTIONS ------------------------------------------------------------------
if (resultHit & WebView::ImageSelection)
{
// send by mail: image url
@@ -271,7 +279,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event)
menu.addAction(a);
}
- // ACTIONS FOR TEXT SELECTION -----------------------------------------------------------------
+ // ACTIONS FOR TEXT SELECTION -----------------------------------------------------
if (resultHit & WebView::TextSelection)
{
// send by mail: text
@@ -355,7 +363,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event)
}
}
- // DEFAULT ACTIONs (on the bottom) ---------------------------------------------------
+ // DEFAULT ACTIONs (on the bottom) ------------------------------------------------
menu.addSeparator();
if (resultHit & WebView::LinkSelection)
{
@@ -561,6 +569,7 @@ void WebView::viewImage(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifier
}
}
+
void WebView::slotCopyImageLocation()
{
KAction *a = qobject_cast<KAction*>(sender());
@@ -609,6 +618,26 @@ void WebView::bookmarkLink()
void WebView::keyPressEvent(QKeyEvent *event)
{
+ if (ReKonfig::accessKeysEnabled())
+ {
+ m_accessKeysPressed = (event->modifiers() == Qt::ControlModifier
+ && event->key() == Qt::Key_Control);
+ if (!m_accessKeysPressed)
+ {
+ if (checkForAccessKey(event))
+ {
+ hideAccessKeys();
+ event->accept();
+ return;
+ }
+ hideAccessKeys();
+ }
+ else
+ {
+ QTimer::singleShot(200, this, SLOT(accessKeyShortcut()));
+ }
+ }
+
if (event->modifiers() == Qt::ControlModifier)
{
if (event->key() == Qt::Key_C)
@@ -898,6 +927,179 @@ void WebView::dragMoveEvent(QDragMoveEvent *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())
+ {
+ 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;
+ }
+ 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());
@@ -906,3 +1108,4 @@ void WebView::sendByMail()
KToolInvocation::invokeMailer("", "", "", "", url);
}
+
diff --git a/src/webview.h b/src/webview.h
index 95f27f17..0d94aaf6 100644
--- a/src/webview.h
+++ b/src/webview.h
@@ -37,6 +37,8 @@
//Qt Includes
#include <QtCore/QTime>
+#include <QLabel>
+#include <QToolTip>
// Forward Declarations
class WebPage;
@@ -100,6 +102,11 @@ private Q_SLOTS:
void stopScrolling();
void changeWindowIcon();
+ void accessKeyShortcut();
+ void hideAccessKeys();
+
+ void loadStarted();
+
Q_SIGNALS:
void loadUrl(const KUrl &, const Rekonq::OpenType &);
void zoomChanged(int);
@@ -107,6 +114,11 @@ Q_SIGNALS:
void openNextInHistory();
private:
+ bool checkForAccessKey(QKeyEvent *event);
+ void showAccessKeys();
+ void makeAccessKeyLabel(const QChar &accessKey, const QWebElement &element);
+
+private:
QPoint m_mousePos;
QPoint m_clickPos;
@@ -125,6 +137,11 @@ private:
bool m_smoothScrolling;
int m_dy;
int m_smoothScrollSteps;
+
+ // Access Keys
+ QList<QLabel*> m_accessKeyLabels;
+ QHash<QChar, QWebElement> m_accessKeyNodes;
+ bool m_accessKeysPressed;
};
#endif