From 56ce7205c151ce084ba7b0e1f91a3ac949202496 Mon Sep 17 00:00:00 2001 From: luxick Date: Wed, 28 Feb 2018 21:49:02 +0100 Subject: [PATCH] Load MySQL connection from config file. --- dsst/dsst_gtk3/dialogs.py | 27 +- dsst/dsst_gtk3/gtk_ui.py | 30 +- dsst/dsst_gtk3/handlers/base_data_handlers.py | 10 +- dsst/dsst_gtk3/handlers/death_handlers.py | 2 +- dsst/dsst_gtk3/handlers/dialog_handlers.py | 9 +- dsst/dsst_gtk3/handlers/handlers.py | 6 +- dsst/dsst_gtk3/handlers/season_handlers.py | 2 +- dsst/dsst_gtk3/handlers/victory_handlers.py | 2 +- dsst/dsst_gtk3/resources/glade/window.glade | 477 +++++++++++------- dsst/dsst_gtk3/util.py | 112 ++-- dsst/dsst_sql/sql.py | 1 + 11 files changed, 407 insertions(+), 271 deletions(-) diff --git a/dsst/dsst_gtk3/dialogs.py b/dsst/dsst_gtk3/dialogs.py index 3793ef9..10a517a 100644 --- a/dsst/dsst_gtk3/dialogs.py +++ b/dsst/dsst_gtk3/dialogs.py @@ -74,10 +74,10 @@ def show_episode_dialog(builder: Gtk.Builder, title: str, season_id: int, episod # Update Date of the Episode cal_value = builder.get_object('episode_calendar').get_date() selected_date = datetime(*cal_value).date() - episode.update(date=selected_date, - number=str(builder.get_object("episode_no_spin_button").get_value()), - name=builder.get_object("episode_name_entry").get_text())\ - .execute() + episode.date = selected_date, + episode.number = int(builder.get_object("episode_no_spin_button").get_value()) + episode.name = builder.get_object("episode_name_entry").get_text() + episode.save() return True @@ -117,7 +117,7 @@ def show_edit_death_dialog(builder: Gtk.Builder, episode_id: int, death: sql.Dea dialog.set_transient_for(builder.get_object("main_window")) with sql.db.atomic(): if death: - index = util.Util.get_index_of_combo_model(builder.get_object('edit_death_enemy_combo'), 0, death.enemy.id) + index = util.get_index_of_combo_model(builder.get_object('edit_death_enemy_combo'), 0, death.enemy.id) builder.get_object('edit_death_enemy_combo').set_active(index) # TODO Default drink should be set in config @@ -135,8 +135,8 @@ def show_edit_death_dialog(builder: Gtk.Builder, episode_id: int, death: sql.Dea return result # Collect info from widgets and save to database - player_id = util.Util.get_combo_value(builder.get_object('edit_death_player_combo'), 0) - enemy_id = util.Util.get_combo_value(builder.get_object('edit_death_enemy_combo'), 3) + player_id = util.get_combo_value(builder.get_object('edit_death_player_combo'), 0) + enemy_id = util.get_combo_value(builder.get_object('edit_death_enemy_combo'), 3) comment = builder.get_object('edit_death_comment_entry').get_text() if not death: death = sql.Death.create(episode=episode_id, player=player_id, enemy=enemy_id, info=comment) @@ -165,7 +165,7 @@ def show_edit_victory_dialog(builder: Gtk.Builder, episode_id: int, victory: sql ['edit_victory_enemy_combo', victory.enemy.id]] for info in infos: combo = builder.get_object(info[0]) - index = util.Util.get_index_of_combo_model(combo, 0, info[1]) + index = util.get_index_of_combo_model(combo, 0, info[1]) combo.set_active(index) builder.get_object('victory_comment_entry').set_text(victory.info) @@ -177,12 +177,15 @@ def show_edit_victory_dialog(builder: Gtk.Builder, episode_id: int, victory: sql return result # Collect info from widgets and save to database - player_id = util.Util.get_combo_value(builder.get_object('edit_victory_player_combo'), 0) - enemy_id = util.Util.get_combo_value(builder.get_object('edit_victory_enemy_combo'), 3) + player_id = util.get_combo_value(builder.get_object('edit_victory_player_combo'), 0) + enemy_id = util.get_combo_value(builder.get_object('edit_victory_enemy_combo'), 3) comment = builder.get_object('victory_comment_entry').get_text() if not victory: sql.Victory.create(episode=episode_id, player=player_id, enemy=enemy_id, info=comment) else: - victory.update(player=player_id, enemy=enemy_id, info=comment).execute() + victory.player = player_id + victory.enemy = enemy_id + victory.info = comment + victory.save() - return result \ No newline at end of file + return result diff --git a/dsst/dsst_gtk3/gtk_ui.py b/dsst/dsst_gtk3/gtk_ui.py index 5e24631..484d525 100644 --- a/dsst/dsst_gtk3/gtk_ui.py +++ b/dsst/dsst_gtk3/gtk_ui.py @@ -1,6 +1,10 @@ from collections import Counter import gi +import math + +import os + gi.require_version('Gtk', '3.0') from gi.repository import Gtk from dsst_gtk3.handlers import handlers @@ -10,7 +14,7 @@ from dsst_sql import sql, sql_func class GtkUi: """ The main UI class """ - def __init__(self): + def __init__(self, config: dict): # Load Glade UI files self.ui = Gtk.Builder() glade_resources = [ @@ -18,15 +22,15 @@ class GtkUi: ['dsst_gtk3', 'resources', 'glade', 'dialogs.glade'] ] for path in glade_resources: - self.ui.add_from_string(util.Util.load_ui_resource_string(path)) + self.ui.add_from_string(util.load_ui_resource_string(path)) # Connect signal handlers to UI self.handlers = handlers.Handlers(self) self.ui.connect_signals(self.handlers) # Show all widgets self.ui.get_object('main_window').show_all() + db_config = config['sql_connections'][0] # Initialize the database - # TODO User input to select database - sql.db.init('dsst', user='dsst', password='dsst') + sql.db.init(db_config['db_name'], user=db_config['user'], password=db_config['password']) # Create database if not exists sql_func.create_tables() @@ -41,7 +45,7 @@ class GtkUi: # Rebuild drink store self.ui.get_object('drink_store').clear() for drink in sql.Drink.select(): - self.ui.get_object('drink_store').append([drink.id, drink.name, str(drink.vol)]) + self.ui.get_object('drink_store').append([drink.id, drink.name, '{:.2f}%'.format(drink.vol)]) # Rebuild seasons store store = self.ui.get_object('seasons_store') store.clear() @@ -115,8 +119,13 @@ class GtkUi: self.ui.get_object('ep_death_count_label').set_text(str(len(episode.deaths))) drink_count = sum(len(death.penalties) for death in episode.deaths) self.ui.get_object('ep_drinks_label').set_text(str(drink_count)) - cl_booze = sum(len(death.penalties) * death.penalties[0].size for death in episode.deaths) - self.ui.get_object('ep_booze_label').set_text(str(cl_booze) + "cl") + self.ui.get_object('ep_player_drinks_label').set_text(str(len(episode.deaths))) + dl_booze = sum(len(death.penalties) * death.penalties[0].size for death in episode.deaths) + l_booze = round(dl_booze / 10, 2) + self.ui.get_object('ep_booze_label').set_text('{}l'.format(l_booze)) + dl_booze = sum(len(death.penalties) * death.penalties[0].size for death in episode.deaths) + ml_booze = round(dl_booze * 10, 0) + self.ui.get_object('ep_player_booze_label').set_text('{}ml'.format(ml_booze)) enemy_list = [death.enemy.name for death in episode.deaths] sorted_list = Counter(enemy_list).most_common(1) if sorted_list: @@ -127,7 +136,7 @@ class GtkUi: """Read ID of the selected season from the UI :return: ID of the selected season """ - season_id = util.Util.get_combo_value(self.ui.get_object('season_combo_box'), 0) + season_id = util.get_combo_value(self.ui.get_object('season_combo_box'), 0) return season_id if season_id != -1 else None def get_selected_episode_id(self): @@ -139,5 +148,8 @@ class GtkUi: def main(): - GtkUi() + if not os.path.isfile(util.CONFIG_PATH): + util.save_config(util.DEFAULT_CONFIG, util.CONFIG_PATH) + config = util.load_config(util.CONFIG_PATH) + GtkUi(config) Gtk.main() diff --git a/dsst/dsst_gtk3/handlers/base_data_handlers.py b/dsst/dsst_gtk3/handlers/base_data_handlers.py index c4324f6..0a45287 100644 --- a/dsst/dsst_gtk3/handlers/base_data_handlers.py +++ b/dsst/dsst_gtk3/handlers/base_data_handlers.py @@ -8,7 +8,7 @@ class BaseDataHandlers: self.app = app def do_manage_players(self, *_): - result = dialogs.show_manage_players_dialog(self.app.ui, 'Manage Players') + dialogs.show_manage_players_dialog(self.app.ui, 'Manage Players') def do_add_player(self, entry): if entry.get_text(): @@ -17,7 +17,7 @@ class BaseDataHandlers: self.app.reload_base_data() def do_manage_enemies(self, *_): - result = dialogs.show_manage_enemies_dialog(self.app.ui, self.app.get_selected_season_id()) + dialogs.show_manage_enemies_dialog(self.app.ui, self.app.get_selected_season_id()) def on_player_name_edited(self, _, index, value): row = self.app.ui.get_object('all_players_store')[index] @@ -33,6 +33,12 @@ class BaseDataHandlers: .execute() self.app.reload_base_data() + def do_add_drink(self, entry): + if entry.get_text(): + sql.Drink.create(name=entry.get_text(), vol=0) + entry.set_text('') + self.app.reload_base_data() + def on_drink_name_edited(self, _, index, value): row = self.app.ui.get_object('drink_store')[index] sql.Drink.update(name=value)\ diff --git a/dsst/dsst_gtk3/handlers/death_handlers.py b/dsst/dsst_gtk3/handlers/death_handlers.py index 12e73a7..d48d808 100644 --- a/dsst/dsst_gtk3/handlers/death_handlers.py +++ b/dsst/dsst_gtk3/handlers/death_handlers.py @@ -16,5 +16,5 @@ class DeathHandlers: self.app.reload_for_season() self.app.reload_for_episode() - def on_penalty_drink_changed(self, widget, path, text): + def on_penalty_drink_changed(self, _, path, text): self.app.ui.get_object('player_penalties_store')[path][2] = text diff --git a/dsst/dsst_gtk3/handlers/dialog_handlers.py b/dsst/dsst_gtk3/handlers/dialog_handlers.py index 60dbcd5..5204828 100644 --- a/dsst/dsst_gtk3/handlers/dialog_handlers.py +++ b/dsst/dsst_gtk3/handlers/dialog_handlers.py @@ -11,7 +11,7 @@ class DialogHandlers: """ Signal Handler for Add Player to Episode Button in Manage Episode Dialog :param combo: Combo box with all the available players """ - player_id = util.Util.get_combo_value(combo, 0) + player_id = util.get_combo_value(combo, 0) if player_id: self.app.ui.get_object('add_player_combo_box').set_active(-1) player = sql.Player.get(sql.Player.id == player_id) @@ -28,10 +28,3 @@ class DialogHandlers: def do_manage_drinks(self, *_): result = dialogs.show_manage_drinks_dialog(self.app.ui) - - def do_add_drink(self, entry): - if entry.get_text(): - store = self.app.ui.get_object('drink_store') - drink = sql.Drink.create(name=entry.get_text(), vol='0') - store.append([drink.id, drink.name, drink.vol]) - entry.set_text('') diff --git a/dsst/dsst_gtk3/handlers/handlers.py b/dsst/dsst_gtk3/handlers/handlers.py index 09ade40..1dd2d62 100644 --- a/dsst/dsst_gtk3/handlers/handlers.py +++ b/dsst/dsst_gtk3/handlers/handlers.py @@ -24,9 +24,9 @@ class Handlers(SeasonHandlers, BaseDataHandlers, DialogHandlers, DeathHandlers, VictoryHandlers.__init__(self, app) @staticmethod - def do_delete_event(*args): + def do_delete_event(*_): """ Signal will be sent when app should close - :param args: Arguments to the delete event + :param _: Arguments to the delete event """ Gtk.main_quit() @@ -35,4 +35,4 @@ class Handlers(SeasonHandlers, BaseDataHandlers, DialogHandlers, DeathHandlers, @staticmethod def do_delete_database(*_): sql_func.drop_tables() - sql_func.create_tables() \ No newline at end of file + sql_func.create_tables() diff --git a/dsst/dsst_gtk3/handlers/season_handlers.py b/dsst/dsst_gtk3/handlers/season_handlers.py index 472301a..07205bc 100644 --- a/dsst/dsst_gtk3/handlers/season_handlers.py +++ b/dsst/dsst_gtk3/handlers/season_handlers.py @@ -20,7 +20,7 @@ class SeasonHandlers: season_id = self.app.get_selected_season_id() if not season_id: return - episode = dialogs.show_episode_dialog(self.app.ui, 'Create new Episode', season_id) + dialogs.show_episode_dialog(self.app.ui, 'Create new Episode', season_id) self.app.reload_for_season() def on_selected_episode_changed(self, *_): diff --git a/dsst/dsst_gtk3/handlers/victory_handlers.py b/dsst/dsst_gtk3/handlers/victory_handlers.py index 46627d9..fef13fa 100644 --- a/dsst/dsst_gtk3/handlers/victory_handlers.py +++ b/dsst/dsst_gtk3/handlers/victory_handlers.py @@ -14,4 +14,4 @@ class VictoryHandlers: result = dialogs.show_edit_victory_dialog(self.app.ui, ep_id) if result == Gtk.ResponseType.OK: self.app.reload_for_season() - self.app.reload_for_episode() \ No newline at end of file + self.app.reload_for_episode() diff --git a/dsst/dsst_gtk3/resources/glade/window.glade b/dsst/dsst_gtk3/resources/glade/window.glade index e9d9684..bf59ea7 100644 --- a/dsst/dsst_gtk3/resources/glade/window.glade +++ b/dsst/dsst_gtk3/resources/glade/window.glade @@ -232,150 +232,6 @@ - - False - Manage Enemies For This Season - False - True - 300 - dialog - False - - - False - vertical - 4 - - - False - end - - - - - - gtk-ok - True - True - True - True - - - True - True - 1 - - - - - False - False - 0 - - - - - True - False - vertical - 5 - - - True - False - 5 - - - True - False - 5 - 5 - Add Enemy - - - False - True - 0 - - - - - True - True - - - - False - True - 1 - - - - - False - True - 0 - - - - - True - False - 5 - 5 - All Enemies - 0 - - - False - True - 1 - - - - - True - True - True - enemy_season_store - 0 - - - - - - Name - - - - 0 - - - - - - - False - True - 2 - - - - - True - True - 1 - - - - - - okButtonRename1 - - - - - 1000000 1 @@ -901,6 +757,157 @@ + + False + Manage Enemies For This Season + False + True + 300 + dialog + False + + + False + vertical + 4 + + + False + end + + + + + + gtk-ok + True + True + True + True + + + True + True + 1 + + + + + False + False + 0 + + + + + True + False + vertical + 5 + + + True + False + 5 + + + True + False + 5 + 5 + Add Enemy + + + False + True + 0 + + + + + True + True + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + 5 + 5 + All Enemies + 0 + + + False + True + 1 + + + + + True + True + in + + + True + True + True + enemy_season_store + 0 + + + + + + Name + + + + 0 + + + + + + + + + True + True + 2 + + + + + True + True + 1 + + + + + + okButtonRename1 + + + + + False Manage Players @@ -1557,7 +1564,7 @@ True - 150 + 180 True False vertical @@ -1814,27 +1821,14 @@ - + True False - Total Drinks: - 1 + [DeathCount] - 0 - 1 - - - - - True - False - Hardest Enemy: - 1 - - - 0 - 3 + 1 + 0 @@ -1846,6 +1840,61 @@ 0 + 7 + + + + + True + False + Hardest Enemy: + 1 + + + 0 + 8 + + + + + True + False + + + 1 + 7 + + + + + True + False + + + 1 + 8 + + + + + True + False + Total Drinks: + 1 + + + 0 + 4 + + + + + True + False + [DrinkCount] + + + 1 4 @@ -1858,29 +1907,7 @@ 0 - 2 - - - - - True - False - [DeathCount] - - - 1 - 0 - - - - - True - False - [DrinkCount] - - - 1 - 1 + 5 @@ -1891,13 +1918,84 @@ 1 + 5 + + + + + True + False + Player Drinks: + 1 + + + 0 + 1 + + + + + True + False + Player Booze: + 1 + + + 0 2 - + True False + Player Alc.: + 1 + + + 0 + 3 + + + + + True + False + Total Alc: + 1 + + + 0 + 6 + + + + + True + False + [PlayerDrinks] + + + 1 + 1 + + + + + True + False + [PlayerBooze] + + + 1 + 2 + + + + + True + False + [PlayerAlc] 1 @@ -1905,13 +2003,14 @@ - + True False + [TotalAlc] 1 - 4 + 6 @@ -2261,7 +2360,7 @@ - Attempts + Deaths True True 1 diff --git a/dsst/dsst_gtk3/util.py b/dsst/dsst_gtk3/util.py index 3cc9b75..7dda7b8 100644 --- a/dsst/dsst_gtk3/util.py +++ b/dsst/dsst_gtk3/util.py @@ -1,57 +1,79 @@ """ This modules contains general utilities for the GTK application to use. """ - +import json import os from zipfile import ZipFile +CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.config', 'dsst', 'config.json') +DEFAULT_CONFIG = { + 'auto_connect': False, + 'sql_connections': [{ + 'host': 'localhost', + 'db_name': 'dsst', + 'user': 'dsst', + 'password': 'dsst'} + ] +} -class Util: - @staticmethod - def get_combo_value(combo, index: int): - """ Retrieve the selected value of a combo box at the selected index in the model - :param combo: Any Gtk Widget that supports 'get_active_iter()' - :param index: Index of the value in the widgets model to be retrieved - :return: The value of the model at the selected index (Default -1) - """ - tree_iter = combo.get_active_iter() - if tree_iter: - return combo.get_model().get_value(tree_iter, index) - else: - return -1 - @staticmethod - def get_index_of_combo_model(widget, column: int, value: int): - """Get the index of a value within a Gtk widgets model based on column an value - :param widget: Any Gtk widget that can be bound to a ListStore or TreeStore - :param column: Column in the model where to look for the value - :param value: Value to look for in the model - :return: List of the indexes where the value occurs - """ - model = widget.get_model() - return [model.index(entry) for entry in model if entry[column] == value] +def get_combo_value(combo, index: int): + """ Retrieve the selected value of a combo box at the selected index in the model + :param combo: Any Gtk Widget that supports 'get_active_iter()' + :param index: Index of the value in the widgets model to be retrieved + :return: The value of the model at the selected index (Default -1) + """ + tree_iter = combo.get_active_iter() + if tree_iter: + return combo.get_model().get_value(tree_iter, index) + else: + return -1 - @staticmethod - def load_ui_resource_string(resource_path: list) -> str: - """ Load content of Glade UI files from resources path - :param resource_path: List of directory names from 'dsst' base directory - :return: String content of the Glade file - """ - if os.path.isdir(os.path.dirname(__file__)): - return Util.load_ui_resource_from_file(resource_path) - else: - return Util.load_ui_resource_from_archive(resource_path) +def get_index_of_combo_model(widget, column: int, value: int): + """Get the index of a value within a Gtk widgets model based on column an value + :param widget: Any Gtk widget that can be bound to a ListStore or TreeStore + :param column: Column in the model where to look for the value + :param value: Value to look for in the model + :return: List of the indexes where the value occurs + """ + model = widget.get_model() + return [model.index(entry) for entry in model if entry[column] == value] - @staticmethod - def load_ui_resource_from_file(resource_path: list) -> str: - project_base_dir = os.path.dirname(os.path.dirname(__file__)) - full_path = os.path.join(project_base_dir, *resource_path) - with open(full_path, 'r') as file: - return file.read() - @staticmethod - def load_ui_resource_from_archive(resource_path: list) -> str: - zip_path = os.path.dirname(os.path.dirname(__file__)) - with ZipFile(zip_path, 'r') as archive: - return archive.read(str(os.path.join(*resource_path))).decode('utf-8') +def load_ui_resource_from_file(resource_path: list) -> str: + project_base_dir = os.path.dirname(os.path.dirname(__file__)) + full_path = os.path.join(project_base_dir, *resource_path) + with open(full_path, 'r') as file: + return file.read() + + +def load_ui_resource_from_archive(resource_path: list) -> str: + zip_path = os.path.dirname(os.path.dirname(__file__)) + with ZipFile(zip_path, 'r') as archive: + return archive.read(str(os.path.join(*resource_path))).decode('utf-8') + + +def load_ui_resource_string(resource_path: list) -> str: + """ Load content of Glade UI files from resources path + :param resource_path: List of directory names from 'dsst' base directory + :return: String content of the Glade file + """ + if os.path.isdir(os.path.dirname(__file__)): + return load_ui_resource_from_file(resource_path) + else: + + return load_ui_resource_from_archive(resource_path) + + +def load_config(config_path: str) -> dict: + with open(config_path) as config_file: + return json.load(config_file) + + +def save_config(config: dict, config_path: str): + path = os.path.dirname(config_path) + if not os.path.isdir(path): + os.mkdir(path) + with open(config_path, 'wb') as file: + file.write(json.dumps(config, sort_keys=True, indent=4, separators=(',', ': ')).encode('utf-8')) diff --git a/dsst/dsst_sql/sql.py b/dsst/dsst_sql/sql.py index 3031c50..16052c2 100644 --- a/dsst/dsst_sql/sql.py +++ b/dsst/dsst_sql/sql.py @@ -56,6 +56,7 @@ class Drink(Model): class Enemy(Model): id = AutoField() name = CharField() + optional = BooleanField() season = ForeignKeyField(Season, backref='enemies') class Meta: