develop #11
|
@ -37,14 +37,14 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
||||||
""" Controller coordinates the mixins and is somewhat the root hub of it all. """
|
""" Controller coordinates the mixins and is somewhat the root hub of it all. """
|
||||||
|
|
||||||
def __init__(self, args, unknownargs):
|
def __init__(self, args, unknownargs):
|
||||||
self.setup_controller_data()
|
self._setup_controller_data()
|
||||||
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
self.generate_windows(self.fm_controller_data)
|
self._generate_file_views(self.fm_controller_data)
|
||||||
|
|
||||||
if args.no_plugins == "false":
|
if args.no_plugins == "false":
|
||||||
self.plugins.launch_plugins()
|
self.plugins.launch_plugins()
|
||||||
|
@ -65,8 +65,10 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
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("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("get_current_state", self.get_current_state)
|
||||||
event_system.subscribe("go_to_path", self.go_to_path)
|
event_system.subscribe("go_to_path", self.go_to_path)
|
||||||
event_system.subscribe("format_to_uris", self.format_to_uris)
|
event_system.subscribe("format_to_uris", self.format_to_uris)
|
||||||
|
@ -105,7 +107,6 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
||||||
FileExistsWidget()
|
FileExistsWidget()
|
||||||
SaveLoadWidget()
|
SaveLoadWidget()
|
||||||
|
|
||||||
|
|
||||||
def reload_plugins(self, widget=None, eve=None):
|
def reload_plugins(self, widget=None, eve=None):
|
||||||
self.plugins.reload_plugins()
|
self.plugins.reload_plugins()
|
||||||
|
|
||||||
|
|
|
@ -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. """
|
""" 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"
|
__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.window = settings.get_main_window()
|
||||||
self.builder = None
|
self.builder = None
|
||||||
self.core_widget = 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.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.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 = 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.store = state.icon_grid.get_model()
|
||||||
state.message_dialog = MessageWidget()
|
state.message_dialog = MessageWidget()
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ class Controller_Data:
|
||||||
# if self.to_cut_files:
|
# if self.to_cut_files:
|
||||||
# state.to_cut_files = self.format_to_uris(state.store, state.wid, state.tid, self.to_cut_files, True)
|
# 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
|
return state
|
||||||
|
|
||||||
def format_to_uris(self, store, wid, tid, treePaths, use_just_path=False):
|
def format_to_uris(self, store, wid, tid, treePaths, use_just_path=False):
|
||||||
|
@ -125,6 +126,20 @@ class Controller_Data:
|
||||||
|
|
||||||
return uris
|
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:
|
def clear_console(self) -> None:
|
||||||
''' Clears the terminal screen. '''
|
''' Clears the terminal screen. '''
|
||||||
os.system('cls' if os.name == 'nt' else 'clear')
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
|
|
@ -22,53 +22,6 @@ class WindowException(Exception):
|
||||||
class WindowMixin(TabMixin):
|
class WindowMixin(TabMixin):
|
||||||
"""docstring for WindowMixin"""
|
"""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):
|
def get_fm_window(self, wid):
|
||||||
return self.fm_controller.get_window_by_nickname(f"window_{wid}")
|
return self.fm_controller.get_window_by_nickname(f"window_{wid}")
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,78 @@
|
||||||
# Python imports
|
# 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
|
# Application imports
|
||||||
from .mixins.ui.pane_mixin import PaneMixin
|
from .mixins.ui.pane_mixin import PaneMixin
|
||||||
from .mixins.ui.window_mixin import WindowMixin
|
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, 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)
|
||||||
|
|
|
@ -80,5 +80,5 @@ class SaveLoadWidget:
|
||||||
state = event_system.emit_and_await("get_current_state")
|
state = event_system.emit_and_await("get_current_state")
|
||||||
event_system.emit("clear_notebooks")
|
event_system.emit("clear_notebooks")
|
||||||
state.fm_controller.unload_tabs_and_windows()
|
state.fm_controller.unload_tabs_and_windows()
|
||||||
event_system.emit("generate_windows", (session_json,))
|
event_system.emit("generate_file_views", (session_json,))
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
"""
|
||||||
|
Files View module
|
||||||
|
"""
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
|
@ -38,11 +38,17 @@ class EventSystem:
|
||||||
def emit_and_await(self, event_type, data = None):
|
def emit_and_await(self, event_type, data = None):
|
||||||
""" NOTE: Should be used when signal has only one listener and vis-a-vis """
|
""" NOTE: Should be used when signal has only one listener and vis-a-vis """
|
||||||
if event_type in self.subscribers:
|
if event_type in self.subscribers:
|
||||||
|
response = None
|
||||||
for fn in self.subscribers[event_type]:
|
for fn in self.subscribers[event_type]:
|
||||||
if data:
|
if data:
|
||||||
if hasattr(data, '__iter__') and not type(data) is str:
|
if hasattr(data, '__iter__') and not type(data) is str:
|
||||||
return fn(*data)
|
response = fn(*data)
|
||||||
else:
|
else:
|
||||||
return fn(data)
|
response = fn(data)
|
||||||
else:
|
else:
|
||||||
return fn()
|
response = fn()
|
||||||
|
|
||||||
|
if not response in (None, ''):
|
||||||
|
break
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
Loading…
Reference in New Issue