Compare commits
	
		
			3 Commits
		
	
	
		
			1798213bfc
			...
			061dbf19ad
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 061dbf19ad | |||
| 247f1a1165 | |||
| 09d8170953 | 
| @@ -13,7 +13,6 @@ sudo apt-get install python3.8 wget python3-setproctitle python3-gi ffmpegthumbn | |||||||
| <ul> | <ul> | ||||||
| <li>Add simpleish preview plugin for various file types.</li> | <li>Add simpleish preview plugin for various file types.</li> | ||||||
| <li>Add simpleish bulk-renamer.</li> | <li>Add simpleish bulk-renamer.</li> | ||||||
| <li>Add a basic favorites manager plugin.</li> |  | ||||||
| </ul> | </ul> | ||||||
|  |  | ||||||
| # Images | # Images | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ Plugins must have a run method defined; though, you do not need to necessarily d | |||||||
| ### Manifest Example (All are required even if empty.) | ### Manifest Example (All are required even if empty.) | ||||||
| ``` | ``` | ||||||
| class Manifest: | class Manifest: | ||||||
|     path: str     = os.path.dirname(os.path.realpath(__file__)) |  | ||||||
|     name: str     = "Example Plugin" |     name: str     = "Example Plugin" | ||||||
|     author: str   = "John Doe" |     author: str   = "John Doe" | ||||||
|     version: str  = "0.0.1" |     version: str  = "0.0.1" | ||||||
| @@ -14,7 +13,6 @@ class Manifest: | |||||||
|     requests: {}  = { |     requests: {}  = { | ||||||
|         'ui_target': "plugin_control_list", |         'ui_target': "plugin_control_list", | ||||||
|         'pass_fm_events': "true" |         'pass_fm_events': "true" | ||||||
|  |  | ||||||
|     } |     } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| @@ -23,8 +21,9 @@ class Manifest: | |||||||
| ``` | ``` | ||||||
| requests: {}  = { | requests: {}  = { | ||||||
|     'ui_target': "plugin_control_list", |     'ui_target': "plugin_control_list", | ||||||
|     'ui_target_id': "<some other Gtk Glade ID>"          # Only needed if using "other" in "ui_target". See below for predefined "ui_target" options... |     'ui_target_id': "<some other Gtk Glade ID>",          # Only needed if using "other" in "ui_target". See below for predefined "ui_target" options... | ||||||
|     'pass_fm_events': "true"                             # If empty or not present will be ignored. |     'pass_fm_events': "true",                             # If empty or not present will be ignored. | ||||||
|  |     "pass_ui_objects": [""],                              # Request reference to a UI component. Will be passed back as array to plugin. | ||||||
|     'bind_keys': [f"{name}||send_message:<Control>f"], |     'bind_keys': [f"{name}||send_message:<Control>f"], | ||||||
|                   f"{name}||do_save:<Control>s"]         # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right. |                   f"{name}||do_save:<Control>s"]         # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right. | ||||||
|  |  | ||||||
| @@ -58,4 +57,8 @@ def set_fm_event_system(self, fm_event_system): | |||||||
| def run(self): | def run(self): | ||||||
|     self._module_event_observer() |     self._module_event_observer() | ||||||
|  |  | ||||||
|  | # Must define in plugin if "pass_ui_objects" is set and an array of valid glade UI IDs. | ||||||
|  | def set_ui_object_collection(self, ui_objects): | ||||||
|  |     self._ui_objects = ui_objects | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								plugins/favorites/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								plugins/favorites/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | """ | ||||||
|  |     Pligin Module | ||||||
|  | """ | ||||||
							
								
								
									
										3
									
								
								plugins/favorites/__main__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								plugins/favorites/__main__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | """ | ||||||
|  |     Pligin Package | ||||||
|  | """ | ||||||
							
								
								
									
										156
									
								
								plugins/favorites/favorites.glade
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								plugins/favorites/favorites.glade
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- Generated with glade 3.38.2 --> | ||||||
|  | <interface> | ||||||
|  |   <requires lib="gtk+" version="3.24"/> | ||||||
|  |   <object class="GtkListStore" id="favorites_store"> | ||||||
|  |     <columns> | ||||||
|  |       <!-- column-name Favorites --> | ||||||
|  |       <column type="gchararray"/> | ||||||
|  |     </columns> | ||||||
|  |   </object> | ||||||
|  |   <object class="GtkDialog" id="favorites_dialog"> | ||||||
|  |     <property name="width-request">320</property> | ||||||
|  |     <property name="height-request">450</property> | ||||||
|  |     <property name="can-focus">False</property> | ||||||
|  |     <property name="modal">True</property> | ||||||
|  |     <property name="window-position">center</property> | ||||||
|  |     <property name="destroy-with-parent">True</property> | ||||||
|  |     <property name="type-hint">dialog</property> | ||||||
|  |     <property name="skip-taskbar-hint">True</property> | ||||||
|  |     <property name="skip-pager-hint">True</property> | ||||||
|  |     <property name="decorated">False</property> | ||||||
|  |     <property name="deletable">False</property> | ||||||
|  |     <property name="gravity">center</property> | ||||||
|  |     <child internal-child="vbox"> | ||||||
|  |       <object class="GtkBox"> | ||||||
|  |         <property name="can-focus">False</property> | ||||||
|  |         <property name="orientation">vertical</property> | ||||||
|  |         <property name="spacing">2</property> | ||||||
|  |         <child internal-child="action_area"> | ||||||
|  |           <object class="GtkButtonBox"> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="layout-style">end</property> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkButton"> | ||||||
|  |                 <property name="label">gtk-delete</property> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="receives-default">True</property> | ||||||
|  |                 <property name="use-stock">True</property> | ||||||
|  |                 <property name="always-show-image">True</property> | ||||||
|  |                 <signal name="released" handler="_remove_from_favorite" swapped="no"/> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkButton"> | ||||||
|  |                 <property name="label">gtk-add</property> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="receives-default">True</property> | ||||||
|  |                 <property name="use-stock">True</property> | ||||||
|  |                 <property name="always-show-image">True</property> | ||||||
|  |                 <signal name="released" handler="_add_to_favorite" swapped="no"/> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">1</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkButton"> | ||||||
|  |                 <property name="label">gtk-close</property> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="receives-default">True</property> | ||||||
|  |                 <property name="use-stock">True</property> | ||||||
|  |                 <signal name="released" handler="_hide_favorites_menu" swapped="no"/> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">True</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">2</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="expand">False</property> | ||||||
|  |             <property name="fill">False</property> | ||||||
|  |             <property name="position">0</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |         <child> | ||||||
|  |           <object class="GtkBox"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="orientation">vertical</property> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkLabel" id="current_dir_lbl"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="margin-start">5</property> | ||||||
|  |                 <property name="margin-end">5</property> | ||||||
|  |                 <property name="margin-top">5</property> | ||||||
|  |                 <property name="margin-bottom">5</property> | ||||||
|  |                 <property name="label" translatable="yes">Current Directory:</property> | ||||||
|  |                 <property name="justify">center</property> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkScrolledWindow"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="shadow-type">in</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkTreeView"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">True</property> | ||||||
|  |                     <property name="model">favorites_store</property> | ||||||
|  |                     <property name="headers-clickable">False</property> | ||||||
|  |                     <signal name="button-release-event" handler="_set_selected_path" swapped="no"/> | ||||||
|  |                     <child internal-child="selection"> | ||||||
|  |                       <object class="GtkTreeSelection"> | ||||||
|  |                         <signal name="changed" handler="_set_selected" swapped="no"/> | ||||||
|  |                       </object> | ||||||
|  |                     </child> | ||||||
|  |                     <child> | ||||||
|  |                       <object class="GtkTreeViewColumn"> | ||||||
|  |                         <property name="title" translatable="yes">Favorites</property> | ||||||
|  |                         <child> | ||||||
|  |                           <object class="GtkCellRendererText"/> | ||||||
|  |                           <attributes> | ||||||
|  |                             <attribute name="text">0</attribute> | ||||||
|  |                           </attributes> | ||||||
|  |                         </child> | ||||||
|  |                       </object> | ||||||
|  |                     </child> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">True</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">1</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="expand">True</property> | ||||||
|  |             <property name="fill">True</property> | ||||||
|  |             <property name="position">1</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |       </object> | ||||||
|  |     </child> | ||||||
|  |   </object> | ||||||
|  | </interface> | ||||||
							
								
								
									
										14
									
								
								plugins/favorites/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								plugins/favorites/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | { | ||||||
|  |     "manifest": { | ||||||
|  |         "name": "Favorites Plugin", | ||||||
|  |         "author": "ITDominator", | ||||||
|  |         "version": "0.0.1", | ||||||
|  |         "support": "", | ||||||
|  |         "requests": { | ||||||
|  |             "ui_target": "plugin_control_list", | ||||||
|  |             "pass_fm_events": "true", | ||||||
|  |             "pass_ui_objects": ["path_entry"], | ||||||
|  |             "bind_keys": [] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										167
									
								
								plugins/favorites/plugin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								plugins/favorites/plugin.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | # Python imports | ||||||
|  | import os, threading, subprocess, time, inspect, json | ||||||
|  |  | ||||||
|  | # Lib imports | ||||||
|  | import gi | ||||||
|  | gi.require_version('Gtk', '3.0') | ||||||
|  | from gi.repository import Gtk | ||||||
|  |  | ||||||
|  | # Application imports | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # NOTE: Threads WILL NOT die with parent's destruction. | ||||||
|  | def threaded(fn): | ||||||
|  |     def wrapper(*args, **kwargs): | ||||||
|  |         threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start() | ||||||
|  |     return wrapper | ||||||
|  |  | ||||||
|  | # NOTE: Threads WILL die with parent's destruction. | ||||||
|  | def daemon_threaded(fn): | ||||||
|  |     def wrapper(*args, **kwargs): | ||||||
|  |         threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() | ||||||
|  |     return wrapper | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Plugin: | ||||||
|  |     def __init__(self): | ||||||
|  |         self.name               = "Favorites Plugin"  # NOTE: Need to remove after establishing private bidirectional 1-1 message bus | ||||||
|  |                                                       #       where self.name should not be needed for message comms | ||||||
|  |         self.path               = os.path.dirname(os.path.realpath(__file__)) | ||||||
|  |         self._GLADE_FILE        = f"{self.path}/favorites.glade" | ||||||
|  |         self._FAVORITES_FILE    = f"{self.path}/favorites.json" | ||||||
|  |  | ||||||
|  |         self._builder           = None | ||||||
|  |         self._event_system      = None | ||||||
|  |         self._event_sleep_time  = .5 | ||||||
|  |         self._event_message     = None | ||||||
|  |  | ||||||
|  |         self._favorites_dialog  = None | ||||||
|  |         self._favorites_store   = None | ||||||
|  |         self._ui_objects        = None | ||||||
|  |         self._favorites         = None | ||||||
|  |         self._state             = None | ||||||
|  |         self._selected          = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def get_ui_element(self): | ||||||
|  |         button = Gtk.Button(label=self.name) | ||||||
|  |         button.connect("button-release-event", self._show_favorites_menu) | ||||||
|  |         return button | ||||||
|  |  | ||||||
|  |     def set_fm_event_system(self, fm_event_system): | ||||||
|  |         self._event_system = fm_event_system | ||||||
|  |  | ||||||
|  |     def set_ui_object_collection(self, ui_objects): | ||||||
|  |         self._ui_objects = ui_objects | ||||||
|  |  | ||||||
|  |     def run(self): | ||||||
|  |         self._module_event_observer() | ||||||
|  |  | ||||||
|  |         self._builder          = Gtk.Builder() | ||||||
|  |         self._builder.add_from_file(self._GLADE_FILE) | ||||||
|  |  | ||||||
|  |         classes  = [self] | ||||||
|  |         handlers = {} | ||||||
|  |         for c in classes: | ||||||
|  |             methods = None | ||||||
|  |             try: | ||||||
|  |                 methods = inspect.getmembers(c, predicate=inspect.ismethod) | ||||||
|  |                 handlers.update(methods) | ||||||
|  |             except Exception as e: | ||||||
|  |                 print(repr(e)) | ||||||
|  |  | ||||||
|  |         self._builder.connect_signals(handlers) | ||||||
|  |  | ||||||
|  |         self._favorites_dialog = self._builder.get_object("favorites_dialog") | ||||||
|  |         self._favorites_store  = self._builder.get_object("favorites_store") | ||||||
|  |         self._current_dir_lbl  = self._builder.get_object("current_dir_lbl") | ||||||
|  |  | ||||||
|  |         if os.path.exists(self._FAVORITES_FILE): | ||||||
|  |             with open(self._FAVORITES_FILE) as f: | ||||||
|  |                 self._favorites = json.load(f) | ||||||
|  |                 for favorite in self._favorites: | ||||||
|  |                     self._favorites_store.append([favorite]) | ||||||
|  |         else: | ||||||
|  |             with open(self._FAVORITES_FILE, 'a') as f: | ||||||
|  |                 f.write('[]') | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @threaded | ||||||
|  |     def _get_state(self, widget=None, eve=None): | ||||||
|  |         self._event_system.push_gui_event([self.name, "get_current_state", ()]) | ||||||
|  |         self.wait_for_fm_message() | ||||||
|  |  | ||||||
|  |         self._state         = self._event_message | ||||||
|  |         self._event_message = None | ||||||
|  |  | ||||||
|  |     @threaded | ||||||
|  |     def _set_current_dir_lbl(self, widget=None, eve=None): | ||||||
|  |         self.wait_for_state() | ||||||
|  |         self._current_dir_lbl.set_label(f"Current Directory:\n{self._state.tab.get_current_directory()}") | ||||||
|  |  | ||||||
|  |     def _add_to_favorite(self, state): | ||||||
|  |         current_directory = self._state.tab.get_current_directory() | ||||||
|  |         self._favorites_store.append([current_directory]) | ||||||
|  |         self._favorites.append(current_directory) | ||||||
|  |         self._save_favorites() | ||||||
|  |  | ||||||
|  |     def _remove_from_favorite(self, state): | ||||||
|  |         path = self._favorites_store.get_value(self._selected, 0) | ||||||
|  |         self._favorites_store.remove(self._selected) | ||||||
|  |         self._favorites.remove(path) | ||||||
|  |         self._save_favorites() | ||||||
|  |  | ||||||
|  |     def _save_favorites(self): | ||||||
|  |         with open(self._FAVORITES_FILE, 'w') as outfile: | ||||||
|  |             json.dump(self._favorites, outfile, separators=(',', ':'), indent=4) | ||||||
|  |  | ||||||
|  |     def _set_selected_path(self, widget=None, eve=None): | ||||||
|  |         path = self._favorites_store.get_value(self._selected, 0) | ||||||
|  |         self._ui_objects[0].set_text(path) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def _show_favorites_menu(self, widget=None, eve=None): | ||||||
|  |         self._state = None | ||||||
|  |         self._get_state() | ||||||
|  |         self._set_current_dir_lbl() | ||||||
|  |         self._favorites_dialog.run() | ||||||
|  |  | ||||||
|  |     def _hide_favorites_menu(self, widget=None, eve=None): | ||||||
|  |         self._favorites_dialog.hide() | ||||||
|  |  | ||||||
|  |     def _set_selected(self, user_data): | ||||||
|  |         selected = user_data.get_selected()[1] | ||||||
|  |         if selected: | ||||||
|  |             self._selected = selected | ||||||
|  |  | ||||||
|  |     def wait_for_fm_message(self): | ||||||
|  |         while not self._event_message: | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |     def wait_for_state(self): | ||||||
|  |         while not self._state: | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |     @daemon_threaded | ||||||
|  |     def _module_event_observer(self): | ||||||
|  |         while True: | ||||||
|  |             time.sleep(self._event_sleep_time) | ||||||
|  |             event = self._event_system.read_module_event() | ||||||
|  |             if event: | ||||||
|  |                 try: | ||||||
|  |                     if event[0] == self.name: | ||||||
|  |                         target_id, method_target, data = self._event_system.consume_module_event() | ||||||
|  |  | ||||||
|  |                         if not method_target: | ||||||
|  |                             self._event_message = data | ||||||
|  |                         else: | ||||||
|  |                             method = getattr(self.__class__, f"{method_target}") | ||||||
|  |                             if data: | ||||||
|  |                                 data = method(*(self, *data)) | ||||||
|  |                             else: | ||||||
|  |                                 method(*(self,)) | ||||||
|  |                 except Exception as e: | ||||||
|  |                     print(repr(e)) | ||||||
| @@ -22,16 +22,13 @@ if __name__ == "__main__": | |||||||
|     """ Set process title, get arguments, and create GTK main thread. """ |     """ Set process title, get arguments, and create GTK main thread. """ | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         # import web_pdb |  | ||||||
|         # web_pdb.set_trace() |  | ||||||
|  |  | ||||||
|         setproctitle('SolarFM') |         setproctitle('SolarFM') | ||||||
|         faulthandler.enable()  # For better debug info |         faulthandler.enable()  # For better debug info | ||||||
|  |  | ||||||
|         parser = argparse.ArgumentParser() |         parser = argparse.ArgumentParser() | ||||||
|         # Add long and short arguments |         # Add long and short arguments | ||||||
|         parser.add_argument("--new-tab", "-t", default="", help="Open a file into new tab.") |         parser.add_argument("--new-tab", "-t", default="", help="Open a file into new tab.") | ||||||
|         parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.") |         parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.") | ||||||
|  |  | ||||||
|         # Read arguments (If any...) |         # Read arguments (If any...) | ||||||
|         args, unknownargs = parser.parse_known_args() |         args, unknownargs = parser.parse_known_args() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -155,7 +155,7 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi | |||||||
|         if action == "empty_trash": |         if action == "empty_trash": | ||||||
|             self.empty_trash() |             self.empty_trash() | ||||||
|         if action == "create": |         if action == "create": | ||||||
|             self.show_new_file_menu() |             self.create_files() | ||||||
|         if action in ["save_session", "save_session_as", "load_session"]: |         if action in ["save_session", "save_session_as", "load_session"]: | ||||||
|             self.save_load_session(action) |             self.save_load_session(action) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -52,6 +52,7 @@ class Controller_Data: | |||||||
|  |  | ||||||
|         self.exists_file_rename_bttn = self.builder.get_object("exists_file_rename_bttn") |         self.exists_file_rename_bttn = self.builder.get_object("exists_file_rename_bttn") | ||||||
|         self.warning_alert      = self.builder.get_object("warning_alert") |         self.warning_alert      = self.builder.get_object("warning_alert") | ||||||
|  |         self.new_file_menu      = self.builder.get_object("new_file_menu") | ||||||
|         self.edit_file_menu     = self.builder.get_object("edit_file_menu") |         self.edit_file_menu     = self.builder.get_object("edit_file_menu") | ||||||
|         self.file_exists_dialog = self.builder.get_object("file_exists_dialog") |         self.file_exists_dialog = self.builder.get_object("file_exists_dialog") | ||||||
|         self.exists_file_label  = self.builder.get_object("exists_file_label") |         self.exists_file_label  = self.builder.get_object("exists_file_label") | ||||||
| @@ -110,6 +111,7 @@ class Controller_Data: | |||||||
|         self.search_icon_grid   = None |         self.search_icon_grid   = None | ||||||
|         self.search_tab         = None |         self.search_tab         = None | ||||||
|  |  | ||||||
|  |         self.cancel_creation    = False | ||||||
|         self.skip_edit          = False |         self.skip_edit          = False | ||||||
|         self.cancel_edit        = False |         self.cancel_edit        = False | ||||||
|         self.ctrl_down          = False |         self.ctrl_down          = False | ||||||
|   | |||||||
| @@ -108,22 +108,23 @@ class ShowHideMixin: | |||||||
|     def hide_context_menu(self, widget=None, eve=None): |     def hide_context_menu(self, widget=None, eve=None): | ||||||
|         self.builder.get_object("context_menu_popup").hide() |         self.builder.get_object("context_menu_popup").hide() | ||||||
|  |  | ||||||
|  |  | ||||||
|     def show_new_file_menu(self, widget=None, eve=None): |     def show_new_file_menu(self, widget=None, eve=None): | ||||||
|         context_menu_fname = self.builder.get_object("context_menu_fname") |         if widget: | ||||||
|         context_menu_fname.set_text("") |             widget.set_text("") | ||||||
|         context_menu_fname.grab_focus() |             widget.grab_focus() | ||||||
|  |  | ||||||
|         new_file_menu = self.builder.get_object("new_file_menu") |         response = self.new_file_menu.run() | ||||||
|         response      = new_file_menu.run() |  | ||||||
|         if response == Gtk.ResponseType.APPLY: |  | ||||||
|             self.create_files() |  | ||||||
|         if response == Gtk.ResponseType.CANCEL: |         if response == Gtk.ResponseType.CANCEL: | ||||||
|             self.hide_new_file_menu() |             self.cancel_creation = True | ||||||
|  |  | ||||||
|     def hide_new_file_menu(self, widget=None, eve=None): |     def hide_new_file_menu(self, widget=None, eve=None): | ||||||
|         self.builder.get_object("new_file_menu").hide() |         self.builder.get_object("new_file_menu").hide() | ||||||
|  |  | ||||||
|  |     def hide_new_file_menu_enter_key(self, widget=None, eve=None): | ||||||
|  |         keyname = Gdk.keyval_name(eve.keyval).lower() | ||||||
|  |         if keyname in ["return", "enter"]: | ||||||
|  |             self.builder.get_object("new_file_menu").hide() | ||||||
|  |  | ||||||
|     def show_edit_file_menu(self, widget=None, eve=None): |     def show_edit_file_menu(self, widget=None, eve=None): | ||||||
|         if widget: |         if widget: | ||||||
|             widget.grab_focus() |             widget.grab_focus() | ||||||
|   | |||||||
| @@ -248,7 +248,13 @@ class WidgetFileActionMixin: | |||||||
|  |  | ||||||
|  |  | ||||||
|     def create_files(self): |     def create_files(self): | ||||||
|         fname_field = self.builder.get_object("context_menu_fname") |         fname_field = self.builder.get_object("new_fname_field") | ||||||
|  |         self.show_new_file_menu(fname_field) | ||||||
|  |  | ||||||
|  |         if self.cancel_creation: | ||||||
|  |             self.cancel_creation    = False | ||||||
|  |             return | ||||||
|  |  | ||||||
|         file_name   = fname_field.get_text().strip() |         file_name   = fname_field.get_text().strip() | ||||||
|         type        = self.builder.get_object("context_menu_type_toggle").get_state() |         type        = self.builder.get_object("context_menu_type_toggle").get_state() | ||||||
|  |  | ||||||
| @@ -264,11 +270,14 @@ class WidgetFileActionMixin: | |||||||
|             else:                # Create Folder |             else:                # Create Folder | ||||||
|                 self.handle_files([path], "create_dir") |                 self.handle_files([path], "create_dir") | ||||||
|  |  | ||||||
|  |         self.cancel_creation    = False | ||||||
|         self.hide_new_file_menu() |         self.hide_new_file_menu() | ||||||
|  |  | ||||||
|  |  | ||||||
|     def move_files(self, files, target): |     def move_files(self, files, target): | ||||||
|         self.handle_files(files, "move", target) |         self.handle_files(files, "move", target) | ||||||
|  |  | ||||||
|  |  | ||||||
|     # NOTE: Gtk recommends using fail flow than pre check which is more |     # NOTE: Gtk recommends using fail flow than pre check which is more | ||||||
|     #       race condition proof. They're right; but, they can't even delete |     #       race condition proof. They're right; but, they can't even delete | ||||||
|     #       directories properly. So... f**k them. I'll do it my way. |     #       directories properly. So... f**k them. I'll do it my way. | ||||||
|   | |||||||
| @@ -69,6 +69,15 @@ class ManifestProcessor: | |||||||
|             if requests["pass_fm_events"] in ["true"]: |             if requests["pass_fm_events"] in ["true"]: | ||||||
|                 loading_data["pass_fm_events"] = True |                 loading_data["pass_fm_events"] = True | ||||||
|  |  | ||||||
|  |         if "pass_ui_objects" in keys: | ||||||
|  |             if len(requests["pass_ui_objects"]) > 0: | ||||||
|  |                 loading_data["pass_ui_objects"] = [] | ||||||
|  |                 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)) | ||||||
|  |  | ||||||
|         if "bind_keys" in keys: |         if "bind_keys" in keys: | ||||||
|             if isinstance(requests["bind_keys"], list): |             if isinstance(requests["bind_keys"], list): | ||||||
|                 loading_data["bind_keys"] = requests["bind_keys"] |                 loading_data["bind_keys"] = requests["bind_keys"] | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ class Plugins: | |||||||
|                 self.execute_plugin(module, plugin, loading_data) |                 self.execute_plugin(module, plugin, loading_data) | ||||||
|             except Exception as e: |             except Exception as e: | ||||||
|                 print(f"Malformed Plugin: Not loading -->: '{folder}' !") |                 print(f"Malformed Plugin: Not loading -->: '{folder}' !") | ||||||
|                 traceback.print_exc()  |                 traceback.print_exc() | ||||||
|  |  | ||||||
|         os.chdir(parent_path) |         os.chdir(parent_path) | ||||||
|  |  | ||||||
| @@ -78,14 +78,17 @@ class Plugins: | |||||||
|         keys             = loading_data.keys() |         keys             = loading_data.keys() | ||||||
|  |  | ||||||
|         if "ui_target" in keys: |         if "ui_target" in keys: | ||||||
|             loading_data["ui_target"].add(plugin.reference.get_ui_element()) |             loading_data["ui_target"].add( plugin.reference.get_ui_element() ) | ||||||
|             loading_data["ui_target"].show_all() |             loading_data["ui_target"].show_all() | ||||||
|  |  | ||||||
|  |         if "pass_ui_objects" in keys: | ||||||
|  |             plugin.reference.set_ui_object_collection( loading_data["pass_ui_objects"] ) | ||||||
|  |  | ||||||
|         if "pass_fm_events" in keys: |         if "pass_fm_events" in keys: | ||||||
|             plugin.reference.set_fm_event_system(event_system) |             plugin.reference.set_fm_event_system(event_system) | ||||||
|  |  | ||||||
|         if "bind_keys" in keys: |         if "bind_keys" in keys: | ||||||
|             self._keybindings.append_bindings(loading_data["bind_keys"]) |             self._keybindings.append_bindings( loading_data["bind_keys"] ) | ||||||
|  |  | ||||||
|         plugin.reference.run() |         plugin.reference.run() | ||||||
|         self._plugin_collection.append(plugin) |         self._plugin_collection.append(plugin) | ||||||
|   | |||||||
| @@ -757,7 +757,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|     <property name="stock">gtk-apply</property> |     <property name="stock">gtk-apply</property> | ||||||
|     <property name="icon_size">3</property> |     <property name="icon_size">3</property> | ||||||
|   </object> |   </object> | ||||||
|   <object class="GtkApplicationWindow" id="Main_Window"> |   <object class="GtkApplicationWindow" id="main_window"> | ||||||
|     <property name="width-request">800</property> |     <property name="width-request">800</property> | ||||||
|     <property name="height-request">600</property> |     <property name="height-request">600</property> | ||||||
|     <property name="can-focus">False</property> |     <property name="can-focus">False</property> | ||||||
| @@ -775,7 +775,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|         <property name="orientation">vertical</property> |         <property name="orientation">vertical</property> | ||||||
|         <property name="baseline-position">top</property> |         <property name="baseline-position">top</property> | ||||||
|         <child> |         <child> | ||||||
|           <object class="GtkBox" id="app_menu_bar"> |           <object class="GtkBox" id="main_menu_bar"> | ||||||
|             <property name="visible">True</property> |             <property name="visible">True</property> | ||||||
|             <property name="can-focus">False</property> |             <property name="can-focus">False</property> | ||||||
|             <child> |             <child> | ||||||
| @@ -1122,7 +1122,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|           </packing> |           </packing> | ||||||
|         </child> |         </child> | ||||||
|         <child> |         <child> | ||||||
|           <object class="GtkBox" id="controll_box"> |           <object class="GtkBox" id="path_menu_bar"> | ||||||
|             <property name="visible">True</property> |             <property name="visible">True</property> | ||||||
|             <property name="can-focus">False</property> |             <property name="can-focus">False</property> | ||||||
|             <child> |             <child> | ||||||
| @@ -1470,13 +1470,13 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|     <property name="modal">True</property> |     <property name="modal">True</property> | ||||||
|     <property name="window-position">center-always</property> |     <property name="window-position">center-always</property> | ||||||
|     <property name="destroy-with-parent">True</property> |     <property name="destroy-with-parent">True</property> | ||||||
|     <property name="type-hint">normal</property> |     <property name="type-hint">dialog</property> | ||||||
|     <property name="skip-taskbar-hint">True</property> |     <property name="skip-taskbar-hint">True</property> | ||||||
|     <property name="skip-pager-hint">True</property> |     <property name="skip-pager-hint">True</property> | ||||||
|     <property name="decorated">False</property> |     <property name="decorated">False</property> | ||||||
|     <property name="deletable">False</property> |     <property name="deletable">False</property> | ||||||
|     <property name="gravity">center</property> |     <property name="gravity">center</property> | ||||||
|     <property name="attached-to">Main_Window</property> |     <property name="attached-to">main_window</property> | ||||||
|     <child internal-child="vbox"> |     <child internal-child="vbox"> | ||||||
|       <object class="GtkBox"> |       <object class="GtkBox"> | ||||||
|         <property name="can-focus">False</property> |         <property name="can-focus">False</property> | ||||||
| @@ -1628,14 +1628,14 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|     <property name="modal">True</property> |     <property name="modal">True</property> | ||||||
|     <property name="window-position">center-always</property> |     <property name="window-position">center-always</property> | ||||||
|     <property name="destroy-with-parent">True</property> |     <property name="destroy-with-parent">True</property> | ||||||
|     <property name="type-hint">normal</property> |     <property name="type-hint">dialog</property> | ||||||
|     <property name="skip-taskbar-hint">True</property> |     <property name="skip-taskbar-hint">True</property> | ||||||
|     <property name="skip-pager-hint">True</property> |     <property name="skip-pager-hint">True</property> | ||||||
|     <property name="urgency-hint">True</property> |     <property name="urgency-hint">True</property> | ||||||
|     <property name="decorated">False</property> |     <property name="decorated">False</property> | ||||||
|     <property name="deletable">False</property> |     <property name="deletable">False</property> | ||||||
|     <property name="gravity">center</property> |     <property name="gravity">center</property> | ||||||
|     <property name="attached-to">Main_Window</property> |     <property name="attached-to">main_window</property> | ||||||
|     <child internal-child="vbox"> |     <child internal-child="vbox"> | ||||||
|       <object class="GtkBox"> |       <object class="GtkBox"> | ||||||
|         <property name="can-focus">False</property> |         <property name="can-focus">False</property> | ||||||
| @@ -1958,7 +1958,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|     <property name="width-request">320</property> |     <property name="width-request">320</property> | ||||||
|     <property name="can-focus">False</property> |     <property name="can-focus">False</property> | ||||||
|     <property name="hexpand">True</property> |     <property name="hexpand">True</property> | ||||||
|     <property name="relative-to">app_menu_bar</property> |     <property name="relative-to">main_menu_bar</property> | ||||||
|     <property name="position">bottom</property> |     <property name="position">bottom</property> | ||||||
|     <child> |     <child> | ||||||
|       <object class="GtkBox"> |       <object class="GtkBox"> | ||||||
| @@ -2015,14 +2015,13 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|     <property name="modal">True</property> |     <property name="modal">True</property> | ||||||
|     <property name="window-position">center-always</property> |     <property name="window-position">center-always</property> | ||||||
|     <property name="destroy-with-parent">True</property> |     <property name="destroy-with-parent">True</property> | ||||||
|     <property name="type-hint">normal</property> |     <property name="type-hint">dialog</property> | ||||||
|     <property name="skip-taskbar-hint">True</property> |     <property name="skip-taskbar-hint">True</property> | ||||||
|     <property name="skip-pager-hint">True</property> |     <property name="skip-pager-hint">True</property> | ||||||
|     <property name="decorated">False</property> |     <property name="decorated">False</property> | ||||||
|     <property name="deletable">False</property> |     <property name="deletable">False</property> | ||||||
|     <property name="gravity">center</property> |     <property name="gravity">center</property> | ||||||
|     <property name="attached-to">Main_Window</property> |     <property name="attached-to">main_window</property> | ||||||
|     <signal name="focus-out-event" handler="hide_new_file_menu" swapped="no"/> |  | ||||||
|     <child internal-child="vbox"> |     <child internal-child="vbox"> | ||||||
|       <object class="GtkBox"> |       <object class="GtkBox"> | ||||||
|         <property name="can-focus">False</property> |         <property name="can-focus">False</property> | ||||||
| @@ -2081,7 +2080,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|             <property name="can-focus">False</property> |             <property name="can-focus">False</property> | ||||||
|             <property name="orientation">vertical</property> |             <property name="orientation">vertical</property> | ||||||
|             <child> |             <child> | ||||||
|               <object class="GtkEntry" id="context_menu_fname"> |               <object class="GtkEntry" id="new_fname_field"> | ||||||
|                 <property name="width-request">500</property> |                 <property name="width-request">500</property> | ||||||
|                 <property name="height-request">26</property> |                 <property name="height-request">26</property> | ||||||
|                 <property name="visible">True</property> |                 <property name="visible">True</property> | ||||||
| @@ -2095,6 +2094,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                 <property name="primary-icon-sensitive">False</property> |                 <property name="primary-icon-sensitive">False</property> | ||||||
|                 <property name="secondary-icon-sensitive">False</property> |                 <property name="secondary-icon-sensitive">False</property> | ||||||
|                 <property name="placeholder-text" translatable="yes">New File/Dir Name...</property> |                 <property name="placeholder-text" translatable="yes">New File/Dir Name...</property> | ||||||
|  |                 <signal name="key-release-event" handler="hide_new_file_menu_enter_key" swapped="no"/> | ||||||
|               </object> |               </object> | ||||||
|               <packing> |               <packing> | ||||||
|                 <property name="expand">False</property> |                 <property name="expand">False</property> | ||||||
| @@ -2219,11 +2219,13 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|       </object> |       </object> | ||||||
|     </child> |     </child> | ||||||
|   </object> |   </object> | ||||||
|   <object class="GtkPopover" id="plugin_list"> |   <object class="GtkPopover" id="plugin_controls"> | ||||||
|     <property name="can-focus">False</property> |     <property name="can-focus">False</property> | ||||||
|     <property name="relative-to">plugins_buttoin</property> |     <property name="relative-to">plugins_buttoin</property> | ||||||
|  |     <signal name="button-release-event" handler="hide_plugins_popup" swapped="no"/> | ||||||
|  |     <signal name="key-release-event" handler="hide_plugins_popup" swapped="no"/> | ||||||
|     <child> |     <child> | ||||||
|       <object class="GtkBox" id="plugin_socket"> |       <object class="GtkBox" id="plugin_control_list"> | ||||||
|         <property name="visible">True</property> |         <property name="visible">True</property> | ||||||
|         <property name="can-focus">False</property> |         <property name="can-focus">False</property> | ||||||
|         <property name="orientation">vertical</property> |         <property name="orientation">vertical</property> | ||||||
| @@ -2329,7 +2331,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|     <property name="can-focus">False</property> |     <property name="can-focus">False</property> | ||||||
|     <property name="icon-name">user-trash</property> |     <property name="icon-name">user-trash</property> | ||||||
|   </object> |   </object> | ||||||
|   <object class="GtkDialog" id="context_menu"> |   <object class="GtkDialog" id="context_menu_popup"> | ||||||
|     <property name="can-focus">False</property> |     <property name="can-focus">False</property> | ||||||
|     <property name="resizable">False</property> |     <property name="resizable">False</property> | ||||||
|     <property name="window-position">mouse</property> |     <property name="window-position">mouse</property> | ||||||
| @@ -2367,7 +2369,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|             <property name="can-focus">False</property> |             <property name="can-focus">False</property> | ||||||
|             <property name="orientation">vertical</property> |             <property name="orientation">vertical</property> | ||||||
|             <child> |             <child> | ||||||
|               <object class="GtkBox" id="iconsButtonBox"> |               <object class="GtkBox" id="context_menu"> | ||||||
|                 <property name="visible">True</property> |                 <property name="visible">True</property> | ||||||
|                 <property name="can-focus">False</property> |                 <property name="can-focus">False</property> | ||||||
|                 <property name="orientation">vertical</property> |                 <property name="orientation">vertical</property> | ||||||
|   | |||||||
| @@ -21,6 +21,6 @@ | |||||||
|         "copy_files"             : "<Control>c", |         "copy_files"             : "<Control>c", | ||||||
|         "cut_files"              : "<Control>x", |         "cut_files"              : "<Control>x", | ||||||
|         "paste_files"            : "<Control>v", |         "paste_files"            : "<Control>v", | ||||||
|         "show_new_file_menu"     : "<Control>n" |         "create_files"           : "<Control>n" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| { | { | ||||||
|     "settings": { |     "config": { | ||||||
|         "base_of_home": "", |         "base_of_home": "", | ||||||
|         "hide_hidden_files": "true", |         "hide_hidden_files": "true", | ||||||
|         "thumbnailer_path": "ffmpegthumbnailer", |         "thumbnailer_path": "ffmpegthumbnailer", | ||||||
| @@ -7,14 +7,29 @@ | |||||||
|         "lock_folder": "false", |         "lock_folder": "false", | ||||||
|         "locked_folders": "venv::::flasks", |         "locked_folders": "venv::::flasks", | ||||||
|         "mplayer_options": "-quiet -really-quiet -xy 1600 -geometry 50%:50%", |         "mplayer_options": "-quiet -really-quiet -xy 1600 -geometry 50%:50%", | ||||||
|         "music_app": "/opt/deadbeef/bin/deadbeef", |         "music_app": "deadbeef", | ||||||
|         "media_app": "mpv", |         "media_app": "mpv", | ||||||
|         "image_app": "mirage", |         "image_app": "mirage2", | ||||||
|         "office_app": "libreoffice", |         "office_app": "libreoffice", | ||||||
|         "pdf_app": "evince", |         "pdf_app": "evince", | ||||||
|         "text_app": "leafpad", |         "code_app": "atom", | ||||||
|         "file_manager_app": "solarfm", |         "text_app": "mousepad", | ||||||
|         "terminal_app": "terminator", |         "terminal_app": "terminator", | ||||||
|  |         "container_icon_wh": [128, 128], | ||||||
|  |         "video_icon_wh":     [128, 64], | ||||||
|  |         "sys_icon_wh":       [56, 56], | ||||||
|  |         "file_manager_app": "solarfm", | ||||||
|  |         "steam_cdn_url": "https://steamcdn-a.akamaihd.net/steam/apps/", | ||||||
|         "remux_folder_max_disk_usage": "8589934592" |         "remux_folder_max_disk_usage": "8589934592" | ||||||
|     } |     }, | ||||||
|  |     "filters": { | ||||||
|  |         "code":   [".cpp", ".css", ".c", ".go", ".html", ".htm", ".java", ".js", ".json", ".lua", ".md", ".py", ".rs"], | ||||||
|  |         "videos": [".mkv", ".mp4", ".webm", ".avi", ".mov", ".m4v", ".mpg", ".mpeg", ".wmv", ".flv"], | ||||||
|  |         "office": [".doc", ".docx", ".xls", ".xlsx", ".xlt", ".xltx", ".xlm", ".ppt", ".pptx", ".pps", ".ppsx", ".odt", ".rtf"], | ||||||
|  |         "images": [".png", ".jpg", ".jpeg", ".gif", ".ico", ".tga", ".webp"], | ||||||
|  |         "text":   [".txt", ".text", ".sh", ".cfg", ".conf", ".log"], | ||||||
|  |         "music":  [".psf", ".mp3", ".ogg", ".flac", ".m4a"], | ||||||
|  |         "pdf":    [".pdf"] | ||||||
|  |  | ||||||
|  |    } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user