Track changes to user data. Allow to undo changes.
This commit is contained in:
@@ -31,7 +31,6 @@ class Application:
|
|||||||
self.ui.add_from_file(util.get_ui_filename("dialogs.glade"))
|
self.ui.add_from_file(util.get_ui_filename("dialogs.glade"))
|
||||||
|
|
||||||
self.current_page = None
|
self.current_page = None
|
||||||
self.unsaved_changes = False
|
|
||||||
self.current_lib_tag = "Untagged"
|
self.current_lib_tag = "Untagged"
|
||||||
|
|
||||||
self.db = database.CardVaultDB(util.get_root_filename(util.DB_NAME))
|
self.db = database.CardVaultDB(util.get_root_filename(util.DB_NAME))
|
||||||
@@ -200,21 +199,22 @@ class Application:
|
|||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def unsaved_changes(self) -> bool:
|
||||||
|
"""Check if database is in transaction"""
|
||||||
|
return self.db.db_unsaved_changes()
|
||||||
|
|
||||||
def save_config(self):
|
def save_config(self):
|
||||||
cf = util.get_root_filename("config.json")
|
cf = util.get_root_filename("config.json")
|
||||||
util.save_config(self.config, cf)
|
util.save_config(self.config, cf)
|
||||||
util.log("Config saved to '{}'".format(cf), util.LogLevel.Info)
|
util.log("Config saved to '{}'".format(cf), util.LogLevel.Info)
|
||||||
|
|
||||||
def save_data(self):
|
def save_data(self):
|
||||||
# util.log("Saving Data to database", util.LogLevel.Info)
|
util.log("Saving Data to database", util.LogLevel.Info)
|
||||||
# start = time.time()
|
start = time.time()
|
||||||
# self.db.save_library(self.library)
|
self.db.db_save_changes()
|
||||||
# self.db.save_tags(self.tags)
|
end = time.time()
|
||||||
# self.db.save_wants(self.wants)
|
util.log("Finished in {}s".format(str(round(end - start, 3))), util.LogLevel.Info)
|
||||||
# end = time.time()
|
self.push_status("All data saved.")
|
||||||
# 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
|
pass
|
||||||
|
|
||||||
def load_user_data(self):
|
def load_user_data(self):
|
||||||
@@ -287,7 +287,6 @@ class Application:
|
|||||||
del self.tags[old]
|
del self.tags[old]
|
||||||
self.db.tag_rename(old, new)
|
self.db.tag_rename(old, new)
|
||||||
util.log("Tag '" + old + "' renamed to '" + new + "'", util.LogLevel.Info)
|
util.log("Tag '" + old + "' renamed to '" + new + "'", util.LogLevel.Info)
|
||||||
self.unsaved_changes = True
|
|
||||||
|
|
||||||
def get_wanted_card_ids(self) -> List[str]:
|
def get_wanted_card_ids(self) -> List[str]:
|
||||||
all_ids = []
|
all_ids = []
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class CardVaultDB:
|
|||||||
"""Data access class for sqlite3"""
|
"""Data access class for sqlite3"""
|
||||||
def __init__(self, db_file: str):
|
def __init__(self, db_file: str):
|
||||||
self.db_file = db_file
|
self.db_file = db_file
|
||||||
|
self.connection = sqlite3.connect(self.db_file)
|
||||||
|
|
||||||
# Database operations ##############################################################################################
|
# Database operations ##############################################################################################
|
||||||
|
|
||||||
@@ -37,7 +38,8 @@ class CardVaultDB:
|
|||||||
"booster TEXT, oldcode TEXT)")
|
"booster TEXT, oldcode TEXT)")
|
||||||
|
|
||||||
def db_card_insert(self, card: Card):
|
def db_card_insert(self, card: Card):
|
||||||
# Connect to database
|
"""Insert single card data into database"""
|
||||||
|
# Use own connection so that inserts are commited directly
|
||||||
con = sqlite3.connect(self.db_file)
|
con = sqlite3.connect(self.db_file)
|
||||||
try:
|
try:
|
||||||
with con:
|
with con:
|
||||||
@@ -54,13 +56,12 @@ class CardVaultDB:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def db_get_all(self):
|
def db_get_all(self):
|
||||||
|
"""Return data of all cards in database"""
|
||||||
sql = 'SELECT * FROM cards'
|
sql = 'SELECT * FROM cards'
|
||||||
con = sqlite3.connect(self.db_file)
|
cur = self.connection.cursor()
|
||||||
cur = con.cursor()
|
|
||||||
cur.row_factory = sqlite3.Row
|
cur.row_factory = sqlite3.Row
|
||||||
cur.execute(sql)
|
cur.execute(sql)
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
con.close()
|
|
||||||
output = []
|
output = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
card = self.table_to_card_mapping(row)
|
card = self.table_to_card_mapping(row)
|
||||||
@@ -85,7 +86,7 @@ class CardVaultDB:
|
|||||||
set = Set(data)
|
set = Set(data)
|
||||||
s_rows.append(self.set_to_table_mapping(set))
|
s_rows.append(self.set_to_table_mapping(set))
|
||||||
|
|
||||||
# Connect to database
|
# Use separate connection to commit changes immediately
|
||||||
con = sqlite3.connect(self.db_file)
|
con = sqlite3.connect(self.db_file)
|
||||||
try:
|
try:
|
||||||
with con:
|
with con:
|
||||||
@@ -117,12 +118,10 @@ class CardVaultDB:
|
|||||||
|
|
||||||
def lib_get_all(self) -> dict:
|
def lib_get_all(self) -> dict:
|
||||||
"""Load library from database"""
|
"""Load library from database"""
|
||||||
con = sqlite3.connect(self.db_file)
|
cur = self.connection.cursor()
|
||||||
cur = con.cursor()
|
|
||||||
cur.row_factory = sqlite3.Row
|
cur.row_factory = sqlite3.Row
|
||||||
cur.execute('SELECT * FROM `library` INNER JOIN `cards` ON library.multiverseid = cards.multiverseid')
|
cur.execute('SELECT * FROM `library` INNER JOIN `cards` ON library.multiverseid = cards.multiverseid')
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
con.close()
|
|
||||||
|
|
||||||
return self.rows_to_card_dict(rows)
|
return self.rows_to_card_dict(rows)
|
||||||
|
|
||||||
@@ -138,8 +137,7 @@ class CardVaultDB:
|
|||||||
|
|
||||||
def tag_get_all(self) -> dict:
|
def tag_get_all(self) -> dict:
|
||||||
"""Loads a dict from database with all tags and the card ids tagged"""
|
"""Loads a dict from database with all tags and the card ids tagged"""
|
||||||
con = sqlite3.connect(self.db_file)
|
cur = self.connection.cursor()
|
||||||
cur = con.cursor()
|
|
||||||
cur.row_factory = sqlite3.Row
|
cur.row_factory = sqlite3.Row
|
||||||
|
|
||||||
# First load all tags
|
# First load all tags
|
||||||
@@ -179,8 +177,7 @@ class CardVaultDB:
|
|||||||
|
|
||||||
def tag_card_check_tagged(self, card) -> tuple:
|
def tag_card_check_tagged(self, card) -> tuple:
|
||||||
"""Check if a card is tagged. Return True/False and a list of tags."""
|
"""Check if a card is tagged. Return True/False and a list of tags."""
|
||||||
con = sqlite3.connect(self.db_file)
|
cur = self.connection.cursor()
|
||||||
cur = con.cursor()
|
|
||||||
cur.row_factory = sqlite3.Row
|
cur.row_factory = sqlite3.Row
|
||||||
cur.execute('SELECT `tag` FROM `tags` WHERE tags.multiverseid = ? ', (card.multiverse_id,))
|
cur.execute('SELECT `tag` FROM `tags` WHERE tags.multiverseid = ? ', (card.multiverse_id,))
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
@@ -197,8 +194,7 @@ class CardVaultDB:
|
|||||||
|
|
||||||
def wants_get_all(self) -> dict:
|
def wants_get_all(self) -> dict:
|
||||||
"""Load all wants lists from database"""
|
"""Load all wants lists from database"""
|
||||||
con = sqlite3.connect(self.db_file)
|
cur = self.connection.cursor()
|
||||||
cur = con.cursor()
|
|
||||||
cur.row_factory = sqlite3.Row
|
cur.row_factory = sqlite3.Row
|
||||||
|
|
||||||
# First load all lists
|
# First load all lists
|
||||||
@@ -294,7 +290,6 @@ class CardVaultDB:
|
|||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
cur.row_factory = sqlite3.Row
|
cur.row_factory = sqlite3.Row
|
||||||
|
|
||||||
# First load all tags
|
|
||||||
cur.execute("SELECT * FROM sets")
|
cur.execute("SELECT * FROM sets")
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
sets = []
|
sets = []
|
||||||
@@ -313,16 +308,27 @@ class CardVaultDB:
|
|||||||
output[card.multiverse_id] = card
|
output[card.multiverse_id] = card
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def db_operation(self, sql: str, parms: tuple=()):
|
def db_operation(self, sql: str, args: tuple=()):
|
||||||
"""Perform an arbitrary sql operation on the database"""
|
"""Perform an arbitrary sql operation on the database"""
|
||||||
con = sqlite3.connect(self.db_file)
|
cur = self.connection.cursor()
|
||||||
try:
|
try:
|
||||||
with con:
|
cur.execute(sql, args)
|
||||||
con.execute(sql, parms)
|
|
||||||
except sqlite3.OperationalError as err:
|
except sqlite3.OperationalError as err:
|
||||||
util.log("Database Error", util.LogLevel.Error)
|
util.log("Database Error", util.LogLevel.Error)
|
||||||
util.log(str(err), util.LogLevel.Error)
|
util.log(str(err), util.LogLevel.Error)
|
||||||
|
|
||||||
|
def db_save_changes(self):
|
||||||
|
try:
|
||||||
|
self.connection.commit()
|
||||||
|
except sqlite3.Error as err:
|
||||||
|
self.connection.rollback()
|
||||||
|
util.log("Database Error", util.LogLevel.Error)
|
||||||
|
util.log(str(err), util.LogLevel.Error)
|
||||||
|
|
||||||
|
def db_unsaved_changes(self) -> bool:
|
||||||
|
"""Checks if database is currently in transaction"""
|
||||||
|
return self.connection.in_transaction
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_colors_list(mana: list) -> str:
|
def filter_colors_list(mana: list) -> str:
|
||||||
symbols = util.unique_list(mana)
|
symbols = util.unique_list(mana)
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
|||||||
self.app.ui.get_object("mainWindow").set_title(app_title)
|
self.app.ui.get_object("mainWindow").set_title(app_title)
|
||||||
|
|
||||||
def do_delete_event(self, arg1, arg2):
|
def do_delete_event(self, arg1, arg2):
|
||||||
if self.app.unsaved_changes:
|
if self.app.unsaved_changes():
|
||||||
response = self.app.show_dialog_ync("Unsaved Changes",
|
response = self.app.show_dialog_ync("Unsaved Changes",
|
||||||
"You have unsaved changes in your library. "
|
"You have unsaved changes in your library. "
|
||||||
"Save before exiting?")
|
"Save before exiting?")
|
||||||
|
|||||||
Reference in New Issue
Block a user