Added feature select files when adding torrent. Patch is from eternalswd,
thanks :).
This commit is contained in:
parent
b06922dcd4
commit
c93a5c57b7
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkDialog" id="file_dialog">
|
||||||
|
<property name="border_width">5</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="title" translatable="yes">Deluge File Selection</property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="default_height">550</property>
|
||||||
|
<property name="default_width">550</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">True</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">True</property>
|
||||||
|
<property name="skip_pager_hint">True</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<property name="has_separator">False</property>
|
||||||
|
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<widget class="GtkVBox" id="dialog-vbox3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">1</property>
|
||||||
|
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<widget class="GtkHButtonBox" id="dialog-action_area3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="button2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">0</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="button1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">1</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">GTK_PACK_END</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
|
||||||
|
<property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTreeView" id="file_view">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">2</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
|
@ -158,35 +158,55 @@
|
||||||
<property name="bottom_padding">2</property>
|
<property name="bottom_padding">2</property>
|
||||||
<property name="left_padding">12</property>
|
<property name="left_padding">12</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox11">
|
<widget class="GtkVBox" id="newvbox1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="spacing">10</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label56">
|
<widget class="GtkHBox" id="hbox11">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="tooltip" translatable="yes">The number of active torrents that Deluge will run. Set to -1 for unlimited.</property>
|
<property name="spacing">10</property>
|
||||||
<property name="xalign">0</property>
|
<child>
|
||||||
<property name="label" translatable="yes">Maximum simultaneous active torrents:</property>
|
<widget class="GtkLabel" id="label56">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">The number of active torrents that Deluge will run. Set to -1 for unlimited.</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Maximum simultaneous active torrents:</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSpinButton" id="spin_torrents">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The number of active torrents that Deluge will run. Set to -1 for unlimited.</property>
|
||||||
|
<property name="xalign">1</property>
|
||||||
|
<property name="adjustment">-1 -1 1000 1 10 10</property>
|
||||||
|
<property name="climb_rate">1</property>
|
||||||
|
<property name="snap_to_ticks">True</property>
|
||||||
|
<property name="update_policy">GTK_UPDATE_IF_VALID</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="padding">2</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkSpinButton" id="spin_torrents">
|
<widget class="GtkCheckButton" id="chk_enable_files_dialog">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="tooltip" translatable="yes">The number of active torrents that Deluge will run. Set to -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">Enable selecting files for torrents before loading</property>
|
||||||
<property name="xalign">1</property>
|
<property name="label" translatable="yes">Enable selecting files for torrents before loading</property>
|
||||||
<property name="adjustment">-1 -1 1000 1 10 10</property>
|
<property name="response_id">0</property>
|
||||||
<property name="climb_rate">1</property>
|
<property name="draw_indicator">True</property>
|
||||||
<property name="snap_to_ticks">True</property>
|
|
||||||
<property name="update_policy">GTK_UPDATE_IF_VALID</property>
|
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="padding">2</property>
|
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -35,6 +35,7 @@ import gtk
|
||||||
import gtk.glade
|
import gtk.glade
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
import files
|
||||||
|
|
||||||
PREFS_FILENAME = "prefs.state"
|
PREFS_FILENAME = "prefs.state"
|
||||||
|
|
||||||
|
@ -85,6 +86,7 @@ class PreferencesDlg:
|
||||||
self.glade.get_widget("finished_path_button").set_sensitive(False)
|
self.glade.get_widget("finished_path_button").set_sensitive(False)
|
||||||
self.glade.get_widget("finished_path_button").set_filename(self.preferences.get("default_finished_path"))
|
self.glade.get_widget("finished_path_button").set_filename(self.preferences.get("default_finished_path"))
|
||||||
self.glade.get_widget("download_path_button").set_filename(self.preferences.get("default_download_path"))
|
self.glade.get_widget("download_path_button").set_filename(self.preferences.get("default_download_path"))
|
||||||
|
self.glade.get_widget("chk_enable_files_dialog").set_active(self.preferences.get("enable_files_dialog"))
|
||||||
self.glade.get_widget("chk_compact").set_active(self.preferences.get("use_compact_storage"))
|
self.glade.get_widget("chk_compact").set_active(self.preferences.get("use_compact_storage"))
|
||||||
self.glade.get_widget("active_port_label").set_text(str(self.parent.manager.get_state()['port']))
|
self.glade.get_widget("active_port_label").set_text(str(self.parent.manager.get_state()['port']))
|
||||||
self.glade.get_widget("spin_port_min").set_value(self.preferences.get("listen_on")[0])
|
self.glade.get_widget("spin_port_min").set_value(self.preferences.get("listen_on")[0])
|
||||||
|
@ -131,6 +133,7 @@ class PreferencesDlg:
|
||||||
self.preferences.set("default_download_path", self.glade.get_widget("download_path_button").get_filename())
|
self.preferences.set("default_download_path", self.glade.get_widget("download_path_button").get_filename())
|
||||||
self.preferences.set("enable_move_completed", self.glade.get_widget("chk_move_completed").get_active())
|
self.preferences.set("enable_move_completed", self.glade.get_widget("chk_move_completed").get_active())
|
||||||
self.preferences.set("default_finished_path", self.glade.get_widget("finished_path_button").get_filename())
|
self.preferences.set("default_finished_path", self.glade.get_widget("finished_path_button").get_filename())
|
||||||
|
self.preferences.set("enable_files_dialog", self.glade.get_widget("chk_enable_files_dialog").get_active())
|
||||||
self.preferences.set("auto_end_seeding", self.glade.get_widget("chk_autoseed").get_active())
|
self.preferences.set("auto_end_seeding", self.glade.get_widget("chk_autoseed").get_active())
|
||||||
self.preferences.set("auto_seed_ratio", self.glade.get_widget("ratio_spinner").get_value())
|
self.preferences.set("auto_seed_ratio", self.glade.get_widget("ratio_spinner").get_value())
|
||||||
self.preferences.set("use_compact_storage", self.glade.get_widget("chk_compact").get_active())
|
self.preferences.set("use_compact_storage", self.glade.get_widget("chk_compact").get_active())
|
||||||
|
@ -168,6 +171,28 @@ class PreferencesDlg:
|
||||||
self.glade.get_widget("chk_move_completed").set_sensitive(True)
|
self.glade.get_widget("chk_move_completed").set_sensitive(True)
|
||||||
self.glade.get_widget("finished_path_button").set_sensitive(True)
|
self.glade.get_widget("finished_path_button").set_sensitive(True)
|
||||||
|
|
||||||
|
class FilesDlg:
|
||||||
|
def __init__(self, parent, files_for_dialog):
|
||||||
|
self.files_for_dialog = files_for_dialog
|
||||||
|
self.parent = parent
|
||||||
|
self.glade = gtk.glade.XML(common.get_glade_file("files_dialog.glade"), domain='deluge')
|
||||||
|
self.dialog = self.glade.get_widget("file_dialog")
|
||||||
|
self.dialog.set_icon_from_file(common.get_pixmap("deluge32.png"))
|
||||||
|
self.file_view = self.glade.get_widget("file_view")
|
||||||
|
|
||||||
|
def show(self, manager, unique_id):
|
||||||
|
self.manager = manager
|
||||||
|
self.files_for_dialog.clear_file_store()
|
||||||
|
self.files_for_dialog.use_unique_id(unique_id)
|
||||||
|
self.files_for_dialog.file_view_actions(self.file_view)
|
||||||
|
self.files_for_dialog.prepare_store()
|
||||||
|
self.dialog.show()
|
||||||
|
r = self.dialog.run()
|
||||||
|
self.dialog.hide()
|
||||||
|
self.files_for_dialog.remove_columns()
|
||||||
|
self.files_for_dialog.clear_file_store()
|
||||||
|
return r
|
||||||
|
|
||||||
class PluginDlg:
|
class PluginDlg:
|
||||||
def __init__(self, parent, plugins):
|
def __init__(self, parent, plugins):
|
||||||
self.glade = gtk.glade.XML(common.get_glade_file("plugin_dialog.glade"), domain='deluge')
|
self.glade = gtk.glade.XML(common.get_glade_file("plugin_dialog.glade"), domain='deluge')
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# files.py
|
||||||
|
#
|
||||||
|
# Copyright (C) Zach Tibbitts 2006 <zach@collegegeek.org>
|
||||||
|
#
|
||||||
|
# This program 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; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 this program. 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.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import imp
|
||||||
|
import gtk
|
||||||
|
import dgtk
|
||||||
|
import common
|
||||||
|
from itertools import izip
|
||||||
|
import gobject
|
||||||
|
|
||||||
|
class FilesManager:
|
||||||
|
def __init__(self, manager, is_file_tab):
|
||||||
|
self.manager = manager
|
||||||
|
self.file_glade = gtk.glade.XML(common.get_glade_file("file_tab_menu.glade"), domain='deluge')
|
||||||
|
self.file_menu = self.file_glade.get_widget("file_tab_menu")
|
||||||
|
self.file_glade.signal_autoconnect({
|
||||||
|
"select_all": self.file_select_all,
|
||||||
|
"unselect_all": self.file_unselect_all,
|
||||||
|
"check_selected": self.file_check_selected,
|
||||||
|
"uncheck_selected": self.file_uncheck_selected,
|
||||||
|
})
|
||||||
|
self.file_unique_id = -1
|
||||||
|
# Stores file path -> gtk.TreeIter's iter mapping for quick look up
|
||||||
|
# in self.update_torrent_info_widget
|
||||||
|
self.file_store_dict = {}
|
||||||
|
self.file_store = gtk.ListStore(bool, str, gobject.TYPE_UINT64)
|
||||||
|
self.file_store_sorted = gtk.TreeModelSort(self.file_store)
|
||||||
|
self.is_file_tab = is_file_tab
|
||||||
|
if self.is_file_tab:
|
||||||
|
self.file_store = gtk.ListStore(bool, str, gobject.TYPE_UINT64, float)
|
||||||
|
self.file_store_sorted = gtk.TreeModelSort(self.file_store)
|
||||||
|
|
||||||
|
def use_unique_id(self, unique_id):
|
||||||
|
self.file_unique_id = unique_id
|
||||||
|
|
||||||
|
def file_view_actions(self, file_view):
|
||||||
|
self.file_view = file_view
|
||||||
|
def percent(column, cell, model, iter, data):
|
||||||
|
percent = float(model.get_value(iter, data))
|
||||||
|
percent_str = "%.2f%%"%percent
|
||||||
|
cell.set_property("text", percent_str)
|
||||||
|
self.file_selected = []
|
||||||
|
self.toggle_column = dgtk.add_toggle_column(self.file_view, _("Download"), 0, toggled_signal=self.file_toggled)
|
||||||
|
self.filename_column = dgtk.add_text_column(self.file_view, _("Filename"), 1)
|
||||||
|
self.filename_column.set_expand(True)
|
||||||
|
self.size_column = dgtk.add_func_column(self.file_view, _("Size"), dgtk.cell_data_size, 2)
|
||||||
|
if self.is_file_tab:
|
||||||
|
dgtk.add_func_column(self.file_view, _("Progress"), percent, 3)
|
||||||
|
self.file_view.set_model(self.file_store_sorted)
|
||||||
|
self.file_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||||
|
self.file_view.get_selection().set_select_function(self.file_clicked)
|
||||||
|
self.file_view.connect("button-press-event", self.file_view_clicked)
|
||||||
|
|
||||||
|
def remove_columns(self):
|
||||||
|
self.file_view.remove_column(self.size_column)
|
||||||
|
self.file_view.remove_column(self.filename_column)
|
||||||
|
self.file_view.remove_column(self.toggle_column)
|
||||||
|
|
||||||
|
def clear_file_store(self):
|
||||||
|
self.file_store.clear()
|
||||||
|
self.file_store_dict = {}
|
||||||
|
|
||||||
|
def prepare_store(self):
|
||||||
|
if not self.file_store_dict:
|
||||||
|
all_files = self.manager.get_torrent_file_info(self.file_unique_id)
|
||||||
|
file_filter = self.manager.get_file_filter(self.file_unique_id)
|
||||||
|
if file_filter is None:
|
||||||
|
file_filter = [False] * len(all_files)
|
||||||
|
if self.is_file_tab:
|
||||||
|
for file, filt in izip(all_files, file_filter):
|
||||||
|
iter = self.file_store.append([not filt, file['path'],
|
||||||
|
file['size'],
|
||||||
|
round(file['progress'], 2)])
|
||||||
|
self.file_store_dict[file['path']] = iter
|
||||||
|
else:
|
||||||
|
for file, filt in izip(all_files, file_filter):
|
||||||
|
iter = self.file_store.append([not filt, file['path'],
|
||||||
|
file['size']])
|
||||||
|
self.file_store_dict[file['path']] = iter
|
||||||
|
|
||||||
|
|
||||||
|
def update_store(self):
|
||||||
|
new_file_info = self.manager.get_torrent_file_info(self.file_unique_id)
|
||||||
|
for file in new_file_info:
|
||||||
|
iter = self.file_store_dict[file['path']]
|
||||||
|
if self.file_store.get_value(iter, 3) != round(file['progress'], 2):
|
||||||
|
self.file_store.set(iter, 3, file['progress'])
|
||||||
|
|
||||||
|
def file_select_all(self, widget):
|
||||||
|
self.file_view.get_selection().select_all()
|
||||||
|
|
||||||
|
def file_unselect_all(self, widget):
|
||||||
|
self.file_view.get_selection().unselect_all()
|
||||||
|
|
||||||
|
def file_check_selected(self, widget):
|
||||||
|
self.file_view.get_selection().selected_foreach(self.file_toggle_selected, True)
|
||||||
|
self.file_toggled_update_filter()
|
||||||
|
|
||||||
|
def file_uncheck_selected(self, widget):
|
||||||
|
self.file_view.get_selection().selected_foreach(self.file_toggle_selected, False)
|
||||||
|
self.file_toggled_update_filter()
|
||||||
|
|
||||||
|
def file_clicked(self, path):
|
||||||
|
return not self.file_selected
|
||||||
|
|
||||||
|
def file_view_clicked(self, widget, event):
|
||||||
|
if event.button == 3:
|
||||||
|
self.file_menu.popup(None, None, None, event.button, event.time)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.file_selected = False
|
||||||
|
return False
|
||||||
|
|
||||||
|
def file_toggle_selected(self, treemodel, path, selected_iter, value):
|
||||||
|
child_iter = self.file_store_sorted.convert_iter_to_child_iter(None,
|
||||||
|
selected_iter)
|
||||||
|
self.file_store_sorted.get_model().set_value(child_iter, 0, value)
|
||||||
|
|
||||||
|
def file_toggled(self, renderer, path):
|
||||||
|
self.file_selected = True
|
||||||
|
file_iter = self.file_store_sorted.get_iter_from_string(path)
|
||||||
|
value = not renderer.get_active()
|
||||||
|
selection = self.file_view.get_selection()
|
||||||
|
if selection.iter_is_selected(file_iter):
|
||||||
|
selection.selected_foreach(self.file_toggle_selected, value)
|
||||||
|
else:
|
||||||
|
child_iter = self.file_store_sorted.convert_iter_to_child_iter(
|
||||||
|
None, file_iter)
|
||||||
|
self.file_store_sorted.get_model().set_value(child_iter, 0, value)
|
||||||
|
|
||||||
|
self.file_toggled_update_filter()
|
||||||
|
|
||||||
|
def file_toggled_update_filter(self):
|
||||||
|
file_filter = [not x[0] for x in self.file_store]
|
||||||
|
self.manager.set_file_filter(self.file_unique_id, file_filter)
|
124
src/interface.py
124
src/interface.py
|
@ -47,6 +47,7 @@ import common
|
||||||
import dialogs
|
import dialogs
|
||||||
import dgtk
|
import dgtk
|
||||||
import ipc_manager
|
import ipc_manager
|
||||||
|
import files
|
||||||
import plugins
|
import plugins
|
||||||
|
|
||||||
class DelugeGTK:
|
class DelugeGTK:
|
||||||
|
@ -66,6 +67,8 @@ class DelugeGTK:
|
||||||
#Start the Deluge Manager:
|
#Start the Deluge Manager:
|
||||||
self.manager = core.Manager(common.CLIENT_CODE, common.CLIENT_VERSION,
|
self.manager = core.Manager(common.CLIENT_CODE, common.CLIENT_VERSION,
|
||||||
'%s %s'%(common.PROGRAM_NAME, common.PROGRAM_VERSION), common.CONFIG_DIR)
|
'%s %s'%(common.PROGRAM_NAME, common.PROGRAM_VERSION), common.CONFIG_DIR)
|
||||||
|
self.files_for_tab = files.FilesManager(self.manager, True)
|
||||||
|
self.files_for_dialog = files.FilesManager(self.manager, False)
|
||||||
self.plugins = plugins.PluginManager(self.manager, self)
|
self.plugins = plugins.PluginManager(self.manager, self)
|
||||||
self.plugins.add_plugin_dir(common.PLUGIN_DIR)
|
self.plugins.add_plugin_dir(common.PLUGIN_DIR)
|
||||||
if os.path.isdir(os.path.join(common.CONFIG_DIR , 'plugins')):
|
if os.path.isdir(os.path.join(common.CONFIG_DIR , 'plugins')):
|
||||||
|
@ -102,6 +105,7 @@ class DelugeGTK:
|
||||||
|
|
||||||
self.preferences_dialog = dialogs.PreferencesDlg(self, self.config)
|
self.preferences_dialog = dialogs.PreferencesDlg(self, self.config)
|
||||||
self.plugin_dialog = dialogs.PluginDlg(self, self.plugins)
|
self.plugin_dialog = dialogs.PluginDlg(self, self.plugins)
|
||||||
|
self.files_dialog = dialogs.FilesDlg(self, self.files_for_dialog)
|
||||||
self.build_torrent_table()
|
self.build_torrent_table()
|
||||||
self.build_summary_tab()
|
self.build_summary_tab()
|
||||||
self.build_file_tab()
|
self.build_file_tab()
|
||||||
|
@ -658,88 +662,13 @@ class DelugeGTK:
|
||||||
self.peer_store_dict = {}
|
self.peer_store_dict = {}
|
||||||
|
|
||||||
def build_file_tab(self):
|
def build_file_tab(self):
|
||||||
def percent(column, cell, model, iter, data):
|
self.files_for_tab.clear_file_store()
|
||||||
percent = float(model.get_value(iter, data))
|
self.files_for_tab.use_unique_id(self.get_selected_torrent())
|
||||||
percent_str = "%.2f%%"%percent
|
|
||||||
cell.set_property("text", percent_str)
|
|
||||||
|
|
||||||
|
|
||||||
self.file_view = self.wtree.get_widget("file_view")
|
self.file_view = self.wtree.get_widget("file_view")
|
||||||
self.file_glade = gtk.glade.XML(common.get_glade_file("file_tab_menu.glade"), domain='deluge')
|
self.files_for_tab.file_view_actions(self.file_view)
|
||||||
self.file_menu = self.file_glade.get_widget("file_tab_menu")
|
|
||||||
self.file_glade.signal_autoconnect({
|
|
||||||
"select_all": self.file_select_all,
|
|
||||||
"unselect_all": self.file_unselect_all,
|
|
||||||
"check_selected": self.file_check_selected,
|
|
||||||
"uncheck_selected": self.file_uncheck_selected,
|
|
||||||
})
|
|
||||||
self.file_store = gtk.ListStore(bool, str, gobject.TYPE_UINT64, float)
|
|
||||||
self.file_store_sorted = gtk.TreeModelSort(self.file_store)
|
|
||||||
# Stores file path -> gtk.TreeIter's iter mapping for quick look up
|
|
||||||
# in self.update_torrent_info_widget
|
|
||||||
self.file_store_dict = {}
|
|
||||||
self.file_view.set_model(self.file_store_sorted)
|
|
||||||
self.file_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
|
||||||
self.file_view.get_selection().set_select_function(self.file_clicked)
|
|
||||||
self.file_selected = []
|
|
||||||
self.file_view.connect("button-press-event", self.file_view_clicked)
|
|
||||||
|
|
||||||
dgtk.add_toggle_column(self.file_view, _("Download"), 0, toggled_signal=self.file_toggled)
|
|
||||||
dgtk.add_text_column(self.file_view, _("Filename"), 1).set_expand(True)
|
|
||||||
dgtk.add_func_column(self.file_view, _("Size"), dgtk.cell_data_size, 2)
|
|
||||||
dgtk.add_func_column(self.file_view, _("Progress"), percent, 3)
|
|
||||||
|
|
||||||
def clear_file_store(self):
|
def clear_file_store(self):
|
||||||
self.file_store.clear()
|
self.files_for_tab.clear_file_store()
|
||||||
self.file_store_dict = {}
|
|
||||||
|
|
||||||
def file_select_all(self, widget):
|
|
||||||
self.file_view.get_selection().select_all()
|
|
||||||
|
|
||||||
def file_unselect_all(self, widget):
|
|
||||||
self.file_view.get_selection().unselect_all()
|
|
||||||
|
|
||||||
def file_check_selected(self, widget):
|
|
||||||
self.file_view.get_selection().selected_foreach(self.file_toggle_selected, True)
|
|
||||||
self.file_toggled_update_filter()
|
|
||||||
|
|
||||||
def file_uncheck_selected(self, widget):
|
|
||||||
self.file_view.get_selection().selected_foreach(self.file_toggle_selected, False)
|
|
||||||
self.file_toggled_update_filter()
|
|
||||||
|
|
||||||
def file_clicked(self, path):
|
|
||||||
return not self.file_selected
|
|
||||||
|
|
||||||
def file_view_clicked(self, widget, event):
|
|
||||||
if event.button == 3:
|
|
||||||
self.file_menu.popup(None, None, None, event.button, event.time)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self.file_selected = False
|
|
||||||
return False
|
|
||||||
|
|
||||||
def file_toggle_selected(self, treemodel, path, selected_iter, value):
|
|
||||||
child_iter = self.file_store_sorted.convert_iter_to_child_iter(None,
|
|
||||||
selected_iter)
|
|
||||||
self.file_store_sorted.get_model().set_value(child_iter, 0, value)
|
|
||||||
|
|
||||||
def file_toggled(self, renderer, path):
|
|
||||||
self.file_selected = True
|
|
||||||
file_iter = self.file_store_sorted.get_iter_from_string(path)
|
|
||||||
value = not renderer.get_active()
|
|
||||||
selection = self.file_view.get_selection()
|
|
||||||
if selection.iter_is_selected(file_iter):
|
|
||||||
selection.selected_foreach(self.file_toggle_selected, value)
|
|
||||||
else:
|
|
||||||
child_iter = self.file_store_sorted.convert_iter_to_child_iter(
|
|
||||||
None, file_iter)
|
|
||||||
self.file_store_sorted.get_model().set_value(child_iter, 0, value)
|
|
||||||
|
|
||||||
self.file_toggled_update_filter()
|
|
||||||
|
|
||||||
def file_toggled_update_filter(self):
|
|
||||||
file_filter = [not x[0] for x in self.file_store]
|
|
||||||
self.manager.set_file_filter(self.get_selected_torrent(), file_filter)
|
|
||||||
|
|
||||||
def show_about_dialog(self, arg=None):
|
def show_about_dialog(self, arg=None):
|
||||||
dialogs.show_about_dialog()
|
dialogs.show_about_dialog()
|
||||||
|
@ -1108,23 +1037,9 @@ class DelugeGTK:
|
||||||
elif page_num == 2: # Files
|
elif page_num == 2: # Files
|
||||||
# Fill self.file_store with files only once and only when we click to
|
# Fill self.file_store with files only once and only when we click to
|
||||||
# Files tab or it's already open
|
# Files tab or it's already open
|
||||||
if not self.file_store_dict:
|
self.files_for_tab.use_unique_id(unique_id)
|
||||||
all_files = self.manager.get_torrent_file_info(unique_id)
|
self.files_for_tab.prepare_store()
|
||||||
file_filter = self.manager.get_file_filter(unique_id)
|
self.files_for_tab.update_store()
|
||||||
if file_filter is None:
|
|
||||||
file_filter = [False] * len(all_files)
|
|
||||||
for file, filt in izip(all_files, file_filter):
|
|
||||||
iter = self.file_store.append([not filt, file['path'],
|
|
||||||
file['size'],
|
|
||||||
round(file['progress'], 2)])
|
|
||||||
self.file_store_dict[file['path']] = iter
|
|
||||||
|
|
||||||
new_file_info = self.manager.get_torrent_file_info(unique_id)
|
|
||||||
|
|
||||||
for file in new_file_info:
|
|
||||||
iter = self.file_store_dict[file['path']]
|
|
||||||
if self.file_store.get_value(iter, 3) != round(file['progress'], 2):
|
|
||||||
self.file_store.set(iter, 3, file['progress'])
|
|
||||||
|
|
||||||
|
|
||||||
def calc_share_ratio(self, unique_id, torrent_state):
|
def calc_share_ratio(self, unique_id, torrent_state):
|
||||||
|
@ -1178,6 +1093,13 @@ class DelugeGTK:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
unique_id = self.manager.add_torrent(torrent, path, self.config.get('use_compact_storage'))
|
unique_id = self.manager.add_torrent(torrent, path, self.config.get('use_compact_storage'))
|
||||||
|
if not append and self.config.get('enable_files_dialog'):
|
||||||
|
self.manager.set_user_pause(unique_id, True)
|
||||||
|
if self.files_dialog.show(self.manager, unique_id) == 1:
|
||||||
|
self.manager.set_user_pause(unique_id, False)
|
||||||
|
else:
|
||||||
|
self.manager.remove_torrent(unique_id, True, True)
|
||||||
|
|
||||||
except core.InvalidEncodingError, e:
|
except core.InvalidEncodingError, e:
|
||||||
print "InvalidEncodingError", e
|
print "InvalidEncodingError", e
|
||||||
dialogs.show_popup_warning(self.window, _("An error occured while trying to add the torrent. It's possible your .torrent file is corrupted."))
|
dialogs.show_popup_warning(self.window, _("An error occured while trying to add the torrent. It's possible your .torrent file is corrupted."))
|
||||||
|
@ -1191,7 +1113,15 @@ class DelugeGTK:
|
||||||
_("Available Space:") + " " + nice_free)
|
_("Available Space:") + " " + nice_free)
|
||||||
else:
|
else:
|
||||||
if append:
|
if append:
|
||||||
self.torrent_model_append(unique_id)
|
if self.config.get('enable_files_dialog'):
|
||||||
|
self.manager.set_user_pause(unique_id, True)
|
||||||
|
if self.files_dialog.show(self.manager, unique_id) == 1:
|
||||||
|
self.manager.set_user_pause(unique_id, False)
|
||||||
|
self.torrent_model_append(unique_id)
|
||||||
|
else:
|
||||||
|
self.manager.remove_torrent(unique_id, True, True)
|
||||||
|
else:
|
||||||
|
self.torrent_model_append(unique_id)
|
||||||
|
|
||||||
def launchpad(self, obj=None):
|
def launchpad(self, obj=None):
|
||||||
common.open_url_in_browser('self', 'https://translations.launchpad.net/deluge/trunk/+pots/deluge')
|
common.open_url_in_browser('self', 'https://translations.launchpad.net/deluge/trunk/+pots/deluge')
|
||||||
|
|
|
@ -41,6 +41,7 @@ DEFAULT_PREFS = {
|
||||||
"auto_end_seeding" : False,
|
"auto_end_seeding" : False,
|
||||||
"auto_seed_ratio" : 0,
|
"auto_seed_ratio" : 0,
|
||||||
"close_to_tray" : False,
|
"close_to_tray" : False,
|
||||||
|
"enable_files_dialog" : False,
|
||||||
"default_download_path" : os.path.expanduser("~/"),
|
"default_download_path" : os.path.expanduser("~/"),
|
||||||
"default_load_path" : os.path.expanduser("~/"),
|
"default_load_path" : os.path.expanduser("~/"),
|
||||||
"default_finished_path" : os.path.expanduser("~/"),
|
"default_finished_path" : os.path.expanduser("~/"),
|
||||||
|
|
Loading…
Reference in New Issue