Philipp Hörist pushed to branch master at gajim / gajim
Commits:
-
782cafb2
by mjk at 2022-12-14T23:32:40+00:00
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:
| ... | ... | @@ -40,6 +40,7 @@ |
| 40 | 40 | from gajim.common import passwords
|
| 41 | 41 | from gajim.common.commands import ChatCommands
|
| 42 | 42 | from gajim.common.dbus import logind
|
| 43 | +from gajim.common.dbus import file_manager
|
|
| 43 | 44 | from gajim.common.events import AccountDisabled
|
| 44 | 45 | from gajim.common.events import AccountDisconnected
|
| 45 | 46 | from gajim.common.events import AccountEnabled
|
| ... | ... | @@ -114,6 +115,8 @@ def _init_core(self) -> None: |
| 114 | 115 | else:
|
| 115 | 116 | logind.enable()
|
| 116 | 117 | |
| 118 | + file_manager.init()
|
|
| 119 | + |
|
| 117 | 120 | for account in app.settings.get_active_accounts():
|
| 118 | 121 | app.connections[account] = Client(account)
|
| 119 | 122 | app.to_be_removed[account] = []
|
| 1 | +# This file is part of Gajim.
|
|
| 2 | +#
|
|
| 3 | +# Gajim is free software; you can redistribute it and/or modify
|
|
| 4 | +# it under the terms of the GNU General Public License as published
|
|
| 5 | +# by the Free Software Foundation; version 3 only.
|
|
| 6 | +#
|
|
| 7 | +# Gajim is distributed in the hope that it will be useful,
|
|
| 8 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 9 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 10 | +# GNU General Public License for more details.
|
|
| 11 | +#
|
|
| 12 | +# You should have received a copy of the GNU General Public License
|
|
| 13 | +# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
|
| 14 | + |
|
| 15 | +from typing import Optional
|
|
| 16 | + |
|
| 17 | +import logging
|
|
| 18 | + |
|
| 19 | +from gi.repository import Gio
|
|
| 20 | +from gi.repository import GLib
|
|
| 21 | + |
|
| 22 | +from gajim.common.util.classes import Singleton
|
|
| 23 | + |
|
| 24 | +log = logging.getLogger('gajim.c.dbus.file_manager')
|
|
| 25 | + |
|
| 26 | + |
|
| 27 | +class DBusFileManager(metaclass=Singleton):
|
|
| 28 | + '''
|
|
| 29 | + (Partial) implementation of a client for
|
|
| 30 | + https://freedesktop.org/wiki/Specifications/file-manager-interface/
|
|
| 31 | + '''
|
|
| 32 | + |
|
| 33 | + def __init__(self) -> None:
|
|
| 34 | + self._proxy: Optional[Gio.DBusProxy]
|
|
| 35 | + Gio.DBusProxy.new_for_bus(
|
|
| 36 | + Gio.BusType.SESSION,
|
|
| 37 | + Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION,
|
|
| 38 | + None,
|
|
| 39 | + 'org.freedesktop.FileManager1',
|
|
| 40 | + '/org/freedesktop/FileManager1',
|
|
| 41 | + 'org.freedesktop.FileManager1',
|
|
| 42 | + None,
|
|
| 43 | + self._on_proxy_ready,
|
|
| 44 | + )
|
|
| 45 | + |
|
| 46 | + def _on_proxy_ready(self, _: None, res: Gio.AsyncResult) -> None:
|
|
| 47 | + try:
|
|
| 48 | + self._proxy = Gio.DBusProxy.new_finish(res)
|
|
| 49 | + except GLib.Error as err:
|
|
| 50 | + log.warning('Couldn’t construct dbus proxy: %s', err.message)
|
|
| 51 | + |
|
| 52 | + def is_available(self) -> bool:
|
|
| 53 | + return self._proxy is not None
|
|
| 54 | + |
|
| 55 | + def show_items_sync(self,
|
|
| 56 | + uris: list[str],
|
|
| 57 | + startup_id: str = '',
|
|
| 58 | + timeout_ms: int = 500,
|
|
| 59 | + ) -> bool:
|
|
| 60 | + '''
|
|
| 61 | + Opens parent folder(s), selecting/highlighting the specified
|
|
| 62 | + files/folders. E.g., for ['file:/home/user/Downloads/xyzzy.foo',
|
|
| 63 | + 'file:/home/user/Downloads/Quuxes'], opens ~/Downloads with
|
|
| 64 | + xyzzy.foo and Quuxes items selected.
|
|
| 65 | + |
|
| 66 | + Returns True on success.
|
|
| 67 | + |
|
| 68 | + Fails if called too early after construction; check `is_available()`.
|
|
| 69 | + '''
|
|
| 70 | + |
|
| 71 | + if self._proxy is None:
|
|
| 72 | + log.debug('ShowItems: no dbus proxy')
|
|
| 73 | + return False
|
|
| 74 | + |
|
| 75 | + try:
|
|
| 76 | + self._proxy.call_sync(
|
|
| 77 | + 'ShowItems',
|
|
| 78 | + GLib.Variant('(ass)', (uris, startup_id)),
|
|
| 79 | + Gio.DBusCallFlags.NONE,
|
|
| 80 | + timeout_ms,
|
|
| 81 | + None,
|
|
| 82 | + )
|
|
| 83 | + return True
|
|
| 84 | + except GLib.Error as err:
|
|
| 85 | + log.warning('ShowItems failed: %s', err.message)
|
|
| 86 | + return False
|
|
| 87 | + |
|
| 88 | + |
|
| 89 | +def init() -> None:
|
|
| 90 | + DBusFileManager() |
| ... | ... | @@ -100,6 +100,7 @@ |
| 100 | 100 | from gajim.common.const import SHOW_LIST
|
| 101 | 101 | from gajim.common.const import CONSONANTS
|
| 102 | 102 | from gajim.common.const import VOWELS
|
| 103 | +from gajim.common.dbus.file_manager import DBusFileManager
|
|
| 103 | 104 | from gajim.common.structs import URI
|
| 104 | 105 | from gajim.common import types
|
| 105 | 106 | if TYPE_CHECKING:
|
| ... | ... | @@ -1102,6 +1103,16 @@ def open_file(path: Path) -> None: |
| 1102 | 1103 | open_file_uri(path.as_uri())
|
| 1103 | 1104 | |
| 1104 | 1105 | |
| 1106 | +def open_directory(path: Path) -> None:
|
|
| 1107 | + return open_file(path)
|
|
| 1108 | + |
|
| 1109 | + |
|
| 1110 | +def show_in_folder(path: Path) -> None:
|
|
| 1111 | + if not DBusFileManager().show_items_sync([path.as_uri()]):
|
|
| 1112 | + # Fall back to just opening the containing folder
|
|
| 1113 | + open_directory(path.parent)
|
|
| 1114 | + |
|
| 1115 | + |
|
| 1105 | 1116 | def filesystem_path_from_uri(uri: str) -> Optional[Path]:
|
| 1106 | 1117 | puri = parse_uri(uri)
|
| 1107 | 1118 | if puri.type != URIType.FILE:
|
| ... | ... | @@ -43,6 +43,7 @@ |
| 43 | 43 | from gajim.common.file_props import FileProp
|
| 44 | 44 | from gajim.common.file_props import FilesProp
|
| 45 | 45 | from gajim.common.helpers import open_file
|
| 46 | +from gajim.common.helpers import show_in_folder
|
|
| 46 | 47 | from gajim.common.i18n import _
|
| 47 | 48 | from gajim.common.modules.contacts import BareContact
|
| 48 | 49 | from gajim.common.storage.archive import ConversationRow
|
| ... | ... | @@ -352,9 +353,7 @@ def _on_open_file(self, _button: Gtk.Button) -> None: |
| 352 | 353 | def _on_open_folder(self, _button: Gtk.Button) -> None:
|
| 353 | 354 | assert self._file_props is not None
|
| 354 | 355 | assert self._file_props.file_name is not None
|
| 355 | - |
|
| 356 | - folder = Path(self._file_props.file_name).parent
|
|
| 357 | - open_file(folder)
|
|
| 356 | + show_in_folder(Path(self._file_props.file_name))
|
|
| 358 | 357 | |
| 359 | 358 | def _on_bad_hash_retry(self, _button: Gtk.Button) -> None:
|
| 360 | 359 | app.interface.instances['file_transfers'].show_hash_error(
|
| ... | ... | @@ -47,9 +47,9 @@ |
| 47 | 47 | from gajim.common.i18n import _
|
| 48 | 48 | from gajim.common.file_props import FilesProp
|
| 49 | 49 | from gajim.common.file_props import FileProp
|
| 50 | -from gajim.common.helpers import open_file
|
|
| 51 | 50 | from gajim.common.helpers import file_is_locked
|
| 52 | 51 | from gajim.common.helpers import AdditionalDataDict
|
| 52 | +from gajim.common.helpers import show_in_folder
|
|
| 53 | 53 | from gajim.common.modules.bytestream import is_transfer_active
|
| 54 | 54 | from gajim.common.modules.bytestream import is_transfer_paused
|
| 55 | 55 | from gajim.common.modules.bytestream import is_transfer_stopped
|
| ... | ... | @@ -1026,8 +1026,7 @@ def _on_open_folder_menuitem_activate(self, widget): |
| 1026 | 1026 | if not file_props.file_name:
|
| 1027 | 1027 | return
|
| 1028 | 1028 | |
| 1029 | - folder = Path(file_props.file_name).parent
|
|
| 1030 | - open_file(folder)
|
|
| 1029 | + show_in_folder(Path(file_props.file_name))
|
|
| 1031 | 1030 | |
| 1032 | 1031 | def _on_cancel_menuitem_activate(self, widget):
|
| 1033 | 1032 | self._on_cancel_button_clicked(widget)
|
| ... | ... | @@ -43,6 +43,7 @@ |
| 43 | 43 | from gajim.common.helpers import open_file
|
| 44 | 44 | from gajim.common.helpers import open_uri
|
| 45 | 45 | from gajim.common.helpers import play_sound
|
| 46 | +from gajim.common.helpers import show_in_folder
|
|
| 46 | 47 | from gajim.common.modules.bytestream import is_transfer_active
|
| 47 | 48 | from gajim.common.modules.contacts import GroupchatContact
|
| 48 | 49 | from gajim.plugins.pluginmanager import PluginManifest
|
| ... | ... | @@ -565,7 +566,7 @@ def _on_ok(paths: list[str]) -> None: |
| 565 | 566 | return
|
| 566 | 567 | |
| 567 | 568 | assert preview.orig_path is not None
|
| 568 | - open_file(preview.orig_path.parent)
|
|
| 569 | + show_in_folder(preview.orig_path)
|
|
| 569 | 570 | |
| 570 | 571 | elif action_name == 'preview-copy-link':
|
| 571 | 572 | display = Gdk.Display.get_default()
|
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | from gajim.common import configpaths
|
| 29 | 29 | from gajim.common.const import THRESHOLD_OPTIONS
|
| 30 | 30 | from gajim.common.i18n import _
|
| 31 | -from gajim.common.helpers import open_file
|
|
| 31 | +from gajim.common.helpers import open_directory
|
|
| 32 | 32 | from gajim.common.multimedia_helpers import AudioInputManager
|
| 33 | 33 | from gajim.common.multimedia_helpers import AudioOutputManager
|
| 34 | 34 | from gajim.common.multimedia_helpers import VideoInputManager
|
| ... | ... | @@ -978,7 +978,7 @@ def _on_debug_logging(value: bool, *args: Any) -> None: |
| 978 | 978 | |
| 979 | 979 | @staticmethod
|
| 980 | 980 | def _on_open_debug_logs(*args: Any) -> None:
|
| 981 | - open_file(configpaths.get('DEBUG'))
|
|
| 981 | + open_directory(configpaths.get('DEBUG'))
|
|
| 982 | 982 | |
| 983 | 983 | @staticmethod
|
| 984 | 984 | def _on_advanced_config_editor(*args: Any) -> None:
|