summaryrefslogtreecommitdiff
path: root/src/webview.cpp
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 /src/webview.cpp
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
Diffstat (limited to 'src/webview.cpp')
-rw-r--r--src/webview.cpp215
1 files changed, 209 insertions, 6 deletions
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);
}
+