[#2098] Add function to highlight the torrent folder/file

* Will show/highlight a file path in system file manager. *nix uses dbus with an xdg_open fallback.
 * [GTKUI] Open Folder still opens the download location but now shows the torrent data file/folder
 * [GTKUI] Files_tab now has a second menu item 'Show' to show a file's location
 * The open_file and show_file functions now use timestamps on *nix so that windows open in front, this fixes recent desktop changes that prevent windows randomly stealing focus.
 * Removed utf8 decode for Windows. All paths should be unicode
string, any resulting errors should be traced to source and corrected.
This commit is contained in:
Calum Lind 2014-01-24 18:27:57 +00:00
parent 670cd21685
commit c5f7eeaacb
4 changed files with 93 additions and 46 deletions

View File

@ -1,38 +1,11 @@
# -*- coding: utf-8 -*-
#
# common.py
# Copyright (C) 2007,2008 Andrew Resch <andrewresch@gmail.com>
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
# Deluge is free software.
#
# You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 3 of the License, or (at your option)
# any later version.
#
# deluge 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 deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
#
#
"""Common functions for various parts of Deluge to use."""
@ -48,6 +21,14 @@ import gettext
import locale
import base64
import urllib
import urlparse
try:
import dbus
bus = dbus.SessionBus()
dbus_fileman = bus.get_object("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1")
except:
dbus_fileman = None
from deluge.error import InvalidPathError
@ -223,20 +204,51 @@ def resource_filename(module, path):
)
def open_file(path):
"""
Opens a file or folder using the system configured program
def open_file(path, timestamp=None):
"""Opens a file or folder using the system configured program.
:param path: the path to the file or folder to open
:type path: string
Args:
path (str): The path to the file or folder to open.
timestamp (int, optional): An event request timestamp.
"""
if windows_check():
os.startfile(path.decode("utf8"))
os.startfile(path)
elif osx_check():
subprocess.Popen(["open", "%s" % path])
subprocess.Popen(["open", path])
else:
subprocess.Popen(["xdg-open", "%s" % path])
if timestamp is None:
timestamp = int(time.time())
env = os.environ.copy()
env["DESKTOP_STARTUP_ID"] = "%s-%u-%s-xdg_open_TIME%d" % \
(os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
subprocess.Popen(["xdg-open", "%s" % path], env=env)
def show_file(path, timestamp=None):
"""Shows (highlights) a file or folder using the system configured file manager.
Args:
path (str): The path to the file or folder to show.
timestamp (int, optional): An event request timestamp.
"""
if windows_check():
subprocess.Popen(["explorer", "/select,", path])
elif osx_check():
subprocess.Popen(["open", "-R", path])
else:
if timestamp is None:
timestamp = int(time.time())
startup_id = "%s_%u_%s-dbus_TIME%d" % (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
if dbus_fileman:
paths = [urlparse.urljoin("file:", urllib.pathname2url(utf8_encoded(path)))]
dbus_fileman.ShowItems(paths, startup_id, dbus_interface="org.freedesktop.FileManager1")
else:
env = os.environ.copy()
env["DESKTOP_STARTUP_ID"] = startup_id.replace("dbus", "xdg-open")
# No option in xdg to highlight a file so just open parent folder.
subprocess.Popen(["xdg-open", os.path.dirname(path.rstrip("/"))], env=env)
def open_url_in_browser(url):

View File

@ -197,6 +197,7 @@ class FilesTab(Tab):
self.localhost_widgets = [
builder.get_object("menuitem_open_file"),
builder.get_object("menuitem_show_file"),
builder.get_object("menuitem3")
]
@ -215,6 +216,7 @@ class FilesTab(Tab):
component.get("MainWindow").connect_signals({
"on_menuitem_open_file_activate": self._on_menuitem_open_file_activate,
"on_menuitem_show_file_activate": self._on_menuitem_show_file_activate,
"on_menuitem_donotdownload_activate": self._on_menuitem_donotdownload_activate,
"on_menuitem_normal_activate": self._on_menuitem_normal_activate,
"on_menuitem_high_activate": self._on_menuitem_high_activate,
@ -319,8 +321,7 @@ class FilesTab(Tab):
self.torrent_id = None
def _on_row_activated(self, tree, path, view_column):
if client.is_localhost:
component.get("SessionProxy").get_torrent_status(self.torrent_id, ["save_path", "files"]).addCallback(self._on_open_file)
self._on_menuitem_open_file_activate()
def get_file_path(self, row, path=""):
if not row:
@ -339,7 +340,21 @@ class FilesTab(Tab):
path = self.get_file_path(select).split("/")
filepath = os.path.join(status["save_path"], *path)
log.debug("Open file '%s'", filepath)
deluge.common.open_file(filepath)
timestamp = gtk.get_current_event_time()
deluge.common.open_file(filepath, timestamp=timestamp)
def _on_show_file(self, status):
paths = self.listview.get_selection().get_selected_rows()[1]
selected = []
for path in paths:
selected.append(self.treestore.get_iter(path))
for select in selected:
path = self.get_file_path(select).split("/")
filepath = os.path.join(status["save_path"], *path)
log.debug("Show file '%s'", filepath)
timestamp = gtk.get_current_event_time()
deluge.common.show_file(filepath, timestamp=timestamp)
## The following 3 methods create the folder/file view in the treeview
def prepare_file_store(self, files):
@ -525,7 +540,14 @@ class FilesTab(Tab):
return True
def _on_menuitem_open_file_activate(self, menuitem):
self._on_row_activated(None, None, None)
if client.is_localhost:
component.get("SessionProxy").get_torrent_status(
self.torrent_id, ["save_path", "files"]).addCallback(self._on_open_file)
def _on_menuitem_show_file_activate(self, menuitem):
if client.is_localhost:
component.get("SessionProxy").get_torrent_status(
self.torrent_id, ["save_path", "files"]).addCallback(self._on_show_file)
def _set_file_priorities_on_user_change(self, selected, priority):
"""Sets the file priorities in the core. It will change the selected

View File

@ -46,6 +46,17 @@
<signal name="activate" handler="on_menuitem_open_file_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="menuitem_show_file">
<property name="label" translatable="yes">_Show</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_menuitem_show_file_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="menuitem3">
<property name="visible">True</property>

View File

@ -326,10 +326,12 @@ class MenuBar(component.Component):
log.debug("on_menuitem_open_folder")
def _on_torrent_status(status):
deluge.common.open_file(status["save_path"])
timestamp = gtk.get_current_event_time()
path = os.path.join(status["save_path"], status["files"][0]["path"].split('/')[0])
deluge.common.show_file(path, timestamp=timestamp)
for torrent_id in component.get("TorrentView").get_selected_torrents():
component.get("SessionProxy").get_torrent_status(
torrent_id, ["save_path"]).addCallback(_on_torrent_status)
torrent_id, ["save_path", "files"]).addCallback(_on_torrent_status)
def on_menuitem_move_activate(self, data=None):
log.debug("on_menuitem_move_activate")