From bd71740207e705bc778d39402cef5855eebcdcb2 Mon Sep 17 00:00:00 2001 From: kramo Date: Mon, 25 Dec 2023 23:59:22 +0100 Subject: [PATCH] Properly set cut files --- hyperplane/editable_row.py | 82 ++++++++++++++++---------------- hyperplane/item.py | 81 +++++++++++++++++-------------- hyperplane/items_page.py | 24 ++++------ hyperplane/path_entry.py | 16 +++---- hyperplane/path_segment.py | 22 ++++----- hyperplane/postmaster_general.py | 9 ++++ hyperplane/shared.py.in | 18 +++---- 7 files changed, 131 insertions(+), 121 deletions(-) diff --git a/hyperplane/editable_row.py b/hyperplane/editable_row.py index 7640e6b..e813e5e 100644 --- a/hyperplane/editable_row.py +++ b/hyperplane/editable_row.py @@ -65,6 +65,47 @@ def __init__(self, identifier: Optional[str] = None, **kwargs) -> None: self.editable = True self.identifier = identifier + @GObject.Property(type=str) + def identifier(self) -> str: + """The identifier for the row used in dconf.""" + return self._identifier + + @identifier.setter + def set_identifier(self, identifier: str) -> None: + if not identifier: + return + + self._identifier = identifier + + self.set_active() + + @GObject.Property(type=bool, default=True) + def editable(self) -> str: + """Whether the row is actually editable.""" + return self._editable + + @editable.setter + def set_editable(self, editable: bool) -> None: + self._editable = editable + + @GObject.Property(type=str) + def icon_name(self) -> str: + """The icon name for self.""" + return self.image.get_icon_name() + + @icon_name.setter + def set_icon_name(self, icon_name: str) -> None: + self.image.set_from_icon_name(icon_name) + + @GObject.Property(type=str) + def title(self) -> str: + """The title for self.""" + self.label.get_label() + + @title.setter + def set_title(self, title: str) -> None: + self.label.set_label(title) + def start_edit(self) -> None: """Reveals the check button for editing.""" self.set_visible(True) @@ -133,44 +174,3 @@ def set_active(self) -> None: # If we are not in edit mode if not self.check_revealer.get_reveal_child(): self.set_visible(self.check.get_active()) - - @GObject.Property(type=str) - def identifier(self) -> str: - """The identifier for the row used in dconf.""" - return self._identifier - - @identifier.setter - def set_identifier(self, identifier: str) -> None: - if not identifier: - return - - self._identifier = identifier - - self.set_active() - - @GObject.Property(type=bool, default=True) - def editable(self) -> str: - """Whether the row is actually editable.""" - return self._editable - - @editable.setter - def set_editable(self, editable: bool) -> None: - self._editable = editable - - @GObject.Property(type=str) - def icon_name(self) -> str: - """The icon name for self.""" - return self.image.get_icon_name() - - @icon_name.setter - def set_icon_name(self, icon_name: str) -> None: - self.image.set_from_icon_name(icon_name) - - @GObject.Property(type=str) - def title(self) -> str: - """The title for self.""" - self.label.get_label() - - @title.setter - def set_title(self, title: str) -> None: - self.label.set_label(title) diff --git a/hyperplane/item.py b/hyperplane/item.py index 7ee215c..c7e5471 100644 --- a/hyperplane/item.py +++ b/hyperplane/item.py @@ -93,8 +93,48 @@ def __init__(self, item, page, **kwargs) -> None: self.dir_thumb_init_classes = self.dir_thumbnail_1.get_css_classes() self.dir_icon_init_classes = self.dir_thumbnail_1.get_child().get_css_classes() + shared.postmaster.connect("cut-uris-changed", self.__cut_uris_changed) + + @GObject.Property(type=str) + def display_name(self) -> str: + """The name of the item visible to the user.""" + return self._display_name + + @display_name.setter + def set_display_name(self, name: str) -> None: + self._display_name = name + + @GObject.Property(type=str) + def extension(self) -> str: + """The extension of the file or None.""" + return self._extension + + @extension.setter + def set_extension(self, extension: str) -> None: + self._extension = extension + + @GObject.Property(type=Gio.Icon) + def gicon(self) -> Gio.Icon: + """The icon of the item displayed to the user if no thumbnail is available.""" + return self._gicon + + @gicon.setter + def set_gicon(self, gicon: Gio.Icon) -> None: + self._gicon = gicon + + @GObject.Property(type=Gdk.Paintable) + def thumbnail_paintable(self) -> Gdk.Paintable: + """The paintable used for the thumbnail.""" + return self._thumbnail_paintable + + @thumbnail_paintable.setter + def set_thumbnail_paintable(self, thumbnail_paintable: Gdk.Paintable) -> None: + self._thumbnail_paintable = thumbnail_paintable + def bind(self) -> None: """Build the icon after the object has been bound.""" + idle_add(self.__cut_uris_changed) + self.file_info = self.item.get_item() self.gfile = self.file_info.get_attribute_object("standard::file") @@ -440,38 +480,9 @@ def __middle_click(self, *_args: Any) -> None: for gfile in self.page.get_selected_gfiles(): self.get_root().new_tab(gfile) - @GObject.Property(type=str) - def display_name(self) -> str: - """The name of the item visible to the user.""" - return self._display_name - - @display_name.setter - def set_display_name(self, name: str) -> None: - self._display_name = name - - @GObject.Property(type=str) - def extension(self) -> str: - """The extension of the file or None.""" - return self._extension - - @extension.setter - def set_extension(self, extension: str) -> None: - self._extension = extension - - @GObject.Property(type=Gio.Icon) - def gicon(self) -> Gio.Icon: - """The icon of the item displayed to the user if no thumbnail is available.""" - return self._gicon - - @gicon.setter - def set_gicon(self, gicon: Gio.Icon) -> None: - self._gicon = gicon - - @GObject.Property(type=Gdk.Paintable) - def thumbnail_paintable(self) -> Gdk.Paintable: - """The paintable used for the thumbnail.""" - return self._thumbnail_paintable - - @thumbnail_paintable.setter - def set_thumbnail_paintable(self, thumbnail_paintable: Gdk.Paintable) -> None: - self._thumbnail_paintable = thumbnail_paintable + def __cut_uris_changed(self, *_args: Any) -> None: + ( + self.add_css_class + if self.gfile.get_uri() in shared.cut_uris + else self.remove_css_class + )("cut-item") diff --git a/hyperplane/items_page.py b/hyperplane/items_page.py index f3e8ce9..eb6dbc0 100644 --- a/hyperplane/items_page.py +++ b/hyperplane/items_page.py @@ -446,7 +446,7 @@ def __right_click(self, _gesture, _n, x, y) -> None: GLib.timeout_add(10, self.__popup_menu) def __drop_file( - self, _drop_target: Gtk.DropTarget, file_list: Gdk.FileList, _x, _y + self, _drop_target: Gtk.DropTarget, file_list: Gdk.FileList, _x: float, _y ) -> None: # TODO: This is copy-paste from __paste() for src in file_list: @@ -480,7 +480,7 @@ def __drop_file( continue def __drop_texture( - self, _drop_target: Gtk.DropTarget, texture: Gdk.Texture, _x, _y + self, _drop_target: Gtk.DropTarget, texture: Gdk.Texture, _x: float, _y ) -> None: # TODO: Again, copy-paste from __paste() if self.tags: @@ -516,7 +516,7 @@ def __drop_texture( output.write_bytes(texture_bytes) def __drop_text( - self, _drop_target: Gtk.DropTarget, text: str, _x, _y + self, _drop_target: Gtk.DropTarget, text: str, _x: float, _y: float ) -> None: # TODO: Again again, copy-paste from __paste() if not text: # If text is an empty string @@ -709,7 +709,7 @@ def create_folder(*_args: Any): dialog.choose() def __copy(self, *_args: Any) -> None: - shared.set_cut_widgets(set()) + shared.set_cut_uris(set()) clipboard = Gdk.Display.get_default().get_clipboard() if not (items := self.get_selected_gfiles()): return @@ -720,15 +720,9 @@ def __copy(self, *_args: Any) -> None: def __cut(self, _obj: Any, *args: Any) -> None: self.__copy(*args) - - children = self.grid_view.observe_children() - - cut_widgets = set() - - for pos in self.get_selected_positions(): - cut_widgets.add(children.get_item(pos).get_first_child()) - - shared.set_cut_widgets(cut_widgets) + shared.set_cut_uris( + set(gfile.get_uri() for gfile in self.get_selected_gfiles()) + ) def __paste(self, *_args: Any) -> None: clipboard = Gdk.Display.get_default().get_clipboard() @@ -754,7 +748,7 @@ def paste_file_cb(clipboard: Gdk.Clipboard, result: Gio.AsyncResult) -> None: try: file_list = clipboard.read_value_finish(result) except GLib.Error: - shared.set_cut_widgets(set()) + shared.set_cut_uris(set()) return for src in file_list: @@ -795,7 +789,7 @@ def paste_file_cb(clipboard: Gdk.Clipboard, result: Gio.AsyncResult) -> None: shared.undo_queue[time()] = ("cut", paths) else: shared.undo_queue[time()] = ("copy", paths) - shared.set_cut_widgets(set()) + shared.set_cut_uris(set()) def paste_texture_cb(clipboard: Gdk.Clipboard, result: Gio.AsyncResult) -> None: nonlocal dst diff --git a/hyperplane/path_entry.py b/hyperplane/path_entry.py index f31bba5..ef605a3 100644 --- a/hyperplane/path_entry.py +++ b/hyperplane/path_entry.py @@ -35,6 +35,14 @@ def __init__(self, **kwargs) -> None: super().__init__(**kwargs) self.connect("activate", self.__activate) + @GObject.Signal(name="hide-entry") + def hide(self) -> None: + """ + Emitted to indicate that the entry is done and should be hidden. + + Containers of this widget should connect to it and react accordingly. + """ + def __activate(self, entry, *_args: Any) -> None: text = entry.get_text().strip() @@ -68,11 +76,3 @@ def __activate(self, entry, *_args: Any) -> None: self.emit("hide-entry") self.get_root().new_page(gfile) - - @GObject.Signal(name="hide-entry") - def hide(self) -> None: - """ - Emitted to indicate that the entry is done and should be hidden. - - Containers of this widget should connect to it and react accordingly. - """ diff --git a/hyperplane/path_segment.py b/hyperplane/path_segment.py index d083ab0..d9338e2 100644 --- a/hyperplane/path_segment.py +++ b/hyperplane/path_segment.py @@ -62,17 +62,6 @@ def __init__( self.button.connect("clicked", self.__navigate) - def __navigate(self, *_args: Any) -> None: - if self.tag: - self.get_root().new_page(tags=[self.tag]) - return - - if self.uri: - if self.active: # pylint: disable=using-constant-test - return - - self.get_root().new_page(Gio.File.new_for_uri(self.uri)) - @GObject.Property(type=bool, default=True) def active(self) -> bool: """Whether the segment is the currently active one.""" @@ -107,3 +96,14 @@ def label(self) -> str: @label.setter def set_label(self, label: str) -> None: (self.button_content if self.icon_name else self.button).set_label(label) + + def __navigate(self, *_args: Any) -> None: + if self.tag: + self.get_root().new_page(tags=[self.tag]) + return + + if self.uri: + if self.active: # pylint: disable=using-constant-test + return + + self.get_root().new_page(Gio.File.new_for_uri(self.uri)) diff --git a/hyperplane/postmaster_general.py b/hyperplane/postmaster_general.py index aac245b..370c89b 100644 --- a/hyperplane/postmaster_general.py +++ b/hyperplane/postmaster_general.py @@ -69,3 +69,12 @@ def trash_emptied(self) -> None: @GObject.Signal(name="sidebar-edited") def sidebar_changed(self) -> None: """Emitted when the visibility of items in the sidebar has been edited.""" + + @GObject.Signal(name="cut-uris-changed") + def cut_files_changed(self) -> None: + """ + Emitted whenever a cut operation starts, finishes or is cancelled. + + Widgets represeting files should connect to this, and + if the URI of the file they represent is in `shared.cut_uris`, react accordingly. + """ diff --git a/hyperplane/shared.py.in b/hyperplane/shared.py.in index 6aefe48..d98ff89 100644 --- a/hyperplane/shared.py.in +++ b/hyperplane/shared.py.in @@ -78,21 +78,17 @@ if ( else: recent_manager = Gtk.RecentManager.get_default() -cut_widgets = set() +cut_uris = set() -def set_cut_widgets(widgets: list[Gtk.Widget]) -> None: +def set_cut_uris(uris: set[str]) -> None: """ - Sets widgets representing files that are going to be moved after a paste operation. + Sets URIs representing files that are going to be moved after a paste operation. - This is so their "opacity" can be reduced. + This is so the widgets' "opacities" can be reduced. """ - global cut_widgets # pylint: disable=global-statement + global cut_uris # pylint: disable=global-statement - for widget in cut_widgets: - widget.remove_css_class("cut-item") + cut_uris = uris - for widget in widgets: - widget.add_css_class("cut-item") - - cut_widgets = widgets + postmaster.emit("cut-uris-changed")