Falkon Develop
Cross-platform Qt-based web browser
locationcompleterrefreshjob.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2014-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
20#include "mainapplication.h"
21#include "bookmarkitem.h"
22#include "iconprovider.h"
23#include "sqldatabase.h"
24#include "qzsettings.h"
25#include "bookmarks.h"
26#include "qztools.h"
27
28#include <algorithm>
29
30#include <QDateTime>
31
32#include <QtConcurrent/QtConcurrentRun>
33
35 : QObject()
36 , m_timestamp(QDateTime::currentMSecsSinceEpoch())
37 , m_searchString(searchString)
38 , m_jobCancelled(false)
39{
40 m_watcher = new QFutureWatcher<void>(this);
41 connect(m_watcher, &QFutureWatcherBase::finished, this, &LocationCompleterRefreshJob::slotFinished);
42
43 QFuture<void> future = QtConcurrent::run(&LocationCompleterRefreshJob::runJob, this);
44 m_watcher->setFuture(future);
45}
46
48{
49 return m_timestamp;
50}
51
53{
54 return m_searchString;
55}
56
58{
59 return m_jobCancelled;
60}
61
62QList<QStandardItem*> LocationCompleterRefreshJob::completions() const
63{
64 return m_items;
65}
66
68{
69 return m_domainCompletion;
70}
71
72void LocationCompleterRefreshJob::jobCancelled()
73{
74 m_jobCancelled = true;
75}
76
77void LocationCompleterRefreshJob::slotFinished()
78{
79 Q_EMIT finished();
80}
81
82static bool countBiggerThan(const QStandardItem* i1, const QStandardItem* i2)
83{
84 int i1Count = i1->data(LocationCompleterModel::CountRole).toInt();
85 int i2Count = i2->data(LocationCompleterModel::CountRole).toInt();
86 return i1Count > i2Count;
87}
88
89void LocationCompleterRefreshJob::runJob()
90{
91 if (m_jobCancelled || mApp->isClosing() || !mApp) {
92 return;
93 }
94
95 if (m_searchString.isEmpty()) {
96 completeMostVisited();
97 }
98 else {
99 completeFromHistory();
100 }
101
102 // Load all icons into QImage
103 for (QStandardItem* item : std::as_const(m_items)) {
104 if (m_jobCancelled) {
105 return;
106 }
107
108 const QUrl url = item->data(LocationCompleterModel::UrlRole).toUrl();
110 }
111
112 if (m_jobCancelled) {
113 return;
114 }
115
116 // Get domain completion
117 if (!m_searchString.isEmpty() && qzSettings->useInlineCompletion) {
118 QSqlQuery domainQuery = LocationCompleterModel::createDomainQuery(m_searchString);
119 if (!domainQuery.lastQuery().isEmpty()) {
120 domainQuery.exec();
121 if (domainQuery.next()) {
122 m_domainCompletion = createDomainCompletion(domainQuery.value(0).toUrl().host());
123 }
124 }
125 }
126
127 if (m_jobCancelled) {
128 return;
129 }
130
131 // Add search/visit item
132 if (!m_searchString.isEmpty()) {
133 auto* item = new QStandardItem();
134 item->setText(m_searchString);
135 item->setData(m_searchString, LocationCompleterModel::UrlRole);
136 item->setData(m_searchString, LocationCompleterModel::SearchStringRole);
138 if (!m_domainCompletion.isEmpty()) {
139 const QUrl url = QUrl(QSL("http://%1").arg(m_domainCompletion));
141 }
142 m_items.prepend(item);
143 }
144}
145
146void LocationCompleterRefreshJob::completeFromHistory()
147{
148 QList<QUrl> urlList;
149 Type showType = (Type) qzSettings->showLocationSuggestions;
150
151 // Search in bookmarks
152 if (showType == HistoryAndBookmarks || showType == Bookmarks) {
153 const int bookmarksLimit = 10;
154 const QList<BookmarkItem*> bookmarks = mApp->bookmarks()->searchBookmarks(m_searchString, bookmarksLimit);
155
156 for (BookmarkItem* bookmark : bookmarks) {
157 Q_ASSERT(bookmark->isUrl());
158
159 // Keyword bookmark replaces visit/search item
160 if (bookmark->keyword() == m_searchString) {
161 continue;
162 }
163
164 auto* item = new QStandardItem();
165 item->setText(QString::fromUtf8(bookmark->url().toEncoded()));
166 item->setData(-1, LocationCompleterModel::IdRole);
167 item->setData(bookmark->title(), LocationCompleterModel::TitleRole);
168 item->setData(bookmark->url(), LocationCompleterModel::UrlRole);
169 item->setData(bookmark->visitCount(), LocationCompleterModel::CountRole);
170 item->setData(true, LocationCompleterModel::BookmarkRole);
171 item->setData(QVariant::fromValue<void*>(static_cast<void*>(bookmark)), LocationCompleterModel::BookmarkItemRole);
172 item->setData(m_searchString, LocationCompleterModel::SearchStringRole);
173
174 urlList.append(bookmark->url());
175 m_items.append(item);
176 }
177 }
178
179 // Sort by count
180 std::sort(m_items.begin(), m_items.end(), countBiggerThan);
181
182 // Search in history
183 if (showType == HistoryAndBookmarks || showType == History) {
184 const int historyLimit = 20;
185 QSqlQuery query = LocationCompleterModel::createHistoryQuery(m_searchString, historyLimit);
186 query.exec();
187
188 while (query.next()) {
189 const QUrl url = query.value(1).toUrl();
190
191 if (urlList.contains(url)) {
192 continue;
193 }
194
195 auto* item = new QStandardItem();
196 item->setText(QString::fromUtf8(url.toEncoded()));
197 item->setData(query.value(0), LocationCompleterModel::IdRole);
198 item->setData(query.value(2), LocationCompleterModel::TitleRole);
199 item->setData(url, LocationCompleterModel::UrlRole);
200 item->setData(query.value(3), LocationCompleterModel::CountRole);
201 item->setData(true, LocationCompleterModel::HistoryRole);
202 item->setData(m_searchString, LocationCompleterModel::SearchStringRole);
203
204 m_items.append(item);
205 }
206 }
207}
208
209void LocationCompleterRefreshJob::completeMostVisited()
210{
211 QSqlQuery query(SqlDatabase::instance()->database());
212 query.exec(QSL("SELECT id, url, title FROM history ORDER BY count DESC LIMIT 15"));
213
214 while (query.next()) {
215 auto* item = new QStandardItem();
216 const QUrl url = query.value(1).toUrl();
217
218 item->setText(QString::fromUtf8(url.toEncoded()));
219 item->setData(query.value(0), LocationCompleterModel::IdRole);
220 item->setData(query.value(2), LocationCompleterModel::TitleRole);
221 item->setData(url, LocationCompleterModel::UrlRole);
222 item->setData(true, LocationCompleterModel::HistoryRole);
223
224 m_items.append(item);
225 }
226}
227
228QString LocationCompleterRefreshJob::createDomainCompletion(const QString &completion) const
229{
230 // Make sure search string and completion matches
231
232 if (m_searchString.startsWith(QL1S("www.")) && !completion.startsWith(QL1S("www."))) {
233 return QL1S("www.") + completion;
234 }
235
236 if (!m_searchString.startsWith(QL1S("www.")) && completion.startsWith(QL1S("www."))) {
237 return completion.mid(4);
238 }
239
240 return completion;
241}
static QImage imageForUrl(const QUrl &url, bool allowNull=false)
static QImage imageForDomain(const QUrl &url, bool allowNull=false)
static QSqlQuery createHistoryQuery(const QString &searchString, int limit, bool exactMatch=false)
static QSqlQuery createDomainQuery(const QString &text)
QList< QStandardItem * > completions() const
LocationCompleterRefreshJob(const QString &searchString)
static SqlDatabase * instance()
#define mApp
#define QL1S(x)
Definition: qzcommon.h:44
#define QSL(x)
Definition: qzcommon.h:40
#define qzSettings
Definition: qzsettings.h:69