Merge lp:~osomon/webbrowser-app/opensearch into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 589
Merged at revision: 593
Proposed branch: lp:~osomon/webbrowser-app/opensearch
Merge into: lp:webbrowser-app
Diff against target: 459 lines (+220/-10)
15 files modified
README (+19/-0)
src/app/AddressBar.qml (+2/-2)
src/app/Chrome.qml (+2/-1)
src/app/PanelLoader.qml (+14/-1)
src/app/config.h.in (+5/-0)
src/app/webbrowser/Browser.qml (+3/-0)
src/app/webbrowser/CMakeLists.txt (+1/-0)
src/app/webbrowser/searchengine.cpp (+92/-0)
src/app/webbrowser/searchengine.h (+58/-0)
src/app/webbrowser/settings.cpp (+9/-0)
src/app/webbrowser/settings.h (+4/-0)
src/app/webbrowser/webbrowser-app.cpp (+6/-3)
src/app/webbrowser/webbrowser-app.qml (+1/-0)
tests/unittests/qml/tst_AddressBar.qml (+3/-2)
webbrowser-app.qmlproject (+1/-1)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/opensearch
Reviewer Review Type Date Requested Status
Adnane Belmadiaf (community) Approve
PS Jenkins bot continuous-integration Approve
Ubuntu Phablet Team Pending
Review via email: mp+224977@code.launchpad.net

Commit message

Add support for custom search engines defined by the OpenSearch description document format
(http://www.opensearch.org/Specifications/OpenSearch/1.1).

Description of the change

Instructions for testing:

To change the default search engine (google), edit the following file:

    $HOME/.config/webbrowser-app/settings.conf

and add the following line: "searchengine = {value}" where {value} is the name of the search engine that you want to use, e.g. "duckduckgo".

Then ensure that the following directory exists (create it if not):

    $HOME/.local/share/webbrowser-app/searchengines/

and create under it a file called "{value}.xml" (e.g. "duckduckgo.xml"). This file is expected to follow the OpenSearch description document format (see documentation at http://www.opensearch.org/Specifications/OpenSearch/1.1), here is an example:

 <?xml version="1.0" encoding="UTF-8"?>
 <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>Duck Duck Go</ShortName>
  <Description>Use Duck Duck Go to search the Web</Description>
  <Url type="text/html" template="https://duckduckgo.com/?q={searchTerms}&amp;t=canonical" />
 </OpenSearchDescription>

To post a comment you must log in.
lp:~osomon/webbrowser-app/opensearch updated
589. By Olivier Tilloy

Keep {searchTerms} as a placeholder token.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Adnane Belmadiaf (daker) wrote :

Tested and it works.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2014-05-06 12:11:27 +0000
3+++ README 2014-06-30 11:01:41 +0000
4@@ -67,3 +67,22 @@
5 This will generate a coverage report in XML format (coverage.xml) and an
6 interactive human-readable report in HTML format (coveragereport/index.html).
7
8+
9+= Settings =
10+
11+webbrowser-app supports a limited set of custom settings, currently not exposed
12+in the UI. The settings are persisted on disk in the following INI-like file:
13+
14+ $HOME/.config/webbrowser-app/settings.conf
15+
16+The following keys are supported:
17+
18+ - 'homepage': a URL that the browser will open when launched if no URL is
19+ specified on the command line
20+
21+ - 'searchengine': a custom search engine specification, looked up in
22+ $HOME/.local/share/webbrowser-app/searchengines/{value}.xml and following
23+ the OpenSearch document description format
24+ (http://www.opensearch.org/Specifications/OpenSearch/1.1)
25+
26+If any of those keys are not specified, the default hardcoded value is used.
27
28=== modified file 'src/app/AddressBar.qml'
29--- src/app/AddressBar.qml 2014-06-20 15:52:26 +0000
30+++ src/app/AddressBar.qml 2014-06-30 11:01:41 +0000
31@@ -30,6 +30,7 @@
32 signal requestReload()
33 signal requestStop()
34 signal pressAndHold()
35+ property string searchUrl
36
37 height: textField.height
38
39@@ -164,9 +165,8 @@
40 }
41
42 function buildSearchUrl(query) {
43- var searchUrl = "https://google.com/search?client=ubuntu&q=%1&ie=utf-8&oe=utf-8"
44 var terms = query.split(/\s/).map(escapeHtmlEntities)
45- return searchUrl.arg(terms.join("+"))
46+ return addressbar.searchUrl.replace("{searchTerms}", terms.join("+"))
47 }
48
49 function validate() {
50
51=== modified file 'src/app/Chrome.qml'
52--- src/app/Chrome.qml 2014-06-25 16:33:12 +0000
53+++ src/app/Chrome.qml 2014-06-30 11:01:41 +0000
54@@ -1,5 +1,5 @@
55 /*
56- * Copyright 2013 Canonical Ltd.
57+ * Copyright 2013-2014 Canonical Ltd.
58 *
59 * This file is part of webbrowser-app.
60 *
61@@ -27,6 +27,7 @@
62 property alias url: addressBar.actualUrl
63 signal urlValidated(url url)
64 property alias addressBar: addressBar
65+ property alias searchUrl: addressBar.searchUrl
66 property string title
67 property alias loading: addressBar.loading
68 property alias loadProgress: progressBar.value
69
70=== modified file 'src/app/PanelLoader.qml'
71--- src/app/PanelLoader.qml 2014-06-23 10:33:44 +0000
72+++ src/app/PanelLoader.qml 2014-06-30 11:01:41 +0000
73@@ -1,5 +1,5 @@
74 /*
75- * Copyright 2013 Canonical Ltd.
76+ * Copyright 2013-2014 Canonical Ltd.
77 *
78 * This file is part of webbrowser-app.
79 *
80@@ -33,9 +33,22 @@
81 property bool activityButtonVisible: true
82 property bool addressBarVisible: true
83
84+ property string searchUrl
85+ onSearchUrlChanged: internal.setSearchUrl()
86+ onChromeChanged: internal.setSearchUrl()
87+
88 signal urlValidated
89 signal toggleActivityViewClicked
90
91+ QtObject {
92+ id: internal
93+ function setSearchUrl() {
94+ if (chromePanel.chrome !== null) {
95+ chromePanel.chrome.searchUrl = chromePanel.searchUrl
96+ }
97+ }
98+ }
99+
100 function open() {
101 if (panel) {
102 panel.open()
103
104=== modified file 'src/app/config.h.in'
105--- src/app/config.h.in 2013-11-14 16:05:18 +0000
106+++ src/app/config.h.in 2014-06-30 11:01:41 +0000
107@@ -27,6 +27,11 @@
108 #define DEFAULT_HOMEPAGE "http://start.ubuntu.com"
109 #define REMOTE_INSPECTOR_PORT 9221
110
111+#define DEFAULT_SEARCH_ENGINE "google"
112+#define DEFAULT_SEARCH_NAME "Google Search"
113+#define DEFAULT_SEARCH_DESC "Use google.com to search the Web"
114+#define DEFAULT_SEARCH_TEMPLATE "https://google.com/search?client=ubuntu&q={searchTerms}&ie=utf-8&oe=utf-8"
115+
116 inline bool isRunningInstalled()
117 {
118 static bool installed = (QCoreApplication::applicationDirPath() == QDir("@CMAKE_INSTALL_FULL_BINDIR@").canonicalPath());
119
120=== modified file 'src/app/webbrowser/Browser.qml'
121--- src/app/webbrowser/Browser.qml 2014-06-20 15:52:26 +0000
122+++ src/app/webbrowser/Browser.qml 2014-06-30 11:01:41 +0000
123@@ -28,6 +28,8 @@
124 property alias currentIndex: tabsModel.currentIndex
125 currentWebview: tabsModel.currentWebview
126
127+ property QtObject searchEngine
128+
129 actions: [
130 Actions.GoTo {
131 onTriggered: currentWebview.url = value
132@@ -154,6 +156,7 @@
133
134 currentWebview: browser.currentWebview
135 chromeless: browser.chromeless
136+ searchUrl: browser.searchEngine ? browser.searchEngine.template : ""
137
138 anchors {
139 left: parent.left
140
141=== modified file 'src/app/webbrowser/CMakeLists.txt'
142--- src/app/webbrowser/CMakeLists.txt 2014-04-02 13:58:42 +0000
143+++ src/app/webbrowser/CMakeLists.txt 2014-06-30 11:01:41 +0000
144@@ -24,6 +24,7 @@
145 qt5_use_modules(${WEBBROWSER_APP_MODELS} Core Sql)
146
147 set(WEBBROWSER_APP_SRC
148+ searchengine.cpp
149 settings.cpp
150 webbrowser-app.cpp
151 )
152
153=== added file 'src/app/webbrowser/searchengine.cpp'
154--- src/app/webbrowser/searchengine.cpp 1970-01-01 00:00:00 +0000
155+++ src/app/webbrowser/searchengine.cpp 2014-06-30 11:01:41 +0000
156@@ -0,0 +1,92 @@
157+/*
158+ * Copyright 2014 Canonical Ltd.
159+ *
160+ * This file is part of webbrowser-app.
161+ *
162+ * webbrowser-app is free software; you can redistribute it and/or modify
163+ * it under the terms of the GNU General Public License as published by
164+ * the Free Software Foundation; version 3.
165+ *
166+ * webbrowser-app is distributed in the hope that it will be useful,
167+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
168+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
169+ * GNU General Public License for more details.
170+ *
171+ * You should have received a copy of the GNU General Public License
172+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
173+ */
174+
175+// local
176+#include "searchengine.h"
177+
178+// Qt
179+#include <QtCore/QDir>
180+#include <QtCore/QFile>
181+#include <QtCore/QStandardPaths>
182+#include <QtCore/QXmlStreamReader>
183+
184+SearchEngine::SearchEngine(const QString& name, QObject* parent)
185+ : QObject(parent)
186+ , m_name(DEFAULT_SEARCH_NAME)
187+ , m_description(DEFAULT_SEARCH_DESC)
188+ , m_template(DEFAULT_SEARCH_TEMPLATE)
189+{
190+ QString searchenginesSubDir("searchengines");
191+ QString filename = searchenginesSubDir + "/" + name + ".xml";
192+ m_path = QStandardPaths::locate(QStandardPaths::DataLocation, filename);
193+ if (!m_path.isEmpty()) {
194+ parseOpenSearchDescription();
195+ }
196+}
197+
198+SearchEngine::SearchEngine(const SearchEngine& other)
199+{
200+ m_path = other.m_path;
201+ m_name = other.m_name;
202+ m_description = other.m_description;
203+ m_template = other.m_template;
204+}
205+
206+bool SearchEngine::isValid() const
207+{
208+ return (!m_name.isEmpty() && !m_template.isEmpty());
209+}
210+
211+const QString& SearchEngine::name() const
212+{
213+ return m_name;
214+}
215+
216+const QString& SearchEngine::description() const
217+{
218+ return m_description;
219+}
220+
221+const QString& SearchEngine::urlTemplate() const
222+{
223+ return m_template;
224+}
225+
226+void SearchEngine::parseOpenSearchDescription()
227+{
228+ QFile file(m_path);
229+ if (!file.open(QIODevice::ReadOnly)) {
230+ return;
231+ }
232+ QXmlStreamReader parser(&file);
233+ while (!parser.atEnd()) {
234+ parser.readNext();
235+ if (parser.isStartElement()) {
236+ QStringRef name = parser.name();
237+ if (name == "ShortName") {
238+ m_name = parser.readElementText();
239+ } else if (name == "Description") {
240+ m_description = parser.readElementText();
241+ } else if (name == "Url") {
242+ if (parser.attributes().value("type") == "text/html") {
243+ m_template = parser.attributes().value("template").toString();
244+ }
245+ }
246+ }
247+ }
248+}
249
250=== added file 'src/app/webbrowser/searchengine.h'
251--- src/app/webbrowser/searchengine.h 1970-01-01 00:00:00 +0000
252+++ src/app/webbrowser/searchengine.h 2014-06-30 11:01:41 +0000
253@@ -0,0 +1,58 @@
254+/*
255+ * Copyright 2014 Canonical Ltd.
256+ *
257+ * This file is part of webbrowser-app.
258+ *
259+ * webbrowser-app is free software; you can redistribute it and/or modify
260+ * it under the terms of the GNU General Public License as published by
261+ * the Free Software Foundation; version 3.
262+ *
263+ * webbrowser-app is distributed in the hope that it will be useful,
264+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
265+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
266+ * GNU General Public License for more details.
267+ *
268+ * You should have received a copy of the GNU General Public License
269+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
270+ */
271+
272+#ifndef __SEARCH_ENGINE_H__
273+#define __SEARCH_ENGINE_H__
274+
275+// local
276+#include "config.h"
277+
278+// Qt
279+#include <QtCore/QMetaType>
280+#include <QtCore/QObject>
281+#include <QtCore/QString>
282+
283+class SearchEngine : public QObject
284+{
285+ Q_OBJECT
286+
287+ Q_PROPERTY(QString name READ name CONSTANT)
288+ Q_PROPERTY(QString description READ description CONSTANT)
289+ Q_PROPERTY(QString template READ urlTemplate CONSTANT)
290+
291+public:
292+ SearchEngine(const QString& name=DEFAULT_SEARCH_ENGINE, QObject* parent=0);
293+ SearchEngine(const SearchEngine& other);
294+
295+ bool isValid() const;
296+ const QString& name() const;
297+ const QString& description() const;
298+ const QString& urlTemplate() const;
299+
300+private:
301+ QString m_path;
302+ QString m_name;
303+ QString m_description;
304+ QString m_template;
305+
306+ void parseOpenSearchDescription();
307+};
308+
309+Q_DECLARE_METATYPE(SearchEngine);
310+
311+#endif // __SEARCH_ENGINE_H__
312
313=== modified file 'src/app/webbrowser/settings.cpp'
314--- src/app/webbrowser/settings.cpp 2013-11-27 14:28:15 +0000
315+++ src/app/webbrowser/settings.cpp 2014-06-30 11:01:41 +0000
316@@ -19,18 +19,27 @@
317 // local
318 #include "settings.h"
319 #include "config.h"
320+#include "searchengine.h"
321
322 // Qt
323 #include <QtCore/QSettings>
324
325 Settings::Settings(QObject* parent)
326 : QObject(parent)
327+ , m_searchengine(NULL)
328 {
329 QSettings settings(QCoreApplication::applicationName(), "settings");
330 m_homepage = settings.value("homepage", QUrl(DEFAULT_HOMEPAGE)).toUrl();
331+ QString name = settings.value("searchengine", QString(DEFAULT_SEARCH_ENGINE)).toString();
332+ m_searchengine = new SearchEngine(name, this);
333 }
334
335 const QUrl& Settings::homepage() const
336 {
337 return m_homepage;
338 }
339+
340+SearchEngine* Settings::searchEngine() const
341+{
342+ return m_searchengine;
343+}
344
345=== modified file 'src/app/webbrowser/settings.h'
346--- src/app/webbrowser/settings.h 2013-11-25 16:04:05 +0000
347+++ src/app/webbrowser/settings.h 2014-06-30 11:01:41 +0000
348@@ -23,6 +23,8 @@
349 #include <QtCore/QObject>
350 #include <QtCore/QUrl>
351
352+class SearchEngine;
353+
354 /*
355 * Temporary helper class for read-only settings
356 * until Settings support lands in the SDK.
357@@ -35,9 +37,11 @@
358 Settings(QObject* parent=0);
359
360 const QUrl& homepage() const;
361+ SearchEngine* searchEngine() const;
362
363 private:
364 QUrl m_homepage;
365+ SearchEngine* m_searchengine;
366 };
367
368 #endif // __SETTINGS_H__
369
370=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
371--- src/app/webbrowser/webbrowser-app.cpp 2014-05-05 12:01:32 +0000
372+++ src/app/webbrowser/webbrowser-app.cpp 2014-06-30 11:01:41 +0000
373@@ -23,6 +23,7 @@
374 #include "history-timeframe-model.h"
375 #include "history-domainlist-model.h"
376 #include "history-domainlist-chronological-model.h"
377+#include "searchengine.h"
378 #include "settings.h"
379 #include "tabs-model.h"
380 #include "webbrowser-app.h"
381@@ -38,6 +39,7 @@
382 #include <QtCore/QMetaObject>
383 #include <QtCore/QString>
384 #include <QtCore/QTextStream>
385+#include <QtCore/QVariant>
386 #include <QtQml/QtQml>
387 #include <QtQuick/QQuickWindow>
388
389@@ -79,19 +81,20 @@
390 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");
391
392 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
393+ Settings settings;
394 m_window->setProperty("chromeless", m_arguments.contains("--chromeless"));
395+ SearchEngine* searchEngine = settings.searchEngine();
396+ searchEngine->setParent(m_window);
397+ m_window->setProperty("searchEngine", QVariant::fromValue(searchEngine));
398 QList<QUrl> urls = this->urls();
399 if (urls.isEmpty()) {
400- Settings settings;
401 urls.append(settings.homepage());
402 }
403 QObject* browser = (QObject*) m_window;
404 Q_FOREACH(const QUrl& url, urls) {
405 QMetaObject::invokeMethod(browser, "newTab", Q_ARG(QVariant, url), Q_ARG(QVariant, true));
406 }
407-
408 m_component->completeCreate();
409-
410 return true;
411 } else {
412 return false;
413
414=== modified file 'src/app/webbrowser/webbrowser-app.qml'
415--- src/app/webbrowser/webbrowser-app.qml 2014-06-18 16:20:49 +0000
416+++ src/app/webbrowser/webbrowser-app.qml 2014-06-30 11:01:41 +0000
417@@ -21,6 +21,7 @@
418 import Ubuntu.Components 0.1
419
420 Window {
421+ property alias searchEngine: browser.searchEngine
422 property alias chromeless: browser.chromeless
423 property alias developerExtrasEnabled: browser.developerExtrasEnabled
424
425
426=== modified file 'tests/unittests/qml/tst_AddressBar.qml'
427--- tests/unittests/qml/tst_AddressBar.qml 2014-06-06 17:01:55 +0000
428+++ tests/unittests/qml/tst_AddressBar.qml 2014-06-30 11:01:41 +0000
429@@ -70,8 +70,8 @@
430
431 function test_search_url_data() {
432 return [
433- {text: "lorem ipsum dolor sit amet", start: "https://google.com", query: "lorem+ipsum+dolor+sit+amet"},
434- {text: "ubuntu", start: "https://google.com", query: "ubuntu"},
435+ {text: "lorem ipsum dolor sit amet", start: "http://www.ubuntu.com", query: "lorem+ipsum+dolor+sit+amet"},
436+ {text: "ubuntu", start: "http://www.ubuntu.com", query: "ubuntu"},
437 ]
438 }
439
440@@ -115,5 +115,6 @@
441
442 AddressBar {
443 id: addressBar
444+ searchUrl: "http://www.ubuntu.com/search?q={searchTerms}"
445 }
446 }
447
448=== modified file 'webbrowser-app.qmlproject'
449--- webbrowser-app.qmlproject 2014-05-30 16:16:56 +0000
450+++ webbrowser-app.qmlproject 2014-06-30 11:01:41 +0000
451@@ -9,7 +9,7 @@
452
453 Files {
454 directory: "."
455- filter: "CMakeLists.txt"
456+ filter: "CMakeLists.txt;README"
457 }
458
459 Files {

Subscribers

People subscribed via source and target branches

to status/vote changes: