Add build script.
This commit is contained in:
326
legacy/handlers.py
Normal file
326
legacy/handlers.py
Normal file
@@ -0,0 +1,326 @@
|
||||
import math
|
||||
import sys
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
import time, datetime
|
||||
import os
|
||||
import threading
|
||||
from gi.repository import Gtk, GObject
|
||||
|
||||
from cardvault import util, application
|
||||
from legacy.search import SearchHandlers
|
||||
from legacy.library import LibraryHandlers
|
||||
from legacy.wants import WantsHandlers
|
||||
|
||||
|
||||
class Handlers(SearchHandlers, LibraryHandlers, WantsHandlers):
|
||||
def __init__(self, app: 'application.Application'):
|
||||
"""Initialize handlers for UI signals"""
|
||||
self.app = app
|
||||
# Token to cancel a running download
|
||||
self.cancel_token = False
|
||||
|
||||
# Call constructor of view handlers classes
|
||||
SearchHandlers.__init__(self, app)
|
||||
LibraryHandlers.__init__(self, app)
|
||||
WantsHandlers.__init__(self, app)
|
||||
|
||||
# --------------------------------- Main Window Handlers ----------------------------------------------
|
||||
|
||||
def do_save_library(self, item):
|
||||
self.app.save_data()
|
||||
|
||||
def do_export_library(self, item):
|
||||
dialog = Gtk.FileChooserDialog("Export Library", self.app.ui.get_object("mainWindow"),
|
||||
Gtk.FileChooserAction.SAVE,
|
||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
||||
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
|
||||
dialog.set_current_name("mtg_export-" + datetime.datetime.now().strftime("%Y-%m-%d"))
|
||||
dialog.set_current_folder(os.path.expanduser("~"))
|
||||
response = dialog.run()
|
||||
|
||||
if response == Gtk.ResponseType.OK:
|
||||
# prepare export file
|
||||
file = {"library": self.app.library, "tags": self.app.tags, "wants": self.app.wants}
|
||||
util.export_library(dialog.get_filename(), file)
|
||||
self.app.push_status("Library exported")
|
||||
|
||||
dialog.destroy()
|
||||
|
||||
def export_cell_toggled(self, widget, pos):
|
||||
model = self.app.ui.get_object("export_treestore")
|
||||
iter = model.get_iter(pos)
|
||||
model.set_value(iter, 0, not widget.get_active())
|
||||
|
||||
if len(pos.split(":")) > 1:
|
||||
# A child node has been clicked
|
||||
pass
|
||||
|
||||
def do_export_json(self, item):
|
||||
"""
|
||||
Export user data to file
|
||||
Called By: Export menu item
|
||||
"""
|
||||
# dialog = self.app.ui.get_object("export_dialog")
|
||||
# dialog.set_transient_for(self.app.ui.get_object("mainWindow"))
|
||||
#
|
||||
# store = self.app.ui.get_object("export_treestore") # type: Gtk.TreeStore
|
||||
# store.clear()
|
||||
# store.append(None, [True, False, "Library"])
|
||||
# store.append(None, [True, False, "Decks"])
|
||||
# store.append(None, [True, False, "Wants Lists"])
|
||||
#
|
||||
# lib_iter = store.get_iter_first()
|
||||
# deck_iter = store.iter_next(lib_iter)
|
||||
# wants_iter = store.iter_next(deck_iter)
|
||||
#
|
||||
# store.append(lib_iter, [True, True, "Untagged Cards"])
|
||||
# for tag in self.app.tags.keys():
|
||||
# store.append(lib_iter, [True, True, tag])
|
||||
#
|
||||
# for name in self.app.wants.keys():
|
||||
# store.append(wants_iter, [True, True, name])
|
||||
#
|
||||
# self.app.ui.get_object("export_sel_tree").expand_all()
|
||||
#
|
||||
# response = dialog.run()
|
||||
# dialog.hide()
|
||||
#
|
||||
# if not response == Gtk.ResponseType.OK:
|
||||
# return
|
||||
|
||||
# TODO Read treemodel to select witch parts to export
|
||||
|
||||
dialog = Gtk.FileChooserDialog("Export Library", self.app.ui.get_object("mainWindow"),
|
||||
Gtk.FileChooserAction.SAVE,
|
||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
||||
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
|
||||
dialog.set_current_name("mtg_export-" + datetime.datetime.now().strftime("%Y-%m-%d") + ".json")
|
||||
dialog.set_current_folder(os.path.expanduser("~"))
|
||||
response = dialog.run()
|
||||
|
||||
if response == Gtk.ResponseType.OK:
|
||||
# prepare export file
|
||||
file = {"library": self.app.library, "tags": self.app.tags, "wants": self.app.wants}
|
||||
util.export_json(dialog.get_filename(), file)
|
||||
self.app.push_status("Library exported")
|
||||
|
||||
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,
|
||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
||||
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
|
||||
dialog.set_current_folder(os.path.expanduser("~"))
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
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]
|
||||
self.app.db_override_user_data()
|
||||
self.app.current_page.emit('show')
|
||||
dialog.destroy()
|
||||
|
||||
def do_card_data_user(self, menu_item):
|
||||
"""
|
||||
Handler for Clear User Data menu item.
|
||||
"""
|
||||
response = self.app.show_dialog_yn("Deleting All User Data", "You are about to delete all data in the "
|
||||
"library.\nThis can not be undone.\nProceed?")
|
||||
if response == Gtk.ResponseType.YES:
|
||||
util.log("Deleting all local card data", util.LogLevel.Info)
|
||||
self.app.db_delete_user_data()
|
||||
util.log("Done", util.LogLevel.Info)
|
||||
self.app.push_status("Library deleted")
|
||||
|
||||
def do_card_data_card(self, item):
|
||||
"""Handler for Clear Card Data menu item"""
|
||||
response = self.app.show_dialog_yn("Deleting All Card Data", "You are about to delete all local card data.\n"
|
||||
"Further searches will use the internet to search "
|
||||
"for cards.\nProceed?")
|
||||
if response == Gtk.ResponseType.YES:
|
||||
util.log("Deleting all library data", util.LogLevel.Info)
|
||||
self.app.db_delete_card_data()
|
||||
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")
|
||||
new_page = self.app.pages[item.get_name()]
|
||||
if self.app.current_page:
|
||||
container.remove(self.app.current_page)
|
||||
self.app.current_page = new_page
|
||||
container.pack_start(self.app.current_page, True, True, 0)
|
||||
container.show_all()
|
||||
self.app.current_page.emit('show')
|
||||
|
||||
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",
|
||||
"You have unsaved changes in your library. "
|
||||
"Save before exiting?")
|
||||
if response == Gtk.ResponseType.YES:
|
||||
self.app.save_data()
|
||||
return False
|
||||
elif response == Gtk.ResponseType.CANCEL:
|
||||
return True
|
||||
|
||||
def do_cancel_download(self, item: Gtk.MenuItem):
|
||||
"""The cancel button was pressed, set cancel_token to stop download thread"""
|
||||
self.cancel_token = True
|
||||
# Delete Dialog
|
||||
self.app.ui.get_object("loadDataDialog").hide()
|
||||
self.app.push_status("Download canceled")
|
||||
util.log("Download canceled by user", util.LogLevel.Info)
|
||||
|
||||
def download_canceled(self):
|
||||
"""The download thread was canceled and finished executing"""
|
||||
self.cancel_token = False
|
||||
util.log("Download thread ended", util.LogLevel.Info)
|
||||
|
||||
def download_failed(self, err):
|
||||
# Delete Dialog
|
||||
self.app.ui.get_object("loadDataDialog").hide()
|
||||
self.app.push_status("Download canceled")
|
||||
self.app.show_message("Download Failed", str(err))
|
||||
|
||||
def download_finished(self):
|
||||
"""Download thread finished without errors"""
|
||||
self.cancel_token = False
|
||||
self.app.set_online(False)
|
||||
self.app.ui.get_object("loadDataDialog").hide()
|
||||
self.app.push_status("Card data downloaded")
|
||||
util.log("Card data download finished", util.LogLevel.Info)
|
||||
|
||||
def do_download_card_data(self, item: Gtk.MenuItem):
|
||||
"""Download button was pressed in the menu bar. Starts a thread to load data from the internet"""
|
||||
info_string = "Start downloading card information from the internet?\n" \
|
||||
"You can cancel the download at any point."
|
||||
response = self.app.show_dialog_yn("Download Card Data", info_string)
|
||||
if response == Gtk.ResponseType.NO:
|
||||
return
|
||||
# Launch download info dialog
|
||||
dl_dialog = self.app.ui.get_object("loadDataDialog")
|
||||
dl_dialog.set_transient_for(self.app.ui.get_object("mainWindow"))
|
||||
dl_dialog.show()
|
||||
|
||||
# Hide Progress UI until download started
|
||||
self.app.ui.get_object("dl_progress_bar").set_visible(False)
|
||||
self.app.ui.get_object("dl_progress_label").set_visible(False)
|
||||
|
||||
# Create and start the download in a separate thread so it will not block the UI
|
||||
thread = threading.Thread(target=self.load_thread)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
util.log("Attempt downloading all cards. This may take a while...", util.LogLevel.Info)
|
||||
|
||||
def load_thread(self):
|
||||
"""Worker thread to download info using the mtgsdk"""
|
||||
|
||||
# Gatherer uses rate limit on Card.all()
|
||||
# Takes ~10 minutes to download all cards
|
||||
# all = self.load_thread_gatherer()
|
||||
|
||||
# Download from mtgjson.com
|
||||
GObject.idle_add(self.load_show_insert_ui, "Downloading...")
|
||||
|
||||
# Waiting in case a canceled thread is still running.
|
||||
while self.cancel_token:
|
||||
continue
|
||||
|
||||
util.log("Starting download", util.LogLevel.Info)
|
||||
s = time.time()
|
||||
all_json = util.net_all_cards_mtgjson()
|
||||
e = time.time()
|
||||
util.log("Finished in {}s".format(round(e - s, 3)), util.LogLevel.Info)
|
||||
|
||||
if self.cancel_token:
|
||||
GObject.idle_add(self.download_canceled)
|
||||
return
|
||||
|
||||
self.app.db_delete_card_data()
|
||||
|
||||
GObject.idle_add(self.load_show_insert_ui, "Saving data to disk...")
|
||||
util.log("Saving to sqlite", util.LogLevel.Info)
|
||||
s = time.time()
|
||||
GObject.idle_add(self.app.db.db_insert_data_card, all_json)
|
||||
e = time.time()
|
||||
util.log("Finished in {}s".format(round(e - s, 3)), util.LogLevel.Info)
|
||||
|
||||
self.download_finished()
|
||||
|
||||
def load_thread_gatherer(self):
|
||||
all = []
|
||||
all_num = util.get_all_cards_num()
|
||||
all_pages = int(math.ceil(all_num / 100))
|
||||
|
||||
# Paging for ui control between downloads
|
||||
for i in range(all_pages):
|
||||
req_start = time.time()
|
||||
try:
|
||||
new_cards = Card.where(page=i).where(pageSize=100).all()
|
||||
except MtgException as err:
|
||||
util.log(str(err), util.LogLevel.Error)
|
||||
return
|
||||
all = all + new_cards
|
||||
req_end = time.time()
|
||||
|
||||
# Check if the action was canceled during download
|
||||
if self.cancel_token:
|
||||
GObject.idle_add(self.download_canceled)
|
||||
return
|
||||
|
||||
# Activate download UI
|
||||
self.app.ui.get_object("dl_spinner").set_visible(False)
|
||||
self.app.ui.get_object("dl_progress_bar").set_visible(True)
|
||||
self.app.ui.get_object("dl_progress_label").set_visible(True)
|
||||
passed = str(round(req_end - req_start, 3))
|
||||
GObject.idle_add(self.load_update_ui, all, all_num, passed)
|
||||
|
||||
return all
|
||||
|
||||
def load_update_ui(self, current_list: list, max_cards: int, time_passed: str):
|
||||
"""Called from withing the worker thread. Updates the download dialog with infos."""
|
||||
# Get info widgets
|
||||
info_label = self.app.ui.get_object("dl_info_label")
|
||||
progress_label = self.app.ui.get_object("dl_progress_label")
|
||||
bar = self.app.ui.get_object("dl_progress_bar")
|
||||
# Compute numbers for display
|
||||
size_human = util.sizeof_fmt(sys.getsizeof(current_list))
|
||||
size_bytes = sys.getsizeof(current_list)
|
||||
percent = len(current_list) / max_cards
|
||||
# Update UI
|
||||
info_label.set_text("Downloading Cards...")
|
||||
progress_label.set_text("{:.1%} ({})".format(percent, size_human))
|
||||
bar.set_fraction(percent)
|
||||
util.log("Downloading: {:.1%} | {} Bytes | {}s".format(percent, size_bytes, time_passed), util.LogLevel.Info)
|
||||
|
||||
def load_show_insert_ui(self, info: str):
|
||||
"""Called from worker thread after download finished. Sets UI to display the passed string"""
|
||||
self.app.ui.get_object("dl_info_label").set_text(info)
|
||||
self.app.ui.get_object("dl_spinner").set_visible(True)
|
||||
self.app.ui.get_object("dl_progress_bar").set_visible(False)
|
||||
self.app.ui.get_object("dl_progress_label").set_visible(False)
|
||||
Reference in New Issue
Block a user