From 9eeb24e19a68f37c2e48b178a1ed634c317ee4be Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Tue, 6 Dec 2022 23:36:10 -0600 Subject: [PATCH] WIP separating fs actions --- plugins/archiver/plugin.py | 2 +- plugins/file_properties/plugin.py | 4 +- plugins/movie_tv_info/plugin.py | 4 +- plugins/trasher/plugin.py | 8 +- plugins/vod_thumbnailer/plugin.py | 6 +- .../SolarFM/solarfm/core/controller.py | 39 +-- .../SolarFM/solarfm/core/controller_data.py | 7 +- .../solarfm/core/fs_actions/__init__.py | 3 + .../solarfm/core/fs_actions/crud_mixin.py | 70 +++++ .../core/fs_actions/file_system_actions.py | 95 ++++++ .../solarfm/core/fs_actions/handler_mixin.py | 167 +++++++++++ .../signals/file_action_signals_mixin.py | 274 +----------------- .../mixins/signals/keyboard_signals_mixin.py | 6 +- .../solarfm/core/mixins/ui/window_mixin.py | 15 +- 14 files changed, 389 insertions(+), 311 deletions(-) create mode 100644 src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/__init__.py create mode 100644 src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/crud_mixin.py create mode 100644 src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/file_system_actions.py create mode 100644 src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/handler_mixin.py diff --git a/plugins/archiver/plugin.py b/plugins/archiver/plugin.py index 6b9b6b7..2ab92cd 100644 --- a/plugins/archiver/plugin.py +++ b/plugins/archiver/plugin.py @@ -113,7 +113,7 @@ class Plugin(PluginBase): self._archiver_dialogue.hide() def archive_files(self, save_target, state): - paths = [shlex.quote(p) for p in state.selected_files] + paths = [shlex.quote(p) for p in state.uris] sItr, eItr = self._arc_command_buffer.get_bounds() pre_command = self._arc_command_buffer.get_text(sItr, eItr, False) diff --git a/plugins/file_properties/plugin.py b/plugins/file_properties/plugin.py index bb1be45..e29a3dc 100644 --- a/plugins/file_properties/plugin.py +++ b/plugins/file_properties/plugin.py @@ -123,8 +123,8 @@ class Plugin(PluginBase): GLib.idle_add(self._process_changes, (state)) def _process_changes(self, state): - if len(state.selected_files) == 1: - uri = state.selected_files[0] + if len(state.uris) == 1: + uri = state.uris[0] path = state.tab.get_current_directory() diff --git a/plugins/movie_tv_info/plugin.py b/plugins/movie_tv_info/plugin.py index 0856437..6f3f4c4 100644 --- a/plugins/movie_tv_info/plugin.py +++ b/plugins/movie_tv_info/plugin.py @@ -95,7 +95,7 @@ class Plugin(PluginBase): def _process_changes(self, state): self._fm_state = None - if len(state.selected_files) == 1: + if len(state.uris) == 1: self._fm_state = state self._set_ui_data() response = self._thumbnailer_dialog.run() @@ -115,7 +115,7 @@ class Plugin(PluginBase): print(video_data["videos"]) if not keys in ("", None) and "videos" in keys else ... def get_video_data(self): - uri = self._fm_state.selected_files[0] + uri = self._fm_state.uris[0] path = self._fm_state.tab.get_current_directory() parts = uri.split("/") _title = parts[ len(parts) - 1 ] diff --git a/plugins/trasher/plugin.py b/plugins/trasher/plugin.py index 640bd71..2c6e8cd 100644 --- a/plugins/trasher/plugin.py +++ b/plugins/trasher/plugin.py @@ -99,9 +99,9 @@ class Plugin(PluginBase): def delete_files(self, widget = None, eve = None): self._event_system.emit("get_current_state") state = self._fm_state - uris = state.selected_files + uris = state.uris response = None - + state.message_dialog.format_secondary_text(f"Do you really want to delete the {len(uris)} file(s)?") for uri in uris: file = Gio.File.new_for_path(uri) @@ -122,13 +122,13 @@ class Plugin(PluginBase): def trash_files(self, widget = None, eve = None, verbocity = False): self._event_system.emit("get_current_state") state = self._fm_state - for uri in state.selected_files: + for uri in state.uris: self.trashman.trash(uri, verbocity) def restore_trash_files(self, widget = None, eve = None, verbocity = False): self._event_system.emit("get_current_state") state = self._fm_state - for uri in state.selected_files: + for uri in state.uris: self.trashman.restore(filename=uri.split("/")[-1], verbose = verbocity) def empty_trash(self, widget = None, eve = None, verbocity = False): diff --git a/plugins/vod_thumbnailer/plugin.py b/plugins/vod_thumbnailer/plugin.py index 9e02c14..ae30515 100644 --- a/plugins/vod_thumbnailer/plugin.py +++ b/plugins/vod_thumbnailer/plugin.py @@ -98,8 +98,8 @@ class Plugin(PluginBase): def _process_changes(self, state): self._fm_state = None - if len(state.selected_files) == 1: - if state.selected_files[0].lower().endswith(state.tab.fvideos): + if len(state.uris) == 1: + if state.uris[0].lower().endswith(state.tab.fvideos): self._fm_state = state self._set_ui_data() response = self._thumbnailer_dialog.run() @@ -132,7 +132,7 @@ class Plugin(PluginBase): def _set_ui_data(self): - uri = self._fm_state.selected_files[0] + uri = self._fm_state.uris[0] path = self._fm_state.tab.get_current_directory() parts = uri.split("/") diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py index bd8db67..7d1462c 100644 --- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py @@ -10,6 +10,7 @@ from gi.repository import GLib # Application imports from .controller_data import Controller_Data +from .fs_actions.file_system_actions import FileSystemActions from .mixins.signals_mixins import SignalsMixins from .ui.dialogs.about_widget import AboutWidget @@ -57,17 +58,16 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): ... def _setup_signals(self): - ... + FileSystemActions() def _subscribe_to_events(self): event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) + event_system.subscribe("generate_windows", self.generate_windows) event_system.subscribe("clear_notebooks", self.clear_notebooks) event_system.subscribe("get_current_state", self.get_current_state) event_system.subscribe("go_to_path", self.go_to_path) event_system.subscribe("do_action_from_menu_controls", self.do_action_from_menu_controls) - # NOTE: Needs to be moved (probably just to file actions class) after reducing mixins usage - event_system.subscribe("open_with_files", self.open_with_files) - event_system.subscribe("generate_windows", self.generate_windows) + event_system.subscribe("set_clipboard_data", self.set_clipboard_data) # NOTE: Really we will move these to the UI/(New) Window 'base' controller # after we're done cleaning and refactoring to use fewer mixins. @@ -96,36 +96,39 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): Gtk.main_quit() - def do_action_from_menu_controls(self, widget, eve = None): - if not isinstance(widget, str): - action = widget.get_name() + def do_action_from_menu_controls(self, _action=None, eve=None): + if not _action: + return + + if not isinstance(_action, str): + action = _action.get_name() else: - action = widget + action = _action event_system.emit("hide_context_menu") event_system.emit("hide_new_file_menu") event_system.emit("hide_rename_file_menu") if action == "open": - self.open_files() + event_system.emit("open_files") if action == "open_with": event_system.emit("show_appchooser_menu") if action == "execute": - self.execute_files() + event_system.emit("execute_files") if action == "execute_in_terminal": - self.execute_files(in_terminal=True) + event_system.emit("execute_files", (True,)) if action == "rename": - self.rename_files() + event_system.emit("rename_files") if action == "cut": - self.cut_files() + event_system.emit("cut_files") if action == "copy": - self.copy_files() + event_system.emit("copy_files") if action == "copy_name": - self.copy_name() + event_system.emit("copy_name") if action == "paste": - self.paste_files() + event_system.emit("paste_files") if action == "create": - self.create_files() + event_system.emit("create_files") if action in ["save_session", "save_session_as", "load_session"]: event_system.emit("save_load_session", (action)) @@ -166,5 +169,5 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): tab = self.get_fm_window(wid).get_tab_by_id(tid) tab.execute([f"{tab.terminal_app}"], start_dir=tab.get_current_directory()) - def go_to_path(self, path): + def go_to_path(self, path: str): self.path_entry.set_text(path) diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py index 84c0552..3565449 100644 --- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py @@ -27,6 +27,7 @@ class State: tab: type = None icon_grid: gi.overrides.Gtk.IconView = None store: gi.overrides.Gtk.ListStore = None + uris: [] = None selected_files: [] = None to_copy_files: [] = None to_cut_files: [] = None @@ -100,11 +101,13 @@ class Controller_Data: state.tab = self.get_fm_window(state.wid).get_tab_by_id(state.tid) state.icon_grid = self.builder.get_object(f"{state.wid}|{state.tid}|icon_grid") state.store = state.icon_grid.get_model() - state.message_dialog = self.message_dialog + state.message_dialog = self.message_dialog selected_files = state.icon_grid.get_selected_items() if selected_files: - state.selected_files = self.format_to_uris(state.store, state.wid, state.tid, selected_files, True) + state.uris = self.format_to_uris(state.store, state.wid, state.tid, selected_files, True) + + state.selected_files = self.selected_files # if self.to_copy_files: # state.to_copy_files = self.format_to_uris(state.store, state.wid, state.tid, self.to_copy_files, True) diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/__init__.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/__init__.py new file mode 100644 index 0000000..8e9c30e --- /dev/null +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/__init__.py @@ -0,0 +1,3 @@ +""" + FS Actions Module +""" diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/crud_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/crud_mixin.py new file mode 100644 index 0000000..a9cf954 --- /dev/null +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/crud_mixin.py @@ -0,0 +1,70 @@ +# Python imports + +# Lib imports + +# Application imports + + + + +class CRUDMixin: + """docstring for CRUDMixin""" + + def move_files(self, files, target): + self.handle_files(files, "move", target) + + def paste_files(self): + state = event_system.emit_and_await("get_current_state") + target = f"{state.tab.get_current_directory()}" + + if self._to_copy_files: + self.handle_files(self._to_copy_files, "copy", target) + elif self._to_cut_files: + self.handle_files(self._to_cut_files, "move", target) + + def create_files(self): + fname_field = self._builder.get_object("new_fname_field") + cancel_creation = event_system.emit_and_await("show_new_file_menu", fname_field) + + if cancel_creation: + event_system.emit("hide_new_file_menu") + return + + file_name = fname_field.get_text().strip() + type = self._builder.get_object("new_file_toggle_type").get_state() + state = event_system.emit_and_await("get_current_state") + target = f"{state.tab.get_current_directory()}" + + if file_name: + path = f"{target}/{file_name}" + + if type == True: # Create File + self.handle_files([path], "create_file") + else: # Create Folder + self.handle_files([path], "create_dir") + + event_system.emit("hide_new_file_menu") + + def rename_files(self): + rename_label = self._builder.get_object("file_to_rename_label") + rename_input = self._builder.get_object("rename_fname") + state = event_system.emit_and_await("get_current_state") + + for uri in state.uris: + entry = uri.split("/")[-1] + rename_label.set_label(entry) + rename_input.set_text(entry) + + response = event_system.emit_and_await("show_rename_file_menu", rename_input) + if response == "skip_edit": + continue + if response == "cancel_edit": + break + + rname_to = rename_input.get_text().strip() + if rname_to: + target = f"{state.tab.get_current_directory()}/{rname_to}" + self.handle_files([uri], "rename", target) + + event_system.emit("hide_rename_file_menu") + event_system.emit_and_await("get_selected_files").clear() diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/file_system_actions.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/file_system_actions.py new file mode 100644 index 0000000..80002ca --- /dev/null +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/file_system_actions.py @@ -0,0 +1,95 @@ +# Python imports +import shlex + +# Lib imports + +# Application imports +from .crud_mixin import CRUDMixin +from .handler_mixin import HandlerMixin + + + + +class FileSystemActions(HandlerMixin, CRUDMixin): + """docstring for FileSystemActions""" + + def __init__(self): + super(FileSystemActions, self).__init__() + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + self._selected_files = [] + self._to_copy_files = [] + self._to_cut_files = [] + + self._builder = settings.get_builder() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + event_system.subscribe("set_selected_files", self.set_selected_files) + event_system.subscribe("get_selected_files", self.get_selected_files) + + event_system.subscribe("open_files", self.open_files) + event_system.subscribe("open_with_files", self.open_with_files) + event_system.subscribe("execute_files", self.execute_files) + + event_system.subscribe("cut_files", self.cut_files) + event_system.subscribe("copy_files", self.copy_files) + event_system.subscribe("paste_files", self.paste_files) + event_system.subscribe("move_files", self.move_files) + event_system.subscribe("copy_name", self.copy_name) + event_system.subscribe("create_files", self.create_files) + event_system.subscribe("rename_files", self.rename_files) + + def _load_widgets(self): + ... + + + def set_selected_files(self, selected_files: []): + self._selected_files = selected_files + + def get_selected_files(self): + return self._selected_files + + + def cut_files(self): + self._to_copy_files.clear() + state = event_system.emit_and_await("get_current_state") + self._to_cut_files = state.uris + + def copy_files(self): + self._to_cut_files.clear() + state = event_system.emit_and_await("get_current_state") + self._to_copy_files = state.uris + + def copy_name(self): + state = event_system.emit_and_await("get_current_state") + if len(state.uris) == 1: + file_name = state.uris[0].split("/")[-1] + event_system.emit("set_clipboard_data", (file_name,)) + + + def open_files(self): + state = event_system.emit_and_await("get_current_state") + for file in state.uris: + state.tab.open_file_locally(file) + + def open_with_files(self, app_info): + state = event_system.emit_and_await("get_current_state") + state.tab.app_chooser_exec(app_info, state.uris) + + def execute_files(self, in_terminal=False): + state = event_system.emit_and_await("get_current_state") + current_dir = state.tab.get_current_directory() + command = None + for path in state.uris: + command = f"{shlex.quote(path)}" if not in_terminal else f"{state.tab.terminal_app} -e {shlex.quote(path)}" + state.tab.execute(shlex.split(command), start_dir=state.tab.get_current_directory()) diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/handler_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/handler_mixin.py new file mode 100644 index 0000000..8053e42 --- /dev/null +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/fs_actions/handler_mixin.py @@ -0,0 +1,167 @@ +# Python imports +import os + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import GObject +from gi.repository import Gio + +# Application imports +from ..ui.io_widget import IOWidget + + + + +class HandlerMixin: + """docstring for HandlerMixin""" + + # NOTE: Gtk recommends using fail flow than pre check which is more + # race condition proof. They're right; but, they can't even delete + # directories properly. So... f**k them. I'll do it my way. + def handle_files(self, paths, action, _target_path=None): + target = None + _file = None + response = None + overwrite_all = False + rename_auto_all = False + + for path in paths: + try: + if "file://" in path: + path = path.split("file://")[1] + + file = Gio.File.new_for_path(path) + if _target_path: + if file.get_parent().get_path() == _target_path: + raise Exception("Parent dir of target and file locations are the same! Won't copy or move!") + + if os.path.isdir(_target_path): + info = file.query_info("standard::display-name", 0, cancellable=None) + _target = f"{_target_path}/{info.get_display_name()}" + _file = Gio.File.new_for_path(_target) + else: + _file = Gio.File.new_for_path(_target_path) + else: + _file = Gio.File.new_for_path(path) + + + if _file.query_exists(): + if not overwrite_all and not rename_auto_all: + event_system.emit("setup_exists_data", (file, _file)) + response = event_system.emit_and_await("show_exists_page") + + if response == "overwrite_all": + overwrite_all = True + if response == "rename_auto_all": + rename_auto_all = True + + if response == "rename": + base_path = _file.get_parent().get_path() + new_name = self._builder.get_object("exists_file_field").get_text().strip() + rfPath = f"{base_path}/{new_name}" + _file = Gio.File.new_for_path(rfPath) + + if response == "rename_auto" or rename_auto_all: + _file = self.rename_proc(_file) + + if response == "overwrite" or overwrite_all: + type = _file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE) + + if type == Gio.FileType.DIRECTORY: + # wid, tid = self.fm_controller.get_active_wid_and_tid() + # tab = self.get_fm_window(wid).get_tab_by_id(tid) + # tab.delete_file( _file.get_path() ) + state = event_system.emit_and_await("get_current_state") + state.tab.delete_file( _file.get_path() ) + else: + _file.delete(cancellable=None) + + if response == "skip": + continue + if response == "skip_all": + break + + if _target_path: + target = _file + else: + file = _file + + + if action == "create_file": + file.create(flags=Gio.FileCreateFlags.NONE, cancellable=None) + continue + if action == "create_dir": + file.make_directory(cancellable=None) + continue + + type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE) + if type == Gio.FileType.DIRECTORY: + # wid, tid = self.fm_controller.get_active_wid_and_tid() + # tab = self.get_fm_window(wid).get_tab_by_id(tid) + state = event_system.emit_and_await("get_current_state") + tab = state.tab + fPath = file.get_path() + tPath = target.get_path() + state = True + + if action == "copy": + tab.copy_file(fPath, tPath) + if action == "move" or action == "rename": + tab.move_file(fPath, tPath) + else: + io_widget = IOWidget(action, file) + + if action == "copy": + file.copy_async(destination=target, + flags=Gio.FileCopyFlags.BACKUP, + io_priority=98, + cancellable=io_widget.cancle_eve, + progress_callback=io_widget.update_progress, + callback=io_widget.finish_callback) + + self._builder.get_object("io_list").add(io_widget) + if action == "move" or action == "rename": + file.move_async(destination=target, + flags=Gio.FileCopyFlags.BACKUP, + io_priority=98, + cancellable=io_widget.cancle_eve, + progress_callback=None, + # NOTE: progress_callback here causes seg fault when set + callback=io_widget.finish_callback) + + self._builder.get_object("io_list").add(io_widget) + + except GObject.GError as e: + raise OSError(e) + + self._builder.get_object("exists_file_rename_bttn").set_sensitive(False) + + def rename_proc(self, gio_file): + full_path = gio_file.get_path() + base_path = gio_file.get_parent().get_path() + file_name = os.path.splitext(gio_file.get_basename())[0] + extension = os.path.splitext(full_path)[-1] + target = Gio.File.new_for_path(full_path) + start = "-copy" + + if settings.is_debug(): + logger.debug(f"Path: {full_path}") + logger.debug(f"Base Path: {base_path}") + logger.debug(f'Name: {file_name}') + logger.debug(f"Extension: {extension}") + + i = 2 + while target.query_exists(): + try: + value = file_name[(file_name.find(start)+len(start)):] + int(value) + file_name = file_name.split(start)[0] + except Exception as e: + pass + + target = Gio.File.new_for_path(f"{base_path}/{file_name}-copy{i}{extension}") + i += 1 + + return target diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/file_action_signals_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/file_action_signals_mixin.py index 5cb0de2..9d0c06a 100644 --- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/file_action_signals_mixin.py +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/file_action_signals_mixin.py @@ -1,40 +1,21 @@ # Python imports -import os import time -import shlex # Lib imports import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk -from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio # Application imports -from ...ui.io_widget import IOWidget class FileActionSignalsMixin: """docstring for FileActionSignalsMixin""" - def get_dir_size(self, sdir): - """Get the size of a directory. Based on code found online.""" - size = os.path.getsize(sdir) - - for item in os.listdir(sdir): - item = os.path.join(sdir, item) - - if os.path.isfile(item): - size = size + os.path.getsize(item) - elif os.path.isdir(item): - size = size + self.get_dir_size(item) - - return size - - def set_file_watcher(self, tab): if tab.get_dir_watcher(): watcher = tab.get_dir_watcher() @@ -120,256 +101,5 @@ class FileActionSignalsMixin: icon_grid.select_path(path) items = icon_grid.get_selected_items() - if len(items) == 1: - icon_grid.scroll_to_path(items[-1], True, 0.5, 0.5) - - - def open_files(self): - state = self.get_current_state() - uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True) - - for file in uris: - state.tab.open_file_locally(file) - - def open_with_files(self, app_info): - state = self.get_current_state() - uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files) - state.tab.app_chooser_exec(app_info, uris) - - def execute_files(self, in_terminal=False): - state = self.get_current_state() - paths = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True) - current_dir = state.tab.get_current_directory() - command = None - for path in paths: - command = f"{shlex.quote(path)}" if not in_terminal else f"{state.tab.terminal_app} -e {shlex.quote(path)}" - state.tab.execute(shlex.split(command), start_dir=state.tab.get_current_directory()) - - def rename_files(self): - rename_label = self.builder.get_object("file_to_rename_label") - rename_input = self.builder.get_object("rename_fname") - state = self.get_current_state() - uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True) - - for uri in uris: - entry = uri.split("/")[-1] - rename_label.set_label(entry) - rename_input.set_text(entry) - - response = event_system.emit_and_await("show_rename_file_menu", rename_input) - if response == "skip_edit": - continue - if response == "cancel_edit": - break - - rname_to = rename_input.get_text().strip() - if rname_to: - target = f"{state.tab.get_current_directory()}/{rname_to}" - self.handle_files([uri], "rename", target) - - event_system.emit("hide_rename_file_menu") - self.selected_files.clear() - - def cut_files(self): - self.to_copy_files.clear() - state = self.get_current_state() - uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True) - self.to_cut_files = uris - - def copy_name(self): - state = self.get_current_state() - uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True) - if len(uris) == 1: - file_name = uris[0].split("/")[-1] - self.set_clipboard_data(file_name) - - def copy_files(self): - self.to_cut_files.clear() - state = self.get_current_state() - uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True) - self.to_copy_files = uris - - def paste_files(self): - wid, tid = self.fm_controller.get_active_wid_and_tid() - tab = self.get_fm_window(wid).get_tab_by_id(tid) - target = f"{tab.get_current_directory()}" - - if self.to_copy_files: - self.handle_files(self.to_copy_files, "copy", target) - elif self.to_cut_files: - self.handle_files(self.to_cut_files, "move", target) - - def create_files(self): - fname_field = self.builder.get_object("new_fname_field") - cancel_creation = event_system.emit_and_await("show_new_file_menu", fname_field) - - if cancel_creation: - event_system.emit("hide_new_file_menu") - return - - file_name = fname_field.get_text().strip() - type = self.builder.get_object("new_file_toggle_type").get_state() - - wid, tid = self.fm_controller.get_active_wid_and_tid() - tab = self.get_fm_window(wid).get_tab_by_id(tid) - target = f"{tab.get_current_directory()}" - - if file_name: - path = f"{target}/{file_name}" - - if type == True: # Create File - self.handle_files([path], "create_file") - else: # Create Folder - self.handle_files([path], "create_dir") - - event_system.emit("hide_new_file_menu") - - - def move_files(self, files, target): - self.handle_files(files, "move", target) - - - # NOTE: Gtk recommends using fail flow than pre check which is more - # race condition proof. They're right; but, they can't even delete - # directories properly. So... f**k them. I'll do it my way. - def handle_files(self, paths, action, _target_path=None): - target = None - _file = None - response = None - overwrite_all = False - rename_auto_all = False - - for path in paths: - try: - if "file://" in path: - path = path.split("file://")[1] - - file = Gio.File.new_for_path(path) - if _target_path: - if file.get_parent().get_path() == _target_path: - raise Exception("Parent dir of target and file locations are the same! Won't copy or move!") - - if os.path.isdir(_target_path): - info = file.query_info("standard::display-name", 0, cancellable=None) - _target = f"{_target_path}/{info.get_display_name()}" - _file = Gio.File.new_for_path(_target) - else: - _file = Gio.File.new_for_path(_target_path) - else: - _file = Gio.File.new_for_path(path) - - - if _file.query_exists(): - if not overwrite_all and not rename_auto_all: - event_system.emit("setup_exists_data", (file, _file)) - response = event_system.emit_and_await("show_exists_page") - - if response == "overwrite_all": - overwrite_all = True - if response == "rename_auto_all": - rename_auto_all = True - - if response == "rename": - base_path = _file.get_parent().get_path() - new_name = self.builder.get_object("exists_file_field").get_text().strip() - rfPath = f"{base_path}/{new_name}" - _file = Gio.File.new_for_path(rfPath) - - if response == "rename_auto" or rename_auto_all: - _file = self.rename_proc(_file) - - if response == "overwrite" or overwrite_all: - type = _file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE) - - if type == Gio.FileType.DIRECTORY: - wid, tid = self.fm_controller.get_active_wid_and_tid() - tab = self.get_fm_window(wid).get_tab_by_id(tid) - tab.delete_file( _file.get_path() ) - else: - _file.delete(cancellable=None) - - if response == "skip": - continue - if response == "skip_all": - break - - if _target_path: - target = _file - else: - file = _file - - - if action == "create_file": - file.create(flags=Gio.FileCreateFlags.NONE, cancellable=None) - continue - if action == "create_dir": - file.make_directory(cancellable=None) - continue - - type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE) - if type == Gio.FileType.DIRECTORY: - wid, tid = self.fm_controller.get_active_wid_and_tid() - tab = self.get_fm_window(wid).get_tab_by_id(tid) - fPath = file.get_path() - tPath = target.get_path() - state = True - - if action == "copy": - tab.copy_file(fPath, tPath) - if action == "move" or action == "rename": - tab.move_file(fPath, tPath) - else: - io_widget = IOWidget(action, file) - - if action == "copy": - file.copy_async(destination=target, - flags=Gio.FileCopyFlags.BACKUP, - io_priority=98, - cancellable=io_widget.cancle_eve, - progress_callback=io_widget.update_progress, - callback=io_widget.finish_callback) - - self.builder.get_object("io_list").add(io_widget) - if action == "move" or action == "rename": - file.move_async(destination=target, - flags=Gio.FileCopyFlags.BACKUP, - io_priority=98, - cancellable=io_widget.cancle_eve, - progress_callback=None, - # NOTE: progress_callback here causes seg fault when set - callback=io_widget.finish_callback) - - self.builder.get_object("io_list").add(io_widget) - - except GObject.GError as e: - raise OSError(e) - - self.builder.get_object("exists_file_rename_bttn").set_sensitive(False) - - def rename_proc(self, gio_file): - full_path = gio_file.get_path() - base_path = gio_file.get_parent().get_path() - file_name = os.path.splitext(gio_file.get_basename())[0] - extension = os.path.splitext(full_path)[-1] - target = Gio.File.new_for_path(full_path) - start = "-copy" - - if settings.is_debug(): - logger.debug(f"Path: {full_path}") - logger.debug(f"Base Path: {base_path}") - logger.debug(f'Name: {file_name}') - logger.debug(f"Extension: {extension}") - - i = 2 - while target.query_exists(): - try: - value = file_name[(file_name.find(start)+len(start)):] - int(value) - file_name = file_name.split(start)[0] - except Exception as e: - pass - - target = Gio.File.new_for_path(f"{base_path}/{file_name}-copy{i}{extension}") - i += 1 - - return target + if len(items) > 0: + icon_grid.scroll_to_path(items[0], False, 0.5, 0.5) diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/keyboard_signals_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/keyboard_signals_mixin.py index 9f8222c..930a994 100644 --- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/keyboard_signals_mixin.py +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/signals/keyboard_signals_mixin.py @@ -50,7 +50,11 @@ class KeyboardSignalsMixin: if mapping: try: # See if in filemanager scope - getattr(self, mapping)() + try: + getattr(self, mapping)() + except Exception as e: + event_system.emit(mapping) + return True except Exception: # Must be plugins scope or we forgot to add method to file manager scope diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/window_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/window_mixin.py index 5c040c7..4554424 100644 --- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/window_mixin.py +++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/window_mixin.py @@ -165,12 +165,14 @@ class WindowMixin(TabMixin): if size == 1: # NOTE: If already in selection, likely dnd else not so wont readd - if items[0] in self.selected_files: + # if items[0] in self.selected_files: + if items[0] in event_system.emit_and_await("get_selected_files"): self.dnd_left_primed += 1 # NOTE: If in selection but trying to just select an already selected item. if self.dnd_left_primed > 1: self.dnd_left_primed = 0 - self.selected_files.clear() + event_system.emit_and_await("get_selected_files").clear() + # self.selected_files.clear() # NOTE: Likely trying dnd, just readd to selection the former set. # Prevents losing highlighting of grid selected. @@ -178,10 +180,11 @@ class WindowMixin(TabMixin): icons_grid.select_path(path) if size > 0: - self.selected_files = icons_grid.get_selected_items() + # self.selected_files = icons_grid.get_selected_items() + event_system.emit("set_selected_files", (icons_grid.get_selected_items(),)) else: self.dnd_left_primed = 0 - self.selected_files.clear() + event_system.emit_and_await("get_selected_files").clear() def grid_icon_single_click(self, icons_grid, eve): try: @@ -228,7 +231,7 @@ class WindowMixin(TabMixin): state.tab.set_path(file) self.update_tab(tab_label, state.tab, state.store, state.wid, state.tid) else: - self.open_files() + event_system.emit("open_files") except WindowException as e: traceback.print_exc() self.display_message(settings.get_error_color(), f"{repr(e)}") @@ -282,7 +285,7 @@ class WindowMixin(TabMixin): from_uri = '/'.join(uris[0].replace("file://", "").split("/")[:-1]) if from_uri != dest: - self.move_files(uris, dest) + event_system.emit("move_files", (uris, dest)) def create_new_tab_notebook(self, widget=None, wid=None, path=None):