From f651125c5c12ee5b068bacbcec722211a8835941 Mon Sep 17 00:00:00 2001 From: nowrep Date: Fri, 10 May 2013 22:33:36 +0200 Subject: [PATCH] [LocationBar] Added inline completion for domains. Closes #880 --- CHANGELOG | 1 + .../completer/locationcompleter.cpp | 22 +++++ .../navigation/completer/locationcompleter.h | 4 + .../completer/locationcompletermodel.cpp | 43 +++++++++ .../completer/locationcompletermodel.h | 2 + src/lib/navigation/locationbar.cpp | 88 ++++++++++++------- 6 files changed, 128 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 862e4eb7b..34b04d278 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ Version 1.5.0 * added option to open another private window from private window * added delete action in edit context menu on page * added possibility to remove EasyList from AdBlock + * added inline domain completion to urlbar * proxy exceptions now supports wildcards (*, ?) * cancel upload when trying to upload non-readable files * GreaseMonkey: added support for GM_Settings diff --git a/src/lib/navigation/completer/locationcompleter.cpp b/src/lib/navigation/completer/locationcompleter.cpp index f73b745d8..0055a0b72 100644 --- a/src/lib/navigation/completer/locationcompleter.cpp +++ b/src/lib/navigation/completer/locationcompleter.cpp @@ -44,6 +44,11 @@ void LocationCompleter::setLocationBar(LocationBar* locationBar) m_locationBar = locationBar; } +QString LocationCompleter::domainCompletion() const +{ + return m_completedDomain; +} + bool LocationCompleter::showingMostVisited() const { return m_showingMostVisited; @@ -56,12 +61,14 @@ bool LocationCompleter::isPopupVisible() const void LocationCompleter::closePopup() { + m_completedDomain.clear(); m_showingMostVisited = false; s_view->close(); } void LocationCompleter::complete(const QString &string) { + m_completedDomain = createDomainCompletionString(string); m_showingMostVisited = string.isEmpty(); s_model->refreshCompletions(string); @@ -98,6 +105,21 @@ void LocationCompleter::slotPopupClosed() emit popupClosed(); } +QString LocationCompleter::createDomainCompletionString(const QString &text) +{ + QString completion = s_model->completeDomain(text); + + if (text.startsWith(QLatin1String("www."))) { + return completion.mid(text.size()); + } + + if (completion.startsWith(QLatin1String("www."))) { + completion = completion.mid(4); + } + + return completion.mid(text.size()); +} + void LocationCompleter::showPopup() { Q_ASSERT(m_locationBar); diff --git a/src/lib/navigation/completer/locationcompleter.h b/src/lib/navigation/completer/locationcompleter.h index bb40b7b94..7bf436ef1 100644 --- a/src/lib/navigation/completer/locationcompleter.h +++ b/src/lib/navigation/completer/locationcompleter.h @@ -36,6 +36,7 @@ public: void setLocationBar(LocationBar* locationBar); + QString domainCompletion() const; bool showingMostVisited() const; bool isPopupVisible() const; void closePopup(); @@ -54,11 +55,14 @@ private slots: void slotPopupClosed(); private: + QString createDomainCompletionString(const QString &text); + void showPopup(); void adjustPopupSize(); LocationBar* m_locationBar; QString m_originalText; + QString m_completedDomain; bool m_ignoreCurrentChangedSignal; bool m_showingMostVisited; diff --git a/src/lib/navigation/completer/locationcompletermodel.cpp b/src/lib/navigation/completer/locationcompletermodel.cpp index 9b4d46be2..9604b087e 100644 --- a/src/lib/navigation/completer/locationcompletermodel.cpp +++ b/src/lib/navigation/completer/locationcompletermodel.cpp @@ -137,6 +137,49 @@ void LocationCompleterModel::showMostVisited() } } +QString LocationCompleterModel::completeDomain(const QString &text) +{ + if (text.isEmpty() || text == QLatin1String("www.")) { + return QString(); + } + + bool withoutWww = text.startsWith(QLatin1Char('w')) && !text.startsWith(QLatin1String("www.")); + QString query = "SELECT url FROM history WHERE "; + + if (withoutWww) { + query.append(QLatin1String("url NOT LIKE ? AND url NOT LIKE ? AND ")); + } + else { + query.append(QLatin1String("url LIKE ? OR url LIKE ? OR ")); + } + + query.append(QLatin1String("(url LIKE ? OR url LIKE ?) ORDER BY count DESC LIMIT 1")); + + QSqlQuery sqlQuery; + sqlQuery.prepare(query); + + if (withoutWww) { + sqlQuery.addBindValue(QString("http://www.%")); + sqlQuery.addBindValue(QString("https://www.%")); + sqlQuery.addBindValue(QString("http://%1%").arg(text)); + sqlQuery.addBindValue(QString("https://%1%").arg(text)); + } + else { + sqlQuery.addBindValue(QString("http://%1%").arg(text)); + sqlQuery.addBindValue(QString("https://%1%").arg(text)); + sqlQuery.addBindValue(QString("http://www.%1%").arg(text)); + sqlQuery.addBindValue(QString("https://www.%1%").arg(text)); + } + + sqlQuery.exec(); + + if (!sqlQuery.next()) { + return QString(); + } + + return sqlQuery.value(0).toUrl().host(); +} + QSqlQuery LocationCompleterModel::createQuery(const QString &searchString, const QString &orderBy, const QList &alreadyFound, int limit, bool bookmarks, bool exactMatch) { diff --git a/src/lib/navigation/completer/locationcompletermodel.h b/src/lib/navigation/completer/locationcompletermodel.h index 587514867..30cfe881e 100644 --- a/src/lib/navigation/completer/locationcompletermodel.h +++ b/src/lib/navigation/completer/locationcompletermodel.h @@ -51,6 +51,8 @@ public: void refreshCompletions(const QString &string); void showMostVisited(); + QString completeDomain(const QString &text); + private: enum Type { HistoryAndBookmarks = 0, diff --git a/src/lib/navigation/locationbar.cpp b/src/lib/navigation/locationbar.cpp index 40fb51142..fdefc0f16 100644 --- a/src/lib/navigation/locationbar.cpp +++ b/src/lib/navigation/locationbar.cpp @@ -151,7 +151,7 @@ QUrl LocationBar::createUrl() { QUrl urlToLoad; - //Check for Search Engine shortcut + // Check for Search Engine shortcut int firstSpacePos = text().indexOf(QLatin1Char(' ')); if (firstSpacePos != -1) { QString shortcut = text().left(firstSpacePos); @@ -163,6 +163,11 @@ QUrl LocationBar::createUrl() } } + // Is inline domain completion active? + if (m_completer.isPopupVisible() && !m_completer.domainCompletion().isEmpty()) { + urlToLoad = WebView::guessUrlFromString(text() + m_completer.domainCompletion()); + } + if (urlToLoad.isEmpty()) { QUrl guessedUrl = WebView::guessUrlFromString(text()); if (!guessedUrl.isEmpty()) { @@ -189,10 +194,17 @@ QString LocationBar::convertUrlToText(const QUrl &url) const void LocationBar::urlEnter() { + const QUrl &url = createUrl(); + const QString &urlString = convertUrlToText(url); + m_completer.closePopup(); m_webView->setFocus(); - emit loadUrl(createUrl()); + if (urlString != text()) { + setText(convertUrlToText(url)); + } + + emit loadUrl(url); } void LocationBar::textEdit() @@ -568,33 +580,61 @@ void LocationBar::hideProgress() void LocationBar::paintEvent(QPaintEvent* event) { + QStyleOptionFrameV3 option; + initStyleOption(&option); + + int lm, tm, rm, bm; + getTextMargins(&lm, &tm, &rm, &bm); + + QRect contentsRect = style()->subElementRect(QStyle::SE_LineEditContents, &option, this); + contentsRect.adjust(lm, tm, -rm, -bm); + + const QFontMetrics &fm = fontMetrics(); + const int x = contentsRect.x() + 3; + const int y = contentsRect.y() + (contentsRect.height() - fm.height() + 1) / 2; + const int width = contentsRect.width() - 6; + const int height = fm.height(); + const QRect textRect(x, y, width, height); + + QTextOption opt; + opt.setWrapMode(QTextOption::NoWrap); + + if (hasFocus() && m_completer.isPopupVisible()) { + // Draw inline domain completion if available + const QString &completionText = m_completer.domainCompletion(); + + if (!completionText.isEmpty()) { + LineEdit::paintEvent(event); + + QRect completionRect = textRect; + completionRect.setX(completionRect.x() + fm.width(text()) + 1); + completionRect.setWidth(fm.width(completionText) + 1); + + QPainter p(this); + p.fillRect(completionRect, palette().color(QPalette::Highlight)); + p.setPen(palette().color(QPalette::HighlightedText)); + p.drawText(completionRect, completionText, opt); + return; + } + } + #ifndef Q_OS_MAC if (m_drawCursor && m_completer.isPopupVisible() && !m_completer.showingMostVisited()) { // We need to draw cursor when popup is visible // But don't paint it if we are just showing most visited sites LineEdit::paintEvent(event); - QStyleOptionFrameV3 option; - initStyleOption(&option); - - int lm, tm, rm, bm; - getTextMargins(&lm, &tm, &rm, &bm); - - QRect contentsRect = style()->subElementRect(QStyle::SE_LineEditContents, &option, this); - contentsRect.adjust(lm, tm, -rm, -bm); - - const QFontMetrics &fm = fontMetrics(); QString textPart = text().left(cursorPosition()); - int cursorXpos = contentsRect.x() + 3 + fontMetrics().width(textPart); - int cursorYpos = contentsRect.y() + (contentsRect.height() - fm.height() + 1) / 2; + int cursorXpos = x + fontMetrics().width(textPart); int cursorWidth = style()->pixelMetric(QStyle::PM_TextCursorWidth, &option, this); int cursorHeight = fontMetrics().height(); - QPainter p(this); - QRect cursorRect(cursorXpos, cursorYpos, cursorWidth, cursorHeight); + QRect cursorRect(cursorXpos, y, cursorWidth, cursorHeight); if (isRightToLeft()) { cursorRect = style()->visualRect(Qt::RightToLeft, contentsRect, cursorRect); } + + QPainter p(this); p.fillRect(cursorRect, option.palette.text().color()); return; } @@ -609,26 +649,12 @@ void LocationBar::paintEvent(QPaintEvent* event) return; } - QStyleOptionFrameV3 option; - initStyleOption(&option); - QPainter p(this); p.setRenderHint(QPainter::Antialiasing, true); p.setRenderHint(QPainter::TextAntialiasing, true); style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, &p, this); - QRect contentsRect = style()->subElementRect(QStyle::SE_LineEditContents, &option, this); - int lm, tm, rm, bm; - getTextMargins(&lm, &tm, &rm, &bm); - contentsRect.adjust(lm, tm, -rm, -bm); - QFontMetrics fm = fontMetrics(); - const int x = contentsRect.x() + 3; - const int y = contentsRect.y() + (contentsRect.height() - fm.height() + 1) / 2; - const int width = contentsRect.width() - 6; - const int height = fm.height(); - QRect textRect(x, y, width, height); - QPen oldPen = p.pen(); if (qzSettings->showLoadingProgress && m_progressVisible) { @@ -675,8 +701,6 @@ void LocationBar::paintEvent(QPaintEvent* event) } p.setPen(oldPen); - QTextOption opt; - opt.setWrapMode(QTextOption::NoWrap); const QString hostName = m_webView->url().host(); QString currentText = text();