# Python imports import os, gc, threading, time # Lib imports import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib # Application imports from .mixins.exception_hook_mixin import ExceptionHookMixin from .mixins.ui_mixin import UIMixin from .signals.ipc_signals_mixin import IPCSignalsMixin from .signals.keyboard_signals_mixin import KeyboardSignalsMixin from .controller_data import Controller_Data def threaded(fn): def wrapper(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() return wrapper class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMixin, Controller_Data): """ Controller coordinates the mixins and is somewhat the root hub of it all. """ def __init__(self, args, unknownargs, _settings): self.setup_controller_data(_settings) self.window.show() self.generate_windows(self.fm_controller_data) self.plugins.launch_plugins() if debug: self.window.set_interactive_debugging(True) if not trace_debug: self.gui_event_observer() if unknownargs: for arg in unknownargs: if os.path.isdir(arg): message = f"FILE|{arg}" event_system.send_ipc_message(message) if args.new_tab and os.path.isdir(args.new_tab): message = f"FILE|{args.new_tab}" event_system.send_ipc_message(message) def tear_down(self, widget=None, eve=None): event_system.send_ipc_message("close server") self.fm_controller.save_state() time.sleep(event_sleep_time) Gtk.main_quit() @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_and_set_message") 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 handle_gui_event_and_set_message(self, type, target, parameters): method = getattr(self.__class__, f"{target}") data = method(*(self, *parameters)) self.plugins.send_message_to_plugin(type, data) def save_load_session(self, action="save_session"): wid, tid = self.fm_controller.get_active_wid_and_tid() tab = self.get_fm_window(wid).get_tab_by_id(tid) save_load_dialog = self.builder.get_object("save_load_dialog") if action == "save_session": self.fm_controller.save_state() return elif action == "save_session_as": save_load_dialog.set_action(Gtk.FileChooserAction.SAVE) elif action == "load_session": save_load_dialog.set_action(Gtk.FileChooserAction.OPEN) else: raise Exception(f"Unknown action given: {action}") save_load_dialog.set_current_folder(tab.get_current_directory()) save_load_dialog.set_current_name("session.json") response = save_load_dialog.run() if response == Gtk.ResponseType.OK: if action == "save_session_as": path = f"{save_load_dialog.get_current_folder()}/{save_load_dialog.get_current_name()}" self.fm_controller.save_state(path) elif action == "load_session": path = f"{save_load_dialog.get_file().get_path()}" session_json = self.fm_controller.load_state(path) self.load_session(session_json) if (response == Gtk.ResponseType.CANCEL) or (response == Gtk.ResponseType.DELETE_EVENT): pass save_load_dialog.hide() def load_session(self, session_json): if debug: print(f"Session Data: {session_json}") self.ctrl_down = False self.shift_down = False self.alt_down = False for notebook in self.notebooks: self.clear_children(notebook) self.fm_controller.unload_tabs_and_windows() self.generate_windows(session_json) gc.collect() def do_action_from_menu_controls(self, widget, event_button): action = widget.get_name() self.hide_context_menu() self.hide_new_file_menu() self.hide_edit_file_menu() if action == "open": self.open_files() if action == "open_with": self.show_appchooser_menu() if action == "execute": self.execute_files() if action == "execute_in_terminal": self.execute_files(in_terminal=True) if action == "rename": self.rename_files() if action == "cut": self.cut_files() if action == "copy": self.copy_files() if action == "paste": self.paste_files() if action == "archive": self.show_archiver_dialogue() if action == "delete": self.delete_files() if action == "trash": self.trash_files() if action == "go_to_trash": self.path_entry.set_text(self.trash_files_path) if action == "restore_from_trash": self.restore_trash_files() if action == "empty_trash": self.empty_trash() if action == "create": self.show_new_file_menu() if action in ["save_session", "save_session_as", "load_session"]: self.save_load_session(action) def go_home(self, widget=None, eve=None): self.builder.get_object("go_home").released() def refresh_tab(self, widget=None, eve=None): self.builder.get_object("refresh_tab").released() def go_up(self, widget=None, eve=None): self.builder.get_object("go_up").released() def grab_focus_path_entry(self, widget=None, eve=None): self.builder.get_object("path_entry").grab_focus() def tggl_top_main_menubar(self, widget=None, eve=None): top_main_menubar = self.builder.get_object("top_main_menubar") top_main_menubar.hide() if top_main_menubar.is_visible() else top_main_menubar.show() def open_terminal(self, widget=None, eve=None): wid, tid = self.fm_controller.get_active_wid_and_tid() tab = self.get_fm_window(wid).get_tab_by_id(tid) dir = tab.get_current_directory() tab.execute(f"{tab.terminal_app}", dir)