Merge lp:~mvo/software-center/apptreeview-tweaks into lp:software-center
- apptreeview-tweaks
- Merge into trunk
Proposed by
Michael Vogt
Status: | Merged |
---|---|
Merged at revision: | 2829 |
Proposed branch: | lp:~mvo/software-center/apptreeview-tweaks |
Merge into: | lp:software-center |
Diff against target: |
802 lines (+234/-254) 8 files modified
softwarecenter/db/application.py (+2/-0) softwarecenter/testutils.py (+7/-0) softwarecenter/ui/gtk3/models/appstore2.py (+43/-71) softwarecenter/ui/gtk3/panes/installedpane.py (+15/-6) softwarecenter/ui/gtk3/views/appview.py (+78/-18) softwarecenter/ui/gtk3/widgets/apptreeview.py (+33/-75) test/gtk3/test_app_view.py (+56/-12) test/gtk3/test_appview.py (+0/-72) |
To merge this branch: | bzr merge lp:~mvo/software-center/apptreeview-tweaks |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gary Lasker (community) | Approve | ||
Review via email: mp+96593@code.launchpad.net |
Commit message
Description of the change
This branch gets rid of the
"""
AttributeError: 'TreeModelFilter' object has no attribute 'load_range' bug
"""
errors when navigating to the installed pane. But in order to fix that I had to look around for quite a bit
and did some refactor/cleanup along the way and added profile data and some more fixes:
- move the logic for appname into the db as far as possible
- merge _AppPropertiesH
- fix a missing self.hide_
- add some profile data
- make the testcode in appview.py show a List and the testcode in apptreeview.py show a test treeview
- merge test_app_view.py and test_appview.py
To post a comment you must log in.
- 2796. By Michael Vogt
-
pyflake fixes
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'softwarecenter/db/application.py' |
2 | --- softwarecenter/db/application.py 2012-02-16 09:52:24 +0000 |
3 | +++ softwarecenter/db/application.py 2012-03-08 15:25:23 +0000 |
4 | @@ -103,6 +103,8 @@ |
5 | if doc: |
6 | appname = db.get_appname(doc) |
7 | if appname: |
8 | + if db.is_appname_duplicated(appname): |
9 | + appname = "%s (%s)" % (appname, db.get_pkgname(doc)) |
10 | return appname |
11 | else: |
12 | return db.get_summary(doc) |
13 | |
14 | === modified file 'softwarecenter/testutils.py' |
15 | --- softwarecenter/testutils.py 2012-03-01 10:13:53 +0000 |
16 | +++ softwarecenter/testutils.py 2012-03-08 15:25:23 +0000 |
17 | @@ -102,6 +102,13 @@ |
18 | import softwarecenter.paths |
19 | return softwarecenter.paths.datadir |
20 | |
21 | +def get_test_categories(db): |
22 | + import softwarecenter.paths |
23 | + from softwarecenter.db.categories import CategoriesParser |
24 | + parser = CategoriesParser(db) |
25 | + cats = parser.parse_applications_menu(softwarecenter.paths.APP_INSTALL_PATH) |
26 | + return cats |
27 | + |
28 | def get_test_enquirer_matches(db, query=None, limit=20, sortmode=0): |
29 | from softwarecenter.db.enquire import AppEnquire |
30 | import xapian |
31 | |
32 | === modified file 'softwarecenter/ui/gtk3/models/appstore2.py' |
33 | --- softwarecenter/ui/gtk3/models/appstore2.py 2012-01-05 11:24:20 +0000 |
34 | +++ softwarecenter/ui/gtk3/models/appstore2.py 2012-03-08 15:25:23 +0000 |
35 | @@ -31,7 +31,6 @@ |
36 | from softwarecenter.utils import ExecutionTime, SimpleFileDownloader, split_icon_ext |
37 | from softwarecenter.backend import get_install_backend |
38 | from softwarecenter.backend.reviews import get_review_loader |
39 | -from softwarecenter.db.database import Application |
40 | from softwarecenter.paths import SOFTWARE_CENTER_ICON_CACHE_DIR |
41 | |
42 | import softwarecenter.paths |
43 | @@ -74,7 +73,7 @@ |
44 | return |
45 | |
46 | |
47 | -class _AppPropertiesHelper(GObject.GObject): |
48 | +class AppPropertiesHelper(GObject.GObject): |
49 | """ Baseclass that contains common functions for our |
50 | liststore/treestore, only useful for subclassing |
51 | """ |
52 | @@ -86,8 +85,30 @@ |
53 | ), |
54 | } |
55 | |
56 | - def __init__(self): |
57 | + def __init__(self, db, cache, icons, icon_size=48, global_icon_cache=False): |
58 | GObject.GObject.__init__(self) |
59 | + self.db = db |
60 | + self.cache = cache |
61 | + |
62 | + # get all categories |
63 | + cat_parser = CategoriesParser(db) |
64 | + self.all_categories = cat_parser.parse_applications_menu( |
65 | + softwarecenter.paths.APP_INSTALL_PATH) |
66 | + |
67 | + # reviews stats loader |
68 | + self.review_loader = get_review_loader(cache, db) |
69 | + |
70 | + # icon jazz |
71 | + self.icons = icons |
72 | + self.icon_size = icon_size |
73 | + |
74 | + # cache the 'missing icon' used in the treeview for apps without an icon |
75 | + self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0) |
76 | + if global_icon_cache: |
77 | + self.icon_cache = _app_icon_cache |
78 | + else: |
79 | + self.icon_cache = {} |
80 | + return |
81 | |
82 | def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name): |
83 | LOG.debug("did not find the icon locally, must download %s" % icon_file_name) |
84 | @@ -138,31 +159,23 @@ |
85 | return self.db.get_pkgname(doc) |
86 | |
87 | def get_application(self, doc): |
88 | - appname = doc.get_value(XapianValues.APPNAME) |
89 | - pkgname = self.db.get_pkgname(doc) |
90 | - # TODO: requests |
91 | - return Application(appname, pkgname, "") |
92 | + return self.db.get_application(doc) |
93 | |
94 | def get_appname(self, doc): |
95 | - appname = doc.get_value(XapianValues.APPNAME) |
96 | - if not appname: |
97 | - appname = self.db.get_summary(doc) |
98 | - else: |
99 | - if self.db.is_appname_duplicated(appname): |
100 | - appname = "%s (%s)" % (appname, self.get_pkgname(doc)) |
101 | - return appname |
102 | + app = self.db.get_application(doc) |
103 | + return app.get_display_name(self.db, doc) |
104 | |
105 | def get_markup(self, doc): |
106 | - appname = doc.get_value(XapianValues.APPNAME) |
107 | + app = self.db.get_application(doc) |
108 | |
109 | - if not appname: |
110 | + # the logic is that "apps" are displayed normally |
111 | + # but "packages" are displayed with their summary as name |
112 | + if app.appname: |
113 | + appname = self.get_appname(doc) |
114 | + summary = self.db.get_summary(doc) |
115 | + else: |
116 | appname = self.db.get_summary(doc) |
117 | summary = self.get_pkgname(doc) |
118 | - else: |
119 | - if self.db.is_appname_duplicated(appname): |
120 | - appname = "%s (%s)" % (appname, self.get_pkgname(doc)) |
121 | - |
122 | - summary = self.db.get_summary(doc) |
123 | |
124 | return "%s\n<small>%s</small>" % ( |
125 | GObject.markup_escape_text(appname), |
126 | @@ -239,44 +252,14 @@ |
127 | else: |
128 | return '' |
129 | |
130 | -class AppPropertiesHelper(_AppPropertiesHelper): |
131 | - |
132 | - def __init__(self, db, cache, icons, icon_size=48, global_icon_cache=False): |
133 | - super(AppPropertiesHelper, self).__init__() |
134 | - self.db = db |
135 | - self.cache = cache |
136 | - |
137 | - cat_parser = CategoriesParser(db) |
138 | - self.all_categories = cat_parser.parse_applications_menu( |
139 | - softwarecenter.paths.APP_INSTALL_PATH) |
140 | - |
141 | - # reviews stats loader |
142 | - self.review_loader = get_review_loader(cache, db) |
143 | - |
144 | - # icon jazz |
145 | - self.icons = icons |
146 | - self.icon_size = icon_size |
147 | - # cache the 'missing icon' used in the treeview for apps without an icon |
148 | - self._missing_icon = icons.load_icon(Icons.MISSING_APP, |
149 | - icon_size, 0) |
150 | - |
151 | - if global_icon_cache: |
152 | - self.icon_cache = _app_icon_cache |
153 | - else: |
154 | - self.icon_cache = {} |
155 | - return |
156 | - |
157 | def get_icon_at_size(self, doc, width, height): |
158 | pixbuf = self.get_icon(doc) |
159 | pixbuf = pixbuf.scale_simple(width, height, |
160 | GdkPixbuf.InterpType.BILINEAR) |
161 | return pixbuf |
162 | |
163 | - def get_transaction_progress(self, doc): |
164 | - raise NotImplemented |
165 | - |
166 | - |
167 | -class AppGenericStore(_AppPropertiesHelper): |
168 | + |
169 | +class AppGenericStore(AppPropertiesHelper): |
170 | |
171 | # column types |
172 | COL_TYPES = (GObject.TYPE_PYOBJECT,) |
173 | @@ -291,12 +274,8 @@ |
174 | LOAD_INITIAL = 75 |
175 | |
176 | def __init__(self, db, cache, icons, icon_size, global_icon_cache): |
177 | - # the usual suspects |
178 | - self.db = db |
179 | - self.cache = cache |
180 | - |
181 | - # reviews stats loader |
182 | - self.review_loader = get_review_loader(cache, db) |
183 | + AppPropertiesHelper.__init__(self, db, cache, icons, icon_size, |
184 | + global_icon_cache) |
185 | |
186 | # backend stuff |
187 | self.backend = get_install_backend() |
188 | @@ -307,21 +286,9 @@ |
189 | # keep track of paths for transactions in progress |
190 | self.transaction_path_map = {} |
191 | |
192 | - # icon jazz |
193 | - self.icons = icons |
194 | - self.icon_size = icon_size |
195 | - |
196 | - if global_icon_cache: |
197 | - self.icon_cache = _app_icon_cache |
198 | - else: |
199 | - self.icon_cache = {} |
200 | - |
201 | # active row path |
202 | self.active_row = None |
203 | |
204 | - # cache the 'missing icon' used in the treeview for apps without an icon |
205 | - self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0) |
206 | - |
207 | self._in_progress = False |
208 | self._break = False |
209 | |
210 | @@ -396,6 +363,10 @@ |
211 | GObject.idle_add(buffer_icons) |
212 | return |
213 | |
214 | + def load_range(self, indices, step): |
215 | + # stub |
216 | + return |
217 | + |
218 | class AppListStore(Gtk.ListStore, AppGenericStore): |
219 | """ use for flat applist views. for large lists this appends rows approx |
220 | three times faster than the AppTreeStore equivalent |
221 | @@ -526,3 +497,4 @@ |
222 | self.transaction_path_map = {} |
223 | Gtk.TreeStore.clear(self) |
224 | return |
225 | + |
226 | |
227 | === modified file 'softwarecenter/ui/gtk3/panes/installedpane.py' |
228 | --- softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-06 18:19:33 +0000 |
229 | +++ softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-08 15:25:23 +0000 |
230 | @@ -30,7 +30,8 @@ |
231 | |
232 | from softwarecenter.enums import (NonAppVisibility, |
233 | SortMethods) |
234 | -from softwarecenter.utils import wait_for_apt_cache_ready, utf8 |
235 | +from softwarecenter.utils import ( |
236 | + wait_for_apt_cache_ready, utf8, ExecutionTime) |
237 | from softwarecenter.db.categories import (CategoriesParser, |
238 | categories_sorted_by_name) |
239 | from softwarecenter.ui.gtk3.models.appstore2 import ( |
240 | @@ -209,6 +210,8 @@ |
241 | # hacky, hide the header |
242 | self.app_view.header_hbox.hide() |
243 | |
244 | + self.hide_appview_spinner() |
245 | + |
246 | # now we are initialized |
247 | self.emit("installed-pane-created") |
248 | |
249 | @@ -313,6 +316,10 @@ |
250 | model = self.base_model # base model not treefilter |
251 | model.clear() |
252 | |
253 | + def profiled_rebuild_categorised_view(): |
254 | + with ExecutionTime("rebuild_categorized_view"): |
255 | + rebuild_categorised_view() |
256 | + |
257 | def rebuild_categorised_view(): |
258 | self.cat_docid_map = {} |
259 | enq = self.enquirer |
260 | @@ -324,6 +331,7 @@ |
261 | |
262 | xfilter = AppFilter(self.db, self.cache) |
263 | xfilter.set_installed_only(True) |
264 | + |
265 | for cat in self._all_cats: |
266 | # for each category do category query and append as a new |
267 | # node to tree_view |
268 | @@ -379,9 +387,6 @@ |
269 | # hide the local spinner |
270 | self.hide_installed_view_spinner() |
271 | |
272 | - # hide the main spinner (if it's showing) |
273 | - self.hide_appview_spinner() |
274 | - |
275 | if window: |
276 | window.set_cursor(None) |
277 | |
278 | @@ -392,7 +397,7 @@ |
279 | self.emit("app-list-changed", i) |
280 | return |
281 | |
282 | - GObject.idle_add(rebuild_categorised_view) |
283 | + GObject.idle_add(profiled_rebuild_categorised_view) |
284 | return |
285 | |
286 | def _build_oneconfview(self): |
287 | @@ -407,6 +412,10 @@ |
288 | model = self.base_model # base model not treefilter |
289 | model.clear() |
290 | |
291 | + def profiled_rebuild_oneconfview(): |
292 | + with ExecutionTime("rebuild_oneconfview"): |
293 | + rebuild_oneconfview() |
294 | + |
295 | def rebuild_oneconfview(): |
296 | |
297 | # FIXME for P: hide the search entry |
298 | @@ -487,7 +496,7 @@ |
299 | self.emit("app-list-changed", i) |
300 | return |
301 | |
302 | - GObject.idle_add(rebuild_oneconfview) |
303 | + GObject.idle_add(profiled_rebuild_oneconfview) |
304 | return |
305 | |
306 | def _check_expand(self): |
307 | |
308 | === modified file 'softwarecenter/ui/gtk3/views/appview.py' |
309 | --- softwarecenter/ui/gtk3/views/appview.py 2012-03-07 06:02:07 +0000 |
310 | +++ softwarecenter/ui/gtk3/views/appview.py 2012-03-08 15:25:23 +0000 |
311 | @@ -16,20 +16,18 @@ |
312 | # this program; if not, write to the Free Software Foundation, Inc., |
313 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
314 | |
315 | -#~ from __future__ import with_statement |
316 | |
317 | import logging |
318 | |
319 | from gi.repository import Gtk, GObject |
320 | from gettext import gettext as _ |
321 | -#~ import gettext |
322 | |
323 | from softwarecenter.enums import SortMethods |
324 | from softwarecenter.ui.gtk3.em import StockEms |
325 | from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore |
326 | from softwarecenter.ui.gtk3.widgets.apptreeview import AppTreeView |
327 | from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper |
328 | -#~ from softwarecenter.ui.gtk3.widgets.containers import FlowableGrid |
329 | +from softwarecenter.utils import ExecutionTime |
330 | |
331 | LOG=logging.getLogger(__name__) |
332 | |
333 | @@ -191,10 +189,10 @@ |
334 | # ... also we dont currently support user sorting in the |
335 | # installedview, so issue is somewhat moot for the time being... |
336 | if isinstance(self.tree_view.appmodel, AppTreeStore): |
337 | + LOG.debug("display_matches called on AppTreeStore, ignoring") |
338 | return |
339 | |
340 | sort_by_relevance = is_search and not self.user_defined_sort_method |
341 | - |
342 | if sort_by_relevance: |
343 | self._use_combobox_with_sort_by_search_ranking() |
344 | self.set_sort_method_with_no_signal(self._SORT_BY_SEARCH_RANKING) |
345 | @@ -257,30 +255,91 @@ |
346 | py+self.tree_view.selected_row_renderer.icon_y_offset) |
347 | |
348 | |
349 | + |
350 | + |
351 | + |
352 | +# ----------------------------------------------- testcode |
353 | +from softwarecenter.enums import NonAppVisibility |
354 | + |
355 | +def get_query_from_search_entry(search_term): |
356 | + import xapian |
357 | + if not search_term: |
358 | + return xapian.Query("") |
359 | + parser = xapian.QueryParser() |
360 | + user_query = parser.parse_query(search_term) |
361 | + return user_query |
362 | + |
363 | +def on_entry_changed(widget, data): |
364 | + |
365 | + def _work(): |
366 | + new_text = widget.get_text() |
367 | + (view, enquirer) = data |
368 | + |
369 | + with ExecutionTime("total time"): |
370 | + with ExecutionTime("enquire.set_query()"): |
371 | + enquirer.set_query(get_query_from_search_entry(new_text), |
372 | + limit=100*1000, |
373 | + nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE) |
374 | + |
375 | + store = view.tree_view.get_model() |
376 | + with ExecutionTime("store.clear()"): |
377 | + store.clear() |
378 | + |
379 | + with ExecutionTime("store.set_from_matches()"): |
380 | + store.set_from_matches(enquirer.matches) |
381 | + |
382 | + with ExecutionTime("model settle (size=%s)" % len(store)): |
383 | + while Gtk.events_pending(): |
384 | + Gtk.main_iteration() |
385 | + return |
386 | + |
387 | + if widget.stamp: |
388 | + GObject.source_remove(widget.stamp) |
389 | + widget.stamp = GObject.timeout_add(250, _work) |
390 | + |
391 | def get_test_window(): |
392 | + import softwarecenter.log |
393 | + softwarecenter.log.root.setLevel(level=logging.DEBUG) |
394 | + softwarecenter.log.add_filters_from_string("performance") |
395 | + fmt = logging.Formatter("%(name)s - %(message)s", None) |
396 | + softwarecenter.log.handler.setFormatter(fmt) |
397 | + |
398 | from softwarecenter.testutils import ( |
399 | - get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache, |
400 | - get_test_enquirer_matches) |
401 | + get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache) |
402 | from softwarecenter.ui.gtk3.models.appstore2 import AppListStore |
403 | |
404 | db = get_test_db() |
405 | cache = get_test_pkg_info() |
406 | icons = get_test_gtk3_icon_cache() |
407 | |
408 | - # create the view |
409 | - appview = AppView(db, cache, icons, show_ratings=True) |
410 | - liststore = AppListStore(db, cache, icons) |
411 | - appview.set_model(liststore) |
412 | - |
413 | - # do a simple query and display that |
414 | - appview.display_matches(get_test_enquirer_matches(db)) |
415 | - |
416 | - # and put it in the window |
417 | + # create a filter |
418 | + from softwarecenter.db.appfilter import AppFilter |
419 | + filter = AppFilter(db, cache) |
420 | + filter.set_supported_only(False) |
421 | + filter.set_installed_only(True) |
422 | + |
423 | + # appview |
424 | + from softwarecenter.db.enquire import AppEnquire |
425 | + enquirer = AppEnquire(cache, db) |
426 | + store = AppListStore(db, cache, icons) |
427 | + |
428 | + from softwarecenter.ui.gtk3.views.appview import AppView |
429 | + view = AppView(db, cache, icons, show_ratings=True) |
430 | + view.set_model(store) |
431 | + |
432 | + entry = Gtk.Entry() |
433 | + entry.stamp = 0 |
434 | + entry.connect("changed", on_entry_changed, (view, enquirer)) |
435 | + |
436 | + box = Gtk.VBox() |
437 | + box.pack_start(entry, False, True, 0) |
438 | + box.pack_start(view, True, True, 0) |
439 | + |
440 | win = Gtk.Window() |
441 | - win.add(appview) |
442 | - win.set_data("appview", appview) |
443 | - |
444 | + win.set_data("appview", view) |
445 | + win.set_data("entry", entry) |
446 | win.connect("destroy", lambda x: Gtk.main_quit()) |
447 | + win.add(box) |
448 | win.set_size_request(600, 400) |
449 | win.show_all() |
450 | |
451 | @@ -288,4 +347,5 @@ |
452 | |
453 | if __name__ == "__main__": |
454 | win = get_test_window() |
455 | + win.get_data("entry").set_text("gtk3") |
456 | Gtk.main() |
457 | |
458 | === modified file 'softwarecenter/ui/gtk3/widgets/apptreeview.py' |
459 | --- softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-07 06:02:07 +0000 |
460 | +++ softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-08 15:25:23 +0000 |
461 | @@ -1,7 +1,5 @@ |
462 | from gi.repository import Gtk, Gdk, GObject |
463 | import logging |
464 | -import os |
465 | -import xapian |
466 | |
467 | from gettext import gettext as _ |
468 | |
469 | @@ -13,7 +11,7 @@ |
470 | CellButtonIDs) |
471 | |
472 | from softwarecenter.ui.gtk3.em import em, StockEms |
473 | -from softwarecenter.enums import (AppActions, NonAppVisibility, Icons) |
474 | +from softwarecenter.enums import (AppActions, Icons) |
475 | from softwarecenter.utils import ExecutionTime |
476 | from softwarecenter.backend import get_install_backend |
477 | from softwarecenter.netstatus import (get_network_watcher, |
478 | @@ -168,7 +166,8 @@ |
479 | return None |
480 | |
481 | def get_rowref(self, model, path): |
482 | - if path == None: return None |
483 | + if path == None: |
484 | + return None |
485 | return model[path][AppGenericStore.COL_ROW_DATA] |
486 | |
487 | def rowref_is_category(self, rowref): |
488 | @@ -469,6 +468,12 @@ |
489 | |
490 | path = model.get_path(it) |
491 | |
492 | + # this will give us the right underlying model regardless if its |
493 | + # a TreeModelFilter, a AppTreeStore or a AppListStore |
494 | + model = self.appmodel |
495 | + |
496 | + # this will pre-load data *only* on a AppListStore, it has |
497 | + # no effect with a AppTreeStore |
498 | if model[path][0] is None: |
499 | indices = path.get_indices() |
500 | model.load_range(indices, 5) |
501 | @@ -586,41 +591,6 @@ |
502 | return self.get_path_at_pos(x, y)[0] == self.get_cursor()[0] |
503 | |
504 | |
505 | -def get_query_from_search_entry(search_term): |
506 | - if not search_term: |
507 | - return xapian.Query("") |
508 | - parser = xapian.QueryParser() |
509 | - user_query = parser.parse_query(search_term) |
510 | - return user_query |
511 | - |
512 | -def on_entry_changed(widget, data): |
513 | - |
514 | - def _work(): |
515 | - new_text = widget.get_text() |
516 | - (view, enquirer) = data |
517 | - |
518 | - with ExecutionTime("total time"): |
519 | - with ExecutionTime("enquire.set_query()"): |
520 | - enquirer.set_query(get_query_from_search_entry(new_text), |
521 | - limit=100*1000, |
522 | - nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE) |
523 | - |
524 | - store = view.tree_view.get_model() |
525 | - with ExecutionTime("store.clear()"): |
526 | - store.clear() |
527 | - |
528 | - with ExecutionTime("store.set_documents()"): |
529 | - store.set_from_matches(enquirer.matches) |
530 | - |
531 | - with ExecutionTime("model settle (size=%s)" % len(store)): |
532 | - while Gtk.events_pending(): |
533 | - Gtk.main_iteration() |
534 | - return |
535 | - |
536 | - if widget.stamp: GObject.source_remove(widget.stamp) |
537 | - widget.stamp = GObject.timeout_add(250, _work) |
538 | - |
539 | - |
540 | |
541 | def get_test_window(): |
542 | import softwarecenter.log |
543 | @@ -629,24 +599,13 @@ |
544 | fmt = logging.Formatter("%(name)s - %(message)s", None) |
545 | softwarecenter.log.handler.setFormatter(fmt) |
546 | |
547 | - from softwarecenter.paths import XAPIAN_BASE_PATH |
548 | - xapian_base_path = XAPIAN_BASE_PATH |
549 | - pathname = os.path.join(xapian_base_path, "xapian") |
550 | - |
551 | - # the store |
552 | - from softwarecenter.db.pkginfo import get_pkg_info |
553 | - cache = get_pkg_info() |
554 | - cache.open() |
555 | - |
556 | - # the db |
557 | - from softwarecenter.db.database import StoreDatabase |
558 | - db = StoreDatabase(pathname, cache) |
559 | - db.open() |
560 | - |
561 | - # additional icons come from app-install-data |
562 | - icons = Gtk.IconTheme.get_default() |
563 | - icons.prepend_search_path("/usr/share/app-install/icons/") |
564 | - icons.prepend_search_path("/usr/share/software-center/icons/") |
565 | + from softwarecenter.testutils import ( |
566 | + get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache, |
567 | + get_test_categories) |
568 | + |
569 | + cache = get_test_pkg_info() |
570 | + db = get_test_db() |
571 | + icons = get_test_gtk3_icon_cache() |
572 | |
573 | # create a filter |
574 | from softwarecenter.db.appfilter import AppFilter |
575 | @@ -654,30 +613,29 @@ |
576 | filter.set_supported_only(False) |
577 | filter.set_installed_only(True) |
578 | |
579 | - # appview |
580 | - from softwarecenter.ui.gtk3.models.appstore2 import AppListStore |
581 | - from softwarecenter.db.enquire import AppEnquire |
582 | - enquirer = AppEnquire(cache, db) |
583 | - store = AppListStore(db, cache, icons) |
584 | + # get the TREEstore |
585 | + from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore |
586 | + store = AppTreeStore(db, cache, icons) |
587 | |
588 | + # populate from data |
589 | + cats = get_test_categories(db) |
590 | + for cat in cats[:3]: |
591 | + with ExecutionTime("query cat '%s'" % cat.name): |
592 | + docs = db.get_docs_from_query(cat.query) |
593 | + store.set_category_documents(cat, docs) |
594 | + |
595 | + # ok, this is confusing - the AppView contains the AppTreeView that |
596 | + # is a tree or list depending on the model |
597 | from softwarecenter.ui.gtk3.views.appview import AppView |
598 | - view = AppView(db, cache, icons, show_ratings=True) |
599 | - view.set_model(store) |
600 | - |
601 | - entry = Gtk.Entry() |
602 | - entry.stamp = 0 |
603 | - entry.connect("changed", on_entry_changed, (view, enquirer)) |
604 | - entry.set_text("gtk3") |
605 | - |
606 | - scroll = Gtk.ScrolledWindow() |
607 | + app_view = AppView(db, cache, icons, show_ratings=True) |
608 | + app_view.set_model(store) |
609 | + |
610 | box = Gtk.VBox() |
611 | - box.pack_start(entry, False, True, 0) |
612 | - box.pack_start(scroll, True, True, 0) |
613 | + box.pack_start(app_view, True, True, 0) |
614 | |
615 | win = Gtk.Window() |
616 | + win.add(box) |
617 | win.connect("destroy", lambda x: Gtk.main_quit()) |
618 | - scroll.add(view) |
619 | - win.add(box) |
620 | win.set_size_request(600, 400) |
621 | win.show_all() |
622 | |
623 | |
624 | === modified file 'test/gtk3/test_app_view.py' |
625 | --- test/gtk3/test_app_view.py 2012-01-16 14:42:49 +0000 |
626 | +++ test/gtk3/test_app_view.py 2012-03-08 15:25:23 +0000 |
627 | @@ -1,11 +1,8 @@ |
628 | #!/usr/bin/python |
629 | |
630 | -import time |
631 | import unittest |
632 | import xapian |
633 | |
634 | -from gi.repository import Gtk |
635 | - |
636 | from testutils import setup_test_env |
637 | setup_test_env() |
638 | |
639 | @@ -15,6 +12,7 @@ |
640 | from softwarecenter.testutils import (get_test_db, |
641 | get_test_pkg_info, |
642 | get_test_gtk3_icon_cache, |
643 | + do_events, |
644 | ) |
645 | |
646 | class TestAppView(unittest.TestCase): |
647 | @@ -39,7 +37,7 @@ |
648 | # set matches |
649 | appview.clear_model() |
650 | appview.display_matches(enquirer.matches) |
651 | - self._p() |
652 | + do_events() |
653 | # verify that the order is actually the correct one |
654 | model = appview.tree_view.get_model() |
655 | docs_in_model = [item[0] for item in model] |
656 | @@ -49,15 +47,61 @@ |
657 | for i in range(len(docs_in_model)): |
658 | self.assertEqual(self.db.get_pkgname(docs_in_model[i]), |
659 | self.db.get_pkgname(docs_from_enquirer[i])) |
660 | - |
661 | - def _p(self): |
662 | - for i in range(5): |
663 | - time.sleep(0.1) |
664 | - while Gtk.events_pending(): |
665 | - Gtk.main_iteration() |
666 | + win.destroy() |
667 | + |
668 | + def test_appview_search_combo(self): |
669 | + from softwarecenter.ui.gtk3.views.appview import get_test_window |
670 | + from softwarecenter.testutils import get_test_enquirer_matches |
671 | + |
672 | + # test if combox sort option "by relevance" vanishes for non-searches |
673 | + # LP: #861778 |
674 | + expected_normal = ["By Name", "By Top Rated", "By Newest First"] |
675 | + expected_search = ["By Name", "By Top Rated", "By Newest First", |
676 | + "By Relevance"] |
677 | + |
678 | + # setup goo |
679 | + win = get_test_window() |
680 | + appview = win.get_data("appview") |
681 | + #entry = win.get_data("entry") |
682 | + do_events() |
683 | + |
684 | + # get the model |
685 | + model = appview.sort_methods_combobox.get_model() |
686 | + |
687 | + # test normal window (no search) |
688 | + matches = get_test_enquirer_matches(appview.helper.db) |
689 | + appview.display_matches(matches, is_search=False) |
690 | + do_events() |
691 | + in_model = [] |
692 | + for item in model: |
693 | + in_model.append(model.get_value(item.iter, 0)) |
694 | + self.assertEqual(in_model, expected_normal) |
695 | + |
696 | + # now repeat and simulate a search |
697 | + matches = get_test_enquirer_matches(appview.helper.db) |
698 | + appview.display_matches(matches, is_search=True) |
699 | + do_events() |
700 | + in_model = [] |
701 | + for item in model: |
702 | + in_model.append(model.get_value(item.iter, 0)) |
703 | + self.assertEqual(in_model, expected_search) |
704 | + |
705 | + # and back again to no search |
706 | + matches = get_test_enquirer_matches(appview.helper.db) |
707 | + appview.display_matches(matches, is_search=False) |
708 | + do_events() |
709 | + # collect items in the model |
710 | + in_model = [] |
711 | + for item in model: |
712 | + in_model.append(model.get_value(item.iter, 0)) |
713 | + self.assertEqual(expected_normal, in_model) |
714 | + |
715 | + # destroy |
716 | + win.destroy() |
717 | + |
718 | |
719 | |
720 | if __name__ == "__main__": |
721 | - import logging |
722 | - logging.basicConfig(level=logging.DEBUG) |
723 | + #import logging |
724 | + #logging.basicConfig(level=logging.DEBUG) |
725 | unittest.main() |
726 | |
727 | === removed file 'test/gtk3/test_appview.py' |
728 | --- test/gtk3/test_appview.py 2012-01-16 14:42:49 +0000 |
729 | +++ test/gtk3/test_appview.py 1970-01-01 00:00:00 +0000 |
730 | @@ -1,72 +0,0 @@ |
731 | -#!/usr/bin/python |
732 | - |
733 | -from gi.repository import Gtk, GObject |
734 | -import time |
735 | -import unittest |
736 | - |
737 | -from testutils import setup_test_env |
738 | -setup_test_env() |
739 | - |
740 | -#from mock import Mock |
741 | - |
742 | -TIMEOUT=300 |
743 | - |
744 | -class TestViews(unittest.TestCase): |
745 | - |
746 | - def test_appview_search_combo(self): |
747 | - from softwarecenter.ui.gtk3.views.appview import get_test_window |
748 | - from softwarecenter.testutils import get_test_enquirer_matches |
749 | - |
750 | - # test if combox sort option "by relevance" vanishes for non-searches |
751 | - # LP: #861778 |
752 | - expected_normal = ["By Name", "By Top Rated", "By Newest First"] |
753 | - expected_search = ["By Name", "By Top Rated", "By Newest First", |
754 | - "By Relevance"] |
755 | - |
756 | - # setup goo |
757 | - win = get_test_window() |
758 | - self._p() |
759 | - appview = win.get_data("appview") |
760 | - |
761 | - # test normal window (no search) |
762 | - model = appview.sort_methods_combobox.get_model() |
763 | - # collect items in the model |
764 | - in_model = [] |
765 | - for item in model: |
766 | - in_model.append(model.get_value(item.iter, 0)) |
767 | - # this is what we expect there |
768 | - self.assertEqual(expected_normal, in_model) |
769 | - |
770 | - # now repeat and simulate a search |
771 | - matches = get_test_enquirer_matches(appview.helper.db) |
772 | - appview.display_matches(matches, is_search=True) |
773 | - self._p() |
774 | - in_model = [] |
775 | - for item in model: |
776 | - in_model.append(model.get_value(item.iter, 0)) |
777 | - self.assertEqual(in_model, expected_search) |
778 | - |
779 | - # and back again to no search |
780 | - matches = get_test_enquirer_matches(appview.helper.db) |
781 | - appview.display_matches(matches, is_search=False) |
782 | - self._p() |
783 | - # collect items in the model |
784 | - in_model = [] |
785 | - for item in model: |
786 | - in_model.append(model.get_value(item.iter, 0)) |
787 | - self.assertEqual(expected_normal, in_model) |
788 | - |
789 | - # destroy |
790 | - GObject.timeout_add(TIMEOUT, lambda: win.destroy()) |
791 | - Gtk.main() |
792 | - |
793 | - def _p(self): |
794 | - for i in range(10): |
795 | - time.sleep(0.1) |
796 | - while Gtk.events_pending(): |
797 | - Gtk.main_iteration() |
798 | - |
799 | -if __name__ == "__main__": |
800 | - import logging |
801 | - logging.basicConfig(level=logging.DEBUG) |
802 | - unittest.main() |
These are very nice changes indeed. Thank you, Michael!!