diff --git a/src/versions/pyfm-0.0.1/PyFM/new/pyfm/resources/Main_Window.glade b/src/versions/pyfm-0.0.1/PyFM/new/pyfm/resources/Main_Window.glade index fd6de60..b6b5cb7 100644 --- a/src/versions/pyfm-0.0.1/PyFM/new/pyfm/resources/Main_Window.glade +++ b/src/versions/pyfm-0.0.1/PyFM/new/pyfm/resources/Main_Window.glade @@ -8,6 +8,7 @@ center-on-parent pyfm.png dialog + center PyFM 0.0.1 Copyright (C) 2021 GPL2 @@ -387,6 +388,303 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti False gtk-new + + False + center + splashscreen + center + + + + False + vertical + 2 + + + False + end + + + + + + + + + False + False + 0 + + + + + True + False + vertical + + + 500 + 26 + True + True + gtk-edit + New File/Dir Name... + + + False + True + 0 + + + + + True + False + 20 + vertical + True + + + True + False + + + True + False + 15 + Folder + + + + + + True + True + 0 + + + + + True + False + 15 + File + + + + + + True + True + 1 + + + + + False + True + 0 + + + + + True + True + File/Folder + True + + + False + True + 1 + + + + + Create + create + True + True + True + Create File/Folder... + createImage + True + + + + False + True + 2 + + + + + True + True + 1 + + + + + True + True + 1 + + + + + + + True + False + gtk-edit + 3 + + + True + False + gtk-edit + + + True + False + gtk-media-forward + + + False + True + center + splashscreen + center + + + + False + vertical + 2 + + + False + end + + + Skip + True + True + True + skip_img + True + + + + True + True + 0 + + + + + gtk-cancel + True + True + True + True + + + + True + True + 1 + + + + + False + False + 0 + + + + + True + False + vertical + + + True + False + + + True + False + Rename: + + + False + True + 0 + + + + + True + False + + + True + True + 1 + + + + + False + True + 0 + + + + + 500 + 26 + True + True + gtk-edit + To: + + + False + True + 1 + + + + + Rename + rename + True + True + True + rename_img + True + + + + False + True + 2 + + + + + True + True + 1 + + + + + True False @@ -961,11 +1259,6 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti - - True - False - icons/trash.png - True False @@ -973,9 +1266,12 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti False + False mouse splashscreen - south + False + False + static @@ -1001,112 +1297,9 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti - 500 True False vertical - - - 500 - 26 - True - True - gtk-edit - New File/Dir Name... - - - False - True - 0 - - - - - True - False - 20 - vertical - - - True - False - - - True - False - 15 - Folder - - - - - - True - True - 0 - - - - - True - False - 15 - File - - - - - - True - True - 1 - - - - - False - True - 0 - - - - - True - True - File/Folder - True - - - False - True - 1 - - - - - Create - create - True - True - True - Create File/Folder... - createImage - True - - - - False - True - 2 - - - - - False - True - 1 - - True @@ -1128,19 +1321,18 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti False True - 4 + 3 - gtk-cut - cut + gtk-open + open True True True - Cut... + Open... True - True @@ -1151,15 +1343,15 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti - gtk-copy - copy + Rename + rename True True True - Copy... - True + Rename... + rename_img2 True - + False @@ -1183,9 +1375,45 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti False True end + 2 + + + + + gtk-cut + cut + True + True + True + Cut... + True + True + + + + False + True 3 + + + gtk-copy + copy + True + True + True + Copy... + True + True + + + + False + True + 4 + + gtk-paste @@ -1201,7 +1429,7 @@ PyFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspecti False True - 4 + 5 diff --git a/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/Signals.py b/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/Signals.py index f2be994..5b50f13 100644 --- a/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/Signals.py +++ b/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/Signals.py @@ -36,6 +36,7 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): self.window4 = self.builder.get_object("window_4") self.notebooks = [self.window1, self.window2, self.window3, self.window4] self.selected_files = [] + self.to_rename_files = [] self.to_copy_files = [] self.to_cut_files = [] @@ -45,6 +46,8 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): self.is_pane3_hidden = False self.is_pane4_hidden = False + self.skip_edit = False + self.cancel_edit = False self.ctrlDown = False self.shiftDown = False self.altDown = False @@ -68,9 +71,9 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): def tear_down(self, widget=None, eve=None): - self.window_controller.save_state() event_system.monitor_events = False event_system.send_ipc_message("close server") + self.window_controller.save_state() time.sleep(event_sleep_time) Gtk.main_quit() @@ -98,14 +101,25 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): view.load_directory() self.load_store(view, store) + def has_method(self, o, name): + return callable(getattr(o, name, None)) + def do_action_from_menu_controls(self, imagemenuitem, eventbutton): action = imagemenuitem.get_name() self.ctrlDown = True self.hide_context_menu() + self.hide_new_file_menu() + self.hide_edit_file_menu() if action == "create": self.create_file() + self.hide_new_file_menu() + if action == "open": + self.open_files() + if action == "rename": + self.to_rename_files = self.selected_files + self.rename_files() if action == "cut": self.to_copy_files.clear() self.cut_files() @@ -160,10 +174,14 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): self.builder.get_object("path_entry").grab_focus() if self.ctrlDown and keyname == "t": self.builder.get_object("create_tab").released() + if self.ctrlDown and keyname == "o": + self.open_files() if self.ctrlDown and keyname == "w": self.keyboard_close_tab() if self.ctrlDown and keyname == "h": self.show_hide_hidden_files() + if (self.ctrlDown and keyname == "e"): + self.edit_files() if self.ctrlDown and keyname == "c": self.to_cut_files.clear() self.copy_files() @@ -172,11 +190,14 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): self.cut_files() if self.ctrlDown and keyname == "v": self.paste_files() - if self.ctrlDown and keyname == "o": - self.open_files() + if self.ctrlDown and keyname == "n": + self.show_new_file_menu() if keyname == "delete": self.trash_files() + if keyname == "f2": + self.to_rename_files = self.selected_files + self.rename_files() if keyname == "f4": wid, tid = self.window_controller.get_active_data() view = self.get_fm_window(wid).get_view_by_id(tid) @@ -190,6 +211,8 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): subprocess.Popen(command, cwd=start_dir, start_new_session=True, stdout=DEVNULL, stderr=DEVNULL) + + def show_about_page(self, widget, eve): about_page = self.builder.get_object("about_page") response = about_page.run() @@ -199,13 +222,35 @@ class Signals(WidgetFileActionMixin, PaneMixin, WindowMixin): def hide_about_page(self, widget=None, eve=None): about_page = self.builder.get_object("about_page").hide() - def show_context_menu(self, widget=None, eve=None): self.builder.get_object("context_menu").run() def hide_context_menu(self, widget=None, eve=None): self.builder.get_object("context_menu").hide() + def show_edit_file_menu(self, widget=None, eve=None): + self.builder.get_object("edit_file_menu").run() + + def hide_edit_file_menu(self, widget=None, eve=None): + self.builder.get_object("edit_file_menu").hide() + + def show_new_file_menu(self, widget=None, eve=None): + self.builder.get_object("new_file_menu").run() + + def hide_new_file_menu(self, widget=None, eve=None): + self.builder.get_object("new_file_menu").hide() + + def hide_edit_file_menu_skip(self, widget=None, eve=None): + self.skip_edit = True + self.builder.get_object("edit_file_menu").hide() + + def hide_edit_file_menu_cancel(self, widget=None, eve=None): + self.cancel_edit = True + self.builder.get_object("edit_file_menu").hide() + + + + def generate_windows(self, data = None): if data: diff --git a/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/mixins/WidgetFileActionMixin.py b/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/mixins/WidgetFileActionMixin.py index 896cbe1..db15ec0 100644 --- a/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/mixins/WidgetFileActionMixin.py +++ b/src/versions/pyfm-0.0.1/PyFM/new/pyfm/signal_classes/mixins/WidgetFileActionMixin.py @@ -1,4 +1,5 @@ # Python imports +import os # Lib imports from gi.repository import GObject, Gio @@ -42,13 +43,17 @@ class WidgetFileActionMixin: self.load_store(view, store) tab_label.set_label(view.get_end_of_path()) - def create_file(self): - file_name = self.builder.get_object("context_menu_fname").get_text().strip() - type = self.builder.get_object("context_menu_type_toggle").get_state() - wid, tid = self.window_controller.get_active_data() - view = self.get_fm_window(wid).get_view_by_id(tid) - target = f"{view.get_current_directory()}" + + + def create_file(self): + fname_field = self.builder.get_object("context_menu_fname") + file_name = fname_field.get_text().strip() + type = self.builder.get_object("context_menu_type_toggle").get_state() + + wid, tid = self.window_controller.get_active_data() + view = self.get_fm_window(wid).get_view_by_id(tid) + target = f"{view.get_current_directory()}" if file_name != "": file_name = "file://" + target + "/" + file_name @@ -57,11 +62,7 @@ class WidgetFileActionMixin: else: # Create Folder self.handle_file([file_name], "create_dir") - def update_file(self): - pass - - def menu_bar_copy(self, widget, eve): - self.copy_file() + fname_field.set_text("") def open_files(self): wid, tid = self.window_controller.get_active_data() @@ -73,12 +74,50 @@ class WidgetFileActionMixin: for file in uris: view.open_file_locally(file) - def copy_files(self): - wid, tid = self.window_controller.get_active_data() - iconview = self.builder.get_object(f"{wid}|{tid}|iconview") - store = iconview.get_model() - uris = self.format_to_uris(store, wid, tid, self.selected_files) - self.to_copy_files = uris + def edit_files(self): + pass + + def rename_files(self): + rename_label = self.builder.get_object("file_to_rename_label") + rename_input = self.builder.get_object("new_rename_fname") + 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() + uris = self.format_to_uris(store, wid, tid, self.to_rename_files, True) + + # The rename button hides the rename dialog box which lets this loop continue. + # Weirdly, the show at the end is needed to flow through all the list properly + # than auto chosing the first rename entry you do. + for uri in uris: + entry = uri.split("/")[-1] + rename_label.set_label(entry) + rename_input.set_text(entry) + if self.skip_edit: + self.skip_edit = False + self.show_edit_file_menu() + + self.show_edit_file_menu() + + if self.skip_edit: + continue + if self.cancel_edit: + break + + rname_to = rename_input.get_text().strip() + target = f"file://{view.get_current_directory()}/{rname_to}" + self.handle_file([f"file://{uri}"], "edit", target) + + self.show_edit_file_menu() + + + self.skip_edit = False + self.cancel_edit = False + self.hide_new_file_menu() + self.to_rename_files.clear() + + + def cut_files(self): wid, tid = self.window_controller.get_active_data() @@ -87,6 +126,13 @@ class WidgetFileActionMixin: uris = self.format_to_uris(store, wid, tid, self.selected_files) self.to_cut_files = uris + def copy_files(self): + wid, tid = self.window_controller.get_active_data() + iconview = self.builder.get_object(f"{wid}|{tid}|iconview") + store = iconview.get_model() + uris = self.format_to_uris(store, wid, tid, self.selected_files) + self.to_copy_files = uris + def paste_files(self): wid, tid = self.window_controller.get_active_data() view = self.get_fm_window(wid).get_view_by_id(tid) @@ -98,6 +144,8 @@ class WidgetFileActionMixin: self.handle_file(self.to_cut_files, "move", target) + + def move_file(self, view, files, target): self.handle_file([files], "move", target) @@ -118,10 +166,12 @@ class WidgetFileActionMixin: self.handle_file(uris, "trash") + + # NOTE: Gio moves files by generating the target file path with name in it # We can't just give a base target directory and run with it. # Also, the display name is UTF-8 safe and meant for displaying in GUIs - def handle_file(self, paths, action, base_dir=None): + def handle_file(self, paths, action, _target_path=None): paths = self.preprocess_paths(paths) target = None @@ -137,13 +187,16 @@ class WidgetFileActionMixin: break - if base_dir: - info = f.query_info("standard::display-name", 0, cancellable=None) - _target = f"file://{base_dir}/{info.get_display_name()}" - target = Gio.File.new_for_uri(_target) + if _target_path: + if os.path.isdir(_target_path): + info = f.query_info("standard::display-name", 0, cancellable=None) + _target = f"file://{base_dir}/{info.get_display_name()}" + target = Gio.File.new_for_uri(_target_path) + else: + target = Gio.File.new_for_uri(_target_path) # See if dragging to same directory then break - if action != "trash" and action != "delete" and \ + if action not in ["trash", "delete", "edit"] and \ (f.get_parent().get_path() == target.get_parent().get_path()): break @@ -153,7 +206,7 @@ class WidgetFileActionMixin: f.trash(cancellable=None) if action == "copy": f.copy(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None) - if action == "move": + if action == "move" or action == "edit": f.move(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None) except GObject.GError as e: raise OSError(e.message)