def __init__(self, datadir, db, icons): gtk.TreeStore.__init__(self, AnimatedImage, str, int, gobject.TYPE_PYOBJECT) self.icons = icons self.datadir = datadir self.backend = get_install_backend() self.backend.connect("transactions-changed", self.on_transactions_changed) self.backend.connect("channels-changed", self.on_channels_changed) self.db = db self.distro = get_distro() # pending transactions self._pending = 0 # setup the normal stuff available_icon = self._get_icon("softwarecenter") self.available_iter = self.append(None, [available_icon, _("Get Software"), self.ACTION_ITEM_AVAILABLE, None]) # do initial channel list update self._update_channel_list() icon = AnimatedImage(self.icons.load_icon("computer", self.ICON_SIZE, 0)) installed_iter = self.append(None, [icon, _("Installed Software"), self.ACTION_ITEM_INSTALLED, None]) icon = AnimatedImage(None) self.append(None, [icon, "<span size='1'> </span>", self.ACTION_ITEM_SEPARATOR_1, None]) # kick off a background check for changes that may have been made # in the channels list glib.timeout_add(300, lambda: self._check_for_channel_updates(self.channels))
def __init__(self, db, doc=None, application=None): """ Create a new AppDetails object. It can be created from a xapian.Document or from a db.application.Application object """ GObject.GObject.__init__(self) if not doc and not application: raise ValueError("Need either document or application") self._db = db self._db.connect("reopen", self._on_db_reopen) self._cache = self._db._aptcache self._distro = get_distro() self._history = None # import here (intead of global) to avoid dbus dependency # in update-software-center (that imports application, but # never uses AppDetails) LP: #620011 from softwarecenter.backend import get_install_backend self._backend = get_install_backend() # FIXME: why two error states ? self._error = None self._error_not_found = None self._screenshot_list = None # load application self._app = application if doc: self._app = Application(self._db.get_appname(doc), self._db.get_pkgname(doc), "") # sustitute for apturl if self._app.request: self._app.request = self._app.request.replace( "$distro", self._distro.get_codename()) # load pkg cache self._pkg = None if (self._app.pkgname in self._cache and self._cache[self._app.pkgname].candidate): self._pkg = self._cache[self._app.pkgname] # load xapian document self._doc = doc if not self._doc: try: self._doc = self._db.get_xapian_document( self._app.appname, self._app.pkgname) except IndexError: # if there is no document and no apturl request, # set error state debfile_matches = re.findall(r'/', self._app.request) channel_matches = re.findall(r'channel=[a-z,-]*', self._app.request) section_matches = re.findall(r'section=[a-z]*', self._app.request) if (not self._pkg and not debfile_matches and not channel_matches and not section_matches): self._error = _("Not found") self._error_not_found = utf8(_(u"There isn\u2019t a software package called \u201c%s\u201D in your current software sources.")) % utf8(self.pkgname)
def test_add_license_key_backend(self): self._finished = False # add repo deb_line = "deb https://mvo:[email protected]/canonical-isd-hackers/internal-qa/ubuntu oneiric main" signing_key_id = "F5410BE0" app = Application("Test app1", self.PKGNAME) # install only when runnig as root, as we require polkit promtps # otherwise # FIXME: provide InstallBackendSimulate() if os.getuid() == 0: backend = get_install_backend() backend.ui = Mock() backend.connect("transaction-finished", self._on_transaction_finished) # simulate repos becomes available for the public 20 s later GObject.timeout_add_seconds(20, self._add_pw_to_commercial_repo) # run it backend.add_repo_add_key_and_install_app(deb_line, signing_key_id, app, "icon", self.LICENSE_KEY) # wait until the pkg is installed while not self._finished: while Gtk.events_pending(): Gtk.main_iteration() time.sleep(0.1) if os.getuid() == 0: self.assertTrue(os.path.exists(self.LICENSE_KEY_PATH)) self.assertEqual( open(self.LICENSE_KEY_PATH).read(), self.LICENSE_KEY)
def __init__(self, view_manager, datadir, db, cache, icons): # boring stuff self.view_manager = view_manager def on_view_changed(widget, view_id): self.view_buttons[view_id].set_active(True) self.view_manager.connect('view-changed', on_view_changed) self.channel_manager = get_channels_manager(db) # backend sig handlers ... self.backend = get_install_backend() self.backend.connect("transactions-changed", self.on_transaction_changed) self.backend.connect("transaction-finished", self.on_transaction_finished) self.backend.connect("channels-changed", self.on_channels_changed) # widgetry Gtk.Box.__init__(self) self.set_orientation(Gtk.Orientation.HORIZONTAL) # Gui stuff self.view_buttons = {} self.selectors = {} self._prev_view = None # track the previous active section self._prev_item = None # track the previous active menu-item self._handlers = [] # order is important here! # first, the availablepane items icon = SymbolicIcon("available") self.append_section_with_channel_sel( ViewPages.AVAILABLE, _("All Software"), icon, self.on_get_available_channels) # the installedpane items icon = SymbolicIcon("installed") self.append_section_with_channel_sel( ViewPages.INSTALLED, _("Installed"), icon, self.on_get_installed_channels) # the historypane item icon = SymbolicIcon("history") self.append_section(ViewPages.HISTORY, _("History"), icon) #icon = SymbolicIcon("history") #self.append_section(ViewPages.UPGRADE, _("Upgrade"), icon) # the pendingpane icon = PendingSymbolicIcon("pending") self.append_section(ViewPages.PENDING, _("Progress"), icon) # set sensible atk name atk_desc = self.get_accessible() atk_desc.set_name(_("Software sources"))
def test_add_license_key_backend(self): self._finished = False # add repo deb_line = "deb https://mvo:[email protected]/canonical-isd-hackers/internal-qa/ubuntu oneiric main" signing_key_id = "F5410BE0" app = Application("Test app1", self.PKGNAME) # install only when runnig as root, as we require polkit promtps # otherwise # FIXME: provide InstallBackendSimulate() if os.getuid() == 0: backend = get_install_backend() backend.ui = Mock() backend.connect("transaction-finished", self._on_transaction_finished) # simulate repos becomes available for the public 20 s later GObject.timeout_add_seconds(20, self._add_pw_to_commercial_repo) # run it backend.add_repo_add_key_and_install_app(deb_line, signing_key_id, app, "icon", self.LICENSE_KEY) # wait until the pkg is installed while not self._finished: while Gtk.events_pending(): Gtk.main_iteration() time.sleep(0.1) if os.getuid() == 0: self.assertTrue(os.path.exists(self.LICENSE_KEY_PATH)) self.assertEqual(open(self.LICENSE_KEY_PATH).read(), self.LICENSE_KEY)
def __init__(self, db, distro, icons, cache, datadir): super(AppDetailsView, self).__init__(datadir) self.db = db self.distro = distro self.icons = icons self.cache = cache self.cache.connect("cache-ready", self._on_cache_ready) self.datadir = datadir self.arch = get_current_arch() # atk atk_desc = self.get_accessible() atk_desc.set_name(_("Description")) # aptdaemon self.backend = get_install_backend() self.backend.connect("transaction-started", self._on_transaction_started) self.backend.connect("transaction-stopped", self._on_transaction_stopped) self.backend.connect("transaction-progress-changed", self._on_transaction_progress_changed) # data self.pkg = None self.app = None self.iconname = "" # setup user-agent settings = self.get_settings() settings.set_property("user-agent", USER_AGENT) self.connect("navigation-requested", self._on_navigation_requested)
def __init__(self, db, doc=None, application=None): """ Create a new AppDetails object. It can be created from a xapian.Document or from a db.application.Application object """ GObject.GObject.__init__(self) if not doc and not application: raise ValueError("Need either document or application") self._db = db self._db.connect("reopen", self._on_db_reopen) self._cache = self._db._aptcache self._distro = get_distro() self._history = None # import here (intead of global) to avoid dbus dependency # in update-software-center (that imports application, but # never uses AppDetails) LP: #620011 from softwarecenter.backend import get_install_backend self._backend = get_install_backend() # FIXME: why two error states ? self._error = None self._error_not_found = None self._screenshot_list = None # load application self._app = application if doc: self._app = Application(self._db.get_appname(doc), self._db.get_pkgname(doc), "") # sustitute for apturl if self._app.request: self._app.request = self._app.request.replace( "$distro", self._distro.get_codename()) # load pkg cache self._pkg = None if (self._app.pkgname in self._cache and self._cache[self._app.pkgname].candidate): self._pkg = self._cache[self._app.pkgname] # load xapian document self._doc = doc if not self._doc: try: self._doc = self._db.get_xapian_document( self._app.appname, self._app.pkgname) except IndexError: # if there is no document and no apturl request, # set error state debfile_matches = re.findall(r'/', self._app.request) channel_matches = re.findall(r'channel=[a-z,-]*', self._app.request) section_matches = re.findall(r'section=[a-z]*', self._app.request) if (not self._pkg and not debfile_matches and not channel_matches and not section_matches): self._error = _("Not found") self._error_not_found = utf8( _(u"There isn\u2019t a software package called \u201c%s\u201D in your current software sources." )) % utf8(self.pkgname)
def __init__(self, view_manager, datadir, db, cache, icons): Gtk.TreeStore.__init__(self) self.set_column_types(( GObject.TYPE_PYOBJECT, # COL_ICON str, # COL_NAME GObject.TYPE_PYOBJECT, # COL_ACTION GObject.TYPE_PYOBJECT, # COL_CHANNEL str, # COL_BUBBLE_TEXT )) # must match columns above self.view_manager = view_manager self.icons = icons self.datadir = datadir self.backend = get_install_backend() self.backend.connect("transactions-changed", self.on_transactions_changed) self.backend.connect("transaction-finished", self.on_transaction_finished) self.db = db self.cache = cache self.distro = get_distro() # pending transactions self._pending = 0 # setup the normal stuff # first, the availablepane items available_icon = self._get_icon("softwarecenter") self.available_iter = self.append(None, [ available_icon, _("Get Software"), ViewPages.AVAILABLE, None, None ]) # the installedpane items icon = self._get_icon("computer") self.installed_iter = self.append( None, [icon, _("Installed Software"), ViewPages.INSTALLED, None, None]) # the channelpane self.channel_manager = ChannelsManager(db, icons) # do initial channel list update self._update_channel_list() # the historypane item icon = self._get_icon("document-open-recent") self.append(None, [icon, _("History"), ViewPages.HISTORY, None, None]) icon = None self.append(None, [ icon, "<span size='1'> </span>", ViewPages.SEPARATOR_1, None, None ]) # the progress pane is build on demand # emit a transactions-changed signal to ensure that we display any # pending transactions self.backend.emit("transactions-changed", self.backend.pending_transactions)
def __init__(self, view_manager, datadir, db, cache, icons): # boring stuff self.view_manager = view_manager def on_view_changed(widget, view_id): self.view_buttons[view_id].set_active(True) self.view_manager.connect('view-changed', on_view_changed) self.channel_manager = get_channels_manager(db) # backend sig handlers ... self.backend = get_install_backend() self.backend.connect("transactions-changed", self.on_transaction_changed) self.backend.connect("transaction-finished", self.on_transaction_finished) self.backend.connect("channels-changed", self.on_channels_changed) # widgetry Gtk.Box.__init__(self) self.set_orientation(Gtk.Orientation.HORIZONTAL) # Gui stuff self.view_buttons = {} self.selectors = {} self._prev_view = None # track the previous active section self._prev_item = None # track the previous active menu-item self._handlers = [] # order is important here! # first, the availablepane items icon = SymbolicIcon("available") self.append_section_with_channel_sel(ViewPages.AVAILABLE, _("All Software"), icon, self.on_get_available_channels) # the installedpane items icon = SymbolicIcon("installed") self.append_section_with_channel_sel(ViewPages.INSTALLED, _("Installed"), icon, self.on_get_installed_channels) # the historypane item icon = SymbolicIcon("history") self.append_section(ViewPages.HISTORY, _("History"), icon) # the pendingpane icon = PendingSymbolicIcon("pending") self.append_section(ViewPages.PENDING, _("Progress"), icon) # set sensible atk name atk_desc = self.get_accessible() atk_desc.set_name(_("Software sources"))
def __init__(self, db): self.db = db self.distro = get_distro() self.backend = get_install_backend() self.backend.connect("channels-changed", self._remove_no_longer_needed_extra_channels) # kick off a background check for changes that may have been made # in the channels list GObject.timeout_add(300, self._check_for_channel_updates_timer) # extra channels from e.g. external sources self.extra_channels = [] self._logger = LOG
def __init__(self, db): self.db = db self.distro = get_distro() self.backend = get_install_backend() self.backend.connect("channels-changed", self._remove_no_longer_needed_extra_channels) # kick off a background check for changes that may have been made # in the channels list GObject.timeout_add_seconds(10, self._check_for_channel_updates_timer) # extra channels from e.g. external sources self.extra_channels = [] self._logger = LOG
def __init__(self, view_manager, datadir, db, cache, icons): Gtk.TreeStore.__init__(self) self.set_column_types((GObject.TYPE_PYOBJECT, # COL_ICON str, # COL_NAME GObject.TYPE_PYOBJECT, # COL_ACTION GObject.TYPE_PYOBJECT, # COL_CHANNEL str, # COL_BUBBLE_TEXT )) # must match columns above self.view_manager = view_manager self.icons = icons self.datadir = datadir self.backend = get_install_backend() self.backend.connect("transactions-changed", self.on_transactions_changed) self.backend.connect("transaction-finished", self.on_transaction_finished) self.db = db self.cache = cache self.distro = get_distro() # pending transactions self._pending = 0 # setup the normal stuff # first, the availablepane items available_icon = self._get_icon("softwarecenter") self.available_iter = self.append(None, [available_icon, _("Get Software"), ViewPages.AVAILABLE, None, None]) # the installedpane items icon = self._get_icon("computer") self.installed_iter = self.append(None, [icon, _("Installed Software"), ViewPages.INSTALLED, None, None]) # the channelpane self.channel_manager = ChannelsManager(db, icons) # do initial channel list update self._update_channel_list() # the historypane item icon = self._get_icon("document-open-recent") self.append(None, [icon, _("History"), ViewPages.HISTORY, None, None]) icon = None self.append(None, [icon, "<span size='1'> </span>", ViewPages.SEPARATOR_1, None, None]) # the progress pane is build on demand # emit a transactions-changed signal to ensure that we display any # pending transactions self.backend.emit("transactions-changed", self.backend.pending_transactions)
def __init__(self, db, distro, icons, cache, datadir): self.db = db self.distro = distro self.icons = icons self.cache = cache self.backend = get_install_backend() self.cache.connect("cache-ready", self._on_cache_ready) self.datadir = datadir self.app = None self.appdetails = None self.addons_to_install = [] self.addons_to_remove = [] # reviews self.review_loader = get_review_loader(self.cache, self.db)
def __init__(self, cache, db, distro, icons, datadir, show_ratings=True): Gtk.VBox.__init__(self) BasePane.__init__(self) # other classes we need self.enquirer = AppEnquire(cache, db) self._query_complete_handler = self.enquirer.connect( "query-complete", self.on_query_complete) self.cache = cache self.db = db self.distro = distro self.icons = icons self.datadir = datadir self.show_ratings = show_ratings self.backend = get_install_backend() self.nonapps_visible = NonAppVisibility.MAYBE_VISIBLE # refreshes can happen out-of-bound so we need to be sure # that we only set the new model (when its available) if # the refresh_seq_nr of the ready model matches that of the # request (e.g. people click on ubuntu channel, get impatient, click # on partner channel) self.refresh_seq_nr = 0 # this should be initialized self.apps_search_term = "" # Create the basic frame for the common view self.state = DisplayState() vm = get_viewmanager() self.searchentry = vm.get_global_searchentry() self.back_forward = vm.get_global_backforward() # a notebook below self.notebook = Gtk.Notebook() if not "SOFTWARE_CENTER_DEBUG_TABS" in os.environ: self.notebook.set_show_tabs(False) self.notebook.set_show_border(False) # make a spinner view to display while the applist is loading self.spinner_notebook = SpinnerNotebook(self.notebook) self.pack_start(self.spinner_notebook, True, True, 0) # add a bar at the bottom (hidden by default) for contextual actions self.action_bar = ActionBar() self.pack_start(self.action_bar, False, True, 0) # cursor self.busy_cursor = Gdk.Cursor.new(Gdk.CursorType.WATCH) # views to be created in init_view self.app_view = None self.app_details_view = None
def __init__(self, cache, db, distro, icons, datadir, show_ratings=True): Gtk.VBox.__init__(self) BasePane.__init__(self) # other classes we need self.enquirer = AppEnquire(cache, db) self._query_complete_handler = self.enquirer.connect( "query-complete", self.on_query_complete) self.cache = cache self.db = db self.distro = distro self.icons = icons self.datadir = datadir self.show_ratings = show_ratings self.backend = get_install_backend() self.nonapps_visible = NonAppVisibility.MAYBE_VISIBLE # refreshes can happen out-of-bound so we need to be sure # that we only set the new model (when its available) if # the refresh_seq_nr of the ready model matches that of the # request (e.g. people click on ubuntu channel, get impatient, click # on partner channel) self.refresh_seq_nr = 0 # this should be initialized self.apps_search_term = "" # Create the basic frame for the common view self.state = DisplayState() vm = get_viewmanager() self.searchentry = vm.get_global_searchentry() self.back_forward = vm.get_global_backforward() # a notebook below self.notebook = Gtk.Notebook() if not SOFTWARE_CENTER_DEBUG_TABS: self.notebook.set_show_tabs(False) self.notebook.set_show_border(False) # make a spinner view to display while the applist is loading self.spinner_notebook = SpinnerNotebook(self.notebook) self.pack_start(self.spinner_notebook, True, True, 0) # add a bar at the bottom (hidden by default) for contextual actions self.action_bar = ActionBar() self.pack_start(self.action_bar, False, True, 0) # cursor self.busy_cursor = Gdk.Cursor.new(Gdk.CursorType.WATCH) # views to be created in init_view self.app_view = None self.app_details_view = None
def __init__(self, icons): # icon, status, progress Gtk.ListStore.__init__(self) self.set_column_types(self.column_types) self._transactions_watcher = get_transactions_watcher() self._transactions_watcher.connect("lowlevel-transactions-changed", self._on_lowlevel_transactions_changed) # data self.icons = icons # the apt-daemon stuff self.backend = get_install_backend() self._signals = [] # let the pulse helper run GObject.timeout_add(500, self._pulse_purchase_helper)
def reinstall_purchased(self): """ reinstall a purchased app """ LOG.debug("reinstall_purchased %s" % self.app) appdetails = self.app.get_details(self.db) iconname = appdetails.icon deb_line = appdetails.deb_line license_key = appdetails.license_key license_key_path = appdetails.license_key_path signing_key_id = appdetails.signing_key_id backend = get_install_backend() backend.add_repo_add_key_and_install_app(deb_line, signing_key_id, self.app, iconname, license_key, license_key_path)
def __init__(self, parent=None): super(PkgListModel, self).__init__() self._docs = [] roles = dict(enumerate(PkgListModel.COLUMNS)) self.setRoleNames(roles) self._query = "" self._category = "" pathname = os.path.join(XAPIAN_BASE_PATH, "xapian") self.cache = get_pkg_info() self.db = StoreDatabase(pathname, self.cache) self.db.open(use_axi=False) self.backend = get_install_backend() 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 self._catparser = CategoriesParser(self.db) self._categories = self._catparser.parse_applications_menu("/usr/share/app-install")
def __init__(self, parent=None): super(PkgListModel, self).__init__() self._docs = [] roles = dict(enumerate(PkgListModel.COLUMNS)) self.setRoleNames(roles) self._query = "" self._category = "" pathname = os.path.join(XAPIAN_BASE_PATH, "xapian") self.cache = get_pkg_info() self.db = StoreDatabase(pathname, self.cache) self.db.open(use_axi=False) self.backend = get_install_backend() 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 self._catparser = CategoriesParser(self.db) self._categories = self._catparser.parse_applications_menu( '/usr/share/app-install')
def set_channel(self, channel): """ set the current software channel object for display in the channel pane and set up the AppViewFilter if required """ self.channel = channel # check to see if there is any section info that needs to be applied # FIXME #~ if channel._channel_color: #~ self.section.set_color(channel._channel_color) #~ if channel._channel_view_id: #~ self.section.set_view_id(channel._channel_view_id) #~ self.section_sync() # check if the channel needs to added if channel.needs_adding and channel._source_entry: dialog = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL, type=Gtk.MessageType.QUESTION) dialog.set_title("") dialog.set_markup("<big><b>%s</b></big>" % _("Add channel")) dialog.format_secondary_text(_("The selected channel is not yet " "added. Do you want to add it now?")) dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_ADD, Gtk.ResponseType.YES) res = dialog.run() dialog.destroy() if res == Gtk.ResponseType.YES: channel.needs_adding = False backend = get_install_backend() backend.add_sources_list_entry(channel._source_entry) backend.emit("channels-changed", True) backend.reload() return # normal operation self.nonapps_visible = NonAppVisibility.MAYBE_VISIBLE self.apps_filter = None if self.channel.installed_only: if self.apps_filter is None: self.apps_filter = AppViewFilter(self.db, self.cache) self.apps_filter.set_installed_only(True) # switch to applist, this will clear searches too self.display_list()
def _process_json(self, json_string): try: LOG.debug("server returned: '%s'" % json_string) res = json.loads(json_string) #print res except: LOG.debug("error processing json: '%s'" % json_string) return if res["successful"] == False: if (res.get("user_canceled", False) or # note the different spelling res.get("user_cancelled", False) or # COMPAT with older clients that do not send the user # canceled property (LP: #696861), this msg appears # to be not translated "CANCELLED" in res.get("failures", "")): self.emit("purchase-cancelled-by-user") self._block_wk_handlers() return # this is what the agent implements elif "failures" in res: LOG.error("the server returned a error: '%s'" % res["failures"]) # show a generic error, the "failures" string we get from the # server is way too technical to show, but we do log it self.emit("purchase-failed") self._block_wk_handlers() return else: self.emit("purchase-succeeded") self._block_wk_handlers() # gather data from response deb_line = res["deb_line"] signing_key_id = res["signing_key_id"] license_key = res.get("license_key") license_key_path = res.get("license_key_path") # add repo and key backend = get_install_backend() backend.add_repo_add_key_and_install_app(deb_line, signing_key_id, self.app, self.iconname, license_key, license_key_path)
def __init__(self, db, cache, icons, icon_size, global_icon_cache): AppPropertiesHelper.__init__(self, db, cache, icons, icon_size, global_icon_cache) # backend stuff self.backend = get_install_backend() self.backend.connect("transaction-progress-changed", self._on_transaction_progress_changed) self.backend.connect("transaction-started", self._on_transaction_started) self.backend.connect("transaction-finished", self._on_transaction_finished) # keep track of paths for transactions in progress self.transaction_path_map = {} # active row path self.active_row = None self._in_progress = False self._break = False # other stuff self.active = False
def _process_json(self, json_string): try: LOG.debug("server returned: '%s'" % json_string) res = json.loads(json_string) #print res except: LOG.debug("error processing json: '%s'" % json_string) return if res["successful"] == False: if (res.get("user_canceled", False) or # note the different spelling res.get("user_cancelled", False) or # COMPAT with older clients that do not send the user # canceled property (LP: #696861), this msg appears # to be not translated "CANCELLED" in res.get("failures", "")): self.emit("purchase-cancelled-by-user") self._block_wk_handlers() return # this is what the agent implements elif "failures" in res: LOG.error("the server returned a error: '%s'" % res["failures"]) # show a generic error, the "failures" string we get from the # server is way too technical to show, but we do log it self.emit("purchase-failed") self._block_wk_handlers() return else: self.emit("purchase-succeeded") self._block_wk_handlers() # gather data from response deb_line = res["deb_line"] signing_key_id = res["signing_key_id"] license_key = res.get("license_key") license_key_path = res.get("license_key_path") # add repo and key backend = get_install_backend() backend.add_repo_add_key_and_install_app( deb_line, signing_key_id, self.app, self.iconname, license_key, license_key_path, json.dumps(self._oauth_token))
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) # backend stuff self.backend = get_install_backend() self.backend.connect("transaction-progress-changed", self._on_transaction_progress_changed) self.backend.connect("transaction-started", self._on_transaction_started) self.backend.connect("transaction-finished", self._on_transaction_finished) # 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 # other stuff self.active = False return
def __init__(self, app_view, db, icons, show_ratings, store=None): Gtk.TreeView.__init__(self) self._logger = logging.getLogger("softwarecenter.view.appview") self.app_view = app_view self.db = db self.pressed = False self.focal_btn = None self._action_block_list = [] self._needs_collapse = [] self.expanded_path = None #~ # if this hacked mode is available everything will be fast #~ # and we can set fixed_height mode and still have growing rows #~ # (see upstream gnome #607447) try: self.set_property("ubuntu-almost-fixed-height-mode", True) self.set_fixed_height_mode(True) except: self._logger.warn("ubuntu-almost-fixed-height-mode extension not available") self.set_headers_visible(False) # a11y: this is a cell renderer that only displays a icon, but still # has a markup property for orca and friends # we use it so that orca and other a11y tools get proper text to read # it needs to be the first one, because that is what the tools look # at by default tr = CellRendererAppView(icons, self.create_pango_layout(''), show_ratings, Icons.INSTALLED_OVERLAY) tr.set_pixbuf_width(32) tr.set_button_spacing(em(0.3)) # create buttons and set initial strings info = CellButtonRenderer(self, name=CellButtonIDs.INFO) info.set_markup_variants( {self.VARIANT_INFO: _('More Info')}) action = CellButtonRenderer(self, name=CellButtonIDs.ACTION) action.set_markup_variants( {self.VARIANT_INSTALL: _('Install'), self.VARIANT_REMOVE: _('Remove'), self.VARIANT_PURCHASE: _(u'Buy\u2026')}) tr.button_pack_start(info) tr.button_pack_end(action) column = Gtk.TreeViewColumn("Applications", tr, application=AppGenericStore.COL_ROW_DATA) column.set_cell_data_func(tr, self._cell_data_func_cb) column.set_fixed_width(200) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self.append_column(column) # network status watcher watcher = get_network_watcher() watcher.connect("changed", self._on_net_state_changed, tr) # custom cursor self._cursor_hand = Gdk.Cursor.new(Gdk.CursorType.HAND2) self.connect("style-updated", self._on_style_updated, tr) # button and motion are "special" self.connect("button-press-event", self._on_button_press_event, tr) self.connect("button-release-event", self._on_button_release_event, tr) self.connect("key-press-event", self._on_key_press_event, tr) self.connect("key-release-event", self._on_key_release_event, tr) self.connect("motion-notify-event", self._on_motion, tr) self.connect("cursor-changed", self._on_cursor_changed, tr) # our own "activate" handler self.connect("row-activated", self._on_row_activated, tr) self.backend = get_install_backend() self._transactions_connected = False self.connect('realize', self._on_realize, tr)
def test_fake_aptd(self): from softwarecenter.backend import get_install_backend backend = get_install_backend() backend.install("2vcard", "", "") self._p()
def __init__(self, cache, db, icons, search_query=None, limit=200, sort=False, filter=None): """ Initalize a AppStore. :Parameters: - `cache`: apt cache (for stuff like the overlay icon) - `db`: a xapian.Database that contians the applications - `icons`: a gtk.IconTheme that contains the icons - `search_query`: a single search as a xapian.Query or a list - `limit`: how many items the search should return (0 == unlimited) - `sort`: sort alphabetically after a search (default is to use relevance sort) - `filter`: filter functions that can be used to filter the data further. A python function that gets a pkgname """ gtk.GenericTreeModel.__init__(self) self.search_query = search_query self.cache = cache self.db = db self.icons = icons # invalidate the cache on icon theme changes self.icons.connect("changed", lambda theme: _app_icon_cache.clear()) self._appicon_missing_icon = self.icons.load_icon(MISSING_APP_ICON, self.ICON_SIZE, 0) self.apps = [] # this is used to re-set the cursor self.app_index_map = {} # this is used to find the in-progress rows self.pkgname_index_map = {} self.sorted = sort self.filter = filter self.active = True self.backend = get_install_backend() self.backend.connect("transaction-progress-changed", self._on_transaction_progress_changed) # rowref of the active app and last active app self.active_app = None self._prev_active_app = 0 self._searches_sort_mode = self._get_searches_sort_mode() # FIXME: do the sorting/adding in a seperate thread? if not search_query: # limit to applications for m in db.xapiandb.postlist("ATapplication"): doc = db.xapiandb.get_document(m.docid) if filter and self.is_filtered_out(filter, doc): continue appname = doc.get_value(XAPIAN_VALUE_APPNAME) pkgname = db.get_pkgname(doc) popcon = db.get_popcon(doc) self.apps.append(Application(appname, pkgname, popcon)) # keep the UI going while gtk.events_pending(): gtk.main_iteration() self.apps.sort() for (i, app) in enumerate(self.apps): self.app_index_map[app] = i else: # we support single and list search_queries, # if list we append them one by one if isinstance(search_query, xapian.Query): search_query = [search_query] already_added = set() for q in search_query: logging.debug("using query: '%s'" % q) enquire = xapian.Enquire(db.xapiandb) enquire.set_query(q) # set search order mode if self._searches_sort_mode == self.SEARCHES_SORTED_BY_POPCON: enquire.set_sort_by_value_then_relevance(XAPIAN_VALUE_POPCON) elif self._searches_sort_mode == self.SEARCHES_SORTED_BY_ALPHABETIC: self.sorted=sort=True if limit == 0: matches = enquire.get_mset(0, len(db)) else: matches = enquire.get_mset(0, limit) logging.debug("found ~%i matches" % matches.get_matches_estimated()) app_index = 0 for m in matches: doc = m.document if "APPVIEW_DEBUG_TERMS" in os.environ: print doc.get_value(XAPIAN_VALUE_APPNAME) for t in doc.termlist(): print "'%s': %s (%s); " % (t.term, t.wdf, t.termfreq), print "\n" appname = doc.get_value(XAPIAN_VALUE_APPNAME) pkgname = db.get_pkgname(doc) if filter and self.is_filtered_out(filter, doc): continue # when doing multiple queries we need to ensure # we don't add duplicates popcon = db.get_popcon(doc) app = Application(appname, pkgname, popcon) if not app in already_added: self.apps.append(app) already_added.add(app) if not sort: self.app_index_map[app] = app_index app_index = app_index + 1 # keep the UI going while gtk.events_pending(): gtk.main_iteration() if sort: self.apps.sort() for (i, app) in enumerate(self.apps): self.app_index_map[app] = i # build the pkgname map for (i, app) in enumerate(self.apps): if not app.pkgname in self.pkgname_index_map: self.pkgname_index_map[app.pkgname] = [] self.pkgname_index_map[app.pkgname].append(i)
def __init__(self, show_ratings, store=None): gtk.TreeView.__init__(self) self.buttons = {} self.focal_btn = None # if this hacked mode is available everything will be fast # and we can set fixed_height mode and still have growing rows # (see upstream gnome #607447) try: self.set_property("ubuntu-almost-fixed-height-mode", True) self.set_fixed_height_mode(True) except: logging.warn("ubuntu-almost-fixed-height-mode extension not available") self.set_headers_visible(False) # a11y: this is a fake cell renderer with a zero size # we use it so that orca and other a11y tools get proper text to read # it needs to be the first one, because that is what the tools look # at by default tt = gtk.CellRendererText() column = gtk.TreeViewColumn("Name", tt, text=AppStore.COL_TEXT) column.set_fixed_width(1) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.append_column(column) # the columns that are actually visible tp = CellRendererPixbufWithOverlay("software-center-installed") tp.set_property('ypad', 2) column = gtk.TreeViewColumn("Icon", tp, pixbuf=AppStore.COL_ICON, overlay=AppStore.COL_INSTALLED) column.set_fixed_width(32) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.append_column(column) tr = CellRendererAppView(show_ratings) tr.set_property('xpad', 3) tr.set_property('ypad', 2) column = gtk.TreeViewColumn("Apps", tr, markup=AppStore.COL_MARKUP, rating=AppStore.COL_POPCON, isactive=AppStore.COL_IS_ACTIVE, installed=AppStore.COL_INSTALLED, available=AppStore.COL_AVAILABLE, action_in_progress=AppStore.COL_ACTION_IN_PROGRESS) column.set_fixed_width(200) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.append_column(column) if store is None: store = gtk.ListStore(str, gtk.gdk.Pixbuf) self.set_model(store) # custom cursor self._cursor_hand = gtk.gdk.Cursor(gtk.gdk.HAND2) # our own "activate" handler self.connect("row-activated", self._on_row_activated) # button and motion are "special" self.connect("style-set", self._on_style_set, tr) self.connect("button-press-event", self._on_button_press_event, column) self.connect("cursor-changed", self._on_cursor_changed) self.connect("motion-notify-event", self._on_motion, tr, column) self.backend = get_install_backend() self.backend.connect("transaction-started", self._on_transaction_started) self.backend.connect("transaction-finished", self._on_transaction_finished) self.backend.connect("transaction-stopped", self._on_transaction_stopped)
def test_fake_aptd(self): from softwarecenter.backend import get_install_backend backend = get_install_backend() backend.install(Application("2vcard", ""), iconname="") self._p()
res = "ok" res = error(parent=parent, primary=primary, secondary=secondary, details=details, alternative_action=alternative_action) if res == Gtk.ResponseType.YES: res = "yes" return res if __name__ == "__main__": from softwarecenter.backend import get_install_backend from softwarecenter.ui.gtk3.aptd_gtk3 import InstallBackendUI from mock import Mock aptd = get_install_backend() aptd.ui = InstallBackendUI() # test config file prompt trans = Mock() res = aptd._config_file_conflict(trans, "/etc/group", "/etc/group-") print (res) # test medium required trans = Mock() res = aptd._medium_required(trans, "medium", "drive") print (res) # test error dialog trans = Mock() trans.error_code = 102 trans.error_details = "details"
def __init__(self, app_view, db, icons, show_ratings, store=None): Gtk.TreeView.__init__(self) self._logger = logging.getLogger("softwarecenter.view.appview") self.app_view = app_view self.db = db self.pressed = False self.focal_btn = None self._action_block_list = [] self._needs_collapse = [] self.expanded_path = None self.selected_row_renderer = 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 #~ # (see upstream gnome #607447) try: self.set_property("ubuntu-almost-fixed-height-mode", True) self.set_fixed_height_mode(True) except: self._logger.warn( "ubuntu-almost-fixed-height-mode extension not available") self.set_headers_visible(False) # our custom renderer self._renderer = CellRendererAppView(icons, self.create_pango_layout(''), show_ratings, Icons.INSTALLED_OVERLAY) self._renderer.set_pixbuf_width(32) self._renderer.set_button_spacing(em(0.3)) # create buttons and set initial strings info = CellButtonRenderer(self, name=CellButtonIDs.INFO) info.set_markup_variants({self.VARIANT_INFO: _('More Info')}) action = CellButtonRenderer(self, name=CellButtonIDs.ACTION) action.set_markup_variants({ self.VARIANT_INSTALL: _('Install'), self.VARIANT_REMOVE: _('Remove'), self.VARIANT_PURCHASE: _(u'Buy\u2026') }) self._renderer.button_pack_start(info) self._renderer.button_pack_end(action) self._column = Gtk.TreeViewColumn( "Applications", self._renderer, application=AppGenericStore.COL_ROW_DATA) self._column.set_cell_data_func(self._renderer, self._cell_data_func_cb) self._column.set_fixed_width(200) self._column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self.append_column(self._column) # network status watcher watcher = get_network_watcher() watcher.connect("changed", self._on_net_state_changed, self._renderer) # custom cursor self._cursor_hand = Gdk.Cursor.new(Gdk.CursorType.HAND2) self.connect("style-updated", self._on_style_updated, self._renderer) # button and motion are "special" self.connect("button-press-event", self._on_button_press_event, self._renderer) self.connect("button-release-event", self._on_button_release_event, self._renderer) self.connect("key-press-event", self._on_key_press_event, self._renderer) self.connect("key-release-event", self._on_key_release_event, self._renderer) self.connect("motion-notify-event", self._on_motion, self._renderer) self.connect("cursor-changed", self._on_cursor_changed, self._renderer) # our own "activate" handler self.connect("row-activated", self._on_row_activated, self._renderer) self.backend = get_install_backend() self._transactions_connected = False self.connect('realize', self._on_realize, self._renderer)
def __init__(self, helper, doc, icon_size=48): TileButton.__init__(self) self._pressed = False label = helper.get_appname(doc) icon = helper.get_icon_at_size(doc, icon_size, icon_size) stats = helper.get_review_stats(doc) doc.installed = doc.available = None self.is_installed = helper.is_installed(doc) self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY, self.INSTALLED_OVERLAY_SIZE, 0) # flags self.box.set_orientation(Gtk.Orientation.HORIZONTAL) self.box.set_spacing(StockEms.SMALL) self.content_left = Gtk.Box.new(Gtk.Orientation.VERTICAL, StockEms.MEDIUM) self.content_right = Gtk.Box.new(Gtk.Orientation.VERTICAL, 1) self.box.pack_start(self.content_left, False, False, 0) self.box.pack_start(self.content_right, False, False, 0) self.image = _parse_icon(icon, icon_size) self.content_left.pack_start(self.image, False, False, 0) self.title = Gtk.Label.new(self._MARKUP % GObject.markup_escape_text(label)) self.title.set_alignment(0.0, 0.5) self.title.set_use_markup(True) self.title.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.title, False, False, 0) categories = helper.get_categories(doc) if categories is not None: self.category = Gtk.Label.new('<span font_desc="%i">%s</span>' % (em(0.6), GObject.markup_escape_text(categories))) self.category.set_use_markup(True) self.category.set_alignment(0.0, 0.5) self.category.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.category, False, False, 4) stats_a11y = None if stats is not None: self.stars = Star(size=StarSize.SMALL) self.stars.render_outline = True self.stars.set_rating(stats.ratings_average) self.rating_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, StockEms.SMALL) self.rating_box.pack_start(self.stars, False, False, 0) self.n_ratings = Gtk.Label.new( '<span font_desc="%i"> (%i)</span>' % ( em(0.45), stats.ratings_total)) self.n_ratings.set_use_markup(True) self.n_ratings.set_name("subtle-label") self.n_ratings.set_alignment(0.0, 0.5) self.rating_box.pack_start(self.n_ratings, False, False, 0) self.content_right.pack_start(self.rating_box, False, False, 0) # TRANSLATORS: this is an accessibility description for eg orca and # is not visible in the ui stats_a11y = _('%(stars)d stars - %(reviews)d reviews') % { 'stars': stats.ratings_average, 'reviews': stats.ratings_total} #work out width tile needs to be to ensure ratings text is all visible req_width = (self.stars.size_request().width + self.image.size_request().width + self.n_ratings.size_request().width + StockEms.MEDIUM * 3 ) global _global_featured_tile_width _global_featured_tile_width = max(_global_featured_tile_width, req_width) details = AppDetails(db=helper.db, doc=doc) price = details.price or _("Free") if price == '0.00': price = _("Free") if price != _("Free"): price = 'US$ ' + price self.price = Gtk.Label.new( '<span font_desc="%i">%s</span>' % (em(0.6), price)) self.price.set_use_markup(True) self.price.set_name("subtle-label") self.price.set_alignment(0.0, 0.5) self.content_right.pack_start(self.price, False, False, 0) self.set_name("featured-tile") a11y_name = '. '.join([t for t in [label, categories, stats_a11y, price] if t]) self.get_accessible().set_name(a11y_name) backend = get_install_backend() backend.connect("transaction-finished", self.on_transaction_finished, helper, doc) self.connect("enter-notify-event", self.on_enter) self.connect("leave-notify-event", self.on_leave) self.connect("button-press-event", self.on_press) self.connect("button-release-event", self.on_release) return
def __init__(self, helper, doc, icon_size=48): TileButton.__init__(self) self._pressed = False label = helper.get_appname(doc) icon = helper.get_icon_at_size(doc, icon_size, icon_size) stats = helper.get_review_stats(doc) helper.update_availability(doc) helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size) self.is_installed = helper.is_installed(doc) self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY, self.INSTALLED_OVERLAY_SIZE, 0) # flags self.box.set_orientation(Gtk.Orientation.HORIZONTAL) self.box.set_spacing(StockEms.SMALL) self.content_left = Gtk.Box.new(Gtk.Orientation.VERTICAL, StockEms.MEDIUM) self.content_right = Gtk.Box.new(Gtk.Orientation.VERTICAL, 1) self.box.pack_start(self.content_left, False, False, 0) self.box.pack_start(self.content_right, False, False, 0) self.image = Gtk.Image() _update_icon(self.image, icon, icon_size) self.content_left.pack_start(self.image, False, False, 0) self.title = Gtk.Label.new(self._MARKUP % GObject.markup_escape_text(label)) self.title.set_alignment(0.0, 0.5) self.title.set_use_markup(True) self.title.set_tooltip_text(label) self.title.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.title, False, False, 0) categories = helper.get_categories(doc) if categories is not None: self.category = Gtk.Label.new( '<span font_desc="%i">%s</span>' % (em(0.6), GObject.markup_escape_text(categories))) self.category.set_use_markup(True) self.category.set_alignment(0.0, 0.5) self.category.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.category, False, False, 4) stats_a11y = None if stats is not None: self.stars = Star(size=StarSize.SMALL) self.stars.render_outline = True self.stars.set_rating(stats.ratings_average) self.rating_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, StockEms.SMALL) self.rating_box.pack_start(self.stars, False, False, 0) self.n_ratings = Gtk.Label.new( '<span font_desc="%i"> (%i)</span>' % (em(0.45), stats.ratings_total)) self.n_ratings.set_use_markup(True) self.n_ratings.set_name("subtle-label") self.n_ratings.set_alignment(0.0, 0.5) self.rating_box.pack_start(self.n_ratings, False, False, 0) self.content_right.pack_start(self.rating_box, False, False, 0) # TRANSLATORS: this is an accessibility description for eg orca and # is not visible in the ui stats_a11y = _('%(stars)d stars - %(reviews)d reviews') % { 'stars': stats.ratings_average, 'reviews': stats.ratings_total } # work out width tile needs to be to ensure ratings text is all # visible req_width = (self.stars.size_request().width + self.image.size_request().width + self.n_ratings.size_request().width + StockEms.MEDIUM * 3) global _global_featured_tile_width _global_featured_tile_width = max(_global_featured_tile_width, req_width) details = AppDetails(db=helper.db, doc=doc) # TRANSLATORS: Free here means Gratis price = details.price or _("Free") if price == '0.00': # TRANSLATORS: Free here means Gratis price = _("Free") # TRANSLATORS: Free here means Gratis if price != _("Free"): price = 'US$ ' + price self.price = Gtk.Label.new('<span font_desc="%i">%s</span>' % (em(0.6), price)) self.price.set_use_markup(True) self.price.set_name("subtle-label") self.price.set_alignment(0.0, 0.5) self.content_right.pack_start(self.price, False, False, 0) self.set_name("featured-tile") a11y_name = '. '.join( [t for t in [label, categories, stats_a11y, price] if t]) self.get_accessible().set_name(a11y_name) backend = get_install_backend() backend.connect("transaction-finished", self.on_transaction_finished, helper, doc) self.connect("enter-notify-event", self.on_enter) self.connect("leave-notify-event", self.on_leave) self.connect("button-press-event", self.on_press) self.connect("button-release-event", self.on_release)
res = error(parent=parent, primary=primary, secondary=secondary, details=details, alternative_action=alternative_action) if res == Gtk.ResponseType.YES: res = "yes" return res if __name__ == "__main__": from softwarecenter.backend import get_install_backend from softwarecenter.ui.gtk3.aptd_gtk3 import InstallBackendUI from mock import Mock aptd = get_install_backend() aptd.ui = InstallBackendUI() # test config file prompt trans = Mock() res = aptd._config_file_conflict(trans, "/etc/group", "/etc/group-") print(res) # test medium required trans = Mock() res = aptd._medium_required(trans, "medium", "drive") print(res) # test error dialog trans = Mock() trans.error_code = 102 trans.error_details = "details"