Merge lp:~mvo/software-center/apptreeview-tweaks into lp:software-center

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
Reviewer Review Type Date Requested Status
Gary Lasker (community) Approve
Review via email: mp+96593@code.launchpad.net

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 _AppPropertiesHelper and AppPropertiesHelper
- fix a missing self.hide_appview_spinner() that prevented the installed pane to show up quicker
- 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

Revision history for this message
Gary Lasker (gary-lasker) wrote :

These are very nice changes indeed. Thank you, Michael!!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'softwarecenter/db/application.py'
--- softwarecenter/db/application.py 2012-02-16 09:52:24 +0000
+++ softwarecenter/db/application.py 2012-03-08 15:25:23 +0000
@@ -103,6 +103,8 @@
103 if doc:103 if doc:
104 appname = db.get_appname(doc)104 appname = db.get_appname(doc)
105 if appname:105 if appname:
106 if db.is_appname_duplicated(appname):
107 appname = "%s (%s)" % (appname, db.get_pkgname(doc))
106 return appname108 return appname
107 else:109 else:
108 return db.get_summary(doc)110 return db.get_summary(doc)
109111
=== modified file 'softwarecenter/testutils.py'
--- softwarecenter/testutils.py 2012-03-01 10:13:53 +0000
+++ softwarecenter/testutils.py 2012-03-08 15:25:23 +0000
@@ -102,6 +102,13 @@
102 import softwarecenter.paths102 import softwarecenter.paths
103 return softwarecenter.paths.datadir103 return softwarecenter.paths.datadir
104104
105def get_test_categories(db):
106 import softwarecenter.paths
107 from softwarecenter.db.categories import CategoriesParser
108 parser = CategoriesParser(db)
109 cats = parser.parse_applications_menu(softwarecenter.paths.APP_INSTALL_PATH)
110 return cats
111
105def get_test_enquirer_matches(db, query=None, limit=20, sortmode=0):112def get_test_enquirer_matches(db, query=None, limit=20, sortmode=0):
106 from softwarecenter.db.enquire import AppEnquire113 from softwarecenter.db.enquire import AppEnquire
107 import xapian114 import xapian
108115
=== modified file 'softwarecenter/ui/gtk3/models/appstore2.py'
--- softwarecenter/ui/gtk3/models/appstore2.py 2012-01-05 11:24:20 +0000
+++ softwarecenter/ui/gtk3/models/appstore2.py 2012-03-08 15:25:23 +0000
@@ -31,7 +31,6 @@
31from softwarecenter.utils import ExecutionTime, SimpleFileDownloader, split_icon_ext31from softwarecenter.utils import ExecutionTime, SimpleFileDownloader, split_icon_ext
32from softwarecenter.backend import get_install_backend32from softwarecenter.backend import get_install_backend
33from softwarecenter.backend.reviews import get_review_loader33from softwarecenter.backend.reviews import get_review_loader
34from softwarecenter.db.database import Application
35from softwarecenter.paths import SOFTWARE_CENTER_ICON_CACHE_DIR34from softwarecenter.paths import SOFTWARE_CENTER_ICON_CACHE_DIR
3635
37import softwarecenter.paths36import softwarecenter.paths
@@ -74,7 +73,7 @@
74 return73 return
7574
7675
77class _AppPropertiesHelper(GObject.GObject):76class AppPropertiesHelper(GObject.GObject):
78 """ Baseclass that contains common functions for our77 """ Baseclass that contains common functions for our
79 liststore/treestore, only useful for subclassing78 liststore/treestore, only useful for subclassing
80 """79 """
@@ -86,8 +85,30 @@
86 ),85 ),
87 }86 }
8887
89 def __init__(self):88 def __init__(self, db, cache, icons, icon_size=48, global_icon_cache=False):
90 GObject.GObject.__init__(self)89 GObject.GObject.__init__(self)
90 self.db = db
91 self.cache = cache
92
93 # get all categories
94 cat_parser = CategoriesParser(db)
95 self.all_categories = cat_parser.parse_applications_menu(
96 softwarecenter.paths.APP_INSTALL_PATH)
97
98 # reviews stats loader
99 self.review_loader = get_review_loader(cache, db)
100
101 # icon jazz
102 self.icons = icons
103 self.icon_size = icon_size
104
105 # cache the 'missing icon' used in the treeview for apps without an icon
106 self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0)
107 if global_icon_cache:
108 self.icon_cache = _app_icon_cache
109 else:
110 self.icon_cache = {}
111 return
91112
92 def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name):113 def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name):
93 LOG.debug("did not find the icon locally, must download %s" % icon_file_name)114 LOG.debug("did not find the icon locally, must download %s" % icon_file_name)
@@ -138,31 +159,23 @@
138 return self.db.get_pkgname(doc)159 return self.db.get_pkgname(doc)
139160
140 def get_application(self, doc):161 def get_application(self, doc):
141 appname = doc.get_value(XapianValues.APPNAME)162 return self.db.get_application(doc)
142 pkgname = self.db.get_pkgname(doc)
143 # TODO: requests
144 return Application(appname, pkgname, "")
145163
146 def get_appname(self, doc):164 def get_appname(self, doc):
147 appname = doc.get_value(XapianValues.APPNAME)165 app = self.db.get_application(doc)
148 if not appname:166 return app.get_display_name(self.db, doc)
149 appname = self.db.get_summary(doc)
150 else:
151 if self.db.is_appname_duplicated(appname):
152 appname = "%s (%s)" % (appname, self.get_pkgname(doc))
153 return appname
154167
155 def get_markup(self, doc):168 def get_markup(self, doc):
156 appname = doc.get_value(XapianValues.APPNAME)169 app = self.db.get_application(doc)
157170
158 if not appname:171 # the logic is that "apps" are displayed normally
172 # but "packages" are displayed with their summary as name
173 if app.appname:
174 appname = self.get_appname(doc)
175 summary = self.db.get_summary(doc)
176 else:
159 appname = self.db.get_summary(doc)177 appname = self.db.get_summary(doc)
160 summary = self.get_pkgname(doc)178 summary = self.get_pkgname(doc)
161 else:
162 if self.db.is_appname_duplicated(appname):
163 appname = "%s (%s)" % (appname, self.get_pkgname(doc))
164
165 summary = self.db.get_summary(doc)
166179
167 return "%s\n<small>%s</small>" % (180 return "%s\n<small>%s</small>" % (
168 GObject.markup_escape_text(appname),181 GObject.markup_escape_text(appname),
@@ -239,44 +252,14 @@
239 else:252 else:
240 return ''253 return ''
241254
242class AppPropertiesHelper(_AppPropertiesHelper):
243
244 def __init__(self, db, cache, icons, icon_size=48, global_icon_cache=False):
245 super(AppPropertiesHelper, self).__init__()
246 self.db = db
247 self.cache = cache
248
249 cat_parser = CategoriesParser(db)
250 self.all_categories = cat_parser.parse_applications_menu(
251 softwarecenter.paths.APP_INSTALL_PATH)
252
253 # reviews stats loader
254 self.review_loader = get_review_loader(cache, db)
255
256 # icon jazz
257 self.icons = icons
258 self.icon_size = icon_size
259 # cache the 'missing icon' used in the treeview for apps without an icon
260 self._missing_icon = icons.load_icon(Icons.MISSING_APP,
261 icon_size, 0)
262
263 if global_icon_cache:
264 self.icon_cache = _app_icon_cache
265 else:
266 self.icon_cache = {}
267 return
268
269 def get_icon_at_size(self, doc, width, height):255 def get_icon_at_size(self, doc, width, height):
270 pixbuf = self.get_icon(doc)256 pixbuf = self.get_icon(doc)
271 pixbuf = pixbuf.scale_simple(width, height,257 pixbuf = pixbuf.scale_simple(width, height,
272 GdkPixbuf.InterpType.BILINEAR)258 GdkPixbuf.InterpType.BILINEAR)
273 return pixbuf259 return pixbuf
274260
275 def get_transaction_progress(self, doc):261
276 raise NotImplemented262class AppGenericStore(AppPropertiesHelper):
277
278
279class AppGenericStore(_AppPropertiesHelper):
280263
281 # column types264 # column types
282 COL_TYPES = (GObject.TYPE_PYOBJECT,)265 COL_TYPES = (GObject.TYPE_PYOBJECT,)
@@ -291,12 +274,8 @@
291 LOAD_INITIAL = 75274 LOAD_INITIAL = 75
292275
293 def __init__(self, db, cache, icons, icon_size, global_icon_cache):276 def __init__(self, db, cache, icons, icon_size, global_icon_cache):
294 # the usual suspects277 AppPropertiesHelper.__init__(self, db, cache, icons, icon_size,
295 self.db = db278 global_icon_cache)
296 self.cache = cache
297
298 # reviews stats loader
299 self.review_loader = get_review_loader(cache, db)
300279
301 # backend stuff280 # backend stuff
302 self.backend = get_install_backend()281 self.backend = get_install_backend()
@@ -307,21 +286,9 @@
307 # keep track of paths for transactions in progress286 # keep track of paths for transactions in progress
308 self.transaction_path_map = {}287 self.transaction_path_map = {}
309288
310 # icon jazz
311 self.icons = icons
312 self.icon_size = icon_size
313
314 if global_icon_cache:
315 self.icon_cache = _app_icon_cache
316 else:
317 self.icon_cache = {}
318
319 # active row path289 # active row path
320 self.active_row = None290 self.active_row = None
321291
322 # cache the 'missing icon' used in the treeview for apps without an icon
323 self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0)
324
325 self._in_progress = False292 self._in_progress = False
326 self._break = False293 self._break = False
327294
@@ -396,6 +363,10 @@
396 GObject.idle_add(buffer_icons)363 GObject.idle_add(buffer_icons)
397 return364 return
398365
366 def load_range(self, indices, step):
367 # stub
368 return
369
399class AppListStore(Gtk.ListStore, AppGenericStore):370class AppListStore(Gtk.ListStore, AppGenericStore):
400 """ use for flat applist views. for large lists this appends rows approx371 """ use for flat applist views. for large lists this appends rows approx
401 three times faster than the AppTreeStore equivalent372 three times faster than the AppTreeStore equivalent
@@ -526,3 +497,4 @@
526 self.transaction_path_map = {}497 self.transaction_path_map = {}
527 Gtk.TreeStore.clear(self)498 Gtk.TreeStore.clear(self)
528 return499 return
500
529501
=== modified file 'softwarecenter/ui/gtk3/panes/installedpane.py'
--- softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-06 18:19:33 +0000
+++ softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-08 15:25:23 +0000
@@ -30,7 +30,8 @@
3030
31from softwarecenter.enums import (NonAppVisibility,31from softwarecenter.enums import (NonAppVisibility,
32 SortMethods)32 SortMethods)
33from softwarecenter.utils import wait_for_apt_cache_ready, utf833from softwarecenter.utils import (
34 wait_for_apt_cache_ready, utf8, ExecutionTime)
34from softwarecenter.db.categories import (CategoriesParser,35from softwarecenter.db.categories import (CategoriesParser,
35 categories_sorted_by_name)36 categories_sorted_by_name)
36from softwarecenter.ui.gtk3.models.appstore2 import (37from softwarecenter.ui.gtk3.models.appstore2 import (
@@ -209,6 +210,8 @@
209 # hacky, hide the header210 # hacky, hide the header
210 self.app_view.header_hbox.hide()211 self.app_view.header_hbox.hide()
211212
213 self.hide_appview_spinner()
214
212 # now we are initialized215 # now we are initialized
213 self.emit("installed-pane-created")216 self.emit("installed-pane-created")
214 217
@@ -313,6 +316,10 @@
313 model = self.base_model # base model not treefilter316 model = self.base_model # base model not treefilter
314 model.clear()317 model.clear()
315318
319 def profiled_rebuild_categorised_view():
320 with ExecutionTime("rebuild_categorized_view"):
321 rebuild_categorised_view()
322
316 def rebuild_categorised_view():323 def rebuild_categorised_view():
317 self.cat_docid_map = {}324 self.cat_docid_map = {}
318 enq = self.enquirer325 enq = self.enquirer
@@ -324,6 +331,7 @@
324331
325 xfilter = AppFilter(self.db, self.cache)332 xfilter = AppFilter(self.db, self.cache)
326 xfilter.set_installed_only(True)333 xfilter.set_installed_only(True)
334
327 for cat in self._all_cats:335 for cat in self._all_cats:
328 # for each category do category query and append as a new336 # for each category do category query and append as a new
329 # node to tree_view337 # node to tree_view
@@ -379,9 +387,6 @@
379 # hide the local spinner387 # hide the local spinner
380 self.hide_installed_view_spinner()388 self.hide_installed_view_spinner()
381 389
382 # hide the main spinner (if it's showing)
383 self.hide_appview_spinner()
384
385 if window:390 if window:
386 window.set_cursor(None)391 window.set_cursor(None)
387 392
@@ -392,7 +397,7 @@
392 self.emit("app-list-changed", i)397 self.emit("app-list-changed", i)
393 return398 return
394399
395 GObject.idle_add(rebuild_categorised_view)400 GObject.idle_add(profiled_rebuild_categorised_view)
396 return401 return
397 402
398 def _build_oneconfview(self):403 def _build_oneconfview(self):
@@ -407,6 +412,10 @@
407 model = self.base_model # base model not treefilter412 model = self.base_model # base model not treefilter
408 model.clear()413 model.clear()
409414
415 def profiled_rebuild_oneconfview():
416 with ExecutionTime("rebuild_oneconfview"):
417 rebuild_oneconfview()
418
410 def rebuild_oneconfview():419 def rebuild_oneconfview():
411 420
412 # FIXME for P: hide the search entry421 # FIXME for P: hide the search entry
@@ -487,7 +496,7 @@
487 self.emit("app-list-changed", i)496 self.emit("app-list-changed", i)
488 return497 return
489498
490 GObject.idle_add(rebuild_oneconfview)499 GObject.idle_add(profiled_rebuild_oneconfview)
491 return500 return
492501
493 def _check_expand(self):502 def _check_expand(self):
494503
=== modified file 'softwarecenter/ui/gtk3/views/appview.py'
--- softwarecenter/ui/gtk3/views/appview.py 2012-03-07 06:02:07 +0000
+++ softwarecenter/ui/gtk3/views/appview.py 2012-03-08 15:25:23 +0000
@@ -16,20 +16,18 @@
16# this program; if not, write to the Free Software Foundation, Inc.,16# this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1818
19#~ from __future__ import with_statement
2019
21import logging20import logging
2221
23from gi.repository import Gtk, GObject22from gi.repository import Gtk, GObject
24from gettext import gettext as _23from gettext import gettext as _
25#~ import gettext
2624
27from softwarecenter.enums import SortMethods25from softwarecenter.enums import SortMethods
28from softwarecenter.ui.gtk3.em import StockEms26from softwarecenter.ui.gtk3.em import StockEms
29from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore27from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore
30from softwarecenter.ui.gtk3.widgets.apptreeview import AppTreeView28from softwarecenter.ui.gtk3.widgets.apptreeview import AppTreeView
31from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper29from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper
32#~ from softwarecenter.ui.gtk3.widgets.containers import FlowableGrid30from softwarecenter.utils import ExecutionTime
3331
34LOG=logging.getLogger(__name__)32LOG=logging.getLogger(__name__)
3533
@@ -191,10 +189,10 @@
191 # ... also we dont currently support user sorting in the189 # ... also we dont currently support user sorting in the
192 # installedview, so issue is somewhat moot for the time being...190 # installedview, so issue is somewhat moot for the time being...
193 if isinstance(self.tree_view.appmodel, AppTreeStore):191 if isinstance(self.tree_view.appmodel, AppTreeStore):
192 LOG.debug("display_matches called on AppTreeStore, ignoring")
194 return193 return
195194
196 sort_by_relevance = is_search and not self.user_defined_sort_method195 sort_by_relevance = is_search and not self.user_defined_sort_method
197
198 if sort_by_relevance:196 if sort_by_relevance:
199 self._use_combobox_with_sort_by_search_ranking()197 self._use_combobox_with_sort_by_search_ranking()
200 self.set_sort_method_with_no_signal(self._SORT_BY_SEARCH_RANKING)198 self.set_sort_method_with_no_signal(self._SORT_BY_SEARCH_RANKING)
@@ -257,30 +255,91 @@
257 py+self.tree_view.selected_row_renderer.icon_y_offset)255 py+self.tree_view.selected_row_renderer.icon_y_offset)
258256
259257
258
259
260
261# ----------------------------------------------- testcode
262from softwarecenter.enums import NonAppVisibility
263
264def get_query_from_search_entry(search_term):
265 import xapian
266 if not search_term:
267 return xapian.Query("")
268 parser = xapian.QueryParser()
269 user_query = parser.parse_query(search_term)
270 return user_query
271
272def on_entry_changed(widget, data):
273
274 def _work():
275 new_text = widget.get_text()
276 (view, enquirer) = data
277
278 with ExecutionTime("total time"):
279 with ExecutionTime("enquire.set_query()"):
280 enquirer.set_query(get_query_from_search_entry(new_text),
281 limit=100*1000,
282 nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE)
283
284 store = view.tree_view.get_model()
285 with ExecutionTime("store.clear()"):
286 store.clear()
287
288 with ExecutionTime("store.set_from_matches()"):
289 store.set_from_matches(enquirer.matches)
290
291 with ExecutionTime("model settle (size=%s)" % len(store)):
292 while Gtk.events_pending():
293 Gtk.main_iteration()
294 return
295
296 if widget.stamp:
297 GObject.source_remove(widget.stamp)
298 widget.stamp = GObject.timeout_add(250, _work)
299
260def get_test_window():300def get_test_window():
301 import softwarecenter.log
302 softwarecenter.log.root.setLevel(level=logging.DEBUG)
303 softwarecenter.log.add_filters_from_string("performance")
304 fmt = logging.Formatter("%(name)s - %(message)s", None)
305 softwarecenter.log.handler.setFormatter(fmt)
306
261 from softwarecenter.testutils import (307 from softwarecenter.testutils import (
262 get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache,308 get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache)
263 get_test_enquirer_matches)
264 from softwarecenter.ui.gtk3.models.appstore2 import AppListStore309 from softwarecenter.ui.gtk3.models.appstore2 import AppListStore
265310
266 db = get_test_db()311 db = get_test_db()
267 cache = get_test_pkg_info()312 cache = get_test_pkg_info()
268 icons = get_test_gtk3_icon_cache()313 icons = get_test_gtk3_icon_cache()
269314
270 # create the view315 # create a filter
271 appview = AppView(db, cache, icons, show_ratings=True)316 from softwarecenter.db.appfilter import AppFilter
272 liststore = AppListStore(db, cache, icons)317 filter = AppFilter(db, cache)
273 appview.set_model(liststore)318 filter.set_supported_only(False)
274319 filter.set_installed_only(True)
275 # do a simple query and display that320
276 appview.display_matches(get_test_enquirer_matches(db))321 # appview
277322 from softwarecenter.db.enquire import AppEnquire
278 # and put it in the window323 enquirer = AppEnquire(cache, db)
324 store = AppListStore(db, cache, icons)
325
326 from softwarecenter.ui.gtk3.views.appview import AppView
327 view = AppView(db, cache, icons, show_ratings=True)
328 view.set_model(store)
329
330 entry = Gtk.Entry()
331 entry.stamp = 0
332 entry.connect("changed", on_entry_changed, (view, enquirer))
333
334 box = Gtk.VBox()
335 box.pack_start(entry, False, True, 0)
336 box.pack_start(view, True, True, 0)
337
279 win = Gtk.Window()338 win = Gtk.Window()
280 win.add(appview)339 win.set_data("appview", view)
281 win.set_data("appview", appview)340 win.set_data("entry", entry)
282
283 win.connect("destroy", lambda x: Gtk.main_quit())341 win.connect("destroy", lambda x: Gtk.main_quit())
342 win.add(box)
284 win.set_size_request(600, 400)343 win.set_size_request(600, 400)
285 win.show_all()344 win.show_all()
286345
@@ -288,4 +347,5 @@
288347
289if __name__ == "__main__":348if __name__ == "__main__":
290 win = get_test_window()349 win = get_test_window()
350 win.get_data("entry").set_text("gtk3")
291 Gtk.main()351 Gtk.main()
292352
=== modified file 'softwarecenter/ui/gtk3/widgets/apptreeview.py'
--- softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-07 06:02:07 +0000
+++ softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-08 15:25:23 +0000
@@ -1,7 +1,5 @@
1from gi.repository import Gtk, Gdk, GObject1from gi.repository import Gtk, Gdk, GObject
2import logging2import logging
3import os
4import xapian
53
6from gettext import gettext as _4from gettext import gettext as _
75
@@ -13,7 +11,7 @@
13 CellButtonIDs)11 CellButtonIDs)
1412
15from softwarecenter.ui.gtk3.em import em, StockEms13from softwarecenter.ui.gtk3.em import em, StockEms
16from softwarecenter.enums import (AppActions, NonAppVisibility, Icons)14from softwarecenter.enums import (AppActions, Icons)
17from softwarecenter.utils import ExecutionTime15from softwarecenter.utils import ExecutionTime
18from softwarecenter.backend import get_install_backend16from softwarecenter.backend import get_install_backend
19from softwarecenter.netstatus import (get_network_watcher,17from softwarecenter.netstatus import (get_network_watcher,
@@ -168,7 +166,8 @@
168 return None166 return None
169167
170 def get_rowref(self, model, path):168 def get_rowref(self, model, path):
171 if path == None: return None169 if path == None:
170 return None
172 return model[path][AppGenericStore.COL_ROW_DATA]171 return model[path][AppGenericStore.COL_ROW_DATA]
173172
174 def rowref_is_category(self, rowref):173 def rowref_is_category(self, rowref):
@@ -469,6 +468,12 @@
469468
470 path = model.get_path(it)469 path = model.get_path(it)
471470
471 # this will give us the right underlying model regardless if its
472 # a TreeModelFilter, a AppTreeStore or a AppListStore
473 model = self.appmodel
474
475 # this will pre-load data *only* on a AppListStore, it has
476 # no effect with a AppTreeStore
472 if model[path][0] is None:477 if model[path][0] is None:
473 indices = path.get_indices()478 indices = path.get_indices()
474 model.load_range(indices, 5)479 model.load_range(indices, 5)
@@ -586,41 +591,6 @@
586 return self.get_path_at_pos(x, y)[0] == self.get_cursor()[0]591 return self.get_path_at_pos(x, y)[0] == self.get_cursor()[0]
587592
588593
589def get_query_from_search_entry(search_term):
590 if not search_term:
591 return xapian.Query("")
592 parser = xapian.QueryParser()
593 user_query = parser.parse_query(search_term)
594 return user_query
595
596def on_entry_changed(widget, data):
597
598 def _work():
599 new_text = widget.get_text()
600 (view, enquirer) = data
601
602 with ExecutionTime("total time"):
603 with ExecutionTime("enquire.set_query()"):
604 enquirer.set_query(get_query_from_search_entry(new_text),
605 limit=100*1000,
606 nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE)
607
608 store = view.tree_view.get_model()
609 with ExecutionTime("store.clear()"):
610 store.clear()
611
612 with ExecutionTime("store.set_documents()"):
613 store.set_from_matches(enquirer.matches)
614
615 with ExecutionTime("model settle (size=%s)" % len(store)):
616 while Gtk.events_pending():
617 Gtk.main_iteration()
618 return
619
620 if widget.stamp: GObject.source_remove(widget.stamp)
621 widget.stamp = GObject.timeout_add(250, _work)
622
623
624594
625def get_test_window():595def get_test_window():
626 import softwarecenter.log596 import softwarecenter.log
@@ -629,24 +599,13 @@
629 fmt = logging.Formatter("%(name)s - %(message)s", None)599 fmt = logging.Formatter("%(name)s - %(message)s", None)
630 softwarecenter.log.handler.setFormatter(fmt)600 softwarecenter.log.handler.setFormatter(fmt)
631601
632 from softwarecenter.paths import XAPIAN_BASE_PATH602 from softwarecenter.testutils import (
633 xapian_base_path = XAPIAN_BASE_PATH603 get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache,
634 pathname = os.path.join(xapian_base_path, "xapian")604 get_test_categories)
635605
636 # the store606 cache = get_test_pkg_info()
637 from softwarecenter.db.pkginfo import get_pkg_info607 db = get_test_db()
638 cache = get_pkg_info()608 icons = get_test_gtk3_icon_cache()
639 cache.open()
640
641 # the db
642 from softwarecenter.db.database import StoreDatabase
643 db = StoreDatabase(pathname, cache)
644 db.open()
645
646 # additional icons come from app-install-data
647 icons = Gtk.IconTheme.get_default()
648 icons.prepend_search_path("/usr/share/app-install/icons/")
649 icons.prepend_search_path("/usr/share/software-center/icons/")
650609
651 # create a filter610 # create a filter
652 from softwarecenter.db.appfilter import AppFilter611 from softwarecenter.db.appfilter import AppFilter
@@ -654,30 +613,29 @@
654 filter.set_supported_only(False)613 filter.set_supported_only(False)
655 filter.set_installed_only(True)614 filter.set_installed_only(True)
656615
657 # appview616 # get the TREEstore
658 from softwarecenter.ui.gtk3.models.appstore2 import AppListStore617 from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore
659 from softwarecenter.db.enquire import AppEnquire618 store = AppTreeStore(db, cache, icons)
660 enquirer = AppEnquire(cache, db)
661 store = AppListStore(db, cache, icons)
662619
620 # populate from data
621 cats = get_test_categories(db)
622 for cat in cats[:3]:
623 with ExecutionTime("query cat '%s'" % cat.name):
624 docs = db.get_docs_from_query(cat.query)
625 store.set_category_documents(cat, docs)
626
627 # ok, this is confusing - the AppView contains the AppTreeView that
628 # is a tree or list depending on the model
663 from softwarecenter.ui.gtk3.views.appview import AppView629 from softwarecenter.ui.gtk3.views.appview import AppView
664 view = AppView(db, cache, icons, show_ratings=True)630 app_view = AppView(db, cache, icons, show_ratings=True)
665 view.set_model(store)631 app_view.set_model(store)
666632
667 entry = Gtk.Entry()
668 entry.stamp = 0
669 entry.connect("changed", on_entry_changed, (view, enquirer))
670 entry.set_text("gtk3")
671
672 scroll = Gtk.ScrolledWindow()
673 box = Gtk.VBox()633 box = Gtk.VBox()
674 box.pack_start(entry, False, True, 0)634 box.pack_start(app_view, True, True, 0)
675 box.pack_start(scroll, True, True, 0)
676635
677 win = Gtk.Window()636 win = Gtk.Window()
637 win.add(box)
678 win.connect("destroy", lambda x: Gtk.main_quit())638 win.connect("destroy", lambda x: Gtk.main_quit())
679 scroll.add(view)
680 win.add(box)
681 win.set_size_request(600, 400)639 win.set_size_request(600, 400)
682 win.show_all()640 win.show_all()
683641
684642
=== modified file 'test/gtk3/test_app_view.py'
--- test/gtk3/test_app_view.py 2012-01-16 14:42:49 +0000
+++ test/gtk3/test_app_view.py 2012-03-08 15:25:23 +0000
@@ -1,11 +1,8 @@
1#!/usr/bin/python1#!/usr/bin/python
22
3import time
4import unittest3import unittest
5import xapian4import xapian
65
7from gi.repository import Gtk
8
9from testutils import setup_test_env6from testutils import setup_test_env
10setup_test_env()7setup_test_env()
118
@@ -15,6 +12,7 @@
15from softwarecenter.testutils import (get_test_db,12from softwarecenter.testutils import (get_test_db,
16 get_test_pkg_info,13 get_test_pkg_info,
17 get_test_gtk3_icon_cache,14 get_test_gtk3_icon_cache,
15 do_events,
18 )16 )
1917
20class TestAppView(unittest.TestCase):18class TestAppView(unittest.TestCase):
@@ -39,7 +37,7 @@
39 # set matches37 # set matches
40 appview.clear_model()38 appview.clear_model()
41 appview.display_matches(enquirer.matches)39 appview.display_matches(enquirer.matches)
42 self._p()40 do_events()
43 # verify that the order is actually the correct one41 # verify that the order is actually the correct one
44 model = appview.tree_view.get_model()42 model = appview.tree_view.get_model()
45 docs_in_model = [item[0] for item in model]43 docs_in_model = [item[0] for item in model]
@@ -49,15 +47,61 @@
49 for i in range(len(docs_in_model)):47 for i in range(len(docs_in_model)):
50 self.assertEqual(self.db.get_pkgname(docs_in_model[i]),48 self.assertEqual(self.db.get_pkgname(docs_in_model[i]),
51 self.db.get_pkgname(docs_from_enquirer[i]))49 self.db.get_pkgname(docs_from_enquirer[i]))
5250 win.destroy()
53 def _p(self):51
54 for i in range(5):52 def test_appview_search_combo(self):
55 time.sleep(0.1)53 from softwarecenter.ui.gtk3.views.appview import get_test_window
56 while Gtk.events_pending():54 from softwarecenter.testutils import get_test_enquirer_matches
57 Gtk.main_iteration()55
56 # test if combox sort option "by relevance" vanishes for non-searches
57 # LP: #861778
58 expected_normal = ["By Name", "By Top Rated", "By Newest First"]
59 expected_search = ["By Name", "By Top Rated", "By Newest First",
60 "By Relevance"]
61
62 # setup goo
63 win = get_test_window()
64 appview = win.get_data("appview")
65 #entry = win.get_data("entry")
66 do_events()
67
68 # get the model
69 model = appview.sort_methods_combobox.get_model()
70
71 # test normal window (no search)
72 matches = get_test_enquirer_matches(appview.helper.db)
73 appview.display_matches(matches, is_search=False)
74 do_events()
75 in_model = []
76 for item in model:
77 in_model.append(model.get_value(item.iter, 0))
78 self.assertEqual(in_model, expected_normal)
79
80 # now repeat and simulate a search
81 matches = get_test_enquirer_matches(appview.helper.db)
82 appview.display_matches(matches, is_search=True)
83 do_events()
84 in_model = []
85 for item in model:
86 in_model.append(model.get_value(item.iter, 0))
87 self.assertEqual(in_model, expected_search)
88
89 # and back again to no search
90 matches = get_test_enquirer_matches(appview.helper.db)
91 appview.display_matches(matches, is_search=False)
92 do_events()
93 # collect items in the model
94 in_model = []
95 for item in model:
96 in_model.append(model.get_value(item.iter, 0))
97 self.assertEqual(expected_normal, in_model)
98
99 # destroy
100 win.destroy()
101
58 102
59103
60if __name__ == "__main__":104if __name__ == "__main__":
61 import logging105 #import logging
62 logging.basicConfig(level=logging.DEBUG)106 #logging.basicConfig(level=logging.DEBUG)
63 unittest.main()107 unittest.main()
64108
=== removed file 'test/gtk3/test_appview.py'
--- test/gtk3/test_appview.py 2012-01-16 14:42:49 +0000
+++ test/gtk3/test_appview.py 1970-01-01 00:00:00 +0000
@@ -1,72 +0,0 @@
1#!/usr/bin/python
2
3from gi.repository import Gtk, GObject
4import time
5import unittest
6
7from testutils import setup_test_env
8setup_test_env()
9
10#from mock import Mock
11
12TIMEOUT=300
13
14class TestViews(unittest.TestCase):
15
16 def test_appview_search_combo(self):
17 from softwarecenter.ui.gtk3.views.appview import get_test_window
18 from softwarecenter.testutils import get_test_enquirer_matches
19
20 # test if combox sort option "by relevance" vanishes for non-searches
21 # LP: #861778
22 expected_normal = ["By Name", "By Top Rated", "By Newest First"]
23 expected_search = ["By Name", "By Top Rated", "By Newest First",
24 "By Relevance"]
25
26 # setup goo
27 win = get_test_window()
28 self._p()
29 appview = win.get_data("appview")
30
31 # test normal window (no search)
32 model = appview.sort_methods_combobox.get_model()
33 # collect items in the model
34 in_model = []
35 for item in model:
36 in_model.append(model.get_value(item.iter, 0))
37 # this is what we expect there
38 self.assertEqual(expected_normal, in_model)
39
40 # now repeat and simulate a search
41 matches = get_test_enquirer_matches(appview.helper.db)
42 appview.display_matches(matches, is_search=True)
43 self._p()
44 in_model = []
45 for item in model:
46 in_model.append(model.get_value(item.iter, 0))
47 self.assertEqual(in_model, expected_search)
48
49 # and back again to no search
50 matches = get_test_enquirer_matches(appview.helper.db)
51 appview.display_matches(matches, is_search=False)
52 self._p()
53 # collect items in the model
54 in_model = []
55 for item in model:
56 in_model.append(model.get_value(item.iter, 0))
57 self.assertEqual(expected_normal, in_model)
58
59 # destroy
60 GObject.timeout_add(TIMEOUT, lambda: win.destroy())
61 Gtk.main()
62
63 def _p(self):
64 for i in range(10):
65 time.sleep(0.1)
66 while Gtk.events_pending():
67 Gtk.main_iteration()
68
69if __name__ == "__main__":
70 import logging
71 logging.basicConfig(level=logging.DEBUG)
72 unittest.main()

Subscribers

People subscribed via source and target branches