Account Management Implemented.
Account management is now implemented for the GTK UI. Some changes to the core were required since the clients need to know which authentication levels exist, and, to expose account creation, update, and removal to the clients. The best effort is done to try not to compromise the auth file.
This commit is contained in:
parent
6ed3136c8e
commit
43e3fe2a1a
|
@ -2,6 +2,7 @@
|
||||||
# authmanager.py
|
# authmanager.py
|
||||||
#
|
#
|
||||||
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
# Copyright (C) 2011 Pedro Algarvio <ufs@ufsoft.org>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# Deluge is free software.
|
||||||
#
|
#
|
||||||
|
@ -40,7 +41,7 @@ import logging
|
||||||
|
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.configmanager as configmanager
|
import deluge.configmanager as configmanager
|
||||||
from deluge.error import BadLoginError, AuthenticationRequired
|
from deluge.error import AuthManagerError, AuthenticationRequired, BadLoginError
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -51,21 +52,35 @@ AUTH_LEVEL_ADMIN = 10
|
||||||
|
|
||||||
AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL
|
AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL
|
||||||
|
|
||||||
|
AUTH_LEVELS_MAPPING = {
|
||||||
|
'NONE': AUTH_LEVEL_NONE,
|
||||||
|
'READONLY': AUTH_LEVEL_READONLY,
|
||||||
|
'DEFAULT': AUTH_LEVEL_NORMAL,
|
||||||
|
'NORMAL': AUTH_LEVEL_DEFAULT,
|
||||||
|
'ADMIN': AUTH_LEVEL_ADMIN
|
||||||
|
}
|
||||||
|
|
||||||
|
AUTH_LEVELS_MAPPING_REVERSE = {}
|
||||||
|
for key, value in AUTH_LEVELS_MAPPING.iteritems():
|
||||||
|
AUTH_LEVELS_MAPPING_REVERSE[value] = key
|
||||||
|
|
||||||
class Account(object):
|
class Account(object):
|
||||||
__slots__ = ('username', 'password', 'auth_level')
|
__slots__ = ('username', 'password', 'authlevel')
|
||||||
def __init__(self, username, password, auth_level):
|
def __init__(self, username, password, authlevel):
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
self.auth_level = auth_level
|
self.authlevel = authlevel
|
||||||
|
|
||||||
def data(self, include_private=True):
|
def data(self):
|
||||||
rv = self.__dict__.copy()
|
return {
|
||||||
if not include_private:
|
'username': self.username,
|
||||||
rv['password'] = ''
|
'password': self.password,
|
||||||
return rv
|
'authlevel': AUTH_LEVELS_MAPPING_REVERSE[self.authlevel],
|
||||||
|
'authlevel_int': self.authlevel
|
||||||
|
}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return ('<Account username="%(username)s" auth_level=%(auth_level)s>' %
|
return ('<Account username="%(username)s" authlevel=%(authlevel)s>' %
|
||||||
self.__dict__)
|
self.__dict__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,52 +119,71 @@ class AuthManager(component.Component):
|
||||||
"Username and Password are required.", username
|
"Username and Password are required.", username
|
||||||
)
|
)
|
||||||
|
|
||||||
self.__test_existing_account(username)
|
if username not in self.__auth:
|
||||||
|
# Let's try to re-load the file.. Maybe it's been updated
|
||||||
|
self.__load_auth_file()
|
||||||
|
if username not in self.__auth:
|
||||||
|
raise BadLoginError("Username does not exist", username)
|
||||||
|
|
||||||
if self.__auth[username].password == password:
|
if self.__auth[username].password == password:
|
||||||
# Return the users auth level
|
# Return the users auth level
|
||||||
return self.__auth[username].auth_level
|
return self.__auth[username].authlevel
|
||||||
elif not password and self.__auth[username].password:
|
elif not password and self.__auth[username].password:
|
||||||
raise AuthenticationRequired("Password is required", username)
|
raise AuthenticationRequired("Password is required", username)
|
||||||
else:
|
else:
|
||||||
raise BadLoginError("Password does not match")
|
raise BadLoginError("Password does not match", username)
|
||||||
|
|
||||||
def get_known_accounts(self, include_private_data=False):
|
def get_known_accounts(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of known deluge usernames.
|
Returns a list of known deluge usernames.
|
||||||
"""
|
"""
|
||||||
self.__load_auth_file()
|
self.__load_auth_file()
|
||||||
rv = {}
|
return [account.data() for account in self.__auth.values()]
|
||||||
for account in self.__auth.items():
|
|
||||||
rv[account.username] = account.data(include_private_data)
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def create_account(self, username, password='', auth_level=AUTH_LEVEL_DEFAULT):
|
def create_account(self, username, password, authlevel):
|
||||||
if username in self.__auth:
|
if username in self.__auth:
|
||||||
raise Something()
|
raise AuthManagerError("Username in use.", username)
|
||||||
self.__create_account(username, password, auth_level)
|
try:
|
||||||
|
self.__auth[username] = Account(username, password,
|
||||||
|
AUTH_LEVELS_MAPPING[authlevel])
|
||||||
|
self.write_auth_file()
|
||||||
|
return True
|
||||||
|
except Exception, err:
|
||||||
|
log.exception(err)
|
||||||
|
raise err
|
||||||
|
|
||||||
def update_account(self, username, password='', auth_level=AUTH_LEVEL_DEFAULT):
|
def update_account(self, username, password, authlevel):
|
||||||
if username in self.__auth:
|
if username not in self.__auth:
|
||||||
raise Something()
|
raise AuthManagerError("Username not known", username)
|
||||||
self.__create_account(username, password, auth_level)
|
try:
|
||||||
|
self.__auth[username].username = username
|
||||||
|
self.__auth[username].password = password
|
||||||
|
self.__auth[username].authlevel = AUTH_LEVELS_MAPPING[authlevel]
|
||||||
|
self.write_auth_file()
|
||||||
|
return True
|
||||||
|
except Exception, err:
|
||||||
|
log.exception(err)
|
||||||
|
raise err
|
||||||
|
|
||||||
def remove_account(self, username):
|
def remove_account(self, username):
|
||||||
if username in self.__auth:
|
if username not in self.__auth:
|
||||||
raise Something()
|
raise AuthManagerError("Username not known", username)
|
||||||
|
elif username == component.get("RPCServer").get_session_user():
|
||||||
|
raise AuthManagerError(
|
||||||
|
"You cannot delete your own account while logged in!", username
|
||||||
|
)
|
||||||
|
|
||||||
del self.__auth[username]
|
del self.__auth[username]
|
||||||
self.write_auth_file()
|
self.write_auth_file()
|
||||||
if component.get("RPCServer").get_session_user() == username:
|
return True
|
||||||
# Force a client logout by the server
|
|
||||||
component.get("RPCServer").logout_current_session()
|
|
||||||
|
|
||||||
def write_auth_file(self):
|
def write_auth_file(self):
|
||||||
old_auth_file = configmanager.get_config_dir("auth")
|
old_auth_file = configmanager.get_config_dir("auth")
|
||||||
new_auth_file = old_auth_file + '.new'
|
new_auth_file = old_auth_file + '.new'
|
||||||
fd = open(new_auth_file, "w")
|
fd = open(new_auth_file, "w")
|
||||||
for account in self.__auth.items():
|
for account in self.__auth.values():
|
||||||
fd.write(
|
fd.write(
|
||||||
"%(username)s:%(password)s:%(auth_level)s\n" % account.__dict__
|
"%(username)s:%(password)s:%(authlevel_int)s\n" % account.data()
|
||||||
)
|
)
|
||||||
fd.flush()
|
fd.flush()
|
||||||
os.fsync(fd.fileno())
|
os.fsync(fd.fileno())
|
||||||
|
@ -157,18 +191,6 @@ class AuthManager(component.Component):
|
||||||
os.rename(new_auth_file, old_auth_file)
|
os.rename(new_auth_file, old_auth_file)
|
||||||
self.__load_auth_file()
|
self.__load_auth_file()
|
||||||
|
|
||||||
def __add_account(self, username, password, auth_level):
|
|
||||||
self.__auth[username] = Account(username, password, auth_level)
|
|
||||||
self.write_auth_file()
|
|
||||||
|
|
||||||
def __test_existing_account(self, username):
|
|
||||||
if username not in self.__auth:
|
|
||||||
# Let's try to re-load the file.. Maybe it's been updated
|
|
||||||
self.__load_auth_file()
|
|
||||||
if username not in self.__auth:
|
|
||||||
raise BadLoginError("Username does not exist")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __create_localclient_account(self):
|
def __create_localclient_account(self):
|
||||||
"""
|
"""
|
||||||
Returns the string.
|
Returns the string.
|
||||||
|
@ -217,23 +239,27 @@ class AuthManager(component.Component):
|
||||||
log.warning("Your auth entry for %s contains no auth level, "
|
log.warning("Your auth entry for %s contains no auth level, "
|
||||||
"using AUTH_LEVEL_DEFAULT(%s)..", username,
|
"using AUTH_LEVEL_DEFAULT(%s)..", username,
|
||||||
AUTH_LEVEL_DEFAULT)
|
AUTH_LEVEL_DEFAULT)
|
||||||
auth_level = AUTH_LEVEL_DEFAULT
|
authlevel = AUTH_LEVEL_DEFAULT
|
||||||
elif len(lsplit) == 3:
|
elif len(lsplit) == 3:
|
||||||
username, password, auth_level = lsplit
|
username, password, authlevel = lsplit
|
||||||
else:
|
else:
|
||||||
log.error("Your auth file is malformed: Incorrect number of fields!")
|
log.error("Your auth file is malformed: "
|
||||||
|
"Incorrect number of fields!")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
username = username.strip()
|
username = username.strip()
|
||||||
password = password.strip()
|
password = password.strip()
|
||||||
try:
|
try:
|
||||||
auth_level = int(auth_level)
|
authlevel = int(authlevel)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
log.error("Your auth file is malformed: %r is not a valid auth "
|
try:
|
||||||
"level" % auth_level)
|
authlevel = AUTH_LEVELS_MAPPING[authlevel]
|
||||||
|
except KeyError:
|
||||||
|
log.error("Your auth file is malformed: %r is not a valid auth "
|
||||||
|
"level" % authlevel)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.__auth[username] = Account(username, password, auth_level)
|
self.__auth[username] = Account(username, password, authlevel)
|
||||||
|
|
||||||
if "localclient" not in self.__auth:
|
if "localclient" not in self.__auth:
|
||||||
self.__create_localclient_account()
|
self.__create_localclient_account()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# core.py
|
# core.py
|
||||||
#
|
#
|
||||||
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
# Copyright (C) 2011 Pedro Algarvio <ufs@ufsoft.org>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# Deluge is free software.
|
||||||
#
|
#
|
||||||
|
@ -43,8 +44,6 @@ import threading
|
||||||
import tempfile
|
import tempfile
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
|
||||||
from twisted.internet import reactor, defer
|
|
||||||
from twisted.internet.task import LoopingCall
|
|
||||||
import twisted.web.client
|
import twisted.web.client
|
||||||
import twisted.web.error
|
import twisted.web.error
|
||||||
|
|
||||||
|
@ -55,7 +54,8 @@ import deluge.common
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
from deluge.event import *
|
from deluge.event import *
|
||||||
from deluge.error import *
|
from deluge.error import *
|
||||||
from deluge.core.authmanager import AUTH_LEVEL_ADMIN, AUTH_LEVEL_DEFAULT
|
from deluge.core.authmanager import AUTH_LEVEL_ADMIN, AUTH_LEVEL_NONE
|
||||||
|
from deluge.core.authmanager import AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE
|
||||||
from deluge.core.torrentmanager import TorrentManager
|
from deluge.core.torrentmanager import TorrentManager
|
||||||
from deluge.core.pluginmanager import PluginManager
|
from deluge.core.pluginmanager import PluginManager
|
||||||
from deluge.core.alertmanager import AlertManager
|
from deluge.core.alertmanager import AlertManager
|
||||||
|
@ -77,7 +77,8 @@ class Core(component.Component):
|
||||||
log.info("Starting libtorrent %s session..", lt.version)
|
log.info("Starting libtorrent %s session..", lt.version)
|
||||||
|
|
||||||
# Create the client fingerprint
|
# Create the client fingerprint
|
||||||
version = [int(value.split("-")[0]) for value in deluge.common.get_version().split(".")]
|
version = [int(value.split("-")[0]) for value in
|
||||||
|
deluge.common.get_version().split(".")]
|
||||||
while len(version) < 4:
|
while len(version) < 4:
|
||||||
version.append(0)
|
version.append(0)
|
||||||
|
|
||||||
|
@ -147,16 +148,16 @@ class Core(component.Component):
|
||||||
def __save_session_state(self):
|
def __save_session_state(self):
|
||||||
"""Saves the libtorrent session state"""
|
"""Saves the libtorrent session state"""
|
||||||
try:
|
try:
|
||||||
open(deluge.configmanager.get_config_dir("session.state"), "wb").write(
|
session_state = deluge.configmanager.get_config_dir("session.state")
|
||||||
lt.bencode(self.session.state()))
|
open(session_state, "wb").write(lt.bencode(self.session.state()))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.warning("Failed to save lt state: %s", e)
|
log.warning("Failed to save lt state: %s", e)
|
||||||
|
|
||||||
def __load_session_state(self):
|
def __load_session_state(self):
|
||||||
"""Loads the libtorrent session state"""
|
"""Loads the libtorrent session state"""
|
||||||
try:
|
try:
|
||||||
self.session.load_state(lt.bdecode(
|
session_state = deluge.configmanager.get_config_dir("session.state")
|
||||||
open(deluge.configmanager.get_config_dir("session.state"), "rb").read()))
|
self.session.load_state(lt.bdecode(open(session_state, "rb").read()))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.warning("Failed to load lt state: %s", e)
|
log.warning("Failed to load lt state: %s", e)
|
||||||
|
|
||||||
|
@ -212,7 +213,9 @@ class Core(component.Component):
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
torrent_id = self.torrentmanager.add(filedump=filedump, options=options, filename=filename)
|
torrent_id = self.torrentmanager.add(
|
||||||
|
filedump=filedump, options=options, filename=filename
|
||||||
|
)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.error("There was an error adding the torrent file %s", filename)
|
log.error("There was an error adding the torrent file %s", filename)
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
@ -245,16 +248,23 @@ class Core(component.Component):
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.warning("Couldn't remove temp file: %s", e)
|
log.warning("Couldn't remove temp file: %s", e)
|
||||||
return self.add_torrent_file(filename, base64.encodestring(data), options)
|
return self.add_torrent_file(
|
||||||
|
filename, base64.encodestring(data), options
|
||||||
|
)
|
||||||
|
|
||||||
def on_download_fail(failure):
|
def on_download_fail(failure):
|
||||||
if failure.check(twisted.web.error.PageRedirect):
|
if failure.check(twisted.web.error.PageRedirect):
|
||||||
new_url = urljoin(url, failure.getErrorMessage().split(" to ")[1])
|
new_url = urljoin(url, failure.getErrorMessage().split(" to ")[1])
|
||||||
result = download_file(new_url, tempfile.mkstemp()[1], headers=headers, force_filename=True)
|
result = download_file(
|
||||||
|
new_url, tempfile.mkstemp()[1], headers=headers,
|
||||||
|
force_filename=True
|
||||||
|
)
|
||||||
result.addCallbacks(on_download_success, on_download_fail)
|
result.addCallbacks(on_download_success, on_download_fail)
|
||||||
elif failure.check(twisted.web.client.PartialDownloadError):
|
elif failure.check(twisted.web.client.PartialDownloadError):
|
||||||
result = download_file(url, tempfile.mkstemp()[1], headers=headers, force_filename=True,
|
result = download_file(
|
||||||
allow_compression=False)
|
url, tempfile.mkstemp()[1], headers=headers,
|
||||||
|
force_filename=True, allow_compression=False
|
||||||
|
)
|
||||||
result.addCallbacks(on_download_success, on_download_fail)
|
result.addCallbacks(on_download_success, on_download_fail)
|
||||||
else:
|
else:
|
||||||
# Log the error and pass the failure onto the client
|
# Log the error and pass the failure onto the client
|
||||||
|
@ -263,7 +273,9 @@ class Core(component.Component):
|
||||||
result = failure
|
result = failure
|
||||||
return result
|
return result
|
||||||
|
|
||||||
d = download_file(url, tempfile.mkstemp()[1], headers=headers, force_filename=True)
|
d = download_file(
|
||||||
|
url, tempfile.mkstemp()[1], headers=headers, force_filename=True
|
||||||
|
)
|
||||||
d.addCallbacks(on_download_success, on_download_fail)
|
d.addCallbacks(on_download_success, on_download_fail)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -829,9 +841,22 @@ class Core(component.Component):
|
||||||
"""
|
"""
|
||||||
return lt.version
|
return lt.version
|
||||||
|
|
||||||
@export(AUTH_LEVEL_DEFAULT)
|
@export(AUTH_LEVEL_ADMIN)
|
||||||
def get_known_accounts(self):
|
def get_known_accounts(self):
|
||||||
auth_level = component.get("RPCServer").get_session_auth_level()
|
return self.authmanager.get_known_accounts()
|
||||||
return self.authmanager.get_known_accounts(
|
|
||||||
include_private_data=(auth_level==AUTH_LEVEL_ADMIN)
|
@export(AUTH_LEVEL_NONE)
|
||||||
)
|
def get_auth_levels_mappings(self):
|
||||||
|
return (AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE)
|
||||||
|
|
||||||
|
@export(AUTH_LEVEL_ADMIN)
|
||||||
|
def create_account(self, username, password, authlevel):
|
||||||
|
return self.authmanager.create_account(username, password, authlevel)
|
||||||
|
|
||||||
|
@export(AUTH_LEVEL_ADMIN)
|
||||||
|
def update_account(self, username, password, authlevel):
|
||||||
|
return self.authmanager.update_account(username, password, authlevel)
|
||||||
|
|
||||||
|
@export(AUTH_LEVEL_ADMIN)
|
||||||
|
def remove_account(self, username):
|
||||||
|
return self.authmanager.remove_account(username)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# error.py
|
# error.py
|
||||||
#
|
#
|
||||||
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
# Copyright (C) 2011 Pedro Algarvio <ufs@ufsoft.org>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# Deluge is free software.
|
||||||
#
|
#
|
||||||
|
@ -52,10 +53,9 @@ class InvalidPathError(DelugeError):
|
||||||
class NotAuthorizedError(DelugeError):
|
class NotAuthorizedError(DelugeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class BadLoginError(DelugeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class AuthenticationRequired(BadLoginError):
|
class _UsernameBasedException(DelugeError):
|
||||||
|
|
||||||
def _get_message(self):
|
def _get_message(self):
|
||||||
return self._message
|
return self._message
|
||||||
def _set_message(self, message):
|
def _set_message(self, message):
|
||||||
|
@ -70,9 +70,17 @@ class AuthenticationRequired(BadLoginError):
|
||||||
username = property(_get_username, _set_username)
|
username = property(_get_username, _set_username)
|
||||||
del _get_username, _set_username
|
del _get_username, _set_username
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, message, username):
|
def __init__(self, message, username):
|
||||||
super(AuthenticationRequired, self).__init__(message)
|
super(_UsernameBasedException, self).__init__(message)
|
||||||
self.message = message
|
self.message = message
|
||||||
self.username = username
|
self.username = username
|
||||||
|
|
||||||
|
|
||||||
|
class BadLoginError(_UsernameBasedException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AuthenticationRequired(BadLoginError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AuthManagerError(_UsernameBasedException):
|
||||||
|
pass
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# client.py
|
# client.py
|
||||||
#
|
#
|
||||||
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
# Copyright (C) 2011 Pedro Algarvio <ufs@ufsoft.org>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# Deluge is free software.
|
||||||
#
|
#
|
||||||
|
@ -76,6 +77,20 @@ class DelugeRPCError(object):
|
||||||
self.exception_msg = exception_msg
|
self.exception_msg = exception_msg
|
||||||
self.traceback = traceback
|
self.traceback = traceback
|
||||||
|
|
||||||
|
def logable(self):
|
||||||
|
# Create a delugerpcrequest to print out a nice RPCRequest string
|
||||||
|
r = DelugeRPCRequest()
|
||||||
|
r.method = self.method
|
||||||
|
r.args = self.args
|
||||||
|
r.kwargs = self.kwargs
|
||||||
|
msg = "RPCError Message Received!"
|
||||||
|
msg += "\n" + "-" * 80
|
||||||
|
msg += "\n" + "RPCRequest: " + r.__repr__()
|
||||||
|
msg += "\n" + "-" * 80
|
||||||
|
msg += "\n" + self.traceback + "\n" + self.exception_type + ": " + self.exception_msg
|
||||||
|
msg += "\n" + "-" * 80
|
||||||
|
return msg
|
||||||
|
|
||||||
class DelugeRPCRequest(object):
|
class DelugeRPCRequest(object):
|
||||||
"""
|
"""
|
||||||
This object is created whenever there is a RPCRequest to be sent to the
|
This object is created whenever there is a RPCRequest to be sent to the
|
||||||
|
@ -118,6 +133,7 @@ class DelugeRPCRequest(object):
|
||||||
return (self.request_id, self.method, self.args, self.kwargs)
|
return (self.request_id, self.method, self.args, self.kwargs)
|
||||||
|
|
||||||
class DelugeRPCProtocol(Protocol):
|
class DelugeRPCProtocol(Protocol):
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
self.__rpc_requests = {}
|
self.__rpc_requests = {}
|
||||||
self.__buffer = None
|
self.__buffer = None
|
||||||
|
@ -273,6 +289,9 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
self.disconnect_deferred = None
|
self.disconnect_deferred = None
|
||||||
self.disconnect_callback = None
|
self.disconnect_callback = None
|
||||||
|
|
||||||
|
self.auth_levels_mapping = None
|
||||||
|
self.auth_levels_mapping_reverse = None
|
||||||
|
|
||||||
def connect(self, host, port):
|
def connect(self, host, port):
|
||||||
"""
|
"""
|
||||||
Connects to a daemon at host:port
|
Connects to a daemon at host:port
|
||||||
|
@ -402,21 +421,8 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Get the DelugeRPCError object from the error_data
|
if error_data.value.exception_type != 'AuthManagerError':
|
||||||
error = error_data.value
|
log.error(error_data.value.logable())
|
||||||
|
|
||||||
# Create a delugerpcrequest to print out a nice RPCRequest string
|
|
||||||
r = DelugeRPCRequest()
|
|
||||||
r.method = error.method
|
|
||||||
r.args = error.args
|
|
||||||
r.kwargs = error.kwargs
|
|
||||||
msg = "RPCError Message Received!"
|
|
||||||
msg += "\n" + "-" * 80
|
|
||||||
msg += "\n" + "RPCRequest: " + r.__repr__()
|
|
||||||
msg += "\n" + "-" * 80
|
|
||||||
msg += "\n" + error.traceback + "\n" + error.exception_type + ": " + error.exception_msg
|
|
||||||
msg += "\n" + "-" * 80
|
|
||||||
log.error(msg)
|
|
||||||
return error_data
|
return error_data
|
||||||
|
|
||||||
def __on_connect(self, result):
|
def __on_connect(self, result):
|
||||||
|
@ -452,13 +458,24 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
self.authentication_level = result
|
self.authentication_level = result
|
||||||
# We need to tell the daemon what events we're interested in receiving
|
# We need to tell the daemon what events we're interested in receiving
|
||||||
if self.__factory.event_handlers:
|
if self.__factory.event_handlers:
|
||||||
self.call("daemon.set_event_interest", self.__factory.event_handlers.keys())
|
self.call("daemon.set_event_interest",
|
||||||
|
self.__factory.event_handlers.keys())
|
||||||
|
|
||||||
|
self.call("core.get_auth_levels_mappings").addCallback(
|
||||||
|
self.__on_auth_levels_mappings
|
||||||
|
)
|
||||||
|
|
||||||
self.login_deferred.callback(result)
|
self.login_deferred.callback(result)
|
||||||
|
|
||||||
def __on_login_fail(self, result):
|
def __on_login_fail(self, result):
|
||||||
log.debug("_on_login_fail(): %s", result)
|
log.debug("_on_login_fail(): %s", result)
|
||||||
self.login_deferred.errback(result)
|
self.login_deferred.errback(result)
|
||||||
|
|
||||||
|
def __on_auth_levels_mappings(self, result):
|
||||||
|
auth_levels_mapping, auth_levels_mapping_reverse = result
|
||||||
|
self.auth_levels_mapping = auth_levels_mapping
|
||||||
|
self.auth_levels_mapping_reverse = auth_levels_mapping_reverse
|
||||||
|
|
||||||
def set_disconnect_callback(self, cb):
|
def set_disconnect_callback(self, cb):
|
||||||
"""
|
"""
|
||||||
Set a function to be called when the connection to the daemon is lost
|
Set a function to be called when the connection to the daemon is lost
|
||||||
|
@ -481,9 +498,13 @@ class DaemonClassicProxy(DaemonProxy):
|
||||||
self.host = "localhost"
|
self.host = "localhost"
|
||||||
self.port = 58846
|
self.port = 58846
|
||||||
# Running in classic mode, it's safe to import auth level
|
# Running in classic mode, it's safe to import auth level
|
||||||
from deluge.core.authmanager import AUTH_LEVEL_ADMIN
|
from deluge.core.authmanager import (AUTH_LEVEL_ADMIN,
|
||||||
|
AUTH_LEVELS_MAPPING,
|
||||||
|
AUTH_LEVELS_MAPPING_REVERSE)
|
||||||
self.username = "localclient"
|
self.username = "localclient"
|
||||||
self.authentication_level = AUTH_LEVEL_ADMIN
|
self.authentication_level = AUTH_LEVEL_ADMIN
|
||||||
|
self.auth_levels_mapping = AUTH_LEVELS_MAPPING
|
||||||
|
self.auth_levels_mapping_reverse = AUTH_LEVELS_MAPPING_REVERSE
|
||||||
# Register the event handlers
|
# Register the event handlers
|
||||||
for event in event_handlers:
|
for event in event_handlers:
|
||||||
for handler in event_handlers[event]:
|
for handler in event_handlers[event]:
|
||||||
|
@ -776,5 +797,13 @@ class Client(object):
|
||||||
"""
|
"""
|
||||||
return self._daemon_proxy.authentication_level
|
return self._daemon_proxy.authentication_level
|
||||||
|
|
||||||
|
@property
|
||||||
|
def auth_levels_mapping(self):
|
||||||
|
return self._daemon_proxy.auth_levels_mapping
|
||||||
|
|
||||||
|
@property
|
||||||
|
def auth_levels_mapping_reverse(self):
|
||||||
|
return self._daemon_proxy.auth_levels_mapping_reverse
|
||||||
|
|
||||||
# This is the object clients will use
|
# This is the object clients will use
|
||||||
client = Client()
|
client = Client()
|
||||||
|
|
|
@ -176,7 +176,7 @@ class ErrorDialog(BaseDialog):
|
||||||
details = tb
|
details = tb
|
||||||
|
|
||||||
if details:
|
if details:
|
||||||
self.set_default_size(500, 400)
|
self.set_default_size(600, 400)
|
||||||
textview = gtk.TextView()
|
textview = gtk.TextView()
|
||||||
textview.set_editable(False)
|
textview.set_editable(False)
|
||||||
textview.get_buffer().set_text(details)
|
textview.get_buffer().set_text(details)
|
||||||
|
@ -245,3 +245,87 @@ class AuthenticationDialog(BaseDialog):
|
||||||
|
|
||||||
def on_password_activate(self, widget):
|
def on_password_activate(self, widget):
|
||||||
self.response(gtk.RESPONSE_OK)
|
self.response(gtk.RESPONSE_OK)
|
||||||
|
|
||||||
|
class AccountDialog(BaseDialog):
|
||||||
|
def __init__(self, username=None, password=None, authlevel=None,
|
||||||
|
levels_mapping=None, parent=None):
|
||||||
|
if username:
|
||||||
|
super(AccountDialog, self).__init__(
|
||||||
|
_("Edit Account"),
|
||||||
|
_("Edit existing account"),
|
||||||
|
gtk.STOCK_DIALOG_INFO,
|
||||||
|
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
|
||||||
|
gtk.STOCK_APPLY, gtk.RESPONSE_OK),
|
||||||
|
parent)
|
||||||
|
else:
|
||||||
|
super(AccountDialog, self).__init__(
|
||||||
|
_("New Account"),
|
||||||
|
_("Create a new account"),
|
||||||
|
gtk.STOCK_DIALOG_INFO,
|
||||||
|
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
|
||||||
|
gtk.STOCK_ADD, gtk.RESPONSE_OK),
|
||||||
|
parent)
|
||||||
|
|
||||||
|
self.levels_mapping = levels_mapping
|
||||||
|
|
||||||
|
table = gtk.Table(2, 3, False)
|
||||||
|
self.username_label = gtk.Label()
|
||||||
|
self.username_label.set_markup(_("<b>Username:</b>"))
|
||||||
|
self.username_label.set_alignment(1.0, 0.5)
|
||||||
|
self.username_label.set_padding(5, 5)
|
||||||
|
self.username_entry = gtk.Entry()
|
||||||
|
table.attach(self.username_label, 0, 1, 0, 1)
|
||||||
|
table.attach(self.username_entry, 1, 2, 0, 1)
|
||||||
|
|
||||||
|
self.authlevel_label = gtk.Label()
|
||||||
|
self.authlevel_label.set_markup(_("<b>Authentication Level:</b>"))
|
||||||
|
self.authlevel_label.set_alignment(1.0, 0.5)
|
||||||
|
self.authlevel_label.set_padding(5, 5)
|
||||||
|
|
||||||
|
self.authlevel_combo = gtk.combo_box_new_text()
|
||||||
|
active_idx = None
|
||||||
|
for idx, level in enumerate(levels_mapping.keys()):
|
||||||
|
self.authlevel_combo.append_text(level)
|
||||||
|
if authlevel and authlevel==level:
|
||||||
|
active_idx = idx
|
||||||
|
elif not authlevel and level == 'DEFAULT':
|
||||||
|
active_idx = idx
|
||||||
|
|
||||||
|
print 'aidx', active_idx
|
||||||
|
if active_idx is not None:
|
||||||
|
self.authlevel_combo.set_active(active_idx)
|
||||||
|
|
||||||
|
table.attach(self.authlevel_label, 0, 1, 1, 2)
|
||||||
|
table.attach(self.authlevel_combo, 1, 2, 1, 2)
|
||||||
|
|
||||||
|
self.password_label = gtk.Label()
|
||||||
|
self.password_label.set_markup(_("<b>Password:</b>"))
|
||||||
|
self.password_label.set_alignment(1.0, 0.5)
|
||||||
|
self.password_label.set_padding(5, 5)
|
||||||
|
self.password_entry = gtk.Entry()
|
||||||
|
self.password_entry.set_visibility(False)
|
||||||
|
table.attach(self.password_label, 0, 1, 2, 3)
|
||||||
|
table.attach(self.password_entry, 1, 2, 2, 3)
|
||||||
|
|
||||||
|
self.vbox.pack_start(table, False, False, padding=5)
|
||||||
|
if username:
|
||||||
|
self.username_entry.set_text(username)
|
||||||
|
self.username_entry.set_editable(False)
|
||||||
|
else:
|
||||||
|
self.set_focus(self.username_entry)
|
||||||
|
|
||||||
|
if password:
|
||||||
|
self.password_entry.set_text(username)
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
def get_username(self):
|
||||||
|
return self.username_entry.get_text()
|
||||||
|
|
||||||
|
def get_password(self):
|
||||||
|
return self.password_entry.get_text()
|
||||||
|
|
||||||
|
def get_authlevel(self):
|
||||||
|
combobox = self.authlevel_combo
|
||||||
|
level = combobox.get_model()[combobox.get_active()][0]
|
||||||
|
return level
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<glade-interface>
|
<glade-interface>
|
||||||
<!-- interface-requires gtk+ 2.12 -->
|
<!-- interface-requires gtk+ 2.12 -->
|
||||||
<!-- interface-naming-policy toplevel-contextual -->
|
<!-- interface-naming-policy toplevel-contextual -->
|
||||||
|
@ -11,13 +11,11 @@
|
||||||
<property name="default_height">530</property>
|
<property name="default_height">530</property>
|
||||||
<property name="destroy_with_parent">True</property>
|
<property name="destroy_with_parent">True</property>
|
||||||
<property name="type_hint">dialog</property>
|
<property name="type_hint">dialog</property>
|
||||||
<property name="has_separator">False</property>
|
|
||||||
<signal name="delete_event" handler="on_pref_dialog_delete_event"/>
|
<signal name="delete_event" handler="on_pref_dialog_delete_event"/>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<widget class="GtkVBox" id="dialog-vbox1">
|
<widget class="GtkVBox" id="dialog-vbox1">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHPaned" id="hpaned1">
|
<widget class="GtkHPaned" id="hpaned1">
|
||||||
|
@ -50,7 +48,7 @@
|
||||||
<property name="show_tabs">False</property>
|
<property name="show_tabs">False</property>
|
||||||
<property name="scrollable">True</property>
|
<property name="scrollable">True</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
<widget class="GtkScrolledWindow" id="DownloadsScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -66,7 +64,6 @@
|
||||||
<widget class="GtkVBox" id="vbox1">
|
<widget class="GtkVBox" id="vbox1">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label21">
|
<widget class="GtkLabel" id="label21">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -294,7 +291,7 @@
|
||||||
<widget class="GtkEntry" id="entry_torrents_path">
|
<widget class="GtkEntry" id="entry_torrents_path">
|
||||||
<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="invisible_char">●</property>
|
<property name="invisible_char">●</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
@ -501,7 +498,7 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow2">
|
<widget class="GtkScrolledWindow" id="NetworkScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -517,7 +514,6 @@
|
||||||
<widget class="GtkVBox" id="vbox2">
|
<widget class="GtkVBox" id="vbox2">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label22">
|
<widget class="GtkLabel" id="label22">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -557,7 +553,6 @@
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox3">
|
<widget class="GtkVBox" id="vbox3">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox2">
|
<widget class="GtkHBox" id="hbox2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -755,7 +750,6 @@
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox25">
|
<widget class="GtkVBox" id="vbox25">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">5</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="chk_random_outgoing_ports">
|
<widget class="GtkCheckButton" id="chk_random_outgoing_ports">
|
||||||
|
@ -880,7 +874,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">Enter the IP address of the interface to listen for incoming bittorrent connections on. Leave this empty if you want to use the default.</property>
|
<property name="tooltip" translatable="yes">Enter the IP address of the interface to listen for incoming bittorrent connections on. Leave this empty if you want to use the default.</property>
|
||||||
<property name="max_length">60</property>
|
<property name="max_length">60</property>
|
||||||
<property name="invisible_char">●</property>
|
<property name="invisible_char">●</property>
|
||||||
<property name="width_chars">30</property>
|
<property name="width_chars">30</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -927,7 +921,6 @@
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox4">
|
<widget class="GtkVBox" id="vbox4">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox4">
|
<widget class="GtkHBox" id="hbox4">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -1127,7 +1120,6 @@
|
||||||
<widget class="GtkVBox" id="vbox10">
|
<widget class="GtkVBox" id="vbox10">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label7">
|
<widget class="GtkLabel" id="label7">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -1159,7 +1151,6 @@
|
||||||
<widget class="GtkVBox" id="vbox12">
|
<widget class="GtkVBox" id="vbox12">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkComboBox" id="combo_encin">
|
<widget class="GtkComboBox" id="combo_encin">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -1193,7 +1184,6 @@ Either</property>
|
||||||
<widget class="GtkVBox" id="vbox15">
|
<widget class="GtkVBox" id="vbox15">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox15">
|
<widget class="GtkHBox" id="hbox15">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -1291,7 +1281,7 @@ Disabled</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow3">
|
<widget class="GtkScrolledWindow" id="BandwidthScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -1307,7 +1297,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox7">
|
<widget class="GtkVBox" id="vbox7">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label23">
|
<widget class="GtkLabel" id="label23">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -1347,7 +1336,6 @@ Disabled</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox21">
|
<widget class="GtkVBox" id="vbox21">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">5</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkTable" id="table1">
|
<widget class="GtkTable" id="table1">
|
||||||
|
@ -1361,7 +1349,7 @@ Disabled</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9999 1 10 0</property>
|
<property name="adjustment">0 -1 9999 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -1377,7 +1365,7 @@ Disabled</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9999 1 10 0</property>
|
<property name="adjustment">0 -1 9999 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -1456,7 +1444,7 @@ Disabled</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
|
||||||
<property name="max_length">4</property>
|
<property name="max_length">4</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9000 1 10 0</property>
|
<property name="adjustment">0 -1 9000 1 10 0</property>
|
||||||
<property name="climb_rate">1</property>
|
<property name="climb_rate">1</property>
|
||||||
<property name="snap_to_ticks">True</property>
|
<property name="snap_to_ticks">True</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
|
@ -1488,7 +1476,7 @@ Disabled</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 maximum download speed for all torrents. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum download speed for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 60000 1 10 0</property>
|
<property name="adjustment">0 -1 60000 1 10 0</property>
|
||||||
<property name="climb_rate">1</property>
|
<property name="climb_rate">1</property>
|
||||||
<property name="digits">1</property>
|
<property name="digits">1</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
|
@ -1507,7 +1495,7 @@ Disabled</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum upload speed for all torrents. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum upload speed for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 60000 1 10 0</property>
|
<property name="adjustment">0 -1 60000 1 10 0</property>
|
||||||
<property name="climb_rate">1</property>
|
<property name="climb_rate">1</property>
|
||||||
<property name="digits">1</property>
|
<property name="digits">1</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
|
@ -1526,7 +1514,7 @@ Disabled</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum upload slots for all torrents. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum upload slots for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9000 1 10 0</property>
|
<property name="adjustment">0 -1 9000 1 10 0</property>
|
||||||
<property name="climb_rate">1</property>
|
<property name="climb_rate">1</property>
|
||||||
<property name="snap_to_ticks">True</property>
|
<property name="snap_to_ticks">True</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
|
@ -1631,7 +1619,7 @@ Disabled</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum upload slots per torrent. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum upload slots per torrent. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9000 1 10 0</property>
|
<property name="adjustment">0 -1 9000 1 10 0</property>
|
||||||
<property name="climb_rate">1</property>
|
<property name="climb_rate">1</property>
|
||||||
<property name="snap_to_ticks">True</property>
|
<property name="snap_to_ticks">True</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
|
@ -1650,7 +1638,7 @@ Disabled</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9000 1 10 0</property>
|
<property name="adjustment">0 -1 9000 1 10 0</property>
|
||||||
<property name="snap_to_ticks">True</property>
|
<property name="snap_to_ticks">True</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -1716,7 +1704,7 @@ Disabled</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9000 1 10 0</property>
|
<property name="adjustment">0 -1 9000 1 10 0</property>
|
||||||
<property name="digits">1</property>
|
<property name="digits">1</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -1734,7 +1722,7 @@ Disabled</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
|
<property name="tooltip" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">-1 -1 9000 1 10 0</property>
|
<property name="adjustment">0 -1 9000 1 10 0</property>
|
||||||
<property name="digits">1</property>
|
<property name="digits">1</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -1790,7 +1778,7 @@ Disabled</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow4">
|
<widget class="GtkScrolledWindow" id="InterfaceScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -1806,7 +1794,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox8">
|
<widget class="GtkVBox" id="vbox8">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label25">
|
<widget class="GtkLabel" id="label25">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -1892,7 +1879,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox27">
|
<widget class="GtkVBox" id="vbox27">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="chk_show_rate_in_title">
|
<widget class="GtkCheckButton" id="chk_show_rate_in_title">
|
||||||
<property name="label" translatable="yes">Show session speed in titlebar</property>
|
<property name="label" translatable="yes">Show session speed in titlebar</property>
|
||||||
|
@ -1943,7 +1929,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox5">
|
<widget class="GtkVBox" id="vbox5">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="chk_show_dialog">
|
<widget class="GtkCheckButton" id="chk_show_dialog">
|
||||||
<property name="label" translatable="yes">Always show</property>
|
<property name="label" translatable="yes">Always show</property>
|
||||||
|
@ -2013,7 +1998,6 @@ Disabled</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox17">
|
<widget class="GtkVBox" id="vbox17">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="chk_use_tray">
|
<widget class="GtkCheckButton" id="chk_use_tray">
|
||||||
<property name="label" translatable="yes">Enable system tray icon</property>
|
<property name="label" translatable="yes">Enable system tray icon</property>
|
||||||
|
@ -2196,7 +2180,7 @@ Disabled</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow7">
|
<widget class="GtkScrolledWindow" id="OtherScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -2212,7 +2196,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox16">
|
<widget class="GtkVBox" id="vbox16">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label40">
|
<widget class="GtkLabel" id="label40">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2254,7 +2237,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox18">
|
<widget class="GtkVBox" id="vbox18">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkAlignment" id="alignment36">
|
<widget class="GtkAlignment" id="alignment36">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2316,7 +2298,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox19">
|
<widget class="GtkVBox" id="vbox19">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label44">
|
<widget class="GtkLabel" id="label44">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2392,7 +2373,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox29">
|
<widget class="GtkVBox" id="vbox29">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkAlignment" id="alignment50">
|
<widget class="GtkAlignment" id="alignment50">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2417,7 +2397,7 @@ Disabled</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip" translatable="yes">If Deluge cannot find the database file at this location it will fallback to using DNS to resolve the peer's country.</property>
|
<property name="tooltip" translatable="yes">If Deluge cannot find the database file at this location it will fallback to using DNS to resolve the peer's country.</property>
|
||||||
<property name="invisible_char">●</property>
|
<property name="invisible_char">●</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
@ -2530,7 +2510,7 @@ Disabled</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow6">
|
<widget class="GtkScrolledWindow" id="DaemonScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -2546,7 +2526,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox13">
|
<widget class="GtkVBox" id="vbox13">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label34">
|
<widget class="GtkLabel" id="label34">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2588,7 +2567,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox14">
|
<widget class="GtkVBox" id="vbox14">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkHBox" id="hbox12">
|
<widget class="GtkHBox" id="hbox12">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2736,6 +2714,111 @@ Disabled</property>
|
||||||
<property name="position">4</property>
|
<property name="position">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkFrame" id="AccountsFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment33">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHBox" id="hbox22">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTreeView" id="accounts_listview">
|
||||||
|
<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>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVButtonBox" id="vbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
<property name="layout_style">start</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="accounts_add">
|
||||||
|
<property name="label">gtk-add</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_accounts_add_clicked"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="accounts_edit">
|
||||||
|
<property name="label">gtk-edit</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_accounts_edit_clicked"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="accounts_delete">
|
||||||
|
<property name="label">gtk-delete</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_accounts_delete_clicked"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="padding">4</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label61">
|
||||||
|
<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="xalign">0</property>
|
||||||
|
<property name="xpad">10</property>
|
||||||
|
<property name="ypad">10</property>
|
||||||
|
<property name="label" translatable="yes"><b>Accounts</b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="type">label_item</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -2757,7 +2840,7 @@ Disabled</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow8">
|
<widget class="GtkScrolledWindow" id="QueueScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -2773,7 +2856,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox9">
|
<widget class="GtkVBox" id="vbox9">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label46">
|
<widget class="GtkLabel" id="label46">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -2803,7 +2885,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="queue_prefs_box2">
|
<widget class="GtkVBox" id="queue_prefs_box2">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">5</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkFrame" id="frame10">
|
<widget class="GtkFrame" id="frame10">
|
||||||
|
@ -2821,7 +2902,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox6">
|
<widget class="GtkVBox" id="vbox6">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkCheckButton" id="chk_queue_new_top">
|
<widget class="GtkCheckButton" id="chk_queue_new_top">
|
||||||
<property name="label" translatable="yes">Queue new torrents to top</property>
|
<property name="label" translatable="yes">Queue new torrents to top</property>
|
||||||
|
@ -2872,7 +2952,6 @@ Disabled</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox20">
|
<widget class="GtkVBox" id="vbox20">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">5</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkTable" id="table3">
|
<widget class="GtkTable" id="table3">
|
||||||
|
@ -3024,7 +3103,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox11">
|
<widget class="GtkVBox" id="vbox11">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkTable" id="table2">
|
<widget class="GtkTable" id="table2">
|
||||||
|
@ -3234,7 +3312,7 @@ Disabled</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow9">
|
<widget class="GtkScrolledWindow" id="ProxyScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -3250,7 +3328,6 @@ Disabled</property>
|
||||||
<widget class="GtkVBox" id="vbox22">
|
<widget class="GtkVBox" id="vbox22">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label83">
|
<widget class="GtkLabel" id="label83">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -3278,7 +3355,6 @@ Disabled</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox26">
|
<widget class="GtkVBox" id="vbox26">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">5</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkFrame" id="frame23">
|
<widget class="GtkFrame" id="frame23">
|
||||||
|
@ -3372,7 +3448,7 @@ Disabled</property>
|
||||||
<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="adjustment">8080 0 65535 1 10 0</property>
|
<property name="adjustment">100 0 65535 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -3556,7 +3632,7 @@ HTTP W/ Auth</property>
|
||||||
<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="adjustment">8080 0 65535 1 10 0</property>
|
<property name="adjustment">100 0 65535 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -3740,7 +3816,7 @@ HTTP W/ Auth</property>
|
||||||
<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="adjustment">8080 0 65535 1 10 0</property>
|
<property name="adjustment">100 0 65535 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -3927,7 +4003,7 @@ HTTP W/ Auth</property>
|
||||||
<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="adjustment">8080 0 65535 1 10 0</property>
|
<property name="adjustment">100 0 65535 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -4042,7 +4118,7 @@ HTTP W/ Auth</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow13">
|
<widget class="GtkScrolledWindow" id="CacheScrolledWindow">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="hscrollbar_policy">automatic</property>
|
<property name="hscrollbar_policy">automatic</property>
|
||||||
|
@ -4055,7 +4131,6 @@ HTTP W/ Auth</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox30">
|
<widget class="GtkVBox" id="vbox30">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label111">
|
<widget class="GtkLabel" id="label111">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -4087,7 +4162,6 @@ HTTP W/ Auth</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox31">
|
<widget class="GtkVBox" id="vbox31">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkFrame" id="frame32">
|
<widget class="GtkFrame" id="frame32">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -4132,9 +4206,9 @@ HTTP W/ Auth</property>
|
||||||
<widget class="GtkSpinButton" id="spin_cache_size">
|
<widget class="GtkSpinButton" id="spin_cache_size">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="invisible_char">●</property>
|
<property name="invisible_char">●</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">512 0 99999 1 10 0</property>
|
<property name="adjustment">100 0 99999 1 10 0</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="update_policy">if-valid</property>
|
<property name="update_policy">if-valid</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -4149,7 +4223,7 @@ HTTP W/ Auth</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="max_length">5</property>
|
<property name="max_length">5</property>
|
||||||
<property name="invisible_char">●</property>
|
<property name="invisible_char">●</property>
|
||||||
<property name="width_chars">5</property>
|
<property name="width_chars">5</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="adjustment">60 1 32000 1 10 0</property>
|
<property name="adjustment">60 1 32000 1 10 0</property>
|
||||||
|
@ -4197,7 +4271,6 @@ HTTP W/ Auth</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox32">
|
<widget class="GtkVBox" id="vbox32">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkFrame" id="frame34">
|
<widget class="GtkFrame" id="frame34">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -4590,7 +4663,7 @@ HTTP W/ Auth</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow5">
|
<widget class="GtkScrolledWindow" id="PluginsScrolledWindow">
|
||||||
<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>
|
||||||
|
@ -4606,7 +4679,6 @@ HTTP W/ Auth</property>
|
||||||
<widget class="GtkVBox" id="vbox28">
|
<widget class="GtkVBox" id="vbox28">
|
||||||
<property name="visible">True</property>
|
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label51">
|
<widget class="GtkLabel" id="label51">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -4637,7 +4709,6 @@ HTTP W/ Auth</property>
|
||||||
<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="orientation">vertical</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow12">
|
<widget class="GtkScrolledWindow" id="scrolledwindow12">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -4996,7 +5067,7 @@ HTTP W/ Auth</property>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">9</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# menubar.py
|
# menubar.py
|
||||||
#
|
#
|
||||||
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
# Copyright (C) 2011 Pedro Algarvio <ufs@ufsoft.org>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# Deluge is free software.
|
||||||
#
|
#
|
||||||
|
@ -212,7 +213,9 @@ class MenuBar(component.Component):
|
||||||
self.menuitem_change_owner.set_visible(False)
|
self.menuitem_change_owner.set_visible(False)
|
||||||
|
|
||||||
# Get Known accounts to allow chaning ownership
|
# Get Known accounts to allow chaning ownership
|
||||||
client.core.get_known_accounts().addCallback(self._on_known_accounts)
|
client.core.get_known_accounts().addCallback(
|
||||||
|
self._on_known_accounts).addErrback(self._on_known_accounts_fail
|
||||||
|
)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
log.debug("MenuBar stopping")
|
log.debug("MenuBar stopping")
|
||||||
|
@ -354,9 +357,9 @@ class MenuBar(component.Component):
|
||||||
|
|
||||||
def show_move_storage_dialog(self, status):
|
def show_move_storage_dialog(self, status):
|
||||||
log.debug("show_move_storage_dialog")
|
log.debug("show_move_storage_dialog")
|
||||||
glade = gtk.glade.XML(
|
glade = gtk.glade.XML(pkg_resources.resource_filename(
|
||||||
pkg_resources.resource_filename("deluge.ui.gtkui",
|
"deluge.ui.gtkui", "glade/move_storage_dialog.glade"
|
||||||
"glade/move_storage_dialog.glade"))
|
))
|
||||||
dialog = glade.get_widget("move_storage_dialog")
|
dialog = glade.get_widget("move_storage_dialog")
|
||||||
dialog.set_transient_for(self.window.window)
|
dialog.set_transient_for(self.window.window)
|
||||||
entry = glade.get_widget("entry_destination")
|
entry = glade.get_widget("entry_destination")
|
||||||
|
@ -439,10 +442,21 @@ class MenuBar(component.Component):
|
||||||
}
|
}
|
||||||
# widget: (header, type_str, image_stockid, image_filename, default)
|
# widget: (header, type_str, image_stockid, image_filename, default)
|
||||||
other_dialog_info = {
|
other_dialog_info = {
|
||||||
"menuitem_down_speed": (_("Set Maximum Download Speed"), "KiB/s", None, "downloading.svg", -1.0),
|
"menuitem_down_speed": (
|
||||||
"menuitem_up_speed": (_("Set Maximum Upload Speed"), "KiB/s", None, "seeding.svg", -1.0),
|
_("Set Maximum Download Speed"),
|
||||||
"menuitem_max_connections": (_("Set Maximum Connections"), "", gtk.STOCK_NETWORK, None, -1),
|
"KiB/s", None, "downloading.svg", -1.0
|
||||||
"menuitem_upload_slots": (_("Set Maximum Upload Slots"), "", gtk.STOCK_SORT_ASCENDING, None, -1)
|
),
|
||||||
|
"menuitem_up_speed": (
|
||||||
|
_("Set Maximum Upload Speed"),
|
||||||
|
"KiB/s", None, "seeding.svg", -1.0
|
||||||
|
),
|
||||||
|
"menuitem_max_connections": (
|
||||||
|
_("Set Maximum Connections"), "", gtk.STOCK_NETWORK, None, -1
|
||||||
|
),
|
||||||
|
"menuitem_upload_slots": (
|
||||||
|
_("Set Maximum Upload Slots"),
|
||||||
|
"", gtk.STOCK_SORT_ASCENDING, None, -1
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Show the other dialog
|
# Show the other dialog
|
||||||
|
@ -483,7 +497,15 @@ class MenuBar(component.Component):
|
||||||
getattr(self.window.main_glade.get_widget(item), attr)()
|
getattr(self.window.main_glade.get_widget(item), attr)()
|
||||||
|
|
||||||
def _on_known_accounts(self, known_accounts):
|
def _on_known_accounts(self, known_accounts):
|
||||||
log.debug("_on_known_accounts: %s", known_accounts)
|
known_accounts_to_log = []
|
||||||
|
for account in known_accounts:
|
||||||
|
account_to_log = {}
|
||||||
|
for key, value in account.copy().iteritems():
|
||||||
|
if key == 'password':
|
||||||
|
value = '*' * len(value)
|
||||||
|
account_to_log[key] = value
|
||||||
|
known_accounts_to_log.append(account_to_log)
|
||||||
|
log.debug("_on_known_accounts: %s", known_accounts_to_log)
|
||||||
if len(known_accounts) <= 1:
|
if len(known_accounts) <= 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -496,14 +518,18 @@ class MenuBar(component.Component):
|
||||||
self.change_owner_submenu_items[None] = gtk.RadioMenuItem(maingroup)
|
self.change_owner_submenu_items[None] = gtk.RadioMenuItem(maingroup)
|
||||||
|
|
||||||
for account in known_accounts:
|
for account in known_accounts:
|
||||||
self.change_owner_submenu_items[account] = item = gtk.RadioMenuItem(maingroup, account)
|
username = account["username"]
|
||||||
|
item = gtk.RadioMenuItem(maingroup, username)
|
||||||
|
self.change_owner_submenu_items[username] = item
|
||||||
self.change_owner_submenu.append(item)
|
self.change_owner_submenu.append(item)
|
||||||
item.connect("toggled", self._on_change_owner_toggled, account)
|
item.connect("toggled", self._on_change_owner_toggled, username)
|
||||||
|
|
||||||
self.change_owner_submenu.show_all()
|
self.change_owner_submenu.show_all()
|
||||||
self.change_owner_submenu_items[None].set_active(True)
|
self.change_owner_submenu_items[None].set_active(True)
|
||||||
self.change_owner_submenu_items[None].hide()
|
self.change_owner_submenu_items[None].hide()
|
||||||
self.menuitem_change_owner.connect("activate", self._on_change_owner_submenu_active)
|
self.menuitem_change_owner.connect(
|
||||||
|
"activate", self._on_change_owner_submenu_active
|
||||||
|
)
|
||||||
self.menuitem_change_owner.set_submenu(self.change_owner_submenu)
|
self.menuitem_change_owner.set_submenu(self.change_owner_submenu)
|
||||||
|
|
||||||
def _on_known_accounts_fail(self, reason):
|
def _on_known_accounts_fail(self, reason):
|
||||||
|
@ -517,18 +543,18 @@ class MenuBar(component.Component):
|
||||||
return
|
return
|
||||||
|
|
||||||
torrent_owner = component.get("TorrentView").get_torrent_status(selected[0])["owner"]
|
torrent_owner = component.get("TorrentView").get_torrent_status(selected[0])["owner"]
|
||||||
for account, item in self.change_owner_submenu_items.iteritems():
|
for username, item in self.change_owner_submenu_items.iteritems():
|
||||||
item.set_active(account == torrent_owner)
|
item.set_active(username == torrent_owner)
|
||||||
|
|
||||||
def _on_change_owner_toggled(self, widget, account):
|
def _on_change_owner_toggled(self, widget, username):
|
||||||
log.debug("_on_change_owner_toggled")
|
log.debug("_on_change_owner_toggled")
|
||||||
update_torrents = []
|
update_torrents = []
|
||||||
selected = component.get("TorrentView").get_selected_torrents()
|
selected = component.get("TorrentView").get_selected_torrents()
|
||||||
for torrent_id in selected:
|
for torrent_id in selected:
|
||||||
torrent_status = component.get("TorrentView").get_torrent_status(torrent_id)
|
torrent_status = component.get("TorrentView").get_torrent_status(torrent_id)
|
||||||
if torrent_status["owner"] != account:
|
if torrent_status["owner"] != username:
|
||||||
update_torrents.append(torrent_id)
|
update_torrents.append(torrent_id)
|
||||||
if update_torrents:
|
if update_torrents:
|
||||||
log.debug("Setting torrent owner \"%s\" on %s", account, update_torrents)
|
log.debug("Setting torrent owner \"%s\" on %s", username, update_torrents)
|
||||||
client.core.set_torrents_owner(update_torrents, account)
|
client.core.set_torrents_owner(update_torrents, username)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# preferences.py
|
# preferences.py
|
||||||
#
|
#
|
||||||
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
|
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
|
||||||
|
# Copyright (C) 2011 Pedro Algarvio <ufs@ufsoft.org>
|
||||||
#
|
#
|
||||||
# Deluge is free software.
|
# Deluge is free software.
|
||||||
#
|
#
|
||||||
|
@ -46,11 +47,14 @@ from deluge.ui.client import client
|
||||||
import deluge.common
|
import deluge.common
|
||||||
import deluge.error
|
import deluge.error
|
||||||
import common
|
import common
|
||||||
|
import dialogs
|
||||||
from deluge.configmanager import ConfigManager
|
from deluge.configmanager import ConfigManager
|
||||||
import deluge.configmanager
|
import deluge.configmanager
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ACCOUNTS_USERNAME, ACCOUNTS_LEVEL, ACCOUNTS_PASSWORD = range(3)
|
||||||
|
|
||||||
class Preferences(component.Component):
|
class Preferences(component.Component):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
component.Component.__init__(self, "Preferences")
|
component.Component.__init__(self, "Preferences")
|
||||||
|
@ -81,6 +85,35 @@ class Preferences(component.Component):
|
||||||
self.liststore.append([i, category])
|
self.liststore.append([i, category])
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
# Setup accounts tab lisview
|
||||||
|
self.accounts_levels_mapping = None
|
||||||
|
self.accounts_authlevel = self.glade.get_widget("accounts_authlevel")
|
||||||
|
self.accounts_liststore = gtk.ListStore(str, str, str, int)
|
||||||
|
self.accounts_liststore.set_sort_column_id(ACCOUNTS_USERNAME,
|
||||||
|
gtk.SORT_ASCENDING)
|
||||||
|
self.accounts_listview = self.glade.get_widget("accounts_listview")
|
||||||
|
self.accounts_listview.append_column(
|
||||||
|
gtk.TreeViewColumn(
|
||||||
|
_("Username"), gtk.CellRendererText(), text=ACCOUNTS_USERNAME
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.accounts_listview.append_column(
|
||||||
|
gtk.TreeViewColumn(
|
||||||
|
_("Level"), gtk.CellRendererText(), text=ACCOUNTS_LEVEL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
password_column = gtk.TreeViewColumn(
|
||||||
|
'password', gtk.CellRendererText(), text=ACCOUNTS_PASSWORD
|
||||||
|
)
|
||||||
|
self.accounts_listview.append_column(password_column)
|
||||||
|
password_column.set_visible(False)
|
||||||
|
self.accounts_listview.set_model(self.accounts_liststore)
|
||||||
|
|
||||||
|
self.accounts_listview.get_selection().connect(
|
||||||
|
"changed", self._on_accounts_selection_changed
|
||||||
|
)
|
||||||
|
self.accounts_frame = self.glade.get_widget("AccountsFrame")
|
||||||
|
|
||||||
# Setup plugin tab listview
|
# Setup plugin tab listview
|
||||||
self.plugin_liststore = gtk.ListStore(str, bool)
|
self.plugin_liststore = gtk.ListStore(str, bool)
|
||||||
self.plugin_liststore.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
self.plugin_liststore.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||||
|
@ -96,11 +129,13 @@ class Preferences(component.Component):
|
||||||
|
|
||||||
# Connect to the 'changed' event of TreeViewSelection to get selection
|
# Connect to the 'changed' event of TreeViewSelection to get selection
|
||||||
# changes.
|
# changes.
|
||||||
self.treeview.get_selection().connect("changed",
|
self.treeview.get_selection().connect(
|
||||||
self.on_selection_changed)
|
"changed", self.on_selection_changed
|
||||||
|
)
|
||||||
|
|
||||||
self.plugin_listview.get_selection().connect("changed",
|
self.plugin_listview.get_selection().connect(
|
||||||
self.on_plugin_selection_changed)
|
"changed", self.on_plugin_selection_changed
|
||||||
|
)
|
||||||
|
|
||||||
self.glade.signal_autoconnect({
|
self.glade.signal_autoconnect({
|
||||||
"on_pref_dialog_delete_event": self.on_pref_dialog_delete_event,
|
"on_pref_dialog_delete_event": self.on_pref_dialog_delete_event,
|
||||||
|
@ -114,7 +149,10 @@ class Preferences(component.Component):
|
||||||
"on_button_find_plugins_clicked": self._on_button_find_plugins_clicked,
|
"on_button_find_plugins_clicked": self._on_button_find_plugins_clicked,
|
||||||
"on_button_cache_refresh_clicked": self._on_button_cache_refresh_clicked,
|
"on_button_cache_refresh_clicked": self._on_button_cache_refresh_clicked,
|
||||||
"on_combo_proxy_type_changed": self._on_combo_proxy_type_changed,
|
"on_combo_proxy_type_changed": self._on_combo_proxy_type_changed,
|
||||||
"on_button_associate_magnet_clicked": self._on_button_associate_magnet_clicked
|
"on_button_associate_magnet_clicked": self._on_button_associate_magnet_clicked,
|
||||||
|
"on_accounts_add_clicked": self._on_accounts_add_clicked,
|
||||||
|
"on_accounts_delete_clicked": self._on_accounts_delete_clicked,
|
||||||
|
"on_accounts_edit_clicked": self._on_accounts_edit_clicked
|
||||||
})
|
})
|
||||||
|
|
||||||
# These get updated by requests done to the core
|
# These get updated by requests done to the core
|
||||||
|
@ -191,9 +229,12 @@ class Preferences(component.Component):
|
||||||
|
|
||||||
component.get("PluginManager").run_on_show_prefs()
|
component.get("PluginManager").run_on_show_prefs()
|
||||||
|
|
||||||
|
|
||||||
# Update the preferences dialog to reflect current config settings
|
# Update the preferences dialog to reflect current config settings
|
||||||
self.core_config = {}
|
self.core_config = {}
|
||||||
if client.connected():
|
if client.connected():
|
||||||
|
self._get_accounts_tab_data()
|
||||||
|
|
||||||
def _on_get_config(config):
|
def _on_get_config(config):
|
||||||
self.core_config = config
|
self.core_config = config
|
||||||
client.core.get_available_plugins().addCallback(_on_get_available_plugins)
|
client.core.get_available_plugins().addCallback(_on_get_available_plugins)
|
||||||
|
@ -832,6 +873,9 @@ class Preferences(component.Component):
|
||||||
# Show the correct notebook page based on what row is selected.
|
# Show the correct notebook page based on what row is selected.
|
||||||
(model, row) = treeselection.get_selected()
|
(model, row) = treeselection.get_selected()
|
||||||
try:
|
try:
|
||||||
|
if model.get_value(row, 1) == _("Daemon"):
|
||||||
|
# Let's see update the accounts related stuff
|
||||||
|
self._get_accounts_tab_data()
|
||||||
self.notebook.set_current_page(model.get_value(row, 0))
|
self.notebook.set_current_page(model.get_value(row, 0))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
@ -961,3 +1005,169 @@ class Preferences(component.Component):
|
||||||
|
|
||||||
def _on_button_associate_magnet_clicked(self, widget):
|
def _on_button_associate_magnet_clicked(self, widget):
|
||||||
common.associate_magnet_links(True)
|
common.associate_magnet_links(True)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_accounts_tab_data(self):
|
||||||
|
def on_ok(accounts):
|
||||||
|
self.accounts_frame.show()
|
||||||
|
self._on_get_known_accounts(accounts)
|
||||||
|
|
||||||
|
def on_fail(failure):
|
||||||
|
if failure.value.exception_type == 'NotAuthorizedError':
|
||||||
|
self.accounts_frame.hide()
|
||||||
|
else:
|
||||||
|
dialogs.ErrorDialog(
|
||||||
|
_("Server Side Error"),
|
||||||
|
_("An error ocurred on the server"),
|
||||||
|
self.pref_dialog, details=failure.value.logable()
|
||||||
|
).run()
|
||||||
|
client.core.get_known_accounts().addCallback(on_ok).addErrback(on_fail)
|
||||||
|
|
||||||
|
def _on_get_known_accounts(self, known_accounts):
|
||||||
|
known_accounts_to_log = []
|
||||||
|
for account in known_accounts:
|
||||||
|
account_to_log = {}
|
||||||
|
for key, value in account.copy().iteritems():
|
||||||
|
if key == 'password':
|
||||||
|
value = '*' * len(value)
|
||||||
|
account_to_log[key] = value
|
||||||
|
known_accounts_to_log.append(account_to_log)
|
||||||
|
log.debug("_on_known_accounts: %s", known_accounts_to_log)
|
||||||
|
|
||||||
|
self.accounts_liststore.clear()
|
||||||
|
|
||||||
|
for account in known_accounts:
|
||||||
|
iter = self.accounts_liststore.append()
|
||||||
|
self.accounts_liststore.set_value(
|
||||||
|
iter, ACCOUNTS_USERNAME, account['username']
|
||||||
|
)
|
||||||
|
self.accounts_liststore.set_value(
|
||||||
|
iter, ACCOUNTS_LEVEL, account['authlevel']
|
||||||
|
)
|
||||||
|
self.accounts_liststore.set_value(
|
||||||
|
iter, ACCOUNTS_PASSWORD, account['password']
|
||||||
|
)
|
||||||
|
|
||||||
|
def _on_accounts_selection_changed(self, treeselection):
|
||||||
|
log.debug("_on_accounts_selection_changed")
|
||||||
|
(model, itr) = treeselection.get_selected()
|
||||||
|
if not itr:
|
||||||
|
return
|
||||||
|
username = model[itr][0]
|
||||||
|
if username:
|
||||||
|
self.glade.get_widget("accounts_edit").set_sensitive(True)
|
||||||
|
self.glade.get_widget("accounts_delete").set_sensitive(True)
|
||||||
|
else:
|
||||||
|
self.glade.get_widget("accounts_edit").set_sensitive(False)
|
||||||
|
self.glade.get_widget("accounts_delete").set_sensitive(False)
|
||||||
|
|
||||||
|
def _on_accounts_add_clicked(self, widget):
|
||||||
|
dialog = dialogs.AccountDialog(
|
||||||
|
levels_mapping=client.auth_levels_mapping,
|
||||||
|
parent=self.pref_dialog
|
||||||
|
)
|
||||||
|
|
||||||
|
def dialog_finished(response_id):
|
||||||
|
username = dialog.get_username()
|
||||||
|
password = dialog.get_password()
|
||||||
|
authlevel = dialog.get_authlevel()
|
||||||
|
|
||||||
|
def add_ok(rv):
|
||||||
|
iter = self.accounts_liststore.append()
|
||||||
|
self.accounts_liststore.set_value(
|
||||||
|
iter, ACCOUNTS_USERNAME, username
|
||||||
|
)
|
||||||
|
self.accounts_liststore.set_value(
|
||||||
|
iter, ACCOUNTS_LEVEL, authlevel
|
||||||
|
)
|
||||||
|
self.accounts_liststore.set_value(
|
||||||
|
iter, ACCOUNTS_PASSWORD, password
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_fail(failure):
|
||||||
|
if failure.value.exception_type == 'AuthManagerError':
|
||||||
|
dialogs.ErrorDialog(
|
||||||
|
_("Error Adding Account"),
|
||||||
|
failure.value.exception_msg
|
||||||
|
).run()
|
||||||
|
else:
|
||||||
|
dialogs.ErrorDialog(
|
||||||
|
_("Error Adding Account"),
|
||||||
|
_("An error ocurred while adding account"),
|
||||||
|
self.pref_dialog, details=failure.value.logable()
|
||||||
|
).run()
|
||||||
|
|
||||||
|
if response_id == gtk.RESPONSE_OK:
|
||||||
|
client.core.create_account(
|
||||||
|
username, password, authlevel
|
||||||
|
).addCallback(add_ok).addErrback(add_fail)
|
||||||
|
|
||||||
|
dialog.run().addCallback(dialog_finished)
|
||||||
|
|
||||||
|
def _on_accounts_edit_clicked(self, widget):
|
||||||
|
(model, itr) = self.accounts_listview.get_selection().get_selected()
|
||||||
|
if not itr:
|
||||||
|
return
|
||||||
|
|
||||||
|
dialog = dialogs.AccountDialog(
|
||||||
|
model[itr][ACCOUNTS_USERNAME],
|
||||||
|
model[itr][ACCOUNTS_PASSWORD],
|
||||||
|
model[itr][ACCOUNTS_LEVEL],
|
||||||
|
levels_mapping=client.auth_levels_mapping,
|
||||||
|
parent=self.pref_dialog
|
||||||
|
)
|
||||||
|
|
||||||
|
def dialog_finished(response_id):
|
||||||
|
|
||||||
|
def update_ok(rc):
|
||||||
|
model.set_value(itr, ACCOUNTS_PASSWORD, dialog.get_username())
|
||||||
|
model.set_value(itr, ACCOUNTS_LEVEL, dialog.get_authlevel())
|
||||||
|
|
||||||
|
def update_fail(failure):
|
||||||
|
dialogs.ErrorDialog(
|
||||||
|
_("Error Updating Account"),
|
||||||
|
_("An error ocurred while updating account"),
|
||||||
|
self.pref_dialog, details=failure.value.logable()
|
||||||
|
).run()
|
||||||
|
|
||||||
|
if response_id == gtk.RESPONSE_OK:
|
||||||
|
client.core.update_account(
|
||||||
|
dialog.get_username(),
|
||||||
|
dialog.get_password(),
|
||||||
|
dialog.get_authlevel()
|
||||||
|
).addCallback(update_ok).addErrback(update_fail)
|
||||||
|
|
||||||
|
dialog.run().addCallback(dialog_finished)
|
||||||
|
|
||||||
|
def _on_accounts_delete_clicked(self, widget):
|
||||||
|
(model, itr) = self.accounts_listview.get_selection().get_selected()
|
||||||
|
if not itr:
|
||||||
|
return
|
||||||
|
|
||||||
|
username = model[itr][0]
|
||||||
|
header = _("Remove Account")
|
||||||
|
text = _("Are you sure you wan't do remove the account with the "
|
||||||
|
"username \"%(username)s\"?" % dict(username=username))
|
||||||
|
dialog = dialogs.YesNoDialog(header, text, parent=self.pref_dialog)
|
||||||
|
|
||||||
|
def dialog_finished(response_id):
|
||||||
|
def remove_ok(rc):
|
||||||
|
model.remove(itr)
|
||||||
|
|
||||||
|
def remove_fail(failure):
|
||||||
|
if failure.value.exception_type == 'AuthManagerError':
|
||||||
|
dialogs.ErrorDialog(
|
||||||
|
_("Error Removing Account"),
|
||||||
|
failure.value.exception_msg
|
||||||
|
).run()
|
||||||
|
else:
|
||||||
|
dialogs.ErrorDialog(
|
||||||
|
_("Error Removing Account"),
|
||||||
|
_("An error ocurred while removing account"),
|
||||||
|
self.pref_dialog, details=failure.value.logable()
|
||||||
|
).run()
|
||||||
|
if response_id == gtk.RESPONSE_YES:
|
||||||
|
client.core.remove_account(
|
||||||
|
username
|
||||||
|
).addCallback(remove_ok).addErrback(remove_fail)
|
||||||
|
dialog.run().addCallback(dialog_finished)
|
||||||
|
|
Loading…
Reference in New Issue