develop #11
|
@ -9,7 +9,7 @@ Copy the share/solarfm folder to your user .config/ directory too.
|
|||
|
||||
<h6>Install Setup</h6>
|
||||
```
|
||||
sudo apt-get install python3.8 wget python3-setproctitle python3-gi ffmpegthumbnailer steamcmd
|
||||
sudo apt-get install python3.8 python3-setproctitle python3-gi wget ffmpegthumbnailer steamcmd
|
||||
```
|
||||
|
||||
# Known Issues
|
||||
|
|
|
@ -31,7 +31,7 @@ class Plugin(PluginBase):
|
|||
# where self.name should not be needed for message comms
|
||||
self._GLADE_FILE = f"{self.path}/translate.glade"
|
||||
|
||||
self._link = "https://duckduckgo.com/translation.js?vqd=4-79469202070473384659389009732578528471&query=translate&to=en"
|
||||
self._link = "https://duckduckgo.com/translation.js?"
|
||||
self._headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0',
|
||||
'Accept': '*/*',
|
||||
|
@ -50,8 +50,19 @@ class Plugin(PluginBase):
|
|||
'Cache-Control': 'no-cache'
|
||||
}
|
||||
|
||||
self.vqd_link = "https://duckduckgo.com/"
|
||||
self.vqd_data = {"q": "translate", "ia":"web"}
|
||||
self.vqd_headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0',
|
||||
"Referer": "https://duckduckgo.com/"
|
||||
}
|
||||
|
||||
self._queue_translate = False
|
||||
self._watcher_running = False
|
||||
self._vqd_attrib = None
|
||||
self.from_trans = "jp"
|
||||
self.to_trans = "en"
|
||||
self.translate_tries = 0
|
||||
|
||||
|
||||
def generate_reference_ui_element(self):
|
||||
|
@ -71,6 +82,9 @@ class Plugin(PluginBase):
|
|||
self._translate_to_buffer = self._builder.get_object("translate_to_buffer")
|
||||
self._detected_language_lbl = self._builder.get_object("detected_language_lbl")
|
||||
|
||||
self._detected_language_lbl.set_label(f"Selected Language: {self.from_trans}")
|
||||
self.get_vqd()
|
||||
|
||||
|
||||
@threaded
|
||||
def _show_translate_page(self, widget=None, eve=None):
|
||||
|
@ -116,20 +130,43 @@ class Plugin(PluginBase):
|
|||
break
|
||||
|
||||
def _translate(self):
|
||||
start_itr, end_itr = self._translate_from_buffer.get_bounds()
|
||||
from_translate = self._translate_from_buffer.get_text(start_itr, end_itr, True).encode('utf-8')
|
||||
start_itr, end_itr = self._translate_from_buffer.get_bounds()
|
||||
from_translate = self._translate_from_buffer.get_text(start_itr, end_itr, True).encode('utf-8')
|
||||
|
||||
if from_translate in ("", None) or self._queue_translate:
|
||||
return
|
||||
|
||||
response = requests.post(self._link, headers=self._headers, data=from_translate)
|
||||
self.translate_tries += 1
|
||||
tlink = f"https://duckduckgo.com/translation.js?vqd={self._vqd_attrib}&query=translate&from={self.from_trans}&to={self.to_trans}"
|
||||
response = requests.post(self.tlink, headers=self._headers, data=from_translate)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
self._translate_to_buffer.set_text(data["translated"])
|
||||
|
||||
self.translate_tries = 0
|
||||
if "detected_language" in data.keys():
|
||||
self._detected_language_lbl.set_label(f"Detected Language: {data['detected_language']}")
|
||||
else:
|
||||
self._detected_language_lbl.set_label(f"Selected Language: {self.from_trans}")
|
||||
elif response.status_code >= 400 or response.status_code < 500:
|
||||
self.get_vqd()
|
||||
if not self.translate_tries > 4:
|
||||
self._translate()
|
||||
else:
|
||||
msg = f"Could not translate... Response Code: {response.status_code}"
|
||||
self._translate_to_buffer.set_text(msg)
|
||||
self._detected_language_lbl.set_label(f"Detected Language:")
|
||||
|
||||
|
||||
def get_vqd(self):
|
||||
response = requests.post(self.vqd_link, headers=self.vqd_headers, data=self.vqd_data, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.content
|
||||
vqd_start_index = data.index(b"vqd='") + 5
|
||||
vqd_end_index = data.index(b"'", vqd_start_index)
|
||||
self._vqd_attrib = data[vqd_start_index:vqd_end_index].decode("utf-8")
|
||||
|
||||
print(f"Translation VQD: {self._vqd_attrib}")
|
||||
else:
|
||||
msg = f"Could not get VQS attribute... Response Code: {response.status_code}"
|
||||
self._translate_to_buffer.set_text(msg)
|
||||
|
|
|
@ -58,7 +58,7 @@ class Plugin(PluginBase):
|
|||
self._file_hash = self._builder.get_object("file_hash")
|
||||
|
||||
def generate_reference_ui_element(self):
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(f"{self.path}/../../icons/video.png", 16, 16, True)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(f"/usr/share/solarfm/icons/video.png", 16, 16, True)
|
||||
icon = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
item = Gtk.ImageMenuItem(self.name)
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,181 +0,0 @@
|
|||
# Python imports
|
||||
import os
|
||||
import json
|
||||
from os import path
|
||||
|
||||
# Gtk imports
|
||||
import gi, cairo
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gdk
|
||||
|
||||
# Application imports
|
||||
from .logger import Logger
|
||||
from .keybindings import Keybindings
|
||||
|
||||
|
||||
|
||||
|
||||
class Settings:
|
||||
def __init__(self):
|
||||
self._SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__))
|
||||
self._USER_HOME = path.expanduser('~')
|
||||
self._CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}"
|
||||
self._UI_WIDEGTS_PATH = f"{self._CONFIG_PATH}/ui_widgets"
|
||||
self._PLUGINS_PATH = f"{self._CONFIG_PATH}/plugins"
|
||||
self._USR_SOLARFM = f"/usr/share/{app_name.lower()}"
|
||||
|
||||
self._CSS_FILE = f"{self._CONFIG_PATH}/stylesheet.css"
|
||||
self._GLADE_FILE = f"{self._CONFIG_PATH}/Main_Window.glade"
|
||||
self._KEY_BINDINGS = f"{self._CONFIG_PATH}/key-bindings.json"
|
||||
self._DEFAULT_ICONS = f"{self._CONFIG_PATH}/icons"
|
||||
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png"
|
||||
self._CONTEXT_MENU = f"{self._CONFIG_PATH}/contexct_menu.json"
|
||||
self._PID_FILE = f"{self._CONFIG_PATH}/{app_name.lower()}.pid"
|
||||
self._ICON_THEME = Gtk.IconTheme.get_default()
|
||||
self._TRASH_FILES_PATH = f"{GLib.get_user_data_dir()}/Trash/files"
|
||||
self._TRASH_INFO_PATH = f"{GLib.get_user_data_dir()}/Trash/info"
|
||||
|
||||
if not os.path.exists(self._CONFIG_PATH):
|
||||
os.mkdir(self._CONFIG_PATH)
|
||||
if not os.path.exists(self._PLUGINS_PATH):
|
||||
os.mkdir(self._PLUGINS_PATH)
|
||||
|
||||
if not os.path.exists(self._GLADE_FILE):
|
||||
self._GLADE_FILE = f"{self._USR_SOLARFM}/Main_Window.glade"
|
||||
if not os.path.exists(self._CONTEXT_MENU):
|
||||
self._CONTEXT_MENU = f"{self._USR_SOLARFM}/contexct_menu.json"
|
||||
if not os.path.exists(self._KEY_BINDINGS):
|
||||
self._KEY_BINDINGS = f"{self._USR_SOLARFM}/key-bindings.json"
|
||||
if not os.path.exists(self._CSS_FILE):
|
||||
self._CSS_FILE = f"{self._USR_SOLARFM}/stylesheet.css"
|
||||
if not os.path.exists(self._WINDOW_ICON):
|
||||
self._WINDOW_ICON = f"{self._USR_SOLARFM}/icons/{app_name.lower()}.png"
|
||||
if not os.path.exists(self._DEFAULT_ICONS):
|
||||
self._DEFAULT_ICONS = f"{self._USR_SOLARFM}/icons"
|
||||
|
||||
self._success_color = "#88cc27"
|
||||
self._warning_color = "#ffa800"
|
||||
self._error_color = "#ff0000"
|
||||
|
||||
self._keybindings = Keybindings()
|
||||
with open(self._KEY_BINDINGS) as file:
|
||||
keybindings = json.load(file)["keybindings"]
|
||||
self._keybindings.configure(keybindings)
|
||||
|
||||
with open(self._CONTEXT_MENU) as file:
|
||||
self._context_menu_data = json.load(file)
|
||||
|
||||
self._main_window = None
|
||||
self._logger = Logger(self._CONFIG_PATH, _fh_log_lvl=20).get_logger()
|
||||
self._builder = Gtk.Builder()
|
||||
self._builder.add_from_file(self._GLADE_FILE)
|
||||
|
||||
self._trace_debug = False
|
||||
self._debug = False
|
||||
self._dirty_start = False
|
||||
|
||||
|
||||
def do_dirty_start_check(self):
|
||||
if not os.path.exists(self._PID_FILE):
|
||||
self._write_new_pid()
|
||||
else:
|
||||
with open(self._PID_FILE, "r") as _pid:
|
||||
pid = _pid.readline().strip()
|
||||
if pid not in ("", None):
|
||||
self._check_alive_status(int(pid))
|
||||
else:
|
||||
self._write_new_pid()
|
||||
|
||||
""" Check For the existence of a unix pid. """
|
||||
def _check_alive_status(self, pid):
|
||||
print(f"PID Found: {pid}")
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError:
|
||||
print(f"{app_name} is starting dirty...")
|
||||
self._dirty_start = True
|
||||
self._write_new_pid()
|
||||
return
|
||||
|
||||
print("PID is alive... Let downstream errors (sans debug args) handle app closure propigation.")
|
||||
|
||||
def _write_new_pid(self):
|
||||
pid = os.getpid()
|
||||
self._write_pid(pid)
|
||||
|
||||
def _clean_pid(self):
|
||||
os.unlink(self._PID_FILE)
|
||||
|
||||
def _write_pid(self, pid):
|
||||
with open(self._PID_FILE, "w") as _pid:
|
||||
_pid.write(f"{pid}")
|
||||
|
||||
|
||||
def create_window(self) -> None:
|
||||
# Get window and connect signals
|
||||
self._main_window = self._builder.get_object("main_window")
|
||||
self._set_window_data()
|
||||
|
||||
def _set_window_data(self) -> None:
|
||||
self._main_window.set_icon_from_file(self._WINDOW_ICON)
|
||||
screen = self._main_window.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
|
||||
if visual != None and screen.is_composited():
|
||||
self._main_window.set_visual(visual)
|
||||
self._main_window.set_app_paintable(True)
|
||||
self._main_window.connect("draw", self._area_draw)
|
||||
|
||||
# bind css file
|
||||
cssProvider = Gtk.CssProvider()
|
||||
cssProvider.load_from_path(self._CSS_FILE)
|
||||
screen = Gdk.Screen.get_default()
|
||||
styleContext = Gtk.StyleContext()
|
||||
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
|
||||
cr.set_source_rgba(0, 0, 0, 0.54)
|
||||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||
cr.paint()
|
||||
cr.set_operator(cairo.OPERATOR_OVER)
|
||||
|
||||
def get_monitor_data(self) -> list:
|
||||
screen = self._builder.get_object("main_window").get_screen()
|
||||
monitors = []
|
||||
for m in range(screen.get_n_monitors()):
|
||||
monitors.append(screen.get_monitor_geometry(m))
|
||||
print("{}x{}+{}+{}".format(monitor.width, monitor.height, monitor.x, monitor.y))
|
||||
|
||||
return monitors
|
||||
|
||||
|
||||
def get_main_window(self) -> Gtk.ApplicationWindow: return self._main_window
|
||||
def get_builder(self) -> Gtk.Builder: return self._builder
|
||||
def get_context_menu_data(self) -> str: return self._context_menu_data
|
||||
def get_ui_widgets_path(self) -> str: return self._UI_WIDEGTS_PATH
|
||||
def get_trash_files_path(self) -> str: return self._TRASH_FILES_PATH
|
||||
def get_trash_info_path(self) -> str: return self._TRASH_INFO_PATH
|
||||
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
||||
|
||||
def get_logger(self) -> Logger: return self._logger
|
||||
def get_keybindings(self) -> Keybindings: return self._keybindings
|
||||
def get_icon_theme(self) -> str: return self._ICON_THEME
|
||||
|
||||
def get_success_color(self) -> str: return self._success_color
|
||||
def get_warning_color(self) -> str: return self._warning_color
|
||||
def get_error_color(self) -> str: return self._error_color
|
||||
|
||||
def is_trace_debug(self) -> bool: return self._trace_debug
|
||||
def is_debug(self) -> bool: return self._debug
|
||||
def is_dirty_start(self) -> bool: return self._dirty_start
|
||||
def clear_pid(self): self._clean_pid()
|
||||
|
||||
|
||||
def set_trace_debug(self, trace_debug: bool):
|
||||
self._trace_debug = trace_debug
|
||||
|
||||
def set_debug(self, debug: bool):
|
||||
self._debug = debug
|
|
@ -1,10 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
chdir("/opt/");
|
||||
system("python solarfm.zip");
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
function main() {
|
||||
gcc -no-pie -s SolarFM_exec_bin.cpp -o solarfm
|
||||
}
|
||||
main;
|
|
@ -1,12 +1,15 @@
|
|||
# Python imports
|
||||
import builtins
|
||||
import threading
|
||||
import sys
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from utils.event_system import EventSystem
|
||||
from utils.endpoint_registry import EndpointRegistry
|
||||
from utils.keybindings import Keybindings
|
||||
from utils.logger import Logger
|
||||
from utils.settings import Settings
|
||||
|
||||
|
||||
|
@ -35,12 +38,26 @@ def sizeof_fmt_def(num, suffix="B"):
|
|||
# NOTE: Just reminding myself we can add to builtins two different ways...
|
||||
# __builtins__.update({"event_system": Builtins()})
|
||||
builtins.app_name = "SolarFM"
|
||||
builtins.settings = Settings()
|
||||
builtins.logger = settings.get_logger()
|
||||
builtins.keybindings = Keybindings()
|
||||
builtins.event_system = EventSystem()
|
||||
builtins.endpoint_registry = EndpointRegistry()
|
||||
builtins.settings = Settings()
|
||||
builtins.logger = Logger(settings.get_home_config_path(), \
|
||||
_ch_log_lvl=settings.get_ch_log_lvl(), \
|
||||
_fh_log_lvl=settings.get_fh_log_lvl()).get_logger()
|
||||
|
||||
builtins.threaded = threaded_wrapper
|
||||
builtins.daemon_threaded = daemon_threaded_wrapper
|
||||
builtins.sizeof_fmt = sizeof_fmt_def
|
||||
builtins.event_sleep_time = 0.05
|
||||
|
||||
|
||||
def custom_except_hook(exc_type, exc_value, exc_traceback):
|
||||
if issubclass(exc_type, KeyboardInterrupt):
|
||||
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||
return
|
||||
|
||||
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
|
||||
|
||||
sys.excepthook = custom_except_hook
|
|
@ -7,14 +7,12 @@ import inspect
|
|||
# Application imports
|
||||
|
||||
from utils.ipc_server import IPCServer
|
||||
from core.controller import Controller
|
||||
from core.window import Window
|
||||
|
||||
|
||||
class AppLaunchException(Exception):
|
||||
...
|
||||
|
||||
class ControllerStartException(Exception):
|
||||
...
|
||||
|
||||
|
||||
class Application(IPCServer):
|
||||
|
@ -38,25 +36,4 @@ class Application(IPCServer):
|
|||
|
||||
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
|
||||
|
||||
|
||||
settings.create_window()
|
||||
self._load_controller_and_builder()
|
||||
|
||||
def _load_controller_and_builder(self):
|
||||
controller = Controller(self.args, self.unknownargs)
|
||||
if not controller:
|
||||
raise ControllerStartException("Controller exited and doesn't exist...")
|
||||
|
||||
# Gets the methods from the classes and sets to handler.
|
||||
# Then, builder connects to any signals it needs.
|
||||
classes = [controller]
|
||||
handlers = {}
|
||||
for c in classes:
|
||||
methods = None
|
||||
try:
|
||||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except AppLaunchException as e:
|
||||
print(repr(e))
|
||||
|
||||
settings.get_builder().connect_signals(handlers)
|
||||
Window(args, unknownargs)
|
|
@ -37,12 +37,13 @@ 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_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.setup_controller_data()
|
||||
self.generate_windows(self.fm_controller_data)
|
||||
|
||||
if args.no_plugins == "false":
|
||||
|
@ -69,6 +70,20 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
|||
event_system.subscribe("do_action_from_menu_controls", self.do_action_from_menu_controls)
|
||||
event_system.subscribe("set_clipboard_data", self.set_clipboard_data)
|
||||
|
||||
def _load_glade_file(self):
|
||||
self.builder = Gtk.Builder()
|
||||
self.builder.add_from_file(settings.get_glade_file())
|
||||
self.builder.expose_object("main_window", self.window)
|
||||
|
||||
self.core_widget = self.builder.get_object("core_widget")
|
||||
|
||||
settings.set_builder(self.builder)
|
||||
settings.register_signals_to_builder([self,])
|
||||
|
||||
def get_core_widget(self):
|
||||
return self.core_widget
|
||||
|
||||
|
||||
# NOTE: Really we will move these to the UI/(New) Window 'base' controller
|
||||
# after we're done cleaning and refactoring to use fewer mixins.
|
||||
def _load_widgets(self):
|
||||
|
@ -87,14 +102,6 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
|||
self.message_dialog = MessageWidget()
|
||||
|
||||
|
||||
def tear_down(self, widget=None, eve=None):
|
||||
if not settings.is_trace_debug():
|
||||
self.fm_controller.save_state()
|
||||
|
||||
settings.clear_pid()
|
||||
time.sleep(event_sleep_time)
|
||||
Gtk.main_quit()
|
||||
|
||||
def reload_plugins(self, widget=None, eve=None):
|
||||
self.plugins.reload_plugins()
|
||||
|
||||
|
@ -143,6 +150,8 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
|||
event_system.emit("show_plugins_popup")
|
||||
if action == "messages_popup":
|
||||
event_system.emit("show_messages_popup")
|
||||
if action == "tear_down":
|
||||
event_system.emit("tear_down")
|
||||
|
||||
|
||||
@endpoint_registry.register(rule="go_home")
|
|
@ -1,7 +1,6 @@
|
|||
# Python imports
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
@ -9,12 +8,13 @@ from dataclasses import dataclass
|
|||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from shellfm.windows.controller import WindowController
|
||||
from plugins.plugins_controller import PluginsController
|
||||
|
||||
# from factories.split_view_widget import SplitViewWidget
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -40,14 +40,21 @@ class Controller_Data:
|
|||
__slots__ = "settings", "builder", "logger", "keybindings", "trashman", "fm_controller", "window", "window1", "window2", "window3", "window4"
|
||||
|
||||
def setup_controller_data(self) -> None:
|
||||
self.builder = settings.get_builder()
|
||||
self.keybindings = settings.get_keybindings()
|
||||
self.window = settings.get_main_window()
|
||||
self.builder = None
|
||||
self.core_widget = None
|
||||
|
||||
self._load_glade_file()
|
||||
self.fm_controller = WindowController()
|
||||
self.plugins = PluginsController()
|
||||
self.fm_controller_data = self.fm_controller.get_state_from_file()
|
||||
|
||||
self.window = settings.get_main_window()
|
||||
|
||||
# self.pane_master = self.builder.get_object("pane_master")
|
||||
# self.pane_master.pack1(SplitViewWidget(), True, True)
|
||||
# self.pane_master.pack2(SplitViewWidget(), True, True)
|
||||
|
||||
|
||||
self.window1 = self.builder.get_object("window_1")
|
||||
self.window2 = self.builder.get_object("window_2")
|
||||
self.window3 = self.builder.get_object("window_3")
|
||||
|
@ -77,14 +84,19 @@ class Controller_Data:
|
|||
self.alt_down = False
|
||||
|
||||
# sys.excepthook = self.custom_except_hook
|
||||
self.window.connect("delete-event", self.tear_down)
|
||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.tear_down)
|
||||
|
||||
self.window.show()
|
||||
if settings.is_debug():
|
||||
self.window.set_interactive_debugging(True)
|
||||
|
||||
|
||||
def custom_except_hook(self, exc_type, exc_value, exc_traceback):
|
||||
if issubclass(exc_type, KeyboardInterrupt):
|
||||
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||
return
|
||||
|
||||
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
|
||||
|
||||
|
||||
def get_current_state(self) -> State:
|
||||
'''
|
||||
Returns the state info most useful for any given context and action intent.
|
|
@ -88,7 +88,13 @@ class FileSystemActions(HandlerMixin, CRUDMixin):
|
|||
|
||||
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_raw)
|
||||
uris = state.uris_raw
|
||||
|
||||
if not state.uris_raw:
|
||||
uris = [f"file://{state.tab.get_current_directory()}"]
|
||||
|
||||
state.tab.app_chooser_exec(app_info, uris)
|
||||
|
||||
|
||||
def execute_files(self, in_terminal=False):
|
||||
state = event_system.emit_and_await("get_current_state")
|
|
@ -70,9 +70,6 @@ class HandlerMixin:
|
|||
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:
|
||||
|
@ -98,8 +95,6 @@ class HandlerMixin:
|
|||
|
||||
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()
|
|
@ -46,7 +46,7 @@ class KeyboardSignalsMixin:
|
|||
if "alt" in keyname:
|
||||
self.alt_down = False
|
||||
|
||||
mapping = self.keybindings.lookup(event)
|
||||
mapping = keybindings.lookup(event)
|
||||
if mapping:
|
||||
# See if in filemanager scope
|
||||
try:
|
||||
|
@ -62,8 +62,7 @@ class KeyboardSignalsMixin:
|
|||
|
||||
self.handle_plugin_key_event(sender, eve_type)
|
||||
else:
|
||||
if settings.is_debug():
|
||||
print(f"on_global_key_release_controller > key > {keyname}")
|
||||
logger.debug(f"on_global_key_release_controller > key > {keyname}")
|
||||
|
||||
if self.ctrl_down:
|
||||
if keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]:
|
|
@ -23,6 +23,12 @@ 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
|
||||
|
@ -54,8 +60,8 @@ class WindowMixin(TabMixin):
|
|||
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:
|
||||
print("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n")
|
||||
print(repr(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
|
||||
|
@ -115,9 +121,7 @@ class WindowMixin(TabMixin):
|
|||
file_size = file_info.get_size()
|
||||
combined_size += file_size
|
||||
except WindowException as e:
|
||||
if settings.is_debug():
|
||||
print(repr(e))
|
||||
|
||||
logger.debug(repr(e))
|
||||
|
||||
formatted_size = sizeof_fmt(combined_size)
|
||||
if tab.is_hiding_hidden():
|
||||
|
@ -204,7 +208,7 @@ class WindowMixin(TabMixin):
|
|||
event_system.emit("show_context_menu")
|
||||
|
||||
except WindowException as e:
|
||||
print(repr(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):
|
|
@ -41,7 +41,7 @@ class ContextMenuWidget(Gtk.Menu):
|
|||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
logger.debug(repr(e))
|
||||
|
||||
self._builder.connect_signals(handlers)
|
||||
|
|
@ -45,7 +45,7 @@ class AboutWidget:
|
|||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
logger.debug(repr(e))
|
||||
|
||||
self._builder.connect_signals(handlers)
|
||||
|
|
@ -59,7 +59,7 @@ class FileExistsWidget:
|
|||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
logger.debug(repr(e))
|
||||
|
||||
self._builder.connect_signals(handlers)
|
||||
|
|
@ -51,7 +51,7 @@ class RenameWidget:
|
|||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
logger.debug(repr(e))
|
||||
|
||||
self._builder.connect_signals(handlers)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
FileView 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 shellfm.windows.tabs.tab import Tab
|
||||
from .icon_view import IconView
|
||||
|
||||
|
||||
|
||||
|
||||
class FileView(Gtk.ScrolledWindow):
|
||||
"""docstring for FileView."""
|
||||
|
||||
def __init__(self):
|
||||
super(FileView, self).__init__()
|
||||
self.tab_state = Tab()
|
||||
self.icon_view = IconView(self.tab_state)
|
||||
self.tab_widget = self.create_tab_widget()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
|
||||
self.add(self.icon_view)
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
# self.connect("update-tab-title", self._update_tab_title)
|
||||
...
|
||||
|
||||
def _update_tab_title(self, widget=None, eve=None):
|
||||
label = self.tab_widget.get_children()[0]
|
||||
label.set_label(f"{self.tab_state.get_end_of_path()}")
|
||||
label.set_width_chars( len(self.tab_state.get_end_of_path()) )
|
||||
|
||||
def set_path(self, path):
|
||||
if path:
|
||||
self.tab_state.set_path(path)
|
||||
self.icon_view.load_store()
|
||||
self._update_tab_title()
|
||||
|
||||
def create_tab_widget(self):
|
||||
button_box = Gtk.ButtonBox()
|
||||
label = Gtk.Label()
|
||||
close = Gtk.Button()
|
||||
icon = Gtk.Image(stock=Gtk.STOCK_CLOSE)
|
||||
|
||||
label.set_label(f"{self.tab_state.get_end_of_path()}")
|
||||
label.set_width_chars(len(self.tab_state.get_end_of_path()))
|
||||
label.set_xalign(0.0)
|
||||
|
||||
close.add(icon)
|
||||
button_box.add(label)
|
||||
button_box.add(close)
|
||||
|
||||
close.connect("released", self.close_tab)
|
||||
|
||||
button_box.show_all()
|
||||
return button_box
|
||||
|
||||
|
||||
def close_tab(self, widget, eve=None):
|
||||
self.get_parent().emit('close-view', (self,))
|
|
@ -0,0 +1,149 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from .file_view import FileView
|
||||
|
||||
|
||||
|
||||
|
||||
class FilesWidget(Gtk.Notebook):
|
||||
"""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.set_group_name("file_window")
|
||||
|
||||
self.NAME = f"window_{self.ccount}"
|
||||
builder = settings.get_builder()
|
||||
builder.expose_object(self.NAME, self)
|
||||
|
||||
self._add_action_widgets()
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_scrollable(True)
|
||||
self.set_show_tabs(True)
|
||||
self.set_show_border(False)
|
||||
self.set_hexpand(True)
|
||||
|
||||
self.set_margin_top(5)
|
||||
self.set_margin_bottom(5)
|
||||
self.set_margin_start(5)
|
||||
self.set_margin_end(5)
|
||||
|
||||
def _setup_signals(self):
|
||||
# self.connect("close-view", self.close_view)
|
||||
event_system.subscribe("load-window-state", self.load_window_state)
|
||||
|
||||
def _add_action_widgets(self):
|
||||
start_box = Gtk.Box()
|
||||
end_box = Gtk.Box()
|
||||
|
||||
search = Gtk.SearchEntry()
|
||||
search.set_placeholder_text("Search...")
|
||||
search.connect("changed", self._do_query)
|
||||
|
||||
home_btn = Gtk.Button()
|
||||
home_btn.set_image( Gtk.Image.new_from_icon_name("gtk-home", 4) )
|
||||
home_btn.set_always_show_image(True)
|
||||
home_btn.connect("released", self.do_action, ("go_home_dir"))
|
||||
|
||||
up_btn = Gtk.Button()
|
||||
up_btn.set_image( Gtk.Image.new_from_icon_name("up", 4) )
|
||||
up_btn.set_always_show_image(True)
|
||||
up_btn.connect("released", self.do_action, ("go_up_dir"))
|
||||
|
||||
refresh_btn = Gtk.Button()
|
||||
refresh_btn.set_image( Gtk.Image.new_from_icon_name("gtk-refresh", 4) )
|
||||
refresh_btn.set_always_show_image(True)
|
||||
refresh_btn.connect("released", self.do_action, ("refresh_dir"))
|
||||
|
||||
add_btn = Gtk.Button()
|
||||
add_btn.set_image( Gtk.Image.new_from_icon_name("add", 4) )
|
||||
add_btn.set_always_show_image(True)
|
||||
add_btn.connect("released", self.create_view)
|
||||
|
||||
start_box.add(home_btn)
|
||||
start_box.add(add_btn)
|
||||
end_box.add(search)
|
||||
end_box.add(up_btn)
|
||||
end_box.add(refresh_btn)
|
||||
|
||||
start_box.show_all()
|
||||
end_box.show_all()
|
||||
|
||||
# PACKTYPE: 0 Start, 1 = End
|
||||
self.set_action_widget(start_box, 0)
|
||||
self.set_action_widget(end_box, 1)
|
||||
|
||||
def _do_query(self, widget):
|
||||
text = widget.get_text()
|
||||
page = self.get_nth_page( self.get_current_page() )
|
||||
page.icon_view.search_filter(text)
|
||||
|
||||
|
||||
def load_window_state(self, win_name=None, tabs=None):
|
||||
if win_name == self.NAME:
|
||||
if len(tabs) > 0:
|
||||
for tab in tabs:
|
||||
self.create_view()
|
||||
self.load_tab(tab)
|
||||
else:
|
||||
self.create_view()
|
||||
|
||||
def create_view(self, widget = None):
|
||||
file_view = FileView()
|
||||
index = self.append_page(file_view, file_view.tab_widget)
|
||||
self.set_current_page(index)
|
||||
|
||||
return file_view
|
||||
|
||||
def load_tab(self, path = None):
|
||||
if path:
|
||||
file_view = self.get_nth_page( self.get_current_page() )
|
||||
file_view.set_path(path)
|
||||
|
||||
|
||||
def do_action(self, widget = None, action = None):
|
||||
file_view = self.get_nth_page( self.get_current_page() )
|
||||
|
||||
if action == "refresh_dir":
|
||||
file_view.icon_view.refresh_dir()
|
||||
|
||||
if action == "go_up_dir":
|
||||
file_view.icon_view.go_up_dir()
|
||||
|
||||
if action == "go_home_dir":
|
||||
file_view.icon_view.go_home_dir()
|
||||
|
||||
|
||||
def close_view(self, parent, data = None):
|
||||
widget = data[0]
|
||||
page = self.page_num(widget)
|
||||
|
||||
# watcher = widget.tab_state.get_dir_watcher()
|
||||
# watcher.cancel()
|
||||
if self.get_n_pages() > 1:
|
||||
self.remove_page(page)
|
||||
|
||||
# NOTE: Will prob try and call a window custom signal...
|
||||
# self.fm_controller.save_state()
|
||||
# self.set_window_title()
|
|
@ -0,0 +1,146 @@
|
|||
# Python 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
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from .signals.icon_view_signals_mixin import IconViewSignalsMixin
|
||||
|
||||
|
||||
|
||||
|
||||
class IconView(IconViewSignalsMixin, Gtk.FlowBox):
|
||||
"""docstring for IconView."""
|
||||
|
||||
def __init__(self, _tab_state):
|
||||
super(IconView, self).__init__()
|
||||
self.tab_state = _tab_state
|
||||
self.selected_files = []
|
||||
self.icon_theme = settings.get_icon_theme()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
# self._setup_dnd()
|
||||
self.load_store()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _emmit_signal_to_file_view(self, signal_type):
|
||||
self.get_parent().get_parent().emit(signal_type, None)
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
self.set_valign(Gtk.Align.START)
|
||||
self.set_column_spacing(15)
|
||||
self.set_row_spacing(15)
|
||||
self.set_homogeneous(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
self.set_activate_on_single_click(False)
|
||||
self.connect("child-activated", self.icon_double_click)
|
||||
|
||||
# self.connect("drag-data-get", self.on_drag_set)
|
||||
# self.connect("drag-data-received", self.on_drag_data_received)
|
||||
# self.connect("drag-motion", self.on_drag_motion)
|
||||
|
||||
|
||||
# NOTE: This gets called by a txt box which then shows/hides the flowbox child
|
||||
# https://stackoverflow.com/questions/55828169/how-to-filter-gtk-flowbox-children-with-gtk-entrysearch
|
||||
def search_filter(self, text):
|
||||
def filter_func(fb_child, text):
|
||||
if text.lower() in fb_child.get_name().lower():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
self.set_filter_func(filter_func, text)
|
||||
|
||||
|
||||
def _setup_dnd(self):
|
||||
URI_TARGET_TYPE = 80
|
||||
uri_target = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
|
||||
targets = [ uri_target ]
|
||||
action = Gdk.DragAction.COPY
|
||||
self.enable_model_drag_dest(targets, action)
|
||||
self.enable_model_drag_source(0, targets, action)
|
||||
|
||||
def _clear_children(self, widget: type) -> None:
|
||||
''' Clear children of a gtk widget. '''
|
||||
for child in widget.get_children():
|
||||
widget.remove(child)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# class IconView(IconViewSignalsMixin, Gtk.IconView):
|
||||
# """docstring for IconView."""
|
||||
#
|
||||
# def __init__(self, _tab_state):
|
||||
# super(IconView, self).__init__()
|
||||
# self.store = None
|
||||
# self.tab_state = _tab_state
|
||||
# self.selected_files = []
|
||||
# self.icon_theme = Gtk.IconTheme.get_default()
|
||||
#
|
||||
# self._setup_store()
|
||||
# self._setup_styling()
|
||||
# self._setup_signals()
|
||||
# self._setup_dnd()
|
||||
# self.load_store()
|
||||
#
|
||||
# self.show_all()
|
||||
#
|
||||
#
|
||||
# def _setup_store(self):
|
||||
# self.store = Gtk.ListStore(GdkPixbuf.Pixbuf or GdkPixbuf.PixbufAnimation or None, str or None)
|
||||
# self.set_model(self.store)
|
||||
# self.set_pixbuf_column(0)
|
||||
# self.set_text_column(1)
|
||||
#
|
||||
# def _setup_styling(self):
|
||||
# self.set_item_orientation(1)
|
||||
# self.set_selection_mode(3)
|
||||
# self.set_item_width(96)
|
||||
# self.set_item_padding(8)
|
||||
# self.set_margin(12)
|
||||
# self.set_row_spacing(18)
|
||||
# self.set_columns(-1)
|
||||
# self.set_spacing(12)
|
||||
# self.set_column_spacing(18)
|
||||
#
|
||||
# def _setup_signals(self):
|
||||
# # self.connect("button_release_event", self.icon_single_click)
|
||||
# self.connect("item-activated", self.icon_double_click)
|
||||
# self.connect("selection-changed", self.set_selected_items)
|
||||
# # self.connect("drag-data-get", self.on_drag_set)
|
||||
# # self.connect("drag-data-received", self.on_drag_data_received)
|
||||
# # self.connect("drag-motion", self.on_drag_motion)
|
||||
# pass
|
||||
#
|
||||
# def _setup_dnd(self):
|
||||
# URI_TARGET_TYPE = 80
|
||||
# uri_target = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
|
||||
# targets = [ uri_target ]
|
||||
# action = Gdk.DragAction.COPY
|
||||
# self.enable_model_drag_dest(targets, action)
|
||||
# self.enable_model_drag_source(0, targets, action)
|
||||
#
|
||||
# def set_selected_items(self, icons_grid):
|
||||
# self.selected_files = self.get_selected_items()
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Signals module
|
||||
"""
|
|
@ -0,0 +1,183 @@
|
|||
# Python imports
|
||||
import os
|
||||
import traceback
|
||||
import threading
|
||||
import subprocess
|
||||
import time
|
||||
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 GLib
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Gio
|
||||
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
|
||||
class FileView(Gtk.Box):
|
||||
"""docstring for FileView."""
|
||||
|
||||
def __init__(self, _icon = None, _label = None):
|
||||
super(FileView, self).__init__()
|
||||
self.icon = None
|
||||
self.label = _label
|
||||
|
||||
self.label.set_line_wrap(True)
|
||||
self.label.set_selectable(True)
|
||||
self.label.set_max_width_chars(20)
|
||||
self.label.set_justify(2)
|
||||
self.label.set_line_wrap_mode(2)
|
||||
|
||||
self.add(self.label)
|
||||
self.set_orientation(1)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def set_img(self, img):
|
||||
self.icon = img
|
||||
self.add(img)
|
||||
self.reorder_child(self.icon, 0)
|
||||
|
||||
|
||||
|
||||
class IconViewSignalsMixin:
|
||||
"""docstring for WidgetMixin"""
|
||||
|
||||
def load_store(self):
|
||||
self._clear_children(self)
|
||||
self.search_filter("")
|
||||
|
||||
dir = self.tab_state.get_current_directory()
|
||||
files = self.tab_state.get_files()
|
||||
|
||||
for i, file in enumerate(files):
|
||||
label = Gtk.Label(label=file[0])
|
||||
child = Gtk.FlowBoxChild()
|
||||
child.set_name(file[0])
|
||||
|
||||
file_view = FileView(_label=label)
|
||||
child.add( file_view )
|
||||
self.add(child)
|
||||
self.create_icon(file_view, dir, file[0])
|
||||
|
||||
@threaded
|
||||
def create_icon(self, file_view, dir, file):
|
||||
icon = self.tab_state.create_icon(dir, file)
|
||||
GLib.idle_add(self.update_store, *(file_view, icon, dir, file,))
|
||||
|
||||
def update_store(self, file_view, icon, dir, file):
|
||||
if not icon:
|
||||
path = f"{dir}/{file}"
|
||||
icon = self.get_system_thumbnail(path, self.tab_state.sys_icon_wh[0])
|
||||
|
||||
if not icon:
|
||||
icon = GdkPixbuf.Pixbuf.new_from_file(self.tab_state.DEFAULT_ICON)
|
||||
|
||||
img = Gtk.Image.new_from_pixbuf(icon)
|
||||
img.show()
|
||||
file_view.set_img(img)
|
||||
self.show_all()
|
||||
|
||||
|
||||
def get_system_thumbnail(self, filename, size):
|
||||
try:
|
||||
gio_file = Gio.File.new_for_path(filename)
|
||||
info = gio_file.query_info('standard::icon' , 0, None)
|
||||
icon = info.get_icon().get_names()[0]
|
||||
icon_path = self.icon_theme.lookup_icon(icon , size , 0).get_filename()
|
||||
|
||||
return GdkPixbuf.Pixbuf.new_from_file(icon_path)
|
||||
except Exception:
|
||||
...
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def icon_double_click(self, icons_grid, item, data=None):
|
||||
try:
|
||||
file_view = item.get_children()[0]
|
||||
file_name = file_view.label.get_label()
|
||||
dir = self.tab_state.get_current_directory()
|
||||
file = f"{dir}/{file_name}"
|
||||
|
||||
if isdir(file):
|
||||
self.tab_state.set_path(file)
|
||||
self.load_store()
|
||||
self._emmit_signal_to_file_view('update-tab-title')
|
||||
else:
|
||||
event_system.emit("open_files", (self, file))
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def go_up_dir(self):
|
||||
self.tab_state.pop_from_path()
|
||||
self.load_store()
|
||||
self._emmit_signal_to_file_view('update-tab-title')
|
||||
|
||||
def go_home_dir(self):
|
||||
self.tab_state.set_to_home()
|
||||
self.load_store()
|
||||
self._emmit_signal_to_file_view('update-tab-title')
|
||||
|
||||
def go_to_path(self, path):
|
||||
self.tab_state.set_path(path)
|
||||
self.load_store()
|
||||
self._emmit_signal_to_file_view('update-tab-title')
|
||||
|
||||
def refresh_dir(self):
|
||||
self.tab_state.load_directory()
|
||||
self.load_store()
|
||||
|
||||
# def 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 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()
|
||||
# treePath = icons_grid.get_drag_dest_item().path
|
||||
#
|
||||
# if treePath:
|
||||
# uri = self.format_to_uris(store, wid, tid, treePath)[0].replace("file://", "")
|
||||
# self.override_drop_dest = uri if isdir(uri) else None
|
||||
#
|
||||
# if target not in current:
|
||||
# self.fm_controller.set_wid_and_tid(wid, tid)
|
||||
#
|
||||
#
|
||||
# def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
|
||||
# if info == 80:
|
||||
# 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)
|
||||
#
|
||||
# uris = data.get_uris()
|
||||
# dest = f"{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:
|
||||
# self.move_files(uris, dest)
|
|
@ -60,7 +60,7 @@ class IOWidget(Gtk.Box):
|
|||
self.add(stats)
|
||||
|
||||
def do_cancel(self, widget, container, eve):
|
||||
print(f"Canceling: [{self._action}] of {self._basename} ...")
|
||||
logger.info(f"Canceling: [{self._action}] of {self._basename} ...")
|
||||
eve.cancel()
|
||||
|
||||
def update_progress(self, current, total, eve=None):
|
||||
|
@ -75,7 +75,7 @@ class IOWidget(Gtk.Box):
|
|||
if status:
|
||||
self.delete_self()
|
||||
else:
|
||||
print(f"{self._action} of {self._basename} failed...")
|
||||
logger.info(f"{self._action} of {self._basename} failed...")
|
||||
|
||||
def delete_self(self, widget=None, eve=None):
|
||||
self.get_parent().remove(self)
|
|
@ -16,18 +16,17 @@ class IOPopupWidget(Gtk.Popover):
|
|||
|
||||
def __init__(self):
|
||||
super(IOPopupWidget, self).__init__()
|
||||
self.builder = settings.get_builder()
|
||||
self._builder = settings.get_builder()
|
||||
|
||||
self.builder.expose_object(f"io_popup", self)
|
||||
self._builder.expose_object(f"io_popup", self)
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
io_button = self.builder.get_object(f"io_button")
|
||||
io_button = self._builder.get_object(f"io_button")
|
||||
self.set_relative_to(io_button)
|
||||
self.set_modal(True)
|
||||
self.set_position(Gtk.PositionType.BOTTOM)
|
||||
|
@ -40,7 +39,7 @@ class IOPopupWidget(Gtk.Popover):
|
|||
vbox = Gtk.Box()
|
||||
|
||||
vbox.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.builder.expose_object(f"io_list", vbox)
|
||||
self._builder.expose_object(f"io_list", vbox)
|
||||
self.add(vbox)
|
||||
|
||||
def show_io_popup(self, widget=None, eve=None):
|
|
@ -28,7 +28,6 @@ class MessagePopupWidget(Gtk.Popover):
|
|||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
|
@ -23,7 +23,6 @@ class PluginsPopupWidget(Gtk.Popover):
|
|||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
|
@ -0,0 +1,95 @@
|
|||
# Python imports
|
||||
import time
|
||||
import signal
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
import cairo
|
||||
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 GLib
|
||||
|
||||
# Application imports
|
||||
from core.controller import Controller
|
||||
|
||||
|
||||
|
||||
|
||||
class Window(Gtk.ApplicationWindow):
|
||||
"""docstring for Window."""
|
||||
|
||||
def __init__(self, args, unknownargs):
|
||||
super(Window, self).__init__()
|
||||
|
||||
self._controller = None
|
||||
settings.set_main_window(self)
|
||||
|
||||
self._set_window_data()
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
|
||||
self._load_widgets(args, unknownargs)
|
||||
|
||||
self.show()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_default_size(1670, 830)
|
||||
self.set_title(f"{app_name}")
|
||||
self.set_icon_from_file( settings.get_window_icon() )
|
||||
self.set_gravity(5) # 5 = CENTER
|
||||
self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("delete-event", self._tear_down)
|
||||
|
||||
# self.connect("focus-out-event", self._controller.unset_keys_and_data)
|
||||
# self.connect("key-press-event", self._controller.on_global_key_press_controller)
|
||||
# self.connect("key-release-event", self._controller.on_global_key_release_controller)
|
||||
|
||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("tear_down", self._tear_down)
|
||||
|
||||
def _load_widgets(self, args, unknownargs):
|
||||
self._controller = Controller(args, unknownargs)
|
||||
|
||||
if not self._controller:
|
||||
raise ControllerStartException("Controller exited and doesn't exist...")
|
||||
|
||||
self.add( self._controller.get_core_widget() )
|
||||
|
||||
def _set_window_data(self) -> None:
|
||||
screen = self.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
|
||||
if visual != None and screen.is_composited():
|
||||
self.set_visual(visual)
|
||||
self.set_app_paintable(True)
|
||||
self.connect("draw", self._area_draw)
|
||||
|
||||
# bind css file
|
||||
cssProvider = Gtk.CssProvider()
|
||||
cssProvider.load_from_path( settings.get_css_file() )
|
||||
screen = Gdk.Screen.get_default()
|
||||
styleContext = Gtk.StyleContext()
|
||||
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
|
||||
cr.set_source_rgba(0, 0, 0, 0.54)
|
||||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||
cr.paint()
|
||||
cr.set_operator(cairo.OPERATOR_OVER)
|
||||
|
||||
|
||||
def _tear_down(self, widget=None, eve=None):
|
||||
if not settings.is_trace_debug():
|
||||
self._controller.fm_controller.save_state()
|
||||
|
||||
settings.clear_pid()
|
||||
time.sleep(event_sleep_time)
|
||||
Gtk.main_quit()
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Factories Module
|
||||
"""
|
|
@ -0,0 +1,33 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from core.widgets.fm_widget.files_widget import FilesWidget
|
||||
|
||||
|
||||
|
||||
|
||||
class SplitViewWidget(Gtk.Paned):
|
||||
def __init__(self):
|
||||
super(SplitViewWidget, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_wide_handle(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.pack1(FilesWidget(), resize=False, shrink=False)
|
||||
self.pack2(FilesWidget(), resize=True, shrink=False)
|
|
@ -82,8 +82,8 @@ class ManifestProcessor:
|
|||
for ui_id in requests["pass_ui_objects"]:
|
||||
try:
|
||||
loading_data["pass_ui_objects"].append( self._builder.get_object(ui_id) )
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
except ManifestProcessorException as e:
|
||||
logger.error(repr(e))
|
||||
|
||||
if "bind_keys" in keys:
|
||||
if isinstance(requests["bind_keys"], list):
|
|
@ -24,7 +24,6 @@ class PluginBase:
|
|||
self._event_system = None
|
||||
|
||||
|
||||
|
||||
def set_fm_event_system(self, fm_event_system):
|
||||
"""
|
||||
Requests Key: 'pass_fm_events': "true"
|
||||
|
@ -76,7 +75,7 @@ class PluginBase:
|
|||
methods = inspect.getmembers(c, predicate=inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
logger.debug(repr(e))
|
||||
|
||||
builder.connect_signals(handlers)
|
||||
|
|
@ -32,7 +32,6 @@ class PluginsController:
|
|||
|
||||
self._builder = settings.get_builder()
|
||||
self._plugins_path = settings.get_plugins_path()
|
||||
self._keybindings = settings.get_keybindings()
|
||||
|
||||
self._plugins_dir_watcher = None
|
||||
self._plugin_collection = []
|
||||
|
@ -54,7 +53,7 @@ class PluginsController:
|
|||
self.reload_plugins(file)
|
||||
|
||||
def load_plugins(self, file: str = None) -> None:
|
||||
print(f"Loading plugins...")
|
||||
logger.info(f"Loading plugins...")
|
||||
parent_path = os.getcwd()
|
||||
|
||||
for path, folder in [[join(self._plugins_path, item), item] if os.path.isdir(join(self._plugins_path, item)) else None for item in os.listdir(self._plugins_path)]:
|
||||
|
@ -63,14 +62,14 @@ class PluginsController:
|
|||
manifest = ManifestProcessor(path, self._builder)
|
||||
|
||||
if not os.path.exists(target):
|
||||
raise InvalidPluginException("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
|
||||
raise FileNotFoundError("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
|
||||
|
||||
plugin, loading_data = manifest.get_loading_data()
|
||||
module = self.load_plugin_module(path, folder, target)
|
||||
self.execute_plugin(module, plugin, loading_data)
|
||||
except Exception as e:
|
||||
print(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
||||
traceback.print_exc()
|
||||
except InvalidPluginException as e:
|
||||
logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
||||
logger.debug("Trace: ", traceback.print_exc())
|
||||
|
||||
os.chdir(parent_path)
|
||||
|
||||
|
@ -111,13 +110,13 @@ class PluginsController:
|
|||
plugin.reference.subscribe_to_events()
|
||||
|
||||
if "bind_keys" in keys:
|
||||
self._keybindings.append_bindings( loading_data["bind_keys"] )
|
||||
keybindings.append_bindings( loading_data["bind_keys"] )
|
||||
|
||||
plugin.reference.run()
|
||||
self._plugin_collection.append(plugin)
|
||||
|
||||
def reload_plugins(self, file: str = None) -> None:
|
||||
print(f"Reloading plugins...")
|
||||
logger.info(f"Reloading plugins...")
|
||||
parent_path = os.getcwd()
|
||||
|
||||
for plugin in self._plugin_collection:
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue