Bringing to latest changes #3
|
@ -10,7 +10,7 @@ from controller import IPCServerMixin
|
||||||
|
|
||||||
|
|
||||||
class Builtins(IPCServerMixin):
|
class Builtins(IPCServerMixin):
|
||||||
"""Docstring for __builtins__ extender"""
|
""" Inheret IPCServerMixin. Create an pub/sub systems. """
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# NOTE: The format used is list of [type, target, (data,)] Where:
|
# NOTE: The format used is list of [type, target, (data,)] Where:
|
||||||
|
|
|
@ -12,6 +12,8 @@ from __builtins__ import Builtins
|
||||||
|
|
||||||
|
|
||||||
class Main(Builtins):
|
class Main(Builtins):
|
||||||
|
''' Create Settings and Controller classes. Bind signal to Builder. Inherit from Builtins to bind global methods and classes.'''
|
||||||
|
|
||||||
def __init__(self, args, unknownargs):
|
def __init__(self, args, unknownargs):
|
||||||
if not debug:
|
if not debug:
|
||||||
event_system.create_ipc_server()
|
event_system.create_ipc_server()
|
||||||
|
|
|
@ -19,6 +19,8 @@ from __init__ import Main
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
''' Set process title, get arguments, and create GTK main thread. '''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# import web_pdb
|
# import web_pdb
|
||||||
# web_pdb.set_trace()
|
# web_pdb.set_trace()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Python imports
|
# Python imports
|
||||||
import sys, traceback, threading, inspect, os, time
|
import traceback, threading, inspect, os, time
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
|
@ -7,7 +7,7 @@ gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, GLib
|
from gi.repository import Gtk, GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .mixins import UIMixin
|
from .mixins import ExceptionHookMixin, UIMixin
|
||||||
from .signals import IPCSignalsMixin, KeyboardSignalsMixin
|
from .signals import IPCSignalsMixin, KeyboardSignalsMixin
|
||||||
from . import Controller_Data
|
from . import Controller_Data
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ def threaded(fn):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, Controller_Data):
|
class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMixin, Controller_Data):
|
||||||
|
''' Controller coordinates the mixins and is somewhat the root hub of it all. '''
|
||||||
def __init__(self, args, unknownargs, _settings):
|
def __init__(self, args, unknownargs, _settings):
|
||||||
sys.excepthook = self.custom_except_hook
|
|
||||||
self.setup_controller_data(_settings)
|
self.setup_controller_data(_settings)
|
||||||
self.window.show()
|
self.window.show()
|
||||||
self.generate_windows(self.state)
|
self.generate_windows(self.state)
|
||||||
|
@ -71,60 +71,6 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, Controller_Data
|
||||||
data = method(*(self, *parameters))
|
data = method(*(self, *parameters))
|
||||||
self.plugins.set_message_on_plugin(type, data)
|
self.plugins.set_message_on_plugin(type, data)
|
||||||
|
|
||||||
def custom_except_hook(self, exctype, value, _traceback):
|
|
||||||
trace = ''.join(traceback.format_tb(_traceback))
|
|
||||||
data = f"Exectype: {exctype} <--> Value: {value}\n\n{trace}\n\n\n\n"
|
|
||||||
start_itr = self.message_buffer.get_start_iter()
|
|
||||||
self.message_buffer.place_cursor(start_itr)
|
|
||||||
self.display_message(self.error, data)
|
|
||||||
|
|
||||||
def display_message(self, type, text, seconds=None):
|
|
||||||
self.message_buffer.insert_at_cursor(text)
|
|
||||||
self.message_widget.popup()
|
|
||||||
if seconds:
|
|
||||||
self.hide_message_timeout(seconds)
|
|
||||||
|
|
||||||
@threaded
|
|
||||||
def hide_message_timeout(self, seconds=3):
|
|
||||||
time.sleep(seconds)
|
|
||||||
GLib.idle_add(self.message_widget.popdown)
|
|
||||||
|
|
||||||
def save_debug_alerts(self, widget=None, eve=None):
|
|
||||||
start_itr, end_itr = self.message_buffer.get_bounds()
|
|
||||||
save_location_prompt = Gtk.FileChooserDialog("Choose Save Folder", self.window, \
|
|
||||||
action = Gtk.FileChooserAction.SAVE, \
|
|
||||||
buttons = (Gtk.STOCK_CANCEL, \
|
|
||||||
Gtk.ResponseType.CANCEL, \
|
|
||||||
Gtk.STOCK_SAVE, \
|
|
||||||
Gtk.ResponseType.OK))
|
|
||||||
|
|
||||||
text = self.message_buffer.get_text(start_itr, end_itr, False)
|
|
||||||
resp = save_location_prompt.run()
|
|
||||||
if (resp == Gtk.ResponseType.CANCEL) or (resp == Gtk.ResponseType.DELETE_EVENT):
|
|
||||||
pass
|
|
||||||
elif resp == Gtk.ResponseType.OK:
|
|
||||||
target = save_location_prompt.get_filename();
|
|
||||||
with open(target, "w") as f:
|
|
||||||
f.write(text)
|
|
||||||
|
|
||||||
save_location_prompt.destroy()
|
|
||||||
|
|
||||||
|
|
||||||
def set_arc_buffer_text(self, widget=None, eve=None):
|
|
||||||
id = widget.get_active_id()
|
|
||||||
self.arc_command_buffer.set_text(self.arc_commands[int(id)])
|
|
||||||
|
|
||||||
|
|
||||||
def clear_children(self, widget):
|
|
||||||
for child in widget.get_children():
|
|
||||||
widget.remove(child)
|
|
||||||
|
|
||||||
def get_current_state(self):
|
|
||||||
wid, tid = self.window_controller.get_active_data()
|
|
||||||
view = self.get_fm_window(wid).get_view_by_id(tid)
|
|
||||||
iconview = self.builder.get_object(f"{wid}|{tid}|iconview")
|
|
||||||
store = iconview.get_model()
|
|
||||||
return wid, tid, view, iconview, store
|
|
||||||
|
|
||||||
def do_action_from_menu_controls(self, widget, eventbutton):
|
def do_action_from_menu_controls(self, widget, eventbutton):
|
||||||
action = widget.get_name()
|
action = widget.get_name()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Python imports
|
# Python imports
|
||||||
import signal
|
import sys, os, signal
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
@ -13,8 +13,7 @@ from plugins import Plugins
|
||||||
|
|
||||||
|
|
||||||
class Controller_Data:
|
class Controller_Data:
|
||||||
def has_method(self, o, name):
|
''' Controller_Data contains most of the state of the app at ay given time. It also has some support methods. '''
|
||||||
return callable(getattr(o, name, None))
|
|
||||||
|
|
||||||
def setup_controller_data(self, _settings):
|
def setup_controller_data(self, _settings):
|
||||||
self.trashman = XDGTrash()
|
self.trashman = XDGTrash()
|
||||||
|
@ -104,6 +103,53 @@ class Controller_Data:
|
||||||
self.warning = "#ffa800"
|
self.warning = "#ffa800"
|
||||||
self.error = "#ff0000"
|
self.error = "#ff0000"
|
||||||
|
|
||||||
|
sys.excepthook = self.custom_except_hook
|
||||||
self.window.connect("delete-event", self.tear_down)
|
self.window.connect("delete-event", self.tear_down)
|
||||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.tear_down)
|
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.tear_down)
|
||||||
|
|
||||||
|
def get_current_state(self):
|
||||||
|
'''
|
||||||
|
Returns the state info most useful for any given context and action intent.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
a (obj): self
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
wid, tid, view, iconview, store
|
||||||
|
'''
|
||||||
|
wid, tid = self.window_controller.get_active_data()
|
||||||
|
view = self.get_fm_window(wid).get_view_by_id(tid)
|
||||||
|
iconview = self.builder.get_object(f"{wid}|{tid}|iconview")
|
||||||
|
store = iconview.get_model()
|
||||||
|
return wid, tid, view, iconview, store
|
||||||
|
|
||||||
|
|
||||||
|
def clear_console(self):
|
||||||
|
''' Clears the terminal screen. '''
|
||||||
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
|
||||||
|
def call_method(self, _method_name, data = None):
|
||||||
|
'''
|
||||||
|
Calls a method from scope of class.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
a (obj): self
|
||||||
|
b (str): method name to be called
|
||||||
|
c (*): Data (if any) to be passed to the method.
|
||||||
|
Note: It must be structured according to the given methods requirements.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Return data is that which the calling method gives.
|
||||||
|
'''
|
||||||
|
method_name = str(_method_name)
|
||||||
|
method = getattr(self, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}")
|
||||||
|
return method(data) if data else method()
|
||||||
|
|
||||||
|
def has_method(self, obj, name):
|
||||||
|
''' Checks if a given method exists. '''
|
||||||
|
return callable(getattr(obj, name, None))
|
||||||
|
|
||||||
|
def clear_children(self, widget):
|
||||||
|
''' Clear children of a gtk widget. '''
|
||||||
|
for child in widget.get_children():
|
||||||
|
widget.remove(child)
|
||||||
|
|
|
@ -16,6 +16,7 @@ def threaded(fn):
|
||||||
|
|
||||||
|
|
||||||
class IPCServerMixin:
|
class IPCServerMixin:
|
||||||
|
''' Create a listener so that other SolarFM instances send requests back to existing instance. '''
|
||||||
|
|
||||||
@threaded
|
@threaded
|
||||||
def create_ipc_server(self):
|
def create_ipc_server(self):
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Python imports
|
||||||
|
import traceback, threading, time
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
from gi.repository import Gtk, GLib
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
def threaded(fn):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionHookMixin:
|
||||||
|
''' ExceptionHookMixin custom exception hook to reroute to a Gtk text area. '''
|
||||||
|
|
||||||
|
def custom_except_hook(self, exctype, value, _traceback):
|
||||||
|
trace = ''.join(traceback.format_tb(_traceback))
|
||||||
|
data = f"Exectype: {exctype} <--> Value: {value}\n\n{trace}\n\n\n\n"
|
||||||
|
start_itr = self.message_buffer.get_start_iter()
|
||||||
|
self.message_buffer.place_cursor(start_itr)
|
||||||
|
self.display_message(self.error, data)
|
||||||
|
|
||||||
|
def display_message(self, type, text, seconds=None):
|
||||||
|
self.message_buffer.insert_at_cursor(text)
|
||||||
|
self.message_widget.popup()
|
||||||
|
if seconds:
|
||||||
|
self.hide_message_timeout(seconds)
|
||||||
|
|
||||||
|
@threaded
|
||||||
|
def hide_message_timeout(self, seconds=3):
|
||||||
|
time.sleep(seconds)
|
||||||
|
GLib.idle_add(self.message_widget.popdown)
|
||||||
|
|
||||||
|
def save_debug_alerts(self, widget=None, eve=None):
|
||||||
|
start_itr, end_itr = self.message_buffer.get_bounds()
|
||||||
|
save_location_prompt = Gtk.FileChooserDialog("Choose Save Folder", self.window, \
|
||||||
|
action = Gtk.FileChooserAction.SAVE, \
|
||||||
|
buttons = (Gtk.STOCK_CANCEL, \
|
||||||
|
Gtk.ResponseType.CANCEL, \
|
||||||
|
Gtk.STOCK_SAVE, \
|
||||||
|
Gtk.ResponseType.OK))
|
||||||
|
|
||||||
|
text = self.message_buffer.get_text(start_itr, end_itr, False)
|
||||||
|
resp = save_location_prompt.run()
|
||||||
|
if (resp == Gtk.ResponseType.CANCEL) or (resp == Gtk.ResponseType.DELETE_EVENT):
|
||||||
|
pass
|
||||||
|
elif resp == Gtk.ResponseType.OK:
|
||||||
|
target = save_location_prompt.get_filename();
|
||||||
|
with open(target, "w") as f:
|
||||||
|
f.write(text)
|
||||||
|
|
||||||
|
save_location_prompt.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
def set_arc_buffer_text(self, widget=None, eve=None):
|
||||||
|
id = widget.get_active_id()
|
||||||
|
self.arc_command_buffer.set_text(self.arc_commands[int(id)])
|
|
@ -1,2 +1,3 @@
|
||||||
from .ShowHideMixin import ShowHideMixin
|
from .ShowHideMixin import ShowHideMixin
|
||||||
|
from .ExceptionHookMixin import ExceptionHookMixin
|
||||||
from .UIMixin import UIMixin
|
from .UIMixin import UIMixin
|
||||||
|
|
Loading…
Reference in New Issue