State saving and loading in core and TorrentQueue.

GtkUI now requests a 'session_state' on start-up to populate it's 
listview.
GtkUI can now shutdown core.
This commit is contained in:
Andrew Resch 2007-08-29 08:00:19 +00:00
commit c5d76cf8ee
12 changed files with 628 additions and 516 deletions

View file

@ -90,6 +90,10 @@ class Core(dbus.service.Object):
"""Shutdown the core""" """Shutdown the core"""
log.info("Shutting down core..") log.info("Shutting down core..")
self.loop.quit() self.loop.quit()
del self.torrents
self.plugins.shutdown()
del self.plugins
del self.session
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge", @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
in_signature="say", out_signature="") in_signature="say", out_signature="")
@ -97,7 +101,6 @@ class Core(dbus.service.Object):
"""Adds a torrent file to the libtorrent session """Adds a torrent file to the libtorrent session
This requires the torrents filename and a dump of it's content This requires the torrents filename and a dump of it's content
""" """
log.info("Adding torrent: %s", filename)
torrent_id = self.torrents.add(filename, filedump) torrent_id = self.torrents.add(filename, filedump)
# Run the plugin hooks for 'post_torrent_add' # Run the plugin hooks for 'post_torrent_add'
@ -149,6 +152,23 @@ class Core(dbus.service.Object):
status.update(self.plugins.get_status(torrent_id, leftover_fields)) status.update(self.plugins.get_status(torrent_id, leftover_fields))
status = pickle.dumps(status) status = pickle.dumps(status)
return status return status
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
in_signature="",
out_signature="ay")
def get_session_state(self):
"""Returns a list of torrent_ids in the session."""
# Get the torrent list from the TorrentManager
torrent_list = self.torrents.get_torrent_list()
# Pickle the list and send it
session_state = pickle.dumps(torrent_list)
return session_state
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge")
def save_state(self):
"""Save the current session state to file."""
# Have the TorrentManager save it's state
self.torrents.save_state()
# Signals # Signals
@dbus.service.signal(dbus_interface="org.deluge_torrent.Deluge", @dbus.service.signal(dbus_interface="org.deluge_torrent.Deluge",

View file

@ -71,6 +71,17 @@ class PluginManager:
self.plugins[name] = instance self.plugins[name] = instance
log.info("Load plugin %s", name) log.info("Load plugin %s", name)
def shutdown(self):
log.debug("PluginManager shutting down..")
# Del all plugins to allow them to deconstruct properly
for plugin in self.plugins.values():
plugin.core.shutdown()
# del plugin
#while plugin is not None:
# del plugin
del self.plugins
def __getitem__(self, key): def __getitem__(self, key):
return self.plugins[key] return self.plugins[key]

View file

@ -41,9 +41,17 @@ import deluge.libtorrent as lt
import deluge.common import deluge.common
from deluge.config import Config from deluge.config import Config
from deluge.core.torrent import Torrent from deluge.core.torrent import Torrent
from deluge.core.torrentmanagerstate import TorrentManagerState, TorrentState
from deluge.log import LOG as log from deluge.log import LOG as log
class TorrentState:
def __init__(self, torrent_id, filename):
self.torrent_id = torrent_id
self.filename = filename
class TorrentManagerState:
def __init__(self):
self.torrents = []
class TorrentManager: class TorrentManager:
"""TorrentManager contains a list of torrents in the current libtorrent """TorrentManager contains a list of torrents in the current libtorrent
session. This object is also responsible for saving the state of the session. This object is also responsible for saving the state of the
@ -55,24 +63,40 @@ class TorrentManager:
self.session = session self.session = session
# Create the torrents dict { torrent_id: Torrent } # Create the torrents dict { torrent_id: Torrent }
self.torrents = {} self.torrents = {}
# Try to load the state from file
self.load_state()
def __del__(self):
log.debug("TorrentManager shutting down..")
# Save state on shutdown
self.save_state()
def __getitem__(self, torrent_id): def __getitem__(self, torrent_id):
"""Return the Torrent with torrent_id""" """Return the Torrent with torrent_id"""
return self.torrents[torrent_id] return self.torrents[torrent_id]
def get_torrent_list(self):
"""Returns a list of torrent_ids"""
return self.torrents.keys()
def add(self, filename, filedump=None): def add(self, filename, filedump=None):
"""Add a torrent to the manager and returns it's torrent_id""" """Add a torrent to the manager and returns it's torrent_id"""
log.info("Adding torrent: %s", filename)
# Get the core config # Get the core config
config = Config("core.conf") config = Config("core.conf")
# Make sure 'filename' is a python string
filename = str(filename)
# Convert the filedump data array into a string of bytes # Convert the filedump data array into a string of bytes
if filedump is not None: if filedump is not None:
filedump = "".join(chr(b) for b in filedump) filedump = "".join(chr(b) for b in filedump)
else: else:
# Get the data from the file # Get the data from the file
try: try:
log.debug("Attempting to open %s for add.", filename)
filedump = open(os.path.join(config["torrentfiles_location"], filedump = open(os.path.join(config["torrentfiles_location"],
filename, "rb")).read() filename), "rb").read()
except IOError: except IOError:
log.warning("Unable to open %s", filename) log.warning("Unable to open %s", filename)
return None return None
@ -104,10 +128,13 @@ class TorrentManager:
except IOError: except IOError:
log.warning("Unable to save torrent file: %s", filename) log.warning("Unable to save torrent file: %s", filename)
log.debug("Torrent %s added.", handle.info_hash())
# Create a Torrent object # Create a Torrent object
torrent = Torrent(filename, handle) torrent = Torrent(filename, handle)
# Add the torrent object to the dictionary # Add the torrent object to the dictionary
self.torrents[torrent.torrent_id] = torrent self.torrents[torrent.torrent_id] = torrent
# Save the session state
self.save_state()
return torrent.torrent_id return torrent.torrent_id
def remove(self, torrent_id): def remove(self, torrent_id):
@ -123,6 +150,8 @@ class TorrentManager:
del self.torrents[torrent_id] del self.torrents[torrent_id]
except KeyError, ValueError: except KeyError, ValueError:
return False return False
# Save the session state
self.save_state()
return True return True
def pause(self, torrent_id): def pause(self, torrent_id):
@ -142,13 +171,30 @@ class TorrentManager:
return False return False
return True return True
def load_state(self):
"""Load the state of the TorrentManager from the torrents.state file"""
state = TorrentManagerState()
try:
log.debug("Opening torrent state file for load.")
state_file = open(deluge.common.get_config_dir("torrents.state"),
"rb")
state = pickle.load(state_file)
state_file.close()
except IOError:
log.warning("Unable to load state file.")
# Try to add the torrents in the state to the session
for torrent_state in state.torrents:
self.add(torrent_state.filename)
def save_state(self): def save_state(self):
"""Save the state of the TorrentManager to the torrents.state file""" """Save the state of the TorrentManager to the torrents.state file"""
state = TorrentManagerState() state = TorrentManagerState()
# Create the state for each Torrent and append to the list # Create the state for each Torrent and append to the list
for torrent in self.torrents.values(): for torrent in self.torrents.values():
torrent_state = TorrentState(torrent.get_state()) torrent_state = TorrentState(*torrent.get_state())
state.torrents.append(torrent_state) state.torrents.append(torrent_state)
# Pickle the TorrentManagerState object # Pickle the TorrentManagerState object

View file

@ -1,43 +0,0 @@
#
# torrentmanagerstate.py
#
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
#
# 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 2 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.
from deluge.log import LOG as log
class TorrentState:
def __init__(self, torrent_id, filename):
self.torrent_id = torrent_id
self.filename = filename
class TorrentManagerState:
def __init__(self):
self.torrents = []

View file

@ -31,25 +31,13 @@
# this exception statement from your version. If you delete this exception # this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here. # statement from all source files in the program, then also delete it here.
import logging import dbus
import dbus.service
try: from dbus.mainloop.glib import DBusGMainLoop
import dbus, dbus.service DBusGMainLoop(set_as_default=True)
dbus_version = getattr(dbus, "version", (0,0,0))
if dbus_version >= (0,41,0) and dbus_version < (0,80,0):
import dbus.glib
elif dbus_version >= (0,80,0):
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
else:
pass
except: dbus_imported = False
else: dbus_imported = True
from torrentqueue import TorrentQueue from torrentqueue import TorrentQueue
from deluge.log import LOG as log
# Get the logger
log = logging.getLogger("deluge")
class Core(dbus.service.Object): class Core(dbus.service.Object):
def __init__(self, plugin, path="/org/deluge_torrent/Plugin/Queue"): def __init__(self, plugin, path="/org/deluge_torrent/Plugin/Queue"):
@ -62,7 +50,7 @@ class Core(dbus.service.Object):
dbus.service.Object.__init__(self, bus_name, path) dbus.service.Object.__init__(self, bus_name, path)
# Instantiate the TorrentQueue object # Instantiate the TorrentQueue object
self.queue = TorrentQueue() self.queue = TorrentQueue()
# Register core hooks # Register core hooks
@ -75,6 +63,10 @@ class Core(dbus.service.Object):
log.info("Queue Core plugin initialized..") log.info("Queue Core plugin initialized..")
def shutdown(self):
# Save the queue state
self.queue.save_state()
## Hooks for core ## ## Hooks for core ##
def post_torrent_add(self, torrent_id): def post_torrent_add(self, torrent_id):
if torrent_id is not None: if torrent_id is not None:

View file

@ -66,7 +66,17 @@ class GtkUI:
menu_glade = gtk.glade.XML(pkg_resources.resource_filename("queue", menu_glade = gtk.glade.XML(pkg_resources.resource_filename("queue",
"glade/queuemenu.glade")) "glade/queuemenu.glade"))
menu = menu_glade.get_widget("menu_queue") menu_glade.signal_autoconnect({
"on_menuitem_queuetop_activate": \
self.on_menuitem_queuetop_activate,
"on_menuitem_queueup_activate": self.on_menuitem_queueup_activate,
"on_menuitem_queuedown_activate": \
self.on_menuitem_queuedown_activate,
"on_menuitem_queuebottom_activate": \
self.on_menuitem_queuebottom_activate
})
menu = menu_glade.get_widget("menu_queue")
# Connect to the 'torrent_queue_changed' signal # Connect to the 'torrent_queue_changed' signal
self.core.connect_to_signal("torrent_queue_changed", self.core.connect_to_signal("torrent_queue_changed",
@ -79,17 +89,20 @@ class GtkUI:
col_type=int, col_type=int,
position=0, position=0,
status_field=["queue"]) status_field=["queue"])
# Update the new column right away
self.torrentview.update(["#"])
# Add a toolbar buttons # Add a toolbar buttons
self.plugin.get_toolbar().add_separator() self.plugin.get_toolbar().add_separator()
self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-up", self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-up",
label="Queue Up", label="Queue Up",
tooltip="Queue selected torrents up", tooltip="Queue selected torrents up",
callback=self.on_queueup_toolbutton_clicked) callback=self.on_toolbutton_queueup_clicked)
self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-down", self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-down",
label="Queue Down", label="Queue Down",
tooltip="Queue selected torrents down", tooltip="Queue selected torrents down",
callback=self.on_queuedown_toolbutton_clicked) callback=self.on_toolbutton_queuedown_clicked)
# Add the queue menu to the torrent menu # Add the queue menu to the torrent menu
queue_menuitem = gtk.ImageMenuItem("Queue") queue_menuitem = gtk.ImageMenuItem("Queue")
@ -98,23 +111,58 @@ class GtkUI:
queue_menuitem.set_image(queue_image) queue_menuitem.set_image(queue_image)
queue_menuitem.set_submenu(menu) queue_menuitem.set_submenu(menu)
self.plugin.get_torrentmenu().append(queue_menuitem) self.plugin.get_torrentmenu().append(queue_menuitem)
def on_queuedown_toolbutton_clicked(self, widget): ## Menu callbacks ##
log.debug("Queue down toolbutton clicked.") def on_menuitem_queuetop_activate(self, data=None):
log.debug("on_menuitem_queuetop_activate")
# Get the selected torrents
torrent_ids = self.plugin.get_selected_torrents()
for torrent_id in torrent_ids:
self.core.queue_top(torrent_id)
return
def on_menuitem_queueup_activate(self, data=None):
log.debug("on_menuitem_queueup_activate")
# Get the selected torrents
torrent_ids = self.plugin.get_selected_torrents()
for torrent_id in torrent_ids:
self.core.queue_up(torrent_id)
return
def on_menuitem_queuedown_activate(self, data=None):
log.debug("on_menuitem_queuedown_activate")
# Get the selected torrents
torrent_ids = self.plugin.get_selected_torrents()
for torrent_id in torrent_ids:
self.core.queue_down(torrent_id)
return
def on_menuitem_queuebottom_activate(self, data=None):
log.debug("on_menuitem_queuebottom_activate")
# Get the selected torrents
torrent_ids = self.plugin.get_selected_torrents()
for torrent_id in torrent_ids:
self.core.queue_bottom(torrent_id)
return
## Toolbutton callbacks ##
def on_toolbutton_queuedown_clicked(self, widget):
log.debug("on_toolbutton_queuedown_clicked")
# Get the selected torrents # Get the selected torrents
torrent_ids = self.plugin.get_selected_torrents() torrent_ids = self.plugin.get_selected_torrents()
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
self.core.queue_down(torrent_id) self.core.queue_down(torrent_id)
return return
def on_queueup_toolbutton_clicked(self, widget): def on_toolbutton_queueup_clicked(self, widget):
log.debug("Queue Up toolbutton clicked.") log.debug("on_toolbutton_queueup_clicked")
# Get the selected torrents # Get the selected torrents
torrent_ids = self.plugin.get_selected_torrents() torrent_ids = self.plugin.get_selected_torrents()
for torrent_id in torrent_ids: for torrent_id in torrent_ids:
self.core.queue_up(torrent_id) self.core.queue_up(torrent_id)
return return
## Signals ##
def torrent_queue_changed_signal(self): def torrent_queue_changed_signal(self):
"""This function is called whenever we receive a 'torrent_queue_changed' """This function is called whenever we receive a 'torrent_queue_changed'
signal from the core plugin. signal from the core plugin.

View file

@ -31,19 +31,45 @@
# this exception statement from your version. If you delete this exception # this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here. # statement from all source files in the program, then also delete it here.
import logging import pickle
# Get the logger import deluge.common
log = logging.getLogger("deluge") from deluge.log import LOG as log
class TorrentQueue: class TorrentQueue:
def __init__(self): def __init__(self):
self.queue = [] self.queue = []
# Try to load the queue state from file
self.load_state()
def __getitem__(self, torrent_id): def __getitem__(self, torrent_id):
"""Return the queue position of the torrent_id""" """Return the queue position of the torrent_id"""
return self.queue.index(torrent_id) return self.queue.index(torrent_id)
def load_state(self):
"""Load the queue state"""
try:
log.debug("Opening queue state file for load.")
state_file = open(deluge.common.get_config_dir("queue.state"),
"rb")
state = pickle.load(state_file)
state_file.close()
self.queue = state
except IOError:
log.warning("Unable to load queue state file.")
def save_state(self):
"""Save the queue state"""
try:
log.debug("Saving queue state file.")
state_file = open(deluge.common.get_config_dir("queue.state"),
"wb")
pickle.dump(self.queue, state_file)
state_file.close()
except IOError:
log.warning("Unable to save queue state file.")
def append(self, torrent_id): def append(self, torrent_id):
"""Append torrent_id to the bottom of the queue""" """Append torrent_id to the bottom of the queue"""
log.debug("Append torrent %s to queue..", torrent_id) log.debug("Append torrent %s to queue..", torrent_id)

View file

@ -63,7 +63,13 @@ def get_core_plugin(plugin):
"/org/deluge_torrent/Plugin/" + plugin) "/org/deluge_torrent/Plugin/" + plugin)
core = dbus.Interface(proxy, "org.deluge_torrent.Deluge." + plugin) core = dbus.Interface(proxy, "org.deluge_torrent.Deluge." + plugin)
return core return core
def shutdown():
"""Shutdown the core daemon"""
core = get_core()
core.shutdown()
return
def add_torrent_file(torrent_files): def add_torrent_file(torrent_files):
"""Adds torrent files to the core """Adds torrent files to the core
Expects a list of torrent files Expects a list of torrent files
@ -118,3 +124,14 @@ def get_torrent_status(core, torrent_id, keys):
# De-serialize the object # De-serialize the object
status = pickle.loads(status) status = pickle.loads(status)
return status return status
def get_session_state(core=None):
# Get the core if not supplied
if core is None:
core = get_core()
state = core.get_session_state()
# Join the array of bytes into a string for pickle to read
state = "".join(chr(b) for b in state)
# De-serialize the object
state = pickle.loads(state)
return state

View file

@ -68,6 +68,7 @@
<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="label" translatable="yes">Quit &amp; Shutdown Daemon</property> <property name="label" translatable="yes">Quit &amp; Shutdown Daemon</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<signal name="activate" handler="on_menuitem_quitdaemon_activate"/>
<child internal-child="image"> <child internal-child="image">
<widget class="GtkImage" id="menu-item-image4"> <widget class="GtkImage" id="menu-item-image4">
<property name="stock">gtk-quit</property> <property name="stock">gtk-quit</property>
@ -343,253 +344,6 @@
<property name="n_rows">1</property> <property name="n_rows">1</property>
<property name="n_columns">2</property> <property name="n_columns">2</property>
<property name="column_spacing">10</property> <property name="column_spacing">10</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">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="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">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="top_padding">10</property>
<property name="bottom_padding">10</property>
<property name="left_padding">15</property>
<property name="right_padding">15</property>
<child>
<widget class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<property name="row_spacing">2</property>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Next Announce:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment5">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Tracker Status:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment6">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Tracker:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment7">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Pieces:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment8">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Total Size:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment9">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Name:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_name1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="wrap">True</property>
<property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_total_size1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_pieces1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_tracker1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="wrap">True</property>
<property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_tracker_status1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_next_announce1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">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="label" translatable="yes">&lt;b&gt;Torrent Info&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child> <child>
<widget class="GtkFrame" id="frame2"> <widget class="GtkFrame" id="frame2">
<property name="visible">True</property> <property name="visible">True</property>
@ -622,36 +376,175 @@
<property name="n_columns">4</property> <property name="n_columns">4</property>
<property name="row_spacing">5</property> <property name="row_spacing">5</property>
<child> <child>
<widget class="GtkAlignment" id="alignment11"> <widget class="GtkLabel" id="summary_total_downloaded1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="left_padding">15</property> <property name="xalign">0</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;ETA:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget> </widget>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">1</property>
<property name="right_attach">3</property> <property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_download_rate1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_total_uploaded1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_upload_rate1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_seeders1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_peers1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_share_ratio1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property> <property name="top_attach">3</property>
<property name="bottom_attach">4</property> <property name="bottom_attach">4</property>
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkAlignment" id="alignment12"> <widget class="GtkLabel" id="summary_eta1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment18">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Downloaded:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkAlignment" id="alignment17">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Uploaded:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment16">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Seeders:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment15">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Share Ratio:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment14">
<property name="visible">True</property> <property name="visible">True</property>
<property name="left_padding">15</property> <property name="left_padding">15</property>
<property name="right_padding">5</property> <property name="right_padding">5</property>
<child> <child>
<widget class="GtkLabel" id="label9"> <widget class="GtkLabel" id="label11">
<property name="visible">True</property> <property name="visible">True</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Peers:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Rate:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</widget> </widget>
</child> </child>
@ -659,8 +552,6 @@
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
<property name="right_attach">3</property> <property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -685,15 +576,15 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkAlignment" id="alignment14"> <widget class="GtkAlignment" id="alignment12">
<property name="visible">True</property> <property name="visible">True</property>
<property name="left_padding">15</property> <property name="left_padding">15</property>
<property name="right_padding">5</property> <property name="right_padding">5</property>
<child> <child>
<widget class="GtkLabel" id="label11"> <widget class="GtkLabel" id="label9">
<property name="visible">True</property> <property name="visible">True</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Rate:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Peers:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</widget> </widget>
</child> </child>
@ -701,168 +592,31 @@
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
<property name="right_attach">3</property> <property name="right_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment15">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Share Ratio:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment16">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Seeders:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">2</property> <property name="top_attach">2</property>
<property name="bottom_attach">3</property> <property name="bottom_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkAlignment" id="alignment17"> <widget class="GtkAlignment" id="alignment11">
<property name="visible">True</property> <property name="visible">True</property>
<property name="left_padding">15</property>
<property name="right_padding">5</property> <property name="right_padding">5</property>
<child> <child>
<widget class="GtkLabel" id="label14"> <widget class="GtkLabel" id="label8">
<property name="visible">True</property> <property name="visible">True</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Uploaded:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;ETA:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</widget> </widget>
</child> </child>
</widget> </widget>
<packing> <packing>
<property name="top_attach">1</property> <property name="left_attach">2</property>
<property name="bottom_attach">2</property> <property name="right_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment18">
<property name="visible">True</property>
<property name="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Downloaded:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="summary_eta1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">3</property> <property name="top_attach">3</property>
<property name="bottom_attach">4</property> <property name="bottom_attach">4</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkLabel" id="summary_share_ratio1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_peers1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_seeders1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_upload_rate1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_total_uploaded1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_download_rate1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_total_downloaded1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -890,6 +644,253 @@
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">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="label_xalign">0</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">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="top_padding">10</property>
<property name="bottom_padding">10</property>
<property name="left_padding">15</property>
<property name="right_padding">15</property>
<child>
<widget class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<property name="row_spacing">2</property>
<child>
<widget class="GtkLabel" id="summary_next_announce1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_tracker_status1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_tracker1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="wrap">True</property>
<property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_pieces1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_total_size1">
<property name="visible">True</property>
<property name="xalign">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="summary_name1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="wrap">True</property>
<property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment9">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Name:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment8">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Total Size:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment7">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Pieces:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment6">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Tracker:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment5">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Tracker Status:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">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="right_padding">5</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">1</property>
<property name="label" translatable="yes">&lt;b&gt;Next Announce:&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">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="label" translatable="yes">&lt;b&gt;Torrent Info&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</widget> </widget>
</child> </child>
</widget> </widget>

View file

@ -185,11 +185,12 @@ class ListView:
# being the new liststore and the columns list # being the new liststore and the columns list
def copy_row(model, path, row, user_data): def copy_row(model, path, row, user_data):
new_list, columns = user_data new_list, columns = user_data
new_row = new_list.append()
for column in range(model.get_n_columns()): for column in range(model.get_n_columns()):
# Get the current value of the column for this row # Get the current value of the column for this row
value = model.get_value(row, column) value = model.get_value(row, column)
# Set the value of this row and column in the new liststore # Set the value of this row and column in the new liststore
new_list.set_value(row, column, value) new_list.set_value(new_row, column, value)
# Do the actual row copy # Do the actual row copy
if self.liststore is not None: if self.liststore is not None:

View file

@ -66,6 +66,8 @@ class MenuBar:
"on_menuitem_addurl_activate": self.on_menuitem_addurl_activate, "on_menuitem_addurl_activate": self.on_menuitem_addurl_activate,
"on_menuitem_clear_activate": \ "on_menuitem_clear_activate": \
self.on_menuitem_clear_activate, self.on_menuitem_clear_activate,
"on_menuitem_quitdaemon_activate": \
self.on_menuitem_quitdaemon_activate,
"on_menuitem_quit_activate": self.on_menuitem_quit_activate, "on_menuitem_quit_activate": self.on_menuitem_quit_activate,
## Edit Menu ## Edit Menu
@ -90,13 +92,7 @@ class MenuBar:
"on_menuitem_edittrackers_activate": \ "on_menuitem_edittrackers_activate": \
self.on_menuitem_edittrackers_activate, self.on_menuitem_edittrackers_activate,
"on_menuitem_remove_activate": self.on_menuitem_remove_activate, "on_menuitem_remove_activate": self.on_menuitem_remove_activate,
"on_menuitem_queuetop_activate": \
self.on_menuitem_queuetop_activate,
"on_menuitem_queueup_activate": self.on_menuitem_queueup_activate,
"on_menuitem_queuedown_activate": \
self.on_menuitem_queuedown_activate,
"on_menuitem_queuebottom_activate": \
self.on_menuitem_queuebottom_activate
}) })
### Callbacks ### ### Callbacks ###
@ -112,6 +108,12 @@ class MenuBar:
def on_menuitem_clear_activate(self, data=None): def on_menuitem_clear_activate(self, data=None):
log.debug("on_menuitem_clear_activate") log.debug("on_menuitem_clear_activate")
def on_menuitem_quitdaemon_activate(self, data=None):
log.debug("on_menuitem_quitdaemon_activate")
# Tell the core to shutdown
functions.shutdown()
self.window.quit()
def on_menuitem_quit_activate(self, data=None): def on_menuitem_quit_activate(self, data=None):
log.debug("on_menuitem_quit_activate") log.debug("on_menuitem_quit_activate")
@ -145,22 +147,6 @@ class MenuBar:
log.debug("on_menuitem_remove_activate") log.debug("on_menuitem_remove_activate")
functions.remove_torrent( functions.remove_torrent(
self.window.torrentview.get_selected_torrents()) self.window.torrentview.get_selected_torrents())
def on_menuitem_queuetop_activate(self, data=None):
log.debug("on_menuitem_queuetop_activate")
functions.queue_top(self.window.torrentview.get_selected_torrents())
def on_menuitem_queueup_activate(self, data=None):
log.debug("on_menuitem_queueup_activate")
functions.queue_up(self.window.torrentview.get_selected_torrents())
def on_menuitem_queuedown_activate(self, data=None):
log.debug("on_menuitem_queuedown_activate")
functions.queue_down(self.window.torrentview.get_selected_torrents())
def on_menuitem_queuebottom_activate(self, data=None):
log.debug("on_menuitem_queuebottom_activate")
functions.queue_bottom(self.window.torrentview.get_selected_torrents())
## View Menu ## ## View Menu ##
def on_menuitem_toolbar_toggled(self, data=None): def on_menuitem_toolbar_toggled(self, data=None):

View file

@ -97,6 +97,13 @@ class TorrentView(listview.ListView):
# changes. # changes.
self.treeview.get_selection().connect("changed", self.treeview.get_selection().connect("changed",
self.on_selection_changed) self.on_selection_changed)
# We need to get the core session state to know which torrents are in
# the session so we can add them to our list.
session_state = functions.get_session_state(self.core)
print "session_state:", session_state
for torrent_id in session_state:
self.add_row(torrent_id)
def update(self, columns=None): def update(self, columns=None):
"""Update the view. If columns is not None, it will attempt to only """Update the view. If columns is not None, it will attempt to only
@ -165,6 +172,7 @@ class TorrentView(listview.ListView):
"""Adds a new torrent row to the treeview""" """Adds a new torrent row to the treeview"""
# Insert a new row to the liststore # Insert a new row to the liststore
row = self.liststore.append() row = self.liststore.append()
print "columnid:", self.columns["torrent_id"].column_indices[0]
# Store the torrent id # Store the torrent id
self.liststore.set_value( self.liststore.set_value(
row, row,
@ -206,8 +214,7 @@ class TorrentView(listview.ListView):
# We only care about right-clicks # We only care about right-clicks
if event.button == 3: if event.button == 3:
# Show the Torrent menu from the MenuBar # Show the Torrent menu from the MenuBar
torrentmenu = self.window.menubar.torrentmenu.get_widget( torrentmenu = self.window.menubar.torrentmenu
"torrent_menu")
torrentmenu.popup(None, None, None, event.button, event.time) torrentmenu.popup(None, None, None, event.button, event.time)
def on_selection_changed(self, treeselection): def on_selection_changed(self, treeselection):