From 16b3a74aa1b710f586bf7d836b422166b4b1f463 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Fri, 11 Aug 2017 12:26:50 +0200 Subject: [PATCH] LocationCompleter: Add persistent first item that shows used search engine Or in case searching from location bar is disabled or entered text is valid URL, it indicates that this URL will be loaded. --- .../completer/locationcompleter.cpp | 36 +++++++++++---- .../navigation/completer/locationcompleter.h | 7 +-- .../completer/locationcompleterdelegate.cpp | 46 +++++++++++++++++-- .../completer/locationcompleterdelegate.h | 6 ++- .../completer/locationcompletermodel.h | 23 +++++----- .../completer/locationcompleterrefreshjob.cpp | 18 +++++++- .../completer/locationcompleterview.cpp | 15 ++++-- .../completer/locationcompleterview.h | 6 ++- src/lib/navigation/locationbar.cpp | 24 ++++++---- src/lib/navigation/locationbar.h | 7 +-- 10 files changed, 141 insertions(+), 47 deletions(-) diff --git a/src/lib/navigation/completer/locationcompleter.cpp b/src/lib/navigation/completer/locationcompleter.cpp index f11e9a13b..5ae9176c6 100644 --- a/src/lib/navigation/completer/locationcompleter.cpp +++ b/src/lib/navigation/completer/locationcompleter.cpp @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2014 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -97,6 +97,12 @@ void LocationCompleter::refreshJobFinished() showPopup(); + if (!s_view->currentIndex().isValid() && s_model->index(0, 0).data(LocationCompleterModel::VisitSearchItemRole).toBool()) { + m_ignoreCurrentChanged = true; + s_view->setCurrentIndex(s_model->index(0, 0)); + m_ignoreCurrentChanged = false; + } + if (qzSettings->useInlineCompletion) { emit showDomainCompletion(job->domainCompletion()); } @@ -119,23 +125,32 @@ void LocationCompleter::slotPopupClosed() void LocationCompleter::currentChanged(const QModelIndex &index) { + if (m_ignoreCurrentChanged) { + return; + } + QString completion = index.data().toString(); - bool isOriginal = false; + bool completeDomain = index.data(LocationCompleterModel::VisitSearchItemRole).toBool(); + + // Domain completion was dismissed + if (completeDomain && completion == m_originalText) { + completeDomain = false; + } if (completion.isEmpty()) { - isOriginal = true; + completeDomain = true; completion = m_originalText; } - emit showCompletion(completion, isOriginal); + emit showCompletion(completion, completeDomain); } void LocationCompleter::indexActivated(const QModelIndex &index) { Q_ASSERT(index.isValid()); - const QUrl url = index.data(LocationCompleterModel::UrlRole).toUrl(); + QUrl url = index.data(LocationCompleterModel::UrlRole).toUrl(); bool ok; const int tabPos = index.data(LocationCompleterModel::TabPositionTabRole).toInt(&ok); @@ -153,6 +168,10 @@ void LocationCompleter::indexActivated(const QModelIndex &index) bookmark->updateVisitCount(); } + if (index.data(LocationCompleterModel::VisitSearchItemRole).toBool()) { + url = QUrl(m_originalText); + } + loadUrl(url); } @@ -308,8 +327,9 @@ void LocationCompleter::adjustPopupSize() const int maxItemsCount = 6; const int popupHeight = s_view->sizeHintForRow(0) * qMin(maxItemsCount, s_model->rowCount()) + 2 * s_view->frameWidth(); + m_originalText = m_locationBar->text(); + + s_view->setOriginalText(m_originalText); s_view->resize(s_view->width(), popupHeight); s_view->show(); - - m_originalText = m_locationBar->text(); } diff --git a/src/lib/navigation/completer/locationcompleter.h b/src/lib/navigation/completer/locationcompleter.h index c2a0e13a9..31d6a5676 100644 --- a/src/lib/navigation/completer/locationcompleter.h +++ b/src/lib/navigation/completer/locationcompleter.h @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2014 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -46,7 +46,7 @@ public slots: void showMostVisited(); signals: - void showCompletion(const QString &completion, bool isOriginal); + void showCompletion(const QString &completion, bool completeDomain); void showDomainCompletion(const QString &completion); void loadCompletion(); void clearCompletion(); @@ -76,6 +76,7 @@ private: qint64 m_lastRefreshTimestamp; QString m_originalText; bool m_popupClosed; + bool m_ignoreCurrentChanged = false; static LocationCompleterView* s_view; static LocationCompleterModel* s_model; diff --git a/src/lib/navigation/completer/locationcompleterdelegate.cpp b/src/lib/navigation/completer/locationcompleterdelegate.cpp index 14f5882e5..d69afcfc4 100644 --- a/src/lib/navigation/completer/locationcompleterdelegate.cpp +++ b/src/lib/navigation/completer/locationcompleterdelegate.cpp @@ -18,6 +18,7 @@ #include "locationcompleterdelegate.h" #include "locationcompleterview.h" #include "locationcompletermodel.h" +#include "locationbar.h" #include "iconprovider.h" #include "qzsettings.h" @@ -28,6 +29,21 @@ #include #include +static bool isUrlOrDomain(const QString &text) +{ + QUrl url(text); + if (!url.scheme().isEmpty() && (!url.host().isEmpty() || !url.path().isEmpty())) { + return true; + } + if (text.contains(QL1C('.')) && !text.contains(QL1C(' '))) { + return true; + } + if (text == QL1S("localhost")) { + return true; + } + return false; +} + LocationCompleterDelegate::LocationCompleterDelegate(LocationCompleterView* parent) : QStyledItemDelegate(parent) , m_rowHeight(0) @@ -84,11 +100,17 @@ void LocationCompleterDelegate::paint(QPainter* painter, const QStyleOptionViewI // Draw background style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, w); + const bool isVisitSearchItem = index.data(LocationCompleterModel::VisitSearchItemRole).toBool(); + const bool isWebSearch = qzSettings->searchFromAddressBar && !isUrlOrDomain(m_originalText.trimmed()); + // Draw icon const int iconSize = 16; const int iconYPos = center - (iconSize / 2); QRect iconRect(leftPosition, iconYPos, iconSize, iconSize); QPixmap pixmap = index.data(Qt::DecorationRole).value().pixmap(iconSize); + if (isVisitSearchItem && isWebSearch) { + pixmap = QIcon::fromTheme(QSL("edit-find"), QIcon(QSL(":icons/menu/search-icon.svg"))).pixmap(iconSize); + } painter->drawPixmap(iconRect, pixmap); leftPosition = iconRect.right() + m_padding * 2; @@ -103,7 +125,7 @@ void LocationCompleterDelegate::paint(QPainter* painter, const QStyleOptionViewI painter->drawPixmap(starRect, icon.pixmap(starSize)); } - const QString searchText = index.data(LocationCompleterModel::SearchStringRole).toString(); + QString searchText = index.data(LocationCompleterModel::SearchStringRole).toString(); // Draw title const int leftTitleEdge = leftPosition + 2; @@ -113,6 +135,13 @@ void LocationCompleterDelegate::paint(QPainter* painter, const QStyleOptionViewI QString title = index.data(LocationCompleterModel::TitleRole).toString(); painter->setFont(titleFont); + if (isVisitSearchItem) { + title = m_originalText.trimmed(); + if (searchText == title) { + searchText.clear(); + } + } + viewItemDrawText(painter, &opt, titleRect, title, textPalette.color(colorRole), searchText); // Draw link @@ -147,8 +176,14 @@ void LocationCompleterDelegate::paint(QPainter* painter, const QStyleOptionViewI QRect textRect(linkRect); textRect.setX(textRect.x() + m_padding + 16 + m_padding); viewItemDrawText(painter, &opt, textRect, LocationCompleterView::tr("Switch to tab"), textPalette.color(colorLinkRole)); - } - else { + } else if (isVisitSearchItem) { + if (!isWebSearch) { + link = LocationCompleterView::tr("Visit"); + } else { + link = LocationCompleterView::tr("Search on %1").arg(LocationBar::searchEngineName()); + } + viewItemDrawText(painter, &opt, linkRect, link, textPalette.color(colorLinkRole)); + } else { viewItemDrawText(painter, &opt, linkRect, link, textPalette.color(colorLinkRole), searchText); } @@ -190,6 +225,11 @@ void LocationCompleterDelegate::setShowSwitchToTab(bool enable) m_drawSwitchToTab = enable; } +void LocationCompleterDelegate::setOriginalText(const QString &originalText) +{ + m_originalText = originalText; +} + bool LocationCompleterDelegate::drawSwitchToTab() const { return qzSettings->showSwitchTab && m_drawSwitchToTab; diff --git a/src/lib/navigation/completer/locationcompleterdelegate.h b/src/lib/navigation/completer/locationcompleterdelegate.h index c6fe491c4..b8279ea37 100644 --- a/src/lib/navigation/completer/locationcompleterdelegate.h +++ b/src/lib/navigation/completer/locationcompleterdelegate.h @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2016 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -33,6 +33,7 @@ public: QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; void setShowSwitchToTab(bool enable); + void setOriginalText(const QString &originalText); private: bool drawSwitchToTab() const; @@ -44,6 +45,7 @@ private: mutable int m_rowHeight; mutable int m_padding; bool m_drawSwitchToTab; + QString m_originalText; LocationCompleterView* m_view; }; diff --git a/src/lib/navigation/completer/locationcompletermodel.h b/src/lib/navigation/completer/locationcompletermodel.h index 14fb400b6..cc8526010 100644 --- a/src/lib/navigation/completer/locationcompletermodel.h +++ b/src/lib/navigation/completer/locationcompletermodel.h @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2014 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -30,15 +30,16 @@ class LocationCompleterModel : public QStandardItemModel public: enum Role { IdRole = Qt::UserRole + 1, - TitleRole = Qt::UserRole + 2, - UrlRole = Qt::UserRole + 3, - CountRole = Qt::UserRole + 4, - BookmarkRole = Qt::UserRole + 5, - BookmarkItemRole = Qt::UserRole + 6, - SearchStringRole = Qt::UserRole + 7, - TabPositionWindowRole = Qt::UserRole + 8, - TabPositionTabRole = Qt::UserRole + 9, - ImageRole = Qt::UserRole + 10 + TitleRole, + UrlRole, + CountRole, + BookmarkRole, + BookmarkItemRole, + SearchStringRole, + TabPositionWindowRole, + TabPositionTabRole, + ImageRole, + VisitSearchItemRole }; explicit LocationCompleterModel(QObject* parent = 0); diff --git a/src/lib/navigation/completer/locationcompleterrefreshjob.cpp b/src/lib/navigation/completer/locationcompleterrefreshjob.cpp index e2cb99876..1952da107 100644 --- a/src/lib/navigation/completer/locationcompleterrefreshjob.cpp +++ b/src/lib/navigation/completer/locationcompleterrefreshjob.cpp @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2014 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2014-2017 David Rosca * * 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 @@ -116,6 +116,20 @@ void LocationCompleterRefreshJob::runJob() m_domainCompletion = createDomainCompletion(domainQuery.value(0).toUrl().host()); } } + + // Add search/visit item + if (!m_searchString.isEmpty()) { + QStandardItem* item = new QStandardItem(); + item->setText(m_searchString); + item->setData(m_searchString, LocationCompleterModel::UrlRole); + item->setData(m_searchString, LocationCompleterModel::SearchStringRole); + item->setData(QVariant(true), LocationCompleterModel::VisitSearchItemRole); + if (!m_domainCompletion.isEmpty()) { + const QUrl url = QUrl(QSL("http://%1").arg(m_domainCompletion)); + item->setData(IconProvider::imageForDomain(url), LocationCompleterModel::ImageRole); + } + m_items.prepend(item); + } } void LocationCompleterRefreshJob::completeFromHistory() diff --git a/src/lib/navigation/completer/locationcompleterview.cpp b/src/lib/navigation/completer/locationcompleterview.cpp index 08d3ee24f..336c1e7e9 100644 --- a/src/lib/navigation/completer/locationcompleterview.cpp +++ b/src/lib/navigation/completer/locationcompleterview.cpp @@ -21,7 +21,6 @@ #include #include -#include #include LocationCompleterView::LocationCompleterView() @@ -56,6 +55,11 @@ QPersistentModelIndex LocationCompleterView::hoveredIndex() const return m_hoveredIndex; } +void LocationCompleterView::setOriginalText(const QString &originalText) +{ + m_delegate->setOriginalText(originalText); +} + bool LocationCompleterView::eventFilter(QObject* object, QEvent* event) { // Event filter based on QCompleter::eventFilter from qcompleter.cpp @@ -68,7 +72,8 @@ bool LocationCompleterView::eventFilter(QObject* object, QEvent* event) case QEvent::KeyPress: { QKeyEvent* keyEvent = static_cast(event); Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); - QModelIndex idx = m_hoveredIndex; + const QModelIndex idx = m_hoveredIndex; + const QModelIndex visitSearchIdx = model()->index(0, 0).data(LocationCompleterModel::VisitSearchItemRole).toBool() ? model()->index(0, 0) : QModelIndex(); if ((keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) && currentIndex() != idx) { setCurrentIndex(idx); @@ -139,7 +144,7 @@ bool LocationCompleterView::eventFilter(QObject* object, QEvent* event) } case Qt::Key_Up: - if (!idx.isValid()) { + if (!idx.isValid() || idx == visitSearchIdx) { int rowCount = model()->rowCount(); QModelIndex lastIndex = model()->index(rowCount - 1, 0); setCurrentIndex(lastIndex); @@ -154,8 +159,8 @@ bool LocationCompleterView::eventFilter(QObject* object, QEvent* event) if (!idx.isValid()) { QModelIndex firstIndex = model()->index(0, 0); setCurrentIndex(firstIndex); - } else if (idx.row() == model()->rowCount() - 1) { - setCurrentIndex(QModelIndex()); + } else if (idx != visitSearchIdx && idx.row() == model()->rowCount() - 1) { + setCurrentIndex(visitSearchIdx); scrollToTop(); } else { setCurrentIndex(model()->index(idx.row() + 1, 0)); diff --git a/src/lib/navigation/completer/locationcompleterview.h b/src/lib/navigation/completer/locationcompleterview.h index f7813671d..34e80f654 100644 --- a/src/lib/navigation/completer/locationcompleterview.h +++ b/src/lib/navigation/completer/locationcompleterview.h @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2014 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -32,6 +32,8 @@ public: QPersistentModelIndex hoveredIndex() const; + void setOriginalText(const QString &originalText); + bool eventFilter(QObject* object, QEvent* event); signals: diff --git a/src/lib/navigation/locationbar.cpp b/src/lib/navigation/locationbar.cpp index e3715dd06..c24f33fe8 100644 --- a/src/lib/navigation/locationbar.cpp +++ b/src/lib/navigation/locationbar.cpp @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2016 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -146,22 +146,19 @@ void LocationBar::setText(const QString &text) void LocationBar::updatePlaceHolderText() { if (qzSettings->searchFromAddressBar) { - QString engineName = qzSettings->searchWithDefaultEngine ? - mApp->searchEnginesManager()->defaultEngine().name : - mApp->searchEnginesManager()->activeEngine().name; - setPlaceholderText(tr("Enter URL address or search on %1").arg(engineName)); + setPlaceholderText(tr("Enter URL address or search on %1").arg(searchEngineName())); } else setPlaceholderText(tr("Enter URL address")); } -void LocationBar::showCompletion(const QString &completion, bool isOriginal) +void LocationBar::showCompletion(const QString &completion, bool completeDomain) { LineEdit::setText(completion); // Move cursor to the end end(false); - if (isOriginal) { + if (completeDomain) { completer()->complete(); } } @@ -242,6 +239,17 @@ QString LocationBar::convertUrlToText(const QUrl &url) return stringUrl; } +QString LocationBar::searchEngineName() +{ + if (!qzSettings->searchFromAddressBar) { + return QString(); + } else if (qzSettings->searchWithDefaultEngine) { + return mApp->searchEnginesManager()->defaultEngine().name; + } else { + return mApp->searchEnginesManager()->activeEngine().name; + } +} + void LocationBar::refreshTextFormat() { if (!m_webView) { diff --git a/src/lib/navigation/locationbar.h b/src/lib/navigation/locationbar.h index edda35576..7f7399a68 100644 --- a/src/lib/navigation/locationbar.h +++ b/src/lib/navigation/locationbar.h @@ -1,6 +1,6 @@ /* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2010-2016 David Rosca +* QupZilla - Qt web browser +* Copyright (C) 2010-2017 David Rosca * * 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 @@ -44,6 +44,7 @@ public: void setWebView(TabbedWebView* view); static QString convertUrlToText(const QUrl &url); + static QString searchEngineName(); public slots: void setText(const QString &text); @@ -60,7 +61,7 @@ private slots: void setPrivacyState(bool state); void setGoIconVisible(bool state); - void showCompletion(const QString &completion, bool isOriginal); + void showCompletion(const QString &completion, bool completeDomain); void showDomainCompletion(const QString &completion); void clearCompletion();