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
=== modified file 'README'
--- README 2014-05-06 12:11:27 +0000
+++ README 2014-06-30 11:01:41 +0000
@@ -67,3 +67,22 @@
67This will generate a coverage report in XML format (coverage.xml) and an67This will generate a coverage report in XML format (coverage.xml) and an
68interactive human-readable report in HTML format (coveragereport/index.html).68interactive human-readable report in HTML format (coveragereport/index.html).
6969
70
71= Settings =
72
73webbrowser-app supports a limited set of custom settings, currently not exposed
74in the UI. The settings are persisted on disk in the following INI-like file:
75
76 $HOME/.config/webbrowser-app/settings.conf
77
78The following keys are supported:
79
80 - 'homepage': a URL that the browser will open when launched if no URL is
81 specified on the command line
82
83 - 'searchengine': a custom search engine specification, looked up in
84 $HOME/.local/share/webbrowser-app/searchengines/{value}.xml and following
85 the OpenSearch document description format
86 (http://www.opensearch.org/Specifications/OpenSearch/1.1)
87
88If any of those keys are not specified, the default hardcoded value is used.
7089
=== modified file 'src/app/AddressBar.qml'
--- src/app/AddressBar.qml 2014-06-20 15:52:26 +0000
+++ src/app/AddressBar.qml 2014-06-30 11:01:41 +0000
@@ -30,6 +30,7 @@
30 signal requestReload()30 signal requestReload()
31 signal requestStop()31 signal requestStop()
32 signal pressAndHold()32 signal pressAndHold()
33 property string searchUrl
3334
34 height: textField.height35 height: textField.height
3536
@@ -164,9 +165,8 @@
164 }165 }
165166
166 function buildSearchUrl(query) {167 function buildSearchUrl(query) {
167 var searchUrl = "https://google.com/search?client=ubuntu&q=%1&ie=utf-8&oe=utf-8"
168 var terms = query.split(/\s/).map(escapeHtmlEntities)168 var terms = query.split(/\s/).map(escapeHtmlEntities)
169 return searchUrl.arg(terms.join("+"))169 return addressbar.searchUrl.replace("{searchTerms}", terms.join("+"))
170 }170 }
171171
172 function validate() {172 function validate() {
173173
=== modified file 'src/app/Chrome.qml'
--- src/app/Chrome.qml 2014-06-25 16:33:12 +0000
+++ src/app/Chrome.qml 2014-06-30 11:01:41 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2013-2014 Canonical Ltd.
3 *3 *
4 * This file is part of webbrowser-app.4 * This file is part of webbrowser-app.
5 *5 *
@@ -27,6 +27,7 @@
27 property alias url: addressBar.actualUrl27 property alias url: addressBar.actualUrl
28 signal urlValidated(url url)28 signal urlValidated(url url)
29 property alias addressBar: addressBar29 property alias addressBar: addressBar
30 property alias searchUrl: addressBar.searchUrl
30 property string title31 property string title
31 property alias loading: addressBar.loading32 property alias loading: addressBar.loading
32 property alias loadProgress: progressBar.value33 property alias loadProgress: progressBar.value
3334
=== modified file 'src/app/PanelLoader.qml'
--- src/app/PanelLoader.qml 2014-06-23 10:33:44 +0000
+++ src/app/PanelLoader.qml 2014-06-30 11:01:41 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2013-2014 Canonical Ltd.
3 *3 *
4 * This file is part of webbrowser-app.4 * This file is part of webbrowser-app.
5 *5 *
@@ -33,9 +33,22 @@
33 property bool activityButtonVisible: true33 property bool activityButtonVisible: true
34 property bool addressBarVisible: true34 property bool addressBarVisible: true
3535
36 property string searchUrl
37 onSearchUrlChanged: internal.setSearchUrl()
38 onChromeChanged: internal.setSearchUrl()
39
36 signal urlValidated40 signal urlValidated
37 signal toggleActivityViewClicked41 signal toggleActivityViewClicked
3842
43 QtObject {
44 id: internal
45 function setSearchUrl() {
46 if (chromePanel.chrome !== null) {
47 chromePanel.chrome.searchUrl = chromePanel.searchUrl
48 }
49 }
50 }
51
39 function open() {52 function open() {
40 if (panel) {53 if (panel) {
41 panel.open()54 panel.open()
4255
=== modified file 'src/app/config.h.in'
--- src/app/config.h.in 2013-11-14 16:05:18 +0000
+++ src/app/config.h.in 2014-06-30 11:01:41 +0000
@@ -27,6 +27,11 @@
27#define DEFAULT_HOMEPAGE "http://start.ubuntu.com"27#define DEFAULT_HOMEPAGE "http://start.ubuntu.com"
28#define REMOTE_INSPECTOR_PORT 922128#define REMOTE_INSPECTOR_PORT 9221
2929
30#define DEFAULT_SEARCH_ENGINE "google"
31#define DEFAULT_SEARCH_NAME "Google Search"
32#define DEFAULT_SEARCH_DESC "Use google.com to search the Web"
33#define DEFAULT_SEARCH_TEMPLATE "https://google.com/search?client=ubuntu&q={searchTerms}&ie=utf-8&oe=utf-8"
34
30inline bool isRunningInstalled()35inline bool isRunningInstalled()
31{36{
32 static bool installed = (QCoreApplication::applicationDirPath() == QDir("@CMAKE_INSTALL_FULL_BINDIR@").canonicalPath());37 static bool installed = (QCoreApplication::applicationDirPath() == QDir("@CMAKE_INSTALL_FULL_BINDIR@").canonicalPath());
3338
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2014-06-20 15:52:26 +0000
+++ src/app/webbrowser/Browser.qml 2014-06-30 11:01:41 +0000
@@ -28,6 +28,8 @@
28 property alias currentIndex: tabsModel.currentIndex28 property alias currentIndex: tabsModel.currentIndex
29 currentWebview: tabsModel.currentWebview29 currentWebview: tabsModel.currentWebview
3030
31 property QtObject searchEngine
32
31 actions: [33 actions: [
32 Actions.GoTo {34 Actions.GoTo {
33 onTriggered: currentWebview.url = value35 onTriggered: currentWebview.url = value
@@ -154,6 +156,7 @@
154156
155 currentWebview: browser.currentWebview157 currentWebview: browser.currentWebview
156 chromeless: browser.chromeless158 chromeless: browser.chromeless
159 searchUrl: browser.searchEngine ? browser.searchEngine.template : ""
157160
158 anchors {161 anchors {
159 left: parent.left162 left: parent.left
160163
=== modified file 'src/app/webbrowser/CMakeLists.txt'
--- src/app/webbrowser/CMakeLists.txt 2014-04-02 13:58:42 +0000
+++ src/app/webbrowser/CMakeLists.txt 2014-06-30 11:01:41 +0000
@@ -24,6 +24,7 @@
24qt5_use_modules(${WEBBROWSER_APP_MODELS} Core Sql)24qt5_use_modules(${WEBBROWSER_APP_MODELS} Core Sql)
2525
26set(WEBBROWSER_APP_SRC26set(WEBBROWSER_APP_SRC
27 searchengine.cpp
27 settings.cpp28 settings.cpp
28 webbrowser-app.cpp29 webbrowser-app.cpp
29)30)
3031
=== added file 'src/app/webbrowser/searchengine.cpp'
--- src/app/webbrowser/searchengine.cpp 1970-01-01 00:00:00 +0000
+++ src/app/webbrowser/searchengine.cpp 2014-06-30 11:01:41 +0000
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app 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
19// local
20#include "searchengine.h"
21
22// Qt
23#include <QtCore/QDir>
24#include <QtCore/QFile>
25#include <QtCore/QStandardPaths>
26#include <QtCore/QXmlStreamReader>
27
28SearchEngine::SearchEngine(const QString& name, QObject* parent)
29 : QObject(parent)
30 , m_name(DEFAULT_SEARCH_NAME)
31 , m_description(DEFAULT_SEARCH_DESC)
32 , m_template(DEFAULT_SEARCH_TEMPLATE)
33{
34 QString searchenginesSubDir("searchengines");
35 QString filename = searchenginesSubDir + "/" + name + ".xml";
36 m_path = QStandardPaths::locate(QStandardPaths::DataLocation, filename);
37 if (!m_path.isEmpty()) {
38 parseOpenSearchDescription();
39 }
40}
41
42SearchEngine::SearchEngine(const SearchEngine& other)
43{
44 m_path = other.m_path;
45 m_name = other.m_name;
46 m_description = other.m_description;
47 m_template = other.m_template;
48}
49
50bool SearchEngine::isValid() const
51{
52 return (!m_name.isEmpty() && !m_template.isEmpty());
53}
54
55const QString& SearchEngine::name() const
56{
57 return m_name;
58}
59
60const QString& SearchEngine::description() const
61{
62 return m_description;
63}
64
65const QString& SearchEngine::urlTemplate() const
66{
67 return m_template;
68}
69
70void SearchEngine::parseOpenSearchDescription()
71{
72 QFile file(m_path);
73 if (!file.open(QIODevice::ReadOnly)) {
74 return;
75 }
76 QXmlStreamReader parser(&file);
77 while (!parser.atEnd()) {
78 parser.readNext();
79 if (parser.isStartElement()) {
80 QStringRef name = parser.name();
81 if (name == "ShortName") {
82 m_name = parser.readElementText();
83 } else if (name == "Description") {
84 m_description = parser.readElementText();
85 } else if (name == "Url") {
86 if (parser.attributes().value("type") == "text/html") {
87 m_template = parser.attributes().value("template").toString();
88 }
89 }
90 }
91 }
92}
093
=== added file 'src/app/webbrowser/searchengine.h'
--- src/app/webbrowser/searchengine.h 1970-01-01 00:00:00 +0000
+++ src/app/webbrowser/searchengine.h 2014-06-30 11:01:41 +0000
@@ -0,0 +1,58 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app 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
19#ifndef __SEARCH_ENGINE_H__
20#define __SEARCH_ENGINE_H__
21
22// local
23#include "config.h"
24
25// Qt
26#include <QtCore/QMetaType>
27#include <QtCore/QObject>
28#include <QtCore/QString>
29
30class SearchEngine : public QObject
31{
32 Q_OBJECT
33
34 Q_PROPERTY(QString name READ name CONSTANT)
35 Q_PROPERTY(QString description READ description CONSTANT)
36 Q_PROPERTY(QString template READ urlTemplate CONSTANT)
37
38public:
39 SearchEngine(const QString& name=DEFAULT_SEARCH_ENGINE, QObject* parent=0);
40 SearchEngine(const SearchEngine& other);
41
42 bool isValid() const;
43 const QString& name() const;
44 const QString& description() const;
45 const QString& urlTemplate() const;
46
47private:
48 QString m_path;
49 QString m_name;
50 QString m_description;
51 QString m_template;
52
53 void parseOpenSearchDescription();
54};
55
56Q_DECLARE_METATYPE(SearchEngine);
57
58#endif // __SEARCH_ENGINE_H__
059
=== modified file 'src/app/webbrowser/settings.cpp'
--- src/app/webbrowser/settings.cpp 2013-11-27 14:28:15 +0000
+++ src/app/webbrowser/settings.cpp 2014-06-30 11:01:41 +0000
@@ -19,18 +19,27 @@
19// local19// local
20#include "settings.h"20#include "settings.h"
21#include "config.h"21#include "config.h"
22#include "searchengine.h"
2223
23// Qt24// Qt
24#include <QtCore/QSettings>25#include <QtCore/QSettings>
2526
26Settings::Settings(QObject* parent)27Settings::Settings(QObject* parent)
27 : QObject(parent)28 : QObject(parent)
29 , m_searchengine(NULL)
28{30{
29 QSettings settings(QCoreApplication::applicationName(), "settings");31 QSettings settings(QCoreApplication::applicationName(), "settings");
30 m_homepage = settings.value("homepage", QUrl(DEFAULT_HOMEPAGE)).toUrl();32 m_homepage = settings.value("homepage", QUrl(DEFAULT_HOMEPAGE)).toUrl();
33 QString name = settings.value("searchengine", QString(DEFAULT_SEARCH_ENGINE)).toString();
34 m_searchengine = new SearchEngine(name, this);
31}35}
3236
33const QUrl& Settings::homepage() const37const QUrl& Settings::homepage() const
34{38{
35 return m_homepage;39 return m_homepage;
36}40}
41
42SearchEngine* Settings::searchEngine() const
43{
44 return m_searchengine;
45}
3746
=== modified file 'src/app/webbrowser/settings.h'
--- src/app/webbrowser/settings.h 2013-11-25 16:04:05 +0000
+++ src/app/webbrowser/settings.h 2014-06-30 11:01:41 +0000
@@ -23,6 +23,8 @@
23#include <QtCore/QObject>23#include <QtCore/QObject>
24#include <QtCore/QUrl>24#include <QtCore/QUrl>
2525
26class SearchEngine;
27
26/*28/*
27 * Temporary helper class for read-only settings29 * Temporary helper class for read-only settings
28 * until Settings support lands in the SDK.30 * until Settings support lands in the SDK.
@@ -35,9 +37,11 @@
35 Settings(QObject* parent=0);37 Settings(QObject* parent=0);
3638
37 const QUrl& homepage() const;39 const QUrl& homepage() const;
40 SearchEngine* searchEngine() const;
3841
39private:42private:
40 QUrl m_homepage;43 QUrl m_homepage;
44 SearchEngine* m_searchengine;
41};45};
4246
43#endif // __SETTINGS_H__47#endif // __SETTINGS_H__
4448
=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
--- src/app/webbrowser/webbrowser-app.cpp 2014-05-05 12:01:32 +0000
+++ src/app/webbrowser/webbrowser-app.cpp 2014-06-30 11:01:41 +0000
@@ -23,6 +23,7 @@
23#include "history-timeframe-model.h"23#include "history-timeframe-model.h"
24#include "history-domainlist-model.h"24#include "history-domainlist-model.h"
25#include "history-domainlist-chronological-model.h"25#include "history-domainlist-chronological-model.h"
26#include "searchengine.h"
26#include "settings.h"27#include "settings.h"
27#include "tabs-model.h"28#include "tabs-model.h"
28#include "webbrowser-app.h"29#include "webbrowser-app.h"
@@ -38,6 +39,7 @@
38#include <QtCore/QMetaObject>39#include <QtCore/QMetaObject>
39#include <QtCore/QString>40#include <QtCore/QString>
40#include <QtCore/QTextStream>41#include <QtCore/QTextStream>
42#include <QtCore/QVariant>
41#include <QtQml/QtQml>43#include <QtQml/QtQml>
42#include <QtQuick/QQuickWindow>44#include <QtQuick/QQuickWindow>
4345
@@ -79,19 +81,20 @@
79 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");81 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");
8082
81 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {83 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
84 Settings settings;
82 m_window->setProperty("chromeless", m_arguments.contains("--chromeless"));85 m_window->setProperty("chromeless", m_arguments.contains("--chromeless"));
86 SearchEngine* searchEngine = settings.searchEngine();
87 searchEngine->setParent(m_window);
88 m_window->setProperty("searchEngine", QVariant::fromValue(searchEngine));
83 QList<QUrl> urls = this->urls();89 QList<QUrl> urls = this->urls();
84 if (urls.isEmpty()) {90 if (urls.isEmpty()) {
85 Settings settings;
86 urls.append(settings.homepage());91 urls.append(settings.homepage());
87 }92 }
88 QObject* browser = (QObject*) m_window;93 QObject* browser = (QObject*) m_window;
89 Q_FOREACH(const QUrl& url, urls) {94 Q_FOREACH(const QUrl& url, urls) {
90 QMetaObject::invokeMethod(browser, "newTab", Q_ARG(QVariant, url), Q_ARG(QVariant, true));95 QMetaObject::invokeMethod(browser, "newTab", Q_ARG(QVariant, url), Q_ARG(QVariant, true));
91 }96 }
92
93 m_component->completeCreate();97 m_component->completeCreate();
94
95 return true;98 return true;
96 } else {99 } else {
97 return false;100 return false;
98101
=== modified file 'src/app/webbrowser/webbrowser-app.qml'
--- src/app/webbrowser/webbrowser-app.qml 2014-06-18 16:20:49 +0000
+++ src/app/webbrowser/webbrowser-app.qml 2014-06-30 11:01:41 +0000
@@ -21,6 +21,7 @@
21import Ubuntu.Components 0.121import Ubuntu.Components 0.1
2222
23Window {23Window {
24 property alias searchEngine: browser.searchEngine
24 property alias chromeless: browser.chromeless25 property alias chromeless: browser.chromeless
25 property alias developerExtrasEnabled: browser.developerExtrasEnabled26 property alias developerExtrasEnabled: browser.developerExtrasEnabled
2627
2728
=== modified file 'tests/unittests/qml/tst_AddressBar.qml'
--- tests/unittests/qml/tst_AddressBar.qml 2014-06-06 17:01:55 +0000
+++ tests/unittests/qml/tst_AddressBar.qml 2014-06-30 11:01:41 +0000
@@ -70,8 +70,8 @@
7070
71 function test_search_url_data() {71 function test_search_url_data() {
72 return [72 return [
73 {text: "lorem ipsum dolor sit amet", start: "https://google.com", query: "lorem+ipsum+dolor+sit+amet"},73 {text: "lorem ipsum dolor sit amet", start: "http://www.ubuntu.com", query: "lorem+ipsum+dolor+sit+amet"},
74 {text: "ubuntu", start: "https://google.com", query: "ubuntu"},74 {text: "ubuntu", start: "http://www.ubuntu.com", query: "ubuntu"},
75 ]75 ]
76 }76 }
7777
@@ -115,5 +115,6 @@
115115
116 AddressBar {116 AddressBar {
117 id: addressBar117 id: addressBar
118 searchUrl: "http://www.ubuntu.com/search?q={searchTerms}"
118 }119 }
119}120}
120121
=== modified file 'webbrowser-app.qmlproject'
--- webbrowser-app.qmlproject 2014-05-30 16:16:56 +0000
+++ webbrowser-app.qmlproject 2014-06-30 11:01:41 +0000
@@ -9,7 +9,7 @@
99
10 Files {10 Files {
11 directory: "."11 directory: "."
12 filter: "CMakeLists.txt"12 filter: "CMakeLists.txt;README"
13 }13 }
1414
15 Files {15 Files {

Subscribers

People subscribed via source and target branches

to status/vote changes: