Merge lp:~jamesh/unity-scope-gdrive/previews into lp:~submarine/unity-scope-gdrive/libunity-7-compatible
- previews
- Merge into libunity-7-compatible
Status: | Merged |
---|---|
Approved by: | Michal Hruby |
Approved revision: | 52 |
Merged at revision: | 47 |
Proposed branch: | lp:~jamesh/unity-scope-gdrive/previews |
Merge into: | lp:~submarine/unity-scope-gdrive/libunity-7-compatible |
Diff against target: |
534 lines (+290/-86) 6 files modified
debian/control (+7/-0) debian/rules (+3/-0) gdrive.scope (+1/-1) test_scope.py (+142/-0) unity-scope-gdrive.service (+1/-1) unity_gdrive_daemon.py (+136/-84) |
To merge this branch: | bzr merge lp:~jamesh/unity-scope-gdrive/previews |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+162505@code.launchpad.net |
Commit message
Convert to the new scope API and add a preview.
Description of the change
Convert scope to new API, and add a simple preview showing author, modification date and whether the document has been starred or shared.
PS Jenkins bot (ps-jenkins) wrote : | # |
Michal Hruby (mhr3) wrote : | # |
Could we get some tests? Or is that too complex with the authentication?
- 50. By James Henstridge
-
Use InfoHint to construct the preview.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:50
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 51. By James Henstridge
-
Add a test for the search functionality. Unfortunately we need to use a
stub document since GData.Parsable.new_from_ xml() segfaults for
GData.Feed subtypes.The preview test is also skipped because I can't initialise the metadata
dictionary. - 52. By James Henstridge
-
Enable tests in packaging.
James Henstridge (jamesh) wrote : | # |
I've added some basic tests for the search functionality, although it stubs out all the account discovery code and provides a fake DocumentsEntry class.
My original plan was to use GData.Parsable.
The previewer test is also disabled because I wasn't able to initialise Unity.ScopeResu
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:52
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'debian/control' | |||
2 | --- debian/control 2013-03-15 10:09:23 +0000 | |||
3 | +++ debian/control 2013-05-09 07:42:25 +0000 | |||
4 | @@ -7,6 +7,13 @@ | |||
5 | 7 | pkg-config, | 7 | pkg-config, |
6 | 8 | python3, | 8 | python3, |
7 | 9 | python3-distutils-extra, | 9 | python3-distutils-extra, |
8 | 10 | python3-nose, | ||
9 | 11 | python3-gi, | ||
10 | 12 | gir1.2-glib-2.0, | ||
11 | 13 | gir1.2-accounts-1.0, | ||
12 | 14 | gir1.2-signon-1.0, | ||
13 | 15 | gir1.2-gdata-0.0, | ||
14 | 16 | gir1.2-unity-5.0 (>= 6.91), | ||
15 | 10 | Standards-Version: 3.9.3 | 17 | Standards-Version: 3.9.3 |
16 | 11 | Homepage: https://launchpad.net/unity-scope-gdrive | 18 | Homepage: https://launchpad.net/unity-scope-gdrive |
17 | 12 | # If you aren't a member of ~online-accounts but need to upload packaging | 19 | # If you aren't a member of ~online-accounts but need to upload packaging |
18 | 13 | 20 | ||
19 | === modified file 'debian/rules' | |||
20 | --- debian/rules 2012-11-30 16:02:18 +0000 | |||
21 | +++ debian/rules 2013-05-09 07:42:25 +0000 | |||
22 | @@ -13,6 +13,9 @@ | |||
23 | 13 | override_dh_auto_build: | 13 | override_dh_auto_build: |
24 | 14 | python3 setup.py build | 14 | python3 setup.py build |
25 | 15 | 15 | ||
26 | 16 | override_dh_auto_test: | ||
27 | 17 | nosetests3 | ||
28 | 18 | |||
29 | 16 | override_dh_auto_install: | 19 | override_dh_auto_install: |
30 | 17 | python3 setup.py install --root=$(CURDIR)/debian/unity-scope-gdrive --install-layout=deb | 20 | python3 setup.py install --root=$(CURDIR)/debian/unity-scope-gdrive --install-layout=deb |
31 | 18 | 21 | ||
32 | 19 | 22 | ||
33 | === modified file 'gdrive.scope' | |||
34 | --- gdrive.scope 2013-05-01 17:52:08 +0000 | |||
35 | +++ gdrive.scope 2013-05-09 07:42:25 +0000 | |||
36 | @@ -4,7 +4,7 @@ | |||
37 | 4 | Icon=/usr/share/icons/unity-icon-theme/places/svg/service-gdrive.svg | 4 | Icon=/usr/share/icons/unity-icon-theme/places/svg/service-gdrive.svg |
38 | 5 | Keywords=gdrive;doc;drive;google; | 5 | Keywords=gdrive;doc;drive;google; |
39 | 6 | Loader=/usr/share/unity-scopes/gdrive/unity_gdrive_daemon.py | 6 | Loader=/usr/share/unity-scopes/gdrive/unity_gdrive_daemon.py |
41 | 7 | RequiredMetadata= | 7 | RequiredMetadata=author[s];shared[b];starred[b];updated[i] |
42 | 8 | OptionalMetadata= | 8 | OptionalMetadata= |
43 | 9 | RemoteContent=true | 9 | RemoteContent=true |
44 | 10 | Type=file | 10 | Type=file |
45 | 11 | 11 | ||
46 | === added file 'test_scope.py' | |||
47 | --- test_scope.py 1970-01-01 00:00:00 +0000 | |||
48 | +++ test_scope.py 2013-05-09 07:42:25 +0000 | |||
49 | @@ -0,0 +1,142 @@ | |||
50 | 1 | import unittest | ||
51 | 2 | |||
52 | 3 | from gi.repository import GData, GLib, Unity | ||
53 | 4 | |||
54 | 5 | import unity_gdrive_daemon as gdrive | ||
55 | 6 | |||
56 | 7 | |||
57 | 8 | class ResultSet(Unity.ResultSet): | ||
58 | 9 | def __init__(self): | ||
59 | 10 | Unity.ResultSet.__init__(self) | ||
60 | 11 | self.results = [] | ||
61 | 12 | |||
62 | 13 | def do_add_result(self, result): | ||
63 | 14 | self.results.append(dict(uri=result.uri, | ||
64 | 15 | icon=result.icon_hint, | ||
65 | 16 | category=result.category, | ||
66 | 17 | result_type=result.result_type, | ||
67 | 18 | mimetype=result.mimetype, | ||
68 | 19 | title=result.title, | ||
69 | 20 | comment=result.comment, | ||
70 | 21 | dnd_uri=result.dnd_uri, | ||
71 | 22 | author=result.metadata['author'].get_string(), | ||
72 | 23 | shared=result.metadata['shared'].get_boolean(), | ||
73 | 24 | starred=result.metadata['starred'].get_boolean(), | ||
74 | 25 | updated=result.metadata['updated'].get_int32())) | ||
75 | 26 | |||
76 | 27 | |||
77 | 28 | class FakeDocumentsEntry: | ||
78 | 29 | """A fake GData.DocumentsEntry""" | ||
79 | 30 | |||
80 | 31 | def get_resource_id(self): | ||
81 | 32 | return 'spreadsheet:abcdefghij' | ||
82 | 33 | |||
83 | 34 | def look_up_link(self, rel): | ||
84 | 35 | assert rel == GData.LINK_ALTERNATE | ||
85 | 36 | return GData.Link.new("http://example.com/view", rel) | ||
86 | 37 | |||
87 | 38 | def get_updated(self): | ||
88 | 39 | return 1000000000 | ||
89 | 40 | |||
90 | 41 | def get_title(self): | ||
91 | 42 | return "Fake title" | ||
92 | 43 | |||
93 | 44 | def get_authors(self): | ||
94 | 45 | return [GData.Author.new('john.smith', '', 'john.smith@example.com')] | ||
95 | 46 | |||
96 | 47 | def get_categories(self): | ||
97 | 48 | return [GData.Category.new( | ||
98 | 49 | 'http://schemas.google.com/g/2005/labels#starred', | ||
99 | 50 | 'http://schemas.google.com/g/2005/labels', 'starred')] | ||
100 | 51 | |||
101 | 52 | def get_content_uri(self): | ||
102 | 53 | return "http://example.com/export" | ||
103 | 54 | |||
104 | 55 | |||
105 | 56 | class StubGDocsAccount(gdrive.GDocsAccount): | ||
106 | 57 | def __init__(self): | ||
107 | 58 | self._enabled = True | ||
108 | 59 | |||
109 | 60 | def get_doc_list(self, search, filters, is_global): | ||
110 | 61 | # It would be nice if we could use | ||
111 | 62 | # GData.Parsable.new_from_xml() to generate the feed from XML, | ||
112 | 63 | # but it segfaults. | ||
113 | 64 | return [FakeDocumentsEntry()] | ||
114 | 65 | |||
115 | 66 | |||
116 | 67 | def fake_setup_accounts(self): | ||
117 | 68 | self._gdocs_accounts.append(StubGDocsAccount()) | ||
118 | 69 | |||
119 | 70 | |||
120 | 71 | class GDriveTests(unittest.TestCase): | ||
121 | 72 | def setUp(self): | ||
122 | 73 | super(GDriveTests, self).setUp() | ||
123 | 74 | self._orig_setup_accounts = gdrive.GDriveScope.setup_accounts | ||
124 | 75 | gdrive.GDriveScope.setup_accounts = fake_setup_accounts | ||
125 | 76 | |||
126 | 77 | def tearDown(self): | ||
127 | 78 | gdrive.GDriveScope.setup_accounts = self._orig_setup_accounts | ||
128 | 79 | super(GDriveTests, self).tearDown() | ||
129 | 80 | |||
130 | 81 | def perform_query(self, query): | ||
131 | 82 | scope = gdrive.GDriveScope() | ||
132 | 83 | filter_set = scope.get_filters() | ||
133 | 84 | result_set = ResultSet() | ||
134 | 85 | context = Unity.SearchContext.create( | ||
135 | 86 | query, 0, filter_set, None, result_set, None) | ||
136 | 87 | |||
137 | 88 | search = scope.create_search_for_query(context) | ||
138 | 89 | search.run() | ||
139 | 90 | return result_set.results | ||
140 | 91 | |||
141 | 92 | def test_get_categories(self): | ||
142 | 93 | scope = gdrive.GDriveScope() | ||
143 | 94 | category_set = scope.get_categories() | ||
144 | 95 | self.assertEqual( | ||
145 | 96 | [cat.props.id for cat in category_set.get_categories()], | ||
146 | 97 | ['global', 'recent', 'downloads', 'folders']) | ||
147 | 98 | |||
148 | 99 | def test_get_filters(self): | ||
149 | 100 | scope = gdrive.GDriveScope() | ||
150 | 101 | filter_set = scope.get_filters() | ||
151 | 102 | self.assertEqual( | ||
152 | 103 | [filter.props.id for filter in filter_set.get_filters()], | ||
153 | 104 | ['modified', 'type']) | ||
154 | 105 | |||
155 | 106 | def test_search(self): | ||
156 | 107 | results = self.perform_query("foo") | ||
157 | 108 | self.assertEqual(len(results), 1) | ||
158 | 109 | self.assertEqual(results[0], dict( | ||
159 | 110 | uri='http://example.com/view', | ||
160 | 111 | icon='x-office-spreadsheet', | ||
161 | 112 | category=1, | ||
162 | 113 | result_type=Unity.ResultType.PERSONAL, | ||
163 | 114 | mimetype='text/html', | ||
164 | 115 | title='Fake title', | ||
165 | 116 | comment='spreadsheet', | ||
166 | 117 | dnd_uri='http://example.com/export', | ||
167 | 118 | author='john.smith', | ||
168 | 119 | shared=False, | ||
169 | 120 | starred=True, | ||
170 | 121 | updated=1000000000)) | ||
171 | 122 | |||
172 | 123 | @unittest.skip("Can not set up metadata in ScopeResult") | ||
173 | 124 | def test_preview(self): | ||
174 | 125 | result = Unity.ScopeResult.create( | ||
175 | 126 | uri='http://example.com/view', | ||
176 | 127 | icon_hint='x-office-spreadsheet', | ||
177 | 128 | category=1, | ||
178 | 129 | result_type=Unity.ResultType.PERSONAL, | ||
179 | 130 | mimetype='text/html', | ||
180 | 131 | title='Fake title', | ||
181 | 132 | comment='spreadsheet', | ||
182 | 133 | dnd_uri='http://example.com/export', | ||
183 | 134 | metadata={ | ||
184 | 135 | 'author': GLib.Variant('s', 'john.smith'), | ||
185 | 136 | 'shared': GLib.Variant('b', False), | ||
186 | 137 | 'starred': GLib.Variant('b', True), | ||
187 | 138 | 'updated': GLib.Variant('i', 1000000000)}) | ||
188 | 139 | metadata = Unity.SearchMetadata() | ||
189 | 140 | scope = gdrive.GDriveScope() | ||
190 | 141 | previewer = scope.create_previewer(result, metadata) | ||
191 | 142 | preview = previewer.run() | ||
192 | 0 | 143 | ||
193 | === modified file 'unity-scope-gdrive.service' | |||
194 | --- unity-scope-gdrive.service 2013-03-22 15:25:03 +0000 | |||
195 | +++ unity-scope-gdrive.service 2013-05-09 07:42:25 +0000 | |||
196 | @@ -1,3 +1,3 @@ | |||
197 | 1 | [D-BUS Service] | 1 | [D-BUS Service] |
198 | 2 | Name=com.canonical.Unity.Scope.File.Gdrive | 2 | Name=com.canonical.Unity.Scope.File.Gdrive |
200 | 3 | Exec=/usr/share/unity-scopes/gdrive/unity_gdrive_daemon.py | 3 | Exec=/usr/bin/python3 /usr/share/unity-scopes/scope-runner-dbus.py /usr/share/unity-scopes/gdrive/unity_gdrive_daemon.py |
201 | 4 | 4 | ||
202 | === modified file 'unity_gdrive_daemon.py' (properties changed: +x to -x) | |||
203 | --- unity_gdrive_daemon.py 2013-03-22 15:25:03 +0000 | |||
204 | +++ unity_gdrive_daemon.py 2013-05-09 07:42:25 +0000 | |||
205 | @@ -1,4 +1,5 @@ | |||
206 | 1 | #! /usr/bin/python3 | 1 | #! /usr/bin/python3 |
207 | 2 | # -*- mode: python; python-indent: 2 -*- | ||
208 | 2 | # | 3 | # |
209 | 3 | # Copyright 2012 Canonical Ltd. | 4 | # Copyright 2012 Canonical Ltd. |
210 | 4 | # | 5 | # |
211 | @@ -7,27 +8,26 @@ | |||
212 | 7 | # GPLv3 | 8 | # GPLv3 |
213 | 8 | # | 9 | # |
214 | 9 | 10 | ||
215 | 11 | from datetime import datetime, timedelta | ||
216 | 12 | import gettext | ||
217 | 13 | import locale | ||
218 | 10 | import sys | 14 | import sys |
219 | 15 | import time | ||
220 | 16 | |||
221 | 11 | from gi.repository import GLib, GObject, Gio | 17 | from gi.repository import GLib, GObject, Gio |
222 | 12 | from gi.repository import Accounts, Signon | 18 | from gi.repository import Accounts, Signon |
223 | 13 | from gi.repository import GData | 19 | from gi.repository import GData |
225 | 14 | from gi.repository import Unity, UnityExtras | 20 | from gi.repository import Unity |
226 | 15 | 21 | ||
227 | 16 | from datetime import datetime, timedelta | ||
228 | 17 | import gettext | ||
229 | 18 | import time | ||
230 | 19 | 22 | ||
231 | 20 | APP_NAME = "unity-scope-gdrive" | 23 | APP_NAME = "unity-scope-gdrive" |
232 | 21 | LOCAL_PATH = "/usr/share/locale/" | 24 | LOCAL_PATH = "/usr/share/locale/" |
233 | 22 | 25 | ||
234 | 26 | locale.setlocale(locale.LC_ALL, '') | ||
235 | 23 | gettext.bindtextdomain(APP_NAME, LOCAL_PATH) | 27 | gettext.bindtextdomain(APP_NAME, LOCAL_PATH) |
236 | 24 | gettext.textdomain(APP_NAME) | 28 | gettext.textdomain(APP_NAME) |
237 | 25 | _ = gettext.gettext | 29 | _ = gettext.gettext |
238 | 26 | 30 | ||
239 | 27 | # | ||
240 | 28 | # The primary bus name we grab *must* match what we specify in our .scope file | ||
241 | 29 | # | ||
242 | 30 | BUS_NAME = "com.canonical.Unity.Scope.File.Gdrive" | ||
243 | 31 | # Map Google Docs types to the values of the "type" filter | 31 | # Map Google Docs types to the values of the "type" filter |
244 | 32 | TYPE_MAP = { | 32 | TYPE_MAP = { |
245 | 33 | "document": "documents", | 33 | "document": "documents", |
246 | @@ -38,34 +38,34 @@ | |||
247 | 38 | } | 38 | } |
248 | 39 | THEME = "/usr/share/icons/unity-icon-theme/places/svg/" | 39 | THEME = "/usr/share/icons/unity-icon-theme/places/svg/" |
249 | 40 | 40 | ||
258 | 41 | class Daemon: | 41 | |
259 | 42 | 42 | class GDriveScope(Unity.AbstractScope): | |
260 | 43 | def __init__ (self): | 43 | __g_type_name__ = "GDriveScope" |
261 | 44 | self._scope = Unity.DeprecatedScope.new ("/com/canonical/unity/scope/file/gdrive", "gdrive") | 44 | |
262 | 45 | self._scope.search_in_global = True; | 45 | def __init__(self): |
263 | 46 | self._preferences = Unity.PreferencesManager.get_default() | 46 | super(GDriveScope, self).__init__() |
264 | 47 | self._preferences.connect ("notify::remote-content-search", | 47 | self.search_in_global = True; |
257 | 48 | self._on_filters_or_preferences_changed); | ||
265 | 49 | 48 | ||
266 | 50 | self._gdocs_accounts = [] | 49 | self._gdocs_accounts = [] |
285 | 51 | try: | 50 | self.setup_accounts() |
286 | 52 | self._account_manager = Accounts.Manager.new_for_service_type("documents") | 51 | |
287 | 53 | except TypeError as e: | 52 | def do_get_group_name(self): |
288 | 54 | print ("Couldn't start account manager, not initialising: %s" % e) | 53 | # The primary bus name we grab *must* match what we specify in our |
289 | 55 | sys.exit(0) | 54 | # .scope file |
290 | 56 | self._account_manager.connect("enabled-event", self._on_enabled_event); | 55 | return "com.canonical.Unity.Scope.File.Gdrive" |
291 | 57 | for account in self._account_manager.get_enabled_account_services(): | 56 | |
292 | 58 | self.add_account_service(account) | 57 | def do_get_unique_name(self): |
293 | 59 | 58 | return "/com/canonical/unity/scope/file/gdrive" | |
294 | 60 | # Listen for changes and requests | 59 | |
295 | 61 | self._scope.connect ("search-changed", self._on_search_changed) | 60 | def do_get_schema(self): |
296 | 62 | 61 | schema = Unity.Schema.new() | |
297 | 63 | # This allows us to re-do the search if any parameter on a filter has changed | 62 | schema.add_field('author', 's', Unity.SchemaFieldType.REQUIRED) |
298 | 64 | # Though it's possible to connect to a more-specific changed signal on each | 63 | schema.add_field('shared', 'b', Unity.SchemaFieldType.REQUIRED) |
299 | 65 | # Fitler, as we re-do the search anyway, this catch-all signal is perfect for | 64 | schema.add_field('starred', 'b', Unity.SchemaFieldType.REQUIRED) |
300 | 66 | # us. | 65 | schema.add_field('updated', 'i', Unity.SchemaFieldType.REQUIRED) |
301 | 67 | self._scope.connect ("notify::filtering", self._on_filters_or_preferences_changed); | 66 | return schema |
302 | 68 | 67 | ||
303 | 68 | def do_get_filters(self): | ||
304 | 69 | filters = Unity.FilterSet.new() | 69 | filters = Unity.FilterSet.new() |
305 | 70 | f = Unity.RadioOptionFilter.new ("modified", _("Last modified"), Gio.ThemedIcon.new("input-keyboard-symbolic"), False) | 70 | f = Unity.RadioOptionFilter.new ("modified", _("Last modified"), Gio.ThemedIcon.new("input-keyboard-symbolic"), False) |
306 | 71 | f.add_option ("last-7-days", _("Last 7 days"), None) | 71 | f.add_option ("last-7-days", _("Last 7 days"), None) |
307 | @@ -81,7 +81,9 @@ | |||
308 | 81 | f2.add_option ("presentations", _("Presentations"), None) | 81 | f2.add_option ("presentations", _("Presentations"), None) |
309 | 82 | f2.add_option ("other", _("Other"), None) | 82 | f2.add_option ("other", _("Other"), None) |
310 | 83 | filters.add (f2) | 83 | filters.add (f2) |
312 | 84 | self._scope.props.filters = filters | 84 | return filters |
313 | 85 | |||
314 | 86 | def do_get_categories(self): | ||
315 | 85 | cats = Unity.CategorySet.new() | 87 | cats = Unity.CategorySet.new() |
316 | 86 | cats.add (Unity.Category.new ('global', | 88 | cats.add (Unity.Category.new ('global', |
317 | 87 | _("Files & Folders"), | 89 | _("Files & Folders"), |
318 | @@ -99,8 +101,26 @@ | |||
319 | 99 | _("Folders"), | 101 | _("Folders"), |
320 | 100 | Gio.ThemedIcon.new(THEME + "group-folders.svg"), | 102 | Gio.ThemedIcon.new(THEME + "group-folders.svg"), |
321 | 101 | Unity.CategoryRenderer.VERTICAL_TILE)) | 103 | Unity.CategoryRenderer.VERTICAL_TILE)) |
324 | 102 | self._scope.props.categories = cats | 104 | return cats |
325 | 103 | self._scope.export() | 105 | |
326 | 106 | def do_create_search_for_query(self, search_context): | ||
327 | 107 | return GDriveScopeSearch(search_context, self._gdocs_accounts) | ||
328 | 108 | |||
329 | 109 | def do_create_previewer(self, result, metadata): | ||
330 | 110 | previewer = GDriveScopePreviewer() | ||
331 | 111 | previewer.set_scope_result(result) | ||
332 | 112 | previewer.set_search_metadata(metadata) | ||
333 | 113 | return previewer | ||
334 | 114 | |||
335 | 115 | def setup_accounts(self): | ||
336 | 116 | try: | ||
337 | 117 | self._account_manager = Accounts.Manager.new_for_service_type("documents") | ||
338 | 118 | except TypeError as e: | ||
339 | 119 | print ("Couldn't start account manager, not initialising: %s" % e) | ||
340 | 120 | sys.exit(0) | ||
341 | 121 | self._account_manager.connect("enabled-event", self._on_enabled_event); | ||
342 | 122 | for account in self._account_manager.get_enabled_account_services(): | ||
343 | 123 | self.add_account_service(account) | ||
344 | 104 | 124 | ||
345 | 105 | def _on_enabled_event (self, account_manager, account_id): | 125 | def _on_enabled_event (self, account_manager, account_id): |
346 | 106 | account = self._account_manager.get_account(account_id) | 126 | account = self._account_manager.get_account(account_id) |
347 | @@ -113,32 +133,49 @@ | |||
348 | 113 | for gdocs_account in self._gdocs_accounts: | 133 | for gdocs_account in self._gdocs_accounts: |
349 | 114 | if gdocs_account.get_account_service() == account_service: | 134 | if gdocs_account.get_account_service() == account_service: |
350 | 115 | return | 135 | return |
352 | 116 | gdocs_account = GDocsAccount(self._scope, account_service); | 136 | gdocs_account = GDocsAccount(account_service); |
353 | 117 | self._gdocs_accounts.append(gdocs_account) | 137 | self._gdocs_accounts.append(gdocs_account) |
354 | 118 | 138 | ||
371 | 119 | def _on_search_changed (self, scope, search, search_type, cancellable): | 139 | |
372 | 120 | search_string = search.props.search_string | 140 | class GDriveScopeSearch(Unity.ScopeSearchBase): |
373 | 121 | results = search.props.results_model | 141 | __g_type_name__ = "GDriveScopeSearch" |
374 | 122 | results.clear() | 142 | |
375 | 123 | 143 | def __init__(self, search_context, accounts): | |
376 | 124 | if self._preferences.props.remote_content_search != Unity.PreferencesManagerRemoteContent.ALL: | 144 | super(GDriveScopeSearch, self).__init__() |
377 | 125 | search.emit("finished") | 145 | self.set_search_context(search_context) |
378 | 126 | return | 146 | self._gdocs_accounts = accounts |
379 | 127 | 147 | ||
380 | 128 | if search_type == Unity.SearchType.GLOBAL: | 148 | def do_run(self): |
381 | 129 | is_global = True | 149 | print("Search changed to: '%s'" % self.search_context.search_query) |
366 | 130 | else: | ||
367 | 131 | is_global = False | ||
368 | 132 | |||
369 | 133 | print("Search changed to: '%s'" % search_string) | ||
370 | 134 | |||
382 | 135 | for gdocs_account in self._gdocs_accounts: | 150 | for gdocs_account in self._gdocs_accounts: |
389 | 136 | gdocs_account.update_results_model (search_string, results, search, is_global) | 151 | gdocs_account.search(self.search_context) |
390 | 137 | search.emit("finished") | 152 | |
391 | 138 | 153 | ||
392 | 139 | def _on_filters_or_preferences_changed (self, *_): | 154 | class GDriveScopePreviewer(Unity.ResultPreviewer): |
393 | 140 | self._scope.queue_search_changed(Unity.SearchType.DEFAULT) | 155 | __g_type_name__ = "GDriveScopePreviewer" |
394 | 141 | 156 | ||
395 | 157 | def do_run(self): | ||
396 | 158 | icon = Gio.ThemedIcon.new(self.result.icon_hint) | ||
397 | 159 | preview = Unity.GenericPreview.new(self.result.title, '', icon) | ||
398 | 160 | author = self.result.metadata['author'].get_string() | ||
399 | 161 | modified = datetime.fromtimestamp( | ||
400 | 162 | self.result.metadata['updated'].get_int32()) | ||
401 | 163 | shared = self.result.metadata['shared'].get_boolean() | ||
402 | 164 | starred = self.result.metadata['starred'].get_boolean() | ||
403 | 165 | preview.props.subtitle = _("By %s") % author | ||
404 | 166 | preview.add_info(Unity.InfoHint.new( | ||
405 | 167 | "format", _("Format"), None, self.result.comment)) | ||
406 | 168 | preview.add_info(Unity.InfoHint.new( | ||
407 | 169 | "modified", _("Modified"), None, modified.strftime('%x, %X'))) | ||
408 | 170 | preview.add_info(Unity.InfoHint.new( | ||
409 | 171 | "shared", _("Shared"), None, _('yes') if shared else _('no'))) | ||
410 | 172 | preview.add_info(Unity.InfoHint.new( | ||
411 | 173 | "starred", _("Starred"), None, _('yes') if starred else _('no'))) | ||
412 | 174 | |||
413 | 175 | action = Unity.PreviewAction.new("open", _("Open"), None) | ||
414 | 176 | preview.add_action(action) | ||
415 | 177 | return preview | ||
416 | 178 | |||
417 | 142 | 179 | ||
418 | 143 | class SignOnAuthorizer(GObject.Object, GData.Authorizer): | 180 | class SignOnAuthorizer(GObject.Object, GData.Authorizer): |
419 | 144 | __g_type_name__ = "SignOnAuthorizer" | 181 | __g_type_name__ = "SignOnAuthorizer" |
420 | @@ -195,8 +232,7 @@ | |||
421 | 195 | 232 | ||
422 | 196 | # Encapsulates searching a single user's GDocs | 233 | # Encapsulates searching a single user's GDocs |
423 | 197 | class GDocsAccount: | 234 | class GDocsAccount: |
426 | 198 | def __init__ (self, scope, account_service): | 235 | def __init__ (self, account_service): |
425 | 199 | self._scope = scope | ||
427 | 200 | self._account_service = account_service | 236 | self._account_service = account_service |
428 | 201 | self._account_service.connect("enabled", self._on_account_enabled) | 237 | self._account_service.connect("enabled", self._on_account_enabled) |
429 | 202 | self._enabled = self._account_service.get_enabled() | 238 | self._enabled = self._account_service.get_enabled() |
430 | @@ -212,12 +248,15 @@ | |||
431 | 212 | print("account %s, enabled %s" % (account, enabled)) | 248 | print("account %s, enabled %s" % (account, enabled)) |
432 | 213 | self._enabled = enabled | 249 | self._enabled = enabled |
433 | 214 | 250 | ||
435 | 215 | def update_results_model (self, search, model, s, is_global=False): | 251 | def search (self, context): |
436 | 216 | if not self._enabled: | 252 | if not self._enabled: |
437 | 217 | return | 253 | return |
438 | 218 | 254 | ||
439 | 219 | # Get the list of documents | 255 | # Get the list of documents |
441 | 220 | feed = self.get_doc_list(search, s, is_global); | 256 | is_global = context.search_type == Unity.SearchType.GLOBAL |
442 | 257 | feed = self.get_doc_list( | ||
443 | 258 | context.search_query, context.filter_state, is_global) | ||
444 | 259 | result_set = context.result_set | ||
445 | 221 | for entry in feed: | 260 | for entry in feed: |
446 | 222 | rtype = entry.get_resource_id().split(":")[0] | 261 | rtype = entry.get_resource_id().split(":")[0] |
447 | 223 | 262 | ||
448 | @@ -229,22 +268,38 @@ | |||
449 | 229 | else: | 268 | else: |
450 | 230 | category = 1 | 269 | category = 1 |
451 | 231 | 270 | ||
460 | 232 | model.append(uri=entry.look_up_link(GData.LINK_ALTERNATE).get_uri(), | 271 | authors = sorted([author.get_name() for author in entry.get_authors()]) |
461 | 233 | icon_hint=self.icon_for_type(rtype), | 272 | shared = False |
462 | 234 | category=category, | 273 | starred = False |
463 | 235 | mimetype="text/html", | 274 | for cat in entry.get_categories(): |
464 | 236 | title=entry.props.title, | 275 | if cat.get_scheme() != 'http://schemas.google.com/g/2005/labels': |
465 | 237 | comment=rtype, | 276 | continue |
466 | 238 | dnd_uri=entry.props.content_uri, | 277 | if cat.get_label() == 'shared': |
467 | 239 | result_type=Unity.ResultType.PERSONAL); | 278 | shared = True |
468 | 279 | elif cat.get_label() == 'starred': | ||
469 | 280 | starred = True | ||
470 | 281 | |||
471 | 282 | result_set.add_result( | ||
472 | 283 | uri=entry.look_up_link(GData.LINK_ALTERNATE).get_uri(), | ||
473 | 284 | icon=self.icon_for_type(rtype), | ||
474 | 285 | category=category, | ||
475 | 286 | result_type=Unity.ResultType.PERSONAL, | ||
476 | 287 | mimetype="text/html", | ||
477 | 288 | title=entry.get_title(), | ||
478 | 289 | comment=rtype, | ||
479 | 290 | dnd_uri=entry.get_content_uri(), | ||
480 | 291 | author=GLib.Variant('s', ', '.join(authors)), | ||
481 | 292 | shared=GLib.Variant('b', shared), | ||
482 | 293 | starred=GLib.Variant('b', starred), | ||
483 | 294 | updated=GLib.Variant('i', entry.get_updated())) | ||
484 | 240 | 295 | ||
485 | 241 | # This is where we do the actual search for documents | 296 | # This is where we do the actual search for documents |
487 | 242 | def get_doc_list (self, search, s, is_global): | 297 | def get_doc_list (self, search, filters, is_global): |
488 | 243 | query = GData.DocumentsQuery(q=search) | 298 | query = GData.DocumentsQuery(q=search) |
489 | 244 | 299 | ||
490 | 245 | # We do not want filters to effect global results | 300 | # We do not want filters to effect global results |
491 | 246 | if not is_global: | 301 | if not is_global: |
493 | 247 | self.apply_filters(query, s) | 302 | self.apply_filters(query, filters) |
494 | 248 | 303 | ||
495 | 249 | print("Searching for: " + query.props.q) | 304 | print("Searching for: " + query.props.q) |
496 | 250 | 305 | ||
497 | @@ -258,11 +313,11 @@ | |||
498 | 258 | return [] | 313 | return [] |
499 | 259 | 314 | ||
500 | 260 | if not is_global: | 315 | if not is_global: |
502 | 261 | feed = self.filter_results(feed, s) | 316 | feed = self.filter_results(feed, filters) |
503 | 262 | return feed | 317 | return feed |
504 | 263 | 318 | ||
507 | 264 | def apply_filters (self, query, s): | 319 | def apply_filters (self, query, filters): |
508 | 265 | f = s.get_filter("modified") | 320 | f = filters.get_filter_by_id("modified") |
509 | 266 | if f != None: | 321 | if f != None: |
510 | 267 | o = f.get_active_option() | 322 | o = f.get_active_option() |
511 | 268 | if o != None: | 323 | if o != None: |
512 | @@ -277,8 +332,8 @@ | |||
513 | 277 | last_time = datetime.now() - timedelta(age) | 332 | last_time = datetime.now() - timedelta(age) |
514 | 278 | query.set_updated_min(time.mktime(last_time.timetuple())) | 333 | query.set_updated_min(time.mktime(last_time.timetuple())) |
515 | 279 | 334 | ||
518 | 280 | def filter_results (self, feed, s): | 335 | def filter_results (self, feed, filters): |
519 | 281 | f = s.get_filter("type") | 336 | f = filters.get_filter_by_id("type") |
520 | 282 | if not f: return feed | 337 | if not f: return feed |
521 | 283 | if not f.props.filtering: | 338 | if not f.props.filtering: |
522 | 284 | return feed | 339 | return feed |
523 | @@ -313,9 +368,6 @@ | |||
524 | 313 | 368 | ||
525 | 314 | return ret; | 369 | return ret; |
526 | 315 | 370 | ||
527 | 316 | if __name__ == '__main__': | ||
528 | 317 | daemon = UnityExtras.dbus_own_name(BUS_NAME, Daemon, None) | ||
529 | 318 | if daemon: | ||
530 | 319 | GLib.unix_signal_add(0, 2, lambda x: daemon.quit(), None) | ||
531 | 320 | daemon.run([]) | ||
532 | 321 | 371 | ||
533 | 372 | def load_scope(): | ||
534 | 373 | return GDriveScope() |
PASSED: Continuous integration, rev:49 jenkins. qa.ubuntu. com/job/ submarine- unity-scope- gdrive- libunity- 7-compatible- ci/3/ jenkins. qa.ubuntu. com/job/ submarine- unity-scope- gdrive- libunity- 7-compatible- raring- amd64-ci/ 3
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ submarine- unity-scope- gdrive- libunity- 7-compatible- ci/3/rebuild
http://