From 4b69622cc667f521f41cceb8274b9ee9c3da382e Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 5 Mar 2023 15:42:11 -0600 Subject: [PATCH] WIP implimentig new files widget attempt 2; keybindings fixed prior commits --- .../solarfm-0.0.1/solarfm/core/controller.py | 9 +- .../solarfm/core/controller_data.py | 19 +- .../solarfm/core/mixins/ui/window_mixin.py | 47 ---- .../solarfm-0.0.1/solarfm/core/ui_mixin.py | 69 +++++- .../core/widgets/dialogs/save_load_widget.py | 2 +- .../core/widgets/files_view/__init__.py | 3 + .../core/widgets/files_view/files_widget.py | 71 ++++++ .../core/widgets/files_view/grid_mixin.py | 105 +++++++++ .../core/widgets/files_view/tab_mixin.py | 206 ++++++++++++++++++ .../core/widgets/files_view/window_mixin.py | 173 +++++++++++++++ .../solarfm/utils/event_system.py | 12 +- 11 files changed, 657 insertions(+), 59 deletions(-) create mode 100644 src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/__init__.py create mode 100644 src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/files_widget.py create mode 100644 src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/grid_mixin.py create mode 100644 src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/tab_mixin.py create mode 100644 src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/window_mixin.py diff --git a/src/versions/solarfm-0.0.1/solarfm/core/controller.py b/src/versions/solarfm-0.0.1/solarfm/core/controller.py index 813f995..ea68f30 100644 --- a/src/versions/solarfm-0.0.1/solarfm/core/controller.py +++ b/src/versions/solarfm-0.0.1/solarfm/core/controller.py @@ -37,14 +37,14 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): """ Controller coordinates the mixins and is somewhat the root hub of it all. """ def __init__(self, args, unknownargs): - self.setup_controller_data() + self._setup_controller_data() self._setup_styling() self._setup_signals() self._subscribe_to_events() self._load_widgets() - self.generate_windows(self.fm_controller_data) + self._generate_file_views(self.fm_controller_data) if args.no_plugins == "false": self.plugins.launch_plugins() @@ -65,8 +65,10 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): 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("generate_file_views", self._generate_file_views) event_system.subscribe("clear_notebooks", self.clear_notebooks) + event_system.subscribe("set_window_title", self._set_window_title) + event_system.subscribe("unset_selected_files_views", self._unset_selected_files_views) event_system.subscribe("get_current_state", self.get_current_state) event_system.subscribe("go_to_path", self.go_to_path) event_system.subscribe("format_to_uris", self.format_to_uris) @@ -105,7 +107,6 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): FileExistsWidget() SaveLoadWidget() - def reload_plugins(self, widget=None, eve=None): self.plugins.reload_plugins() diff --git a/src/versions/solarfm-0.0.1/solarfm/core/controller_data.py b/src/versions/solarfm-0.0.1/solarfm/core/controller_data.py index 57d06d4..5ddc2c9 100644 --- a/src/versions/solarfm-0.0.1/solarfm/core/controller_data.py +++ b/src/versions/solarfm-0.0.1/solarfm/core/controller_data.py @@ -37,7 +37,7 @@ class Controller_Data: """ Controller_Data contains most of the state of the app at ay given time. It also has some support methods. """ __slots__ = "settings", "builder", "logger", "keybindings", "trashman", "fm_controller", "window", "window1", "window2", "window3", "window4" - def setup_controller_data(self) -> None: + def _setup_controller_data(self) -> None: self.window = settings.get_main_window() self.builder = None self.core_widget = None @@ -87,6 +87,7 @@ class Controller_Data: state.wid, state.tid = self.fm_controller.get_active_wid_and_tid() 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.icon_grid = event_system.emit_and_await("get_files_view_icon_grid", (state.wid, state.tid)) state.store = state.icon_grid.get_model() state.message_dialog = MessageWidget() @@ -103,7 +104,7 @@ class Controller_Data: # if self.to_cut_files: # state.to_cut_files = self.format_to_uris(state.store, state.wid, state.tid, self.to_cut_files, True) - event_system.emit("update_state_info_plugins", state) + event_system.emit("update_state_info_plugins", state) # NOTE: Need to remove after we convert plugins to use emit_and_await return state def format_to_uris(self, store, wid, tid, treePaths, use_just_path=False): @@ -125,6 +126,20 @@ class Controller_Data: return uris + + def get_fm_window(self, wid): + return self.fm_controller.get_window_by_nickname(f"window_{wid}") + + def _unset_selected_files_views(self): + for _notebook in self.notebooks: + ctx = _notebook.get_style_context() + ctx.remove_class("notebook-selected-focus") + ctx.add_class("notebook-unselected-focus") + + def _set_window_title(self, dir): + self.window.set_title(f"{app_name} ~ {dir}") + + def clear_console(self) -> None: ''' Clears the terminal screen. ''' os.system('cls' if os.name == 'nt' else 'clear') diff --git a/src/versions/solarfm-0.0.1/solarfm/core/mixins/ui/window_mixin.py b/src/versions/solarfm-0.0.1/solarfm/core/mixins/ui/window_mixin.py index 94655e7..3da0f4c 100644 --- a/src/versions/solarfm-0.0.1/solarfm/core/mixins/ui/window_mixin.py +++ b/src/versions/solarfm-0.0.1/solarfm/core/mixins/ui/window_mixin.py @@ -22,53 +22,6 @@ class WindowException(Exception): class WindowMixin(TabMixin): """docstring for WindowMixin""" - def generate_windows(self, session_json = None): - # for session in session_json: - # nickname = session["window"]["Nickname"] - # tabs = session["window"]["tabs"] - # isHidden = True if session["window"]["isHidden"] == "True" else False - # event_system.emit("load-window-state", (nickname, tabs)) - - if session_json: - for j, value in enumerate(session_json): - i = j + 1 - notebook_tggl_button = self.builder.get_object(f"tggl_notebook_{i}") - is_hidden = True if value["window"]["isHidden"] == "True" else False - tabs = value["window"]["tabs"] - self.fm_controller.create_window() - notebook_tggl_button.set_active(True) - - if tabs: - for tab in tabs: - self.create_new_tab_notebook(None, i, tab) - else: - self.create_new_tab_notebook(None, i, None) - - if is_hidden: - self.toggle_notebook_pane(notebook_tggl_button) - - try: - if not self.is_pane4_hidden: - icon_grid = self.window4.get_children()[-1].get_children()[0] - elif not self.is_pane3_hidden: - icon_grid = self.window3.get_children()[-1].get_children()[0] - elif not self.is_pane2_hidden: - icon_grid = self.window2.get_children()[-1].get_children()[0] - elif not self.is_pane1_hidden: - icon_grid = self.window1.get_children()[-1].get_children()[0] - - icon_grid.event(Gdk.Event().new(type=Gdk.EventType.BUTTON_RELEASE)) - icon_grid.event(Gdk.Event().new(type=Gdk.EventType.BUTTON_RELEASE)) - except WindowException as e: - logger.info("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n") - logger.debug(repr(e)) - else: - for j in range(0, 4): - i = j + 1 - self.fm_controller.create_window() - self.create_new_tab_notebook(None, i, None) - - def get_fm_window(self, wid): return self.fm_controller.get_window_by_nickname(f"window_{wid}") diff --git a/src/versions/solarfm-0.0.1/solarfm/core/ui_mixin.py b/src/versions/solarfm-0.0.1/solarfm/core/ui_mixin.py index 77b03b7..663ae4a 100644 --- a/src/versions/solarfm-0.0.1/solarfm/core/ui_mixin.py +++ b/src/versions/solarfm-0.0.1/solarfm/core/ui_mixin.py @@ -1,13 +1,78 @@ # Python imports -# Gtk imports +# 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.ui.pane_mixin import PaneMixin from .mixins.ui.window_mixin import WindowMixin +from .widgets.files_view.files_widget import FilesWidget +class UIMixinException(Exception): + ... + class UIMixin(PaneMixin, WindowMixin): - ... +# class UIMixin(PaneMixin): + def _generate_file_views(self, session_json = None): + # self._wip_hybrid_approach_loading_process(session_json) + self._current_loading_process(session_json) + + + def _wip_hybrid_approach_loading_process(self, session_json = None): + for session in session_json: + self.fm_controller.create_window() + FilesWidget().set_fm_controller(self.fm_controller) + + for session in session_json: + nickname = session["window"]["Nickname"] + tabs = session["window"]["tabs"] + isHidden = True if session["window"]["isHidden"] == "True" else False + event_system.emit("load_files_view_state", (nickname, tabs)) + + + def _current_loading_process(self, session_json = None): + if session_json: + for j, value in enumerate(session_json): + i = j + 1 + notebook_tggl_button = self.builder.get_object(f"tggl_notebook_{i}") + is_hidden = True if value["window"]["isHidden"] == "True" else False + tabs = value["window"]["tabs"] + self.fm_controller.create_window() + notebook_tggl_button.set_active(True) + + if tabs: + for tab in tabs: + self.create_new_tab_notebook(None, i, tab) + else: + self.create_new_tab_notebook(None, i, None) + + if is_hidden: + self.toggle_notebook_pane(notebook_tggl_button) + + try: + if not self.is_pane4_hidden: + icon_grid = self.window4.get_children()[-1].get_children()[0] + elif not self.is_pane3_hidden: + icon_grid = self.window3.get_children()[-1].get_children()[0] + elif not self.is_pane2_hidden: + icon_grid = self.window2.get_children()[-1].get_children()[0] + elif not self.is_pane1_hidden: + icon_grid = self.window1.get_children()[-1].get_children()[0] + + icon_grid.event(Gdk.Event().new(type=Gdk.EventType.BUTTON_RELEASE)) + icon_grid.event(Gdk.Event().new(type=Gdk.EventType.BUTTON_RELEASE)) + except UIMixinException as e: + logger.info("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n") + logger.debug(repr(e)) + else: + for j in range(0, 4): + i = j + 1 + self.fm_controller.create_window() + self.create_new_tab_notebook(None, i, None) diff --git a/src/versions/solarfm-0.0.1/solarfm/core/widgets/dialogs/save_load_widget.py b/src/versions/solarfm-0.0.1/solarfm/core/widgets/dialogs/save_load_widget.py index 3dc6f07..9e277fd 100644 --- a/src/versions/solarfm-0.0.1/solarfm/core/widgets/dialogs/save_load_widget.py +++ b/src/versions/solarfm-0.0.1/solarfm/core/widgets/dialogs/save_load_widget.py @@ -80,5 +80,5 @@ class SaveLoadWidget: state = event_system.emit_and_await("get_current_state") event_system.emit("clear_notebooks") state.fm_controller.unload_tabs_and_windows() - event_system.emit("generate_windows", (session_json,)) + event_system.emit("generate_file_views", (session_json,)) gc.collect() diff --git a/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/__init__.py b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/__init__.py new file mode 100644 index 0000000..d7f3dd9 --- /dev/null +++ b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/__init__.py @@ -0,0 +1,3 @@ +""" + Files View module +""" diff --git a/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/files_widget.py b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/files_widget.py new file mode 100644 index 0000000..3ae3898 --- /dev/null +++ b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/files_widget.py @@ -0,0 +1,71 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from ...mixins.signals.file_action_signals_mixin import FileActionSignalsMixin +from .window_mixin import WindowMixin + + + +class FilesWidget(FileActionSignalsMixin, WindowMixin): + """docstring for FilesWidget.""" + + ccount = 0 + + def __new__(cls, *args, **kwargs): + obj = super(FilesWidget, cls).__new__(cls) + cls.ccount += 1 + + return obj + + def __init__(self): + super(FilesWidget, self).__init__() + + self.INDEX = self.ccount + self.NAME = f"window_{self.INDEX}" + self.builder = Gtk.Builder() + self.files_view = None + self.fm_controller = None + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + settings.register_signals_to_builder([self,], self.builder) + + def _subscribe_to_events(self): + event_system.subscribe("load_files_view_state", self._load_files_view_state) + event_system.subscribe("get_files_view_icon_grid", self._get_files_view_icon_grid) + + def _load_widgets(self): + _builder = settings.get_builder() + self.files_view = _builder.get_object(f"{self.NAME}") + + self.files_view.set_group_name("files_widget") + self.builder.expose_object(f"{self.NAME}", self.files_view) + + def _load_files_view_state(self, win_name=None, tabs=None): + if win_name == self.NAME: + if tabs: + for tab in tabs: + self.create_new_tab_notebook(None, self.INDEX, tab) + else: + self.create_new_tab_notebook(None, self.INDEX, None) + + def _get_files_view_icon_grid(self, win_index=None, tid=None): + if win_index == str(self.INDEX): + return self.builder.get_object(f"{self.INDEX}|{tid}|icon_grid") + + + def set_fm_controller(self, _fm_controller): + self.fm_controller = _fm_controller diff --git a/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/grid_mixin.py b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/grid_mixin.py new file mode 100644 index 0000000..9e7fc42 --- /dev/null +++ b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/grid_mixin.py @@ -0,0 +1,105 @@ +# Python imports + +# Lib imports +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk +from gi.repository import GLib + +# Application imports +from ...widgets.tab_header_widget import TabHeaderWidget +from ...widgets.icon_grid_widget import IconGridWidget +from ...widgets.icon_tree_widget import IconTreeWidget + + + + +class GridMixin: + """docstring for GridMixin""" + + def load_store(self, tab, store, save_state=False): + store.clear() + dir = tab.get_current_directory() + files = tab.get_files() + + for file in files: + store.append([None, file[0]]) + + Gtk.main_iteration() + for i, file in enumerate(files): + self.create_icon(i, tab, store, dir, file[0]) + + # NOTE: Not likely called often from here but it could be useful + if save_state and not trace_debug: + self.fm_controller.save_state() + + + @daemon_threaded + def create_icon(self, i, tab, store, dir, file): + icon = tab.create_icon(dir, file) + GLib.idle_add(self.update_store, *(i, store, icon,)) + + def update_store(self, i, store, icon): + itr = store.get_iter(i) + store.set_value(itr, 0, icon) + + def create_tab_widget(self, tab): + return TabHeaderWidget(tab, self.close_tab) + + def create_scroll_and_store(self, tab, wid, use_tree_view=False): + scroll = Gtk.ScrolledWindow() + + if not use_tree_view: + grid = self.create_icon_grid_widget() + else: + # TODO: Fix global logic to make the below work too + grid = self.create_icon_tree_widget() + + scroll.add(grid) + scroll.set_name(f"{wid}|{tab.get_id()}") + grid.set_name(f"{wid}|{tab.get_id()}") + self.builder.expose_object(f"{wid}|{tab.get_id()}|icon_grid", grid) + self.builder.expose_object(f"{wid}|{tab.get_id()}", scroll) + + return scroll, grid.get_store() + + def create_icon_grid_widget(self): + grid = IconGridWidget() + grid._setup_additional_signals( + self.grid_icon_single_click, + self.grid_icon_double_click, + self.grid_set_selected_items, + self.grid_on_drag_set, + self.grid_on_drag_data_received, + self.grid_on_drag_motion + ) + + return grid + + def create_icon_tree_widget(self): + grid = IconTreeWidget() + grid._setup_additional_signals( + self.grid_icon_single_click, + self.grid_icon_double_click, + self.grid_on_drag_set, + self.grid_on_drag_data_received, + self.grid_on_drag_motion + ) + + grid.columns_autosize() + return grid + + def get_store_and_label_from_notebook(self, notebook, _name): + icon_grid = None + tab_label = None + store = None + + for obj in notebook.get_children(): + icon_grid = obj.get_children()[0] + name = icon_grid.get_name() + if name == _name: + store = icon_grid.get_model() + tab_label = notebook.get_tab_label(obj).get_children()[0] + + return store, tab_label diff --git a/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/tab_mixin.py b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/tab_mixin.py new file mode 100644 index 0000000..fa7401d --- /dev/null +++ b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/tab_mixin.py @@ -0,0 +1,206 @@ +# Python imports +import os + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from .grid_mixin import GridMixin + + + + +class TabMixin(GridMixin): + """docstring for TabMixin""" + + def create_tab(self, wid=None, tid=None, path=None): + if not wid: + wid, tid = self.fm_controller.get_active_wid_and_tid() + + notebook = self.builder.get_object(f"window_{wid}") + # path_entry = self.builder.get_object(f"path_entry") + tab = self.fm_controller.add_tab_for_window_by_nickname(f"window_{wid}") + # tab.logger = logger + + tab.set_wid(wid) + if not path: + if wid and tid: + _tab = self.get_fm_window(wid).get_tab_by_id(tid) + tab.set_path(_tab.get_current_directory()) + else: + tab.set_path(path) + + tab_widget = self.create_tab_widget(tab) + scroll, store = self.create_scroll_and_store(tab, wid) + index = notebook.append_page(scroll, tab_widget) + notebook.set_tab_detachable(scroll, True) + + self.fm_controller.set_wid_and_tid(wid, tab.get_id()) + event_system.emit("go_to_path", (tab.get_current_directory(),)) # NOTE: Not efficent if I understand how + # path_entry.set_text(tab.get_current_directory()) + notebook.show_all() + notebook.set_current_page(index) + + ctx = notebook.get_style_context() + ctx.add_class("notebook-unselected-focus") + notebook.set_tab_reorderable(scroll, True) + self.load_store(tab, store) + # self.set_window_title() + event_system.emit("set_window_title", (tab.get_current_directory(),)) + self.set_file_watcher(tab) + + + + + def close_tab(self, button, eve=None): + notebook = button.get_parent().get_parent() + wid = int(notebook.get_name()[-1]) + tid = self.get_id_from_tab_box(button.get_parent()) + scroll = self.builder.get_object(f"{wid}|{tid}") + page = notebook.page_num(scroll) + tab = self.get_fm_window(wid).get_tab_by_id(tid) + watcher = tab.get_dir_watcher() + + watcher.cancel() + self.get_fm_window(wid).delete_tab_by_id(tid) + notebook.remove_page(page) + if not settings.is_trace_debug(): + self.fm_controller.save_state() + self.set_window_title() + + # NOTE: Not actually getting called even tho set in the glade file... + def on_tab_dnded(self, notebook, page, x, y): + ... + + def on_tab_reorder(self, child, page_num, new_index): + wid, tid = page_num.get_name().split("|") + window = self.get_fm_window(wid) + tab = None + + for i, tab in enumerate(window.get_all_tabs()): + if tab.get_id() == tid: + _tab = window.get_tab_by_id(tid) + watcher = _tab.get_dir_watcher() + watcher.cancel() + window.get_all_tabs().insert(new_index, window.get_all_tabs().pop(i)) + + tab = window.get_tab_by_id(tid) + self.set_file_watcher(tab) + if not settings.is_trace_debug(): + self.fm_controller.save_state() + + def on_tab_switch_update(self, notebook, content=None, index=None): + self.selected_files.clear() + wid, tid = content.get_children()[0].get_name().split("|") + self.fm_controller.set_wid_and_tid(wid, tid) + self.set_path_text(wid, tid) + self.set_window_title() + + def get_id_from_tab_box(self, tab_box): + return tab_box.get_children()[2].get_text() + + def get_tab_label(self, notebook, icon_grid): + return notebook.get_tab_label(icon_grid.get_parent()).get_children()[0] + + def get_tab_close(self, notebook, icon_grid): + return notebook.get_tab_label(icon_grid.get_parent()).get_children()[1] + + def get_tab_icon_grid_from_notebook(self, notebook): + return notebook.get_children()[1].get_children()[0] + + def refresh_tab(data=None): + state = self.get_current_state() + state.tab.load_directory() + self.load_store(state.tab, state.store) + + def update_tab(self, tab_label, tab, store, wid, tid): + self.load_store(tab, store) + self.set_path_text(wid, tid) + + char_width = len(tab.get_end_of_path()) + tab_label.set_width_chars(char_width) + tab_label.set_label(tab.get_end_of_path()) + self.set_window_title() + self.set_file_watcher(tab) + if not settings.is_trace_debug(): + self.fm_controller.save_state() + + def do_action_from_bar_controls(self, widget, eve=None): + action = widget.get_name() + wid, tid = self.fm_controller.get_active_wid_and_tid() + notebook = self.builder.get_object(f"window_{wid}") + store, tab_label = self.get_store_and_label_from_notebook(notebook, f"{wid}|{tid}") + tab = self.get_fm_window(wid).get_tab_by_id(tid) + + if action == "create_tab": + dir = tab.get_current_directory() + self.create_tab(wid, None, dir) + if not settings.is_trace_debug(): + self.fm_controller.save_state() + + return + if action == "go_up": + tab.pop_from_path() + if action == "go_home": + tab.set_to_home() + if action == "refresh_tab": + tab.load_directory() + if action == "path_entry": + focused_obj = self.window.get_focus() + dir = f"{tab.get_current_directory()}/" + path = widget.get_text() + + if isinstance(focused_obj, Gtk.Entry): + path_menu_buttons = self.builder.get_object("path_menu_buttons") + query = widget.get_text().replace(dir, "") + files = tab.get_files() + tab.get_hidden() + + self.clear_children(path_menu_buttons) + show_path_menu = False + for file, hash, size in files: + if os.path.isdir(f"{dir}{file}"): + if query.lower() in file.lower(): + button = Gtk.Button(label=file) + button.show() + button.connect("clicked", self.set_path_entry) + path_menu_buttons.add(button) + show_path_menu = True + + if not show_path_menu: + event_system.emit("hide_path_menu") + else: + event_system.emit("show_path_menu") + widget.grab_focus_without_selecting() + widget.set_position(-1) + + if path.endswith(".") or path == dir: + return + + if not tab.set_path(path): + return + + self.update_tab(tab_label, tab, store, wid, tid) + + try: + widget.grab_focus_without_selecting() + widget.set_position(-1) + except Exception as e: + pass + + def set_path_entry(self, button=None, eve=None): + state = self.get_current_state() + path = f"{state.tab.get_current_directory()}/{button.get_label()}" + path_entry = self.builder.get_object("path_entry") + path_entry.set_text(path) + path_entry.grab_focus_without_selecting() + path_entry.set_position(-1) + event_system.emit("hide_path_menu") + + def show_hide_hidden_files(self): + wid, tid = self.fm_controller.get_active_wid_and_tid() + tab = self.get_fm_window(wid).get_tab_by_id(tid) + tab.set_hiding_hidden(not tab.is_hiding_hidden()) + tab.load_directory() + self.builder.get_object("refresh_tab").released() diff --git a/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/window_mixin.py b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/window_mixin.py new file mode 100644 index 0000000..2566979 --- /dev/null +++ b/src/versions/solarfm-0.0.1/solarfm/core/widgets/files_view/window_mixin.py @@ -0,0 +1,173 @@ +# Python imports +import copy +import traceback +from os.path import isdir + +# 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 +from gi.repository import Gio + +# Application imports +from .tab_mixin import TabMixin + + +class WindowException(Exception): + ... + + +class WindowMixin(TabMixin): + """docstring for WindowMixin""" + + def get_fm_window(self, wid): + return self.fm_controller.get_window_by_nickname(f"window_{wid}") + + def set_bottom_labels(self, tab): + event_system.emit("set_bottom_labels", (tab,)) + + def set_window_title(self): + wid, tid = self.fm_controller.get_active_wid_and_tid() + notebook = self.builder.get_object(f"window_{wid}") + tab = self.get_fm_window(wid).get_tab_by_id(tid) + dir = tab.get_current_directory() + + event_system.emit("unset_selected_files_views") + ctx = self.files_view.get_style_context() + ctx.remove_class("notebook-unselected-focus") + ctx.add_class("notebook-selected-focus") + + event_system.emit("set_window_title", (dir,)) + self.set_bottom_labels(tab) + + def set_path_text(self, wid, tid): + tab = self.get_fm_window(wid).get_tab_by_id(tid) + event_system.emit("go_to_path", (tab.get_current_directory(),)) + + def grid_set_selected_items(self, icons_grid): + new_items = icons_grid.get_selected_items() + items_size = len(new_items) + selected_items = event_system.emit_and_await("get_selected_files") + + if items_size == 1: + # NOTE: If already in selection, likely dnd else not so wont readd + if new_items[0] in selected_items: + 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 + selected_items.clear() + + # NOTE: Likely trying dnd, just readd to selection the former set. + # Prevents losing highlighting of grid selected. + for path in selected_items: + icons_grid.select_path(path) + + if items_size > 0: + event_system.emit("set_selected_files", (new_items,)) + else: + self.dnd_left_primed = 0 + selected_items.clear() + + def grid_icon_single_click(self, icons_grid, eve): + try: + event_system.emit("hide_path_menu") + wid, tid = icons_grid.get_name().split("|") + self.fm_controller.set_wid_and_tid(wid, tid) + self.set_path_text(wid, tid) + self.set_window_title() + + if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click + if self.ctrl_down: + self.dnd_left_primed = 0 + + if self.single_click_open: # FIXME: need to find a way to pass the model index + self.grid_icon_double_click(icons_grid) + elif eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 3: # r-click + event_system.emit("show_context_menu") + + except WindowException as e: + logger.info(repr(e)) + self.display_message(settings.get_error_color(), f"{repr(e)}") + + def grid_icon_double_click(self, icons_grid, item, data=None): + try: + if self.ctrl_down and self.shift_down: + self.unset_keys_and_data() + self.execute_files(in_terminal=True) + return + elif self.ctrl_down: + self.unset_keys_and_data() + self.execute_files() + return + + + state = self.get_current_state() + notebook = self.builder.get_object(f"window_{state.wid}") + tab_label = self.get_tab_label(notebook, icons_grid) + + fileName = state.store[item][1] + dir = state.tab.get_current_directory() + file = f"{dir}/{fileName}" + + if isdir(file): + state.tab.set_path(file) + self.update_tab(tab_label, state.tab, state.store, state.wid, state.tid) + else: + event_system.emit("open_files") + except WindowException as e: + traceback.print_exc() + self.display_message(settings.get_error_color(), f"{repr(e)}") + + + + def grid_on_drag_set(self, icons_grid, drag_context, data, info, time): + action = icons_grid.get_name() + wid, tid = action.split("|") + store = icons_grid.get_model() + treePaths = icons_grid.get_selected_items() + # NOTE: Need URIs as URI format for DnD to work. Will strip 'file://' + # further down call chain when doing internal fm stuff. + uris = self.format_to_uris(store, wid, tid, treePaths) + uris_text = '\n'.join(uris) + + data.set_uris(uris) + data.set_text(uris_text, -1) + + def grid_on_drag_motion(self, icons_grid, drag_context, x, y, data): + current = '|'.join(self.fm_controller.get_active_wid_and_tid()) + target = icons_grid.get_name() + wid, tid = target.split("|") + store = icons_grid.get_model() + path_at_loc = None + + try: + path_at_loc = icons_grid.get_item_at_pos(x, y)[0] + highlighted_item_path = icons_grid.get_drag_dest_item().path + if path_at_loc and path_at_loc == highlighted_item_path: + uri = self.format_to_uris(store, wid, tid, highlighted_item_path)[0].replace("file://", "") + self.override_drop_dest = uri if isdir(uri) else None + except Exception as e: + ... + + if target not in current: + self.fm_controller.set_wid_and_tid(wid, tid) + + + def grid_on_drag_data_received(self, widget, drag_context, x, y, data, info, time): + if info == 80: + uris = data.get_uris() + state = event_system.emit_and_await("get_current_state") + dest = f"{state.tab.get_current_directory()}" if not self.override_drop_dest else self.override_drop_dest + if len(uris) == 0: + uris = data.get_text().split("\n") + + from_uri = '/'.join(uris[0].replace("file://", "").split("/")[:-1]) + if from_uri != dest: + event_system.emit("move_files", (uris, dest)) + + + def create_new_tab_notebook(self, widget=None, wid=None, path=None): + self.create_tab(wid, None, path) diff --git a/src/versions/solarfm-0.0.1/solarfm/utils/event_system.py b/src/versions/solarfm-0.0.1/solarfm/utils/event_system.py index b2d4a71..88f7299 100644 --- a/src/versions/solarfm-0.0.1/solarfm/utils/event_system.py +++ b/src/versions/solarfm-0.0.1/solarfm/utils/event_system.py @@ -38,11 +38,17 @@ class EventSystem: def emit_and_await(self, event_type, data = None): """ NOTE: Should be used when signal has only one listener and vis-a-vis """ if event_type in self.subscribers: + response = None for fn in self.subscribers[event_type]: if data: if hasattr(data, '__iter__') and not type(data) is str: - return fn(*data) + response = fn(*data) else: - return fn(data) + response = fn(data) else: - return fn() + response = fn() + + if not response in (None, ''): + break + + return response