Philipp Hörist pushed to branch master at gajim / gajim
Commits: 782cafb2 by mjk at 2022-12-14T23:32:40+00:00 imprv: Highlight the file when opening containing folder
- - - - -
7 changed files:
- gajim/common/application.py - + gajim/common/dbus/file_manager.py - gajim/common/helpers.py - gajim/gtk/conversation/rows/file_transfer_jingle.py - gajim/gtk/filetransfer.py - gajim/gtk/main.py - gajim/gtk/preferences.py
Changes:
===================================== gajim/common/application.py ===================================== @@ -40,6 +40,7 @@ from gajim.common import passwords from gajim.common.commands import ChatCommands from gajim.common.dbus import logind +from gajim.common.dbus import file_manager from gajim.common.events import AccountDisabled from gajim.common.events import AccountDisconnected from gajim.common.events import AccountEnabled @@ -114,6 +115,8 @@ def _init_core(self) -> None: else: logind.enable()
+ file_manager.init() + for account in app.settings.get_active_accounts(): app.connections[account] = Client(account) app.to_be_removed[account] = []
===================================== gajim/common/dbus/file_manager.py ===================================== @@ -0,0 +1,90 @@ +# This file is part of Gajim. +# +# Gajim is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 3 only. +# +# Gajim is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Gajim. If not, see http://www.gnu.org/licenses/. + +from typing import Optional + +import logging + +from gi.repository import Gio +from gi.repository import GLib + +from gajim.common.util.classes import Singleton + +log = logging.getLogger('gajim.c.dbus.file_manager') + + +class DBusFileManager(metaclass=Singleton): + ''' + (Partial) implementation of a client for + https://freedesktop.org/wiki/Specifications/file-manager-interface/ + ''' + + def __init__(self) -> None: + self._proxy: Optional[Gio.DBusProxy] + Gio.DBusProxy.new_for_bus( + Gio.BusType.SESSION, + Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION, + None, + 'org.freedesktop.FileManager1', + '/org/freedesktop/FileManager1', + 'org.freedesktop.FileManager1', + None, + self._on_proxy_ready, + ) + + def _on_proxy_ready(self, _: None, res: Gio.AsyncResult) -> None: + try: + self._proxy = Gio.DBusProxy.new_finish(res) + except GLib.Error as err: + log.warning('Couldn’t construct dbus proxy: %s', err.message) + + def is_available(self) -> bool: + return self._proxy is not None + + def show_items_sync(self, + uris: list[str], + startup_id: str = '', + timeout_ms: int = 500, + ) -> bool: + ''' + Opens parent folder(s), selecting/highlighting the specified + files/folders. E.g., for ['file:/home/user/Downloads/xyzzy.foo', + 'file:/home/user/Downloads/Quuxes'], opens ~/Downloads with + xyzzy.foo and Quuxes items selected. + + Returns True on success. + + Fails if called too early after construction; check `is_available()`. + ''' + + if self._proxy is None: + log.debug('ShowItems: no dbus proxy') + return False + + try: + self._proxy.call_sync( + 'ShowItems', + GLib.Variant('(ass)', (uris, startup_id)), + Gio.DBusCallFlags.NONE, + timeout_ms, + None, + ) + return True + except GLib.Error as err: + log.warning('ShowItems failed: %s', err.message) + return False + + +def init() -> None: + DBusFileManager()
===================================== gajim/common/helpers.py ===================================== @@ -100,6 +100,7 @@ from gajim.common.const import SHOW_LIST from gajim.common.const import CONSONANTS from gajim.common.const import VOWELS +from gajim.common.dbus.file_manager import DBusFileManager from gajim.common.structs import URI from gajim.common import types if TYPE_CHECKING: @@ -1102,6 +1103,16 @@ def open_file(path: Path) -> None: open_file_uri(path.as_uri())
+def open_directory(path: Path) -> None: + return open_file(path) + + +def show_in_folder(path: Path) -> None: + if not DBusFileManager().show_items_sync([path.as_uri()]): + # Fall back to just opening the containing folder + open_directory(path.parent) + + def filesystem_path_from_uri(uri: str) -> Optional[Path]: puri = parse_uri(uri) if puri.type != URIType.FILE:
===================================== gajim/gtk/conversation/rows/file_transfer_jingle.py ===================================== @@ -43,6 +43,7 @@ from gajim.common.file_props import FileProp from gajim.common.file_props import FilesProp from gajim.common.helpers import open_file +from gajim.common.helpers import show_in_folder from gajim.common.i18n import _ from gajim.common.modules.contacts import BareContact from gajim.common.storage.archive import ConversationRow @@ -352,9 +353,7 @@ def _on_open_file(self, _button: Gtk.Button) -> None: def _on_open_folder(self, _button: Gtk.Button) -> None: assert self._file_props is not None assert self._file_props.file_name is not None - - folder = Path(self._file_props.file_name).parent - open_file(folder) + show_in_folder(Path(self._file_props.file_name))
def _on_bad_hash_retry(self, _button: Gtk.Button) -> None: app.interface.instances['file_transfers'].show_hash_error(
===================================== gajim/gtk/filetransfer.py ===================================== @@ -47,9 +47,9 @@ from gajim.common.i18n import _ from gajim.common.file_props import FilesProp from gajim.common.file_props import FileProp -from gajim.common.helpers import open_file from gajim.common.helpers import file_is_locked from gajim.common.helpers import AdditionalDataDict +from gajim.common.helpers import show_in_folder from gajim.common.modules.bytestream import is_transfer_active from gajim.common.modules.bytestream import is_transfer_paused from gajim.common.modules.bytestream import is_transfer_stopped @@ -1026,8 +1026,7 @@ def _on_open_folder_menuitem_activate(self, widget): if not file_props.file_name: return
- folder = Path(file_props.file_name).parent - open_file(folder) + show_in_folder(Path(file_props.file_name))
def _on_cancel_menuitem_activate(self, widget): self._on_cancel_button_clicked(widget)
===================================== gajim/gtk/main.py ===================================== @@ -43,6 +43,7 @@ from gajim.common.helpers import open_file from gajim.common.helpers import open_uri from gajim.common.helpers import play_sound +from gajim.common.helpers import show_in_folder from gajim.common.modules.bytestream import is_transfer_active from gajim.common.modules.contacts import GroupchatContact from gajim.plugins.pluginmanager import PluginManifest @@ -565,7 +566,7 @@ def _on_ok(paths: list[str]) -> None: return
assert preview.orig_path is not None - open_file(preview.orig_path.parent) + show_in_folder(preview.orig_path)
elif action_name == 'preview-copy-link': display = Gdk.Display.get_default()
===================================== gajim/gtk/preferences.py ===================================== @@ -28,7 +28,7 @@ from gajim.common import configpaths from gajim.common.const import THRESHOLD_OPTIONS from gajim.common.i18n import _ -from gajim.common.helpers import open_file +from gajim.common.helpers import open_directory from gajim.common.multimedia_helpers import AudioInputManager from gajim.common.multimedia_helpers import AudioOutputManager from gajim.common.multimedia_helpers import VideoInputManager @@ -978,7 +978,7 @@ def _on_debug_logging(value: bool, *args: Any) -> None:
@staticmethod def _on_open_debug_logs(*args: Any) -> None: - open_file(configpaths.get('DEBUG')) + open_directory(configpaths.get('DEBUG'))
@staticmethod def _on_advanced_config_editor(*args: Any) -> None:
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/782cafb2720bd740303d9df644a8c5060...