30#include <QNetworkReply>
36#define ENSURE_LOADED if (!m_settingsLoaded) loadSettings();
38static QIcon iconFromBase64(
const QByteArray &data)
41 QByteArray bArray = QByteArray::fromBase64(data);
42 QBuffer buffer(&bArray);
43 buffer.open(QIODevice::ReadOnly);
44 QDataStream in(&buffer);
48 if (!image.isNull()) {
55static QByteArray iconToBase64(
const QIcon &icon)
58 QBuffer buffer(&bArray);
59 buffer.open(QIODevice::WriteOnly);
60 QDataStream out(&buffer);
63 return bArray.toBase64();
68 , m_settingsLoaded(false)
69 , m_saveScheduled(false)
73 m_startingEngineName = settings.
value(
QSL(
"activeEngine"),
QSL(
"DuckDuckGo")).toString();
74 m_defaultEngineName = settings.
value(
QSL(
"DefaultEngine"),
QSL(
"DuckDuckGo")).toString();
80void SearchEnginesManager::loadSettings()
82 m_settingsLoaded =
true;
85 query.exec(
QSL(
"SELECT name, icon, url, shortcut, suggestionsUrl, suggestionsParameters, postData FROM search_engines"));
87 while (query.next()) {
89 en.name = query.value(0).toString();
90 en.icon = iconFromBase64(query.value(1).toByteArray());
91 en.url = query.value(2).toString();
92 en.shortcut = query.value(3).toString();
93 en.suggestionsUrl = query.value(4).toString();
94 en.suggestionsParameters = query.value(5).toByteArray();
95 en.postData = query.value(6).toByteArray();
97 m_allEngines.append(en);
99 if (en.name == m_defaultEngineName) {
100 m_defaultEngine = en;
104 if (m_allEngines.isEmpty()) {
108 if (m_defaultEngine.
name.isEmpty()) {
109 m_defaultEngine = m_allEngines[0];
117 if (shortcut.isEmpty()) {
121 for (
const Engine &en : std::as_const(m_allEngines)) {
122 if (en.shortcut == shortcut) {
137 QByteArray url = engine.
url.toUtf8();
138 url.replace(
"%s", QUrl::toPercentEncoding(
string));
145 data.replace(
"%s", QUrl::toPercentEncoding(
string));
154 const Engine en =
qzSettings->searchWithDefaultEngine ? m_defaultEngine : m_activeEngine;
162 duck.
icon = QIcon(
QSL(
":/icons/sites/duck.png"));
163 duck.
url =
QSL(
"https://duckduckgo.com/?q=%s&t=qupzilla");
169 sp.
icon = QIcon(
QSL(
":/icons/sites/startpage.png"));
170 sp.
url =
QSL(
"https://www.startpage.com/sp/search?query=%s&cat=web&pl=opensearch");
175 wiki.
name =
QSL(
"Wikipedia (en)");
176 wiki.
icon = QIcon(
QSL(
":/icons/sites/wikipedia.png"));
177 wiki.
url =
QSL(
"https://en.wikipedia.org/wiki/Special:Search?search=%s&fulltext=Search");
179 wiki.
suggestionsUrl =
QSL(
"https://en.wikipedia.org/w/api.php?action=opensearch&search=%s&namespace=0");
183 google.
icon = QIcon(
QSL(
":icons/sites/google.png"));
184 google.
url =
QSL(
"https://www.google.com/search?client=falkon&q=%s");
186 google.
suggestionsUrl =
QSL(
"https://suggestqueries.google.com/complete/search?output=firefox&q=%s");
193 m_defaultEngine = duck;
204 ic = QIcon::fromTheme(
QSL(
"edit-find"), QIcon(
QSL(
":icons/menu/search-icon.svg")));
210void SearchEnginesManager::engineChangedImage()
212 auto* engine = qobject_cast<OpenSearchEngine*>(sender());
218 for (
const Engine &e : std::as_const(m_allEngines)) {
219 if (e.name == engine->name() &&
220 e.url.contains(engine->searchUrl(
QSL(
"%s")).toString()) &&
221 !engine->image().isNull()
223 int index = m_allEngines.indexOf(e);
225 m_allEngines[index].icon = QIcon(QPixmap::fromImage(engine->image()));
246 if (m_allEngines.contains(engine)) {
250 m_allEngines.append(engine);
257 if (formData.isEmpty())
260 const QString method = formData.value(
QSL(
"method")).toString();
261 bool isPost = method ==
QL1S(
"post");
263 QUrl actionUrl = formData.value(
QSL(
"action")).toUrl();
265 if (actionUrl.isRelative()) {
266 actionUrl = view->url().resolved(actionUrl);
269 QUrl parameterUrl = actionUrl;
272 parameterUrl = QUrl(
QSL(
"http://foo.bar"));
275 const QString &inputName = formData.value(
QSL(
"inputName")).toString();
277 QUrlQuery query(parameterUrl);
278 query.addQueryItem(inputName,
QSL(
"SEARCH"));
280 const QVariantList &inputs = formData.value(
QSL(
"inputs")).toList();
281 for (
const QVariant &pair : inputs) {
282 const QVariantList &list = pair.toList();
283 if (list.size() != 2)
286 const QString &name = list.at(0).toString();
287 const QString &
value = list.at(1).toString();
289 if (name == inputName || name.isEmpty() ||
value.isEmpty())
292 query.addQueryItem(name,
value);
295 parameterUrl.setQuery(query);
298 actionUrl = parameterUrl;
304 engine.
url = QString::fromUtf8(actionUrl.toEncoded());
307 QByteArray data = parameterUrl.toEncoded(QUrl::RemoveScheme);
308 engine.
postData = data.contains(
'?') ? data.mid(data.lastIndexOf(
'?') + 1) : QByteArray();
309 engine.
postData.replace((inputName +
QL1S(
"=SEARCH")).toUtf8(), (inputName +
QL1S(
"=%s")).toUtf8());
311 engine.
url.replace(inputName +
QL1S(
"=SEARCH"), inputName +
QL1S(
"=%s"));
314 EditSearchEngine dialog(SearchEnginesDialog::tr(
"Add Search Engine"), view);
320 if (dialog.exec() != QDialog::Accepted) {
326 engine.
url = dialog.
url();
330 if (engine.
name.isEmpty() || engine.
url.isEmpty()) {
343 en.
url = engine->
searchUrl(
QSL(
"searchstring")).toString().replace(QLatin1String(
"searchstring"), QLatin1String(
"%s"));
345 if (engine->
image().isNull()) {
349 en.
icon = QIcon(QPixmap::fromImage(engine->
image()));
365 if (!url.isValid()) {
369 qApp->setOverrideCursor(Qt::WaitCursor);
371 QNetworkReply* reply =
mApp->networkManager()->get(QNetworkRequest(url));
372 reply->setParent(
this);
373 connect(reply, &QNetworkReply::finished,
this, &SearchEnginesManager::replyFinished);
376void SearchEnginesManager::replyFinished()
378 qApp->restoreOverrideCursor();
380 auto* reply = qobject_cast<QNetworkReply*>(sender());
385 if (reply->error() != QNetworkReply::NoError) {
387 reply->deleteLater();
396 reply->deleteLater();
398 if (checkEngine(engine)) {
400 QMessageBox::information(
nullptr, tr(
"Search Engine Added"), tr(
"Search Engine \"%1\" has been successfully added.").arg(engine->
name()));
407 QString errorString = tr(
"Search Engine is not valid!");
408 QMessageBox::warning(
nullptr, tr(
"Error"), tr(
"Error while adding Search Engine <br><b>Error Message: </b> %1").arg(errorString));
420 if (!m_allEngines.contains(engine)) {
424 m_activeEngine = engine;
432 if (!m_allEngines.contains(engine)) {
436 m_defaultEngine = engine;
444 int index = m_allEngines.indexOf(engine);
451 query.prepare(
QSL(
"DELETE FROM search_engines WHERE name=? AND url=?"));
452 query.bindValue(0, engine.
name);
453 query.bindValue(1, engine.
url);
456 m_allEngines.remove(index);
464 m_allEngines = engines;
483 if (!m_saveScheduled) {
495 query.exec(
QSL(
"DELETE FROM search_engines"));
497 for (
const Engine &en : std::as_const(m_allEngines)) {
498 query.prepare(
QSL(
"INSERT INTO search_engines (name, icon, url, shortcut, suggestionsUrl, suggestionsParameters, postData) VALUES (?, ?, ?, ?, ?, ?, ?)"));
499 query.addBindValue(en.name);
500 query.addBindValue(iconToBase64(en.icon));
501 query.addBindValue(en.url);
502 query.addBindValue(en.shortcut);
503 query.addBindValue(en.suggestionsUrl);
504 query.addBindValue(en.suggestionsParameters);
505 query.addBindValue(en.postData);
void setPostData(const QString &postData)
void setUrl(const QString &url)
void setIcon(const QIcon &icon)
void setName(const QString &name)
static QIcon iconForDomain(const QUrl &url, bool allowNull=false)
static QIcon emptyWebIcon()
A class representing a single search engine described in OpenSearch format.
QUrl searchUrl(const QString &searchTerm) const
QByteArray getSuggestionsParameters()
void setNetworkAccessManager(QNetworkAccessManager *networkAccessManager)
QByteArray getPostData(const QString &searchTerm) const
QString getSuggestionsUrl()
QString name
the name of the engine
A class reading a search engine description from an external source.
OpenSearchEngine * read(QIODevice *device)
QVector< Engine > allEngines()
void editEngine(const Engine &before, const Engine &after)
void defaultEngineChanged()
Engine engineForShortcut(const QString &shortcut)
void addEngine(const QUrl &url)
static QIcon iconForSearchEngine(const QUrl &url)
void setDefaultEngine(const Engine &engine)
void activeEngineChanged()
void setActiveEngine(const Engine &engine)
void addEngineFromForm(const QVariantMap &formData, WebView *view)
void removeEngine(const Engine &engine)
LoadRequest searchResult(const Engine &engine, const QString &string)
SearchEnginesManager(QObject *parent=nullptr)
void setAllEngines(const QVector< Engine > &engines)
void beginGroup(const QString &prefix)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant())
void setValue(const QString &key, const QVariant &defaultValue=QVariant())
static SqlDatabase * instance()
QIcon icon(bool allowNull=false) const
QString title(bool allowEmpty=false) const
int value(const QColor &c)
QByteArray suggestionsParameters