From a6897f0d5c2d358b3dcb2967a643e0b8d0377577 Mon Sep 17 00:00:00 2001 From: luxick Date: Fri, 14 Apr 2017 20:15:11 +0200 Subject: [PATCH] Tagging in library --- cardvault/cardlist.py | 54 +++++++++++++-------- cardvault/gui/library.glade | 84 +++++++++++++++++++++++++++++--- cardvault/gui/mainwindow.glade | 39 ++++++++++++++- cardvault/gui/overlays.glade | 79 ++++++++++++++++++++++++------ cardvault/gui/search.glade | 8 +-- cardvault/handlers.py | 89 ++++++++++++++++++++++++++++++---- cardvault/lib_funct.py | 44 +++++++++++++---- cardvault/search_funct.py | 9 +++- cardvault/util.py | 48 ++++++++++++++++-- 9 files changed, 384 insertions(+), 70 deletions(-) diff --git a/cardvault/cardlist.py b/cardvault/cardlist.py index d2c07d7..6a72bff 100644 --- a/cardvault/cardlist.py +++ b/cardvault/cardlist.py @@ -1,8 +1,9 @@ import gi import util - gi.require_version('Gtk', '3.0') -from gi.repository import Gtk, GdkPixbuf, GObject +gi.require_version('Gdk', '3.0') +from gi.repository import Gtk, GdkPixbuf, Gdk + class CardList(Gtk.ScrolledWindow): @@ -27,7 +28,8 @@ class CardList(Gtk.ScrolledWindow): # 8 Mana Cost(Form: {G}{2}) # 9 CMC # 10 Edition - self.store = Gtk.ListStore(int, str, str, str, str, str, str, str, GdkPixbuf.Pixbuf, int, str) + # 11 Color indicating if the card is owned or wanted + self.store = Gtk.ListStore(int, str, str, str, str, str, str, str, GdkPixbuf.Pixbuf, int, str, str) if self.filtered: self.filter = self.store.filter_new() self.filter_and_sort = Gtk.TreeModelSort(self.filter) @@ -49,37 +51,37 @@ class CardList(Gtk.ScrolledWindow): text_renderer.set_property("weight", 500) image_renderer = Gtk.CellRendererPixbuf() - col_id = Gtk.TreeViewColumn(title="Multiverse ID", cell_renderer=text_renderer, text=0) + col_id = Gtk.TreeViewColumn(title="Multiverse ID", cell_renderer=text_renderer, text=0, foreground=11) col_id.set_visible(False) - col_title = Gtk.TreeViewColumn(title="Name", cell_renderer=bold_renderer, text=1) + col_title = Gtk.TreeViewColumn(title="Name", cell_renderer=bold_renderer, text=1, foreground=11) col_title.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col_title.set_expand(True) col_title.set_sort_column_id(1) - col_supertypes = Gtk.TreeViewColumn(title="Supertypes", cell_renderer=text_renderer, text=2) + col_supertypes = Gtk.TreeViewColumn(title="Supertypes", cell_renderer=text_renderer, text=2, foreground=11) col_supertypes.set_sort_column_id(2) col_supertypes.set_visible(False) - col_types = Gtk.TreeViewColumn(title="Types", cell_renderer=text_renderer, text=3) + col_types = Gtk.TreeViewColumn(title="Types", cell_renderer=text_renderer, text=3, foreground=11) col_types.set_sort_column_id(3) - col_rarity = Gtk.TreeViewColumn(title="Rarity", cell_renderer=text_renderer, text=4) + col_rarity = Gtk.TreeViewColumn(title="Rarity", cell_renderer=text_renderer, text=4, foreground=11) col_rarity.set_sort_column_id(4) - col_power = Gtk.TreeViewColumn(title="Power", cell_renderer=text_renderer, text=5) + col_power = Gtk.TreeViewColumn(title="Power", cell_renderer=text_renderer, text=5, foreground=11) col_power.set_sizing(Gtk.TreeViewColumnSizing.FIXED) col_power.set_fixed_width(50) col_power.set_sort_column_id(5) col_power.set_visible(False) - col_thoughness = Gtk.TreeViewColumn(title="Toughness", cell_renderer=text_renderer, text=6) + col_thoughness = Gtk.TreeViewColumn(title="Toughness", cell_renderer=text_renderer, text=6, foreground=11) col_thoughness.set_sizing(Gtk.TreeViewColumnSizing.FIXED) col_thoughness.set_fixed_width(50) col_thoughness.set_sort_column_id(6) col_thoughness.set_visible(False) - col_printings = Gtk.TreeViewColumn(title="Printings", cell_renderer=text_renderer, text=7) + col_printings = Gtk.TreeViewColumn(title="Printings", cell_renderer=text_renderer, text=7, foreground=11) col_printings.set_sort_column_id(7) col_printings.set_visible(False) @@ -88,10 +90,10 @@ class CardList(Gtk.ScrolledWindow): col_mana.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col_mana.set_sort_column_id(9) - col_cmc = Gtk.TreeViewColumn(title="CMC", cell_renderer=text_renderer, text=9) + col_cmc = Gtk.TreeViewColumn(title="CMC", cell_renderer=text_renderer, text=9, foreground=11) col_cmc.set_visible(False) - col_set_name = Gtk.TreeViewColumn(title="Edition", cell_renderer=text_renderer, text=10) + col_set_name = Gtk.TreeViewColumn(title="Edition", cell_renderer=text_renderer, text=10, foreground=11) col_set_name.set_expand(False) col_set_name.set_sort_column_id(10) @@ -107,26 +109,37 @@ class CardList(Gtk.ScrolledWindow): self.list.append_column(col_mana) self.list.append_column(col_cmc) + def get_selected_cards(self): + (model, pathlist) = self.selection.get_selected_rows() + output = {} + for path in pathlist: + tree_iter = model.get_iter(path) + card_id = model.get_value(tree_iter, 0) + card = self.lib[card_id] + output[card_id] = card + return output + def update(self, library): self.store.clear() - if library is None: return - self.lib = library - if self.filtered: self.list.freeze_child_notify() self.list.set_model(None) for multiverse_id, card in library.items(): if card.multiverse_id is not None: - if card.supertypes is None: - card.supertypes = "" + color = "" + if util.library.__contains__(multiverse_id): + color = util.card_view_colors["owned"] + else: + color = util.card_view_colors["unowned"] + item =[ card.multiverse_id, card.name, - " ".join(card.supertypes), + " ".join(card.supertypes if card.supertypes else ""), " ".join(card.types), card.rarity, card.power, @@ -134,7 +147,8 @@ class CardList(Gtk.ScrolledWindow): ", ".join(card.printings), util.create_mana_icons(card.mana_cost), card.cmc, - card.set_name] + card.set_name, + color] self.store.append(item) if self.filtered: diff --git a/cardvault/gui/library.glade b/cardvault/gui/library.glade index 33059f5..862f806 100644 --- a/cardvault/gui/library.glade +++ b/cardvault/gui/library.glade @@ -10,6 +10,16 @@ + + tagStore + 0 + + + + 0 + + + Library True @@ -31,13 +41,15 @@ True - True + False True tagStore - True 1 + True + + - + @@ -71,6 +83,45 @@ 0 + + + True + False + + + Untagged + True + True + True + + + + True + True + 0 + + + + + All + True + True + True + + + + True + True + 1 + + + + + False + True + 1 + + True @@ -109,7 +160,7 @@ False True - 1 + 2 @@ -145,10 +196,31 @@ - + + True + True + tagCompleter + + + + False + True + 1 + - + + Tag card + True + True + True + + + + False + True + 2 + diff --git a/cardvault/gui/mainwindow.glade b/cardvault/gui/mainwindow.glade index d7e4961..fafcf09 100644 --- a/cardvault/gui/mainwindow.glade +++ b/cardvault/gui/mainwindow.glade @@ -9,6 +9,7 @@ 800 600 application-x-executable + True @@ -32,6 +33,17 @@ mainMenu True False + + + gtk-save + True + False + True + True + + + + True @@ -39,12 +51,37 @@ - + + True + False + Export Library + True + + + + + + True + False + Import Library + True + + + + + + True + False + + + + gtk-quit True False True True + diff --git a/cardvault/gui/overlays.glade b/cardvault/gui/overlays.glade index 1f03a26..28ba536 100644 --- a/cardvault/gui/overlays.glade +++ b/cardvault/gui/overlays.glade @@ -86,6 +86,57 @@ + + True + False + center + center + True + + + True + False + True + end + 100 + edit-find-symbolic + + + 0 + 0 + + + + + True + False + True + center + No Results + + + + + + + 0 + 1 + + + + + True + False + True + start + No cards found + + + 0 + 2 + + + Not Found True @@ -129,20 +180,6 @@ center 10 True - - - True - False - True - end - 100 - edit-find-symbolic - - - 0 - 0 - - True @@ -173,5 +210,19 @@ 2 + + + True + False + True + end + 100 + edit-find-symbolic + + + 0 + 0 + + diff --git a/cardvault/gui/search.glade b/cardvault/gui/search.glade index 5d5e99d..aaf5b3f 100644 --- a/cardvault/gui/search.glade +++ b/cardvault/gui/search.glade @@ -8,6 +8,7 @@ False True True + 2 2 @@ -281,15 +282,14 @@ - True False - Add Card to Library + Add to Library + True True True - True - + False diff --git a/cardvault/handlers.py b/cardvault/handlers.py index c21a219..cd75e75 100644 --- a/cardvault/handlers.py +++ b/cardvault/handlers.py @@ -2,6 +2,7 @@ import gi import config import lib_funct import search_funct +import util from gi.repository import Gtk gi.require_version('Gtk', '3.0') @@ -9,16 +10,18 @@ gi.require_version('Gtk', '3.0') class Handlers: def __init__(self, app): self.app = app - - def do_search_cards(self, sender): - search_term = self.app.ui.get_object("searchEntry").get_text() - results = search_funct.search_cards(search_term) + # ----------------Main Window----------------- - card_list = self.app.ui.get_object("searchResults").get_child() - card_list.update(results) + def do_save_library(self, item): + util.save_library() - self.app.ui.get_object("searchOverlay").set_visible(False) + def do_export_library(self, item): + util.export_library() + + def do_import_library(self, item): + util.import_library() + self.app.current_page.emit('show') def on_view_changed(self, item): if item.get_active(): @@ -34,6 +37,25 @@ class Handlers: app_title = new_page.get_name() + " - " + config.application_title self.app.ui.get_object("mainWindow").set_title(app_title) + def do_delete_event(self, arg1, arg2): + if util.unsaved_changes: + response = util.show_question_dialog("Unsaved Changes", "You have unsaved changes in your library. " + "Save before exiting?") + if response == Gtk.ResponseType.YES: + util.save_library() + + # ----------------Search----------------- + + def do_search_cards(self, sender): + search_term = self.app.ui.get_object("searchEntry").get_text() + + results = search_funct.search_cards(search_term) + + card_list = self.app.ui.get_object("searchResults").get_child() + card_list.update(results) + + self.app.ui.get_object("searchOverlay").set_visible(False) + def do_clear_mana_filter(self, mana_filter_grid): for toggle_button in mana_filter_grid.get_children(): if isinstance(toggle_button, Gtk.ToggleButton): @@ -42,8 +64,16 @@ class Handlers: def do_clear_set_filter(self, entry, icon_pos, button): entry.set_text("") - def do_add_remove_clicked(self, button): - pass + def do_add_clicked(self, button): + card_view = self.app.ui.get_object("searchResults").get_child() + (model, pathlist) = card_view.selection.get_selected_rows() + + for path in pathlist: + tree_iter = model.get_iter(path) + card_id = model.get_value(tree_iter, 0) + card = card_view.lib[card_id] + search_funct.add_to_library(card) + search_funct.reload_serach_view(self.app) #----------------Library----------------- @@ -58,8 +88,37 @@ class Handlers: lib_funct.add_new_tag(entry.get_text(), self.app) entry.set_text("") + def do_show_all_clicked(self, button): + # Clear selection in tag list + self.app.ui.get_object("tagTree").get_selection().unselect_all() + lib_funct.reload_library(self.app) + + def do_show_untagged_clicked(self, button): + # Clear selection in tag list + self.app.ui.get_object("tagTree").get_selection().unselect_all() + lib_funct.reload_library(self.app, "untagged") + + def do_tag_cards(self, entry): + card_view = self.app.ui.get_object("libraryContainer").get_child() + selected_cards = card_view.get_selected_cards() + tag = entry.get_text() + lib_funct.tag_cards(selected_cards, tag) + lib_funct.reload_library(self.app, tag) + + def on_drag_data_received(self, widget, drag_context, x,y, data,info, time): + print("drag received") + + def on_tag_selected(self, selection, path, column): + (model, pathlist) = selection.get_selected_rows() + for path in pathlist: + tree_iter = model.get_iter(path) + tag = model.get_value(tree_iter, 0) + lib_funct.reload_library(self.app, tag) + # Handlers for TreeViews etc. wich have been not added by Glade + #----------------Search----------------- + def on_search_card_selected(self, tree, row_no, column): (model, path_list) = tree.get_selection().get_selected_rows() for path in path_list: @@ -69,6 +128,18 @@ class Handlers: card = card_list.lib[card_id] self.app.show_card_details(card) + def on_search_selection_changed(self, selection): + (model, pathlist) = selection.get_selected_rows() + tools = self.app.ui.get_object("selectionToolsBox") + add_remove_button = self.app.ui.get_object("addRemoveButton") + + if pathlist: + add_remove_button.set_sensitive(True) + else: + add_remove_button.set_sensitive(False) + + # ----------------Library----------------- + def on_library_card_selected(self, tree, row_no, column): (model, path_list) = tree.get_selection().get_selected_rows() for path in path_list: diff --git a/cardvault/lib_funct.py b/cardvault/lib_funct.py index 35207aa..b9b695e 100644 --- a/cardvault/lib_funct.py +++ b/cardvault/lib_funct.py @@ -1,7 +1,6 @@ import cardlist import util import gi -from gi.repository import GObject gi.require_version('Gtk', '3.0') @@ -12,26 +11,53 @@ def init_library_view(app): card_list.set_name("libScroller") card_list.list.connect("row-activated", app.handlers.on_library_card_selected) container.add(card_list) + container.add_overlay(app.ui.get_object("noResults")) container.add_overlay(app.ui.get_object("libEmpty")) container.show_all() + app.ui.get_object("noResults").set_visible(False) -def reload_library(app): - reload_tag_list(app) + +def reload_library(app, tag=None): + lib = {} + if tag == "untagged": + lib = util.get_untagged_cards() + tag = None + else: + lib = util.get_library(tag) + reload_tag_list(app, tag) card_tree = app.ui.get_object("libraryContainer").get_child() - if util.library.items(): + if lib: app.ui.get_object("libEmpty").set_visible(False) - card_tree.update(util.library) + app.ui.get_object("noResults").set_visible(False) + card_tree.update(lib) + else: + card_tree.store.clear() + app.ui.get_object("noResults").set_visible(True) + def add_new_tag(name, app): util.add_tag(name) - reload_tag_list(app) + reload_tag_list(app, True) -def reload_tag_list(app): + +def reload_tag_list(app, preserve=False): tree = app.ui.get_object("tagTree") + (path, column) = tree.get_cursor() store = tree.get_model() store.clear() - store.append(["_All", "All" + " (" + str(len(util.library)) + ")"]) for tag, ids in util.tags.items(): - store.append([tag, tag + " (" + str(len(ids)) + ")"]) \ No newline at end of file + store.append([tag, tag + " (" + str(len(ids)) + ")"]) + if preserve: + tree.set_cursor(path if path else 0) + + +def tag_cards(card_list, tag): + # Check if tag exist and create if necessary + if not util.tags.__contains__(tag): + util.add_tag(tag) + + for card in card_list.values(): + if not util.tags[tag].__contains__(card.multiverse_id): + util.tag_card(card, tag) diff --git a/cardvault/search_funct.py b/cardvault/search_funct.py index 802b395..6346647 100644 --- a/cardvault/search_funct.py +++ b/cardvault/search_funct.py @@ -2,8 +2,7 @@ import gi import util import config import cardlist -import handlers -from gi.repository import Gtk +from gi.repository import Gtk, Gdk from mtgsdk import Card from urllib.error import URLError, HTTPError gi.require_version('Gtk', '3.0') @@ -23,11 +22,16 @@ def init_search_view(app): # Create Model for search results _init_results_tree(app) + app.ui.get_object("tagTree").drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY) + def reload_serach_view(app): pass +def add_to_library(card): + util.add_card_to_lib(card) + def search_cards(term): # Load filters from UI filters = _get_filters(util.app) @@ -65,6 +69,7 @@ def _init_results_tree(app): card_list = cardlist.CardList(False) card_list.set_name("resultsScroller") card_list.list.connect("row-activated", app.handlers.on_search_card_selected) + card_list.selection.connect("changed", app.handlers.on_search_selection_changed) overlay.add(card_list) overlay.add_overlay(app.ui.get_object("searchOverlay")) overlay.show_all() diff --git a/cardvault/util.py b/cardvault/util.py index 9027069..3fa1bae 100644 --- a/cardvault/util.py +++ b/cardvault/util.py @@ -21,6 +21,8 @@ set_dict = {} library = {} # Dictionary for tagged cards tags = {} +# Dictionary of untagged cards +untagged_cards = {} status_bar = None app = None @@ -32,6 +34,12 @@ legality_colors ={ "Legal": "#62B62F" } +card_view_colors ={ + "unowned": "black", + "wanted": "#D39F30", + "owned": "#62B62F" +} + rarity_dict = { "special": 0, "common": 1, @@ -166,21 +174,51 @@ def reload_image_cache(): # endregion +def get_library(tag=None): + if tag is None or tag == "All": + return library + else: + lib = {} + for card_id in tags[tag]: + lib[card_id] = library[card_id] + return lib + + +def get_untagged_cards(): + lib = {} + for card_id in untagged_cards.keys(): + lib[card_id] = library[card_id] + return lib + + +def tag_card(card, tag): + if untagged_cards.__contains__(card.multiverse_id): + del untagged_cards[card.multiverse_id] + list = tags[tag] + list.append(card.multiverse_id) + global unsaved_changes + unsaved_changes = True + + def add_tag(tag): - tags[tag] = {} + tags[tag] = [] app.push_status("Added Tag \"" + tag + "\"") global unsaved_changes unsaved_changes = True def remove_tag(tag): - tags[tag] = None + del tags[tag] app.push_status("Removed Tag \"" + tag + "\"") global unsaved_changes unsaved_changes = True -def add_card_to_lib(card): +def add_card_to_lib(card, tag=None): + if tag is None: + untagged_cards[card.multiverse_id] = None + else: + tag_card(card, tag) library[card.multiverse_id] = card app.push_status(card.name + " added to library") global unsaved_changes @@ -193,8 +231,9 @@ def remove_card_from_lib(card): global unsaved_changes unsaved_changes = True + def show_question_dialog(title, message): - dialog = Gtk.MessageDialog(app.ui.get_object("mainWindow"), 0, Gtk.MessageType.QUESTION, + dialog = Gtk.MessageDialog(app.ui.get_object("mainWindow"), 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO, title) dialog.format_secondary_text(message) response = dialog.run() @@ -234,7 +273,6 @@ def load_card_image_online(card, sizex, sizey): print("No Image URL provided") return load_dummy_image(sizex, sizey) filename = config.image_cache_path + card.multiverse_id.__str__() + ".PNG" - print("Loading image for " + card.name + "from: " + url) request.urlretrieve(url, filename) reload_image_cache() return GdkPixbuf.Pixbuf.new_from_file_at_size(filename, sizex, sizey)