PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/opensearch/searchenginesmanager.cpp

https://github.com/JHooverman/QupZilla
C++ | 340 lines | 251 code | 66 blank | 23 comment | 25 complexity | 51345f09280c61fa19e84199e393edd8 MD5 | raw file
Possible License(s): BSD-3-Clause, MPL-2.0-no-copyleft-exception
  1. /* ============================================================
  2. * QupZilla - WebKit based browser
  3. * Copyright (C) 2010-2012 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. * ============================================================ */
  18. #include "searchenginesmanager.h"
  19. #include "iconprovider.h"
  20. #include "mainapplication.h"
  21. #include "networkmanager.h"
  22. #include "opensearchreader.h"
  23. #include "opensearchengine.h"
  24. #include "databasewriter.h"
  25. #include "settings.h"
  26. #define ENSURE_LOADED if (!m_settingsLoaded) loadSettings();
  27. QIcon SearchEnginesManager::iconForSearchEngine(const QUrl &url)
  28. {
  29. QIcon ic = IconProvider::iconFromImage(mApp->iconProvider()->iconForDomain(url));
  30. if (ic.isNull()) {
  31. ic = QIcon(":icons/menu/search-icon.png");
  32. }
  33. return ic;
  34. }
  35. SearchEnginesManager::SearchEnginesManager()
  36. : QObject()
  37. , m_settingsLoaded(false)
  38. , m_saveScheduled(false)
  39. {
  40. Settings settings;
  41. settings.beginGroup("SearchEngines");
  42. m_startingEngineName = settings.value("activeEngine", "Google").toString();
  43. settings.endGroup();
  44. connect(this, SIGNAL(enginesChanged()), this, SLOT(scheduleSave()));
  45. }
  46. void SearchEnginesManager::loadSettings()
  47. {
  48. m_settingsLoaded = true;
  49. QSqlQuery query;
  50. query.exec("SELECT name, icon, url, shortcut, suggestionsUrl FROM search_engines");
  51. while (query.next()) {
  52. Engine en;
  53. en.name = query.value(0).toString();
  54. en.icon = IconProvider::iconFromBase64(query.value(1).toByteArray());
  55. en.url = query.value(2).toString();
  56. en.shortcut = query.value(3).toString();
  57. en.suggestionsUrl = query.value(4).toString();
  58. m_allEngines.append(en);
  59. }
  60. if (m_allEngines.isEmpty()) {
  61. restoreDefaults();
  62. }
  63. }
  64. SearchEngine SearchEnginesManager::engineForShortcut(const QString &shortcut)
  65. {
  66. Engine returnEngine;
  67. if (shortcut.isEmpty()) {
  68. return returnEngine;
  69. }
  70. foreach(Engine en, m_allEngines) {
  71. if (en.shortcut == shortcut) {
  72. returnEngine = en;
  73. break;
  74. }
  75. }
  76. return returnEngine;
  77. }
  78. QUrl SearchEnginesManager::searchUrl(const Engine &engine, const QString &string)
  79. {
  80. ENSURE_LOADED;
  81. QByteArray url = engine.url.toUtf8();
  82. url.replace("%s", QUrl::toPercentEncoding(string));
  83. return QUrl::fromEncoded(url);
  84. }
  85. QUrl SearchEnginesManager::searchUrl(const QString &string)
  86. {
  87. return searchUrl(m_activeEngine, string);
  88. }
  89. void SearchEnginesManager::restoreDefaults()
  90. {
  91. Engine google;
  92. google.name = "Google";
  93. google.icon = QIcon(":icons/menu/google.png");
  94. google.url = "http://www.google.com/search?client=qupzilla&q=%s";
  95. google.shortcut = "g";
  96. google.suggestionsUrl = "http://suggestqueries.google.com/complete/search?output=firefox&q=%s";
  97. Engine wiki;
  98. wiki.name = "Wikipedia (en)";
  99. wiki.icon = QIcon(":/icons/menu/wikipedia.png");
  100. wiki.url = "http://en.wikipedia.org/wiki/Special:Search?search=%s&fulltext=Search";
  101. wiki.shortcut = "w";
  102. wiki.suggestionsUrl = "http://en.wikipedia.org/w/api.php?action=opensearch&search=%s&namespace=0";
  103. Engine yt;
  104. yt.name = "YouTube";
  105. yt.icon = QIcon(":/icons/menu/youtube.png");
  106. yt.url = "http://www.youtube.com/results?search_query=%s&search=Search";
  107. yt.shortcut = "yt";
  108. yt.suggestionsUrl = "http://suggestqueries.google.com/complete/search?ds=yt&output=firefox&q=%s";
  109. Engine duck;
  110. duck.name = "DuckDuckGo";
  111. duck.icon = QIcon(":/icons/menu/duck.png");
  112. duck.url = "https://duckduckgo.com/?q=%s";
  113. duck.shortcut = "d";
  114. addEngine(google, false);
  115. addEngine(wiki, false);
  116. addEngine(yt, false);
  117. addEngine(duck, false);
  118. emit enginesChanged();
  119. }
  120. void SearchEnginesManager::engineChangedImage()
  121. {
  122. OpenSearchEngine* engine = qobject_cast<OpenSearchEngine*>(sender());
  123. if (!engine) {
  124. return;
  125. }
  126. foreach(Engine e, m_allEngines) {
  127. if (e.name == engine->name() && e.url.contains(engine->searchUrl("%s").toString())
  128. && !engine->image().isNull()) {
  129. e.icon = QIcon(QPixmap::fromImage(engine->image()));
  130. m_allEngines.removeOne(e);
  131. m_allEngines.append(e);
  132. emit enginesChanged();
  133. delete engine;
  134. break;
  135. }
  136. }
  137. }
  138. void SearchEnginesManager::editEngine(const Engine &before, const Engine &after)
  139. {
  140. removeEngine(before);
  141. addEngine(after);
  142. }
  143. void SearchEnginesManager::addEngine(const Engine &engine, bool emitSignal)
  144. {
  145. ENSURE_LOADED;
  146. if (m_allEngines.contains(engine)) {
  147. return;
  148. }
  149. m_allEngines.append(engine);
  150. if (emitSignal) {
  151. emit enginesChanged();
  152. }
  153. }
  154. void SearchEnginesManager::addEngine(OpenSearchEngine* engine)
  155. {
  156. ENSURE_LOADED;
  157. Engine en;
  158. en.name = engine->name();
  159. en.url = engine->searchUrl("searchstring").toString().replace("searchstring", "%s");
  160. if (engine->image().isNull()) {
  161. en.icon = iconForSearchEngine(engine->searchUrl(""));
  162. }
  163. else {
  164. en.icon = QIcon(QPixmap::fromImage(engine->image()));
  165. }
  166. en.suggestionsUrl = engine->getSuggestionsUrl();
  167. en.suggestionsParameters = engine->getSuggestionsParameters();
  168. addEngine(en);
  169. connect(engine, SIGNAL(imageChanged()), this, SLOT(engineChangedImage()));
  170. }
  171. void SearchEnginesManager::addEngine(const QUrl &url)
  172. {
  173. ENSURE_LOADED;
  174. if (!url.isValid()) {
  175. return;
  176. }
  177. qApp->setOverrideCursor(Qt::WaitCursor);
  178. QNetworkReply* reply = mApp->networkManager()->get(QNetworkRequest(url));
  179. reply->setParent(this);
  180. connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
  181. }
  182. void SearchEnginesManager::replyFinished()
  183. {
  184. qApp->restoreOverrideCursor();
  185. QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
  186. if (!reply) {
  187. return;
  188. }
  189. if (reply->error() != QNetworkReply::NoError) {
  190. reply->close();
  191. reply->deleteLater();
  192. return;
  193. }
  194. OpenSearchReader reader;
  195. OpenSearchEngine* engine = reader.read(reply);
  196. engine->setNetworkAccessManager(mApp->networkManager());
  197. reply->close();
  198. reply->deleteLater();
  199. if (checkEngine(engine)) {
  200. addEngine(engine);
  201. QMessageBox::information(0, tr("Search Engine Added"), tr("Search Engine \"%1\" has been successfully added.").arg(engine->name()));
  202. }
  203. }
  204. bool SearchEnginesManager::checkEngine(OpenSearchEngine* engine)
  205. {
  206. if (!engine->isValid()) {
  207. QString errorString = tr("Search Engine is not valid!");
  208. QMessageBox::warning(0, tr("Error"), tr("Error while adding Search Engine <br><b>Error Message: </b> %1").arg(errorString));
  209. return false;
  210. }
  211. return true;
  212. }
  213. void SearchEnginesManager::setActiveEngine(const Engine &engine)
  214. {
  215. ENSURE_LOADED;
  216. if (!m_allEngines.contains(engine)) {
  217. return;
  218. }
  219. m_activeEngine = engine;
  220. emit activeEngineChanged();
  221. }
  222. void SearchEnginesManager::removeEngine(const Engine &engine)
  223. {
  224. ENSURE_LOADED;
  225. if (!m_allEngines.contains(engine)) {
  226. return;
  227. }
  228. QSqlQuery query;
  229. query.prepare("DELETE FROM search_engines WHERE name=? AND url=?");
  230. query.bindValue(0, engine.name);
  231. query.bindValue(1, engine.url);
  232. query.exec();
  233. m_allEngines.removeOne(engine);
  234. emit enginesChanged();
  235. }
  236. void SearchEnginesManager::setAllEngines(const QList<Engine> &engines)
  237. {
  238. ENSURE_LOADED;
  239. m_allEngines = engines;
  240. emit enginesChanged();
  241. }
  242. QList<SearchEngine> SearchEnginesManager::allEngines()
  243. {
  244. ENSURE_LOADED;
  245. return m_allEngines;
  246. }
  247. void SearchEnginesManager::saveSettings()
  248. {
  249. Settings settings;
  250. settings.beginGroup("SearchEngines");
  251. settings.setValue("activeEngine", m_activeEngine.name);
  252. settings.endGroup();
  253. if (!m_saveScheduled) {
  254. return;
  255. }
  256. // Well, this is not the best implementation to do as this is taking some time.
  257. // Actually, it is delaying the quit of app for about a 1 sec on my machine with only
  258. // 5 engines. Another problem is that deleting rows without VACUUM isn't actually freeing
  259. // space in database.
  260. //
  261. // But as long as user is not playing with search engines every run it is acceptable.
  262. QSqlQuery query;
  263. query.exec("DELETE FROM search_engines");
  264. foreach(Engine en, m_allEngines) {
  265. query.prepare("INSERT INTO search_engines (name, icon, url, shortcut, suggestionsUrl, suggestionsParameters) VALUES (?, ?, ?, ?, ?, ?)");
  266. query.bindValue(0, en.name);
  267. query.bindValue(1, IconProvider::iconToBase64(en.icon));
  268. query.bindValue(2, en.url);
  269. query.bindValue(3, en.shortcut);
  270. query.bindValue(4, en.suggestionsUrl);
  271. query.bindValue(5, en.suggestionsParameters);
  272. query.exec();
  273. }
  274. }