class GameStore(GObject.Object): __gsignals__ = { "icons-changed": (GObject.SIGNAL_RUN_FIRST, None, ()), } def __init__(self, service, service_media): super().__init__() self.service = service self.service_media = service_media self._installed_games = [] self._installed_games_accessed = False self._icon_updates = {} self._icon_update_timer = None self.store = Gtk.ListStore( str, str, str, Pixbuf, str, str, str, str, int, str, bool, int, str, float, str, ) self.media_loader = MediaLoader() self.media_loader.connect("icon-loaded", self.on_icon_loaded) GObject.add_emission_hook(BaseService, "service-games-loaded", self.on_service_games_updated) @property def installed_game_slugs(self): previous_access = self._installed_games_accessed or 0 self._installed_games_accessed = time.time() if self._installed_games_accessed - previous_access > 1: self._installed_games = [ g["slug"] for g in get_games(filters={"installed": "1"}) ] return self._installed_games def load_icons(self): """Downloads the icons for a service""" media_urls = self.service_media.get_media_urls() self.media_loader.download_icons(media_urls, self.service_media) def add_games(self, games): """Add games to the store""" for game in list(games): GLib.idle_add(self.add_game, game) def get_row_by_id(self, _id): if not _id: return for model_row in self.store: try: if model_row[COL_ID] == _id: return model_row except TypeError: return def remove_game(self, _id): """Remove a game from the view.""" row = self.get_row_by_id(_id) if row: self.store.remove(row.iter) def update(self, db_game): """Update game informations.""" game = StoreItem(db_game, self.service_media) row = self.get_row_by_id(game.id) if not row: return row[COL_ID] = game.id row[COL_SLUG] = game.slug row[COL_NAME] = gtk_safe(game.name) row[COL_ICON] = game.get_pixbuf() row[COL_YEAR] = game.year row[COL_RUNNER] = game.runner row[COL_RUNNER_HUMAN_NAME] = gtk_safe(game.runner_text) row[COL_PLATFORM] = gtk_safe(game.platform) row[COL_LASTPLAYED] = game.lastplayed row[COL_LASTPLAYED_TEXT] = game.lastplayed_text row[COL_INSTALLED] = game.installed row[COL_INSTALLED_AT] = game.installed_at row[COL_INSTALLED_AT_TEXT] = game.installed_at_text row[COL_PLAYTIME] = game.playtime row[COL_PLAYTIME_TEXT] = game.playtime_text def add_game(self, db_game): """Add a PGA game to the store""" game = StoreItem(db_game, self.service_media) self.store.append(( str(game.id), game.slug, game.name, game.get_pixbuf(), game.year, game.runner, game.runner_text, gtk_safe(game.platform), game.lastplayed, game.lastplayed_text, game.installed, game.installed_at, game.installed_at_text, game.playtime, game.playtime_text, )) def on_game_updated(self, game): if self.service: db_games = sql.filtered_query(settings.PGA_DB, "service_games", filters=({ "service": self.service_media.service, "appid": game.appid })) else: db_games = sql.filtered_query(settings.PGA_DB, "games", filters=({ "id": game.id })) for db_game in db_games: GLib.idle_add(self.update, db_game) return True def on_service_games_updated(self, service): """Reload icons when service games are loaded""" if not self.service or service.id != self.service.id: return True GLib.idle_add(self.load_icons) return True def on_icon_loaded(self, _media_loader, rowid, path): """Callback for the icon-loaded signal. Stacks all icon updates together and set up a timed function to update all of them at once. """ self._icon_updates[rowid] = path if self._icon_update_timer: GLib.source_remove(self._icon_update_timer) self._icon_update_timer = GLib.timeout_add(2000, self.update_icons) def update_icons(self): """Updates the store with newly updated icons""" icon_updates = copy(self._icon_updates) self._icon_updates = {} logger.debug("Updating %s icons", len(icon_updates)) for rowid in icon_updates: row = self.get_row_by_id(rowid) if not row: continue path = icon_updates[rowid] installed = rowid in self.installed_game_slugs row[COL_ICON] = get_pixbuf(path, self.service_media.size, is_installed=installed) return False
class GameStore(GObject.Object): __gsignals__ = { "icons-changed": (GObject.SIGNAL_RUN_FIRST, None, ()), } def __init__(self, service, service_media): super().__init__() self.service = service self.service_media = service_media self._installed_games = [] self._installed_games_accessed = False self.store = Gtk.ListStore( str, str, str, Pixbuf, str, str, str, str, int, str, bool, int, str, float, str, ) self.media_loader = MediaLoader() self.media_loader.connect("icon-loaded", self.on_icon_loaded) GObject.add_emission_hook(Game, "game-updated", self.on_game_updated) GObject.add_emission_hook(Game, "game-removed", self.on_game_updated) GObject.add_emission_hook(BaseService, "service-games-loaded", self.on_service_games_updated) @property def installed_game_slugs(self): previous_access = self._installed_games_accessed or 0 self._installed_games_accessed = time.time() if self._installed_games_accessed - previous_access > 1: self._installed_games = [ g["slug"] for g in get_games(filters={"installed": "1"}) ] return self._installed_games def load_icons(self): """Downloads the icons for a service""" media_urls = self.service_media.get_media_urls() self.media_loader.download_icons(media_urls, self.service_media) def add_games(self, games): """Add games to the store""" for game in list(games): GLib.idle_add(self.add_game, game) def get_row_by_id(self, _id): if not _id: return for model_row in self.store: try: if model_row[COL_ID] == _id: return model_row except TypeError: return def remove_game(self, _id): """Remove a game from the view.""" row = self.get_row_by_id(_id) if row: self.store.remove(row.iter) def update(self, db_game): """Update game informations.""" game = StoreItem(db_game, self.service_media) row = self.get_row_by_id(game.id) if not row: return row[COL_ID] = game.id row[COL_SLUG] = game.slug row[COL_NAME] = gtk_safe(game.name) row[COL_ICON] = game.get_pixbuf() row[COL_YEAR] = game.year row[COL_RUNNER] = game.runner row[COL_RUNNER_HUMAN_NAME] = gtk_safe(game.runner_text) row[COL_PLATFORM] = gtk_safe(game.platform) row[COL_LASTPLAYED] = game.lastplayed row[COL_LASTPLAYED_TEXT] = game.lastplayed_text row[COL_INSTALLED] = game.installed row[COL_INSTALLED_AT] = game.installed_at row[COL_INSTALLED_AT_TEXT] = game.installed_at_text row[COL_PLAYTIME] = game.playtime row[COL_PLAYTIME_TEXT] = game.playtime_text def add_game(self, db_game): """Add a PGA game to the store""" game = StoreItem(db_game, self.service_media) self.store.append(( str(game.id), game.slug, game.name, game.get_pixbuf(), game.year, game.runner, game.runner_text, gtk_safe(game.platform), game.lastplayed, game.lastplayed_text, game.installed, game.installed_at, game.installed_at_text, game.playtime, game.playtime_text, )) def set_service_media(self, service_media): """Change the icon type""" if service_media == self.service_media: return self.service_media = service_media for row in self.store: try: slug = row[COL_SLUG] is_installed = row[COL_INSTALLED] row[COL_ICON] = get_pixbuf_for_game(slug, self.service_media.size, is_installed=is_installed) except TypeError: return self.emit("icons-changed") def on_icon_loaded(self, media_loader, appid, _path, width, heigth): row = self.get_row_by_id(appid) if not row: return if width != self.service_media.size[0]: return installed = appid in self.installed_game_slugs row[COL_ICON] = get_pixbuf(_path, (width, heigth), is_installed=installed) def on_game_updated(self, game): if self.service: db_games = sql.filtered_query(PGA_DB, "service_games", filters=({ "service": self.service_media.service, "appid": game.appid })) else: db_games = sql.filtered_query(PGA_DB, "games", filters=({ "id": game.id })) for db_game in db_games: GLib.idle_add(self.update, db_game) return True def on_service_games_updated(self, game): """Reload icons when service games are loaded""" GLib.idle_add(self.load_icons) return True
class GameStore(GObject.Object): __gsignals__ = { "icons-changed": (GObject.SIGNAL_RUN_FIRST, None, ()), } def __init__(self, service_media): super().__init__() self.service_media = service_media self.store = Gtk.ListStore( str, str, str, Pixbuf, str, str, str, str, int, str, bool, int, str, float, str, ) self.media_loader = MediaLoader(service_media) self.media_loader.connect("icon-loaded", self.on_icon_loaded) def load_icons(self): """Downloads the icons for a service""" media_urls = self.service_media.get_media_urls() self.media_loader.download_icons(media_urls, self.service_media) def add_games(self, games): """Add games to the store""" for game in list(games): GLib.idle_add(self.add_game, game) def get_row_by_id(self, _id): for model_row in self.store: if model_row[COL_ID] == _id: return model_row def remove_game(self, _id): """Remove a game from the view.""" row = self.get_row_by_id(_id) if row: self.store.remove(row.iter) def update(self, db_game): """Update game informations.""" game = StoreItem(db_game, self.service_media) row = self.get_row_by_id(game.id) if not row: logger.debug("No row for %s", game.id) return row[COL_ID] = game.id row[COL_SLUG] = game.slug row[COL_NAME] = gtk_safe(game.name) row[COL_ICON] = game.get_pixbuf() row[COL_YEAR] = game.year row[COL_RUNNER] = game.runner row[COL_RUNNER_HUMAN_NAME] = gtk_safe(game.runner_text) row[COL_PLATFORM] = gtk_safe(game.platform) row[COL_LASTPLAYED] = game.lastplayed row[COL_LASTPLAYED_TEXT] = game.lastplayed_text row[COL_INSTALLED] = game.installed row[COL_INSTALLED_AT] = game.installed_at row[COL_INSTALLED_AT_TEXT] = game.installed_at_text row[COL_PLAYTIME] = game.playtime row[COL_PLAYTIME_TEXT] = game.playtime_text def add_game(self, db_game): """Add a PGA game to the store""" game = StoreItem(db_game, self.service_media) self.store.append(( str(game.id), game.slug, game.name, game.get_pixbuf(), game.year, game.runner, game.runner_text, gtk_safe(game.platform), game.lastplayed, game.lastplayed_text, game.installed, game.installed_at, game.installed_at_text, game.playtime, game.playtime_text, )) def set_service_media(self, service_media): """Change the icon type""" if service_media == self.service_media: return self.service_media = service_media for row in self.store: row[COL_ICON] = get_pixbuf_for_game( row[COL_SLUG], self.service_media.size, is_installed=row[COL_INSTALLED], ) self.emit("icons-changed") def on_icon_loaded(self, media_loader, appid, path): """Callback signal for when a icon has downloaded. Update the image in the view. """ games = sql.filtered_query( PGA_DB, "service_games", filters=({ "service": self.service_media.service, "appid": appid }), ) for game in games: GLib.idle_add(self.update, game)