diff --git a/cardvault/application.py b/cardvault/application.py
index 4ce60ab..9f7b6e7 100644
--- a/cardvault/application.py
+++ b/cardvault/application.py
@@ -1,9 +1,12 @@
+from collections import OrderedDict
+
import gi
import os
import copy
import re
import mtgsdk
import time
+
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject, Pango
from typing import Type, Dict, List
@@ -15,12 +18,10 @@ from cardvault import database
class Application:
# ---------------------------------Initialize the Application----------------------------------------------
def __init__(self):
-
# Load configuration file
- self.configfile = util.get_root_filename("config.json")
- self.config = util.parse_config(self.configfile, util.default_config)
+ self.config = self.load_config()
util.LOG_LEVEL = self.config["log_level"]
- util.log("Start using config file: '{}'".format(self.configfile), util.LogLevel.Info)
+ util.log("Start using config file: '{}'".format(util.get_root_filename("config.json")), util.LogLevel.Info)
self.ui = Gtk.Builder()
self.ui.add_from_file(util.get_ui_filename("mainwindow.glade"))
@@ -68,7 +69,8 @@ class Application:
self.push_status("Card Vault ready.")
view_menu = self.ui.get_object("viewMenu")
- start_page = [page for page in view_menu.get_children() if page.get_name() == util.START_PAGE]
+ view = self.config["start_page"] if not self.config["start_page"] == "dynamic" else self.config["last_viewed"]
+ start_page = [page for page in view_menu.get_children() if page.get_name() == view]
start_page[0].activate()
util.log("Launching Card Vault version {}".format(util.VERSION), util.LogLevel.Info)
@@ -129,7 +131,7 @@ class Application:
text_label.set_line_wrap_mode(Pango.WrapMode.WORD)
text_label.set_line_wrap(True)
text_label.set_halign(Gtk.Align.END)
- color = self.config['legality_colors'][legality["legality"]]
+ color = util.LEGALITY_COLORS[legality["legality"]]
date_label.set_markup("" + legality["format"] + ":" + "")
text_label.set_markup("" + legality["legality"] + "")
grid.attach(date_label, 0, rows + 2, 1, 1)
@@ -199,6 +201,40 @@ class Application:
else:
return value
+ def show_preferences_dialog(self):
+ """Show a dialog to adjust user preferences"""
+ dialog = self.ui.get_object("pref_dialog") # type: Gtk.Dialog
+ dialog.set_transient_for(self.ui.get_object("mainWindow"))
+
+ store = Gtk.ListStore(str, str)
+ for page in self.pages.keys():
+ store.append([page.title(), page])
+ store.append(["Continue where you left", "dynamic"])
+ page_map = {"search": 0,
+ "library": 1,
+ "decks": 2,
+ "wants": 3,
+ "dynamic": 4}
+ self.ui.get_object("pref_start_view_combo").set_model(store)
+ self.ui.get_object("pref_start_view_combo").set_active(page_map[self.config["start_page"]])
+
+ self.ui.get_object("pref_show_all_check").set_active(self.config["show_all_in_search"])
+
+ result = dialog.run()
+ dialog.hide()
+
+ if not result == Gtk.ResponseType.OK:
+ return
+
+ tree_iter = self.ui.get_object("pref_start_view_combo").get_active_iter()
+ value = self.ui.get_object("pref_start_view_combo").get_model().get_value(tree_iter, 1)
+ self.config["start_page"] = value
+
+ self.config["show_all_in_search"] = self.ui.get_object("pref_show_all_check").get_active()
+
+ self.save_config()
+ self.config = self.load_config()
+
def unsaved_changes(self) -> bool:
"""Check if database is in transaction"""
return self.db.db_unsaved_changes()
@@ -206,7 +242,11 @@ class Application:
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)
+
+ @staticmethod
+ def load_config() -> dict:
+ configfile = util.get_root_filename("config.json")
+ return util.parse_config(configfile, util.DEFAULT_CONFIG)
def save_data(self):
util.log("Saving Data to database", util.LogLevel.Info)
diff --git a/cardvault/database.py b/cardvault/database.py
index 7e972fd..a19116b 100644
--- a/cardvault/database.py
+++ b/cardvault/database.py
@@ -105,8 +105,17 @@ 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")
+ con = sqlite3.connect(self.db_file)
+ try:
+ with con:
+ con.execute("DELETE FROM cards")
+ con.execute("DELETE FROM sets")
+ except sqlite3.OperationalError as err:
+ util.log("Database Error", util.LogLevel.Error)
+ util.log(str(err), util.LogLevel.Error)
+ except sqlite3.IntegrityError as err:
+ util.log("Database Error", util.LogLevel.Error)
+ util.log(str(err), util.LogLevel.Error)
def db_clear_data_user(self):
"""Delete all user data from database"""
@@ -236,7 +245,7 @@ class CardVaultDB:
# Query operations #################################################################################################
- def search_by_name_filtered(self, term: str, filters: dict, list_size: int) -> dict:
+ def search_by_name_filtered(self, term: str, filters: dict, list_size: int) -> list:
"""Search for cards based on the cards name with filter constrains"""
filter_rarity = filters["rarity"]
filer_type = filters["type"]
@@ -268,10 +277,10 @@ class CardVaultDB:
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_by_name(self, term: str) -> dict:
diff --git a/cardvault/gui/dialogs.glade b/cardvault/gui/dialogs.glade
index 3ab875a..5d3cfa8 100644
--- a/cardvault/gui/dialogs.glade
+++ b/cardvault/gui/dialogs.glade
@@ -201,6 +201,200 @@
+
+
False
False
diff --git a/cardvault/gui/mainwindow.glade b/cardvault/gui/mainwindow.glade
index 4fb4e58..7226968 100644
--- a/cardvault/gui/mainwindow.glade
+++ b/cardvault/gui/mainwindow.glade
@@ -205,6 +205,30 @@
+
+
+
False
diff --git a/cardvault/handlers.py b/cardvault/handlers.py
index 6475635..e0e715d 100644
--- a/cardvault/handlers.py
+++ b/cardvault/handlers.py
@@ -86,7 +86,6 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
dialog.set_current_folder(os.path.expanduser("~"))
response = dialog.run()
if response == Gtk.ResponseType.OK:
- # Show confirmation message
override_question = self.app.show_dialog_yn(
"Import Library", "Importing a library will override your current library.\nProceed?")
if override_question == Gtk.ResponseType.YES:
@@ -94,9 +93,7 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
self.app.library = imports[0]
self.app.tags = imports[1]
self.app.wants = imports[2]
- # Save imported data to database
self.app.db_override_user_data()
- # Cause current page to reload with imported data
self.app.current_page.emit('show')
dialog.destroy()
@@ -123,6 +120,13 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
util.log("Done", util.LogLevel.Info)
self.app.push_status("Local card data deleted. Switching to online mode.")
+ def prefs_open(self, item):
+ """
+ Handler for open preferences menu item
+ Called By: prefs_item menu item
+ """
+ self.app.show_preferences_dialog()
+
def on_view_changed(self, item):
if item.get_active():
container = self.app.ui.get_object("contentPage")
@@ -137,6 +141,9 @@ class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
app_title = new_page.get_name() + " - " + util.APPLICATION_TITLE
self.app.ui.get_object("mainWindow").set_title(app_title)
+ self.app.config["last_viewed"] = new_page.get_name().lower()
+ self.app.save_config()
+
def do_delete_event(self, arg1, arg2):
if self.app.unsaved_changes():
response = self.app.show_dialog_ync("Unsaved Changes",
diff --git a/cardvault/search.py b/cardvault/search.py
index c2d06ed..6f64572 100644
--- a/cardvault/search.py
+++ b/cardvault/search.py
@@ -197,7 +197,7 @@ class SearchHandlers:
def search_cards(self, term: str, filters: dict) -> dict:
"""Return a dict of cards based on a search term and filters"""
-
+ cards = {}
# Check if a local database can be used for searching
if self.app.config["local_db"]:
util.log("Starting local search for '" + term + "'", util.LogLevel.Info)
@@ -207,7 +207,6 @@ class SearchHandlers:
end = time.time()
util.log("Card info fetched in {}s".format(round(end - start, 3)), util.LogLevel.Info)
-
else:
util.log("Starting online search for '" + term + "'", util.LogLevel.Info)
util.log("Used Filters: " + str(filters), util.LogLevel.Info)
@@ -216,7 +215,7 @@ class SearchHandlers:
try:
util.log("Fetching card info ...", util.LogLevel.Info)
start = time.time()
- data = Card.where(name=term) \
+ cards = Card.where(name=term) \
.where(colorIdentity=",".join(filters["mana"])) \
.where(types=filters["type"]) \
.where(set=filters["set"]) \
@@ -229,21 +228,19 @@ class SearchHandlers:
util.log(err, util.LogLevel.Error)
return {}
- # Remove duplicate entries
- if util.SHOW_FROM_ALL_SETS is False:
- data = self._remove_duplicates(data)
- # Pack results in a dictionary
- cards = {}
- for card in data:
- cards[card.multiverse_id] = card
+ if not self.app.config["show_all_in_search"]:
+ cards = self._remove_duplicates(cards)
- # Check if results were found
if len(cards) == 0:
# TODO UI show no cards found
util.log("No Cards found", util.LogLevel.Info)
return {}
util.log("Found " + str(len(cards)) + " cards", util.LogLevel.Info)
- return cards
+
+ output = {}
+ for card in cards:
+ output[card.multiverse_id] = card
+ return output
# ---------------------------------Search Tree----------------------------------------------
diff --git a/cardvault/util.py b/cardvault/util.py
index 89419d1..a3bac28 100644
--- a/cardvault/util.py
+++ b/cardvault/util.py
@@ -13,10 +13,10 @@ from urllib import request
from mtgsdk import Set, Card, MtgException
import gi
+
gi.require_version('Gtk', '3.0')
from gi.repository import GdkPixbuf, GLib
-
# Title of the Program Window
APPLICATION_TITLE = "Card Vault"
@@ -28,12 +28,6 @@ CACHE_PATH = os.path.expanduser('~') + "/.cardvault/"
IMAGE_CACHE_PATH = os.path.expanduser('~') + "/.cardvault/images/"
ICON_CACHE_PATH = os.path.expanduser('~') + "/.cardvault/icons/"
-# When True Search view will list a card multiple times for each set they appear in
-SHOW_FROM_ALL_SETS = True
-
-# First page to show after startup
-START_PAGE = "search"
-
# Log level of the application
# 1 Info
# 2 Warning
@@ -67,32 +61,28 @@ GENERIC_TREE_COLORS = {
"owned": "black"
}
-default_config = {
- "hide_duplicates_in_search": False,
- "start_page": "search",
- "local_db": False,
- "first_run": True,
- "log_level": 3,
- "legality_colors": {
- "Banned": "#C65642",
- "Restricted": "#D39F30",
- "Legal": "#62B62F"
- }
-}
-
-legality_colors = {
+LEGALITY_COLORS = {
"Banned": "#C65642",
"Restricted": "#D39F30",
"Legal": "#62B62F"
}
+DEFAULT_CONFIG = {
+ "last_viewed": "",
+ "show_all_in_search": True,
+ "start_page": "search",
+ "local_db": False,
+ "first_run": True,
+ "log_level": 3
+}
+
card_colors = {
- 'White': 'W',
- 'Blue': 'U',
- 'Black': 'B',
- 'Red': 'R',
- 'Green': 'G'
- }
+ 'White': 'W',
+ 'Blue': 'U',
+ 'Black': 'B',
+ 'Red': 'R',
+ 'Green': 'G'
+}
color_sort_order = {
'W': 0,
@@ -157,10 +147,6 @@ def parse_config(filename: str, default: dict):
try:
with open(filename) as configfile:
loaded_config = json.load(configfile)
- if 'legality_colors' in config and 'legality_colors' in loaded_config:
- # Need to prevent nested dict from being overwritten with an incomplete dict
- config['legality_colors'].update(loaded_config['legality_colors'])
- loaded_config['legality_colors'] = config['legality_colors']
config.update(loaded_config)
except IOError:
# Will just use the default config