diff -Nru software-center-5.1.11/contrib/simulate-slow-network.sh software-center-5.1.12/contrib/simulate-slow-network.sh --- software-center-5.1.11/contrib/simulate-slow-network.sh 1970-01-01 00:00:00.000000000 +0000 +++ software-center-5.1.12/contrib/simulate-slow-network.sh 2012-03-08 19:37:37.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/sh + +if [ -z "$1" ]; then + NETDEV=$(route -n|grep ^0.0.0.0|awk '{print $8}') +else + NETDEV="$1" +fi + +if [ "$(id -u)" != "0" ]; then + echo "You need to be root to run this script" + exit 1 +fi + +if [ -z "$NETDEV" ]; then + echo "Can not find a default netdev, please specifcy one" + exit 1 +fi + +echo "Simulating slow network for default gateway device $NETDEV" + +# reset +tc qdisc del dev $NETDEV root 2> /dev/null + +# make it slow +tc qdisc add dev $NETDEV root handle 1: tbf rate 64kbit buffer 1600 limit 3000 +tc qdisc add dev $NETDEV parent 1: handle 10: netem delay 1000ms diff -Nru software-center-5.1.11/data/expunge-cache.py software-center-5.1.12/data/expunge-cache.py --- software-center-5.1.11/data/expunge-cache.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/data/expunge-cache.py 2012-03-07 17:25:50.000000000 +0000 @@ -75,6 +75,9 @@ print "Need either --by-days or --by-unsuccessful-http-states argument" sys.exit(1) + # be nice + os.nice(19) + # do it cleaner = ExpungeCache(args.directories, args) cleaner.clean() diff -Nru software-center-5.1.11/debian/changelog software-center-5.1.12/debian/changelog --- software-center-5.1.11/debian/changelog 2012-03-01 19:11:27.000000000 +0000 +++ software-center-5.1.12/debian/changelog 2012-03-09 07:55:51.000000000 +0000 @@ -1,3 +1,69 @@ +software-center (5.1.12) precise; urgency=low + + [ Michael Vogt ] + * lp:~mvo/software-center/webcam-string-fix: + - small fix to support the debtagshw updated tags for hardware::camera + (split into webcam,digicam now) + * lp:~mvo/software-center/trivial-nm-state-override: + - support the SOFTWARE_CENTER_NET_CONNECTED environment value to + force the connected state as a stopgap workaround for bug 911706 + * lp:~mvo/software-center/lp941361: + - adds a general make_string_from_list() helper to build (somewhat) + i18n friendly human readable strings easily (LP: #941361) + * lp:~mvo/software-center/expunge-cache: + - merge os.nice() addition + * lp:~mvo/software-center/lp789596: + - better (less scary) string for updates from third-party + venders (LP: #789596) + * lp:~mvo/software-center/fix-refresh-of-whats-new: + - fix missing refresh of the what's new content on a database + reopen so that new content from the agent appears as soon + as it finishes the update + * lp:~mvo/software-center/review-fixes: + - ensure ui is correctly updated after submitting/modifying review + * lp:~mvo/software-center/simulate-slow-network: + - add a small helper to simulate a slow network connection to + see if we have hidden latencies in the UI when the network + is (really) slow + * lp:~mvo/software-center/top-rated-refresh: + - ensure that the top-rated apps are refreshed when we have new data + * lp:~mvo/software-center/apptreeview-tweaks: + - fix 'load_range" errors when navigating the installed view + (LP: #913675), and do some nice needed refactoring/cleanup + + [ Anthony Lenton ] + * lp:~elachuni/software-center/dont-store: + - consolidate Ubunty SSO logins to use "Ubuntu Software Center", fixes + inconsistent UI and storing of two keys in they keyring, as well as + being prompted to log in twice the first time that you review an app + * lp:~elachuni/software-center/pep8-test, + lp:~elachuni/software-center/pep8-test-part2, + lp:~elachuni/software-center/pep8-test-part3, + lp:~elachuni/software-center/pep8-test-part4: + - add a unit test to check code statically for pep8 compliance and update + more and more of the code to meet it + + [ Gary Lasker ] + * lp:~gary-lasker/software-center/fix-crash-lp944875: + - Fix an intermittent crash that can happen if the installed view pane + has not been built yet when a call to show the spinner is made as a + result of a refresh (LP: #944875) + * lp:~gary-lasker/software-center/list-view-icon-coordinates-lp947624: + - This branch adds support for providing the correct icon size and + on-screen coordinates values in the Unity launcher integration dbus + call when an installation is initiated via the list view + (LP: #947624) + * lp:~gary-lasker/software-center/enable-published-date-unit-test: + - unit test change only, enable the published-date unit test that was + disabled pending deployment of support on the staging server + + [ Natalia Bidart ] + * lp:~nataliabidart/software-center/one-auth: + - use consistently the same app name for every Ubuntu SSO call to + ensure SSO tokens are handled properly + + -- Michael Vogt Fri, 09 Mar 2012 08:55:46 +0100 + software-center (5.1.11) precise; urgency=low [ Michael Vogt ] diff -Nru software-center-5.1.11/README software-center-5.1.12/README --- software-center-5.1.11/README 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/README 2012-03-08 19:37:37.000000000 +0000 @@ -11,7 +11,7 @@ extra packages are installed: sudo apt-get install xvfb python-coverage python-mock python-aptdaemon.test \ - python-qt4 python-unittest2 python-lxml + python-qt4 python-unittest2 python-lxml pep8 sudo apt-get build-dep software-center You can then run tests with: diff -Nru software-center-5.1.11/softwarecenter/backend/reviews/__init__.py software-center-5.1.12/softwarecenter/backend/reviews/__init__.py --- software-center-5.1.11/softwarecenter/backend/reviews/__init__.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/backend/reviews/__init__.py 2012-03-08 19:59:06.000000000 +0000 @@ -209,15 +209,23 @@ setattr(review, k, v) return review -class ReviewLoader(object): +class ReviewLoader(GObject.GObject): """A loader that returns a review object list""" + __gsignals__ = { + "refresh-review-stats-finished" : (GObject.SIGNAL_RUN_LAST, + GObject.TYPE_NONE, + (GObject.TYPE_PYOBJECT,), + ), + } + # cache the ReviewStats REVIEW_STATS_CACHE = {} _cache_version_old = False _review_sort_methods = ReviewSortMethods.REVIEW_SORT_METHODS def __init__(self, cache, db, distro=None): + GObject.GObject.__init__(self) self.cache = cache self.db = db self.distro = distro @@ -436,6 +444,7 @@ IPSUM = "no ipsum\n\nstill no ipsum" def __init__(self, cache, db): + ReviewLoader.__init__(self, cache, db) self._review_stats_cache = {} self._reviews_cache = {} def _random_person(self): @@ -614,6 +623,7 @@ """A dummy review loader which just returns empty results.""" def __init__(self, cache, db): + ReviewLoader.__init__(self, cache, db) self._review_stats_cache = {} self._reviews_cache = {} diff -Nru software-center-5.1.11/softwarecenter/backend/reviews/rnr.py software-center-5.1.12/softwarecenter/backend/reviews/rnr.py --- software-center-5.1.11/softwarecenter/backend/reviews/rnr.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/backend/reviews/rnr.py 2012-03-08 19:37:37.000000000 +0000 @@ -169,6 +169,7 @@ review_stats[s.app] = s self.REVIEW_STATS_CACHE = review_stats callback(review_stats) + self.emit("refresh-review-stats-finished", review_stats) self.save_review_stats_cache_file() def _server_has_histogram(self, piston_review_stats): @@ -210,7 +211,6 @@ successfully the callback is triggered with the new reviews """ LOG.debug("_on_submit_review_data") - return # read stdout from submit_review review = ReviewDetails.from_dict(review_json) # FIXME: ideally this would be stored in ubuntu-sso-client @@ -356,7 +356,6 @@ def _on_modify_review_finished(self, spawn_helper, review_json, review_id, callback): """called when modify_review finished""" LOG.debug("_on_modify_review_finished") - return #review_json = spawn_helper._stdout mod_review = ReviewDetails.from_dict(review_json) for (app, reviews) in self._reviews.items(): diff -Nru software-center-5.1.11/softwarecenter/db/application.py software-center-5.1.12/softwarecenter/db/application.py --- software-center-5.1.11/softwarecenter/db/application.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/db/application.py 2012-03-08 15:15:30.000000000 +0000 @@ -103,6 +103,8 @@ if doc: appname = db.get_appname(doc) if appname: + if db.is_appname_duplicated(appname): + appname = "%s (%s)" % (appname, db.get_pkgname(doc)) return appname else: return db.get_summary(doc) diff -Nru software-center-5.1.11/softwarecenter/db/pkginfo_impl/aptcache.py software-center-5.1.12/softwarecenter/db/pkginfo_impl/aptcache.py --- software-center-5.1.11/softwarecenter/db/pkginfo_impl/aptcache.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/db/pkginfo_impl/aptcache.py 2012-03-08 07:48:06.000000000 +0000 @@ -32,6 +32,7 @@ LOG = logging.getLogger(__name__) + class GtkMainIterationProgress(apt.progress.base.OpProgress): """Progress that just runs the main loop""" def update(self, percent=0): @@ -39,6 +40,7 @@ while context.pending(): context.iteration() + def convert_package_argument(f): """ decorator converting _Package argument to Package object from cache """ def _converted(self, pkg, *args): @@ -47,18 +49,20 @@ if type(pkg) is str: pkg = self._cache[pkg] else: - pkg = self._cache[pkg.name] + pkg = self._cache[pkg.name] except Exception as e: logging.exception(e) pkg = None return f(self, pkg, *args) return _converted + def pkg_downloaded(pkg_version): filename = os.path.basename(pkg_version.filename) # FIXME: use relative path here return os.path.exists("/var/cache/apt/archives/" + filename) + class AptCacheVersion(_Version): def __init__(self, version): self.ver = version @@ -66,24 +70,31 @@ @property def description(self): return self.ver.description + @property def summary(self): return self.ver.summary + @property def size(self): return self.ver.size + @property def installed_size(self): return self.ver.installed_size + @property def version(self): return self.ver.version + @property def origins(self): return self.ver.origins + @property def downloadable(self): return self.ver.downloadable + @property def not_automatic(self): priority = self.ver.policy_priority @@ -91,8 +102,9 @@ return True return False + class AptCache(PackageInfo): - """ + """ A apt cache that opens in the background and keeps the UI alive """ @@ -115,8 +127,10 @@ self._ready = False self._timeout_id = None # setup monitor watch for install/remove changes - self.apt_finished_stamp=Gio.File.new_for_path(self.APT_FINISHED_STAMP) - self.apt_finished_monitor = self.apt_finished_stamp.monitor_file(0, None) + self.apt_finished_stamp = Gio.File.new_for_path( + self.APT_FINISHED_STAMP) + self.apt_finished_monitor = self.apt_finished_stamp.monitor_file(0, + None) self.apt_finished_monitor.connect( "changed", self._on_apt_finished_stamp_changed) # this is fast, so ok @@ -125,10 +139,12 @@ @staticmethod def version_compare(a, b): return apt_pkg.version_compare(a, b) + @staticmethod def upstream_version_compare(a, b): return apt_pkg.version_compare(apt_pkg.upstream_version(a), apt_pkg.upstream_version(b)) + @staticmethod def upstream_version(v): return apt_pkg.upstream_version(v) @@ -138,11 +154,13 @@ lowlevel_cache = self._cache._cache return (pkgname in lowlevel_cache and lowlevel_cache[pkgname].current_ver is not None) + def is_upgradable(self, pkgname): # use the lowlevel cache here, twice as fast if not pkgname in self._cache: return False return self._cache[pkgname].is_upgradable + def is_available(self, pkgname): return (pkgname in self._cache and self._cache[pkgname].candidate) @@ -166,7 +184,7 @@ return [AptCacheVersion(v) for v in self._cache[pkgname].versions] def get_section(self, pkgname): - if (pkgname not in self._cache or + if (pkgname not in self._cache or not self._cache[pkgname].candidate): return '' return self._cache[pkgname].candidate.section @@ -209,8 +227,10 @@ @property def ready(self): return self._ready + def get_license(self, name): return None + def open(self): """ (re)open the cache, this sends cache-invalid, cache-ready signals """ @@ -231,21 +251,25 @@ # temporarely return a full apt.Package so that the tests and the # code keeps working for now, this needs to go away eventually - # and get replaced with the abstract _Package class + # and get replaced with the abstract _Package class #def __getitem__(self, key): # return self._cache[key] def __iter__(self): return self._cache.__iter__() + def __contains__(self, k): return self._cache.__contains__(k) - def _on_apt_finished_stamp_changed(self, monitor, afile, other_file, event): + + def _on_apt_finished_stamp_changed(self, monitor, afile, other_file, + event): if not event == Gio.FileMonitorEvent.CHANGES_DONE_HINT: - return + return if self._timeout_id: GObject.source_remove(self._timeout_id) self._timeout_id = None self._timeout_id = GObject.timeout_add_seconds(10, self.open) + def _get_rdepends_by_type(self, pkg, type, onlyInstalled): rdeps = set() # make sure this is a apt.Package object @@ -262,6 +286,7 @@ (onlyInstalled and self._cache[rdep_name].is_installed)): rdeps.add(rdep.parent_pkg.name) return rdeps + def _installed_dependencies(self, pkg_name, all_deps=None): """ recursively return all installed dependencies of a given pkg """ #print "_installed_dependencies", pkg_name, all_deps @@ -272,16 +297,18 @@ cur = self._cache[pkg_name]._pkg.current_ver if not cur: return all_deps - for t in self.DEPENDENCY_TYPES+self.RECOMMENDS_TYPES: + for t in self.DEPENDENCY_TYPES + self.RECOMMENDS_TYPES: try: for dep in cur.depends_list[t]: dep_name = dep[0].target_pkg.name if not dep_name in all_deps: all_deps.add(dep_name) - all_deps |= self._installed_dependencies(dep_name, all_deps) + all_deps |= self._installed_dependencies(dep_name, + all_deps) except KeyError: pass return all_deps + def get_installed_automatic_depends_for_pkg(self, pkg): """ Get the installed automatic dependencies for this given package only. @@ -298,7 +325,7 @@ except KeyError: continue else: - if (pkg.is_installed and + if (pkg.is_installed and pkg.is_auto_removable): installed_auto_deps.add(dep_name) return installed_auto_deps @@ -334,7 +361,7 @@ def get_origin(self, pkgname): """ return a uniqe origin for the given package name. currently - this will use + this will use """ if not pkgname in self._cache or not self._cache[pkgname].candidate: return @@ -352,9 +379,9 @@ """ check if the given component is enabled """ # FIXME: test for more properties here? for it in self._cache._cache.file_list: - if (it.component != "" and + if (it.component != "" and it.component == component and - it.archive != "" and + it.archive != "" and it.archive == distro_codename): return True return False @@ -365,6 +392,7 @@ if version == None: version = pkg.candidate return version.get_dependencies(*types) + def _get_depends_by_type_str(self, pkg, *types): def not_in_list(list, item): for i in list: @@ -384,33 +412,41 @@ # pkg relations def _get_depends(self, pkg): return self._get_depends_by_type_str(pkg, self.DEPENDENCY_TYPES) + def _get_recommends(self, pkg): return self._get_depends_by_type_str(pkg, self.RECOMMENDS_TYPES) + def _get_suggests(self, pkg): return self._get_depends_by_type_str(pkg, self.SUGGESTS_TYPES) + def _get_enhances(self, pkg): return self._get_depends_by_type_str(pkg, self.ENHANCES_TYPES) + @convert_package_argument def _get_provides(self, pkg): # note: can use ._cand, because pkg has been converted to apt.Package provides_list = pkg.candidate._cand.provides_list provides = [] for provided in provides_list: - provides.append(provided[0]) # the package name + provides.append(provided[0]) # the package name return provides # reverse pkg relations def _get_rdepends(self, pkg): return self._get_rdepends_by_type(pkg, self.DEPENDENCY_TYPES, False) + def _get_rrecommends(self, pkg): return self._get_rdepends_by_type(pkg, self.RECOMMENDS_TYPES, False) + def _get_rsuggests(self, pkg): return self._get_rdepends_by_type(pkg, self.SUGGESTS_TYPES, False) + def _get_renhances(self, pkg): return self._get_rdepends_by_type(pkg, self.ENHANCES_TYPES, False) + @convert_package_argument def _get_renhances_lowlevel_apt_pkg(self, pkg): - """ takes a apt_pkg.Package and returns a list of pkgnames that + """ takes a apt_pkg.Package and returns a list of pkgnames that enhance this package - this is needed to support enhances for virtual packages """ @@ -419,6 +455,7 @@ if dep.dep_type_untranslated == "Enhances": renhances.append(dep.parent_pkg.name) return renhances + def _get_rprovides(self, pkg): return self._get_rdepends_by_type(pkg, self.PROVIDES_TYPES, False) @@ -436,10 +473,13 @@ def _get_installed_rrecommends(self, pkg): return self._get_rdepends_by_type(pkg, self.RECOMMENDS_TYPES, True) + def _get_installed_rsuggests(self, pkg): return self._get_rdepends_by_type(pkg, self.SUGGESTS_TYPES, True) + def _get_installed_renhances(self, pkg): return self._get_rdepends_by_type(pkg, self.ENHANCES_TYPES, True) + def _get_installed_rprovides(self, pkg): return self._get_rdepends_by_type(pkg, self.PROVIDES_TYPES, True) @@ -450,6 +490,7 @@ if addon.startswith(template): return True return False + def _read_language_pkgs(self): language_packages = set() if not os.path.exists(self.LANGPACK_PKGDEPENDS): @@ -464,7 +505,7 @@ continue language_packages.add(language_pkg) return language_packages - + # these are used for calculating the total size @convert_package_argument def _get_changes_without_applying(self, pkg): @@ -492,6 +533,7 @@ changes[change.name] = PkgStates.UNKNOWN self._cache.clear() return changes + def _try_install_and_get_all_deps_installed(self, pkg): """ Return all dependencies of pkg that will be marked for install """ changes = self._get_changes_without_applying(pkg) @@ -500,6 +542,7 @@ if change != pkg.name and changes[change] == PkgStates.INSTALLING: installing_deps.append(change) return installing_deps + def _try_install_and_get_all_deps_removed(self, pkg): """ Return all dependencies of pkg that will be marked for remove""" changes = self._get_changes_without_applying(pkg) @@ -508,6 +551,7 @@ if change != pkg.name and changes[change] == PkgStates.REMOVING: removing_deps.append(change) return removing_deps + def _set_candidate_release(self, pkg, archive_suite): # Check if the package is provided in the release for version in pkg.versions: @@ -519,13 +563,14 @@ res = pkg._pcache._depcache.set_candidate_release( pkg._pkg, version._cand, archive_suite) return res - def get_total_size_on_install(self, pkgname, + + def get_total_size_on_install(self, pkgname, addons_install=None, addons_remove=None, archive_suite=None): pkgs_to_install = [] pkgs_to_remove = [] - total_download_size = 0 # in kB - total_install_size = 0 # in kB + total_download_size = 0 # in kB + total_install_size = 0 # in kB if not pkgname in self._cache: return (0, 0) @@ -536,7 +581,7 @@ all_install = [] if addons_install is not None: all_install += addons_install - + if version == None: # its important that its the first pkg as the depcache will # get cleared for each pkg and that will means that the @@ -552,12 +597,14 @@ version = self._cache[p].candidate pkgs_to_install.append(version) # now do it - deps_inst = self._try_install_and_get_all_deps_installed(self._cache[p]) + deps_inst = self._try_install_and_get_all_deps_installed( + self._cache[p]) for dep in deps_inst: if self._cache[dep].installed == None: dep_version = self._cache[dep].candidate pkgs_to_install.append(dep_version) - deps_remove = self._try_install_and_get_all_deps_removed(self._cache[p]) + deps_remove = self._try_install_and_get_all_deps_removed( + self._cache[p]) for dep in deps_remove: if self._cache[dep].is_installed: dep_version = self._cache[dep].installed @@ -567,12 +614,14 @@ for p in all_remove: version = self._cache[p].installed pkgs_to_remove.append(version) - deps_inst = self._try_install_and_get_all_deps_installed(self._cache[p]) + deps_inst = self._try_install_and_get_all_deps_installed( + self._cache[p]) for dep in deps_inst: if self._cache[dep].installed == None: version = self._cache[dep].candidate pkgs_to_install.append(version) - deps_remove = self._try_install_and_get_all_deps_removed(self._cache[p]) + deps_remove = self._try_install_and_get_all_deps_removed( + self._cache[p]) for dep in deps_remove: if self._cache[dep].installed != None: version = self._cache[dep].installed @@ -580,7 +629,7 @@ pkgs_to_install = list(set(pkgs_to_install)) pkgs_to_remove = list(set(pkgs_to_remove)) - + for pkg in pkgs_to_install: if not pkg_downloaded(pkg) and not pkg.package.installed: total_download_size += pkg.size @@ -610,6 +659,7 @@ :return: a tuple of pkgnames (recommends, suggests) """ logging.debug("get_addons for '%s'" % pkgname) + def _addons_filter(addon): """ helper for get_addons that filters out unneeded ones """ # we don't know about this one (prefectly legal for suggests) @@ -648,6 +698,7 @@ # looks good return True #---------------------------------------------------------------- + def _addons_filter_slow(addon): """ helper for get_addons that filters out unneeded ones """ # this addon would get installed anyway (e.g. via indirect @@ -660,7 +711,7 @@ # deb file, or pkg needing source, etc if (not pkgname in self._cache or not self._cache[pkgname].candidate): - return ([],[]) + return ([], []) # initial setup pkg = self._cache[pkgname] @@ -678,7 +729,8 @@ LOG.debug("provides: %s" % provides) for provide in provides: virtual_aptpkg_pkg = self._cache._cache[provide] - renhances = self._get_renhances_lowlevel_apt_pkg(virtual_aptpkg_pkg) + renhances = self._get_renhances_lowlevel_apt_pkg( + virtual_aptpkg_pkg) LOG.debug("renhances of %s: %s" % (provide, renhances)) addons_sug += renhances context = GObject.main_context_default() @@ -688,9 +740,9 @@ # get more addons, the idea is that if a package foo-data # just depends on foo we want to get the info about # "recommends, suggests, enhances" for foo-data as well - # + # # FIXME: find a good package where this is actually the case and - # replace the existing test + # replace the existing test # (arduino-core -> avrdude -> avrdude-doc) with that # FIXME2: if it turns out we don't have good/better examples, # kill it @@ -700,11 +752,11 @@ pkgdep = self._cache[dep] if len(self._get_rdepends(pkgdep)) == 1: # pkg is the only known package that depends on pkgdep - pkgdep_rec = self._get_recommends(pkgdep) + pkgdep_rec = self._get_recommends(pkgdep) LOG.debug("recommends from lonley dependency %s: %s" % ( pkgdep, pkgdep_rec)) addons_rec += pkgdep_rec - pkgdep_sug = self._get_suggests(pkgdep) + pkgdep_sug = self._get_suggests(pkgdep) LOG.debug("suggests from lonley dependency %s: %s" % ( pkgdep, pkgdep_sug)) addons_sug += pkgdep_sug @@ -718,26 +770,30 @@ context.iteration() # remove duplicates from suggests (sets are great!) - addons_sug = list(set(addons_sug)-set(addons_rec)) + addons_sug = list(set(addons_sug) - set(addons_rec)) # filter out stuff we don't want addons_rec = filter(_addons_filter, addons_rec) addons_sug = filter(_addons_filter, addons_sug) - # this is not integrated into the filter above, as it is quite expensive - # to run this call, so we only run it if we actually have addons + # this is not integrated into the filter above, as it is quite + # expensive to run this call, so we only run it if we actually have + # addons if addons_rec or addons_sug: # now get all_deps if the package would be installed try: - all_deps_if_installed = self._try_install_and_get_all_deps_installed(pkg) + all_deps_if_installed = \ + self._try_install_and_get_all_deps_installed(pkg) except: # if we have broken packages, then we return no addons - LOG.warn("broken packages encountered while getting deps for %s" % pkgname) - return ([],[]) + LOG.warn( + "broken packages encountered while getting deps for %s" % + pkgname) + return ([], []) # filter out stuff we don't want addons_rec = filter(_addons_filter_slow, addons_rec) addons_sug = filter(_addons_filter_slow, addons_sug) - + return (addons_rec, addons_sug) if __name__ == "__main__": @@ -756,7 +812,7 @@ print(c.get_packages_removed_on_remove(pkg)) print(c._get_installed_rrecommends(pkg)) print(c._get_installed_rsuggests(pkg)) - + print("deps of gimp") pkg = c["gimp"] print(c._get_depends(pkg)) @@ -764,7 +820,7 @@ print(c._get_suggests(pkg)) print(c._get_enhances(pkg)) print(c._get_provides(pkg)) - + print("rdeps of gimp") print(c._get_rdepends(pkg)) print(c._get_rrecommends(pkg)) diff -Nru software-center-5.1.11/softwarecenter/db/pkginfo_impl/packagekit.py software-center-5.1.12/softwarecenter/db/pkginfo_impl/packagekit.py --- software-center-5.1.11/softwarecenter/db/pkginfo_impl/packagekit.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/db/pkginfo_impl/packagekit.py 2012-03-08 07:48:06.000000000 +0000 @@ -27,6 +27,7 @@ LOG = logging.getLogger('softwarecenter.db.packagekit') + class PkOrigin: def __init__(self, repo): if repo: @@ -63,6 +64,7 @@ self.component = 'main' self.site = '' + class PackagekitVersion(_Version): def __init__(self, package, pkginfo): self.package = package @@ -75,31 +77,39 @@ @property def downloadable(self): - return True #FIXME: check for an equivalent + return True # FIXME: check for an equivalent + @property def summary(self): return self.package.get_property('summary') + @property def size(self): return self.pkginfo.get_size(self.package.get_name()) + @property def installed_size(self): - """ In packagekit, installed_size can be fetched only for installed packages, - and is stored in the same 'size' property as the package size """ + """In packagekit, installed_size can be fetched only for installed + packages, and is stored in the same 'size' property as the package + size""" return self.pkginfo.get_installed_size(self.package.get_name()) + @property def version(self): return self.package.get_version() + @property def origins(self): return self.pkginfo.get_origins(self.package.get_name()) + def make_locale_string(): loc = locale.getlocale(locale.LC_MESSAGES) if loc[1]: return loc[0] + '.' + loc[1] return loc[0] + class PackagekitInfo(PackageInfo): USE_CACHE = True @@ -107,7 +117,7 @@ super(PackagekitInfo, self).__init__() self.client = packagekit.Client() self.client.set_locale(make_locale_string()) - self._cache = {} # temporary hack for decent testing + self._cache = {} # temporary hack for decent testing self._notfound_cache = [] self._repocache = {} self.distro = get_distro() @@ -136,11 +146,13 @@ return PackagekitVersion(p, self) if p else None def get_candidate(self, pkgname): - p = self._get_one_package(pkgname, pfilter=packagekit.FilterEnum.NEWEST) + p = self._get_one_package(pkgname, + pfilter=packagekit.FilterEnum.NEWEST) return PackagekitVersion(p, self) if p else None def get_versions(self, pkgname): - return [PackagekitVersion(p, self) for p in self._get_packages(pkgname)] + return [PackagekitVersion(p, self) + for p in self._get_packages(pkgname)] def get_section(self, pkgname): # FIXME: things are fuzzy here - group-section association @@ -167,7 +179,8 @@ p = self._get_one_package(pkgname) if not p: return [] - res = self.client.get_files((p.get_id(),), None, self._on_progress_changed, None) + res = self.client.get_files((p.get_id(),), None, + self._on_progress_changed, None) files = res.get_files_array() if not files: return [] @@ -185,7 +198,8 @@ def get_origins(self, pkgname): self._get_repolist() - pkgs = self._get_packages(pkgname, pfilter=packagekit.FilterEnum.NOT_INSTALLED) + pkgs = self._get_packages(pkgname, + pfilter=packagekit.FilterEnum.NOT_INSTALLED) out = set() for p in pkgs: @@ -223,13 +237,15 @@ if not p: return [] autoremove = False - res = self.client.simulate_remove_packages((p.get_id(),), + res = self.client.simulate_remove_packages((p.get_id(),), autoremove, None, self._on_progress_changed, None, ) if not res: return [] - return [p.get_name() for p in res.get_package_array() if p.get_name() != pkg.name] + return [p.get_name() + for p in res.get_package_array() + if p.get_name() != pkg.name] def get_packages_removed_on_install(self, pkg): """ Returns a package names list of dependencies @@ -237,15 +253,18 @@ p = self._get_one_package(pkg.name) if not p: return [] - res = self.client.simulate_install_packages((p.get_id(),), + res = self.client.simulate_install_packages((p.get_id(),), None, self._on_progress_changed, None, ) if not res: return [] - return [p.get_name() for p in res.get_package_array() if (p.get_name() != pkg.name) and p.get_info() == packagekit.InfoEnum.INSTALLED] + return [p.get_name() + for p in res.get_package_array() + if (p.get_name() != pkg.name) + and p.get_info() == packagekit.InfoEnum.INSTALLED] - def get_total_size_on_install(self, pkgname, + def get_total_size_on_install(self, pkgname, addons_install=None, addons_remove=None, archive_suite=None): """ Returns a tuple (download_size, installed_size) @@ -253,7 +272,7 @@ plus addons change. """ # FIXME: support archive_suite here too - + # FIXME: PackageKit reports only one size at a time if self.is_installed(pkgname): return (0, self.get_size(pkgname)) @@ -276,20 +295,22 @@ """ private methods """ def _get_package_details(self, packageid, cache=USE_CACHE): - LOG.debug("package_details %s", packageid) #, self._cache.keys() + LOG.debug("package_details %s", packageid) # , self._cache.keys() if (packageid in self._cache.keys()) and cache: return self._cache[packageid] - result = self.client.get_details((packageid,), None, self._on_progress_changed, None) + result = self.client.get_details((packageid,), None, + self._on_progress_changed, None) pkgs = result.get_details_array() if not pkgs: return None packageid = pkgs[0].get_property('package-id') self._cache[packageid] = pkgs[0] return pkgs[0] - - def _get_one_package(self, pkgname, pfilter=packagekit.FilterEnum.NONE, cache=USE_CACHE): - LOG.debug("package_one %s", pkgname) #, self._cache.keys() + + def _get_one_package(self, pkgname, pfilter=packagekit.FilterEnum.NONE, + cache=USE_CACHE): + LOG.debug("package_one %s", pkgname) # , self._cache.keys() if (pkgname in self._cache.keys()) and cache: return self._cache[pkgname] ps = self._get_packages(pkgname, pfilter) @@ -313,7 +334,8 @@ pkgs = result.get_package_array() return pkgs - def _get_repolist(self, pfilter=packagekit.FilterEnum.NONE, cache=USE_CACHE): + def _get_repolist(self, pfilter=packagekit.FilterEnum.NONE, + cache=USE_CACHE): """ obtain and cache a dictionary of repositories """ if self._repocache: return self._repocache @@ -342,7 +364,7 @@ def _on_progress_changed(self, progress, ptype, data=None): pass -if __name__=="__main__": +if __name__ == "__main__": pi = PackagekitInfo() print "Firefox, installed ", pi.is_installed('firefox') diff -Nru software-center-5.1.11/softwarecenter/distro/Ubuntu.py software-center-5.1.12/softwarecenter/distro/Ubuntu.py --- software-center-5.1.11/softwarecenter/distro/Ubuntu.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/distro/Ubuntu.py 2012-03-07 17:25:50.000000000 +0000 @@ -213,9 +213,7 @@ # string without the date if (channelname or component in ("partner", "independent", "commercial")): - return _("Canonical does not provide updates for %s. " - "Some updates may be provided by the third party " - "vendor.") % appname + return _("Provided by the vendor.") elif component == "main": return _("Canonical provides critical updates for %s.") % appname elif component == "restricted": diff -Nru software-center-5.1.11/softwarecenter/enums.py software-center-5.1.12/softwarecenter/enums.py --- software-center-5.1.11/softwarecenter/enums.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/enums.py 2012-03-07 17:25:50.000000000 +0000 @@ -23,7 +23,7 @@ SOFTWARE_CENTER_PKGNAME = 'software-center' # name of the app in the keyring, untranslated, see bug #773214 for the rational -SOFTWARE_CENTER_NAME_KEYRING = "Ubuntu Software Center Store" +SOFTWARE_CENTER_NAME_KEYRING = "Ubuntu Software Center" SOFTWARE_CENTER_SSO_DESCRIPTION = _( "To reinstall previous purchases, sign in to the " "Ubuntu Single Sign-On account you used to pay for them.") diff -Nru software-center-5.1.11/softwarecenter/hw.py software-center-5.1.12/softwarecenter/hw.py --- software-center-5.1.11/softwarecenter/hw.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/hw.py 2012-03-07 17:25:50.000000000 +0000 @@ -19,7 +19,8 @@ from gettext import gettext as _ TAG_DESCRIPTION = { - 'hardware::camera' : _('camera'), + 'hardware::webcam' : _('webcam'), + 'hardware::digicam' : _('digicam'), 'hardware::input:mouse' : _('mouse'), 'hardware::input:joystick' : _('joystick'), 'hardware::input:touchscreen' : _('touchscreen'), @@ -37,7 +38,9 @@ } TAG_MISSING_DESCRIPTION = { - 'hardware::camera' : _('This software requires a camera, but none ' + 'hardware::digicam' : _('This software requires a digital camera, but none ' + 'are currently connected'), + 'hardware::webcam' : _('This software requires a video camera, but none ' 'are currently connected'), 'hardware::input:mouse' : _('This software requires a mouse, ' 'but none is currently setup.'), diff -Nru software-center-5.1.11/softwarecenter/netstatus.py software-center-5.1.12/softwarecenter/netstatus.py --- software-center-5.1.11/softwarecenter/netstatus.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/netstatus.py 2012-03-07 17:25:50.000000000 +0000 @@ -88,14 +88,16 @@ def __init_network_state(): global NETWORK_STATE - # check is SOFTWARE_CENTER_NET_DISCONNECTED is in the environment variables - # if so force the network status to be disconnected + # honor SOFTWARE_CENTER_NET_{DIS,}CONNECTED in the environment variables import os - if ("SOFTWARE_CENTER_NET_DISCONNECTED" in os.environ and - os.environ["SOFTWARE_CENTER_NET_DISCONNECTED"] == 1): - NETWORK_STATE = NetState.NM_STATE_DISCONNECTED - print('forced netstate into disconnected mode...') - return + env_map = { + 'SOFTWARE_CENTER_NET_DISCONNECTED' : NetState.NM_STATE_DISCONNECTED, + 'SOFTWARE_CENTER_NET_CONNECTED' : NetState.NM_STATE_CONNECTED_GLOBAL, + } + for envkey, state in env_map.iteritems(): + if envkey in os.environ: + NETWORK_STATE = state + return dbus_loop = DBusGMainLoop() try: diff -Nru software-center-5.1.11/softwarecenter/testutils.py software-center-5.1.12/softwarecenter/testutils.py --- software-center-5.1.11/softwarecenter/testutils.py 2012-03-01 19:08:21.000000000 +0000 +++ software-center-5.1.12/softwarecenter/testutils.py 2012-03-09 07:45:49.000000000 +0000 @@ -102,6 +102,13 @@ import softwarecenter.paths return softwarecenter.paths.datadir +def get_test_categories(db): + import softwarecenter.paths + from softwarecenter.db.categories import CategoriesParser + parser = CategoriesParser(db) + cats = parser.parse_applications_menu(softwarecenter.paths.APP_INSTALL_PATH) + return cats + def get_test_enquirer_matches(db, query=None, limit=20, sortmode=0): from softwarecenter.db.enquire import AppEnquire import xapian diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/app.py software-center-5.1.12/softwarecenter/ui/gtk3/app.py --- software-center-5.1.11/softwarecenter/ui/gtk3/app.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/app.py 2012-03-08 07:48:06.000000000 +0000 @@ -58,7 +58,8 @@ AppActions, DB_SCHEMA_VERSION, MOUSE_EVENT_FORWARD_BUTTON, - MOUSE_EVENT_BACK_BUTTON) + MOUSE_EVENT_BACK_BUTTON, + SOFTWARE_CENTER_NAME_KEYRING) from softwarecenter.utils import (clear_token_from_ubuntu_sso, get_http_proxy_string_from_gsettings, wait_for_apt_cache_ready, @@ -109,10 +110,10 @@ return isinstance(func, collections.Callable) class SoftwarecenterDbusController(dbus.service.Object): - """ + """ This is a helper to provide the SoftwarecenterIFace - - It provides only a bringToFront method that takes + + It provides only a bringToFront method that takes additional arguments about what packages to show """ def __init__(self, parent, bus_name, @@ -137,23 +138,23 @@ # XXX Haven't really thought this through.... #~ class SoftwareCenterInitOndemand(object): -#~ +#~ #~ """ Init objects/data that are low priority, i.e, use case is #~ niche and/or load times are low and will not impact user #~ experience. All data and objects are loaded on request. #~ """ -#~ +#~ #~ def init(self): #~ pass #~ class SoftwareCenterInitDelayed(object): -#~ +#~ #~ """ Init objects/data that are medium priority, not needed instantly #~ but rather _potentially_ required within the first few seconds #~ of USC usage. #~ """ -#~ +#~ #~ def init(self): #~ # reviews #~ self.review_loader = get_review_loader(self.cache, self.db) @@ -181,8 +182,8 @@ self.setup_dbus_or_bring_other_instance_to_front(args) self.datadir = datadir - SimpleGtkbuilderApp.__init__(self, - datadir+"/ui/gtk3/SoftwareCenter.ui", + SimpleGtkbuilderApp.__init__(self, + datadir+"/ui/gtk3/SoftwareCenter.ui", "software-center") gettext.bindtextdomain("software-center", "/usr/share/locale") gettext.textdomain("software-center") @@ -229,7 +230,7 @@ self._rebuild_and_reopen_local_db(pathname) except xapian.DatabaseCorruptError: LOG.exception("xapian open failed") - dialogs.error(None, + dialogs.error(None, _("Sorry, can not open the software database"), _("Please re-install the 'software-center' " "package.")) @@ -253,7 +254,7 @@ # misc state self._block_menuitem_view = False - + # for use when viewing previous purchases self.scagent = None self.sso = None @@ -296,7 +297,7 @@ # installed pane (view not fully initialized at this point) self.installed_pane = InstalledPane(self.cache, - self.db, + self.db, self.distro, self.icons, self.datadir) @@ -354,7 +355,7 @@ supported_menuitem = self.builder.get_object("menuitem_view_supported_only") supported_menuitem.set_label(self.distro.get_supported_filter_name()) file_menu = self.builder.get_object("menu1") - + if not self.distro.DEVELOPER_URL: help_menu = self.builder.get_object("menu_help") developer_separator = self.builder.get_object("separator_developer") @@ -366,7 +367,7 @@ och = is_oneconf_available() if not och: file_menu.remove(self.builder.get_object("menuitem_sync_between_computers")) - + # restore the state of the add to launcher menu item, or remove the menu # item if Unity is not currently running add_to_launcher_menuitem = self.builder.get_object( @@ -428,7 +429,7 @@ sc_expunge_cache = os.path.join( self.datadir, "expunge-cache.py") (pid, stdin, stdout, stderr) = GObject.spawn_async( - [sc_expunge_cache, + [sc_expunge_cache, "--by-unsuccessful-http-states", softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR, ]) @@ -476,18 +477,18 @@ self.available_pane.cat_view.recommended_for_you_panel.connect( "recommendations-opt-out", self._on_recommendations_opt_out) - + #~ def on_installed_pane_created(self, widget): #~ pass - + def _on_recommendations_opt_in(self, agent, recommender_uuid): self.recommender_uuid = recommender_uuid - + def _on_recommendations_opt_out(self): # if the user opts back out of the recommender service, we # reset the UUID to indicate it self.recommender_uuid = "" - + def _on_update_software_center_agent_finished(self, pid, condition): LOG.info("software-center-agent finished with status %i" % os.WEXITSTATUS(condition)) if os.WEXITSTATUS(condition) == 0: @@ -504,7 +505,7 @@ Gtk.main_quit() except Exception as e: LOG.warning(e) - + def on_window_main_key_press_event(self, widget, event): """ Define all the accelerator keys here - slightly messy, but the ones defined in the menu don't seem to work.. """ @@ -590,7 +591,7 @@ self.menuitem_view.activate() if self.menuitem_go_forward.get_sensitive(): self.menuitem_go_forward.activate() - + def on_window_main_button_press_event(self, widget, event): """ Implement back/forward navigation via mouse navigation keys using @@ -604,7 +605,7 @@ self.menuitem_view.activate() if self.menuitem_go_forward.get_sensitive(): self.menuitem_go_forward.activate() - + def _on_lp_login(self, lp, token): self._lp_login_successful = True private_archives = self.glaunchpad.get_subscribed_archives() @@ -628,7 +629,7 @@ add_from_purchased_but_needs_reinstall_data) self.available_for_me_query = add_from_purchased_but_needs_reinstall_data( result_list, self.db, self.cache) - self.available_pane.on_previous_purchases_activated(self.available_for_me_query) + self.available_pane.on_previous_purchases_activated(self.available_for_me_query) def get_icon_filename(self, iconname, iconsize): iconinfo = self.icons.lookup_icon(iconname, iconsize, 0) @@ -685,9 +686,9 @@ self.menuitem_remove.set_sensitive(True) elif pkg_state == PkgStates.UNINSTALLED and not error: self.menuitem_install.set_sensitive(True) - elif (not pkg_state and - not self.active_pane.is_category_view_showing() and - app.pkgname in self.cache and + elif (not pkg_state and + not self.active_pane.is_category_view_showing() and + app.pkgname in self.cache and not app.pkgname in self.active_pane.app_view.tree_view._action_block_list and not error): # when does this happen? @@ -707,9 +708,9 @@ d.login() def _create_dbus_sso(self): - # see bug #773214 for the rationale - #appname = _("Ubuntu Software Center Store") - appname = "Ubuntu Software Center Store" + # see bug #773214 for the rationale, do not translate the appname + #appname = _("Ubuntu Software Center") + appname = SOFTWARE_CENTER_NAME_KEYRING help_text = _("To reinstall previous purchases, sign in to the " "Ubuntu Single Sign-On account you used to pay for them.") #window = self.window_main.get_window() @@ -729,7 +730,7 @@ from softwarecenter.backend.scagent import SoftwareCenterAgent self.scagent = SoftwareCenterAgent() self.scagent.connect("available-for-me", self._available_for_me_result) - + def on_menuitem_reinstall_purchases_activate(self, menuitem): self.view_manager.set_active_view(ViewPages.AVAILABLE) self.available_pane.show_appview_spinner() @@ -740,13 +741,13 @@ # fetch the list of available items and show it self._create_scagent_if_needed() self._login_via_dbus_sso() - + def on_menuitem_deauthorize_computer_activate(self, menuitem): - + # FIXME: need Ubuntu SSO username here # account_name = get_person_from_config() account_name = None - + # get a list of installed purchased packages installed_purchased_packages = self.db.get_installed_purchased_packages() @@ -759,12 +760,8 @@ installed_purchased_packages) if deauthorize: # clear the ubuntu SSO token for this account - # FIXME: this needs to be consolidated - one token is - # aquired for purchase in utils/submit_review.py - # the other one in softwarecenter/app.py - clear_token_from_ubuntu_sso(_("Ubuntu Software Center")) - clear_token_from_ubuntu_sso(_("Ubuntu Software Center Store")) - + clear_token_from_ubuntu_sso(SOFTWARE_CENTER_NAME_KEYRING) + # uninstall the list of purchased packages # TODO: do we need to check for dependencies and show a removal # dialog for that case? seems not since these are purchased apps @@ -772,7 +769,7 @@ app = Application(pkgname=pkgname) appdetails = app.get_details(self.db) self.backend.remove(app, appdetails.icon) - + # TODO: remove the corresponding private PPA sources # FIXME: this should really be done using aptdaemon, update this if/when # remove repository support is added to aptdaemon @@ -790,7 +787,7 @@ self.view_manager.display_page(pane, page, state) self.installed_pane.refresh_apps() get_oneconf_handler().sync_between_computers(True) - + def on_menuitem_install_activate(self, menuitem): app = self.active_pane.get_current_app() get_appmanager().request_action(app, [], [], AppActions.INSTALL) @@ -798,7 +795,7 @@ def on_menuitem_remove_activate(self, menuitem): app = self.active_pane.get_current_app() get_appmanager().request_action(app, [], [], AppActions.REMOVE) - + def on_menuitem_close_activate(self, widget): Gtk.main_quit() @@ -809,7 +806,7 @@ """ edit_menu_items = [self.menuitem_undo, self.menuitem_redo, - self.menuitem_cut, + self.menuitem_cut, self.menuitem_copy, self.menuitem_copy_web_link, self.menuitem_paste, @@ -825,10 +822,10 @@ return False self.active_pane = vm.get_view_widget(vm.get_active_view()) - if (self.active_pane and + if (self.active_pane and self.active_pane.searchentry and self.active_pane.searchentry.get_visible()): - # undo, redo, cut, copy, paste, delete, select_all sensitive + # undo, redo, cut, copy, paste, delete, select_all sensitive # if searchentry is focused (and other more specific conditions) if self.active_pane.searchentry.is_focus(): if len(self.active_pane.searchentry._undo_stack) > 1: @@ -854,7 +851,7 @@ self.menuitem_copy_web_link.set_sensitive(True) # details view - if (self.active_pane and + if (self.active_pane and self.active_pane.is_app_details_view_showing()): self.menuitem_select_all.set_sensitive(True) @@ -865,7 +862,7 @@ def on_menuitem_undo_activate(self, menuitem): self.active_pane.searchentry.undo() - + def on_menuitem_redo_activate(self, menuitem): self.active_pane.searchentry.redo() @@ -920,8 +917,8 @@ xid = 0 p = subprocess.Popen( - ["/usr/bin/software-properties-gtk", - "-n", + ["/usr/bin/software-properties-gtk", + "-n", "-t", str(xid)]) # Monitor the subprocess regularly GObject.timeout_add(100, self._poll_software_sources_subprocess, p) @@ -947,7 +944,7 @@ self.menuitem_go_back.set_sensitive(False) self.menuitem_go_forward.set_sensitive(False) return False - + left_sensitive = vm.back_forward.left.get_sensitive() self.menuitem_go_back.set_sensitive(left_sensitive) right_sensitive = vm.back_forward.right.get_sensitive() @@ -1007,13 +1004,13 @@ #~ ap.navigation_bar.navigate_up_twice() #~ else: #~ ap.navigation_bar.navigate_up() - #~ ap.on_application_selected(None, None) + #~ ap.on_application_selected(None, None) #~ # navigate up if the list page is empty - #~ elif (ap and ap.is_applist_view_showing() and + #~ elif (ap and ap.is_applist_view_showing() and #~ len(ap.app_view.get_model()) == 0): #~ ap.navigation_bar.navigate_up() - #~ ap.on_application_selected(None, None) + #~ ap.on_application_selected(None, None) def on_navhistory_back_action_activate(self, navhistory_back_action=None): vm = get_viewmanager() @@ -1022,7 +1019,7 @@ def on_navhistory_forward_action_activate(self, navhistory_forward_action=None): vm = get_viewmanager() vm.nav_forward() - + def on_menuitem_add_to_launcher_toggled(self, menu_item): self.available_pane.add_to_launcher_enabled = menu_item.get_active() @@ -1054,8 +1051,8 @@ self._ask_and_repair_broken_cache() def _on_transaction_finished(self, backend, result): - """ callback when an application install/remove transaction - (or a cache reload) has finished + """ callback when an application install/remove transaction + (or a cache reload) has finished """ self.cache.open() @@ -1122,7 +1119,7 @@ "com.ubuntu.Softwarecenter") def setup_dbus_or_bring_other_instance_to_front(self, args): - """ + """ This sets up a dbus listener """ try: @@ -1133,7 +1130,7 @@ # if there is another Softwarecenter running bring it to front # and exit, otherwise install the dbus controller try: - proxy_obj = bus.get_object('com.ubuntu.Softwarecenter', + proxy_obj = bus.get_object('com.ubuntu.Softwarecenter', '/com/ubuntu/Softwarecenter') iface = dbus.Interface(proxy_obj, 'com.ubuntu.SoftwarecenterIFace') if args: @@ -1187,7 +1184,7 @@ @wait_for_apt_cache_ready def show_app(self, app): # if the pkg is installed, show it in the installed pane - if (app.pkgname in self.cache and + if (app.pkgname in self.cache and self.cache[app.pkgname].installed): with ExecutionTime("installed_pane.init_view()"): self.installed_pane.init_view() @@ -1197,7 +1194,7 @@ self.available_pane.init_view() self.available_pane.show_app(app) show_app(self, app) - return + return elif len(packages) > 1: # turn multiple packages into a search with "," self.available_pane.init_view() @@ -1249,7 +1246,7 @@ else: self.config.set("general", "maximized", "False") # size only matters when non-maximized - size = self.window_main.get_size() + size = self.window_main.get_size() self.config.set("general","size", "%s, %s" % (size[0], size[1])) if self.available_pane.add_to_launcher_enabled: self.config.set("general", "add_to_launcher", "True") diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/models/appstore2.py software-center-5.1.12/softwarecenter/ui/gtk3/models/appstore2.py --- software-center-5.1.11/softwarecenter/ui/gtk3/models/appstore2.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/models/appstore2.py 2012-03-08 19:37:37.000000000 +0000 @@ -31,7 +31,6 @@ from softwarecenter.utils import ExecutionTime, SimpleFileDownloader, split_icon_ext from softwarecenter.backend import get_install_backend from softwarecenter.backend.reviews import get_review_loader -from softwarecenter.db.database import Application from softwarecenter.paths import SOFTWARE_CENTER_ICON_CACHE_DIR import softwarecenter.paths @@ -74,7 +73,7 @@ return -class _AppPropertiesHelper(GObject.GObject): +class AppPropertiesHelper(GObject.GObject): """ Baseclass that contains common functions for our liststore/treestore, only useful for subclassing """ @@ -86,8 +85,30 @@ ), } - def __init__(self): + def __init__(self, db, cache, icons, icon_size=48, global_icon_cache=False): GObject.GObject.__init__(self) + self.db = db + self.cache = cache + + # get all categories + cat_parser = CategoriesParser(db) + self.all_categories = cat_parser.parse_applications_menu( + softwarecenter.paths.APP_INSTALL_PATH) + + # reviews stats loader + self.review_loader = get_review_loader(cache, db) + + # icon jazz + self.icons = icons + self.icon_size = icon_size + + # cache the 'missing icon' used in the treeview for apps without an icon + self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0) + if global_icon_cache: + self.icon_cache = _app_icon_cache + else: + self.icon_cache = {} + return def _download_icon_and_show_when_ready(self, url, pkgname, icon_file_name): LOG.debug("did not find the icon locally, must download %s" % icon_file_name) @@ -138,31 +159,23 @@ return self.db.get_pkgname(doc) def get_application(self, doc): - appname = doc.get_value(XapianValues.APPNAME) - pkgname = self.db.get_pkgname(doc) - # TODO: requests - return Application(appname, pkgname, "") + return self.db.get_application(doc) def get_appname(self, doc): - appname = doc.get_value(XapianValues.APPNAME) - if not appname: - appname = self.db.get_summary(doc) - else: - if self.db.is_appname_duplicated(appname): - appname = "%s (%s)" % (appname, self.get_pkgname(doc)) - return appname + app = self.db.get_application(doc) + return app.get_display_name(self.db, doc) def get_markup(self, doc): - appname = doc.get_value(XapianValues.APPNAME) + app = self.db.get_application(doc) - if not appname: + # the logic is that "apps" are displayed normally + # but "packages" are displayed with their summary as name + if app.appname: + appname = self.get_appname(doc) + summary = self.db.get_summary(doc) + else: appname = self.db.get_summary(doc) summary = self.get_pkgname(doc) - else: - if self.db.is_appname_duplicated(appname): - appname = "%s (%s)" % (appname, self.get_pkgname(doc)) - - summary = self.db.get_summary(doc) return "%s\n%s" % ( GObject.markup_escape_text(appname), @@ -239,44 +252,14 @@ else: return '' -class AppPropertiesHelper(_AppPropertiesHelper): - - def __init__(self, db, cache, icons, icon_size=48, global_icon_cache=False): - super(AppPropertiesHelper, self).__init__() - self.db = db - self.cache = cache - - cat_parser = CategoriesParser(db) - self.all_categories = cat_parser.parse_applications_menu( - softwarecenter.paths.APP_INSTALL_PATH) - - # reviews stats loader - self.review_loader = get_review_loader(cache, db) - - # icon jazz - self.icons = icons - self.icon_size = icon_size - # cache the 'missing icon' used in the treeview for apps without an icon - self._missing_icon = icons.load_icon(Icons.MISSING_APP, - icon_size, 0) - - if global_icon_cache: - self.icon_cache = _app_icon_cache - else: - self.icon_cache = {} - return - def get_icon_at_size(self, doc, width, height): pixbuf = self.get_icon(doc) pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR) return pixbuf - def get_transaction_progress(self, doc): - raise NotImplemented - -class AppGenericStore(_AppPropertiesHelper): +class AppGenericStore(AppPropertiesHelper): # column types COL_TYPES = (GObject.TYPE_PYOBJECT,) @@ -291,12 +274,8 @@ LOAD_INITIAL = 75 def __init__(self, db, cache, icons, icon_size, global_icon_cache): - # the usual suspects - self.db = db - self.cache = cache - - # reviews stats loader - self.review_loader = get_review_loader(cache, db) + AppPropertiesHelper.__init__(self, db, cache, icons, icon_size, + global_icon_cache) # backend stuff self.backend = get_install_backend() @@ -307,21 +286,9 @@ # keep track of paths for transactions in progress self.transaction_path_map = {} - # icon jazz - self.icons = icons - self.icon_size = icon_size - - if global_icon_cache: - self.icon_cache = _app_icon_cache - else: - self.icon_cache = {} - # active row path self.active_row = None - # cache the 'missing icon' used in the treeview for apps without an icon - self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0) - self._in_progress = False self._break = False @@ -396,6 +363,10 @@ GObject.idle_add(buffer_icons) return + def load_range(self, indices, step): + # stub + return + class AppListStore(Gtk.ListStore, AppGenericStore): """ use for flat applist views. for large lists this appends rows approx three times faster than the AppTreeStore equivalent @@ -526,3 +497,4 @@ self.transaction_path_map = {} Gtk.TreeStore.clear(self) return + diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/panes/availablepane.py software-center-5.1.12/softwarecenter/ui/gtk3/panes/availablepane.py --- software-center-5.1.11/softwarecenter/ui/gtk3/panes/availablepane.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/panes/availablepane.py 2012-03-07 17:25:50.000000000 +0000 @@ -407,8 +407,10 @@ def _get_onscreen_icon_details_for_launcher_service(self, app): if self.is_app_details_view_showing(): return self.app_details_view.get_app_icon_details() + elif self.is_applist_view_showing(): + return self.app_view.get_app_icon_details() else: - # TODO: implement the app list view case once it has been specified + # set a default, even though we cannot install from the other panes return (0, 0, 0) def on_app_list_changed(self, pane, length): diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/panes/installedpane.py software-center-5.1.12/softwarecenter/ui/gtk3/panes/installedpane.py --- software-center-5.1.11/softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-08 15:15:30.000000000 +0000 @@ -30,7 +30,8 @@ from softwarecenter.enums import (NonAppVisibility, SortMethods) -from softwarecenter.utils import wait_for_apt_cache_ready, utf8 +from softwarecenter.utils import ( + wait_for_apt_cache_ready, utf8, ExecutionTime) from softwarecenter.db.categories import (CategoriesParser, categories_sorted_by_name) from softwarecenter.ui.gtk3.models.appstore2 import ( @@ -113,6 +114,8 @@ self.visible_docids = None self.visible_cats = {} + + self.installed_spinner_notebook = None def init_view(self): if self.view_initialized: @@ -207,6 +210,8 @@ # hacky, hide the header self.app_view.header_hbox.hide() + self.hide_appview_spinner() + # now we are initialized self.emit("installed-pane-created") @@ -215,11 +220,13 @@ def show_installed_view_spinner(self): """ display the local spinner for the installed view panel """ - self.installed_spinner_notebook.show_spinner() + if self.installed_spinner_notebook: + self.installed_spinner_notebook.show_spinner() def hide_installed_view_spinner(self): """ hide the local spinner for the installed view panel """ - self.installed_spinner_notebook.hide_spinner() + if self.installed_spinner_notebook: + self.installed_spinner_notebook.hide_spinner() def _selected_computer_changed(self, oneconf_pickler, hostid, hostname): if self.current_hostid == hostid: @@ -309,6 +316,10 @@ model = self.base_model # base model not treefilter model.clear() + def profiled_rebuild_categorised_view(): + with ExecutionTime("rebuild_categorized_view"): + rebuild_categorised_view() + def rebuild_categorised_view(): self.cat_docid_map = {} enq = self.enquirer @@ -320,6 +331,7 @@ xfilter = AppFilter(self.db, self.cache) xfilter.set_installed_only(True) + for cat in self._all_cats: # for each category do category query and append as a new # node to tree_view @@ -375,9 +387,6 @@ # hide the local spinner self.hide_installed_view_spinner() - # hide the main spinner (if it's showing) - self.hide_appview_spinner() - if window: window.set_cursor(None) @@ -388,7 +397,7 @@ self.emit("app-list-changed", i) return - GObject.idle_add(rebuild_categorised_view) + GObject.idle_add(profiled_rebuild_categorised_view) return def _build_oneconfview(self): @@ -403,6 +412,10 @@ model = self.base_model # base model not treefilter model.clear() + def profiled_rebuild_oneconfview(): + with ExecutionTime("rebuild_oneconfview"): + rebuild_oneconfview() + def rebuild_oneconfview(): # FIXME for P: hide the search entry @@ -483,7 +496,7 @@ self.emit("app-list-changed", i) return - GObject.idle_add(rebuild_oneconfview) + GObject.idle_add(profiled_rebuild_oneconfview) return def _check_expand(self): diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/review_gui_helper.py software-center-5.1.12/softwarecenter/ui/gtk3/review_gui_helper.py --- software-center-5.1.11/softwarecenter/ui/gtk3/review_gui_helper.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/review_gui_helper.py 2012-03-07 17:25:50.000000000 +0000 @@ -62,7 +62,7 @@ from softwarecenter.ui.gtk3.SimpleGtkbuilderApp import SimpleGtkbuilderApp from softwarecenter.ui.gtk3.dialogs import SimpleGtkbuilderDialog from softwarecenter.ui.gtk3.widgets.stars import ReactiveStar - +from softwarecenter.utils import make_string_from_list from softwarecenter.backend.piston.rnrclient import RatingsAndReviewsAPI from softwarecenter.backend.piston.rnrclient_pristine import ReviewRequest @@ -1051,27 +1051,19 @@ for account in failed_accounts: failed_services.append("%s (@%s)" % (account['service'].capitalize(), account['username'])) - failed = len(failed_services) - - #sets first part of failed services string to first account in list - failed_services_string = failed_services[0] - - #if more than 1 failed account in list, continues to add service strings to the failed_service_string - if failed > 1: - #comma separates services for all accounts in list up to the last one, if there is 3 or more - if failed > 2: - for i in range(1,failed-1): - # Translators: this is the second part of "There was a problem posting this review to %s, %s and %s" - failed_services_string = failed_services_string + (_(", %s") % failed_services[i]) - #final account in list is added to end of string with 'and' - # Translators: this is the last part of "There was a problem posting this review to %s, %s and %s" - failed_services_string = failed_services_string + (_(" and %s") % failed_services[failed-1]) - glade_dialog = SimpleGtkbuilderDialog(self.datadir, domain="software-center") dialog = glade_dialog.dialog_gwibber_error dialog.set_transient_for(self.submit_window) - # Translators: this is the first part of "There was a problem posting this review to %s, %s and %s" - dialog.set_markup(_("There was a problem posting this review to %s.") % failed_services_string) + # build the failure string + # TRANSLATORS: the part in %s can either be a single entry + # like "facebook" or a string like + # "factbook and twister" + error_str = gettext.ngettext( + "There was a problem posting this review to %s.", + "There was a problem posting this review to %s.", + len(failed_services)) + error_str = make_string_from_list(error_str, failed_services) + dialog.set_markup(error_str) dialog.format_secondary_text(error) result = dialog.run() dialog.destroy() diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/views/appview.py software-center-5.1.12/softwarecenter/ui/gtk3/views/appview.py --- software-center-5.1.11/softwarecenter/ui/gtk3/views/appview.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/views/appview.py 2012-03-08 15:15:30.000000000 +0000 @@ -16,21 +16,20 @@ # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -#~ from __future__ import with_statement - +import logging from gi.repository import Gtk, GObject from gettext import gettext as _ -#~ import gettext from softwarecenter.enums import SortMethods from softwarecenter.ui.gtk3.em import StockEms from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore from softwarecenter.ui.gtk3.widgets.apptreeview import AppTreeView from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper -#~ from softwarecenter.ui.gtk3.widgets.containers import FlowableGrid +from softwarecenter.utils import ExecutionTime +LOG=logging.getLogger(__name__) class AppView(Gtk.VBox): @@ -190,10 +189,10 @@ # ... also we dont currently support user sorting in the # installedview, so issue is somewhat moot for the time being... if isinstance(self.tree_view.appmodel, AppTreeStore): + LOG.debug("display_matches called on AppTreeStore, ignoring") return sort_by_relevance = is_search and not self.user_defined_sort_method - if sort_by_relevance: self._use_combobox_with_sort_by_search_ranking() self.set_sort_method_with_no_signal(self._SORT_BY_SEARCH_RANKING) @@ -219,32 +218,128 @@ def get_sort_mode(self): active_index = self.sort_methods_combobox.get_active() return self._SORT_METHOD_INDEX[active_index] + + def get_app_icon_details(self): + """ helper for unity dbus support to provide details about the + application icon as it is displayed on-screen + """ + icon_size = self._get_app_icon_size_on_screen() + (icon_x, icon_y) = self._get_app_icon_xy_position_on_screen() + return (icon_size, icon_x, icon_y) + + def _get_app_icon_size_on_screen(self): + """ helper for unity dbus support to get the size of the maximum side + for the application icon as it is displayed on-screen + """ + icon_size = 32 + if self.tree_view.selected_row_renderer.icon: + pb = self.tree_view.selected_row_renderer.icon + if pb.get_width() > pb.get_height(): + icon_size = pb.get_width() + else: + icon_size = pb.get_height() + return icon_size + + def _get_app_icon_xy_position_on_screen(self): + """ helper for unity dbus support to get the x,y position of + the application icon as it is displayed on-screen + """ + # find toplevel parent + parent = self + while parent.get_parent(): + parent = parent.get_parent() + # get toplevel window position + (px, py) = parent.get_position() + # and return the coordinate values + return (px+self.tree_view.selected_row_renderer.icon_x_offset, + py+self.tree_view.selected_row_renderer.icon_y_offset) + + + +# ----------------------------------------------- testcode +from softwarecenter.enums import NonAppVisibility + +def get_query_from_search_entry(search_term): + import xapian + if not search_term: + return xapian.Query("") + parser = xapian.QueryParser() + user_query = parser.parse_query(search_term) + return user_query + +def on_entry_changed(widget, data): + + def _work(): + new_text = widget.get_text() + (view, enquirer) = data + + with ExecutionTime("total time"): + with ExecutionTime("enquire.set_query()"): + enquirer.set_query(get_query_from_search_entry(new_text), + limit=100*1000, + nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE) + + store = view.tree_view.get_model() + with ExecutionTime("store.clear()"): + store.clear() + + with ExecutionTime("store.set_from_matches()"): + store.set_from_matches(enquirer.matches) + + with ExecutionTime("model settle (size=%s)" % len(store)): + while Gtk.events_pending(): + Gtk.main_iteration() + return + + if widget.stamp: + GObject.source_remove(widget.stamp) + widget.stamp = GObject.timeout_add(250, _work) + def get_test_window(): + import softwarecenter.log + softwarecenter.log.root.setLevel(level=logging.DEBUG) + softwarecenter.log.add_filters_from_string("performance") + fmt = logging.Formatter("%(name)s - %(message)s", None) + softwarecenter.log.handler.setFormatter(fmt) + from softwarecenter.testutils import ( - get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache, - get_test_enquirer_matches) + get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache) from softwarecenter.ui.gtk3.models.appstore2 import AppListStore db = get_test_db() cache = get_test_pkg_info() icons = get_test_gtk3_icon_cache() - # create the view - appview = AppView(db, cache, icons, show_ratings=True) - liststore = AppListStore(db, cache, icons) - appview.set_model(liststore) + # create a filter + from softwarecenter.db.appfilter import AppFilter + filter = AppFilter(db, cache) + filter.set_supported_only(False) + filter.set_installed_only(True) + + # appview + from softwarecenter.db.enquire import AppEnquire + enquirer = AppEnquire(cache, db) + store = AppListStore(db, cache, icons) + + from softwarecenter.ui.gtk3.views.appview import AppView + view = AppView(db, cache, icons, show_ratings=True) + view.set_model(store) + + entry = Gtk.Entry() + entry.stamp = 0 + entry.connect("changed", on_entry_changed, (view, enquirer)) + + box = Gtk.VBox() + box.pack_start(entry, False, True, 0) + box.pack_start(view, True, True, 0) - # do a simple query and display that - appview.display_matches(get_test_enquirer_matches(db)) - - # and put it in the window win = Gtk.Window() - win.add(appview) - win.set_data("appview", appview) - + win.set_data("appview", view) + win.set_data("entry", entry) win.connect("destroy", lambda x: Gtk.main_quit()) + win.add(box) win.set_size_request(600, 400) win.show_all() @@ -252,4 +347,5 @@ if __name__ == "__main__": win = get_test_window() + win.get_data("entry").set_text("gtk3") Gtk.main() diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/views/catview_gtk.py software-center-5.1.12/softwarecenter/ui/gtk3/views/catview_gtk.py --- software-center-5.1.11/softwarecenter/ui/gtk3/views/catview_gtk.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/views/catview_gtk.py 2012-03-09 07:45:49.000000000 +0000 @@ -53,6 +53,7 @@ from softwarecenter.db.utils import get_query_for_pkgnames from softwarecenter.distro import get_distro from softwarecenter.backend.scagent import SoftwareCenterAgent +from softwarecenter.backend.reviews import get_review_loader LOG=logging.getLogger(__name__) @@ -226,14 +227,23 @@ self.departments = None self.appcount = None - # this means that the departments don't jump down once the cache loads - # it doesn't look odd if the recommends are never loaded - #~ self.recommended = Gtk.Label() - #~ self.vbox.pack_start(self.recommended, False, False, 0) + # ensure that on db-reopen we refresh the whats-new titles + self.db.connect("reopen", self._on_db_reopen) + + # ensure that updates to the stats are reflected in the UI + self.reviews_loader = get_review_loader(self.cache) + self.reviews_loader.connect( + "refresh-review-stats-finished", self._on_refresh_review_stats) self.build(desktopdir) return + def _on_db_reopen(self, db): + self._update_whats_new_content() + + def _on_refresh_review_stats(self, reviews_loader, review_stats): + self._update_top_rated_content() + def _build_homepage_view(self): # these methods add sections to the page # changing order of methods changes order that they appear in the page diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/apptreeview.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/apptreeview.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/apptreeview.py 2012-03-08 19:48:54.000000000 +0000 @@ -1,7 +1,5 @@ from gi.repository import Gtk, Gdk, GObject import logging -import os -import xapian from gettext import gettext as _ @@ -13,7 +11,7 @@ CellButtonIDs) from softwarecenter.ui.gtk3.em import em, StockEms -from softwarecenter.enums import (AppActions, NonAppVisibility, Icons) +from softwarecenter.enums import (AppActions, Icons) from softwarecenter.utils import ExecutionTime from softwarecenter.backend import get_install_backend from softwarecenter.netstatus import (get_network_watcher, @@ -45,6 +43,9 @@ self._action_block_list = [] self._needs_collapse = [] self.expanded_path = None + + # pixbuf for the icon that is displayed in the selected row + self.selected_row_icon = None #~ # if this hacked mode is available everything will be fast #~ # and we can set fixed_height mode and still have growing rows @@ -165,7 +166,8 @@ return None def get_rowref(self, model, path): - if path == None: return None + if path == None: + return None return model[path][AppGenericStore.COL_ROW_DATA] def rowref_is_category(self, rowref): @@ -267,6 +269,11 @@ return def _update_selected_row(self, view, tr, path=None): + # keep track of the currently selected row renderer for use when + # calculating icon size and coordinate values for the Unity + # launcher integration feature + self.selected_row_renderer = tr + ## sel = view.get_selection() if not sel: return False @@ -461,6 +468,12 @@ path = model.get_path(it) + # this will give us the right underlying model regardless if its + # a TreeModelFilter, a AppTreeStore or a AppListStore + model = self.appmodel + + # this will pre-load data *only* on a AppListStore, it has + # no effect with a AppTreeStore if model[path][0] is None: indices = path.get_indices() model.load_range(indices, 5) @@ -578,41 +591,6 @@ return self.get_path_at_pos(x, y)[0] == self.get_cursor()[0] -def get_query_from_search_entry(search_term): - if not search_term: - return xapian.Query("") - parser = xapian.QueryParser() - user_query = parser.parse_query(search_term) - return user_query - -def on_entry_changed(widget, data): - - def _work(): - new_text = widget.get_text() - (view, enquirer) = data - - with ExecutionTime("total time"): - with ExecutionTime("enquire.set_query()"): - enquirer.set_query(get_query_from_search_entry(new_text), - limit=100*1000, - nonapps_visible=NonAppVisibility.ALWAYS_VISIBLE) - - store = view.tree_view.get_model() - with ExecutionTime("store.clear()"): - store.clear() - - with ExecutionTime("store.set_documents()"): - store.set_from_matches(enquirer.matches) - - with ExecutionTime("model settle (size=%s)" % len(store)): - while Gtk.events_pending(): - Gtk.main_iteration() - return - - if widget.stamp: GObject.source_remove(widget.stamp) - widget.stamp = GObject.timeout_add(250, _work) - - def get_test_window(): import softwarecenter.log @@ -621,24 +599,13 @@ fmt = logging.Formatter("%(name)s - %(message)s", None) softwarecenter.log.handler.setFormatter(fmt) - from softwarecenter.paths import XAPIAN_BASE_PATH - xapian_base_path = XAPIAN_BASE_PATH - pathname = os.path.join(xapian_base_path, "xapian") - - # the store - from softwarecenter.db.pkginfo import get_pkg_info - cache = get_pkg_info() - cache.open() - - # the db - from softwarecenter.db.database import StoreDatabase - db = StoreDatabase(pathname, cache) - db.open() - - # additional icons come from app-install-data - icons = Gtk.IconTheme.get_default() - icons.prepend_search_path("/usr/share/app-install/icons/") - icons.prepend_search_path("/usr/share/software-center/icons/") + from softwarecenter.testutils import ( + get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache, + get_test_categories) + + cache = get_test_pkg_info() + db = get_test_db() + icons = get_test_gtk3_icon_cache() # create a filter from softwarecenter.db.appfilter import AppFilter @@ -646,30 +613,29 @@ filter.set_supported_only(False) filter.set_installed_only(True) - # appview - from softwarecenter.ui.gtk3.models.appstore2 import AppListStore - from softwarecenter.db.enquire import AppEnquire - enquirer = AppEnquire(cache, db) - store = AppListStore(db, cache, icons) - + # get the TREEstore + from softwarecenter.ui.gtk3.models.appstore2 import AppTreeStore + store = AppTreeStore(db, cache, icons) + + # populate from data + cats = get_test_categories(db) + for cat in cats[:3]: + with ExecutionTime("query cat '%s'" % cat.name): + docs = db.get_docs_from_query(cat.query) + store.set_category_documents(cat, docs) + + # ok, this is confusing - the AppView contains the AppTreeView that + # is a tree or list depending on the model from softwarecenter.ui.gtk3.views.appview import AppView - view = AppView(db, cache, icons, show_ratings=True) - view.set_model(store) - - entry = Gtk.Entry() - entry.stamp = 0 - entry.connect("changed", on_entry_changed, (view, enquirer)) - entry.set_text("gtk3") + app_view = AppView(db, cache, icons, show_ratings=True) + app_view.set_model(store) - scroll = Gtk.ScrolledWindow() box = Gtk.VBox() - box.pack_start(entry, False, True, 0) - box.pack_start(scroll, True, True, 0) + box.pack_start(app_view, True, True, 0) win = Gtk.Window() - win.connect("destroy", lambda x: Gtk.main_quit()) - scroll.add(view) win.add(box) + win.connect("destroy", lambda x: Gtk.main_quit()) win.set_size_request(600, 400) win.show_all() diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/cellrenderers.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/cellrenderers.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/cellrenderers.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/cellrenderers.py 2012-03-07 17:25:50.000000000 +0000 @@ -56,6 +56,9 @@ def __init__(self, icons, layout, show_ratings, overlay_icon_name): GObject.GObject.__init__(self) + + # the icon pixbuf to be displayed in the row + self.icon = None # geometry-state values self.pixbuf_width = 0 @@ -126,9 +129,11 @@ def _render_icon(self, cr, app, cell_area, xpad, ypad, is_rtl): # calc offsets so icon is nicely centered - icon = self.model.get_icon(app) - xo = (self.pixbuf_width - icon.get_width())/2 - + self.icon = self.model.get_icon(app) + self.icon_x_offset = xpad + cell_area.x + self.icon_y_offset = ypad + cell_area.y + xo = (self.pixbuf_width - self.icon.get_width())/2 + if not is_rtl: x = cell_area.x + xo + xpad else: @@ -136,9 +141,9 @@ y = cell_area.y + ypad # draw appicon pixbuf - Gdk.cairo_set_source_pixbuf(cr, icon, x, y) + Gdk.cairo_set_source_pixbuf(cr, self.icon, x, y) cr.paint() - + # draw overlay if application is installed if self.model.is_installed(app): if not is_rtl: diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/reviews.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/reviews.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/reviews.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/reviews.py 2012-03-09 07:45:56.000000000 +0000 @@ -32,21 +32,27 @@ from stars import Star from softwarecenter.utils import ( get_person_from_config, - get_nice_date_string, - upstream_version_compare, + get_nice_date_string, + upstream_version_compare, upstream_version, utf8, ) -from softwarecenter.i18n import get_languages, langcode_to_name +from softwarecenter.i18n import ( + get_languages, + langcode_to_name, + ) -from softwarecenter.netstatus import network_state_is_connected, get_network_watcher +from softwarecenter.netstatus import ( + network_state_is_connected, + get_network_watcher, + ) from softwarecenter.enums import ( - PkgStates, + PkgStates, ReviewSortMethods, ) - + from softwarecenter.backend.reviews import UsefulnessCache from softwarecenter.ui.gtk3.em import StockEms @@ -58,33 +64,34 @@ (COL_LANGNAME, COL_LANGCODE) = range(2) + class UIReviewsList(Gtk.VBox): __gsignals__ = { - 'new-review':(GObject.SignalFlags.RUN_FIRST, + 'new-review': (GObject.SignalFlags.RUN_FIRST, None, ()), - 'report-abuse':(GObject.SignalFlags.RUN_FIRST, + 'report-abuse': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), - 'submit-usefulness':(GObject.SignalFlags.RUN_FIRST, + 'submit-usefulness': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT, bool)), - 'modify-review':(GObject.SignalFlags.RUN_FIRST, + 'modify-review': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), - 'delete-review':(GObject.SignalFlags.RUN_FIRST, + 'delete-review': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), - 'more-reviews-clicked':(GObject.SignalFlags.RUN_FIRST, + 'more-reviews-clicked': (GObject.SignalFlags.RUN_FIRST, None, - () ), - 'different-review-language-clicked':(GObject.SignalFlags.RUN_FIRST, + ()), + 'different-review-language-clicked': (GObject.SignalFlags.RUN_FIRST, None, - (GObject.TYPE_STRING,) ), - 'review-sort-changed':(GObject.SignalFlags.RUN_FIRST, + (GObject.TYPE_STRING,)), + 'review-sort-changed': (GObject.SignalFlags.RUN_FIRST, None, - (GObject.TYPE_INT,) ), + (GObject.TYPE_INT,)), } def __init__(self, parent): @@ -109,7 +116,7 @@ label.set_alignment(0, 0.5) self.pack_start(label, False, False, 0) - # header + # header self.header = Gtk.HBox() self.header.set_spacing(StockEms.MEDIUM) @@ -136,8 +143,8 @@ self.review_language.add_attribute(cell, "text", COL_LANGNAME) self.review_language_model = Gtk.ListStore(str, str) for lang in get_languages(): - self.review_language_model.append( (langcode_to_name(lang), lang) ) - self.review_language_model.append( (_('Any language'), 'any') ) + self.review_language_model.append((langcode_to_name(lang), lang)) + self.review_language_model.append((_('Any language'), 'any')) self.review_language.set_model(self.review_language_model) self.review_language.set_active(0) self.review_language.connect( @@ -153,10 +160,9 @@ self.no_network_msg = None watcher = get_network_watcher() watcher.connect( - "changed", lambda w,s: self._on_network_state_change()) + "changed", lambda w, s: self._on_network_state_change()) self.show_all() - return def _on_network_state_change(self): is_connected = network_state_is_connected() @@ -171,7 +177,7 @@ def _on_button_new_clicked(self, button): self.emit("new-review") - + def _on_sort_method_changed(self, cb): selection = self.sort_combo.get_active() if selection == self._current_sort: @@ -179,7 +185,7 @@ else: self._current_sort = selection self.emit("review-sort-changed", selection) - + def update_useful_votes(self, my_votes): self.useful_votes = my_votes @@ -191,26 +197,25 @@ if self.reviews: for r in self.reviews: pkgversion = self._parent.app_details.version - review = UIReview(r, pkgversion, self.logged_in_person, self.useful_votes) + review = UIReview(r, pkgversion, self.logged_in_person, + self.useful_votes) self.vbox.pack_start(review, True, True, 0) - return def _be_the_first_to_review(self): s = _('Be the first to review it') self.new_review.set_label(s) self.vbox.pack_start(NoReviewYetWriteOne(), True, True, 0) self.vbox.show_all() - return def _install_to_review(self): - s = '%s' % _("You need to install this before you can review it") + s = ('%s' % + _("You need to install this before you can review it")) self.install_first_label = Gtk.Label(label=s) self.install_first_label.set_use_markup(True) self.install_first_label.set_alignment(1.0, 0.5) self.header.pack_start(self.install_first_label, False, False, 0) self.install_first_label.show() - return - + # FIXME: this needs to be smarter in the future as we will # not allow multiple reviews for the same software version def _any_reviews_current_user(self): @@ -225,14 +230,14 @@ m = EmbeddedMessage(title, msg, 'network-offline') self.vbox.pack_start(m, True, True, 0) return m - + def _clear_vbox(self, vbox): children = vbox.get_children() for child in children: child.destroy() - # FIXME: instead of clear/add_reviews/configure_reviews_ui we should provide - # a single show_reviews(reviews_data_list) + # FIXME: instead of clear/add_reviews/configure_reviews_ui we should + # provide a single show_reviews(reviews_data_list) def configure_reviews_ui(self): """ this needs to be called after add_reviews, it will actually show the reviews @@ -243,7 +248,7 @@ self.install_first_label.hide() except AttributeError: pass - + self._clear_vbox(self.vbox) # network sensitive stuff, only show write_review if connected, @@ -253,14 +258,14 @@ # only show new_review for installed stuff is_installed = (self._parent.app_details and - self._parent.app_details.pkg_state == PkgStates.INSTALLED) + self._parent.app_details.pkg_state == PkgStates.INSTALLED) # show/hide new review button if is_installed: self.new_review.show() else: self.new_review.hide() - # if there are no reviews, the install to review text appears + # if there are no reviews, the install to review text appears # where the reviews usually are (LP #823255) if self.reviews: self._install_to_review() @@ -301,7 +306,6 @@ # always run this here to make update the current ui based on the # network state self._on_network_state_change() - return def _on_more_reviews_clicked(self, button): # remove buttn and emit signal @@ -323,11 +327,10 @@ ids = [] for review in self.reviews: ids.append(review.id) - return ids + return ids def add_review(self, review): self.reviews.append(review) - return def replace_review(self, review): for r in self.reviews: @@ -336,14 +339,12 @@ self.reviews.remove(r) self.reviews.insert(pos, review) break - return def remove_review(self, review): for r in self.reviews: if r.id == review.id: self.reviews.remove(r) break - return def clear(self): self.reviews = [] @@ -358,7 +359,7 @@ self.install_first_label.hide() except AttributeError: pass - + a = Gtk.Alignment.new(0.5, 0.5, 1.0, 1.0) hb = Gtk.HBox(spacing=12) hb.show() @@ -380,26 +381,23 @@ self.vbox.pack_start(a, False, False, 0) self.vbox.show() - return def hide_spinner(self): for child in self.vbox.get_children(): if isinstance(child, Gtk.Alignment): child.destroy() - return def draw(self, cr, a): for r in self.vbox: if isinstance(r, (UIReview)): r.draw(cr, r.get_allocation()) - return class UIReview(Gtk.VBox): """ the UI for a individual review including all button to mark useful/inappropriate etc """ - def __init__(self, review_data=None, app_version=None, + def __init__(self, review_data=None, app_version=None, logged_in_person=None, useful_votes=None): GObject.GObject.__init__(self) self.set_spacing(StockEms.SMALL) @@ -420,15 +418,15 @@ self.delete_error_img = Gtk.Image() self.delete_error_img.set_from_stock( Gtk.STOCK_DIALOG_ERROR, - Gtk.IconSize.SMALL_TOOLBAR) + Gtk.IconSize.SMALL_TOOLBAR) self.submit_error_img = Gtk.Image() self.submit_error_img.set_from_stock( Gtk.STOCK_DIALOG_ERROR, Gtk.IconSize.SMALL_TOOLBAR) self.submit_status_spinner = Gtk.Spinner() - self.submit_status_spinner.set_size_request(12,12) + self.submit_status_spinner.set_size_request(12, 12) self.delete_status_spinner = Gtk.Spinner() - self.delete_status_spinner.set_size_request(12,12) + self.delete_status_spinner.set_size_request(12, 12) self.acknowledge_error = Gtk.Button() label = Gtk.Label() label.set_markup('%s' % _("OK")) @@ -465,7 +463,6 @@ def _on_realize(self, widget, *content): self._build(*content) - return def _on_report_abuse_clicked(self, button): reviews = self.get_ancestor(UIReviewsList) @@ -476,46 +473,54 @@ reviews = self.get_ancestor(UIReviewsList) if reviews: reviews.emit("modify-review", self.id) - + def _on_useful_clicked(self, btn, is_useful): reviews = self.get_ancestor(UIReviewsList) if reviews: self._usefulness_ui_update('progress') reviews.emit("submit-usefulness", self.id, is_useful) - - def _on_error_acknowledged(self, button, current_user_reviewer, useful_total, useful_favorable): + + def _on_error_acknowledged(self, button, current_user_reviewer, + useful_total, useful_favorable): self.usefulness_error = False - self._usefulness_ui_update('renew', current_user_reviewer, useful_total, useful_favorable) - - def _usefulness_ui_update(self, type, current_user_reviewer=False, useful_total=0, useful_favorable=0): + self._usefulness_ui_update('renew', current_user_reviewer, + useful_total, useful_favorable) + + def _usefulness_ui_update(self, type, current_user_reviewer=False, + useful_total=0, useful_favorable=0): self._hide_usefulness_elements() #print "_usefulness_ui_update: %s" % type if type == 'renew': - self._build_usefulness_ui(current_user_reviewer, useful_total, useful_favorable, self.useful_votes) + self._build_usefulness_ui(current_user_reviewer, useful_total, + useful_favorable, self.useful_votes) return if type == 'progress': - self.status_label = Gtk.Label.new("%s" % _(u"Submitting now\u2026")) + self.status_label = Gtk.Label.new( + "%s" % _(u"Submitting now\u2026")) self.status_label.set_use_markup(True) - self.status_box.pack_start(self.submit_status_spinner, False, False, 0) + self.status_box.pack_start(self.submit_status_spinner, False, + False, 0) self.submit_status_spinner.show() self.submit_status_spinner.start() - self.status_label.set_padding(2,0) + self.status_label.set_padding(2, 0) self.status_box.pack_start(self.status_label, False, False, 0) self.status_label.show() if type == 'error': self.submit_error_img.show() - self.status_label = Gtk.Label.new("%s" % _("Error submitting usefulness")) + self.status_label = Gtk.Label.new( + "%s" % _("Error submitting usefulness")) self.status_label.set_use_markup(True) self.status_box.pack_start(self.submit_error_img, False, False, 0) - self.status_label.set_padding(2,0) + self.status_label.set_padding(2, 0) self.status_box.pack_start(self.status_label, False, False, 0) self.status_label.show() self.acknowledge_error.show() self.status_box.pack_start(self.acknowledge_error, False, False, 0) - self.acknowledge_error.connect('clicked', self._on_error_acknowledged, current_user_reviewer, useful_total, useful_favorable) + self.acknowledge_error.connect('clicked', + self._on_error_acknowledged, current_user_reviewer, + useful_total, useful_favorable) self.status_box.show() self.footer.pack_start(self.status_box, False, False, 0) - return def _hide_usefulness_elements(self): """ hide all usefulness elements """ @@ -526,13 +531,13 @@ widget = getattr(self, attr, None) if widget: widget.hide() - return def _get_datetime_from_review_date(self, raw_date_str): # example raw_date str format: 2011-01-28 19:15:21 return datetime.datetime.strptime(raw_date_str, '%Y-%m-%d %H:%M:%S') - def _delete_ui_update(self, type, current_user_reviewer=False, action=None): + def _delete_ui_update(self, type, current_user_reviewer=False, + action=None): self._hide_delete_elements() if type == 'renew': self._build_delete_flag_ui(current_user_reviewer) @@ -540,35 +545,42 @@ if type == 'progress': self.delete_status_spinner.start() self.delete_status_spinner.show() - self.delete_status_label = Gtk.Label("%s" % _(u"Deleting now\u2026")) - self.delete_status_box.pack_start(self.delete_status_spinner, False, False, 0) + self.delete_status_label = Gtk.Label( + "%s" % _(u"Deleting now\u2026")) + self.delete_status_box.pack_start(self.delete_status_spinner, + False, False, 0) self.delete_status_label.set_use_markup(True) - self.delete_status_label.set_padding(2,0) - self.delete_status_box.pack_start(self.delete_status_label, False, False, 0) + self.delete_status_label.set_padding(2, 0) + self.delete_status_box.pack_start(self.delete_status_label, False, + False, 0) self.delete_status_label.show() if type == 'error': self.delete_error_img.show() - # build full strings for easier i18n + # build full strings for easier i18n if action == 'deleting': s = _("Error deleting review") elif action == 'modifying': s = _("Error modifying review") else: - # or unknown error, but we are in string freeze, + # or unknown error, but we are in string freeze, # should never happen anyway s = _("Internal Error") - self.delete_status_label = Gtk.Label("%s" % s) - self.delete_status_box.pack_start(self.delete_error_img, False, False, 0) + self.delete_status_label = Gtk.Label( + "%s" % s) + self.delete_status_box.pack_start(self.delete_error_img, + False, False, 0) self.delete_status_label.set_use_markup(True) - self.delete_status_label.set_padding(2,0) - self.delete_status_box.pack_start(self.delete_status_label, False, False, 0) + self.delete_status_label.set_padding(2, 0) + self.delete_status_box.pack_start(self.delete_status_label, + False, False, 0) self.delete_status_label.show() self.delete_acknowledge_error.show() - self.delete_status_box.pack_start(self.delete_acknowledge_error, False, False, 0) - self.delete_acknowledge_error.connect('clicked', self._on_delete_error_acknowledged, current_user_reviewer) + self.delete_status_box.pack_start(self.delete_acknowledge_error, + False, False, 0) + self.delete_acknowledge_error.connect('clicked', + self._on_delete_error_acknowledged, current_user_reviewer) self.delete_status_box.show() self.footer.pack_end(self.delete_status_box, False, False, 0) - return def _on_delete_clicked(self, btn): reviews = self.get_ancestor(UIReviewsList) @@ -583,16 +595,16 @@ def _hide_delete_elements(self): """ hide all delete elements """ for attr in ["complain", "edit", "delete", "delete_status_spinner", - "delete_error_img", "delete_status_box", "delete_status_label", - "delete_acknowledge_error", "flagbox" + "delete_error_img", "delete_status_box", + "delete_status_label", "delete_acknowledge_error", + "flagbox" ]: o = getattr(self, attr, None) if o: o.hide() - return def _build(self, review_data, app_version, logged_in_person, useful_votes): - # all the attributes of review_data may need markup escape, + # all the attributes of review_data may need markup escape, # depening on if they are used as text or markup self.id = review_data.id self.person = review_data.reviewer_username @@ -610,15 +622,15 @@ # upstream version version = GObject.markup_escape_text(upstream_version(review_version)) # default string - version_string = _("For version %(version)s") % { - 'version' : version, + version_string = _("For version %(version)s") % { + 'version': version, } # If its for the same version, show it as such if (review_version and app_version and upstream_version_compare(review_version, app_version) == 0): - version_string = _("For this version (%(version)s)") % { - 'version' : version, + version_string = _("For this version (%(version)s)") % { + 'version': version, } m = '%s' @@ -663,31 +675,34 @@ current_user_reviewer = True self._build_usefulness_ui(current_user_reviewer, useful_total, - useful_favorable, useful_votes, useful_submit_error) + useful_favorable, useful_votes, + useful_submit_error) self.flagbox = Gtk.HBox() self.flagbox.set_spacing(4) - self._build_delete_flag_ui(current_user_reviewer, delete_error, modify_error) + self._build_delete_flag_ui(current_user_reviewer, delete_error, + modify_error) self.footer.pack_end(self.flagbox, False, False, 0) # connect network signals self.connect("realize", lambda w: self._on_network_state_change()) watcher = get_network_watcher() watcher.connect( - "changed", lambda w,s: self._on_network_state_change()) - return - - def _build_usefulness_ui(self, current_user_reviewer, useful_total, - useful_favorable, useful_votes, usefulness_submit_error=False): + "changed", lambda w, s: self._on_network_state_change()) + + def _build_usefulness_ui(self, current_user_reviewer, useful_total, + useful_favorable, useful_votes, + usefulness_submit_error=False): if usefulness_submit_error: - self._usefulness_ui_update('error', current_user_reviewer, + self._usefulness_ui_update('error', current_user_reviewer, useful_total, useful_favorable) else: already_voted = useful_votes.check_for_usefulness(self.id) - #get correct label based on retrieved usefulness totals and + #get correct label based on retrieved usefulness totals and # if user is reviewer self.useful = self._get_usefulness_label( - current_user_reviewer, useful_total, useful_favorable, already_voted) + current_user_reviewer, useful_total, useful_favorable, + already_voted) self.useful.set_use_markup(True) #vertically centre so it lines up with the Yes and No buttons self.useful.set_alignment(0, 0.5) @@ -714,7 +729,6 @@ self.likebox.pack_start(self.yes_no_separator, False, False, 0) self.likebox.pack_start(self.no_like, False, False, 0) self.footer.pack_start(self.likebox, False, False, 0) - return def _on_network_state_change(self): """ show/hide widgets based on network connection state """ @@ -732,10 +746,10 @@ # actually submit anything without network self.useful.hide() self.complain.hide() - - def _get_usefulness_label(self, current_user_reviewer, - useful_total, useful_favorable, already_voted): - '''returns Gtk.Label() to be used as usefulness label depending + + def _get_usefulness_label(self, current_user_reviewer, + useful_total, useful_favorable, already_voted): + '''returns Gtk.Label() to be used as usefulness label depending on passed in parameters ''' if already_voted == None: @@ -751,9 +765,10 @@ "found this review helpful.", "%(useful_favorable)s of %(useful_total)s people " "found this review helpful.", - useful_total) % { 'useful_total' : useful_total, - 'useful_favorable' : useful_favorable, - } + useful_total) % { + 'useful_total': useful_total, + 'useful_favorable': useful_favorable, + } else: # user has not already voted for the review s = gettext.ngettext( @@ -761,9 +776,10 @@ "found this review helpful. Did you?", "%(useful_favorable)s of %(useful_total)s people " "found this review helpful. Did you?", - useful_total) % { 'useful_total' : useful_total, - 'useful_favorable' : useful_favorable, - } + useful_total) % { + 'useful_total': useful_total, + 'useful_favorable': useful_favorable, + } else: #only display these special strings if the user voted either way if already_voted: @@ -775,9 +791,10 @@ "found this review helpful, including you", "%(useful_favorable)s of %(useful_total)s people " "found this review helpful, including you.", - useful_total) % { 'useful_total' : useful_total, - 'useful_favorable' : useful_favorable, - } + useful_total) % { + 'useful_total': useful_total, + 'useful_favorable': useful_favorable, + } else: if useful_total == 1: s = _("You found this review unhelpful.") @@ -787,17 +804,19 @@ "found this review helpful; you did not.", "%(useful_favorable)s of %(useful_total)s people " "found this review helpful; you did not.", - useful_total) % { 'useful_total' : useful_total, - 'useful_favorable' : useful_favorable, - } + useful_total) % { + 'useful_total': useful_total, + 'useful_favorable': useful_favorable, + } m = '%s' label = Gtk.Label() label.set_name("subtle-label") label.set_markup(m % s) return label - - def _build_delete_flag_ui(self, current_user_reviewer, delete_error=False, modify_error=False): + + def _build_delete_flag_ui(self, current_user_reviewer, delete_error=False, + modify_error=False): if delete_error: self._delete_ui_update('error', current_user_reviewer, 'deleting') elif modify_error: @@ -814,16 +833,16 @@ self.edit.connect('clicked', self._on_modify_clicked) self.delete.connect('clicked', self._on_delete_clicked) else: - # Translators: This link is for flagging a review as inappropriate. - # To minimize repetition, if at all possible, keep it to a single word. - # If your language has an obvious verb, it won't need a question mark. + # Translators: This link is for flagging a review as + # inappropriate. To minimize repetition, if at all possible, + # keep it to a single word. If your language has an obvious + # verb, it won't need a question mark. self.complain = Link(m % _('Inappropriate?')) self.complain.set_name("subtle-label") self.complain.set_sensitive(network_state_is_connected()) self.flagbox.pack_start(self.complain, False, False, 0) self.complain.connect('clicked', self._on_report_abuse_clicked) self.flagbox.show_all() - return def _whom_when_markup(self, person, displayname, cur_t): nice_date = get_nice_date_string(cur_t) @@ -851,7 +870,7 @@ return m def draw(self, widget, cr): - return + pass class EmbeddedMessage(UIReview): @@ -860,7 +879,7 @@ UIReview.__init__(self) self.label = None self.image = None - + a = Gtk.Alignment.new(0.5, 0.5, 1.0, 1.0) self.body.pack_start(a, False, False, 0) @@ -878,16 +897,16 @@ self.label.set_alignment(0, 0.5) if title: - self.label.set_markup('%s\n%s' % (title, message)) + self.label.set_markup('%s\n%s' % + (title, message)) else: self.label.set_markup(message) hb.pack_start(self.label, True, True, 0) self.show_all() - return def draw(self, cr, a): - return + pass class NoReviewRelaxLanguage(EmbeddedMessage): @@ -922,7 +941,6 @@ msg = _('Be the first to contribute a review for this application') EmbeddedMessage.__init__(self, title, msg, 'text-editor') - return def get_test_reviews_window(): diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/searchaid.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/searchaid.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/searchaid.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/searchaid.py 2012-03-09 07:45:56.000000000 +0000 @@ -10,10 +10,10 @@ class Suggestions(Gtk.VBox): __gsignals__ = { - "activate-link" : (GObject.SignalFlags.RUN_LAST, - None, - (GObject.TYPE_PYOBJECT, str), - ), + "activate-link": (GObject.SignalFlags.RUN_LAST, + None, + (GObject.TYPE_PYOBJECT, str), + ), } def __init__(self): @@ -29,28 +29,24 @@ self._labels = [] self._handlers = [] - return def on_link_activate(self, widget, uri): self.reset_all() self.emit("activate-link", widget, uri) - return True #silences the gtk-warning + return True # silences the gtk-warning def foreach(self, label_func, *args): - for label in [self.title,] + self._labels: + for label in [self.title] + self._labels: label_func(label, *args) - return def set_alignment(self, xalign, yalign): self.xalign = xalign self.yalign = yalign self.foreach(Gtk.Label.set_alignment, xalign, yalign) - return def set_title(self, title_markup): self.title.set_markup(title_markup) - return def append_suggestion(self, suggestion_markup): label = Gtk.Label() @@ -62,13 +58,12 @@ self._handlers.append( label.connect("activate-link", self.on_link_activate)) self._labels.append(label) - return def set_suggestions(self, suggestions): - if self._labels: self.reset() + if self._labels: + self.reset() for s in suggestions: self.append_suggestion(s) - return def reset(self): for label, handler in zip(self._labels, self._handlers): @@ -77,26 +72,24 @@ self._labels = [] self._handlers = [] - return def reset_all(self): self.title.set_text('') self.reset() - return class SearchAidLogic(object): HEADER_ICON_NAME = "face-sad" HEADER_MARKUP = '%s' - #TRANSLATORS: this is the layout of an indented line starting with a bullet point + #TRANSLATORS: this is the layout of an indented + # line starting with a bullet point BULLET = unicode(_("\t• %s"), 'utf8').encode('utf8') def __init__(self, pane): self.pane = pane self.db = pane.db self.enquirer = pane.enquirer - return def is_search_aid_required(self, state): return (state.search_term and @@ -115,7 +108,7 @@ return category.name plain_text = _("%(category_name)s → %(subcategory_name)s") usable_text = unicode(plain_text, 'utf8').encode('utf8') - return usable_text % {'category_name': category.name, + return usable_text % {'category_name': category.name, 'subcategory_name': state.subcategory.name} if not category: @@ -172,7 +165,8 @@ "suggestions that may aid you in your search") def get_include_parent_suggestion_text(self, term, category, state): - if not state.subcategory: return None + if not state.subcategory: + return enq = self.enquirer query = self.db.get_query_list_from_search_entry( @@ -195,14 +189,13 @@ n=enq.nr_apps) % \ {'category': category.name, 'n': enq.nr_apps} return text - return None def get_unsupported_suggestion_text(self, term, category, state): if state.filter is None: - return None + return supported_only = state.filter.get_supported_only() if not supported_only: - return None + return state.filter.set_supported_only(False) @@ -224,12 +217,11 @@ if enq.nr_apps > 0: text = self.BULLET % gettext.ngettext("Try " "the %(amount)d item " - "that matches in software not maintained by Canonical", + "that matches in software not maintained by Canonical", "Try the %(amount)d items " "that match in software not maintained by Canonical", enq.nr_apps) % {'amount': enq.nr_apps} return text - return None def update_search_help(self, state): # do any non toolkit logic here @@ -238,12 +230,10 @@ # do toolkit stuff here if hasattr(self, 'on_update_search_help'): self.on_update_search_help(state) - return def reset(self): if hasattr(self, 'on_reset'): self.on_reset() - return class SearchAid(Gtk.Table, SearchAidLogic): @@ -259,8 +249,8 @@ image = Gtk.Image.new_from_icon_name(self.HEADER_ICON_NAME, Gtk.IconSize.DIALOG) self.attach(image, - 0, 1, # left_attach, right_attach - 0, 1, # top_attach, bottom_attach + 0, 1, # left_attach, right_attach + 0, 1, # top_attach, bottom_attach Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK, StockEms.LARGE, 0) @@ -270,8 +260,8 @@ self.title.set_use_markup(True) self.title.set_alignment(0.0, 0.5) self.attach(self.title, - 1, 2, # left_attach, right_attach - 0, 1, # top_attach, bottom_attach + 1, 2, # left_attach, right_attach + 0, 1, # top_attach, bottom_attach Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL, StockEms.MEDIUM, 0) @@ -280,17 +270,15 @@ self.suggestion = Suggestions() self.suggestion.set_alignment(0.0, 0.5) self.attach(self.suggestion, - 1, 2, # left_attach, right_attach - 1, 2, # top_attach, bottom_attach + 1, 2, # left_attach, right_attach + 1, 2, # top_attach, bottom_attach Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.FILL, StockEms.MEDIUM, StockEms.MEDIUM) self.suggestion.connect("activate-link", self.on_link_activate) - return def on_update_search_help(self, state): - if not self.is_search_aid_required(state): # catchall self.pane.app_view.set_visible(True) @@ -311,17 +299,14 @@ suggestions_title = self.get_suggestion_title_text(suggestions) self.suggestion.set_title(suggestions_title) self.suggestion.set_suggestions(suggestions) - return def on_reset(self): self.suggestion.reset_all() - return def on_link_activate(self, suggestions, link, uri): markup = self.HEADER_MARKUP % _('Trying suggestion ...') self.title.set_markup(markup) GObject.timeout_add(750, self._handle_suggestion_action, uri) - return def _handle_suggestion_action(self, uri): self = self.pane @@ -339,4 +324,3 @@ # FIXME: add ability to remove categories restriction here # True stops event propergation return False - diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/searchentry.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/searchentry.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/searchentry.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/searchentry.py 2012-03-09 07:45:56.000000000 +0000 @@ -30,13 +30,12 @@ class SearchEntry(Gtk.Entry): # FIMXE: we need "can-undo", "can-redo" signals - __gsignals__ = {'terms-changed':(GObject.SignalFlags.RUN_FIRST, - None, - (GObject.TYPE_STRING,))} + __gsignals__ = {'terms-changed': (GObject.SignalFlags.RUN_FIRST, + None, + (GObject.TYPE_STRING,))} SEARCH_TIMEOUT = 600 - def __init__(self, icon_theme=None): """ Creates an enhanced IconEntry that triggers a timeout when typing @@ -52,7 +51,8 @@ self.connect("icon-press", self._on_icon_pressed) - self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, 'edit-find-symbolic') + self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, + 'edit-find-symbolic') self.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None) # set sensible atk name @@ -90,7 +90,7 @@ text = self._undo_stack.pop() self.set_text(text) self.set_position(-1) - + def redo(self): if not self._redo_stack: return @@ -106,7 +106,6 @@ def set_text(self, text, cursor_to_end=True): Gtk.Entry.set_text(self, text) self.emit("move-cursor", Gtk.MovementStep.BUFFER_ENDS, 1, False) - return def set_text_with_no_signal(self, text): """Clear and do not send a term-changed signal""" @@ -143,17 +142,21 @@ Show the clear icon whenever the field is not empty """ if self.get_text() != "": - self.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, Gtk.STOCK_CLEAR) + self.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, + Gtk.STOCK_CLEAR) # reverse the icon if we are in an rtl environment if self.get_direction() == Gtk.TextDirection.RTL: - pb = self.get_icon_pixbuf(Gtk.EntryIconPosition.SECONDARY).flip(True) + pb = self.get_icon_pixbuf( + Gtk.EntryIconPosition.SECONDARY).flip(True) self.set_icon_from_pixbuf(Gtk.EntryIconPosition.SECONDARY, pb) else: self.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None) + def on_entry_changed(self, terms): print(terms) + def get_test_searchentry_window(): icons = Gtk.IconTheme.get_default() entry = SearchEntry(icons) @@ -162,12 +165,11 @@ win = Gtk.Window() win.connect("destroy", Gtk.main_quit) win.add(entry) - win.set_size_request(400,400) + win.set_size_request(400, 400) win.show_all() win.entry = entry return win - + if __name__ == "__main__": win = get_test_searchentry_window() Gtk.main() - diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/sections.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/sections.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/sections.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/sections.py 2012-03-09 07:45:56.000000000 +0000 @@ -1,30 +1,32 @@ #from gi.repository import Gtk -import cairo, os +import cairo +import os from softwarecenter.enums import ViewPages from softwarecenter.paths import datadir from mkit import floats_from_string + class SectionPainter(object): - - # specify background overlay image and color mappings for available and installed view ids - BACKGROUND_IMAGES = {ViewPages.AVAILABLE : cairo.ImageSurface.create_from_png( - os.path.join(datadir, 'images/clouds.png')), - ViewPages.INSTALLED : cairo.ImageSurface.create_from_png( - os.path.join(datadir, 'images/arrows.png')), + + # specify background overlay image and color mappings for available and + # installed view ids + BACKGROUND_IMAGES = { + ViewPages.AVAILABLE: cairo.ImageSurface.create_from_png( + os.path.join(datadir, 'images/clouds.png')), + ViewPages.INSTALLED: cairo.ImageSurface.create_from_png( + os.path.join(datadir, 'images/arrows.png')), } - BACKGROUND_COLORS = {ViewPages.AVAILABLE : floats_from_string('#0769BC'), - ViewPages.INSTALLED : floats_from_string('#aea79f'), + BACKGROUND_COLORS = {ViewPages.AVAILABLE: floats_from_string('#0769BC'), + ViewPages.INSTALLED: floats_from_string('#aea79f'), } def __init__(self): self._view_id = None - return - + def set_view_id(self, id): self._view_id = id - return def draw(self, widget, cr): # sky @@ -43,7 +45,7 @@ # cr.set_source_surface(s, a.x, 0) #cr.paint() - return + pass def get_background_color(self): return self.BACKGROUND_COLORS[self._view_id] diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/separators.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/separators.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/separators.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/separators.py 2012-03-08 19:37:37.000000000 +0000 @@ -29,8 +29,7 @@ a = self.get_allocation() cr.move_to(0, 0) cr.rel_line_to(a.width, 0) - cr.set_dash((width, 2*width), 0) - cr.set_line_width(2*width) + cr.set_dash((width, 2 * width), 0) + cr.set_line_width(2 * width) cr.stroke() cr.restore() - return diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/spinner.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/spinner.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/spinner.py 2012-03-01 11:31:29.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/spinner.py 2012-03-09 07:45:56.000000000 +0000 @@ -22,6 +22,7 @@ from gi.repository import Gtk, GObject + class SpinnerView(Gtk.Viewport): """ a panel that contains a spinner preset to a standard size and centered @@ -31,7 +32,7 @@ Gtk.Viewport.__init__(self) self.spinner = Gtk.Spinner() self.spinner.set_size_request(48, 48) - + # use a table for the spinner (otherwise the spinner is massive!) spinner_table = Gtk.Table(3, 3, False) self.spinner_label = Gtk.Label() @@ -39,39 +40,40 @@ spinner_vbox = Gtk.VBox() spinner_vbox.pack_start(self.spinner, True, True, 0) spinner_vbox.pack_start(self.spinner_label, True, True, 10) - spinner_table.attach(spinner_vbox, 1, 2, 1, 2, Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.EXPAND) - + spinner_table.attach(spinner_vbox, 1, 2, 1, 2, + Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.EXPAND) + #~ self.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(1.0, 1.0, 1.0)) self.add(spinner_table) self.set_shadow_type(Gtk.ShadowType.NONE) - + def start_and_show(self): """ start the spinner and show it """ self.spinner.start() self.spinner.show() - + def stop_and_hide(self): """ stop the spinner and hide it """ self.spinner.stop() self.spinner.hide() - - def set_text(self, spinner_text = ""): + + def set_text(self, spinner_text=""): """ - useful for adding/removing/changing the label text after the spinner instance has been created + useful for adding/removing/changing the label text after the spinner + instance has been created """ self.spinner_label.set_markup('%s' % spinner_text) + class SpinnerNotebook(Gtk.Notebook): """ this provides a Gtk.Notebook that contains a content page and a spinner page. """ - - - (CONTENT_PAGE, + (CONTENT_PAGE, SPINNER_PAGE) = range(2) def __init__(self, content, msg=""): @@ -79,7 +81,7 @@ self.spinner_view = SpinnerView(msg) # its critical to show() the spinner early as otherwise # gtk_notebook_set_active_page() will not switch to it - self.spinner_view.show() + self.spinner_view.show() if not "SOFTWARE_CENTER_DEBUG_TABS" in os.environ: self.set_show_tabs(False) self.set_show_border(False) @@ -106,15 +108,16 @@ self.spinner_view.stop_and_hide() self.set_current_page(self.CONTENT_PAGE) -def get_test_spinner_window(): + +def get_test_spinner_window(): label = Gtk.Label("foo") spinner_notebook = SpinnerNotebook(label, "random msg") - + window = Gtk.Window() window.add(spinner_notebook) window.set_size_request(600, 500) window.set_position(Gtk.WindowPosition.CENTER) - window.show_all() + window.show_all() window.connect('destroy', Gtk.main_quit) spinner_notebook.show_spinner("Loading for 1s ...") GObject.timeout_add_seconds(1, lambda: spinner_notebook.hide_spinner()) diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/stars.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/stars.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/stars.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/stars.py 2012-03-08 19:37:37.000000000 +0000 @@ -30,7 +30,8 @@ _star_surface_cache = {} -LOG=logging.getLogger(__name__) +LOG = logging.getLogger(__name__) + class StarSize: SMALL = 1 @@ -66,7 +67,6 @@ StarSize.NORMAL: em, StarSize.BIG: big_em, StarSize.PIXEL_VALUE: self.get_pixel_size} - return # private def _get_mangled_keys(self, size): @@ -95,8 +95,8 @@ cr.set_line_join(cairo.LINE_CAP_ROUND) for i in range(self.n_stars): - x = 1 + i*(star_width + self.spacing) - self.layout(cr, x+1, 1, star_width-2, vis_height-2) + x = 1 + i * (star_width + self.spacing) + self.layout(cr, x + 1, 1, star_width - 2, vis_height - 2) cr.stroke_preserve() cr.fill() @@ -112,8 +112,8 @@ cr.set_line_join(cairo.LINE_CAP_ROUND) for i in range(self.n_stars): - x = 1 + i*(star_width + self.spacing) - self.layout(cr, x+1, 1, star_width-2, vis_height-2) + x = 1 + i * (star_width + self.spacing) + self.layout(cr, x + 1, 1, star_width - 2, vis_height - 2) cr.stroke() del cr @@ -132,8 +132,8 @@ cr.set_line_join(cairo.LINE_CAP_ROUND) for i in range(self.n_stars): - x = 1 + i*(star_width + self.spacing) - self.layout(cr, x+2, 2, star_width-4, vis_height-4) + x = 1 + i * (star_width + self.spacing) + self.layout(cr, x + 2, 2, star_width - 4, vis_height - 4) line_color = context.get_border_color(Gtk.StateFlags.NORMAL) cr.set_source_rgb(line_color.red, line_color.green, @@ -144,7 +144,7 @@ cr.clip() context.save() - context.add_class ("button") + context.add_class("button") context.set_state(Gtk.StateFlags.NORMAL) Gtk.render_background(context, cr, 0, 0, vis_width, vis_height) @@ -152,8 +152,8 @@ context.restore() for i in range(self.n_stars): - x = 1 + i*(star_width + self.spacing) - self.layout(cr, x+1.5, 1.5, star_width-3, vis_height-3) + x = 1 + i * (star_width + self.spacing) + self.layout(cr, x + 1.5, 1.5, star_width - 3, vis_height - 3) cr.set_source_rgba(1, 1, 1, 0.8) cr.set_line_width(1) @@ -174,8 +174,8 @@ line_color.blue) for i in range(self.n_stars): - x = 1 + i*(star_width + self.spacing) - self.layout(cr, x+2, 2, star_width-4, vis_height-4) + x = 1 + i * (star_width + self.spacing) + self.layout(cr, x + 2, 2, star_width - 4, vis_height - 4) cr.set_line_width(3) cr.stroke() @@ -209,7 +209,7 @@ def lookup_surfaces_for_size(self, size): full_key, empty_key = self._get_mangled_keys(size) - + if full_key not in _star_surface_cache: return None, None @@ -237,12 +237,11 @@ if fraction < 1.0: empty_width = stars_width - full_width - cr.rectangle(x+full_width, y, empty_width, star_height) + cr.rectangle(x + full_width, y, empty_width, star_height) cr.clip() cr.set_source_surface(empty, x, y) cr.paint() cr.reset_clip() - return def get_pixel_size(self): return self.pixel_value @@ -254,9 +253,7 @@ return surf.get_width(), surf.get_height() - class Star(Gtk.EventBox, StarRenderer): - def __init__(self, size=StarSize.NORMAL): Gtk.EventBox.__init__(self) StarRenderer.__init__(self) @@ -273,7 +270,6 @@ self.set_visible_window(False) self.connect("draw", self.on_draw) self.connect("style-updated", self.on_style_updated) - return def do_get_preferred_width(self): context = self.get_style_context() @@ -289,7 +285,6 @@ self.xalign = xalign self.yalign = yalign self.queue_draw() - return #~ def set_padding(*args): #~ return @@ -304,7 +299,6 @@ global _star_surface_cache _star_surface_cache = {} self.queue_draw() - return def on_draw(self, widget, cr): self.render_star(widget.get_style_context(), cr, 0, 0) @@ -312,25 +306,22 @@ if self._render_allocation_bbox: a = widget.get_allocation() cr.rectangle(0, 0, a.width, a.height) - cr.set_source_rgb(1,0,0) + cr.set_source_rgb(1, 0, 0) cr.set_line_width(2) cr.stroke() - return - def set_n_stars(self, n_stars): - if n_stars == self.n_stars: return + if n_stars == self.n_stars: + return self.n_stars = n_stars global _star_surface_cache _star_surface_cache = {} self.queue_draw() - return def set_rating(self, rating): self.rating = float(rating) self.queue_draw() - return def set_avg_rating(self, rating): # compat for ratings container @@ -339,7 +330,6 @@ def set_size(self, size): self.size = size self.queue_draw() - return def set_size_big(self): return self.set_size(StarSize.BIG) @@ -355,10 +345,10 @@ global _star_surface_cache _star_surface_cache = {} self.queue_draw() - return def set_size_as_pixel_value(self, pixel_value): - if pixel_value == self.pixel_value: return + if pixel_value == self.pixel_value: + return global _star_surface_cache keys = (StarSize.PIXEL_VALUE + StarFillState.FULL, @@ -370,7 +360,6 @@ self.pixel_value = pixel_value self.set_size(StarSize.PIXEL_VALUE) - return class StarRatingsWidget(Gtk.HBox): @@ -384,7 +373,6 @@ self.label = Gtk.Label() self.label.set_alignment(0, 0.5) self.pack_start(self.label, False, False, 0) - return def set_avg_rating(self, rating): # compat for ratings container @@ -394,20 +382,19 @@ s = gettext.ngettext( "%(nr_ratings)i rating", "%(nr_ratings)i ratings", - nr_reviews) % { 'nr_ratings' : nr_reviews, } + nr_reviews) % {'nr_ratings': nr_reviews} # FIXME don't use fixed color m = '(%s)' self.label.set_markup(m % s) - return class ReactiveStar(Star): __gsignals__ = { - "changed" : (GObject.SignalFlags.RUN_LAST, - None, - (),) + "changed": (GObject.SignalFlags.RUN_LAST, + None, + (),) } def __init__(self, size=StarSize.BIG): @@ -416,11 +403,11 @@ self.set_rating(0) self.set_can_focus(True) - self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK| - Gdk.EventMask.BUTTON_RELEASE_MASK| - Gdk.EventMask.KEY_RELEASE_MASK| - Gdk.EventMask.KEY_PRESS_MASK| - Gdk.EventMask.ENTER_NOTIFY_MASK| + self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.KEY_RELEASE_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK) self.connect("enter-notify-event", self.on_enter_notify) @@ -431,37 +418,35 @@ self.connect("key-release-event", self.on_key_release) self.connect("focus-in-event", self.on_focus_in) self.connect("focus-out-event", self.on_focus_out) - return # signal handlers def on_enter_notify(self, widget, event): - return + pass def on_leave_notify(self, widget, event): - return + pass def on_button_press(self, widget, event): - return + pass def on_button_release(self, widget, event): star_index = self.get_star_at_xy(event.x, event.y) - if star_index is None: + if star_index is None: return self.set_rating(star_index) self.emit('changed') - return def on_key_press(self, widget, event): - return + pass def on_key_release(self, widget, event): - return + pass def on_focus_in(self, widget, event): - return + pass def on_focus_out(self, widget, event): - return + pass # public def get_rating(self): @@ -471,9 +456,7 @@ # paint focus StarRenderer.render_star(self, widget, cr, x, y) - # if a star is hovered paint prelit star - return def get_star_at_xy(self, x, y, half_star_precision=False): star_width = self._size_map[self.size]() @@ -492,8 +475,7 @@ class StarRatingSelector(Gtk.Box): - - RATING_WORDS = [_('Hint: Click a star to rate this app'), # unrated caption + RATING_WORDS = [_('Hint: Click a star to rate this app'), # unrated _('Awful'), # 1 star rating _('Poor'), # 2 star rating _('Adequate'), # 3 star rating @@ -503,7 +485,6 @@ INIT_RATING = 3 N_STARS = 5 - def __init__(self): Gtk.Box.__init__(self) self.set_spacing(StockEms.SMALL) @@ -519,7 +500,7 @@ self.set_orientation(Gtk.Orientation.HORIZONTAL) self.pack_start(self.selector, False, False, 0) self.pack_start(self.caption, False, False, 0) - return + # test helper also used in the unit tests def get_test_stars_window(): diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/symbolic_icons.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/symbolic_icons.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/symbolic_icons.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/symbolic_icons.py 2012-03-08 19:37:37.000000000 +0000 @@ -28,7 +28,7 @@ # pi constants _2PI = 2 * PI -PI_OVER_180 = PI / 180 +PI_OVER_180 = PI / 180 def radian(deg): @@ -60,7 +60,6 @@ self.connect("draw", self.on_draw, self.drop_shadow, self.icon, self.drop_shadow_x_offset, self.drop_shadow_y_offset) - return def do_get_preferred_width(self): ds = self.drop_shadow @@ -87,13 +86,12 @@ x = (a.width - icon.get_width()) * 0.5 + xo y = (a.height - icon.get_height()) * 0.5 + yo cr.mask_surface(icon, int(x), int(y)) - return class RotationAboutCenterAnimation(object): - NEW_FRAME_DELAY = 50 # msec - ROTATION_INCREMENT = radian(5) # 5 degrees -> radians + NEW_FRAME_DELAY = 50 # msec + ROTATION_INCREMENT = radian(5) # 5 degrees -> radians def __init__(self): self.rotation = 0 @@ -113,15 +111,13 @@ return _continue def start(self): - if self.is_animating(): return - self.animator = GObject.timeout_add(self.NEW_FRAME_DELAY, - self.new_frame) - return + if not self.is_animating(): + self.animator = GObject.timeout_add(self.NEW_FRAME_DELAY, + self.new_frame) def stop(self): - if not self.is_animating(): return - self._stop_requested = True - return + if self.is_animating(): + self._stop_requested = True def is_animating(self): return self.animator is not None @@ -141,7 +137,6 @@ # for painting the trans count bubble self.layout = self.create_pango_layout("") self.transaction_count = 0 - return def on_draw(self, widget, cr, *args, **kwargs): cr.save() @@ -158,18 +153,21 @@ SymbolicIcon.on_draw(self, widget, cr, *args, **kwargs) cr.restore() - if not self.is_animating() or not self.transaction_count: return + if not self.is_animating() or not self.transaction_count: + return # paint transactions bubble # get the layout extents and calc the bubble size ex = self.layout.get_pixel_extents()[1] - x = (a.width - self.icon.get_width()) / 2 + self.icon.get_width() - ex.width + 2 - y = (a.height - self.icon.get_height()) / 2 + self.icon.get_height() - ex.height + 2 - w = ex.width + 2*self.BUBBLE_XPADDING - h = ex.height + 2*self.BUBBLE_YPADDING + x = ((a.width - self.icon.get_width()) / 2 + + self.icon.get_width() - ex.width + 2) + y = ((a.height - self.icon.get_height()) / 2 + + self.icon.get_height() - ex.height + 2) + w = ex.width + 2 * self.BUBBLE_XPADDING + h = ex.height + 2 * self.BUBBLE_YPADDING - border_radius = w/3 + border_radius = w / 3 if border_radius > self.BUBBLE_MAX_BORDER_RADIUS: border_radius = self.BUBBLE_MAX_BORDER_RADIUS @@ -177,37 +175,36 @@ context = widget.get_style_context() context.save() color = context.get_background_color(Gtk.StateFlags.SELECTED) - rounded_rect(cr, x+1, y+1, w-2, h-2, border_radius) + rounded_rect(cr, x + 1, y + 1, w - 2, h - 2, border_radius) Gdk.cairo_set_source_rgba(cr, color) cr.fill() context.restore() # paint outline - rounded_rect(cr, x+1.5, y+1.5, w-3, h-3, border_radius-1) - cr.set_source_rgb(1,1,1) + rounded_rect(cr, x + 1.5, y + 1.5, w - 3, h - 3, border_radius - 1) + cr.set_source_rgb(1, 1, 1) cr.set_line_width(1) cr.stroke() # paint layout cr.save() - cr.translate(x+(w-ex.width)*0.5, y+(h-ex.height)*0.5) + cr.translate(x + (w - ex.width) * 0.5, y + (h - ex.height) * 0.5) cr.move_to(0, 1) PangoCairo.layout_path(cr, self.layout) - cr.set_source_rgba(0,0,0,0.6) + cr.set_source_rgba(0, 0, 0, 0.6) cr.fill() Gtk.render_layout(context, cr, 0, 0, self.layout) cr.restore() - return def set_transaction_count(self, count): - if count == self.transaction_count: return + if count == self.transaction_count: + return self.transaction_count = count - m = '%i' % (self.BUBBLE_FONT_DESC, - "white", - count) + m = ('%i' % + (self.BUBBLE_FONT_DESC, "white", count)) self.layout.set_markup(m, -1) self.queue_draw() - return + def get_test_symbolic_icons_window(): win = Gtk.Window() diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/thumbnail.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/thumbnail.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/thumbnail.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/thumbnail.py 2012-03-08 19:37:37.000000000 +0000 @@ -44,7 +44,6 @@ GObject.GObject.__init__(self) self._sig = 0 self._screenshots = [] - return def set_app_details(self, app_details): if self._sig > 0: @@ -59,7 +58,6 @@ self._screenshots = [] self.app_details.query_multiple_screenshots() - return def _on_screenshots_available(self, screenshot_data, screenshots): self._screenshots = screenshots @@ -83,7 +81,6 @@ self.set_valign(Gtk.Align.CENTER) self.image = Gtk.Image() self.add(self.image) - return def do_draw(self, cr): if self.has_focus(): @@ -101,7 +98,6 @@ for child in self: self.propagate_draw(child, cr) - return class ScreenshotGallery(Gtk.VBox): @@ -231,23 +227,19 @@ self.button.connect('enter-notify-event', self._on_enter) self.button.connect('leave-notify-event', self._on_leave) self.show_all() - return - + def _on_enter(self, widget, event): if self.get_is_actionable(): self.get_window().set_cursor(self._zoom_cursor) - return def _on_leave(self, widget, event): self.get_window().set_cursor(None) - return def _on_key_press(self, widget, event): # react to spacebar, enter, numpad-enter if (event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter) and self.get_is_actionable()): self.set_state(Gtk.StateType.ACTIVE) - return def _on_key_release(self, widget, event): # react to spacebar, enter, numpad-enter @@ -255,7 +247,6 @@ Gdk.KEY_KP_Enter) and self.get_is_actionable()): self.set_state(Gtk.StateType.NORMAL) self._show_image_dialog() - return def _show_image_dialog(self): """ Displays the large screenshot in a seperate dialog window """ @@ -267,14 +258,14 @@ title, self.screenshot_pixbuf, toplevel) d.run() d.destroy() - return def _on_screenshots_available(self, screenshots): self.thumbnails.set_thumbnails_from_data(screenshots) def _on_screenshot_download_complete(self, loader, screenshot_path): try: - self.screenshot_pixbuf = GdkPixbuf.Pixbuf.new_from_file(screenshot_path) + self.screenshot_pixbuf = GdkPixbuf.Pixbuf.new_from_file( + screenshot_path) except Exception, e: LOG.exception("Pixbuf.new_from_file() failed") self.loader.emit('error', GObject.GError, e) @@ -286,18 +277,15 @@ self.button.image.set_from_pixbuf(pb) self.ready = True self.display_image() - return def _on_screenshot_load_error(self, loader, err_type, err_message): self.set_screenshot_available(False) self.ready = True - return def _on_screenshot_query_complete(self, loader, reachable): self.set_screenshot_available(reachable) if not reachable: self.ready = True - return def _downsize_pixbuf(self, pb, target_w, target_h): w = pb.get_width() @@ -310,7 +298,6 @@ # public def download_and_display_from_url(self, url): self.loader.download_file(url, use_cache=self.USE_CACHING) - return def clear(self): """ All state trackers are set to their intitial states, and @@ -319,13 +306,11 @@ self._height = 0 self.clear_main_screenshot() self.thumbnails.clear() - return def clear_main_screenshot(self): self.screenshot_available = True self.ready = False self.display_spinner() - return def display_spinner(self): self.button.image.clear() @@ -333,7 +318,6 @@ self.unavailable.hide() self.spinner.show() self.spinner.start() - return def display_unavailable(self): self.spinner.hide() @@ -343,7 +327,6 @@ acc = self.get_accessible() acc.set_name(self.NOT_AVAILABLE_STRING) acc.set_role(Atk.Role.LABEL) - return def display_image(self): self.unavailable.hide() @@ -351,7 +334,6 @@ self.spinner.hide() self.button.show_all() self.thumbnails.show() - return def get_is_actionable(self): """ Returns true if there is a screenshot available and @@ -368,13 +350,10 @@ elif available and self.unavailable.get_property("visible"): self.display_spinner() self.screenshot_available = available - return def on_clicked(self, button): - if not self.get_is_actionable(): - return - self._show_image_dialog() - return + if self.get_is_actionable(): + self._show_image_dialog() def fetch_screenshots(self, app_details): """ Called to configure the screenshotview for a new application. @@ -387,17 +366,15 @@ self.data.set_app_details(app_details) self.display_spinner() self.download_and_display_from_url(app_details.screenshot) - return def on_thumbnail_selected(self, gallery, id_): self.clear_main_screenshot() large_url = self.data.get_nth_large_screenshot(id_) self.download_and_display_from_url(large_url) - return def draw(self, widget, cr): """ Draws the thumbnail frame """ - return + pass class Thumbnail(Gtk.Button): @@ -415,7 +392,6 @@ im = Gtk.Image.new_from_pixbuf(pixbuf) self.add(im) self.show_all() - return loader = SimpleFileDownloader() loader.connect("file-download-complete", download_complete_cb) @@ -423,7 +399,6 @@ url, use_cache=ScreenshotGallery.USE_CACHING) self.connect("draw", self.on_draw) - return def on_draw(self, thumb, cr): state = self.get_state_flags() @@ -453,7 +428,6 @@ self.cancel = Gio.Cancellable() self._prev = None self._handlers = [] - return def clear(self): self.cancel.cancel() @@ -464,7 +438,6 @@ for child in self: child.destroy() - return def set_thumbnails_from_data(self, data): self.clear() @@ -486,14 +459,12 @@ self._prev.set_state_flags(Gtk.StateFlags.SELECTED, False) self.show_all() - return def _create_thumbnail_for_url(self, index, url): thumbnail = Thumbnail(index, url, self.cancel, self.gallery) self.pack_start(thumbnail, False, False, 0) sig = thumbnail.connect("clicked", self.on_clicked) self._handlers.append(sig) - return def on_clicked(self, thumb): if self._prev is not None: diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/unused__pathbar.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/unused__pathbar.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/unused__pathbar.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/unused__pathbar.py 2012-03-08 19:37:37.000000000 +0000 @@ -13,7 +13,7 @@ # pi constants from math import pi -PI = pi +PI = pi PI_OVER_180 = pi / 180 @@ -30,7 +30,7 @@ If the Shape is direction dependent, the Shape MUST implement <_layout_ltr> and <_layout_rtl> methods. - + If the Shape is not direction dependent, then it simply can override the method. @@ -51,7 +51,6 @@ self.name = 'Shapeless' self.hadjustment = 0 self._color = 1, 0, 0 - return def __eq__(self, other): return self.name == other.name @@ -61,7 +60,6 @@ self._layout_ltr(cr, x, y, w, h, r, aw) else: self._layout_rtl(cr, x, y, w, h, r, aw) - return class ShapeRoundedRect(Shape): @@ -79,16 +77,14 @@ def __init__(self, direction=Gtk.TextDirection.LTR): Shape.__init__(self, direction) self.name = 'RoundedRect' - return def layout(self, cr, x, y, w, h, r, aw): cr.new_sub_path() - cr.arc(r+x, r+y, r, PI, 270*PI_OVER_180) - cr.arc(x+w-r, r+y, r, 270*PI_OVER_180, 0) - cr.arc(x+w-r, y+h-r, r, 0, 90*PI_OVER_180) - cr.arc(r+x, y+h-r, r, 90*PI_OVER_180, PI) + cr.arc(r + x, r + y, r, PI, 270 * PI_OVER_180) + cr.arc(x + w - r, r + y, r, 270 * PI_OVER_180, 0) + cr.arc(x + w - r, y + h - r, r, 0, 90 * PI_OVER_180) + cr.arc(r + x, y + h - r, r, 90 * PI_OVER_180, PI) cr.close_path() - return class ShapeStartArrow(Shape): @@ -96,34 +92,31 @@ def __init__(self, direction=Gtk.TextDirection.LTR): Shape.__init__(self, direction) self.name = 'StartArrow' - return def _layout_ltr(self, cr, x, y, w, h, r, aw): - haw = aw/2 + haw = aw / 2 cr.new_sub_path() - cr.arc(r+x, r+y, r, PI, 270*PI_OVER_180) + cr.arc(r + x, r + y, r, PI, 270 * PI_OVER_180) # arrow head - cr.line_to(x+w-haw, y) - cr.line_to(x+w+haw, y+(h/2)) - cr.line_to(x+w-haw, y+h) - - cr.arc(r+x, y+h-r, r, 90*PI_OVER_180, PI) + cr.line_to(x + w - haw, y) + cr.line_to(x + w + haw, y + (h / 2)) + cr.line_to(x + w - haw, y + h) + + cr.arc(r + x, y + h - r, r, 90 * PI_OVER_180, PI) cr.close_path() - return def _layout_rtl(self, cr, x, y, w, h, r, aw): - haw = aw/2 + haw = aw / 2 cr.new_sub_path() - cr.move_to(x-haw, (y+h)/2) - cr.line_to(x+aw-haw, y) - cr.arc(x+w-r, r+y, r, 270*PI_OVER_180, 0) - cr.arc(x+w-r, y+h-r, r, 0, 90*PI_OVER_180) - cr.line_to(x+aw-haw, y+h) + cr.move_to(x - haw, (y + h) / 2) + cr.line_to(x + aw - haw, y) + cr.arc(x + w - r, r + y, r, 270 * PI_OVER_180, 0) + cr.arc(x + w - r, y + h - r, r, 0, 90 * PI_OVER_180) + cr.line_to(x + aw - haw, y + h) cr.close_path() - return class ShapeMidArrow(Shape): @@ -133,33 +126,30 @@ #~ self.draw_xoffset = -2 self._color = 0, 1, 0 self.name = 'MidArrow' - return def _layout_ltr(self, cr, x, y, w, h, r, aw): - self.hadjustment = haw = aw/2 - cr.move_to(x-haw-1, y) + self.hadjustment = haw = aw / 2 + cr.move_to(x - haw - 1, y) # arrow head - cr.line_to(x+w-haw, y) - cr.line_to(x+w+haw, y+(h/2)) - cr.line_to(x+w-haw, y+h) - cr.line_to(x-haw-1, y+h) + cr.line_to(x + w - haw, y) + cr.line_to(x + w + haw, y + (h / 2)) + cr.line_to(x + w - haw, y + h) + cr.line_to(x - haw - 1, y + h) - cr.line_to(x+haw-1, y+(h/2)) + cr.line_to(x + haw - 1, y + (h / 2)) cr.close_path() - return def _layout_rtl(self, cr, x, y, w, h, r, aw): - self.hadjustment = haw = -aw/2 + self.hadjustment = haw = -aw / 2 - cr.move_to(x+haw, (h+y)/2) - cr.line_to(x+aw+haw, y) - cr.line_to(x+w-haw+1, y) - cr.line_to(x+w-aw-haw+1, (y+h)/2) - cr.line_to(x+w-haw+1, y+h) - cr.line_to(x+aw+haw, y+h) + cr.move_to(x + haw, (h + y) / 2) + cr.line_to(x + aw + haw, y) + cr.line_to(x + w - haw + 1, y) + cr.line_to(x + w - aw - haw + 1, (y + h) / 2) + cr.line_to(x + w - haw + 1, y + h) + cr.line_to(x + aw + haw, y + h) cr.close_path() - return class ShapeEndCap(Shape): @@ -169,49 +159,42 @@ #~ self.draw_xoffset = -2 self._color = 0, 0, 1 self.name = 'EndCap' - return def _layout_ltr(self, cr, x, y, w, h, r, aw): - self.hadjustment = haw = aw/2 + self.hadjustment = haw = aw / 2 - cr.move_to(x-haw-1, y) + cr.move_to(x - haw - 1, y) # rounded end - cr.arc(x+w-r, r+y, r, 270*PI_OVER_180, 0) - cr.arc(x+w-r, y+h-r, r, 0, 90*PI_OVER_180) + cr.arc(x + w - r, r + y, r, 270 * PI_OVER_180, 0) + cr.arc(x + w - r, y + h - r, r, 0, 90 * PI_OVER_180) # arrow - cr.line_to(x-haw-1, y+h) - cr.line_to(x+haw-1, y+(h/2)) + cr.line_to(x - haw - 1, y + h) + cr.line_to(x + haw - 1, y + (h / 2)) cr.close_path() - return def _layout_rtl(self, cr, x, y, w, h, r, aw): - self.hadjustment = haw = -aw/2 + self.hadjustment = haw = -aw / 2 - cr.arc(r+x, r+y, r, PI, 270*PI_OVER_180) - cr.line_to(x+w-haw+1, y) - cr.line_to(x+w-haw-aw+1, (y+h)/2) - cr.line_to(x+w-haw+1, y+h) - cr.arc(r+x, y+h-r, r, 90*PI_OVER_180, PI) + cr.arc(r + x, r + y, r, PI, 270 * PI_OVER_180) + cr.line_to(x + w - haw + 1, y) + cr.line_to(x + w - haw - aw + 1, (y + h) / 2) + cr.line_to(x + w - haw + 1, y + h) + cr.arc(r + x, y + h - r, r, 90 * PI_OVER_180, PI) cr.close_path() - return class AnimationClock(GObject.GObject): - _1SECOND = 1000 - - __gsignals__ = { - "animation-frame" : (GObject.SignalFlags.RUN_LAST, + "animation-frame": (GObject.SignalFlags.RUN_LAST, None, (float,),), - "animation-finished" : (GObject.SignalFlags.RUN_FIRST, + "animation-finished": (GObject.SignalFlags.RUN_FIRST, None, (bool,),), } - def __init__(self, fps, duration): GObject.GObject.__init__(self) @@ -221,7 +204,6 @@ self._clock = None self._progress = 0 # progress as an msec offset - return def _get_timstep(self): d = self.duration @@ -245,7 +227,6 @@ def set_duration(self, duration): self.duration = float(duration) self._timestep = self._get_timstep() - return def stop(self, who_called='?'): @@ -257,29 +238,27 @@ self._clock = None self._progress = 0 self.in_progress = False - return def start(self): self.stop(who_called='start') - if not self.sequence: return + if not self.sequence: + return self._clock = GObject.timeout_add(self._timestep, self._schedule_animation_frame, priority=100) self.in_progress = True - return class PathBarAnimator(AnimationClock): - # animation display constants - FPS = 50 + FPS = 50 DURATION = 150 # spec says 150ms # animation modes - NONE = 'animation-none' - OUT = 'animation-out' - IN = 'animation-in' + NONE = 'animation-none' + OUT = 'animation-out' + IN = 'animation-in' WIDTH_CHANGE = 'animation-width-change' def __init__(self, pathbar): @@ -290,7 +269,6 @@ self.connect('animation-frame', self._on_animation_frame) self.connect('animation-finished', self._on_animation_finished) - return def _animate_out(self, part, progress, kwargs): real_alloc = part.get_allocation() @@ -300,13 +278,12 @@ xo *= -1 anim_alloc = Gdk.Rectangle() - anim_alloc.x = real_alloc.x-xo + anim_alloc.x = real_alloc.x - xo anim_alloc.y = real_alloc.y anim_alloc.width = real_alloc.width anim_alloc.height = real_alloc.height part.new_frame(anim_alloc) - return def _animate_in(self, part, progress, kwargs): real_alloc = part.get_allocation() @@ -316,13 +293,12 @@ xo *= -1 anim_alloc = Gdk.Rectangle() - anim_alloc.x = real_alloc.x-xo + anim_alloc.x = real_alloc.x - xo anim_alloc.y = real_alloc.y anim_alloc.width = real_alloc.width anim_alloc.height = real_alloc.height part.new_frame(anim_alloc) - return def _animate_width_change(self, part, progress, kwargs): start_w = kwargs['start_width'] @@ -330,14 +306,14 @@ width = int(round(start_w + (end_w - start_w) * progress)) part.set_size_request(width, part.get_height_request()) - return def _on_animation_frame(self, clock, progress): - if not self.sequence: return + if not self.sequence: + return for actor, animation, kwargs in self.sequence: - - if animation == PathBarAnimator.NONE: continue + if animation == PathBarAnimator.NONE: + continue if animation == PathBarAnimator.OUT: self._animate_out(actor, progress, kwargs) @@ -348,8 +324,6 @@ elif animation == PathBarAnimator.WIDTH_CHANGE: self._animate_width_change(actor, progress, kwargs) - return - def _on_animation_finished(self, clock, interrupted): for actor, animation, kwargs in self.sequence: actor.animation_finished() @@ -357,21 +331,18 @@ self.sequence = [] self.pathbar.psuedo_parts = [] self.pathbar.queue_draw() - return def append_animation(self, actor, animation, **kwargs): self.sequence.append((actor, animation, kwargs)) - return def reset(self, who_called='?'): - AnimationClock.stop(self, who_called=who_called+'.reset') + AnimationClock.stop(self, who_called=who_called + '.reset') self.sequence = [] - return class PathBar(Gtk.HBox): - MIN_PART_WIDTH = 25 # pixels + MIN_PART_WIDTH = 25 # pixels def __init__(self): GObject.GObject.__init__(self) @@ -405,7 +376,6 @@ # les signales! self.connect('size-allocate', self._on_allocate) self.connect('draw', self._on_draw) - return # sugar def __len__(self): @@ -454,7 +424,6 @@ self.animator.start() else: self.queue_draw() - return def _on_draw(self, widget, cr): # always paint psuedo parts first @@ -467,7 +436,7 @@ # paint a frame around the entire pathbar width = self.get_parts_width() - Gtk.render_background(context, cr, 1, 1, width-2, a.height-2) + Gtk.render_background(context, cr, 1, 1, width - 2, a.height - 2) self._paint_widget_parts(cr, context, a.x, a.y) @@ -486,7 +455,6 @@ part.animation_allocation or part.get_allocation(), context, xo, yo) - return def _paint_psuedo_parts(self, cr, context, xo, yo): # a special case: paint psuedo parts paint first, @@ -496,7 +464,6 @@ part.animation_allocation or part.get_allocation(), context, xo, yo) - return def _shrink_parts(self, overhang): self.out_of_width = True @@ -505,7 +472,7 @@ old_width = part.get_width_request() new_width = max(self.MIN_PART_WIDTH, old_width - overhang) - if False:#self.use_animations: + if False: # self.use_animations: self.animator.append_animation(part, PathBarAnimator.WIDTH_CHANGE, start_width=old_width, @@ -515,8 +482,8 @@ part.get_height_request()) overhang -= old_width - new_width - if overhang <= 0: break - return + if overhang <= 0: + break def _grow_parts(self, claim): children = self.get_children() @@ -528,7 +495,8 @@ continue growth = min(claim, (part.get_natural_width() - part.width)) - if growth <= 0: break + if growth <= 0: + break claim -= growth @@ -540,11 +508,11 @@ else: part.set_size_request(part.width + growth, part.get_height_request()) - return def _make_space(self, part): children = self.get_children() - if not children: return + if not children: + return cur_width = self.get_parts_width() incomming_width = cur_width + part.get_width_request() @@ -553,14 +521,13 @@ if overhang > 0: print 'shrink parts by:', overhang self._shrink_parts(overhang) - return def _reclaim_space(self, part): - if not self.out_of_width: return + if not self.out_of_width: + return claim = part.get_width_request() self._grow_parts(claim) - return def _append_compose_parts(self, new_part): d = self.get_direction() @@ -574,11 +541,11 @@ else: new_part.set_shape(ShapeRoundedRect(d)) - if not n_parts > 1: return + if not n_parts > 1: + return new_mid = children[-1] new_mid.set_shape(ShapeMidArrow(d)) - return def _remove_compose_parts(self): d = self.get_direction() @@ -595,31 +562,29 @@ last = children[-1] last.set_shape(ShapeEndCap(d)) self.queue_draw() - return def _cleanup_revealer(self): - if not self._revealer: return + if not self._revealer: + return GObject.source_remove(self._revealer) self._revealer = None - return def _theme(self, part): #~ part.set_padding(self.theme['xpad'], self.theme['ypad']) part.set_padding(12, 4) - return # public methods @property def first_part(self): children = self.get_children() - if not children: return None - return children[0] + if children: + return children[0] @property def last_part(self): children = self.get_children() - if not children: return None - return children[-1] + if children: + return children[-1] def reveal_part(self, part, animate=True): # do not do here: @@ -629,7 +594,8 @@ part_old_width = part.get_width_request() part_new_width = part.get_natural_width() - if part_new_width == part_old_width: return + if part_new_width == part_old_width: + return change_amount = part_new_width - part_old_width @@ -639,7 +605,8 @@ old_width = part_old_width new_width = part_new_width else: - if change_amount <= 0: continue + if change_amount <= 0: + continue old_width = p.get_width_request() new_width = max(self.MIN_PART_WIDTH, old_width - change_amount) @@ -655,7 +622,6 @@ p.get_height_request()) self.animator.start() - return def queue_reveal_part(self, part): @@ -667,11 +633,11 @@ self._revealer = GObject.timeout_add(self._timeout_reveal, reveal_part_cb, part) - return def get_parts_width(self): last = self.last_part - if not last: return 0 + if not last: + return 0 if self.get_direction() != Gtk.TextDirection.RTL: return last.x + last.width - self.first_part.x @@ -682,7 +648,8 @@ def get_visual_width(self): last = self.last_part first = self.first_part - if not last: return 0 + if not last: + return 0 la = last.animation_allocation or last.get_allocation() fa = first.animation_allocation or first.get_allocation() @@ -691,13 +658,11 @@ return la.x + la.width - fa.x return fa.x + fa.width - la.x - def set_use_animations(self, use_animations): self.use_animations = use_animations if not use_animations and self.animator.in_progress: self.animator.reset() - return def append(self, part): print 'append', part @@ -721,11 +686,11 @@ else: part.set_nopaint(False) part.queue_draw() - return def pop(self): children = self.get_children() - if not children: return + if not children: + return self.animator.reset('pop') @@ -744,11 +709,11 @@ last.destroy() - if not self.use_animations: return + if not self.use_animations: + return self.animator.append_animation(part, PathBarAnimator.IN) self.animator.start() - return def navigate_up(self): """ just another name for pop() """ @@ -760,7 +725,6 @@ def __init__(self): self.animation_in_progress = False self.animation_allocation = None - return @property def x(self): @@ -786,41 +750,41 @@ self.animation_allocation = allocation self.queue_draw() - return def animation_finished(self): self.animation_in_progress = False self.animation_allocation = None - if self.get_parent(): self.get_parent().queue_draw() - return + if self.get_parent(): + self.get_parent().queue_draw() def paint(self, cr, a, context, xo, yo): - if self.is_nopaint: return + if self.is_nopaint: + return cr.save() x, y = 0, 0 w, h = a.width, a.height - arrow_width = 12#theme['arrow-width'] + arrow_width = 12 # theme['arrow-width'] if isinstance(self, PathPart): _a = self.get_allocation() self.shape.layout(cr, - _a.x-xo+1, _a.y-yo, + _a.x - xo + 1, _a.y - yo, w, h, 3, arrow_width) cr.clip() else: Gtk.render_background(context, cr, - a.x-xo-10, a.y-yo, - a.width+10, a.height) + a.x - xo - 10, a.y - yo, + a.width + 10, a.height) - cr.translate(a.x-xo, a.y-yo) + cr.translate(a.x - xo, a.y - yo) if self.shape.name.find('Arrow') != -1: # draw arrow head - cr.move_to(w-arrow_width/2, 2) - cr.line_to(w+5, h/2) - cr.line_to(w-arrow_width/2, h-2) + cr.move_to(w - arrow_width / 2, 2) + cr.line_to(w + 5, h / 2) + cr.line_to(w - arrow_width / 2, h - 2) # fetch the line color and stroke rgba = context.get_border_color(Gtk.StateFlags.NORMAL) cr.set_source_rgb(rgba.red, rgba.green, rgba.blue) @@ -831,13 +795,13 @@ e = self.layout.get_pixel_extents()[1] lw, lh = e.width, e.height pw, ph = a.width, a.height - - x = min(self.xpadding, (pw-lw)/2) - y = (ph-lh)/2 + + x = min(self.xpadding, (pw - lw) / 2) + y = (ph - lh) / 2 # layout area Gtk.render_layout(context, - cr, + cr, int(x), int(y), self.layout) @@ -845,11 +809,10 @@ # paint the focus frame if need be if isinstance(self, PathPart) and self.has_focus(): # layout area - x, w, h = x-2, lw+4, lh+1 + x, w, h = x - 2, lw + 4, lh + 1 Gtk.render_focus(context, cr, x, y, w, h) cr.restore() - return class PsuedoPathPart(PathPartCommon): @@ -872,7 +835,6 @@ self.layout = real_part.create_pango_layout(self.label) self.is_nopaint = False - return def get_allocation(self): return self.allocation @@ -887,20 +849,19 @@ return self.size_request[1] def animation_finished(self): - return + pass def queue_draw(self): a = self.allocation aw = 12 - self.parent.queue_draw_area(a.x-aw/2, a.y, - a.width+aw, a.height) - return + self.parent.queue_draw_area(a.x - aw / 2, a.y, + a.width + aw, a.height) class PathPart(Gtk.EventBox, PathPartCommon): __gsignals__ = { - "clicked" : (GObject.SignalFlags.RUN_LAST, + "clicked": (GObject.SignalFlags.RUN_LAST, None, (),), } @@ -924,7 +885,6 @@ self.set_label(label) self._init_event_handling() - return def __repr__(self): return "PathPart: '%s'" % self.label @@ -940,23 +900,22 @@ else: part.set_state(Gtk.StateFlags.PRELIGHT) self.queue_draw() - return def _on_leave_notify(self, part, event): self.pathbar.queue_reveal_part(self.pathbar.last_part) part.set_state(Gtk.StateFlags.NORMAL) self.queue_draw() - return def _on_button_press(self, part, event): - if event.button != 1: return + if event.button != 1: + return self.pathbar._press_origin = part part.set_state(Gtk.StateFlags.ACTIVE) self.queue_draw() - return def _on_button_release(self, part, event): - if event.button != 1: return + if event.button != 1: + return if self.pathbar._press_origin != part: self.pathbar._press_origin = None @@ -971,13 +930,11 @@ self.emit, 'clicked') self.queue_draw() - return def _on_key_press(self, part, event): if event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter): part.set_state(Gtk.StateFlags.ACTIVE) self.queue_draw() - return def _on_key_release(self, part, event): if event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_KP_Enter): @@ -985,24 +942,21 @@ GObject.timeout_add(self.pathbar._timeout_initial, self.emit, 'clicked') self.queue_draw() - return def _on_focus_in(self, part, event): self.pathbar.reveal_part(self) - return def _on_focus_out(self, part, event): self.queue_draw() - return # private methods def _init_event_handling(self): self.set_property("can-focus", True) - self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK| - Gdk.EventMask.BUTTON_RELEASE_MASK| - Gdk.EventMask.KEY_RELEASE_MASK| - Gdk.EventMask.KEY_PRESS_MASK| - Gdk.EventMask.ENTER_NOTIFY_MASK| + self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.KEY_RELEASE_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK) self.connect("enter-notify-event", self._on_enter_notify) @@ -1013,18 +967,16 @@ self.connect("key-release-event", self._on_key_release) self.connect("focus-in-event", self._on_focus_in) self.connect("focus-out-event", self._on_focus_out) - return def _calc_natural_size(self, who_called='?'): ne = self.natural_extents nw, nh = ne.width, ne.height - nw += self.shape.hadjustment + 2*self.xpadding - nh += 2*self.ypadding + nw += self.shape.hadjustment + 2 * self.xpadding + nh += 2 * self.ypadding self.natural_size = nw, nh self.set_size_request(nw, nh) - return # public methods @property @@ -1035,26 +987,23 @@ self.xpadding = xpadding self.ypadding = ypadding self._calc_natural_size() - return def set_size_request(self, width, height): - width = max(2*self.xpadding+1, width) - height = max(2*self.ypadding+1, height) - self.layout.set_width(Pango.SCALE * (width - 2*self.xpadding)) + width = max(2 * self.xpadding + 1, width) + height = max(2 * self.ypadding + 1, height) + self.layout.set_width(Pango.SCALE * (width - 2 * self.xpadding)) Gtk.Widget.set_size_request(self, width, height) - return def set_nopaint(self, is_nopaint): self.is_nopaint = is_nopaint self.queue_draw() - return def set_shape(self, shape): - if shape == self.shape: return + if shape == self.shape: + return self.shape = shape self._calc_natural_size() self.queue_draw() - return def set_label(self, label): self.label = label @@ -1068,7 +1017,6 @@ self._calc_natural_size() self.queue_draw() - return def get_natural_size(self): return self.natural_size @@ -1092,9 +1040,8 @@ aw = 12 else: aw = 0 - self.queue_draw_area(a.x-aw/2, a.y, - a.width+aw, a.height) - return + self.queue_draw_area(a.x - aw / 2, a.y, + a.width + aw, a.height) class NavigationBar(PathBar): @@ -1103,11 +1050,9 @@ PathBar.__init__(self) self.id_to_part = {} self._callback_id = None - return def _on_part_clicked(self, part): part.callback(self, part) - return def add_with_id(self, label, callback, id, do_callback=True, animate=True): """ @@ -1149,13 +1094,12 @@ self._callback_id = None # if i do not have call the callback in an idle, - # all hell breaks loose + # all hell breaks loose self._callback_id = GObject.idle_add(callback, self, # pathbar part) self.append(part) - return def remove_ids(self, *ids, **kwargs): parts = self.get_parts() @@ -1169,14 +1113,16 @@ index = len(parts) for id, part in self.id_to_part.iteritems(): - if id not in ids: continue + if id not in ids: + continue if part not in parts: cleanup_ids.append(id) part.destroy() else: index = min(index, parts.index(part)) - if index == len(parts): return + if index == len(parts): + return # cleanup any stale id:part pairs in the id_to_part dict for id in cleanup_ids: @@ -1192,7 +1138,7 @@ # the index is used to remove all parts after the index but we # keep one part around to animate its removal - for part in parts[index+1:]: + for part in parts[index + 1:]: part.destroy() animate = True @@ -1207,36 +1153,33 @@ if 'do_callback' in kwargs and kwargs['do_callback']: part = self[-1] part.callback(self, part) - return def remove_all(self, **kwargs): - if len(self) <= 1: return + if len(self) <= 1: + return ids = filter(lambda k: k != 'category', self.id_to_part.keys()) self.remove_ids(*ids, **kwargs) - return def has_id(self, id): - return self.id_to_part.has_key(id) + return id in self.id_to_part def get_parts(self): return self.get_children() def get_active(self): parts = self.get_parts() - if not parts: return None - return parts[-1] + if parts: + return parts[-1] def get_button_from_id(self, id): """ return the button for the given id (or None) """ - if not id in self.id_to_part: - return None - return self.id_to_part[id] + return self.id_to_part.get(id) def set_active_no_callback(self, part): - return + pass class TestIt: @@ -1247,11 +1190,9 @@ t = entry.get_text() or 'no label %s' % len(pathbar) part = PathPart(t) pathbar.append(part) - return def remove(button, entry, pathbar): pathbar.pop() - return win = Gtk.Window() win.set_border_width(30) @@ -1284,6 +1225,7 @@ self.win = win self.win.pb = pb + def get_test_pathbar_window(): t = TestIt() return t.win @@ -1291,4 +1233,3 @@ if __name__ == '__main__': win = get_test_pathbar_window() Gtk.main() - diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/videoplayer.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/videoplayer.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/videoplayer.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/videoplayer.py 2012-03-08 19:37:37.000000000 +0000 @@ -35,6 +35,7 @@ LOG = logging.getLogger(__name__) + class VideoPlayer(Gtk.VBox): def __init__(self): super(VideoPlayer, self).__init__() @@ -43,7 +44,7 @@ settings = self.webkit.get_settings() # this disables the flash and other plugins so that we force html5 # video on the system. This is works currently (11/2011) fine with - # dailymotion and vimeo but youtube is opt-in only so we need + # dailymotion and vimeo but youtube is opt-in only so we need # to monitor the situation settings.set_property("enable-plugins", False) # on navigation/new window etc, just use the proper browser @@ -57,21 +58,22 @@ def _on_new_window(self, view, frame, request, action, policy): subprocess.Popen(['xdg-open', request.get_uri()]) return True + # helper for the embedded html5 viewer def _on_create_web_view(self, view, frame): # mvo: this is not ideal, the trouble is that we do not get the # url that the new view points to until after the view was - # created. But we don't want to be a full blow internal + # created. But we don't want to be a full blow internal # webbrowser so we simply go back to the youtube url here # and the user needs to click "youtube" there again :/ uri = frame.get_uri() subprocess.Popen(['xdg-open', uri]) - return None # uri property def _set_uri(self, v): self._uri = v or "" self.webkit.load_uri(self._uri) + def _get_uri(self): return self._uri uri = property(_get_uri, _set_uri, None, "uri property") @@ -85,6 +87,7 @@ base_uri = "http://www.ubuntu.com" self.webkit.load_html_string(html, base_uri) + # AKA the-segfault-edition-with-no-documentation class VideoPlayerGtk3(Gtk.VBox): @@ -119,7 +122,7 @@ else: self.player.set_state(Gst.State.NULL) self.button.set_label(_("Play")) - + def on_message(self, bus, message): print("message: %s" % bus, message) if message is None: @@ -134,7 +137,7 @@ err, debug = message.parse_error() LOG.error("Error playing video: %s (%s)" % (err, debug)) self.button.set_label(_("Play")) - + def on_sync_message(self, bus, message): print("sync: %s" % bus, message) if message is None or message.structure is None: @@ -148,35 +151,40 @@ # exported in the GIR xid = self.player.movie_window.get_window().get_xid() imagesink.set_xwindow_id(xid) - Gdk.threads_leave() + Gdk.threads_leave() def get_test_videoplayer_window(): # youtube example fragment - html_youtube = """ - -""" + html_youtube = """""" # vimeo example video fragment - html_vimeo = """ -

Supertuxkart 0.6 from constantin pelikan on Vimeo.

-""" + html_vimeo = """

+Supertuxkart 0.6 from +constantin pelikan on Vimeo.

""" # dailymotion example video fragment - html_dailymotion = """ -""" - html_dailymotion2 = """""" - - html_youtube # pyflakes - html_dailymotion # pyflakes - html_dailymotion2 # pyflakes - + html_dailymotion = """""" + html_dailymotion2 = """""" + + html_youtube # pyflakes + html_dailymotion # pyflakes + html_dailymotion2 # pyflakes + win = Gtk.Window.new(Gtk.WindowType.TOPLEVEL) win.set_default_size(500, 400) win.connect("destroy", Gtk.main_quit) player = VideoPlayer() win.add(player) if len(sys.argv) < 2: - #player.uri = "http://upload.wikimedia.org/wikipedia/commons/9/9b/Pentagon_News_Sample.ogg" + #player.uri = "http://upload.wikimedia.org/wikipedia/commons/9/9b/" \ + # "Pentagon_News_Sample.ogg" #player.uri = "http://people.canonical.com/~mvo/totem.html" player.load_html_string(html_vimeo) else: diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/viewport.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/viewport.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/viewport.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/viewport.py 2012-03-08 19:37:37.000000000 +0000 @@ -5,7 +5,6 @@ _downers = (Gdk.KEY_KP_Down, Gdk.KEY_Down) - class Viewport(Gtk.Viewport): def __init__(self): @@ -19,11 +18,13 @@ if kv in _uppers or kv in _downers: # get the ScrolledWindow adjustments and tweak them appropriately - if not self.get_parent(): return False + if not self.get_parent(): + return False # the ScrolledWindow vertical-adjustment scroll = self.get_ancestor('GtkScrolledWindow') - if not scroll: return False + if not scroll: + return False v_adj = scroll.get_vadjustment() @@ -32,7 +33,7 @@ v = max(v_adj.get_value() - v_adj.get_step_increment(), v_adj.get_lower()) - # scroll down + # scroll down elif kv in _downers: v = min(v_adj.get_value() + v_adj.get_step_increment(), v_adj.get_upper() - v_adj.get_page_size()) diff -Nru software-center-5.1.11/softwarecenter/ui/gtk3/widgets/weblivedialog.py software-center-5.1.12/softwarecenter/ui/gtk3/widgets/weblivedialog.py --- software-center-5.1.11/softwarecenter/ui/gtk3/widgets/weblivedialog.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/gtk3/widgets/weblivedialog.py 2012-03-08 19:37:37.000000000 +0000 @@ -26,6 +26,7 @@ from gettext import gettext as _ + class ShowWebLiveServerChooserDialog(Gtk.Dialog): """A dialog to choose between multiple server""" @@ -40,35 +41,37 @@ parent = parent.get_parent() # servers - self.servers_vbox=Gtk.VBox(homogeneous=False, spacing=0) + self.servers_vbox = Gtk.VBox(homogeneous=False, spacing=0) # Merge duplicate servers, keep the one with the most space - servers=[] + servers = [] for server in supplied_servers: - duplicate=False + duplicate = False for otherserver in servers: if server.title == otherserver.title: - percent_server=((float(server.current_users)/float(server.userlimit))*100.0) - percent_otherserver=((float(otherserver.current_users)/float(otherserver.userlimit))*100.0) + percent_server = ((float(server.current_users) / + float(server.userlimit)) * 100.0) + percent_otherserver = ((float(otherserver.current_users) / + float(otherserver.userlimit)) * 100.0) for package in server.packages: if package.pkgname == pkgname: - autoinstall_server=package.autoinstall + autoinstall_server = package.autoinstall for package in otherserver.packages: if package.pkgname == pkgname: - autoinstall_otherserver=package.autoinstall + autoinstall_otherserver = package.autoinstall # Replace existing server if: - # current server has more free slots and we don't switch + # current server has more free slots and we don't switch # to a server requiring autoinstall # or doesn't need autoinstall but existing one does - if ( (percent_otherserver > percent_server and - not autoinstall_otherserver < autoinstall_server) or - autoinstall_otherserver > autoinstall_server ): + if ((percent_otherserver > percent_server and + not autoinstall_otherserver < autoinstall_server) or + autoinstall_otherserver > autoinstall_server): servers.remove(otherserver) servers.append(server) - duplicate=True + duplicate = True if duplicate: continue @@ -76,15 +79,15 @@ servers.append(server) if len(servers) == 1: - self.show_dialog=False + self.show_dialog = False else: - self.show_dialog=True + self.show_dialog = True - button=Gtk.RadioButton() + button = Gtk.RadioButton() for server in sorted(servers, key=lambda server: server.title): - button=Gtk.RadioButton.new_from_widget(button) + button = Gtk.RadioButton.new_from_widget(button) button.set_label("%s - %s" % (server.title, server.description)) - button.serverid=server.name + button.serverid = server.name self.servers_vbox.pack_start(button, True, True, 0) # dialog @@ -110,8 +113,8 @@ sys.path.append('../../../') from softwarecenter.backend.weblive_pristine import WebLive - weblive=WebLive('https://weblive.stgraber.org/weblive/json',True) - servers=weblive.list_everything() + weblive = WebLive('https://weblive.stgraber.org/weblive/json', True) + servers = weblive.list_everything() d = ShowWebLiveServerChooserDialog(servers, "gimp") if d.run() == Gtk.ResponseType.OK: diff -Nru software-center-5.1.11/softwarecenter/ui/qml/app.py software-center-5.1.12/softwarecenter/ui/qml/app.py --- software-center-5.1.11/softwarecenter/ui/qml/app.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/qml/app.py 2012-03-08 07:48:06.000000000 +0000 @@ -27,7 +27,7 @@ from PyQt4 import QtDeclarative from PyQt4.QtCore import QUrl from PyQt4.QtGui import QApplication, QIcon -from PyQt4.QtDeclarative import QDeclarativeView +from PyQt4.QtDeclarative import QDeclarativeView from softwarecenter.db.pkginfo import get_pkg_info @@ -46,7 +46,8 @@ view = QDeclarativeView() view.setWindowTitle(view.tr("Ubuntu Software Center")) - view.setWindowIcon(QIcon(os.path.join(os.path.dirname(__file__), "../../../data/icons/scalable/apps/softwarecenter.svg"))) + view.setWindowIcon(QIcon(os.path.join(os.path.dirname(__file__), + "../../../data/icons/scalable/apps/softwarecenter.svg"))) view.setResizeMode(QtDeclarative.QDeclarativeView.SizeRootObjectToView) # if running locally, fixup softwarecenter.paths diff -Nru software-center-5.1.11/softwarecenter/ui/qml/categoriesmodel.py software-center-5.1.12/softwarecenter/ui/qml/categoriesmodel.py --- software-center-5.1.11/softwarecenter/ui/qml/categoriesmodel.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/qml/categoriesmodel.py 2012-03-08 07:48:06.000000000 +0000 @@ -19,7 +19,7 @@ import os -# this is a bit silly, but *something* imports gtk2 symbols, so if we +# this is a bit silly, but *something* imports gtk2 symbols, so if we # force gtk3 here it crashes - the only reason we need this at all is to # get the icon path import gi @@ -35,13 +35,14 @@ from softwarecenter.paths import XAPIAN_BASE_PATH import softwarecenter.paths + class CategoriesModel(QAbstractListModel): # should match the softwarecenter.backend.reviews.Review attributes COLUMNS = ('_name', '_iconname', ) - + def __init__(self, parent=None): super(CategoriesModel, self).__init__() self._categories = [] @@ -76,10 +77,10 @@ if info: return info.get_filename() return "" - + if __name__ == "__main__": from PyQt4.QtGui import QApplication - from PyQt4.QtDeclarative import QDeclarativeView + from PyQt4.QtDeclarative import QDeclarativeView import sys app = QApplication(sys.argv) @@ -97,4 +98,3 @@ # show it view.show() sys.exit(app.exec_()) - diff -Nru software-center-5.1.11/softwarecenter/ui/qml/pkglist.py software-center-5.1.12/softwarecenter/ui/qml/pkglist.py --- software-center-5.1.11/softwarecenter/ui/qml/pkglist.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/qml/pkglist.py 2012-03-08 07:48:06.000000000 +0000 @@ -29,6 +29,7 @@ from softwarecenter.backend import get_install_backend from softwarecenter.backend.reviews import get_review_loader + class PkgListModel(QAbstractListModel): COLUMNS = ('_appname', @@ -40,7 +41,7 @@ '_ratings_total', '_ratings_average', '_installremoveprogress') - + def __init__(self, parent=None): super(PkgListModel, self).__init__() self._docs = [] @@ -53,7 +54,7 @@ self.db = StoreDatabase(pathname, self.cache) self.db.open(use_axi=False) self.backend = get_install_backend() - self.backend.connect("transaction-progress-changed", + self.backend.connect("transaction-progress-changed", self._on_backend_transaction_progress_changed) self.reviews = get_review_loader(self.cache) # FIXME: get this from a parent @@ -71,9 +72,9 @@ doc = self._docs[index.row()] role = self.COLUMNS[role] pkgname = unicode(self.db.get_pkgname(doc), "utf8", "ignore") - appname = unicode(self.db.get_appname(doc), "utf8", "ignore") + appname = unicode(self.db.get_appname(doc), "utf8", "ignore") if role == "_pkgname": - return pkgname + return pkgname elif role == "_appname": return appname elif role == "_summary": @@ -90,12 +91,14 @@ iconname = self.db.get_iconname(doc) return self._findIcon(iconname) elif role == "_ratings_average": - stats = self.reviews.get_review_stats(Application(appname, pkgname)) + stats = self.reviews.get_review_stats(Application(appname, + pkgname)) if stats: return stats.ratings_average return 0 elif role == "_ratings_total": - stats = self.reviews.get_review_stats(Application(appname, pkgname)) + stats = self.reviews.get_review_stats(Application(appname, + pkgname)) if stats: return stats.ratings_total return 0 @@ -106,26 +109,27 @@ return None # helper - def _on_backend_transaction_progress_changed(self, backend, pkgname, progress): + def _on_backend_transaction_progress_changed(self, backend, pkgname, + progress): column = self.COLUMNS.index("_installremoveprogress") # FIXME: instead of the entire model, just find the row that changed top = self.createIndex(0, column) - bottom = self.createIndex(self.rowCount()-1, column) + bottom = self.createIndex(self.rowCount() - 1, column) self.dataChanged.emit(top, bottom) def _findIcon(self, iconname): path = "/usr/share/icons/Humanity/categories/32/applications-other.svg" for ext in ["svg", "png", ".xpm"]: p = "/usr/share/app-install/icons/%s" % iconname - if os.path.exists(p+ext): - path = "file://%s" % p+ext + if os.path.exists(p + ext): + path = "file://%s" % p + ext break return path - + def clear(self): if self._docs == []: return - self.beginRemoveRows(QModelIndex(), 0, self.rowCount()-1) + self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1) self._docs = [] self.endRemoveRows() @@ -133,7 +137,7 @@ self.clear() docs = self.db.get_docs_from_query( str(querystr), start=0, end=500, category=self._category) - self.beginInsertRows(QModelIndex(), 0, len(docs)-1) + self.beginInsertRows(QModelIndex(), 0, len(docs) - 1) self._docs = docs self.endInsertRows() @@ -143,6 +147,7 @@ appname = "" iconname = "" self.backend.install(pkgname, appname, iconname) + @pyqtSlot(str) def removePackage(self, pkgname): appname = "" @@ -152,11 +157,13 @@ # searchQuery property (for qml ) def getSearchQuery(self): return self._query + def setSearchQuery(self, query): self._query = query self._runQuery(query) searchQueryChanged = QtCore.pyqtSignal() - searchQuery = QtCore.pyqtProperty(unicode, getSearchQuery, setSearchQuery, notify=searchQueryChanged) + searchQuery = QtCore.pyqtProperty(unicode, getSearchQuery, setSearchQuery, + notify=searchQueryChanged) # allow to refine searches for specific categories @pyqtSlot(str) @@ -177,7 +184,7 @@ if __name__ == "__main__": from PyQt4.QtGui import QApplication - from PyQt4.QtDeclarative import QDeclarativeView + from PyQt4.QtDeclarative import QDeclarativeView import sys app = QApplication(sys.argv) @@ -195,4 +202,3 @@ # show it view.show() sys.exit(app.exec_()) - diff -Nru software-center-5.1.11/softwarecenter/ui/qml/reviewslist.py software-center-5.1.12/softwarecenter/ui/qml/reviewslist.py --- software-center-5.1.11/softwarecenter/ui/qml/reviewslist.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/ui/qml/reviewslist.py 2012-03-08 07:48:06.000000000 +0000 @@ -26,6 +26,7 @@ from softwarecenter.db.pkginfo import get_pkg_info from softwarecenter.backend.reviews import get_review_loader + class ReviewsListModel(QAbstractListModel): # should match the softwarecenter.backend.reviews.Review attributes @@ -35,7 +36,7 @@ '_date_created', '_reviewer_displayname', ) - + def __init__(self, parent=None): super(ReviewsListModel, self).__init__() self._reviews = [] @@ -56,20 +57,21 @@ review = self._reviews[index.row()] role = self.COLUMNS[role] if role == '_date_created': - when = datetime.strptime(getattr(review, role[1:]), '%Y-%m-%d %H:%M:%S') + when = datetime.strptime(getattr(review, role[1:]), + '%Y-%m-%d %H:%M:%S') return when.strftime('%Y-%m-%d') return unicode(getattr(review, role[1:])) # helper def clear(self): - self.beginRemoveRows(QModelIndex(), 0, self.rowCount()-1) + self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1) self._reviews = [] self.endRemoveRows() def _on_reviews_ready_callback(self, loader, reviews): self.beginInsertRows(QModelIndex(), - self.rowCount(), # first - self.rowCount() + len(reviews)-1) # last + self.rowCount(), # first + self.rowCount() + len(reviews) - 1) # last self._reviews += reviews self.endInsertRows() @@ -99,5 +101,3 @@ # FIXME: how is this signal actually used in the qml JS? # signals reviewStatsChanged = pyqtSignal() - - diff -Nru software-center-5.1.11/softwarecenter/utils.py software-center-5.1.12/softwarecenter/utils.py --- software-center-5.1.11/softwarecenter/utils.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/softwarecenter/utils.py 2012-03-07 17:25:50.000000000 +0000 @@ -706,7 +706,26 @@ self.emit('file-download-complete', self.dest_file_path) - +def make_string_from_list(base_str, item_list): + """ This function takes a list of items and builds a nice human readable + string with it of the form. Note that the base string needs a "%s". + Example return: + The base string with the list items a,b and c in it. + Note that base_str needs to be a ngettext string already, so the + example usage is: + l = ["foo", "bar"] + base_str = ngettext("This list: %s.", "This list: %s", len(l)) + s = make_string_from_list(base_string, l) + """ + list_str = item_list[0] + if len(item_list) > 1: + # TRANSLATORS: this is a generic list delimit char, e.g. "foo, bar" + list_str = _(", ").join(item_list[:-1]) + # TRANSLATORS: this is the last part of a list, e.g. "foo, bar and baz" + list_str = _("%s and %s") % (list_str, + item_list[-1]) + s = base_str % list_str + return s # those helpers are packaging system specific diff -Nru software-center-5.1.11/softwarecenter/version.py software-center-5.1.12/softwarecenter/version.py --- software-center-5.1.11/softwarecenter/version.py 2012-03-01 19:28:49.000000000 +0000 +++ software-center-5.1.12/softwarecenter/version.py 2012-03-09 08:07:47.000000000 +0000 @@ -1,5 +1,5 @@ -VERSION='5.1.11' +VERSION='5.1.12' CODENAME='precise' DISTRO='Ubuntu' RELEASE='12.04' diff -Nru software-center-5.1.11/test/coverage_summary software-center-5.1.12/test/coverage_summary --- software-center-5.1.11/test/coverage_summary 2012-03-01 19:28:38.000000000 +0000 +++ software-center-5.1.12/test/coverage_summary 2012-03-09 08:07:38.000000000 +0000 @@ -1,139 +1,138 @@ Name Stmts Miss Cover -------------------------------------------------------------------------------------------------------------------------------------------- -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/__init__ 2 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/channel 182 19 90% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/channel_impl/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/channel_impl/aptchannels 144 46 68% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/fake_review_settings 77 33 57% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/installbackend 36 14 61% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/installbackend_impl/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/installbackend_impl/aptd 478 296 38% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/launchpad 184 112 39% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/login 9 2 78% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/login_sso 96 31 68% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/oneconfhandler/__init__ 17 5 71% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/oneconfhandler/core 98 15 85% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/piston/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/piston/rnrclient 44 29 34% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/piston/rnrclient_fake 147 80 46% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/piston/rnrclient_pristine 80 26 68% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/recagent 115 34 70% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/reviews/__init__ 358 135 62% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/reviews/rnr 206 102 50% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/scagent 78 26 67% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/spawn_helper 87 14 84% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/transactionswatcher 50 19 62% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/ubuntusso 75 38 49% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/unitylauncher 26 11 58% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/weblive 168 100 40% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/backend/weblive_pristine 145 84 42% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/cmdfinder 31 3 90% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/config 28 9 68% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/__init__ 8 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/appfilter 67 11 84% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/application 516 123 76% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/categories 301 36 88% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/database 347 89 74% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/debfile 124 35 72% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/enquire 147 6 96% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/history 36 13 64% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/history_impl/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/history_impl/apthistory 132 33 75% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/pkginfo 108 35 68% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/pkginfo_impl/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/pkginfo_impl/aptcache 520 148 72% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/update 653 63 90% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/db/utils 23 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/distro/Debian 88 66 25% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/distro/Ubuntu 126 51 60% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/distro/__init__ 90 43 52% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/enums 120 8 93% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/gwibber_helper 64 22 66% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/hw 11 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/i18n 46 4 91% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/log 62 14 77% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/netstatus 87 19 78% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/paths 53 13 75% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/plugin 62 4 94% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/region 79 5 94% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/testutils 108 4 96% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/toolkit 13 3 77% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/SimpleGtkbuilderApp 18 5 72% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/app 692 344 50% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/aptd_gtk3 44 36 18% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/dialogs/__init__ 67 24 64% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/dialogs/deauthorize_dialog 78 66 15% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/dialogs/dependency_dialogs 79 19 76% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/drawing 68 34 50% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/em 33 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/gmenusearch 82 37 55% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/models/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/models/appstore2 299 44 85% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/models/pendingstore 111 65 41% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/availablepane 419 140 67% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/basepane 15 5 67% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/globalpane 60 4 93% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/historypane 254 22 91% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/installedpane 410 115 72% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/pendingpane 95 28 71% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/softwarepane 297 74 75% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/panes/viewswitcher 174 70 60% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/review_gui_helper 807 320 60% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/session/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/session/appmanager 89 12 87% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/session/navhistory 167 17 90% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/session/viewmanager 129 31 76% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/shapes 157 97 38% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/utils 53 7 87% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/views/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/views/appdetailsview 1306 203 84% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/views/appview 125 6 95% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/views/catview_gtk 429 61 86% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/views/pkgnamesview 64 8 88% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/views/purchaseview 235 104 56% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/actionbar 230 81 65% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/apptreeview 465 260 44% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/backforward 108 23 79% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/buttons 437 81 81% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/cellrenderers 327 111 66% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/containers 396 28 93% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/description 837 448 46% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/exhibits 381 67 82% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/imagedialog 35 3 91% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/labels 59 11 81% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/menubutton 64 45 30% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/oneconfviews 98 45 54% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/recommendations 133 14 89% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/reviews 599 115 81% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/searchaid 194 64 67% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/searchentry 90 25 72% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/separators 27 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/spinner 64 2 97% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/stars 355 47 87% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/symbolic_icons 154 11 93% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/thumbnail 370 65 82% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/videoplayer 111 57 49% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/viewport 22 13 41% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/gtk3/widgets/weblivedialog 68 58 15% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/qml/__init__ 0 0 100% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/qml/categoriesmodel 53 21 60% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/qml/pkglist 132 64 52% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/ui/qml/reviewslist 46 3 93% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/utils 426 120 72% -/home/egon/devel/software-center/build-area/software-center-5.1.11/softwarecenter/version 4 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/__init__ 2 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/channel 182 19 90% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/channel_impl/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/channel_impl/aptchannels 144 46 68% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/fake_review_settings 77 33 57% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/installbackend 36 14 61% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/installbackend_impl/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/installbackend_impl/aptd 478 296 38% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/launchpad 184 112 39% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/login 9 2 78% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/login_sso 96 32 67% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/oneconfhandler/__init__ 17 5 71% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/oneconfhandler/core 98 15 85% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/piston/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/piston/rnrclient 44 29 34% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/piston/rnrclient_fake 147 80 46% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/piston/rnrclient_pristine 80 26 68% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/recagent 115 34 70% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/reviews/__init__ 362 129 64% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/reviews/rnr 205 100 51% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/scagent 78 26 67% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/spawn_helper 87 14 84% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/transactionswatcher 50 19 62% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/ubuntusso 75 38 49% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/unitylauncher 26 11 58% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/weblive 168 100 40% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/backend/weblive_pristine 145 84 42% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/cmdfinder 31 3 90% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/config 28 9 68% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/__init__ 8 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/appfilter 67 11 84% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/application 518 122 76% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/categories 301 36 88% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/database 347 88 75% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/debfile 124 35 72% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/enquire 147 6 96% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/history 36 13 64% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/history_impl/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/history_impl/apthistory 132 33 75% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/pkginfo 108 35 68% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/pkginfo_impl/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/pkginfo_impl/aptcache 520 147 72% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/update 653 63 90% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/db/utils 23 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/distro/Debian 88 66 25% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/distro/Ubuntu 126 51 60% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/distro/__init__ 90 43 52% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/enums 120 8 93% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/gwibber_helper 64 22 66% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/hw 11 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/i18n 46 4 91% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/log 62 14 77% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/netstatus 88 18 80% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/paths 53 13 75% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/plugin 62 4 94% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/region 79 5 94% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/testutils 114 4 96% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/toolkit 13 3 77% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/SimpleGtkbuilderApp 18 5 72% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/app 691 343 50% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/aptd_gtk3 44 36 18% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/dialogs/__init__ 67 24 64% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/dialogs/deauthorize_dialog 78 66 15% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/dialogs/dependency_dialogs 79 19 76% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/drawing 68 34 50% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/em 33 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/gmenusearch 82 37 55% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/models/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/models/appstore2 280 42 85% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/models/pendingstore 111 65 41% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/availablepane 421 136 68% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/basepane 15 5 67% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/globalpane 60 4 93% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/historypane 254 23 91% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/installedpane 419 118 72% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/pendingpane 95 28 71% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/softwarepane 297 74 75% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/panes/viewswitcher 174 70 60% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/review_gui_helper 803 315 61% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/session/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/session/appmanager 89 12 87% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/session/navhistory 167 17 90% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/session/viewmanager 129 31 76% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/shapes 157 97 38% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/utils 53 7 87% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/views/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/views/appdetailsview 1306 200 85% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/views/appview 193 32 83% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/views/catview_gtk 437 61 86% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/views/pkgnamesview 64 8 88% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/views/purchaseview 235 104 56% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/actionbar 230 81 65% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/apptreeview 431 216 50% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/backforward 108 23 79% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/buttons 437 80 82% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/cellrenderers 330 49 85% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/containers 396 28 93% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/description 837 448 46% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/exhibits 381 67 82% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/imagedialog 35 3 91% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/labels 59 11 81% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/menubutton 64 45 30% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/oneconfviews 98 45 54% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/recommendations 133 12 91% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/reviews 578 99 83% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/searchaid 179 61 66% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/searchentry 89 25 72% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/separators 26 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/spinner 64 2 97% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/stars 340 44 87% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/symbolic_icons 149 10 93% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/thumbnail 340 59 83% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/videoplayer 110 56 49% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/viewport 24 15 38% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/gtk3/widgets/weblivedialog 68 58 15% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/qml/__init__ 0 0 100% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/qml/categoriesmodel 53 21 60% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/qml/pkglist 132 64 52% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/ui/qml/reviewslist 46 3 93% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/utils 433 120 72% +/home/egon/devel/software-center/build-area/software-center-5.1.12/softwarecenter/version 4 0 100% __init__ 0 0 100% data/plugins/mock_plugin 4 0 100% -gtk3/test_app_view 38 0 100% +gtk3/test_app_view 61 0 100% gtk3/test_appdetailsview 323 5 98% gtk3/test_appmanager 51 0 100% gtk3/test_appstore2 35 0 100% -gtk3/test_appview 45 0 100% -gtk3/test_catview 130 0 100% +gtk3/test_catview 136 0 100% gtk3/test_custom_lists 38 0 100% gtk3/test_debfile_view 27 0 100% gtk3/test_dialogs 27 0 100% @@ -146,7 +145,7 @@ gtk3/test_recommendations_widgets 14 0 100% gtk3/test_reviews 129 2 98% gtk3/test_search 48 0 100% -gtk3/test_unity_launcher_integration 66 0 100% +gtk3/test_unity_launcher_integration 84 0 100% gtk3/test_views 40 0 100% gtk3/test_widgets 161 1 99% qml/test_ui_qml_helpers 78 0 100% @@ -156,7 +155,7 @@ test_categories 58 0 100% test_channels 25 0 100% test_cmdfiner 20 0 100% -test_database 419 34 92% +test_database 398 1 99% test_debfileapplication 67 1 99% test_description_norm 35 0 100% test_distro 20 0 100% @@ -171,12 +170,13 @@ test_netstatus 16 0 100% test_origin 22 0 100% test_package_info 59 0 100% +test_pep8 41 1 98% test_pkginfo 36 1 97% test_plugin 18 0 100% test_ppa_iconfilename 41 1 98% test_purchase_backend 47 23 51% test_pyflakes 9 0 100% -test_recagent 101 20 80% +test_recagent 102 20 80% test_region 46 0 100% test_reinstall_purchased 140 0 100% test_rnr_api 14 0 100% @@ -184,9 +184,9 @@ test_startup 39 24 38% test_testutils 37 0 100% test_ubuntu_sso_api 19 0 100% -test_utils 93 11 88% +test_utils 104 11 89% test_where_is_it 51 9 82% test_xapian 71 1 99% test_xapian_query 53 1 98% -------------------------------------------------------------------------------------------------------------------------------------------- -TOTAL 23682 6186 74% +TOTAL 23680 6021 75% diff -Nru software-center-5.1.11/test/gtk3/test_app_view.py software-center-5.1.12/test/gtk3/test_app_view.py --- software-center-5.1.11/test/gtk3/test_app_view.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/test/gtk3/test_app_view.py 2012-03-08 19:48:54.000000000 +0000 @@ -1,11 +1,8 @@ #!/usr/bin/python -import time import unittest import xapian -from gi.repository import Gtk - from testutils import setup_test_env setup_test_env() @@ -15,6 +12,7 @@ from softwarecenter.testutils import (get_test_db, get_test_pkg_info, get_test_gtk3_icon_cache, + do_events, ) class TestAppView(unittest.TestCase): @@ -39,7 +37,7 @@ # set matches appview.clear_model() appview.display_matches(enquirer.matches) - self._p() + do_events() # verify that the order is actually the correct one model = appview.tree_view.get_model() docs_in_model = [item[0] for item in model] @@ -49,15 +47,61 @@ for i in range(len(docs_in_model)): self.assertEqual(self.db.get_pkgname(docs_in_model[i]), self.db.get_pkgname(docs_from_enquirer[i])) + win.destroy() + + def test_appview_search_combo(self): + from softwarecenter.ui.gtk3.views.appview import get_test_window + from softwarecenter.testutils import get_test_enquirer_matches + + # test if combox sort option "by relevance" vanishes for non-searches + # LP: #861778 + expected_normal = ["By Name", "By Top Rated", "By Newest First"] + expected_search = ["By Name", "By Top Rated", "By Newest First", + "By Relevance"] + + # setup goo + win = get_test_window() + appview = win.get_data("appview") + #entry = win.get_data("entry") + do_events() + + # get the model + model = appview.sort_methods_combobox.get_model() + + # test normal window (no search) + matches = get_test_enquirer_matches(appview.helper.db) + appview.display_matches(matches, is_search=False) + do_events() + in_model = [] + for item in model: + in_model.append(model.get_value(item.iter, 0)) + self.assertEqual(in_model, expected_normal) + + # now repeat and simulate a search + matches = get_test_enquirer_matches(appview.helper.db) + appview.display_matches(matches, is_search=True) + do_events() + in_model = [] + for item in model: + in_model.append(model.get_value(item.iter, 0)) + self.assertEqual(in_model, expected_search) + + # and back again to no search + matches = get_test_enquirer_matches(appview.helper.db) + appview.display_matches(matches, is_search=False) + do_events() + # collect items in the model + in_model = [] + for item in model: + in_model.append(model.get_value(item.iter, 0)) + self.assertEqual(expected_normal, in_model) + + # destroy + win.destroy() - def _p(self): - for i in range(5): - time.sleep(0.1) - while Gtk.events_pending(): - Gtk.main_iteration() if __name__ == "__main__": - import logging - logging.basicConfig(level=logging.DEBUG) + #import logging + #logging.basicConfig(level=logging.DEBUG) unittest.main() diff -Nru software-center-5.1.11/test/gtk3/test_appview.py software-center-5.1.12/test/gtk3/test_appview.py --- software-center-5.1.11/test/gtk3/test_appview.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/test/gtk3/test_appview.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -#!/usr/bin/python - -from gi.repository import Gtk, GObject -import time -import unittest - -from testutils import setup_test_env -setup_test_env() - -#from mock import Mock - -TIMEOUT=300 - -class TestViews(unittest.TestCase): - - def test_appview_search_combo(self): - from softwarecenter.ui.gtk3.views.appview import get_test_window - from softwarecenter.testutils import get_test_enquirer_matches - - # test if combox sort option "by relevance" vanishes for non-searches - # LP: #861778 - expected_normal = ["By Name", "By Top Rated", "By Newest First"] - expected_search = ["By Name", "By Top Rated", "By Newest First", - "By Relevance"] - - # setup goo - win = get_test_window() - self._p() - appview = win.get_data("appview") - - # test normal window (no search) - model = appview.sort_methods_combobox.get_model() - # collect items in the model - in_model = [] - for item in model: - in_model.append(model.get_value(item.iter, 0)) - # this is what we expect there - self.assertEqual(expected_normal, in_model) - - # now repeat and simulate a search - matches = get_test_enquirer_matches(appview.helper.db) - appview.display_matches(matches, is_search=True) - self._p() - in_model = [] - for item in model: - in_model.append(model.get_value(item.iter, 0)) - self.assertEqual(in_model, expected_search) - - # and back again to no search - matches = get_test_enquirer_matches(appview.helper.db) - appview.display_matches(matches, is_search=False) - self._p() - # collect items in the model - in_model = [] - for item in model: - in_model.append(model.get_value(item.iter, 0)) - self.assertEqual(expected_normal, in_model) - - # destroy - GObject.timeout_add(TIMEOUT, lambda: win.destroy()) - Gtk.main() - - def _p(self): - for i in range(10): - time.sleep(0.1) - while Gtk.events_pending(): - Gtk.main_iteration() - -if __name__ == "__main__": - import logging - logging.basicConfig(level=logging.DEBUG) - unittest.main() diff -Nru software-center-5.1.11/test/gtk3/test_catview.py software-center-5.1.12/test/gtk3/test_catview.py --- software-center-5.1.11/test/gtk3/test_catview.py 2012-03-01 19:08:21.000000000 +0000 +++ software-center-5.1.12/test/gtk3/test_catview.py 2012-03-09 07:45:49.000000000 +0000 @@ -1,7 +1,7 @@ from gi.repository import Gtk, GObject import time import unittest -from mock import patch +from mock import patch, Mock from testutils import setup_test_env setup_test_env() @@ -24,6 +24,12 @@ # get the widgets we need win = get_test_window_catview() lobby = win.get_data("lobby") + + # simulate review-stats refresh + lobby._update_top_rated_content = Mock() + lobby.reviews_loader.emit("refresh-review-stats-finished", []) + self.assertTrue(lobby._update_top_rated_content.called) + # test clicking top_rated lobby.connect("category-selected", self._on_category_selected) lobby.top_rated_frame.more.clicked() @@ -38,6 +44,12 @@ # get the widgets we need win = get_test_window_catview() lobby = win.get_data("lobby") + + # test db reopen triggers whats-new update + lobby._update_whats_new_content = Mock() + lobby.db.emit("reopen") + self.assertTrue(lobby._update_whats_new_content.called) + # test clicking new lobby.connect("category-selected", self._on_category_selected) lobby.whats_new_frame.more.clicked() diff -Nru software-center-5.1.11/test/gtk3/test_unity_launcher_integration.py software-center-5.1.12/test/gtk3/test_unity_launcher_integration.py --- software-center-5.1.11/test/gtk3/test_unity_launcher_integration.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/test/gtk3/test_unity_launcher_integration.py 2012-03-07 17:25:50.000000000 +0000 @@ -16,14 +16,19 @@ from softwarecenter.ui.gtk3.panes.availablepane import get_test_window from softwarecenter.backend.unitylauncher import UnityLauncherInfo +# Tests for Ubuntu Software Center's integration with the Unity launcher, +# see https://wiki.ubuntu.com/SoftwareCenter#Learning%20how%20to%20launch%20an%20application + # we can only have one instance of availablepane, so create it here win = get_test_window() available_pane = win.get_data("pane") -# see https://wiki.ubuntu.com/SoftwareCenter#Learning%20how%20to%20launch%20an%20application - class TestUnityLauncherIntegration(unittest.TestCase): - + + def setUp(self): + # monkey patch is_unity_running + softwarecenter.utils.is_unity_running = lambda: True + def _zzz(self): for i in range(10): time.sleep(0.1) @@ -33,9 +38,28 @@ while Gtk.events_pending(): Gtk.main_iteration() - def setUp(self): - # monkey patch is_unity_running - softwarecenter.utils.is_unity_running = lambda: True + def _install_from_list_view(self, pkgname): + from softwarecenter.ui.gtk3.panes.availablepane import AvailablePane + available_pane.notebook.set_current_page(AvailablePane.Pages.LIST) + + self._p() + available_pane.on_search_terms_changed(None, "ark,artha,software-center") + self._p() + + # select the first item in the list + available_pane.app_view.tree_view.set_cursor(Gtk.TreePath(0), + None, False) + # ok to just use the test app here + app = Application("", pkgname) + self._p() + + # pretend we started an install + available_pane.backend.emit("transaction-started", + app.pkgname, app.appname, + "testid101", + TransactionTypes.INSTALL) + # wait a wee bit + self._zzz() def _navigate_to_appdetails_and_install(self, pkgname): app = Application("", pkgname) @@ -59,14 +83,38 @@ self.expected_launcher_info.icon_name) self.assertTrue(launcher_info.icon_x > 5) self.assertTrue(launcher_info.icon_y > 5) - self.assertEqual(launcher_info.icon_size, 96) + # check that the icon size is one of either 32 pixels (for the + # list view case) or 96 pixels (for the details view case) + self.assertTrue(launcher_info.icon_size == 32 or + launcher_info.icon_size == 96) self.assertEqual(launcher_info.app_install_desktop_file_path, self.expected_launcher_info.app_install_desktop_file_path) self.assertEqual(launcher_info.trans_id, self.expected_launcher_info.trans_id) + + def test_unity_launcher_integration_list_view(self): + # test the automatic add to launcher enabled functionality when + # installing an app form the list view + available_pane.add_to_launcher_enabled = True + test_pkgname = "lincity-ng" + # now pretend + # for testing, we substitute a fake version of UnityLauncher's + # send_application_to_launcher method that lets us check for the + # correct values and also avoids firing the actual dbus signal + # to the unity launcher service + self.expected_pkgname = test_pkgname + self.expected_launcher_info = UnityLauncherInfo("lincity-ng", + "lincity-ng", + 0, 0, 0, 0, # these values are set in availablepane + "/usr/share/app-install/desktop/lincity-ng:lincity-ng.desktop", + "testid101") + available_pane.unity_launcher.send_application_to_launcher = ( + self._fake_send_application_to_launcher_and_check) + self._install_from_list_view(test_pkgname) - def test_unity_launcher_integration(self): - # test the automatic add to launcher enabled functionality + def test_unity_launcher_integration_details_view(self): + # test the automatic add to launcher enabled functionality when + # installing an app from the details view available_pane.add_to_launcher_enabled = True test_pkgname = "lincity-ng" # now pretend @@ -134,7 +182,7 @@ # FIXME: this will only work if update-manager is installed self.assertEqual(installed_desktop_path, "/usr/share/applications/update-manager.desktop") - + if __name__ == "__main__": unittest.main() diff -Nru software-center-5.1.11/test/gtk3/testutils.py software-center-5.1.12/test/gtk3/testutils.py --- software-center-5.1.11/test/gtk3/testutils.py 2012-03-01 19:08:21.000000000 +0000 +++ software-center-5.1.12/test/gtk3/testutils.py 2012-03-09 07:45:49.000000000 +0000 @@ -102,6 +102,13 @@ import softwarecenter.paths return softwarecenter.paths.datadir +def get_test_categories(db): + import softwarecenter.paths + from softwarecenter.db.categories import CategoriesParser + parser = CategoriesParser(db) + cats = parser.parse_applications_menu(softwarecenter.paths.APP_INSTALL_PATH) + return cats + def get_test_enquirer_matches(db, query=None, limit=20, sortmode=0): from softwarecenter.db.enquire import AppEnquire import xapian diff -Nru software-center-5.1.11/test/test_addons.py software-center-5.1.12/test/test_addons.py --- software-center-5.1.11/test/test_addons.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/test/test_addons.py 2012-03-08 19:49:09.000000000 +0000 @@ -52,7 +52,7 @@ # this package too # FIXME: why only for "lonley" dependencies and not all? res = self.cache.get_addons("arduino-core") - self.assertEqual(res, ([], ["avrdude-doc"])) + self.assertEqual(res, ([], ["avrdude-doc", "arduino-mk"])) def test_addons_removal_included_depends(self): res = self.cache.get_addons("amule-gnome-support") diff -Nru software-center-5.1.11/test/test_database.py software-center-5.1.12/test/test_database.py --- software-center-5.1.11/test/test_database.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/test/test_database.py 2012-03-08 07:48:06.000000000 +0000 @@ -319,9 +319,7 @@ doc.get_value(value_time) >= last_time last_time = doc.get_value(value_time) - # FIXME: re-enable both tests once sc.staging.ubuntu.com has the new - # version of scagent with support for the publication date - def disabled_test_for_purchase_apps_date_published(self): + def test_for_purchase_apps_date_published(self): from softwarecenter.testutils import get_test_pkg_info #os.environ["SOFTWARE_CENTER_DEBUG_HTTP"] = "1" os.environ["SOFTWARE_CENTER_AGENT_HOST"] = "http://sc.staging.ubuntu.com/" @@ -341,36 +339,6 @@ self.assertNotEqual(date_published, None) del os.environ["SOFTWARE_CENTER_AGENT_HOST"] - def disabled_test_for_purchase_apps_cataloged_time(self): - from softwarecenter.testutils import get_test_pkg_info - #os.environ["SOFTWARE_CENTER_DEBUG_HTTP"] = "1" - os.environ["SOFTWARE_CENTER_AGENT_HOST"] = "http://sc.staging.ubuntu.com/" - # staging does not have a valid cert - os.environ["PISTON_MINI_CLIENT_DISABLE_SSL_VALIDATION"] = "1" - cache = get_test_pkg_info() - db = xapian.WritableDatabase("./data/test.db", - xapian.DB_CREATE_OR_OVERWRITE) - res = update_from_software_center_agent(db, cache, ignore_cache=True) - self.assertTrue(res) - res = update_from_app_install_data(db, self.cache, datadir="./data/desktop") - self.assertTrue(res) - db = StoreDatabase("./data/test.db", self.cache) - db.open(use_axi=True) - - axi_value_time = db._axi_values["catalogedtime"] - sc_app = Application("Ubuntu Software Center Test", "software-center") - sc_doc = db.get_xapian_document(sc_app.appname, sc_app.pkgname) - sc_cataloged_time = sc_doc.get_value(axi_value_time) - for_purch_app = Application("For Purchase Test App", "hellox") - for_purch_doc = db.get_xapian_document(for_purch_app.appname, - for_purch_app.pkgname) - for_purch_cataloged_time = for_purch_doc.get_value(axi_value_time) - # the for-purchase test package should be cataloged at a - # later time than axi package Ubuntu Software Center - self.assertTrue(for_purch_cataloged_time > sc_cataloged_time) - - del os.environ["SOFTWARE_CENTER_AGENT_HOST"] - def test_hardware_requirements_satisfied(self): with patch.object(AppDetails, 'hardware_requirements') as mock_hw: # setup env diff -Nru software-center-5.1.11/test/test_pep8.py software-center-5.1.12/test/test_pep8.py --- software-center-5.1.11/test/test_pep8.py 1970-01-01 00:00:00.000000000 +0000 +++ software-center-5.1.12/test/test_pep8.py 2012-03-09 07:45:56.000000000 +0000 @@ -0,0 +1,55 @@ +import os +import pep8 +import unittest +from collections import defaultdict + +from testutils import setup_test_env +setup_test_env() + +# Only test these two packages for now: +import softwarecenter.db.pkginfo_impl +import softwarecenter.ui.gtk3.widgets +import softwarecenter.ui.qml + +class PackagePep8TestCase(unittest.TestCase): + maxDiff = None + packages = [softwarecenter.ui.qml, + softwarecenter.ui.gtk3.widgets, + softwarecenter.db.pkginfo_impl] + exclude = ['recommendations.py', 'oneconfviews.py', 'menubutton.py', + 'labels.py', 'imagedialog.py', 'exhibits.py', 'description.py', + 'containers.py', 'cellrenderers.py', 'buttons.py', 'backforward.py', + 'apptreeview.py', 'animatedimage.py', 'actionbar.py'] + + def message(self, text): + self.errors.append(text) + + def setUp(self): + self.errors = [] + + class Options(object): + exclude = self.exclude + filename = ['*.py'] + testsuite = '' + doctest = '' + counters = defaultdict(int) + messages = {} + verbose = 0 + quiet = 0 + repeat = True + show_source = False + show_pep8 = False + select = [] + ignore = [] + pep8.options = Options() + pep8.message = self.message + Options.physical_checks = pep8.find_checks('physical_line') + Options.logical_checks = pep8.find_checks('logical_line') + + def test_all_code(self): + for package in self.packages: + pep8.input_dir(os.path.dirname(package.__file__)) + self.assertEqual([], self.errors) + +if __name__ == "__main__": + unittest.main() diff -Nru software-center-5.1.11/test/test_recagent.py software-center-5.1.12/test/test_recagent.py --- software-center-5.1.11/test/test_recagent.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/test/test_recagent.py 2012-03-08 20:28:40.000000000 +0000 @@ -24,7 +24,9 @@ self.error = False self.orig_host = os.environ.get("SOFTWARE_CENTER_RECOMMENDER_HOST") if not "SOFTWARE_CENTER_RECOMMENDER_HOST" in os.environ: - os.environ["SOFTWARE_CENTER_RECOMMENDER_HOST"] = "https://rec.staging.ubuntu.com" + #server = "https://rec.staging.ubuntu.com" + server = "https://rec.ubuntu.com" + os.environ["SOFTWARE_CENTER_RECOMMENDER_HOST"] = server def tearDown(self): if self.orig_host is None: diff -Nru software-center-5.1.11/test/test_utils.py software-center-5.1.12/test/test_utils.py --- software-center-5.1.11/test/test_utils.py 2012-03-01 11:32:16.000000000 +0000 +++ software-center-5.1.12/test/test_utils.py 2012-03-07 17:25:50.000000000 +0000 @@ -124,6 +124,31 @@ uuid = get_uuid() self.assertTrue(uuid and len(uuid) > 0) + def test_make_string_from_list(self): + from softwarecenter.utils import make_string_from_list + base = "There was a problem posting this review to %s (omg!)" + # test the various forms + l = ["twister"] + self.assertEqual( + make_string_from_list(base, l), + "There was a problem posting this review to twister (omg!)") + # two + l = ["twister", "factbook"] + self.assertEqual( + make_string_from_list(base, l), + "There was a problem posting this review to twister and factbook (omg!)") + # three + l = ["twister", "factbook", "identi.catz"] + self.assertEqual( + make_string_from_list(base, l), + "There was a problem posting this review to twister, factbook and identi.catz (omg!)") + # four + l = ["twister", "factbook", "identi.catz", "baz"] + self.assertEqual( + make_string_from_list(base, l), + "There was a problem posting this review to twister, factbook, identi.catz and baz (omg!)") + + class TestExpungeCache(unittest.TestCase): def test_expunge_cache(self): @@ -161,6 +186,7 @@ self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random"))) + if __name__ == "__main__": import logging logging.basicConfig(level=logging.DEBUG) diff -Nru software-center-5.1.11/test/testutils.py software-center-5.1.12/test/testutils.py --- software-center-5.1.11/test/testutils.py 2012-03-01 19:08:21.000000000 +0000 +++ software-center-5.1.12/test/testutils.py 2012-03-09 07:45:49.000000000 +0000 @@ -102,6 +102,13 @@ import softwarecenter.paths return softwarecenter.paths.datadir +def get_test_categories(db): + import softwarecenter.paths + from softwarecenter.db.categories import CategoriesParser + parser = CategoriesParser(db) + cats = parser.parse_applications_menu(softwarecenter.paths.APP_INSTALL_PATH) + return cats + def get_test_enquirer_matches(db, query=None, limit=20, sortmode=0): from softwarecenter.db.enquire import AppEnquire import xapian diff -Nru software-center-5.1.11/utils/expunge-cache.py software-center-5.1.12/utils/expunge-cache.py --- software-center-5.1.11/utils/expunge-cache.py 2012-03-01 11:30:44.000000000 +0000 +++ software-center-5.1.12/utils/expunge-cache.py 2012-03-07 17:25:50.000000000 +0000 @@ -75,6 +75,9 @@ print "Need either --by-days or --by-unsuccessful-http-states argument" sys.exit(1) + # be nice + os.nice(19) + # do it cleaner = ExpungeCache(args.directories, args) cleaner.clean()