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
except ImportError as ex:
print("Couldn't import GTK dependencies. Make sure you "
"installed the PyGTK package and %s module." % ex.name)
sys.exit(-1)
import os
import copy
import re
import mtgsdk
from typing import Type, Dict, List
from cardvault import handlers
from cardvault import util
from cardvault import search_funct
from cardvault import lib_funct
from cardvault import wants_funct
class Application:
# ---------------------------------Initialize the Application----------------------------------------------
def __init__(self):
# 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"))
self.ui.add_from_file(util.get_ui_filename("search.glade"))
self.ui.add_from_file(util.get_ui_filename("library.glade"))
self.ui.add_from_file(util.get_ui_filename("wants.glade"))
self.current_page = None
self.unsaved_changes = False
self.current_lib_tag = "All"
not_found = self.ui.get_object("pageNotFound")
self.pages = {
"search": self.ui.get_object("searchView"),
"library": self.ui.get_object("libraryView"),
"decks": not_found,
"wants": self.ui.get_object("wantsView")
}
# Load configuration file
self.configfile = util.get_root_filename("config.json")
self.config = util.parse_config(self.configfile, util.default_config)
util.LOG_LEVEL = self.config["log_level"]
# Load data from cache path
self.image_cache = util.reload_image_cache(util.CACHE_PATH + "images/")
self.precon_icons = util.reload_preconstructed_icons(util.CACHE_PATH + "icons/")
self.mana_icons = util.load_mana_icons(os.path.dirname(__file__) + "/resources/mana/")
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_library()
self.handlers = handlers.Handlers(self)
self.ui.connect_signals(self.handlers)
# Initialize the views
search_funct.init_search_view(self)
lib_funct.init_library_view(self)
wants_funct.init_wants_view(self)
self.ui.get_object("mainWindow").connect('delete-event', Gtk.main_quit)
self.ui.get_object("mainWindow").show_all()
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]
start_page[0].activate()
def push_status(self, msg):
status_bar = self.ui.get_object("statusBar")
status_bar.pop(0)
status_bar.push(0, msg)
def show_card_details(self, card):
builder = Gtk.Builder()
builder.add_from_file(util.get_ui_filename("detailswindow.glade"))
builder.add_from_file(util.get_ui_filename("overlays.glade"))
window = builder.get_object("cardDetails")
window.set_title(card.name)
# Card Image
container = builder.get_object("imageContainer")
pixbuf = self.get_card_image(card, 63 * 5, 88 * 5)
image = Gtk.Image().new_from_pixbuf(pixbuf)
container.add(image)
# Name
builder.get_object("cardName").set_text(card.name)
# Types
supertypes = ""
if card.subtypes is not None:
supertypes = " - " + " ".join(card.subtypes)
types = " ".join(card.types) + supertypes
builder.get_object("cardTypes").set_text(types)
# Rarity
builder.get_object("cardRarity").set_text(card.rarity if card.rarity else "")
# Release
builder.get_object("cardReleaseDate").set_text(card.release_date if card.release_date else "")
# Set
builder.get_object("cardSet").set_text(card.set_name)
# Printings
prints = []
for set in card.printings:
prints.append(self.sets[set].name)
builder.get_object("cardPrintings").set_text(", ".join(prints))
# Legalities
grid = builder.get_object("legalitiesGrid")
rows = 1
for legality in card.legalities if card.legalities else {}:
date_label = Gtk.Label()
date_label.set_halign(Gtk.Align.END)
text_label = Gtk.Label()
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"]]
date_label.set_markup("" + legality["format"] + ":" + "")
text_label.set_markup("" + legality["legality"] + "")
grid.attach(date_label, 0, rows + 2, 1, 1)
grid.attach(text_label, 1, rows + 2, 1, 1)
rows += 1
grid.show_all()
# Rulings
if card.rulings:
grid = builder.get_object("rulesGrid")
rows = 1
for rule in card.rulings:
date_label = Gtk.Label(rule["date"])
text_label = Gtk.Label(rule["text"])
text_label.set_line_wrap_mode(Pango.WrapMode.WORD)
text_label.set_line_wrap(True)
text_label.set_justify(Gtk.Justification.LEFT)
text_label.set_halign(Gtk.Align.START)
grid.attach(date_label, 0, rows+2, 1, 1)
grid.attach(text_label, 1, rows+2, 1, 1)
rows += 1
grid.show_all()
else:
builder.get_object("ruleBox").set_visible(False)
window.show_all()
def eval_key_pressed(widget,event):
key, modifier = Gtk.accelerator_parse('Escape')
keyval = event.keyval
if keyval == key:
window.destroy()
window.connect("key-press-event", eval_key_pressed)
def show_question_dialog(self, title, message):
dialog = Gtk.MessageDialog(self.ui.get_object("mainWindow"), 0, Gtk.MessageType.WARNING,
Gtk.ButtonsType.YES_NO, title)
dialog.format_secondary_text(message)
response = dialog.run()
dialog.destroy()
return response
def show_message(self, title, message):
dialog = Gtk.MessageDialog(self.ui.get_object("mainWindow"), 0, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, title)
dialog.format_secondary_text(message)
dialog.run()
dialog.destroy()
def show_tag_rename_dialog(self, tag):
def rename(button, entry):
self.rename_tag(tag, entry.get_text())
window.destroy()
self.current_page.emit('show')
def eval_key_pressed(widget,event):
key, modifier = Gtk.accelerator_parse('Escape')
keyval = event.keyval
if keyval == key:
window.destroy()
builder = Gtk.Builder()
builder.add_from_file(util.get_ui_filename("dialogs.glade"))
window = builder.get_object("renameWindow")
entry = builder.get_object("renameEntry")
entry.set_text(tag)
builder.get_object("renameButton").connect('clicked', rename, entry)
entry.connect('activate', rename, entry)
window.show_all()
window.connect("key-press-event", eval_key_pressed)
def save_library(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 load_library(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()
self.push_status("Library loaded")
def get_untagged_cards(self):
lib = copy.copy(self.library)
for ids in self.tags.values():
for card_id in ids:
try:
del lib[card_id]
except KeyError:
pass
return lib
def get_tagged_cards(self, tag):
if not tag:
return self.library
else:
lib = {}
for card_id in self.tags[tag]:
lib[card_id] = self.library[card_id]
return lib
def tag_card(self, card, tag):
list = self.tags[tag]
list.append(card.multiverse_id)
self.unsaved_changes = True
def untag_card(self, card, tag):
list = self.tags[tag]
list.remove(card.multiverse_id)
self.unsaved_changes = True
def add_tag(self, tag):
self.tags[tag] = []
util.log("Tag '" + tag + "' added", util.LogLevel.Info)
self.push_status("Added Tag \"" + tag + "\"")
self.unsaved_changes = True
def remove_tag(self, tag):
del self.tags[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):
self.tags[new] = self.tags[old]
del self.tags[old]
util.log("Tag '" + old + "' renamed to '" + new + "'", util.LogLevel.Info)
self.unsaved_changes = True
def get_wanted_card_ids(self) -> List[str]:
all_ids = []
for cards in self.wants.values():
next_ids = [card.multiverse_id for card in cards]
all_ids = list(set(all_ids) | set(next_ids))
return all_ids
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, card):
self.wants[list_name].append(card)
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):
if tag is not None:
self.tag_card(card, tag)
self.library[card.multiverse_id] = card
self.push_status(card.name + " added to library")
self.unsaved_changes = True
def remove_card_from_lib(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)
del self.library[card.multiverse_id]
self.push_status(card.name + " removed from library")
self.unsaved_changes = True
def get_card_image(self, card, sizex, sizey):
# Try using file from local cache, or load online
try:
pixbuf = self.image_cache[card.multiverse_id]
except KeyError as err:
util.log("No local image for " + card.name + ". Loading from " + card.image_url, util.LogLevel.Info)
pixbuf = util.load_card_image_online(card, sizex, sizey)
self.image_cache[card.multiverse_id] = pixbuf
return pixbuf
def get_mana_icons(self, mana_string):
if not mana_string:
util.log("No mana string provided", util.LogLevel.Warning)
return
icon_list = re.findall("{(.*?)}", mana_string)
icon_name = "_".join(icon_list)
try:
icon = self.precon_icons[icon_name]
except KeyError:
icon = util.create_mana_icons(self.mana_icons, mana_string)
self.precon_icons[icon_name] = icon
return icon
def filter_lib_func(self, model, iter, data):
filter_text = self.ui.get_object("searchLibEntry").get_text()
if filter_text == "":
return True
else:
return filter_text.lower() in model[iter][1].lower()
def main():
win = Application()
Gtk.main()