From 391142135649b90cccebfc7f1915ada3b0fdd9fd Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 16 Jan 2023 22:47:28 -0600 Subject: [PATCH] Refactored to use better event system --- src/__builtins__.py | 99 ++---------- src/__init__.py | 24 +-- src/__main__.py | 18 ++- src/app.py | 19 +++ src/controller/ChangeView.py | 73 --------- src/controller/__init__.py | 2 - src/controller/widgets/__init__.py | 5 - src/core/__init__.py | 3 + src/core/change_view.py | 147 ++++++++++++++++++ .../Controller.py => core/controller.py} | 118 +++++++------- src/core/widgets/__init__.py | 6 + .../widgets/Case.py => core/widgets/case.py} | 18 ++- .../Insert.py => core/widgets/insert.py} | 16 +- .../Remove.py => core/widgets/remove.py} | 18 ++- .../widgets/remove_from_to.py} | 14 +- .../Replace.py => core/widgets/replace.py} | 17 +- .../widgets/Time.py => core/widgets/time.py} | 16 +- src/{Window.py => core/window.py} | 13 +- src/mixins/CommonActionsMixin.py | 21 ++- src/mixins/CommonWidgetGeneratorMixin.py | 3 +- src/utils/__init__.py | 3 + src/utils/event_system.py | 42 +++++ 22 files changed, 386 insertions(+), 309 deletions(-) create mode 100644 src/app.py delete mode 100644 src/controller/ChangeView.py delete mode 100644 src/controller/__init__.py delete mode 100644 src/controller/widgets/__init__.py create mode 100644 src/core/__init__.py create mode 100644 src/core/change_view.py rename src/{controller/Controller.py => core/controller.py} (71%) create mode 100644 src/core/widgets/__init__.py rename src/{controller/widgets/Case.py => core/widgets/case.py} (73%) rename src/{controller/widgets/Insert.py => core/widgets/insert.py} (83%) rename src/{controller/widgets/Remove.py => core/widgets/remove.py} (80%) rename src/{controller/widgets/RemoveFromTo.py => core/widgets/remove_from_to.py} (89%) rename src/{controller/widgets/Replace.py => core/widgets/replace.py} (69%) rename src/{controller/widgets/Time.py => core/widgets/time.py} (82%) rename src/{Window.py => core/window.py} (64%) create mode 100644 src/utils/__init__.py create mode 100644 src/utils/event_system.py diff --git a/src/__builtins__.py b/src/__builtins__.py index f52e77d..ae850f2 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -1,101 +1,34 @@ # Python imports -import builtins, os, re +import builtins +import threading from os import path + # Lib imports # Application imports +from utils.event_system import EventSystem -class Builtins: - """ Create an pub/sub systems. """ - def __init__(self): - self.USER_HOME = path.expanduser('~') - self.block_from_update = False - self.block_to_update = False - self.active_path = None - self.from_changes = [] - self.to_changes = [] +# NOTE: Threads WILL NOT die with parent's destruction. +def threaded_wrapper(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start() + return wrapper - # NOTE: The format used is list of [type, target, (data,)] Where: - # type is useful context for control flow, - # target is the method to call, - # data is the method parameters to give - # Where data may be any kind of data - self._gui_events = [] - self._module_events = [] - - - # Makeshift fake "events" type system FIFO - def _pop_gui_event(self): - if len(self._gui_events) > 0: - return self._gui_events.pop(0) - return None - - def _pop_module_event(self): - if len(self._module_events) > 0: - return self._module_events.pop(0) - return None - - - def set_active_path(self, _file): - if os.path.isdir(_file) : - self.from_changes.clear() - self.active_path = _file - for f in os.listdir(_file): - self.from_changes.append(f) - - self.from_changes.sort(key=self._natural_keys) - self.to_changes = self.from_changes - event_system.push_gui_event(["update-from", None, ()]) - event_system.push_gui_event(["update-to", None, ()]) - - def reset_to_view(self): - self.to_changes = self.from_changes - event_system.push_gui_event(["update-to", None, ()]) - - def reset_from_view(self): - self.set_active_path(self.active_path) - - def push_gui_event(self, event): - if len(event) == 3: - self._gui_events.append(event) - return None - - raise Exception("Invald event format! Please do: [type, target, (data,)]") - - def push_module_event(self, event): - if len(event) == 3: - self._module_events.append(event) - return None - - raise Exception("Invald event format! Please do: [type, target, (data,)]") - - def read_gui_event(self): - return self._gui_events[0] - - def read_module_event(self): - return self._module_events[0] - - def consume_gui_event(self): - return self._pop_gui_event() - - def consume_module_event(self): - return self._pop_module_event() - - def _atoi(self, text): - return int(text) if text.isdigit() else text - - def _natural_keys(self, text): - return [ self._atoi(c) for c in re.split('(\d+)',text) ] +# NOTE: Threads WILL die with parent's destruction. +def daemon_threaded_wrapper(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() + return wrapper # NOTE: Just reminding myself we can add to builtins two different ways... # __builtins__.update({"event_system": Builtins()}) builtins.app_name = "BulkR" -builtins.event_system = Builtins() -builtins.event_sleep_time = 0.1 +builtins.USER_HOME = path.expanduser('~') +builtins.event_system = EventSystem() builtins.debug = False builtins.trace_debug = False diff --git a/src/__init__.py b/src/__init__.py index db3945b..cd8371b 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,21 +1,3 @@ -#!/usr/bin/python3 - - -# Python imports - -# Lib imports -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk - -# Application imports -from __builtins__ import Builtins -from Window import Window -from controller import Controller - - -class Main(Window): - """docstring for Main.""" - - def __init__(self, args): - super(Main, self).__init__(args) +""" + Base module +""" diff --git a/src/__main__.py b/src/__main__.py index e5c6de1..bc10bc2 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -2,33 +2,37 @@ # Python imports -import sys, argparse +import argparse +import faulthandler from setproctitle import setproctitle +import signal # Gtk imports -import gi, faulthandler, signal +import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GLib # Application imports -from __init__ import Main +from __builtins__ import * +from app import Application if __name__ == "__main__": try: - setproctitle('BulkR') + setproctitle('{app_name}') GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit) faulthandler.enable() # For better debug info parser = argparse.ArgumentParser() # Add long and short arguments - parser.add_argument("--path", "-p", default="default", help="Path to folder.") + parser.add_argument("--path", "-p", default=None, help="Path to folder.") # Read arguments (If any...) - args = parser.parse_args() - main = Main(args) + args, unknownargs = parser.parse_known_args() + + Application(args, unknownargs) Gtk.main() except Exception as e: print( repr(e) ) diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..12bac57 --- /dev/null +++ b/src/app.py @@ -0,0 +1,19 @@ +#!/usr/bin/python3 + + +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from core.window import Window + + +class Application(Window): + """docstring for Application.""" + + def __init__(self, args, unknownargs): + super(Application, self).__init__(args, unknownargs) diff --git a/src/controller/ChangeView.py b/src/controller/ChangeView.py deleted file mode 100644 index 09cdf4c..0000000 --- a/src/controller/ChangeView.py +++ /dev/null @@ -1,73 +0,0 @@ -# Python imports - -# Lib imports -import gi -gi.require_version('Gtk', '3.0') -gi.require_version('Gdk', '3.0') -from gi.repository import Gtk, Gdk - -# Application imports -from mixins import CommonWidgetGeneratorMixin, CommonActionsMixin - - -class ChangeView(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): - def __init__(self): - super(ChangeView, self).__init__() - - from_container = Gtk.Box() - to_container = Gtk.Box() - from_scroll_vw, \ - self.from_store = self._create_treeview_widget(title="From:") - to_scroll_vw, \ - self.to_store = self._create_treeview_widget(title="To:") - - from_container.add(from_scroll_vw) - to_container.add(to_scroll_vw) - - from_container.set_orientation(1) - to_container.set_orientation(1) - - fchild = from_scroll_vw.get_children()[0] - fchild.connect("drag-data-received", self._on_drag_data_received) - URI_TARGET_TYPE = 80 - uri_target = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE) - targets = [ uri_target ] - action = Gdk.DragAction.COPY - fchild.enable_model_drag_dest(targets, action) - fchild.enable_model_drag_source(0, targets, action) - - self.set_spacing(20) - self.set_border_width(2) - self.set_homogeneous(True) - self.add(from_container) - self.add(to_container) - self.show_all() - - def _on_drag_data_received(self, widget, drag_context, x, y, data, info, time): - if info == 80: - uri = data.get_uris()[0].split("file://")[1] - event_system.set_active_path(uri) - - - - def update_from_list(self): - if event_system.block_from_update: - return - - print("Updating From List...") - if self.from_store: - self.from_store.clear() - - for i, change in enumerate(event_system.from_changes): - self.from_store.insert(i, [change]) - - def update_to_list(self): - if event_system.block_to_update: - return - - print("Updating To List...") - if self.to_store: - self.to_store.clear() - - for i, change in enumerate(event_system.to_changes): - self.to_store.insert(i, [change]) diff --git a/src/controller/__init__.py b/src/controller/__init__.py deleted file mode 100644 index b290d33..0000000 --- a/src/controller/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .ChangeView import ChangeView -from .Controller import Controller diff --git a/src/controller/widgets/__init__.py b/src/controller/widgets/__init__.py deleted file mode 100644 index 4688b2e..0000000 --- a/src/controller/widgets/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .Insert import Insert -from .Replace import Replace -from .Remove import Remove -from .RemoveFromTo import RemoveFromTo -from .Case import Case diff --git a/src/core/__init__.py b/src/core/__init__.py new file mode 100644 index 0000000..3641b89 --- /dev/null +++ b/src/core/__init__.py @@ -0,0 +1,3 @@ +""" + Core Module +""" diff --git a/src/core/change_view.py b/src/core/change_view.py new file mode 100644 index 0000000..5ab54f8 --- /dev/null +++ b/src/core/change_view.py @@ -0,0 +1,147 @@ +# Python imports +import os +import re + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +from gi.repository import Gtk +from gi.repository import Gdk + +# Application imports +from mixins import CommonWidgetGeneratorMixin +from mixins import CommonActionsMixin + + +class ChangeView(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): + def __init__(self): + super(ChangeView, self).__init__() + + self._active_path = None + self._from_store = None + self._to_store = None + self._from_changes = [] + self._to_changes = [] + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + self.show_all() + + + def _setup_styling(self): + self.set_spacing(20) + self.set_border_width(2) + self.set_homogeneous(True) + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + event_system.subscribe("reset-from-view", self.reset_from_view) + event_system.subscribe("reset-to-view", self.reset_to_view) + event_system.subscribe("get-from", self.get_from_list) + event_system.subscribe("get-to", self.get_to_list) + event_system.subscribe("set-from", self.set_from_list) + event_system.subscribe("set-to", self.set_to_list) + event_system.subscribe("update-from", self.update_from_list) + event_system.subscribe("update-to", self.update_to_list) + event_system.subscribe("get-active-path", self._get_active_path) + event_system.subscribe("set-active-path", self._set_active_path) + + + def _load_widgets(self): + from_container = Gtk.Box() + to_container = Gtk.Box() + + from_scroll_vw, \ + self._from_store = self._create_treeview_widget(title="From:") + to_scroll_vw, \ + self._to_store = self._create_treeview_widget(title="To:") + + from_container.add(from_scroll_vw) + to_container.add(to_scroll_vw) + + from_container.set_orientation(1) + to_container.set_orientation(1) + + fchild = from_scroll_vw.get_children()[0] + fchild.connect("drag-data-received", self._on_drag_data_received) + URI_TARGET_TYPE = 80 + uri_target = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE) + targets = [ uri_target ] + action = Gdk.DragAction.COPY + fchild.enable_model_drag_dest(targets, action) + fchild.enable_model_drag_source(0, targets, action) + + self.add(from_container) + self.add(to_container) + + + def _on_drag_data_received(self, widget, drag_context, x, y, data, info, time): + if info == 80: + uri = data.get_uris()[0].split("file://")[1] + self._set_active_path(uri) + + + def _get_active_path(self): + return self._active_path + + def _set_active_path(self, _file): + if os.path.isdir(_file) : + self._from_changes.clear() + self._active_path = _file + for f in os.listdir(_file): + self._from_changes.append(f) + + self._from_changes.sort(key=self._natural_keys) + self._to_changes = self._from_changes + + event_system.emit("update-from") + event_system.emit("update-to") + + def get_from_list(self): + return self._from_changes + + def get_to_list(self): + return self._to_changes + + def set_from_list(self, from_list): + self._from_changes = from_list + + def set_to_list(self, to_list): + self._to_changes = to_list + + def update_from_list(self): + print("Updating From List...") + if self._from_store: + self._from_store.clear() + + for i, change in enumerate(self._from_changes): + self._from_store.insert(i, [change]) + + def update_to_list(self): + print("Updating To List...") + if self._to_store: + self._to_store.clear() + + for i, change in enumerate(self._to_changes): + self._to_store.insert(i, [change]) + + + def reset_to_view(self): + self._to_changes = self._from_changes + event_system.emit("update-to") + + def reset_from_view(self): + self._set_active_path(self._active_path) + + + def _atoi(self, text): + return int(text) if text.isdigit() else text + + def _natural_keys(self, text): + return [ self._atoi(c) for c in re.split('(\d+)',text) ] diff --git a/src/controller/Controller.py b/src/core/controller.py similarity index 71% rename from src/controller/Controller.py rename to src/core/controller.py index 2932db1..448adeb 100644 --- a/src/controller/Controller.py +++ b/src/core/controller.py @@ -1,35 +1,69 @@ # Python imports -import os, sys, threading, time +import os +import sys # lib imports import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk -from gi.repository import GLib # Application imports from mixins import CommonWidgetGeneratorMixin -from . import ChangeView +from .change_view import ChangeView from .widgets import * -def threaded(fn): - def wrapper(*args, **kwargs): - threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() - return wrapper class Controller(Gtk.Box, CommonWidgetGeneratorMixin): - def __init__(self, args): + def __init__(self, args, unknownargs): super(Controller, self).__init__() - # Add header + # # Add header + self.change_view = None + self.copy_window = None + self.store = None + self.combo_box = None + self.action_collection = [] + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + self.show_all() + + if unknownargs: + for arg in unknownargs: + if os.path.isdir(arg): + event_system.emit("set-active-path", (arg,)) + + if args.path and os.path.isdir(args.path): + event_system.emit("set-active-path", (args.path,)) + + + def _setup_styling(self): + self.set_spacing(20) + self.set_margin_top(5) + self.set_margin_bottom(10) + self.set_margin_left(15) + self.set_margin_right(15) + self.set_orientation(1) + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + event_system.subscribe("handle-gui-event", self._handle_gui_event) + + def _load_widgets(self): self.change_view = ChangeView() - action_bar = Gtk.Box() - file_choser = Gtk.FileChooserButton(title="Directory Chooser", action=2) # 2 = SELECT_FOLDER - file_filter = Gtk.FileFilter() + action_bar = Gtk.Box() + + file_choser = Gtk.FileChooserButton(title="Directory Chooser", action=2) # 2 = SELECT_FOLDER + file_filter = Gtk.FileFilter() file_choser.show() - file_choser.set_filename(event_system.USER_HOME) + file_choser.set_filename(USER_HOME) file_filter.add_mime_type("inode/directory") file_choser.add_filter(file_filter) @@ -64,56 +98,19 @@ class Controller(Gtk.Box, CommonWidgetGeneratorMixin): self.copy_window = Gtk.Box() - self.set_spacing(20) - self.set_margin_top(5) - self.set_margin_bottom(10) - self.set_margin_left(15) - self.set_margin_right(15) - self.set_orientation(1) - self.add(file_choser) self.add(action_bar) self.add(self.change_view) self.add(actions_scroll_label) self.add(actions_scroll_view) self.add(run_button) - self.show_all() - - self.gui_event_observer() - self.action_collection = [] - - - @threaded - def gui_event_observer(self): - while True: - time.sleep(event_sleep_time) - event = event_system.consume_gui_event() - if event: - try: - type, target, data = event - if type: - method = getattr(self.__class__, "_handle_gui_event") - GLib.idle_add(method, *(self, type, target, data)) - else: - method = getattr(self.__class__, target) - GLib.idle_add(method, *(self, *data,)) - except Exception as e: - print(repr(e)) def update_dir_path(self, widget): path = widget.get_filename() - event_system.set_active_path(path) + event_system.emit("set-active-path", (path,)) def _handle_gui_event(self, type, target, parameters): - if type == "update-from": - self.change_view.update_from_list() - return - - if type == "update-to": - self.change_view.update_to_list() - return - for i, action in enumerate(self.action_collection): if action == target: if type == "move-up": @@ -150,34 +147,33 @@ class Controller(Gtk.Box, CommonWidgetGeneratorMixin): self.action_collection.append(widget) def _test_all(self, widget=None): - event_system.block_to_update = True - event_system.reset_to_view() + event_system.emit("reset-to-view") for action in self.action_collection: action.run() - event_system.block_to_update = False - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("update-to") def _reset_to_view(self, widget): - event_system.reset_to_view() + event_system.emit("reset-to-view") def _run_all(self, widget): - if not event_system.active_path: + dir = event_system.emit_and_await("get-active-path") + if not dir: print("No active path set. Returning...") return self._test_all() - dir = event_system.active_path - for i, file in enumerate(event_system.from_changes): + to_changes = event_system.emit_and_await("get-to") + for i, file in enumerate(event_system.emit_and_await("get-from")): fPath = f"{dir}/{file}" - tPath = f"{dir}/{event_system.to_changes[i]}" + tPath = f"{dir}/{to_changes[i]}" if fPath != tPath: try: os.rename(fPath, tPath) except Exception as e: print(f"Cant Move: {fPath}\nTo File: {tPath}") - event_system.reset_from_view() + event_system.emit("reset-from-view") def _clean_text(self, text): return text.replace(" ", "") \ diff --git a/src/core/widgets/__init__.py b/src/core/widgets/__init__.py new file mode 100644 index 0000000..9c73bb7 --- /dev/null +++ b/src/core/widgets/__init__.py @@ -0,0 +1,6 @@ +from .case import Case +from .insert import Insert +from .time import Time +from .replace import Replace +from .remove import Remove +from .remove_from_to import RemoveFromTo diff --git a/src/controller/widgets/Case.py b/src/core/widgets/case.py similarity index 73% rename from src/controller/widgets/Case.py rename to src/core/widgets/case.py index 3b263fb..07cc61f 100644 --- a/src/controller/widgets/Case.py +++ b/src/core/widgets/case.py @@ -6,7 +6,10 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from mixins import CommonWidgetGeneratorMixin, CommonActionsMixin +from mixins import CommonWidgetGeneratorMixin +from mixins import CommonActionsMixin + + class Case(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): @@ -27,20 +30,21 @@ class Case(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): new_collection = [] itr = self.combo_box.get_active_iter() type = self.store.get(itr, 0)[0] + to_changes = event_system.emit_and_await("get-to") print(f"Changing Case...") if type == "Title Case": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(name.title()) if type == "UPPER": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(name.upper()) if type == "lower": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(name.lower()) if type == "InVert CaSe --> iNvERT cAsE": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(name.swapcase()) - event_system.to_changes = new_collection - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("set-to", (new_collection,)) + event_system.emit("update-to") diff --git a/src/controller/widgets/Insert.py b/src/core/widgets/insert.py similarity index 83% rename from src/controller/widgets/Insert.py rename to src/core/widgets/insert.py index 7ce660e..1f2f297 100644 --- a/src/controller/widgets/Insert.py +++ b/src/core/widgets/insert.py @@ -7,7 +7,10 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from mixins import CommonWidgetGeneratorMixin, CommonActionsMixin +from mixins import CommonWidgetGeneratorMixin +from mixins import CommonActionsMixin + + class Insert(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): @@ -33,23 +36,24 @@ class Insert(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): insert_str = self.insert_entry.get_text() itr = self.combo_box.get_active_iter() type = self.store.get(itr, 0)[0] + to_changes = event_system.emit_and_await("get-to") print(f"Inserting...") if type == "Start": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(f"{insert_str}{name}") if type == "End": - for name in event_system.to_changes: + for name in to_changes: base, file_extension = self.get_file_parts() new_collection.append(f"{base}{insert_str}{file_extension}") if type == "Position": position = self.spin_button.get_value_as_int() - for name in event_system.to_changes: + for name in to_changes: name = f"{name[:position]}{insert_str}{name[position:]}" new_collection.append(f"{name}") - event_system.to_changes = new_collection - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("set-to", (new_collection,)) + event_system.emit("update-to") def _combo_box_changed(self, widget, eve=None): diff --git a/src/controller/widgets/Remove.py b/src/core/widgets/remove.py similarity index 80% rename from src/controller/widgets/Remove.py rename to src/core/widgets/remove.py index e2649c5..8955309 100644 --- a/src/controller/widgets/Remove.py +++ b/src/core/widgets/remove.py @@ -6,7 +6,10 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from mixins import CommonWidgetGeneratorMixin, CommonActionsMixin +from mixins import CommonWidgetGeneratorMixin +from mixins import CommonActionsMixin + + class Remove(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): @@ -32,23 +35,24 @@ class Remove(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): new_collection = [] itr = self.combo_box.get_active_iter() type = self.store.get(itr, 0)[0] - print(f"To Remove: {from_str}") + to_changes = event_system.emit_and_await("get-to") + print(f"To Remove: {from_str}") if type == "All": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(name.replace(from_str, '')) if type == "Word Start": print("Stub...") if type == "Word End": print("Stub...") if type == "First Instance": - for name in event_system.to_changes: + for name in to_changes: new_collection.append( name.replace(from_str, "", 1) ) if type == "Last Instance": - for name in event_system.to_changes: + for name in to_changes: new_collection.append( self._replace_last(name, from_str, "") ) if type == "RegEx": print("Stub...") - event_system.to_changes = new_collection - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("set-to", (new_collection,)) + event_system.emit("update-to") diff --git a/src/controller/widgets/RemoveFromTo.py b/src/core/widgets/remove_from_to.py similarity index 89% rename from src/controller/widgets/RemoveFromTo.py rename to src/core/widgets/remove_from_to.py index dca3057..d53c3e5 100644 --- a/src/controller/widgets/RemoveFromTo.py +++ b/src/core/widgets/remove_from_to.py @@ -6,7 +6,10 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from mixins import CommonWidgetGeneratorMixin, CommonActionsMixin +from mixins import CommonWidgetGeneratorMixin +from mixins import CommonActionsMixin + + class RemoveFromTo(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): @@ -46,13 +49,14 @@ class RemoveFromTo(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): new_collection = [] itr = self.combo_box.get_active_iter() type = self.store.get(itr, 0)[0] + to_changes = event_system.emit_and_await("get-to") if type == "Using Sub String": fsub = self.entry_from.get_text() tsub = self.entry_to.get_text() print(f"From: {fsub}\nTo: {tsub}") - for name in event_system.to_changes: + for name in to_changes: startIndex = name.index(fsub) + 1 endIndex = name.index(tsub) toRemove = name[startIndex:endIndex] @@ -62,12 +66,12 @@ class RemoveFromTo(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): tsub = self.spin_button_to.get_value_as_int() print(f"From: {fsub}\nTo: {tsub}") - for name in event_system.to_changes: + for name in to_changes: toRemove = name[fsub:tsub] new_collection.append(name.replace(toRemove, '')) - event_system.to_changes = new_collection - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("set-to", (new_collection,)) + event_system.emit("update-to") def _combo_box_changed(self, widget, eve=None): itr = widget.get_active_iter() diff --git a/src/controller/widgets/Replace.py b/src/core/widgets/replace.py similarity index 69% rename from src/controller/widgets/Replace.py rename to src/core/widgets/replace.py index c9ac688..c7377fe 100644 --- a/src/controller/widgets/Replace.py +++ b/src/core/widgets/replace.py @@ -6,7 +6,10 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from mixins import CommonWidgetGeneratorMixin, CommonActionsMixin +from mixins import CommonWidgetGeneratorMixin +from mixins import CommonActionsMixin + + class Replace(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): @@ -28,13 +31,15 @@ class Replace(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): def run(self): - fsub = self.entry_from.get_text() - tsub = self.entry_to.get_text() + fsub = self.entry_from.get_text() + tsub = self.entry_to.get_text() + to_changes = event_system.emit_and_await("get-to") + if fsub and tsub: new_collection = [] print(f"From: {fsub}\nTo: {tsub}") - for name in event_system.to_changes: + for name in to_changes: new_collection.append(name.replace(fsub, tsub)) - event_system.to_changes = new_collection - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("set-to", (new_collection,)) + event_system.emit("update-to") diff --git a/src/controller/widgets/Time.py b/src/core/widgets/time.py similarity index 82% rename from src/controller/widgets/Time.py rename to src/core/widgets/time.py index 08d083b..53049c6 100644 --- a/src/controller/widgets/Time.py +++ b/src/core/widgets/time.py @@ -7,10 +7,13 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports +from mixins import CommonWidgetGeneratorMixin from mixins import CommonActionsMixin -class Time(Gtk.Box, CommonActionsMixin): + + +class Time(Gtk.Box, CommonWidgetGeneratorMixin, CommonActionsMixin): def __init__(self): super(Time, self).__init__() @@ -34,23 +37,24 @@ class Time(Gtk.Box, CommonActionsMixin): insert_str = self.insert_entry.get_text() itr = self.combo_box.get_active_iter() type = self.store.get(itr, 0)[0] + to_changes = event_system.emit_and_await("get-to") print(f"Inserting...") if type == "Start": - for name in event_system.to_changes: + for name in to_changes: new_collection.append(f"{insert_str}{name}") if type == "End": - for name in event_system.to_changes: + for name in to_changes: base, file_extension = self.get_file_parts() new_collection.append(f"{base}{insert_str}{file_extension}") if type == "Position": position = self.spin_button.get_value_as_int() - for name in event_system.to_changes: + for name in to_changes: name = f"{name[:position]}{insert_str}{name[position:]}" new_collection.append(f"{name}") - event_system.to_changes = new_collection - event_system.push_gui_event(["update-to", self, ()]) + event_system.emit("set-to", (new_collection,)) + event_system.emit("update-to") def _combo_box_changed(self, widget, eve=None): diff --git a/src/Window.py b/src/core/window.py similarity index 64% rename from src/Window.py rename to src/core/window.py index 108673c..d022747 100644 --- a/src/Window.py +++ b/src/core/window.py @@ -9,21 +9,20 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from __builtins__ import Builtins -from controller import Controller +from .controller import Controller -class Window(Gtk.Window, Builtins): - """docstring for Main.""" +class Window(Gtk.Window): + """docstring for Window.""" - def __init__(self, args): + def __init__(self, args, unknownargs): super(Window, self).__init__() - self.add(Controller(args)) + self.add(Controller(args, unknownargs)) self.connect("delete-event", Gtk.main_quit) self.set_default_size(850, 600) self.set_title(f"{app_name}") self.set_icon_from_file("/usr/share/bulkr/bulkr.png") self.set_gravity(5) # 5 = CENTER - self.set_position(3) # 4 = CENTER_ALWAYS + self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS self.show_all() diff --git a/src/mixins/CommonActionsMixin.py b/src/mixins/CommonActionsMixin.py index 0755493..0ca53ee 100644 --- a/src/mixins/CommonActionsMixin.py +++ b/src/mixins/CommonActionsMixin.py @@ -40,11 +40,19 @@ class CommonActionsMixin: def delete(self): self.get_parent().destroy() + def _move_up(self, widget): - event_system.push_gui_event(["move-up", self, ()]) + event_system.emit("handle-gui-event", ("move-up", self, ())) def _move_down(self, widget): - event_system.push_gui_event(["move-down", self, ()]) + event_system.emit("handle-gui-event", ("move-down", self, ())) + + def _remove_self(self, widget): + event_system.emit("handle-gui-event", ("delete", self, ())) + + def _do_run(self, widget): + event_system.emit("handle-gui-event", ("run", self, ())) + def _has_method(self, obj, name): ''' Checks if a given method exists. ''' @@ -59,12 +67,3 @@ class CommonActionsMixin: reversed = string[::-1] replaced = reversed.replace(find[::-1], replace[::-1], 1) return replaced[::-1] - - - - - def _remove_self(self, widget): - event_system.push_gui_event(["delete", self, ()]) - - def _do_run(self, widget): - event_system.push_gui_event(["run", self, ()]) diff --git a/src/mixins/CommonWidgetGeneratorMixin.py b/src/mixins/CommonWidgetGeneratorMixin.py index 80d8710..756b764 100644 --- a/src/mixins/CommonWidgetGeneratorMixin.py +++ b/src/mixins/CommonWidgetGeneratorMixin.py @@ -1,5 +1,4 @@ # Python imports -import pathlib # lib imports import gi @@ -16,7 +15,7 @@ class CommonWidgetGeneratorMixin: spin_button.set_wrap(True) spin_button.set_digits(0) spin_button.set_increments(1.0, 1.0) - spin_button.set_range(1, 1000000) + spin_button.set_range(0, 1000000) spin_button.set_sensitive(False) return spin_button diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..a8e5edd --- /dev/null +++ b/src/utils/__init__.py @@ -0,0 +1,3 @@ +""" + Utils module +""" diff --git a/src/utils/event_system.py b/src/utils/event_system.py new file mode 100644 index 0000000..f8f9a7c --- /dev/null +++ b/src/utils/event_system.py @@ -0,0 +1,42 @@ +# Python imports +from collections import defaultdict + +# Lib imports + +# Application imports + + + + +class EventSystem: + """ Create event system. """ + + def __init__(self): + self.subscribers = defaultdict(list) + + + def subscribe(self, event_type, fn): + self.subscribers[event_type].append(fn) + + def emit(self, event_type, data = None): + if event_type in self.subscribers: + for fn in self.subscribers[event_type]: + if data: + if hasattr(data, '__iter__') and not type(data) is str: + fn(*data) + else: + fn(data) + else: + fn() + + # NOTE: Should be used when signal has only one listener and vis-a-vis + def emit_and_await(self, event_type, data = None): + if event_type in self.subscribers: + for fn in self.subscribers[event_type]: + if data: + if hasattr(data, '__iter__') and not type(data) is str: + return fn(*data) + else: + return fn(data) + else: + return fn()