Merge Stable Changesto Master #9
@@ -70,7 +70,8 @@ class Plugin(PluginBase):
 | 
			
		||||
    def generate_reference_ui_element(self):
 | 
			
		||||
        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(f"{self.path}/../../icons/video.png", 16, 16, True)
 | 
			
		||||
        icon   = Gtk.Image.new_from_pixbuf(pixbuf)
 | 
			
		||||
        item   = Gtk.ImageMenuItem("Delete")
 | 
			
		||||
        item   = Gtk.ImageMenuItem(self.name)
 | 
			
		||||
 | 
			
		||||
        item.set_image( icon )
 | 
			
		||||
        item.connect("activate", self._show_thumbnailer_page)
 | 
			
		||||
        item.set_always_show_image(True)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
# Python imports
 | 
			
		||||
 | 
			
		||||
# Lib imports
 | 
			
		||||
import gi
 | 
			
		||||
gi.require_version('Gtk', '3.0')
 | 
			
		||||
from gi.repository import Gtk
 | 
			
		||||
from gi.repository import GLib
 | 
			
		||||
 | 
			
		||||
# Application imports
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ContextMenu(Gtk.Menu):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super(ContextMenu, self).__init__()
 | 
			
		||||
        self._builder           = settings.get_builder()
 | 
			
		||||
        self._context_menu_data = settings.get_context_menu_data()
 | 
			
		||||
        self._window            = settings.get_main_window()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def make_submenu(self, name, data, keys):
 | 
			
		||||
        menu      = Gtk.Menu()
 | 
			
		||||
        menu_item = Gtk.MenuItem(name)
 | 
			
		||||
 | 
			
		||||
        for key in keys:
 | 
			
		||||
            if isinstance(data, dict):
 | 
			
		||||
                entry = self.make_menu_item(key, data[key])
 | 
			
		||||
            elif isinstance(data, list):
 | 
			
		||||
                entry = self.make_menu_item(key, data)
 | 
			
		||||
            else:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            menu.append(entry)
 | 
			
		||||
 | 
			
		||||
        menu_item.set_submenu(menu)
 | 
			
		||||
        return menu_item
 | 
			
		||||
 | 
			
		||||
    def make_menu_item(self, name, data) -> Gtk.MenuItem:
 | 
			
		||||
        if isinstance(data, dict):
 | 
			
		||||
            return self.make_submenu(name, data, data.keys())
 | 
			
		||||
        elif isinstance(data, list):
 | 
			
		||||
            entry = Gtk.ImageMenuItem(name)
 | 
			
		||||
            icon  = getattr(Gtk, f"{data[0]}")
 | 
			
		||||
            entry.set_image( Gtk.Image(stock=icon) )
 | 
			
		||||
            entry.set_always_show_image(True)
 | 
			
		||||
            entry.connect("activate", self._emit, (data[1]))
 | 
			
		||||
            return entry
 | 
			
		||||
 | 
			
		||||
    def build_context_menu(self) -> None:
 | 
			
		||||
        data          = self._context_menu_data
 | 
			
		||||
        dkeys         = data.keys()
 | 
			
		||||
        plugins_entry = None
 | 
			
		||||
 | 
			
		||||
        for dkey in dkeys:
 | 
			
		||||
            entry = self.make_menu_item(dkey, data[dkey])
 | 
			
		||||
            self.append(entry)
 | 
			
		||||
            if dkey == "Plugins":
 | 
			
		||||
                plugins_entry = entry
 | 
			
		||||
 | 
			
		||||
        self.attach_to_widget(self._window, None)
 | 
			
		||||
        self.show_all()
 | 
			
		||||
        self._builder.expose_object("context_menu", self)
 | 
			
		||||
        if plugins_entry:
 | 
			
		||||
            self._builder.expose_object("context_menu_plugins", plugins_entry.get_submenu())
 | 
			
		||||
 | 
			
		||||
    def _emit(self, menu_item, type):
 | 
			
		||||
        event_system.emit("do_action_from_menu_controls", type)
 | 
			
		||||
@@ -12,7 +12,7 @@ from .mixins.ui_mixin import UIMixin
 | 
			
		||||
from .signals.ipc_signals_mixin import IPCSignalsMixin
 | 
			
		||||
from .signals.keyboard_signals_mixin import KeyboardSignalsMixin
 | 
			
		||||
from .controller_data import Controller_Data
 | 
			
		||||
 | 
			
		||||
from .context_menu import ContextMenu
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -22,6 +22,10 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
 | 
			
		||||
        self._subscribe_to_events()
 | 
			
		||||
        self.setup_controller_data()
 | 
			
		||||
        self.generate_windows(self.fm_controller_data)
 | 
			
		||||
 | 
			
		||||
        cm = ContextMenu()
 | 
			
		||||
        cm.build_context_menu()
 | 
			
		||||
 | 
			
		||||
        self.plugins.launch_plugins()
 | 
			
		||||
 | 
			
		||||
        for arg in unknownargs + [args.new_tab,]:
 | 
			
		||||
@@ -36,6 +40,7 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
 | 
			
		||||
        event_system.subscribe("display_message", self.display_message)
 | 
			
		||||
        event_system.subscribe("go_to_path", self.go_to_path)
 | 
			
		||||
        event_system.subscribe("do_hide_context_menu", self.do_hide_context_menu)
 | 
			
		||||
        event_system.subscribe("do_action_from_menu_controls", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
    def tear_down(self, widget=None, eve=None):
 | 
			
		||||
        if not settings.is_trace_debug():
 | 
			
		||||
@@ -95,7 +100,11 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def do_action_from_menu_controls(self, widget, eve = None):
 | 
			
		||||
        if not isinstance(widget, str):
 | 
			
		||||
            action = widget.get_name()
 | 
			
		||||
        else:
 | 
			
		||||
            action = widget
 | 
			
		||||
 | 
			
		||||
        self.hide_context_menu()
 | 
			
		||||
        self.hide_new_file_menu()
 | 
			
		||||
        self.hide_edit_file_menu()
 | 
			
		||||
 
 | 
			
		||||
@@ -102,89 +102,6 @@ class Controller_Data:
 | 
			
		||||
        if settings.is_debug():
 | 
			
		||||
            self.window.set_interactive_debugging(True)
 | 
			
		||||
 | 
			
		||||
        self.build_context_menu()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def build_context_menu(self) -> None:
 | 
			
		||||
        main_menu    = Gtk.Menu()
 | 
			
		||||
        open_menu    = Gtk.Menu()
 | 
			
		||||
        filea_menu   = Gtk.Menu()
 | 
			
		||||
        plugins_menu = Gtk.Menu()
 | 
			
		||||
        open_a       = Gtk.MenuItem("Open Actions")
 | 
			
		||||
        file_a       = Gtk.MenuItem("File Actions")
 | 
			
		||||
        plugins      = Gtk.MenuItem("Plugins")
 | 
			
		||||
 | 
			
		||||
        self._appen_menu_items(main_menu, [open_a, file_a, plugins])
 | 
			
		||||
 | 
			
		||||
        open = Gtk.ImageMenuItem("Open")
 | 
			
		||||
        open.set_name("open")
 | 
			
		||||
        open.set_image( Gtk.Image(stock=Gtk.STOCK_OPEN) )
 | 
			
		||||
        open.set_always_show_image(True)
 | 
			
		||||
        open.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        open_with = Gtk.ImageMenuItem("Open With")
 | 
			
		||||
        open_with.set_name("open_with")
 | 
			
		||||
        open_with.set_image( Gtk.Image(stock=Gtk.STOCK_OPEN) )
 | 
			
		||||
        open_with.set_always_show_image(True)
 | 
			
		||||
        open_with.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        execute = Gtk.ImageMenuItem("Execute")
 | 
			
		||||
        execute.set_name("execute")
 | 
			
		||||
        execute.set_image( Gtk.Image(stock=Gtk.STOCK_EXECUTE) )
 | 
			
		||||
        execute.set_always_show_image(True)
 | 
			
		||||
        execute.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        execute_term = Gtk.ImageMenuItem("Execute in Terminal")
 | 
			
		||||
        execute_term.set_name("execute_in_terminal")
 | 
			
		||||
        execute_term.set_image( Gtk.Image(stock=Gtk.STOCK_EXECUTE) )
 | 
			
		||||
        execute_term.set_always_show_image(True)
 | 
			
		||||
        execute_term.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        self._appen_menu_items(open_menu, [open, open_with, execute, execute_term])
 | 
			
		||||
 | 
			
		||||
        new = Gtk.ImageMenuItem("New")
 | 
			
		||||
        new.set_name("create")
 | 
			
		||||
        new.set_image( Gtk.Image(stock=Gtk.STOCK_ADD) )
 | 
			
		||||
        new.set_always_show_image(True)
 | 
			
		||||
        new.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        rename = Gtk.ImageMenuItem("Rename")
 | 
			
		||||
        rename.set_name("rename")
 | 
			
		||||
        rename.set_image( Gtk.Image(stock=Gtk.STOCK_EDIT) )
 | 
			
		||||
        rename.set_always_show_image(True)
 | 
			
		||||
        rename.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        cut = Gtk.ImageMenuItem("Cut")
 | 
			
		||||
        cut.set_name("cut")
 | 
			
		||||
        cut.set_image( Gtk.Image(stock=Gtk.STOCK_CUT) )
 | 
			
		||||
        cut.set_always_show_image(True)
 | 
			
		||||
        cut.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        copy = Gtk.ImageMenuItem("Copy")
 | 
			
		||||
        copy.set_name("copy")
 | 
			
		||||
        copy.set_image( Gtk.Image(stock=Gtk.STOCK_COPY) )
 | 
			
		||||
        copy.set_always_show_image(True)
 | 
			
		||||
        copy.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        paste = Gtk.ImageMenuItem("Paste")
 | 
			
		||||
        paste.set_name("paste")
 | 
			
		||||
        paste.set_image( Gtk.Image(stock=Gtk.STOCK_PASTE) )
 | 
			
		||||
        paste.set_always_show_image(True)
 | 
			
		||||
        paste.connect("activate", self.do_action_from_menu_controls)
 | 
			
		||||
 | 
			
		||||
        self._appen_menu_items(filea_menu, [new, rename, cut, copy, paste])
 | 
			
		||||
        open_a.set_submenu(open_menu)
 | 
			
		||||
        file_a.set_submenu(filea_menu)
 | 
			
		||||
        plugins.set_submenu(plugins_menu)
 | 
			
		||||
 | 
			
		||||
        main_menu.attach_to_widget(self.window, None)
 | 
			
		||||
        main_menu.show_all()
 | 
			
		||||
        self.builder.expose_object("context_menu", main_menu)
 | 
			
		||||
        self.builder.expose_object("context_menu_plugins", plugins_menu)
 | 
			
		||||
 | 
			
		||||
    def _appen_menu_items(self, menu, items):
 | 
			
		||||
        for item in items:
 | 
			
		||||
            menu.append(item)
 | 
			
		||||
 | 
			
		||||
    def get_current_state(self) -> State:
 | 
			
		||||
        '''
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ class Settings:
 | 
			
		||||
        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()
 | 
			
		||||
 | 
			
		||||
@@ -41,6 +42,8 @@ class Settings:
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
@@ -59,6 +62,9 @@ class Settings:
 | 
			
		||||
            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()
 | 
			
		||||
@@ -143,6 +149,7 @@ class Settings:
 | 
			
		||||
        return monitors
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_context_menu_data(self) -> Gtk.Builder:  return self._context_menu_data
 | 
			
		||||
    def get_main_window(self)   -> Gtk.ApplicationWindow: return self._main_window
 | 
			
		||||
    def get_builder(self)       -> Gtk.Builder:  return self._builder
 | 
			
		||||
    def get_logger(self)        -> Logger:       return self._logger
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								user_config/usr/share/solarfm/contexct_menu.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								user_config/usr/share/solarfm/contexct_menu.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
    "Open Actions": {
 | 
			
		||||
        "Open":      ["STOCK_OPEN", "open"],
 | 
			
		||||
        "Open With": ["STOCK_OPEN", "open_with"],
 | 
			
		||||
        "Execute":   ["STOCK_EXECUTE", "execute"],
 | 
			
		||||
        "Execute in Terminal": ["STOCK_EXECUTE", "execute_in_terminal"]
 | 
			
		||||
    },
 | 
			
		||||
    "File Actions": {
 | 
			
		||||
        "New":    ["STOCK_ADD", "create"],
 | 
			
		||||
        "Rename": ["STOCK_EDIT", "rename"],
 | 
			
		||||
        "Cut":    ["STOCK_CUT", "cut"],
 | 
			
		||||
        "Copy":   ["STOCK_COPY", "copy"],
 | 
			
		||||
        "Paste":  ["STOCK_PASTE", "paste"]
 | 
			
		||||
    },
 | 
			
		||||
    "Plugins": {}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user