From 10f28e3e94f213d7d4ef5599aba3b1cfed998c79 Mon Sep 17 00:00:00 2001 From: luxick Date: Tue, 1 Aug 2017 18:58:32 +0200 Subject: [PATCH] Display online mode in statusbar. Save set data in sqlite. --- cardvault/application.py | 42 +++++++++++++++++++------ cardvault/database.py | 57 +++++++++++++++++++++++++++++++--- cardvault/gui/mainwindow.glade | 6 ++-- cardvault/handlers.py | 4 +-- cardvault/search.py | 4 +-- cardvault/util.py | 15 ++++++++- 6 files changed, 105 insertions(+), 23 deletions(-) diff --git a/cardvault/application.py b/cardvault/application.py index edc2840..b8a4bd6 100644 --- a/cardvault/application.py +++ b/cardvault/application.py @@ -2,9 +2,7 @@ import sys try: import gi gi.require_version('Gtk', '3.0') - from gi.repository import Gtk - from gi.repository import Pango - from gi.repository import GdkPixbuf + from gi.repository import Gtk, GObject, Pango, GdkPixbuf except ImportError as ex: print("Couldn't import GTK dependencies. Make sure you " "installed the PyGTK package and %s module." % ex.name) @@ -22,6 +20,8 @@ from cardvault import util from cardvault import database + + class Application: # ---------------------------------Initialize the Application---------------------------------------------- def __init__(self): @@ -32,7 +32,6 @@ class Application: util.LOG_LEVEL = self.config["log_level"] util.log("Start using config file: '{}'".format(self.configfile), util.LogLevel.Info) - # Load ui files self.ui = Gtk.Builder() self.ui.add_from_file(util.get_ui_filename("mainwindow.glade")) self.ui.add_from_file(util.get_ui_filename("overlays.glade")) @@ -64,14 +63,14 @@ class Application: self.precon_icons = util.reload_preconstructed_icons(util.CACHE_PATH + "icons/") self.mana_icons = util.load_mana_icons(os.path.dirname(__file__) + "/resources/mana/") - util.log("Loading set list...", util.LogLevel.Info) - self.sets = util.load_sets(util.get_root_filename("sets")) - self.library = Dict[str, Type[mtgsdk.Card]] self.tags = Dict[str, str] self.wants = Dict[str, List[Type[mtgsdk.Card]]] + self.load_user_data() - self.load_data() + self.ui.get_object('statusbar_icon').set_from_icon_name( + util.online_icons[self.is_online()], Gtk.IconSize.BUTTON) + self.ui.get_object('statusbar_icon').set_tooltip_text(util.online_tooltips[self.is_online()]) self.handlers = handlers.Handlers(self) self.ui.connect_signals(self.handlers) @@ -119,7 +118,7 @@ class Application: # Printings prints = [] for set in card.printings: - prints.append(self.sets[set].name) + prints.append(self.get_all_sets()[set].name) builder.get_object("cardPrintings").set_text(", ".join(prints)) # Legalities grid = builder.get_object("legalitiesGrid") @@ -219,7 +218,7 @@ class Application: # self.push_status("All data saved.") pass - def load_data(self): + def load_user_data(self): util.log("Loading Data from database", util.LogLevel.Info) start = time.time() self.library = self.db.lib_get_all() @@ -229,6 +228,17 @@ class Application: util.log("Finished in {}s".format(str(round(end-start, 3))), util.LogLevel.Info) self.push_status("All data loaded.") + def set_online(self, status: bool): + """Online status of the application. True if no local card data is present.""" + self.ui.get_object('statusbar_icon').set_from_icon_name(util.online_icons[status], Gtk.IconSize.BUTTON) + self.ui.get_object('statusbar_icon').set_tooltip_text(util.online_tooltips[status]) + self.config['local_db'] = not status + self.save_config() + + def is_online(self) -> bool: + """Return the online status of the application. True if no local data present.""" + return not self.config['local_db'] + def get_untagged_cards(self): lib = copy.copy(self.library) for ids in self.tags.values(): @@ -384,8 +394,19 @@ class Application: """Called before before rebuilding local data storage""" util.log("Clearing local card data", util.LogLevel.Info) self.db.db_clear_data_card() + self.set_online(True) util.log("Done", util.LogLevel.Info) + def get_all_sets(self) -> dict: + if not self.is_online (): + l = self.db.set_get_all() + out = {} + for s in l: + out[s.code] = s + else: + out = util.load_sets(util.get_root_filename('sets')) + return out + def get_mana_icons(self, mana_string): if not mana_string: util.log("No mana string provided", util.LogLevel.Info) @@ -408,5 +429,6 @@ class Application: def main(): + GObject.threads_init() Application() Gtk.main() diff --git a/cardvault/database.py b/cardvault/database.py index 18590ad..bda845a 100644 --- a/cardvault/database.py +++ b/cardvault/database.py @@ -1,7 +1,7 @@ import sqlite3 import ast -from mtgsdk import Card +from mtgsdk import Card, Set from cardvault import util @@ -32,6 +32,9 @@ class CardVaultDB: con.execute("CREATE TABLE IF NOT EXISTS library ( multiverseid INT PRIMARY KEY, copies INT )") con.execute("CREATE TABLE IF NOT EXISTS tags ( tag TEXT, multiverseid INT )") con.execute("CREATE TABLE IF NOT EXISTS wants ( listName TEXT, multiverseid INT )") + con.execute("CREATE TABLE IF NOT EXISTS sets ( code TEXT PRIMARY KEY , name TEXT, type TEXT, border TEXT, " + "mkmid INT, mkmname TEXT, releasedate TEXT, gatherercode TEXT, magiccardsinfocode TEXT, " + "booster TEXT, oldcode TEXT)") def db_card_insert(self, card: Card): # Connect to database @@ -66,7 +69,8 @@ class CardVaultDB: def db_insert_data_card(self, cards_json): """Insert download from mtgjson""" - rows = [] + c_rows = [] + s_rows = [] for data in cards_json.values(): cards = [] for raw in data["cards"]: @@ -77,14 +81,20 @@ class CardVaultDB: cards.append(c) for c in cards: - rows.append(self.card_to_table_mapping(c)) + c_rows.append(self.card_to_table_mapping(c)) + set = Set(data) + s_rows.append(self.set_to_table_mapping(set)) + # Connect to database con = sqlite3.connect(self.db_file) try: with con: sql_string = "INSERT INTO `cards` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," \ "?,?,?,?,?,?,?,?,?,?,?)" - con.executemany(sql_string, rows) + con.executemany(sql_string, c_rows) + sql_string = "INSERT INTO `sets` VALUES (?,?,?,?,?,?,?,?,?,?,?)" + con.executemany(sql_string, s_rows) + except sqlite3.OperationalError as err: util.log("Database Error", util.LogLevel.Error) util.log(str(err), util.LogLevel.Error) @@ -95,6 +105,7 @@ class CardVaultDB: def db_clear_data_card(self): """Delete all resource data from database""" self.db_operation("DELETE FROM cards") + self.db_operation("DELETE FROM sets") def db_clear_data_user(self): """Delete all user data from database""" @@ -278,6 +289,20 @@ class CardVaultDB: return self.rows_to_card_dict(rows) + def set_get_all(self): + con = sqlite3.connect(self.db_file) + cur = con.cursor() + cur.row_factory = sqlite3.Row + + # First load all tags + cur.execute("SELECT * FROM sets") + rows = cur.fetchall() + sets = [] + for row in rows: + sets.append(self.table_to_set_mapping(row)) + + return sets + # DB internal functions ############################################################################################ def rows_to_card_dict(self, rows): @@ -383,3 +408,27 @@ class CardVaultDB: card.foreign_names = ast.literal_eval(row["foreignNames"]) return card + + @staticmethod + def set_to_table_mapping(set: Set): + """Convert Set object to a table row""" + return (set.code, set.name, set.type, set.border, set.mkm_id, set.mkm_name, set.release_date, set.gatherer_code, + set.magic_cards_info_code, str(set.booster), set.old_code) + + @staticmethod + def table_to_set_mapping(row): + """Return Set object representation of a table row""" + set = Set() + set.code = row['code'] + set.name = row['name'] + set.type = row['type'] + set.border = row['border'] + set.mkm_id = row['mkmid'] + set.mkm_name = row['mkmname'] + set.release_date = row['releasedate'] + set.gatherer_code = row['gatherercode'] + set.magic_cards_info_code = row['magiccardsinfocode'] + set.booster = ast.literal_eval(row['booster']) + set.old_code = row['oldcode'] + + return set diff --git a/cardvault/gui/mainwindow.glade b/cardvault/gui/mainwindow.glade index 6b86e15..c558fb8 100644 --- a/cardvault/gui/mainwindow.glade +++ b/cardvault/gui/mainwindow.glade @@ -264,10 +264,9 @@ - + True False - Online False @@ -276,10 +275,9 @@ - + True False - network-idle False diff --git a/cardvault/handlers.py b/cardvault/handlers.py index 51ebb24..a9449b6 100644 --- a/cardvault/handlers.py +++ b/cardvault/handlers.py @@ -122,8 +122,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers): def download_finished(self): """Download thread finished without errors""" self.cancel_token = False - self.app.config["local_db"] = True - self.app.save_config() + self.app.set_online(False) self.app.ui.get_object("loadDataDialog").hide() self.app.push_status("Card data downloaded") util.log("Card data download finished", util.LogLevel.Info) @@ -238,6 +237,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers): def do_clear_card_data(self, menu_item): util.log("Deleting all local card data", util.LogLevel.Info) self.app.db.db_clear_data_card() + self.app.set_online(True) util.log("Done", util.LogLevel.Info) def do_clear_data(self, item): diff --git a/cardvault/search.py b/cardvault/search.py index d908408..ee98ece 100644 --- a/cardvault/search.py +++ b/cardvault/search.py @@ -195,7 +195,7 @@ class SearchHandlers: # Set name = self.app.ui.get_object("setEntry").get_text() output["set"] = "" - for mtgset in self.app.sets.values(): + for mtgset in self.app.get_all_sets().values(): if mtgset.name == name: output["set"] = mtgset.code return output @@ -343,7 +343,7 @@ class SearchHandlers: def _init_set_entry(self, entry): """ Initialize model for set entry """ set_store = Gtk.ListStore(str, str) - for mtgset in self.app.sets.values(): + for mtgset in self.app.get_all_sets().values(): set_store.append([mtgset.name, mtgset.code]) completer = Gtk.EntryCompletion() completer.set_model(set_store) diff --git a/cardvault/util.py b/cardvault/util.py index 648341d..b27b7f7 100644 --- a/cardvault/util.py +++ b/cardvault/util.py @@ -106,6 +106,16 @@ rarity_dict = { } card_types = ["Creature", "Artifact", "Instant", "Enchantment", "Sorcery", "Land", "Planeswalker"] +online_icons = { + True: 'network-wired', + False: 'drive-harddisk' +} + +online_tooltips = { + True: 'Using online card data', + False: 'Using card data from local database.' +} + class LogLevel(enum.Enum): Error = 1 @@ -258,7 +268,10 @@ def net_load_set_list() -> dict: def load_sets(filename: str) -> dict: - # TODO Update Data function + """ + Load sets from local file if possible. + Called by: Application if in online mode + """ if not os.path.isfile(filename): # use mtgsdk api to retrieve al list of all sets sets = net_load_set_list()