Save changes immediately to database.
This commit is contained in:
@@ -48,7 +48,7 @@ class Application:
|
||||
self.db = database.CardVaultDB(util.get_root_filename(util.DB_NAME))
|
||||
|
||||
# Create database tables if they do not exist
|
||||
self.db.create_database()
|
||||
self.db.db_create()
|
||||
|
||||
not_found = self.ui.get_object("pageNotFound")
|
||||
self.pages = {
|
||||
@@ -158,7 +158,7 @@ class Application:
|
||||
|
||||
window.connect("key-press-event", eval_key_pressed)
|
||||
|
||||
def show_dialog_yes_no_cancel(self, title: str, message: str) -> Gtk.ResponseType:
|
||||
def show_dialog_ync(self, title: str, message: str) -> Gtk.ResponseType:
|
||||
"""Display a simple Yes/No Question dialog and return the result"""
|
||||
dialog = self.ui.get_object("ync_dialog")
|
||||
dialog.set_transient_for(self.ui.get_object("mainWindow"))
|
||||
@@ -168,7 +168,7 @@ class Application:
|
||||
dialog.hide()
|
||||
return response
|
||||
|
||||
def show_dialog_yes_no(self, title: str, message: str) -> Gtk.ResponseType:
|
||||
def show_dialog_yn(self, title: str, message: str) -> Gtk.ResponseType:
|
||||
"""Display a simple Yes/No Question dialog and return the result"""
|
||||
dialog = self.ui.get_object("yn_dialog")
|
||||
dialog.set_transient_for(self.ui.get_object("mainWindow"))
|
||||
@@ -202,23 +202,29 @@ class Application:
|
||||
else:
|
||||
return value
|
||||
|
||||
def save_config(self):
|
||||
cf = util.get_root_filename("config.json")
|
||||
util.save_config(self.config, cf)
|
||||
util.log("Config saved to '{}'".format(cf), util.LogLevel.Info)
|
||||
|
||||
def save_data(self):
|
||||
util.log("Saving Data to database", util.LogLevel.Info)
|
||||
start = time.time()
|
||||
self.db.save_library(self.library)
|
||||
self.db.save_tags(self.tags)
|
||||
self.db.save_wants(self.wants)
|
||||
end = time.time()
|
||||
util.log("Finished in {}s".format(str(round(end - start, 3))), util.LogLevel.Info)
|
||||
self.unsaved_changes = False
|
||||
self.push_status("All data saved.")
|
||||
# util.log("Saving Data to database", util.LogLevel.Info)
|
||||
# start = time.time()
|
||||
# self.db.save_library(self.library)
|
||||
# self.db.save_tags(self.tags)
|
||||
# self.db.save_wants(self.wants)
|
||||
# end = time.time()
|
||||
# util.log("Finished in {}s".format(str(round(end - start, 3))), util.LogLevel.Info)
|
||||
# self.unsaved_changes = False
|
||||
# self.push_status("All data saved.")
|
||||
pass
|
||||
|
||||
def load_data(self):
|
||||
util.log("Loading Data from database", util.LogLevel.Info)
|
||||
start = time.time()
|
||||
self.library = self.db.get_library()
|
||||
self.tags = self.db.get_tags()
|
||||
self.wants = self.db.get_wants()
|
||||
self.library = self.db.lib_get_all()
|
||||
self.tags = self.db.tag_get_all()
|
||||
self.wants = self.db.wants_get_all()
|
||||
end = time.time()
|
||||
util.log("Finished in {}s".format(str(round(end-start, 3))), util.LogLevel.Info)
|
||||
self.push_status("All data loaded.")
|
||||
@@ -242,33 +248,35 @@ class Application:
|
||||
lib[card_id] = self.library[card_id]
|
||||
return lib
|
||||
|
||||
def tag_card(self, card, tag):
|
||||
def tag_card(self, card, tag: str):
|
||||
"""Add a card to tag"""
|
||||
list = self.tags[tag]
|
||||
list.append(card.multiverse_id)
|
||||
self.unsaved_changes = True
|
||||
self.db.tag_card_add(tag, card.multiverse_id)
|
||||
|
||||
def untag_card(self, card, tag):
|
||||
def untag_card(self, card, tag: str):
|
||||
list = self.tags[tag]
|
||||
list.remove(card.multiverse_id)
|
||||
self.unsaved_changes = True
|
||||
self.db.tag_card_remove(tag, card.multiverse_id)
|
||||
|
||||
def add_tag(self, tag):
|
||||
def tag_new(self, tag: str):
|
||||
self.tags[tag] = []
|
||||
self.db.tag_new(tag)
|
||||
util.log("Tag '" + tag + "' added", util.LogLevel.Info)
|
||||
self.push_status("Added Tag \"" + tag + "\"")
|
||||
self.unsaved_changes = True
|
||||
|
||||
def remove_tag(self, tag):
|
||||
def tag_delete(self, tag: str):
|
||||
del self.tags[tag]
|
||||
self.db.tag_delete(tag)
|
||||
util.log("Tag '" + tag + "' removed", util.LogLevel.Info)
|
||||
self.push_status("Removed Tag \"" + tag + "\"")
|
||||
self.unsaved_changes = True
|
||||
|
||||
def rename_tag(self, old, new):
|
||||
def tag_rename(self, old, new):
|
||||
if old == new:
|
||||
return
|
||||
self.tags[new] = self.tags[old]
|
||||
del self.tags[old]
|
||||
self.db.tag_rename(old, new)
|
||||
util.log("Tag '" + old + "' renamed to '" + new + "'", util.LogLevel.Info)
|
||||
self.unsaved_changes = True
|
||||
|
||||
@@ -284,61 +292,93 @@ class Application:
|
||||
out = {card.multiverse_id: card for card in self.wants[list_name]}
|
||||
return out
|
||||
|
||||
def delete_wants_list(self, name: str):
|
||||
def wants_new(self, name):
|
||||
"""Add a empty wants list"""
|
||||
self.wants[name] = []
|
||||
self.db.wants_new(name)
|
||||
util.log("Want list '" + name + "' created", util.LogLevel.Info)
|
||||
self.push_status("Created want list '" + name + "'")
|
||||
|
||||
def wants_delete(self, name: str):
|
||||
"""Delete an wants list an all cards in it"""
|
||||
del self.wants[name]
|
||||
self.db.wants_delete(name)
|
||||
util.log("Deleted Wants List '{}'".format(name), util.LogLevel.Info)
|
||||
self.push_status("Deleted Wants List '{}'".format(name))
|
||||
self.unsaved_changes = True
|
||||
|
||||
def rename_want_list(self, old, new):
|
||||
def wants_rename(self, old: str, new: str):
|
||||
if old == new:
|
||||
return
|
||||
self.wants[new] = self.wants[old]
|
||||
del self.wants[old]
|
||||
self.db.wants_rename(old, new)
|
||||
util.log("Want List '" + old + "' renamed to '" + new + "'", util.LogLevel.Info)
|
||||
self.unsaved_changes = True
|
||||
|
||||
def add_want_list(self, name):
|
||||
self.wants[name] = []
|
||||
util.log("Want list '" + name + "' created", util.LogLevel.Info)
|
||||
self.push_status("Created want list '" + name + "'")
|
||||
self.unsaved_changes = True
|
||||
|
||||
def add_card_to_want_list(self, list_name: str, card: 'mtgsdk.Card'):
|
||||
def wants_card_add(self, list_name: str, card: 'mtgsdk.Card'):
|
||||
self.wants[list_name].append(card)
|
||||
self.db.wants_card_add(list_name, card.multiverse_id)
|
||||
util.log(card.name + " added to want list " + list_name, util.LogLevel.Info)
|
||||
self.unsaved_changes = True
|
||||
|
||||
def add_card_to_lib(self, card, tag=None):
|
||||
def wants_card_remove(self, card: mtgsdk.Card, list: str):
|
||||
"""Remove a card from a wants list"""
|
||||
l = self.wants[list]
|
||||
l.remove(card)
|
||||
self.db.wants_card_remove(list, card.multiverse_id)
|
||||
util.log("Removed '{}' from wants list '{}'".format(card.name, list), util.LogLevel.Info)
|
||||
|
||||
def lib_card_add(self, card, tag=None):
|
||||
if tag is not None:
|
||||
self.tag_card(card, tag)
|
||||
self.db.tag_card_add(tag, card.multiverse_id)
|
||||
self.library[card.multiverse_id] = card
|
||||
self.db.lib_card_add(card)
|
||||
self.push_status(card.name + " added to library")
|
||||
self.unsaved_changes = True
|
||||
|
||||
self.db.insert_card(card)
|
||||
|
||||
def bulk_add_card_to_lib(self, cards: list, tag: str = None):
|
||||
def lib_card_add_bulk(self, cards: list, tag: str = None):
|
||||
for card in cards:
|
||||
self.add_card_to_lib(card, tag)
|
||||
if tag is not None:
|
||||
self.tag_card(card, tag)
|
||||
self.db.tag_card_add(tag, card.multiverse_id)
|
||||
self.lib_card_add(card, tag)
|
||||
self.db.lib_card_add(card)
|
||||
util.log("Added {} cards to library.".format(str(len(cards))), util.LogLevel.Info)
|
||||
self.push_status("Added {} cards to library.".format(str(len(cards))))
|
||||
|
||||
def remove_card_from_lib(self, card):
|
||||
def lib_card_remove(self, card):
|
||||
# Check if card is tagged
|
||||
for card_ids in self.tags.values():
|
||||
if card_ids.__contains__(card.multiverse_id):
|
||||
card_ids.remove(card.multiverse_id)
|
||||
is_tagged, tags = self.db.tag_card_check_tagged(card)
|
||||
if is_tagged:
|
||||
for tag in tags:
|
||||
self.tags[tag].remove(card.multiverse_id)
|
||||
self.db.tag_card_remove(tag, card.multiverse_id)
|
||||
|
||||
del self.library[card.multiverse_id]
|
||||
self.db.lib_card_remove(card)
|
||||
util.log("Removed {} from library".format(card.name), util.LogLevel.Info)
|
||||
self.push_status(card.name + " removed from library")
|
||||
self.unsaved_changes = True
|
||||
|
||||
def remove_card_from_want_list(self, card: mtgsdk.Card, list: str):
|
||||
l = self.wants[list]
|
||||
l.remove(card)
|
||||
self.unsaved_changes = True
|
||||
util.log("Removed '{}' from wants list '{}'".format(card.name, list), util.LogLevel.Info)
|
||||
def override_user_data(self):
|
||||
"""Called after import of user data. Overrides existing user data in database"""
|
||||
util.log("Clearing old user data", util.LogLevel.Info)
|
||||
self.db.db_clear_data_user()
|
||||
util.log("Attempt loading user data to database", util.LogLevel.Info)
|
||||
start = time.time()
|
||||
# Library
|
||||
for card in self.library.values():
|
||||
self.db.lib_card_add(card)
|
||||
# Tags
|
||||
for tag, card_ids in self.tags.items():
|
||||
self.db.tag_new(tag)
|
||||
for card_id in card_ids:
|
||||
self.db.tag_card_add(tag, card_id)
|
||||
# Wants
|
||||
for list_name, cards in self.wants.items():
|
||||
self.db.wants_new(list_name)
|
||||
for card in cards:
|
||||
self.db.wants_card_add(list_name, card.multiverse_id)
|
||||
end = time.time()
|
||||
util.log("Finished in {}s".format(str(round(end - start, 3))), util.LogLevel.Info)
|
||||
self.push_status("User data imported")
|
||||
|
||||
def get_mana_icons(self, mana_string):
|
||||
if not mana_string:
|
||||
@@ -360,38 +400,6 @@ class Application:
|
||||
else:
|
||||
return filter_text.lower() in model[iter][1].lower()
|
||||
|
||||
def load_data_legacy(self):
|
||||
all_existing = True
|
||||
# Load library file
|
||||
self.library = util.load_file(util.get_root_filename("library"))
|
||||
if not self.library:
|
||||
all_existing = False
|
||||
self.library = {}
|
||||
# Load tags file
|
||||
self.tags = util.load_file(util.get_root_filename("tags"))
|
||||
if not self.tags:
|
||||
all_existing = False
|
||||
self.tags = {}
|
||||
# Load wants lists
|
||||
self.wants = util.load_file(util.get_root_filename("wants"))
|
||||
if not self.wants:
|
||||
all_existing = False
|
||||
self.wants = {}
|
||||
# If parts were missing save to create the files
|
||||
if not all_existing:
|
||||
self.save_library_legacy()
|
||||
self.push_status("Library loaded")
|
||||
|
||||
def save_library_legacy(self):
|
||||
# Save library file
|
||||
util.save_file(util.get_root_filename("library"), self.library)
|
||||
# Save tags file
|
||||
util.save_file(util.get_root_filename("tags"), self.tags)
|
||||
# Save wants file
|
||||
util.save_file(util.get_root_filename("wants"), self.wants)
|
||||
|
||||
self.unsaved_changes = False
|
||||
self.push_status("Library saved")
|
||||
|
||||
def main():
|
||||
Application()
|
||||
|
||||
@@ -16,7 +16,6 @@ gi.require_version('Gdk', '3.0')
|
||||
class CardList(Gtk.ScrolledWindow):
|
||||
def __init__(self, filtered, app: 'application.Application', row_colors: Dict[str, str]):
|
||||
Gtk.ScrolledWindow.__init__(self)
|
||||
#self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import sqlite3
|
||||
import ast
|
||||
|
||||
from pygments.lexers.robotframework import _Table
|
||||
|
||||
from mtgsdk import Card
|
||||
|
||||
from cardvault import util
|
||||
|
||||
|
||||
@@ -13,7 +10,9 @@ class CardVaultDB:
|
||||
def __init__(self, db_file: str):
|
||||
self.db_file = db_file
|
||||
|
||||
def create_database(self):
|
||||
# Database operations ##############################################################################################
|
||||
|
||||
def db_create(self):
|
||||
"""Create initial database"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
|
||||
@@ -35,7 +34,7 @@ class CardVaultDB:
|
||||
con.execute("CREATE TABLE IF NOT EXISTS tags ( tag TEXT, multiverseid INT )")
|
||||
con.execute("CREATE TABLE IF NOT EXISTS wants ( listName TEXT, multiverseid INT )")
|
||||
|
||||
def insert_card(self, card: Card):
|
||||
def db_card_insert(self, card: Card):
|
||||
# Connect to database
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
@@ -51,90 +50,37 @@ class CardVaultDB:
|
||||
except sqlite3.IntegrityError:
|
||||
pass
|
||||
|
||||
def bulk_insert_card(self, card_list: list):
|
||||
def db_card_insert_bulk(self, card_list: list):
|
||||
for card in card_list:
|
||||
self.insert_card(card)
|
||||
|
||||
def clear_card_data(self):
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute("DELETE FROM cards")
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
|
||||
def clear_database(self):
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute('DELETE FROM library')
|
||||
con.execute('DELETE FROM wants')
|
||||
con.execute('DELETE FROM tags')
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
|
||||
def search_cards_by_name_filtered(self, term: str, filters: dict, list_size: int) -> dict:
|
||||
"""Search for cards based on the cards name with filter constrains"""
|
||||
filter_rarity = filters["rarity"]
|
||||
filer_type = filters["type"]
|
||||
filter_set = filters["set"]
|
||||
filter_mana = filters["mana"].split(',')
|
||||
|
||||
sql = 'SELECT * FROM cards WHERE `name` LIKE ?'
|
||||
parameters = ['%' + term + '%']
|
||||
if filter_rarity != "":
|
||||
sql += ' AND `rarity` = ?'
|
||||
parameters.append(filter_rarity)
|
||||
if filer_type != "":
|
||||
sql += ' AND `types` LIKE ?'
|
||||
parameters.append('%'+filer_type+'%')
|
||||
if filter_set != "":
|
||||
sql += ' AND `set` = ?'
|
||||
parameters.append(filter_set)
|
||||
if len(filter_mana) != 0:
|
||||
for color in filter_mana:
|
||||
sql += ' AND `manaCost` LIKE ?'
|
||||
parameters.append('%'+color+'%')
|
||||
sql += ' LIMIT ?'
|
||||
parameters.append(list_size)
|
||||
self.db_card_insert(card)
|
||||
|
||||
def db_get_all(self):
|
||||
sql = 'SELECT * FROM cards'
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
cur.row_factory = sqlite3.Row
|
||||
cur.execute(sql, parameters)
|
||||
cur.execute(sql)
|
||||
rows = cur.fetchall()
|
||||
con.close()
|
||||
|
||||
output = {}
|
||||
output = []
|
||||
for row in rows:
|
||||
card = self.table_to_card_mapping(row)
|
||||
output[card.multiverse_id] = card
|
||||
output.append(card)
|
||||
return output
|
||||
|
||||
def search_cards_by_name(self, term: str) -> dict:
|
||||
"""Search for cards based on the cards name"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
cur.row_factory = sqlite3.Row
|
||||
cur.execute("SELECT * FROM cards WHERE `name` LIKE ? LIMIT 50", ('%'+term+'%', ))
|
||||
rows = cur.fetchall()
|
||||
con.close()
|
||||
def db_clear_data_card(self):
|
||||
"""Delete all resource data from database"""
|
||||
self.db_operation("DELETE FROM cards")
|
||||
|
||||
return self.rows_to_card_dict(rows)
|
||||
def db_clear_data_user(self):
|
||||
"""Delete all user data from database"""
|
||||
self.db_operation('DELETE FROM library')
|
||||
self.db_operation('DELETE FROM wants')
|
||||
self.db_operation('DELETE FROM tags')
|
||||
|
||||
def add_card_to_lib(self, card: Card):
|
||||
"""Insert card into library"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute("INSERT INTO `library` (`copies`, `multiverseid`) VALUES (?, ?)", (1, card.multiverse_id))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
# Library operations ###############################################################################################
|
||||
|
||||
def get_library(self) -> dict:
|
||||
def lib_get_all(self) -> dict:
|
||||
"""Load library from database"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
@@ -145,7 +91,17 @@ class CardVaultDB:
|
||||
|
||||
return self.rows_to_card_dict(rows)
|
||||
|
||||
def get_tags(self):
|
||||
def lib_card_add(self, card: Card):
|
||||
"""Insert card into library"""
|
||||
self.db_operation("INSERT INTO `library` (`copies`, `multiverseid`) VALUES (?, ?)", (1, card.multiverse_id))
|
||||
|
||||
def lib_card_remove(self, card: Card):
|
||||
"""Remove a from the library"""
|
||||
self.db_operation("DELETE FROM `library` WHERE `multiverseid` = ?", (card.multiverse_id,))
|
||||
|
||||
# Tag operations ###################################################################################################
|
||||
|
||||
def tag_get_all(self) -> dict:
|
||||
"""Loads a dict from database with all tags and the card ids tagged"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
@@ -160,62 +116,51 @@ class CardVaultDB:
|
||||
|
||||
# Go trough all tags an load the card ids
|
||||
for tag in tags.keys():
|
||||
cur.execute('SELECT `multiverseid` FROM `tags` WHERE tags.tag = ? AND multiverseid NOT NULL', (tag, ))
|
||||
cur.execute('SELECT `multiverseid` FROM `tags` WHERE tags.tag = ? AND multiverseid NOT NULL', (tag,))
|
||||
rows = cur.fetchall()
|
||||
for row in rows:
|
||||
tags[tag].append(row["multiverseid"])
|
||||
|
||||
return tags
|
||||
|
||||
def add_tag(self, tag: str):
|
||||
def tag_new(self, tag: str):
|
||||
"""Add a new tag to the database"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute("INSERT INTO `tags` VALUES (?, NULL)", (tag, ))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
self.db_operation("INSERT INTO `tags` VALUES (?, NULL)", (tag,))
|
||||
|
||||
def tag_card(self, tag: str, card_id: int):
|
||||
def tag_delete(self, tag: str):
|
||||
"""Remove a tag with all entries"""
|
||||
self.db_operation("DELETE FROM `tags` WHERE `tag` = ?", (tag,))
|
||||
|
||||
def tag_rename(self, name_old: str, name_new: str):
|
||||
"""Rename a tag"""
|
||||
self.db_operation('UPDATE `tags` SET `tag`=? WHERE `tag` = ?;', (name_new, name_old))
|
||||
|
||||
def tag_card_add(self, tag: str, card_id: int):
|
||||
"""Add an entry for a tagged card"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute("INSERT INTO `tags` VALUES (?, ?)", (tag, card_id))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
self.db_operation("INSERT INTO `tags` VALUES (?, ?)", (tag, card_id))
|
||||
|
||||
def rows_to_card_dict(self, rows):
|
||||
"""Convert database rows to a card dict"""
|
||||
output = {}
|
||||
def tag_card_remove(self, tag: str, card_id: int):
|
||||
"""Remove a card from a tag"""
|
||||
self.db_operation("DELETE FROM `tags` WHERE `tag` = ? AND `multiverseid` = ?", (tag, card_id))
|
||||
|
||||
def tag_card_check_tagged(self, card) -> tuple:
|
||||
"""Check if a card is tagged. Return True/False and a list of tags."""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
cur.row_factory = sqlite3.Row
|
||||
cur.execute('SELECT `tag` FROM `tags` WHERE tags.multiverseid = ? ', (card.multiverse_id,))
|
||||
rows = cur.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
return False, []
|
||||
else:
|
||||
tags = []
|
||||
for row in rows:
|
||||
card = self.table_to_card_mapping(row)
|
||||
output[card.multiverse_id] = card
|
||||
return output
|
||||
tags.append(row["tag"])
|
||||
return True, tags
|
||||
|
||||
def add_wants_list(self, name: str):
|
||||
"""Add a new wants list to the database"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute("INSERT INTO `wants` VALUES (?, NULL)", (name,))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
# Wants operations #################################################################################################
|
||||
|
||||
def add_card_to_wants(self, list_name: str, card_id: int):
|
||||
"""Add a card entry to a wants list"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
con.execute("INSERT INTO `wants` VALUES (?, ?)", (list_name, card_id))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
|
||||
def get_wants(self):
|
||||
def wants_get_all(self) -> dict:
|
||||
"""Load all wants lists from database"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
@@ -232,51 +177,99 @@ class CardVaultDB:
|
||||
for list_name in wants.keys():
|
||||
cur.execute('SELECT * FROM '
|
||||
'(SELECT `multiverseid` FROM `wants` WHERE `listName` = ? AND multiverseid NOT NULL) tagged '
|
||||
'INNER JOIN `cards` ON tagged.multiverseid = cards.multiverseid', (list_name, ))
|
||||
'INNER JOIN `cards` ON tagged.multiverseid = cards.multiverseid', (list_name,))
|
||||
rows = cur.fetchall()
|
||||
for row in rows:
|
||||
wants[list_name].append(self.table_to_card_mapping(row))
|
||||
|
||||
return wants
|
||||
|
||||
def save_library(self, cards: dict):
|
||||
"""Updates the library, adds new cards"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
for multiverse_id in cards.keys():
|
||||
con.execute('UPDATE `library` SET `copies`=?, `multiverseid`=? WHERE multiverseid = ?;', (1, multiverse_id, multiverse_id))
|
||||
con.execute('INSERT INTO `library` (`copies`, `multiverseid`) '
|
||||
'SELECT ?,? WHERE (Select Changes() = 0);', (1, multiverse_id))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
def wants_new(self, name: str):
|
||||
"""Add a new wants list to the database"""
|
||||
self.db_operation("INSERT INTO `wants` VALUES (?, NULL)", (name,))
|
||||
|
||||
def save_tags(self, tags: dict):
|
||||
"""Updates the tags table"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
for tag, id_list in tags.items():
|
||||
for id in id_list:
|
||||
con.execute('UPDATE `tags` SET `tag`=?, `multiverseid`=? WHERE tags.multiverseid = ?;', (tag, id, id))
|
||||
con.execute('INSERT INTO `tags` (`tag`, `multiverseid`) '
|
||||
'SELECT ?,? WHERE (Select Changes() = 0);', (tag, id))
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
def wants_delete(self, name: str):
|
||||
"""Remove a tag with all entries"""
|
||||
self.db_operation("DELETE FROM `wants` WHERE `listName` = ?", (name,))
|
||||
|
||||
def save_wants(self, wants: dict):
|
||||
"""Updates the wants table"""
|
||||
def wants_rename(self, name_old: str, name_new: str):
|
||||
"""Rename a tag"""
|
||||
self.db_operation('UPDATE `wants` SET `listName`=? WHERE `listName` = ?;', (name_new, name_old))
|
||||
|
||||
def wants_card_add(self, list_name: str, card_id: int):
|
||||
"""Add a card entry to a wants list"""
|
||||
self.db_operation("INSERT INTO `wants` VALUES (?, ?)", (list_name, card_id))
|
||||
|
||||
def wants_card_remove(self, list_name: str, card_id: int):
|
||||
"""Remove a card from a want list """
|
||||
self.db_operation("DELETE FROM `wants` WHERE `listName` = ? AND `multiverseid` = ?", (list_name, card_id))
|
||||
|
||||
# Query operations #################################################################################################
|
||||
|
||||
def search_by_name_filtered(self, term: str, filters: dict, list_size: int) -> dict:
|
||||
"""Search for cards based on the cards name with filter constrains"""
|
||||
filter_rarity = filters["rarity"]
|
||||
filer_type = filters["type"]
|
||||
filter_set = filters["set"]
|
||||
filter_mana = filters["mana"].split(',')
|
||||
|
||||
sql = 'SELECT * FROM cards WHERE `name` LIKE ?'
|
||||
parameters = ['%' + term + '%']
|
||||
if filter_rarity != "":
|
||||
sql += ' AND `rarity` = ?'
|
||||
parameters.append(filter_rarity)
|
||||
if filer_type != "":
|
||||
sql += ' AND `types` LIKE ?'
|
||||
parameters.append('%' + filer_type + '%')
|
||||
if filter_set != "":
|
||||
sql += ' AND `set` = ?'
|
||||
parameters.append(filter_set)
|
||||
if len(filter_mana) != 0:
|
||||
for color in filter_mana:
|
||||
sql += ' AND `manaCost` LIKE ?'
|
||||
parameters.append('%' + color + '%')
|
||||
sql += ' LIMIT ?'
|
||||
parameters.append(list_size)
|
||||
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
cur.row_factory = sqlite3.Row
|
||||
cur.execute(sql, parameters)
|
||||
rows = cur.fetchall()
|
||||
con.close()
|
||||
|
||||
output = {}
|
||||
for row in rows:
|
||||
card = self.table_to_card_mapping(row)
|
||||
output[card.multiverse_id] = card
|
||||
return output
|
||||
|
||||
def search_by_name(self, term: str) -> dict:
|
||||
"""Search for cards based on the cards name"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
cur = con.cursor()
|
||||
cur.row_factory = sqlite3.Row
|
||||
cur.execute("SELECT * FROM cards WHERE `name` LIKE ? LIMIT 50", ('%' + term + '%',))
|
||||
rows = cur.fetchall()
|
||||
con.close()
|
||||
|
||||
return self.rows_to_card_dict(rows)
|
||||
|
||||
# DB internal functions ############################################################################################
|
||||
|
||||
def rows_to_card_dict(self, rows):
|
||||
"""Convert database rows to a card dict"""
|
||||
output = {}
|
||||
for row in rows:
|
||||
card = self.table_to_card_mapping(row)
|
||||
output[card.multiverse_id] = card
|
||||
return output
|
||||
|
||||
def db_operation(self, sql: str, parms: tuple=()):
|
||||
"""Perform an arbitrary sql operation on the database"""
|
||||
con = sqlite3.connect(self.db_file)
|
||||
try:
|
||||
with con:
|
||||
for name, cards in wants.items():
|
||||
for card in cards:
|
||||
con.execute('UPDATE `wants` SET `listName`=?, `multiverseid`=? WHERE wants.multiverseid = ?;',
|
||||
(name, card.multiverse_id, card.multiverse_id))
|
||||
con.execute('INSERT INTO `wants` (`listName`, `multiverseid`) '
|
||||
'SELECT ?,? WHERE (Select Changes() = 0);', (name, card.multiverse_id))
|
||||
con.execute(sql, parms)
|
||||
except sqlite3.OperationalError as err:
|
||||
util.log("Database Error", util.LogLevel.Error)
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
@@ -349,3 +342,47 @@ class CardVaultDB:
|
||||
|
||||
return card
|
||||
|
||||
|
||||
# def save_library(self, cards: dict):
|
||||
# """Updates the library, adds new cards"""
|
||||
# con = sqlite3.connect(self.db_file)
|
||||
# try:
|
||||
# with con:
|
||||
# for multiverse_id in cards.keys():
|
||||
# con.execute('UPDATE `library` SET `copies`=?, `multiverseid`=? WHERE multiverseid = ?;',
|
||||
# (1, multiverse_id, multiverse_id))
|
||||
# con.execute('INSERT INTO `library` (`copies`, `multiverseid`) '
|
||||
# 'SELECT ?,? WHERE (SELECT Changes() = 0);', (1, multiverse_id))
|
||||
# except sqlite3.OperationalError as err:
|
||||
# util.log("Database Error", util.LogLevel.Error)
|
||||
# util.log(str(err), util.LogLevel.Error)
|
||||
#
|
||||
# def save_tags(self, tags: dict):
|
||||
# """Updates the tags table"""
|
||||
# con = sqlite3.connect(self.db_file)
|
||||
# try:
|
||||
# with con:
|
||||
# for tag, id_list in tags.items():
|
||||
# for id in id_list:
|
||||
# con.execute('UPDATE `tags` SET `tag`=?, `multiverseid`=? WHERE tags.multiverseid = ?;',
|
||||
# (tag, id, id))
|
||||
# con.execute('INSERT INTO `tags` (`tag`, `multiverseid`) '
|
||||
# 'SELECT ?,? WHERE (SELECT Changes() = 0);', (tag, id))
|
||||
# except sqlite3.OperationalError as err:
|
||||
# util.log("Database Error", util.LogLevel.Error)
|
||||
# util.log(str(err), util.LogLevel.Error)
|
||||
#
|
||||
# def save_wants(self, wants: dict):
|
||||
# """Updates the wants table"""
|
||||
# con = sqlite3.connect(self.db_file)
|
||||
# try:
|
||||
# with con:
|
||||
# for name, cards in wants.items():
|
||||
# for card in cards:
|
||||
# con.execute('UPDATE `wants` SET `listName`=?, `multiverseid`=? WHERE wants.multiverseid = ?;',
|
||||
# (name, card.multiverse_id, card.multiverse_id))
|
||||
# con.execute('INSERT INTO `wants` (`listName`, `multiverseid`) '
|
||||
# 'SELECT ?,? WHERE (SELECT Changes() = 0);', (name, card.multiverse_id))
|
||||
# except sqlite3.OperationalError as err:
|
||||
# util.log("Database Error", util.LogLevel.Error)
|
||||
# util.log(str(err), util.LogLevel.Error)
|
||||
|
||||
@@ -213,15 +213,6 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="load_data_to_db">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Load Library to DB</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="do_load_data_to_db" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -52,6 +52,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
dialog.destroy()
|
||||
|
||||
def do_import_library(self, item):
|
||||
"""Called by menu item import library"""
|
||||
# Show file picker dialog for import
|
||||
dialog = Gtk.FileChooserDialog("Import Library", self.app.ui.get_object("mainWindow"),
|
||||
Gtk.FileChooserAction.OPEN,
|
||||
@@ -61,20 +62,20 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
# Show confirmation message
|
||||
override_question = self.app.show_dialog_yes_no_cancel("Import Library",
|
||||
"Importing a library will override your current library. "
|
||||
"Proceed?")
|
||||
override_question = self.app.show_dialog_yn(
|
||||
"Import Library", "Importing a library will override your current library.\nProceed?")
|
||||
if override_question == Gtk.ResponseType.YES:
|
||||
imports = util.import_library(dialog.get_filename())
|
||||
self.app.library = imports[0]
|
||||
self.app.tags = imports[1]
|
||||
self.app.wants = imports[2]
|
||||
# Save imported data to database
|
||||
self.app.override_user_data()
|
||||
# Cause current page to reload with imported data
|
||||
self.app.current_page.emit('show')
|
||||
self.app.unsaved_changes = True
|
||||
self.app.push_status("Library imported")
|
||||
dialog.destroy()
|
||||
|
||||
|
||||
def on_view_changed(self, item):
|
||||
if item.get_active():
|
||||
container = self.app.ui.get_object("contentPage")
|
||||
@@ -91,7 +92,8 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
|
||||
def do_delete_event(self, arg1, arg2):
|
||||
if self.app.unsaved_changes:
|
||||
response = self.app.show_dialog_yes_no_cancel("Unsaved Changes", "You have unsaved changes in your library. "
|
||||
response = self.app.show_dialog_ync("Unsaved Changes",
|
||||
"You have unsaved changes in your library. "
|
||||
"Save before exiting?")
|
||||
if response == Gtk.ResponseType.YES:
|
||||
self.app.save_data()
|
||||
@@ -121,6 +123,8 @@ 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.ui.get_object("loadDataDialog").destroy()
|
||||
self.app.push_status("Card data downloaded")
|
||||
util.log("Card data download finished", util.LogLevel.Info)
|
||||
@@ -130,7 +134,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
info_string = "Start downloading card information from the internet?\n" \
|
||||
"This process can take up to 10 minutes.\n" \
|
||||
"You can cancel the download at any point."
|
||||
response = self.app.show_dialog_yes_no("Download Card Data", info_string)
|
||||
response = self.app.show_dialog_yn("Download Card Data", info_string)
|
||||
if response == Gtk.ResponseType.NO:
|
||||
return
|
||||
# Launch download info dialog
|
||||
@@ -153,7 +157,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
all_cards = []
|
||||
# Request total number of cards we are going to download
|
||||
all_num = util.get_all_cards_num()
|
||||
all_pages = int(math.ceil(all_num/100))
|
||||
all_pages = int(math.ceil(all_num / 100))
|
||||
|
||||
# Download cards in pages until no new cards are added
|
||||
for i in range(all_pages):
|
||||
@@ -180,7 +184,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
|
||||
# All cards have been downloaded
|
||||
GObject.idle_add(self.load_show_insert_ui, "Saving data to disk...")
|
||||
self.app.db.bulk_insert_card(all_cards)
|
||||
self.app.db.db_card_insert_bulk(all_cards)
|
||||
|
||||
self.download_finished()
|
||||
|
||||
@@ -209,32 +213,12 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
|
||||
# ---------------------- Debug actions -------------------------------
|
||||
|
||||
def do_load_data_to_db(self, item):
|
||||
util.log("Attempt loading library to database", util.LogLevel.Info)
|
||||
start = datetime.datetime.now()
|
||||
|
||||
for card in self.app.library.values():
|
||||
self.app.db.add_card_to_lib(card)
|
||||
|
||||
for tag, card_ids in self.app.tags.items():
|
||||
self.app.db.add_tag(tag)
|
||||
for card_id in card_ids:
|
||||
self.app.db.tag_card(tag, card_id)
|
||||
|
||||
for list_name, cards in self.app.wants.items():
|
||||
self.app.db.add_wants_list(list_name)
|
||||
for card in cards:
|
||||
self.app.db.add_card_to_wants(list_name, card.multiverse_id)
|
||||
|
||||
end = datetime.datetime.now()
|
||||
util.log("Finished in {}s".format(str(end - start)), util.LogLevel.Info)
|
||||
|
||||
def do_clear_card_data(self, menu_item):
|
||||
util.log("Deleting all local card data", util.LogLevel.Info)
|
||||
self.app.db.clear_card_data()
|
||||
self.app.db.db_clear_data_card()
|
||||
util.log("Done", util.LogLevel.Info)
|
||||
|
||||
def do_clear_data(self, item):
|
||||
util.log("Deleting all library data", util.LogLevel.Info)
|
||||
self.app.db.clear_database()
|
||||
self.app.db.db_clear_data_user()
|
||||
util.log("Done", util.LogLevel.Info)
|
||||
@@ -83,7 +83,7 @@ class LibraryHandlers:
|
||||
|
||||
new_name = self.app.show_name_enter_dialog("Rename Tag", tag)
|
||||
if new_name and new_name != "":
|
||||
self.app.rename_tag(tag, new_name)
|
||||
self.app.tag_rename(tag, new_name)
|
||||
self.app.current_page.emit('show')
|
||||
|
||||
def do_tag_list_delete(self, tree):
|
||||
@@ -98,7 +98,7 @@ class LibraryHandlers:
|
||||
dialog.destroy()
|
||||
if response == Gtk.ResponseType.NO:
|
||||
return
|
||||
self.app.remove_tag(tag)
|
||||
self.app.tag_delete(tag)
|
||||
self.app.current_page.emit('show')
|
||||
|
||||
def do_refilter_library(self, container):
|
||||
@@ -139,7 +139,7 @@ class LibraryHandlers:
|
||||
cards = card_list.get_selected_cards()
|
||||
# Remove selected cards
|
||||
for card in cards.values():
|
||||
self.app.remove_card_from_lib(card)
|
||||
self.app.lib_card_remove(card)
|
||||
self.reload_library(self.app.current_lib_tag)
|
||||
self.reload_tag_list(none_selected=True)
|
||||
|
||||
@@ -191,7 +191,7 @@ class LibraryHandlers:
|
||||
self.app.ui.get_object("noResults").set_visible(True)
|
||||
|
||||
def add_new_tag(self, name):
|
||||
self.app.add_tag(name)
|
||||
self.app.tag_new(name)
|
||||
self.reload_tag_list(True)
|
||||
|
||||
def reload_tag_list(self, none_selected=False):
|
||||
@@ -209,7 +209,7 @@ class LibraryHandlers:
|
||||
def tag_cards(self, card_list, tag):
|
||||
# Check if tag exist and create if necessary
|
||||
if not self.app.tags.__contains__(tag):
|
||||
self.app.add_tag(tag)
|
||||
self.app.tag_new(tag)
|
||||
|
||||
for card in card_list.values():
|
||||
if not self.app.tags[tag].__contains__(card.multiverse_id):
|
||||
|
||||
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
@@ -59,7 +59,7 @@ class SearchHandlers:
|
||||
tree_iter = model.get_iter(path)
|
||||
card_id = model.get_value(tree_iter, 0)
|
||||
card = card_view.lib[card_id]
|
||||
self.app.add_card_to_lib(card)
|
||||
self.app.lib_card_add(card)
|
||||
self.reload_search_view()
|
||||
self.app.ui.get_object("searchEntry").grab_focus()
|
||||
|
||||
@@ -110,9 +110,9 @@ class SearchHandlers:
|
||||
cards = card_list.get_selected_cards()
|
||||
response = self.app.show_name_enter_dialog("Enter name for new Tag", "")
|
||||
if not response == "":
|
||||
self.app.add_tag(response)
|
||||
self.app.tag_new(response)
|
||||
for card in cards.values():
|
||||
self.app.add_card_to_lib(card, response)
|
||||
self.app.lib_card_add(card, response)
|
||||
else:
|
||||
util.log("No tag name entered", util.LogLevel.Warning)
|
||||
self.app.push_status("No name for new tag entered")
|
||||
@@ -124,9 +124,9 @@ class SearchHandlers:
|
||||
cards = card_list.get_selected_cards()
|
||||
response = self.app.show_name_enter_dialog("Enter name for new Want List", "")
|
||||
if not response == "":
|
||||
self.app.add_want_list(response)
|
||||
self.app.wants_new(response)
|
||||
for card in cards.values():
|
||||
self.app.add_card_to_want_list(response, card)
|
||||
self.app.wants_card_add(response, card)
|
||||
else:
|
||||
util.log("No list name entered", util.LogLevel.Warning)
|
||||
self.app.push_status("No name for new wants list entered")
|
||||
@@ -137,7 +137,7 @@ class SearchHandlers:
|
||||
card_list = self.app.ui.get_object("searchResults").get_child()
|
||||
cards = card_list.get_selected_cards()
|
||||
for card in cards.values():
|
||||
self.app.add_card_to_lib(card, item.get_label())
|
||||
self.app.lib_card_add(card, item.get_label())
|
||||
self.reload_search_view()
|
||||
self.app.push_status("Added " + str(len(cards)) + " card(s) to library.")
|
||||
|
||||
@@ -146,7 +146,7 @@ class SearchHandlers:
|
||||
card_list = self.app.ui.get_object("searchResults").get_child()
|
||||
cards = card_list.get_selected_cards()
|
||||
for card in cards.values():
|
||||
self.app.add_card_to_want_list(item.get_label(), card)
|
||||
self.app.wants_card_add(item.get_label(), card)
|
||||
self.reload_search_view()
|
||||
self.app.push_status("Added " + str(len(cards)) + " card(s) to Want List '" + item.get_label() + "'")
|
||||
|
||||
@@ -168,7 +168,7 @@ class SearchHandlers:
|
||||
tree = self.app.ui.get_object("searchResults").get_child()
|
||||
cards = tree.get_selected_cards()
|
||||
for card in cards.values():
|
||||
self.app.add_card_to_lib(card)
|
||||
self.app.lib_card_add(card)
|
||||
self.reload_search_view()
|
||||
|
||||
def reload_search_view(self):
|
||||
@@ -209,7 +209,7 @@ class SearchHandlers:
|
||||
util.log("Starting local search for '" + term + "'", util.LogLevel.Info)
|
||||
start = time.time()
|
||||
|
||||
cards = self.app.db.search_cards_by_name_filtered(term, filters, 100)
|
||||
cards = self.app.db.search_by_name_filtered(term, filters, 100)
|
||||
|
||||
end = time.time()
|
||||
util.log("Card info fetched in {}s".format(round(end - start, 3)), util.LogLevel.Info)
|
||||
|
||||
@@ -21,7 +21,7 @@ class WantsHandlers:
|
||||
# Check if list name already exists
|
||||
if self.app.wants.__contains__(name):
|
||||
return
|
||||
self.app.add_want_list(name)
|
||||
self.app.wants_new(name)
|
||||
self.reload_wants_view()
|
||||
|
||||
def on_want_list_selected(self, selection, path, column):
|
||||
@@ -54,7 +54,7 @@ class WantsHandlers:
|
||||
|
||||
new_name = self.app.show_name_enter_dialog("Rename Want List", tag)
|
||||
if not tag == new_name:
|
||||
self.app.rename_want_list(tag, new_name)
|
||||
self.app.wants_rename(tag, new_name)
|
||||
self.app.current_page.emit('show')
|
||||
|
||||
def do_delete_wants_list(self, tree):
|
||||
@@ -63,7 +63,7 @@ class WantsHandlers:
|
||||
tree_iter = model.get_iter(path)
|
||||
name = model.get_value(tree_iter, 0)
|
||||
|
||||
self.app.delete_wants_list(name)
|
||||
self.app.wants_delete(name)
|
||||
self.app.current_page.emit('show')
|
||||
|
||||
def on_want_cards_add_activated(self, menu_item):
|
||||
@@ -79,8 +79,8 @@ class WantsHandlers:
|
||||
list_name = model.get_value(tree_iter, 0)
|
||||
|
||||
for card in selected.values():
|
||||
self.app.add_card_to_lib(card)
|
||||
self.app.remove_card_from_want_list(card, list_name)
|
||||
self.app.lib_card_add(card)
|
||||
self.app.wants_card_remove(card, list_name)
|
||||
|
||||
self.reload_wants_view(list_name)
|
||||
|
||||
@@ -97,7 +97,7 @@ class WantsHandlers:
|
||||
list_name = model.get_value(tree_iter, 0)
|
||||
|
||||
for card in selected.values():
|
||||
self.app.remove_card_from_want_list(card, list_name)
|
||||
self.app.wants_card_remove(card, list_name)
|
||||
|
||||
self.reload_wants_view(list_name)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user