summaryrefslogtreecommitdiffstats
path: root/deluge/ui
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/ui')
-rw-r--r--deluge/ui/client.py19
-rw-r--r--deluge/ui/common.py39
-rw-r--r--deluge/ui/console/__init__.py5
-rw-r--r--deluge/ui/console/cmdline/command.py7
-rw-r--r--deluge/ui/console/cmdline/commands/__init__.py3
-rw-r--r--deluge/ui/console/cmdline/commands/add.py17
-rw-r--r--deluge/ui/console/cmdline/commands/cache.py5
-rw-r--r--deluge/ui/console/cmdline/commands/config.py84
-rw-r--r--deluge/ui/console/cmdline/commands/connect.py12
-rw-r--r--deluge/ui/console/cmdline/commands/debug.py3
-rw-r--r--deluge/ui/console/cmdline/commands/gui.py3
-rw-r--r--deluge/ui/console/cmdline/commands/halt.py3
-rw-r--r--deluge/ui/console/cmdline/commands/help.py3
-rw-r--r--deluge/ui/console/cmdline/commands/info.py40
-rw-r--r--deluge/ui/console/cmdline/commands/manage.py9
-rw-r--r--deluge/ui/console/cmdline/commands/move.py5
-rw-r--r--deluge/ui/console/cmdline/commands/pause.py3
-rw-r--r--deluge/ui/console/cmdline/commands/plugin.py5
-rw-r--r--deluge/ui/console/cmdline/commands/quit.py3
-rw-r--r--deluge/ui/console/cmdline/commands/recheck.py3
-rw-r--r--deluge/ui/console/cmdline/commands/resume.py3
-rw-r--r--deluge/ui/console/cmdline/commands/rm.py9
-rw-r--r--deluge/ui/console/cmdline/commands/status.py12
-rw-r--r--deluge/ui/console/cmdline/commands/update_tracker.py3
-rw-r--r--deluge/ui/console/console.py15
-rw-r--r--deluge/ui/console/main.py74
-rw-r--r--deluge/ui/console/modes/add_util.py5
-rw-r--r--deluge/ui/console/modes/addtorrents.py15
-rw-r--r--deluge/ui/console/modes/basemode.py19
-rw-r--r--deluge/ui/console/modes/cmdline.py23
-rw-r--r--deluge/ui/console/modes/connectionmanager.py46
-rw-r--r--deluge/ui/console/modes/eventview.py7
-rw-r--r--deluge/ui/console/modes/preferences/__init__.py2
-rw-r--r--deluge/ui/console/modes/preferences/preference_panes.py15
-rw-r--r--deluge/ui/console/modes/preferences/preferences.py5
-rw-r--r--deluge/ui/console/modes/torrentdetail.py41
-rw-r--r--deluge/ui/console/modes/torrentlist/__init__.py5
-rw-r--r--deluge/ui/console/modes/torrentlist/add_torrents_popup.py5
-rw-r--r--deluge/ui/console/modes/torrentlist/filtersidebar.py3
-rw-r--r--deluge/ui/console/modes/torrentlist/queue_mode.py5
-rw-r--r--deluge/ui/console/modes/torrentlist/search_mode.py8
-rw-r--r--deluge/ui/console/modes/torrentlist/torrentactions.py7
-rw-r--r--deluge/ui/console/modes/torrentlist/torrentlist.py9
-rw-r--r--deluge/ui/console/modes/torrentlist/torrentview.py11
-rw-r--r--deluge/ui/console/modes/torrentlist/torrentviewcolumns.py3
-rw-r--r--deluge/ui/console/parser.py33
-rw-r--r--deluge/ui/console/utils/colors.py11
-rw-r--r--deluge/ui/console/utils/column.py3
-rw-r--r--deluge/ui/console/utils/common.py3
-rw-r--r--deluge/ui/console/utils/curses_util.py7
-rw-r--r--deluge/ui/console/utils/format_utils.py19
-rw-r--r--deluge/ui/console/widgets/__init__.py2
-rw-r--r--deluge/ui/console/widgets/fields.py46
-rw-r--r--deluge/ui/console/widgets/inputpane.py3
-rw-r--r--deluge/ui/console/widgets/popup.py7
-rw-r--r--deluge/ui/console/widgets/sidebar.py3
-rw-r--r--deluge/ui/console/widgets/statusbars.py20
-rw-r--r--deluge/ui/console/widgets/window.py5
-rw-r--r--deluge/ui/coreconfig.py3
-rw-r--r--deluge/ui/countries.py9
-rw-r--r--deluge/ui/data/__pycache__/__init__.cpython-37.pycbin141 -> 0 bytes
-rw-r--r--deluge/ui/data/pixmaps/__pycache__/__init__.cpython-37.pycbin149 -> 0 bytes
-rw-r--r--deluge/ui/data/pixmaps/checking16.pngbin490 -> 519 bytes
-rw-r--r--deluge/ui/data/pixmaps/inactive16.pngbin432 -> 434 bytes
-rw-r--r--deluge/ui/data/pixmaps/magnet.pngbin906 -> 0 bytes
-rw-r--r--deluge/ui/data/pixmaps/magnet.svg166
-rw-r--r--deluge/ui/data/pixmaps/magnet16.pngbin0 -> 303 bytes
-rw-r--r--deluge/ui/data/pixmaps/magnet_add.svg175
-rw-r--r--deluge/ui/data/pixmaps/magnet_add16.pngbin0 -> 392 bytes
-rw-r--r--deluge/ui/data/pixmaps/magnet_copy.svg163
-rw-r--r--deluge/ui/data/pixmaps/magnet_copy16.pngbin0 -> 446 bytes
-rw-r--r--deluge/ui/data/share/applications/deluge.desktop.in1
-rw-r--r--deluge/ui/gtk3/__init__.py13
-rw-r--r--deluge/ui/gtk3/aboutdialog.py7
-rw-r--r--deluge/ui/gtk3/addtorrentdialog.py17
-rw-r--r--deluge/ui/gtk3/common.py128
-rw-r--r--deluge/ui/gtk3/connectionmanager.py14
-rw-r--r--deluge/ui/gtk3/createtorrentdialog.py5
-rw-r--r--deluge/ui/gtk3/details_tab.py7
-rw-r--r--deluge/ui/gtk3/dialogs.py129
-rw-r--r--deluge/ui/gtk3/edittrackersdialog.py70
-rw-r--r--deluge/ui/gtk3/files_tab.py14
-rw-r--r--deluge/ui/gtk3/filtertreeview.py22
-rw-r--r--deluge/ui/gtk3/glade/add_torrent_dialog.infohash.ui2
-rw-r--r--deluge/ui/gtk3/glade/add_torrent_dialog.ui8
-rw-r--r--deluge/ui/gtk3/glade/add_torrent_dialog.url.ui2
-rw-r--r--deluge/ui/gtk3/glade/connect_peer_dialog.ui2
-rw-r--r--deluge/ui/gtk3/glade/connection_manager.addhost.ui137
-rw-r--r--deluge/ui/gtk3/glade/connection_manager.ui2
-rw-r--r--deluge/ui/gtk3/glade/create_torrent_dialog.remote_path.ui2
-rw-r--r--deluge/ui/gtk3/glade/create_torrent_dialog.remote_save.ui2
-rw-r--r--deluge/ui/gtk3/glade/create_torrent_dialog.ui5
-rw-r--r--deluge/ui/gtk3/glade/edit_trackers.edit.ui2
-rw-r--r--deluge/ui/gtk3/glade/main_window.tabs.ui48
-rw-r--r--deluge/ui/gtk3/glade/main_window.tabs.ui~1507
-rw-r--r--deluge/ui/gtk3/glade/main_window.ui1
-rw-r--r--deluge/ui/gtk3/glade/other_dialog.ui2
-rw-r--r--deluge/ui/gtk3/glade/path_combo_chooser.ui3
-rw-r--r--deluge/ui/gtk3/glade/preferences_dialog.ui158
-rw-r--r--deluge/ui/gtk3/glade/torrent_menu.ui16
-rw-r--r--deluge/ui/gtk3/gtkui.py33
-rw-r--r--deluge/ui/gtk3/ipcinterface.py15
-rw-r--r--deluge/ui/gtk3/listview.py33
-rw-r--r--deluge/ui/gtk3/mainwindow.py43
-rw-r--r--deluge/ui/gtk3/menubar.py36
-rw-r--r--deluge/ui/gtk3/menubar_osx.py3
-rw-r--r--deluge/ui/gtk3/new_release_dialog.py5
-rw-r--r--deluge/ui/gtk3/options_tab.py10
-rw-r--r--deluge/ui/gtk3/path_chooser.py5
-rwxr-xr-xdeluge/ui/gtk3/path_combo_chooser.py48
-rw-r--r--deluge/ui/gtk3/peers_tab.py36
-rw-r--r--deluge/ui/gtk3/piecesbar.py16
-rw-r--r--deluge/ui/gtk3/pluginmanager.py3
-rw-r--r--deluge/ui/gtk3/preferences.py125
-rw-r--r--deluge/ui/gtk3/queuedtorrents.py3
-rw-r--r--deluge/ui/gtk3/removetorrentdialog.py5
-rw-r--r--deluge/ui/gtk3/sidebar.py3
-rw-r--r--deluge/ui/gtk3/status_tab.py7
-rw-r--r--deluge/ui/gtk3/statusbar.py34
-rw-r--r--deluge/ui/gtk3/systemtray.py17
-rw-r--r--deluge/ui/gtk3/tab_data_funcs.py11
-rw-r--r--deluge/ui/gtk3/toolbar.py3
-rw-r--r--deluge/ui/gtk3/torrentdetails.py45
-rw-r--r--deluge/ui/gtk3/torrentview.py20
-rw-r--r--deluge/ui/gtk3/torrentview_data_funcs.py16
-rw-r--r--deluge/ui/gtk3/trackers_tab.py7
-rw-r--r--deluge/ui/hostlist.py77
-rw-r--r--deluge/ui/sessionproxy.py19
-rw-r--r--deluge/ui/tracker_icons.py139
-rw-r--r--deluge/ui/ui.py8
-rw-r--r--deluge/ui/ui_entry.py7
-rw-r--r--deluge/ui/web/__init__.py2
-rw-r--r--deluge/ui/web/auth.py7
-rw-r--r--deluge/ui/web/common.py7
-rw-r--r--deluge/ui/web/css/deluge.css14
-rw-r--r--deluge/ui/web/icons/active.pngbin503 -> 505 bytes
-rw-r--r--deluge/ui/web/icons/add_magnet.pngbin589 -> 0 bytes
-rw-r--r--deluge/ui/web/icons/checking.pngbin489 -> 519 bytes
-rw-r--r--deluge/ui/web/icons/deluge.pngbin551 -> 552 bytes
-rw-r--r--deluge/ui/web/icons/downloading.pngbin462 -> 465 bytes
-rw-r--r--deluge/ui/web/icons/inactive.pngbin431 -> 434 bytes
-rw-r--r--deluge/ui/web/icons/magnet.pngbin0 -> 303 bytes
-rw-r--r--deluge/ui/web/icons/magnet_add.pngbin0 -> 392 bytes
-rw-r--r--deluge/ui/web/icons/magnet_copy.pngbin0 -> 446 bytes
-rw-r--r--deluge/ui/web/js/deluge-all-debug.js1477
-rw-r--r--deluge/ui/web/js/deluge-all.js291
-rw-r--r--deluge/ui/web/js/deluge-all/AboutWindow.js23
-rw-r--r--deluge/ui/web/js/deluge-all/AddConnectionWindow.js8
-rw-r--r--deluge/ui/web/js/deluge-all/AddTrackerWindow.js28
-rw-r--r--deluge/ui/web/js/deluge-all/Client.js24
-rw-r--r--deluge/ui/web/js/deluge-all/ConnectionManager.js60
-rw-r--r--deluge/ui/web/js/deluge-all/CopyMagnetWindow.js73
-rw-r--r--deluge/ui/web/js/deluge-all/Deluge.js25
-rw-r--r--deluge/ui/web/js/deluge-all/EditConnectionWindow.js20
-rw-r--r--deluge/ui/web/js/deluge-all/EditTrackerWindow.js25
-rw-r--r--deluge/ui/web/js/deluge-all/EditTrackersWindow.js49
-rw-r--r--deluge/ui/web/js/deluge-all/EventsManager.js20
-rw-r--r--deluge/ui/web/js/deluge-all/FileBrowser.js2
-rw-r--r--deluge/ui/web/js/deluge-all/FilterPanel.js22
-rw-r--r--deluge/ui/web/js/deluge-all/Formatters.js301
-rw-r--r--deluge/ui/web/js/deluge-all/Keys.js2
-rw-r--r--deluge/ui/web/js/deluge-all/LoginWindow.js24
-rw-r--r--deluge/ui/web/js/deluge-all/Menus.js18
-rw-r--r--deluge/ui/web/js/deluge-all/MoveStorage.js12
-rw-r--r--deluge/ui/web/js/deluge-all/MultiOptionsManager.js28
-rw-r--r--deluge/ui/web/js/deluge-all/OptionsManager.js38
-rw-r--r--deluge/ui/web/js/deluge-all/OtherLimitWindow.js17
-rw-r--r--deluge/ui/web/js/deluge-all/Plugin.js16
-rw-r--r--deluge/ui/web/js/deluge-all/RemoveWindow.js16
-rw-r--r--deluge/ui/web/js/deluge-all/Sidebar.js26
-rw-r--r--deluge/ui/web/js/deluge-all/Statusbar.js22
-rw-r--r--deluge/ui/web/js/deluge-all/StatusbarMenu.js14
-rw-r--r--deluge/ui/web/js/deluge-all/Toolbar.js34
-rw-r--r--deluge/ui/web/js/deluge-all/TorrentGrid.js48
-rw-r--r--deluge/ui/web/js/deluge-all/UI.js38
-rw-r--r--deluge/ui/web/js/deluge-all/add/AddWindow.js83
-rw-r--r--deluge/ui/web/js/deluge-all/add/FilesTab.js17
-rw-r--r--deluge/ui/web/js/deluge-all/add/OptionsPanel.js31
-rw-r--r--deluge/ui/web/js/deluge-all/add/OptionsTab.js6
-rw-r--r--deluge/ui/web/js/deluge-all/add/UrlWindow.js22
-rw-r--r--deluge/ui/web/js/deluge-all/add/Window.js6
-rw-r--r--deluge/ui/web/js/deluge-all/data/SortTypes.js4
-rw-r--r--deluge/ui/web/js/deluge-all/details/DetailsPanel.js18
-rw-r--r--deluge/ui/web/js/deluge-all/details/DetailsTab.js18
-rw-r--r--deluge/ui/web/js/deluge-all/details/FilesTab.js39
-rw-r--r--deluge/ui/web/js/deluge-all/details/OptionsTab.js24
-rw-r--r--deluge/ui/web/js/deluge-all/details/PeersTab.js18
-rw-r--r--deluge/ui/web/js/deluge-all/details/StatusTab.js14
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/BandwidthPage.js7
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/CachePage.js2
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/DaemonPage.js2
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/DownloadsPage.js4
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/EncryptionPage.js2
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/InstallPluginWindow.js8
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/InterfacePage.js22
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/NetworkPage.js8
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/OtherPage.js4
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/PluginsPage.js46
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js31
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/ProxyField.js12
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/ProxyPage.js10
-rw-r--r--deluge/ui/web/js/deluge-all/preferences/QueuePage.js4
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions-debug.js338
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions.js84
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/JSLoader.js8
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/Spinner.js74
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/StatusBar.js18
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js34
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js12
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js10
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js29
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js13
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js32
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js2
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js6
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js48
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js18
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js4
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js2
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js10
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js2
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js2
-rw-r--r--deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js14
-rw-r--r--deluge/ui/web/js/gettext.js4
-rw-r--r--deluge/ui/web/json_api.py72
-rw-r--r--deluge/ui/web/pluginmanager.py28
-rw-r--r--deluge/ui/web/server.py18
-rw-r--r--deluge/ui/web/web.py7
228 files changed, 5477 insertions, 3162 deletions
diff --git a/deluge/ui/client.py b/deluge/ui/client.py
index 686f962..6b657d5 100644
--- a/deluge/ui/client.py
+++ b/deluge/ui/client.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import subprocess
import sys
@@ -33,7 +30,7 @@ def format_kwargs(kwargs):
return ', '.join([key + '=' + str(value) for key, value in kwargs.items()])
-class DelugeRPCRequest(object):
+class DelugeRPCRequest:
"""
This object is created whenever there is a RPCRequest to be sent to the
daemon. It is generally only used by the DaemonProxy's call method.
@@ -65,7 +62,7 @@ class DelugeRPCRequest(object):
Returns a properly formatted RPCRequest based on the properties. Will
raise a TypeError if the properties haven't been set yet.
- :returns: a properly formated RPCRequest
+ :returns: a properly formatted RPCRequest
"""
if (
self.request_id is None
@@ -150,7 +147,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
# so it could pass back to the 2nd deferred on the chain. But,
# that does not always happen.
# So, just do some instance checking and just log rpc error at
- # diferent levels.
+ # different levels.
r = self.__rpc_requests[request_id]
msg = 'RPCError Message Received!'
msg += '\n' + '-' * 80
@@ -168,7 +165,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
# Let's log these as errors
log.error(msg)
else:
- # The rest just get's logged in debug level, just to log
+ # The rest just gets logged in debug level, just to log
# what's happening
log.debug(msg)
except Exception:
@@ -243,7 +240,7 @@ class DelugeRPCClientFactory(ClientFactory):
self.daemon.disconnect_callback()
-class DaemonProxy(object):
+class DaemonProxy:
pass
@@ -526,7 +523,7 @@ class DaemonStandaloneProxy(DaemonProxy):
self.__daemon.core.eventmanager.deregister_event_handler(event, handler)
-class DottedObject(object):
+class DottedObject:
"""
This is used for dotted name calls to client
"""
@@ -551,7 +548,7 @@ class RemoteMethod(DottedObject):
return self.daemon.call(self.base, *args, **kwargs)
-class Client(object):
+class Client:
"""
This class is used to connect to a daemon process and issue RPC requests.
"""
@@ -615,7 +612,7 @@ class Client(object):
d.addErrback(on_authenticate_fail)
return d
- d.addCallback(on_connected)
+ d.addCallbacks(on_connected)
d.addErrback(on_connect_fail)
if not skip_authentication:
d.addCallback(authenticate, username, password)
diff --git a/deluge/ui/common.py b/deluge/ui/common.py
index 21bcafd..f9f774e 100644
--- a/deluge/ui/common.py
+++ b/deluge/ui/common.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) Damien Churchill 2008-2009 <damoxc@gmail.com>
# Copyright (C) Andrew Resch 2009 <andrewresch@gmail.com>
@@ -11,11 +10,8 @@
"""
The ui common module contains methods and classes that are deemed useful for all the interfaces.
"""
-from __future__ import unicode_literals
-
import logging
import os
-from binascii import hexlify
from hashlib import sha1 as sha
from deluge import bencode
@@ -161,7 +157,6 @@ DISK_CACHE_KEYS = [
'disk.num_blocks_written',
'disk.num_read_ops',
'disk.num_write_ops',
- 'disk.num_blocks_cache_hits',
'read_hit_ratio',
'write_hit_ratio',
'disk.disk_blocks_in_use',
@@ -169,7 +164,7 @@ DISK_CACHE_KEYS = [
]
-class TorrentInfo(object):
+class TorrentInfo:
"""Collects information about a torrent file.
Args:
@@ -188,7 +183,7 @@ class TorrentInfo(object):
try:
with open(filename, 'rb') as _file:
self._filedata = _file.read()
- except IOError as ex:
+ except OSError as ex:
log.warning('Unable to open %s: %s', filename, ex)
return
@@ -206,12 +201,9 @@ class TorrentInfo(object):
self._info_hash = sha(bencode.bencode(info_dict)).hexdigest()
# Get encoding from torrent file if available
- encoding = info_dict.get('encoding', None)
- codepage = info_dict.get('codepage', None)
- if not encoding:
- encoding = codepage if codepage else b'UTF-8'
- if encoding:
- encoding = encoding.decode()
+ encoding = info_dict.get(
+ 'encoding', info_dict.get('codepage', b'UTF-8')
+ ).decode()
# Decode 'name' with encoding unless 'name.utf-8' found.
if 'name.utf-8' in info_dict:
@@ -231,27 +223,20 @@ class TorrentInfo(object):
if 'path.utf-8' in f:
path = decode_bytes(os.path.join(*f['path.utf-8']))
- del f['path.utf-8']
else:
path = decode_bytes(os.path.join(*f['path']), encoding)
if prefix:
path = os.path.join(prefix, path)
+ # Ensure agnostic path separator
+ path = path.replace('\\', '/')
+
self._files.append(
{'path': path, 'size': f['length'], 'download': True}
)
+ paths[path] = {'path': path, 'index': index, 'length': f['length']}
- f['path'] = path
- f['index'] = index
- if 'sha1' in f and len(f['sha1']) == 20:
- f['sha1'] = hexlify(f['sha1']).decode()
- if 'ed2k' in f and len(f['ed2k']) == 16:
- f['ed2k'] = hexlify(f['ed2k']).decode()
- if 'filehash' in f and len(f['filehash']) == 20:
- f['filehash'] = hexlify(f['filehash']).decode()
-
- paths[path] = f
dirname = os.path.dirname(path)
while dirname:
dirinfo = dirs.setdefault(dirname, {})
@@ -399,7 +384,7 @@ class TorrentInfo(object):
return self._filedata
-class FileTree2(object):
+class FileTree2:
"""
Converts a list of paths in to a file tree.
@@ -479,7 +464,7 @@ class FileTree2(object):
return '\n'.join(lines)
-class FileTree(object):
+class FileTree:
"""
Convert a list of paths in a file tree.
@@ -538,7 +523,7 @@ class FileTree(object):
def walk(directory, parent_path):
for path in list(directory):
- full_path = os.path.join(parent_path, path)
+ full_path = os.path.join(parent_path, path).replace('\\', '/')
if isinstance(directory[path], dict):
directory[path] = (
callback(full_path, directory[path]) or directory[path]
diff --git a/deluge/ui/console/__init__.py b/deluge/ui/console/__init__.py
index 56e8d62..7da04a6 100644
--- a/deluge/ui/console/__init__.py
+++ b/deluge/ui/console/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from deluge.ui.console.console import Console
UI_PATH = __path__[0]
@@ -16,4 +13,4 @@ UI_PATH = __path__[0]
def start():
- Console().start()
+ return Console().start()
diff --git a/deluge/ui/console/cmdline/command.py b/deluge/ui/console/cmdline/command.py
index 2ff32df..40edd78 100644
--- a/deluge/ui/console/cmdline/command.py
+++ b/deluge/ui/console/cmdline/command.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -9,8 +8,6 @@
# See LICENSE for more details.
#
-from __future__ import print_function, unicode_literals
-
import logging
import shlex
@@ -23,7 +20,7 @@ from deluge.ui.console.utils.colors import strip_colors
log = logging.getLogger(__name__)
-class Commander(object):
+class Commander:
def __init__(self, cmds, interactive=False):
self._commands = cmds
self.interactive = interactive
@@ -144,7 +141,7 @@ class Commander(object):
return ret
-class BaseCommand(object):
+class BaseCommand:
usage = None
interactive_only = False
diff --git a/deluge/ui/console/cmdline/commands/__init__.py b/deluge/ui/console/cmdline/commands/__init__.py
index 628fae5..39dbefe 100644
--- a/deluge/ui/console/cmdline/commands/__init__.py
+++ b/deluge/ui/console/cmdline/commands/__init__.py
@@ -1,6 +1,3 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
from deluge.ui.console.cmdline.command import BaseCommand
__all__ = ['BaseCommand']
diff --git a/deluge/ui/console/cmdline/commands/add.py b/deluge/ui/console/cmdline/commands/add.py
index 34881d8..706ae16 100644
--- a/deluge/ui/console/cmdline/commands/add.py
+++ b/deluge/ui/console/cmdline/commands/add.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,10 +7,10 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import os
from base64 import b64encode
+from urllib.parse import urlparse
+from urllib.request import url2pathname
from twisted.internet import defer
@@ -21,14 +20,6 @@ from deluge.ui.client import client
from . import BaseCommand
-try:
- from urllib.parse import urlparse
- from urllib.request import url2pathname
-except ImportError:
- # PY2 fallback
- from urlparse import urlparse # pylint: disable=ungrouped-imports
- from urllib import url2pathname # pylint: disable=ungrouped-imports
-
class Command(BaseCommand):
"""Add torrents"""
@@ -81,7 +72,7 @@ class Command(BaseCommand):
continue
if deluge.common.is_url(torrent):
self.console.write(
- '{!info!}Attempting to add torrent from url: %s' % torrent
+ '{!info!}Attempting to add torrent from URL: %s' % torrent
)
deferreds.append(
client.core.add_torrent_url(torrent, t_options)
@@ -90,7 +81,7 @@ class Command(BaseCommand):
)
elif deluge.common.is_magnet(torrent):
self.console.write(
- '{!info!}Attempting to add torrent from magnet uri: %s' % torrent
+ '{!info!}Attempting to add torrent from magnet URI: %s' % torrent
)
deferreds.append(
client.core.add_torrent_magnet(torrent, t_options)
diff --git a/deluge/ui/console/cmdline/commands/cache.py b/deluge/ui/console/cmdline/commands/cache.py
index e427f08..fe6cd58 100644
--- a/deluge/ui/console/cmdline/commands/cache.py
+++ b/deluge/ui/console/cmdline/commands/cache.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from deluge.ui.client import client
from deluge.ui.common import DISK_CACHE_KEYS
@@ -24,7 +21,7 @@ class Command(BaseCommand):
def on_cache_status(status):
for key, value in sorted(status.items()):
- self.console.write('{!info!}%s: {!input!}%s' % (key, value))
+ self.console.write(f'{{!info!}}{key}: {{!input!}}{value}')
return client.core.get_session_status(DISK_CACHE_KEYS).addCallback(
on_cache_status
diff --git a/deluge/ui/console/cmdline/commands/config.py b/deluge/ui/console/cmdline/commands/config.py
index bd0a1e1..8b31ca3 100644
--- a/deluge/ui/console/cmdline/commands/config.py
+++ b/deluge/ui/console/cmdline/commands/config.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,11 +7,9 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
+import json
import logging
-import tokenize
-from io import StringIO
+import re
import deluge.component as component
import deluge.ui.console.utils.colors as colors
@@ -23,54 +20,25 @@ from . import BaseCommand
log = logging.getLogger(__name__)
-def atom(src, token):
- """taken with slight modifications from http://effbot.org/zone/simple-iterator-parser.htm"""
- if token[1] == '(':
- out = []
- token = next(src)
- while token[1] != ')':
- out.append(atom(src, token))
- token = next(src)
- if token[1] == ',':
- token = next(src)
- return tuple(out)
- elif token[0] is tokenize.NUMBER or token[1] == '-':
- try:
- if token[1] == '-':
- return int(token[-1], 0)
- else:
- if token[1].startswith('0x'):
- # Hex number so return unconverted as string.
- return token[1].decode('string-escape')
- else:
- return int(token[1], 0)
- except ValueError:
- try:
- return float(token[-1])
- except ValueError:
- return str(token[-1])
- elif token[1].lower() == 'true':
- return True
- elif token[1].lower() == 'false':
- return False
- elif token[0] is tokenize.STRING or token[1] == '/':
- return token[-1].decode('string-escape')
- elif token[1].isalpha():
- # Parse Windows paths e.g. 'C:\\xyz' or 'C:/xyz'.
- if next()[1] == ':' and next()[1] in '\\/':
- return token[-1].decode('string-escape')
-
- raise SyntaxError('malformed expression (%s)' % token[1])
-
-
-def simple_eval(source):
- """ evaluates the 'source' string into a combination of primitive python objects
- taken from http://effbot.org/zone/simple-iterator-parser.htm"""
- src = StringIO(source).readline
- src = tokenize.generate_tokens(src)
- src = (token for token in src if token[0] is not tokenize.NL)
- res = atom(src, next(src))
- return res
+def json_eval(source):
+ """Evaluates string as json data and returns Python objects."""
+ if source == '':
+ return source
+
+ src = source.splitlines()[0]
+
+ # Substitutions to enable usage of pythonic syntax.
+ if src.startswith('(') and src.endswith(')'):
+ src = re.sub(r'^\((.*)\)$', r'[\1]', src)
+ elif src.lower() in ('true', 'false'):
+ src = src.lower()
+ elif src.lower() == 'none':
+ src = 'null'
+
+ try:
+ return json.loads(src)
+ except ValueError:
+ return src
class Command(BaseCommand):
@@ -126,10 +94,10 @@ class Command(BaseCommand):
value = pprint.pformat(value, 2, 80)
new_value = []
for line in value.splitlines():
- new_value.append('%s%s' % (color, line))
+ new_value.append(f'{color}{line}')
value = '\n'.join(new_value)
- string += '%s: %s%s\n' % (key, color, value)
+ string += f'{key}: {color}{value}\n'
self.console.write(string.strip())
return client.core.get_config().addCallback(_on_get_config)
@@ -140,8 +108,8 @@ class Command(BaseCommand):
val = ' '.join(options.values)
try:
- val = simple_eval(val)
- except SyntaxError as ex:
+ val = json_eval(val)
+ except Exception as ex:
self.console.write('{!error!}%s' % ex)
return
@@ -161,7 +129,7 @@ class Command(BaseCommand):
def on_set_config(result):
self.console.write('{!success!}Configuration value successfully updated.')
- self.console.write('Setting "%s" to: %s' % (key, val))
+ self.console.write(f'Setting "{key}" to: {val!r}')
return client.core.set_config({key: val}).addCallback(on_set_config)
def complete(self, text):
diff --git a/deluge/ui/console/cmdline/commands/connect.py b/deluge/ui/console/cmdline/commands/connect.py
index 6588f7a..4c76de3 100644
--- a/deluge/ui/console/cmdline/commands/connect.py
+++ b/deluge/ui/console/cmdline/commands/connect.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -57,17 +54,12 @@ class Command(BaseCommand):
def on_connect(result):
if self.console.interactive:
- self.console.write('{!success!}Connected to %s:%s!' % (host, port))
+ self.console.write(f'{{!success!}}Connected to {host}:{port}!')
return component.start()
def on_connect_fail(result):
- try:
- msg = result.value.exception_msg
- except AttributeError:
- msg = result.value.message
self.console.write(
- '{!error!}Failed to connect to %s:%s with reason: %s'
- % (host, port, msg)
+ f'{{!error!}}Failed to connect to {host}:{port} with reason: {result.value.message}'
)
return result
diff --git a/deluge/ui/console/cmdline/commands/debug.py b/deluge/ui/console/cmdline/commands/debug.py
index 3ca06ed..af48a8b 100644
--- a/deluge/ui/console/cmdline/commands/debug.py
+++ b/deluge/ui/console/cmdline/commands/debug.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from twisted.internet import defer
import deluge.component as component
diff --git a/deluge/ui/console/cmdline/commands/gui.py b/deluge/ui/console/cmdline/commands/gui.py
index 10e4c49..575bc9b 100644
--- a/deluge/ui/console/cmdline/commands/gui.py
+++ b/deluge/ui/console/cmdline/commands/gui.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
diff --git a/deluge/ui/console/cmdline/commands/halt.py b/deluge/ui/console/cmdline/commands/halt.py
index 6355958..608f2de 100644
--- a/deluge/ui/console/cmdline/commands/halt.py
+++ b/deluge/ui/console/cmdline/commands/halt.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from deluge.ui.client import client
diff --git a/deluge/ui/console/cmdline/commands/help.py b/deluge/ui/console/cmdline/commands/help.py
index 2711eea..754dadb 100644
--- a/deluge/ui/console/cmdline/commands/help.py
+++ b/deluge/ui/console/cmdline/commands/help.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from twisted.internet import defer
diff --git a/deluge/ui/console/cmdline/commands/info.py b/deluge/ui/console/cmdline/commands/info.py
index 0d22f76..7ea9a67 100644
--- a/deluge/ui/console/cmdline/commands/info.py
+++ b/deluge/ui/console/cmdline/commands/info.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
from os.path import sep as dirsep
import deluge.component as component
@@ -70,6 +67,7 @@ STATUS_KEYS = [
'total_payload_download',
'total_payload_upload',
'time_added',
+ 'label',
]
# Add filter specific state to torrent states
@@ -177,7 +175,7 @@ class Command(BaseCommand):
sort_key = 'name'
sort_reverse = False
for key, value in sorted(
- list(status.items()),
+ status.items(),
key=lambda x: x[1].get(sort_key),
reverse=sort_reverse,
):
@@ -218,9 +216,9 @@ class Command(BaseCommand):
for depth, subdir in enumerate(filepath):
indent = ' ' * depth * spaces_per_level
if depth >= len(prevpath):
- self.console.write('%s{!cyan!}%s' % (indent, subdir))
+ self.console.write(f'{indent}{{!cyan!}}{subdir}')
elif subdir != prevpath[depth]:
- self.console.write('%s{!cyan!}%s' % (indent, subdir))
+ self.console.write(f'{indent}{{!cyan!}}{subdir}')
depth = len(filepath)
@@ -296,7 +294,7 @@ class Command(BaseCommand):
s += peer['ip']
else:
# IPv6
- s += '[%s]:%s' % (
+ s += '[{}]:{}'.format(
':'.join(peer['ip'].split(':')[:-1]),
peer['ip'].split(':')[-1],
)
@@ -308,7 +306,7 @@ class Command(BaseCommand):
s += '\t\t'
else:
s += '\t'
- s += '%s%s\t%s%s' % (
+ s += '{}{}\t{}{}'.format(
colors.state_color['Seeding'],
fspeed(peer['up_speed']),
colors.state_color['Downloading'],
@@ -336,7 +334,7 @@ class Command(BaseCommand):
if verbose or detailed:
self.console.write('{!info!}Name: {!input!}%s' % (status['name']))
self.console.write('{!info!}ID: {!input!}%s' % (torrent_id))
- s = '{!info!}State: %s%s' % (
+ s = '{{!info!}}State: {}{}'.format(
colors.state_color[status['state']],
status['state'],
)
@@ -354,12 +352,12 @@ class Command(BaseCommand):
self.console.write(s)
if status['state'] in ('Seeding', 'Downloading', 'Queued'):
- s = '{!info!}Seeds: {!input!}%s (%s)' % (
+ s = '{{!info!}}Seeds: {{!input!}}{} ({})'.format(
status['num_seeds'],
status['total_seeds'],
)
s += sep
- s += '{!info!}Peers: {!input!}%s (%s)' % (
+ s += '{{!info!}}Peers: {{!input!}}{} ({})'.format(
status['num_peers'],
status['total_peers'],
)
@@ -378,7 +376,7 @@ class Command(BaseCommand):
if total_done == total_size:
s = '{!info!}Size: {!input!}%s' % (total_size)
else:
- s = '{!info!}Size: {!input!}%s/%s' % (total_done, total_size)
+ s = f'{{!info!}}Size: {{!input!}}{total_done}/{total_size}'
s += sep
s += '{!info!}Downloaded: {!input!}%s' % fsize(
status['all_time_download'], shortform=True
@@ -418,14 +416,20 @@ class Command(BaseCommand):
pbar = f_progressbar(
status['progress'], cols - (13 + len('%.2f%%' % status['progress']))
)
- s = '{!info!}Progress: {!input!}%.2f%% %s' % (status['progress'], pbar)
+ s = '{{!info!}}Progress: {{!input!}}{:.2f}% {}'.format(
+ status['progress'], pbar
+ )
self.console.write(s)
s = '{!info!}Download Folder: {!input!}%s' % status['download_location']
- self.console.write(s + '\n')
+ self.console.write(s)
+
+ if 'label' in status:
+ s = '{!info!}Label: {!input!}%s' % status['label']
+ self.console.write(s)
if detailed:
- self.console.write('{!info!}Files in torrent')
+ self.console.write('\n{!info!}Files in torrent')
self.show_file_info(torrent_id, status)
self.console.write('{!info!}Connected peers')
self.show_peer_info(torrent_id, status)
@@ -433,7 +437,7 @@ class Command(BaseCommand):
up_color = colors.state_color['Seeding']
down_color = colors.state_color['Downloading']
- s = '%s%s' % (
+ s = '{}{}'.format(
colors.state_color[status['state']],
'[' + status['state'][0] + ']',
)
@@ -458,7 +462,7 @@ class Command(BaseCommand):
)
if status['download_payload_rate'] > 0:
- dl_info += ' @ %s%s' % (
+ dl_info += ' @ {}{}'.format(
down_color,
fspeed(status['download_payload_rate'], shortform=True),
)
@@ -468,7 +472,7 @@ class Command(BaseCommand):
status['total_uploaded'], status['total_payload_upload']
)
if status['upload_payload_rate'] > 0:
- ul_info += ' @ %s%s' % (
+ ul_info += ' @ {}{}'.format(
up_color,
fspeed(status['upload_payload_rate'], shortform=True),
)
diff --git a/deluge/ui/console/cmdline/commands/manage.py b/deluge/ui/console/cmdline/commands/manage.py
index 6375a74..e5ea9b2 100644
--- a/deluge/ui/console/cmdline/commands/manage.py
+++ b/deluge/ui/console/cmdline/commands/manage.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from twisted.internet import defer
@@ -69,7 +66,7 @@ class Command(BaseCommand):
self.console.write('{!info!}ID: {!input!}%s' % torrentid)
for k, v in data.items():
if k != 'name':
- self.console.write('{!info!}%s: {!input!}%s' % (k, v))
+ self.console.write(f'{{!info!}}{k}: {{!input!}}{v}')
def on_torrents_status_fail(reason):
self.console.write('{!error!}Failed to get torrent data.')
@@ -106,9 +103,7 @@ class Command(BaseCommand):
self.console.write('{!success!}Torrent option successfully updated.')
deferred.callback(True)
- self.console.write(
- 'Setting %s to %s for torrents %s..' % (key, val, torrent_ids)
- )
+ self.console.write(f'Setting {key} to {val} for torrents {torrent_ids}..')
client.core.set_torrent_options(torrent_ids, {key: val}).addCallback(
on_set_config
)
diff --git a/deluge/ui/console/cmdline/commands/move.py b/deluge/ui/console/cmdline/commands/move.py
index 13e475e..67ee0af 100644
--- a/deluge/ui/console/cmdline/commands/move.py
+++ b/deluge/ui/console/cmdline/commands/move.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os.path
@@ -52,7 +49,7 @@ class Command(BaseCommand):
names.append(self.console.get_torrent_name(tid))
def on_move(res):
- msg = 'Moved "%s" to %s' % (', '.join(names), options.path)
+ msg = 'Moved "{}" to {}'.format(', '.join(names), options.path)
self.console.write(msg)
log.info(msg)
diff --git a/deluge/ui/console/cmdline/commands/pause.py b/deluge/ui/console/cmdline/commands/pause.py
index 1f7ef31..1334242 100644
--- a/deluge/ui/console/cmdline/commands/pause.py
+++ b/deluge/ui/console/cmdline/commands/pause.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from deluge.ui.client import client
diff --git a/deluge/ui/console/cmdline/commands/plugin.py b/deluge/ui/console/cmdline/commands/plugin.py
index fafc77a..c424cb2 100644
--- a/deluge/ui/console/cmdline/commands/plugin.py
+++ b/deluge/ui/console/cmdline/commands/plugin.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
import deluge.configmanager
from deluge.ui.client import client
@@ -106,8 +103,8 @@ class Command(BaseCommand):
elif options.install:
import os.path
- from base64 import b64encode
import shutil
+ from base64 import b64encode
filepath = options.install
diff --git a/deluge/ui/console/cmdline/commands/quit.py b/deluge/ui/console/cmdline/commands/quit.py
index 261a01a..4459dfc 100644
--- a/deluge/ui/console/cmdline/commands/quit.py
+++ b/deluge/ui/console/cmdline/commands/quit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from . import BaseCommand
diff --git a/deluge/ui/console/cmdline/commands/recheck.py b/deluge/ui/console/cmdline/commands/recheck.py
index c9b6360..046cb0b 100644
--- a/deluge/ui/console/cmdline/commands/recheck.py
+++ b/deluge/ui/console/cmdline/commands/recheck.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from deluge.ui.client import client
diff --git a/deluge/ui/console/cmdline/commands/resume.py b/deluge/ui/console/cmdline/commands/resume.py
index 1f62c5f..27b8528 100644
--- a/deluge/ui/console/cmdline/commands/resume.py
+++ b/deluge/ui/console/cmdline/commands/resume.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from deluge.ui.client import client
diff --git a/deluge/ui/console/cmdline/commands/rm.py b/deluge/ui/console/cmdline/commands/rm.py
index ff3125d..4a3fd00 100644
--- a/deluge/ui/console/cmdline/commands/rm.py
+++ b/deluge/ui/console/cmdline/commands/rm.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -70,9 +67,11 @@ class Command(BaseCommand):
def on_removed_finished(errors):
if errors:
- self.console.write('Error(s) occured when trying to delete torrent(s).')
+ self.console.write(
+ 'Error(s) occurred when trying to delete torrent(s).'
+ )
for t_id, e_msg in errors:
- self.console.write('Error removing torrent %s : %s' % (t_id, e_msg))
+ self.console.write(f'Error removing torrent {t_id} : {e_msg}')
log.info('Removing %d torrents', len(torrent_ids))
d = client.core.remove_torrents(torrent_ids, options.remove_data)
diff --git a/deluge/ui/console/cmdline/commands/status.py b/deluge/ui/console/cmdline/commands/status.py
index 948ad6b..05c9796 100644
--- a/deluge/ui/console/cmdline/commands/status.py
+++ b/deluge/ui/console/cmdline/commands/status.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from twisted.internet import defer
@@ -65,7 +62,12 @@ class Command(BaseCommand):
deferreds = []
ds = client.core.get_session_status(
- ['num_peers', 'payload_upload_rate', 'payload_download_rate', 'dht_nodes']
+ [
+ 'peer.num_peers_connected',
+ 'payload_upload_rate',
+ 'payload_download_rate',
+ 'dht.dht_nodes',
+ ]
)
ds.addCallback(on_session_status)
deferreds.append(ds)
@@ -95,7 +97,7 @@ class Command(BaseCommand):
'{!info!}Total download: %s'
% fspeed(self.status['payload_download_rate'])
)
- self.console.write('{!info!}DHT Nodes: %i' % self.status['dht_nodes'])
+ self.console.write('{!info!}DHT Nodes: %i' % self.status['dht.dht_nodes'])
if isinstance(self.torrents, int):
if self.torrents == -2:
diff --git a/deluge/ui/console/cmdline/commands/update_tracker.py b/deluge/ui/console/cmdline/commands/update_tracker.py
index 591b951..c05569d 100644
--- a/deluge/ui/console/cmdline/commands/update_tracker.py
+++ b/deluge/ui/console/cmdline/commands/update_tracker.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.component as component
from deluge.ui.client import client
diff --git a/deluge/ui/console/console.py b/deluge/ui/console/console.py
index 58d31d5..8ef87e8 100644
--- a/deluge/ui/console/console.py
+++ b/deluge/ui/console/console.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -7,8 +6,6 @@
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
-from __future__ import print_function, unicode_literals
-
import fnmatch
import logging
import os
@@ -53,7 +50,7 @@ def load_commands(command_dir):
return dict(commands)
-class LogStream(object):
+class LogStream:
out = sys.stdout
def write(self, data):
@@ -68,9 +65,7 @@ class Console(UI):
cmd_description = """Console or command-line user interface"""
def __init__(self, *args, **kwargs):
- super(Console, self).__init__(
- 'console', *args, log_stream=LogStream(), **kwargs
- )
+ super().__init__('console', *args, log_stream=LogStream(), **kwargs)
group = self.parser.add_argument_group(
_('Console Options'),
@@ -112,9 +107,9 @@ class Console(UI):
)
# To properly print help message for the console commands ( e.g. deluge-console info -h),
# we add a subparser for each command which will trigger the help/usage when given
- from deluge.ui.console.parser import (
+ from deluge.ui.console.parser import ( # import here because (see top)
ConsoleCommandParser,
- ) # import here because (see top)
+ )
self.console_parser = ConsoleCommandParser(
parents=[self.parser],
@@ -150,7 +145,7 @@ class Console(UI):
self.console_parser.subcommand = False
self.parser.subcommand = False if i == -1 else True
- super(Console, self).start(self.console_parser)
+ super().start(self.console_parser)
from deluge.ui.console.main import ConsoleUI # import here because (see top)
def run(options):
diff --git a/deluge/ui/console/main.py b/deluge/ui/console/main.py
index 23965bb..31d1db1 100644
--- a/deluge/ui/console/main.py
+++ b/deluge/ui/console/main.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import print_function, unicode_literals
-
import locale
import logging
import os
@@ -67,6 +64,14 @@ DEFAULT_CONSOLE_PREFS = {
}
+class MockConsoleLog:
+ def write(self, data):
+ pass
+
+ def flush(self):
+ pass
+
+
class ConsoleUI(component.Component, TermResizeHandler):
def __init__(self, options, cmds, log_stream):
component.Component.__init__(self, 'ConsoleUI')
@@ -114,6 +119,7 @@ class ConsoleUI(component.Component, TermResizeHandler):
all commands are executed. Else None is returned.
"""
if self.options.parsed_cmds:
+ # Non-Interactive mode
self.interactive = False
if not self._commands:
print('No valid console commands found')
@@ -122,41 +128,37 @@ class ConsoleUI(component.Component, TermResizeHandler):
deferred = self.exec_args(self.options)
reactor.run()
return deferred
- else:
- # Interactive
- if deluge.common.windows_check():
- print(
- """\nDeluge-console does not run in interactive mode on Windows. \n
-Please use commands from the command line, e.g.:\n
- deluge-console.exe help
- deluge-console.exe info
- deluge-console.exe "add --help"
- deluge-console.exe "add -p c:\\mytorrents c:\\new.torrent"
-"""
- )
- else:
- class ConsoleLog(object):
- def write(self, data):
- pass
+ # Interactive
- def flush(self):
- pass
+ # We use the curses.wrapper function to prevent the console from getting
+ # messed up if an uncaught exception is experienced.
+ try:
+ from curses import wrapper
+ except ImportError:
+ wrapper = None
- # We don't ever want log output to terminal when running in
- # interactive mode, so insert a dummy here
- self.log_stream.out = ConsoleLog()
+ if deluge.common.windows_check() and not wrapper:
+ print(
+ """\nDeluge-console does not run in interactive mode on Windows. \n
+Please use commands from the command line, e.g.:\n
+deluge-console.exe help
+deluge-console.exe info
+deluge-console.exe "add --help"
+deluge-console.exe "add -p c:\\mytorrents c:\\new.torrent"
+"""
+ )
- # Set Esc key delay to 0 to avoid a very annoying delay
- # due to curses waiting in case of other key are pressed
- # after ESC is pressed
- os.environ.setdefault('ESCDELAY', '0')
+ # We don't ever want log output to terminal when running in
+ # interactive mode, so insert a dummy here
+ self.log_stream.out = MockConsoleLog()
- # We use the curses.wrapper function to prevent the console from getting
- # messed up if an uncaught exception is experienced.
- from curses import wrapper
+ # Set Esc key delay to 0 to avoid a very annoying delay
+ # due to curses waiting in case of other key are pressed
+ # after ESC is pressed
+ os.environ.setdefault('ESCDELAY', '0')
- wrapper(self.run)
+ wrapper(self.run)
def quit(self):
if client.connected():
@@ -281,7 +283,7 @@ Please use commands from the command line, e.g.:\n
@overrides(TermResizeHandler)
def on_terminal_size(self, *args):
- rows, cols = super(ConsoleUI, self).on_terminal_size(args)
+ rows, cols = super().on_terminal_size(args)
for mode in self.modes:
self.modes[mode].on_resize(rows, cols)
@@ -706,7 +708,7 @@ class EventLog(component.Component):
if not t_name:
return
- self.write('%s: {!info!}%s ({!cyan!}%s{!info!})' % (state, t_name, torrent_id))
+ self.write(f'{state}: {{!info!}}{t_name} ({{!cyan!}}{torrent_id}{{!info!}})')
def on_torrent_finished_event(self, torrent_id):
if component.get('TorrentList').config['ring_bell']:
@@ -734,7 +736,7 @@ class EventLog(component.Component):
except KeyError:
pass
- self.write('ConfigValueChanged: {!input!}%s: %s%s' % (key, color, value))
+ self.write(f'ConfigValueChanged: {{!input!}}{key}: {color}{value}')
def write(self, s):
current_time = time.localtime()
@@ -748,8 +750,6 @@ class EventLog(component.Component):
if date_different:
string = time.strftime(self.date_change_format)
- if deluge.common.PY2:
- string = string.decode()
self.console.write_event(' ')
self.console.write_event(string)
diff --git a/deluge/ui/console/modes/add_util.py b/deluge/ui/console/modes/add_util.py
index 88a24d0..9d29a1f 100644
--- a/deluge/ui/console/modes/add_util.py
+++ b/deluge/ui/console/modes/add_util.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -9,15 +8,11 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import glob
import logging
import os
from base64 import b64encode
-from six import unichr as chr
-
import deluge.common
from deluge.ui.client import client
from deluge.ui.common import TorrentInfo
diff --git a/deluge/ui/console/modes/addtorrents.py b/deluge/ui/console/modes/addtorrents.py
index 6b2c105..217b63d 100644
--- a/deluge/ui/console/modes/addtorrents.py
+++ b/deluge/ui/console/modes/addtorrents.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2012 Arek Stefański <asmageddon@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
from base64 import b64encode
@@ -24,12 +21,6 @@ from deluge.ui.console.utils import format_utils
from deluge.ui.console.widgets.popup import InputPopup, MessagePopup
try:
- from future_builtins import zip
-except ImportError:
- # Ignore on Py3.
- pass
-
-try:
import curses
except ImportError:
pass
@@ -377,7 +368,7 @@ class AddTorrents(BaseMode):
def fail_cb(msg, t_file, ress):
log.debug('failed to add torrent: %s: %s', t_file, msg)
ress['fail'] += 1
- ress['fmsg'].append('{!input!} * %s: {!error!}%s' % (t_file, msg))
+ ress['fmsg'].append(f'{{!input!}} * {t_file}: {{!error!}}{msg}')
if (ress['succ'] + ress['fail']) >= ress['total']:
report_add_status(
component.get('TorrentList'),
@@ -526,9 +517,9 @@ class AddTorrents(BaseMode):
self.last_mark = self.cursel
elif chr(c) == 'j':
- self.scroll_list_up(1)
- elif chr(c) == 'k':
self.scroll_list_down(1)
+ elif chr(c) == 'k':
+ self.scroll_list_up(1)
elif chr(c) == 'M':
if self.last_mark != -1:
if self.last_mark > self.cursel:
diff --git a/deluge/ui/console/modes/basemode.py b/deluge/ui/console/modes/basemode.py
index dd3681f..5ebaf86 100644
--- a/deluge/ui/console/modes/basemode.py
+++ b/deluge/ui/console/modes/basemode.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import sys
@@ -26,9 +23,9 @@ except ImportError:
try:
import signal
- from fcntl import ioctl
- import termios
import struct
+ import termios
+ from fcntl import ioctl
except ImportError:
pass
@@ -36,7 +33,7 @@ except ImportError:
log = logging.getLogger(__name__)
-class InputKeyHandler(object):
+class InputKeyHandler:
def __init__(self):
self._input_result = None
@@ -62,12 +59,14 @@ class InputKeyHandler(object):
return util.ReadState.IGNORED
-class TermResizeHandler(object):
+class TermResizeHandler:
def __init__(self):
try:
signal.signal(signal.SIGWINCH, self.on_terminal_size)
except ValueError as ex:
- log.debug('Unable to catch SIGWINCH signal: %s', ex)
+ log.debug('TermResize unavailable, unable to catch SIGWINCH signal: %s', ex)
+ except AttributeError as ex:
+ log.debug('TermResize unavailable, no SIGWINCH signal on Windows: %s', ex)
def on_terminal_size(self, *args):
# Get the new rows and cols value
@@ -78,14 +77,14 @@ class TermResizeHandler(object):
return rows, cols
-class CursesStdIO(object):
+class CursesStdIO:
"""
fake fd to be registered as a reader with the twisted reactor.
Curses classes needing input should extend this
"""
def fileno(self):
- """ We want to select on FD 0 """
+ """We want to select on FD 0"""
return 0
def doRead(self): # NOQA: N802
diff --git a/deluge/ui/console/modes/cmdline.py b/deluge/ui/console/modes/cmdline.py
index 2735168..7b0ff2d 100644
--- a/deluge/ui/console/modes/cmdline.py
+++ b/deluge/ui/console/modes/cmdline.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
@@ -8,16 +7,12 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
import re
-from io import open
import deluge.component as component
import deluge.configmanager
-from deluge.common import PY2
from deluge.decorators import overrides
from deluge.ui.console.cmdline.command import Commander
from deluge.ui.console.modes.basemode import BaseMode, move_cursor
@@ -139,18 +134,18 @@ class CmdLine(BaseMode, Commander):
self._hf_lines = [0, 0]
if self.console_config['cmdline']['save_command_history']:
try:
- with open(self.history_file[0], 'r', encoding='utf8') as _file:
+ with open(self.history_file[0], encoding='utf8') as _file:
lines1 = _file.read().splitlines()
self._hf_lines[0] = len(lines1)
- except IOError:
+ except OSError:
lines1 = []
self._hf_lines[0] = 0
try:
- with open(self.history_file[1], 'r', encoding='utf8') as _file:
+ with open(self.history_file[1], encoding='utf8') as _file:
lines2 = _file.read().splitlines()
self._hf_lines[1] = len(lines2)
- except IOError:
+ except OSError:
lines2 = []
self._hf_lines[1] = 0
@@ -332,10 +327,10 @@ class CmdLine(BaseMode, Commander):
# A key to add to the input string
else:
- if c > 31 and c < 256:
+ if 31 < c < 256:
# Emulate getwch
stroke = chr(c)
- uchar = '' if PY2 else stroke
+ uchar = stroke
while not uchar:
try:
uchar = stroke.decode(self.encoding)
@@ -826,21 +821,21 @@ class CmdLine(BaseMode, Commander):
# Let's avoid listing all torrents twice if there's no pattern
if not empty and torrent_id.startswith(line):
# Highlight the matching part
- text = '{!info!}%s{!input!}%s - "%s"' % (
+ text = '{{!info!}}{}{{!input!}}{} - "{}"'.format(
torrent_id[:line_len],
torrent_id[line_len:],
torrent_name,
)
possible_matches.append(text)
if torrent_name.startswith(line):
- text = '{!info!}%s{!input!}%s ({!cyan!}%s{!input!})' % (
+ text = '{{!info!}}{}{{!input!}}{} ({{!cyan!}}{}{{!input!}})'.format(
escaped_name[:line_len],
escaped_name[line_len:],
torrent_id,
)
possible_matches.append(text)
elif torrent_name.lower().startswith(line.lower()):
- text = '{!info!}%s{!input!}%s ({!cyan!}%s{!input!})' % (
+ text = '{{!info!}}{}{{!input!}}{} ({{!cyan!}}{}{{!input!}})'.format(
escaped_name[:line_len],
escaped_name[line_len:],
torrent_id,
diff --git a/deluge/ui/console/modes/connectionmanager.py b/deluge/ui/console/modes/connectionmanager.py
index 84a3fbc..0ccdd93 100644
--- a/deluge/ui/console/modes/connectionmanager.py
+++ b/deluge/ui/console/modes/connectionmanager.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -32,11 +29,13 @@ class ConnectionManager(BaseMode, PopupsHandler):
self.statuses = {}
self.all_torrents = None
self.hostlist = HostList()
- self.update_hosts_status()
BaseMode.__init__(self, stdscr, encoding=encoding)
- self.update_select_host_popup()
def update_select_host_popup(self):
+ if self.popup and not isinstance(self.popup, SelectablePopup):
+ # Ignore MessagePopup on popup stack upon connect fail
+ return
+
selected_index = self.popup.current_selection() if self.popup else None
popup = SelectablePopup(
@@ -51,32 +50,33 @@ class ConnectionManager(BaseMode, PopupsHandler):
% (_('Quit'), _('Add Host'), _('Delete Host')),
space_below=True,
)
- self.push_popup(popup, clear=True)
for host_entry in self.hostlist.get_hosts_info():
host_id, hostname, port, user = host_entry
- args = {'data': host_id, 'foreground': 'red'}
- state = 'Offline'
- if host_id in self.statuses:
- state = 'Online'
- args.update({'data': self.statuses[host_id], 'foreground': 'green'})
- host_str = '%s:%d [%s]' % (hostname, port, state)
- self.popup.add_line(
+ host_status = self.statuses.get(host_id)
+
+ state = host_status[1] if host_status else 'Offline'
+ state_color = 'green' if state in ('Online', 'Connected') else 'red'
+ host_str = f'{hostname}:{port} [{state}]'
+
+ args = {'data': host_id, 'foreground': state_color}
+ popup.add_line(
host_id, host_str, selectable=True, use_underline=True, **args
)
if selected_index:
- self.popup.set_selection(selected_index)
+ popup.set_selection(selected_index)
+
+ self.push_popup(popup, clear=True)
self.inlist = True
self.refresh()
def update_hosts_status(self):
- for host_entry in self.hostlist.get_hosts_info():
-
- def on_host_status(status_info):
- self.statuses[status_info[0]] = status_info
- self.update_select_host_popup()
+ def on_host_status(status_info):
+ self.statuses[status_info[0]] = status_info
+ self.update_select_host_popup()
+ for host_entry in self.hostlist.get_hosts_info():
self.hostlist.get_host_status(host_entry[0]).addCallback(on_host_status)
def _on_connected(self, result):
@@ -87,7 +87,7 @@ class ConnectionManager(BaseMode, PopupsHandler):
d.addCallback(on_console_start)
def _on_connect_fail(self, result):
- self.report_message('Failed to connect!', result)
+ self.report_message('Failed to connect!', result.getErrorMessage())
self.refresh()
if hasattr(result, 'getTraceback'):
log.exception(result)
@@ -130,7 +130,7 @@ class ConnectionManager(BaseMode, PopupsHandler):
try:
self.hostlist.add_host(hostname, port, username, password)
except ValueError as ex:
- self.report_message(_('Error adding host'), '%s: %s' % (hostname, ex))
+ self.report_message(_('Error adding host'), f'{hostname}: {ex}')
else:
self.update_select_host_popup()
@@ -169,7 +169,9 @@ class ConnectionManager(BaseMode, PopupsHandler):
if not self.popup:
self.update_select_host_popup()
- self.popup.refresh()
+ if self.popup:
+ self.popup.refresh()
+
curses.doupdate()
@overrides(BaseMode)
diff --git a/deluge/ui/console/modes/eventview.py b/deluge/ui/console/modes/eventview.py
index cd3308c..b6e63b0 100644
--- a/deluge/ui/console/modes/eventview.py
+++ b/deluge/ui/console/modes/eventview.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -100,9 +97,9 @@ class EventView(BaseMode):
elif c == curses.KEY_END:
self.offset += num_events
elif c == ord('j'):
- self.offset -= 1
- elif c == ord('k'):
self.offset += 1
+ elif c == ord('k'):
+ self.offset -= 1
if self.offset <= 0:
self.offset = 0
diff --git a/deluge/ui/console/modes/preferences/__init__.py b/deluge/ui/console/modes/preferences/__init__.py
index 15d77c4..e827d91 100644
--- a/deluge/ui/console/modes/preferences/__init__.py
+++ b/deluge/ui/console/modes/preferences/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import unicode_literals
-
from deluge.ui.console.modes.preferences.preferences import Preferences
__all__ = ['Preferences']
diff --git a/deluge/ui/console/modes/preferences/preference_panes.py b/deluge/ui/console/modes/preferences/preference_panes.py
index 62029a6..b47bc4b 100644
--- a/deluge/ui/console/modes/preferences/preference_panes.py
+++ b/deluge/ui/console/modes/preferences/preference_panes.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,11 +6,9 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
-from deluge.common import is_ip
+from deluge.common import is_interface
from deluge.decorators import overrides
from deluge.i18n import get_languages
from deluge.ui.client import client
@@ -94,11 +91,12 @@ class BasePreferencePane(BaseInputPane, BaseWindow, PopupsHandler):
)
elif ipt.name == 'listen_interface':
listen_interface = ipt.get_value().strip()
- if is_ip(listen_interface) or not listen_interface:
+ if is_interface(listen_interface) or not listen_interface:
conf_dict['listen_interface'] = listen_interface
elif ipt.name == 'outgoing_interface':
outgoing_interface = ipt.get_value().strip()
- conf_dict['outgoing_interface'] = outgoing_interface
+ if is_interface(outgoing_interface) or not outgoing_interface:
+ conf_dict['outgoing_interface'] = outgoing_interface
elif ipt.name.startswith('proxy_'):
if ipt.name == 'proxy_type':
conf_dict.setdefault('proxy', {})['type'] = ipt.get_value()
@@ -724,11 +722,6 @@ class CachePane(BasePreferencePane):
self.add_info_field(
'blocks_read', ' %s:' % _('Blocks Read'), status['disk.num_blocks_read']
)
- self.add_info_field(
- 'blocks_read_hit',
- ' %s:' % _('Blocks Read hit'),
- status['disk.num_blocks_cache_hits'],
- )
self.add_info_field('reads', ' %s:' % _('Reads'), status['disk.num_read_ops'])
self.add_info_field(
'read_hit_ratio',
diff --git a/deluge/ui/console/modes/preferences/preferences.py b/deluge/ui/console/modes/preferences/preferences.py
index 45a39a6..2c95323 100644
--- a/deluge/ui/console/modes/preferences/preferences.py
+++ b/deluge/ui/console/modes/preferences/preferences.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from collections import deque
@@ -74,7 +71,7 @@ arrow to edit the other value, and escape to get back to the check box.
"""
-class ZONE(object):
+class ZONE:
length = 3
CATEGORIES, PREFRENCES, ACTIONS = list(range(length))
diff --git a/deluge/ui/console/modes/torrentdetail.py b/deluge/ui/console/modes/torrentdetail.py
index d02a0d3..16bd08a 100644
--- a/deluge/ui/console/modes/torrentdetail.py
+++ b/deluge/ui/console/modes/torrentdetail.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
import logging
import deluge.component as component
@@ -220,7 +217,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
self.refresh()
def build_file_list(self, torrent_files, progress, priority):
- """ Split file list from torrent state into a directory tree.
+ """Split file list from torrent state into a directory tree.
Returns:
@@ -425,9 +422,9 @@ class TorrentDetail(BaseMode, PopupsHandler):
attr = 'bold'
if attr:
- color_string = '{!%s,%s,%s!}' % (fg, bg, attr)
+ color_string = f'{{!{fg},{bg},{attr}!}}'
else:
- color_string = '{!%s,%s!}' % (fg, bg)
+ color_string = f'{{!{fg},{bg}!}}'
# actually draw the dir/file string
if fl[3] and fl[4]: # this is an expanded directory
@@ -439,7 +436,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
r = format_row(
[
- '%s%s %s' % (' ' * depth, xchar, fl[0]),
+ '{}{} {}'.format(' ' * depth, xchar, fl[0]),
fsize(fl[2]),
fl[5],
format_priority(fl[6]),
@@ -447,7 +444,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
self.column_widths,
)
- self.add_string(off, '%s%s' % (color_string, r), trim=False)
+ self.add_string(off, f'{color_string}{r}', trim=False)
off += 1
if fl[3] and fl[4]:
@@ -502,7 +499,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
download_color = colors.state_color['Downloading']
def add_field(name, row, pre_color='{!info!}', post_color='{!input!}'):
- s = '%s%s: %s%s' % (
+ s = '{}{}: {}{}'.format(
pre_color,
torrent_data_fields[name]['name'],
post_color,
@@ -523,7 +520,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
if status['progress'] != 100.0:
s += '/%s' % fsize(status['total_wanted'])
if status['download_payload_rate'] > 0:
- s += ' {!yellow!}@ %s%s' % (
+ s += ' {{!yellow!}}@ {}{}'.format(
download_color,
fsize(status['download_payload_rate']),
)
@@ -534,7 +531,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
# Print UL info and ratio
s = add_field('uploaded', 0, download_color)
if status['upload_payload_rate'] > 0:
- s += ' {!yellow!}@ %s%s' % (
+ s += ' {{!yellow!}}@ {}{}'.format(
colors.state_color['Seeding'],
fsize(status['upload_payload_rate']),
)
@@ -542,13 +539,13 @@ class TorrentDetail(BaseMode, PopupsHandler):
row = self.add_string(row, s)
# Seed/peer info
- s = '{!info!}%s:{!green!} %s {!input!}(%s)' % (
+ s = '{{!info!}}{}:{{!green!}} {} {{!input!}}({})'.format(
torrent_data_fields['seeds']['name'],
status['num_seeds'],
status['total_seeds'],
)
row = self.add_string(row, s)
- s = '{!info!}%s:{!red!} %s {!input!}(%s)' % (
+ s = '{{!info!}}{}:{{!red!}} {} {{!input!}}({})'.format(
torrent_data_fields['peers']['name'],
status['num_peers'],
status['total_peers'],
@@ -557,7 +554,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
# Tracker
tracker_color = '{!green!}' if status['message'] == 'OK' else '{!red!}'
- s = '{!info!}%s: {!magenta!}%s{!input!} says "%s%s{!input!}"' % (
+ s = '{{!info!}}{}: {{!magenta!}}{}{{!input!}} says "{}{}{{!input!}}"'.format(
torrent_data_fields['tracker']['name'],
status['tracker_host'],
tracker_color,
@@ -566,13 +563,13 @@ class TorrentDetail(BaseMode, PopupsHandler):
row = self.add_string(row, s)
# Pieces and availability
- s = '{!info!}%s: {!yellow!}%s {!input!}x {!yellow!}%s' % (
+ s = '{{!info!}}{}: {{!yellow!}}{} {{!input!}}x {{!yellow!}}{}'.format(
torrent_data_fields['pieces']['name'],
status['num_pieces'],
fsize(status['piece_length']),
)
if status['distributed_copies']:
- s += '{!info!}%s: {!input!}%s' % (
+ s += '{{!info!}}{}: {{!input!}}{}'.format(
torrent_data_fields['seed_rank']['name'],
status['seed_rank'],
)
@@ -710,7 +707,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
'skip_priority',
'_Skip',
foreground='red',
- cb_arg=FILE_PRIORITY['Low'],
+ cb_arg=FILE_PRIORITY['Skip'],
was_empty=was_empty,
)
popup.add_line(
@@ -878,7 +875,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
idx += 1
continue
if num == idx:
- return '%s%s/' % (path, element[0])
+ return f'{path}{element[0]}/'
if element[4]:
i = self._get_full_folder_path(
num, element[3], path + element[0] + '/', idx + 1
@@ -923,7 +920,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
self.popup.close(None, call_cb=False)
return
old_fname = self._get_full_folder_path(self.current_file_idx)
- new_fname = '%s/%s/' % (
+ new_fname = '{}/{}/'.format(
old_fname.strip('/').rpartition('/')[0],
result['new_foldername']['value'],
)
@@ -949,7 +946,7 @@ class TorrentDetail(BaseMode, PopupsHandler):
):
self.popup.close(None, call_cb=False)
return
- fname = '%s/%s' % (
+ fname = '{}/{}'.format(
self.full_names[idx].rpartition('/')[0],
result['new_filename']['value'],
)
@@ -1019,8 +1016,8 @@ class TorrentDetail(BaseMode, PopupsHandler):
elif c == ord('h'):
self.push_popup(MessagePopup(self, 'Help', HELP_STR, width_req=0.75))
elif c == ord('j'):
- self.file_list_up()
- elif c == ord('k'):
self.file_list_down()
+ elif c == ord('k'):
+ self.file_list_up()
self.refresh()
diff --git a/deluge/ui/console/modes/torrentlist/__init__.py b/deluge/ui/console/modes/torrentlist/__init__.py
index 18c4db3..48c60ce 100644
--- a/deluge/ui/console/modes/torrentlist/__init__.py
+++ b/deluge/ui/console/modes/torrentlist/__init__.py
@@ -1,7 +1,4 @@
-from __future__ import unicode_literals
-
-
-class ACTION(object):
+class ACTION:
PAUSE = 'pause'
RESUME = 'resume'
REANNOUNCE = 'update_tracker'
diff --git a/deluge/ui/console/modes/torrentlist/add_torrents_popup.py b/deluge/ui/console/modes/torrentlist/add_torrents_popup.py
index b0ac483..3ff9ab7 100644
--- a/deluge/ui/console/modes/torrentlist/add_torrents_popup.py
+++ b/deluge/ui/console/modes/torrentlist/add_torrents_popup.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.common
@@ -40,7 +37,7 @@ def show_torrent_add_popup(torrentlist):
def fail_cb(msg, url):
log.debug('failed to add torrent: %s: %s', url, msg)
- error_msg = '{!input!} * %s: {!error!}%s' % (url, msg)
+ error_msg = f'{{!input!}} * {url}: {{!error!}}{msg}'
report_add_status(torrentlist, 0, 1, [error_msg])
def success_cb(tid, url):
diff --git a/deluge/ui/console/modes/torrentlist/filtersidebar.py b/deluge/ui/console/modes/torrentlist/filtersidebar.py
index 0f39b5c..982e245 100644
--- a/deluge/ui/console/modes/torrentlist/filtersidebar.py
+++ b/deluge/ui/console/modes/torrentlist/filtersidebar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 bendikro <bro.devel+deluge@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import curses
import logging
diff --git a/deluge/ui/console/modes/torrentlist/queue_mode.py b/deluge/ui/console/modes/torrentlist/queue_mode.py
index 0c44aaf..33af013 100644
--- a/deluge/ui/console/modes/torrentlist/queue_mode.py
+++ b/deluge/ui/console/modes/torrentlist/queue_mode.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from deluge.ui.client import client
from deluge.ui.console.utils import curses_util as util
from deluge.ui.console.widgets.popup import MessagePopup, SelectablePopup
@@ -38,7 +35,7 @@ Change queue position of selected torrents
"""
-class QueueMode(object):
+class QueueMode:
def __init__(self, torrentslist, torrent_ids):
self.torrentslist = torrentslist
self.torrentview = torrentslist.torrentview
diff --git a/deluge/ui/console/modes/torrentlist/search_mode.py b/deluge/ui/console/modes/torrentlist/search_mode.py
index 57a8e5f..6f79628 100644
--- a/deluge/ui/console/modes/torrentlist/search_mode.py
+++ b/deluge/ui/console/modes/torrentlist/search_mode.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,11 +6,8 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
-from deluge.common import PY2
from deluge.decorators import overrides
from deluge.ui.console.modes.basemode import InputKeyHandler, move_cursor
from deluge.ui.console.modes.torrentlist.torrentactions import torrent_actions_popup
@@ -49,7 +45,7 @@ SEARCH_FORMAT = {
class SearchMode(InputKeyHandler):
def __init__(self, torrentlist):
- super(SearchMode, self).__init__()
+ super().__init__()
self.torrentlist = torrentlist
self.torrentview = torrentlist.torrentview
self.search_state = SEARCH_EMPTY
@@ -176,7 +172,7 @@ class SearchMode(InputKeyHandler):
elif c > 31 and c < 256:
old_search_string = self.search_string
stroke = chr(c)
- uchar = '' if PY2 else stroke
+ uchar = stroke
while not uchar:
try:
uchar = stroke.decode(self.torrentlist.encoding)
diff --git a/deluge/ui/console/modes/torrentlist/torrentactions.py b/deluge/ui/console/modes/torrentlist/torrentactions.py
index f3cd395..6450118 100644
--- a/deluge/ui/console/modes/torrentlist/torrentactions.py
+++ b/deluge/ui/console/modes/torrentlist/torrentactions.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
@@ -46,7 +43,7 @@ def action_remove(mode=None, torrent_ids=None, **kwargs):
if errors:
error_msgs = ''
for t_id, e_msg in errors:
- error_msgs += 'Error removing torrent %s : %s\n' % (t_id, e_msg)
+ error_msgs += f'Error removing torrent {t_id} : {e_msg}\n'
mode.report_message(
'Error(s) occured when trying to delete torrent(s).', error_msgs
)
@@ -77,7 +74,7 @@ def action_remove(mode=None, torrent_ids=None, **kwargs):
show_max = 6
for i, (name, state) in enumerate(status):
color = colors.state_color[state]
- rem_msg += '\n %s* {!input!}%s' % (color, name)
+ rem_msg += f'\n {color}* {{!input!}}{name}'
if i == show_max - 1:
if i < len(status) - 1:
rem_msg += '\n {!red!}And %i more' % (len(status) - show_max)
diff --git a/deluge/ui/console/modes/torrentlist/torrentlist.py b/deluge/ui/console/modes/torrentlist/torrentlist.py
index a427d65..d3c32ec 100644
--- a/deluge/ui/console/modes/torrentlist/torrentlist.py
+++ b/deluge/ui/console/modes/torrentlist/torrentlist.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from collections import deque
@@ -179,7 +176,7 @@ class TorrentList(BaseMode, PopupsHandler):
@overrides(BaseMode)
def resume(self):
- super(TorrentList, self).resume()
+ super().resume()
@overrides(BaseMode)
def on_resize(self, rows, cols):
@@ -222,7 +219,9 @@ class TorrentList(BaseMode, PopupsHandler):
# Update the status bars
statusbar_args = {'scr': self.stdscr, 'bottombar_help': True}
if self.torrentview.curr_filter is not None:
- statusbar_args['topbar'] = '%s {!filterstatus!}Current filter: %s' % (
+ statusbar_args[
+ 'topbar'
+ ] = '{} {{!filterstatus!}}Current filter: {}'.format(
self.statusbars.topbar,
self.torrentview.curr_filter,
)
diff --git a/deluge/ui/console/modes/torrentlist/torrentview.py b/deluge/ui/console/modes/torrentlist/torrentview.py
index 67de3e7..1ce5097 100644
--- a/deluge/ui/console/modes/torrentlist/torrentview.py
+++ b/deluge/ui/console/modes/torrentlist/torrentview.py
@@ -1,12 +1,9 @@
-# -*- coding: utf-8 -*-
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -90,7 +87,7 @@ for col_i, col_name in enumerate(torrentviewcolumns.column_pref_names):
class TorrentView(InputKeyHandler):
def __init__(self, torrentlist, config):
- super(TorrentView, self).__init__()
+ super().__init__()
self.torrentlist = torrentlist
self.config = config
self.filter_dict = {}
@@ -331,7 +328,7 @@ class TorrentView(InputKeyHandler):
self.torrentlist.add_string(
currow + self.torrentlist_offset,
- '%s%s' % (colorstr, row[0]),
+ f'{colorstr}{row[0]}',
trim=False,
scr=self.torrentlist.torrentview_panel,
)
@@ -467,9 +464,9 @@ class TorrentView(InputKeyHandler):
)
self.torrentlist.refresh()
elif c == ord('j'):
- affected_lines = self._scroll_up(1)
- elif c == ord('k'):
affected_lines = self._scroll_down(1)
+ elif c == ord('k'):
+ affected_lines = self._scroll_up(1)
elif c == ord('m'):
self.mark_unmark(self.cursel)
affected_lines = [self.cursel]
diff --git a/deluge/ui/console/modes/torrentlist/torrentviewcolumns.py b/deluge/ui/console/modes/torrentlist/torrentviewcolumns.py
index 9dff843..586a569 100644
--- a/deluge/ui/console/modes/torrentlist/torrentviewcolumns.py
+++ b/deluge/ui/console/modes/torrentlist/torrentviewcolumns.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 bendikro <bro.devel+deluge@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from deluge.decorators import overrides
from deluge.ui.console.utils import curses_util as util
from deluge.ui.console.utils.column import torrent_data_fields
diff --git a/deluge/ui/console/parser.py b/deluge/ui/console/parser.py
index 27f2485..c0686b1 100644
--- a/deluge/ui/console/parser.py
+++ b/deluge/ui/console/parser.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 bendikro <bro.devel+deluge@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import print_function, unicode_literals
-
import argparse
import shlex
@@ -23,13 +20,13 @@ class OptionParserError(Exception):
class ConsoleBaseParser(argparse.ArgumentParser):
def format_help(self):
"""Differs from ArgumentParser.format_help by adding the raw epilog
- as formatted in the string. Default bahavior mangles the formatting.
+ as formatted in the string. Default behavior mangles the formatting.
"""
# Handle epilog manually to keep the text formatting
epilog = self.epilog
self.epilog = ''
- help_str = super(ConsoleBaseParser, self).format_help()
+ help_str = super().format_help()
if epilog is not None:
help_str += epilog
self.epilog = epilog
@@ -51,7 +48,7 @@ class ConsoleCommandParser(ConsoleBaseParser):
for cmd_line in cmd_lines:
cmds = shlex.split(cmd_line)
- cmd_options = super(ConsoleCommandParser, self).parse_args(args=cmds)
+ cmd_options = super().parse_args(args=cmds)
cmd_options.command = cmds[0]
command_options.append(cmd_options)
@@ -60,14 +57,14 @@ class ConsoleCommandParser(ConsoleBaseParser):
def parse_args(self, args=None):
"""Parse known UI args and handle common and process group options.
- Notes:
- If started by deluge entry script this has already been done.
+ Notes:
+ If started by deluge entry script this has already been done.
- Args:
- args (list, optional): The arguments to parse.
+ Args:
+ args (list, optional): The arguments to parse.
- Returns:
- argparse.Namespace: The parsed arguments.
+ Returns:
+ argparse.Namespace: The parsed arguments.
"""
from deluge.ui.ui_entry import AMBIGUOUS_CMD_ARGS
@@ -96,7 +93,7 @@ class ConsoleCommandParser(ConsoleBaseParser):
options = self.base_parser.parse_args(args=args)
options.parsed_cmds = []
else:
- options = super(ConsoleCommandParser, self).parse_args(args=args)
+ options = super().parse_args(args=args)
options.parsed_cmds = [options]
if not hasattr(options, 'remaining'):
@@ -107,7 +104,7 @@ class ConsoleCommandParser(ConsoleBaseParser):
class OptionParser(ConsoleBaseParser):
def __init__(self, **kwargs):
- super(OptionParser, self).__init__(**kwargs)
+ super().__init__(**kwargs)
self.formatter = ConsoleColorFormatter()
def exit(self, status=0, msg=None):
@@ -118,9 +115,9 @@ class OptionParser(ConsoleBaseParser):
def error(self, msg):
"""error(msg : string)
- Print a usage message incorporating 'msg' to stderr and exit.
- If you override this in a subclass, it should not return -- it
- should either exit or raise an exception.
+ Print a usage message incorporating 'msg' to stderr and exit.
+ If you override this in a subclass, it should not return -- it
+ should either exit or raise an exception.
"""
raise OptionParserError(msg)
@@ -139,5 +136,5 @@ class OptionParser(ConsoleBaseParser):
def format_help(self):
"""Return help formatted with colors."""
- help_str = super(OptionParser, self).format_help()
+ help_str = super().format_help()
return self.formatter.format_colors(help_str)
diff --git a/deluge/ui/console/utils/colors.py b/deluge/ui/console/utils/colors.py
index 587c1f3..cc414fe 100644
--- a/deluge/ui/console/utils/colors.py
+++ b/deluge/ui/console/utils/colors.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import re
@@ -91,8 +88,8 @@ def init_colors():
curses.init_pair(counter, fg, bg)
color_pairs[(fg_name, bg_name)] = counter
counter += 1
- except curses.error as ex:
- log.warning('Error: %s', ex)
+ except (curses.error, ValueError) as ex:
+ log.debug(f'Color pair {fg_name} {bg_name} not available: {ex}')
return counter
# Create the color_pairs dict
@@ -271,7 +268,7 @@ def parse_color_string(string):
last_color_attr = color_pair
attrs = attrs[2:] # Remove colors
except KeyError:
- raise BadColorString('Bad color value in tag: %s,%s' % (fg, bg))
+ raise BadColorString(f'Bad color value in tag: {fg},{bg}')
# Check for additional attributes and OR them to the color_pair
color_pair = apply_attrs(color_pair, attrs)
last_color_attr = color_pair
@@ -292,7 +289,7 @@ def parse_color_string(string):
return ret
-class ConsoleColorFormatter(object):
+class ConsoleColorFormatter:
"""
Format help in a way suited to deluge CmdLine mode - colors, format, indentation...
"""
diff --git a/deluge/ui/console/utils/column.py b/deluge/ui/console/utils/column.py
index d932159..ecbe04b 100644
--- a/deluge/ui/console/utils/column.py
+++ b/deluge/ui/console/utils/column.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import copy
import logging
diff --git a/deluge/ui/console/utils/common.py b/deluge/ui/console/utils/common.py
index df1c079..fdc88c4 100644
--- a/deluge/ui/console/utils/common.py
+++ b/deluge/ui/console/utils/common.py
@@ -1,12 +1,9 @@
-# -*- coding: utf-8 -*-
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
TORRENT_OPTIONS = {
'max_download_speed': float,
'max_upload_speed': float,
diff --git a/deluge/ui/console/utils/curses_util.py b/deluge/ui/console/utils/curses_util.py
index a0cd6dc..50b0444 100644
--- a/deluge/ui/console/utils/curses_util.py
+++ b/deluge/ui/console/utils/curses_util.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 bendikro <bro.devel+deluge@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
try:
import curses
except ImportError:
@@ -39,7 +36,7 @@ def is_int_chr(c):
return c > 47 and c < 58
-class Curser(object):
+class Curser:
INVISIBLE = 0
NORMAL = 1
VERY_VISIBLE = 2
@@ -59,7 +56,7 @@ def safe_curs_set(visibility):
pass
-class ReadState(object):
+class ReadState:
IGNORED = 0
READ = 1
CHANGED = 2
diff --git a/deluge/ui/console/utils/format_utils.py b/deluge/ui/console/utils/format_utils.py
index 029fb20..50ec191 100644
--- a/deluge/ui/console/utils/format_utils.py
+++ b/deluge/ui/console/utils/format_utils.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import re
from collections import deque
from unicodedata import east_asian_width, normalize
@@ -98,7 +95,7 @@ def f_seedrank_dash(seed_rank, seeding_time):
def ftotal_sized(first, second):
- return '%s (%s)' % (
+ return '{} ({})'.format(
deluge.common.fsize(first, shortform=True),
deluge.common.fsize(second, shortform=True),
)
@@ -159,7 +156,7 @@ def format_column(col, lim):
if size >= lim - 1:
return trim_string(col, lim, dbls > 0)
else:
- return '%s%s' % (col, ' ' * (lim - size))
+ return '{}{}'.format(col, ' ' * (lim - size))
def format_row(row, column_widths):
@@ -213,7 +210,7 @@ def wrap_string(string, width, min_lines=0, strip_colors=True):
mtc = mtchs.popleft() - offset
clr = clrs.popleft()
end_pos += len(clr)
- s = '%s%s%s' % (s[:mtc], clr, s[mtc:])
+ s = f'{s[:mtc]}{clr}{s[mtc:]}'
return s
for s in s1:
@@ -238,11 +235,11 @@ def wrap_string(string, width, min_lines=0, strip_colors=True):
else:
cstr = s
- def append_indent(l, string, offset):
+ def append_indent(line, string, offset):
"""Prepends indent to string if specified"""
if indent and offset != 0:
string = indent + string
- l.append(string)
+ line.append(string)
while cstr:
# max with for a line. If indent is specified, we account for this
@@ -290,7 +287,7 @@ def wrap_string(string, width, min_lines=0, strip_colors=True):
last_color_string = ''
for i, line in enumerate(ret):
if i != 0:
- ret[i] = '%s%s' % (last_color_string, ret[i])
+ ret[i] = f'{last_color_string}{ret[i]}'
colors = re.findall('\\{![^!]+!\\}', line)
if colors:
@@ -313,9 +310,9 @@ def pad_string(string, length, character=' ', side='right'):
w = strwidth(string)
diff = length - w
if side == 'left':
- return '%s%s' % (character * diff, string)
+ return f'{character * diff}{string}'
elif side == 'right':
- return '%s%s' % (string, character * diff)
+ return f'{string}{character * diff}'
def delete_alt_backspace(input_text, input_cursor, sep_chars=' *?!._~-#$^;\'"/'):
diff --git a/deluge/ui/console/widgets/__init__.py b/deluge/ui/console/widgets/__init__.py
index a11e3f2..bc88a3b 100644
--- a/deluge/ui/console/widgets/__init__.py
+++ b/deluge/ui/console/widgets/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import unicode_literals
-
from deluge.ui.console.widgets.inputpane import BaseInputPane
from deluge.ui.console.widgets.statusbars import StatusBars
from deluge.ui.console.widgets.window import BaseWindow
diff --git a/deluge/ui/console/widgets/fields.py b/deluge/ui/console/widgets/fields.py
index 1966c66..d8d892d 100644
--- a/deluge/ui/console/widgets/fields.py
+++ b/deluge/ui/console/widgets/fields.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
@@ -9,12 +8,9 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
-from deluge.common import PY2
from deluge.decorators import overrides
from deluge.ui.console.modes.basemode import InputKeyHandler
from deluge.ui.console.utils import colors
@@ -35,7 +31,7 @@ log = logging.getLogger(__name__)
class BaseField(InputKeyHandler):
def __init__(self, parent=None, name=None, selectable=True, **kwargs):
- super(BaseField, self).__init__()
+ super().__init__()
self.name = name
self.parent = parent
self.fmt_keys = {}
@@ -74,7 +70,7 @@ class BaseField(InputKeyHandler):
def build_fmt_string(self, focused, active, value_key='msg', **kwargs):
color_key, font_key = self.get_fmt_keys(focused, active, **kwargs)
- return '{!%%(%s)s,%%(%s)s!}%%(%s)s{!%%(%s)s!}' % (
+ return '{{!%({})s,%({})s!}}%({})s{{!%({})s!}}'.format(
color_key,
font_key,
value_key,
@@ -176,7 +172,7 @@ class InfoField(NoInputField):
NoInputField.__init__(self, parent=parent, name=name, **kwargs)
self.label = label
self.value = value
- self.txt = '%s %s' % (label, value)
+ self.txt = f'{label} {value}'
@overrides(BaseField)
def render(self, screen, row, col=0, **kwargs):
@@ -187,9 +183,9 @@ class InfoField(NoInputField):
def set_value(self, v):
self.value = v
if isinstance(v, float):
- self.txt = '%s %.2f' % (self.label, self.value)
+ self.txt = f'{self.label} {self.value:.2f}'
else:
- self.txt = '%s %s' % (self.label, self.value)
+ self.txt = f'{self.label} {self.value}'
class CheckedInput(InputField):
@@ -202,7 +198,7 @@ class CheckedInput(InputField):
checked_char='X',
unchecked_char=' ',
checkbox_format='[%s] ',
- **kwargs
+ **kwargs,
):
InputField.__init__(self, parent, name, message, **kwargs)
self.set_value(checked)
@@ -231,9 +227,7 @@ class CheckedInput(InputField):
@overrides(BaseField)
def get_fmt_keys(self, focused, active, **kwargs):
- color_key, font_key = super(CheckedInput, self).get_fmt_keys(
- focused, active, **kwargs
- )
+ color_key, font_key = super().get_fmt_keys(focused, active, **kwargs)
if self.checked:
color_key += '_checked'
font_key += '_checked'
@@ -284,7 +278,7 @@ class CheckedPlusInput(CheckedInput):
child_always_visible=False,
show_usage_hints=True,
msg_fmt='%s ',
- **kwargs
+ **kwargs,
):
CheckedInput.__init__(self, parent, name, message, **kwargs)
self.child = child
@@ -372,7 +366,7 @@ class IntSpinInput(InputField):
incr_large=10,
strict_validation=False,
fmt='%d',
- **kwargs
+ **kwargs,
):
InputField.__init__(self, parent, name, message, **kwargs)
self.convert_func = int
@@ -618,7 +612,7 @@ class SelectInput(InputField):
active_index,
active_default=False,
require_select_action=True,
- **kwargs
+ **kwargs,
):
InputField.__init__(self, parent, name, message, **kwargs)
self.opts = opts
@@ -667,9 +661,7 @@ class SelectInput(InputField):
@overrides(BaseField)
def get_fmt_keys(self, focused, active, selected=False, **kwargs):
- color_key, font_key = super(SelectInput, self).get_fmt_keys(
- focused, active, **kwargs
- )
+ color_key, font_key = super().get_fmt_keys(focused, active, **kwargs)
if selected:
color_key += '_selected'
font_key += '_selected'
@@ -739,7 +731,7 @@ class TextInput(InputField):
value,
complete=False,
activate_input=False,
- **kwargs
+ **kwargs,
):
InputField.__init__(self, parent, name, message, **kwargs)
self.move_func = move_func
@@ -815,7 +807,7 @@ class TextInput(InputField):
focused=True,
col=0,
cursor_offset=0,
- **kwargs
+ **kwargs,
):
if not self.value and not active and len(self.default_value) != 0:
self.value = self.default_value
@@ -951,7 +943,7 @@ class TextInput(InputField):
elif c > 31 and c < 256:
# Emulate getwch
stroke = chr(c)
- uchar = '' if PY2 else stroke
+ uchar = stroke
while not uchar:
try:
uchar = stroke.decode(self.parent.encoding)
@@ -1061,9 +1053,9 @@ class ComboInput(InputField):
# No match, so start at beginning
select_in_range(0, selected)
- from deluge.ui.console.widgets.popup import (
+ from deluge.ui.console.widgets.popup import ( # Must import here
SelectablePopup,
- ) # Must import here
+ )
select_popup = SelectablePopup(
self.parent,
@@ -1081,7 +1073,7 @@ class ComboInput(InputField):
choice[1],
selectable=True,
selected=choice[0] == self.get_value(),
- **args
+ **args,
)
self.parent.push_popup(select_popup)
return util.ReadState.CHANGED
@@ -1149,7 +1141,7 @@ class TextArea(TextField):
for i, line in enumerate(lines):
self.parent.add_string(
row + i,
- '%s%s' % (color, line),
+ f'{color}{line}',
scr=screen,
col=col,
pad=False,
@@ -1176,7 +1168,7 @@ class DividerField(NoInputField):
selectable=False,
fill_width=True,
value_fmt='%s',
- **kwargs
+ **kwargs,
):
NoInputField.__init__(
self, parent=parent, name=name, selectable=selectable, **kwargs
diff --git a/deluge/ui/console/widgets/inputpane.py b/deluge/ui/console/widgets/inputpane.py
index 097a6cb..d8d2175 100644
--- a/deluge/ui/console/widgets/inputpane.py
+++ b/deluge/ui/console/widgets/inputpane.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
@@ -9,8 +8,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from deluge.decorators import overrides
diff --git a/deluge/ui/console/widgets/popup.py b/deluge/ui/console/widgets/popup.py
index d588bbb..4b0d027 100644
--- a/deluge/ui/console/widgets/popup.py
+++ b/deluge/ui/console/widgets/popup.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from deluge.decorators import overrides
@@ -25,7 +22,7 @@ except ImportError:
log = logging.getLogger(__name__)
-class ALIGN(object):
+class ALIGN:
TOP_LEFT = 1
TOP_CENTER = 2
TOP_RIGHT = 3
@@ -38,7 +35,7 @@ class ALIGN(object):
DEFAULT = MIDDLE_CENTER
-class PopupsHandler(object):
+class PopupsHandler:
def __init__(self):
self._popups = []
diff --git a/deluge/ui/console/widgets/sidebar.py b/deluge/ui/console/widgets/sidebar.py
index cc23717..4015a13 100644
--- a/deluge/ui/console/widgets/sidebar.py
+++ b/deluge/ui/console/widgets/sidebar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 bendikro <bro.devel+deluge@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import curses
import logging
diff --git a/deluge/ui/console/widgets/statusbars.py b/deluge/ui/console/widgets/statusbars.py
index fcf4f2f..1b91737 100644
--- a/deluge/ui/console/widgets/statusbars.py
+++ b/deluge/ui/console/widgets/statusbars.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,13 +6,12 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import deluge.common
import deluge.component as component
-from deluge.core.preferencesmanager import DEFAULT_PREFS
from deluge.ui.client import client
+DEFAULT_DAEMON_PORT = 58846
+
class StatusBars(component.Component):
def __init__(self):
@@ -38,19 +36,23 @@ class StatusBars(component.Component):
def on_get_session_status(status):
self.upload = deluge.common.fsize(status['payload_upload_rate'])
self.download = deluge.common.fsize(status['payload_download_rate'])
- self.connections = status['num_peers']
+ self.connections = status['peer.num_peers_connected']
if 'dht_nodes' in status:
- self.dht = status['dht_nodes']
+ self.dht = status['dht.dht_nodes']
self.update_statusbars()
def on_get_external_ip(external_ip):
self.external_ip = external_ip
- keys = ['num_peers', 'payload_upload_rate', 'payload_download_rate']
+ keys = [
+ 'peer.num_peers_connected',
+ 'payload_upload_rate',
+ 'payload_download_rate',
+ ]
if self.config['dht']:
- keys.append('dht_nodes')
+ keys.append('dht.dht_nodes')
client.core.get_session_status(keys).addCallback(on_get_session_status)
client.core.get_external_ip().addCallback(on_get_external_ip)
@@ -76,7 +78,7 @@ class StatusBars(component.Component):
connection_info += '{!white,blue,bold!}@{!red,blue,bold!}%s'
# Port
- if info[1] == DEFAULT_PREFS['daemon_port']:
+ if info[1] == DEFAULT_DAEMON_PORT:
connection_info += '{!white,blue!}:%s'
else:
connection_info += '{!status!}:%s'
diff --git a/deluge/ui/console/widgets/window.py b/deluge/ui/console/widgets/window.py
index 2ef3528..77aff88 100644
--- a/deluge/ui/console/widgets/window.py
+++ b/deluge/ui/console/widgets/window.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
@@ -9,8 +8,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from deluge.ui.console.modes.basemode import add_string, mkpad, mkpanel
@@ -24,7 +21,7 @@ except ImportError:
log = logging.getLogger(__name__)
-class BaseWindow(object):
+class BaseWindow:
"""
BaseWindow creates a curses screen to be used for showing panels and popup dialogs
"""
diff --git a/deluge/ui/coreconfig.py b/deluge/ui/coreconfig.py
index ed6b614..1e2927b 100644
--- a/deluge/ui/coreconfig.py
+++ b/deluge/ui/coreconfig.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
diff --git a/deluge/ui/countries.py b/deluge/ui/countries.py
index fe17da1..eb94df6 100644
--- a/deluge/ui/countries.py
+++ b/deluge/ui/countries.py
@@ -1,10 +1,7 @@
-# -*- coding: utf-8 -*-
#
# This file is public domain.
#
-from __future__ import unicode_literals
-
# ISO 3166-1 country names and codes
COUNTRIES = {
'AF': _('Afghanistan'),
@@ -60,7 +57,7 @@ COUNTRIES = {
'CD': _('Congo, The Democratic Republic of the'),
'CK': _('Cook Islands'),
'CR': _('Costa Rica'),
- 'CI': _('Cote d\'Ivoire'),
+ 'CI': _("Cote d'Ivoire"),
'HR': _('Croatia'),
'CU': _('Cuba'),
'CY': _('Cyprus'),
@@ -122,11 +119,11 @@ COUNTRIES = {
'KZ': _('Kazakhstan'),
'KE': _('Kenya'),
'KI': _('Kiribati'),
- 'KP': _('Korea, Democratic People\'s Republic of'),
+ 'KP': _("Korea, Democratic People's Republic of"),
'KR': _('Korea, Republic of'),
'KW': _('Kuwait'),
'KG': _('Kyrgyzstan'),
- 'LA': _('Lao People\'s Democratic Republic'),
+ 'LA': _("Lao People's Democratic Republic"),
'LV': _('Latvia'),
'LB': _('Lebanon'),
'LS': _('Lesotho'),
diff --git a/deluge/ui/data/__pycache__/__init__.cpython-37.pyc b/deluge/ui/data/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 498f846..0000000
--- a/deluge/ui/data/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/deluge/ui/data/pixmaps/__pycache__/__init__.cpython-37.pyc b/deluge/ui/data/pixmaps/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index e07f647..0000000
--- a/deluge/ui/data/pixmaps/__pycache__/__init__.cpython-37.pyc
+++ /dev/null
Binary files differ
diff --git a/deluge/ui/data/pixmaps/checking16.png b/deluge/ui/data/pixmaps/checking16.png
index 0ac2c65..6758e36 100644
--- a/deluge/ui/data/pixmaps/checking16.png
+++ b/deluge/ui/data/pixmaps/checking16.png
Binary files differ
diff --git a/deluge/ui/data/pixmaps/inactive16.png b/deluge/ui/data/pixmaps/inactive16.png
index 9f38e77..cae8b2c 100644
--- a/deluge/ui/data/pixmaps/inactive16.png
+++ b/deluge/ui/data/pixmaps/inactive16.png
Binary files differ
diff --git a/deluge/ui/data/pixmaps/magnet.png b/deluge/ui/data/pixmaps/magnet.png
deleted file mode 100644
index a192cd8..0000000
--- a/deluge/ui/data/pixmaps/magnet.png
+++ /dev/null
Binary files differ
diff --git a/deluge/ui/data/pixmaps/magnet.svg b/deluge/ui/data/pixmaps/magnet.svg
new file mode 100644
index 0000000..f470b33
--- /dev/null
+++ b/deluge/ui/data/pixmaps/magnet.svg
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg16888"
+ sodipodi:version="0.32"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
+ sodipodi:docname="magnet.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.1"
+ inkscape:export-filename="/home/kali/code/deluge/deluge/ui/data/pixmaps/x-deluge-copy-magnet-uri-icon.png"
+ inkscape:export-xdpi="227.45343"
+ inkscape:export-ydpi="227.45343">
+ <defs
+ id="defs16890" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="9.3390267"
+ inkscape:cx="18.71894"
+ inkscape:cy="13.37636"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="925"
+ inkscape:window-x="0"
+ inkscape:window-y="31"
+ inkscape:grid-points="true"
+ inkscape:document-rotation="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata16893">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:date>November 2007</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://www.gnome.org</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>copy</rdf:li>
+ <rdf:li>copy to clipboard</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/LGPL/2.1/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/LGPL/2.1/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer 2"
+ style="display:inline">
+ <path
+ style="stroke-width:0.084844;fill:#ff0000;fill-opacity:1"
+ d="m 19.334232,31.418784 a 0.90623357,1.1438367 0 0 0 0.906233,-1.14384 V 25.31832 c 0,-12.210457 12.083111,-12.191395 12.083111,0 v 4.956624 a 0.90623357,1.1438367 0 0 0 0.906233,1.14384 h 11.471402 a 0.90623357,1.1438367 0 0 0 0.906234,-1.153375 c -0.0073,-2.039841 -0.04535,-3.841381 0,-5.080542 0,-14.35515 -10.283474,-23.5058431 -19.389614,-23.5058431 -9.106142,0 -19.257461,9.1506931 -19.257461,23.5153781 0.045378,1.220091 0.015034,3.145549 0,5.071007 a 0.90623357,1.1438367 0 0 0 0.9062351,1.153375 z"
+ id="path1134" />
+ <path
+ style="stroke-width:0.084844;fill:#515151;fill-opacity:0.54381627"
+ d="m 6.9490455,35.612845 v 7.63511 a 2.7187006,3.4315101 0 0 0 2.7186865,3.431514 h 7.85403 a 2.7187006,3.4315101 0 0 0 2.718703,-3.431514 V 35.62238 A 0.90623357,1.1438367 0 0 0 19.334232,34.478548 H 7.8552793 a 0.89792643,1.1333516 0 0 0 -0.9062338,1.134297 z"
+ id="path1132" />
+ <path
+ style="stroke-width:0.084844;fill:#515151;fill-opacity:0.54381627"
+ d="m 33.224525,34.469013 h 11.484252 a 0.90623357,1.1438367 0 0 1 0.906219,1.143832 v 7.625583 a 2.7187006,3.4315101 0 0 1 -2.718688,3.431506 h -7.85403 a 2.7187006,3.4315101 0 0 1 -2.718702,-3.431506 v -7.625583 a 0.89792643,1.1333516 0 0 1 0.900949,-1.143832 z"
+ id="path267" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ style="display:none">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:7.09866;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3157"
+ width="30.975992"
+ height="30.975992"
+ x="18.097294"
+ y="17.130117" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect11064"
+ width="15.487996"
+ height="13.551996"
+ x="21.323959"
+ y="31.327448"
+ ry="1.9584693" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect11066"
+ width="11.615996"
+ height="9.6799974"
+ x="23.259958"
+ y="33.263447"
+ ry="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 25.195958,36.167447 h 7.743998"
+ id="path12037" />
+ <path
+ id="path13008"
+ d="m 25.195958,40.039446 h 7.743998"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect16900"
+ width="15.487996"
+ height="13.551996"
+ x="30.358624"
+ y="20.356785"
+ ry="2.0447536" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect16902"
+ width="11.615996"
+ height="9.6799974"
+ x="32.294624"
+ y="22.292784"
+ ry="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 34.230623,25.196783 h 7.743998"
+ id="path16904" />
+ <path
+ id="path16906"
+ d="m 34.230623,29.068782 h 7.743998"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/deluge/ui/data/pixmaps/magnet16.png b/deluge/ui/data/pixmaps/magnet16.png
new file mode 100644
index 0000000..61d6dab
--- /dev/null
+++ b/deluge/ui/data/pixmaps/magnet16.png
Binary files differ
diff --git a/deluge/ui/data/pixmaps/magnet_add.svg b/deluge/ui/data/pixmaps/magnet_add.svg
new file mode 100644
index 0000000..d9ba67a
--- /dev/null
+++ b/deluge/ui/data/pixmaps/magnet_add.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg16888"
+ sodipodi:version="0.32"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
+ sodipodi:docname="add-magnet.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.1"
+ inkscape:export-filename="/home/kali/code/deluge/deluge/ui/data/pixmaps/x-deluge-copy-magnet-uri-icon.png"
+ inkscape:export-xdpi="227.45343"
+ inkscape:export-ydpi="227.45343">
+ <defs
+ id="defs16890" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="6.6036891"
+ inkscape:cx="24.635975"
+ inkscape:cy="13.381649"
+ inkscape:current-layer="layer3"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="925"
+ inkscape:window-x="0"
+ inkscape:window-y="31"
+ inkscape:grid-points="true"
+ inkscape:document-rotation="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata16893">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:date>November 2007</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://www.gnome.org</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>copy</rdf:li>
+ <rdf:li>copy to clipboard</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/LGPL/2.1/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/LGPL/2.1/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer 2"
+ style="display:inline">
+ <path
+ style="fill:#ff0000;fill-opacity:1;stroke-width:0.084844"
+ d="m 19.334232,31.418784 a 0.90623357,1.1438367 0 0 0 0.906233,-1.14384 V 25.31832 c 0,-12.210457 12.083111,-12.191395 12.083111,0 v 4.956624 a 0.90623357,1.1438367 0 0 0 0.906233,1.14384 h 11.471402 a 0.90623357,1.1438367 0 0 0 0.906234,-1.153375 c -0.0073,-2.039841 -0.04535,-3.841381 0,-5.080542 0,-14.35515 -10.283474,-23.5058431 -19.389614,-23.5058431 -9.106142,0 -19.257461,9.1506931 -19.257461,23.5153781 0.045378,1.220091 0.015034,3.145549 0,5.071007 a 0.90623357,1.1438367 0 0 0 0.9062351,1.153375 z"
+ id="path1134" />
+ <path
+ style="fill:#515151;fill-opacity:0.543816;stroke-width:0.084844"
+ d="m 6.9490455,35.612845 v 7.63511 a 2.7187006,3.4315101 0 0 0 2.7186865,3.431514 h 7.85403 a 2.7187006,3.4315101 0 0 0 2.718703,-3.431514 V 35.62238 A 0.90623357,1.1438367 0 0 0 19.334232,34.478548 H 7.8552793 a 0.89792643,1.1333516 0 0 0 -0.9062338,1.134297 z"
+ id="path1132" />
+ <path
+ style="fill:#515151;fill-opacity:0.543816;stroke-width:0.084844"
+ d="m 33.224525,34.469013 h 11.484252 a 0.90623357,1.1438367 0 0 1 0.906219,1.143832 v 7.625583 a 2.7187006,3.4315101 0 0 1 -2.718688,3.431506 h -7.85403 a 2.7187006,3.4315101 0 0 1 -2.718702,-3.431506 v -7.625583 a 0.89792643,1.1333516 0 0 1 0.900949,-1.143832 z"
+ id="path267" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ style="display:none">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:7.09866;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3157"
+ width="30.975992"
+ height="30.975992"
+ x="18.097294"
+ y="17.130117" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect11064"
+ width="15.487996"
+ height="13.551996"
+ x="21.323959"
+ y="31.327448"
+ ry="1.9584693" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect11066"
+ width="11.615996"
+ height="9.6799974"
+ x="23.259958"
+ y="33.263447"
+ ry="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 25.195958,36.167447 h 7.743998"
+ id="path12037" />
+ <path
+ id="path13008"
+ d="m 25.195958,40.039446 h 7.743998"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect16900"
+ width="15.487996"
+ height="13.551996"
+ x="30.358624"
+ y="20.356785"
+ ry="2.0447536" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect16902"
+ width="11.615996"
+ height="9.6799974"
+ x="32.294624"
+ y="22.292784"
+ ry="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 34.230623,25.196783 h 7.743998"
+ id="path16904" />
+ <path
+ id="path16906"
+ d="m 34.230623,29.068782 h 7.743998"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="Layer 3">
+ <path
+ id="text1353"
+ style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;fill:#03ff48;fill-opacity:1;stroke:#000000;stroke-width:0.674513;stroke-opacity:1"
+ d="m 8.4078166,2.1897337 c 10e-7,1.9963132 0,3.9926271 0,5.9889403 -2.445989,0 -4.891978,0 -7.337967,0 0,2.545234 0,5.090468 0,7.635701 2.445989,0 4.891978,0 7.337967,0 0,2.445989 0,4.891978 0,7.337968 2.5364514,0 5.0729034,0 7.6093534,0 1e-6,-2.44599 0,-4.891979 0,-7.337968 2.44599,0 4.891979,0 7.337968,0 0,-2.545233 0,-5.090467 0,-7.635701 -2.445989,0 -4.891978,0 -7.337968,0 1e-6,-2.445989 0,-4.891978 0,-7.33796734 -2.53645,0 -5.072902,0 -7.6093534,0 0,0.44967504 10e-7,0.89935104 0,1.34902704 z" />
+ </g>
+</svg>
diff --git a/deluge/ui/data/pixmaps/magnet_add16.png b/deluge/ui/data/pixmaps/magnet_add16.png
new file mode 100644
index 0000000..37c1c36
--- /dev/null
+++ b/deluge/ui/data/pixmaps/magnet_add16.png
Binary files differ
diff --git a/deluge/ui/data/pixmaps/magnet_copy.svg b/deluge/ui/data/pixmaps/magnet_copy.svg
new file mode 100644
index 0000000..dd4ba42
--- /dev/null
+++ b/deluge/ui/data/pixmaps/magnet_copy.svg
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg16888"
+ sodipodi:version="0.32"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
+ sodipodi:docname="copy-magnet.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.1">
+ <defs
+ id="defs16890" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="9.3390267"
+ inkscape:cx="20.00387"
+ inkscape:cy="13.37636"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="925"
+ inkscape:window-x="0"
+ inkscape:window-y="31"
+ inkscape:grid-points="true"
+ inkscape:document-rotation="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata16893">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:date>November 2007</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://www.gnome.org</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>copy</rdf:li>
+ <rdf:li>copy to clipboard</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/LGPL/2.1/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/LGPL/2.1/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer 2"
+ style="display:inline">
+ <path
+ style="stroke-width:0.084844;fill:#ff0000;fill-opacity:1"
+ d="m 19.334232,31.418784 a 0.90623357,1.1438367 0 0 0 0.906233,-1.14384 V 25.31832 c 0,-12.210457 12.083111,-12.191395 12.083111,0 v 4.956624 a 0.90623357,1.1438367 0 0 0 0.906233,1.14384 h 11.471402 a 0.90623357,1.1438367 0 0 0 0.906234,-1.153375 c -0.0073,-2.039841 -0.04535,-3.841381 0,-5.080542 0,-14.35515 -10.283474,-23.5058431 -19.389614,-23.5058431 -9.106142,0 -19.257461,9.1506931 -19.257461,23.5153781 0.045378,1.220091 0.015034,3.145549 0,5.071007 a 0.90623357,1.1438367 0 0 0 0.9062351,1.153375 z"
+ id="path1134" />
+ <path
+ style="stroke-width:0.084844;fill:#515151;fill-opacity:0.54381627"
+ d="m 6.9490455,35.612845 v 7.63511 a 2.7187006,3.4315101 0 0 0 2.7186865,3.431514 h 7.85403 a 2.7187006,3.4315101 0 0 0 2.718703,-3.431514 V 35.62238 A 0.90623357,1.1438367 0 0 0 19.334232,34.478548 H 7.8552793 a 0.89792643,1.1333516 0 0 0 -0.9062338,1.134297 z"
+ id="path1132" />
+ <path
+ style="stroke-width:0.084844;fill:#515151;fill-opacity:0.54381627"
+ d="m 33.224525,34.469013 h 11.484252 a 0.90623357,1.1438367 0 0 1 0.906219,1.143832 v 7.625583 a 2.7187006,3.4315101 0 0 1 -2.718688,3.431506 h -7.85403 a 2.7187006,3.4315101 0 0 1 -2.718702,-3.431506 v -7.625583 a 0.89792643,1.1333516 0 0 1 0.900949,-1.143832 z"
+ id="path267" />
+ </g>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ style="display:inline">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:7.09866;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3157"
+ width="30.975992"
+ height="30.975992"
+ x="18.097294"
+ y="17.130117" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect11064"
+ width="15.487996"
+ height="13.551996"
+ x="21.323959"
+ y="31.327448"
+ ry="1.9584693" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect11066"
+ width="11.615996"
+ height="9.6799974"
+ x="23.259958"
+ y="33.263447"
+ ry="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 25.195958,36.167447 h 7.743998"
+ id="path12037" />
+ <path
+ id="path13008"
+ d="m 25.195958,40.039446 h 7.743998"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect16900"
+ width="15.487996"
+ height="13.551996"
+ x="30.358624"
+ y="20.356785"
+ ry="2.0447536" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5.16267;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect16902"
+ width="11.615996"
+ height="9.6799974"
+ x="32.294624"
+ y="22.292784"
+ ry="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 34.230623,25.196783 h 7.743998"
+ id="path16904" />
+ <path
+ id="path16906"
+ d="m 34.230623,29.068782 h 7.743998"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.936;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/deluge/ui/data/pixmaps/magnet_copy16.png b/deluge/ui/data/pixmaps/magnet_copy16.png
new file mode 100644
index 0000000..a4be9d2
--- /dev/null
+++ b/deluge/ui/data/pixmaps/magnet_copy16.png
Binary files differ
diff --git a/deluge/ui/data/share/applications/deluge.desktop.in b/deluge/ui/data/share/applications/deluge.desktop.in
index c952d42..4335b6d 100644
--- a/deluge/ui/data/share/applications/deluge.desktop.in
+++ b/deluge/ui/data/share/applications/deluge.desktop.in
@@ -4,6 +4,7 @@ _Name=Deluge
_GenericName=BitTorrent Client
_X-GNOME-FullName=Deluge BitTorrent Client
_Comment=Download and share files over BitTorrent
+_Keywords=bittorrent;torrent;magnet;download;p2p;torrents;downloading;uploading;share;sharing;
TryExec=deluge-gtk
Exec=deluge-gtk %U
Icon=deluge
diff --git a/deluge/ui/gtk3/__init__.py b/deluge/ui/gtk3/__init__.py
index 3b9d2b1..8db2773 100644
--- a/deluge/ui/gtk3/__init__.py
+++ b/deluge/ui/gtk3/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,13 +6,14 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
+from os import environ
from deluge.ui.ui import UI
log = logging.getLogger(__name__)
+# Hide pygame community banner
+environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
# Keep this class in __init__.py to avoid the console having to import everything in gtkui.py
@@ -22,7 +22,7 @@ class Gtk(UI):
cmd_description = """GTK-based graphical user interface"""
def __init__(self, *args, **kwargs):
- super(Gtk, self).__init__(
+ super().__init__(
'gtk', *args, description='Starts the Deluge GTK+ interface', **kwargs
)
@@ -39,10 +39,11 @@ class Gtk(UI):
)
def start(self):
- super(Gtk, self).start()
- from .gtkui import GtkUI
+ super().start()
import deluge.common
+ from .gtkui import GtkUI
+
def run(options):
try:
gtkui = GtkUI(options)
diff --git a/deluge/ui/gtk3/aboutdialog.py b/deluge/ui/gtk3/aboutdialog.py
index 9974a13..fe3452b 100644
--- a/deluge/ui/gtk3/aboutdialog.py
+++ b/deluge/ui/gtk3/aboutdialog.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Marcos Mobley ('markybob') <markybob@gmail.com>
#
@@ -7,7 +6,7 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
+from datetime import date
from gi.repository import Gtk
@@ -18,7 +17,7 @@ from deluge.ui.client import client
from .common import get_deluge_icon, get_pixbuf
-class AboutDialog(object):
+class AboutDialog:
def __init__(self):
self.about = Gtk.AboutDialog()
self.about.set_transient_for(component.get('MainWindow').window)
@@ -38,7 +37,7 @@ class AboutDialog(object):
self.about.set_copyright(
_('Copyright %(year_start)s-%(year_end)s Deluge Team')
- % {'year_start': 2007, 'year_end': 2019}
+ % {'year_start': 2007, 'year_end': date.today().year}
)
self.about.set_comments(
_('A peer-to-peer file sharing program\nutilizing the BitTorrent protocol.')
diff --git a/deluge/ui/gtk3/addtorrentdialog.py b/deluge/ui/gtk3/addtorrentdialog.py
index 9ede710..cf3851d 100644
--- a/deluge/ui/gtk3/addtorrentdialog.py
+++ b/deluge/ui/gtk3/addtorrentdialog.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,11 +6,9 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
import logging
import os
-from base64 import b64encode
+from base64 import b64decode, b64encode
from xml.sax.saxutils import escape as xml_escape
from xml.sax.saxutils import unescape as xml_unescape
@@ -19,6 +16,7 @@ from gi.repository import Gtk
from gi.repository.GObject import TYPE_INT64, TYPE_UINT64
import deluge.component as component
+from deluge.bencode import bdecode
from deluge.common import (
create_magnet_uri,
decode_bytes,
@@ -271,6 +269,7 @@ class AddTorrentDialog(component.Component):
return
if metadata:
+ metadata = bdecode(b64decode(metadata))
info = TorrentInfo.from_metadata(metadata, [[t] for t in trackers])
self.files[info_hash] = info.files
self.infos[info_hash] = info.filedata
@@ -301,7 +300,7 @@ class AddTorrentDialog(component.Component):
self.builder.get_object('prefetch_hbox').hide()
def add_from_magnets(self, uris):
- """Add a list of magnet uris to torrent_liststore."""
+ """Add a list of magnet URIs to torrent_liststore."""
already_added = 0
for uri in uris:
@@ -775,7 +774,7 @@ class AddTorrentDialog(component.Component):
else:
ErrorDialog(
_('Invalid URL'),
- '%s %s' % (url, _('is not a valid URL.')),
+ '{} {}'.format(url, _('is not a valid URL.')),
self.dialog,
).run()
@@ -817,7 +816,7 @@ class AddTorrentDialog(component.Component):
dialog.destroy()
ErrorDialog(
_('Download Failed'),
- '%s %s' % (_('Failed to download:'), url),
+ '{} {}'.format(_('Failed to download:'), url),
details=result.getErrorMessage(),
parent=self.dialog,
).run()
@@ -853,11 +852,11 @@ class AddTorrentDialog(component.Component):
log.debug('Create torrent tracker lines: %s', trackers_text)
trackers = list(trackers_tiers_from_text(trackers_text).keys())
- # Convert the information to a magnet uri, this is just easier to
+ # Convert the information to a magnet URI, this is just easier to
# handle this way.
log.debug('trackers: %s', trackers)
magnet = create_magnet_uri(infohash, infohash, trackers)
- log.debug('magnet uri: %s', magnet)
+ log.debug('magnet URI: %s', magnet)
self.add_from_magnets([magnet])
entry.set_text('')
diff --git a/deluge/ui/gtk3/common.py b/deluge/ui/gtk3/common.py
index 8359327..42a14b4 100644
--- a/deluge/ui/gtk3/common.py
+++ b/deluge/ui/gtk3/common.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Marcos Mobley ('markybob') <markybob@gmail.com>
#
@@ -7,16 +6,14 @@
# See LICENSE for more details.
#
"""Common functions for various parts of gtkui to use."""
-from __future__ import unicode_literals
-
import contextlib
import logging
import os
+import pickle
import shutil
import sys
-import six.moves.cPickle as pickle # noqa: N813
-from gi.repository.Gdk import SELECTION_CLIPBOARD, Display
+from gi.repository.Gdk import SELECTION_CLIPBOARD, SELECTION_PRIMARY, Display
from gi.repository.GdkPixbuf import Colorspace, Pixbuf
from gi.repository.GLib import GError
from gi.repository.Gtk import (
@@ -29,7 +26,7 @@ from gi.repository.Gtk import (
SortType,
)
-from deluge.common import PY2, get_pixmap, osx_check, windows_check
+from deluge.common import get_pixmap, is_ip, osx_check, windows_check
log = logging.getLogger(__name__)
@@ -42,7 +39,18 @@ def cmp(x, y):
and strictly positive if x > y.
"""
- return (x > y) - (x < y)
+ try:
+ return (x > y) - (x < y)
+ except TypeError:
+ # Handle NoneType comparison
+ if x is None:
+ if y is None:
+ return 0
+ return -1
+ elif y is None:
+ return 1
+ else:
+ raise
def create_blank_pixbuf(size=16):
@@ -51,12 +59,36 @@ def create_blank_pixbuf(size=16):
return pix
-def get_pixbuf(filename):
+def get_pixbuf(filename: str, size: int = 0) -> Pixbuf:
+ """Creates a new pixbuf by loading an image from file
+
+ Args:
+ filename: An image file to load
+ size: Specify a size constraint (equal aspect ratio)
+
+ Returns:
+ A newly created pixbuf
+
+ """
+ # Skip ico and gif that cause Pixbuf crash on Windows
+ # https://dev.deluge-torrent.org/ticket/3501
+ if windows_check() and filename.endswith(('.ico', '.gif')):
+ return create_blank_pixbuf(size)
+
+ if not os.path.isabs(filename):
+ filename = get_pixmap(filename)
+
+ pixbuf = None
try:
- return Pixbuf.new_from_file(get_pixmap(filename))
+ if size:
+ pixbuf = Pixbuf.new_from_file_at_size(filename, size, size)
+ else:
+ pixbuf = Pixbuf.new_from_file(filename)
except GError as ex:
+ # Failed to load the pixbuf (Bad image file), so return a blank pixbuf.
log.warning(ex)
- return create_blank_pixbuf()
+
+ return pixbuf or create_blank_pixbuf(size or 16)
# Status icons.. Create them from file only once to avoid constantly re-creating them.
@@ -68,17 +100,6 @@ icon_queued = get_pixbuf('queued16.png')
icon_checking = get_pixbuf('checking16.png')
-def get_pixbuf_at_size(filename, size):
- if not os.path.isabs(filename):
- filename = get_pixmap(filename)
- try:
- return Pixbuf.new_from_file_at_size(filename, size, size)
- except GError as ex:
- # Failed to load the pixbuf (Bad image file), so return a blank pixbuf.
- log.warning(ex)
- return create_blank_pixbuf(size)
-
-
def get_logo(size):
"""A Deluge logo.
@@ -91,7 +112,7 @@ def get_logo(size):
filename = 'deluge.svg'
if windows_check():
filename = 'deluge.png'
- return get_pixbuf_at_size(filename, size)
+ return get_pixbuf(filename, size)
def build_menu_radio_list(
@@ -221,14 +242,11 @@ def associate_magnet_links(overwrite=False):
"""
if windows_check():
- try:
- import winreg
- except ImportError:
- import _winreg as winreg # For Python 2.
+ import winreg
try:
hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, 'Magnet')
- except WindowsError:
+ except OSError:
overwrite = True
else:
winreg.CloseKey(hkey)
@@ -237,7 +255,7 @@ def associate_magnet_links(overwrite=False):
deluge_exe = os.path.join(os.path.dirname(sys.executable), 'deluge.exe')
try:
magnet_key = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, 'Magnet')
- except WindowsError:
+ except OSError:
# Could not create for all users, falling back to current user
magnet_key = winreg.CreateKey(
winreg.HKEY_CURRENT_USER, 'Software\\Classes\\Magnet'
@@ -246,14 +264,12 @@ def associate_magnet_links(overwrite=False):
winreg.SetValue(magnet_key, '', winreg.REG_SZ, 'URL:Magnet Protocol')
winreg.SetValueEx(magnet_key, 'URL Protocol', 0, winreg.REG_SZ, '')
winreg.SetValueEx(magnet_key, 'BrowserFlags', 0, winreg.REG_DWORD, 0x8)
- winreg.SetValue(
- magnet_key, 'DefaultIcon', winreg.REG_SZ, '{},0'.format(deluge_exe)
- )
+ winreg.SetValue(magnet_key, 'DefaultIcon', winreg.REG_SZ, f'{deluge_exe},0')
winreg.SetValue(
magnet_key,
r'shell\open\command',
winreg.REG_SZ,
- '"{}" "%1"'.format(deluge_exe),
+ f'"{deluge_exe}" "%1"',
)
winreg.CloseKey(magnet_key)
@@ -267,7 +283,7 @@ def associate_magnet_links(overwrite=False):
from gi.repository import GConf
except ValueError:
log.debug(
- 'gconf not available, so will not attempt to register magnet uri handler'
+ 'gconf not available, so will not attempt to register magnet URI handler'
)
return False
else:
@@ -282,11 +298,11 @@ def associate_magnet_links(overwrite=False):
gconf_client.set_bool(
'/desktop/gnome/url-handlers/magnet/enabled', True
)
- log.info('Deluge registered as default magnet uri handler!')
+ log.info('Deluge registered as default magnet URI handler!')
return True
else:
log.error(
- 'Unable to register Deluge as default magnet uri handler.'
+ 'Unable to register Deluge as default magnet URI handler.'
)
return False
return False
@@ -309,7 +325,7 @@ def save_pickled_state_file(filename, state):
if os.path.isfile(filepath):
log.debug('Creating backup of %s at: %s', filename, filepath_bak)
shutil.copy2(filepath, filepath_bak)
- except IOError as ex:
+ except OSError as ex:
log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
else:
log.info('Saving the %s at: %s', filename, filepath)
@@ -320,7 +336,7 @@ def save_pickled_state_file(filename, state):
_file.flush()
os.fsync(_file.fileno())
shutil.move(filepath_tmp, filepath)
- except (IOError, EOFError, pickle.PicklingError) as ex:
+ except (OSError, EOFError, pickle.PicklingError) as ex:
log.error('Unable to save %s: %s', filename, ex)
if os.path.isfile(filepath_bak):
log.info('Restoring backup of %s from: %s', filename, filepath_bak)
@@ -345,11 +361,8 @@ def load_pickled_state_file(filename):
log.info('Opening %s for load: %s', filename, _filepath)
try:
with open(_filepath, 'rb') as _file:
- if PY2:
- state = pickle.load(_file)
- else:
- state = pickle.load(_file, encoding='utf8')
- except (IOError, pickle.UnpicklingError) as ex:
+ state = pickle.load(_file, encoding='utf8')
+ except (OSError, pickle.UnpicklingError) as ex:
log.warning('Unable to load %s: %s', _filepath, ex)
else:
log.info('Successfully loaded %s: %s', filename, _filepath)
@@ -384,8 +397,8 @@ def listview_replace_treestore(listview):
def get_clipboard_text():
text = (
- Clipboard.get(selection=SELECTION_CLIPBOARD).wait_for_text()
- or Clipboard.get().wait_for_text()
+ Clipboard.get(SELECTION_CLIPBOARD).wait_for_text()
+ or Clipboard.get(SELECTION_PRIMARY).wait_for_text()
)
if text:
return text.strip()
@@ -393,3 +406,30 @@ def get_clipboard_text():
def windowing(like):
return like.lower() in str(type(Display.get_default())).lower()
+
+
+def parse_ip_port(text):
+ """Return an IP and port from text.
+
+ Parses both IPv4 and IPv6.
+
+ Params:
+ text (str): Text to be parsed for IP and port.
+
+ Returns:
+ tuple: (ip (str), port (int))
+
+ """
+ if '.' in text:
+ # ipv4
+ ip, __, port = text.rpartition(':')
+ elif '[' in text:
+ # ipv6
+ ip, __, port = text.partition('[')[2].partition(']:')
+ else:
+ return None, None
+
+ if ip and is_ip(ip) and port.isdigit():
+ return ip, int(port)
+ else:
+ return None, None
diff --git a/deluge/ui/gtk3/connectionmanager.py b/deluge/ui/gtk3/connectionmanager.py
index d5883c4..b53dd8e 100644
--- a/deluge/ui/gtk3/connectionmanager.py
+++ b/deluge/ui/gtk3/connectionmanager.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,11 +6,10 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
-from socket import gaierror, gethostbyname
+from socket import gaierror, getaddrinfo
+from urllib.parse import urlparse
from gi.repository import Gtk
from twisted.internet import defer, reactor
@@ -26,12 +24,6 @@ from deluge.ui.hostlist import DEFAULT_PORT, LOCALHOST, HostList
from .common import get_clipboard_text
from .dialogs import AuthenticationDialog, ErrorDialog
-try:
- from urllib.parse import urlparse
-except ImportError:
- # PY2 fallback
- from urlparse import urlparse # pylint: disable=ungrouped-imports
-
log = logging.getLogger(__name__)
HOSTLIST_COL_ID = 0
@@ -230,7 +222,7 @@ class ConnectionManager(component.Component):
__, host, port, __, __, status, __, __ = model[row]
try:
- gethostbyname(host)
+ getaddrinfo(host, None)
except gaierror as ex:
log.error(
'Error resolving host %s to ip: %s', row[HOSTLIST_COL_HOST], ex.args[1]
diff --git a/deluge/ui/gtk3/createtorrentdialog.py b/deluge/ui/gtk3/createtorrentdialog.py
index 1e5e73c..e9f1690 100644
--- a/deluge/ui/gtk3/createtorrentdialog.py
+++ b/deluge/ui/gtk3/createtorrentdialog.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
import logging
import os.path
from base64 import b64encode
@@ -31,7 +28,7 @@ from .torrentview_data_funcs import cell_data_size
log = logging.getLogger(__name__)
-class CreateTorrentDialog(object):
+class CreateTorrentDialog:
def __init__(self):
pass
diff --git a/deluge/ui/gtk3/details_tab.py b/deluge/ui/gtk3/details_tab.py
index 2431e08..04a5eab 100644
--- a/deluge/ui/gtk3/details_tab.py
+++ b/deluge/ui/gtk3/details_tab.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from xml.sax.saxutils import escape as xml_escape
@@ -23,7 +20,7 @@ log = logging.getLogger(__name__)
class DetailsTab(Tab):
def __init__(self):
- super(DetailsTab, self).__init__('Details', 'details_tab', 'details_tab_label')
+ super().__init__('Details', 'details_tab', 'details_tab_label')
self.add_tab_widget('summary_name', None, ('name',))
self.add_tab_widget('summary_total_size', fsize, ('total_size',))
@@ -65,7 +62,7 @@ class DetailsTab(Tab):
txt = xml_escape(self.widget_status_as_fstr(widget, status))
if decode_bytes(widget.obj.get_text()) != txt:
if 'comment' in widget.status_keys and is_url(txt):
- widget.obj.set_markup('<a href="%s">%s</a>' % (txt, txt))
+ widget.obj.set_markup(f'<a href="{txt}">{txt}</a>')
else:
widget.obj.set_markup(txt)
diff --git a/deluge/ui/gtk3/dialogs.py b/deluge/ui/gtk3/dialogs.py
index 5169ab4..db337d3 100644
--- a/deluge/ui/gtk3/dialogs.py
+++ b/deluge/ui/gtk3/dialogs.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -9,7 +8,7 @@
# pylint: disable=super-on-old-class
-from __future__ import unicode_literals
+from collections import namedtuple
from gi.repository import Gtk
from twisted.internet import defer
@@ -17,7 +16,9 @@ from twisted.internet import defer
import deluge.component as component
from deluge.common import windows_check
-from .common import get_deluge_icon, get_pixbuf_at_size
+from .common import get_deluge_icon, get_pixbuf
+
+Account = namedtuple('Account', 'username password authlevel')
class BaseDialog(Gtk.Dialog):
@@ -34,7 +35,7 @@ class BaseDialog(Gtk.Dialog):
:param parent: gtkWindow, the parent window, if None it will default to the
MainWindow
"""
- super(BaseDialog, self).__init__(
+ super().__init__(
title=header,
parent=parent if parent else component.get('MainWindow').window,
flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
@@ -55,7 +56,7 @@ class BaseDialog(Gtk.Dialog):
# Hack for Windows since it doesn't support svg
if icon.endswith('.svg') and windows_check():
icon = icon.rpartition('.svg')[0] + '16.png'
- image.set_from_pixbuf(get_pixbuf_at_size(icon, 24))
+ image.set_from_pixbuf(get_pixbuf(icon, 24))
else:
image.set_from_icon_name(icon, Gtk.IconSize.LARGE_TOOLBAR)
image.set_alignment(0.5, 0.0)
@@ -72,12 +73,12 @@ class BaseDialog(Gtk.Dialog):
self.vbox.show_all()
def _on_delete_event(self, widget, event):
- self.deferred.callback(Gtk.ResponseType.DELETE_EVENT)
self.destroy()
+ self.deferred.callback(Gtk.ResponseType.DELETE_EVENT)
def _on_response(self, widget, response):
- self.deferred.callback(response)
self.destroy()
+ self.deferred.callback(response)
def run(self):
"""
@@ -103,13 +104,15 @@ class YesNoDialog(BaseDialog):
:param text: see `:class:BaseDialog`
:param parent: see `:class:BaseDialog`
"""
- super(YesNoDialog, self).__init__(
+ super().__init__(
header,
text,
'dialog-question',
(_('_No'), Gtk.ResponseType.NO, _('_Yes'), Gtk.ResponseType.YES),
parent,
)
+ # Use the preferred size calculated from the content
+ self.set_default_size(-1, -1)
class InformationDialog(BaseDialog):
@@ -125,7 +128,7 @@ class InformationDialog(BaseDialog):
:param text: see `:class:BaseDialog`
:param parent: see `:class:BaseDialog`
"""
- super(InformationDialog, self).__init__(
+ super().__init__(
header,
text,
'dialog-information',
@@ -152,13 +155,13 @@ class ErrorDialog(BaseDialog):
:param traceback: show the traceback information in the details area
:type traceback: bool
"""
- super(ErrorDialog, self).__init__(
+ super().__init__(
header, text, 'dialog-error', (_('_Close'), Gtk.ResponseType.CLOSE), parent
)
if traceback:
- import traceback
import sys
+ import traceback
tb = sys.exc_info()
tb = traceback.format_exc(tb[2])
@@ -196,7 +199,7 @@ class AuthenticationDialog(BaseDialog):
:param err_msg: the error message we got back from the server
:type err_msg: string
"""
- super(AuthenticationDialog, self).__init__(
+ super().__init__(
_('Authenticate'),
err_msg,
'dialog-password',
@@ -253,7 +256,7 @@ class AccountDialog(BaseDialog):
parent=None,
):
if username:
- super(AccountDialog, self).__init__(
+ super().__init__(
_('Edit Account'),
_('Edit existing account'),
'dialog-information',
@@ -266,7 +269,7 @@ class AccountDialog(BaseDialog):
parent,
)
else:
- super(AccountDialog, self).__init__(
+ super().__init__(
_('New Account'),
_('Create a new account'),
'dialog-information',
@@ -274,21 +277,21 @@ class AccountDialog(BaseDialog):
parent,
)
- self.levels_mapping = levels_mapping
+ self.account = None
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)
+ username_label = Gtk.Label()
+ username_label.set_markup('<b>' + _('Username:') + '</b>')
+ username_label.set_alignment(1.0, 0.5)
+ username_label.set_padding(5, 5)
self.username_entry = Gtk.Entry()
- table.attach(self.username_label, 0, 1, 0, 1)
+ table.attach(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)
+ authlevel_label = Gtk.Label()
+ authlevel_label.set_markup('<b>' + _('Authentication Level:') + '</b>')
+ authlevel_label.set_alignment(1.0, 0.5)
+ authlevel_label.set_padding(5, 5)
# combo_box_new_text is deprecated but no other pygtk alternative.
self.authlevel_combo = Gtk.ComboBoxText()
@@ -303,16 +306,16 @@ class AccountDialog(BaseDialog):
if active_idx is not None:
self.authlevel_combo.set_active(active_idx)
- table.attach(self.authlevel_label, 0, 1, 1, 2)
+ table.attach(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)
+ password_label = Gtk.Label()
+ password_label.set_markup('<b>' + _('Password:') + '</b>')
+ password_label.set_alignment(1.0, 0.5)
+ 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(password_label, 0, 1, 2, 3)
table.attach(self.password_entry, 1, 2, 2, 3)
self.vbox.pack_start(table, False, False, padding=5)
@@ -325,18 +328,17 @@ class AccountDialog(BaseDialog):
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()
+ self.vbox.show_all()
- def get_authlevel(self):
- combobox = self.authlevel_combo
- level = combobox.get_model()[combobox.get_active()][0]
- return level
+ def _on_response(self, widget, response):
+ if response == Gtk.ResponseType.OK:
+ self.account = Account(
+ self.username_entry.get_text(),
+ self.password_entry.get_text(),
+ self.authlevel_combo.get_active_text(),
+ )
+ self.destroy()
+ self.deferred.callback(response)
class OtherDialog(BaseDialog):
@@ -357,7 +359,7 @@ class OtherDialog(BaseDialog):
if not icon:
icon = 'dialog-information'
- super(OtherDialog, self).__init__(
+ super().__init__(
header,
text,
icon,
@@ -419,7 +421,7 @@ class PasswordDialog(BaseDialog):
:param password_msg: the error message we got back from the server
:type password_msg: string
"""
- super(PasswordDialog, self).__init__(
+ super().__init__(
header=_('Password Protected'),
text=password_msg,
icon='dialog-password',
@@ -453,3 +455,44 @@ class PasswordDialog(BaseDialog):
def on_password_activate(self, widget):
self.response(Gtk.ResponseType.OK)
+
+
+class CopyMagnetDialog(BaseDialog):
+ """
+ Displays a dialog with a magnet URI
+ """
+
+ def __init__(self, torrent_magnet='', parent=None):
+ super().__init__(
+ header=_('Copy Magnet URI'),
+ text='',
+ icon='magnet_copy.svg',
+ buttons=(_('_Close'), Gtk.ResponseType.CLOSE),
+ parent=parent,
+ )
+ self.copied = False
+
+ table = Gtk.Table(1, 2, False)
+ self.magnet_entry = Gtk.Entry()
+ self.magnet_entry.set_text(torrent_magnet)
+ self.magnet_entry.set_editable(False)
+ self.magnet_entry.connect('copy-clipboard', self.on_copy_emitted)
+ table.attach(self.magnet_entry, 0, 1, 0, 1)
+
+ copy_button = Gtk.Button.new_with_label(_('Copy'))
+ copy_button.connect('clicked', self.on_copy_clicked)
+ table.attach(copy_button, 1, 2, 0, 1)
+
+ self.vbox.pack_start(table, False, False, padding=5)
+ self.set_focus(self.magnet_entry)
+
+ self.show_all()
+
+ def on_copy_clicked(self, widget):
+ self.magnet_entry.select_region(0, -1)
+ self.magnet_entry.copy_clipboard()
+ self.magnet_entry.set_position(0)
+ self.copied = True
+
+ def on_copy_emitted(self, widget):
+ self.copied = True
diff --git a/deluge/ui/gtk3/edittrackersdialog.py b/deluge/ui/gtk3/edittrackersdialog.py
index 1dfdd2a..861e392 100644
--- a/deluge/ui/gtk3/edittrackersdialog.py
+++ b/deluge/ui/gtk3/edittrackersdialog.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,12 +6,10 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os.path
-from gi.repository import Gtk
+from gi.repository import Gdk, Gtk
from twisted.internet import defer
import deluge.component as component
@@ -77,7 +74,7 @@ def trackers_tiers_from_text(text_str=''):
return trackers
-class EditTrackersDialog(object):
+class EditTrackersDialog:
def __init__(self, torrent_id, parent=None):
self.torrent_id = torrent_id
self.builder = Gtk.Builder()
@@ -132,6 +129,12 @@ class EditTrackersDialog(object):
self.dialog.connect('delete-event', self._on_delete_event)
self.dialog.connect('response', self._on_response)
+ self.treeview.connect('button_press_event', self.on_button_press_event)
+
+ self.add_tracker_dialog.connect('key-press-event', self.on_key_add_press_event)
+ self.add_tracker_dialog.connect('delete-event', self.on_delete_event_add)
+ self.edit_tracker_entry.connect('key-press-event', self.on_key_edit_press_event)
+ self.edit_tracker_entry.connect('delete-event', self.on_delete_event_edit)
def run(self):
# Make sure we have a torrent_id.. if not just return
@@ -191,7 +194,7 @@ class EditTrackersDialog(object):
self.old_trackers = list(status['trackers'])
for tracker in self.old_trackers:
self.add_tracker(tracker['tier'], tracker['url'])
- self.treeview.set_cursor((0))
+ self.treeview.set_cursor(0)
self.dialog.show()
def add_tracker(self, tier, url):
@@ -207,6 +210,7 @@ class EditTrackersDialog(object):
# Show the add tracker dialog
self.add_tracker_dialog.show()
self.builder.get_object('textview_trackers').grab_focus()
+ self.dialog.set_sensitive(False)
def on_button_remove_clicked(self, widget):
log.debug('on_button_remove_clicked')
@@ -215,8 +219,18 @@ class EditTrackersDialog(object):
self.liststore.remove(selected)
def on_button_edit_clicked(self, widget):
- """edits an existing tracker"""
+ """edits an existing tracker on edit button click"""
log.debug('on_button_edit_clicked')
+ self._edit_tracker()
+
+ def on_button_press_event(self, widget, event):
+ """edits an existing tracker on double click on tracker name"""
+ if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
+ log.debug('button_press_event double click')
+ self._edit_tracker()
+
+ def _edit_tracker(self):
+ """edits an existing tracker"""
selected = self.get_selected()
if selected:
tracker = self.liststore.get_value(selected, 1)
@@ -225,11 +239,27 @@ class EditTrackersDialog(object):
self.edit_tracker_entry.grab_focus()
self.dialog.set_sensitive(False)
- def on_button_edit_cancel_clicked(self, widget):
- log.debug('on_button_edit_cancel_clicked')
+ def _close_edit_dialog(self):
self.dialog.set_sensitive(True)
self.edit_tracker_entry.hide()
+ def on_button_edit_cancel_clicked(self, widget):
+ """handles the cancel button"""
+ log.debug('on_button_edit_cancel_clicked')
+ self._close_edit_dialog()
+
+ def on_key_edit_press_event(self, widget, event):
+ """handles Escape key press"""
+ if event.keyval == Gdk.KEY_Escape:
+ log.debug('on_key_edit_press_event')
+ self._close_edit_dialog()
+
+ def on_delete_event_edit(self, widget, event):
+ """handles the Top-Right X button"""
+ log.debug('on_delete_event_edit')
+ self._close_edit_dialog()
+ return True
+
def on_button_edit_ok_clicked(self, widget):
log.debug('on_button_edit_ok_clicked')
selected = self.get_selected()
@@ -290,11 +320,29 @@ class EditTrackersDialog(object):
# Clear the entry widget and hide the dialog
textview_buf.set_text('')
+ self.dialog.set_sensitive(True)
self.add_tracker_dialog.hide()
- def on_button_add_cancel_clicked(self, widget):
- log.debug('on_button_add_cancel_clicked')
+ def _discard_and_close_add_dialog(self):
# Clear the entry widget and hide the dialog
b = Gtk.TextBuffer()
self.builder.get_object('textview_trackers').set_buffer(b)
+ self.dialog.set_sensitive(True)
self.add_tracker_dialog.hide()
+
+ def on_button_add_cancel_clicked(self, widget):
+ """handles the cancel button"""
+ log.debug('on_button_add_cancel_clicked')
+ self._discard_and_close_add_dialog()
+
+ def on_key_add_press_event(self, widget, event):
+ """handles Escape key press"""
+ if event.keyval == Gdk.KEY_Escape:
+ log.debug('on_key_add_press_event')
+ self._discard_and_close_add_dialog()
+
+ def on_delete_event_add(self, widget, event):
+ """handles the Top-Right X button"""
+ log.debug('on_delete_event_add')
+ self._discard_and_close_add_dialog()
+ return True
diff --git a/deluge/ui/gtk3/files_tab.py b/deluge/ui/gtk3/files_tab.py
index b3bd5b5..24c1697 100644
--- a/deluge/ui/gtk3/files_tab.py
+++ b/deluge/ui/gtk3/files_tab.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,21 +6,26 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
import json
import logging
import os.path
+import gi # isort:skip (Required before Gtk import).
+
+gi.require_version('Gtk', '3.0')
+
+# isort:imports-thirdparty
from gi.repository import Gio, Gtk
from gi.repository.Gdk import DragAction, ModifierType, keyval_name
from gi.repository.GObject import TYPE_UINT64
+# isort:imports-firstparty
import deluge.component as component
from deluge.common import open_file, show_file
from deluge.ui.client import client
from deluge.ui.common import FILE_PRIORITY
+# isort:imports-localfolder
from .common import (
listview_replace_treestore,
load_pickled_state_file,
@@ -77,7 +81,7 @@ def cell_progress(column, cell, model, row, data):
class FilesTab(Tab):
def __init__(self):
- super(FilesTab, self).__init__('Files', 'files_tab', 'files_tab_label')
+ super().__init__('Files', 'files_tab', 'files_tab_label')
self.listview = self.main_builder.get_object('files_listview')
# filename, size, progress string, progress value, priority, file index, icon id
@@ -442,7 +446,7 @@ class FilesTab(Tab):
try:
value = completed_bytes / self.treestore[parent][1] * 100
except ZeroDivisionError:
- # Catch the unusal error found when moving folders around
+ # Catch the unusual error found when moving folders around
value = 0
self.treestore[parent][3] = value
self.treestore[parent][2] = '%i%%' % value
diff --git a/deluge/ui/gtk3/filtertreeview.py b/deluge/ui/gtk3/filtertreeview.py
index bd781e0..40752d7 100644
--- a/deluge/ui/gtk3/filtertreeview.py
+++ b/deluge/ui/gtk3/filtertreeview.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# 2008 Andrew Resch <andrewresch@gmail.com>
@@ -9,8 +8,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
import warnings
@@ -24,7 +21,7 @@ from deluge.common import TORRENT_STATE, decode_bytes, resource_filename
from deluge.configmanager import ConfigManager
from deluge.ui.client import client
-from .common import get_pixbuf, get_pixbuf_at_size
+from .common import get_pixbuf
log = logging.getLogger(__name__)
@@ -89,10 +86,10 @@ class FilterTreeView(component.Component):
self.treeview.set_headers_visible(False)
self.treeview.set_level_indentation(-21)
# Force theme to use expander-size so we don't cut out entries due to indentation hack.
- Gtk.rc_parse_string(
- """style "treeview-style" {GtkTreeView::expander-size = 7}
- class "GtkTreeView" style "treeview-style" """
- )
+ provider = Gtk.CssProvider()
+ provider.load_from_data(b'* {-GtkTreeView-expander-size: 9;}')
+ context = self.treeview.get_style_context()
+ context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
self.treeview.set_model(self.treestore)
self.treeview.get_selection().connect('changed', self.on_selection_changed)
@@ -100,11 +97,6 @@ class FilterTreeView(component.Component):
self.treeview.connect('button-press-event', self.on_button_press_event)
- # colors using current theme.
- style_ctx = component.get('MainWindow').window.get_style_context()
- self.colour_background = style_ctx.get_background_color(Gtk.StateFlags.NORMAL)
- self.colour_foreground = style_ctx.get_color(Gtk.StateFlags.NORMAL)
-
# filtertree menu
builder = Gtk.Builder()
builder.add_from_file(
@@ -229,7 +221,7 @@ class FilterTreeView(component.Component):
label = decode_bytes(model.get_value(row, 2))
count = model.get_value(row, 3)
- # Supress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
+ # Suppress Warning: g_object_set_qdata: assertion `G_IS_OBJECT (object)' failed
original_filters = warnings.filters[:]
warnings.simplefilter('ignore')
try:
@@ -261,7 +253,7 @@ class FilterTreeView(component.Component):
return get_pixbuf('%s16.png' % pix)
def set_row_image(self, cat, value, filename):
- pix = get_pixbuf_at_size(filename, 16)
+ pix = get_pixbuf(filename, size=16)
row = self.filters[(cat, value)]
self.treestore.set_value(row, 4, pix)
return False
diff --git a/deluge/ui/gtk3/glade/add_torrent_dialog.infohash.ui b/deluge/ui/gtk3/glade/add_torrent_dialog.infohash.ui
index a7a8cae..8adbad3 100644
--- a/deluge/ui/gtk3/glade/add_torrent_dialog.infohash.ui
+++ b/deluge/ui/gtk3/glade/add_torrent_dialog.infohash.ui
@@ -144,8 +144,6 @@
<property name="invisible_char">•</property>
<property name="activates_default">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/deluge/ui/gtk3/glade/add_torrent_dialog.ui b/deluge/ui/gtk3/glade/add_torrent_dialog.ui
index 4d36803..7183272 100644
--- a/deluge/ui/gtk3/glade/add_torrent_dialog.ui
+++ b/deluge/ui/gtk3/glade/add_torrent_dialog.ui
@@ -727,8 +727,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_maxup">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment2</property>
<property name="update_policy">if-valid</property>
</object>
@@ -741,8 +739,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_maxconnections">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment3</property>
</object>
<packing>
@@ -754,8 +750,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_maxupslots">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment4</property>
</object>
<packing>
@@ -767,8 +761,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_maxdown">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment1</property>
</object>
<packing>
diff --git a/deluge/ui/gtk3/glade/add_torrent_dialog.url.ui b/deluge/ui/gtk3/glade/add_torrent_dialog.url.ui
index ecbd0f7..6b75b23 100644
--- a/deluge/ui/gtk3/glade/add_torrent_dialog.url.ui
+++ b/deluge/ui/gtk3/glade/add_torrent_dialog.url.ui
@@ -143,8 +143,6 @@
<property name="invisible_char">•</property>
<property name="activates_default">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/deluge/ui/gtk3/glade/connect_peer_dialog.ui b/deluge/ui/gtk3/glade/connect_peer_dialog.ui
index f5e9337..4a60751 100644
--- a/deluge/ui/gtk3/glade/connect_peer_dialog.ui
+++ b/deluge/ui/gtk3/glade/connect_peer_dialog.ui
@@ -128,8 +128,6 @@
<property name="width_chars">39</property>
<property name="text" translatable="yes">hostname:port</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/deluge/ui/gtk3/glade/connection_manager.addhost.ui b/deluge/ui/gtk3/glade/connection_manager.addhost.ui
index 641a71c..ea5376e 100644
--- a/deluge/ui/gtk3/glade/connection_manager.addhost.ui
+++ b/deluge/ui/gtk3/glade/connection_manager.addhost.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkAdjustment" id="adjustment_port">
@@ -16,7 +16,7 @@
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
- <child>
+ <child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
@@ -24,11 +24,12 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
- <property name="spacing">2</property>
+ <property name="spacing">5</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area5">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="margin_top">15</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button_addhost_cancel">
@@ -65,49 +66,41 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkBox" id="hbox2">
+ <object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="spacing">5</property>
+ <property name="row_spacing">5</property>
+ <property name="column_spacing">5</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Hostname:</property>
+ <property name="xalign">0</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
</packing>
</child>
<child>
- <object class="GtkAlignment" id="alignment4">
+ <object class="GtkEntry" id="entry_hostname">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="left_padding">1</property>
- <child>
- <object class="GtkEntry" id="entry_hostname">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">•</property>
- <property name="activates_default">True</property>
- <property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <signal name="paste-clipboard" handler="on_entry_host_paste_clipboard" swapped="no"/>
- </object>
- </child>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">True</property>
+ <property name="truncate_multiline">True</property>
+ <signal name="paste-clipboard" handler="on_entry_host_paste_clipboard" swapped="no"/>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
</packing>
</child>
<child>
@@ -115,116 +108,90 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Port:</property>
+ <property name="xalign">0</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="halign">start</property>
<property name="max_length">5</property>
<property name="invisible_char">•</property>
<property name="width_chars">5</property>
+ <property name="max_width_chars">5</property>
<property name="progress_pulse_step">1</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_port</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">3</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
</packing>
</child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkGrid" id="table1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
<child>
- <object class="GtkAlignment" id="alignment3">
+ <object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="left_padding">5</property>
- <child>
- <object class="GtkEntry" id="entry_password">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="invisible_char">•</property>
- <property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- </object>
- </child>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Username:</property>
+ <property name="xalign">0</property>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
</packing>
</child>
<child>
- <object class="GtkAlignment" id="alignment2">
+ <object class="GtkEntry" id="entry_username">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="left_padding">5</property>
- <child>
- <object class="GtkEntry" id="entry_username">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">•</property>
- <property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- </object>
- </child>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="invisible_char">•</property>
+ <property name="truncate_multiline">True</property>
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">0</property>
+ <property name="top_attach">2</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label5">
+ <object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
- <property name="label" translatable="yes">Username:</property>
+ <property name="label" translatable="yes">Password:</property>
+ <property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">0</property>
+ <property name="top_attach">3</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label6">
+ <object class="GtkEntry" id="entry_password">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Password:</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">•</property>
+ <property name="truncate_multiline">True</property>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">0</property>
</packing>
</child>
</object>
diff --git a/deluge/ui/gtk3/glade/connection_manager.ui b/deluge/ui/gtk3/glade/connection_manager.ui
index 11516aa..44f4b34 100644
--- a/deluge/ui/gtk3/glade/connection_manager.ui
+++ b/deluge/ui/gtk3/glade/connection_manager.ui
@@ -30,7 +30,7 @@
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">300</property>
- <property name="default_height">250</property>
+ <property name="default_height">285</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<child>
diff --git a/deluge/ui/gtk3/glade/create_torrent_dialog.remote_path.ui b/deluge/ui/gtk3/glade/create_torrent_dialog.remote_path.ui
index dc7b7e9..4328330 100644
--- a/deluge/ui/gtk3/glade/create_torrent_dialog.remote_path.ui
+++ b/deluge/ui/gtk3/glade/create_torrent_dialog.remote_path.ui
@@ -143,8 +143,6 @@
<property name="invisible_char">•</property>
<property name="activates_default">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/deluge/ui/gtk3/glade/create_torrent_dialog.remote_save.ui b/deluge/ui/gtk3/glade/create_torrent_dialog.remote_save.ui
index a380718..7123054 100644
--- a/deluge/ui/gtk3/glade/create_torrent_dialog.remote_save.ui
+++ b/deluge/ui/gtk3/glade/create_torrent_dialog.remote_save.ui
@@ -143,8 +143,6 @@
<property name="invisible_char">•</property>
<property name="activates_default">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/deluge/ui/gtk3/glade/create_torrent_dialog.ui b/deluge/ui/gtk3/glade/create_torrent_dialog.ui
index c27a4b8..0d15940 100644
--- a/deluge/ui/gtk3/glade/create_torrent_dialog.ui
+++ b/deluge/ui/gtk3/glade/create_torrent_dialog.ui
@@ -356,8 +356,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
@@ -393,8 +391,6 @@
<object class="GtkEntry" id="entry_comments">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
@@ -810,6 +806,7 @@
<property name="receives_default">True</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_button_cancel_clicked" swapped="no"/>
+ <accelerator key="Escape" signal="clicked"/>
</object>
<packing>
<property name="expand">False</property>
diff --git a/deluge/ui/gtk3/glade/edit_trackers.edit.ui b/deluge/ui/gtk3/glade/edit_trackers.edit.ui
index 2521e8f..fc3e51b 100644
--- a/deluge/ui/gtk3/glade/edit_trackers.edit.ui
+++ b/deluge/ui/gtk3/glade/edit_trackers.edit.ui
@@ -144,8 +144,6 @@
<property name="invisible_char">•</property>
<property name="activates_default">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/deluge/ui/gtk3/glade/main_window.tabs.ui b/deluge/ui/gtk3/glade/main_window.tabs.ui
index 30bd395..7ecf618 100644
--- a/deluge/ui/gtk3/glade/main_window.tabs.ui
+++ b/deluge/ui/gtk3/glade/main_window.tabs.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkAdjustment" id="spin_max_connections_adjustment">
@@ -38,14 +38,14 @@
</object>
<object class="GtkWindow" id="tabs">
<property name="can_focus">False</property>
- <child>
+ <child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkNotebook" id="dummy_nb_see_main_win_torrent_info">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="tab_pos">left</property>
+ <property name="enable_popup">True</property>
<child>
<object class="GtkScrolledWindow" id="status_tab">
<property name="visible">True</property>
@@ -105,7 +105,7 @@
<property name="row_spacing">5</property>
<property name="column_spacing">10</property>
<child>
- <object class="GtkLabel" id="summary_total_uploaded">
+ <object class="GtkLabel" id="summary_download_speed">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="width_chars">20</property>
@@ -305,7 +305,7 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="summary_download_speed">
+ <object class="GtkLabel" id="summary_total_uploaded">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="width_chars">15</property>
@@ -490,7 +490,6 @@
<object class="GtkLabel" id="status_tab_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="ypad">1</property>
<property name="label" translatable="yes">_Status</property>
<property name="use_underline">True</property>
</object>
@@ -850,12 +849,6 @@
<child>
<placeholder/>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
</child>
</object>
@@ -871,7 +864,6 @@
<object class="GtkLabel" id="details_tab_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="ypad">1</property>
<property name="label" translatable="yes">_Details</property>
<property name="use_underline">True</property>
</object>
@@ -902,7 +894,6 @@
<object class="GtkLabel" id="files_tab_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="ypad">1</property>
<property name="label" translatable="yes">Fi_les</property>
<property name="use_underline">True</property>
</object>
@@ -933,7 +924,6 @@
<object class="GtkLabel" id="peers_tab_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="ypad">1</property>
<property name="label" translatable="yes">_Peers</property>
<property name="use_underline">True</property>
</object>
@@ -1065,23 +1055,20 @@
</packing>
</child>
<child>
- <placeholder/>
- </child>
- <child>
<object class="GtkCheckButton" id="chk_super_seeding">
<property name="label" translatable="yes">Super Seeding</property>
- <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="halign">start</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_chk_toggled" swapped="no"/>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">4</property>
- </packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
</child>
<child>
<object class="GtkCheckButton" id="chk_move_completed">
@@ -1113,6 +1100,9 @@
<property name="position">6</property>
</packing>
</child>
+ <child>
+ <placeholder/>
+ </child>
</object>
</child>
</object>
@@ -1176,8 +1166,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">spin_stop_ratio_adjustment</property>
<property name="digits">1</property>
<property name="numeric">True</property>
@@ -1277,8 +1265,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">spin_max_connections_adjustment</property>
<property name="numeric">True</property>
</object>
@@ -1292,8 +1278,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">spin_max_upload_adjustment</property>
<property name="digits">1</property>
<property name="numeric">True</property>
@@ -1308,8 +1292,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">spin_max_download_adjustment</property>
<property name="climb_rate">1</property>
<property name="digits">1</property>
@@ -1366,8 +1348,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">spin_max_upload_slots_adjustment</property>
<property name="numeric">True</property>
</object>
@@ -1453,7 +1433,6 @@
<object class="GtkLabel" id="options_tab_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="ypad">1</property>
<property name="label" translatable="yes">_Options</property>
<property name="use_underline">True</property>
</object>
@@ -1664,7 +1643,6 @@
<object class="GtkLabel" id="trackers_tab_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="ypad">1</property>
<property name="label" translatable="yes">_Trackers</property>
<property name="use_underline">True</property>
</object>
diff --git a/deluge/ui/gtk3/glade/main_window.tabs.ui~ b/deluge/ui/gtk3/glade/main_window.tabs.ui~
new file mode 100644
index 0000000..4362183
--- /dev/null
+++ b/deluge/ui/gtk3/glade/main_window.tabs.ui~
@@ -0,0 +1,1507 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <object class="GtkAdjustment" id="spin_max_connections_adjustment">
+ <property name="lower">-1</property>
+ <property name="upper">999999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ <signal name="value-changed" handler="on_spin_value_changed" swapped="no"/>
+ </object>
+ <object class="GtkAdjustment" id="spin_max_download_adjustment">
+ <property name="lower">-1</property>
+ <property name="upper">2097151</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ <signal name="value-changed" handler="on_spin_value_changed" swapped="no"/>
+ </object>
+ <object class="GtkAdjustment" id="spin_max_upload_adjustment">
+ <property name="lower">-1</property>
+ <property name="upper">2097151</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ <signal name="value-changed" handler="on_spin_value_changed" swapped="no"/>
+ </object>
+ <object class="GtkAdjustment" id="spin_max_upload_slots_adjustment">
+ <property name="lower">-1</property>
+ <property name="upper">999999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ <signal name="value-changed" handler="on_spin_value_changed" swapped="no"/>
+ </object>
+ <object class="GtkAdjustment" id="spin_stop_ratio_adjustment">
+ <property name="upper">999999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ <signal name="value-changed" handler="on_spin_value_changed" swapped="no"/>
+ </object>
+ <object class="GtkWindow" id="tabs">
+ <property name="can_focus">False</property>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="dummy_nb_see_main_win_torrent_info">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="enable_popup">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="status_tab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resize_mode">queue</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment43">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">5</property>
+ <property name="bottom_padding">2</property>
+ <property name="left_padding">10</property>
+ <property name="right_padding">10</property>
+ <child>
+ <object class="GtkBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkBox" id="status_progress_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkProgressBar" id="progressbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pulse_step">0.10000000149</property>
+ <property name="show_text">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="table8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">5</property>
+ <property name="column_spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="summary_download_speed">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_chars">20</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_total_downloaded">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_upload_speed">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_chars">15</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_seed_rank">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_availability">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">word-char</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_share_ratio">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_peers">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_chars">10</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_eta">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_active_time">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_seed_time">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_last_transfer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">char</property>
+ </object>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_last_seen_complete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">char</property>
+ </object>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label42">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Down Speed:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label43">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Up Speed:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label38">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Downloaded:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label39">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Uploaded:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_seeds">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_chars">10</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_total_uploaded">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="width_chars">15</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_seeds">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Seeds:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_peers">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Peers:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label41">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Share Ratio:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_availablity">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Availability:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_seed_rank">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Seed Rank:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_eta">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">ETA Time:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_last_transfer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Last Transfer:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_active_time">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Active Time:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_last_seen_complete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Complete Seen:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_seed_time">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Seeding Time:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="status_tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Status</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="details_tab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkViewport" id="viewport2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resize_mode">queue</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment54">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">5</property>
+ <property name="bottom_padding">2</property>
+ <property name="left_padding">10</property>
+ <property name="right_padding">15</property>
+ <child>
+ <object class="GtkGrid" id="table_details">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">5</property>
+ <property name="column_spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="summary_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">word-char</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_total_size">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_num_files">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_completed">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_date_added">
+ <property name="width_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_private">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_pieces">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Pieces:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_pieces">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_hash">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="width_chars">40</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_torrent_path">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">char</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_comments">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="wrap_mode">char</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_creator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="wrap_mode">char</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Name:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_path">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Download Folder:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_date_added">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Added:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_total_size">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Total Size:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_num_files">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Total Files:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_hash">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Hash:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_creator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Created By:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_comments">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Comments:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_completed">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Completed:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_private">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Private Torrent:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="vseparator5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="height">4</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="details_tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Details</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="files_tab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkTreeView" id="files_listview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeselection1"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="files_tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Fi_les</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="peers_tab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkTreeView" id="peers_listview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeselection2"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="peers_tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Peers</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="options_tab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkViewport" id="viewport3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resize_mode">queue</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">5</property>
+ <property name="bottom_padding">2</property>
+ <property name="left_padding">5</property>
+ <property name="right_padding">15</property>
+ <child>
+ <object class="GtkGrid" id="table6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">2</property>
+ <property name="left_padding">5</property>
+ <property name="right_padding">5</property>
+ <child>
+ <object class="GtkBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label_owner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Owner:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_owner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="wrap_mode">char</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">10</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_shared">
+ <property name="label" translatable="yes">Shared</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_prioritize_first_last">
+ <property name="label" translatable="yes">Prioritize First/Last</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_sequential_download">
+ <property name="label" translatable="yes">Sequential Download</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_super_seeding">
+ <property name="label" translatable="yes">Super Seeding</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_move_completed">
+ <property name="label" translatable="yes">Move completed:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_move_completed_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="hbox_move_completed_path_chooser">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">10</property>
+ <child>
+ <object class="GtkBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">15</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="chk_auto_managed">
+ <property name="label" translatable="yes">Auto Managed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_stop_at_ratio">
+ <property name="label" translatable="yes">Stop seed at ratio:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_stop_at_ratio_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">10</property>
+ <property name="right_padding">10</property>
+ <child>
+ <object class="GtkSpinButton" id="spin_stop_ratio">
+ <property name="width_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">spin_stop_ratio_adjustment</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">10</property>
+ <child>
+ <object class="GtkCheckButton" id="chk_remove_at_ratio">
+ <property name="label" translatable="yes">Remove at ratio</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="hseparator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">7</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="button_apply">
+ <property name="label" translatable="yes">_Apply</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_underline">True</property>
+ <signal name="clicked" handler="on_button_apply_clicked" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkGrid" id="table1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="row_spacing">2</property>
+ <property name="column_spacing">4</property>
+ <child>
+ <object class="GtkSpinButton" id="spin_max_connections">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">spin_max_connections_adjustment</property>
+ <property name="numeric">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin_max_upload">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">spin_max_upload_adjustment</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin_max_download">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">spin_max_download_adjustment</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Upload Speed:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">K/s</property>
+ <property name="ellipsize">start</property>
+ <attributes>
+ <attribute name="scale" value="0.90000000000000002"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">K/s</property>
+ <attributes>
+ <attribute name="scale" value="0.90000000000000002"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin_max_upload_slots">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">spin_max_upload_slots_adjustment</property>
+ <property name="numeric">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Download Speed:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Connections:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Upload Slots:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Bandwidth Limits</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="options_tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Options</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="trackers_tab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkTreeView" id="trackers_listview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeselection3"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="trackers_tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Trackers</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">5</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/deluge/ui/gtk3/glade/main_window.ui b/deluge/ui/gtk3/glade/main_window.ui
index 43d8bf0..ecbb8f6 100644
--- a/deluge/ui/gtk3/glade/main_window.ui
+++ b/deluge/ui/gtk3/glade/main_window.ui
@@ -174,6 +174,7 @@
<property name="use_stock">False</property>
<property name="accel_group">accelgroup1</property>
<signal name="activate" handler="on_menuitem_quit_activate" swapped="no"/>
+ <accelerator key="Q" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
</object>
diff --git a/deluge/ui/gtk3/glade/other_dialog.ui b/deluge/ui/gtk3/glade/other_dialog.ui
index 26d3d08..01a5597 100644
--- a/deluge/ui/gtk3/glade/other_dialog.ui
+++ b/deluge/ui/gtk3/glade/other_dialog.ui
@@ -148,8 +148,6 @@
<property name="max_length">6</property>
<property name="activates_default">True</property>
<property name="width_chars">6</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment1</property>
</object>
</child>
diff --git a/deluge/ui/gtk3/glade/path_combo_chooser.ui b/deluge/ui/gtk3/glade/path_combo_chooser.ui
index f79685d..871bac0 100644
--- a/deluge/ui/gtk3/glade/path_combo_chooser.ui
+++ b/deluge/ui/gtk3/glade/path_combo_chooser.ui
@@ -98,8 +98,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">2</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment3</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
@@ -571,6 +569,7 @@
<object class="GtkEntry" id="entry_text">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="hexpand">True</property>
<property name="invisible_char">•</property>
<signal name="changed" handler="on_entry_text_changed" swapped="no"/>
<signal name="delete-text" handler="on_entry_text_delete_text" swapped="no"/>
diff --git a/deluge/ui/gtk3/glade/preferences_dialog.ui b/deluge/ui/gtk3/glade/preferences_dialog.ui
index e1bbc74..aa1531d 100644
--- a/deluge/ui/gtk3/glade/preferences_dialog.ui
+++ b/deluge/ui/gtk3/glade/preferences_dialog.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkAdjustment" id="adjustment_cache_expiry">
@@ -245,7 +245,7 @@
<property name="type_hint">dialog</property>
<signal name="configure-event" handler="on_pref_dialog_configure_event" swapped="no"/>
<signal name="delete-event" handler="on_pref_dialog_delete_event" swapped="no"/>
- <child>
+ <child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
@@ -479,6 +479,23 @@
</packing>
</child>
<child>
+ <object class="GtkCheckButton" id="urldetect_toggle">
+ <property name="label" translatable="yes">Detect torrent URLs from clipboard</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Automatically open Add Torrent dialog when clipboard contains a torrent URL</property>
+ <property name="halign">start</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_urldetect_toggle_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkCheckButton" id="piecesbar_toggle">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -501,7 +518,7 @@ and daemon (does not apply in Standalone mode).</property>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
<child>
@@ -697,7 +714,7 @@ and daemon (does not apply in Standalone mode).</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">3</property>
+ <property name="position">4</property>
</packing>
</child>
</object>
@@ -912,8 +929,6 @@ and daemon (does not apply in Standalone mode).</property>
<property name="width_chars">16</property>
<property name="text">********</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1078,7 +1093,7 @@ and daemon (does not apply in Standalone mode).</property>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">&lt;b&gt;Languge&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;Language&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
@@ -1133,6 +1148,7 @@ and daemon (does not apply in Standalone mode).</property>
<property name="top_padding">2</property>
<property name="bottom_padding">2</property>
<property name="left_padding">12</property>
+ <property name="right_padding">12</property>
<child>
<object class="GtkGrid" id="table9">
<property name="visible">True</property>
@@ -1528,8 +1544,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_max_connections_per_second">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_conn_per_sec</property>
<property name="numeric">True</property>
</object>
@@ -1542,8 +1556,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_max_half_open_connections">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_half_open_conn</property>
<property name="numeric">True</property>
</object>
@@ -1607,8 +1619,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_conn_global</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
@@ -1638,8 +1648,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum download speed for all torrents. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_download</property>
<property name="climb_rate">1</property>
<property name="digits">1</property>
@@ -1655,8 +1663,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum upload speed for all torrents. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_upload</property>
<property name="climb_rate">1</property>
<property name="digits">1</property>
@@ -1672,8 +1678,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum upload slots for all torrents. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_upload_slots_global</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
@@ -1832,8 +1836,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum upload slots per torrent. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_upload_slots_per_torrent</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
@@ -1849,8 +1851,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum number of connections per torrent. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_conn_per_torrent</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
@@ -1913,8 +1913,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum number download speed per torrent. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_download_per_torrent</property>
<property name="digits">1</property>
<property name="numeric">True</property>
@@ -1929,8 +1927,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The maximum upload speed per torrent. Set -1 for unlimited.</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_max_upload_per_torrent</property>
<property name="digits">1</property>
<property name="numeric">True</property>
@@ -2114,8 +2110,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_active">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_active</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
@@ -2129,8 +2123,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_seeding">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_seeding</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
@@ -2168,8 +2160,6 @@ used sparingly.</property>
<object class="GtkSpinButton" id="spin_downloading">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_downloading</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
@@ -2204,7 +2194,7 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="tooltip_text" translatable="yes">Torrents not transfering any data do not count towards download/seeding active count.</property>
+ <property name="tooltip_text" translatable="yes">Torrents not transferring any data do not count towards download/seeding active count.</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
@@ -2306,8 +2296,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_seed_time_limit</property>
</object>
<packing>
@@ -2320,8 +2308,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_time_ratio_limit</property>
<property name="digits">2</property>
</object>
@@ -2335,8 +2321,6 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_share_ratio_limit</property>
<property name="digits">2</property>
</object>
@@ -2408,8 +2392,6 @@ used sparingly.</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_share_ratio</property>
<property name="digits">2</property>
<property name="numeric">True</property>
@@ -2555,12 +2537,10 @@ used sparingly.</property>
<object class="GtkEntry" id="entry_interface">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="tooltip_text" translatable="yes">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">15</property>
+ <property name="tooltip_text" translatable="yes">IP address or network interface name to listen for incoming BitTorrent connections. Leave empty to use system default.</property>
+ <property name="max_length">40</property>
<property name="width_chars">15</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
</child>
</object>
@@ -2569,7 +2549,7 @@ used sparingly.</property>
<object class="GtkLabel" id="label110">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Incoming Address</property>
+ <property name="label" translatable="yes">Incoming Interface</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -2611,8 +2591,6 @@ used sparingly.</property>
<property name="can_focus">True</property>
<property name="max_length">5</property>
<property name="max_width_chars">6</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_incoming_port</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
@@ -2711,6 +2689,24 @@ used sparingly.</property>
</packing>
</child>
<child>
+ <object class="GtkAlignment" id="alignment31">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">10</property>
+ <child>
+ <object class="GtkSpinner" id="port_spinner">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkAlignment" id="alignment48">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -2725,7 +2721,7 @@ used sparingly.</property>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
@@ -2776,14 +2772,12 @@ used sparingly.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">
-The network interface name or IP address for outgoing BitTorrent connections. (Leave empty for default.)
+ IP address or network interface name for outgoing BitTorrent connections. Leave empty to use system default.
</property>
- <property name="max_length">15</property>
+ <property name="max_length">40</property>
<property name="invisible_char">●</property>
<property name="width_chars">15</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
</child>
</object>
@@ -2862,8 +2856,7 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="max_length">5</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
+ <property name="width_chars">7</property>
<property name="adjustment">adjustment_spin_outgoing_port_min</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
@@ -2894,8 +2887,7 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="max_length">5</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
+ <property name="width_chars">7</property>
<property name="adjustment">adjustment_spin_outgoing_port_max</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
@@ -3217,8 +3209,6 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<property name="width_chars">1</property>
<property name="text">0x00</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">False</property>
@@ -3326,8 +3316,6 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -3351,8 +3339,6 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<signal name="paste-clipboard" handler="on_entry_proxy_host_paste_clipboard" swapped="no"/>
</object>
<packing>
@@ -3380,8 +3366,6 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<object class="GtkSpinButton" id="spin_proxy_port">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_proxy_port</property>
<property name="numeric">True</property>
</object>
@@ -3397,8 +3381,6 @@ The network interface name or IP address for outgoing BitTorrent connections. (L
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -3677,8 +3659,6 @@ the proxy instead of using the local DNS service</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_cache_size</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
@@ -3694,8 +3674,6 @@ the proxy instead of using the local DNS service</property>
<property name="can_focus">True</property>
<property name="max_length">5</property>
<property name="invisible_char">●</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_cache_expiry</property>
</object>
<packing>
@@ -3878,28 +3856,16 @@ the proxy instead of using the local DNS service</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label119">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">The number of blocks that were served from cache.</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Blocks Read Hit:</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
<object class="GtkLabel" id="label122">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">The cache hit ratio for the read cache.</property>
+ <property name="halign">start</property>
<property name="label" translatable="yes">Read Cache Hit Ratio:</property>
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">3</property>
+ <property name="top_attach">2</property>
</packing>
</child>
<child>
@@ -3913,23 +3879,13 @@ the proxy instead of using the local DNS service</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label_cache_num_blocks_cache_hits">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
<object class="GtkLabel" id="label_cache_read_hit_ratio">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">3</property>
+ <property name="top_attach">2</property>
</packing>
</child>
<child>
@@ -3943,7 +3899,7 @@ the proxy instead of using the local DNS service</property>
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">2</property>
+ <property name="top_attach">1</property>
</packing>
</child>
<child>
@@ -3953,7 +3909,7 @@ the proxy instead of using the local DNS service</property>
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">2</property>
+ <property name="top_attach">1</property>
</packing>
</child>
</object>
@@ -4251,8 +4207,6 @@ the proxy instead of using the local DNS service</property>
<property name="tooltip_text" 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="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="expand">False</property>
@@ -4430,8 +4384,6 @@ the proxy instead of using the local DNS service</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_width_chars">6</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
<property name="adjustment">adjustment_spin_daemon_port</property>
</object>
<packing>
diff --git a/deluge/ui/gtk3/glade/torrent_menu.ui b/deluge/ui/gtk3/glade/torrent_menu.ui
index c1b77b4..c9ee289 100644
--- a/deluge/ui/gtk3/glade/torrent_menu.ui
+++ b/deluge/ui/gtk3/glade/torrent_menu.ui
@@ -31,6 +31,11 @@
<property name="icon_name">media-playback-pause-symbolic</property>
<property name="icon_size">1</property>
</object>
+ <object class="GtkImage" id="menu-item-image15">
+ <property name="can_focus">False</property>
+ <property name="icon_name">edit-copy-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
<object class="GtkImage" id="menu-item-image19">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -155,6 +160,17 @@
</object>
</child>
<child>
+ <object class="GtkImageMenuItem" id="menuitem_copymagnet">
+ <property name="label" translatable="yes">_Copy Magnet URI</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_underline">True</property>
+ <property name="image">menu-item-image15</property>
+ <property name="use_stock">False</property>
+ <signal name="activate" handler="on_menuitem_copymagnet_activate" swapped="no"/>
+ </object>
+ </child>
+ <child>
<object class="GtkImageMenuItem" id="menuitem_updatetracker">
<property name="label" translatable="yes">_Update Tracker</property>
<property name="visible">True</property>
diff --git a/deluge/ui/gtk3/gtkui.py b/deluge/ui/gtk3/gtkui.py
index d93bd2e..ddb2eb5 100644
--- a/deluge/ui/gtk3/gtkui.py
+++ b/deluge/ui/gtk3/gtkui.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -8,8 +7,6 @@
#
# pylint: disable=wrong-import-position
-from __future__ import division, unicode_literals
-
import logging
import os
import signal
@@ -18,8 +15,8 @@ import time
import gi # isort:skip (Required before Gtk import).
-gi.require_version('Gtk', '3.0') # NOQA: E402
-gi.require_version('Gdk', '3.0') # NOQA: E402
+gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
# isort:imports-thirdparty
from gi.repository.GLib import set_prgname
@@ -32,7 +29,7 @@ try:
# Install twisted reactor, before any other modules import reactor.
reactor = gtk3reactor.install()
except ReactorAlreadyInstalledError:
- # Running unit tests so trial already installed a rector
+ # Running unit tests so already installed a rector
from twisted.internet import reactor
# isort:imports-firstparty
@@ -45,7 +42,7 @@ from deluge.common import (
windows_check,
)
from deluge.configmanager import ConfigManager, get_config_dir
-from deluge.error import DaemonRunningError
+from deluge.error import DaemonRunningError, LibtorrentImportError
from deluge.i18n import I18N_DOMAIN, set_language, setup_translation
from deluge.ui.client import client
from deluge.ui.hostlist import LOCALHOST
@@ -75,7 +72,7 @@ set_prgname('deluge')
log = logging.getLogger(__name__)
try:
- from setproctitle import setproctitle, getproctitle
+ from setproctitle import getproctitle, setproctitle
except ImportError:
def setproctitle(title):
@@ -121,6 +118,7 @@ DEFAULT_PREFS = {
'show_toolbar': True,
'show_statusbar': True,
'show_tabsbar': True,
+ 'tabsbar_tab_pos': 'top',
'tabsbar_position': 235,
'sidebar_show_zero': False,
'sidebar_show_trackers': True,
@@ -129,6 +127,7 @@ DEFAULT_PREFS = {
'show_rate_in_title': False,
'createtorrent.trackers': [],
'show_piecesbar': False,
+ 'detect_urls': True,
'pieces_color_missing': [65535, 0, 0],
'pieces_color_waiting': [4874, 56494, 0],
'pieces_color_downloading': [65535, 55255, 0],
@@ -138,7 +137,7 @@ DEFAULT_PREFS = {
}
-class GtkUI(object):
+class GtkUI:
def __init__(self, args):
# Setup gtkbuilder/glade translation
setup_translation()
@@ -220,7 +219,7 @@ class GtkUI(object):
menubar_osx(self, self.osxapp)
self.osxapp.ready()
- # Initalize the plugins
+ # Initialize the plugins
self.plugins = PluginManager()
# Show the connection manager
@@ -313,8 +312,8 @@ class GtkUI(object):
'A Deluge daemon (deluged) is already running.\n'
'To use Standalone mode, stop local daemon and restart Deluge.'
)
- except ImportError as ex:
- if 'No module named libtorrent' in str(ex):
+ except LibtorrentImportError as ex:
+ if 'libtorrent library not found' in str(ex):
err_msg = _(
'Only Thin Client mode is available because libtorrent is not installed.\n'
'To use Standalone mode, please install libtorrent package.'
@@ -322,9 +321,17 @@ class GtkUI(object):
else:
log.exception(ex)
err_msg = _(
- 'Only Thin Client mode is available due to unknown Import Error.\n'
+ 'Only Thin Client mode is available due to libtorrent import error: %s\n'
'To use Standalone mode, please see logs for error details.'
+ % (str(ex))
)
+
+ except ImportError as ex:
+ log.exception(ex)
+ err_msg = _(
+ 'Only Thin Client mode is available due to unknown Import Error.\n'
+ 'To use Standalone mode, please see logs for error details.'
+ )
except Exception as ex:
log.exception(ex)
err_msg = _(
diff --git a/deluge/ui/gtk3/ipcinterface.py b/deluge/ui/gtk3/ipcinterface.py
index dc51a87..0ef28d8 100644
--- a/deluge/ui/gtk3/ipcinterface.py
+++ b/deluge/ui/gtk3/ipcinterface.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,14 +6,14 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
import sys
from base64 import b64encode
from glob import glob
from tempfile import mkstemp
+from urllib.parse import urlparse
+from urllib.request import url2pathname
import rencode
import twisted.internet.error
@@ -26,14 +25,6 @@ from deluge.common import decode_bytes, is_magnet, is_url, windows_check
from deluge.configmanager import ConfigManager, get_config_dir
from deluge.ui.client import client
-try:
- from urllib.parse import urlparse
- from urllib.request import url2pathname
-except ImportError:
- # PY2 fallback
- from urlparse import urlparse # pylint: disable=ungrouped-imports
- from urllib import url2pathname # pylint: disable=ungrouped-imports
-
log = logging.getLogger(__name__)
@@ -84,8 +75,8 @@ class IPCInterface(component.Component):
if windows_check():
# If we're on windows we need to check the global mutex to see if deluge is
# already running.
- import win32event
import win32api
+ import win32event
import winerror
self.mutex = win32event.CreateMutex(None, False, 'deluge')
diff --git a/deluge/ui/gtk3/listview.py b/deluge/ui/gtk3/listview.py
index 666bb67..e9f6b10 100644
--- a/deluge/ui/gtk3/listview.py
+++ b/deluge/ui/gtk3/listview.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,20 +6,18 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from gi.repository import GObject, Gtk
-from deluge.common import PY2, decode_bytes
+from deluge.common import decode_bytes
from .common import cmp, load_pickled_state_file, save_pickled_state_file
log = logging.getLogger(__name__)
-class ListViewColumnState(object):
+class ListViewColumnState:
"""Class used for saving/loading column state."""
def __init__(self, name, position, width, visible, sort, sort_order):
@@ -32,13 +29,13 @@ class ListViewColumnState(object):
self.sort_order = sort_order
-class ListView(object):
+class ListView:
"""ListView is used to make custom GtkTreeViews. It supports the adding
and removing of columns, creating a menu for a column toggle list and
support for 'status_field's which are used while updating the columns data.
"""
- class ListViewColumn(object):
+ class ListViewColumn:
"""Holds information regarding a column in the ListView"""
def __init__(self, name, column_indices):
@@ -66,22 +63,20 @@ class ListView(object):
self.pixbuf_index = 0
self.data_func = None
- class TreeviewColumn(Gtk.TreeViewColumn, object):
+ class TreeviewColumn(Gtk.TreeViewColumn):
"""
- TreeViewColumn does not signal right-click events, and we need them
- This subclass is equivalent to TreeViewColumn, but it signals these events
+ TreeViewColumn does not signal right-click events, and we need them
+ This subclass is equivalent to TreeViewColumn, but it signals these events
- Most of the code of this class comes from Quod Libet (http://www.sacredchao.net/quodlibet)
+ Most of the code of this class comes from Quod Libet (http://www.sacredchao.net/quodlibet)
"""
__gsignals__ = {
- 'button-press-event'
- if not PY2
- else b'button-press-event': (GObject.SIGNAL_RUN_LAST, None, (object,))
+ 'button-press-event': (GObject.SIGNAL_RUN_LAST, None, (object,))
}
def __init__(self, title=None, cell_renderer=None, **args):
- """ Constructor, see Gtk.TreeViewColumn """
+ """Constructor, see Gtk.TreeViewColumn"""
Gtk.TreeViewColumn.__init__(self, title, cell_renderer, **args)
label = Gtk.Label(label=title)
self.set_widget(label)
@@ -112,7 +107,7 @@ class ListView(object):
Gtk.TreeViewColumn.set_visible(self, visible)
if self.data_func:
if not visible:
- # Set data function to None to prevent unecessary calls when column is hidden
+ # Set data function to None to prevent unnecessary calls when column is hidden
self.set_cell_data_func(self.cell_renderer, None, func_data=None)
else:
self.set_cell_data_func(
@@ -144,7 +139,6 @@ class ListView(object):
self.liststore = None
self.model_filter = None
- self.treeview.set_rules_hint(True)
self.treeview.set_reorderable(False)
self.treeview.set_rubber_banding(True) # Enable mouse multi-row selection.
self.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
@@ -281,7 +275,7 @@ class ListView(object):
def save_state(self, filename):
"""Saves the listview state (column positions and visibility) to
- filename."""
+ filename."""
# A list of ListViewColumnStates
state = []
@@ -627,8 +621,7 @@ class ListView(object):
unique=False,
default_sort=False,
):
- """Add a text column to the listview. Only the header name is required.
- """
+ """Add a text column to the listview. Only the header name is required."""
render = Gtk.CellRendererText()
self.add_column(
header,
diff --git a/deluge/ui/gtk3/mainwindow.py b/deluge/ui/gtk3/mainwindow.py
index 5b4240c..d11ff31 100644
--- a/deluge/ui/gtk3/mainwindow.py
+++ b/deluge/ui/gtk3/mainwindow.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os.path
from hashlib import sha1 as sha
@@ -20,11 +17,11 @@ from twisted.internet import reactor
from twisted.internet.error import ReactorNotRunning
import deluge.component as component
-from deluge.common import decode_bytes, fspeed, resource_filename
+from deluge.common import decode_bytes, fspeed, is_magnet, is_url, resource_filename
from deluge.configmanager import ConfigManager
from deluge.ui.client import client
-from .common import get_deluge_icon, windowing
+from .common import get_clipboard_text, get_deluge_icon, windowing
from .dialogs import PasswordDialog
from .ipcinterface import process_args
@@ -45,7 +42,7 @@ if windowing('X11'):
log = logging.getLogger(__name__)
-class _GtkBuilderSignalsHolder(object):
+class _GtkBuilderSignalsHolder:
def connect_signals(self, mapping_or_class):
if isinstance(mapping_or_class, dict):
@@ -108,6 +105,7 @@ class MainWindow(component.Component):
self.window = self.main_builder.get_object('main_window')
self.window.set_icon(get_deluge_icon())
self.tabsbar_pane = self.main_builder.get_object('tabsbar_pane')
+ self.tabsbar_torrent_info = self.main_builder.get_object('torrent_info')
self.sidebar_pane = self.main_builder.get_object('sidebar_pane')
# Keep a list of components to pause and resume when changing window state.
@@ -131,6 +129,7 @@ class MainWindow(component.Component):
self.window.connect('configure-event', self.on_window_configure_event)
self.window.connect('delete-event', self.on_window_delete_event)
self.window.connect('drag-data-received', self.on_drag_data_received_event)
+ self.window.connect('notify::is-active', self.on_focus)
self.tabsbar_pane.connect(
'notify::position', self.on_tabsbar_pane_position_event
)
@@ -147,6 +146,9 @@ class MainWindow(component.Component):
'NewVersionAvailableEvent', self.on_newversionavailable_event
)
+ self.previous_clipboard_text = ''
+ self.first_run = True
+
def connect_signals(self, mapping_or_class):
self.gtk_builder_signals_holder.connect_signals(mapping_or_class)
@@ -277,12 +279,14 @@ class MainWindow(component.Component):
def save_position(self):
self.config['window_maximized'] = self.window.props.is_maximized
if not self.config['window_maximized'] and self.visible():
- self.config['window_x_pos'], self.config[
- 'window_y_pos'
- ] = self.window.get_position()
- self.config['window_width'], self.config[
- 'window_height'
- ] = self.window.get_size()
+ (
+ self.config['window_x_pos'],
+ self.config['window_y_pos'],
+ ) = self.window.get_position()
+ (
+ self.config['window_width'],
+ self.config['window_height'],
+ ) = self.window.get_size()
def on_window_configure_event(self, widget, event):
self.save_position()
@@ -327,6 +331,21 @@ class MainWindow(component.Component):
def on_expose_event(self, widget, event):
component.get('SystemTray').blink(False)
+ def on_focus(self, window, param):
+ if window.props.is_active and not self.first_run and self.config['detect_urls']:
+ text = get_clipboard_text()
+ if text == self.previous_clipboard_text:
+ return
+ self.previous_clipboard_text = text
+ if text and (
+ (is_url(text) and text.endswith('.torrent'))
+ or is_magnet(text)
+ and not component.get('MenuBar').magnet_copied()
+ ):
+ component.get('AddTorrentDialog').show()
+ component.get('AddTorrentDialog').on_button_url_clicked(window)
+ self.first_run = False
+
def stop(self):
self.window.set_title('Deluge')
diff --git a/deluge/ui/gtk3/menubar.py b/deluge/ui/gtk3/menubar.py
index e09f394..a812a8c 100644
--- a/deluge/ui/gtk3/menubar.py
+++ b/deluge/ui/gtk3/menubar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
@@ -9,8 +8,6 @@
#
-from __future__ import unicode_literals
-
import logging
import os.path
@@ -21,7 +18,7 @@ import deluge.component as component
from deluge.configmanager import ConfigManager
from deluge.ui.client import client
-from .dialogs import ErrorDialog, OtherDialog
+from .dialogs import CopyMagnetDialog, ErrorDialog, OtherDialog
from .path_chooser import PathChooser
log = logging.getLogger(__name__)
@@ -34,6 +31,7 @@ class MenuBar(component.Component):
self.mainwindow = component.get('MainWindow')
self.main_builder = self.mainwindow.get_builder()
self.config = ConfigManager('gtk3ui.conf')
+ self._magnet_copied = False
self.builder = Gtk.Builder()
# Get the torrent menu from the gtk builder file
@@ -142,6 +140,19 @@ class MenuBar(component.Component):
self.change_sensitivity = ['menuitem_addtorrent']
+ def magnet_copied(self):
+ """
+ lets the caller know whether a magnet was copied internally
+
+ the `mainwindow` checks every time the data in the clipboard,
+ so it will automatically open the AddTorrentURL dialog in case it
+ contains a valid link (URL to a torrent or a magnet URI).
+
+ """
+ val = self._magnet_copied
+ self._magnet_copied = False
+ return val
+
def start(self):
for widget in self.change_sensitivity:
self.main_builder.get_object(widget).set_sensitive(True)
@@ -282,6 +293,21 @@ class MenuBar(component.Component):
component.get('TorrentView').get_selected_torrents()
)
+ def on_menuitem_copymagnet_activate(self, data=None):
+ log.debug('on_menuitem_copymagnet_activate')
+ torrent_ids = component.get('TorrentView').get_selected_torrents()
+ if torrent_ids:
+
+ def _on_magnet_uri(magnet_uri):
+ def update_copied(response_id):
+ if dialog.copied:
+ self._magnet_copied = True
+
+ dialog = CopyMagnetDialog(magnet_uri)
+ dialog.run().addCallback(update_copied)
+
+ client.core.get_magnet_uri(torrent_ids[0]).addCallback(_on_magnet_uri)
+
def on_menuitem_updatetracker_activate(self, data=None):
log.debug('on_menuitem_updatetracker_activate')
client.core.force_reannounce(
@@ -541,7 +567,7 @@ class MenuBar(component.Component):
account_to_log = {}
for key, value in account.copy().items():
if key == 'password':
- value = '*' * len(value)
+ value = '*' * 10
account_to_log[key] = value
known_accounts_to_log.append(account_to_log)
log.debug('_on_known_accounts: %s', known_accounts_to_log)
diff --git a/deluge/ui/gtk3/menubar_osx.py b/deluge/ui/gtk3/menubar_osx.py
index 1df6fab..53150fb 100644
--- a/deluge/ui/gtk3/menubar_osx.py
+++ b/deluge/ui/gtk3/menubar_osx.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from gi.repository.Gdk import ModifierType
from gi.repository.Gtk import SeparatorMenuItem, accel_groups_from_object
from gi.repository.Gtk.AccelFlags import VISIBLE
diff --git a/deluge/ui/gtk3/new_release_dialog.py b/deluge/ui/gtk3/new_release_dialog.py
index 6aa3282..a635bd2 100644
--- a/deluge/ui/gtk3/new_release_dialog.py
+++ b/deluge/ui/gtk3/new_release_dialog.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from gi.repository.Gtk import IconSize
import deluge.common
@@ -17,7 +14,7 @@ from deluge.configmanager import ConfigManager
from deluge.ui.client import client
-class NewReleaseDialog(object):
+class NewReleaseDialog:
def __init__(self):
pass
diff --git a/deluge/ui/gtk3/options_tab.py b/deluge/ui/gtk3/options_tab.py
index 6a25fd1..b0411a8 100644
--- a/deluge/ui/gtk3/options_tab.py
+++ b/deluge/ui/gtk3/options_tab.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
# 2017 Calum Lind <calumlind+deluge@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from gi.repository.Gdk import keyval_name
import deluge.component as component
@@ -21,7 +18,7 @@ from .torrentdetails import Tab
class OptionsTab(Tab):
def __init__(self):
- super(OptionsTab, self).__init__('Options', 'options_tab', 'options_tab_label')
+ super().__init__('Options', 'options_tab', 'options_tab_label')
self.prev_torrent_ids = None
self.prev_status = None
@@ -191,8 +188,9 @@ class OptionsTab(Tab):
):
options[status_key] = widget_value
- if options.get('move_completed', False):
- options['move_completed_path'] = self.move_completed_path_chooser.get_text()
+ move_completed_path = self.move_completed_path_chooser.get_text()
+ if move_completed_path != self.prev_status['move_completed_path']:
+ options['move_completed_path'] = move_completed_path
client.core.set_torrent_options(self.prev_torrent_ids, options)
self.button_apply.set_sensitive(False)
diff --git a/deluge/ui/gtk3/path_chooser.py b/deluge/ui/gtk3/path_chooser.py
index b722841..8058196 100644
--- a/deluge/ui/gtk3/path_chooser.py
+++ b/deluge/ui/gtk3/path_chooser.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2013 Bro <bro.development@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -125,7 +122,7 @@ class PathChoosersHandler(component.Component):
class PathChooser(PathChooserComboBox):
def __init__(self, paths_config_key=None, parent=None):
self.paths_config_key = paths_config_key
- super(PathChooser, self).__init__(parent=parent)
+ super().__init__(parent=parent)
self.chooser_handler = PathChoosersHandler()
self.chooser_handler.register_chooser(self)
self.set_auto_completer_func(self.on_completion)
diff --git a/deluge/ui/gtk3/path_combo_chooser.py b/deluge/ui/gtk3/path_combo_chooser.py
index c26289d..74d9055 100755
--- a/deluge/ui/gtk3/path_combo_chooser.py
+++ b/deluge/ui/gtk3/path_combo_chooser.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2013 Bro <bro.development@gmail.com>
#
@@ -8,15 +7,13 @@
# See LICENSE for more details.
#
-from __future__ import division, print_function, unicode_literals
-
import os
import warnings
from gi.repository import Gdk, GObject, Gtk
from gi.repository.GObject import SignalFlags
-from deluge.common import PY2, resource_filename
+from deluge.common import resource_filename
from deluge.path_chooser_common import get_completion_paths
# Filter the pygobject signal warning:
@@ -64,7 +61,7 @@ def path_without_trailing_path_sep(path):
return path
-class ValueList(object):
+class ValueList:
paths_without_trailing_path_sep = False
@@ -176,7 +173,7 @@ class ValueList(object):
"""
for i, row in enumerate(self.tree_store):
if row[0] == value:
- self.treeview.set_cursor((i))
+ self.treeview.set_cursor(i)
return
# The value was not found
if select_first:
@@ -374,7 +371,7 @@ class StoredValuesList(ValueList):
"""
# This is left click
if event.button != 3:
- super(StoredValuesList, self).on_treeview_mouse_button_press_event(
+ super().on_treeview_mouse_button_press_event(
treeview, event, double_click=True
)
return False
@@ -390,9 +387,9 @@ class StoredValuesList(ValueList):
treeview.set_cursor(path, col, 0)
self.path_list_popup = Gtk.Menu()
- menuitem_edit = Gtk.MenuItem.new_with_label('Edit path')
+ menuitem_edit = Gtk.MenuItem.new_with_label(_('Edit path'))
self.path_list_popup.append(menuitem_edit)
- menuitem_remove = Gtk.MenuItem.new_with_label('Remove path')
+ menuitem_remove = Gtk.MenuItem.new_with_label(_('Remove path'))
self.path_list_popup.append(menuitem_remove)
def on_edit_clicked(widget, path):
@@ -412,9 +409,7 @@ class StoredValuesList(ValueList):
PathChooserPopup.popup(self)
def on_stored_values_treeview_key_press_event(self, widget, event):
- super(StoredValuesList, self).on_value_list_treeview_key_press_event(
- widget, event
- )
+ super().on_value_list_treeview_key_press_event(widget, event)
# Prevent the default event handler to move the cursor in the list
if key_is_up_or_down(event.keyval):
return True
@@ -479,9 +474,9 @@ class CompletionList(ValueList):
] = self.on_completion_treeview_motion_notify_event
# Add super class signal handler
- self.signal_handlers['on_completion_treeview_mouse_button_press_event'] = super(
- CompletionList, self
- ).on_treeview_mouse_button_press_event
+ self.signal_handlers[
+ 'on_completion_treeview_mouse_button_press_event'
+ ] = super().on_treeview_mouse_button_press_event
def reduce_values(self, prefix):
"""
@@ -499,9 +494,7 @@ class CompletionList(ValueList):
self.add_values(matching_values, clear=True)
def on_completion_treeview_key_press_event(self, widget, event):
- ret = super(CompletionList, self).on_value_list_treeview_key_press_event(
- widget, event
- )
+ ret = super().on_value_list_treeview_key_press_event(widget, event)
if ret:
return ret
keyval = event.keyval
@@ -529,7 +522,7 @@ class CompletionList(ValueList):
self.handle_list_scroll(path=path[0], _next=None)
-class PathChooserPopup(object):
+class PathChooserPopup:
"""This creates the popop window for the ComboEntry."""
def __init__(self, min_visible_rows, max_visible_rows, popup_alignment_widget):
@@ -538,9 +531,8 @@ class PathChooserPopup(object):
self.set_max_popup_rows(max_visible_rows)
self.popup_window.realize()
self.alignment_widget = popup_alignment_widget
- self.popup_buttonbox = (
- None
- ) # If set, the height of this widget is the minimum height
+ # If set, the height of this widget is the minimum height
+ self.popup_buttonbox = None
def popup(self):
"""Make the popup visible."""
@@ -984,7 +976,7 @@ class PathCompletionPopup(CompletionList, PathChooserPopup):
return True
-class PathAutoCompleter(object):
+class PathAutoCompleter:
def __init__(self, builder, path_entry, max_visible_rows):
self.completion_popup = PathCompletionPopup(
builder, path_entry, max_visible_rows
@@ -1107,9 +1099,7 @@ class PathAutoCompleter(object):
class PathChooserComboBox(Gtk.Box, StoredValuesPopup, GObject.GObject):
__gsignals__ = {
- signal
- if not PY2
- else signal.encode(): (SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (object,))
+ signal: (SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (object,))
for signal in [
'text-changed',
'accelerator-set',
@@ -1415,7 +1405,7 @@ class PathChooserComboBox(Gtk.Box, StoredValuesPopup, GObject.GObject):
self.set_text(self.get_text())
def _on_entry_combobox_hbox_realize(self, widget):
- """ Must do this when the widget is realized """
+ """Must do this when the widget is realized"""
self.set_filechooser_button_visible(self.filechooser_visible)
self.set_path_entry_visible(self.path_entry_visible)
@@ -1467,7 +1457,7 @@ class PathChooserComboBox(Gtk.Box, StoredValuesPopup, GObject.GObject):
)
return True
elif is_ascii_value(keyval, 's'):
- super(PathChooserComboBox, self).add_current_value_to_saved_list()
+ super().add_current_value_to_saved_list()
return True
elif is_ascii_value(keyval, 'd'):
# Set the default value in the text entry
@@ -1697,7 +1687,7 @@ if __name__ == '__main__':
box1 = Gtk.Box.new(Gtk.Orientation.VERTICAL, spacing=0)
def get_resource2(filename):
- return '%s/glade/%s' % (os.path.abspath(os.path.dirname(sys.argv[0])), filename)
+ return f'{os.path.abspath(os.path.dirname(sys.argv[0]))}/glade/{filename}'
# Override get_resource which fetches from deluge install
# get_resource = get_resource2
diff --git a/deluge/ui/gtk3/peers_tab.py b/deluge/ui/gtk3/peers_tab.py
index 33395b9..b458f7a 100644
--- a/deluge/ui/gtk3/peers_tab.py
+++ b/deluge/ui/gtk3/peers_tab.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os.path
@@ -32,6 +29,7 @@ from .common import (
icon_downloading,
icon_seeding,
load_pickled_state_file,
+ parse_ip_port,
save_pickled_state_file,
)
from .torrentdetails import Tab
@@ -41,18 +39,12 @@ from .torrentview_data_funcs import (
cell_data_speed_up,
)
-try:
- from future_builtins import zip
-except ImportError:
- # Ignore on Py3.
- pass
-
log = logging.getLogger(__name__)
class PeersTab(Tab):
def __init__(self):
- super(PeersTab, self).__init__('Peers', 'peers_tab', 'peers_tab_label')
+ super().__init__('Peers', 'peers_tab', 'peers_tab_label')
self.peer_menu = self.main_builder.get_object('menu_peer_tab')
component.get('MainWindow').connect_signals(self)
@@ -304,15 +296,15 @@ class PeersTab(Tab):
peer_ip = peer['ip']
else:
# This is an IPv6 address
- import socket
import binascii
+ import socket
# Split out the :port
ip = ':'.join(peer['ip'].split(':')[:-1])
ip_int = int(
binascii.hexlify(socket.inet_pton(socket.AF_INET6, ip)), 16
)
- peer_ip = '[%s]:%s' % (ip, peer['ip'].split(':')[-1])
+ peer_ip = '[{}]:{}'.format(ip, peer['ip'].split(':')[-1])
if peer['seed']:
icon = self.seed_pixbuf
@@ -376,19 +368,15 @@ class PeersTab(Tab):
peer_dialog = builder.get_object('connect_peer_dialog')
txt_ip = builder.get_object('txt_ip')
response = peer_dialog.run()
+
if response:
value = txt_ip.get_text()
- if value and ':' in value:
- if ']' in value:
- # ipv6
- ip = value.split(']')[0][1:]
- port = value.split(']')[1][1:]
- else:
- # ipv4
- ip = value.split(':')[0]
- port = value.split(':')[1]
- if deluge.common.is_ip(ip):
- log.debug('adding peer %s to %s', value, self.torrent_id)
- client.core.connect_peer(self.torrent_id, ip, port)
+ ip, port = parse_ip_port(value)
+ if ip and port:
+ log.info('Adding peer IP: %s port: %s to %s', ip, port, self.torrent_id)
+ client.core.connect_peer(self.torrent_id, ip, port)
+ else:
+ log.error('Error parsing peer "%s"', value)
+
peer_dialog.destroy()
return True
diff --git a/deluge/ui/gtk3/piecesbar.py b/deluge/ui/gtk3/piecesbar.py
index ba03e55..8665328 100644
--- a/deluge/ui/gtk3/piecesbar.py
+++ b/deluge/ui/gtk3/piecesbar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
#
@@ -7,14 +6,13 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
from math import pi
import gi # isort:skip (Version check required before import).
-gi.require_version('PangoCairo', '1.0') # NOQA: E402
-gi.require_version('cairo', '1.0') # NOQA: E402
+gi.require_version('PangoCairo', '1.0')
+gi.require_foreign('cairo')
+gi.require_version('cairo', '1.0')
# isort:imports-thirdparty
import cairo # Backward compat cairo <= 1.15
@@ -23,7 +21,6 @@ from gi.repository.Gtk import DrawingArea, ProgressBar, StateFlags
from gi.repository.Pango import SCALE, Weight
# isort:imports-firstparty
-from deluge.common import PY2
from deluge.configmanager import ConfigManager
COLOR_STATES = ['missing', 'waiting', 'downloading', 'completed']
@@ -31,14 +28,15 @@ COLOR_STATES = ['missing', 'waiting', 'downloading', 'completed']
class PiecesBar(DrawingArea):
# Draw in response to an draw
- __gsignals__ = {'draw': 'override'} if not PY2 else {b'draw': b'override'}
+ __gsignals__ = {'draw': 'override'}
def __init__(self):
- super(PiecesBar, self).__init__()
+ super().__init__()
# Get progress bar styles, in order to keep font consistency
pb = ProgressBar()
pb_style = pb.get_style_context()
- self.text_font = pb_style.get_property('font', StateFlags.NORMAL)
+ # Get a copy of Pango.FontDescription since original needs freed.
+ self.text_font = pb_style.get_property('font', StateFlags.NORMAL).copy()
self.text_font.set_weight(Weight.BOLD)
# Done with the ProgressBar styles, don't keep refs of it
del pb, pb_style
diff --git a/deluge/ui/gtk3/pluginmanager.py b/deluge/ui/gtk3/pluginmanager.py
index d60f8d3..63353c0 100644
--- a/deluge/ui/gtk3/pluginmanager.py
+++ b/deluge/ui/gtk3/pluginmanager.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
diff --git a/deluge/ui/gtk3/preferences.py b/deluge/ui/gtk3/preferences.py
index b196128..a008a95 100644
--- a/deluge/ui/gtk3/preferences.py
+++ b/deluge/ui/gtk3/preferences.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
@@ -8,11 +7,10 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
from hashlib import sha1 as sha
+from urllib.parse import urlparse
from gi import require_version
from gi.repository import Gtk
@@ -21,6 +19,7 @@ from gi.repository.Gdk import Color
import deluge.common
import deluge.component as component
from deluge.configmanager import ConfigManager, get_config_dir
+from deluge.decorators import maybe_coroutine
from deluge.error import AuthManagerError, NotAuthorizedError
from deluge.i18n import get_languages
from deluge.ui.client import client
@@ -31,12 +30,6 @@ from .dialogs import AccountDialog, ErrorDialog, InformationDialog, YesNoDialog
from .path_chooser import PathChooser
try:
- from urllib.parse import urlparse
-except ImportError:
- # PY2 fallback
- from urlparse import urlparse # pylint: disable=ungrouped-imports
-
-try:
require_version('AppIndicator3', '0.1')
from gi.repository import AppIndicator3 # noqa: F401
except (ImportError, ValueError):
@@ -77,7 +70,7 @@ class Preferences(component.Component):
self.load_pref_dialog_state()
self.builder.get_object('image_magnet').set_from_file(
- deluge.common.get_pixmap('magnet.png')
+ deluge.common.get_pixmap('magnet16.png')
)
# Hide the unused associate magnet button on OSX see: #2420
@@ -255,11 +248,10 @@ class Preferences(component.Component):
vbox.pack_start(label, False, True, 0)
sep = Gtk.HSeparator()
vbox.pack_start(sep, False, True, 0)
- align = Gtk.Alignment()
- align.set_padding(5, 0, 0, 0)
- align.set(0, 0, 1, 1)
- align.add(widget)
- vbox.pack_start(align, True, True, 0)
+ widget.set_margin_top(7)
+ widget.set_vexpand(True)
+ widget.set_hexpand(True)
+ vbox.pack_start(widget, True, True, 0)
scrolled = Gtk.ScrolledWindow()
viewport = Gtk.Viewport()
viewport.set_shadow_type(Gtk.ShadowType.NONE)
@@ -571,6 +563,9 @@ class Preferences(component.Component):
self.builder.get_object('piecesbar_toggle').set_active(
self.gtkui_config['show_piecesbar']
)
+ self.builder.get_object('urldetect_toggle').set_active(
+ self.gtkui_config['detect_urls']
+ )
self.__set_color('completed', from_config=True)
self.__set_color('downloading', from_config=True)
self.__set_color('waiting', from_config=True)
@@ -677,11 +672,15 @@ class Preferences(component.Component):
'chk_random_outgoing_ports'
).get_active()
incoming_address = self.builder.get_object('entry_interface').get_text().strip()
- if deluge.common.is_ip(incoming_address) or not incoming_address:
+ if deluge.common.is_interface(incoming_address) or not incoming_address:
new_core_config['listen_interface'] = incoming_address
- new_core_config['outgoing_interface'] = (
+ outgoing_address = (
self.builder.get_object('entry_outgoing_interface').get_text().strip()
)
+ if deluge.common.is_interface(outgoing_address) or not outgoing_address:
+ new_core_config['outgoing_interface'] = (
+ self.builder.get_object('entry_outgoing_interface').get_text().strip()
+ )
new_core_config['peer_tos'] = self.builder.get_object(
'entry_peer_tos'
).get_text()
@@ -937,7 +936,7 @@ class Preferences(component.Component):
not self.gtkui_config['standalone']
)
- mode = 'Thinclient' if was_standalone else 'Standalone'
+ mode = _('Thinclient') if was_standalone else _('Standalone')
dialog = YesNoDialog(
_('Switching Deluge Client Mode...'),
_('Do you want to restart to use %s mode?' % mode),
@@ -946,6 +945,7 @@ class Preferences(component.Component):
def hide(self):
self.window_open = False
+ self.builder.get_object('port_spinner').stop()
self.builder.get_object('port_img').hide()
self.pref_dialog.hide()
@@ -958,7 +958,6 @@ class Preferences(component.Component):
'label_cache_num_blocks_written',
'label_cache_read_hit_ratio',
'label_cache_write_hit_ratio',
- 'label_cache_num_blocks_cache_hits',
'label_cache_disk_blocks_in_use',
'label_cache_read_cache_blocks',
)
@@ -1091,6 +1090,8 @@ class Preferences(component.Component):
log.debug('on_test_port_clicked')
def on_get_test(status):
+ self.builder.get_object('port_spinner').stop()
+ self.builder.get_object('port_spinner').hide()
if status:
self.builder.get_object('port_img').set_from_icon_name(
'emblem-ok-symbolic', Gtk.IconSize.MENU
@@ -1103,12 +1104,9 @@ class Preferences(component.Component):
self.builder.get_object('port_img').show()
client.core.test_listen_port().addCallback(on_get_test)
- # XXX: Consider using gtk.Spinner() instead of the loading gif
- # It requires gtk.ver > 2.12
- self.builder.get_object('port_img').set_from_file(
- deluge.common.get_pixmap('loading.gif')
- )
- self.builder.get_object('port_img').show()
+ self.builder.get_object('port_spinner').start()
+ self.builder.get_object('port_spinner').show()
+ self.builder.get_object('port_img').hide()
client.force_call()
def on_plugin_toggled(self, renderer, path):
@@ -1180,8 +1178,8 @@ class Preferences(component.Component):
chooser.destroy()
return
- from base64 import b64encode
import shutil
+ from base64 import b64encode
filename = os.path.split(filepath)[1]
shutil.copyfile(filepath, os.path.join(get_config_dir(), 'plugins', filename))
@@ -1332,58 +1330,46 @@ class Preferences(component.Component):
(model, itr) = treeselection.get_selected()
if not itr:
return
- username = model[itr][0]
- if username:
+ level = model[itr][1]
+ if level:
self.builder.get_object('accounts_edit').set_sensitive(True)
self.builder.get_object('accounts_delete').set_sensitive(True)
else:
self.builder.get_object('accounts_edit').set_sensitive(False)
self.builder.get_object('accounts_delete').set_sensitive(False)
- def on_accounts_add_clicked(self, widget):
+ @maybe_coroutine
+ async def on_accounts_add_clicked(self, widget):
dialog = AccountDialog(
levels_mapping=client.auth_levels_mapping, parent=self.pref_dialog
)
+ response = await dialog.run()
+ if response != Gtk.ResponseType.OK:
+ return
- def dialog_finished(response_id):
- username = dialog.get_username()
- password = dialog.get_password()
- authlevel = dialog.get_authlevel()
-
- def add_ok(rv):
- accounts_iter = self.accounts_liststore.append()
- self.accounts_liststore.set_value(
- accounts_iter, ACCOUNTS_USERNAME, username
- )
- self.accounts_liststore.set_value(
- accounts_iter, ACCOUNTS_LEVEL, authlevel
- )
- self.accounts_liststore.set_value(
- accounts_iter, ACCOUNTS_PASSWORD, password
- )
-
- def add_fail(failure):
- if failure.type == AuthManagerError:
- ErrorDialog(
- _('Error Adding Account'),
- _('Authentication failed'),
- parent=self.pref_dialog,
- details=failure.getErrorMessage(),
- ).run()
- else:
- ErrorDialog(
- _('Error Adding Account'),
- _('An error occurred while adding account'),
- parent=self.pref_dialog,
- details=failure.getErrorMessage(),
- ).run()
-
- if response_id == Gtk.ResponseType.OK:
- client.core.create_account(username, password, authlevel).addCallback(
- add_ok
- ).addErrback(add_fail)
-
- dialog.run().addCallback(dialog_finished)
+ account = dialog.account
+ try:
+ await client.core.create_account(*account)
+ except AuthManagerError as ex:
+ return ErrorDialog(
+ _('Error Adding Account'),
+ _('Authentication failed'),
+ parent=self.pref_dialog,
+ details=ex,
+ ).run()
+ except Exception as ex:
+ return ErrorDialog(
+ _('Error Adding Account'),
+ _(f'An error occurred while adding account: {account}'),
+ parent=self.pref_dialog,
+ details=ex,
+ ).run()
+
+ self.accounts_liststore.set(
+ self.accounts_liststore.append(),
+ [ACCOUNTS_USERNAME, ACCOUNTS_LEVEL, ACCOUNTS_PASSWORD],
+ [account.username, account.authlevel, account.password],
+ )
def on_accounts_edit_clicked(self, widget):
(model, itr) = self.accounts_listview.get_selection().get_selected()
@@ -1463,6 +1449,9 @@ class Preferences(component.Component):
colors_widget = self.builder.get_object('piecebar_colors_expander')
colors_widget.set_visible(widget.get_active())
+ def on_urldetect_toggle_toggled(self, widget):
+ self.gtkui_config['detect_urls'] = widget.get_active()
+
def on_checkbutton_language_toggled(self, widget):
self.language_combo.set_visible(not self.language_checkbox.get_active())
diff --git a/deluge/ui/gtk3/queuedtorrents.py b/deluge/ui/gtk3/queuedtorrents.py
index 0f08c24..6fdecec 100644
--- a/deluge/ui/gtk3/queuedtorrents.py
+++ b/deluge/ui/gtk3/queuedtorrents.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os.path
diff --git a/deluge/ui/gtk3/removetorrentdialog.py b/deluge/ui/gtk3/removetorrentdialog.py
index 48806a5..06fca77 100644
--- a/deluge/ui/gtk3/removetorrentdialog.py
+++ b/deluge/ui/gtk3/removetorrentdialog.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
@@ -21,7 +18,7 @@ from deluge.ui.client import client
log = logging.getLogger(__name__)
-class RemoveTorrentDialog(object):
+class RemoveTorrentDialog:
"""
This class is used to create and show a Remove Torrent Dialog.
diff --git a/deluge/ui/gtk3/sidebar.py b/deluge/ui/gtk3/sidebar.py
index 1d75191..5a2b154 100644
--- a/deluge/ui/gtk3/sidebar.py
+++ b/deluge/ui/gtk3/sidebar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
@@ -8,8 +7,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from gi.repository.Gtk import Label, PolicyType, ScrolledWindow
diff --git a/deluge/ui/gtk3/status_tab.py b/deluge/ui/gtk3/status_tab.py
index fab6719..6a9010b 100644
--- a/deluge/ui/gtk3/status_tab.py
+++ b/deluge/ui/gtk3/status_tab.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
import logging
import deluge.component as component
@@ -32,7 +29,7 @@ log = logging.getLogger(__name__)
class StatusTab(Tab):
def __init__(self):
- super(StatusTab, self).__init__('Status', 'status_tab', 'status_tab_label')
+ super().__init__('Status', 'status_tab', 'status_tab_label')
self.config = ConfigManager('gtk3ui.conf')
@@ -110,7 +107,7 @@ class StatusTab(Tab):
if decode_bytes(widget[0].get_text()) != txt:
widget[0].set_text(txt)
- # Update progress bar seperately as it's a special case (not a label).
+ # Update progress bar separately as it's a special case (not a label).
fraction = status['progress'] / 100
if self.config['show_piecesbar']:
diff --git a/deluge/ui/gtk3/statusbar.py b/deluge/ui/gtk3/statusbar.py
index 265e7c8..0a2e800 100644
--- a/deluge/ui/gtk3/statusbar.py
+++ b/deluge/ui/gtk3/statusbar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
import logging
from gi.repository import Gtk
@@ -25,7 +22,7 @@ from .dialogs import OtherDialog
log = logging.getLogger(__name__)
-class StatusBarItem(object):
+class StatusBarItem:
def __init__(
self,
image=None,
@@ -142,12 +139,11 @@ class StatusBar(component.Component):
self.current_warnings = []
# Add hbox to the statusbar after removing the initial label widget
self.hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, spacing=10)
- align = Gtk.Alignment()
- align.set_padding(2, 0, 3, 0)
- align.add(self.hbox)
+ self.hbox.set_margin_top(2)
+ self.hbox.set_margin_bottom(3)
frame = self.statusbar.get_children()[0]
frame.remove(frame.get_children()[0])
- frame.add(align)
+ frame.add(self.hbox)
self.statusbar.show_all()
# Create the not connected item
self.not_connected_item = StatusBarItem(
@@ -321,18 +317,22 @@ class StatusBar(component.Component):
def send_status_request(self):
# Sends an async request for data from the core
keys = [
- 'num_peers',
+ 'peer.num_peers_connected',
'upload_rate',
'download_rate',
'payload_upload_rate',
'payload_download_rate',
+ 'net.sent_bytes',
+ 'net.recv_bytes',
+ 'net.sent_payload_bytes',
+ 'net.recv_payload_bytes',
]
if self.dht_status:
- keys.append('dht_nodes')
+ keys.append('dht.dht_nodes')
if not self.health:
- keys.append('has_incoming_connections')
+ keys.append('net.has_incoming_connections')
client.core.get_session_status(keys).addCallback(self._on_get_session_status)
client.core.get_free_space().addCallback(self._on_get_free_space)
@@ -371,18 +371,18 @@ class StatusBar(component.Component):
self.upload_protocol_rate = (
status['upload_rate'] - status['payload_upload_rate']
) // 1024
- self.num_connections = status['num_peers']
+ self.num_connections = status['peer.num_peers_connected']
self.update_download_label()
self.update_upload_label()
self.update_traffic_label()
self.update_connections_label()
- if 'dht_nodes' in status:
- self.dht_nodes = status['dht_nodes']
+ if 'dht.dht_nodes' in status:
+ self.dht_nodes = status['dht.dht_nodes']
self.update_dht_label()
- if 'has_incoming_connections' in status:
- self.health = status['has_incoming_connections']
+ if 'net.has_incoming_connections' in status:
+ self.health = status['net.has_incoming_connections']
if self.health:
self.remove_item(self.health_item)
@@ -413,7 +413,7 @@ class StatusBar(component.Component):
if self.max_connections_global < 0:
label_string = '%s' % self.num_connections
else:
- label_string = '%s <small>(%s)</small>' % (
+ label_string = '{} <small>({})</small>'.format(
self.num_connections,
self.max_connections_global,
)
diff --git a/deluge/ui/gtk3/systemtray.py b/deluge/ui/gtk3/systemtray.py
index f851f32..f65fde5 100644
--- a/deluge/ui/gtk3/systemtray.py
+++ b/deluge/ui/gtk3/systemtray.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
@@ -30,8 +27,12 @@ from .common import build_menu_radio_list, get_logo
from .dialogs import OtherDialog
try:
- require_version('AppIndicator3', '0.1')
- from gi.repository import AppIndicator3
+ try:
+ require_version('AyatanaAppIndicator3', '0.1')
+ from gi.repository import AyatanaAppIndicator3 as AppIndicator3
+ except (ValueError, ImportError):
+ require_version('AppIndicator3', '0.1')
+ from gi.repository import AppIndicator3
except (ValueError, ImportError):
AppIndicator3 = None
@@ -234,13 +235,13 @@ class SystemTray(component.Component):
if max_download_speed == -1:
max_download_speed = _('Unlimited')
else:
- max_download_speed = '%s %s' % (max_download_speed, _('K/s'))
+ max_download_speed = '{} {}'.format(max_download_speed, _('K/s'))
if max_upload_speed == -1:
max_upload_speed = _('Unlimited')
else:
- max_upload_speed = '%s %s' % (max_upload_speed, _('K/s'))
+ max_upload_speed = '{} {}'.format(max_upload_speed, _('K/s'))
- msg = '%s\n%s: %s (%s)\n%s: %s (%s)' % (
+ msg = '{}\n{}: {} ({})\n{}: {} ({})'.format(
_('Deluge'),
_('Down'),
self.download_rate,
diff --git a/deluge/ui/gtk3/tab_data_funcs.py b/deluge/ui/gtk3/tab_data_funcs.py
index 6fa0ba5..a78994f 100644
--- a/deluge/ui/gtk3/tab_data_funcs.py
+++ b/deluge/ui/gtk3/tab_data_funcs.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,14 +6,12 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
from deluge.common import fdate, fsize, fspeed, ftime
from deluge.ui.common import TRACKER_STATUS_TRANSLATION
def ftotal_sized(first, second):
- return '%s (%s)' % (fsize(first, shortform=True), fsize(second, shortform=True))
+ return f'{fsize(first, shortform=True)} ({fsize(second, shortform=True)})'
def fratio(value):
@@ -24,7 +21,7 @@ def fratio(value):
def fpcnt(value, state, message):
state_i18n = _(state)
if state not in ('Error', 'Seeding') and value < 100:
- percent = '{:.2f}'.format(value).rstrip('0').rstrip('.')
+ percent = f'{value:.2f}'.rstrip('0').rstrip('.')
return _('{state} {percent}%').format(state=state_i18n, percent=percent)
elif state == 'Error':
return _('{state}: {err_msg}').format(state=state_i18n, err_msg=message)
@@ -34,7 +31,7 @@ def fpcnt(value, state, message):
def fspeed_max(value, max_value=-1):
value = fspeed(value, shortform=True)
- return '%s (%s %s)' % (value, max_value, _('K/s')) if max_value > -1 else value
+ return '{} ({} {})'.format(value, max_value, _('K/s')) if max_value > -1 else value
def fdate_or_never(value):
@@ -73,7 +70,7 @@ def fseed_rank_or_dash(seed_rank, seeding_time):
def fpieces_num_size(num_pieces, piece_size):
- return '%s (%s)' % (num_pieces, fsize(piece_size, precision=0))
+ return f'{num_pieces} ({fsize(piece_size, precision=0)})'
def fcount(value):
diff --git a/deluge/ui/gtk3/toolbar.py b/deluge/ui/gtk3/toolbar.py
index 7bc029e..1b6952e 100644
--- a/deluge/ui/gtk3/toolbar.py
+++ b/deluge/ui/gtk3/toolbar.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from gi.repository.Gtk import SeparatorToolItem, ToolButton
diff --git a/deluge/ui/gtk3/torrentdetails.py b/deluge/ui/gtk3/torrentdetails.py
index 29e0193..08c37a1 100644
--- a/deluge/ui/gtk3/torrentdetails.py
+++ b/deluge/ui/gtk3/torrentdetails.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
#
@@ -9,12 +8,17 @@
"""The torrent details component shows info about the selected torrent."""
-from __future__ import unicode_literals
-
import logging
from collections import namedtuple
-from gi.repository.Gtk import CheckMenuItem, Menu, SeparatorMenuItem
+from gi.repository.Gtk import (
+ CheckMenuItem,
+ Menu,
+ MenuItem,
+ PositionType,
+ RadioMenuItem,
+ SeparatorMenuItem,
+)
import deluge.component as component
from deluge.ui.client import client
@@ -26,7 +30,7 @@ log = logging.getLogger(__name__)
TabWidget = namedtuple('TabWidget', ('obj', 'func', 'status_keys'))
-class Tab(object):
+class Tab:
def __init__(self, name=None, child_widget=None, tab_label=None):
self._name = name
self.is_visible = True
@@ -100,8 +104,12 @@ class TorrentDetails(component.Component):
def __init__(self):
component.Component.__init__(self, 'TorrentDetails', interval=2)
main_builder = component.get('MainWindow').get_builder()
+ self.config = component.get('MainWindow').config
self.notebook = main_builder.get_object('torrent_info')
+ self.notebook.set_tab_pos(
+ getattr(PositionType, self.config['tabsbar_tab_pos'].upper())
+ )
# This is the menu item we'll attach the tabs checklist menu to
self.menu_tabs = main_builder.get_object('menu_tabs')
@@ -112,11 +120,11 @@ class TorrentDetails(component.Component):
self.tabs = {}
# Add the default tabs
- from .status_tab import StatusTab
from .details_tab import DetailsTab
from .files_tab import FilesTab
- from .peers_tab import PeersTab
from .options_tab import OptionsTab
+ from .peers_tab import PeersTab
+ from .status_tab import StatusTab
from .trackers_tab import TrackersTab
default_tabs = {
@@ -175,7 +183,6 @@ class TorrentDetails(component.Component):
# Generate the checklist menu
self.generate_menu()
- self.config = component.get('MainWindow').config
self.visible(self.config['show_tabsbar'])
def tab_insert_position(self, weight):
@@ -314,9 +321,24 @@ class TorrentDetails(component.Component):
self.generate_menu()
self.visible(True)
+ def create_tab_pos_menuitem(self):
+ """Returns a menu to select which side of the notebook the tabs should be shown"""
+ tab_pos_menu = Menu()
+ tab_pos_menuitem = MenuItem.new_with_label(_('Position'))
+ group = []
+ for pos in ('top', 'right', 'bottom', 'left'):
+ menuitem = RadioMenuItem.new_with_mnemonic(group, _(pos.capitalize()))
+ group = menuitem.get_group()
+ menuitem.connect('toggled', self._on_tabs_pos_toggled, pos)
+ menuitem.set_active(pos == self.notebook.get_tab_pos().value_nick)
+ tab_pos_menu.append(menuitem)
+ tab_pos_menuitem.set_submenu(tab_pos_menu)
+ return tab_pos_menuitem
+
def generate_menu(self):
"""Generates the checklist menu for all the tabs and attaches it"""
menu = Menu()
+
# Create 'All' menuitem and a separator
menuitem = CheckMenuItem.new_with_mnemonic(self.translate_tabs['All'])
menuitem.set_name('All')
@@ -347,6 +369,9 @@ class TorrentDetails(component.Component):
menuitem.connect('toggled', self._on_menuitem_toggled)
menu.append(menuitem)
+ menu.append(SeparatorMenuItem())
+ menu.append(self.create_tab_pos_menuitem())
+
self.menu_tabs.set_submenu(menu)
self.menu_tabs.show_all()
@@ -440,6 +465,10 @@ class TorrentDetails(component.Component):
self.set_tab_visible(name, widget.get_active())
+ def _on_tabs_pos_toggled(self, widget, position):
+ self.config['tabsbar_tab_pos'] = position
+ self.notebook.set_tab_pos(getattr(PositionType, position.upper()))
+
def save_state(self):
"""We save the state, which is basically the tab_index list"""
# Update the visiblity status of all tabs
diff --git a/deluge/ui/gtk3/torrentview.py b/deluge/ui/gtk3/torrentview.py
index fcc6edf..16de16e 100644
--- a/deluge/ui/gtk3/torrentview.py
+++ b/deluge/ui/gtk3/torrentview.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -8,8 +7,6 @@
#
"""The torrent view component that lists all torrents in the session."""
-from __future__ import unicode_literals
-
import logging
from locale import strcoll
@@ -77,13 +74,13 @@ def eta_column_sort(model, iter1, iter2, data):
if v1 == v2:
return 0
if v1 == 0:
- return 1
- if v2 == 0:
return -1
- if v1 > v2:
+ if v2 == 0:
return 1
- if v2 > v1:
+ if v1 > v2:
return -1
+ if v2 > v1:
+ return 1
def seed_peer_column_sort(model, iter1, iter2, data):
@@ -107,7 +104,7 @@ def progress_sort(model, iter1, iter2, sort_column_id):
return cmp(progress1, progress2)
-class SearchBox(object):
+class SearchBox:
def __init__(self, torrentview):
self.torrentview = torrentview
mainwindow = component.get('MainWindow')
@@ -404,6 +401,13 @@ class TorrentView(ListView, component.Component):
status_field=['last_seen_complete'],
default=False,
)
+ self.add_func_column(
+ _('Last Transfer'),
+ funcs.cell_data_time,
+ [int],
+ status_field=['time_since_transfer'],
+ default=False,
+ )
self.add_texticon_column(
_('Tracker'),
function=funcs.cell_data_trackericon,
diff --git a/deluge/ui/gtk3/torrentview_data_funcs.py b/deluge/ui/gtk3/torrentview_data_funcs.py
index 8bd1f9c..0b2545d 100644
--- a/deluge/ui/gtk3/torrentview_data_funcs.py
+++ b/deluge/ui/gtk3/torrentview_data_funcs.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import print_function, unicode_literals
-
import warnings
from functools import partial
@@ -17,7 +14,7 @@ import deluge.component as component
from .common import (
create_blank_pixbuf,
- get_pixbuf_at_size,
+ get_pixbuf,
icon_alert,
icon_checking,
icon_downloading,
@@ -42,7 +39,6 @@ ICON_STATE = {
# renderer. This is much cheaper than fetch the current value and test if
# it's equal.
func_last_value = {
- 'cell_data_time': None,
'cell_data_ratio_seeds_peers': None,
'cell_data_ratio_ratio': None,
'cell_data_ratio_avail': None,
@@ -86,7 +82,7 @@ def set_tracker_icon(tracker_icon, cell):
if tracker_icon:
pixbuf = tracker_icon.get_cached_icon()
if pixbuf is None:
- pixbuf = get_pixbuf_at_size(tracker_icon.get_filename(), 16)
+ pixbuf = get_pixbuf(tracker_icon.get_filename(), 16)
tracker_icon.set_cached_icon(pixbuf)
else:
pixbuf = create_blank_pixbuf()
@@ -162,7 +158,7 @@ def cell_data_speed(cell, model, row, data):
if speed > 0:
speed_str = common.fspeed(speed, shortform=True)
cell.set_property(
- 'markup', '{0} <small>{1}</small>'.format(*tuple(speed_str.split()))
+ 'markup', '{} <small>{}</small>'.format(*tuple(speed_str.split()))
)
else:
cell.set_property('text', '')
@@ -189,7 +185,7 @@ def cell_data_speed_limit(cell, model, row, data, cache_key):
if speed > 0:
speed_str = common.fspeed(speed * 1024, shortform=True)
cell.set_property(
- 'markup', '{0} <small>{1}</small>'.format(*tuple(speed_str.split()))
+ 'markup', '{} <small>{}</small>'.format(*tuple(speed_str.split()))
)
else:
cell.set_property('text', '')
@@ -222,10 +218,6 @@ def cell_data_peer(column, cell, model, row, data):
def cell_data_time(column, cell, model, row, data):
"""Display value as time, eg 1m10s"""
time = model.get_value(row, data)
- if func_last_value['cell_data_time'] == time:
- return
- func_last_value['cell_data_time'] = time
-
if time <= 0:
time_str = ''
else:
diff --git a/deluge/ui/gtk3/trackers_tab.py b/deluge/ui/gtk3/trackers_tab.py
index d83b995..d671471 100644
--- a/deluge/ui/gtk3/trackers_tab.py
+++ b/deluge/ui/gtk3/trackers_tab.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import deluge.component as component
@@ -22,9 +19,7 @@ log = logging.getLogger(__name__)
class TrackersTab(Tab):
def __init__(self):
- super(TrackersTab, self).__init__(
- 'Trackers', 'trackers_tab', 'trackers_tab_label'
- )
+ super().__init__('Trackers', 'trackers_tab', 'trackers_tab_label')
self.add_tab_widget('summary_next_announce', ftime, ('next_announce',))
self.add_tab_widget('summary_tracker', None, ('tracker_host',))
diff --git a/deluge/ui/hostlist.py b/deluge/ui/hostlist.py
index ee4c7df..0fc3eab 100644
--- a/deluge/ui/hostlist.py
+++ b/deluge/ui/hostlist.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) Calum Lind 2017 <calumlind+deluge@gmail.com>
#
@@ -7,12 +6,10 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
import uuid
-from socket import gaierror, gethostbyname
+from socket import gaierror, getaddrinfo
from twisted.internet import defer
@@ -25,7 +22,7 @@ log = logging.getLogger(__name__)
DEFAULT_HOST = '127.0.0.1'
DEFAULT_PORT = 58846
-LOCALHOST = ('127.0.0.1', 'localhost')
+LOCALHOST = ('127.0.0.1', 'localhost', '::1')
def default_hostlist():
@@ -47,7 +44,7 @@ def validate_host_info(hostname, port):
"""
try:
- gethostbyname(hostname)
+ getaddrinfo(hostname, None)
except gaierror as ex:
raise ValueError('Host %s: %s', hostname, ex.args[1])
@@ -87,7 +84,15 @@ def migrate_config_2_to_3(config):
return config
-class HostList(object):
+def mask_hosts_password(hosts):
+ """Replace passwords in hosts list with *'s for log output"""
+ if not hosts:
+ return hosts
+
+ return [list(host)[:-1] + ['*' * 10] for host in hosts]
+
+
+class HostList:
"""This class contains methods for adding, removing and looking up hosts in hostlist.conf."""
def __init__(self):
@@ -97,12 +102,13 @@ class HostList(object):
default_hostlist(),
config_dir=get_config_dir(),
file_version=3,
+ log_mask_funcs={'hosts': mask_hosts_password},
)
self.config.run_converter((1, 2), 3, migrate_config_2_to_3)
self.config.save()
def check_info_exists(self, hostname, port, username, skip_host_id=None):
- """Check for exising host entries with the same details.
+ """Check for existing host entries with the same details.
Args:
hostname (str): The IP or hostname of the deluge daemon.
@@ -207,33 +213,38 @@ class HostList(object):
host_id, host, port, user = self.get_host_info(host_id)
except ValueError:
log.warning('Problem getting host_id info from hostlist')
- return status_offline
+ return defer.succeed(status_offline)
try:
- ip = gethostbyname(host)
- except gaierror as ex:
- log.error('Error resolving host %s to ip: %s', host, ex.args[1])
- return status_offline
-
- host_conn_info = (
- ip,
- port,
- 'localclient' if not user and host in LOCALHOST else user,
- )
- if client.connected() and host_conn_info == client.connection_info():
- # Currently connected to host_id daemon.
- def on_info(info, host_id):
- log.debug('Client connected, query info: %s', info)
- return host_id, 'Connected', info
-
- return client.daemon.info().addCallback(on_info, host_id)
- else:
- # Attempt to connect to daemon with host_id details.
- c = Client()
- d = c.connect(host, port, skip_authentication=True)
- d.addCallback(on_connect, c, host_id)
- d.addErrback(on_connect_failed, host_id)
- return d
+ ips = list({addrinfo[4][0] for addrinfo in getaddrinfo(host, None)})
+ except (gaierror, IndexError) as ex:
+ log.warning('Unable to resolve host %s to IP: %s', host, ex.args[1])
+ return defer.succeed(status_offline)
+
+ host_conn_list = [
+ (
+ host_ip,
+ port,
+ 'localclient' if not user and host_ip in LOCALHOST else user,
+ )
+ for host_ip in ips
+ ]
+
+ for host_conn_info in host_conn_list:
+ if client.connected() and host_conn_info == client.connection_info():
+ # Currently connected to host_id daemon.
+ def on_info(info, host_id):
+ log.debug('Client connected, query info: %s', info)
+ return host_id, 'Connected', info
+
+ return client.daemon.info().addCallback(on_info, host_id)
+ else:
+ # Attempt to connect to daemon with host_id details.
+ c = Client()
+ d = c.connect(host, port, skip_authentication=True)
+ d.addCallback(on_connect, c, host_id)
+ d.addErrback(on_connect_failed, host_id)
+ return d
def update_host(self, host_id, hostname, port, username, password):
"""Update the supplied host id with new connection details.
diff --git a/deluge/ui/sessionproxy.py b/deluge/ui/sessionproxy.py
index 5af8e79..b50ba6c 100644
--- a/deluge/ui/sessionproxy.py
+++ b/deluge/ui/sessionproxy.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2010 Andrew Resch <andrewresch@gmail.com>
#
@@ -6,8 +5,6 @@
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
from time import time
@@ -148,11 +145,17 @@ class SessionProxy(component.Component):
def on_status(result, torrent_id):
t = time()
- self.torrents[torrent_id][0] = t
- self.torrents[torrent_id][1].update(result)
- for key in keys_to_get:
- self.cache_times[torrent_id][key] = t
- return self.create_status_dict([torrent_id], keys)[torrent_id]
+ try:
+ self.torrents[torrent_id][0] = t
+ self.torrents[torrent_id][1].update(result)
+ for key in keys_to_get:
+ self.cache_times[torrent_id][key] = t
+ return self.create_status_dict([torrent_id], keys)[torrent_id]
+ except KeyError:
+ log.debug(
+ f'Status missing for torrent (removed?): {torrent_id}'
+ )
+ return {}
return d.addCallback(on_status, torrent_id)
else:
diff --git a/deluge/ui/tracker_icons.py b/deluge/ui/tracker_icons.py
index c10cd2f..5f619af 100644
--- a/deluge/ui/tracker_icons.py
+++ b/deluge/ui/tracker_icons.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2010 John Garland <johnnybg+deluge@gmail.com>
#
@@ -7,14 +6,14 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
-from tempfile import mkstemp
+import tempfile
+from html.parser import HTMLParser
+from urllib.parse import urljoin, urlparse
from twisted.internet import defer, threads
-from twisted.web.error import PageRedirect
+from twisted.python.failure import Failure
from twisted.web.resource import ForbiddenResource, NoResource
from deluge.component import Component
@@ -23,12 +22,9 @@ from deluge.decorators import proxy
from deluge.httpdownloader import download_file
try:
- from html.parser import HTMLParser
- from urllib.parse import urljoin, urlparse
+ import chardet
except ImportError:
- # PY2 fallback
- from HTMLParser import HTMLParser
- from urlparse import urljoin, urlparse # pylint: disable=ungrouped-imports
+ chardet = None
try:
from PIL import Image
@@ -38,7 +34,7 @@ except ImportError:
log = logging.getLogger(__name__)
-class TrackerIcon(object):
+class TrackerIcon:
"""
Represents a tracker's icon
"""
@@ -207,17 +203,19 @@ class TrackerIcons(Component):
else:
# We need to fetch it
self.pending[host] = []
+ tmp_file = tempfile.mkstemp(prefix='deluge_trackericon_html.')
+ filename = tmp_file[1]
# Start callback chain
- d = self.download_page(host)
+ d = self.download_page(host, filename)
d.addCallbacks(
self.on_download_page_complete,
self.on_download_page_fail,
- errbackArgs=(host,),
)
d.addCallback(self.parse_html_page)
d.addCallbacks(
self.on_parse_complete, self.on_parse_fail, callbackArgs=(host,)
)
+ d.addBoth(self.del_tmp_file, tmp_file)
d.addCallback(self.download_icon, host)
d.addCallbacks(
self.on_download_icon_complete,
@@ -229,24 +227,38 @@ class TrackerIcons(Component):
d.addCallback(self.store_icon, host)
return d
- def download_page(self, host, url=None):
- """
- Downloads a tracker host's page
+ @staticmethod
+ def del_tmp_file(result, tmp_file):
+ """Remove tmp_file created when downloading tracker page"""
+ fd, filename = tmp_file
+ try:
+ os.close(fd)
+ os.remove(filename)
+ except OSError:
+ log.debug(f'Unable to delete temporary file: {filename}')
+
+ return result
+
+ def download_page(
+ self, host: str, filename: str, url: str = None
+ ) -> 'defer.Deferred[str]':
+ """Downloads a tracker host's page
+
If no url is provided, it bases the url on the host
- :param host: the tracker host
- :type host: string
- :param url: the (optional) url of the host
- :type url: string
- :returns: the filename of the tracker host's page
- :rtype: Deferred
+ Args:
+ host: The tracker host
+ filename: Location to download page
+ url: The url of the host
+
+ Returns:
+ The filename of the tracker host's page
"""
if not url:
url = self.host_to_url(host)
- log.debug('Downloading %s %s', host, url)
- tmp_fd, tmp_file = mkstemp(prefix='deluge_ticon.')
- os.close(tmp_fd)
- return download_file(url, tmp_file, force_filename=True, handle_redirects=False)
+
+ log.debug(f'Downloading {host} {url} to {filename}')
+ return download_file(url, filename, force_filename=True)
def on_download_page_complete(self, page):
"""
@@ -260,33 +272,18 @@ class TrackerIcons(Component):
log.debug('Finished downloading %s', page)
return page
- def on_download_page_fail(self, f, host):
- """
- Recovers from download error
+ def on_download_page_fail(self, failure: 'Failure') -> 'Failure':
+ """Runs any download failure clean-up functions
- :param f: the failure that occurred
- :type f: Failure
- :param host: the name of the host whose page failed to download
- :type host: string
- :returns: a Deferred if recovery was possible
- else the original failure
- :rtype: Deferred or Failure
- """
- error_msg = f.getErrorMessage()
- log.debug('Error downloading page: %s', error_msg)
- d = f
- if f.check(PageRedirect):
- # Handle redirect errors
- location = urljoin(self.host_to_url(host), error_msg.split(' to ')[1])
- self.redirects[host] = url_to_host(location)
- d = self.download_page(host, url=location)
- d.addCallbacks(
- self.on_download_page_complete,
- self.on_download_page_fail,
- errbackArgs=(host,),
- )
+ Args:
+ failure: The failure that occurred.
- return d
+ Returns:
+ The original failure.
+
+ """
+ log.debug(f'Error downloading page: {failure.getErrorMessage()}')
+ return failure
@proxy(threads.deferToThread)
def parse_html_page(self, page):
@@ -298,17 +295,19 @@ class TrackerIcons(Component):
:returns: a Deferred which callbacks a list of available favicons (url, type)
:rtype: Deferred
"""
- with open(page, 'r') as _file:
+ encoding = 'UTF-8'
+ if chardet:
+ with open(page, 'rb') as _file:
+ result = chardet.detect(_file.read())
+ encoding = result['encoding']
+
+ with open(page, encoding=encoding) as _file:
parser = FaviconParser()
for line in _file:
parser.feed(line)
if parser.left_head:
break
parser.close()
- try:
- os.remove(page)
- except OSError as ex:
- log.warning('Could not remove temp file: %s', ex)
return parser.get_icons()
@@ -382,7 +381,7 @@ class TrackerIcons(Component):
try:
with Image.open(icon_name):
pass
- except IOError as ex:
+ except OSError as ex:
raise InvalidIconError(ex)
else:
if not os.path.getsize(icon_name):
@@ -423,22 +422,7 @@ class TrackerIcons(Component):
error_msg = f.getErrorMessage()
log.debug('Error downloading icon from %s: %s', host, error_msg)
d = f
- if f.check(PageRedirect):
- # Handle redirect errors
- location = urljoin(self.host_to_url(host), error_msg.split(' to ')[1])
- d = self.download_icon(
- [(location, extension_to_mimetype(location.rpartition('.')[2]))]
- + icons,
- host,
- )
- if not icons:
- d.addCallbacks(
- self.on_download_icon_complete,
- self.on_download_icon_fail,
- callbackArgs=(host,),
- errbackArgs=(host,),
- )
- elif f.check(NoResource, ForbiddenResource) and icons:
+ if f.check(NoResource, ForbiddenResource) and icons:
d = self.download_icon(icons, host)
elif f.check(NoIconsError):
# No icons, try favicon.ico as an act of desperation
@@ -477,14 +461,17 @@ class TrackerIcons(Component):
# Requires Pillow(PIL) to resize.
if icon and Image:
filename = icon.get_filename()
+ remove_old = False
with Image.open(filename) as img:
if img.size > (16, 16):
new_filename = filename.rpartition('.')[0] + '.png'
img = img.resize((16, 16), Image.ANTIALIAS)
img.save(new_filename)
if new_filename != filename:
- os.remove(filename)
- icon = TrackerIcon(new_filename)
+ remove_old = True
+ if remove_old:
+ os.remove(filename)
+ icon = TrackerIcon(new_filename)
return icon
def store_icon(self, icon, host):
@@ -617,11 +604,13 @@ MIME_MAP = {
'image/png': 'png',
'image/vnd.microsoft.icon': 'ico',
'image/x-icon': 'ico',
+ 'image/svg+xml': 'svg',
'gif': 'image/gif',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'ico': 'image/vnd.microsoft.icon',
+ 'svg': 'image/svg+xml',
}
diff --git a/deluge/ui/ui.py b/deluge/ui/ui.py
index 0986ec7..338f8a8 100644
--- a/deluge/ui/ui.py
+++ b/deluge/ui/ui.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
#
@@ -7,9 +6,8 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
+import sys
import deluge.common
import deluge.configmanager
@@ -27,7 +25,7 @@ except ImportError:
return
-class UI(object):
+class UI:
"""
Base class for UI implementations.
@@ -60,7 +58,7 @@ class UI(object):
return self.__options
def start(self, parser=None):
- args = deluge.common.unicode_argv()[1:]
+ args = sys.argv[1:]
if parser is None:
parser = self.parser
self.__options = self.parse_args(parser, args)
diff --git a/deluge/ui/ui_entry.py b/deluge/ui/ui_entry.py
index 71ce837..e185fda 100644
--- a/deluge/ui/ui_entry.py
+++ b/deluge/ui/ui_entry.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2010 Pedro Algarvio <pedro@algarvio.me>
@@ -12,8 +11,6 @@
# user runs the command 'deluge'.
"""Main starting point for Deluge"""
-from __future__ import unicode_literals
-
import argparse
import logging
import os
@@ -100,7 +97,7 @@ def start_ui():
# If the UI is set as default, indicate this in help by prefixing with a star.
subactions = subparsers._get_subactions()
prefix = '*' if ui == default_ui else ' '
- subactions[-1].metavar = '%s %s' % (prefix, ui)
+ subactions[-1].metavar = f'{prefix} {ui}'
# Insert a default UI subcommand unless one of the ambiguous_args are specified
parser.set_default_subparser(default_ui, abort_opts=AMBIGUOUS_CMD_ARGS)
@@ -115,7 +112,7 @@ def start_ui():
try:
ui = ui_entrypoints[selected_ui](
- prog='%s %s' % (os.path.basename(sys.argv[0]), selected_ui), ui_args=ui_args
+ prog=f'{os.path.basename(sys.argv[0])} {selected_ui}', ui_args=ui_args
)
except KeyError:
log.error(
diff --git a/deluge/ui/web/__init__.py b/deluge/ui/web/__init__.py
index 0be7eed..3757e0b 100644
--- a/deluge/ui/web/__init__.py
+++ b/deluge/ui/web/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import unicode_literals
-
from deluge.ui.web.web import Web
diff --git a/deluge/ui/web/auth.py b/deluge/ui/web/auth.py
index fa95049..eacbbf5 100644
--- a/deluge/ui/web/auth.py
+++ b/deluge/ui/web/auth.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import hashlib
import logging
import os
@@ -60,11 +57,11 @@ def make_expires(timeout):
class Auth(JSONComponent):
"""
- The component that implements authentification into the JSON interface.
+ The component that implements authentication into the JSON interface.
"""
def __init__(self, config):
- super(Auth, self).__init__('Auth')
+ super().__init__('Auth')
self.worker = LoopingCall(self._clean_sessions)
self.config = config
diff --git a/deluge/ui/web/common.py b/deluge/ui/web/common.py
index 475f335..32c29c8 100644
--- a/deluge/ui/web/common.py
+++ b/deluge/ui/web/common.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
@@ -7,19 +6,15 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import gettext
from mako.template import Template as MakoTemplate
-from deluge.common import PY2, get_version
+from deluge.common import get_version
def _(text):
text_local = gettext.gettext(text)
- if PY2:
- return text_local.decode('utf-8')
return text_local
diff --git a/deluge/ui/web/css/deluge.css b/deluge/ui/web/css/deluge.css
index b9fa03e..9460286 100644
--- a/deluge/ui/web/css/deluge.css
+++ b/deluge/ui/web/css/deluge.css
@@ -6,6 +6,8 @@ body {
border: 0 none;
overflow: hidden;
height: 100%;
+ color: black;
+ background: white;
}
input {
@@ -458,8 +460,16 @@ dl.singleline dd {
background-image: url('../icons/add_url.png') !important;
}
-.icon-add-magnet {
- background-image: url('../icons/add_magnet.png') !important;
+.icon-magnet-add {
+ background-image: url('../icons/magnet_add.png') !important;
+}
+
+.icon-magnet-copy {
+ background-image: url('../icons/magnet_copy.png') !important;
+}
+
+.icon-magnet {
+ background-image: url('../icons/magnet.png') !important;
}
.icon-pause {
diff --git a/deluge/ui/web/icons/active.png b/deluge/ui/web/icons/active.png
index daa4f64..c9af82a 100644
--- a/deluge/ui/web/icons/active.png
+++ b/deluge/ui/web/icons/active.png
Binary files differ
diff --git a/deluge/ui/web/icons/add_magnet.png b/deluge/ui/web/icons/add_magnet.png
deleted file mode 100644
index c015b18..0000000
--- a/deluge/ui/web/icons/add_magnet.png
+++ /dev/null
Binary files differ
diff --git a/deluge/ui/web/icons/checking.png b/deluge/ui/web/icons/checking.png
index 7487352..6758e36 100644
--- a/deluge/ui/web/icons/checking.png
+++ b/deluge/ui/web/icons/checking.png
Binary files differ
diff --git a/deluge/ui/web/icons/deluge.png b/deluge/ui/web/icons/deluge.png
index 2f4ae4c..5afdbe4 100644
--- a/deluge/ui/web/icons/deluge.png
+++ b/deluge/ui/web/icons/deluge.png
Binary files differ
diff --git a/deluge/ui/web/icons/downloading.png b/deluge/ui/web/icons/downloading.png
index ec58cb5..24d6ffa 100644
--- a/deluge/ui/web/icons/downloading.png
+++ b/deluge/ui/web/icons/downloading.png
Binary files differ
diff --git a/deluge/ui/web/icons/inactive.png b/deluge/ui/web/icons/inactive.png
index b56213e..cae8b2c 100644
--- a/deluge/ui/web/icons/inactive.png
+++ b/deluge/ui/web/icons/inactive.png
Binary files differ
diff --git a/deluge/ui/web/icons/magnet.png b/deluge/ui/web/icons/magnet.png
new file mode 100644
index 0000000..61d6dab
--- /dev/null
+++ b/deluge/ui/web/icons/magnet.png
Binary files differ
diff --git a/deluge/ui/web/icons/magnet_add.png b/deluge/ui/web/icons/magnet_add.png
new file mode 100644
index 0000000..37c1c36
--- /dev/null
+++ b/deluge/ui/web/icons/magnet_add.png
Binary files differ
diff --git a/deluge/ui/web/icons/magnet_copy.png b/deluge/ui/web/icons/magnet_copy.png
new file mode 100644
index 0000000..a4be9d2
--- /dev/null
+++ b/deluge/ui/web/icons/magnet_copy.png
Binary files differ
diff --git a/deluge/ui/web/js/deluge-all-debug.js b/deluge/ui/web/js/deluge-all-debug.js
index afbbabe..67bb83a 100644
--- a/deluge/ui/web/js/deluge-all-debug.js
+++ b/deluge/ui/web/js/deluge-all-debug.js
@@ -15,15 +15,15 @@ Ext.ns('Deluge.add');
* Base class for an add Window
*/
Deluge.add.Window = Ext.extend(Ext.Window, {
- initComponent: function() {
+ initComponent: function () {
Deluge.add.Window.superclass.initComponent.call(this);
- this.addEvents('beforeadd', 'add');
+ this.addEvents('beforeadd', 'add', 'addfailed');
},
/**
* Create an id for the torrent before we have any info about it.
*/
- createTorrentId: function() {
+ createTorrentId: function () {
return new Date().getTime().toString();
},
});
@@ -41,7 +41,7 @@ Ext.namespace('Deluge.add');
// This override allows file upload buttons to contain icons
Ext.override(Ext.ux.form.FileUploadField, {
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Ext.ux.form.FileUploadField.superclass.onRender.call(
this,
ct,
@@ -87,26 +87,12 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
plain: true,
iconCls: 'x-deluge-add-window-icon',
- initComponent: function() {
+ initComponent: function () {
Deluge.add.AddWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
this.addButton(_('Add'), this.onAddClick, this);
- function torrentRenderer(value, p, r) {
- if (r.data['info_hash']) {
- return String.format(
- '<div class="x-deluge-add-torrent-name">{0}</div>',
- value
- );
- } else {
- return String.format(
- '<div class="x-deluge-add-torrent-name-loading">{0}</div>',
- value
- );
- }
- }
-
this.list = new Ext.list.ListView({
store: new Ext.data.SimpleStore({
fields: [
@@ -120,8 +106,10 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
id: 'torrent',
width: 150,
sortable: true,
- renderer: torrentRenderer,
dataIndex: 'text',
+ tpl: new Ext.XTemplate(
+ '<div class="x-deluge-add-torrent-name">{text:htmlEncode}</div>'
+ ),
},
],
stripeRows: true,
@@ -176,7 +164,7 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
},
{
text: _('Infohash'),
- iconCls: 'icon-add-magnet',
+ iconCls: 'icon-magnet-add',
hidden: true,
disabled: true,
},
@@ -197,17 +185,17 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
this.on('show', this.onShow, this);
},
- clear: function() {
+ clear: function () {
this.list.getStore().removeAll();
this.optionsPanel.clear();
// Reset upload form so handler fires when a canceled file is reselected
this.fileUploadForm.reset();
},
- onAddClick: function() {
+ onAddClick: function () {
var torrents = [];
if (!this.list) return;
- this.list.getStore().each(function(r) {
+ this.list.getStore().each(function (r) {
var id = r.get('info_hash');
torrents.push({
path: this.optionsPanel.getFilename(id),
@@ -216,29 +204,29 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}, this);
deluge.client.web.add_torrents(torrents, {
- success: function(result) {},
+ success: function (result) {},
});
this.clear();
this.hide();
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.clear();
this.hide();
},
- onFile: function() {
+ onFile: function () {
if (!this.file) this.file = new Deluge.add.FileWindow();
this.file.show();
},
- onHide: function() {
+ onHide: function () {
this.optionsPanel.setActiveTab(0);
this.optionsPanel.files.setDisabled(true);
this.optionsPanel.form.setDisabled(true);
},
- onRemove: function() {
+ onRemove: function () {
if (!this.list.getSelectionCount()) return;
var torrent = this.list.getSelectedRecords()[0];
if (!torrent) return;
@@ -249,7 +237,7 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
delete this.torrents[torrent.id];
},
- onSelect: function(list, selections) {
+ onSelect: function (list, selections) {
if (selections.length) {
var record = this.list.getRecord(selections[0]);
this.optionsPanel.setTorrent(record.get('info_hash'));
@@ -259,24 +247,25 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}
},
- onShow: function() {
+ onShow: function () {
if (!this.url) {
this.url = new Deluge.add.UrlWindow();
this.url.on('beforeadd', this.onTorrentBeforeAdd, this);
this.url.on('add', this.onTorrentAdd, this);
+ this.url.on('addfailed', this.onTorrentAddFailed, this);
}
this.optionsPanel.form.getDefaults();
},
- onFileSelected: function() {
+ onFileSelected: function () {
if (this.fileUploadForm.isValid()) {
var torrentIds = [];
var files = this.fileUploadForm.findField('torrentFile').value;
var randomId = this.createTorrentId();
Array.prototype.forEach.call(
files,
- function(file, i) {
+ function (file, i) {
// Append index for batch of unique torrentIds.
var torrentId = randomId + i.toString();
torrentIds.push(torrentId);
@@ -287,20 +276,21 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
url: deluge.config.base + 'upload',
waitMsg: _('Uploading your torrent...'),
success: this.onUploadSuccess,
+ failure: this.onUploadFailure,
scope: this,
torrentIds: torrentIds,
});
}
},
- onUploadSuccess: function(fp, upload) {
+ onUploadSuccess: function (fp, upload) {
if (!upload.result.success) {
this.clear();
return;
}
upload.result.files.forEach(
- function(filename, i) {
+ function (filename, i) {
deluge.client.web.get_torrent_info(filename, {
success: this.onGotInfo,
scope: this,
@@ -312,18 +302,31 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
this.fileUploadForm.reset();
},
- onGotInfo: function(info, obj, response, request) {
+ onUploadFailure: function (form, action) {
+ this.hide();
+ Ext.MessageBox.show({
+ title: _('Error'),
+ msg: _('Failed to upload torrent'),
+ buttons: Ext.MessageBox.OK,
+ modal: false,
+ icon: Ext.MessageBox.ERROR,
+ iconCls: 'x-deluge-icon-error',
+ });
+ this.fireEvent('addfailed', this.torrentId);
+ },
+
+ onGotInfo: function (info, obj, response, request) {
info.filename = request.options.filename;
torrentId = request.options.torrentId;
this.onTorrentAdd(torrentId, info);
},
- onTorrentBeforeAdd: function(torrentId, text) {
+ onTorrentBeforeAdd: function (torrentId, text) {
var store = this.list.getStore();
store.loadData([[torrentId, null, text]], true);
},
- onTorrentAdd: function(torrentId, info) {
+ onTorrentAdd: function (torrentId, info) {
var r = this.list.getStore().getById(torrentId);
if (!info) {
Ext.MessageBox.show({
@@ -344,7 +347,15 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}
},
- onUrl: function(button, event) {
+ onTorrentAddFailed: function (torrentId) {
+ var store = this.list.getStore();
+ var torrentRecord = store.getById(torrentId);
+ if (torrentRecord) {
+ store.remove(torrentRecord);
+ }
+ },
+
+ onUrl: function (button, event) {
this.url.show();
},
});
@@ -378,13 +389,14 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
header: _('Filename'),
width: 295,
dataIndex: 'filename',
+ tpl: new Ext.XTemplate('{filename:htmlEncode}'),
},
{
header: _('Size'),
width: 60,
dataIndex: 'size',
tpl: new Ext.XTemplate('{size:this.fsize}', {
- fsize: function(v) {
+ fsize: function (v) {
return fsize(v);
},
}),
@@ -394,7 +406,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
width: 65,
dataIndex: 'download',
tpl: new Ext.XTemplate('{download:this.format}', {
- format: function(v) {
+ format: function (v) {
return (
'<div rel="chkbox" class="x-grid3-check-col' +
(v ? '-on' : '') +
@@ -405,21 +417,21 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
},
],
- initComponent: function() {
+ initComponent: function () {
Deluge.add.FilesTab.superclass.initComponent.call(this);
this.on('click', this.onNodeClick, this);
},
- clearFiles: function() {
+ clearFiles: function () {
var root = this.getRootNode();
if (!root.hasChildNodes()) return;
- root.cascade(function(node) {
+ root.cascade(function (node) {
if (!node.parentNode || !node.getOwnerTree()) return;
node.remove();
});
},
- setDownload: function(node, value, suppress) {
+ setDownload: function (node, value, suppress) {
node.attributes.download = value;
node.ui.updateColumns();
@@ -429,7 +441,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}
} else {
var nodes = [node];
- node.cascade(function(n) {
+ node.cascade(function (n) {
n.attributes.download = value;
n.ui.updateColumns();
nodes.push(n);
@@ -440,7 +452,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}
},
- onNodeClick: function(node, e) {
+ onNodeClick: function (node, e) {
var el = new Ext.Element(e.target);
if (el.getAttribute('rel') == 'chkbox') {
this.setDownload(node, !node.attributes.download);
@@ -477,7 +489,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
activeTab: 0,
height: 265,
- initComponent: function() {
+ initComponent: function () {
Deluge.add.OptionsPanel.superclass.initComponent.call(this);
this.files = this.add(new Deluge.add.FilesTab());
this.form = this.add(new Deluge.add.OptionsTab());
@@ -485,12 +497,12 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
this.files.on('fileschecked', this.onFilesChecked, this);
},
- addTorrent: function(torrent) {
+ addTorrent: function (torrent) {
this.torrents[torrent['info_hash']] = torrent;
var fileIndexes = {};
this.walkFileTree(
torrent['files_tree'],
- function(filename, type, entry, parent) {
+ function (filename, type, entry, parent) {
if (type != 'file') return;
fileIndexes[entry.index] = entry.download;
},
@@ -498,7 +510,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
);
var priorities = [];
- Ext.each(Ext.keys(fileIndexes), function(index) {
+ Ext.each(Ext.keys(fileIndexes), function (index) {
priorities[index] = fileIndexes[index];
});
@@ -510,26 +522,26 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
this.form.optionsManager.changeId(oldId, true);
},
- clear: function() {
+ clear: function () {
this.files.clearFiles();
this.form.optionsManager.resetAll();
},
- getFilename: function(torrentId) {
+ getFilename: function (torrentId) {
return this.torrents[torrentId]['filename'];
},
- getOptions: function(torrentId) {
+ getOptions: function (torrentId) {
var oldId = this.form.optionsManager.changeId(torrentId, true);
var options = this.form.optionsManager.get();
this.form.optionsManager.changeId(oldId, true);
- Ext.each(options['file_priorities'], function(priority, index) {
+ Ext.each(options['file_priorities'], function (priority, index) {
options['file_priorities'][index] = priority ? 1 : 0;
});
return options;
},
- setTorrent: function(torrentId) {
+ setTorrent: function (torrentId) {
if (!torrentId) return;
this.torrentId = torrentId;
@@ -544,7 +556,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
if (this.torrents[torrentId]['files_tree']) {
this.walkFileTree(
this.torrents[torrentId]['files_tree'],
- function(filename, type, entry, parentNode) {
+ function (filename, type, entry, parentNode) {
var node = new Ext.tree.TreeNode({
download: entry.index ? priorities[entry.index] : true,
filename: filename,
@@ -568,7 +580,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
}
},
- walkFileTree: function(files, callback, scope, parentNode) {
+ walkFileTree: function (files, callback, scope, parentNode) {
for (var filename in files.contents) {
var entry = files.contents[filename];
var type = entry.type;
@@ -588,14 +600,13 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
}
},
- onFilesChecked: function(nodes, newValue, oldValue) {
+ onFilesChecked: function (nodes, newValue, oldValue) {
Ext.each(
nodes,
- function(node) {
+ function (node) {
if (node.attributes.fileindex < 0) return;
- var priorities = this.form.optionsManager.get(
- 'file_priorities'
- );
+ var priorities =
+ this.form.optionsManager.get('file_priorities');
priorities[node.attributes.fileindex] = newValue;
this.form.optionsManager.update('file_priorities', priorities);
},
@@ -626,7 +637,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
disabled: true,
labelWidth: 1,
- initComponent: function() {
+ initComponent: function () {
Deluge.add.OptionsTab.superclass.initComponent.call(this);
this.optionsManager = new Deluge.MultiOptionsManager();
@@ -779,7 +790,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
);
},
- getDefaults: function() {
+ getDefaults: function () {
var keys = [
'add_paused',
'pre_allocate_storage',
@@ -795,7 +806,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
];
deluge.client.core.get_config_values(keys, {
- success: function(config) {
+ success: function (config) {
var options = {
file_priorities: [],
add_paused: config.add_paused,
@@ -844,7 +855,7 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
bodyStyle: 'padding: 10px 5px;',
iconCls: 'x-deluge-add-url-window-icon',
- initComponent: function() {
+ initComponent: function () {
Deluge.add.UrlWindow.superclass.initComponent.call(this);
this.addButton(_('Add'), this.onAddClick, this);
@@ -872,7 +883,7 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
this.cookieField.on('specialkey', this.onAdd, this);
},
- onAddClick: function(field, e) {
+ onAddClick: function (field, e) {
if (
(field.id == 'url' || field.id == 'cookies') &&
e.getKey() != e.ENTER
@@ -894,6 +905,7 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
} else {
deluge.client.web.download_torrent_from_url(url, cookies, {
success: this.onDownload,
+ failure: this.onDownloadFailed,
scope: this,
torrentId: torrentId,
});
@@ -904,16 +916,29 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
this.fireEvent('beforeadd', torrentId, url);
},
- onDownload: function(filename, obj, resp, req) {
+ onDownload: function (filename, obj, resp, req) {
deluge.client.web.get_torrent_info(filename, {
success: this.onGotInfo,
+ failure: this.onDownloadFailed,
scope: this,
filename: filename,
torrentId: req.options.torrentId,
});
},
- onGotInfo: function(info, obj, response, request) {
+ onDownloadFailed: function (obj, resp, req) {
+ Ext.MessageBox.show({
+ title: _('Error'),
+ msg: _('Failed to download torrent'),
+ buttons: Ext.MessageBox.OK,
+ modal: false,
+ icon: Ext.MessageBox.ERROR,
+ iconCls: 'x-deluge-icon-error',
+ });
+ this.fireEvent('addfailed', req.options.torrentId);
+ },
+
+ onGotInfo: function (info, obj, response, request) {
info['filename'] = request.options.filename;
this.fireEvent('add', request.options.torrentId, info);
},
@@ -947,11 +972,11 @@ Deluge.data.SortTypes = {
return ((+d[1] * 256 + (+d[2])) * 256 + (+d[3])) * 256 + (+d[4]);
},
- asQueuePosition: function(value) {
+ asQueuePosition: function (value) {
return value > -1 ? value : Number.MAX_VALUE;
},
- asName: function(value) {
+ asName: function (value) {
return String(value).toLowerCase();
},
};
@@ -1147,7 +1172,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
id: 'torrentDetails',
activeTab: 0,
- initComponent: function() {
+ initComponent: function () {
Deluge.details.DetailsPanel.superclass.initComponent.call(this);
this.add(new Deluge.details.StatusTab());
this.add(new Deluge.details.DetailsTab());
@@ -1156,8 +1181,8 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
this.add(new Deluge.details.OptionsTab());
},
- clear: function() {
- this.items.each(function(panel) {
+ clear: function () {
+ this.items.each(function (panel) {
if (panel.clear) {
panel.clear.defer(100, panel);
panel.disable();
@@ -1165,14 +1190,14 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
});
},
- update: function(tab) {
+ update: function (tab) {
var torrent = deluge.torrents.getSelected();
if (!torrent) {
this.clear();
return;
}
- this.items.each(function(tab) {
+ this.items.each(function (tab) {
if (tab.disabled) tab.enable();
});
@@ -1183,7 +1208,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
/* Event Handlers */
// We need to add the events in onRender since Deluge.Torrents has not been created yet.
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.DetailsPanel.superclass.onRender.call(
this,
ct,
@@ -1195,18 +1220,18 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
deluge.torrents.getSelectionModel().on(
'selectionchange',
- function(selModel) {
+ function (selModel) {
if (!selModel.hasSelection()) this.clear();
},
this
);
},
- onTabChange: function(panel, tab) {
+ onTabChange: function (panel, tab) {
this.update(tab);
},
- onTorrentsClick: function(grid, rowIndex, e) {
+ onTorrentsClick: function (grid, rowIndex, e) {
this.update();
},
});
@@ -1230,7 +1255,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
oldData: {},
- initComponent: function() {
+ initComponent: function () {
Deluge.details.DetailsTab.superclass.initComponent.call(this);
this.addItem('torrent_name', _('Name:'));
this.addItem('hash', _('Hash:'));
@@ -1243,7 +1268,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
this.addItem('creator', _('Created By:'));
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.DetailsTab.superclass.onRender.call(this, ct, position);
this.body.setStyle('padding', '10px');
this.dl = Ext.DomHelper.append(this.body, { tag: 'dl' }, true);
@@ -1253,7 +1278,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
}
},
- addItem: function(id, label) {
+ addItem: function (id, label) {
if (!this.rendered) {
this.queuedItems[id] = label;
} else {
@@ -1262,7 +1287,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
},
// private
- doAddItem: function(id, label) {
+ doAddItem: function (id, label) {
Ext.DomHelper.append(this.dl, { tag: 'dt', cls: id, html: label });
this.fields[id] = Ext.DomHelper.append(
this.dl,
@@ -1271,7 +1296,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
);
},
- clear: function() {
+ clear: function () {
if (!this.fields) return;
for (var k in this.fields) {
this.fields[k].dom.innerHTML = '';
@@ -1279,7 +1304,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
this.oldData = {};
},
- update: function(torrentId) {
+ update: function (torrentId) {
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Details, {
success: this.onRequestComplete,
scope: this,
@@ -1287,7 +1312,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
});
},
- onRequestComplete: function(torrent, request, response, options) {
+ onRequestComplete: function (torrent, request, response, options) {
var data = {
torrent_name: torrent.name,
hash: options.options.torrentId,
@@ -1303,7 +1328,9 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
for (var field in this.fields) {
if (!Ext.isDefined(data[field])) continue; // This is a field we are not responsible for.
if (data[field] == this.oldData[field]) continue;
- this.fields[field].dom.innerHTML = Ext.escapeHTML(data[field]);
+ this.fields[field].dom.innerHTML = Ext.util.Format.htmlEncode(
+ data[field]
+ );
}
this.oldData = data;
},
@@ -1328,13 +1355,14 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
header: _('Filename'),
width: 330,
dataIndex: 'filename',
+ tpl: new Ext.XTemplate('{filename:htmlEncode}'),
},
{
header: _('Size'),
width: 150,
dataIndex: 'size',
tpl: new Ext.XTemplate('{size:this.fsize}', {
- fsize: function(v) {
+ fsize: function (v) {
return fsize(v);
},
}),
@@ -1344,7 +1372,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
header: _('Progress'),
width: 150,
dataIndex: 'progress',
- renderer: function(v) {
+ renderer: function (v) {
var progress = v * 100;
return Deluge.progressBar(
progress,
@@ -1364,11 +1392,11 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
'{priority:this.getName}' +
'</div></tpl>',
{
- getClass: function(v) {
+ getClass: function (v) {
return FILE_PRIORITY_CSS[v];
},
- getName: function(v) {
+ getName: function (v) {
return _(FILE_PRIORITY[v]);
},
}
@@ -1378,15 +1406,15 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
selModel: new Ext.tree.MultiSelectionModel(),
- initComponent: function() {
+ initComponent: function () {
Deluge.details.FilesTab.superclass.initComponent.call(this);
this.setRootNode(new Ext.tree.TreeNode({ text: _('Files') }));
},
- clear: function() {
+ clear: function () {
var root = this.getRootNode();
if (!root.hasChildNodes()) return;
- root.cascade(function(node) {
+ root.cascade(function (node) {
var parentNode = node.parentNode;
if (!parentNode) return;
if (!parentNode.ownerTree) return;
@@ -1394,7 +1422,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
});
},
- createFileTree: function(files) {
+ createFileTree: function (files) {
function walk(files, parentNode) {
for (var file in files.contents) {
var item = files.contents[file];
@@ -1433,7 +1461,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
root.firstChild.expand();
},
- update: function(torrentId) {
+ update: function (torrentId) {
if (this.torrentId != torrentId) {
this.clear();
this.torrentId = torrentId;
@@ -1446,7 +1474,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
});
},
- updateFileTree: function(files) {
+ updateFileTree: function (files) {
function walk(files, parentNode) {
for (var file in files.contents) {
var item = files.contents[file];
@@ -1463,7 +1491,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
walk(files, this.getRootNode());
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.FilesTab.superclass.onRender.call(this, ct, position);
deluge.menus.filePriorities.on('itemclick', this.onItemClick, this);
this.on('contextmenu', this.onContextMenu, this);
@@ -1472,7 +1500,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
});
},
- onContextMenu: function(node, e) {
+ onContextMenu: function (node, e) {
e.stopEvent();
var selModel = this.getSelectionModel();
if (selModel.getSelectedNodes().length < 2) {
@@ -1482,14 +1510,14 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
deluge.menus.filePriorities.showAt(e.getPoint());
},
- onItemClick: function(baseItem, e) {
+ onItemClick: function (baseItem, e) {
switch (baseItem.id) {
case 'expandAll':
this.expandAll();
break;
default:
var indexes = {};
- var walk = function(node) {
+ var walk = function (node) {
if (Ext.isEmpty(node.attributes.fileIndex)) return;
indexes[node.attributes.fileIndex] =
node.attributes.priority;
@@ -1497,9 +1525,9 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
this.getRootNode().cascade(walk);
var nodes = this.getSelectionModel().getSelectedNodes();
- Ext.each(nodes, function(node) {
+ Ext.each(nodes, function (node) {
if (!node.isLeaf()) {
- var setPriorities = function(node) {
+ var setPriorities = function (node) {
if (Ext.isEmpty(node.attributes.fileIndex)) return;
indexes[node.attributes.fileIndex] =
baseItem.filePriority;
@@ -1521,8 +1549,8 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
[this.torrentId],
{ file_priorities: priorities },
{
- success: function() {
- Ext.each(nodes, function(node) {
+ success: function () {
+ Ext.each(nodes, function (node) {
node.setColumnValue(3, baseItem.filePriority);
});
},
@@ -1533,7 +1561,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}
},
- onRequestComplete: function(files, options) {
+ onRequestComplete: function (files, options) {
if (!this.getRootNode().hasChildNodes()) {
this.createFileTree(files);
} else {
@@ -1552,7 +1580,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
*/
Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
autoScroll: true,
@@ -1573,7 +1601,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
Deluge.details.OptionsTab.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.details.OptionsTab.superclass.initComponent.call(this);
(this.fieldsets = {}), (this.fields = {});
@@ -1882,7 +1910,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
});
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.OptionsTab.superclass.onRender.call(this, ct, position);
// This is another hack I think, so keep an eye out here when upgrading.
@@ -1891,17 +1919,17 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
this.doLayout();
},
- clear: function() {
+ clear: function () {
if (this.torrentId == null) return;
this.torrentId = null;
this.optionsManager.changeId(null);
},
- reset: function() {
+ reset: function () {
if (this.torrentId) this.optionsManager.reset();
},
- update: function(torrentId) {
+ update: function (torrentId) {
if (this.torrentId && !torrentId) this.clear(); // we want to clear the pane if we get a null torrent torrentIds
if (!torrentId) return; // We do not care about null torrentIds.
@@ -1916,33 +1944,33 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
});
},
- onApply: function() {
+ onApply: function () {
var changed = this.optionsManager.getDirty();
deluge.client.core.set_torrent_options([this.torrentId], changed, {
- success: function() {
+ success: function () {
this.optionsManager.commit();
},
scope: this,
});
},
- onEditTrackers: function() {
+ onEditTrackers: function () {
deluge.editTrackers.show();
},
- onMoveCompletedChecked: function(checkbox, checked) {
+ onMoveCompletedChecked: function (checkbox, checked) {
this.fields.move_completed_path.setDisabled(!checked);
if (!checked) return;
this.fields.move_completed_path.focus();
},
- onStopRatioChecked: function(checkbox, checked) {
+ onStopRatioChecked: function (checkbox, checked) {
this.fields.remove_at_ratio.setDisabled(!checked);
this.fields.stop_ratio.setDisabled(!checked);
},
- onRequestComplete: function(torrent, options) {
+ onRequestComplete: function (torrent, options) {
this.fields['private'].setValue(torrent['private']);
this.fields['private'].setDisabled(true);
delete torrent['private'];
@@ -1968,13 +1996,13 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
* See LICENSE for more details.
*/
-(function() {
+(function () {
function flagRenderer(value) {
if (!value.replace(' ', '').replace(' ', '')) {
return '';
}
return String.format(
- '<img src="{0}flag/{1}" />',
+ '<img alt="{1}" title="{1}" src="{0}flag/{1}" />',
deluge.config.base,
value
);
@@ -2000,7 +2028,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
// fast way to figure out if we have a peer already.
peers: {},
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
title: _('Peers'),
@@ -2033,7 +2061,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
header: _('Client'),
width: 125,
sortable: true,
- renderer: fplain,
+ renderer: 'htmlEncode',
dataIndex: 'client',
},
{
@@ -2067,19 +2095,19 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
Deluge.details.PeersTab.superclass.constructor.call(this, config);
},
- clear: function() {
+ clear: function () {
this.getStore().removeAll();
this.peers = {};
},
- update: function(torrentId) {
+ update: function (torrentId) {
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Peers, {
success: this.onRequestComplete,
scope: this,
});
},
- onRequestComplete: function(torrent, options) {
+ onRequestComplete: function (torrent, options) {
if (!torrent) return;
var store = this.getStore();
@@ -2089,7 +2117,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
// Go through the peers updating and creating peer records
Ext.each(
torrent.peers,
- function(peer) {
+ function (peer) {
if (this.peers[peer.ip]) {
var record = store.getById(peer.ip);
record.beginEdit();
@@ -2110,7 +2138,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
store.add(newPeers);
// Remove any peers that should not be left in the store.
- store.each(function(record) {
+ store.each(function (record) {
if (!addresses[record.id]) {
store.remove(record);
delete this.peers[record.id];
@@ -2143,7 +2171,7 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
title: _('Status'),
autoScroll: true,
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.StatusTab.superclass.onRender.call(this, ct, position);
this.progressBar = this.add({
@@ -2159,7 +2187,7 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
width: 1000,
listeners: {
render: {
- fn: function(panel) {
+ fn: function (panel) {
panel.load({
url: deluge.config.base + 'render/tab_status.html',
text: _('Loading') + '...',
@@ -2174,14 +2202,14 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
});
},
- clear: function() {
+ clear: function () {
this.progressBar.updateProgress(0, ' ');
for (var k in this.fields) {
this.fields[k].innerHTML = '';
}
},
- update: function(torrentId) {
+ update: function (torrentId) {
if (!this.fields) this.getFields();
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Status, {
success: this.onRequestComplete,
@@ -2189,18 +2217,18 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
});
},
- onPanelUpdate: function(el, response) {
+ onPanelUpdate: function (el, response) {
this.fields = {};
Ext.each(
Ext.query('dd', this.status.body.dom),
- function(field) {
+ function (field) {
this.fields[field.className] = field;
},
this
);
},
- onRequestComplete: function(status) {
+ onRequestComplete: function (status) {
seeds =
status.total_seeds > -1
? status.num_seeds + ' (' + status.total_seeds + ')'
@@ -2295,7 +2323,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -2309,7 +2337,7 @@ Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, {
Deluge.preferences.Bandwidth.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Bandwidth.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
@@ -2398,8 +2426,7 @@ Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, {
border: false,
title: '',
defaultType: 'checkbox',
- style:
- 'padding-top: 0px; padding-bottom: 5px; margin-top: 0px; margin-bottom: 0px;',
+ style: 'padding-top: 0px; padding-bottom: 5px; margin-top: 0px; margin-bottom: 0px;',
autoHeight: true,
});
om.bind(
@@ -2503,7 +2530,7 @@ Deluge.preferences.Cache = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Cache.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
@@ -2564,7 +2591,7 @@ Deluge.preferences.Daemon = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Daemon.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
@@ -2644,7 +2671,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Downloads = Ext.extend(Ext.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -2659,7 +2686,7 @@ Deluge.preferences.Downloads = Ext.extend(Ext.FormPanel, {
Deluge.preferences.Downloads.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Downloads.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
@@ -2772,7 +2799,7 @@ Deluge.preferences.Encryption = Ext.extend(Ext.form.FormPanel, {
title: _('Encryption'),
header: false,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Encryption.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
@@ -2879,7 +2906,7 @@ Deluge.preferences.InstallPluginWindow = Ext.extend(Ext.Window, {
modal: true,
plain: true,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.InstallPluginWindow.superclass.initComponent.call(
this
);
@@ -2906,7 +2933,7 @@ Deluge.preferences.InstallPluginWindow = Ext.extend(Ext.Window, {
});
},
- onInstall: function(field, e) {
+ onInstall: function (field, e) {
this.form.getForm().submit({
url: deluge.config.base + 'upload',
waitMsg: _('Uploading your plugin...'),
@@ -2915,11 +2942,11 @@ Deluge.preferences.InstallPluginWindow = Ext.extend(Ext.Window, {
});
},
- onUploadPlugin: function(info, obj, response, request) {
+ onUploadPlugin: function (info, obj, response, request) {
this.fireEvent('pluginadded');
},
- onUploadSuccess: function(fp, upload) {
+ onUploadSuccess: function (fp, upload) {
this.hide();
if (upload.result.success) {
var filename = this.form.getForm().getFieldValues().file;
@@ -2955,7 +2982,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Interface.superclass.initComponent.call(this);
var om = (this.optionsManager = new Deluge.OptionsManager());
@@ -3125,7 +3152,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
);
},
- onApply: function() {
+ onApply: function () {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
deluge.client.web.set_config(changed, {
@@ -3147,7 +3174,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
no: _('Close'),
},
multiline: false,
- fn: function(btnText) {
+ fn: function (btnText) {
if (btnText === 'yes') location.reload();
},
icon: Ext.MessageBox.QUESTION,
@@ -3159,21 +3186,21 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
}
},
- onOk: function() {
+ onOk: function () {
this.onApply();
},
- onGotConfig: function(config) {
+ onGotConfig: function (config) {
this.optionsManager.set(config);
},
- onGotLanguages: function(info, obj, response, request) {
+ onGotLanguages: function (info, obj, response, request) {
info.unshift(['', _('System Default')]);
this.language.store.loadData(info);
this.language.setValue(this.optionsManager.get('language'));
},
- onPasswordChange: function() {
+ onPasswordChange: function () {
var newPassword = this.newPassword.getValue();
if (newPassword != this.confirmPassword.getValue()) {
Ext.MessageBox.show({
@@ -3189,7 +3216,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
var oldPassword = this.oldPassword.getValue();
deluge.client.auth.change_password(oldPassword, newPassword, {
- success: function(result) {
+ success: function (result) {
if (!result) {
Ext.MessageBox.show({
title: _('Password'),
@@ -3218,11 +3245,11 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
});
},
- onSetConfig: function() {
+ onSetConfig: function () {
this.optionsManager.commit();
},
- onPageShow: function() {
+ onPageShow: function () {
deluge.client.web.get_config({
success: this.onGotConfig,
scope: this,
@@ -3233,7 +3260,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
});
},
- onSSLCheck: function(e, checked) {
+ onSSLCheck: function (e, checked) {
this.pkeyField.setDisabled(!checked);
this.certField.setDisabled(!checked);
},
@@ -3251,7 +3278,7 @@ Ext.namespace('Deluge.preferences');
// custom Vtype for vtype:'IPAddress'
Ext.apply(Ext.form.VTypes, {
- IPAddress: function(v) {
+ IPAddress: function (v) {
return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
},
IPAddressText: 'Must be a numeric IP address',
@@ -3268,7 +3295,7 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
title: _('Network'),
header: false,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Network.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
@@ -3311,7 +3338,7 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
height: 22,
listeners: {
check: {
- fn: function(e, checked) {
+ fn: function (e, checked) {
this.listenPort.setDisabled(checked);
},
scope: this,
@@ -3373,7 +3400,7 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
height: 22,
listeners: {
check: {
- fn: function(e, checked) {
+ fn: function (e, checked) {
this.outgoingPorts.setDisabled(checked);
},
scope: this,
@@ -3511,7 +3538,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Other = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -3524,7 +3551,7 @@ Deluge.preferences.Other = Ext.extend(Ext.form.FormPanel, {
Deluge.preferences.Other.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Other.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
@@ -3637,7 +3664,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
'</dl>'
),
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Plugins.superclass.initComponent.call(this);
this.defaultValues = {
version: '',
@@ -3647,7 +3674,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
};
this.pluginTemplate.compile();
- var checkboxRenderer = function(v, p, record) {
+ var checkboxRenderer = function (v, p, record) {
p.css += ' x-grid3-check-col-td';
return (
'<div class="x-grid3-check-col' + (v ? '-on' : '') + '"> </div>'
@@ -3669,7 +3696,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
width: 0.2,
sortable: true,
tpl: new Ext.XTemplate('{enabled:this.getCheckbox}', {
- getCheckbox: function(v) {
+ getCheckbox: function (v) {
return (
'<div class="x-grid3-check-col' +
(v ? '-on' : '') +
@@ -3738,23 +3765,23 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
deluge.events.on('PluginEnabledEvent', this.onPluginEnabled, this);
},
- disablePlugin: function(plugin) {
+ disablePlugin: function (plugin) {
deluge.client.core.disable_plugin(plugin);
},
- enablePlugin: function(plugin) {
+ enablePlugin: function (plugin) {
deluge.client.core.enable_plugin(plugin);
},
- setInfo: function(plugin) {
+ setInfo: function (plugin) {
if (!this.pluginInfo.rendered) return;
var values = plugin || this.defaultValues;
this.pluginInfo.body.dom.innerHTML = this.pluginTemplate.apply(values);
},
- updatePlugins: function() {
- var onGotAvailablePlugins = function(plugins) {
- this.availablePlugins = plugins.sort(function(a, b) {
+ updatePlugins: function () {
+ var onGotAvailablePlugins = function (plugins) {
+ this.availablePlugins = plugins.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
@@ -3764,7 +3791,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
});
};
- var onGotEnabledPlugins = function(plugins) {
+ var onGotEnabledPlugins = function (plugins) {
this.enabledPlugins = plugins;
this.onGotPlugins();
};
@@ -3775,11 +3802,11 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
});
},
- updatePluginsGrid: function() {
+ updatePluginsGrid: function () {
var plugins = [];
Ext.each(
this.availablePlugins,
- function(plugin) {
+ function (plugin) {
if (this.enabledPlugins.indexOf(plugin) > -1) {
plugins.push([true, plugin]);
} else {
@@ -3791,7 +3818,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
this.list.getStore().loadData(plugins);
},
- onNodeClick: function(dv, index, node, e) {
+ onNodeClick: function (dv, index, node, e) {
var el = new Ext.Element(e.target);
if (el.getAttribute('rel') != 'chkbox') return;
@@ -3806,16 +3833,16 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
}
},
- onFindMorePlugins: function() {
+ onFindMorePlugins: function () {
window.open('http://dev.deluge-torrent.org/wiki/Plugins');
},
- onGotPlugins: function() {
+ onGotPlugins: function () {
this.setInfo();
this.updatePluginsGrid();
},
- onGotPluginInfo: function(info) {
+ onGotPluginInfo: function (info) {
var values = {
author: info['Author'],
version: info['Version'],
@@ -3827,7 +3854,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
delete info;
},
- onInstallPluginWindow: function() {
+ onInstallPluginWindow: function () {
if (!this.installWindow) {
this.installWindow = new Deluge.preferences.InstallPluginWindow();
this.installWindow.on('pluginadded', this.onPluginInstall, this);
@@ -3835,7 +3862,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
this.installWindow.show();
},
- onPluginEnabled: function(pluginName) {
+ onPluginEnabled: function (pluginName) {
var index = this.list.getStore().find('plugin', pluginName);
if (index == -1) return;
var plugin = this.list.getStore().getAt(index);
@@ -3843,7 +3870,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
plugin.commit();
},
- onPluginDisabled: function(pluginName) {
+ onPluginDisabled: function (pluginName) {
var index = this.list.getStore().find('plugin', pluginName);
if (index == -1) return;
var plugin = this.list.getStore().getAt(index);
@@ -3851,11 +3878,11 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
plugin.commit();
},
- onPluginInstall: function() {
+ onPluginInstall: function () {
this.updatePlugins();
},
- onPluginSelect: function(dv, selections) {
+ onPluginSelect: function (dv, selections) {
if (selections.length == 0) return;
var r = dv.getRecords(selections)[0];
deluge.client.web.get_plugin_info(r.get('plugin'), {
@@ -3864,11 +3891,11 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
});
},
- onPreferencesShow: function() {
+ onPreferencesShow: function () {
this.updatePlugins();
},
- onPluginInfoRender: function(ct, position) {
+ onPluginInfoRender: function (ct, position) {
this.setInfo();
},
});
@@ -3910,7 +3937,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
pages: {},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.PreferencesWindow.superclass.initComponent.call(
this
);
@@ -3920,7 +3947,6 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
columns: [
{
id: 'name',
- renderer: fplain,
dataIndex: 'name',
},
],
@@ -3968,7 +3994,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
this.initPages();
},
- initPages: function() {
+ initPages: function () {
deluge.preferences = this;
this.addPage(new Deluge.preferences.Downloads());
this.addPage(new Deluge.preferences.Network());
@@ -3983,7 +4009,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
this.addPage(new Deluge.preferences.Plugins());
},
- onApply: function(e) {
+ onApply: function (e) {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
// Workaround for only displaying single listen port but still pass array to core.
@@ -4008,7 +4034,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Return the options manager for the preferences window.
* @returns {Deluge.OptionsManager} the options manager
*/
- getOptionsManager: function() {
+ getOptionsManager: function () {
return this.optionsManager;
},
@@ -4016,7 +4042,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Adds a page to the preferences window.
* @param {Mixed} page
*/
- addPage: function(page) {
+ addPage: function (page) {
var store = this.list.getStore();
var name = page.title;
store.add([new PreferencesRecord({ name: name })]);
@@ -4031,7 +4057,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Removes a preferences page from the window.
* @param {mixed} name
*/
- removePage: function(page) {
+ removePage: function (page) {
var name = page.title;
var store = this.list.getStore();
store.removeAt(store.find('name', name));
@@ -4043,7 +4069,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Select which preferences page is displayed.
* @param {String} page The page name to change to
*/
- selectPage: function(page) {
+ selectPage: function (page) {
if (this.pages[page].index < 0) {
this.pages[page].index = this.configPanel.items.indexOf(
this.pages[page]
@@ -4053,7 +4079,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- doSelectPage: function(page) {
+ doSelectPage: function (page) {
if (this.pages[page].index < 0) {
this.pages[page].index = this.configPanel.items.indexOf(
this.pages[page]
@@ -4064,23 +4090,23 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- onGotConfig: function(config) {
+ onGotConfig: function (config) {
this.getOptionsManager().set(config);
},
// private
- onPageSelect: function(list, selections) {
+ onPageSelect: function (list, selections) {
var r = list.getRecord(selections[0]);
this.doSelectPage(r.get('name'));
},
// private
- onSetConfig: function() {
+ onSetConfig: function () {
this.getOptionsManager().commit();
},
// private
- onAfterRender: function() {
+ onAfterRender: function () {
if (!this.list.getSelectionCount()) {
this.list.select(0);
}
@@ -4088,7 +4114,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- onShow: function() {
+ onShow: function () {
if (!deluge.client.core) return;
deluge.client.core.get_config({
success: this.onGotConfig,
@@ -4097,12 +4123,12 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- onClose: function() {
+ onClose: function () {
this.hide();
},
// private
- onOk: function() {
+ onOk: function () {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
deluge.client.core.set_config(changed, {
@@ -4138,7 +4164,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
autoHeight: true,
labelWidth: 70,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.ProxyField.superclass.initComponent.call(this);
this.proxyType = this.add({
xtype: 'combo',
@@ -4265,11 +4291,11 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
this.setting = false;
},
- getName: function() {
+ getName: function () {
return this.initialConfig.name;
},
- getValue: function() {
+ getValue: function () {
return {
type: this.proxyType.getValue(),
hostname: this.hostname.getValue(),
@@ -4285,7 +4311,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
},
// Set the values of the proxies
- setValue: function(value) {
+ setValue: function (value) {
this.setting = true;
this.proxyType.setValue(value['type']);
var index = this.proxyType.getStore().find('id', value['type']);
@@ -4305,7 +4331,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
this.setting = false;
},
- onFieldChange: function(field, newValue, oldValue) {
+ onFieldChange: function (field, newValue, oldValue) {
if (this.setting) return;
var newValues = this.getValue();
var oldValues = Ext.apply({}, newValues);
@@ -4314,7 +4340,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
this.fireEvent('change', this, newValues, oldValues);
},
- onTypeSelect: function(combo, record, index) {
+ onTypeSelect: function (combo, record, index) {
var typeId = record.get('id');
if (typeId > 0) {
this.hostname.show();
@@ -4359,7 +4385,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -4373,7 +4399,7 @@ Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, {
Deluge.preferences.Proxy.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Proxy.superclass.initComponent.call(this);
this.proxy = this.add(
new Deluge.preferences.ProxyField({
@@ -4385,19 +4411,19 @@ Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, {
deluge.preferences.getOptionsManager().bind('proxy', this.proxy);
},
- getValue: function() {
+ getValue: function () {
return {
proxy: this.proxy.getValue(),
};
},
- setValue: function(value) {
+ setValue: function (value) {
for (var proxy in value) {
this[proxy].setValue(value[proxy]);
}
},
- onProxyChange: function(field, newValue, oldValue) {
+ onProxyChange: function (field, newValue, oldValue) {
var newValues = this.getValue();
var oldValues = Ext.apply({}, newValues);
oldValues[field.getName()] = oldValue;
@@ -4426,7 +4452,7 @@ Deluge.preferences.Queue = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Queue.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
@@ -4634,7 +4660,7 @@ Deluge.preferences.Queue = Ext.extend(Ext.form.FormPanel, {
om.bind('remove_seed_at_ratio', this.removeAtRatio);
},
- onStopRatioCheck: function(e, checked) {
+ onStopRatioCheck: function (e, checked) {
this.stopRatio.setDisabled(!checked);
this.removeAtRatio.setDisabled(!checked);
},
@@ -4656,13 +4682,13 @@ Ext.ns('Deluge');
* @extends Ext.menu.Menu
*/
Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
- initComponent: function() {
+ initComponent: function () {
Deluge.StatusbarMenu.superclass.initComponent.call(this);
this.otherWin = new Deluge.OtherLimitWindow(
this.initialConfig.otherWin || {}
);
- this.items.each(function(item) {
+ this.items.each(function (item) {
if (item.getXType() != 'menucheckitem') return;
if (item.value == 'other') {
item.on('click', this.onOtherClicked, this);
@@ -4672,14 +4698,14 @@ Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
}, this);
},
- setValue: function(value) {
+ setValue: function (value) {
var beenSet = false;
// set the new value
this.value = value = value == 0 ? -1 : value;
var other = null;
// uncheck all items
- this.items.each(function(item) {
+ this.items.each(function (item) {
if (item.setChecked) {
item.suspendEvents();
if (item.value == value) {
@@ -4701,18 +4727,18 @@ Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
other.resumeEvents();
},
- onLimitChanged: function(item, checked) {
+ onLimitChanged: function (item, checked) {
if (!checked || item.value == 'other') return; // We do not care about unchecked or other.
var config = {};
config[item.group] = item.value;
deluge.client.core.set_config(config, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
},
- onOtherClicked: function(item, e) {
+ onOtherClicked: function (item, e) {
this.otherWin.group = item.group;
this.otherWin.setValue(this.value);
this.otherWin.show();
@@ -4738,7 +4764,7 @@ Ext.namespace('Deluge');
* @param {Object} config Configuration options
*/
Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
- constructor: function(config) {
+ constructor: function (config) {
config = config || {};
this.binds = {};
this.changed = {};
@@ -4776,7 +4802,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Add a set of default options and values to the options manager
* @param {Object} options The default options.
*/
- addOptions: function(options) {
+ addOptions: function (options) {
this.options = Ext.applyIf(this.options, options);
},
@@ -4785,7 +4811,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} option
* @param {Ext.form.Field} field
*/
- bind: function(option, field) {
+ bind: function (option, field) {
this.binds[option] = this.binds[option] || [];
this.binds[option].push(field);
field._doption = option;
@@ -4801,7 +4827,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
/**
* Changes all the changed values to be the default values
*/
- commit: function() {
+ commit: function () {
this.options = Ext.apply(this.options, this.changed);
this.reset();
},
@@ -4811,7 +4837,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {Mixed} oldValue The original value
* @param {Mixed} value The new value to convert
*/
- convertValueType: function(oldValue, value) {
+ convertValueType: function (oldValue, value) {
if (Ext.type(oldValue) != Ext.type(value)) {
switch (Ext.type(oldValue)) {
case 'string':
@@ -4841,7 +4867,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} [option] A single option or an array of options to return.
* @returns {Object} the options value.
*/
- get: function() {
+ get: function () {
if (arguments.length == 1) {
var option = arguments[0];
return this.isDirty(option)
@@ -4851,7 +4877,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
var options = {};
Ext.each(
arguments,
- function(option) {
+ function (option) {
if (!this.has(option)) return;
options[option] = this.isDirty(option)
? this.changed[option]
@@ -4868,7 +4894,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String|Array} [option] A single option or an array of options to return.
* @returns {Object} the value of the option
*/
- getDefault: function(option) {
+ getDefault: function (option) {
return this.options[option];
},
@@ -4876,7 +4902,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Returns the dirty (changed) values.
* @returns {Object} the changed options
*/
- getDirty: function() {
+ getDirty: function () {
return this.changed;
},
@@ -4884,7 +4910,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} [option] The option to check
* @returns {Boolean} true if the option has been changed from the default.
*/
- isDirty: function(option) {
+ isDirty: function (option) {
return !Ext.isEmpty(this.changed[option]);
},
@@ -4893,14 +4919,14 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} option
* @returns {Boolean} true if the option exists, else false.
*/
- has: function(option) {
+ has: function (option) {
return this.options[option];
},
/**
* Reset the options back to the default values.
*/
- reset: function() {
+ reset: function () {
this.changed = {};
},
@@ -4909,7 +4935,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} option
* @param {Object} value The value for the option
*/
- set: function(option, value) {
+ set: function (option, value) {
if (option === undefined) {
return;
} else if (typeof option == 'object') {
@@ -4929,7 +4955,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String/Object} option or options to update
* @param {Object} [value];
*/
- update: function(option, value) {
+ update: function (option, value) {
if (option === undefined) {
return;
} else if (value === undefined) {
@@ -4958,7 +4984,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Lets the option manager know when a field is blurred so if a value
* so value changing operations can continue on that field.
*/
- onFieldBlur: function(field, event) {
+ onFieldBlur: function (field, event) {
if (this.focused == field) {
this.focused = null;
}
@@ -4969,7 +4995,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {Ext.form.Field} field
* @private
*/
- onFieldChange: function(field, event) {
+ onFieldChange: function (field, event) {
if (field.field) field = field.field; // fix for spinners
this.update(field._doption, field.getValue());
},
@@ -4978,16 +5004,16 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Lets the option manager know when a field is focused so if a value changing
* operation is performed it will not change the value of the field.
*/
- onFieldFocus: function(field, event) {
+ onFieldFocus: function (field, event) {
this.focused = field;
},
- onChange: function(option, newValue, oldValue) {
+ onChange: function (option, newValue, oldValue) {
// If we don't have a bind there's nothing to do.
if (Ext.isEmpty(this.binds[option])) return;
Ext.each(
this.binds[option],
- function(bind) {
+ function (bind) {
// The field is currently focused so we do not want to change it.
if (bind == this.focused) return;
// Set the form field to the new value.
@@ -5027,16 +5053,16 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
},
buttonAlign: 'center',
- initComponent: function() {
+ initComponent: function () {
Deluge.about.AboutWindow.superclass.initComponent.call(this);
this.addEvents({
build_ready: true,
});
var self = this;
- var libtorrent = function() {
+ var libtorrent = function () {
deluge.client.core.get_libtorrent_version({
- success: function(lt_version) {
+ success: function (lt_version) {
comment += '<br/>' + _('libtorrent:') + ' ' + lt_version;
Ext.getCmp('about_comment').setText(comment, false);
self.fireEvent('build_ready');
@@ -5056,10 +5082,10 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
client_version +
'<br/>';
deluge.client.web.connected({
- success: function(connected) {
+ success: function (connected) {
if (connected) {
deluge.client.daemon.get_version({
- success: function(server_version) {
+ success: function (server_version) {
comment +=
_('Server:') + ' ' + server_version + '<br/>';
libtorrent();
@@ -5069,7 +5095,7 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
this.fireEvent('build_ready');
}
},
- failure: function() {
+ failure: function () {
this.fireEvent('build_ready');
},
scope: this,
@@ -5103,27 +5129,26 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
{
xtype: 'label',
style: 'padding-top: 5px; font-size: 12px;',
- html:
- '<a href="https://deluge-torrent.org" target="_blank">deluge-torrent.org</a>',
+ html: '<a href="https://deluge-torrent.org" target="_blank">deluge-torrent.org</a>',
},
]);
this.addButton(_('Close'), this.onCloseClick, this);
},
- show: function() {
- this.on('build_ready', function() {
+ show: function () {
+ this.on('build_ready', function () {
Deluge.about.AboutWindow.superclass.show.call(this);
});
},
- onCloseClick: function() {
+ onCloseClick: function () {
this.close();
},
});
Ext.namespace('Deluge');
-Deluge.About = function() {
+Deluge.About = function () {
new Deluge.about.AboutWindow().show();
};
/**
@@ -5152,7 +5177,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
bodyStyle: 'padding: 10px 5px;',
closeAction: 'hide',
- initComponent: function() {
+ initComponent: function () {
Deluge.AddConnectionWindow.superclass.initComponent.call(this);
this.addEvents('hostadded');
@@ -5208,7 +5233,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
});
},
- onAddClick: function() {
+ onAddClick: function () {
var values = this.form.getForm().getValues();
deluge.client.web.add_host(
values.host,
@@ -5216,7 +5241,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
values.username,
values.password,
{
- success: function(result) {
+ success: function (result) {
if (!result[0]) {
Ext.MessageBox.show({
title: _('Error'),
@@ -5239,7 +5264,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
);
},
- onHide: function() {
+ onHide: function () {
this.form.getForm().reset();
},
});
@@ -5255,9 +5280,10 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
Ext.ns('Deluge');
// Custom VType validator for tracker urls
-var trackerUrlTest = /(((^https?)|(^udp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
+var trackerUrlTest =
+ /(((^https?)|(^udp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
Ext.apply(Ext.form.VTypes, {
- trackerUrl: function(val, field) {
+ trackerUrl: function (val, field) {
return trackerUrlTest.test(val);
},
trackerUrlText: 'Not a valid tracker url',
@@ -5281,7 +5307,7 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
closeAction: 'hide',
iconCls: 'x-deluge-edit-trackers',
- initComponent: function() {
+ initComponent: function () {
Deluge.AddTrackerWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
@@ -5304,17 +5330,14 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
});
},
- onAddClick: function() {
- var trackers = this.form
- .getForm()
- .findField('trackers')
- .getValue();
+ onAddClick: function () {
+ var trackers = this.form.getForm().findField('trackers').getValue();
trackers = trackers.split('\n');
var cleaned = [];
Ext.each(
trackers,
- function(tracker) {
+ function (tracker) {
if (Ext.form.VTypes.trackerUrl(tracker)) {
cleaned.push(tracker);
}
@@ -5323,17 +5346,11 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
);
this.fireEvent('add', cleaned);
this.hide();
- this.form
- .getForm()
- .findField('trackers')
- .setValue('');
+ this.form.getForm().findField('trackers').setValue('');
},
- onCancelClick: function() {
- this.form
- .getForm()
- .findField('trackers')
- .setValue('');
+ onCancelClick: function () {
+ this.form.getForm().findField('trackers').setValue('');
this.hide();
},
});
@@ -5370,7 +5387,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
* Fires when the client has retrieved the list of methods from the server.
* @param {Ext.ux.util.RpcClient} this
*/
- constructor: function(config) {
+ constructor: function (config) {
Ext.ux.util.RpcClient.superclass.constructor.call(this, config);
this._url = config.url || null;
this._id = 0;
@@ -5383,14 +5400,14 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
this.reloadMethods();
},
- reloadMethods: function() {
+ reloadMethods: function () {
this._execute('system.listMethods', {
success: this._setMethods,
scope: this,
});
},
- _execute: function(method, options) {
+ _execute: function (method, options) {
options = options || {};
options.params = options.params || [];
options.id = this._id;
@@ -5413,7 +5430,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
});
},
- _onFailure: function(response, requestOptions) {
+ _onFailure: function (response, requestOptions) {
var options = requestOptions.options;
errorObj = {
id: options.id,
@@ -5439,7 +5456,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}
},
- _onSuccess: function(response, requestOptions) {
+ _onSuccess: function (response, requestOptions) {
var responseObj = Ext.decode(response.responseText);
var options = requestOptions.options;
if (responseObj.error) {
@@ -5477,9 +5494,9 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}
},
- _parseArgs: function(args) {
+ _parseArgs: function (args) {
var params = [];
- Ext.each(args, function(arg) {
+ Ext.each(args, function (arg) {
params.push(arg);
});
@@ -5488,7 +5505,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
var keys = Ext.keys(options),
isOption = false;
- Ext.each(this._optionKeys, function(key) {
+ Ext.each(this._optionKeys, function (key) {
if (keys.indexOf(key) > -1) isOption = true;
});
@@ -5504,15 +5521,15 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
return options;
},
- _setMethods: function(methods) {
+ _setMethods: function (methods) {
var components = {},
self = this;
- Ext.each(methods, function(method) {
+ Ext.each(methods, function (method) {
var parts = method.split('.');
var component = components[parts[0]] || {};
- var fn = function() {
+ var fn = function () {
var options = self._parseArgs(arguments);
return self._execute(method, options);
};
@@ -5525,7 +5542,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}
Ext.each(
this._components,
- function(component) {
+ function (component) {
if (!component in components) {
delete this[component];
}
@@ -5559,7 +5576,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
title: _('Connection Manager'),
iconCls: 'x-deluge-connect-window-icon',
- initComponent: function() {
+ initComponent: function () {
Deluge.ConnectionManager.superclass.initComponent.call(this);
this.on('hide', this.onHide, this);
this.on('show', this.onShow, this);
@@ -5671,9 +5688,9 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
* Check to see if the the web interface is currently connected
* to a Deluge Daemon and show the Connection Manager if not.
*/
- checkConnected: function() {
+ checkConnected: function () {
deluge.client.web.connected({
- success: function(connected) {
+ success: function (connected) {
if (connected) {
deluge.events.fire('connect');
} else {
@@ -5684,7 +5701,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
});
},
- disconnect: function(show) {
+ disconnect: function (show) {
deluge.events.fire('disconnect');
if (show) {
if (this.isVisible()) return;
@@ -5692,15 +5709,15 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
}
},
- loadHosts: function() {
+ loadHosts: function () {
deluge.client.web.get_hosts({
success: this.onGetHosts,
scope: this,
});
},
- update: function() {
- this.list.getStore().each(function(r) {
+ update: function () {
+ this.list.getStore().each(function (r) {
deluge.client.web.get_host_status(r.id, {
success: this.onGetHostStatus,
scope: this,
@@ -5713,7 +5730,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
* passed in records host state.
* @param {Ext.data.Record} record The hosts record to update the UI for
*/
- updateButtons: function(record) {
+ updateButtons: function (record) {
var button = this.buttons[1],
status = record.get('status');
@@ -5747,7 +5764,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onAddClick: function(button, e) {
+ onAddClick: function (button, e) {
if (!this.addWindow) {
this.addWindow = new Deluge.AddConnectionWindow();
this.addWindow.on('hostadded', this.onHostChange, this);
@@ -5756,7 +5773,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onEditClick: function(button, e) {
+ onEditClick: function (button, e) {
var connection = this.list.getSelectedRecords()[0];
if (!connection) return;
@@ -5768,24 +5785,24 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onHostChange: function() {
+ onHostChange: function () {
this.loadHosts();
},
// private
- onClose: function(e) {
+ onClose: function (e) {
this.hide();
},
// private
- onConnect: function(e) {
+ onConnect: function (e) {
var selected = this.list.getSelectedRecords()[0];
if (!selected) return;
var me = this;
- var disconnect = function() {
+ var disconnect = function () {
deluge.client.web.disconnect({
- success: function(result) {
+ success: function (result) {
this.update(this);
deluge.events.fire('disconnect');
},
@@ -5806,11 +5823,11 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
var id = selected.id;
deluge.client.web.connect(id, {
- success: function(methods) {
+ success: function (methods) {
deluge.client.reloadMethods();
deluge.client.on(
'connected',
- function(e) {
+ function (e) {
deluge.events.fire('connect');
},
this,
@@ -5823,11 +5840,11 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onGetHosts: function(hosts) {
+ onGetHosts: function (hosts) {
this.list.getStore().loadData(hosts);
Ext.each(
hosts,
- function(host) {
+ function (host) {
deluge.client.web.get_host_status(host[0], {
success: this.onGetHostStatus,
scope: this,
@@ -5838,7 +5855,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onGetHostStatus: function(host) {
+ onGetHostStatus: function (host) {
var record = this.list.getStore().getById(host[0]);
record.set('status', host[1]);
record.set('version', host[2]);
@@ -5849,19 +5866,19 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onHide: function() {
+ onHide: function () {
if (this.running) window.clearInterval(this.running);
},
// private
- onLogin: function() {
+ onLogin: function () {
if (deluge.config.first_login) {
Ext.MessageBox.confirm(
_('Change Default Password'),
_(
'We recommend changing the default password.<br><br>Would you like to change it now?'
),
- function(res) {
+ function (res) {
this.checkConnected();
if (res == 'yes') {
deluge.preferences.show();
@@ -5877,7 +5894,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onLogout: function() {
+ onLogout: function () {
this.disconnect();
if (!this.hidden && this.rendered) {
this.hide();
@@ -5885,12 +5902,12 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onRemoveClick: function(button) {
+ onRemoveClick: function (button) {
var connection = this.list.getSelectedRecords()[0];
if (!connection) return;
deluge.client.web.remove_host(connection.id, {
- success: function(result) {
+ success: function (result) {
if (!result) {
Ext.MessageBox.show({
title: _('Error'),
@@ -5909,7 +5926,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onSelectionChanged: function(list, selections) {
+ onSelectionChanged: function (list, selections) {
if (selections[0]) {
this.editHostButton.enable();
this.removeHostButton.enable();
@@ -5925,7 +5942,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// FIXME: Find out why this is being fired twice
// private
- onShow: function() {
+ onShow: function () {
if (!this.addHostButton) {
var bbar = this.panel.getBottomToolbar();
this.addHostButton = bbar.items.get('cm-add');
@@ -5939,7 +5956,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onStopClick: function(button, e) {
+ onStopClick: function (button, e) {
var connection = this.list.getSelectedRecords()[0];
if (!connection) return;
@@ -5949,7 +5966,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
} else {
// This means we need to stop the daemon
deluge.client.web.stop_daemon(connection.id, {
- success: function(result) {
+ success: function (result) {
if (!result[0]) {
Ext.MessageBox.show({
title: _('Error'),
@@ -5965,6 +5982,79 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
}
},
});
+/*
+ * Deluge.CopyMagnet.js
+ *
+ * Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the OpenSSL
+ * library.
+ * You must obey the GNU General Public License in all respects for all of
+ * the code used other than OpenSSL. If you modify file(s) with this
+ * exception, you may extend this exception to your version of the file(s),
+ * but you are not obligated to do so. If you do not wish to do so, delete
+ * this exception statement from your version. If you delete this exception
+ * statement from all source files in the program, then also delete it here.
+ */
+Deluge.CopyMagnet = Ext.extend(Ext.Window, {
+ title: _('Copy Magnet URI'),
+ width: 375,
+ closeAction: 'hide',
+ iconCls: 'icon-magnet-copy',
+
+ initComponent: function () {
+ Deluge.CopyMagnet.superclass.initComponent.call(this);
+ form = this.add({
+ xtype: 'form',
+ defaultType: 'textfield',
+ hideLabels: true,
+ });
+ this.magnetURI = form.add({
+ name: 'URI',
+ anchor: '100%',
+ });
+ this.addButton(_('Close'), this.onClose, this);
+ this.addButton(_('Copy'), this.onCopy, this);
+ },
+ show: function (a) {
+ Deluge.CopyMagnet.superclass.show.call(this);
+ var torrent = deluge.torrents.getSelected();
+ deluge.client.core.get_magnet_uri(torrent.id, {
+ success: this.onRequestComplete,
+ scope: this,
+ });
+ },
+ onRequestComplete: function (uri) {
+ this.magnetURI.setValue(uri);
+ },
+ onCopy: function () {
+ this.magnetURI.focus();
+ this.magnetURI.el.dom.select();
+ document.execCommand('copy');
+ },
+ onClose: function () {
+ this.hide();
+ },
+});
+
+deluge.copyMagnetWindow = new Deluge.CopyMagnet();
/**
* Deluge.js
*
@@ -5992,21 +6082,14 @@ Ext.state.Manager.setProvider(
// Add some additional functions to ext and setup some of the
// configurable parameters
Ext.apply(Ext, {
- escapeHTML: function(text) {
- text = String(text)
- .replace('<', '&lt;')
- .replace('>', '&gt;');
- return text.replace('&', '&amp;');
- },
-
- isObjectEmpty: function(obj) {
+ isObjectEmpty: function (obj) {
for (var i in obj) {
return false;
}
return true;
},
- areObjectsEqual: function(obj1, obj2) {
+ areObjectsEqual: function (obj1, obj2) {
var equal = true;
if (!obj1 || !obj2) return false;
for (var i in obj1) {
@@ -6017,7 +6100,7 @@ Ext.apply(Ext, {
return equal;
},
- keys: function(obj) {
+ keys: function (obj) {
var keys = [];
for (var i in obj)
if (obj.hasOwnProperty(i)) {
@@ -6026,7 +6109,7 @@ Ext.apply(Ext, {
return keys;
},
- values: function(obj) {
+ values: function (obj) {
var values = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
@@ -6036,7 +6119,7 @@ Ext.apply(Ext, {
return values;
},
- splat: function(obj) {
+ splat: function (obj) {
var type = Ext.type(obj);
return type ? (type != 'array' ? [obj] : obj) : [];
},
@@ -6073,7 +6156,7 @@ Ext.apply(Deluge, {
* @param {String} text The text to display on the bar
* @param {Number} modified Amount to subtract from the width allowing for fixes
*/
- progressBar: function(progress, width, text, modifier) {
+ progressBar: function (progress, width, text, modifier) {
modifier = Ext.value(modifier, 10);
var progressWidth = ((width / 100.0) * progress).toFixed(0);
var barWidth = progressWidth - 1;
@@ -6092,7 +6175,7 @@ Ext.apply(Deluge, {
* Constructs a new instance of the specified plugin.
* @param {String} name The plugin name to create
*/
- createPlugin: function(name) {
+ createPlugin: function (name) {
return new Deluge.pluginStore[name]();
},
@@ -6100,7 +6183,7 @@ Ext.apply(Deluge, {
* Check to see if a plugin has been registered.
* @param {String} name The plugin name to check
*/
- hasPlugin: function(name) {
+ hasPlugin: function (name) {
return Deluge.pluginStore[name] ? true : false;
},
@@ -6109,7 +6192,7 @@ Ext.apply(Deluge, {
* @param {String} name The plugin name to register
* @param {Plugin} plugin The plugin to register
*/
- registerPlugin: function(name, plugin) {
+ registerPlugin: function (name, plugin) {
Deluge.pluginStore[name] = plugin;
},
});
@@ -6177,7 +6260,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
bodyStyle: 'padding: 10px 5px;',
closeAction: 'hide',
- initComponent: function() {
+ initComponent: function () {
Deluge.EditConnectionWindow.superclass.initComponent.call(this);
this.addEvents('hostedited');
@@ -6233,17 +6316,11 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
});
},
- show: function(connection) {
+ show: function (connection) {
Deluge.EditConnectionWindow.superclass.show.call(this);
- this.form
- .getForm()
- .findField('host')
- .setValue(connection.get('host'));
- this.form
- .getForm()
- .findField('port')
- .setValue(connection.get('port'));
+ this.form.getForm().findField('host').setValue(connection.get('host'));
+ this.form.getForm().findField('port').setValue(connection.get('port'));
this.form
.getForm()
.findField('username')
@@ -6251,7 +6328,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
this.host_id = connection.id;
},
- onEditClick: function() {
+ onEditClick: function () {
var values = this.form.getForm().getValues();
deluge.client.web.edit_host(
this.host_id,
@@ -6260,7 +6337,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
values.username,
values.password,
{
- success: function(result) {
+ success: function (result) {
if (!result) {
console.log(result);
Ext.MessageBox.show({
@@ -6281,7 +6358,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
);
},
- onHide: function() {
+ onHide: function () {
this.form.getForm().reset();
},
});
@@ -6314,7 +6391,7 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
closeAction: 'hide',
iconCls: 'x-deluge-edit-trackers',
- initComponent: function() {
+ initComponent: function () {
Deluge.EditTrackerWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
@@ -6337,32 +6414,23 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
});
},
- show: function(record) {
+ show: function (record) {
Deluge.EditTrackerWindow.superclass.show.call(this);
this.record = record;
- this.form
- .getForm()
- .findField('tracker')
- .setValue(record.data['url']);
+ this.form.getForm().findField('tracker').setValue(record.data['url']);
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.hide();
},
- onHide: function() {
- this.form
- .getForm()
- .findField('tracker')
- .setValue('');
+ onHide: function () {
+ this.form.getForm().findField('tracker').setValue('');
},
- onSaveClick: function() {
- var url = this.form
- .getForm()
- .findField('tracker')
- .getValue();
+ onSaveClick: function () {
+ var url = this.form.getForm().findField('tracker').getValue();
this.record.set('url', url);
this.record.commit();
this.hide();
@@ -6380,7 +6448,7 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
Ext.ns('Deluge');
/**
- * @class Deluge.EditTrackerWindow
+ * @class Deluge.EditTrackersWindow
* @extends Ext.Window
*/
Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
@@ -6398,7 +6466,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
closeAction: 'hide',
iconCls: 'x-deluge-edit-trackers',
- initComponent: function() {
+ initComponent: function () {
Deluge.EditTrackersWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
@@ -6427,6 +6495,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
header: _('Tracker'),
width: 0.9,
dataIndex: 'url',
+ tpl: new Ext.XTemplate('{url:htmlEncode}'),
},
],
columnSort: {
@@ -6481,18 +6550,18 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
});
},
- onAddClick: function() {
+ onAddClick: function () {
this.addWindow.show();
},
- onAddTrackers: function(trackers) {
+ onAddTrackers: function (trackers) {
var store = this.list.getStore();
Ext.each(
trackers,
- function(tracker) {
+ function (tracker) {
var duplicate = false,
heightestTier = -1;
- store.each(function(record) {
+ store.each(function (record) {
if (record.get('tier') > heightestTier) {
heightestTier = record.get('tier');
}
@@ -6513,27 +6582,27 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
);
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.hide();
},
- onEditClick: function() {
+ onEditClick: function () {
var selected = this.list.getSelectedRecords()[0];
if (!selected) return;
this.editWindow.show(selected);
},
- onHide: function() {
+ onHide: function () {
this.list.getStore().removeAll();
},
- onListNodeDblClicked: function(list, index, node, e) {
+ onListNodeDblClicked: function (list, index, node, e) {
this.editWindow.show(this.list.getRecord(node));
},
- onOkClick: function() {
+ onOkClick: function () {
var trackers = [];
- this.list.getStore().each(function(record) {
+ this.list.getStore().each(function (record) {
trackers.push({
tier: record.get('tier'),
url: record.get('url'),
@@ -6548,34 +6617,28 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
this.hide();
},
- onRemoveClick: function() {
+ onRemoveClick: function () {
// Remove from the grid
var selected = this.list.getSelectedRecords()[0];
if (!selected) return;
this.list.getStore().remove(selected);
},
- onRequestComplete: function(status) {
+ onRequestComplete: function (status) {
this.list.getStore().loadData(status);
this.list.getStore().sort('tier', 'ASC');
},
- onSaveFail: function() {},
+ onSaveFail: function () {},
- onSelect: function(list) {
+ onSelect: function (list) {
if (list.getSelectionCount()) {
- this.panel
- .getBottomToolbar()
- .items.get(4)
- .enable();
+ this.panel.getBottomToolbar().items.get(4).enable();
}
},
- onShow: function() {
- this.panel
- .getBottomToolbar()
- .items.get(4)
- .disable();
+ onShow: function () {
+ this.panel.getBottomToolbar().items.get(4).disable();
var r = deluge.torrents.getSelected();
this.torrentId = r.id;
deluge.client.core.get_torrent_status(r.id, ['trackers'], {
@@ -6584,7 +6647,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
});
},
- onDownClick: function() {
+ onDownClick: function () {
var r = this.list.getSelectedRecords()[0];
if (!r) return;
@@ -6595,7 +6658,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
this.list.select(r.store.indexOf(r));
},
- onUpClick: function() {
+ onUpClick: function () {
var r = this.list.getSelectedRecords()[0];
if (!r) return;
@@ -6624,7 +6687,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
* Class for holding global events that occur within the UI.
*/
Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
- constructor: function() {
+ constructor: function () {
this.toRegister = [];
this.on('login', this.onLogin, this);
Deluge.EventsManager.superclass.constructor.call(this);
@@ -6633,7 +6696,7 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
/**
* Append an event handler to this object.
*/
- addListener: function(eventName, fn, scope, o) {
+ addListener: function (eventName, fn, scope, o) {
this.addEvents(eventName);
if (/[A-Z]/.test(eventName.substring(0, 1))) {
if (!deluge.client) {
@@ -6651,7 +6714,7 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
);
},
- getEvents: function() {
+ getEvents: function () {
deluge.client.web.get_events({
success: this.onGetEventsSuccess,
failure: this.onGetEventsFailure,
@@ -6662,8 +6725,8 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
/**
* Starts the EventsManagerManager checking for events.
*/
- start: function() {
- Ext.each(this.toRegister, function(eventName) {
+ start: function () {
+ Ext.each(this.toRegister, function (eventName) {
deluge.client.web.register_event_listener(eventName);
});
this.running = true;
@@ -6674,21 +6737,21 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
/**
* Stops the EventsManagerManager checking for events.
*/
- stop: function() {
+ stop: function () {
this.running = false;
},
// private
- onLogin: function() {
+ onLogin: function () {
this.start();
},
- onGetEventsSuccess: function(events) {
+ onGetEventsSuccess: function (events) {
if (!this.running) return;
if (events) {
Ext.each(
events,
- function(event) {
+ function (event) {
var name = event[0],
args = event[1];
args.splice(0, 0, name);
@@ -6701,7 +6764,7 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
},
// private
- onGetEventsFailure: function(result, error) {
+ onGetEventsFailure: function (result, error) {
// the request timed out or we had a communication failure
if (!this.running) return;
if (!error.isTimeout && this.errorCount++ >= 3) {
@@ -6742,7 +6805,7 @@ Deluge.FileBrowser = Ext.extend(Ext.Window, {
width: 500,
height: 400,
- initComponent: function() {
+ initComponent: function () {
Deluge.FileBrowser.superclass.initComponent.call(this);
this.add({
@@ -6790,7 +6853,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
show_zero: null,
- initComponent: function() {
+ initComponent: function () {
Deluge.FilterPanel.superclass.initComponent.call(this);
this.filterType = this.initialConfig.filter;
var title = '';
@@ -6806,7 +6869,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
(title = this.filterType.replace('_', ' ')),
(parts = title.split(' ')),
(title = '');
- Ext.each(parts, function(p) {
+ Ext.each(parts, function (p) {
fl = p.substring(0, 1).toUpperCase();
title += fl + p.substring(1) + ' ';
});
@@ -6845,7 +6908,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
* Return the currently selected filter state
* @returns {String} the current filter state
*/
- getState: function() {
+ getState: function () {
if (!this.list.getSelectionCount()) return;
var state = this.list.getSelectedRecords()[0];
@@ -6857,7 +6920,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
/**
* Return the current states in the filter
*/
- getStates: function() {
+ getStates: function () {
return this.states;
},
@@ -6865,18 +6928,18 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
* Return the Store for the ListView of the FilterPanel
* @returns {Ext.data.Store} the ListView store
*/
- getStore: function() {
+ getStore: function () {
return this.list.getStore();
},
/**
* Update the states in the FilterPanel
*/
- updateStates: function(states) {
+ updateStates: function (states) {
this.states = {};
Ext.each(
states,
- function(state) {
+ function (state) {
this.states[state[0]] = state[1];
},
this
@@ -6888,7 +6951,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
: this.show_zero;
if (!show_zero) {
var newStates = [];
- Ext.each(states, function(state) {
+ Ext.each(states, function (state) {
if (state[1] > 0 || state[0] == 'All') {
newStates.push(state);
}
@@ -6900,7 +6963,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
var filters = {};
Ext.each(
states,
- function(s, i) {
+ function (s, i) {
var record = store.getById(s[0]);
if (!record) {
record = new store.recordType({
@@ -6919,7 +6982,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
this
);
- store.each(function(record) {
+ store.each(function (record) {
if (filters[record.id]) return;
store.remove(record);
var selected = this.list.getSelectedRecords()[0];
@@ -6941,7 +7004,7 @@ Deluge.FilterPanel.templates = {
tracker_host:
'<div class="x-deluge-filter" style="background-image: url(' +
deluge.config.base +
- 'tracker/{filter});">{filter} ({count})</div>',
+ 'tracker/{filter});">{filter:htmlEncode} ({count})</div>',
};
/**
* Deluge.Formatters.js
@@ -6960,7 +7023,23 @@ Deluge.FilterPanel.templates = {
* @version 1.3
* @singleton
*/
-Deluge.Formatters = {
+Deluge.Formatters = (function () {
+ var charToEntity = {
+ '&': '&amp;',
+ '>': '&gt;',
+ '<': '&lt;',
+ '"': '&quot;',
+ "'": '&#39;',
+ };
+
+ var charToEntityRegex = new RegExp(
+ '(' + Object.keys(charToEntity).join('|') + ')',
+ 'g'
+ );
+ var htmlEncodeReplaceFn = function (match, capture) {
+ return charToEntity[capture];
+ };
+
/**
* Formats a date string in the date representation of the current locale,
* based on the systems timezone.
@@ -6969,154 +7048,162 @@ Deluge.Formatters = {
* @return {String} a string in the date representation of the current locale
* or "" if seconds < 0.
*/
- date: function(timestamp) {
- function zeroPad(num, count) {
- var numZeropad = num + '';
- while (numZeropad.length < count) {
- numZeropad = '0' + numZeropad;
+ return (Formatters = {
+ date: function (timestamp) {
+ function zeroPad(num, count) {
+ var numZeropad = num + '';
+ while (numZeropad.length < count) {
+ numZeropad = '0' + numZeropad;
+ }
+ return numZeropad;
}
- return numZeropad;
- }
- timestamp = timestamp * 1000;
- var date = new Date(timestamp);
- return String.format(
- '{0}/{1}/{2} {3}:{4}:{5}',
- zeroPad(date.getDate(), 2),
- zeroPad(date.getMonth() + 1, 2),
- date.getFullYear(),
- zeroPad(date.getHours(), 2),
- zeroPad(date.getMinutes(), 2),
- zeroPad(date.getSeconds(), 2)
- );
- },
+ timestamp = timestamp * 1000;
+ var date = new Date(timestamp);
+ return String.format(
+ '{0}/{1}/{2} {3}:{4}:{5}',
+ zeroPad(date.getDate(), 2),
+ zeroPad(date.getMonth() + 1, 2),
+ date.getFullYear(),
+ zeroPad(date.getHours(), 2),
+ zeroPad(date.getMinutes(), 2),
+ zeroPad(date.getSeconds(), 2)
+ );
+ },
- /**
- * Formats the bytes value into a string with KiB, MiB or GiB units.
- *
- * @param {Number} bytes the filesize in bytes
- * @param {Boolean} showZero pass in true to displays 0 values
- * @return {String} formatted string with KiB, MiB or GiB units.
- */
- size: function(bytes, showZero) {
- if (!bytes && !showZero) return '';
- bytes = bytes / 1024.0;
+ /**
+ * Formats the bytes value into a string with KiB, MiB or GiB units.
+ *
+ * @param {Number} bytes the filesize in bytes
+ * @param {Boolean} showZero pass in true to displays 0 values
+ * @return {String} formatted string with KiB, MiB or GiB units.
+ */
+ size: function (bytes, showZero) {
+ if (!bytes && !showZero) return '';
+ bytes = bytes / 1024.0;
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' KiB';
- } else {
- bytes = bytes / 1024;
- }
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' KiB';
+ } else {
+ bytes = bytes / 1024;
+ }
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' MiB';
- } else {
- bytes = bytes / 1024;
- }
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' MiB';
+ } else {
+ bytes = bytes / 1024;
+ }
- return bytes.toFixed(1) + ' GiB';
- },
+ return bytes.toFixed(1) + ' GiB';
+ },
- /**
- * Formats the bytes value into a string with K, M or G units.
- *
- * @param {Number} bytes the filesize in bytes
- * @param {Boolean} showZero pass in true to displays 0 values
- * @return {String} formatted string with K, M or G units.
- */
- sizeShort: function(bytes, showZero) {
- if (!bytes && !showZero) return '';
- bytes = bytes / 1024.0;
+ /**
+ * Formats the bytes value into a string with K, M or G units.
+ *
+ * @param {Number} bytes the filesize in bytes
+ * @param {Boolean} showZero pass in true to displays 0 values
+ * @return {String} formatted string with K, M or G units.
+ */
+ sizeShort: function (bytes, showZero) {
+ if (!bytes && !showZero) return '';
+ bytes = bytes / 1024.0;
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' K';
- } else {
- bytes = bytes / 1024;
- }
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' K';
+ } else {
+ bytes = bytes / 1024;
+ }
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' M';
- } else {
- bytes = bytes / 1024;
- }
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' M';
+ } else {
+ bytes = bytes / 1024;
+ }
- return bytes.toFixed(1) + ' G';
- },
+ return bytes.toFixed(1) + ' G';
+ },
- /**
- * Formats a string to display a transfer speed utilizing {@link #size}
- *
- * @param {Number} bytes the number of bytes per second
- * @param {Boolean} showZero pass in true to displays 0 values
- * @return {String} formatted string with KiB, MiB or GiB units.
- */
- speed: function(bytes, showZero) {
- return !bytes && !showZero ? '' : fsize(bytes, showZero) + '/s';
- },
+ /**
+ * Formats a string to display a transfer speed utilizing {@link #size}
+ *
+ * @param {Number} bytes the number of bytes per second
+ * @param {Boolean} showZero pass in true to displays 0 values
+ * @return {String} formatted string with KiB, MiB or GiB units.
+ */
+ speed: function (bytes, showZero) {
+ return !bytes && !showZero ? '' : fsize(bytes, showZero) + '/s';
+ },
- /**
- * Formats a string to show time in a human readable form.
- *
- * @param {Number} time the number of seconds
- * @return {String} a formatted time string. will return '' if seconds == 0
- */
- timeRemaining: function(time) {
- if (time <= 0) {
- return '&infin;';
- }
- time = time.toFixed(0);
- if (time < 60) {
- return time + 's';
- } else {
- time = time / 60;
- }
+ /**
+ * Formats a string to show time in a human readable form.
+ *
+ * @param {Number} time the number of seconds
+ * @return {String} a formatted time string. will return '' if seconds == 0
+ */
+ timeRemaining: function (time) {
+ if (time <= 0) {
+ return '&infin;';
+ }
+ time = time.toFixed(0);
+ if (time < 60) {
+ return time + 's';
+ } else {
+ time = time / 60;
+ }
- if (time < 60) {
- var minutes = Math.floor(time);
- var seconds = Math.round(60 * (time - minutes));
- if (seconds > 0) {
- return minutes + 'm ' + seconds + 's';
+ if (time < 60) {
+ var minutes = Math.floor(time);
+ var seconds = Math.round(60 * (time - minutes));
+ if (seconds > 0) {
+ return minutes + 'm ' + seconds + 's';
+ } else {
+ return minutes + 'm';
+ }
} else {
- return minutes + 'm';
+ time = time / 60;
}
- } else {
- time = time / 60;
- }
- if (time < 24) {
- var hours = Math.floor(time);
- var minutes = Math.round(60 * (time - hours));
- if (minutes > 0) {
- return hours + 'h ' + minutes + 'm';
+ if (time < 24) {
+ var hours = Math.floor(time);
+ var minutes = Math.round(60 * (time - hours));
+ if (minutes > 0) {
+ return hours + 'h ' + minutes + 'm';
+ } else {
+ return hours + 'h';
+ }
} else {
- return hours + 'h';
+ time = time / 24;
}
- } else {
- time = time / 24;
- }
- var days = Math.floor(time);
- var hours = Math.round(24 * (time - days));
- if (hours > 0) {
- return days + 'd ' + hours + 'h';
- } else {
- return days + 'd';
- }
- },
+ var days = Math.floor(time);
+ var hours = Math.round(24 * (time - days));
+ if (hours > 0) {
+ return days + 'd ' + hours + 'h';
+ } else {
+ return days + 'd';
+ }
+ },
- /**
- * Simply returns the value untouched, for when no formatting is required.
- *
- * @param {Mixed} value the value to be displayed
- * @return the untouched value.
- */
- plain: function(value) {
- return value;
- },
+ /**
+ * Simply returns the value untouched, for when no formatting is required.
+ *
+ * @param {Mixed} value the value to be displayed
+ * @return the untouched value.
+ */
+ plain: function (value) {
+ return value;
+ },
- cssClassEscape: function(value) {
- return value.toLowerCase().replace('.', '_');
- },
-};
+ cssClassEscape: function (value) {
+ return value.toLowerCase().replace('.', '_');
+ },
+
+ htmlEncode: function (value) {
+ return !value
+ ? value
+ : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
+ },
+ });
+})();
var fsize = Deluge.Formatters.size;
var fsize_short = Deluge.Formatters.sizeShort;
var fspeed = Deluge.Formatters.speed;
@@ -7124,6 +7211,7 @@ var ftime = Deluge.Formatters.timeRemaining;
var fdate = Deluge.Formatters.date;
var fplain = Deluge.Formatters.plain;
Ext.util.Format.cssClassEscape = Deluge.Formatters.cssClassEscape;
+Ext.util.Format.htmlEncode = Deluge.Formatters.htmlEncode;
/**
* Deluge.Keys.js
*
@@ -7259,7 +7347,7 @@ Deluge.Keys = {
// Merge the grid and status keys together as the status keys contain all the
// grid ones.
-Ext.each(Deluge.Keys.Grid, function(key) {
+Ext.each(Deluge.Keys.Grid, function (key) {
Deluge.Keys.Status.push(key);
});
/**
@@ -7287,7 +7375,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
width: 300,
height: 120,
- initComponent: function() {
+ initComponent: function () {
Deluge.LoginWindow.superclass.initComponent.call(this);
this.on('show', this.onShow, this);
@@ -7320,17 +7408,17 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
this.passwordField.on('specialkey', this.onSpecialKey, this);
},
- logout: function() {
+ logout: function () {
deluge.events.fire('logout');
deluge.client.auth.delete_session({
- success: function(result) {
+ success: function (result) {
this.show(true);
},
scope: this,
});
},
- show: function(skipCheck) {
+ show: function (skipCheck) {
if (this.firstShow) {
deluge.client.on('error', this.onClientError, this);
this.firstShow = false;
@@ -7341,28 +7429,28 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
}
deluge.client.auth.check_session({
- success: function(result) {
+ success: function (result) {
if (result) {
deluge.events.fire('login');
} else {
this.show(true);
}
},
- failure: function(result) {
+ failure: function (result) {
this.show(true);
},
scope: this,
});
},
- onSpecialKey: function(field, e) {
+ onSpecialKey: function (field, e) {
if (e.getKey() == 13) this.onLogin();
},
- onLogin: function() {
+ onLogin: function () {
var passwordField = this.passwordField;
deluge.client.auth.login(passwordField.getValue(), {
- success: function(result) {
+ success: function (result) {
if (result) {
deluge.events.fire('login');
this.hide();
@@ -7373,7 +7461,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
msg: _('You entered an incorrect password'),
buttons: Ext.MessageBox.OK,
modal: false,
- fn: function() {
+ fn: function () {
passwordField.focus(true, 10);
},
icon: Ext.MessageBox.WARNING,
@@ -7385,14 +7473,14 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
});
},
- onClientError: function(errorObj, response, requestOptions) {
+ onClientError: function (errorObj, response, requestOptions) {
if (errorObj.error.code == 1) {
deluge.events.fire('logout');
this.show(true);
}
},
- onShow: function() {
+ onShow: function () {
this.passwordField.focus(true, 300);
},
});
@@ -7407,7 +7495,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
*/
deluge.menus = {
- onTorrentActionSetOpt: function(item, e) {
+ onTorrentActionSetOpt: function (item, e) {
var ids = deluge.torrents.getSelectedIds();
var action = item.initialConfig.torrentAction;
var opts = {};
@@ -7415,20 +7503,23 @@ deluge.menus = {
deluge.client.core.set_torrent_options(ids, opts);
},
- onTorrentActionMethod: function(item, e) {
+ onTorrentActionMethod: function (item, e) {
var ids = deluge.torrents.getSelectedIds();
var action = item.initialConfig.torrentAction;
deluge.client.core[action](ids, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
},
- onTorrentActionShow: function(item, e) {
+ onTorrentActionShow: function (item, e) {
var ids = deluge.torrents.getSelectedIds();
var action = item.initialConfig.torrentAction;
switch (action) {
+ case 'copy_magnet':
+ deluge.copyMagnetWindow.show();
+ break;
case 'edit_trackers':
deluge.editTrackers.show();
break;
@@ -7710,6 +7801,13 @@ deluge.menus.torrent = new Ext.menu.Menu({
},
'-',
{
+ torrentAction: 'copy_magnet',
+ text: _('Copy Magnet URI'),
+ iconCls: 'icon-magnet-copy',
+ handler: deluge.menus.onTorrentActionShow,
+ scope: deluge.menus,
+ },
+ {
torrentAction: 'force_reannounce',
text: _('Update Tracker'),
iconCls: 'icon-update-tracker',
@@ -7796,7 +7894,7 @@ deluge.menus.filePriorities = new Ext.menu.Menu({
Ext.namespace('Deluge');
Deluge.MoveStorage = Ext.extend(Ext.Window, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
title: _('Move Download Folder'),
@@ -7816,7 +7914,7 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
Deluge.MoveStorage.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.MoveStorage.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancel, this);
@@ -7848,21 +7946,21 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
//});
},
- hide: function() {
+ hide: function () {
Deluge.MoveStorage.superclass.hide.call(this);
this.torrentIds = null;
},
- show: function(torrentIds) {
+ show: function (torrentIds) {
Deluge.MoveStorage.superclass.show.call(this);
this.torrentIds = torrentIds;
},
- onCancel: function() {
+ onCancel: function () {
this.hide();
},
- onMove: function() {
+ onMove: function () {
var dest = this.moveLocation.getValue();
deluge.client.core.move_storage(this.torrentIds, dest);
this.hide();
@@ -7886,7 +7984,7 @@ deluge.moveStorage = new Deluge.MoveStorage();
* @extends Deluge.OptionsManager
*/
Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
- constructor: function(config) {
+ constructor: function (config) {
this.currentId = null;
this.stored = {};
Deluge.MultiOptionsManager.superclass.constructor.call(this, config);
@@ -7896,7 +7994,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* Changes bound fields to use the specified id.
* @param {String} id
*/
- changeId: function(id, dontUpdateBinds) {
+ changeId: function (id, dontUpdateBinds) {
var oldId = this.currentId;
this.currentId = id;
if (!dontUpdateBinds) {
@@ -7904,7 +8002,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
if (!this.binds[option]) continue;
Ext.each(
this.binds[option],
- function(bind) {
+ function (bind) {
bind.setValue(this.get(option));
},
this
@@ -7918,7 +8016,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* Changes all the changed values to be the default values
* @param {String} id
*/
- commit: function() {
+ commit: function () {
this.stored[this.currentId] = Ext.apply(
this.stored[this.currentId],
this.changed[this.currentId]
@@ -7931,7 +8029,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String/Array} option A single option or an array of options to return.
* @returns {Object} the options value.
*/
- get: function() {
+ get: function () {
if (arguments.length == 1) {
var option = arguments[0];
return this.isDirty(option)
@@ -7949,7 +8047,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
var options = {};
Ext.each(
arguments,
- function(option) {
+ function (option) {
options[option] = this.isDirty(option)
? this.changed[this.currentId][option]
: this.getDefault(option);
@@ -7965,7 +8063,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option A single option.
* @returns {Object} the value of the option
*/
- getDefault: function(option) {
+ getDefault: function (option) {
return this.has(option)
? this.stored[this.currentId][option]
: this.options[option];
@@ -7975,7 +8073,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* Returns the dirty (changed) values.
* @returns {Object} the changed options
*/
- getDirty: function() {
+ getDirty: function () {
return this.changed[this.currentId] ? this.changed[this.currentId] : {};
},
@@ -7984,7 +8082,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option
* @returns {Boolean} true if the option has been changed, else false.
*/
- isDirty: function(option) {
+ isDirty: function (option) {
return (
this.changed[this.currentId] &&
!Ext.isEmpty(this.changed[this.currentId][option])
@@ -7997,7 +8095,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option
* @returns {Boolean} true if the id has an option, else false.
*/
- has: function(option) {
+ has: function (option) {
return (
this.stored[this.currentId] &&
!Ext.isEmpty(this.stored[this.currentId][option])
@@ -8007,7 +8105,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
/**
* Reset the options back to the default values for the specified id.
*/
- reset: function() {
+ reset: function () {
if (this.changed[this.currentId]) delete this.changed[this.currentId];
if (this.stored[this.currentId]) delete this.stored[this.currentId];
},
@@ -8015,7 +8113,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
/**
* Reset the options back to their defaults for all ids.
*/
- resetAll: function() {
+ resetAll: function () {
this.changed = {};
this.stored = {};
this.changeId(null);
@@ -8027,7 +8125,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option
* @param {Object} value The value for the option
*/
- setDefault: function(option, value) {
+ setDefault: function (option, value) {
if (option === undefined) {
return;
} else if (value === undefined) {
@@ -8058,7 +8156,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String/Object} option or options to update
* @param {Object} [value];
*/
- update: function(option, value) {
+ update: function (option, value) {
if (option === undefined) {
return;
} else if (value === undefined) {
@@ -8109,7 +8207,7 @@ Deluge.OtherLimitWindow = Ext.extend(Ext.Window, {
constrainHeader: true,
closeAction: 'hide',
- initComponent: function() {
+ initComponent: function () {
Deluge.OtherLimitWindow.superclass.initComponent.call(this);
this.form = this.add({
xtype: 'form',
@@ -8142,31 +8240,28 @@ Deluge.OtherLimitWindow = Ext.extend(Ext.Window, {
this.afterMethod('show', this.doFocusField, this);
},
- setValue: function(value) {
+ setValue: function (value) {
this.form.getForm().setValues({ limit: value });
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.form.getForm().reset();
this.hide();
},
- onOkClick: function() {
+ onOkClick: function () {
var config = {};
config[this.group] = this.form.getForm().getValues().limit;
deluge.client.core.set_config(config, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
this.hide();
},
- doFocusField: function() {
- this.form
- .getForm()
- .findField('limit')
- .focus(true, 10);
+ doFocusField: function () {
+ this.form.getForm().findField('limit').focus(true, 10);
},
});
/**
@@ -8192,7 +8287,7 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
*/
name: null,
- constructor: function(config) {
+ constructor: function (config) {
this.isDelugePlugin = true;
this.addEvents({
/**
@@ -8214,7 +8309,7 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
* Disables the plugin, firing the "{@link #disabled}" event and
* then executing the plugins clean up method onDisabled.
*/
- disable: function() {
+ disable: function () {
this.fireEvent('disabled', this);
if (this.onDisable) this.onDisable();
},
@@ -8223,13 +8318,13 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
* Enables the plugin, firing the "{@link #enabled}" event and
* then executes the plugins setup method, onEnabled.
*/
- enable: function() {
+ enable: function () {
deluge.client.reloadMethods();
this.fireEvent('enable', this);
if (this.onEnable) this.onEnable();
},
- registerTorrentStatus: function(key, header, options) {
+ registerTorrentStatus: function (key, header, options) {
options = options || {};
var cc = options.colCfg || {},
sc = options.storeCfg || {};
@@ -8250,23 +8345,23 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
deluge.torrents.getView().refresh(true);
},
- deregisterTorrentStatus: function(key) {
+ deregisterTorrentStatus: function (key) {
var fields = [];
- Ext.each(deluge.torrents.meta.fields, function(field) {
+ Ext.each(deluge.torrents.meta.fields, function (field) {
if (field.name != key) fields.push(field);
});
deluge.torrents.meta.fields = fields;
deluge.torrents.getStore().reader.onMetaChange(deluge.torrents.meta);
var cols = [];
- Ext.each(deluge.torrents.columns, function(col) {
+ Ext.each(deluge.torrents.columns, function (col) {
if (col.dataIndex != key) cols.push(col);
});
deluge.torrents.colModel.setConfig(cols);
deluge.torrents.columns = cols;
var keys = [];
- Ext.each(Deluge.Keys.Grid, function(k) {
+ Ext.each(Deluge.Keys.Grid, function (k) {
if (k == key) keys.push(k);
});
Deluge.Keys.Grid = keys;
@@ -8304,16 +8399,16 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
bodyStyle: 'padding: 5px; padding-left: 10px;',
html: 'Are you sure you wish to remove the torrent (s)?',
- initComponent: function() {
+ initComponent: function () {
Deluge.RemoveWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancel, this);
this.addButton(_('Remove With Data'), this.onRemoveData, this);
this.addButton(_('Remove Torrent'), this.onRemove, this);
},
- remove: function(removeData) {
+ remove: function (removeData) {
deluge.client.core.remove_torrents(this.torrentIds, removeData, {
- success: function(result) {
+ success: function (result) {
if (result == true) {
console.log(
'Error(s) occured when trying to delete torrent(s).'
@@ -8326,25 +8421,25 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
});
},
- show: function(ids) {
+ show: function (ids) {
Deluge.RemoveWindow.superclass.show.call(this);
this.torrentIds = ids;
},
- onCancel: function() {
+ onCancel: function () {
this.hide();
this.torrentIds = null;
},
- onRemove: function() {
+ onRemove: function () {
this.remove(false);
},
- onRemoveData: function() {
+ onRemoveData: function () {
this.remove(true);
},
- onRemoved: function(torrentIds) {
+ onRemoved: function (torrentIds) {
deluge.events.fire('torrentsRemoved', torrentIds);
this.hide();
deluge.ui.update();
@@ -8378,7 +8473,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
// private
selected: null,
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
id: 'sidebar',
@@ -8397,16 +8492,16 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
},
// private
- initComponent: function() {
+ initComponent: function () {
Deluge.Sidebar.superclass.initComponent.call(this);
deluge.events.on('disconnect', this.onDisconnect, this);
},
- createFilter: function(filter, states) {
+ createFilter: function (filter, states) {
var panel = new Deluge.FilterPanel({
filter: filter,
});
- panel.on('selectionchange', function(view, nodes) {
+ panel.on('selectionchange', function (view, nodes) {
deluge.ui.update();
});
this.add(panel);
@@ -8414,7 +8509,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.doLayout();
this.panels[filter] = panel;
- panel.header.on('click', function(header) {
+ panel.header.on('click', function (header) {
if (!deluge.config.sidebar_multiple_filters) {
deluge.ui.update();
}
@@ -8428,16 +8523,16 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.fireEvent('afterfiltercreate', this, panel);
},
- getFilter: function(filter) {
+ getFilter: function (filter) {
return this.panels[filter];
},
- getFilterStates: function() {
+ getFilterStates: function () {
var states = {};
if (deluge.config.sidebar_multiple_filters) {
// Grab the filters from each of the filter panels
- this.items.each(function(panel) {
+ this.items.each(function (panel) {
var state = panel.getState();
if (state == null) return;
states[panel.filterType] = state;
@@ -8454,12 +8549,12 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
return states;
},
- hasFilter: function(filter) {
+ hasFilter: function (filter) {
return this.panels[filter] ? true : false;
},
// private
- onDisconnect: function() {
+ onDisconnect: function () {
for (var filter in this.panels) {
this.remove(this.panels[filter]);
}
@@ -8467,11 +8562,11 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.selected = null;
},
- onFilterSelect: function(selModel, rowIndex, record) {
+ onFilterSelect: function (selModel, rowIndex, record) {
deluge.ui.update();
},
- update: function(filters) {
+ update: function (filters) {
for (var filter in filters) {
var states = filters[filter];
if (Ext.getKeys(this.panels).indexOf(filter) > -1) {
@@ -8484,7 +8579,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
// Perform a cleanup of fitlers that are not enabled any more.
Ext.each(
Ext.keys(this.panels),
- function(filter) {
+ function (filter) {
if (Ext.keys(filters).indexOf(filter) == -1) {
// We need to remove the panel
this.remove(this.panels[filter]);
@@ -8508,7 +8603,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
Ext.namespace('Deluge');
Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
id: 'deluge-statusbar',
@@ -8520,14 +8615,14 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
Deluge.Statusbar.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.Statusbar.superclass.initComponent.call(this);
deluge.events.on('connect', this.onConnect, this);
deluge.events.on('disconnect', this.onDisconnect, this);
},
- createButtons: function() {
+ createButtons: function () {
this.buttons = this.add(
{
id: 'statusbar-connections',
@@ -8711,7 +8806,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon',
iconCls: 'x-deluge-traffic',
tooltip: _('Protocol Traffic Download/Upload'),
- handler: function() {
+ handler: function () {
deluge.preferences.show();
deluge.preferences.selectPage('Network');
},
@@ -8738,7 +8833,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon',
iconCls: 'x-deluge-freespace',
tooltip: _('Freespace in download folder'),
- handler: function() {
+ handler: function () {
deluge.preferences.show();
deluge.preferences.selectPage('Downloads');
},
@@ -8747,7 +8842,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
this.created = true;
},
- onConnect: function() {
+ onConnect: function () {
this.setStatus({
iconCls: 'x-connected',
text: '',
@@ -8755,7 +8850,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
if (!this.created) {
this.createButtons();
} else {
- Ext.each(this.buttons, function(item) {
+ Ext.each(this.buttons, function (item) {
item.show();
item.enable();
});
@@ -8763,23 +8858,23 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
this.doLayout();
},
- onDisconnect: function() {
+ onDisconnect: function () {
this.clearStatus({ useDefaults: true });
- Ext.each(this.buttons, function(item) {
+ Ext.each(this.buttons, function (item) {
item.hide();
item.disable();
});
this.doLayout();
},
- update: function(stats) {
+ update: function (stats) {
if (!stats) return;
function addSpeed(val) {
return val + ' KiB/s';
}
- var updateStat = function(name, config) {
+ var updateStat = function (name, config) {
var item = this.items.get('statusbar-' + name);
if (config.limit.value > 0) {
var value = config.value.formatter
@@ -8874,7 +8969,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
* @extends Ext.Toolbar
*/
Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
items: [
@@ -8978,62 +9073,62 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
connectedButtons: ['add', 'remove', 'pause', 'resume', 'up', 'down'],
- initComponent: function() {
+ initComponent: function () {
Deluge.Toolbar.superclass.initComponent.call(this);
deluge.events.on('connect', this.onConnect, this);
deluge.events.on('login', this.onLogin, this);
},
- onConnect: function() {
+ onConnect: function () {
Ext.each(
this.connectedButtons,
- function(buttonId) {
+ function (buttonId) {
this.items.get(buttonId).enable();
},
this
);
},
- onDisconnect: function() {
+ onDisconnect: function () {
Ext.each(
this.connectedButtons,
- function(buttonId) {
+ function (buttonId) {
this.items.get(buttonId).disable();
},
this
);
},
- onLogin: function() {
+ onLogin: function () {
this.items.get('logout').enable();
},
- onLogout: function() {
+ onLogout: function () {
this.items.get('logout').disable();
deluge.login.logout();
},
- onConnectionManagerClick: function() {
+ onConnectionManagerClick: function () {
deluge.connectionManager.show();
},
- onHelpClick: function() {
+ onHelpClick: function () {
window.open('http://dev.deluge-torrent.org/wiki/UserGuide');
},
- onAboutClick: function() {
+ onAboutClick: function () {
var about = new Deluge.about.AboutWindow();
about.show();
},
- onPreferencesClick: function() {
+ onPreferencesClick: function () {
deluge.preferences.show();
},
- onTorrentAction: function(item) {
+ onTorrentAction: function (item) {
var selection = deluge.torrents.getSelections();
var ids = [];
- Ext.each(selection, function(record) {
+ Ext.each(selection, function (record) {
ids.push(record.id);
});
@@ -9044,7 +9139,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
case 'pause':
case 'resume':
deluge.client.core[item.id + '_torrent'](ids, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
@@ -9052,7 +9147,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
case 'up':
case 'down':
deluge.client.core['queue_' + item.id](ids, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
@@ -9060,7 +9155,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
}
},
- onTorrentAdd: function() {
+ onTorrentAdd: function () {
deluge.add.show();
},
});
@@ -9074,7 +9169,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
* See LICENSE for more details.
*/
-(function() {
+(function () {
/* Renderers for the Torrent Grid */
function queueRenderer(value) {
return value == -1 ? '' : value + 1;
@@ -9083,7 +9178,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
return String.format(
'<div class="torrent-name x-deluge-{0}">{1}</div>',
r.data['state'].toLowerCase(),
- value
+ Ext.util.Format.htmlEncode(value)
);
}
function torrentSpeedRenderer(value) {
@@ -9128,12 +9223,14 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
'<div style="background: url(' +
deluge.config.base +
'tracker/{0}) no-repeat; padding-left: 20px;">{0}</div>',
- value
+ Ext.util.Format.htmlEncode(value)
);
}
function etaSorter(eta) {
- return eta * -1;
+ if (eta === 0) return Number.MAX_VALUE;
+ if (eta <= -1) return Number.MAX_SAFE_INTEGER;
+ return eta;
}
function dateOrNever(date) {
@@ -9141,7 +9238,9 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
}
function timeOrInf(time) {
- return time < 0 ? '&infin;' : ftime(time);
+ if (time === 0) return '';
+ if (time <= -1) return '&infin;';
+ return ftime(time);
}
/**
@@ -9386,6 +9485,8 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
{ name: 'ratio', type: 'float' },
{ name: 'distributed_copies', type: 'float' },
{ name: 'time_added', type: 'int' },
+ { name: 'last_seen_complete', type: 'int' },
+ { name: 'completed_time', type: 'int' },
{ name: 'tracker_host' },
{ name: 'download_location' },
{ name: 'total_done', type: 'int' },
@@ -9403,21 +9504,21 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
key: 'a',
ctrl: true,
stopEvent: true,
- handler: function() {
+ handler: function () {
deluge.torrents.getSelectionModel().selectAll();
},
},
{
key: [46],
stopEvent: true,
- handler: function() {
+ handler: function () {
ids = deluge.torrents.getSelectedIds();
deluge.removeWindow.show(ids);
},
},
],
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
id: 'torrentGrid',
@@ -9442,12 +9543,12 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
Deluge.TorrentGrid.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.TorrentGrid.superclass.initComponent.call(this);
deluge.events.on('torrentsRemoved', this.onTorrentsRemoved, this);
deluge.events.on('disconnect', this.onDisconnect, this);
- this.on('rowcontextmenu', function(grid, rowIndex, e) {
+ this.on('rowcontextmenu', function (grid, rowIndex, e) {
e.stopEvent();
var selection = grid.getSelectionModel();
if (!selection.isSelected(rowIndex)) {
@@ -9463,7 +9564,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
* @param index {int} The row index of the torrent you wish to retrieve.
* @return {Ext.data.Record} The record representing the torrent.
*/
- getTorrent: function(index) {
+ getTorrent: function (index) {
return this.getStore().getAt(index);
},
@@ -9471,14 +9572,14 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
* Returns the currently selected record.
* @ return {Array/Ext.data.Record} The record(s) representing the rows
*/
- getSelected: function() {
+ getSelected: function () {
return this.getSelectionModel().getSelected();
},
/**
* Returns the currently selected records.
*/
- getSelections: function() {
+ getSelections: function () {
return this.getSelectionModel().getSelections();
},
@@ -9486,7 +9587,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
* Return the currently selected torrent id.
* @return {String} The currently selected id.
*/
- getSelectedId: function() {
+ getSelectedId: function () {
return this.getSelectionModel().getSelected().id;
},
@@ -9494,15 +9595,15 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
* Return the currently selected torrent ids.
* @return {Array} The currently selected ids.
*/
- getSelectedIds: function() {
+ getSelectedIds: function () {
var ids = [];
- Ext.each(this.getSelectionModel().getSelections(), function(r) {
+ Ext.each(this.getSelectionModel().getSelections(), function (r) {
ids.push(r.id);
});
return ids;
},
- update: function(torrents, wipe) {
+ update: function (torrents, wipe) {
var store = this.getStore();
// Need to perform a complete reload of the torrent grid.
@@ -9536,7 +9637,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
store.add(newTorrents);
// Remove any torrents that should not be in the store.
- store.each(function(record) {
+ store.each(function (record) {
if (!torrents[record.id]) {
store.remove(record);
delete this.torrents[record.id];
@@ -9550,17 +9651,17 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
},
// private
- onDisconnect: function() {
+ onDisconnect: function () {
this.getStore().removeAll();
this.torrents = {};
},
// private
- onTorrentsRemoved: function(torrentIds) {
+ onTorrentsRemoved: function (torrentIds) {
var selModel = this.getSelectionModel();
Ext.each(
torrentIds,
- function(torrentId) {
+ function (torrentId) {
var record = this.getStore().getById(torrentId);
if (selModel.isSelected(record)) {
selModel.deselectRow(this.getStore().indexOf(record));
@@ -9618,7 +9719,7 @@ deluge.ui = {
* @description Create all the interface components, the json-rpc client
* and set up various events that the UI will utilise.
*/
- initialize: function() {
+ initialize: function () {
deluge.add = new Deluge.add.AddWindow();
deluge.details = new Deluge.details.DetailsPanel();
deluge.connectionManager = new Deluge.ConnectionManager();
@@ -9676,7 +9777,7 @@ deluge.ui = {
deluge.client.on(
'connected',
- function(e) {
+ function (e) {
deluge.login.show();
},
this,
@@ -9689,7 +9790,7 @@ deluge.ui = {
this.originalTitle = document.title;
},
- checkConnection: function() {
+ checkConnection: function () {
deluge.client.web.connected({
success: this.onConnectionSuccess,
failure: this.onConnectionError,
@@ -9697,7 +9798,7 @@ deluge.ui = {
});
},
- update: function() {
+ update: function () {
var filters = deluge.sidebar.getFilterStates();
this.oldFilters = this.filters;
this.filters = filters;
@@ -9710,9 +9811,9 @@ deluge.ui = {
deluge.details.update();
},
- onConnectionError: function(error) {},
+ onConnectionError: function (error) {},
- onConnectionSuccess: function(result) {
+ onConnectionSuccess: function (result) {
deluge.statusbar.setStatus({
iconCls: 'x-deluge-statusbar icon-ok',
text: _('Connection restored'),
@@ -9723,7 +9824,7 @@ deluge.ui = {
}
},
- onUpdateError: function(error) {
+ onUpdateError: function (error) {
if (this.errorCount == 2) {
Ext.MessageBox.show({
title: _('Lost Connection'),
@@ -9745,7 +9846,7 @@ deluge.ui = {
* @private
* Updates the various components in the interface.
*/
- onUpdate: function(data) {
+ onUpdate: function (data) {
if (!data['connected']) {
deluge.connectionManager.disconnect(true);
return;
@@ -9775,7 +9876,7 @@ deluge.ui = {
* @private
* Start the Deluge UI polling the server and update the interface.
*/
- onConnect: function() {
+ onConnect: function () {
if (!this.running) {
this.running = setInterval(this.update, 2000);
this.update();
@@ -9790,14 +9891,14 @@ deluge.ui = {
* @static
* @private
*/
- onDisconnect: function() {
+ onDisconnect: function () {
this.stop();
},
- onGotPlugins: function(plugins) {
+ onGotPlugins: function (plugins) {
Ext.each(
plugins.enabled_plugins,
- function(plugin) {
+ function (plugin) {
if (deluge.plugins[plugin]) return;
deluge.client.web.get_plugin_resources(plugin, {
success: this.onGotPluginResources,
@@ -9808,7 +9909,7 @@ deluge.ui = {
);
},
- onPluginEnabled: function(pluginName) {
+ onPluginEnabled: function (pluginName) {
if (deluge.plugins[pluginName]) {
deluge.plugins[pluginName].enable();
} else {
@@ -9819,13 +9920,13 @@ deluge.ui = {
}
},
- onGotPluginResources: function(resources) {
+ onGotPluginResources: function (resources) {
var scripts = Deluge.debug
? resources.debug_scripts
: resources.scripts;
Ext.each(
scripts,
- function(script) {
+ function (script) {
Ext.ux.JSLoader({
url: deluge.config.base + script,
onLoad: this.onPluginLoaded,
@@ -9836,11 +9937,11 @@ deluge.ui = {
);
},
- onPluginDisabled: function(pluginName) {
+ onPluginDisabled: function (pluginName) {
if (deluge.plugins[pluginName]) deluge.plugins[pluginName].disable();
},
- onPluginLoaded: function(options) {
+ onPluginLoaded: function (options) {
// This could happen if the plugin has multiple scripts
if (!Deluge.hasPlugin(options.pluginName)) return;
@@ -9854,7 +9955,7 @@ deluge.ui = {
* @static
* Stop the Deluge UI polling the server and clear the interface.
*/
- stop: function() {
+ stop: function () {
if (this.running) {
clearInterval(this.running);
this.running = false;
@@ -9863,6 +9964,6 @@ deluge.ui = {
},
};
-Ext.onReady(function(e) {
+Ext.onReady(function (e) {
deluge.ui.initialize();
});
diff --git a/deluge/ui/web/js/deluge-all.js b/deluge/ui/web/js/deluge-all.js
new file mode 100644
index 0000000..f9fd796
--- /dev/null
+++ b/deluge/ui/web/js/deluge-all.js
@@ -0,0 +1,291 @@
+Ext.ns("Deluge.add");Deluge.add.Window=Ext.extend(Ext.Window,{initComponent:function(){Deluge.add.Window.superclass.initComponent.call(this);this.addEvents("beforeadd","add","addfailed")},createTorrentId:function(){return(new Date).getTime().toString()}});Ext.namespace("Deluge.add");
+Ext.override(Ext.ux.form.FileUploadField,{onRender:function(a,b){Ext.ux.form.FileUploadField.superclass.onRender.call(this,a,b);this.wrap=this.el.wrap({cls:"x-form-field-wrap x-form-file-wrap"});this.el.addClass("x-form-file-text");this.el.dom.removeAttribute("name");this.createFileInput();var c=Ext.applyIf(this.buttonCfg||{},{text:this.buttonText});this.button=new Ext.Button(Ext.apply(c,{renderTo:this.wrap,cls:"x-form-file-btn"+(c.iconCls?" x-btn-text-icon":"")}));this.buttonOnly&&(this.el.hide(),
+this.wrap.setWidth(this.button.getEl().getWidth()));this.bindListeners();this.resizeEl=this.positionEl=this.wrap}});
+Deluge.add.AddWindow=Ext.extend(Deluge.add.Window,{title:_("Add Torrents"),layout:"border",width:470,height:450,bodyStyle:"padding: 10px 5px;",buttonAlign:"right",closeAction:"hide",closable:!0,plain:!0,iconCls:"x-deluge-add-window-icon",initComponent:function(){Deluge.add.AddWindow.superclass.initComponent.call(this);this.addButton(_("Cancel"),this.onCancelClick,this);this.addButton(_("Add"),this.onAddClick,this);this.list=new Ext.list.ListView({store:new Ext.data.SimpleStore({fields:[{name:"info_hash",
+mapping:1},{name:"text",mapping:2}],id:0}),columns:[{id:"torrent",width:150,sortable:!0,dataIndex:"text",tpl:new Ext.XTemplate('<div class="x-deluge-add-torrent-name">{text:htmlEncode}</div>')}],stripeRows:!0,singleSelect:!0,listeners:{selectionchange:{fn:this.onSelect,scope:this}},hideHeaders:!0,autoExpandColumn:"torrent",height:"100%",autoScroll:!0});this.add({region:"center",items:[this.list],border:!1,bbar:new Ext.Toolbar({items:[{id:"fileUploadForm",xtype:"form",layout:"fit",baseCls:"x-plain",
+fileUpload:!0,items:[{buttonOnly:!0,xtype:"fileuploadfield",id:"torrentFile",name:"file",multiple:!0,buttonCfg:{iconCls:"x-deluge-add-file",text:_("File")},listeners:{scope:this,fileselected:this.onFileSelected}}]},{text:_("Url"),iconCls:"icon-add-url",handler:this.onUrl,scope:this},{text:_("Infohash"),iconCls:"icon-magnet-add",hidden:!0,disabled:!0},"->",{text:_("Remove"),iconCls:"icon-remove",handler:this.onRemove,scope:this}]})});this.fileUploadForm=Ext.getCmp("fileUploadForm").getForm();this.optionsPanel=
+this.add(new Deluge.add.OptionsPanel);this.on("hide",this.onHide,this);this.on("show",this.onShow,this)},clear:function(){this.list.getStore().removeAll();this.optionsPanel.clear();this.fileUploadForm.reset()},onAddClick:function(){var a=[];this.list&&(this.list.getStore().each(function(b){b=b.get("info_hash");a.push({path:this.optionsPanel.getFilename(b),options:this.optionsPanel.getOptions(b)})},this),deluge.client.web.add_torrents(a,{success:function(a){}}),this.clear(),this.hide())},onCancelClick:function(){this.clear();
+this.hide()},onFile:function(){this.file||(this.file=new Deluge.add.FileWindow);this.file.show()},onHide:function(){this.optionsPanel.setActiveTab(0);this.optionsPanel.files.setDisabled(!0);this.optionsPanel.form.setDisabled(!0)},onRemove:function(){if(this.list.getSelectionCount()){var a=this.list.getSelectedRecords()[0];a&&(this.list.getStore().remove(a),this.optionsPanel.clear(),this.torrents&&this.torrents[a.id]&&delete this.torrents[a.id])}},onSelect:function(a,b){if(b.length){var c=this.list.getRecord(b[0]);
+this.optionsPanel.setTorrent(c.get("info_hash"))}else this.optionsPanel.files.setDisabled(!0),this.optionsPanel.form.setDisabled(!0)},onShow:function(){this.url||(this.url=new Deluge.add.UrlWindow,this.url.on("beforeadd",this.onTorrentBeforeAdd,this),this.url.on("add",this.onTorrentAdd,this),this.url.on("addfailed",this.onTorrentAddFailed,this));this.optionsPanel.form.getDefaults()},onFileSelected:function(){if(this.fileUploadForm.isValid()){var a=[],b=this.fileUploadForm.findField("torrentFile").value,
+c=this.createTorrentId();Array.prototype.forEach.call(b,function(b,f){var g=c+f.toString();a.push(g);this.onTorrentBeforeAdd(g,b.name)}.bind(this));this.fileUploadForm.submit({url:deluge.config.base+"upload",waitMsg:_("Uploading your torrent..."),success:this.onUploadSuccess,failure:this.onUploadFailure,scope:this,torrentIds:a})}},onUploadSuccess:function(a,b){b.result.success?(b.result.files.forEach(function(a,d){deluge.client.web.get_torrent_info(a,{success:this.onGotInfo,scope:this,filename:a,
+torrentId:b.options.torrentIds[d]})}.bind(this)),this.fileUploadForm.reset()):this.clear()},onUploadFailure:function(a,b){this.hide();Ext.MessageBox.show({title:_("Error"),msg:_("Failed to upload torrent"),buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"});this.fireEvent("addfailed",this.torrentId)},onGotInfo:function(a,b,c,d){a.filename=d.options.filename;torrentId=d.options.torrentId;this.onTorrentAdd(torrentId,a)},onTorrentBeforeAdd:function(a,b){this.list.getStore().loadData([[a,
+null,b]],!0)},onTorrentAdd:function(a,b){var c=this.list.getStore().getById(a);b?(c.set("info_hash",b.info_hash),c.set("text",b.name),this.list.getStore().commitChanges(),this.optionsPanel.addTorrent(b),this.list.select(c)):(Ext.MessageBox.show({title:_("Error"),msg:_("Not a valid torrent"),buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"}),this.list.getStore().remove(c))},onTorrentAddFailed:function(a){var b=this.list.getStore();(a=b.getById(a))&&b.remove(a)},
+onUrl:function(a,b){this.url.show()}});Ext.ns("Deluge.add");
+Deluge.add.FilesTab=Ext.extend(Ext.ux.tree.TreeGrid,{layout:"fit",title:_("Files"),autoScroll:!1,animate:!1,border:!1,disabled:!0,rootVisible:!1,columns:[{header:_("Filename"),width:295,dataIndex:"filename",tpl:new Ext.XTemplate("{filename:htmlEncode}")},{header:_("Size"),width:60,dataIndex:"size",tpl:new Ext.XTemplate("{size:this.fsize}",{fsize:function(a){return fsize(a)}})},{header:_("Download"),width:65,dataIndex:"download",tpl:new Ext.XTemplate("{download:this.format}",{format:function(a){return'<div rel="chkbox" class="x-grid3-check-col'+
+(a?"-on":"")+'"> </div>'}})}],initComponent:function(){Deluge.add.FilesTab.superclass.initComponent.call(this);this.on("click",this.onNodeClick,this)},clearFiles:function(){var a=this.getRootNode();a.hasChildNodes()&&a.cascade(function(a){a.parentNode&&a.getOwnerTree()&&a.remove()})},setDownload:function(a,b,c){a.attributes.download=b;a.ui.updateColumns();if(a.isLeaf()){if(!c)return this.fireEvent("fileschecked",[a],b,!b)}else{var d=[a];a.cascade(function(a){a.attributes.download=b;a.ui.updateColumns();
+d.push(a)},this);if(!c)return this.fireEvent("fileschecked",d,b,!b)}},onNodeClick:function(a,b){"chkbox"==(new Ext.Element(b.target)).getAttribute("rel")&&this.setDownload(a,!a.attributes.download)}});Ext.namespace("Ext.deluge.add");Ext.ns("Deluge.add");
+Deluge.add.OptionsPanel=Ext.extend(Ext.TabPanel,{torrents:{},region:"south",border:!1,activeTab:0,height:265,initComponent:function(){Deluge.add.OptionsPanel.superclass.initComponent.call(this);this.files=this.add(new Deluge.add.FilesTab);this.form=this.add(new Deluge.add.OptionsTab);this.files.on("fileschecked",this.onFilesChecked,this)},addTorrent:function(a){this.torrents[a.info_hash]=a;var b={};this.walkFileTree(a.files_tree,function(a,c,g,e){"file"==c&&(b[g.index]=g.download)},this);var c=[];
+Ext.each(Ext.keys(b),function(a){c[a]=b[a]});a=this.form.optionsManager.changeId(a.info_hash,!0);this.form.optionsManager.setDefault("file_priorities",c);this.form.optionsManager.changeId(a,!0)},clear:function(){this.files.clearFiles();this.form.optionsManager.resetAll()},getFilename:function(a){return this.torrents[a].filename},getOptions:function(a){a=this.form.optionsManager.changeId(a,!0);var b=this.form.optionsManager.get();this.form.optionsManager.changeId(a,!0);Ext.each(b.file_priorities,function(a,
+d){b.file_priorities[d]=a?1:0});return b},setTorrent:function(a){if(a){this.torrentId=a;this.form.optionsManager.changeId(a);this.files.clearFiles();var b=this.files.getRootNode(),c=this.form.optionsManager.get("file_priorities");this.form.setDisabled(!1);this.torrents[a].files_tree?(this.walkFileTree(this.torrents[a].files_tree,function(a,b,g,e){a=new Ext.tree.TreeNode({download:g.index?c[g.index]:!0,filename:a,fileindex:g.index,leaf:"dir"!=b,size:g.length});e.appendChild(a);if("dir"==b)return a},
+this,b),b.firstChild.expand(),this.files.setDisabled(!1),this.files.show()):(this.form.show(),this.files.setDisabled(!0))}},walkFileTree:function(a,b,c,d){for(var f in a.contents){var g=a.contents[f],e=g.type,l=c?b.apply(c,[f,e,g,d]):b(f,e,g,d);"dir"==e&&this.walkFileTree(g,b,c,l)}},onFilesChecked:function(a,b,c){Ext.each(a,function(a){if(!(0>a.attributes.fileindex)){var c=this.form.optionsManager.get("file_priorities");c[a.attributes.fileindex]=b;this.form.optionsManager.update("file_priorities",
+c)}},this)}});Ext.ns("Deluge.add");
+Deluge.add.OptionsTab=Ext.extend(Ext.form.FormPanel,{title:_("Options"),height:170,border:!1,bodyStyle:"padding: 5px",disabled:!0,labelWidth:1,initComponent:function(){Deluge.add.OptionsTab.superclass.initComponent.call(this);this.optionsManager=new Deluge.MultiOptionsManager;var a=this.add({xtype:"fieldset",title:_("Download Folder"),border:!1,autoHeight:!0,defaultType:"textfield",labelWidth:1,fieldLabel:"",style:"padding: 5px 0; margin-bottom: 0;"});this.optionsManager.bind("download_location",a.add({fieldLabel:"",
+name:"download_location",anchor:"95%",labelSeparator:""}));a=this.add({xtype:"fieldset",title:_("Move Completed Folder"),border:!1,autoHeight:!0,defaultType:"togglefield",labelWidth:1,fieldLabel:"",style:"padding: 5px 0; margin-bottom: 0;"});a=a.add({fieldLabel:"",name:"move_completed_path",anchor:"98%"});this.optionsManager.bind("move_completed",a.toggle);this.optionsManager.bind("move_completed_path",a.input);var b=this.add({border:!1,layout:"column",defaultType:"fieldset"}),a=b.add({title:_("Bandwidth"),
+border:!1,autoHeight:!0,bodyStyle:"padding: 2px 5px",labelWidth:105,width:200,defaultType:"spinnerfield",style:"padding-right: 10px;"});this.optionsManager.bind("max_download_speed",a.add({fieldLabel:_("Max Down Speed"),name:"max_download_speed",width:60}));this.optionsManager.bind("max_upload_speed",a.add({fieldLabel:_("Max Up Speed"),name:"max_upload_speed",width:60}));this.optionsManager.bind("max_connections",a.add({fieldLabel:_("Max Connections"),name:"max_connections",width:60}));this.optionsManager.bind("max_upload_slots",
+a.add({fieldLabel:_("Max Upload Slots"),name:"max_upload_slots",width:60}));a=b.add({border:!1,autoHeight:!0,defaultType:"checkbox"});this.optionsManager.bind("add_paused",a.add({name:"add_paused",boxLabel:_("Add In Paused State"),fieldLabel:"",labelSeparator:""}));this.optionsManager.bind("prioritize_first_last_pieces",a.add({name:"prioritize_first_last_pieces",boxLabel:_("Prioritize First/Last Pieces"),fieldLabel:"",labelSeparator:""}));this.optionsManager.bind("sequential_download",a.add({name:"sequential_download",
+boxLabel:_("Sequential Download"),fieldLabel:"",labelSeparator:""}));this.optionsManager.bind("seed_mode",a.add({name:"seed_mode",boxLabel:_("Skip File Hash Check"),fieldLabel:"",labelSeparator:""}));this.optionsManager.bind("super_seeding",a.add({name:"super_seeding",boxLabel:_("Super Seed"),fieldLabel:"",labelSeparator:""}));this.optionsManager.bind("pre_allocate_storage",a.add({name:"pre_allocate_storage",boxLabel:_("Preallocate Disk Space"),fieldLabel:"",labelSeparator:""}))},getDefaults:function(){deluge.client.core.get_config_values("add_paused pre_allocate_storage download_location max_connections_per_torrent max_download_speed_per_torrent move_completed move_completed_path max_upload_slots_per_torrent max_upload_speed_per_torrent prioritize_first_last_pieces sequential_download".split(" "),
+{success:function(a){this.optionsManager.options={file_priorities:[],add_paused:a.add_paused,sequential_download:a.sequential_download,pre_allocate_storage:a.pre_allocate_storage,download_location:a.download_location,move_completed:a.move_completed,move_completed_path:a.move_completed_path,max_connections:a.max_connections_per_torrent,max_download_speed:a.max_download_speed_per_torrent,max_upload_slots:a.max_upload_slots_per_torrent,max_upload_speed:a.max_upload_speed_per_torrent,prioritize_first_last_pieces:a.prioritize_first_last_pieces,
+seed_mode:!1,super_seeding:!1};this.optionsManager.resetAll()},scope:this})}});Ext.namespace("Deluge.add");
+Deluge.add.UrlWindow=Ext.extend(Deluge.add.Window,{title:_("Add from Url"),modal:!0,plain:!0,layout:"fit",width:350,height:155,buttonAlign:"center",closeAction:"hide",bodyStyle:"padding: 10px 5px;",iconCls:"x-deluge-add-url-window-icon",initComponent:function(){Deluge.add.UrlWindow.superclass.initComponent.call(this);this.addButton(_("Add"),this.onAddClick,this);var a=this.add({xtype:"form",defaultType:"textfield",baseCls:"x-plain",labelWidth:55});this.urlField=a.add({fieldLabel:_("Url"),id:"url",
+name:"url",width:"97%"});this.urlField.on("specialkey",this.onAdd,this);this.cookieField=a.add({fieldLabel:_("Cookies"),id:"cookies",name:"cookies",width:"97%"});this.cookieField.on("specialkey",this.onAdd,this)},onAddClick:function(a,b){if(!(("url"==a.id||"cookies"==a.id)&&b.getKey()!=b.ENTER)){a=this.urlField;var c=a.getValue(),d=this.cookieField.getValue(),f=this.createTorrentId();0==c.indexOf("magnet:?")&&-1<c.indexOf("xt=urn:btih")?deluge.client.web.get_magnet_info(c,{success:this.onGotInfo,
+scope:this,filename:c,torrentId:f}):deluge.client.web.download_torrent_from_url(c,d,{success:this.onDownload,failure:this.onDownloadFailed,scope:this,torrentId:f});this.hide();this.urlField.setValue("");this.fireEvent("beforeadd",f,c)}},onDownload:function(a,b,c,d){deluge.client.web.get_torrent_info(a,{success:this.onGotInfo,failure:this.onDownloadFailed,scope:this,filename:a,torrentId:d.options.torrentId})},onDownloadFailed:function(a,b,c){Ext.MessageBox.show({title:_("Error"),msg:_("Failed to download torrent"),
+buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"});this.fireEvent("addfailed",c.options.torrentId)},onGotInfo:function(a,b,c,d){a.filename=d.options.filename;this.fireEvent("add",d.options.torrentId,a)}});Ext.namespace("Deluge.data");Deluge.data.SortTypes={asIPAddress:function(a){a=a.match(/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\:(\d+)/);return 256*(256*(256*+a[1]+ +a[2])+ +a[3])+ +a[4]},asQueuePosition:function(a){return-1<a?a:Number.MAX_VALUE},asName:function(a){return String(a).toLowerCase()}};
+Ext.namespace("Deluge.data");Deluge.data.Peer=Ext.data.Record.create([{name:"country",type:"string"},{name:"ip",type:"string",sortType:Deluge.data.SortTypes.asIPAddress},{name:"client",type:"string"},{name:"progress",type:"float"},{name:"down_speed",type:"int"},{name:"up_speed",type:"int"},{name:"seed",type:"int"}]);Ext.namespace("Deluge.data");
+Deluge.data.Torrent=Ext.data.Record.create([{name:"queue",type:"int"},{name:"name",type:"string",sortType:Deluge.data.SortTypes.asName},{name:"total_wanted",type:"int"},{name:"state",type:"string"},{name:"progress",type:"int"},{name:"num_seeds",type:"int"},{name:"total_seeds",type:"int"},{name:"num_peers",type:"int"},{name:"total_peers",type:"int"},{name:"download_payload_rate",type:"int"},{name:"upload_payload_rate",type:"int"},{name:"eta",type:"int"},{name:"ratio",type:"float"},{name:"distributed_copies",
+type:"float"},{name:"time_added",type:"int"},{name:"tracker_host",type:"string"},{name:"save_path",type:"string"},{name:"total_done",type:"int"},{name:"total_uploaded",type:"int"},{name:"total_remaining",type:"int"},{name:"max_download_speed",type:"int"},{name:"max_upload_speed",type:"int"},{name:"seeds_peers_ratio",type:"float"},{name:"time_since_transfer",type:"int"}]);Ext.namespace("Deluge.details");
+Deluge.details.DetailsPanel=Ext.extend(Ext.TabPanel,{id:"torrentDetails",activeTab:0,initComponent:function(){Deluge.details.DetailsPanel.superclass.initComponent.call(this);this.add(new Deluge.details.StatusTab);this.add(new Deluge.details.DetailsTab);this.add(new Deluge.details.FilesTab);this.add(new Deluge.details.PeersTab);this.add(new Deluge.details.OptionsTab)},clear:function(){this.items.each(function(a){a.clear&&(a.clear.defer(100,a),a.disable())})},update:function(a){var b=deluge.torrents.getSelected();
+b?(this.items.each(function(a){a.disabled&&a.enable()}),a=a||this.getActiveTab(),a.update&&a.update(b.id)):this.clear()},onRender:function(a,b){Deluge.details.DetailsPanel.superclass.onRender.call(this,a,b);deluge.events.on("disconnect",this.clear,this);deluge.torrents.on("rowclick",this.onTorrentsClick,this);this.on("tabchange",this.onTabChange,this);deluge.torrents.getSelectionModel().on("selectionchange",function(a){a.hasSelection()||this.clear()},this)},onTabChange:function(a,b){this.update(b)},
+onTorrentsClick:function(a,b,c){this.update()}});
+Deluge.details.DetailsTab=Ext.extend(Ext.Panel,{title:_("Details"),fields:{},autoScroll:!0,queuedItems:{},oldData:{},initComponent:function(){Deluge.details.DetailsTab.superclass.initComponent.call(this);this.addItem("torrent_name",_("Name:"));this.addItem("hash",_("Hash:"));this.addItem("path",_("Download Folder:"));this.addItem("size",_("Total Size:"));this.addItem("files",_("Total Files:"));this.addItem("comment",_("Comment:"));this.addItem("status",_("Status:"));this.addItem("tracker",_("Tracker:"));
+this.addItem("creator",_("Created By:"))},onRender:function(a,b){Deluge.details.DetailsTab.superclass.onRender.call(this,a,b);this.body.setStyle("padding","10px");this.dl=Ext.DomHelper.append(this.body,{tag:"dl"},!0);for(var c in this.queuedItems)this.doAddItem(c,this.queuedItems[c])},addItem:function(a,b){this.rendered?this.doAddItem(a,b):this.queuedItems[a]=b},doAddItem:function(a,b){Ext.DomHelper.append(this.dl,{tag:"dt",cls:a,html:b});this.fields[a]=Ext.DomHelper.append(this.dl,{tag:"dd",cls:a,
+html:""},!0)},clear:function(){if(this.fields){for(var a in this.fields)this.fields[a].dom.innerHTML="";this.oldData={}}},update:function(a){deluge.client.web.get_torrent_status(a,Deluge.Keys.Details,{success:this.onRequestComplete,scope:this,torrentId:a})},onRequestComplete:function(a,b,c,d){a={torrent_name:a.name,hash:d.options.torrentId,path:a.download_location,size:fsize(a.total_size),files:a.num_files,status:a.message,tracker:a.tracker_host,comment:a.comment,creator:a.creator};for(var f in this.fields)Ext.isDefined(a[f])&&
+a[f]!=this.oldData[f]&&(this.fields[f].dom.innerHTML=Ext.util.Format.htmlEncode(a[f]));this.oldData=a}});
+Deluge.details.FilesTab=Ext.extend(Ext.ux.tree.TreeGrid,{title:_("Files"),rootVisible:!1,columns:[{header:_("Filename"),width:330,dataIndex:"filename",tpl:new Ext.XTemplate("{filename:htmlEncode}")},{header:_("Size"),width:150,dataIndex:"size",tpl:new Ext.XTemplate("{size:this.fsize}",{fsize:function(a){return fsize(a)}})},{xtype:"tgrendercolumn",header:_("Progress"),width:150,dataIndex:"progress",renderer:function(a){a*=100;return Deluge.progressBar(a,this.col.width,a.toFixed(2)+"%",0)}},{header:_("Priority"),
+width:150,dataIndex:"priority",tpl:new Ext.XTemplate('<tpl if="!isNaN(priority)"><div class="{priority:this.getClass}">{priority:this.getName}</div></tpl>',{getClass:function(a){return FILE_PRIORITY_CSS[a]},getName:function(a){return _(FILE_PRIORITY[a])}})}],selModel:new Ext.tree.MultiSelectionModel,initComponent:function(){Deluge.details.FilesTab.superclass.initComponent.call(this);this.setRootNode(new Ext.tree.TreeNode({text:_("Files")}))},clear:function(){var a=this.getRootNode();a.hasChildNodes()&&
+a.cascade(function(a){var c=a.parentNode;c&&c.ownerTree&&c.removeChild(a)})},createFileTree:function(a){function b(a,c){for(var g in a.contents){var e=a.contents[g];"dir"==e.type?b(e,c.appendChild(new Ext.tree.TreeNode({text:g,filename:g,size:e.size,progress:e.progress,priority:e.priority}))):c.appendChild(new Ext.tree.TreeNode({text:g,filename:g,fileIndex:e.index,size:e.size,progress:e.progress,priority:e.priority,leaf:!0,iconCls:"x-deluge-file",uiProvider:Ext.ux.tree.TreeGridNodeUI}))}}var c=this.getRootNode();
+b(a,c);c.firstChild.expand()},update:function(a){this.torrentId!=a&&(this.clear(),this.torrentId=a);deluge.client.web.get_torrent_files(a,{success:this.onRequestComplete,scope:this,torrentId:a})},updateFileTree:function(a){function b(a,d){for(var f in a.contents){var g=a.contents[f],e=d.findChild("filename",f);e.attributes.size=g.size;e.attributes.progress=g.progress;e.attributes.priority=g.priority;e.ui.updateColumns();"dir"==g.type&&b(g,e)}}b(a,this.getRootNode())},onRender:function(a,b){Deluge.details.FilesTab.superclass.onRender.call(this,
+a,b);deluge.menus.filePriorities.on("itemclick",this.onItemClick,this);this.on("contextmenu",this.onContextMenu,this);this.sorter=new Ext.tree.TreeSorter(this,{folderSort:!0})},onContextMenu:function(a,b){b.stopEvent();var c=this.getSelectionModel();2>c.getSelectedNodes().length&&(c.clearSelections(),a.select());deluge.menus.filePriorities.showAt(b.getPoint())},onItemClick:function(a,b){switch(a.id){case "expandAll":this.expandAll();break;default:var c={};this.getRootNode().cascade(function(a){Ext.isEmpty(a.attributes.fileIndex)||
+(c[a.attributes.fileIndex]=a.attributes.priority)});var d=this.getSelectionModel().getSelectedNodes();Ext.each(d,function(b){b.isLeaf()?Ext.isEmpty(b.attributes.fileIndex)||(c[b.attributes.fileIndex]=a.filePriority):b.cascade(function(b){Ext.isEmpty(b.attributes.fileIndex)||(c[b.attributes.fileIndex]=a.filePriority)})});var f=Array(Ext.keys(c).length),g;for(g in c)f[g]=c[g];deluge.client.core.set_torrent_options([this.torrentId],{file_priorities:f},{success:function(){Ext.each(d,function(b){b.setColumnValue(3,
+a.filePriority)})},scope:this})}},onRequestComplete:function(a,b){this.getRootNode().hasChildNodes()?this.updateFileTree(a):this.createFileTree(a)}});
+Deluge.details.OptionsTab=Ext.extend(Ext.form.FormPanel,{constructor:function(a){a=Ext.apply({autoScroll:!0,bodyStyle:"padding: 5px;",border:!1,cls:"x-deluge-options",defaults:{autoHeight:!0,labelWidth:1,defaultType:"checkbox"},deferredRender:!1,layout:"column",title:_("Options")},a);Deluge.details.OptionsTab.superclass.constructor.call(this,a)},initComponent:function(){Deluge.details.OptionsTab.superclass.initComponent.call(this);this.fieldsets={};this.fields={};this.optionsManager=new Deluge.MultiOptionsManager({options:{max_download_speed:-1,
+max_upload_speed:-1,max_connections:-1,max_upload_slots:-1,auto_managed:!1,stop_at_ratio:!1,stop_ratio:2,remove_at_ratio:!1,move_completed:!1,move_completed_path:"","private":!1,prioritize_first_last:!1,super_seeding:!1}});this.fieldsets.bandwidth=this.add({xtype:"fieldset",defaultType:"spinnerfield",bodyStyle:"padding: 5px",layout:"table",layoutConfig:{columns:3},labelWidth:150,style:"margin-left: 10px; margin-right: 5px; padding: 5px",title:_("Bandwidth"),width:250});this.fieldsets.bandwidth.add({xtype:"label",
+text:_("Max Download Speed:"),forId:"max_download_speed",cls:"x-deluge-options-label"});this.fields.max_download_speed=this.fieldsets.bandwidth.add({id:"max_download_speed",name:"max_download_speed",width:70,strategy:{xtype:"number",decimalPrecision:1,minValue:-1,maxValue:99999}});this.fieldsets.bandwidth.add({xtype:"label",text:_("KiB/s"),style:"margin-left: 10px"});this.fieldsets.bandwidth.add({xtype:"label",text:_("Max Upload Speed:"),forId:"max_upload_speed",cls:"x-deluge-options-label"});this.fields.max_upload_speed=
+this.fieldsets.bandwidth.add({id:"max_upload_speed",name:"max_upload_speed",width:70,value:-1,strategy:{xtype:"number",decimalPrecision:1,minValue:-1,maxValue:99999}});this.fieldsets.bandwidth.add({xtype:"label",text:_("KiB/s"),style:"margin-left: 10px"});this.fieldsets.bandwidth.add({xtype:"label",text:_("Max Connections:"),forId:"max_connections",cls:"x-deluge-options-label"});this.fields.max_connections=this.fieldsets.bandwidth.add({id:"max_connections",name:"max_connections",width:70,value:-1,
+strategy:{xtype:"number",decimalPrecision:0,minValue:-1,maxValue:99999},colspan:2});this.fieldsets.bandwidth.add({xtype:"label",text:_("Max Upload Slots:"),forId:"max_upload_slots",cls:"x-deluge-options-label"});this.fields.max_upload_slots=this.fieldsets.bandwidth.add({id:"max_upload_slots",name:"max_upload_slots",width:70,value:-1,strategy:{xtype:"number",decimalPrecision:0,minValue:-1,maxValue:99999},colspan:2});this.fieldsets.queue=this.add({xtype:"fieldset",title:_("Queue"),style:"margin-left: 5px; margin-right: 5px; padding: 5px",
+width:210,layout:"table",layoutConfig:{columns:2},labelWidth:0,defaults:{fieldLabel:"",labelSeparator:""}});this.fields.auto_managed=this.fieldsets.queue.add({xtype:"checkbox",fieldLabel:"",labelSeparator:"",name:"is_auto_managed",boxLabel:_("Auto Managed"),width:200,colspan:2});this.fields.stop_at_ratio=this.fieldsets.queue.add({fieldLabel:"",labelSeparator:"",id:"stop_at_ratio",width:120,boxLabel:_("Stop seed at ratio:"),handler:this.onStopRatioChecked,scope:this});this.fields.stop_ratio=this.fieldsets.queue.add({xtype:"spinnerfield",
+id:"stop_ratio",name:"stop_ratio",disabled:!0,width:50,value:2,strategy:{xtype:"number",minValue:-1,maxValue:99999,incrementValue:0.1,alternateIncrementValue:1,decimalPrecision:1}});this.fields.remove_at_ratio=this.fieldsets.queue.add({fieldLabel:"",labelSeparator:"",id:"remove_at_ratio",ctCls:"x-deluge-indent-checkbox",bodyStyle:"padding-left: 10px",boxLabel:_("Remove at ratio"),disabled:!0,colspan:2});this.fields.move_completed=this.fieldsets.queue.add({fieldLabel:"",labelSeparator:"",id:"move_completed",
+boxLabel:_("Move Completed:"),colspan:2,handler:this.onMoveCompletedChecked,scope:this});this.fields.move_completed_path=this.fieldsets.queue.add({xtype:"textfield",fieldLabel:"",id:"move_completed_path",colspan:3,bodyStyle:"margin-left: 20px",width:180,disabled:!0});this.rightColumn=this.add({border:!1,autoHeight:!0,style:"margin-left: 5px",width:210});this.fieldsets.general=this.rightColumn.add({xtype:"fieldset",autoHeight:!0,defaultType:"checkbox",title:_("General"),layout:"form"});this.fields["private"]=
+this.fieldsets.general.add({fieldLabel:"",labelSeparator:"",boxLabel:_("Private"),id:"private",disabled:!0});this.fields.prioritize_first_last=this.fieldsets.general.add({fieldLabel:"",labelSeparator:"",boxLabel:_("Prioritize First/Last"),id:"prioritize_first_last"});this.fields.super_seeding=this.fieldsets.general.add({fieldLabel:"",labelSeparator:"",boxLabel:_("Super Seeding"),id:"super_seeding"});for(var a in this.fields)this.optionsManager.bind(a,this.fields[a]);this.buttonPanel=this.rightColumn.add({layout:"hbox",
+xtype:"panel",border:!1});this.buttonPanel.add({id:"edit_trackers",xtype:"button",text:_("Edit Trackers"),cls:"x-btn-text-icon",iconCls:"x-deluge-edit-trackers",border:!1,width:100,handler:this.onEditTrackers,scope:this});this.buttonPanel.add({id:"apply",xtype:"button",text:_("Apply"),style:"margin-left: 10px;",border:!1,width:100,handler:this.onApply,scope:this})},onRender:function(a,b){Deluge.details.OptionsTab.superclass.onRender.call(this,a,b);this.layout=new Ext.layout.ColumnLayout;this.layout.setContainer(this);
+this.doLayout()},clear:function(){null!=this.torrentId&&(this.torrentId=null,this.optionsManager.changeId(null))},reset:function(){this.torrentId&&this.optionsManager.reset()},update:function(a){this.torrentId&&!a&&this.clear();a&&(this.torrentId!=a&&(this.torrentId=a,this.optionsManager.changeId(a)),deluge.client.web.get_torrent_status(a,Deluge.Keys.Options,{success:this.onRequestComplete,scope:this}))},onApply:function(){var a=this.optionsManager.getDirty();deluge.client.core.set_torrent_options([this.torrentId],
+a,{success:function(){this.optionsManager.commit()},scope:this})},onEditTrackers:function(){deluge.editTrackers.show()},onMoveCompletedChecked:function(a,b){this.fields.move_completed_path.setDisabled(!b);b&&this.fields.move_completed_path.focus()},onStopRatioChecked:function(a,b){this.fields.remove_at_ratio.setDisabled(!b);this.fields.stop_ratio.setDisabled(!b)},onRequestComplete:function(a,b){this.fields["private"].setValue(a["private"]);this.fields["private"].setDisabled(!0);delete a["private"];
+a.auto_managed=a.is_auto_managed;a.prioritize_first_last_pieces=a.prioritize_first_last;this.optionsManager.setDefault(a);var c=this.optionsManager.get("stop_at_ratio");this.fields.remove_at_ratio.setDisabled(!c);this.fields.stop_ratio.setDisabled(!c);this.fields.move_completed_path.setDisabled(!this.optionsManager.get("move_completed"))}});
+(function(){function a(a){return!a.replace(" ","").replace(" ","")?"":String.format('<img alt="{1}" title="{1}" src="{0}flag/{1}" />',deluge.config.base,a)}function b(a,b,c){b=1024==c.data.seed?"x-deluge-seed":"x-deluge-peer";c=a.split(":");2<c.length&&(a=c.pop(),a="["+c.join(":")+"]:"+a);return String.format('<div class="{0}">{1}</div>',b,a)}function c(a){a=(100*a).toFixed(0);return Deluge.progressBar(a,this.width-8,a+"%")}Deluge.details.PeersTab=Ext.extend(Ext.grid.GridPanel,{peers:{},constructor:function(d){d=
+Ext.apply({title:_("Peers"),cls:"x-deluge-peers",store:new Ext.data.Store({reader:new Ext.data.JsonReader({idProperty:"ip",root:"peers"},Deluge.data.Peer)}),columns:[{header:"&nbsp;",width:30,sortable:!0,renderer:a,dataIndex:"country"},{header:_("Address"),width:125,sortable:!0,renderer:b,dataIndex:"ip"},{header:_("Client"),width:125,sortable:!0,renderer:"htmlEncode",dataIndex:"client"},{header:_("Progress"),width:150,sortable:!0,renderer:c,dataIndex:"progress"},{header:_("Down Speed"),width:100,
+sortable:!0,renderer:fspeed,dataIndex:"down_speed"},{header:_("Up Speed"),width:100,sortable:!0,renderer:fspeed,dataIndex:"up_speed"}],stripeRows:!0,deferredRender:!1,autoScroll:!0},d);Deluge.details.PeersTab.superclass.constructor.call(this,d)},clear:function(){this.getStore().removeAll();this.peers={}},update:function(a){deluge.client.web.get_torrent_status(a,Deluge.Keys.Peers,{success:this.onRequestComplete,scope:this})},onRequestComplete:function(a,b){if(a){var c=this.getStore(),e=[],l={};Ext.each(a.peers,
+function(a){if(this.peers[a.ip]){var b=c.getById(a.ip);b.beginEdit();for(var d in a)b.get(d)!=a[d]&&b.set(d,a[d]);b.endEdit()}else this.peers[a.ip]=1,e.push(new Deluge.data.Peer(a,a.ip));l[a.ip]=1},this);c.add(e);c.each(function(a){l[a.id]||(c.remove(a),delete this.peers[a.id])},this);c.commitChanges();var h=c.getSortState();h&&c.sort(h.field,h.direction)}}})})();Ext.ns("Deluge.details");
+Deluge.details.StatusTab=Ext.extend(Ext.Panel,{title:_("Status"),autoScroll:!0,onRender:function(a,b){Deluge.details.StatusTab.superclass.onRender.call(this,a,b);this.progressBar=this.add({xtype:"progress",cls:"x-deluge-status-progressbar"});this.status=this.add({cls:"x-deluge-status",id:"deluge-details-status",border:!1,width:1E3,listeners:{render:{fn:function(a){a.load({url:deluge.config.base+"render/tab_status.html",text:_("Loading")+"..."});a.getUpdater().on("update",this.onPanelUpdate,this)},
+scope:this}}})},clear:function(){this.progressBar.updateProgress(0," ");for(var a in this.fields)this.fields[a].innerHTML=""},update:function(a){this.fields||this.getFields();deluge.client.web.get_torrent_status(a,Deluge.Keys.Status,{success:this.onRequestComplete,scope:this})},onPanelUpdate:function(a,b){this.fields={};Ext.each(Ext.query("dd",this.status.body.dom),function(a){this.fields[a.className]=a},this)},onRequestComplete:function(a){seeds=-1<a.total_seeds?a.num_seeds+" ("+a.total_seeds+")":
+a.num_seeds;peers=-1<a.total_peers?a.num_peers+" ("+a.total_peers+")":a.num_peers;last_seen_complete=0<a.last_seen_complete?fdate(a.last_seen_complete):"Never";completed_time=0<a.completed_time?fdate(a.completed_time):"";var b={downloaded:fsize(a.total_done,!0),uploaded:fsize(a.total_uploaded,!0),share:-1==a.ratio?"&infin;":a.ratio.toFixed(3),announce:ftime(a.next_announce),tracker_status:a.tracker_status,downspeed:a.download_payload_rate?fspeed(a.download_payload_rate):"0.0 KiB/s",upspeed:a.upload_payload_rate?
+fspeed(a.upload_payload_rate):"0.0 KiB/s",eta:0>a.eta?"&infin;":ftime(a.eta),pieces:a.num_pieces+" ("+fsize(a.piece_length)+")",seeds:seeds,peers:peers,avail:a.distributed_copies.toFixed(3),active_time:ftime(a.active_time),seeding_time:ftime(a.seeding_time),seed_rank:a.seed_rank,time_added:fdate(a.time_added),last_seen_complete:last_seen_complete,completed_time:completed_time,time_since_transfer:ftime(a.time_since_transfer)};b.auto_managed=_(a.is_auto_managed?"True":"False");var c={Error:_("Error"),
+Warning:_("Warning"),"Announce OK":_("Announce OK"),"Announce Sent":_("Announce Sent")},d;for(d in c)if(-1!=b.tracker_status.indexOf(d)){b.tracker_status=b.tracker_status.replace(d,c[d]);break}b.downloaded+=" ("+(a.total_payload_download?fsize(a.total_payload_download):"0.0 KiB")+")";b.uploaded+=" ("+(a.total_payload_upload?fsize(a.total_payload_upload):"0.0 KiB")+")";for(var f in this.fields)this.fields[f].innerHTML=b[f];b=a.state+" "+a.progress.toFixed(2)+"%";this.progressBar.updateProgress(a.progress/
+100,b)}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Bandwidth=Ext.extend(Ext.form.FormPanel,{constructor:function(a){a=Ext.apply({border:!1,title:_("Bandwidth"),header:!1,layout:"form",labelWidth:10},a);Deluge.preferences.Bandwidth.superclass.constructor.call(this,a)},initComponent:function(){Deluge.preferences.Bandwidth.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Global Bandwidth Usage"),labelWidth:200,defaultType:"spinnerfield",defaults:{minValue:-1,
+maxValue:99999},style:"margin-bottom: 0px; padding-bottom: 0px;",autoHeight:!0});a.bind("max_connections_global",b.add({name:"max_connections_global",fieldLabel:_("Maximum Connections:"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}));a.bind("max_upload_slots_global",b.add({name:"max_upload_slots_global",fieldLabel:_("Maximum Upload Slots"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}));a.bind("max_download_speed",b.add({name:"max_download_speed",fieldLabel:_("Maximum Download Speed (KiB/s):"),
+labelSeparator:"",width:80,value:-1,decimalPrecision:1}));a.bind("max_upload_speed",b.add({name:"max_upload_speed",fieldLabel:_("Maximum Upload Speed (KiB/s):"),labelSeparator:"",width:80,value:-1,decimalPrecision:1}));a.bind("max_half_open_connections",b.add({name:"max_half_open_connections",fieldLabel:_("Maximum Half-Open Connections:"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}));a.bind("max_connections_per_second",b.add({name:"max_connections_per_second",fieldLabel:_("Maximum Connection Attempts per Second:"),
+labelSeparator:"",width:80,value:-1,decimalPrecision:0}));b=this.add({xtype:"fieldset",border:!1,title:"",defaultType:"checkbox",style:"padding-top: 0px; padding-bottom: 5px; margin-top: 0px; margin-bottom: 0px;",autoHeight:!0});a.bind("ignore_limits_on_local_network",b.add({name:"ignore_limits_on_local_network",height:22,fieldLabel:"",labelSeparator:"",boxLabel:_("Ignore limits on local network")}));a.bind("rate_limit_ip_overhead",b.add({name:"rate_limit_ip_overhead",height:22,fieldLabel:"",labelSeparator:"",
+boxLabel:_("Rate limit IP overhead")}));b=this.add({xtype:"fieldset",border:!1,title:_("Per Torrent Bandwidth Usage"),style:"margin-bottom: 0px; padding-bottom: 0px;",defaultType:"spinnerfield",labelWidth:200,defaults:{minValue:-1,maxValue:99999},autoHeight:!0});a.bind("max_connections_per_torrent",b.add({name:"max_connections_per_torrent",fieldLabel:_("Maximum Connections:"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}));a.bind("max_upload_slots_per_torrent",b.add({name:"max_upload_slots_per_torrent",
+fieldLabel:_("Maximum Upload Slots:"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}));a.bind("max_download_speed_per_torrent",b.add({name:"max_download_speed_per_torrent",fieldLabel:_("Maximum Download Speed (KiB/s):"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}));a.bind("max_upload_speed_per_torrent",b.add({name:"max_upload_speed_per_torrent",fieldLabel:_("Maximum Upload Speed (KiB/s):"),labelSeparator:"",width:80,value:-1,decimalPrecision:0}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Cache=Ext.extend(Ext.form.FormPanel,{border:!1,title:_("Cache"),header:!1,layout:"form",initComponent:function(){Deluge.preferences.Cache.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Settings"),autoHeight:!0,labelWidth:180,defaultType:"spinnerfield",defaults:{decimalPrecision:0,minValue:-1,maxValue:999999}});a.bind("cache_size",b.add({fieldLabel:_("Cache Size (16 KiB Blocks):"),labelSeparator:"",
+name:"cache_size",width:60,value:512}));a.bind("cache_expiry",b.add({fieldLabel:_("Cache Expiry (seconds):"),labelSeparator:"",name:"cache_expiry",width:60,value:60}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Daemon=Ext.extend(Ext.form.FormPanel,{border:!1,title:_("Daemon"),header:!1,layout:"form",initComponent:function(){Deluge.preferences.Daemon.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Port"),autoHeight:!0,defaultType:"spinnerfield"});a.bind("daemon_port",b.add({fieldLabel:_("Daemon port:"),labelSeparator:"",name:"daemon_port",value:58846,decimalPrecision:0,minValue:-1,maxValue:99999}));b=this.add({xtype:"fieldset",
+border:!1,title:_("Connections"),autoHeight:!0,labelWidth:1,defaultType:"checkbox"});a.bind("allow_remote",b.add({fieldLabel:"",height:22,labelSeparator:"",boxLabel:_("Allow Remote Connections"),name:"allow_remote"}));b=this.add({xtype:"fieldset",border:!1,title:_("Other"),autoHeight:!0,labelWidth:1,defaultType:"checkbox"});a.bind("new_release_check",b.add({fieldLabel:"",labelSeparator:"",height:40,boxLabel:_("Periodically check the website for new releases"),id:"new_release_check"}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Downloads=Ext.extend(Ext.FormPanel,{constructor:function(a){a=Ext.apply({border:!1,title:_("Downloads"),header:!1,layout:"form",autoHeight:!0,width:320},a);Deluge.preferences.Downloads.superclass.constructor.call(this,a)},initComponent:function(){Deluge.preferences.Downloads.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Folders"),labelWidth:150,defaultType:"togglefield",autoHeight:!0,labelAlign:"top",
+width:300,style:"margin-bottom: 5px; padding-bottom: 5px;"});a.bind("download_location",b.add({xtype:"textfield",name:"download_location",fieldLabel:_("Download to:"),labelSeparator:"",width:280}));var c=b.add({name:"move_completed_path",fieldLabel:_("Move completed to:"),labelSeparator:"",width:280});a.bind("move_completed",c.toggle);a.bind("move_completed_path",c.input);c=b.add({name:"torrentfiles_location",fieldLabel:_("Copy of .torrent files to:"),labelSeparator:"",width:280});a.bind("copy_torrent_file",
+c.toggle);a.bind("torrentfiles_location",c.input);b=this.add({xtype:"fieldset",border:!1,title:_("Options"),autoHeight:!0,labelWidth:1,defaultType:"checkbox",style:"margin-bottom: 0; padding-bottom: 0;",width:280});a.bind("prioritize_first_last_pieces",b.add({name:"prioritize_first_last_pieces",labelSeparator:"",height:22,boxLabel:_("Prioritize first and last pieces of torrent")}));a.bind("sequential_download",b.add({name:"sequential_download",labelSeparator:"",height:22,boxLabel:_("Sequential download")}));
+a.bind("add_paused",b.add({name:"add_paused",labelSeparator:"",height:22,boxLabel:_("Add torrents in Paused state")}));a.bind("pre_allocate_storage",b.add({name:"pre_allocate_storage",labelSeparator:"",height:22,boxLabel:_("Pre-allocate disk space")}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Encryption=Ext.extend(Ext.form.FormPanel,{border:!1,title:_("Encryption"),header:!1,initComponent:function(){Deluge.preferences.Encryption.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Settings"),header:!1,autoHeight:!0,defaultType:"combo",width:300});a.bind("enc_in_policy",b.add({fieldLabel:_("Incoming:"),labelSeparator:"",mode:"local",width:150,store:new Ext.data.ArrayStore({fields:["id","text"],
+data:[[0,_("Forced")],[1,_("Enabled")],[2,_("Disabled")]]}),editable:!1,triggerAction:"all",valueField:"id",displayField:"text"}));a.bind("enc_out_policy",b.add({fieldLabel:_("Outgoing:"),labelSeparator:"",mode:"local",width:150,store:new Ext.data.SimpleStore({fields:["id","text"],data:[[0,_("Forced")],[1,_("Enabled")],[2,_("Disabled")]]}),editable:!1,triggerAction:"all",valueField:"id",displayField:"text"}));a.bind("enc_level",b.add({fieldLabel:_("Level:"),labelSeparator:"",mode:"local",width:150,
+store:new Ext.data.SimpleStore({fields:["id","text"],data:[[0,_("Handshake")],[1,_("Full Stream")],[2,_("Either")]]}),editable:!1,triggerAction:"all",valueField:"id",displayField:"text"}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.InstallPluginWindow=Ext.extend(Ext.Window,{title:_("Install Plugin"),layout:"fit",height:115,width:350,constrainHeader:!0,bodyStyle:"padding: 10px 5px;",buttonAlign:"center",closeAction:"hide",iconCls:"x-deluge-install-plugin",modal:!0,plain:!0,initComponent:function(){Deluge.preferences.InstallPluginWindow.superclass.initComponent.call(this);this.addButton(_("Install"),this.onInstall,this);this.form=this.add({xtype:"form",baseCls:"x-plain",labelWidth:70,autoHeight:!0,fileUpload:!0,
+items:[{xtype:"fileuploadfield",width:240,emptyText:_("Select an egg"),fieldLabel:_("Plugin Egg"),name:"file",buttonCfg:{text:_("Browse...")}}]})},onInstall:function(a,b){this.form.getForm().submit({url:deluge.config.base+"upload",waitMsg:_("Uploading your plugin..."),success:this.onUploadSuccess,scope:this})},onUploadPlugin:function(a,b,c,d){this.fireEvent("pluginadded")},onUploadSuccess:function(a,b){this.hide();if(b.result.success){var c=this.form.getForm().getFieldValues().file,c=c.split("\\").slice(-1)[0],
+d=b.result.files[0];this.form.getForm().setValues({file:""});deluge.client.web.upload_plugin(c,d,{success:this.onUploadPlugin,scope:this,filename:c})}}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Interface=Ext.extend(Ext.form.FormPanel,{border:!1,title:_("Interface"),header:!1,layout:"form",initComponent:function(){Deluge.preferences.Interface.superclass.initComponent.call(this);var a=this.optionsManager=new Deluge.OptionsManager;this.on("show",this.onPageShow,this);var b=this.add({xtype:"fieldset",border:!1,title:_("Interface"),style:"margin-bottom: 0px; padding-bottom: 5px; padding-top: 5px",autoHeight:!0,labelWidth:1,defaultType:"checkbox",defaults:{height:17,fieldLabel:"",
+labelSeparator:""}});a.bind("show_session_speed",b.add({name:"show_session_speed",boxLabel:_("Show session speed in titlebar")}));a.bind("sidebar_show_zero",b.add({name:"sidebar_show_zero",boxLabel:_("Show filters with zero torrents")}));a.bind("sidebar_multiple_filters",b.add({name:"sidebar_multiple_filters",boxLabel:_("Allow the use of multiple filters at once")}));b=this.add({xtype:"fieldset",border:!1,title:_("Language"),style:"margin-bottom: 0px; padding-bottom: 5px; padding-top: 5px",autoHeight:!0,
+labelWidth:1,defaultType:"checkbox"});this.language=a.bind("language",b.add({xtype:"combo",labelSeparator:"",name:"language",mode:"local",width:200,store:new Ext.data.ArrayStore({fields:["id","text"]}),editable:!1,triggerAction:"all",valueField:"id",displayField:"text"}));b=this.add({xtype:"fieldset",border:!1,title:_("WebUI Password"),style:"margin-bottom: 0px; padding-bottom: 5px; padding-top: 5px",autoHeight:!0,labelWidth:100,defaultType:"textfield",defaults:{width:100,inputType:"password",labelStyle:"padding-left: 5px",
+height:20,labelSeparator:""}});this.oldPassword=b.add({name:"old_password",fieldLabel:_("Old:")});this.newPassword=b.add({name:"new_password",fieldLabel:_("New:")});this.confirmPassword=b.add({name:"confirm_password",fieldLabel:_("Confirm:")});b=this.add({xtype:"fieldset",border:!1,title:_("Server"),style:"padding-top: 5px; margin-bottom: 0px; padding-bottom: 5px",autoHeight:!0,labelWidth:100,defaultType:"spinnerfield",defaults:{labelSeparator:"",labelStyle:"padding-left: 5px",height:20,width:80}});
+a.bind("session_timeout",b.add({name:"session_timeout",fieldLabel:_("Session Timeout:"),decimalPrecision:0,minValue:-1,maxValue:99999}));a.bind("port",b.add({name:"port",fieldLabel:_("Port:"),decimalPrecision:0,minValue:1,maxValue:65535}));this.httpsField=a.bind("https",b.add({xtype:"checkbox",name:"https",hideLabel:!0,width:300,style:"margin-left: 5px",boxLabel:_("Enable SSL (paths relative to Deluge config folder)")}));this.httpsField.on("check",this.onSSLCheck,this);this.pkeyField=a.bind("pkey",
+b.add({xtype:"textfield",disabled:!0,name:"pkey",width:180,fieldLabel:_("Private Key:")}));this.certField=a.bind("cert",b.add({xtype:"textfield",disabled:!0,name:"cert",width:180,fieldLabel:_("Certificate:")}))},onApply:function(){var a=this.optionsManager.getDirty();if(!Ext.isObjectEmpty(a)){deluge.client.web.set_config(a,{success:this.onSetConfig,scope:this});for(var b in deluge.config)deluge.config[b]=this.optionsManager.get(b);"language"in a&&Ext.Msg.show({title:_("WebUI Language Changed"),msg:_("Do you want to refresh the page now to use the new language?"),
+buttons:{yes:_("Refresh"),no:_("Close")},multiline:!1,fn:function(a){"yes"===a&&location.reload()},icon:Ext.MessageBox.QUESTION})}if(this.oldPassword.getValue()||this.newPassword.getValue())this.onPasswordChange()},onOk:function(){this.onApply()},onGotConfig:function(a){this.optionsManager.set(a)},onGotLanguages:function(a,b,c,d){a.unshift(["",_("System Default")]);this.language.store.loadData(a);this.language.setValue(this.optionsManager.get("language"))},onPasswordChange:function(){var a=this.newPassword.getValue();
+if(a!=this.confirmPassword.getValue())Ext.MessageBox.show({title:_("Invalid Password"),msg:_("Your passwords don't match!"),buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"});else{var b=this.oldPassword.getValue();deluge.client.auth.change_password(b,a,{success:function(a){a?(Ext.MessageBox.show({title:_("Change Successful"),msg:_("Your password was successfully changed!"),buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.INFO,iconCls:"x-deluge-icon-info"}),
+this.oldPassword.setValue(""),this.newPassword.setValue(""),this.confirmPassword.setValue("")):(Ext.MessageBox.show({title:_("Password"),msg:_("Your old password was incorrect!"),buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"}),this.oldPassword.setValue(""))},scope:this})}},onSetConfig:function(){this.optionsManager.commit()},onPageShow:function(){deluge.client.web.get_config({success:this.onGotConfig,scope:this});deluge.client.webutils.get_languages({success:this.onGotLanguages,
+scope:this})},onSSLCheck:function(a,b){this.pkeyField.setDisabled(!b);this.certField.setDisabled(!b)}});Ext.namespace("Deluge.preferences");Ext.apply(Ext.form.VTypes,{IPAddress:function(a){return/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(a)},IPAddressText:"Must be a numeric IP address",IPAddressMask:/[\d\.]/i});
+Deluge.preferences.Network=Ext.extend(Ext.form.FormPanel,{border:!1,layout:"form",title:_("Network"),header:!1,initComponent:function(){Deluge.preferences.Network.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Incoming Address"),style:"margin-bottom: 5px; padding-bottom: 0px;",autoHeight:!0,labelWidth:1,defaultType:"textfield"});a.bind("listen_interface",b.add({name:"listen_interface",fieldLabel:"",labelSeparator:"",
+width:200,vtype:"IPAddress"}));var b=this.add({xtype:"fieldset",border:!1,title:_("Incoming Port"),style:"margin-bottom: 5px; padding-bottom: 0px;",autoHeight:!0,labelWidth:1,defaultType:"checkbox"});a.bind("random_port",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("Use Random Port"),name:"random_port",height:22,listeners:{check:{fn:function(a,b){this.listenPort.setDisabled(b)},scope:this}}}));this.listenPort=b.add({xtype:"spinnerfield",name:"listen_port",fieldLabel:"",labelSeparator:"",width:75,
+strategy:{xtype:"number",decimalPrecision:0,minValue:0,maxValue:65535}});a.bind("listen_ports",this.listenPort);b=this.add({xtype:"fieldset",border:!1,title:_("Outgoing Interface"),style:"margin-bottom: 5px; padding-bottom: 0px;",autoHeight:!0,labelWidth:1,defaultType:"textfield"});a.bind("outgoing_interface",b.add({name:"outgoing_interface",fieldLabel:"",labelSeparator:"",width:40}));b=this.add({xtype:"fieldset",border:!1,title:_("Outgoing Ports"),style:"margin-bottom: 5px; padding-bottom: 0px;",
+autoHeight:!0,labelWidth:1,defaultType:"checkbox"});a.bind("random_outgoing_ports",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("Use Random Ports"),name:"random_outgoing_ports",height:22,listeners:{check:{fn:function(a,b){this.outgoingPorts.setDisabled(b)},scope:this}}}));this.outgoingPorts=b.add({xtype:"spinnergroup",name:"outgoing_ports",fieldLabel:"",labelSeparator:"",colCfg:{labelWidth:40,style:"margin-right: 10px;"},items:[{fieldLabel:_("From:"),labelSeparator:"",strategy:{xtype:"number",
+decimalPrecision:0,minValue:0,maxValue:65535}},{fieldLabel:_("To:"),labelSeparator:"",strategy:{xtype:"number",decimalPrecision:0,minValue:0,maxValue:65535}}]});a.bind("outgoing_ports",this.outgoingPorts);b=this.add({xtype:"fieldset",border:!1,title:_("Network Extras"),autoHeight:!0,layout:"table",layoutConfig:{columns:3},defaultType:"checkbox"});a.bind("upnp",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("UPnP"),name:"upnp"}));a.bind("natpmp",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("NAT-PMP"),
+ctCls:"x-deluge-indent-checkbox",name:"natpmp"}));a.bind("utpex",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("Peer Exchange"),ctCls:"x-deluge-indent-checkbox",name:"utpex"}));a.bind("lsd",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("LSD"),name:"lsd"}));a.bind("dht",b.add({fieldLabel:"",labelSeparator:"",boxLabel:_("DHT"),ctCls:"x-deluge-indent-checkbox",name:"dht"}));b=this.add({xtype:"fieldset",border:!1,title:_("Type Of Service"),style:"margin-bottom: 5px; padding-bottom: 0px;",bodyStyle:"margin: 0px; padding: 0px",
+autoHeight:!0,defaultType:"textfield"});a.bind("peer_tos",b.add({name:"peer_tos",fieldLabel:_("Peer TOS Byte:"),labelSeparator:"",width:40}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Other=Ext.extend(Ext.form.FormPanel,{constructor:function(a){a=Ext.apply({border:!1,title:_("Other"),header:!1,layout:"form"},a);Deluge.preferences.Other.superclass.constructor.call(this,a)},initComponent:function(){Deluge.preferences.Other.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("Updates"),autoHeight:!0,labelWidth:1,defaultType:"checkbox"});a.bind("new_release_check",b.add({fieldLabel:"",labelSeparator:"",
+height:22,name:"new_release_check",boxLabel:_("Be alerted about new releases")}));b=this.add({xtype:"fieldset",border:!1,title:_("System Information"),autoHeight:!0,labelWidth:1,defaultType:"checkbox"});b.add({xtype:"panel",border:!1,bodyCfg:{html:_("Help us improve Deluge by sending us your Python version, PyGTK version, OS and processor types. Absolutely no other information is sent.")}});a.bind("send_info",b.add({fieldLabel:"",labelSeparator:"",height:22,boxLabel:_("Yes, please send anonymous statistics"),
+name:"send_info"}));b=this.add({xtype:"fieldset",border:!1,title:_("GeoIP Database"),autoHeight:!0,labelWidth:80,defaultType:"textfield"});a.bind("geoip_db_location",b.add({name:"geoip_db_location",fieldLabel:_("Path:"),labelSeparator:"",width:200}))}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Plugins=Ext.extend(Ext.Panel,{layout:"border",title:_("Plugins"),header:!1,border:!1,cls:"x-deluge-plugins",pluginTemplate:new Ext.Template('<dl class="singleline"><dt>'+_("Author:")+"</dt><dd>{author}</dd><dt>"+_("Version:")+"</dt><dd>{version}</dd><dt>"+_("Author Email:")+"</dt><dd>{email}</dd><dt>"+_("Homepage:")+"</dt><dd>{homepage}</dd><dt>"+_("Details:")+'</dt><dd style="white-space:normal">{details}</dd></dl>'),initComponent:function(){Deluge.preferences.Plugins.superclass.initComponent.call(this);
+this.defaultValues={version:"",email:"",homepage:"",details:""};this.pluginTemplate.compile();this.list=this.add({xtype:"listview",store:new Ext.data.ArrayStore({fields:[{name:"enabled",mapping:0},{name:"plugin",mapping:1,sortType:"asUCString"}]}),columns:[{id:"enabled",header:_("Enabled"),width:0.2,sortable:!0,tpl:new Ext.XTemplate("{enabled:this.getCheckbox}",{getCheckbox:function(a){return'<div class="x-grid3-check-col'+(a?"-on":"")+'" rel="chkbox"> </div>'}}),dataIndex:"enabled"},{id:"plugin",
+header:_("Plugin"),width:0.8,sortable:!0,dataIndex:"plugin"}],singleSelect:!0,autoExpandColumn:"plugin",listeners:{selectionchange:{fn:this.onPluginSelect,scope:this}}});this.panel=this.add({region:"center",autoScroll:!0,items:[this.list],bbar:new Ext.Toolbar({items:[{cls:"x-btn-text-icon",iconCls:"x-deluge-install-plugin",text:_("Install"),handler:this.onInstallPluginWindow,scope:this},"->",{cls:"x-btn-text-icon",text:_("Find More"),iconCls:"x-deluge-find-more",handler:this.onFindMorePlugins,scope:this}]})});
+this.pluginInfo=this.add({xtype:"panel",border:!1,height:100,region:"south",padding:"5",autoScroll:!0,bodyCfg:{style:"white-space: nowrap"}});this.pluginInfo.on("render",this.onPluginInfoRender,this);this.list.on("click",this.onNodeClick,this);deluge.preferences.on("show",this.onPreferencesShow,this);deluge.events.on("PluginDisabledEvent",this.onPluginDisabled,this);deluge.events.on("PluginEnabledEvent",this.onPluginEnabled,this)},disablePlugin:function(a){deluge.client.core.disable_plugin(a)},enablePlugin:function(a){deluge.client.core.enable_plugin(a)},
+setInfo:function(a){this.pluginInfo.rendered&&(this.pluginInfo.body.dom.innerHTML=this.pluginTemplate.apply(a||this.defaultValues))},updatePlugins:function(){var a=function(a){this.enabledPlugins=a;this.onGotPlugins()};deluge.client.core.get_available_plugins({success:function(b){this.availablePlugins=b.sort(function(a,b){return a.toLowerCase().localeCompare(b.toLowerCase())});deluge.client.core.get_enabled_plugins({success:a,scope:this})},scope:this})},updatePluginsGrid:function(){var a=[];Ext.each(this.availablePlugins,
+function(b){-1<this.enabledPlugins.indexOf(b)?a.push([!0,b]):a.push([!1,b])},this);this.list.getStore().loadData(a)},onNodeClick:function(a,b,c,d){"chkbox"==(new Ext.Element(d.target)).getAttribute("rel")&&(a=a.getStore().getAt(b),"WebUi"!=a.get("plugin")&&(a.set("enabled",!a.get("enabled")),a.commit(),a.get("enabled")?this.enablePlugin(a.get("plugin")):this.disablePlugin(a.get("plugin"))))},onFindMorePlugins:function(){window.open("http://dev.deluge-torrent.org/wiki/Plugins")},onGotPlugins:function(){this.setInfo();
+this.updatePluginsGrid()},onGotPluginInfo:function(a){this.setInfo({author:a.Author,version:a.Version,email:a["Author-email"],homepage:a["Home-page"],details:a.Description});delete a},onInstallPluginWindow:function(){this.installWindow||(this.installWindow=new Deluge.preferences.InstallPluginWindow,this.installWindow.on("pluginadded",this.onPluginInstall,this));this.installWindow.show()},onPluginEnabled:function(a){a=this.list.getStore().find("plugin",a);-1!=a&&(a=this.list.getStore().getAt(a),a.set("enabled",
+!0),a.commit())},onPluginDisabled:function(a){a=this.list.getStore().find("plugin",a);-1!=a&&(a=this.list.getStore().getAt(a),a.set("enabled",!1),a.commit())},onPluginInstall:function(){this.updatePlugins()},onPluginSelect:function(a,b){if(0!=b.length){var c=a.getRecords(b)[0];deluge.client.web.get_plugin_info(c.get("plugin"),{success:this.onGotPluginInfo,scope:this})}},onPreferencesShow:function(){this.updatePlugins()},onPluginInfoRender:function(a,b){this.setInfo()}});Ext.namespace("Deluge.preferences");
+PreferencesRecord=Ext.data.Record.create([{name:"name",type:"string"}]);
+Deluge.preferences.PreferencesWindow=Ext.extend(Ext.Window,{currentPage:null,title:_("Preferences"),layout:"border",width:485,height:500,border:!1,constrainHeader:!0,buttonAlign:"right",closeAction:"hide",closable:!0,iconCls:"x-deluge-preferences",plain:!0,resizable:!1,pages:{},initComponent:function(){Deluge.preferences.PreferencesWindow.superclass.initComponent.call(this);this.list=new Ext.list.ListView({store:new Ext.data.Store,columns:[{id:"name",dataIndex:"name"}],singleSelect:!0,listeners:{selectionchange:{fn:this.onPageSelect,
+scope:this}},hideHeaders:!0,autoExpandColumn:"name",deferredRender:!1,autoScroll:!0,collapsible:!0});this.add({region:"west",items:[this.list],width:120,margins:"0 5 0 0",cmargins:"0 5 0 0"});this.configPanel=this.add({type:"container",autoDestroy:!1,region:"center",layout:"card",layoutConfig:{deferredRender:!0},autoScroll:!0,width:300});this.addButton(_("Close"),this.onClose,this);this.addButton(_("Apply"),this.onApply,this);this.addButton(_("OK"),this.onOk,this);this.optionsManager=new Deluge.OptionsManager;
+this.on("afterrender",this.onAfterRender,this);this.on("show",this.onShow,this);this.initPages()},initPages:function(){deluge.preferences=this;this.addPage(new Deluge.preferences.Downloads);this.addPage(new Deluge.preferences.Network);this.addPage(new Deluge.preferences.Encryption);this.addPage(new Deluge.preferences.Bandwidth);this.addPage(new Deluge.preferences.Interface);this.addPage(new Deluge.preferences.Other);this.addPage(new Deluge.preferences.Daemon);this.addPage(new Deluge.preferences.Queue);
+this.addPage(new Deluge.preferences.Proxy);this.addPage(new Deluge.preferences.Cache);this.addPage(new Deluge.preferences.Plugins)},onApply:function(a){a=this.optionsManager.getDirty();Ext.isObjectEmpty(a)||("listen_ports"in a&&(a.listen_ports=[a.listen_ports,a.listen_ports]),deluge.client.core.set_config(a,{success:this.onSetConfig,scope:this}));for(var b in this.pages)if(this.pages[b].onApply)this.pages[b].onApply()},getOptionsManager:function(){return this.optionsManager},addPage:function(a){var b=
+this.list.getStore(),c=a.title;b.add([new PreferencesRecord({name:c})]);a.bodyStyle="padding: 5px";a.preferences=this;this.pages[c]=this.configPanel.add(a);this.pages[c].index=-1;return this.pages[c]},removePage:function(a){var b=a.title,c=this.list.getStore();c.removeAt(c.find("name",b));this.configPanel.remove(a);delete this.pages[a.title]},selectPage:function(a){0>this.pages[a].index&&(this.pages[a].index=this.configPanel.items.indexOf(this.pages[a]));this.list.select(this.pages[a].index)},doSelectPage:function(a){0>
+this.pages[a].index&&(this.pages[a].index=this.configPanel.items.indexOf(this.pages[a]));this.configPanel.getLayout().setActiveItem(this.pages[a].index);this.currentPage=a},onGotConfig:function(a){this.getOptionsManager().set(a)},onPageSelect:function(a,b){var c=a.getRecord(b[0]);this.doSelectPage(c.get("name"))},onSetConfig:function(){this.getOptionsManager().commit()},onAfterRender:function(){this.list.getSelectionCount()||this.list.select(0);this.configPanel.getLayout().setActiveItem(0)},onShow:function(){deluge.client.core&&
+deluge.client.core.get_config({success:this.onGotConfig,scope:this})},onClose:function(){this.hide()},onOk:function(){var a=this.optionsManager.getDirty();Ext.isObjectEmpty(a)||deluge.client.core.set_config(a,{success:this.onSetConfig,scope:this});for(var b in this.pages)if(this.pages[b].onOk)this.pages[b].onOk();this.hide()}});Ext.ns("Deluge.preferences");
+Deluge.preferences.ProxyField=Ext.extend(Ext.form.FieldSet,{border:!1,autoHeight:!0,labelWidth:70,initComponent:function(){Deluge.preferences.ProxyField.superclass.initComponent.call(this);this.proxyType=this.add({xtype:"combo",fieldLabel:_("Type:"),labelSeparator:"",name:"proxytype",mode:"local",width:150,store:new Ext.data.ArrayStore({fields:["id","text"],data:[[0,_("None")],[1,_("Socks4")],[2,_("Socks5")],[3,_("Socks5 Auth")],[4,_("HTTP")],[5,_("HTTP Auth")],[6,_("I2P")]]}),editable:!1,triggerAction:"all",
+valueField:"id",displayField:"text"});this.proxyType.on("change",this.onFieldChange,this);this.proxyType.on("select",this.onTypeSelect,this);this.hostname=this.add({xtype:"textfield",name:"hostname",fieldLabel:_("Host:"),labelSeparator:"",width:220});this.hostname.on("change",this.onFieldChange,this);this.port=this.add({xtype:"spinnerfield",name:"port",fieldLabel:_("Port:"),labelSeparator:"",width:80,decimalPrecision:0,minValue:0,maxValue:65535});this.port.on("change",this.onFieldChange,this);this.username=
+this.add({xtype:"textfield",name:"username",fieldLabel:_("Username:"),labelSeparator:"",width:220});this.username.on("change",this.onFieldChange,this);this.password=this.add({xtype:"textfield",name:"password",fieldLabel:_("Password:"),labelSeparator:"",inputType:"password",width:220});this.password.on("change",this.onFieldChange,this);this.proxy_host_resolve=this.add({xtype:"checkbox",name:"proxy_host_resolve",fieldLabel:"",boxLabel:_("Proxy Hostnames"),width:220});this.proxy_host_resolve.on("change",
+this.onFieldChange,this);this.proxy_peer_conn=this.add({xtype:"checkbox",name:"proxy_peer_conn",fieldLabel:"",boxLabel:_("Proxy Peers"),width:220});this.proxy_peer_conn.on("change",this.onFieldChange,this);this.proxy_tracker_conn=this.add({xtype:"checkbox",name:"proxy_tracker_conn",fieldLabel:"",boxLabel:_("Proxy Trackers"),width:220});this.proxy_tracker_conn.on("change",this.onFieldChange,this);var a=this.add({xtype:"fieldset",border:!1,title:_("Force Proxy"),autoHeight:!0,labelWidth:1,defaultType:"checkbox",
+style:"padding-left: 0px; margin-top: 10px"});this.force_proxy=a.add({fieldLabel:"",labelSeparator:"",height:20,name:"force_proxy",boxLabel:_("Force Use of Proxy")});this.force_proxy.on("change",this.onFieldChange,this);this.anonymous_mode=a.add({fieldLabel:"",labelSeparator:"",height:20,name:"anonymous_mode",boxLabel:_("Hide Client Identity")});this.anonymous_mode.on("change",this.onFieldChange,this);this.setting=!1},getName:function(){return this.initialConfig.name},getValue:function(){return{type:this.proxyType.getValue(),
+hostname:this.hostname.getValue(),port:Number(this.port.getValue()),username:this.username.getValue(),password:this.password.getValue(),proxy_hostnames:this.proxy_host_resolve.getValue(),proxy_peer_connections:this.proxy_peer_conn.getValue(),proxy_tracker_connections:this.proxy_tracker_conn.getValue(),force_proxy:this.force_proxy.getValue(),anonymous_mode:this.anonymous_mode.getValue()}},setValue:function(a){this.setting=!0;this.proxyType.setValue(a.type);var b=this.proxyType.getStore().find("id",
+a.type),c=this.proxyType.getStore().getAt(b);this.hostname.setValue(a.hostname);this.port.setValue(a.port);this.username.setValue(a.username);this.password.setValue(a.password);this.proxy_host_resolve.setValue(a.proxy_hostnames);this.proxy_peer_conn.setValue(a.proxy_peer_connections);this.proxy_tracker_conn.setValue(a.proxy_tracker_connections);this.force_proxy.setValue(a.force_proxy);this.anonymous_mode.setValue(a.anonymous_mode);this.onTypeSelect(this.type,c,b);this.setting=!1},onFieldChange:function(a,
+b,c){if(!this.setting){b=this.getValue();var d=Ext.apply({},b);d[a.getName()]=c;this.fireEvent("change",this,b,d)}},onTypeSelect:function(a,b,c){a=b.get("id");0<a?(this.hostname.show(),this.port.show(),this.proxy_peer_conn.show(),this.proxy_tracker_conn.show(),1<a&&6>a?this.proxy_host_resolve.show():this.proxy_host_resolve.hide()):(this.hostname.hide(),this.port.hide(),this.proxy_host_resolve.hide(),this.proxy_peer_conn.hide(),this.proxy_tracker_conn.hide());3==a||5==a?(this.username.show(),this.password.show()):
+(this.username.hide(),this.password.hide())}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Proxy=Ext.extend(Ext.form.FormPanel,{constructor:function(a){a=Ext.apply({border:!1,title:_("Proxy"),header:!1,layout:"form",autoScroll:!0},a);Deluge.preferences.Proxy.superclass.constructor.call(this,a)},initComponent:function(){Deluge.preferences.Proxy.superclass.initComponent.call(this);this.proxy=this.add(new Deluge.preferences.ProxyField({title:_("Proxy"),name:"proxy"}));this.proxy.on("change",this.onProxyChange,this);deluge.preferences.getOptionsManager().bind("proxy",this.proxy)},
+getValue:function(){return{proxy:this.proxy.getValue()}},setValue:function(a){for(var b in a)this[b].setValue(a[b])},onProxyChange:function(a,b,c){b=this.getValue();var d=Ext.apply({},b);d[a.getName()]=c;this.fireEvent("change",this,b,d)}});Ext.namespace("Deluge.preferences");
+Deluge.preferences.Queue=Ext.extend(Ext.form.FormPanel,{border:!1,title:_("Queue"),header:!1,layout:"form",initComponent:function(){Deluge.preferences.Queue.superclass.initComponent.call(this);var a=deluge.preferences.getOptionsManager(),b=this.add({xtype:"fieldset",border:!1,title:_("New Torrents"),style:"padding-top: 5px; margin-bottom: 0px;",autoHeight:!0,labelWidth:1,defaultType:"checkbox"});a.bind("queue_new_to_top",b.add({fieldLabel:"",labelSeparator:"",height:22,boxLabel:_("Queue to top"),
+name:"queue_new_to_top"}));b=this.add({xtype:"fieldset",border:!1,title:_("Active Torrents"),autoHeight:!0,labelWidth:150,defaultType:"spinnerfield",style:"padding-top: 5px; margin-bottom: 0px"});a.bind("max_active_limit",b.add({fieldLabel:_("Total:"),labelSeparator:"",name:"max_active_limit",value:8,width:80,decimalPrecision:0,minValue:-1,maxValue:99999}));a.bind("max_active_downloading",b.add({fieldLabel:_("Downloading:"),labelSeparator:"",name:"max_active_downloading",value:3,width:80,decimalPrecision:0,
+minValue:-1,maxValue:99999}));a.bind("max_active_seeding",b.add({fieldLabel:_("Seeding:"),labelSeparator:"",name:"max_active_seeding",value:5,width:80,decimalPrecision:0,minValue:-1,maxValue:99999}));a.bind("dont_count_slow_torrents",b.add({xtype:"checkbox",name:"dont_count_slow_torrents",height:22,hideLabel:!0,boxLabel:_("Ignore slow torrents")}));a.bind("auto_manage_prefer_seeds",b.add({xtype:"checkbox",name:"auto_manage_prefer_seeds",hideLabel:!0,boxLabel:_("Prefer seeding torrents")}));b=this.add({xtype:"fieldset",
+border:!1,title:_("Seeding Rotation"),autoHeight:!0,labelWidth:150,defaultType:"spinnerfield",style:"padding-top: 5px; margin-bottom: 0px"});a.bind("share_ratio_limit",b.add({fieldLabel:_("Share Ratio:"),labelSeparator:"",name:"share_ratio_limit",value:8,width:80,incrementValue:0.1,minValue:-1,maxValue:99999,alternateIncrementValue:1,decimalPrecision:2}));a.bind("seed_time_ratio_limit",b.add({fieldLabel:_("Time Ratio:"),labelSeparator:"",name:"seed_time_ratio_limit",value:3,width:80,incrementValue:0.1,
+minValue:-1,maxValue:99999,alternateIncrementValue:1,decimalPrecision:2}));a.bind("seed_time_limit",b.add({fieldLabel:_("Time (m):"),labelSeparator:"",name:"seed_time_limit",value:5,width:80,decimalPrecision:0,minValue:-1,maxValue:99999}));b=this.add({xtype:"fieldset",border:!1,autoHeight:!0,style:"padding-top: 5px; margin-bottom: 0px",title:_("Share Ratio Reached"),layout:"table",layoutConfig:{columns:2},labelWidth:0,defaultType:"checkbox",defaults:{fieldLabel:"",labelSeparator:""}});this.stopAtRatio=
+b.add({name:"stop_seed_at_ratio",boxLabel:_("Share Ratio:")});this.stopAtRatio.on("check",this.onStopRatioCheck,this);a.bind("stop_seed_at_ratio",this.stopAtRatio);this.stopRatio=b.add({xtype:"spinnerfield",name:"stop_seed_ratio",ctCls:"x-deluge-indent-checkbox",disabled:!0,value:"2.0",width:60,incrementValue:0.1,minValue:-1,maxValue:99999,alternateIncrementValue:1,decimalPrecision:2});a.bind("stop_seed_ratio",this.stopRatio);this.removeAtRatio=b.add({xtype:"radiogroup",columns:1,colspan:2,disabled:!0,
+style:"margin-left: 10px",items:[{boxLabel:_("Pause torrent"),name:"at_ratio",inputValue:!1,checked:!0},{boxLabel:_("Remove torrent"),name:"at_ratio",inputValue:!0}]});a.bind("remove_seed_at_ratio",this.removeAtRatio)},onStopRatioCheck:function(a,b){this.stopRatio.setDisabled(!b);this.removeAtRatio.setDisabled(!b)}});Ext.ns("Deluge");
+Deluge.StatusbarMenu=Ext.extend(Ext.menu.Menu,{initComponent:function(){Deluge.StatusbarMenu.superclass.initComponent.call(this);this.otherWin=new Deluge.OtherLimitWindow(this.initialConfig.otherWin||{});this.items.each(function(a){if("menucheckitem"==a.getXType())if("other"==a.value)a.on("click",this.onOtherClicked,this);else a.on("checkchange",this.onLimitChanged,this)},this)},setValue:function(a){var b=!1;this.value=a=0==a?-1:a;var c=null;this.items.each(function(d){d.setChecked&&(d.suspendEvents(),
+d.value==a?(d.setChecked(!0),b=!0):d.setChecked(!1),d.resumeEvents());"other"==d.value&&(c=d)});b||(c.suspendEvents(),c.setChecked(!0),c.resumeEvents())},onLimitChanged:function(a,b){if(b&&"other"!=a.value){var c={};c[a.group]=a.value;deluge.client.core.set_config(c,{success:function(){deluge.ui.update()}})}},onOtherClicked:function(a,b){this.otherWin.group=a.group;this.otherWin.setValue(this.value);this.otherWin.show()}});Ext.namespace("Deluge");
+Deluge.OptionsManager=Ext.extend(Ext.util.Observable,{constructor:function(a){a=a||{};this.binds={};this.changed={};this.options=a&&a.options||{};this.focused=null;this.addEvents({add:!0,changed:!0,reset:!0});this.on("changed",this.onChange,this);Deluge.OptionsManager.superclass.constructor.call(this)},addOptions:function(a){this.options=Ext.applyIf(this.options,a)},bind:function(a,b){this.binds[a]=this.binds[a]||[];this.binds[a].push(b);b._doption=a;b.on("focus",this.onFieldFocus,this);b.on("blur",
+this.onFieldBlur,this);b.on("change",this.onFieldChange,this);b.on("check",this.onFieldChange,this);b.on("spin",this.onFieldChange,this);return b},commit:function(){this.options=Ext.apply(this.options,this.changed);this.reset()},convertValueType:function(a,b){if(Ext.type(a)!=Ext.type(b))switch(Ext.type(a)){case "string":b=String(b);break;case "number":b=Number(b);break;case "boolean":"string"==Ext.type(b)?(b=b.toLowerCase(),b="true"==b||"1"==b||"on"==b?!0:!1):b=Boolean(b)}return b},get:function(){if(1==
+arguments.length){var a=arguments[0];return this.isDirty(a)?this.changed[a]:this.options[a]}var b={};Ext.each(arguments,function(a){this.has(a)&&(b[a]=this.isDirty(a)?this.changed[a]:this.options[a])},this);return b},getDefault:function(a){return this.options[a]},getDirty:function(){return this.changed},isDirty:function(a){return!Ext.isEmpty(this.changed[a])},has:function(a){return this.options[a]},reset:function(){this.changed={}},set:function(a,b){if(void 0!==a)if("object"==typeof a){var c=a;this.options=
+Ext.apply(this.options,c);for(a in c)this.onChange(a,c[a])}else this.options[a]=b,this.onChange(a,b)},update:function(a,b){if(void 0!==a)if(void 0===b)for(var c in a)this.update(c,a[c]);else{c=this.getDefault(a);b=this.convertValueType(c,b);var d=this.get(a);d!=b&&(c==b?this.isDirty(a)&&delete this.changed[a]:this.changed[a]=b,this.fireEvent("changed",a,b,d))}},onFieldBlur:function(a,b){this.focused==a&&(this.focused=null)},onFieldChange:function(a,b){a.field&&(a=a.field);this.update(a._doption,a.getValue())},
+onFieldFocus:function(a,b){this.focused=a},onChange:function(a,b,c){Ext.isEmpty(this.binds[a])||Ext.each(this.binds[a],function(a){a!=this.focused&&a.setValue(b)},this)}});Ext.namespace("Deluge.about");
+Deluge.about.AboutWindow=Ext.extend(Ext.Window,{id:"AboutWindow",title:_("About Deluge"),height:330,width:270,iconCls:"x-deluge-main-panel",resizable:!1,plain:!0,layout:{type:"vbox",align:"center"},buttonAlign:"center",initComponent:function(){Deluge.about.AboutWindow.superclass.initComponent.call(this);this.addEvents({build_ready:!0});var a=this,b=function(){deluge.client.core.get_libtorrent_version({success:function(b){d+="<br/>"+_("libtorrent:")+" "+b;Ext.getCmp("about_comment").setText(d,!1);
+a.fireEvent("build_ready")}})},c=deluge.version,d=_("A peer-to-peer file sharing program\nutilizing the BitTorrent protocol.").replace("\n","<br/>")+"<br/><br/>"+_("Client:")+" "+c+"<br/>";deluge.client.web.connected({success:function(a){a?deluge.client.daemon.get_version({success:function(a){d+=_("Server:")+" "+a+"<br/>";b()}}):this.fireEvent("build_ready")},failure:function(){this.fireEvent("build_ready")},scope:this});this.add([{xtype:"box",style:"padding-top: 5px",height:80,width:240,cls:"x-deluge-logo",
+hideLabel:!0},{xtype:"label",style:"padding-top: 10px; font-weight: bold; font-size: 16px;",text:_("Deluge")+" "+c},{xtype:"label",id:"about_comment",style:"padding-top: 10px; text-align:center; font-size: 12px;",html:d},{xtype:"label",style:"padding-top: 10px; font-size: 10px;",text:_("Copyright 2007-2018 Deluge Team")},{xtype:"label",style:"padding-top: 5px; font-size: 12px;",html:'<a href="https://deluge-torrent.org" target="_blank">deluge-torrent.org</a>'}]);this.addButton(_("Close"),this.onCloseClick,
+this)},show:function(){this.on("build_ready",function(){Deluge.about.AboutWindow.superclass.show.call(this)})},onCloseClick:function(){this.close()}});Ext.namespace("Deluge");Deluge.About=function(){(new Deluge.about.AboutWindow).show()};Ext.ns("Deluge");
+Deluge.AddConnectionWindow=Ext.extend(Ext.Window,{title:_("Add Connection"),iconCls:"x-deluge-add-window-icon",layout:"fit",width:300,height:195,constrainHeader:!0,bodyStyle:"padding: 10px 5px;",closeAction:"hide",initComponent:function(){Deluge.AddConnectionWindow.superclass.initComponent.call(this);this.addEvents("hostadded");this.addButton(_("Close"),this.hide,this);this.addButton(_("Add"),this.onAddClick,this);this.on("hide",this.onHide,this);this.form=this.add({xtype:"form",defaultType:"textfield",
+baseCls:"x-plain",labelWidth:60,items:[{fieldLabel:_("Host:"),labelSeparator:"",name:"host",anchor:"75%",value:""},{xtype:"spinnerfield",fieldLabel:_("Port:"),labelSeparator:"",name:"port",strategy:{xtype:"number",decimalPrecision:0,minValue:-1,maxValue:65535},value:"58846",anchor:"40%"},{fieldLabel:_("Username:"),labelSeparator:"",name:"username",anchor:"75%",value:""},{fieldLabel:_("Password:"),labelSeparator:"",anchor:"75%",name:"password",inputType:"password",value:""}]})},onAddClick:function(){var a=
+this.form.getForm().getValues();deluge.client.web.add_host(a.host,Number(a.port),a.username,a.password,{success:function(a){a[0]?this.fireEvent("hostadded"):Ext.MessageBox.show({title:_("Error"),msg:String.format(_("Unable to add host: {0}"),a[1]),buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"});this.hide()},scope:this})},onHide:function(){this.form.getForm().reset()}});Ext.ns("Deluge");var trackerUrlTest=/(((^https?)|(^udp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
+Ext.apply(Ext.form.VTypes,{trackerUrl:function(a,b){return trackerUrlTest.test(a)},trackerUrlText:"Not a valid tracker url"});
+Deluge.AddTrackerWindow=Ext.extend(Ext.Window,{title:_("Add Tracker"),layout:"fit",width:375,height:150,plain:!0,closable:!0,resizable:!1,constrainHeader:!0,bodyStyle:"padding: 5px",buttonAlign:"right",closeAction:"hide",iconCls:"x-deluge-edit-trackers",initComponent:function(){Deluge.AddTrackerWindow.superclass.initComponent.call(this);this.addButton(_("Cancel"),this.onCancelClick,this);this.addButton(_("Add"),this.onAddClick,this);this.addEvents("add");this.form=this.add({xtype:"form",defaultType:"textarea",
+baseCls:"x-plain",labelWidth:55,items:[{fieldLabel:_("Trackers:"),labelSeparator:"",name:"trackers",anchor:"100%"}]})},onAddClick:function(){var a=this.form.getForm().findField("trackers").getValue(),a=a.split("\n"),b=[];Ext.each(a,function(a){Ext.form.VTypes.trackerUrl(a)&&b.push(a)},this);this.fireEvent("add",b);this.hide();this.form.getForm().findField("trackers").setValue("")},onCancelClick:function(){this.form.getForm().findField("trackers").setValue("");this.hide()}});Ext.namespace("Ext.ux.util");
+Ext.ux.util.RpcClient=Ext.extend(Ext.util.Observable,{_components:[],_methods:[],_requests:{},_url:null,_optionKeys:["scope","success","failure"],constructor:function(a){Ext.ux.util.RpcClient.superclass.constructor.call(this,a);this._url=a.url||null;this._id=0;this.addEvents("connected","error");this.reloadMethods()},reloadMethods:function(){this._execute("system.listMethods",{success:this._setMethods,scope:this})},_execute:function(a,b){b=b||{};b.params=b.params||[];b.id=this._id;var c=Ext.encode({method:a,
+params:b.params,id:b.id});this._id++;return Ext.Ajax.request({url:this._url,method:"POST",success:this._onSuccess,failure:this._onFailure,scope:this,jsonData:c,options:b})},_onFailure:function(a,b){var c=b.options;errorObj={id:c.id,result:null,error:{msg:"HTTP: "+a.status+" "+a.statusText,code:255}};this.fireEvent("error",errorObj,a,b);"function"==Ext.type(c.failure)&&(c.scope?c.failure.call(c.scope,errorObj,a,b):c.failure(errorObj,a,b))},_onSuccess:function(a,b){var c=Ext.decode(a.responseText),
+d=b.options;c.error?(this.fireEvent("error",c,a,b),"function"==Ext.type(d.failure)&&(d.scope?d.failure.call(d.scope,c,a,b):d.failure(c,a,b))):"function"==Ext.type(d.success)&&(d.scope?d.success.call(d.scope,c.result,c,a,b):d.success(c.result,c,a,b))},_parseArgs:function(a){var b=[];Ext.each(a,function(a){b.push(a)});a=b[b.length-1];if("object"==Ext.type(a)){var c=Ext.keys(a),d=!1;Ext.each(this._optionKeys,function(a){-1<c.indexOf(a)&&(d=!0)});d?b.remove(a):a={}}else a={};a.params=b;return a},_setMethods:function(a){var b=
+{},c=this;Ext.each(a,function(a){var d=a.split("."),e=b[d[0]]||{};e[d[1]]=function(){var b=c._parseArgs(arguments);return c._execute(a,b)};b[d[0]]=e});for(var d in b)c[d]=b[d];Ext.each(this._components,function(a){!a in b&&delete this[a]},this);this._components=Ext.keys(b);this.fireEvent("connected",this)}});
+Deluge.ConnectionManager=Ext.extend(Ext.Window,{layout:"fit",width:300,height:220,bodyStyle:"padding: 10px 5px;",buttonAlign:"right",closeAction:"hide",closable:!0,plain:!0,constrainHeader:!0,title:_("Connection Manager"),iconCls:"x-deluge-connect-window-icon",initComponent:function(){Deluge.ConnectionManager.superclass.initComponent.call(this);this.on("hide",this.onHide,this);this.on("show",this.onShow,this);deluge.events.on("login",this.onLogin,this);deluge.events.on("logout",this.onLogout,this);
+this.addButton(_("Close"),this.onClose,this);this.addButton(_("Connect"),this.onConnect,this);this.list=new Ext.list.ListView({store:new Ext.data.ArrayStore({fields:[{name:"status",mapping:4},{name:"host",mapping:1},{name:"port",mapping:2},{name:"user",mapping:3},{name:"version",mapping:5}],id:0}),columns:[{header:_("Status"),width:0.24,sortable:!0,tpl:new Ext.XTemplate("<tpl if=\"status == 'Online'\">",_("Online"),"</tpl>","<tpl if=\"status == 'Offline'\">",_("Offline"),"</tpl>","<tpl if=\"status == 'Connected'\">",
+_("Connected"),"</tpl>"),dataIndex:"status"},{id:"host",header:_("Host"),width:0.51,sortable:!0,tpl:"{user}@{host}:{port}",dataIndex:"host"},{header:_("Version"),width:0.25,sortable:!0,tpl:'<tpl if="version">{version}</tpl>',dataIndex:"version"}],singleSelect:!0,listeners:{selectionchange:{fn:this.onSelectionChanged,scope:this}}});this.panel=this.add({autoScroll:!0,items:[this.list],bbar:new Ext.Toolbar({buttons:[{id:"cm-add",cls:"x-btn-text-icon",text:_("Add"),iconCls:"icon-add",handler:this.onAddClick,
+scope:this},{id:"cm-edit",cls:"x-btn-text-icon",text:_("Edit"),iconCls:"icon-edit",handler:this.onEditClick,scope:this},{id:"cm-remove",cls:"x-btn-text-icon",text:_("Remove"),iconCls:"icon-remove",handler:this.onRemoveClick,disabled:!0,scope:this},"->",{id:"cm-stop",cls:"x-btn-text-icon",text:_("Stop Daemon"),iconCls:"icon-error",handler:this.onStopClick,disabled:!0,scope:this}]})});this.update=this.update.createDelegate(this)},checkConnected:function(){deluge.client.web.connected({success:function(a){a?
+deluge.events.fire("connect"):this.show()},scope:this})},disconnect:function(a){deluge.events.fire("disconnect");a&&!this.isVisible()&&this.show()},loadHosts:function(){deluge.client.web.get_hosts({success:this.onGetHosts,scope:this})},update:function(){this.list.getStore().each(function(a){deluge.client.web.get_host_status(a.id,{success:this.onGetHostStatus,scope:this})},this)},updateButtons:function(a){var b=this.buttons[1],c=a.get("status");b.enable();"connected"==c.toLowerCase()?b.setText(_("Disconnect")):
+(b.setText(_("Connect")),"online"!=c.toLowerCase()&&b.disable());"connected"==c.toLowerCase()||"online"==c.toLowerCase()?(this.stopHostButton.enable(),this.stopHostButton.setText(_("Stop Daemon"))):"127.0.0.1"==a.get("host")||"localhost"==a.get("host")?(this.stopHostButton.enable(),this.stopHostButton.setText(_("Start Daemon"))):this.stopHostButton.disable()},onAddClick:function(a,b){this.addWindow||(this.addWindow=new Deluge.AddConnectionWindow,this.addWindow.on("hostadded",this.onHostChange,this));
+this.addWindow.show()},onEditClick:function(a,b){var c=this.list.getSelectedRecords()[0];c&&(this.editWindow||(this.editWindow=new Deluge.EditConnectionWindow,this.editWindow.on("hostedited",this.onHostChange,this)),this.editWindow.show(c))},onHostChange:function(){this.loadHosts()},onClose:function(a){this.hide()},onConnect:function(a){if(a=this.list.getSelectedRecords()[0]){var b=this,c=function(){deluge.client.web.disconnect({success:function(a){this.update(this);deluge.events.fire("disconnect")},
+scope:b})};"connected"==a.get("status").toLowerCase()?c():(-1<this.list.getStore().find("status","Connected",0,!1,!1)&&c(),deluge.client.web.connect(a.id,{success:function(a){deluge.client.reloadMethods();deluge.client.on("connected",function(a){deluge.events.fire("connect")},this,{single:!0})}}),this.hide())}},onGetHosts:function(a){this.list.getStore().loadData(a);Ext.each(a,function(a){deluge.client.web.get_host_status(a[0],{success:this.onGetHostStatus,scope:this})},this)},onGetHostStatus:function(a){var b=
+this.list.getStore().getById(a[0]);b.set("status",a[1]);b.set("version",a[2]);b.commit();(a=this.list.getSelectedRecords()[0])&&a==b&&this.updateButtons(b)},onHide:function(){this.running&&window.clearInterval(this.running)},onLogin:function(){deluge.config.first_login?Ext.MessageBox.confirm(_("Change Default Password"),_("We recommend changing the default password.<br><br>Would you like to change it now?"),function(a){this.checkConnected();"yes"==a&&(deluge.preferences.show(),deluge.preferences.selectPage("Interface"));
+deluge.client.web.set_config({first_login:!1})},this):this.checkConnected()},onLogout:function(){this.disconnect();!this.hidden&&this.rendered&&this.hide()},onRemoveClick:function(a){var b=this.list.getSelectedRecords()[0];b&&deluge.client.web.remove_host(b.id,{success:function(a){a?this.list.getStore().remove(b):Ext.MessageBox.show({title:_("Error"),msg:a[1],buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"})},scope:this})},onSelectionChanged:function(a,b){b[0]?
+(this.editHostButton.enable(),this.removeHostButton.enable(),this.stopHostButton.enable(),this.stopHostButton.setText(_("Stop Daemon")),this.updateButtons(this.list.getRecord(b[0]))):(this.editHostButton.disable(),this.removeHostButton.disable(),this.stopHostButton.disable())},onShow:function(){if(!this.addHostButton){var a=this.panel.getBottomToolbar();this.addHostButton=a.items.get("cm-add");this.editHostButton=a.items.get("cm-edit");this.removeHostButton=a.items.get("cm-remove");this.stopHostButton=
+a.items.get("cm-stop")}this.loadHosts();this.running||(this.running=window.setInterval(this.update,2E3,this))},onStopClick:function(a,b){var c=this.list.getSelectedRecords()[0];c&&("Offline"==c.get("status")?deluge.client.web.start_daemon(c.get("port")):deluge.client.web.stop_daemon(c.id,{success:function(a){a[0]||Ext.MessageBox.show({title:_("Error"),msg:a[1],buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"})}}))}});
+Deluge.CopyMagnet=Ext.extend(Ext.Window,{title:_("Copy Magnet URI"),width:375,closeAction:"hide",iconCls:"icon-magnet-copy",initComponent:function(){Deluge.CopyMagnet.superclass.initComponent.call(this);form=this.add({xtype:"form",defaultType:"textfield",hideLabels:!0});this.magnetURI=form.add({name:"URI",anchor:"100%"});this.addButton(_("Close"),this.onClose,this);this.addButton(_("Copy"),this.onCopy,this)},show:function(a){Deluge.CopyMagnet.superclass.show.call(this);a=deluge.torrents.getSelected();
+deluge.client.core.get_magnet_uri(a.id,{success:this.onRequestComplete,scope:this})},onRequestComplete:function(a){this.magnetURI.setValue(a)},onCopy:function(){this.magnetURI.focus();this.magnetURI.el.dom.select();document.execCommand("copy")},onClose:function(){this.hide()}});deluge.copyMagnetWindow=new Deluge.CopyMagnet;Ext.state.Manager.setProvider(new Ext.state.CookieProvider({expires:new Date((new Date).getTime()+31536E7)}));
+Ext.apply(Ext,{isObjectEmpty:function(a){for(var b in a)return!1;return!0},areObjectsEqual:function(a,b){var c=!0;if(!a||!b)return!1;for(var d in a)a[d]!=b[d]&&(c=!1);return c},keys:function(a){var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push(c);return b},values:function(a){var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push(a[c]);return b},splat:function(a){var b=Ext.type(a);return b?"array"!=b?[a]:a:[]}});Ext.getKeys=Ext.keys;Ext.BLANK_IMAGE_URL=deluge.config.base+"images/s.gif";
+Ext.USE_NATIVE_JSON=!0;
+Ext.apply(Deluge,{pluginStore:{},progressTpl:'<div class="x-progress-wrap x-progress-renderered"><div class="x-progress-inner"><div style="width: {2}px" class="x-progress-bar"><div style="z-index: 99; width: {3}px" class="x-progress-text"><div style="width: {1}px;">{0}</div></div></div><div class="x-progress-text x-progress-text-back"><div style="width: {1}px;">{0}</div></div></div></div>',progressBar:function(a,b,c,d){d=Ext.value(d,10);a=(b/100*a).toFixed(0);return String.format(Deluge.progressTpl,c,
+b,a-1,0<a-d?a-d:0)},createPlugin:function(a){return new Deluge.pluginStore[a]},hasPlugin:function(a){return Deluge.pluginStore[a]?!0:!1},registerPlugin:function(a,b){Deluge.pluginStore[a]=b}});deluge.plugins={};FILE_PRIORITY={"0":"Skip",1:"Low",2:"Low",3:"Low",4:"Normal",5:"High",6:"High",7:"High",9:"Mixed",Skip:0,Low:1,Normal:4,High:7,Mixed:9};
+FILE_PRIORITY_CSS={"0":"x-no-download",1:"x-low-download",2:"x-low-download",3:"x-low-download",4:"x-normal-download",5:"x-high-download",6:"x-high-download",7:"x-high-download",9:"x-mixed-download"};Ext.ns("Deluge");
+Deluge.EditConnectionWindow=Ext.extend(Ext.Window,{title:_("Edit Connection"),iconCls:"x-deluge-add-window-icon",layout:"fit",width:300,height:195,constrainHeader:!0,bodyStyle:"padding: 10px 5px;",closeAction:"hide",initComponent:function(){Deluge.EditConnectionWindow.superclass.initComponent.call(this);this.addEvents("hostedited");this.addButton(_("Close"),this.hide,this);this.addButton(_("Edit"),this.onEditClick,this);this.on("hide",this.onHide,this);this.form=this.add({xtype:"form",defaultType:"textfield",
+baseCls:"x-plain",labelWidth:60,items:[{fieldLabel:_("Host:"),labelSeparator:"",name:"host",anchor:"75%",value:""},{xtype:"spinnerfield",fieldLabel:_("Port:"),labelSeparator:"",name:"port",strategy:{xtype:"number",decimalPrecision:0,minValue:0,maxValue:65535},anchor:"40%",value:58846},{fieldLabel:_("Username:"),labelSeparator:"",name:"username",anchor:"75%",value:""},{fieldLabel:_("Password:"),labelSeparator:"",anchor:"75%",name:"password",inputType:"password",value:""}]})},show:function(a){Deluge.EditConnectionWindow.superclass.show.call(this);
+this.form.getForm().findField("host").setValue(a.get("host"));this.form.getForm().findField("port").setValue(a.get("port"));this.form.getForm().findField("username").setValue(a.get("user"));this.host_id=a.id},onEditClick:function(){var a=this.form.getForm().getValues();deluge.client.web.edit_host(this.host_id,a.host,Number(a.port),a.username,a.password,{success:function(a){a?this.fireEvent("hostedited"):(console.log(a),Ext.MessageBox.show({title:_("Error"),msg:String.format(_("Unable to edit host")),
+buttons:Ext.MessageBox.OK,modal:!1,icon:Ext.MessageBox.ERROR,iconCls:"x-deluge-icon-error"}));this.hide()},scope:this})},onHide:function(){this.form.getForm().reset()}});Ext.ns("Deluge");
+Deluge.EditTrackerWindow=Ext.extend(Ext.Window,{title:_("Edit Tracker"),layout:"fit",width:375,height:110,plain:!0,closable:!0,resizable:!1,constrainHeader:!0,bodyStyle:"padding: 5px",buttonAlign:"right",closeAction:"hide",iconCls:"x-deluge-edit-trackers",initComponent:function(){Deluge.EditTrackerWindow.superclass.initComponent.call(this);this.addButton(_("Cancel"),this.onCancelClick,this);this.addButton(_("Save"),this.onSaveClick,this);this.on("hide",this.onHide,this);this.form=this.add({xtype:"form",
+defaultType:"textfield",baseCls:"x-plain",labelWidth:55,items:[{fieldLabel:_("Tracker:"),labelSeparator:"",name:"tracker",anchor:"100%"}]})},show:function(a){Deluge.EditTrackerWindow.superclass.show.call(this);this.record=a;this.form.getForm().findField("tracker").setValue(a.data.url)},onCancelClick:function(){this.hide()},onHide:function(){this.form.getForm().findField("tracker").setValue("")},onSaveClick:function(){var a=this.form.getForm().findField("tracker").getValue();this.record.set("url",
+a);this.record.commit();this.hide()}});Ext.ns("Deluge");
+Deluge.EditTrackersWindow=Ext.extend(Ext.Window,{title:_("Edit Trackers"),layout:"fit",width:350,height:220,plain:!0,closable:!0,resizable:!0,constrainHeader:!0,bodyStyle:"padding: 5px",buttonAlign:"right",closeAction:"hide",iconCls:"x-deluge-edit-trackers",initComponent:function(){Deluge.EditTrackersWindow.superclass.initComponent.call(this);this.addButton(_("Cancel"),this.onCancelClick,this);this.addButton(_("OK"),this.onOkClick,this);this.addEvents("save");this.on("show",this.onShow,this);this.on("save",
+this.onSave,this);this.addWindow=new Deluge.AddTrackerWindow;this.addWindow.on("add",this.onAddTrackers,this);this.editWindow=new Deluge.EditTrackerWindow;this.list=new Ext.list.ListView({store:new Ext.data.JsonStore({root:"trackers",fields:["tier","url"]}),columns:[{header:_("Tier"),width:0.1,dataIndex:"tier"},{header:_("Tracker"),width:0.9,dataIndex:"url",tpl:new Ext.XTemplate("{url:htmlEncode}")}],columnSort:{sortClasses:["",""]},stripeRows:!0,singleSelect:!0,listeners:{dblclick:{fn:this.onListNodeDblClicked,
+scope:this},selectionchange:{fn:this.onSelect,scope:this}}});this.panel=this.add({items:[this.list],autoScroll:!0,bbar:new Ext.Toolbar({items:[{text:_("Up"),iconCls:"icon-up",handler:this.onUpClick,scope:this},{text:_("Down"),iconCls:"icon-down",handler:this.onDownClick,scope:this},"->",{text:_("Add"),iconCls:"icon-add",handler:this.onAddClick,scope:this},{text:_("Edit"),iconCls:"icon-edit-trackers",handler:this.onEditClick,scope:this},{text:_("Remove"),iconCls:"icon-remove",handler:this.onRemoveClick,
+scope:this}]})})},onAddClick:function(){this.addWindow.show()},onAddTrackers:function(a){var b=this.list.getStore();Ext.each(a,function(a){var d=!1,f=-1;b.each(function(b){b.get("tier")>f&&(f=b.get("tier"));if(a==b.get("tracker"))return d=!0,!1},this);d||b.add(new b.recordType({tier:f+1,url:a}))},this)},onCancelClick:function(){this.hide()},onEditClick:function(){var a=this.list.getSelectedRecords()[0];a&&this.editWindow.show(a)},onHide:function(){this.list.getStore().removeAll()},onListNodeDblClicked:function(a,
+b,c,d){this.editWindow.show(this.list.getRecord(c))},onOkClick:function(){var a=[];this.list.getStore().each(function(b){a.push({tier:b.get("tier"),url:b.get("url")})},this);deluge.client.core.set_torrent_trackers(this.torrentId,a,{failure:this.onSaveFail,scope:this});this.hide()},onRemoveClick:function(){var a=this.list.getSelectedRecords()[0];a&&this.list.getStore().remove(a)},onRequestComplete:function(a){this.list.getStore().loadData(a);this.list.getStore().sort("tier","ASC")},onSaveFail:function(){},
+onSelect:function(a){a.getSelectionCount()&&this.panel.getBottomToolbar().items.get(4).enable()},onShow:function(){this.panel.getBottomToolbar().items.get(4).disable();var a=deluge.torrents.getSelected();this.torrentId=a.id;deluge.client.core.get_torrent_status(a.id,["trackers"],{success:this.onRequestComplete,scope:this})},onDownClick:function(){var a=this.list.getSelectedRecords()[0];a&&(a.set("tier",a.get("tier")+1),a.store.sort("tier","ASC"),a.store.commitChanges(),this.list.select(a.store.indexOf(a)))},
+onUpClick:function(){var a=this.list.getSelectedRecords()[0];a&&0!=a.get("tier")&&(a.set("tier",a.get("tier")-1),a.store.sort("tier","ASC"),a.store.commitChanges(),this.list.select(a.store.indexOf(a)))}});
+Deluge.EventsManager=Ext.extend(Ext.util.Observable,{constructor:function(){this.toRegister=[];this.on("login",this.onLogin,this);Deluge.EventsManager.superclass.constructor.call(this)},addListener:function(a,b,c,d){this.addEvents(a);/[A-Z]/.test(a.substring(0,1))&&(deluge.client?deluge.client.web.register_event_listener(a):this.toRegister.push(a));Deluge.EventsManager.superclass.addListener.call(this,a,b,c,d)},getEvents:function(){deluge.client.web.get_events({success:this.onGetEventsSuccess,failure:this.onGetEventsFailure,
+scope:this})},start:function(){Ext.each(this.toRegister,function(a){deluge.client.web.register_event_listener(a)});this.running=!0;this.errorCount=0;this.getEvents()},stop:function(){this.running=!1},onLogin:function(){this.start()},onGetEventsSuccess:function(a){this.running&&(a&&Ext.each(a,function(a){var c=a[1];c.splice(0,0,a[0]);this.fireEvent.apply(this,c)},this),this.getEvents())},onGetEventsFailure:function(a,b){this.running&&(!b.isTimeout&&3<=this.errorCount++?this.stop():this.getEvents())}});
+Deluge.EventsManager.prototype.on=Deluge.EventsManager.prototype.addListener;Deluge.EventsManager.prototype.fire=Deluge.EventsManager.prototype.fireEvent;deluge.events=new Deluge.EventsManager;Ext.namespace("Deluge");
+Deluge.FileBrowser=Ext.extend(Ext.Window,{title:_("File Browser"),width:500,height:400,initComponent:function(){Deluge.FileBrowser.superclass.initComponent.call(this);this.add({xtype:"toolbar",items:[{text:_("Back"),iconCls:"icon-back"},{text:_("Forward"),iconCls:"icon-forward"},{text:_("Up"),iconCls:"icon-up"},{text:_("Home"),iconCls:"icon-home"}]})}});Ext.ns("Deluge");
+Deluge.FilterPanel=Ext.extend(Ext.Panel,{autoScroll:!0,border:!1,show_zero:null,initComponent:function(){Deluge.FilterPanel.superclass.initComponent.call(this);this.filterType=this.initialConfig.filter;var a="";"state"==this.filterType?a=_("States"):"tracker_host"==this.filterType?a=_("Trackers"):"owner"==this.filterType?a=_("Owner"):"label"==this.filterType?a=_("Labels"):(a=this.filterType.replace("_"," "),parts=a.split(" "),a="",Ext.each(parts,function(b){fl=b.substring(0,1).toUpperCase();a+=fl+
+b.substring(1)+" "}));this.setTitle(_(a));var b=Deluge.FilterPanel.templates[this.filterType]?Deluge.FilterPanel.templates[this.filterType]:'<div class="x-deluge-filter x-deluge-{filter:lowercase}">{filter} ({count})</div>';this.list=this.add({xtype:"listview",singleSelect:!0,hideHeaders:!0,reserveScrollOffset:!0,store:new Ext.data.ArrayStore({idIndex:0,fields:["filter","count"]}),columns:[{id:"filter",sortable:!1,tpl:b,dataIndex:"filter"}]});this.relayEvents(this.list,["selectionchange"])},getState:function(){if(this.list.getSelectionCount()){var a=
+this.list.getSelectedRecords()[0];if(a&&"All"!=a.id)return a.id}},getStates:function(){return this.states},getStore:function(){return this.list.getStore()},updateStates:function(a){this.states={};Ext.each(a,function(a){this.states[a[0]]=a[1]},this);if(!(null==this.show_zero?deluge.config.sidebar_show_zero:this.show_zero)){var b=[];Ext.each(a,function(a){(0<a[1]||"All"==a[0])&&b.push(a)});a=b}var c=this.getStore(),d={};Ext.each(a,function(a,b){var e=c.getById(a[0]);e||(e=new c.recordType({filter:a[0],
+count:a[1]}),e.id=a[0],c.insert(b,e));e.beginEdit();e.set("filter",_(a[0]));e.set("count",a[1]);e.endEdit();d[a[0]]=!0},this);c.each(function(a){if(!d[a.id]){c.remove(a);var b=this.list.getSelectedRecords()[0];b&&b.id==a.id&&this.list.select(0)}},this);c.commitChanges();this.list.getSelectionCount()||this.list.select(0)}});Deluge.FilterPanel.templates={tracker_host:'<div class="x-deluge-filter" style="background-image: url('+deluge.config.base+'tracker/{filter});">{filter:htmlEncode} ({count})</div>'};
+Deluge.Formatters=function(){var a={"&":"&amp;",">":"&gt;","<":"&lt;",'"':"&quot;","'":"&#39;"},b=RegExp("("+Object.keys(a).join("|")+")","g"),c=function(b,c){return a[c]};return Formatters={date:function(a){function b(a,c){for(var d=a+"";d.length<c;)d="0"+d;return d}a=new Date(1E3*a);return String.format("{0}/{1}/{2} {3}:{4}:{5}",b(a.getDate(),2),b(a.getMonth()+1,2),a.getFullYear(),b(a.getHours(),2),b(a.getMinutes(),2),b(a.getSeconds(),2))},size:function(a,b){if(!a&&!b)return"";a/=1024;if(1024>a)return a.toFixed(1)+
+" KiB";a/=1024;return 1024>a?a.toFixed(1)+" MiB":(a/1024).toFixed(1)+" GiB"},sizeShort:function(a,b){if(!a&&!b)return"";a/=1024;if(1024>a)return a.toFixed(1)+" K";a/=1024;return 1024>a?a.toFixed(1)+" M":(a/1024).toFixed(1)+" G"},speed:function(a,b){return!a&&!b?"":fsize(a,b)+"/s"},timeRemaining:function(a){if(0>=a)return"&infin;";a=a.toFixed(0);if(60>a)return a+"s";a/=60;if(60>a){var b=Math.floor(a);a=Math.round(60*(a-b));return 0<a?b+"m "+a+"s":b+"m"}a/=60;if(24>a){var c=Math.floor(a),b=Math.round(60*
+(a-c));return 0<b?c+"h "+b+"m":c+"h"}a/=24;b=Math.floor(a);c=Math.round(24*(a-b));return 0<c?b+"d "+c+"h":b+"d"},plain:function(a){return a},cssClassEscape:function(a){return a.toLowerCase().replace(".","_")},htmlEncode:function(a){return!a?a:String(a).replace(b,c)}}}();var fsize=Deluge.Formatters.size,fsize_short=Deluge.Formatters.sizeShort,fspeed=Deluge.Formatters.speed,ftime=Deluge.Formatters.timeRemaining,fdate=Deluge.Formatters.date,fplain=Deluge.Formatters.plain;
+Ext.util.Format.cssClassEscape=Deluge.Formatters.cssClassEscape;Ext.util.Format.htmlEncode=Deluge.Formatters.htmlEncode;
+Deluge.Keys={Grid:"queue name total_wanted state progress num_seeds total_seeds num_peers total_peers download_payload_rate upload_payload_rate eta ratio distributed_copies is_auto_managed time_added tracker_host download_location last_seen_complete total_done total_uploaded max_download_speed max_upload_speed seeds_peers_ratio total_remaining completed_time time_since_transfer".split(" "),Status:"total_done total_payload_download total_uploaded total_payload_upload next_announce tracker_status num_pieces piece_length is_auto_managed active_time seeding_time time_since_transfer seed_rank last_seen_complete completed_time owner public shared".split(" "),
+Files:["files","file_progress","file_priorities"],Peers:["peers"],Details:"name download_location total_size num_files message tracker_host comment creator".split(" "),Options:"max_download_speed max_upload_speed max_connections max_upload_slots is_auto_managed stop_at_ratio stop_ratio remove_at_ratio private prioritize_first_last move_completed move_completed_path super_seeding".split(" ")};Ext.each(Deluge.Keys.Grid,function(a){Deluge.Keys.Status.push(a)});
+Deluge.LoginWindow=Ext.extend(Ext.Window,{firstShow:!0,bodyStyle:"padding: 10px 5px;",buttonAlign:"center",closable:!1,closeAction:"hide",iconCls:"x-deluge-login-window-icon",layout:"fit",modal:!0,plain:!0,resizable:!1,title:_("Login"),width:300,height:120,initComponent:function(){Deluge.LoginWindow.superclass.initComponent.call(this);this.on("show",this.onShow,this);this.addButton({text:_("Login"),handler:this.onLogin,scope:this});this.form=this.add({xtype:"form",baseCls:"x-plain",labelWidth:120,
+labelAlign:"right",defaults:{width:110},defaultType:"textfield"});this.passwordField=this.form.add({xtype:"textfield",fieldLabel:_("Password:"),labelSeparator:"",grow:!0,growMin:"110",growMax:"145",id:"_password",name:"password",inputType:"password"});this.passwordField.on("specialkey",this.onSpecialKey,this)},logout:function(){deluge.events.fire("logout");deluge.client.auth.delete_session({success:function(a){this.show(!0)},scope:this})},show:function(a){this.firstShow&&(deluge.client.on("error",
+this.onClientError,this),this.firstShow=!1);if(a)return Deluge.LoginWindow.superclass.show.call(this);deluge.client.auth.check_session({success:function(a){a?deluge.events.fire("login"):this.show(!0)},failure:function(a){this.show(!0)},scope:this})},onSpecialKey:function(a,b){if(13==b.getKey())this.onLogin()},onLogin:function(){var a=this.passwordField;deluge.client.auth.login(a.getValue(),{success:function(b){b?(deluge.events.fire("login"),this.hide(),a.setRawValue("")):Ext.MessageBox.show({title:_("Login Failed"),
+msg:_("You entered an incorrect password"),buttons:Ext.MessageBox.OK,modal:!1,fn:function(){a.focus(!0,10)},icon:Ext.MessageBox.WARNING,iconCls:"x-deluge-icon-warning"})},scope:this})},onClientError:function(a,b,c){1==a.error.code&&(deluge.events.fire("logout"),this.show(!0))},onShow:function(){this.passwordField.focus(!0,300)}});
+deluge.menus={onTorrentActionSetOpt:function(a,b){var c=deluge.torrents.getSelectedIds(),d=a.initialConfig.torrentAction,f={};f[d[0]]=d[1];deluge.client.core.set_torrent_options(c,f)},onTorrentActionMethod:function(a,b){var c=deluge.torrents.getSelectedIds();deluge.client.core[a.initialConfig.torrentAction](c,{success:function(){deluge.ui.update()}})},onTorrentActionShow:function(a,b){var c=deluge.torrents.getSelectedIds();switch(a.initialConfig.torrentAction){case "copy_magnet":deluge.copyMagnetWindow.show();
+break;case "edit_trackers":deluge.editTrackers.show();break;case "remove":deluge.removeWindow.show(c);break;case "move":deluge.moveStorage.show(c)}}};
+deluge.menus.torrent=new Ext.menu.Menu({id:"torrentMenu",items:[{torrentAction:"pause_torrent",text:_("Pause"),iconCls:"icon-pause",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus},{torrentAction:"resume_torrent",text:_("Resume"),iconCls:"icon-resume",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus},"-",{text:_("Options"),iconCls:"icon-options",hideOnClick:!1,menu:new Ext.menu.Menu({items:[{text:_("D/L Speed Limit"),iconCls:"x-deluge-downloading",hideOnClick:!1,menu:new Ext.menu.Menu({items:[{torrentAction:["max_download_speed",
+5],text:_("5 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_download_speed",10],text:_("10 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_download_speed",30],text:_("30 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_download_speed",80],text:_("80 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_download_speed",300],text:_("300 KiB/s"),
+handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_download_speed",-1],text:_("Unlimited"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus}]})},{text:_("U/L Speed Limit"),iconCls:"x-deluge-seeding",hideOnClick:!1,menu:new Ext.menu.Menu({items:[{torrentAction:["max_upload_speed",5],text:_("5 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_speed",10],text:_("10 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,
+scope:deluge.menus},{torrentAction:["max_upload_speed",30],text:_("30 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_speed",80],text:_("80 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_speed",300],text:_("300 KiB/s"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_speed",-1],text:_("Unlimited"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus}]})},
+{text:_("Connection Limit"),iconCls:"x-deluge-connections",hideOnClick:!1,menu:new Ext.menu.Menu({items:[{torrentAction:["max_connections",50],text:"50",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_connections",100],text:"100",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_connections",200],text:"200",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_connections",300],text:"300",handler:deluge.menus.onTorrentActionSetOpt,
+scope:deluge.menus},{torrentAction:["max_connections",500],text:"500",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_connections",-1],text:_("Unlimited"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus}]})},{text:_("Upload Slot Limit"),iconCls:"icon-upload-slots",hideOnClick:!1,menu:new Ext.menu.Menu({items:[{torrentAction:["max_upload_slots",0],text:"0",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_slots",
+1],text:"1",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_slots",2],text:"2",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_slots",3],text:"3",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_slots",5],text:"5",handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["max_upload_slots",-1],text:_("Unlimited"),handler:deluge.menus.onTorrentActionSetOpt,
+scope:deluge.menus}]})},{id:"auto_managed",text:_("Auto Managed"),hideOnClick:!1,menu:new Ext.menu.Menu({items:[{torrentAction:["auto_managed",!0],text:_("On"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus},{torrentAction:["auto_managed",!1],text:_("Off"),handler:deluge.menus.onTorrentActionSetOpt,scope:deluge.menus}]})}]})},"-",{text:_("Queue"),iconCls:"icon-queue",hideOnClick:!1,menu:new Ext.menu.Menu({items:[{torrentAction:"queue_top",text:_("Top"),iconCls:"icon-top",handler:deluge.menus.onTorrentActionMethod,
+scope:deluge.menus},{torrentAction:"queue_up",text:_("Up"),iconCls:"icon-up",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus},{torrentAction:"queue_down",text:_("Down"),iconCls:"icon-down",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus},{torrentAction:"queue_bottom",text:_("Bottom"),iconCls:"icon-bottom",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus}]})},"-",{torrentAction:"copy_magnet",text:_("Copy Magnet URI"),iconCls:"icon-magnet-copy",handler:deluge.menus.onTorrentActionShow,
+scope:deluge.menus},{torrentAction:"force_reannounce",text:_("Update Tracker"),iconCls:"icon-update-tracker",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus},{torrentAction:"edit_trackers",text:_("Edit Trackers"),iconCls:"icon-edit-trackers",handler:deluge.menus.onTorrentActionShow,scope:deluge.menus},"-",{torrentAction:"remove",text:_("Remove Torrent"),iconCls:"icon-remove",handler:deluge.menus.onTorrentActionShow,scope:deluge.menus},"-",{torrentAction:"force_recheck",text:_("Force Recheck"),
+iconCls:"icon-recheck",handler:deluge.menus.onTorrentActionMethod,scope:deluge.menus},{torrentAction:"move",text:_("Move Download Folder"),iconCls:"icon-move",handler:deluge.menus.onTorrentActionShow,scope:deluge.menus}]});
+deluge.menus.filePriorities=new Ext.menu.Menu({id:"filePrioritiesMenu",items:[{id:"expandAll",text:_("Expand All"),iconCls:"icon-expand-all"},"-",{id:"skip",text:_("Skip"),iconCls:"icon-do-not-download",filePriority:FILE_PRIORITY.Skip},{id:"low",text:_("Low"),iconCls:"icon-low",filePriority:FILE_PRIORITY.Low},{id:"normal",text:_("Normal"),iconCls:"icon-normal",filePriority:FILE_PRIORITY.Normal},{id:"high",text:_("High"),iconCls:"icon-high",filePriority:FILE_PRIORITY.High}]});Ext.namespace("Deluge");
+Deluge.MoveStorage=Ext.extend(Ext.Window,{constructor:function(a){a=Ext.apply({title:_("Move Download Folder"),width:375,height:110,layout:"fit",buttonAlign:"right",closeAction:"hide",closable:!0,iconCls:"x-deluge-move-storage",plain:!0,constrainHeader:!0,resizable:!1},a);Deluge.MoveStorage.superclass.constructor.call(this,a)},initComponent:function(){Deluge.MoveStorage.superclass.initComponent.call(this);this.addButton(_("Cancel"),this.onCancel,this);this.addButton(_("Move"),this.onMove,this);this.form=
+this.add({xtype:"form",border:!1,defaultType:"textfield",width:300,bodyStyle:"padding: 5px"});this.moveLocation=this.form.add({fieldLabel:_("Download Folder"),name:"location",width:240})},hide:function(){Deluge.MoveStorage.superclass.hide.call(this);this.torrentIds=null},show:function(a){Deluge.MoveStorage.superclass.show.call(this);this.torrentIds=a},onCancel:function(){this.hide()},onMove:function(){var a=this.moveLocation.getValue();deluge.client.core.move_storage(this.torrentIds,a);this.hide()}});
+deluge.moveStorage=new Deluge.MoveStorage;
+Deluge.MultiOptionsManager=Ext.extend(Deluge.OptionsManager,{constructor:function(a){this.currentId=null;this.stored={};Deluge.MultiOptionsManager.superclass.constructor.call(this,a)},changeId:function(a,b){var c=this.currentId;this.currentId=a;if(!b)for(var d in this.options)this.binds[d]&&Ext.each(this.binds[d],function(a){a.setValue(this.get(d))},this);return c},commit:function(){this.stored[this.currentId]=Ext.apply(this.stored[this.currentId],this.changed[this.currentId]);this.reset()},get:function(){if(1==
+arguments.length){var a=arguments[0];return this.isDirty(a)?this.changed[this.currentId][a]:this.getDefault(a)}if(0==arguments.length){var b={};for(a in this.options)b[a]=this.isDirty(a)?this.changed[this.currentId][a]:this.getDefault(a)}else b={},Ext.each(arguments,function(a){b[a]=this.isDirty(a)?this.changed[this.currentId][a]:this.getDefault(a)},this);return b},getDefault:function(a){return this.has(a)?this.stored[this.currentId][a]:this.options[a]},getDirty:function(){return this.changed[this.currentId]?
+this.changed[this.currentId]:{}},isDirty:function(a){return this.changed[this.currentId]&&!Ext.isEmpty(this.changed[this.currentId][a])},has:function(a){return this.stored[this.currentId]&&!Ext.isEmpty(this.stored[this.currentId][a])},reset:function(){this.changed[this.currentId]&&delete this.changed[this.currentId];this.stored[this.currentId]&&delete this.stored[this.currentId]},resetAll:function(){this.changed={};this.stored={};this.changeId(null)},setDefault:function(a,b){if(void 0!==a)if(void 0===
+b)for(var c in a)this.setDefault(c,a[c]);else c=this.getDefault(a),b=this.convertValueType(c,b),c!=b&&(this.stored[this.currentId]||(this.stored[this.currentId]={}),this.stored[this.currentId][a]=b,this.isDirty(a)||this.fireEvent("changed",a,b,c))},update:function(a,b){if(void 0!==a)if(void 0===b)for(var c in a)this.update(c,a[c]);else{this.changed[this.currentId]||(this.changed[this.currentId]={});c=this.getDefault(a);b=this.convertValueType(c,b);var d=this.get(a);d!=b&&(c==b?this.isDirty(a)&&delete this.changed[this.currentId][a]:
+this.changed[this.currentId][a]=b,this.fireEvent("changed",a,b,d))}}});Ext.ns("Deluge");
+Deluge.OtherLimitWindow=Ext.extend(Ext.Window,{layout:"fit",width:210,height:100,constrainHeader:!0,closeAction:"hide",initComponent:function(){Deluge.OtherLimitWindow.superclass.initComponent.call(this);this.form=this.add({xtype:"form",baseCls:"x-plain",bodyStyle:"padding: 5px",layout:"hbox",layoutConfig:{pack:"start"},items:[{xtype:"spinnerfield",name:"limit"}]});this.initialConfig.unit?this.form.add({border:!1,baseCls:"x-plain",bodyStyle:"padding: 5px",html:this.initialConfig.unit}):this.setSize(180,
+100);this.addButton(_("Cancel"),this.onCancelClick,this);this.addButton(_("OK"),this.onOkClick,this);this.afterMethod("show",this.doFocusField,this)},setValue:function(a){this.form.getForm().setValues({limit:a})},onCancelClick:function(){this.form.getForm().reset();this.hide()},onOkClick:function(){var a={};a[this.group]=this.form.getForm().getValues().limit;deluge.client.core.set_config(a,{success:function(){deluge.ui.update()}});this.hide()},doFocusField:function(){this.form.getForm().findField("limit").focus(!0,
+10)}});Ext.ns("Deluge");
+Deluge.Plugin=Ext.extend(Ext.util.Observable,{name:null,constructor:function(a){this.isDelugePlugin=!0;this.addEvents({enabled:!0,disabled:!0});Deluge.Plugin.superclass.constructor.call(this,a)},disable:function(){this.fireEvent("disabled",this);if(this.onDisable)this.onDisable()},enable:function(){deluge.client.reloadMethods();this.fireEvent("enable",this);if(this.onEnable)this.onEnable()},registerTorrentStatus:function(a,b,c){c=c||{};var d=c.colCfg||{};c=c.storeCfg||{};c=Ext.apply(c,{name:a});deluge.torrents.meta.fields.push(c);
+deluge.torrents.getStore().reader.onMetaChange(deluge.torrents.meta);d=Ext.apply(d,{header:b,dataIndex:a});b=deluge.torrents.columns.slice(0);b.push(d);deluge.torrents.colModel.setConfig(b);deluge.torrents.columns=b;Deluge.Keys.Grid.push(a);deluge.torrents.getView().refresh(!0)},deregisterTorrentStatus:function(a){var b=[];Ext.each(deluge.torrents.meta.fields,function(c){c.name!=a&&b.push(c)});deluge.torrents.meta.fields=b;deluge.torrents.getStore().reader.onMetaChange(deluge.torrents.meta);var c=
+[];Ext.each(deluge.torrents.columns,function(b){b.dataIndex!=a&&c.push(b)});deluge.torrents.colModel.setConfig(c);deluge.torrents.columns=c;var d=[];Ext.each(Deluge.Keys.Grid,function(b){b==a&&d.push(b)});Deluge.Keys.Grid=d;deluge.torrents.getView().refresh(!0)}});Ext.ns("Deluge.plugins");
+Deluge.RemoveWindow=Ext.extend(Ext.Window,{title:_("Remove Torrent"),layout:"fit",width:350,height:100,constrainHeader:!0,buttonAlign:"right",closeAction:"hide",closable:!0,iconCls:"x-deluge-remove-window-icon",plain:!0,bodyStyle:"padding: 5px; padding-left: 10px;",html:"Are you sure you wish to remove the torrent (s)?",initComponent:function(){Deluge.RemoveWindow.superclass.initComponent.call(this);this.addButton(_("Cancel"),this.onCancel,this);this.addButton(_("Remove With Data"),this.onRemoveData,
+this);this.addButton(_("Remove Torrent"),this.onRemove,this)},remove:function(a){deluge.client.core.remove_torrents(this.torrentIds,a,{success:function(a){!0==a&&console.log("Error(s) occured when trying to delete torrent(s).");this.onRemoved(this.torrentIds)},scope:this,torrentIds:this.torrentIds})},show:function(a){Deluge.RemoveWindow.superclass.show.call(this);this.torrentIds=a},onCancel:function(){this.hide();this.torrentIds=null},onRemove:function(){this.remove(!1)},onRemoveData:function(){this.remove(!0)},
+onRemoved:function(a){deluge.events.fire("torrentsRemoved",a);this.hide();deluge.ui.update()}});deluge.removeWindow=new Deluge.RemoveWindow;
+Deluge.Sidebar=Ext.extend(Ext.Panel,{panels:{},selected:null,constructor:function(a){a=Ext.apply({id:"sidebar",region:"west",cls:"deluge-sidebar",title:_("Filters"),layout:"accordion",split:!0,width:200,minSize:100,collapsible:!0},a);Deluge.Sidebar.superclass.constructor.call(this,a)},initComponent:function(){Deluge.Sidebar.superclass.initComponent.call(this);deluge.events.on("disconnect",this.onDisconnect,this)},createFilter:function(a,b){var c=new Deluge.FilterPanel({filter:a});c.on("selectionchange",
+function(a,b){deluge.ui.update()});this.add(c);this.doLayout();this.panels[a]=c;c.header.on("click",function(a){deluge.config.sidebar_multiple_filters||deluge.ui.update();c.list.getSelectionCount()||c.list.select(0)});this.fireEvent("filtercreate",this,c);c.updateStates(b);this.fireEvent("afterfiltercreate",this,c)},getFilter:function(a){return this.panels[a]},getFilterStates:function(){var a={};if(deluge.config.sidebar_multiple_filters)this.items.each(function(b){var c=b.getState();null!=c&&(a[b.filterType]=
+c)},this);else{var b=this.getLayout().activeItem;if(b){var c=b.getState();if(null==!c)return;a[b.filterType]=c}}return a},hasFilter:function(a){return this.panels[a]?!0:!1},onDisconnect:function(){for(var a in this.panels)this.remove(this.panels[a]);this.panels={};this.selected=null},onFilterSelect:function(a,b,c){deluge.ui.update()},update:function(a){for(var b in a){var c=a[b];-1<Ext.getKeys(this.panels).indexOf(b)?this.panels[b].updateStates(c):this.createFilter(b,c)}Ext.each(Ext.keys(this.panels),
+function(b){-1==Ext.keys(a).indexOf(b)&&(this.remove(this.panels[b]),this.doLayout(),delete this.panels[b])},this)}});Ext.namespace("Deluge");
+Deluge.Statusbar=Ext.extend(Ext.ux.StatusBar,{constructor:function(a){a=Ext.apply({id:"deluge-statusbar",defaultIconCls:"x-deluge-statusbar x-not-connected",defaultText:_("Not Connected")},a);Deluge.Statusbar.superclass.constructor.call(this,a)},initComponent:function(){Deluge.Statusbar.superclass.initComponent.call(this);deluge.events.on("connect",this.onConnect,this);deluge.events.on("disconnect",this.onDisconnect,this)},createButtons:function(){this.buttons=this.add({id:"statusbar-connections",
+text:" ",cls:"x-btn-text-icon",iconCls:"x-deluge-connections",tooltip:_("Connections"),menu:new Deluge.StatusbarMenu({items:[{text:"50",value:"50",group:"max_connections_global",checked:!1},{text:"100",value:"100",group:"max_connections_global",checked:!1},{text:"200",value:"200",group:"max_connections_global",checked:!1},{text:"300",value:"300",group:"max_connections_global",checked:!1},{text:"500",value:"500",group:"max_connections_global",checked:!1},{text:_("Unlimited"),value:"-1",group:"max_connections_global",
+checked:!1},"-",{text:_("Other"),value:"other",group:"max_connections_global",checked:!1}],otherWin:{title:_("Set Maximum Connections")}})},"-",{id:"statusbar-downspeed",text:" ",cls:"x-btn-text-icon",iconCls:"x-deluge-downloading",tooltip:_("Download Speed"),menu:new Deluge.StatusbarMenu({items:[{value:"5",text:_("5 KiB/s"),group:"max_download_speed",checked:!1},{value:"10",text:_("10 KiB/s"),group:"max_download_speed",checked:!1},{value:"30",text:_("30 KiB/s"),group:"max_download_speed",checked:!1},
+{value:"80",text:_("80 KiB/s"),group:"max_download_speed",checked:!1},{value:"300",text:_("300 KiB/s"),group:"max_download_speed",checked:!1},{value:"-1",text:_("Unlimited"),group:"max_download_speed",checked:!1},"-",{value:"other",text:_("Other"),group:"max_download_speed",checked:!1}],otherWin:{title:_("Set Maximum Download Speed"),unit:_("KiB/s")}})},"-",{id:"statusbar-upspeed",text:" ",cls:"x-btn-text-icon",iconCls:"x-deluge-seeding",tooltip:_("Upload Speed"),menu:new Deluge.StatusbarMenu({items:[{value:"5",
+text:_("5 KiB/s"),group:"max_upload_speed",checked:!1},{value:"10",text:_("10 KiB/s"),group:"max_upload_speed",checked:!1},{value:"30",text:_("30 KiB/s"),group:"max_upload_speed",checked:!1},{value:"80",text:_("80 KiB/s"),group:"max_upload_speed",checked:!1},{value:"300",text:_("300 KiB/s"),group:"max_upload_speed",checked:!1},{value:"-1",text:_("Unlimited"),group:"max_upload_speed",checked:!1},"-",{value:"other",text:_("Other"),group:"max_upload_speed",checked:!1}],otherWin:{title:_("Set Maximum Upload Speed"),
+unit:_("KiB/s")}})},"-",{id:"statusbar-traffic",text:" ",cls:"x-btn-text-icon",iconCls:"x-deluge-traffic",tooltip:_("Protocol Traffic Download/Upload"),handler:function(){deluge.preferences.show();deluge.preferences.selectPage("Network")}},"-",{id:"statusbar-externalip",text:" ",cls:"x-btn-text",tooltip:_("External IP Address")},"-",{id:"statusbar-dht",text:" ",cls:"x-btn-text-icon",iconCls:"x-deluge-dht",tooltip:_("DHT Nodes")},"-",{id:"statusbar-freespace",text:" ",cls:"x-btn-text-icon",iconCls:"x-deluge-freespace",
+tooltip:_("Freespace in download folder"),handler:function(){deluge.preferences.show();deluge.preferences.selectPage("Downloads")}});this.created=!0},onConnect:function(){this.setStatus({iconCls:"x-connected",text:""});this.created?Ext.each(this.buttons,function(a){a.show();a.enable()}):this.createButtons();this.doLayout()},onDisconnect:function(){this.clearStatus({useDefaults:!0});Ext.each(this.buttons,function(a){a.hide();a.disable()});this.doLayout()},update:function(a){function b(a){return a+
+" KiB/s"}if(a){var c=function(a,b){var c=this.items.get("statusbar-"+a);if(0<b.limit.value)var e=b.value.formatter?b.value.formatter(b.value.value,!0):b.value.value,l=b.limit.formatter?b.limit.formatter(b.limit.value,!0):b.limit.value,e=String.format(b.format,e,l);else e=b.value.formatter?b.value.formatter(b.value.value,!0):b.value.value;c.setText(e);c.menu&&c.menu.setValue(b.limit.value)}.createDelegate(this);c("connections",{value:{value:a.num_connections},limit:{value:a.max_num_connections},format:"{0} ({1})"});
+c("downspeed",{value:{value:a.download_rate,formatter:Deluge.Formatters.speed},limit:{value:a.max_download,formatter:b},format:"{0} ({1})"});c("upspeed",{value:{value:a.upload_rate,formatter:Deluge.Formatters.speed},limit:{value:a.max_upload,formatter:b},format:"{0} ({1})"});c("traffic",{value:{value:a.download_protocol_rate,formatter:Deluge.Formatters.speed},limit:{value:a.upload_protocol_rate,formatter:Deluge.Formatters.speed},format:"{0}/{1}"});this.items.get("statusbar-dht").setText(a.dht_nodes);
+this.items.get("statusbar-freespace").setText(0<=a.free_space?fsize(a.free_space):_("Error"));this.items.get("statusbar-externalip").setText(String.format(_("<b>IP</b> {0}"),a.external_ip?a.external_ip:_("n/a")))}}});
+Deluge.Toolbar=Ext.extend(Ext.Toolbar,{constructor:function(a){a=Ext.apply({items:[{id:"tbar-deluge-text",text:_("Deluge"),iconCls:"x-deluge-main-panel",handler:this.onAboutClick},new Ext.Toolbar.Separator,{id:"create",disabled:!0,hidden:!0,text:_("Create"),iconCls:"icon-create",handler:this.onTorrentAction},{id:"add",disabled:!0,text:_("Add"),iconCls:"icon-add",handler:this.onTorrentAdd},{id:"remove",disabled:!0,text:_("Remove"),iconCls:"icon-remove",handler:this.onTorrentAction},new Ext.Toolbar.Separator,
+{id:"pause",disabled:!0,text:_("Pause"),iconCls:"icon-pause",handler:this.onTorrentAction},{id:"resume",disabled:!0,text:_("Resume"),iconCls:"icon-resume",handler:this.onTorrentAction},new Ext.Toolbar.Separator,{id:"up",cls:"x-btn-text-icon",disabled:!0,text:_("Up"),iconCls:"icon-up",handler:this.onTorrentAction},{id:"down",disabled:!0,text:_("Down"),iconCls:"icon-down",handler:this.onTorrentAction},new Ext.Toolbar.Separator,{id:"preferences",text:_("Preferences"),iconCls:"x-deluge-preferences",handler:this.onPreferencesClick,
+scope:this},{id:"connectionman",text:_("Connection Manager"),iconCls:"x-deluge-connection-manager",handler:this.onConnectionManagerClick,scope:this},"->",{id:"help",iconCls:"icon-help",text:_("Help"),handler:this.onHelpClick,scope:this},{id:"logout",iconCls:"icon-logout",disabled:!0,text:_("Logout"),handler:this.onLogout,scope:this}]},a);Deluge.Toolbar.superclass.constructor.call(this,a)},connectedButtons:"add remove pause resume up down".split(" "),initComponent:function(){Deluge.Toolbar.superclass.initComponent.call(this);
+deluge.events.on("connect",this.onConnect,this);deluge.events.on("login",this.onLogin,this)},onConnect:function(){Ext.each(this.connectedButtons,function(a){this.items.get(a).enable()},this)},onDisconnect:function(){Ext.each(this.connectedButtons,function(a){this.items.get(a).disable()},this)},onLogin:function(){this.items.get("logout").enable()},onLogout:function(){this.items.get("logout").disable();deluge.login.logout()},onConnectionManagerClick:function(){deluge.connectionManager.show()},onHelpClick:function(){window.open("http://dev.deluge-torrent.org/wiki/UserGuide")},
+onAboutClick:function(){(new Deluge.about.AboutWindow).show()},onPreferencesClick:function(){deluge.preferences.show()},onTorrentAction:function(a){var b=deluge.torrents.getSelections(),c=[];Ext.each(b,function(a){c.push(a.id)});switch(a.id){case "remove":deluge.removeWindow.show(c);break;case "pause":case "resume":deluge.client.core[a.id+"_torrent"](c,{success:function(){deluge.ui.update()}});break;case "up":case "down":deluge.client.core["queue_"+a.id](c,{success:function(){deluge.ui.update()}})}},
+onTorrentAdd:function(){deluge.add.show()}});
+(function(){function a(a){if(a)return fspeed(a)}function b(a){return-1==a?"":fspeed(1024*a)}function c(a,b,c){return 0>a?"&infin;":parseFloat((new Number(a)).toFixed(3))}function d(a){return 0<a?fdate(a):_("Never")}Deluge.TorrentGrid=Ext.extend(Ext.grid.GridPanel,{torrents:{},columns:[{id:"queue",header:"#",width:30,sortable:!0,renderer:function(a){return-1==a?"":a+1},dataIndex:"queue"},{id:"name",header:_("Name"),width:150,sortable:!0,renderer:function(a,b,c){return String.format('<div class="torrent-name x-deluge-{0}">{1}</div>',
+c.data.state.toLowerCase(),Ext.util.Format.htmlEncode(a))},dataIndex:"name"},{header:_("Size"),width:75,sortable:!0,renderer:fsize,dataIndex:"total_wanted"},{header:_("Progress"),width:150,sortable:!0,renderer:function(a,b,c){a=new Number(a);c=_(c.data.state)+" "+a.toFixed(2)+"%";b=new Number((this.style?this.style:b.style).match(/\w+:\s*(\d+)\w+/)[1]);return Deluge.progressBar(a,b-8,c)},dataIndex:"progress"},{header:_("Seeds"),hidden:!0,width:60,sortable:!0,renderer:function(a,b,c){return-1<c.data.total_seeds?
+String.format("{0} ({1})",a,c.data.total_seeds):a},dataIndex:"num_seeds"},{header:_("Peers"),hidden:!0,width:60,sortable:!0,renderer:function(a,b,c){return-1<c.data.total_peers?String.format("{0} ({1})",a,c.data.total_peers):a},dataIndex:"num_peers"},{header:_("Down Speed"),width:80,sortable:!0,renderer:a,dataIndex:"download_payload_rate"},{header:_("Up Speed"),width:80,sortable:!0,renderer:a,dataIndex:"upload_payload_rate"},{header:_("ETA"),width:60,sortable:!0,renderer:function(a){return 0===a?
+"":-1>=a?"&infin;":ftime(a)},dataIndex:"eta"},{header:_("Ratio"),hidden:!0,width:60,sortable:!0,renderer:c,dataIndex:"ratio"},{header:_("Avail"),hidden:!0,width:60,sortable:!0,renderer:c,dataIndex:"distributed_copies"},{header:_("Added"),hidden:!0,width:80,sortable:!0,renderer:fdate,dataIndex:"time_added"},{header:_("Complete Seen"),hidden:!0,width:80,sortable:!0,renderer:d,dataIndex:"last_seen_complete"},{header:_("Completed"),hidden:!0,width:80,sortable:!0,renderer:d,dataIndex:"completed_time"},
+{header:_("Tracker"),hidden:!0,width:120,sortable:!0,renderer:function(a,b,c){return String.format('<div style="background: url('+deluge.config.base+'tracker/{0}) no-repeat; padding-left: 20px;">{0}</div>',Ext.util.Format.htmlEncode(a))},dataIndex:"tracker_host"},{header:_("Download Folder"),hidden:!0,width:120,sortable:!0,renderer:fplain,dataIndex:"download_location"},{header:_("Owner"),width:80,sortable:!0,renderer:fplain,dataIndex:"owner"},{header:_("Public"),hidden:!0,width:80,sortable:!0,renderer:fplain,
+dataIndex:"public"},{header:_("Shared"),hidden:!0,width:80,sortable:!0,renderer:fplain,dataIndex:"shared"},{header:_("Downloaded"),hidden:!0,width:75,sortable:!0,renderer:fsize,dataIndex:"total_done"},{header:_("Uploaded"),hidden:!0,width:75,sortable:!0,renderer:fsize,dataIndex:"total_uploaded"},{header:_("Remaining"),hidden:!0,width:75,sortable:!0,renderer:fsize,dataIndex:"total_remaining"},{header:_("Down Limit"),hidden:!0,width:75,sortable:!0,renderer:b,dataIndex:"max_download_speed"},{header:_("Up Limit"),
+hidden:!0,width:75,sortable:!0,renderer:b,dataIndex:"max_upload_speed"},{header:_("Seeds:Peers"),hidden:!0,width:75,sortable:!0,renderer:c,dataIndex:"seeds_peers_ratio"},{header:_("Last Transfer"),hidden:!0,width:75,sortable:!0,renderer:ftime,dataIndex:"time_since_transfer"}],meta:{root:"torrents",idProperty:"id",fields:[{name:"queue",sortType:Deluge.data.SortTypes.asQueuePosition},{name:"name",sortType:Deluge.data.SortTypes.asName},{name:"total_wanted",type:"int"},{name:"state"},{name:"progress",
+type:"float"},{name:"num_seeds",type:"int"},{name:"total_seeds",type:"int"},{name:"num_peers",type:"int"},{name:"total_peers",type:"int"},{name:"download_payload_rate",type:"int"},{name:"upload_payload_rate",type:"int"},{name:"eta",type:"int",sortType:function(a){return 0===a?Number.MAX_VALUE:-1>=a?Number.MAX_SAFE_INTEGER:a}},{name:"ratio",type:"float"},{name:"distributed_copies",type:"float"},{name:"time_added",type:"int"},{name:"last_seen_complete",type:"int"},{name:"completed_time",type:"int"},
+{name:"tracker_host"},{name:"download_location"},{name:"total_done",type:"int"},{name:"total_uploaded",type:"int"},{name:"total_remaining",type:"int"},{name:"max_download_speed",type:"int"},{name:"max_upload_speed",type:"int"},{name:"seeds_peers_ratio",type:"float"},{name:"time_since_transfer",type:"int"}]},keys:[{key:"a",ctrl:!0,stopEvent:!0,handler:function(){deluge.torrents.getSelectionModel().selectAll()}},{key:[46],stopEvent:!0,handler:function(){ids=deluge.torrents.getSelectedIds();deluge.removeWindow.show(ids)}}],
+constructor:function(a){a=Ext.apply({id:"torrentGrid",store:new Ext.data.JsonStore(this.meta),columns:this.columns,keys:this.keys,region:"center",cls:"deluge-torrents",stripeRows:!0,autoExpandColumn:"name",autoExpandMin:150,deferredRender:!1,autoScroll:!0,stateful:!0,view:new Ext.ux.grid.BufferView({rowHeight:26,scrollDelay:!1})},a);Deluge.TorrentGrid.superclass.constructor.call(this,a)},initComponent:function(){Deluge.TorrentGrid.superclass.initComponent.call(this);deluge.events.on("torrentsRemoved",
+this.onTorrentsRemoved,this);deluge.events.on("disconnect",this.onDisconnect,this);this.on("rowcontextmenu",function(a,b,c){c.stopEvent();a=a.getSelectionModel();a.isSelected(b)||a.selectRow(b);deluge.menus.torrent.showAt(c.getPoint())})},getTorrent:function(a){return this.getStore().getAt(a)},getSelected:function(){return this.getSelectionModel().getSelected()},getSelections:function(){return this.getSelectionModel().getSelections()},getSelectedId:function(){return this.getSelectionModel().getSelected().id},
+getSelectedIds:function(){var a=[];Ext.each(this.getSelectionModel().getSelections(),function(b){a.push(b.id)});return a},update:function(a,b){var c=this.getStore();b&&(c.removeAll(),this.torrents={});var d=[],h;for(h in a){var m=a[h];if(this.torrents[h]){var k=c.getById(h);k.beginEdit();for(var n in m)k.get(n)!=m[n]&&k.set(n,m[n]);k.endEdit()}else k=new Deluge.data.Torrent(m),k.id=h,this.torrents[h]=1,d.push(k)}c.add(d);c.each(function(b){a[b.id]||(c.remove(b),delete this.torrents[b.id])},this);
+c.commitChanges();(d=c.getSortState())&&c.sort(d.field,d.direction)},onDisconnect:function(){this.getStore().removeAll();this.torrents={}},onTorrentsRemoved:function(a){var b=this.getSelectionModel();Ext.each(a,function(a){var c=this.getStore().getById(a);b.isSelected(c)&&b.deselectRow(this.getStore().indexOf(c));this.getStore().remove(c);delete this.torrents[a]},this)}});deluge.torrents=new Deluge.TorrentGrid})();
+var TORRENT_STATE_TRANSLATION=[_("All"),_("Active"),_("Allocating"),_("Checking"),_("Downloading"),_("Seeding"),_("Paused"),_("Checking"),_("Queued"),_("Error")];
+deluge.ui={errorCount:0,filters:null,initialize:function(){deluge.add=new Deluge.add.AddWindow;deluge.details=new Deluge.details.DetailsPanel;deluge.connectionManager=new Deluge.ConnectionManager;deluge.editTrackers=new Deluge.EditTrackersWindow;deluge.login=new Deluge.LoginWindow;deluge.preferences=new Deluge.preferences.PreferencesWindow;deluge.sidebar=new Deluge.Sidebar;deluge.statusbar=new Deluge.Statusbar;deluge.toolbar=new Deluge.Toolbar;this.detailsPanel=new Ext.Panel({id:"detailsPanel",cls:"detailsPanel",
+region:"south",split:!0,height:215,minSize:100,collapsible:!0,layout:"fit",items:[deluge.details]});this.MainPanel=new Ext.Panel({id:"mainPanel",iconCls:"x-deluge-main-panel",layout:"border",border:!1,tbar:deluge.toolbar,items:[deluge.sidebar,this.detailsPanel,deluge.torrents],bbar:deluge.statusbar});this.Viewport=new Ext.Viewport({layout:"fit",items:[this.MainPanel]});deluge.events.on("connect",this.onConnect,this);deluge.events.on("disconnect",this.onDisconnect,this);deluge.events.on("PluginDisabledEvent",
+this.onPluginDisabled,this);deluge.events.on("PluginEnabledEvent",this.onPluginEnabled,this);deluge.client=new Ext.ux.util.RpcClient({url:deluge.config.base+"json"});for(var a in Deluge.pluginStore)a=Deluge.createPlugin(a),a.enable(),deluge.plugins[a.name]=a;Ext.QuickTips.init();deluge.client.on("connected",function(a){deluge.login.show()},this,{single:!0});this.update=this.update.createDelegate(this);this.checkConnection=this.checkConnection.createDelegate(this);this.originalTitle=document.title},
+checkConnection:function(){deluge.client.web.connected({success:this.onConnectionSuccess,failure:this.onConnectionError,scope:this})},update:function(){var a=deluge.sidebar.getFilterStates();this.oldFilters=this.filters;this.filters=a;deluge.client.web.update_ui(Deluge.Keys.Grid,a,{success:this.onUpdate,failure:this.onUpdateError,scope:this});deluge.details.update()},onConnectionError:function(a){},onConnectionSuccess:function(a){deluge.statusbar.setStatus({iconCls:"x-deluge-statusbar icon-ok",text:_("Connection restored")});
+clearInterval(this.checking);a||deluge.connectionManager.show()},onUpdateError:function(a){2==this.errorCount&&(Ext.MessageBox.show({title:_("Lost Connection"),msg:_("The connection to the webserver has been lost!"),buttons:Ext.MessageBox.OK,icon:Ext.MessageBox.ERROR}),deluge.events.fire("disconnect"),deluge.statusbar.setStatus({text:_("Lost connection to webserver")}),this.checking=setInterval(this.checkConnection,2E3));this.errorCount++},onUpdate:function(a){a.connected?(deluge.config.show_session_speed&&
+(document.title="D: "+fsize_short(a.stats.download_rate,!0)+" U: "+fsize_short(a.stats.upload_rate,!0)+" - "+this.originalTitle),Ext.areObjectsEqual(this.filters,this.oldFilters)?deluge.torrents.update(a.torrents):deluge.torrents.update(a.torrents,!0),deluge.statusbar.update(a.stats),deluge.sidebar.update(a.filters),this.errorCount=0):deluge.connectionManager.disconnect(!0)},onConnect:function(){this.running||(this.running=setInterval(this.update,2E3),this.update());deluge.client.web.get_plugins({success:this.onGotPlugins,
+scope:this})},onDisconnect:function(){this.stop()},onGotPlugins:function(a){Ext.each(a.enabled_plugins,function(a){deluge.plugins[a]||deluge.client.web.get_plugin_resources(a,{success:this.onGotPluginResources,scope:this})},this)},onPluginEnabled:function(a){deluge.plugins[a]?deluge.plugins[a].enable():deluge.client.web.get_plugin_resources(a,{success:this.onGotPluginResources,scope:this})},onGotPluginResources:function(a){Ext.each(Deluge.debug?a.debug_scripts:a.scripts,function(b){Ext.ux.JSLoader({url:deluge.config.base+
+b,onLoad:this.onPluginLoaded,pluginName:a.name})},this)},onPluginDisabled:function(a){deluge.plugins[a]&&deluge.plugins[a].disable()},onPluginLoaded:function(a){Deluge.hasPlugin(a.pluginName)&&(plugin=Deluge.createPlugin(a.pluginName),plugin.enable(),deluge.plugins[plugin.name]=plugin)},stop:function(){this.running&&(clearInterval(this.running),this.running=!1,deluge.torrents.getStore().removeAll())}};Ext.onReady(function(a){deluge.ui.initialize()});
diff --git a/deluge/ui/web/js/deluge-all/AboutWindow.js b/deluge/ui/web/js/deluge-all/AboutWindow.js
index 5376d05..cfae7a8 100644
--- a/deluge/ui/web/js/deluge-all/AboutWindow.js
+++ b/deluge/ui/web/js/deluge-all/AboutWindow.js
@@ -28,16 +28,16 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
},
buttonAlign: 'center',
- initComponent: function() {
+ initComponent: function () {
Deluge.about.AboutWindow.superclass.initComponent.call(this);
this.addEvents({
build_ready: true,
});
var self = this;
- var libtorrent = function() {
+ var libtorrent = function () {
deluge.client.core.get_libtorrent_version({
- success: function(lt_version) {
+ success: function (lt_version) {
comment += '<br/>' + _('libtorrent:') + ' ' + lt_version;
Ext.getCmp('about_comment').setText(comment, false);
self.fireEvent('build_ready');
@@ -57,10 +57,10 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
client_version +
'<br/>';
deluge.client.web.connected({
- success: function(connected) {
+ success: function (connected) {
if (connected) {
deluge.client.daemon.get_version({
- success: function(server_version) {
+ success: function (server_version) {
comment +=
_('Server:') + ' ' + server_version + '<br/>';
libtorrent();
@@ -70,7 +70,7 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
this.fireEvent('build_ready');
}
},
- failure: function() {
+ failure: function () {
this.fireEvent('build_ready');
},
scope: this,
@@ -104,26 +104,25 @@ Deluge.about.AboutWindow = Ext.extend(Ext.Window, {
{
xtype: 'label',
style: 'padding-top: 5px; font-size: 12px;',
- html:
- '<a href="https://deluge-torrent.org" target="_blank">deluge-torrent.org</a>',
+ html: '<a href="https://deluge-torrent.org" target="_blank">deluge-torrent.org</a>',
},
]);
this.addButton(_('Close'), this.onCloseClick, this);
},
- show: function() {
- this.on('build_ready', function() {
+ show: function () {
+ this.on('build_ready', function () {
Deluge.about.AboutWindow.superclass.show.call(this);
});
},
- onCloseClick: function() {
+ onCloseClick: function () {
this.close();
},
});
Ext.namespace('Deluge');
-Deluge.About = function() {
+Deluge.About = function () {
new Deluge.about.AboutWindow().show();
};
diff --git a/deluge/ui/web/js/deluge-all/AddConnectionWindow.js b/deluge/ui/web/js/deluge-all/AddConnectionWindow.js
index 6d26370..4d821f2 100644
--- a/deluge/ui/web/js/deluge-all/AddConnectionWindow.js
+++ b/deluge/ui/web/js/deluge-all/AddConnectionWindow.js
@@ -24,7 +24,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
bodyStyle: 'padding: 10px 5px;',
closeAction: 'hide',
- initComponent: function() {
+ initComponent: function () {
Deluge.AddConnectionWindow.superclass.initComponent.call(this);
this.addEvents('hostadded');
@@ -80,7 +80,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
});
},
- onAddClick: function() {
+ onAddClick: function () {
var values = this.form.getForm().getValues();
deluge.client.web.add_host(
values.host,
@@ -88,7 +88,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
values.username,
values.password,
{
- success: function(result) {
+ success: function (result) {
if (!result[0]) {
Ext.MessageBox.show({
title: _('Error'),
@@ -111,7 +111,7 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
);
},
- onHide: function() {
+ onHide: function () {
this.form.getForm().reset();
},
});
diff --git a/deluge/ui/web/js/deluge-all/AddTrackerWindow.js b/deluge/ui/web/js/deluge-all/AddTrackerWindow.js
index c9c835d..aaf4a3f 100644
--- a/deluge/ui/web/js/deluge-all/AddTrackerWindow.js
+++ b/deluge/ui/web/js/deluge-all/AddTrackerWindow.js
@@ -10,9 +10,10 @@
Ext.ns('Deluge');
// Custom VType validator for tracker urls
-var trackerUrlTest = /(((^https?)|(^udp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
+var trackerUrlTest =
+ /(((^https?)|(^udp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
Ext.apply(Ext.form.VTypes, {
- trackerUrl: function(val, field) {
+ trackerUrl: function (val, field) {
return trackerUrlTest.test(val);
},
trackerUrlText: 'Not a valid tracker url',
@@ -36,7 +37,7 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
closeAction: 'hide',
iconCls: 'x-deluge-edit-trackers',
- initComponent: function() {
+ initComponent: function () {
Deluge.AddTrackerWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
@@ -59,17 +60,14 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
});
},
- onAddClick: function() {
- var trackers = this.form
- .getForm()
- .findField('trackers')
- .getValue();
+ onAddClick: function () {
+ var trackers = this.form.getForm().findField('trackers').getValue();
trackers = trackers.split('\n');
var cleaned = [];
Ext.each(
trackers,
- function(tracker) {
+ function (tracker) {
if (Ext.form.VTypes.trackerUrl(tracker)) {
cleaned.push(tracker);
}
@@ -78,17 +76,11 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
);
this.fireEvent('add', cleaned);
this.hide();
- this.form
- .getForm()
- .findField('trackers')
- .setValue('');
+ this.form.getForm().findField('trackers').setValue('');
},
- onCancelClick: function() {
- this.form
- .getForm()
- .findField('trackers')
- .setValue('');
+ onCancelClick: function () {
+ this.form.getForm().findField('trackers').setValue('');
this.hide();
},
});
diff --git a/deluge/ui/web/js/deluge-all/Client.js b/deluge/ui/web/js/deluge-all/Client.js
index bcabbae..a06e863 100644
--- a/deluge/ui/web/js/deluge-all/Client.js
+++ b/deluge/ui/web/js/deluge-all/Client.js
@@ -31,7 +31,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
* Fires when the client has retrieved the list of methods from the server.
* @param {Ext.ux.util.RpcClient} this
*/
- constructor: function(config) {
+ constructor: function (config) {
Ext.ux.util.RpcClient.superclass.constructor.call(this, config);
this._url = config.url || null;
this._id = 0;
@@ -44,14 +44,14 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
this.reloadMethods();
},
- reloadMethods: function() {
+ reloadMethods: function () {
this._execute('system.listMethods', {
success: this._setMethods,
scope: this,
});
},
- _execute: function(method, options) {
+ _execute: function (method, options) {
options = options || {};
options.params = options.params || [];
options.id = this._id;
@@ -74,7 +74,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
});
},
- _onFailure: function(response, requestOptions) {
+ _onFailure: function (response, requestOptions) {
var options = requestOptions.options;
errorObj = {
id: options.id,
@@ -100,7 +100,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}
},
- _onSuccess: function(response, requestOptions) {
+ _onSuccess: function (response, requestOptions) {
var responseObj = Ext.decode(response.responseText);
var options = requestOptions.options;
if (responseObj.error) {
@@ -138,9 +138,9 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}
},
- _parseArgs: function(args) {
+ _parseArgs: function (args) {
var params = [];
- Ext.each(args, function(arg) {
+ Ext.each(args, function (arg) {
params.push(arg);
});
@@ -149,7 +149,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
var keys = Ext.keys(options),
isOption = false;
- Ext.each(this._optionKeys, function(key) {
+ Ext.each(this._optionKeys, function (key) {
if (keys.indexOf(key) > -1) isOption = true;
});
@@ -165,15 +165,15 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
return options;
},
- _setMethods: function(methods) {
+ _setMethods: function (methods) {
var components = {},
self = this;
- Ext.each(methods, function(method) {
+ Ext.each(methods, function (method) {
var parts = method.split('.');
var component = components[parts[0]] || {};
- var fn = function() {
+ var fn = function () {
var options = self._parseArgs(arguments);
return self._execute(method, options);
};
@@ -186,7 +186,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}
Ext.each(
this._components,
- function(component) {
+ function (component) {
if (!component in components) {
delete this[component];
}
diff --git a/deluge/ui/web/js/deluge-all/ConnectionManager.js b/deluge/ui/web/js/deluge-all/ConnectionManager.js
index 001e46b..5261726 100644
--- a/deluge/ui/web/js/deluge-all/ConnectionManager.js
+++ b/deluge/ui/web/js/deluge-all/ConnectionManager.js
@@ -21,7 +21,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
title: _('Connection Manager'),
iconCls: 'x-deluge-connect-window-icon',
- initComponent: function() {
+ initComponent: function () {
Deluge.ConnectionManager.superclass.initComponent.call(this);
this.on('hide', this.onHide, this);
this.on('show', this.onShow, this);
@@ -133,9 +133,9 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
* Check to see if the the web interface is currently connected
* to a Deluge Daemon and show the Connection Manager if not.
*/
- checkConnected: function() {
+ checkConnected: function () {
deluge.client.web.connected({
- success: function(connected) {
+ success: function (connected) {
if (connected) {
deluge.events.fire('connect');
} else {
@@ -146,7 +146,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
});
},
- disconnect: function(show) {
+ disconnect: function (show) {
deluge.events.fire('disconnect');
if (show) {
if (this.isVisible()) return;
@@ -154,15 +154,15 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
}
},
- loadHosts: function() {
+ loadHosts: function () {
deluge.client.web.get_hosts({
success: this.onGetHosts,
scope: this,
});
},
- update: function() {
- this.list.getStore().each(function(r) {
+ update: function () {
+ this.list.getStore().each(function (r) {
deluge.client.web.get_host_status(r.id, {
success: this.onGetHostStatus,
scope: this,
@@ -175,7 +175,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
* passed in records host state.
* @param {Ext.data.Record} record The hosts record to update the UI for
*/
- updateButtons: function(record) {
+ updateButtons: function (record) {
var button = this.buttons[1],
status = record.get('status');
@@ -209,7 +209,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onAddClick: function(button, e) {
+ onAddClick: function (button, e) {
if (!this.addWindow) {
this.addWindow = new Deluge.AddConnectionWindow();
this.addWindow.on('hostadded', this.onHostChange, this);
@@ -218,7 +218,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onEditClick: function(button, e) {
+ onEditClick: function (button, e) {
var connection = this.list.getSelectedRecords()[0];
if (!connection) return;
@@ -230,24 +230,24 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onHostChange: function() {
+ onHostChange: function () {
this.loadHosts();
},
// private
- onClose: function(e) {
+ onClose: function (e) {
this.hide();
},
// private
- onConnect: function(e) {
+ onConnect: function (e) {
var selected = this.list.getSelectedRecords()[0];
if (!selected) return;
var me = this;
- var disconnect = function() {
+ var disconnect = function () {
deluge.client.web.disconnect({
- success: function(result) {
+ success: function (result) {
this.update(this);
deluge.events.fire('disconnect');
},
@@ -268,11 +268,11 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
var id = selected.id;
deluge.client.web.connect(id, {
- success: function(methods) {
+ success: function (methods) {
deluge.client.reloadMethods();
deluge.client.on(
'connected',
- function(e) {
+ function (e) {
deluge.events.fire('connect');
},
this,
@@ -285,11 +285,11 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onGetHosts: function(hosts) {
+ onGetHosts: function (hosts) {
this.list.getStore().loadData(hosts);
Ext.each(
hosts,
- function(host) {
+ function (host) {
deluge.client.web.get_host_status(host[0], {
success: this.onGetHostStatus,
scope: this,
@@ -300,7 +300,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onGetHostStatus: function(host) {
+ onGetHostStatus: function (host) {
var record = this.list.getStore().getById(host[0]);
record.set('status', host[1]);
record.set('version', host[2]);
@@ -311,19 +311,19 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onHide: function() {
+ onHide: function () {
if (this.running) window.clearInterval(this.running);
},
// private
- onLogin: function() {
+ onLogin: function () {
if (deluge.config.first_login) {
Ext.MessageBox.confirm(
_('Change Default Password'),
_(
'We recommend changing the default password.<br><br>Would you like to change it now?'
),
- function(res) {
+ function (res) {
this.checkConnected();
if (res == 'yes') {
deluge.preferences.show();
@@ -339,7 +339,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onLogout: function() {
+ onLogout: function () {
this.disconnect();
if (!this.hidden && this.rendered) {
this.hide();
@@ -347,12 +347,12 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onRemoveClick: function(button) {
+ onRemoveClick: function (button) {
var connection = this.list.getSelectedRecords()[0];
if (!connection) return;
deluge.client.web.remove_host(connection.id, {
- success: function(result) {
+ success: function (result) {
if (!result) {
Ext.MessageBox.show({
title: _('Error'),
@@ -371,7 +371,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onSelectionChanged: function(list, selections) {
+ onSelectionChanged: function (list, selections) {
if (selections[0]) {
this.editHostButton.enable();
this.removeHostButton.enable();
@@ -387,7 +387,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// FIXME: Find out why this is being fired twice
// private
- onShow: function() {
+ onShow: function () {
if (!this.addHostButton) {
var bbar = this.panel.getBottomToolbar();
this.addHostButton = bbar.items.get('cm-add');
@@ -401,7 +401,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
},
// private
- onStopClick: function(button, e) {
+ onStopClick: function (button, e) {
var connection = this.list.getSelectedRecords()[0];
if (!connection) return;
@@ -411,7 +411,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
} else {
// This means we need to stop the daemon
deluge.client.web.stop_daemon(connection.id, {
- success: function(result) {
+ success: function (result) {
if (!result[0]) {
Ext.MessageBox.show({
title: _('Error'),
diff --git a/deluge/ui/web/js/deluge-all/CopyMagnetWindow.js b/deluge/ui/web/js/deluge-all/CopyMagnetWindow.js
new file mode 100644
index 0000000..ddcd4ab
--- /dev/null
+++ b/deluge/ui/web/js/deluge-all/CopyMagnetWindow.js
@@ -0,0 +1,73 @@
+/*
+ * Deluge.CopyMagnet.js
+ *
+ * Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the OpenSSL
+ * library.
+ * You must obey the GNU General Public License in all respects for all of
+ * the code used other than OpenSSL. If you modify file(s) with this
+ * exception, you may extend this exception to your version of the file(s),
+ * but you are not obligated to do so. If you do not wish to do so, delete
+ * this exception statement from your version. If you delete this exception
+ * statement from all source files in the program, then also delete it here.
+ */
+Deluge.CopyMagnet = Ext.extend(Ext.Window, {
+ title: _('Copy Magnet URI'),
+ width: 375,
+ closeAction: 'hide',
+ iconCls: 'icon-magnet-copy',
+
+ initComponent: function () {
+ Deluge.CopyMagnet.superclass.initComponent.call(this);
+ form = this.add({
+ xtype: 'form',
+ defaultType: 'textfield',
+ hideLabels: true,
+ });
+ this.magnetURI = form.add({
+ name: 'URI',
+ anchor: '100%',
+ });
+ this.addButton(_('Close'), this.onClose, this);
+ this.addButton(_('Copy'), this.onCopy, this);
+ },
+ show: function (a) {
+ Deluge.CopyMagnet.superclass.show.call(this);
+ var torrent = deluge.torrents.getSelected();
+ deluge.client.core.get_magnet_uri(torrent.id, {
+ success: this.onRequestComplete,
+ scope: this,
+ });
+ },
+ onRequestComplete: function (uri) {
+ this.magnetURI.setValue(uri);
+ },
+ onCopy: function () {
+ this.magnetURI.focus();
+ this.magnetURI.el.dom.select();
+ document.execCommand('copy');
+ },
+ onClose: function () {
+ this.hide();
+ },
+});
+
+deluge.copyMagnetWindow = new Deluge.CopyMagnet();
diff --git a/deluge/ui/web/js/deluge-all/Deluge.js b/deluge/ui/web/js/deluge-all/Deluge.js
index 31b9947..260ad97 100644
--- a/deluge/ui/web/js/deluge-all/Deluge.js
+++ b/deluge/ui/web/js/deluge-all/Deluge.js
@@ -25,21 +25,14 @@ Ext.state.Manager.setProvider(
// Add some additional functions to ext and setup some of the
// configurable parameters
Ext.apply(Ext, {
- escapeHTML: function(text) {
- text = String(text)
- .replace('<', '&lt;')
- .replace('>', '&gt;');
- return text.replace('&', '&amp;');
- },
-
- isObjectEmpty: function(obj) {
+ isObjectEmpty: function (obj) {
for (var i in obj) {
return false;
}
return true;
},
- areObjectsEqual: function(obj1, obj2) {
+ areObjectsEqual: function (obj1, obj2) {
var equal = true;
if (!obj1 || !obj2) return false;
for (var i in obj1) {
@@ -50,7 +43,7 @@ Ext.apply(Ext, {
return equal;
},
- keys: function(obj) {
+ keys: function (obj) {
var keys = [];
for (var i in obj)
if (obj.hasOwnProperty(i)) {
@@ -59,7 +52,7 @@ Ext.apply(Ext, {
return keys;
},
- values: function(obj) {
+ values: function (obj) {
var values = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
@@ -69,7 +62,7 @@ Ext.apply(Ext, {
return values;
},
- splat: function(obj) {
+ splat: function (obj) {
var type = Ext.type(obj);
return type ? (type != 'array' ? [obj] : obj) : [];
},
@@ -106,7 +99,7 @@ Ext.apply(Deluge, {
* @param {String} text The text to display on the bar
* @param {Number} modified Amount to subtract from the width allowing for fixes
*/
- progressBar: function(progress, width, text, modifier) {
+ progressBar: function (progress, width, text, modifier) {
modifier = Ext.value(modifier, 10);
var progressWidth = ((width / 100.0) * progress).toFixed(0);
var barWidth = progressWidth - 1;
@@ -125,7 +118,7 @@ Ext.apply(Deluge, {
* Constructs a new instance of the specified plugin.
* @param {String} name The plugin name to create
*/
- createPlugin: function(name) {
+ createPlugin: function (name) {
return new Deluge.pluginStore[name]();
},
@@ -133,7 +126,7 @@ Ext.apply(Deluge, {
* Check to see if a plugin has been registered.
* @param {String} name The plugin name to check
*/
- hasPlugin: function(name) {
+ hasPlugin: function (name) {
return Deluge.pluginStore[name] ? true : false;
},
@@ -142,7 +135,7 @@ Ext.apply(Deluge, {
* @param {String} name The plugin name to register
* @param {Plugin} plugin The plugin to register
*/
- registerPlugin: function(name, plugin) {
+ registerPlugin: function (name, plugin) {
Deluge.pluginStore[name] = plugin;
},
});
diff --git a/deluge/ui/web/js/deluge-all/EditConnectionWindow.js b/deluge/ui/web/js/deluge-all/EditConnectionWindow.js
index 63bd305..bfeb38f 100644
--- a/deluge/ui/web/js/deluge-all/EditConnectionWindow.js
+++ b/deluge/ui/web/js/deluge-all/EditConnectionWindow.js
@@ -24,7 +24,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
bodyStyle: 'padding: 10px 5px;',
closeAction: 'hide',
- initComponent: function() {
+ initComponent: function () {
Deluge.EditConnectionWindow.superclass.initComponent.call(this);
this.addEvents('hostedited');
@@ -80,17 +80,11 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
});
},
- show: function(connection) {
+ show: function (connection) {
Deluge.EditConnectionWindow.superclass.show.call(this);
- this.form
- .getForm()
- .findField('host')
- .setValue(connection.get('host'));
- this.form
- .getForm()
- .findField('port')
- .setValue(connection.get('port'));
+ this.form.getForm().findField('host').setValue(connection.get('host'));
+ this.form.getForm().findField('port').setValue(connection.get('port'));
this.form
.getForm()
.findField('username')
@@ -98,7 +92,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
this.host_id = connection.id;
},
- onEditClick: function() {
+ onEditClick: function () {
var values = this.form.getForm().getValues();
deluge.client.web.edit_host(
this.host_id,
@@ -107,7 +101,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
values.username,
values.password,
{
- success: function(result) {
+ success: function (result) {
if (!result) {
console.log(result);
Ext.MessageBox.show({
@@ -128,7 +122,7 @@ Deluge.EditConnectionWindow = Ext.extend(Ext.Window, {
);
},
- onHide: function() {
+ onHide: function () {
this.form.getForm().reset();
},
});
diff --git a/deluge/ui/web/js/deluge-all/EditTrackerWindow.js b/deluge/ui/web/js/deluge-all/EditTrackerWindow.js
index 82bc32c..646b8de 100644
--- a/deluge/ui/web/js/deluge-all/EditTrackerWindow.js
+++ b/deluge/ui/web/js/deluge-all/EditTrackerWindow.js
@@ -27,7 +27,7 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
closeAction: 'hide',
iconCls: 'x-deluge-edit-trackers',
- initComponent: function() {
+ initComponent: function () {
Deluge.EditTrackerWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
@@ -50,32 +50,23 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
});
},
- show: function(record) {
+ show: function (record) {
Deluge.EditTrackerWindow.superclass.show.call(this);
this.record = record;
- this.form
- .getForm()
- .findField('tracker')
- .setValue(record.data['url']);
+ this.form.getForm().findField('tracker').setValue(record.data['url']);
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.hide();
},
- onHide: function() {
- this.form
- .getForm()
- .findField('tracker')
- .setValue('');
+ onHide: function () {
+ this.form.getForm().findField('tracker').setValue('');
},
- onSaveClick: function() {
- var url = this.form
- .getForm()
- .findField('tracker')
- .getValue();
+ onSaveClick: function () {
+ var url = this.form.getForm().findField('tracker').getValue();
this.record.set('url', url);
this.record.commit();
this.hide();
diff --git a/deluge/ui/web/js/deluge-all/EditTrackersWindow.js b/deluge/ui/web/js/deluge-all/EditTrackersWindow.js
index 47ffa86..178fd58 100644
--- a/deluge/ui/web/js/deluge-all/EditTrackersWindow.js
+++ b/deluge/ui/web/js/deluge-all/EditTrackersWindow.js
@@ -10,7 +10,7 @@
Ext.ns('Deluge');
/**
- * @class Deluge.EditTrackerWindow
+ * @class Deluge.EditTrackersWindow
* @extends Ext.Window
*/
Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
@@ -28,7 +28,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
closeAction: 'hide',
iconCls: 'x-deluge-edit-trackers',
- initComponent: function() {
+ initComponent: function () {
Deluge.EditTrackersWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
@@ -57,6 +57,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
header: _('Tracker'),
width: 0.9,
dataIndex: 'url',
+ tpl: new Ext.XTemplate('{url:htmlEncode}'),
},
],
columnSort: {
@@ -111,18 +112,18 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
});
},
- onAddClick: function() {
+ onAddClick: function () {
this.addWindow.show();
},
- onAddTrackers: function(trackers) {
+ onAddTrackers: function (trackers) {
var store = this.list.getStore();
Ext.each(
trackers,
- function(tracker) {
+ function (tracker) {
var duplicate = false,
heightestTier = -1;
- store.each(function(record) {
+ store.each(function (record) {
if (record.get('tier') > heightestTier) {
heightestTier = record.get('tier');
}
@@ -143,27 +144,27 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
);
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.hide();
},
- onEditClick: function() {
+ onEditClick: function () {
var selected = this.list.getSelectedRecords()[0];
if (!selected) return;
this.editWindow.show(selected);
},
- onHide: function() {
+ onHide: function () {
this.list.getStore().removeAll();
},
- onListNodeDblClicked: function(list, index, node, e) {
+ onListNodeDblClicked: function (list, index, node, e) {
this.editWindow.show(this.list.getRecord(node));
},
- onOkClick: function() {
+ onOkClick: function () {
var trackers = [];
- this.list.getStore().each(function(record) {
+ this.list.getStore().each(function (record) {
trackers.push({
tier: record.get('tier'),
url: record.get('url'),
@@ -178,34 +179,28 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
this.hide();
},
- onRemoveClick: function() {
+ onRemoveClick: function () {
// Remove from the grid
var selected = this.list.getSelectedRecords()[0];
if (!selected) return;
this.list.getStore().remove(selected);
},
- onRequestComplete: function(status) {
+ onRequestComplete: function (status) {
this.list.getStore().loadData(status);
this.list.getStore().sort('tier', 'ASC');
},
- onSaveFail: function() {},
+ onSaveFail: function () {},
- onSelect: function(list) {
+ onSelect: function (list) {
if (list.getSelectionCount()) {
- this.panel
- .getBottomToolbar()
- .items.get(4)
- .enable();
+ this.panel.getBottomToolbar().items.get(4).enable();
}
},
- onShow: function() {
- this.panel
- .getBottomToolbar()
- .items.get(4)
- .disable();
+ onShow: function () {
+ this.panel.getBottomToolbar().items.get(4).disable();
var r = deluge.torrents.getSelected();
this.torrentId = r.id;
deluge.client.core.get_torrent_status(r.id, ['trackers'], {
@@ -214,7 +209,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
});
},
- onDownClick: function() {
+ onDownClick: function () {
var r = this.list.getSelectedRecords()[0];
if (!r) return;
@@ -225,7 +220,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
this.list.select(r.store.indexOf(r));
},
- onUpClick: function() {
+ onUpClick: function () {
var r = this.list.getSelectedRecords()[0];
if (!r) return;
diff --git a/deluge/ui/web/js/deluge-all/EventsManager.js b/deluge/ui/web/js/deluge-all/EventsManager.js
index 1714339..89d8980 100644
--- a/deluge/ui/web/js/deluge-all/EventsManager.js
+++ b/deluge/ui/web/js/deluge-all/EventsManager.js
@@ -15,7 +15,7 @@
* Class for holding global events that occur within the UI.
*/
Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
- constructor: function() {
+ constructor: function () {
this.toRegister = [];
this.on('login', this.onLogin, this);
Deluge.EventsManager.superclass.constructor.call(this);
@@ -24,7 +24,7 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
/**
* Append an event handler to this object.
*/
- addListener: function(eventName, fn, scope, o) {
+ addListener: function (eventName, fn, scope, o) {
this.addEvents(eventName);
if (/[A-Z]/.test(eventName.substring(0, 1))) {
if (!deluge.client) {
@@ -42,7 +42,7 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
);
},
- getEvents: function() {
+ getEvents: function () {
deluge.client.web.get_events({
success: this.onGetEventsSuccess,
failure: this.onGetEventsFailure,
@@ -53,8 +53,8 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
/**
* Starts the EventsManagerManager checking for events.
*/
- start: function() {
- Ext.each(this.toRegister, function(eventName) {
+ start: function () {
+ Ext.each(this.toRegister, function (eventName) {
deluge.client.web.register_event_listener(eventName);
});
this.running = true;
@@ -65,21 +65,21 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
/**
* Stops the EventsManagerManager checking for events.
*/
- stop: function() {
+ stop: function () {
this.running = false;
},
// private
- onLogin: function() {
+ onLogin: function () {
this.start();
},
- onGetEventsSuccess: function(events) {
+ onGetEventsSuccess: function (events) {
if (!this.running) return;
if (events) {
Ext.each(
events,
- function(event) {
+ function (event) {
var name = event[0],
args = event[1];
args.splice(0, 0, name);
@@ -92,7 +92,7 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
},
// private
- onGetEventsFailure: function(result, error) {
+ onGetEventsFailure: function (result, error) {
// the request timed out or we had a communication failure
if (!this.running) return;
if (!error.isTimeout && this.errorCount++ >= 3) {
diff --git a/deluge/ui/web/js/deluge-all/FileBrowser.js b/deluge/ui/web/js/deluge-all/FileBrowser.js
index 72962a6..2afe1b1 100644
--- a/deluge/ui/web/js/deluge-all/FileBrowser.js
+++ b/deluge/ui/web/js/deluge-all/FileBrowser.js
@@ -15,7 +15,7 @@ Deluge.FileBrowser = Ext.extend(Ext.Window, {
width: 500,
height: 400,
- initComponent: function() {
+ initComponent: function () {
Deluge.FileBrowser.superclass.initComponent.call(this);
this.add({
diff --git a/deluge/ui/web/js/deluge-all/FilterPanel.js b/deluge/ui/web/js/deluge-all/FilterPanel.js
index 2362dbb..f1fade1 100644
--- a/deluge/ui/web/js/deluge-all/FilterPanel.js
+++ b/deluge/ui/web/js/deluge-all/FilterPanel.js
@@ -20,7 +20,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
show_zero: null,
- initComponent: function() {
+ initComponent: function () {
Deluge.FilterPanel.superclass.initComponent.call(this);
this.filterType = this.initialConfig.filter;
var title = '';
@@ -36,7 +36,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
(title = this.filterType.replace('_', ' ')),
(parts = title.split(' ')),
(title = '');
- Ext.each(parts, function(p) {
+ Ext.each(parts, function (p) {
fl = p.substring(0, 1).toUpperCase();
title += fl + p.substring(1) + ' ';
});
@@ -75,7 +75,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
* Return the currently selected filter state
* @returns {String} the current filter state
*/
- getState: function() {
+ getState: function () {
if (!this.list.getSelectionCount()) return;
var state = this.list.getSelectedRecords()[0];
@@ -87,7 +87,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
/**
* Return the current states in the filter
*/
- getStates: function() {
+ getStates: function () {
return this.states;
},
@@ -95,18 +95,18 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
* Return the Store for the ListView of the FilterPanel
* @returns {Ext.data.Store} the ListView store
*/
- getStore: function() {
+ getStore: function () {
return this.list.getStore();
},
/**
* Update the states in the FilterPanel
*/
- updateStates: function(states) {
+ updateStates: function (states) {
this.states = {};
Ext.each(
states,
- function(state) {
+ function (state) {
this.states[state[0]] = state[1];
},
this
@@ -118,7 +118,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
: this.show_zero;
if (!show_zero) {
var newStates = [];
- Ext.each(states, function(state) {
+ Ext.each(states, function (state) {
if (state[1] > 0 || state[0] == 'All') {
newStates.push(state);
}
@@ -130,7 +130,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
var filters = {};
Ext.each(
states,
- function(s, i) {
+ function (s, i) {
var record = store.getById(s[0]);
if (!record) {
record = new store.recordType({
@@ -149,7 +149,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
this
);
- store.each(function(record) {
+ store.each(function (record) {
if (filters[record.id]) return;
store.remove(record);
var selected = this.list.getSelectedRecords()[0];
@@ -171,5 +171,5 @@ Deluge.FilterPanel.templates = {
tracker_host:
'<div class="x-deluge-filter" style="background-image: url(' +
deluge.config.base +
- 'tracker/{filter});">{filter} ({count})</div>',
+ 'tracker/{filter});">{filter:htmlEncode} ({count})</div>',
};
diff --git a/deluge/ui/web/js/deluge-all/Formatters.js b/deluge/ui/web/js/deluge-all/Formatters.js
index a511f34..6b09abe 100644
--- a/deluge/ui/web/js/deluge-all/Formatters.js
+++ b/deluge/ui/web/js/deluge-all/Formatters.js
@@ -15,7 +15,23 @@
* @version 1.3
* @singleton
*/
-Deluge.Formatters = {
+Deluge.Formatters = (function () {
+ var charToEntity = {
+ '&': '&amp;',
+ '>': '&gt;',
+ '<': '&lt;',
+ '"': '&quot;',
+ "'": '&#39;',
+ };
+
+ var charToEntityRegex = new RegExp(
+ '(' + Object.keys(charToEntity).join('|') + ')',
+ 'g'
+ );
+ var htmlEncodeReplaceFn = function (match, capture) {
+ return charToEntity[capture];
+ };
+
/**
* Formats a date string in the date representation of the current locale,
* based on the systems timezone.
@@ -24,154 +40,162 @@ Deluge.Formatters = {
* @return {String} a string in the date representation of the current locale
* or "" if seconds < 0.
*/
- date: function(timestamp) {
- function zeroPad(num, count) {
- var numZeropad = num + '';
- while (numZeropad.length < count) {
- numZeropad = '0' + numZeropad;
+ return (Formatters = {
+ date: function (timestamp) {
+ function zeroPad(num, count) {
+ var numZeropad = num + '';
+ while (numZeropad.length < count) {
+ numZeropad = '0' + numZeropad;
+ }
+ return numZeropad;
+ }
+ timestamp = timestamp * 1000;
+ var date = new Date(timestamp);
+ return String.format(
+ '{0}/{1}/{2} {3}:{4}:{5}',
+ zeroPad(date.getDate(), 2),
+ zeroPad(date.getMonth() + 1, 2),
+ date.getFullYear(),
+ zeroPad(date.getHours(), 2),
+ zeroPad(date.getMinutes(), 2),
+ zeroPad(date.getSeconds(), 2)
+ );
+ },
+
+ /**
+ * Formats the bytes value into a string with KiB, MiB or GiB units.
+ *
+ * @param {Number} bytes the filesize in bytes
+ * @param {Boolean} showZero pass in true to displays 0 values
+ * @return {String} formatted string with KiB, MiB or GiB units.
+ */
+ size: function (bytes, showZero) {
+ if (!bytes && !showZero) return '';
+ bytes = bytes / 1024.0;
+
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' KiB';
+ } else {
+ bytes = bytes / 1024;
}
- return numZeropad;
- }
- timestamp = timestamp * 1000;
- var date = new Date(timestamp);
- return String.format(
- '{0}/{1}/{2} {3}:{4}:{5}',
- zeroPad(date.getDate(), 2),
- zeroPad(date.getMonth() + 1, 2),
- date.getFullYear(),
- zeroPad(date.getHours(), 2),
- zeroPad(date.getMinutes(), 2),
- zeroPad(date.getSeconds(), 2)
- );
- },
-
- /**
- * Formats the bytes value into a string with KiB, MiB or GiB units.
- *
- * @param {Number} bytes the filesize in bytes
- * @param {Boolean} showZero pass in true to displays 0 values
- * @return {String} formatted string with KiB, MiB or GiB units.
- */
- size: function(bytes, showZero) {
- if (!bytes && !showZero) return '';
- bytes = bytes / 1024.0;
-
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' KiB';
- } else {
- bytes = bytes / 1024;
- }
-
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' MiB';
- } else {
- bytes = bytes / 1024;
- }
-
- return bytes.toFixed(1) + ' GiB';
- },
-
- /**
- * Formats the bytes value into a string with K, M or G units.
- *
- * @param {Number} bytes the filesize in bytes
- * @param {Boolean} showZero pass in true to displays 0 values
- * @return {String} formatted string with K, M or G units.
- */
- sizeShort: function(bytes, showZero) {
- if (!bytes && !showZero) return '';
- bytes = bytes / 1024.0;
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' K';
- } else {
- bytes = bytes / 1024;
- }
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' MiB';
+ } else {
+ bytes = bytes / 1024;
+ }
- if (bytes < 1024) {
- return bytes.toFixed(1) + ' M';
- } else {
- bytes = bytes / 1024;
- }
+ return bytes.toFixed(1) + ' GiB';
+ },
+
+ /**
+ * Formats the bytes value into a string with K, M or G units.
+ *
+ * @param {Number} bytes the filesize in bytes
+ * @param {Boolean} showZero pass in true to displays 0 values
+ * @return {String} formatted string with K, M or G units.
+ */
+ sizeShort: function (bytes, showZero) {
+ if (!bytes && !showZero) return '';
+ bytes = bytes / 1024.0;
+
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' K';
+ } else {
+ bytes = bytes / 1024;
+ }
- return bytes.toFixed(1) + ' G';
- },
+ if (bytes < 1024) {
+ return bytes.toFixed(1) + ' M';
+ } else {
+ bytes = bytes / 1024;
+ }
- /**
- * Formats a string to display a transfer speed utilizing {@link #size}
- *
- * @param {Number} bytes the number of bytes per second
- * @param {Boolean} showZero pass in true to displays 0 values
- * @return {String} formatted string with KiB, MiB or GiB units.
- */
- speed: function(bytes, showZero) {
- return !bytes && !showZero ? '' : fsize(bytes, showZero) + '/s';
- },
+ return bytes.toFixed(1) + ' G';
+ },
+
+ /**
+ * Formats a string to display a transfer speed utilizing {@link #size}
+ *
+ * @param {Number} bytes the number of bytes per second
+ * @param {Boolean} showZero pass in true to displays 0 values
+ * @return {String} formatted string with KiB, MiB or GiB units.
+ */
+ speed: function (bytes, showZero) {
+ return !bytes && !showZero ? '' : fsize(bytes, showZero) + '/s';
+ },
+
+ /**
+ * Formats a string to show time in a human readable form.
+ *
+ * @param {Number} time the number of seconds
+ * @return {String} a formatted time string. will return '' if seconds == 0
+ */
+ timeRemaining: function (time) {
+ if (time <= 0) {
+ return '&infin;';
+ }
+ time = time.toFixed(0);
+ if (time < 60) {
+ return time + 's';
+ } else {
+ time = time / 60;
+ }
- /**
- * Formats a string to show time in a human readable form.
- *
- * @param {Number} time the number of seconds
- * @return {String} a formatted time string. will return '' if seconds == 0
- */
- timeRemaining: function(time) {
- if (time <= 0) {
- return '&infin;';
- }
- time = time.toFixed(0);
- if (time < 60) {
- return time + 's';
- } else {
- time = time / 60;
- }
-
- if (time < 60) {
- var minutes = Math.floor(time);
- var seconds = Math.round(60 * (time - minutes));
- if (seconds > 0) {
- return minutes + 'm ' + seconds + 's';
+ if (time < 60) {
+ var minutes = Math.floor(time);
+ var seconds = Math.round(60 * (time - minutes));
+ if (seconds > 0) {
+ return minutes + 'm ' + seconds + 's';
+ } else {
+ return minutes + 'm';
+ }
} else {
- return minutes + 'm';
+ time = time / 60;
}
- } else {
- time = time / 60;
- }
-
- if (time < 24) {
- var hours = Math.floor(time);
- var minutes = Math.round(60 * (time - hours));
- if (minutes > 0) {
- return hours + 'h ' + minutes + 'm';
+
+ if (time < 24) {
+ var hours = Math.floor(time);
+ var minutes = Math.round(60 * (time - hours));
+ if (minutes > 0) {
+ return hours + 'h ' + minutes + 'm';
+ } else {
+ return hours + 'h';
+ }
} else {
- return hours + 'h';
+ time = time / 24;
}
- } else {
- time = time / 24;
- }
-
- var days = Math.floor(time);
- var hours = Math.round(24 * (time - days));
- if (hours > 0) {
- return days + 'd ' + hours + 'h';
- } else {
- return days + 'd';
- }
- },
- /**
- * Simply returns the value untouched, for when no formatting is required.
- *
- * @param {Mixed} value the value to be displayed
- * @return the untouched value.
- */
- plain: function(value) {
- return value;
- },
-
- cssClassEscape: function(value) {
- return value.toLowerCase().replace('.', '_');
- },
-};
+ var days = Math.floor(time);
+ var hours = Math.round(24 * (time - days));
+ if (hours > 0) {
+ return days + 'd ' + hours + 'h';
+ } else {
+ return days + 'd';
+ }
+ },
+
+ /**
+ * Simply returns the value untouched, for when no formatting is required.
+ *
+ * @param {Mixed} value the value to be displayed
+ * @return the untouched value.
+ */
+ plain: function (value) {
+ return value;
+ },
+
+ cssClassEscape: function (value) {
+ return value.toLowerCase().replace('.', '_');
+ },
+
+ htmlEncode: function (value) {
+ return !value
+ ? value
+ : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
+ },
+ });
+})();
var fsize = Deluge.Formatters.size;
var fsize_short = Deluge.Formatters.sizeShort;
var fspeed = Deluge.Formatters.speed;
@@ -179,3 +203,4 @@ var ftime = Deluge.Formatters.timeRemaining;
var fdate = Deluge.Formatters.date;
var fplain = Deluge.Formatters.plain;
Ext.util.Format.cssClassEscape = Deluge.Formatters.cssClassEscape;
+Ext.util.Format.htmlEncode = Deluge.Formatters.htmlEncode;
diff --git a/deluge/ui/web/js/deluge-all/Keys.js b/deluge/ui/web/js/deluge-all/Keys.js
index 25cf38b..7b3e3af 100644
--- a/deluge/ui/web/js/deluge-all/Keys.js
+++ b/deluge/ui/web/js/deluge-all/Keys.js
@@ -133,6 +133,6 @@ Deluge.Keys = {
// Merge the grid and status keys together as the status keys contain all the
// grid ones.
-Ext.each(Deluge.Keys.Grid, function(key) {
+Ext.each(Deluge.Keys.Grid, function (key) {
Deluge.Keys.Status.push(key);
});
diff --git a/deluge/ui/web/js/deluge-all/LoginWindow.js b/deluge/ui/web/js/deluge-all/LoginWindow.js
index 964f5ff..a055a69 100644
--- a/deluge/ui/web/js/deluge-all/LoginWindow.js
+++ b/deluge/ui/web/js/deluge-all/LoginWindow.js
@@ -23,7 +23,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
width: 300,
height: 120,
- initComponent: function() {
+ initComponent: function () {
Deluge.LoginWindow.superclass.initComponent.call(this);
this.on('show', this.onShow, this);
@@ -56,17 +56,17 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
this.passwordField.on('specialkey', this.onSpecialKey, this);
},
- logout: function() {
+ logout: function () {
deluge.events.fire('logout');
deluge.client.auth.delete_session({
- success: function(result) {
+ success: function (result) {
this.show(true);
},
scope: this,
});
},
- show: function(skipCheck) {
+ show: function (skipCheck) {
if (this.firstShow) {
deluge.client.on('error', this.onClientError, this);
this.firstShow = false;
@@ -77,28 +77,28 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
}
deluge.client.auth.check_session({
- success: function(result) {
+ success: function (result) {
if (result) {
deluge.events.fire('login');
} else {
this.show(true);
}
},
- failure: function(result) {
+ failure: function (result) {
this.show(true);
},
scope: this,
});
},
- onSpecialKey: function(field, e) {
+ onSpecialKey: function (field, e) {
if (e.getKey() == 13) this.onLogin();
},
- onLogin: function() {
+ onLogin: function () {
var passwordField = this.passwordField;
deluge.client.auth.login(passwordField.getValue(), {
- success: function(result) {
+ success: function (result) {
if (result) {
deluge.events.fire('login');
this.hide();
@@ -109,7 +109,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
msg: _('You entered an incorrect password'),
buttons: Ext.MessageBox.OK,
modal: false,
- fn: function() {
+ fn: function () {
passwordField.focus(true, 10);
},
icon: Ext.MessageBox.WARNING,
@@ -121,14 +121,14 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
});
},
- onClientError: function(errorObj, response, requestOptions) {
+ onClientError: function (errorObj, response, requestOptions) {
if (errorObj.error.code == 1) {
deluge.events.fire('logout');
this.show(true);
}
},
- onShow: function() {
+ onShow: function () {
this.passwordField.focus(true, 300);
},
});
diff --git a/deluge/ui/web/js/deluge-all/Menus.js b/deluge/ui/web/js/deluge-all/Menus.js
index 529c6cc..34550a6 100644
--- a/deluge/ui/web/js/deluge-all/Menus.js
+++ b/deluge/ui/web/js/deluge-all/Menus.js
@@ -9,7 +9,7 @@
*/
deluge.menus = {
- onTorrentActionSetOpt: function(item, e) {
+ onTorrentActionSetOpt: function (item, e) {
var ids = deluge.torrents.getSelectedIds();
var action = item.initialConfig.torrentAction;
var opts = {};
@@ -17,20 +17,23 @@ deluge.menus = {
deluge.client.core.set_torrent_options(ids, opts);
},
- onTorrentActionMethod: function(item, e) {
+ onTorrentActionMethod: function (item, e) {
var ids = deluge.torrents.getSelectedIds();
var action = item.initialConfig.torrentAction;
deluge.client.core[action](ids, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
},
- onTorrentActionShow: function(item, e) {
+ onTorrentActionShow: function (item, e) {
var ids = deluge.torrents.getSelectedIds();
var action = item.initialConfig.torrentAction;
switch (action) {
+ case 'copy_magnet':
+ deluge.copyMagnetWindow.show();
+ break;
case 'edit_trackers':
deluge.editTrackers.show();
break;
@@ -312,6 +315,13 @@ deluge.menus.torrent = new Ext.menu.Menu({
},
'-',
{
+ torrentAction: 'copy_magnet',
+ text: _('Copy Magnet URI'),
+ iconCls: 'icon-magnet-copy',
+ handler: deluge.menus.onTorrentActionShow,
+ scope: deluge.menus,
+ },
+ {
torrentAction: 'force_reannounce',
text: _('Update Tracker'),
iconCls: 'icon-update-tracker',
diff --git a/deluge/ui/web/js/deluge-all/MoveStorage.js b/deluge/ui/web/js/deluge-all/MoveStorage.js
index 208031f..9ba638a 100644
--- a/deluge/ui/web/js/deluge-all/MoveStorage.js
+++ b/deluge/ui/web/js/deluge-all/MoveStorage.js
@@ -10,7 +10,7 @@
Ext.namespace('Deluge');
Deluge.MoveStorage = Ext.extend(Ext.Window, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
title: _('Move Download Folder'),
@@ -30,7 +30,7 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
Deluge.MoveStorage.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.MoveStorage.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancel, this);
@@ -62,21 +62,21 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
//});
},
- hide: function() {
+ hide: function () {
Deluge.MoveStorage.superclass.hide.call(this);
this.torrentIds = null;
},
- show: function(torrentIds) {
+ show: function (torrentIds) {
Deluge.MoveStorage.superclass.show.call(this);
this.torrentIds = torrentIds;
},
- onCancel: function() {
+ onCancel: function () {
this.hide();
},
- onMove: function() {
+ onMove: function () {
var dest = this.moveLocation.getValue();
deluge.client.core.move_storage(this.torrentIds, dest);
this.hide();
diff --git a/deluge/ui/web/js/deluge-all/MultiOptionsManager.js b/deluge/ui/web/js/deluge-all/MultiOptionsManager.js
index 1cd7d19..82f9838 100644
--- a/deluge/ui/web/js/deluge-all/MultiOptionsManager.js
+++ b/deluge/ui/web/js/deluge-all/MultiOptionsManager.js
@@ -15,7 +15,7 @@
* @extends Deluge.OptionsManager
*/
Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
- constructor: function(config) {
+ constructor: function (config) {
this.currentId = null;
this.stored = {};
Deluge.MultiOptionsManager.superclass.constructor.call(this, config);
@@ -25,7 +25,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* Changes bound fields to use the specified id.
* @param {String} id
*/
- changeId: function(id, dontUpdateBinds) {
+ changeId: function (id, dontUpdateBinds) {
var oldId = this.currentId;
this.currentId = id;
if (!dontUpdateBinds) {
@@ -33,7 +33,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
if (!this.binds[option]) continue;
Ext.each(
this.binds[option],
- function(bind) {
+ function (bind) {
bind.setValue(this.get(option));
},
this
@@ -47,7 +47,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* Changes all the changed values to be the default values
* @param {String} id
*/
- commit: function() {
+ commit: function () {
this.stored[this.currentId] = Ext.apply(
this.stored[this.currentId],
this.changed[this.currentId]
@@ -60,7 +60,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String/Array} option A single option or an array of options to return.
* @returns {Object} the options value.
*/
- get: function() {
+ get: function () {
if (arguments.length == 1) {
var option = arguments[0];
return this.isDirty(option)
@@ -78,7 +78,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
var options = {};
Ext.each(
arguments,
- function(option) {
+ function (option) {
options[option] = this.isDirty(option)
? this.changed[this.currentId][option]
: this.getDefault(option);
@@ -94,7 +94,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option A single option.
* @returns {Object} the value of the option
*/
- getDefault: function(option) {
+ getDefault: function (option) {
return this.has(option)
? this.stored[this.currentId][option]
: this.options[option];
@@ -104,7 +104,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* Returns the dirty (changed) values.
* @returns {Object} the changed options
*/
- getDirty: function() {
+ getDirty: function () {
return this.changed[this.currentId] ? this.changed[this.currentId] : {};
},
@@ -113,7 +113,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option
* @returns {Boolean} true if the option has been changed, else false.
*/
- isDirty: function(option) {
+ isDirty: function (option) {
return (
this.changed[this.currentId] &&
!Ext.isEmpty(this.changed[this.currentId][option])
@@ -126,7 +126,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option
* @returns {Boolean} true if the id has an option, else false.
*/
- has: function(option) {
+ has: function (option) {
return (
this.stored[this.currentId] &&
!Ext.isEmpty(this.stored[this.currentId][option])
@@ -136,7 +136,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
/**
* Reset the options back to the default values for the specified id.
*/
- reset: function() {
+ reset: function () {
if (this.changed[this.currentId]) delete this.changed[this.currentId];
if (this.stored[this.currentId]) delete this.stored[this.currentId];
},
@@ -144,7 +144,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
/**
* Reset the options back to their defaults for all ids.
*/
- resetAll: function() {
+ resetAll: function () {
this.changed = {};
this.stored = {};
this.changeId(null);
@@ -156,7 +156,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String} option
* @param {Object} value The value for the option
*/
- setDefault: function(option, value) {
+ setDefault: function (option, value) {
if (option === undefined) {
return;
} else if (value === undefined) {
@@ -187,7 +187,7 @@ Deluge.MultiOptionsManager = Ext.extend(Deluge.OptionsManager, {
* @param {String/Object} option or options to update
* @param {Object} [value];
*/
- update: function(option, value) {
+ update: function (option, value) {
if (option === undefined) {
return;
} else if (value === undefined) {
diff --git a/deluge/ui/web/js/deluge-all/OptionsManager.js b/deluge/ui/web/js/deluge-all/OptionsManager.js
index a1c4e65..529f7af 100644
--- a/deluge/ui/web/js/deluge-all/OptionsManager.js
+++ b/deluge/ui/web/js/deluge-all/OptionsManager.js
@@ -18,7 +18,7 @@ Ext.namespace('Deluge');
* @param {Object} config Configuration options
*/
Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
- constructor: function(config) {
+ constructor: function (config) {
config = config || {};
this.binds = {};
this.changed = {};
@@ -56,7 +56,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Add a set of default options and values to the options manager
* @param {Object} options The default options.
*/
- addOptions: function(options) {
+ addOptions: function (options) {
this.options = Ext.applyIf(this.options, options);
},
@@ -65,7 +65,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} option
* @param {Ext.form.Field} field
*/
- bind: function(option, field) {
+ bind: function (option, field) {
this.binds[option] = this.binds[option] || [];
this.binds[option].push(field);
field._doption = option;
@@ -81,7 +81,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
/**
* Changes all the changed values to be the default values
*/
- commit: function() {
+ commit: function () {
this.options = Ext.apply(this.options, this.changed);
this.reset();
},
@@ -91,7 +91,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {Mixed} oldValue The original value
* @param {Mixed} value The new value to convert
*/
- convertValueType: function(oldValue, value) {
+ convertValueType: function (oldValue, value) {
if (Ext.type(oldValue) != Ext.type(value)) {
switch (Ext.type(oldValue)) {
case 'string':
@@ -121,7 +121,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} [option] A single option or an array of options to return.
* @returns {Object} the options value.
*/
- get: function() {
+ get: function () {
if (arguments.length == 1) {
var option = arguments[0];
return this.isDirty(option)
@@ -131,7 +131,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
var options = {};
Ext.each(
arguments,
- function(option) {
+ function (option) {
if (!this.has(option)) return;
options[option] = this.isDirty(option)
? this.changed[option]
@@ -148,7 +148,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String|Array} [option] A single option or an array of options to return.
* @returns {Object} the value of the option
*/
- getDefault: function(option) {
+ getDefault: function (option) {
return this.options[option];
},
@@ -156,7 +156,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Returns the dirty (changed) values.
* @returns {Object} the changed options
*/
- getDirty: function() {
+ getDirty: function () {
return this.changed;
},
@@ -164,7 +164,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} [option] The option to check
* @returns {Boolean} true if the option has been changed from the default.
*/
- isDirty: function(option) {
+ isDirty: function (option) {
return !Ext.isEmpty(this.changed[option]);
},
@@ -173,14 +173,14 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} option
* @returns {Boolean} true if the option exists, else false.
*/
- has: function(option) {
+ has: function (option) {
return this.options[option];
},
/**
* Reset the options back to the default values.
*/
- reset: function() {
+ reset: function () {
this.changed = {};
},
@@ -189,7 +189,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String} option
* @param {Object} value The value for the option
*/
- set: function(option, value) {
+ set: function (option, value) {
if (option === undefined) {
return;
} else if (typeof option == 'object') {
@@ -209,7 +209,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {String/Object} option or options to update
* @param {Object} [value];
*/
- update: function(option, value) {
+ update: function (option, value) {
if (option === undefined) {
return;
} else if (value === undefined) {
@@ -238,7 +238,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Lets the option manager know when a field is blurred so if a value
* so value changing operations can continue on that field.
*/
- onFieldBlur: function(field, event) {
+ onFieldBlur: function (field, event) {
if (this.focused == field) {
this.focused = null;
}
@@ -249,7 +249,7 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* @param {Ext.form.Field} field
* @private
*/
- onFieldChange: function(field, event) {
+ onFieldChange: function (field, event) {
if (field.field) field = field.field; // fix for spinners
this.update(field._doption, field.getValue());
},
@@ -258,16 +258,16 @@ Deluge.OptionsManager = Ext.extend(Ext.util.Observable, {
* Lets the option manager know when a field is focused so if a value changing
* operation is performed it will not change the value of the field.
*/
- onFieldFocus: function(field, event) {
+ onFieldFocus: function (field, event) {
this.focused = field;
},
- onChange: function(option, newValue, oldValue) {
+ onChange: function (option, newValue, oldValue) {
// If we don't have a bind there's nothing to do.
if (Ext.isEmpty(this.binds[option])) return;
Ext.each(
this.binds[option],
- function(bind) {
+ function (bind) {
// The field is currently focused so we do not want to change it.
if (bind == this.focused) return;
// Set the form field to the new value.
diff --git a/deluge/ui/web/js/deluge-all/OtherLimitWindow.js b/deluge/ui/web/js/deluge-all/OtherLimitWindow.js
index 3e5880f..0d53d4a 100644
--- a/deluge/ui/web/js/deluge-all/OtherLimitWindow.js
+++ b/deluge/ui/web/js/deluge-all/OtherLimitWindow.js
@@ -20,7 +20,7 @@ Deluge.OtherLimitWindow = Ext.extend(Ext.Window, {
constrainHeader: true,
closeAction: 'hide',
- initComponent: function() {
+ initComponent: function () {
Deluge.OtherLimitWindow.superclass.initComponent.call(this);
this.form = this.add({
xtype: 'form',
@@ -53,30 +53,27 @@ Deluge.OtherLimitWindow = Ext.extend(Ext.Window, {
this.afterMethod('show', this.doFocusField, this);
},
- setValue: function(value) {
+ setValue: function (value) {
this.form.getForm().setValues({ limit: value });
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.form.getForm().reset();
this.hide();
},
- onOkClick: function() {
+ onOkClick: function () {
var config = {};
config[this.group] = this.form.getForm().getValues().limit;
deluge.client.core.set_config(config, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
this.hide();
},
- doFocusField: function() {
- this.form
- .getForm()
- .findField('limit')
- .focus(true, 10);
+ doFocusField: function () {
+ this.form.getForm().findField('limit').focus(true, 10);
},
});
diff --git a/deluge/ui/web/js/deluge-all/Plugin.js b/deluge/ui/web/js/deluge-all/Plugin.js
index af2cda4..26971f7 100644
--- a/deluge/ui/web/js/deluge-all/Plugin.js
+++ b/deluge/ui/web/js/deluge-all/Plugin.js
@@ -21,7 +21,7 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
*/
name: null,
- constructor: function(config) {
+ constructor: function (config) {
this.isDelugePlugin = true;
this.addEvents({
/**
@@ -43,7 +43,7 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
* Disables the plugin, firing the "{@link #disabled}" event and
* then executing the plugins clean up method onDisabled.
*/
- disable: function() {
+ disable: function () {
this.fireEvent('disabled', this);
if (this.onDisable) this.onDisable();
},
@@ -52,13 +52,13 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
* Enables the plugin, firing the "{@link #enabled}" event and
* then executes the plugins setup method, onEnabled.
*/
- enable: function() {
+ enable: function () {
deluge.client.reloadMethods();
this.fireEvent('enable', this);
if (this.onEnable) this.onEnable();
},
- registerTorrentStatus: function(key, header, options) {
+ registerTorrentStatus: function (key, header, options) {
options = options || {};
var cc = options.colCfg || {},
sc = options.storeCfg || {};
@@ -79,23 +79,23 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
deluge.torrents.getView().refresh(true);
},
- deregisterTorrentStatus: function(key) {
+ deregisterTorrentStatus: function (key) {
var fields = [];
- Ext.each(deluge.torrents.meta.fields, function(field) {
+ Ext.each(deluge.torrents.meta.fields, function (field) {
if (field.name != key) fields.push(field);
});
deluge.torrents.meta.fields = fields;
deluge.torrents.getStore().reader.onMetaChange(deluge.torrents.meta);
var cols = [];
- Ext.each(deluge.torrents.columns, function(col) {
+ Ext.each(deluge.torrents.columns, function (col) {
if (col.dataIndex != key) cols.push(col);
});
deluge.torrents.colModel.setConfig(cols);
deluge.torrents.columns = cols;
var keys = [];
- Ext.each(Deluge.Keys.Grid, function(k) {
+ Ext.each(Deluge.Keys.Grid, function (k) {
if (k == key) keys.push(k);
});
Deluge.Keys.Grid = keys;
diff --git a/deluge/ui/web/js/deluge-all/RemoveWindow.js b/deluge/ui/web/js/deluge-all/RemoveWindow.js
index a629008..ccac2ef 100644
--- a/deluge/ui/web/js/deluge-all/RemoveWindow.js
+++ b/deluge/ui/web/js/deluge-all/RemoveWindow.js
@@ -27,16 +27,16 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
bodyStyle: 'padding: 5px; padding-left: 10px;',
html: 'Are you sure you wish to remove the torrent (s)?',
- initComponent: function() {
+ initComponent: function () {
Deluge.RemoveWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancel, this);
this.addButton(_('Remove With Data'), this.onRemoveData, this);
this.addButton(_('Remove Torrent'), this.onRemove, this);
},
- remove: function(removeData) {
+ remove: function (removeData) {
deluge.client.core.remove_torrents(this.torrentIds, removeData, {
- success: function(result) {
+ success: function (result) {
if (result == true) {
console.log(
'Error(s) occured when trying to delete torrent(s).'
@@ -49,25 +49,25 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
});
},
- show: function(ids) {
+ show: function (ids) {
Deluge.RemoveWindow.superclass.show.call(this);
this.torrentIds = ids;
},
- onCancel: function() {
+ onCancel: function () {
this.hide();
this.torrentIds = null;
},
- onRemove: function() {
+ onRemove: function () {
this.remove(false);
},
- onRemoveData: function() {
+ onRemoveData: function () {
this.remove(true);
},
- onRemoved: function(torrentIds) {
+ onRemoved: function (torrentIds) {
deluge.events.fire('torrentsRemoved', torrentIds);
this.hide();
deluge.ui.update();
diff --git a/deluge/ui/web/js/deluge-all/Sidebar.js b/deluge/ui/web/js/deluge-all/Sidebar.js
index 74c3ecb..eb08a89 100644
--- a/deluge/ui/web/js/deluge-all/Sidebar.js
+++ b/deluge/ui/web/js/deluge-all/Sidebar.js
@@ -24,7 +24,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
// private
selected: null,
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
id: 'sidebar',
@@ -43,16 +43,16 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
},
// private
- initComponent: function() {
+ initComponent: function () {
Deluge.Sidebar.superclass.initComponent.call(this);
deluge.events.on('disconnect', this.onDisconnect, this);
},
- createFilter: function(filter, states) {
+ createFilter: function (filter, states) {
var panel = new Deluge.FilterPanel({
filter: filter,
});
- panel.on('selectionchange', function(view, nodes) {
+ panel.on('selectionchange', function (view, nodes) {
deluge.ui.update();
});
this.add(panel);
@@ -60,7 +60,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.doLayout();
this.panels[filter] = panel;
- panel.header.on('click', function(header) {
+ panel.header.on('click', function (header) {
if (!deluge.config.sidebar_multiple_filters) {
deluge.ui.update();
}
@@ -74,16 +74,16 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.fireEvent('afterfiltercreate', this, panel);
},
- getFilter: function(filter) {
+ getFilter: function (filter) {
return this.panels[filter];
},
- getFilterStates: function() {
+ getFilterStates: function () {
var states = {};
if (deluge.config.sidebar_multiple_filters) {
// Grab the filters from each of the filter panels
- this.items.each(function(panel) {
+ this.items.each(function (panel) {
var state = panel.getState();
if (state == null) return;
states[panel.filterType] = state;
@@ -100,12 +100,12 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
return states;
},
- hasFilter: function(filter) {
+ hasFilter: function (filter) {
return this.panels[filter] ? true : false;
},
// private
- onDisconnect: function() {
+ onDisconnect: function () {
for (var filter in this.panels) {
this.remove(this.panels[filter]);
}
@@ -113,11 +113,11 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.selected = null;
},
- onFilterSelect: function(selModel, rowIndex, record) {
+ onFilterSelect: function (selModel, rowIndex, record) {
deluge.ui.update();
},
- update: function(filters) {
+ update: function (filters) {
for (var filter in filters) {
var states = filters[filter];
if (Ext.getKeys(this.panels).indexOf(filter) > -1) {
@@ -130,7 +130,7 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
// Perform a cleanup of fitlers that are not enabled any more.
Ext.each(
Ext.keys(this.panels),
- function(filter) {
+ function (filter) {
if (Ext.keys(filters).indexOf(filter) == -1) {
// We need to remove the panel
this.remove(this.panels[filter]);
diff --git a/deluge/ui/web/js/deluge-all/Statusbar.js b/deluge/ui/web/js/deluge-all/Statusbar.js
index c2327be..00ad6b2 100644
--- a/deluge/ui/web/js/deluge-all/Statusbar.js
+++ b/deluge/ui/web/js/deluge-all/Statusbar.js
@@ -10,7 +10,7 @@
Ext.namespace('Deluge');
Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
id: 'deluge-statusbar',
@@ -22,14 +22,14 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
Deluge.Statusbar.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.Statusbar.superclass.initComponent.call(this);
deluge.events.on('connect', this.onConnect, this);
deluge.events.on('disconnect', this.onDisconnect, this);
},
- createButtons: function() {
+ createButtons: function () {
this.buttons = this.add(
{
id: 'statusbar-connections',
@@ -213,7 +213,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon',
iconCls: 'x-deluge-traffic',
tooltip: _('Protocol Traffic Download/Upload'),
- handler: function() {
+ handler: function () {
deluge.preferences.show();
deluge.preferences.selectPage('Network');
},
@@ -240,7 +240,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon',
iconCls: 'x-deluge-freespace',
tooltip: _('Freespace in download folder'),
- handler: function() {
+ handler: function () {
deluge.preferences.show();
deluge.preferences.selectPage('Downloads');
},
@@ -249,7 +249,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
this.created = true;
},
- onConnect: function() {
+ onConnect: function () {
this.setStatus({
iconCls: 'x-connected',
text: '',
@@ -257,7 +257,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
if (!this.created) {
this.createButtons();
} else {
- Ext.each(this.buttons, function(item) {
+ Ext.each(this.buttons, function (item) {
item.show();
item.enable();
});
@@ -265,23 +265,23 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
this.doLayout();
},
- onDisconnect: function() {
+ onDisconnect: function () {
this.clearStatus({ useDefaults: true });
- Ext.each(this.buttons, function(item) {
+ Ext.each(this.buttons, function (item) {
item.hide();
item.disable();
});
this.doLayout();
},
- update: function(stats) {
+ update: function (stats) {
if (!stats) return;
function addSpeed(val) {
return val + ' KiB/s';
}
- var updateStat = function(name, config) {
+ var updateStat = function (name, config) {
var item = this.items.get('statusbar-' + name);
if (config.limit.value > 0) {
var value = config.value.formatter
diff --git a/deluge/ui/web/js/deluge-all/StatusbarMenu.js b/deluge/ui/web/js/deluge-all/StatusbarMenu.js
index b988253..1365c9c 100644
--- a/deluge/ui/web/js/deluge-all/StatusbarMenu.js
+++ b/deluge/ui/web/js/deluge-all/StatusbarMenu.js
@@ -15,13 +15,13 @@ Ext.ns('Deluge');
* @extends Ext.menu.Menu
*/
Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
- initComponent: function() {
+ initComponent: function () {
Deluge.StatusbarMenu.superclass.initComponent.call(this);
this.otherWin = new Deluge.OtherLimitWindow(
this.initialConfig.otherWin || {}
);
- this.items.each(function(item) {
+ this.items.each(function (item) {
if (item.getXType() != 'menucheckitem') return;
if (item.value == 'other') {
item.on('click', this.onOtherClicked, this);
@@ -31,14 +31,14 @@ Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
}, this);
},
- setValue: function(value) {
+ setValue: function (value) {
var beenSet = false;
// set the new value
this.value = value = value == 0 ? -1 : value;
var other = null;
// uncheck all items
- this.items.each(function(item) {
+ this.items.each(function (item) {
if (item.setChecked) {
item.suspendEvents();
if (item.value == value) {
@@ -60,18 +60,18 @@ Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
other.resumeEvents();
},
- onLimitChanged: function(item, checked) {
+ onLimitChanged: function (item, checked) {
if (!checked || item.value == 'other') return; // We do not care about unchecked or other.
var config = {};
config[item.group] = item.value;
deluge.client.core.set_config(config, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
},
- onOtherClicked: function(item, e) {
+ onOtherClicked: function (item, e) {
this.otherWin.group = item.group;
this.otherWin.setValue(this.value);
this.otherWin.show();
diff --git a/deluge/ui/web/js/deluge-all/Toolbar.js b/deluge/ui/web/js/deluge-all/Toolbar.js
index d51818b..1ecdd75 100644
--- a/deluge/ui/web/js/deluge-all/Toolbar.js
+++ b/deluge/ui/web/js/deluge-all/Toolbar.js
@@ -14,7 +14,7 @@
* @extends Ext.Toolbar
*/
Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
items: [
@@ -118,62 +118,62 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
connectedButtons: ['add', 'remove', 'pause', 'resume', 'up', 'down'],
- initComponent: function() {
+ initComponent: function () {
Deluge.Toolbar.superclass.initComponent.call(this);
deluge.events.on('connect', this.onConnect, this);
deluge.events.on('login', this.onLogin, this);
},
- onConnect: function() {
+ onConnect: function () {
Ext.each(
this.connectedButtons,
- function(buttonId) {
+ function (buttonId) {
this.items.get(buttonId).enable();
},
this
);
},
- onDisconnect: function() {
+ onDisconnect: function () {
Ext.each(
this.connectedButtons,
- function(buttonId) {
+ function (buttonId) {
this.items.get(buttonId).disable();
},
this
);
},
- onLogin: function() {
+ onLogin: function () {
this.items.get('logout').enable();
},
- onLogout: function() {
+ onLogout: function () {
this.items.get('logout').disable();
deluge.login.logout();
},
- onConnectionManagerClick: function() {
+ onConnectionManagerClick: function () {
deluge.connectionManager.show();
},
- onHelpClick: function() {
+ onHelpClick: function () {
window.open('http://dev.deluge-torrent.org/wiki/UserGuide');
},
- onAboutClick: function() {
+ onAboutClick: function () {
var about = new Deluge.about.AboutWindow();
about.show();
},
- onPreferencesClick: function() {
+ onPreferencesClick: function () {
deluge.preferences.show();
},
- onTorrentAction: function(item) {
+ onTorrentAction: function (item) {
var selection = deluge.torrents.getSelections();
var ids = [];
- Ext.each(selection, function(record) {
+ Ext.each(selection, function (record) {
ids.push(record.id);
});
@@ -184,7 +184,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
case 'pause':
case 'resume':
deluge.client.core[item.id + '_torrent'](ids, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
@@ -192,7 +192,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
case 'up':
case 'down':
deluge.client.core['queue_' + item.id](ids, {
- success: function() {
+ success: function () {
deluge.ui.update();
},
});
@@ -200,7 +200,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
}
},
- onTorrentAdd: function() {
+ onTorrentAdd: function () {
deluge.add.show();
},
});
diff --git a/deluge/ui/web/js/deluge-all/TorrentGrid.js b/deluge/ui/web/js/deluge-all/TorrentGrid.js
index b0e0c5e..333d133 100644
--- a/deluge/ui/web/js/deluge-all/TorrentGrid.js
+++ b/deluge/ui/web/js/deluge-all/TorrentGrid.js
@@ -8,7 +8,7 @@
* See LICENSE for more details.
*/
-(function() {
+(function () {
/* Renderers for the Torrent Grid */
function queueRenderer(value) {
return value == -1 ? '' : value + 1;
@@ -17,7 +17,7 @@
return String.format(
'<div class="torrent-name x-deluge-{0}">{1}</div>',
r.data['state'].toLowerCase(),
- value
+ Ext.util.Format.htmlEncode(value)
);
}
function torrentSpeedRenderer(value) {
@@ -62,12 +62,14 @@
'<div style="background: url(' +
deluge.config.base +
'tracker/{0}) no-repeat; padding-left: 20px;">{0}</div>',
- value
+ Ext.util.Format.htmlEncode(value)
);
}
function etaSorter(eta) {
- return eta * -1;
+ if (eta === 0) return Number.MAX_VALUE;
+ if (eta <= -1) return Number.MAX_SAFE_INTEGER;
+ return eta;
}
function dateOrNever(date) {
@@ -75,7 +77,9 @@
}
function timeOrInf(time) {
- return time < 0 ? '&infin;' : ftime(time);
+ if (time === 0) return '';
+ if (time <= -1) return '&infin;';
+ return ftime(time);
}
/**
@@ -320,6 +324,8 @@
{ name: 'ratio', type: 'float' },
{ name: 'distributed_copies', type: 'float' },
{ name: 'time_added', type: 'int' },
+ { name: 'last_seen_complete', type: 'int' },
+ { name: 'completed_time', type: 'int' },
{ name: 'tracker_host' },
{ name: 'download_location' },
{ name: 'total_done', type: 'int' },
@@ -337,21 +343,21 @@
key: 'a',
ctrl: true,
stopEvent: true,
- handler: function() {
+ handler: function () {
deluge.torrents.getSelectionModel().selectAll();
},
},
{
key: [46],
stopEvent: true,
- handler: function() {
+ handler: function () {
ids = deluge.torrents.getSelectedIds();
deluge.removeWindow.show(ids);
},
},
],
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
id: 'torrentGrid',
@@ -376,12 +382,12 @@
Deluge.TorrentGrid.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.TorrentGrid.superclass.initComponent.call(this);
deluge.events.on('torrentsRemoved', this.onTorrentsRemoved, this);
deluge.events.on('disconnect', this.onDisconnect, this);
- this.on('rowcontextmenu', function(grid, rowIndex, e) {
+ this.on('rowcontextmenu', function (grid, rowIndex, e) {
e.stopEvent();
var selection = grid.getSelectionModel();
if (!selection.isSelected(rowIndex)) {
@@ -397,7 +403,7 @@
* @param index {int} The row index of the torrent you wish to retrieve.
* @return {Ext.data.Record} The record representing the torrent.
*/
- getTorrent: function(index) {
+ getTorrent: function (index) {
return this.getStore().getAt(index);
},
@@ -405,14 +411,14 @@
* Returns the currently selected record.
* @ return {Array/Ext.data.Record} The record(s) representing the rows
*/
- getSelected: function() {
+ getSelected: function () {
return this.getSelectionModel().getSelected();
},
/**
* Returns the currently selected records.
*/
- getSelections: function() {
+ getSelections: function () {
return this.getSelectionModel().getSelections();
},
@@ -420,7 +426,7 @@
* Return the currently selected torrent id.
* @return {String} The currently selected id.
*/
- getSelectedId: function() {
+ getSelectedId: function () {
return this.getSelectionModel().getSelected().id;
},
@@ -428,15 +434,15 @@
* Return the currently selected torrent ids.
* @return {Array} The currently selected ids.
*/
- getSelectedIds: function() {
+ getSelectedIds: function () {
var ids = [];
- Ext.each(this.getSelectionModel().getSelections(), function(r) {
+ Ext.each(this.getSelectionModel().getSelections(), function (r) {
ids.push(r.id);
});
return ids;
},
- update: function(torrents, wipe) {
+ update: function (torrents, wipe) {
var store = this.getStore();
// Need to perform a complete reload of the torrent grid.
@@ -470,7 +476,7 @@
store.add(newTorrents);
// Remove any torrents that should not be in the store.
- store.each(function(record) {
+ store.each(function (record) {
if (!torrents[record.id]) {
store.remove(record);
delete this.torrents[record.id];
@@ -484,17 +490,17 @@
},
// private
- onDisconnect: function() {
+ onDisconnect: function () {
this.getStore().removeAll();
this.torrents = {};
},
// private
- onTorrentsRemoved: function(torrentIds) {
+ onTorrentsRemoved: function (torrentIds) {
var selModel = this.getSelectionModel();
Ext.each(
torrentIds,
- function(torrentId) {
+ function (torrentId) {
var record = this.getStore().getById(torrentId);
if (selModel.isSelected(record)) {
selModel.deselectRow(this.getStore().indexOf(record));
diff --git a/deluge/ui/web/js/deluge-all/UI.js b/deluge/ui/web/js/deluge-all/UI.js
index dec4850..cc877d5 100644
--- a/deluge/ui/web/js/deluge-all/UI.js
+++ b/deluge/ui/web/js/deluge-all/UI.js
@@ -42,7 +42,7 @@ deluge.ui = {
* @description Create all the interface components, the json-rpc client
* and set up various events that the UI will utilise.
*/
- initialize: function() {
+ initialize: function () {
deluge.add = new Deluge.add.AddWindow();
deluge.details = new Deluge.details.DetailsPanel();
deluge.connectionManager = new Deluge.ConnectionManager();
@@ -100,7 +100,7 @@ deluge.ui = {
deluge.client.on(
'connected',
- function(e) {
+ function (e) {
deluge.login.show();
},
this,
@@ -113,7 +113,7 @@ deluge.ui = {
this.originalTitle = document.title;
},
- checkConnection: function() {
+ checkConnection: function () {
deluge.client.web.connected({
success: this.onConnectionSuccess,
failure: this.onConnectionError,
@@ -121,7 +121,7 @@ deluge.ui = {
});
},
- update: function() {
+ update: function () {
var filters = deluge.sidebar.getFilterStates();
this.oldFilters = this.filters;
this.filters = filters;
@@ -134,9 +134,9 @@ deluge.ui = {
deluge.details.update();
},
- onConnectionError: function(error) {},
+ onConnectionError: function (error) {},
- onConnectionSuccess: function(result) {
+ onConnectionSuccess: function (result) {
deluge.statusbar.setStatus({
iconCls: 'x-deluge-statusbar icon-ok',
text: _('Connection restored'),
@@ -147,7 +147,7 @@ deluge.ui = {
}
},
- onUpdateError: function(error) {
+ onUpdateError: function (error) {
if (this.errorCount == 2) {
Ext.MessageBox.show({
title: _('Lost Connection'),
@@ -169,7 +169,7 @@ deluge.ui = {
* @private
* Updates the various components in the interface.
*/
- onUpdate: function(data) {
+ onUpdate: function (data) {
if (!data['connected']) {
deluge.connectionManager.disconnect(true);
return;
@@ -199,7 +199,7 @@ deluge.ui = {
* @private
* Start the Deluge UI polling the server and update the interface.
*/
- onConnect: function() {
+ onConnect: function () {
if (!this.running) {
this.running = setInterval(this.update, 2000);
this.update();
@@ -214,14 +214,14 @@ deluge.ui = {
* @static
* @private
*/
- onDisconnect: function() {
+ onDisconnect: function () {
this.stop();
},
- onGotPlugins: function(plugins) {
+ onGotPlugins: function (plugins) {
Ext.each(
plugins.enabled_plugins,
- function(plugin) {
+ function (plugin) {
if (deluge.plugins[plugin]) return;
deluge.client.web.get_plugin_resources(plugin, {
success: this.onGotPluginResources,
@@ -232,7 +232,7 @@ deluge.ui = {
);
},
- onPluginEnabled: function(pluginName) {
+ onPluginEnabled: function (pluginName) {
if (deluge.plugins[pluginName]) {
deluge.plugins[pluginName].enable();
} else {
@@ -243,13 +243,13 @@ deluge.ui = {
}
},
- onGotPluginResources: function(resources) {
+ onGotPluginResources: function (resources) {
var scripts = Deluge.debug
? resources.debug_scripts
: resources.scripts;
Ext.each(
scripts,
- function(script) {
+ function (script) {
Ext.ux.JSLoader({
url: deluge.config.base + script,
onLoad: this.onPluginLoaded,
@@ -260,11 +260,11 @@ deluge.ui = {
);
},
- onPluginDisabled: function(pluginName) {
+ onPluginDisabled: function (pluginName) {
if (deluge.plugins[pluginName]) deluge.plugins[pluginName].disable();
},
- onPluginLoaded: function(options) {
+ onPluginLoaded: function (options) {
// This could happen if the plugin has multiple scripts
if (!Deluge.hasPlugin(options.pluginName)) return;
@@ -278,7 +278,7 @@ deluge.ui = {
* @static
* Stop the Deluge UI polling the server and clear the interface.
*/
- stop: function() {
+ stop: function () {
if (this.running) {
clearInterval(this.running);
this.running = false;
@@ -287,6 +287,6 @@ deluge.ui = {
},
};
-Ext.onReady(function(e) {
+Ext.onReady(function (e) {
deluge.ui.initialize();
});
diff --git a/deluge/ui/web/js/deluge-all/add/AddWindow.js b/deluge/ui/web/js/deluge-all/add/AddWindow.js
index 89803f3..f5f2fdf 100644
--- a/deluge/ui/web/js/deluge-all/add/AddWindow.js
+++ b/deluge/ui/web/js/deluge-all/add/AddWindow.js
@@ -12,7 +12,7 @@ Ext.namespace('Deluge.add');
// This override allows file upload buttons to contain icons
Ext.override(Ext.ux.form.FileUploadField, {
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Ext.ux.form.FileUploadField.superclass.onRender.call(
this,
ct,
@@ -58,26 +58,12 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
plain: true,
iconCls: 'x-deluge-add-window-icon',
- initComponent: function() {
+ initComponent: function () {
Deluge.add.AddWindow.superclass.initComponent.call(this);
this.addButton(_('Cancel'), this.onCancelClick, this);
this.addButton(_('Add'), this.onAddClick, this);
- function torrentRenderer(value, p, r) {
- if (r.data['info_hash']) {
- return String.format(
- '<div class="x-deluge-add-torrent-name">{0}</div>',
- value
- );
- } else {
- return String.format(
- '<div class="x-deluge-add-torrent-name-loading">{0}</div>',
- value
- );
- }
- }
-
this.list = new Ext.list.ListView({
store: new Ext.data.SimpleStore({
fields: [
@@ -91,8 +77,10 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
id: 'torrent',
width: 150,
sortable: true,
- renderer: torrentRenderer,
dataIndex: 'text',
+ tpl: new Ext.XTemplate(
+ '<div class="x-deluge-add-torrent-name">{text:htmlEncode}</div>'
+ ),
},
],
stripeRows: true,
@@ -147,7 +135,7 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
},
{
text: _('Infohash'),
- iconCls: 'icon-add-magnet',
+ iconCls: 'icon-magnet-add',
hidden: true,
disabled: true,
},
@@ -168,17 +156,17 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
this.on('show', this.onShow, this);
},
- clear: function() {
+ clear: function () {
this.list.getStore().removeAll();
this.optionsPanel.clear();
// Reset upload form so handler fires when a canceled file is reselected
this.fileUploadForm.reset();
},
- onAddClick: function() {
+ onAddClick: function () {
var torrents = [];
if (!this.list) return;
- this.list.getStore().each(function(r) {
+ this.list.getStore().each(function (r) {
var id = r.get('info_hash');
torrents.push({
path: this.optionsPanel.getFilename(id),
@@ -187,29 +175,29 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}, this);
deluge.client.web.add_torrents(torrents, {
- success: function(result) {},
+ success: function (result) {},
});
this.clear();
this.hide();
},
- onCancelClick: function() {
+ onCancelClick: function () {
this.clear();
this.hide();
},
- onFile: function() {
+ onFile: function () {
if (!this.file) this.file = new Deluge.add.FileWindow();
this.file.show();
},
- onHide: function() {
+ onHide: function () {
this.optionsPanel.setActiveTab(0);
this.optionsPanel.files.setDisabled(true);
this.optionsPanel.form.setDisabled(true);
},
- onRemove: function() {
+ onRemove: function () {
if (!this.list.getSelectionCount()) return;
var torrent = this.list.getSelectedRecords()[0];
if (!torrent) return;
@@ -220,7 +208,7 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
delete this.torrents[torrent.id];
},
- onSelect: function(list, selections) {
+ onSelect: function (list, selections) {
if (selections.length) {
var record = this.list.getRecord(selections[0]);
this.optionsPanel.setTorrent(record.get('info_hash'));
@@ -230,24 +218,25 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}
},
- onShow: function() {
+ onShow: function () {
if (!this.url) {
this.url = new Deluge.add.UrlWindow();
this.url.on('beforeadd', this.onTorrentBeforeAdd, this);
this.url.on('add', this.onTorrentAdd, this);
+ this.url.on('addfailed', this.onTorrentAddFailed, this);
}
this.optionsPanel.form.getDefaults();
},
- onFileSelected: function() {
+ onFileSelected: function () {
if (this.fileUploadForm.isValid()) {
var torrentIds = [];
var files = this.fileUploadForm.findField('torrentFile').value;
var randomId = this.createTorrentId();
Array.prototype.forEach.call(
files,
- function(file, i) {
+ function (file, i) {
// Append index for batch of unique torrentIds.
var torrentId = randomId + i.toString();
torrentIds.push(torrentId);
@@ -258,20 +247,21 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
url: deluge.config.base + 'upload',
waitMsg: _('Uploading your torrent...'),
success: this.onUploadSuccess,
+ failure: this.onUploadFailure,
scope: this,
torrentIds: torrentIds,
});
}
},
- onUploadSuccess: function(fp, upload) {
+ onUploadSuccess: function (fp, upload) {
if (!upload.result.success) {
this.clear();
return;
}
upload.result.files.forEach(
- function(filename, i) {
+ function (filename, i) {
deluge.client.web.get_torrent_info(filename, {
success: this.onGotInfo,
scope: this,
@@ -283,18 +273,31 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
this.fileUploadForm.reset();
},
- onGotInfo: function(info, obj, response, request) {
+ onUploadFailure: function (form, action) {
+ this.hide();
+ Ext.MessageBox.show({
+ title: _('Error'),
+ msg: _('Failed to upload torrent'),
+ buttons: Ext.MessageBox.OK,
+ modal: false,
+ icon: Ext.MessageBox.ERROR,
+ iconCls: 'x-deluge-icon-error',
+ });
+ this.fireEvent('addfailed', this.torrentId);
+ },
+
+ onGotInfo: function (info, obj, response, request) {
info.filename = request.options.filename;
torrentId = request.options.torrentId;
this.onTorrentAdd(torrentId, info);
},
- onTorrentBeforeAdd: function(torrentId, text) {
+ onTorrentBeforeAdd: function (torrentId, text) {
var store = this.list.getStore();
store.loadData([[torrentId, null, text]], true);
},
- onTorrentAdd: function(torrentId, info) {
+ onTorrentAdd: function (torrentId, info) {
var r = this.list.getStore().getById(torrentId);
if (!info) {
Ext.MessageBox.show({
@@ -315,7 +318,15 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}
},
- onUrl: function(button, event) {
+ onTorrentAddFailed: function (torrentId) {
+ var store = this.list.getStore();
+ var torrentRecord = store.getById(torrentId);
+ if (torrentRecord) {
+ store.remove(torrentRecord);
+ }
+ },
+
+ onUrl: function (button, event) {
this.url.show();
},
});
diff --git a/deluge/ui/web/js/deluge-all/add/FilesTab.js b/deluge/ui/web/js/deluge-all/add/FilesTab.js
index a433ad6..d712c02 100644
--- a/deluge/ui/web/js/deluge-all/add/FilesTab.js
+++ b/deluge/ui/web/js/deluge-all/add/FilesTab.js
@@ -28,13 +28,14 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
header: _('Filename'),
width: 295,
dataIndex: 'filename',
+ tpl: new Ext.XTemplate('{filename:htmlEncode}'),
},
{
header: _('Size'),
width: 60,
dataIndex: 'size',
tpl: new Ext.XTemplate('{size:this.fsize}', {
- fsize: function(v) {
+ fsize: function (v) {
return fsize(v);
},
}),
@@ -44,7 +45,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
width: 65,
dataIndex: 'download',
tpl: new Ext.XTemplate('{download:this.format}', {
- format: function(v) {
+ format: function (v) {
return (
'<div rel="chkbox" class="x-grid3-check-col' +
(v ? '-on' : '') +
@@ -55,21 +56,21 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
},
],
- initComponent: function() {
+ initComponent: function () {
Deluge.add.FilesTab.superclass.initComponent.call(this);
this.on('click', this.onNodeClick, this);
},
- clearFiles: function() {
+ clearFiles: function () {
var root = this.getRootNode();
if (!root.hasChildNodes()) return;
- root.cascade(function(node) {
+ root.cascade(function (node) {
if (!node.parentNode || !node.getOwnerTree()) return;
node.remove();
});
},
- setDownload: function(node, value, suppress) {
+ setDownload: function (node, value, suppress) {
node.attributes.download = value;
node.ui.updateColumns();
@@ -79,7 +80,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}
} else {
var nodes = [node];
- node.cascade(function(n) {
+ node.cascade(function (n) {
n.attributes.download = value;
n.ui.updateColumns();
nodes.push(n);
@@ -90,7 +91,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}
},
- onNodeClick: function(node, e) {
+ onNodeClick: function (node, e) {
var el = new Ext.Element(e.target);
if (el.getAttribute('rel') == 'chkbox') {
this.setDownload(node, !node.attributes.download);
diff --git a/deluge/ui/web/js/deluge-all/add/OptionsPanel.js b/deluge/ui/web/js/deluge-all/add/OptionsPanel.js
index 3dfb6f8..365b001 100644
--- a/deluge/ui/web/js/deluge-all/add/OptionsPanel.js
+++ b/deluge/ui/web/js/deluge-all/add/OptionsPanel.js
@@ -18,7 +18,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
activeTab: 0,
height: 265,
- initComponent: function() {
+ initComponent: function () {
Deluge.add.OptionsPanel.superclass.initComponent.call(this);
this.files = this.add(new Deluge.add.FilesTab());
this.form = this.add(new Deluge.add.OptionsTab());
@@ -26,12 +26,12 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
this.files.on('fileschecked', this.onFilesChecked, this);
},
- addTorrent: function(torrent) {
+ addTorrent: function (torrent) {
this.torrents[torrent['info_hash']] = torrent;
var fileIndexes = {};
this.walkFileTree(
torrent['files_tree'],
- function(filename, type, entry, parent) {
+ function (filename, type, entry, parent) {
if (type != 'file') return;
fileIndexes[entry.index] = entry.download;
},
@@ -39,7 +39,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
);
var priorities = [];
- Ext.each(Ext.keys(fileIndexes), function(index) {
+ Ext.each(Ext.keys(fileIndexes), function (index) {
priorities[index] = fileIndexes[index];
});
@@ -51,26 +51,26 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
this.form.optionsManager.changeId(oldId, true);
},
- clear: function() {
+ clear: function () {
this.files.clearFiles();
this.form.optionsManager.resetAll();
},
- getFilename: function(torrentId) {
+ getFilename: function (torrentId) {
return this.torrents[torrentId]['filename'];
},
- getOptions: function(torrentId) {
+ getOptions: function (torrentId) {
var oldId = this.form.optionsManager.changeId(torrentId, true);
var options = this.form.optionsManager.get();
this.form.optionsManager.changeId(oldId, true);
- Ext.each(options['file_priorities'], function(priority, index) {
+ Ext.each(options['file_priorities'], function (priority, index) {
options['file_priorities'][index] = priority ? 1 : 0;
});
return options;
},
- setTorrent: function(torrentId) {
+ setTorrent: function (torrentId) {
if (!torrentId) return;
this.torrentId = torrentId;
@@ -85,7 +85,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
if (this.torrents[torrentId]['files_tree']) {
this.walkFileTree(
this.torrents[torrentId]['files_tree'],
- function(filename, type, entry, parentNode) {
+ function (filename, type, entry, parentNode) {
var node = new Ext.tree.TreeNode({
download: entry.index ? priorities[entry.index] : true,
filename: filename,
@@ -109,7 +109,7 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
}
},
- walkFileTree: function(files, callback, scope, parentNode) {
+ walkFileTree: function (files, callback, scope, parentNode) {
for (var filename in files.contents) {
var entry = files.contents[filename];
var type = entry.type;
@@ -129,14 +129,13 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
}
},
- onFilesChecked: function(nodes, newValue, oldValue) {
+ onFilesChecked: function (nodes, newValue, oldValue) {
Ext.each(
nodes,
- function(node) {
+ function (node) {
if (node.attributes.fileindex < 0) return;
- var priorities = this.form.optionsManager.get(
- 'file_priorities'
- );
+ var priorities =
+ this.form.optionsManager.get('file_priorities');
priorities[node.attributes.fileindex] = newValue;
this.form.optionsManager.update('file_priorities', priorities);
},
diff --git a/deluge/ui/web/js/deluge-all/add/OptionsTab.js b/deluge/ui/web/js/deluge-all/add/OptionsTab.js
index e897b17..73a8a5c 100644
--- a/deluge/ui/web/js/deluge-all/add/OptionsTab.js
+++ b/deluge/ui/web/js/deluge-all/add/OptionsTab.js
@@ -21,7 +21,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
disabled: true,
labelWidth: 1,
- initComponent: function() {
+ initComponent: function () {
Deluge.add.OptionsTab.superclass.initComponent.call(this);
this.optionsManager = new Deluge.MultiOptionsManager();
@@ -174,7 +174,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
);
},
- getDefaults: function() {
+ getDefaults: function () {
var keys = [
'add_paused',
'pre_allocate_storage',
@@ -190,7 +190,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
];
deluge.client.core.get_config_values(keys, {
- success: function(config) {
+ success: function (config) {
var options = {
file_priorities: [],
add_paused: config.add_paused,
diff --git a/deluge/ui/web/js/deluge-all/add/UrlWindow.js b/deluge/ui/web/js/deluge-all/add/UrlWindow.js
index d3a9a69..caf2250 100644
--- a/deluge/ui/web/js/deluge-all/add/UrlWindow.js
+++ b/deluge/ui/web/js/deluge-all/add/UrlWindow.js
@@ -22,7 +22,7 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
bodyStyle: 'padding: 10px 5px;',
iconCls: 'x-deluge-add-url-window-icon',
- initComponent: function() {
+ initComponent: function () {
Deluge.add.UrlWindow.superclass.initComponent.call(this);
this.addButton(_('Add'), this.onAddClick, this);
@@ -50,7 +50,7 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
this.cookieField.on('specialkey', this.onAdd, this);
},
- onAddClick: function(field, e) {
+ onAddClick: function (field, e) {
if (
(field.id == 'url' || field.id == 'cookies') &&
e.getKey() != e.ENTER
@@ -72,6 +72,7 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
} else {
deluge.client.web.download_torrent_from_url(url, cookies, {
success: this.onDownload,
+ failure: this.onDownloadFailed,
scope: this,
torrentId: torrentId,
});
@@ -82,16 +83,29 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
this.fireEvent('beforeadd', torrentId, url);
},
- onDownload: function(filename, obj, resp, req) {
+ onDownload: function (filename, obj, resp, req) {
deluge.client.web.get_torrent_info(filename, {
success: this.onGotInfo,
+ failure: this.onDownloadFailed,
scope: this,
filename: filename,
torrentId: req.options.torrentId,
});
},
- onGotInfo: function(info, obj, response, request) {
+ onDownloadFailed: function (obj, resp, req) {
+ Ext.MessageBox.show({
+ title: _('Error'),
+ msg: _('Failed to download torrent'),
+ buttons: Ext.MessageBox.OK,
+ modal: false,
+ icon: Ext.MessageBox.ERROR,
+ iconCls: 'x-deluge-icon-error',
+ });
+ this.fireEvent('addfailed', req.options.torrentId);
+ },
+
+ onGotInfo: function (info, obj, response, request) {
info['filename'] = request.options.filename;
this.fireEvent('add', request.options.torrentId, info);
},
diff --git a/deluge/ui/web/js/deluge-all/add/Window.js b/deluge/ui/web/js/deluge-all/add/Window.js
index 206b3ee..20851e7 100644
--- a/deluge/ui/web/js/deluge-all/add/Window.js
+++ b/deluge/ui/web/js/deluge-all/add/Window.js
@@ -15,15 +15,15 @@ Ext.ns('Deluge.add');
* Base class for an add Window
*/
Deluge.add.Window = Ext.extend(Ext.Window, {
- initComponent: function() {
+ initComponent: function () {
Deluge.add.Window.superclass.initComponent.call(this);
- this.addEvents('beforeadd', 'add');
+ this.addEvents('beforeadd', 'add', 'addfailed');
},
/**
* Create an id for the torrent before we have any info about it.
*/
- createTorrentId: function() {
+ createTorrentId: function () {
return new Date().getTime().toString();
},
});
diff --git a/deluge/ui/web/js/deluge-all/data/SortTypes.js b/deluge/ui/web/js/deluge-all/data/SortTypes.js
index 199f895..ac915d1 100644
--- a/deluge/ui/web/js/deluge-all/data/SortTypes.js
+++ b/deluge/ui/web/js/deluge-all/data/SortTypes.js
@@ -27,11 +27,11 @@ Deluge.data.SortTypes = {
return ((+d[1] * 256 + (+d[2])) * 256 + (+d[3])) * 256 + (+d[4]);
},
- asQueuePosition: function(value) {
+ asQueuePosition: function (value) {
return value > -1 ? value : Number.MAX_VALUE;
},
- asName: function(value) {
+ asName: function (value) {
return String(value).toLowerCase();
},
};
diff --git a/deluge/ui/web/js/deluge-all/details/DetailsPanel.js b/deluge/ui/web/js/deluge-all/details/DetailsPanel.js
index 1c51de4..3f28b25 100644
--- a/deluge/ui/web/js/deluge-all/details/DetailsPanel.js
+++ b/deluge/ui/web/js/deluge-all/details/DetailsPanel.js
@@ -16,7 +16,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
id: 'torrentDetails',
activeTab: 0,
- initComponent: function() {
+ initComponent: function () {
Deluge.details.DetailsPanel.superclass.initComponent.call(this);
this.add(new Deluge.details.StatusTab());
this.add(new Deluge.details.DetailsTab());
@@ -25,8 +25,8 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
this.add(new Deluge.details.OptionsTab());
},
- clear: function() {
- this.items.each(function(panel) {
+ clear: function () {
+ this.items.each(function (panel) {
if (panel.clear) {
panel.clear.defer(100, panel);
panel.disable();
@@ -34,14 +34,14 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
});
},
- update: function(tab) {
+ update: function (tab) {
var torrent = deluge.torrents.getSelected();
if (!torrent) {
this.clear();
return;
}
- this.items.each(function(tab) {
+ this.items.each(function (tab) {
if (tab.disabled) tab.enable();
});
@@ -52,7 +52,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
/* Event Handlers */
// We need to add the events in onRender since Deluge.Torrents has not been created yet.
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.DetailsPanel.superclass.onRender.call(
this,
ct,
@@ -64,18 +64,18 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
deluge.torrents.getSelectionModel().on(
'selectionchange',
- function(selModel) {
+ function (selModel) {
if (!selModel.hasSelection()) this.clear();
},
this
);
},
- onTabChange: function(panel, tab) {
+ onTabChange: function (panel, tab) {
this.update(tab);
},
- onTorrentsClick: function(grid, rowIndex, e) {
+ onTorrentsClick: function (grid, rowIndex, e) {
this.update();
},
});
diff --git a/deluge/ui/web/js/deluge-all/details/DetailsTab.js b/deluge/ui/web/js/deluge-all/details/DetailsTab.js
index 84929ae..f1da178 100644
--- a/deluge/ui/web/js/deluge-all/details/DetailsTab.js
+++ b/deluge/ui/web/js/deluge-all/details/DetailsTab.js
@@ -18,7 +18,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
oldData: {},
- initComponent: function() {
+ initComponent: function () {
Deluge.details.DetailsTab.superclass.initComponent.call(this);
this.addItem('torrent_name', _('Name:'));
this.addItem('hash', _('Hash:'));
@@ -31,7 +31,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
this.addItem('creator', _('Created By:'));
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.DetailsTab.superclass.onRender.call(this, ct, position);
this.body.setStyle('padding', '10px');
this.dl = Ext.DomHelper.append(this.body, { tag: 'dl' }, true);
@@ -41,7 +41,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
}
},
- addItem: function(id, label) {
+ addItem: function (id, label) {
if (!this.rendered) {
this.queuedItems[id] = label;
} else {
@@ -50,7 +50,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
},
// private
- doAddItem: function(id, label) {
+ doAddItem: function (id, label) {
Ext.DomHelper.append(this.dl, { tag: 'dt', cls: id, html: label });
this.fields[id] = Ext.DomHelper.append(
this.dl,
@@ -59,7 +59,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
);
},
- clear: function() {
+ clear: function () {
if (!this.fields) return;
for (var k in this.fields) {
this.fields[k].dom.innerHTML = '';
@@ -67,7 +67,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
this.oldData = {};
},
- update: function(torrentId) {
+ update: function (torrentId) {
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Details, {
success: this.onRequestComplete,
scope: this,
@@ -75,7 +75,7 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
});
},
- onRequestComplete: function(torrent, request, response, options) {
+ onRequestComplete: function (torrent, request, response, options) {
var data = {
torrent_name: torrent.name,
hash: options.options.torrentId,
@@ -91,7 +91,9 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
for (var field in this.fields) {
if (!Ext.isDefined(data[field])) continue; // This is a field we are not responsible for.
if (data[field] == this.oldData[field]) continue;
- this.fields[field].dom.innerHTML = Ext.escapeHTML(data[field]);
+ this.fields[field].dom.innerHTML = Ext.util.Format.htmlEncode(
+ data[field]
+ );
}
this.oldData = data;
},
diff --git a/deluge/ui/web/js/deluge-all/details/FilesTab.js b/deluge/ui/web/js/deluge-all/details/FilesTab.js
index 3a212fa..60de832 100644
--- a/deluge/ui/web/js/deluge-all/details/FilesTab.js
+++ b/deluge/ui/web/js/deluge-all/details/FilesTab.js
@@ -18,13 +18,14 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
header: _('Filename'),
width: 330,
dataIndex: 'filename',
+ tpl: new Ext.XTemplate('{filename:htmlEncode}'),
},
{
header: _('Size'),
width: 150,
dataIndex: 'size',
tpl: new Ext.XTemplate('{size:this.fsize}', {
- fsize: function(v) {
+ fsize: function (v) {
return fsize(v);
},
}),
@@ -34,7 +35,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
header: _('Progress'),
width: 150,
dataIndex: 'progress',
- renderer: function(v) {
+ renderer: function (v) {
var progress = v * 100;
return Deluge.progressBar(
progress,
@@ -54,11 +55,11 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
'{priority:this.getName}' +
'</div></tpl>',
{
- getClass: function(v) {
+ getClass: function (v) {
return FILE_PRIORITY_CSS[v];
},
- getName: function(v) {
+ getName: function (v) {
return _(FILE_PRIORITY[v]);
},
}
@@ -68,15 +69,15 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
selModel: new Ext.tree.MultiSelectionModel(),
- initComponent: function() {
+ initComponent: function () {
Deluge.details.FilesTab.superclass.initComponent.call(this);
this.setRootNode(new Ext.tree.TreeNode({ text: _('Files') }));
},
- clear: function() {
+ clear: function () {
var root = this.getRootNode();
if (!root.hasChildNodes()) return;
- root.cascade(function(node) {
+ root.cascade(function (node) {
var parentNode = node.parentNode;
if (!parentNode) return;
if (!parentNode.ownerTree) return;
@@ -84,7 +85,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
});
},
- createFileTree: function(files) {
+ createFileTree: function (files) {
function walk(files, parentNode) {
for (var file in files.contents) {
var item = files.contents[file];
@@ -123,7 +124,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
root.firstChild.expand();
},
- update: function(torrentId) {
+ update: function (torrentId) {
if (this.torrentId != torrentId) {
this.clear();
this.torrentId = torrentId;
@@ -136,7 +137,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
});
},
- updateFileTree: function(files) {
+ updateFileTree: function (files) {
function walk(files, parentNode) {
for (var file in files.contents) {
var item = files.contents[file];
@@ -153,7 +154,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
walk(files, this.getRootNode());
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.FilesTab.superclass.onRender.call(this, ct, position);
deluge.menus.filePriorities.on('itemclick', this.onItemClick, this);
this.on('contextmenu', this.onContextMenu, this);
@@ -162,7 +163,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
});
},
- onContextMenu: function(node, e) {
+ onContextMenu: function (node, e) {
e.stopEvent();
var selModel = this.getSelectionModel();
if (selModel.getSelectedNodes().length < 2) {
@@ -172,14 +173,14 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
deluge.menus.filePriorities.showAt(e.getPoint());
},
- onItemClick: function(baseItem, e) {
+ onItemClick: function (baseItem, e) {
switch (baseItem.id) {
case 'expandAll':
this.expandAll();
break;
default:
var indexes = {};
- var walk = function(node) {
+ var walk = function (node) {
if (Ext.isEmpty(node.attributes.fileIndex)) return;
indexes[node.attributes.fileIndex] =
node.attributes.priority;
@@ -187,9 +188,9 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
this.getRootNode().cascade(walk);
var nodes = this.getSelectionModel().getSelectedNodes();
- Ext.each(nodes, function(node) {
+ Ext.each(nodes, function (node) {
if (!node.isLeaf()) {
- var setPriorities = function(node) {
+ var setPriorities = function (node) {
if (Ext.isEmpty(node.attributes.fileIndex)) return;
indexes[node.attributes.fileIndex] =
baseItem.filePriority;
@@ -211,8 +212,8 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
[this.torrentId],
{ file_priorities: priorities },
{
- success: function() {
- Ext.each(nodes, function(node) {
+ success: function () {
+ Ext.each(nodes, function (node) {
node.setColumnValue(3, baseItem.filePriority);
});
},
@@ -223,7 +224,7 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}
},
- onRequestComplete: function(files, options) {
+ onRequestComplete: function (files, options) {
if (!this.getRootNode().hasChildNodes()) {
this.createFileTree(files);
} else {
diff --git a/deluge/ui/web/js/deluge-all/details/OptionsTab.js b/deluge/ui/web/js/deluge-all/details/OptionsTab.js
index b11486b..7e59cba 100644
--- a/deluge/ui/web/js/deluge-all/details/OptionsTab.js
+++ b/deluge/ui/web/js/deluge-all/details/OptionsTab.js
@@ -9,7 +9,7 @@
*/
Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
autoScroll: true,
@@ -30,7 +30,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
Deluge.details.OptionsTab.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.details.OptionsTab.superclass.initComponent.call(this);
(this.fieldsets = {}), (this.fields = {});
@@ -339,7 +339,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
});
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.OptionsTab.superclass.onRender.call(this, ct, position);
// This is another hack I think, so keep an eye out here when upgrading.
@@ -348,17 +348,17 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
this.doLayout();
},
- clear: function() {
+ clear: function () {
if (this.torrentId == null) return;
this.torrentId = null;
this.optionsManager.changeId(null);
},
- reset: function() {
+ reset: function () {
if (this.torrentId) this.optionsManager.reset();
},
- update: function(torrentId) {
+ update: function (torrentId) {
if (this.torrentId && !torrentId) this.clear(); // we want to clear the pane if we get a null torrent torrentIds
if (!torrentId) return; // We do not care about null torrentIds.
@@ -373,33 +373,33 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
});
},
- onApply: function() {
+ onApply: function () {
var changed = this.optionsManager.getDirty();
deluge.client.core.set_torrent_options([this.torrentId], changed, {
- success: function() {
+ success: function () {
this.optionsManager.commit();
},
scope: this,
});
},
- onEditTrackers: function() {
+ onEditTrackers: function () {
deluge.editTrackers.show();
},
- onMoveCompletedChecked: function(checkbox, checked) {
+ onMoveCompletedChecked: function (checkbox, checked) {
this.fields.move_completed_path.setDisabled(!checked);
if (!checked) return;
this.fields.move_completed_path.focus();
},
- onStopRatioChecked: function(checkbox, checked) {
+ onStopRatioChecked: function (checkbox, checked) {
this.fields.remove_at_ratio.setDisabled(!checked);
this.fields.stop_ratio.setDisabled(!checked);
},
- onRequestComplete: function(torrent, options) {
+ onRequestComplete: function (torrent, options) {
this.fields['private'].setValue(torrent['private']);
this.fields['private'].setDisabled(true);
delete torrent['private'];
diff --git a/deluge/ui/web/js/deluge-all/details/PeersTab.js b/deluge/ui/web/js/deluge-all/details/PeersTab.js
index 515e533..a191963 100644
--- a/deluge/ui/web/js/deluge-all/details/PeersTab.js
+++ b/deluge/ui/web/js/deluge-all/details/PeersTab.js
@@ -8,13 +8,13 @@
* See LICENSE for more details.
*/
-(function() {
+(function () {
function flagRenderer(value) {
if (!value.replace(' ', '').replace(' ', '')) {
return '';
}
return String.format(
- '<img src="{0}flag/{1}" />',
+ '<img alt="{1}" title="{1}" src="{0}flag/{1}" />',
deluge.config.base,
value
);
@@ -40,7 +40,7 @@
// fast way to figure out if we have a peer already.
peers: {},
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
title: _('Peers'),
@@ -73,7 +73,7 @@
header: _('Client'),
width: 125,
sortable: true,
- renderer: fplain,
+ renderer: 'htmlEncode',
dataIndex: 'client',
},
{
@@ -107,19 +107,19 @@
Deluge.details.PeersTab.superclass.constructor.call(this, config);
},
- clear: function() {
+ clear: function () {
this.getStore().removeAll();
this.peers = {};
},
- update: function(torrentId) {
+ update: function (torrentId) {
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Peers, {
success: this.onRequestComplete,
scope: this,
});
},
- onRequestComplete: function(torrent, options) {
+ onRequestComplete: function (torrent, options) {
if (!torrent) return;
var store = this.getStore();
@@ -129,7 +129,7 @@
// Go through the peers updating and creating peer records
Ext.each(
torrent.peers,
- function(peer) {
+ function (peer) {
if (this.peers[peer.ip]) {
var record = store.getById(peer.ip);
record.beginEdit();
@@ -150,7 +150,7 @@
store.add(newPeers);
// Remove any peers that should not be left in the store.
- store.each(function(record) {
+ store.each(function (record) {
if (!addresses[record.id]) {
store.remove(record);
delete this.peers[record.id];
diff --git a/deluge/ui/web/js/deluge-all/details/StatusTab.js b/deluge/ui/web/js/deluge-all/details/StatusTab.js
index a8753bb..6055161 100644
--- a/deluge/ui/web/js/deluge-all/details/StatusTab.js
+++ b/deluge/ui/web/js/deluge-all/details/StatusTab.js
@@ -17,7 +17,7 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
title: _('Status'),
autoScroll: true,
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Deluge.details.StatusTab.superclass.onRender.call(this, ct, position);
this.progressBar = this.add({
@@ -33,7 +33,7 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
width: 1000,
listeners: {
render: {
- fn: function(panel) {
+ fn: function (panel) {
panel.load({
url: deluge.config.base + 'render/tab_status.html',
text: _('Loading') + '...',
@@ -48,14 +48,14 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
});
},
- clear: function() {
+ clear: function () {
this.progressBar.updateProgress(0, ' ');
for (var k in this.fields) {
this.fields[k].innerHTML = '';
}
},
- update: function(torrentId) {
+ update: function (torrentId) {
if (!this.fields) this.getFields();
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Status, {
success: this.onRequestComplete,
@@ -63,18 +63,18 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
});
},
- onPanelUpdate: function(el, response) {
+ onPanelUpdate: function (el, response) {
this.fields = {};
Ext.each(
Ext.query('dd', this.status.body.dom),
- function(field) {
+ function (field) {
this.fields[field.className] = field;
},
this
);
},
- onRequestComplete: function(status) {
+ onRequestComplete: function (status) {
seeds =
status.total_seeds > -1
? status.num_seeds + ' (' + status.total_seeds + ')'
diff --git a/deluge/ui/web/js/deluge-all/preferences/BandwidthPage.js b/deluge/ui/web/js/deluge-all/preferences/BandwidthPage.js
index 031104c..8c32da5 100644
--- a/deluge/ui/web/js/deluge-all/preferences/BandwidthPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/BandwidthPage.js
@@ -14,7 +14,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -28,7 +28,7 @@ Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, {
Deluge.preferences.Bandwidth.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Bandwidth.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
@@ -117,8 +117,7 @@ Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, {
border: false,
title: '',
defaultType: 'checkbox',
- style:
- 'padding-top: 0px; padding-bottom: 5px; margin-top: 0px; margin-bottom: 0px;',
+ style: 'padding-top: 0px; padding-bottom: 5px; margin-top: 0px; margin-bottom: 0px;',
autoHeight: true,
});
om.bind(
diff --git a/deluge/ui/web/js/deluge-all/preferences/CachePage.js b/deluge/ui/web/js/deluge-all/preferences/CachePage.js
index 2c84c7b..bd5acd8 100644
--- a/deluge/ui/web/js/deluge-all/preferences/CachePage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/CachePage.js
@@ -19,7 +19,7 @@ Deluge.preferences.Cache = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Cache.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
diff --git a/deluge/ui/web/js/deluge-all/preferences/DaemonPage.js b/deluge/ui/web/js/deluge-all/preferences/DaemonPage.js
index 38f5750..1787826 100644
--- a/deluge/ui/web/js/deluge-all/preferences/DaemonPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/DaemonPage.js
@@ -19,7 +19,7 @@ Deluge.preferences.Daemon = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Daemon.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
diff --git a/deluge/ui/web/js/deluge-all/preferences/DownloadsPage.js b/deluge/ui/web/js/deluge-all/preferences/DownloadsPage.js
index bba5e47..04ffd15 100644
--- a/deluge/ui/web/js/deluge-all/preferences/DownloadsPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/DownloadsPage.js
@@ -14,7 +14,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Downloads = Ext.extend(Ext.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -29,7 +29,7 @@ Deluge.preferences.Downloads = Ext.extend(Ext.FormPanel, {
Deluge.preferences.Downloads.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Downloads.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
diff --git a/deluge/ui/web/js/deluge-all/preferences/EncryptionPage.js b/deluge/ui/web/js/deluge-all/preferences/EncryptionPage.js
index af5ad51..1bcf95e 100644
--- a/deluge/ui/web/js/deluge-all/preferences/EncryptionPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/EncryptionPage.js
@@ -18,7 +18,7 @@ Deluge.preferences.Encryption = Ext.extend(Ext.form.FormPanel, {
title: _('Encryption'),
header: false,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Encryption.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
diff --git a/deluge/ui/web/js/deluge-all/preferences/InstallPluginWindow.js b/deluge/ui/web/js/deluge-all/preferences/InstallPluginWindow.js
index c394664..9aefce3 100644
--- a/deluge/ui/web/js/deluge-all/preferences/InstallPluginWindow.js
+++ b/deluge/ui/web/js/deluge-all/preferences/InstallPluginWindow.js
@@ -26,7 +26,7 @@ Deluge.preferences.InstallPluginWindow = Ext.extend(Ext.Window, {
modal: true,
plain: true,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.InstallPluginWindow.superclass.initComponent.call(
this
);
@@ -53,7 +53,7 @@ Deluge.preferences.InstallPluginWindow = Ext.extend(Ext.Window, {
});
},
- onInstall: function(field, e) {
+ onInstall: function (field, e) {
this.form.getForm().submit({
url: deluge.config.base + 'upload',
waitMsg: _('Uploading your plugin...'),
@@ -62,11 +62,11 @@ Deluge.preferences.InstallPluginWindow = Ext.extend(Ext.Window, {
});
},
- onUploadPlugin: function(info, obj, response, request) {
+ onUploadPlugin: function (info, obj, response, request) {
this.fireEvent('pluginadded');
},
- onUploadSuccess: function(fp, upload) {
+ onUploadSuccess: function (fp, upload) {
this.hide();
if (upload.result.success) {
var filename = this.form.getForm().getFieldValues().file;
diff --git a/deluge/ui/web/js/deluge-all/preferences/InterfacePage.js b/deluge/ui/web/js/deluge-all/preferences/InterfacePage.js
index f5b0290..b6b76eb 100644
--- a/deluge/ui/web/js/deluge-all/preferences/InterfacePage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/InterfacePage.js
@@ -19,7 +19,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Interface.superclass.initComponent.call(this);
var om = (this.optionsManager = new Deluge.OptionsManager());
@@ -189,7 +189,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
);
},
- onApply: function() {
+ onApply: function () {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
deluge.client.web.set_config(changed, {
@@ -211,7 +211,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
no: _('Close'),
},
multiline: false,
- fn: function(btnText) {
+ fn: function (btnText) {
if (btnText === 'yes') location.reload();
},
icon: Ext.MessageBox.QUESTION,
@@ -223,21 +223,21 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
}
},
- onOk: function() {
+ onOk: function () {
this.onApply();
},
- onGotConfig: function(config) {
+ onGotConfig: function (config) {
this.optionsManager.set(config);
},
- onGotLanguages: function(info, obj, response, request) {
+ onGotLanguages: function (info, obj, response, request) {
info.unshift(['', _('System Default')]);
this.language.store.loadData(info);
this.language.setValue(this.optionsManager.get('language'));
},
- onPasswordChange: function() {
+ onPasswordChange: function () {
var newPassword = this.newPassword.getValue();
if (newPassword != this.confirmPassword.getValue()) {
Ext.MessageBox.show({
@@ -253,7 +253,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
var oldPassword = this.oldPassword.getValue();
deluge.client.auth.change_password(oldPassword, newPassword, {
- success: function(result) {
+ success: function (result) {
if (!result) {
Ext.MessageBox.show({
title: _('Password'),
@@ -282,11 +282,11 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
});
},
- onSetConfig: function() {
+ onSetConfig: function () {
this.optionsManager.commit();
},
- onPageShow: function() {
+ onPageShow: function () {
deluge.client.web.get_config({
success: this.onGotConfig,
scope: this,
@@ -297,7 +297,7 @@ Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, {
});
},
- onSSLCheck: function(e, checked) {
+ onSSLCheck: function (e, checked) {
this.pkeyField.setDisabled(!checked);
this.certField.setDisabled(!checked);
},
diff --git a/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js b/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js
index 651ba4f..5ba98e7 100644
--- a/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js
@@ -11,7 +11,7 @@ Ext.namespace('Deluge.preferences');
// custom Vtype for vtype:'IPAddress'
Ext.apply(Ext.form.VTypes, {
- IPAddress: function(v) {
+ IPAddress: function (v) {
return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
},
IPAddressText: 'Must be a numeric IP address',
@@ -28,7 +28,7 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
title: _('Network'),
header: false,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Network.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
@@ -71,7 +71,7 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
height: 22,
listeners: {
check: {
- fn: function(e, checked) {
+ fn: function (e, checked) {
this.listenPort.setDisabled(checked);
},
scope: this,
@@ -133,7 +133,7 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
height: 22,
listeners: {
check: {
- fn: function(e, checked) {
+ fn: function (e, checked) {
this.outgoingPorts.setDisabled(checked);
},
scope: this,
diff --git a/deluge/ui/web/js/deluge-all/preferences/OtherPage.js b/deluge/ui/web/js/deluge-all/preferences/OtherPage.js
index 1538203..607da22 100644
--- a/deluge/ui/web/js/deluge-all/preferences/OtherPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/OtherPage.js
@@ -14,7 +14,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Other = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -27,7 +27,7 @@ Deluge.preferences.Other = Ext.extend(Ext.form.FormPanel, {
Deluge.preferences.Other.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Other.superclass.initComponent.call(this);
var optMan = deluge.preferences.getOptionsManager();
diff --git a/deluge/ui/web/js/deluge-all/preferences/PluginsPage.js b/deluge/ui/web/js/deluge-all/preferences/PluginsPage.js
index e22fc7f..f771d96 100644
--- a/deluge/ui/web/js/deluge-all/preferences/PluginsPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/PluginsPage.js
@@ -40,7 +40,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
'</dl>'
),
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Plugins.superclass.initComponent.call(this);
this.defaultValues = {
version: '',
@@ -50,7 +50,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
};
this.pluginTemplate.compile();
- var checkboxRenderer = function(v, p, record) {
+ var checkboxRenderer = function (v, p, record) {
p.css += ' x-grid3-check-col-td';
return (
'<div class="x-grid3-check-col' + (v ? '-on' : '') + '"> </div>'
@@ -72,7 +72,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
width: 0.2,
sortable: true,
tpl: new Ext.XTemplate('{enabled:this.getCheckbox}', {
- getCheckbox: function(v) {
+ getCheckbox: function (v) {
return (
'<div class="x-grid3-check-col' +
(v ? '-on' : '') +
@@ -141,23 +141,23 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
deluge.events.on('PluginEnabledEvent', this.onPluginEnabled, this);
},
- disablePlugin: function(plugin) {
+ disablePlugin: function (plugin) {
deluge.client.core.disable_plugin(plugin);
},
- enablePlugin: function(plugin) {
+ enablePlugin: function (plugin) {
deluge.client.core.enable_plugin(plugin);
},
- setInfo: function(plugin) {
+ setInfo: function (plugin) {
if (!this.pluginInfo.rendered) return;
var values = plugin || this.defaultValues;
this.pluginInfo.body.dom.innerHTML = this.pluginTemplate.apply(values);
},
- updatePlugins: function() {
- var onGotAvailablePlugins = function(plugins) {
- this.availablePlugins = plugins.sort(function(a, b) {
+ updatePlugins: function () {
+ var onGotAvailablePlugins = function (plugins) {
+ this.availablePlugins = plugins.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
@@ -167,7 +167,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
});
};
- var onGotEnabledPlugins = function(plugins) {
+ var onGotEnabledPlugins = function (plugins) {
this.enabledPlugins = plugins;
this.onGotPlugins();
};
@@ -178,11 +178,11 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
});
},
- updatePluginsGrid: function() {
+ updatePluginsGrid: function () {
var plugins = [];
Ext.each(
this.availablePlugins,
- function(plugin) {
+ function (plugin) {
if (this.enabledPlugins.indexOf(plugin) > -1) {
plugins.push([true, plugin]);
} else {
@@ -194,7 +194,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
this.list.getStore().loadData(plugins);
},
- onNodeClick: function(dv, index, node, e) {
+ onNodeClick: function (dv, index, node, e) {
var el = new Ext.Element(e.target);
if (el.getAttribute('rel') != 'chkbox') return;
@@ -209,16 +209,16 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
}
},
- onFindMorePlugins: function() {
+ onFindMorePlugins: function () {
window.open('http://dev.deluge-torrent.org/wiki/Plugins');
},
- onGotPlugins: function() {
+ onGotPlugins: function () {
this.setInfo();
this.updatePluginsGrid();
},
- onGotPluginInfo: function(info) {
+ onGotPluginInfo: function (info) {
var values = {
author: info['Author'],
version: info['Version'],
@@ -230,7 +230,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
delete info;
},
- onInstallPluginWindow: function() {
+ onInstallPluginWindow: function () {
if (!this.installWindow) {
this.installWindow = new Deluge.preferences.InstallPluginWindow();
this.installWindow.on('pluginadded', this.onPluginInstall, this);
@@ -238,7 +238,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
this.installWindow.show();
},
- onPluginEnabled: function(pluginName) {
+ onPluginEnabled: function (pluginName) {
var index = this.list.getStore().find('plugin', pluginName);
if (index == -1) return;
var plugin = this.list.getStore().getAt(index);
@@ -246,7 +246,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
plugin.commit();
},
- onPluginDisabled: function(pluginName) {
+ onPluginDisabled: function (pluginName) {
var index = this.list.getStore().find('plugin', pluginName);
if (index == -1) return;
var plugin = this.list.getStore().getAt(index);
@@ -254,11 +254,11 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
plugin.commit();
},
- onPluginInstall: function() {
+ onPluginInstall: function () {
this.updatePlugins();
},
- onPluginSelect: function(dv, selections) {
+ onPluginSelect: function (dv, selections) {
if (selections.length == 0) return;
var r = dv.getRecords(selections)[0];
deluge.client.web.get_plugin_info(r.get('plugin'), {
@@ -267,11 +267,11 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
});
},
- onPreferencesShow: function() {
+ onPreferencesShow: function () {
this.updatePlugins();
},
- onPluginInfoRender: function(ct, position) {
+ onPluginInfoRender: function (ct, position) {
this.setInfo();
},
});
diff --git a/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js b/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
index 1bc98a8..4cfed01 100644
--- a/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
+++ b/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
@@ -36,7 +36,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
pages: {},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.PreferencesWindow.superclass.initComponent.call(
this
);
@@ -46,7 +46,6 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
columns: [
{
id: 'name',
- renderer: fplain,
dataIndex: 'name',
},
],
@@ -94,7 +93,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
this.initPages();
},
- initPages: function() {
+ initPages: function () {
deluge.preferences = this;
this.addPage(new Deluge.preferences.Downloads());
this.addPage(new Deluge.preferences.Network());
@@ -109,7 +108,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
this.addPage(new Deluge.preferences.Plugins());
},
- onApply: function(e) {
+ onApply: function (e) {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
// Workaround for only displaying single listen port but still pass array to core.
@@ -134,7 +133,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Return the options manager for the preferences window.
* @returns {Deluge.OptionsManager} the options manager
*/
- getOptionsManager: function() {
+ getOptionsManager: function () {
return this.optionsManager;
},
@@ -142,7 +141,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Adds a page to the preferences window.
* @param {Mixed} page
*/
- addPage: function(page) {
+ addPage: function (page) {
var store = this.list.getStore();
var name = page.title;
store.add([new PreferencesRecord({ name: name })]);
@@ -157,7 +156,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Removes a preferences page from the window.
* @param {mixed} name
*/
- removePage: function(page) {
+ removePage: function (page) {
var name = page.title;
var store = this.list.getStore();
store.removeAt(store.find('name', name));
@@ -169,7 +168,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
* Select which preferences page is displayed.
* @param {String} page The page name to change to
*/
- selectPage: function(page) {
+ selectPage: function (page) {
if (this.pages[page].index < 0) {
this.pages[page].index = this.configPanel.items.indexOf(
this.pages[page]
@@ -179,7 +178,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- doSelectPage: function(page) {
+ doSelectPage: function (page) {
if (this.pages[page].index < 0) {
this.pages[page].index = this.configPanel.items.indexOf(
this.pages[page]
@@ -190,23 +189,23 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- onGotConfig: function(config) {
+ onGotConfig: function (config) {
this.getOptionsManager().set(config);
},
// private
- onPageSelect: function(list, selections) {
+ onPageSelect: function (list, selections) {
var r = list.getRecord(selections[0]);
this.doSelectPage(r.get('name'));
},
// private
- onSetConfig: function() {
+ onSetConfig: function () {
this.getOptionsManager().commit();
},
// private
- onAfterRender: function() {
+ onAfterRender: function () {
if (!this.list.getSelectionCount()) {
this.list.select(0);
}
@@ -214,7 +213,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- onShow: function() {
+ onShow: function () {
if (!deluge.client.core) return;
deluge.client.core.get_config({
success: this.onGotConfig,
@@ -223,12 +222,12 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
},
// private
- onClose: function() {
+ onClose: function () {
this.hide();
},
// private
- onOk: function() {
+ onOk: function () {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
deluge.client.core.set_config(changed, {
diff --git a/deluge/ui/web/js/deluge-all/preferences/ProxyField.js b/deluge/ui/web/js/deluge-all/preferences/ProxyField.js
index 6d500ba..d3bb0bf 100644
--- a/deluge/ui/web/js/deluge-all/preferences/ProxyField.js
+++ b/deluge/ui/web/js/deluge-all/preferences/ProxyField.js
@@ -18,7 +18,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
autoHeight: true,
labelWidth: 70,
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.ProxyField.superclass.initComponent.call(this);
this.proxyType = this.add({
xtype: 'combo',
@@ -145,11 +145,11 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
this.setting = false;
},
- getName: function() {
+ getName: function () {
return this.initialConfig.name;
},
- getValue: function() {
+ getValue: function () {
return {
type: this.proxyType.getValue(),
hostname: this.hostname.getValue(),
@@ -165,7 +165,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
},
// Set the values of the proxies
- setValue: function(value) {
+ setValue: function (value) {
this.setting = true;
this.proxyType.setValue(value['type']);
var index = this.proxyType.getStore().find('id', value['type']);
@@ -185,7 +185,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
this.setting = false;
},
- onFieldChange: function(field, newValue, oldValue) {
+ onFieldChange: function (field, newValue, oldValue) {
if (this.setting) return;
var newValues = this.getValue();
var oldValues = Ext.apply({}, newValues);
@@ -194,7 +194,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
this.fireEvent('change', this, newValues, oldValues);
},
- onTypeSelect: function(combo, record, index) {
+ onTypeSelect: function (combo, record, index) {
var typeId = record.get('id');
if (typeId > 0) {
this.hostname.show();
diff --git a/deluge/ui/web/js/deluge-all/preferences/ProxyPage.js b/deluge/ui/web/js/deluge-all/preferences/ProxyPage.js
index 4d3c402..2dc4cae 100644
--- a/deluge/ui/web/js/deluge-all/preferences/ProxyPage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/ProxyPage.js
@@ -14,7 +14,7 @@ Ext.namespace('Deluge.preferences');
* @extends Ext.form.FormPanel
*/
Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, {
- constructor: function(config) {
+ constructor: function (config) {
config = Ext.apply(
{
border: false,
@@ -28,7 +28,7 @@ Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, {
Deluge.preferences.Proxy.superclass.constructor.call(this, config);
},
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Proxy.superclass.initComponent.call(this);
this.proxy = this.add(
new Deluge.preferences.ProxyField({
@@ -40,19 +40,19 @@ Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, {
deluge.preferences.getOptionsManager().bind('proxy', this.proxy);
},
- getValue: function() {
+ getValue: function () {
return {
proxy: this.proxy.getValue(),
};
},
- setValue: function(value) {
+ setValue: function (value) {
for (var proxy in value) {
this[proxy].setValue(value[proxy]);
}
},
- onProxyChange: function(field, newValue, oldValue) {
+ onProxyChange: function (field, newValue, oldValue) {
var newValues = this.getValue();
var oldValues = Ext.apply({}, newValues);
oldValues[field.getName()] = oldValue;
diff --git a/deluge/ui/web/js/deluge-all/preferences/QueuePage.js b/deluge/ui/web/js/deluge-all/preferences/QueuePage.js
index db2da7c..c7b47c5 100644
--- a/deluge/ui/web/js/deluge-all/preferences/QueuePage.js
+++ b/deluge/ui/web/js/deluge-all/preferences/QueuePage.js
@@ -19,7 +19,7 @@ Deluge.preferences.Queue = Ext.extend(Ext.form.FormPanel, {
header: false,
layout: 'form',
- initComponent: function() {
+ initComponent: function () {
Deluge.preferences.Queue.superclass.initComponent.call(this);
var om = deluge.preferences.getOptionsManager();
@@ -227,7 +227,7 @@ Deluge.preferences.Queue = Ext.extend(Ext.form.FormPanel, {
om.bind('remove_seed_at_ratio', this.removeAtRatio);
},
- onStopRatioCheck: function(e, checked) {
+ onStopRatioCheck: function (e, checked) {
this.stopRatio.setDisabled(!checked);
this.removeAtRatio.setDisabled(!checked);
},
diff --git a/deluge/ui/web/js/extjs/ext-extensions-debug.js b/deluge/ui/web/js/extjs/ext-extensions-debug.js
index a5b4a60..8a05e61 100644
--- a/deluge/ui/web/js/extjs/ext-extensions-debug.js
+++ b/deluge/ui/web/js/extjs/ext-extensions-debug.js
@@ -50,7 +50,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
autoSize: Ext.emptyFn,
// private
- initComponent: function() {
+ initComponent: function () {
Ext.ux.form.FileUploadField.superclass.initComponent.call(this);
this.addEvents(
@@ -66,7 +66,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
},
// private
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Ext.ux.form.FileUploadField.superclass.onRender.call(
this,
ct,
@@ -97,30 +97,30 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
this.resizeEl = this.positionEl = this.wrap;
},
- bindListeners: function() {
+ bindListeners: function () {
this.fileInput.on({
scope: this,
- mouseenter: function() {
+ mouseenter: function () {
this.button.addClass(['x-btn-over', 'x-btn-focus']);
},
- mouseleave: function() {
+ mouseleave: function () {
this.button.removeClass([
'x-btn-over',
'x-btn-focus',
'x-btn-click',
]);
},
- mousedown: function() {
+ mousedown: function () {
this.button.addClass('x-btn-click');
},
- mouseup: function() {
+ mouseup: function () {
this.button.removeClass([
'x-btn-over',
'x-btn-focus',
'x-btn-click',
]);
},
- change: function() {
+ change: function () {
var value = this.fileInput.dom.files;
// Fallback to value.
if (!value) value = this.fileInput.dom.value;
@@ -130,7 +130,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
});
},
- createFileInput: function() {
+ createFileInput: function () {
this.fileInput = this.wrap.createChild({
id: this.getFileInputId(),
name: this.name || this.getId(),
@@ -142,7 +142,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
this.fileInput.dom.multiple = this.multiple;
},
- reset: function() {
+ reset: function () {
if (this.rendered) {
this.fileInput.remove();
this.createFileInput();
@@ -152,12 +152,12 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
},
// private
- getFileInputId: function() {
+ getFileInputId: function () {
return this.id + '-file';
},
// private
- onResize: function(w, h) {
+ onResize: function (w, h) {
Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);
this.wrap.setWidth(w);
@@ -172,23 +172,23 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
},
// private
- onDestroy: function() {
+ onDestroy: function () {
Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
Ext.destroy(this.fileInput, this.button, this.wrap);
},
- onDisable: function() {
+ onDisable: function () {
Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
this.doDisable(true);
},
- onEnable: function() {
+ onEnable: function () {
Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
this.doDisable(false);
},
// private
- doDisable: function(disabled) {
+ doDisable: function (disabled) {
this.fileInput.dom.disabled = disabled;
this.button.setDisabled(disabled);
},
@@ -197,7 +197,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
preFocus: Ext.emptyFn,
// private
- alignErrorIcon: function() {
+ alignErrorIcon: function () {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
},
});
@@ -218,8 +218,8 @@ Ext.form.FileUploadField = Ext.ux.form.FileUploadField;
// Allow radiogroups to be treated as a single form element.
Ext.override(Ext.form.RadioGroup, {
- afterRender: function() {
- this.items.each(function(i) {
+ afterRender: function () {
+ this.items.each(function (i) {
this.relayEvents(i, ['check']);
}, this);
if (this.lazyValue) {
@@ -230,21 +230,21 @@ Ext.override(Ext.form.RadioGroup, {
Ext.form.RadioGroup.superclass.afterRender.call(this);
},
- getName: function() {
+ getName: function () {
return this.items.first().getName();
},
- getValue: function() {
+ getValue: function () {
return this.items.first().getGroupValue();
},
- setValue: function(v) {
+ setValue: function (v) {
if (!this.items.each) {
this.value = v;
this.lazyValue = true;
return;
}
- this.items.each(function(item) {
+ this.items.each(function (item) {
if (item.rendered) {
var checked = item.el.getValue() == String(v);
item.el.dom.checked = checked;
@@ -277,7 +277,7 @@ Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
onBlur: Ext.emptyFn,
adjustSize: Ext.BoxComponent.prototype.adjustSize,
- constructor: function(config) {
+ constructor: function (config) {
var spinnerConfig = Ext.copyTo(
{},
config,
@@ -299,23 +299,23 @@ Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
},
// private
- getResizeEl: function() {
+ getResizeEl: function () {
return this.wrap;
},
// private
- getPositionEl: function() {
+ getPositionEl: function () {
return this.wrap;
},
// private
- alignErrorIcon: function() {
+ alignErrorIcon: function () {
if (this.wrap) {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
},
- validateBlur: function() {
+ validateBlur: function () {
return true;
},
});
@@ -362,7 +362,7 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
colCfg: {},
// private
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
if (!this.el) {
var panelCfg = {
cls: this.groupCls,
@@ -419,9 +419,8 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
// Generate the column configs with the correct width setting
for (var i = 0; i < numCols; i++) {
var cc = Ext.apply({ items: [] }, colCfg);
- cc[
- this.columns[i] <= 1 ? 'columnWidth' : 'width'
- ] = this.columns[i];
+ cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] =
+ this.columns[i];
if (this.defaults) {
cc.defaults = Ext.apply(
cc.defaults || {},
@@ -470,14 +469,14 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
}
}
- var fields = this.panel.findBy(function(c) {
+ var fields = this.panel.findBy(function (c) {
return c.isFormField;
}, this);
this.items = new Ext.util.MixedCollection();
this.items.addAll(fields);
- this.items.each(function(field) {
+ this.items.each(function (field) {
field.on('spin', this.onFieldChange, this);
field.on('change', this.onFieldChange, this);
}, this);
@@ -498,45 +497,45 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
Ext.ux.form.SpinnerGroup.superclass.onRender.call(this, ct, position);
},
- onFieldChange: function(spinner) {
+ onFieldChange: function (spinner) {
this.fireEvent('change', this, this.getValue());
},
initValue: Ext.emptyFn,
- getValue: function() {
+ getValue: function () {
var value = [this.items.getCount()];
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
value[i] = Number(item.getValue());
});
return value;
},
- getRawValue: function() {
+ getRawValue: function () {
var value = [this.items.getCount()];
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
value[i] = Number(item.getRawValue());
});
return value;
},
- setValue: function(value) {
+ setValue: function (value) {
if (!this.rendered) {
this.value = value;
this.lazyValueSet = true;
} else {
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
item.setValue(value[i]);
});
}
},
- setRawValue: function(value) {
+ setRawValue: function (value) {
if (!this.rendered) {
this.rawValue = value;
this.lazyRawValueSet = true;
} else {
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
item.setRawValue(value[i]);
});
}
@@ -566,7 +565,7 @@ Ext.namespace('Ext.ux.form');
Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
cls: 'x-toggle-field',
- initComponent: function() {
+ initComponent: function () {
Ext.ux.form.ToggleField.superclass.initComponent.call(this);
this.toggle = new Ext.form.Checkbox();
@@ -577,7 +576,7 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
});
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
if (!this.el) {
this.panel = new Ext.Panel({
cls: this.groupCls,
@@ -595,16 +594,13 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
this.panel.add(this.input);
this.panel.doLayout();
- this.toggle
- .getEl()
- .parent()
- .setStyle('padding-right', '10px');
+ this.toggle.getEl().parent().setStyle('padding-right', '10px');
}
Ext.ux.form.ToggleField.superclass.onRender.call(this, ct, position);
},
// private
- onResize: function(w, h) {
+ onResize: function (w, h) {
this.panel.setSize(w, h);
this.panel.doLayout();
@@ -613,7 +609,7 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
this.input.setSize(inputWidth, h);
},
- onToggleCheck: function(toggle, checked) {
+ onToggleCheck: function (toggle, checked) {
this.input.setDisabled(!checked);
},
});
@@ -666,7 +662,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
*/
cleanDelay: 500,
- initTemplates: function() {
+ initTemplates: function () {
Ext.ux.grid.BufferView.superclass.initTemplates.call(this);
var ts = this.templates;
// empty div to act as a place holder for a row
@@ -688,23 +684,23 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
ts.rowBody.compile();
},
- getStyleRowHeight: function() {
+ getStyleRowHeight: function () {
return Ext.isBorderBox
? this.rowHeight + this.borderHeight
: this.rowHeight;
},
- getCalculatedRowHeight: function() {
+ getCalculatedRowHeight: function () {
return this.rowHeight + this.borderHeight;
},
- getVisibleRowCount: function() {
+ getVisibleRowCount: function () {
var rh = this.getCalculatedRowHeight(),
visibleHeight = this.scroller.dom.clientHeight;
return visibleHeight < 1 ? 0 : Math.ceil(visibleHeight / rh);
},
- getVisibleRows: function() {
+ getVisibleRows: function () {
var count = this.getVisibleRowCount(),
sc = this.scroller.dom.scrollTop,
start =
@@ -717,7 +713,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
};
},
- doRender: function(cs, rs, ds, startRow, colCount, stripe, onlyBody) {
+ doRender: function (cs, rs, ds, startRow, colCount, stripe, onlyBody) {
var ts = this.templates,
ct = ts.cell,
rt = ts.row,
@@ -782,18 +778,18 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
return buf.join('');
},
- isRowRendered: function(index) {
+ isRowRendered: function (index) {
var row = this.getRow(index);
return row && row.childNodes.length > 0;
},
- syncScroll: function() {
+ syncScroll: function () {
Ext.ux.grid.BufferView.superclass.syncScroll.apply(this, arguments);
this.update();
},
// a (optionally) buffered method to update contents of gridview
- update: function() {
+ update: function () {
if (this.scrollDelay) {
if (!this.renderTask) {
this.renderTask = new Ext.util.DelayedTask(this.doUpdate, this);
@@ -804,14 +800,14 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
}
},
- onRemove: function(ds, record, index, isUpdate) {
+ onRemove: function (ds, record, index, isUpdate) {
Ext.ux.grid.BufferView.superclass.onRemove.apply(this, arguments);
if (isUpdate !== true) {
this.update();
}
},
- doUpdate: function() {
+ doUpdate: function () {
if (this.getVisibleRowCount() > 0) {
var g = this.grid,
cm = g.colModel,
@@ -839,14 +835,14 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
},
// a buffered method to clean rows
- clean: function() {
+ clean: function () {
if (!this.cleanTask) {
this.cleanTask = new Ext.util.DelayedTask(this.doClean, this);
}
this.cleanTask.delay(this.cleanDelay);
},
- doClean: function() {
+ doClean: function () {
if (this.getVisibleRowCount() > 0) {
var vr = this.getVisibleRows();
vr.first -= this.cacheSize;
@@ -869,7 +865,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
}
},
- removeTask: function(name) {
+ removeTask: function (name) {
var task = this[name];
if (task && task.cancel) {
task.cancel();
@@ -877,13 +873,13 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
}
},
- destroy: function() {
+ destroy: function () {
this.removeTask('cleanTask');
this.removeTask('renderTask');
Ext.ux.grid.BufferView.superclass.destroy.call(this);
},
- layout: function() {
+ layout: function () {
Ext.ux.grid.BufferView.superclass.layout.call(this);
this.update();
},
@@ -902,7 +898,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
// remove spaces for hidden elements and make show(), hide(), enable() and disable() act on
// the label. don't use hideLabel with this.
Ext.override(Ext.layout.FormLayout, {
- renderItem: function(c, position, target) {
+ renderItem: function (c, position, target) {
if (
c &&
!c.rendered &&
@@ -942,7 +938,7 @@ Ext.override(Ext.layout.FormLayout, {
* @author Damien Churchill <damoxc@gmail.com>
*/
Ext.override(Ext.tree.MultiSelectionModel, {
- onNodeClick: function(node, e) {
+ onNodeClick: function (node, e) {
if (e.ctrlKey && this.isSelected(node)) {
this.unselect(node);
} else if (e.shiftKey && !this.isSelected(node)) {
@@ -963,7 +959,7 @@ Ext.override(Ext.tree.MultiSelectionModel, {
}
// Select all the nodes
- parentNode.eachChild(function(n) {
+ parentNode.eachChild(function (n) {
var i = parentNode.indexOf(n);
if (fi < i && i < li) {
this.select(n, e, true, true);
@@ -977,7 +973,7 @@ Ext.override(Ext.tree.MultiSelectionModel, {
}
},
- select: function(node, e, keepExisting, suppressEvent) {
+ select: function (node, e, keepExisting, suppressEvent) {
if (keepExisting !== true) {
this.clearSelections(true);
}
@@ -1023,7 +1019,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
columnsText: 'Columns',
- initComponent: function() {
+ initComponent: function () {
if (!this.root) {
this.root = new Ext.tree.AsyncTreeNode({ text: 'Root' });
}
@@ -1095,7 +1091,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- initColumns: function() {
+ initColumns: function () {
var cs = this.columns,
len = cs.length,
columns = [],
@@ -1124,7 +1120,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.columns = columns;
},
- onRender: function() {
+ onRender: function () {
Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
this.el.addClass('x-treegrid');
@@ -1173,7 +1169,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- setRootNode: function(node) {
+ setRootNode: function (node) {
node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;
node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
if (this.innerCt) {
@@ -1184,7 +1180,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return node;
},
- clearInnerCt: function() {
+ clearInnerCt: function () {
if (Ext.isIE) {
var dom = this.innerCt.dom;
while (dom.firstChild) {
@@ -1195,7 +1191,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- initEvents: function() {
+ initEvents: function () {
Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);
this.mon(this.innerBody, 'scroll', this.syncScroll, this);
@@ -1207,7 +1203,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
});
},
- onResize: function(w, h) {
+ onResize: function (w, h) {
Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
var bd = this.innerBody.dom;
@@ -1231,7 +1227,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.setScrollOffset(sw);
} else {
var me = this;
- setTimeout(function() {
+ setTimeout(function () {
me.setScrollOffset(
bd.offsetWidth - bd.clientWidth > 10 ? sw : 0
);
@@ -1240,7 +1236,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- updateColumnWidths: function() {
+ updateColumnWidths: function () {
var cols = this.columns,
colCount = cols.length,
groups = this.outerCt.query('colgroup'),
@@ -1279,7 +1275,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.syncHeaderScroll();
},
- getVisibleColumns: function() {
+ getVisibleColumns: function () {
var columns = [],
cs = this.columns,
len = cs.length,
@@ -1293,7 +1289,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return columns;
},
- getTotalColumnWidth: function() {
+ getTotalColumnWidth: function () {
var total = 0;
for (
var i = 0, cs = this.getVisibleColumns(), len = cs.length;
@@ -1305,13 +1301,13 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return total;
},
- setScrollOffset: function(scrollOffset) {
+ setScrollOffset: function (scrollOffset) {
this.scrollOffset = scrollOffset;
this.updateColumnWidths();
},
// private
- handleHdDown: function(e, t) {
+ handleHdDown: function (e, t) {
var hd = e.getTarget('.x-treegrid-hd');
if (hd && Ext.fly(t).hasClass('x-grid3-hd-btn')) {
@@ -1329,7 +1325,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.hmenu.on(
'hide',
- function() {
+ function () {
Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
},
this,
@@ -1344,7 +1340,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- handleHdOver: function(e, t) {
+ handleHdOver: function (e, t) {
var hd = e.getTarget('.x-treegrid-hd');
if (hd && !this.headersDisabled) {
index = this.findHeaderIndex(hd);
@@ -1362,7 +1358,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- handleHdOut: function(e, t) {
+ handleHdOut: function (e, t) {
var hd = e.getTarget('.x-treegrid-hd');
if (hd && (!Ext.isIE || !e.within(hd, true))) {
this.activeHdRef = null;
@@ -1371,7 +1367,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- findHeaderIndex: function(hd) {
+ findHeaderIndex: function (hd) {
hd = hd.dom || hd;
var cs = hd.parentNode.childNodes;
for (var i = 0, c; (c = cs[i]); i++) {
@@ -1383,7 +1379,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- beforeColMenuShow: function() {
+ beforeColMenuShow: function () {
var cols = this.columns,
colCount = cols.length,
i,
@@ -1406,7 +1402,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- handleHdMenuClick: function(item) {
+ handleHdMenuClick: function (item) {
var index = this.hdCtxIndex,
id = item.getItemId();
@@ -1427,7 +1423,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return true;
},
- setColumnVisible: function(index, visible) {
+ setColumnVisible: function (index, visible) {
this.columns[index].hidden = !visible;
this.updateColumnWidths();
},
@@ -1435,26 +1431,26 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
/**
* Scrolls the grid to the top
*/
- scrollToTop: function() {
+ scrollToTop: function () {
this.innerBody.dom.scrollTop = 0;
this.innerBody.dom.scrollLeft = 0;
},
// private
- syncScroll: function() {
+ syncScroll: function () {
this.syncHeaderScroll();
var mb = this.innerBody.dom;
this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
},
// private
- syncHeaderScroll: function() {
+ syncHeaderScroll: function () {
var mb = this.innerBody.dom;
this.innerHd.dom.scrollLeft = mb.scrollLeft;
this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
},
- registerNode: function(n) {
+ registerNode: function (n) {
Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
if (!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
@@ -1480,17 +1476,17 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
*/
minWidth: 14,
- constructor: function(config) {
+ constructor: function (config) {
Ext.apply(this, config);
Ext.tree.ColumnResizer.superclass.constructor.call(this);
},
- init: function(tree) {
+ init: function (tree) {
this.tree = tree;
tree.on('render', this.initEvents, this);
},
- initEvents: function(tree) {
+ initEvents: function (tree) {
tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this);
this.tracker = new Ext.dd.DragTracker({
onBeforeStart: this.onBeforeStart.createDelegate(this),
@@ -1504,7 +1500,7 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
tree.on('beforedestroy', this.tracker.destroy, this.tracker);
},
- handleHdMove: function(e, t) {
+ handleHdMove: function (e, t) {
var hw = 5,
x = e.getPageX(),
hd = e.getTarget('.x-treegrid-hd', 3, true);
@@ -1539,12 +1535,12 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
}
},
- onBeforeStart: function(e) {
+ onBeforeStart: function (e) {
this.dragHd = this.activeHd;
return !!this.dragHd;
},
- onStart: function(e) {
+ onStart: function (e) {
this.dragHeadersDisabled = this.tree.headersDisabled;
this.tree.headersDisabled = true;
this.proxy = this.tree.body.createChild({ cls: 'x-treegrid-resizer' });
@@ -1563,14 +1559,14 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
this.tree.innerBody.translatePoints(this.hdX).left;
},
- onDrag: function(e) {
+ onDrag: function (e) {
var cursorX = this.tracker.getXY()[0];
this.proxy.setWidth(
(cursorX - this.hdX).constrain(this.minWidth, this.maxWidth)
);
},
- onEnd: function(e) {
+ onEnd: function (e) {
var nw = this.proxy.getWidth(),
tree = this.tree,
disabled = this.dragHeadersDisabled;
@@ -1581,7 +1577,7 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
tree.columns[this.hdIndex].width = nw;
tree.updateColumnWidths();
- setTimeout(function() {
+ setTimeout(function () {
tree.headersDisabled = disabled;
}, 100);
},
@@ -1592,9 +1588,9 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
* licensing@sencha.com
* http://www.sencha.com/license
*/
-(function() {
+(function () {
Ext.override(Ext.list.Column, {
- init: function() {
+ init: function () {
var types = Ext.data.Types,
st = this.sortType;
@@ -1637,7 +1633,7 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
* @extends Ext.tree.TreeLoader
*/
Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
- createNode: function(attr) {
+ createNode: function (attr) {
if (!attr.uiProvider) {
attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
}
@@ -1657,7 +1653,7 @@ Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
- renderElements: function(n, a, targetNode, bulkRender) {
+ renderElements: function (n, a, targetNode, bulkRender) {
var t = n.getOwnerTree(),
cols = t.columns,
c = cols[0],
@@ -1757,7 +1753,7 @@ Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
},
// private
- animExpand: function(cb) {
+ animExpand: function (cb) {
this.ctNode.style.display = '';
Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb);
},
@@ -1767,7 +1763,7 @@ Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
// private
- render: function() {
+ render: function () {
if (!this.rendered) {
this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom;
this.node.expanded = true;
@@ -1777,13 +1773,13 @@ Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
// weird table-layout: fixed issue in webkit
var ct = this.ctNode;
ct.style.tableLayout = null;
- (function() {
+ (function () {
ct.style.tableLayout = 'fixed';
}.defer(1));
}
},
- destroy: function() {
+ destroy: function () {
if (this.elNode) {
Ext.dd.Registry.unregister(this.elNode.id);
}
@@ -1804,7 +1800,7 @@ Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
*/
Ext.override(Ext.ux.tree.TreeGridNodeUI, {
- updateColumns: function() {
+ updateColumns: function () {
if (!this.rendered) return;
var a = this.node.attributes,
@@ -1827,7 +1823,7 @@ Ext.override(Ext.ux.tree.TreeGridNodeUI, {
},
});
Ext.tree.RenderColumn = Ext.extend(Ext.tree.Column, {
- constructor: function(c) {
+ constructor: function (c) {
c.tpl = c.tpl || new Ext.XTemplate('{' + c.dataIndex + ':this.format}');
c.tpl.format = c.renderer;
c.tpl.col = this;
@@ -1877,7 +1873,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
*/
sortDescText: 'Sort Descending',
- constructor: function(tree, config) {
+ constructor: function (tree, config) {
if (!Ext.isObject(config)) {
config = {
property: tree.columns[0].dataIndex || 'text',
@@ -1895,7 +1891,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
tree.ddAppendOnly = true;
var me = this;
- this.defaultSortFn = function(n1, n2) {
+ this.defaultSortFn = function (n1, n2) {
var desc = me.dir && me.dir.toLowerCase() == 'desc',
prop = me.property || 'text',
sortType = me.sortType,
@@ -1938,7 +1934,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
tree.on('headermenuclick', this.onHeaderMenuClick, this);
},
- onAfterTreeRender: function() {
+ onAfterTreeRender: function () {
if (this.tree.hmenu) {
this.tree.hmenu.insert(
0,
@@ -1957,14 +1953,14 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
this.updateSortIcon(0, 'asc');
},
- onHeaderMenuClick: function(c, id, index) {
+ onHeaderMenuClick: function (c, id, index) {
if (id === 'asc' || id === 'desc') {
this.onHeaderClick(c, null, index);
return false;
}
},
- onHeaderClick: function(c, el, i) {
+ onHeaderClick: function (c, el, i) {
if (c && !this.tree.headersDisabled) {
var me = this;
@@ -1976,7 +1972,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
: this.caseSensitive;
me.sortFn = c.sortFn || this.defaultSortFn;
- this.tree.root.cascade(function(n) {
+ this.tree.root.cascade(function (n) {
if (!n.isLeaf()) {
me.updateSort(me.tree, n);
}
@@ -1987,13 +1983,13 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
},
// private
- updateSortIcon: function(col, dir) {
+ updateSortIcon: function (col, dir) {
var sc = this.sortClasses,
hds = this.tree.innerHd.select('td').removeClass(sc);
hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]);
},
});
-Ext.ux.JSLoader = function(options) {
+Ext.ux.JSLoader = function (options) {
Ext.ux.JSLoader.scripts[++Ext.ux.JSLoader.index] = {
url: options.url,
success: true,
@@ -2007,7 +2003,7 @@ Ext.ux.JSLoader = function(options) {
Ext.Ajax.request({
url: options.url,
scriptIndex: Ext.ux.JSLoader.index,
- success: function(response, options) {
+ success: function (response, options) {
var script = Ext.ux.JSLoader.scripts[options.scriptIndex];
try {
eval(response.responseText);
@@ -2019,7 +2015,7 @@ Ext.ux.JSLoader = function(options) {
script.onLoad.call(script.scope, script.options);
}
},
- failure: function(response, options) {
+ failure: function (response, options) {
var script = Ext.ux.JSLoader.scripts[options.scriptIndex];
script.success = false;
script.onError(script.options, response.status);
@@ -2028,7 +2024,7 @@ Ext.ux.JSLoader = function(options) {
};
Ext.ux.JSLoader.index = 0;
Ext.ux.JSLoader.scripts = [];
-Ext.ux.JSLoader.stdError = function(options, e) {
+Ext.ux.JSLoader.stdError = function (options, e) {
window.alert(
'Error loading script:\n\n' + options.url + '\n\nstatus: ' + e
);
@@ -2053,13 +2049,13 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
defaultValue: 0,
accelerate: false,
- constructor: function(config) {
+ constructor: function (config) {
Ext.ux.Spinner.superclass.constructor.call(this, config);
Ext.apply(this, config);
this.mimicing = false;
},
- init: function(field) {
+ init: function (field) {
this.field = field;
field.afterMethod('onRender', this.doRender, this);
@@ -2071,7 +2067,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
field.beforeMethod('onDestroy', this.doDestroy, this);
},
- doRender: function(ct, position) {
+ doRender: function (ct, position) {
var el = (this.el = this.field.getEl());
var f = this.field;
@@ -2116,7 +2112,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.initSpinner();
},
- doAfterRender: function() {
+ doAfterRender: function () {
var y;
if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
this.el.position();
@@ -2124,14 +2120,14 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
}
},
- doEnable: function() {
+ doEnable: function () {
if (this.wrap) {
this.disabled = false;
this.wrap.removeClass(this.field.disabledClass);
}
},
- doDisable: function() {
+ doDisable: function () {
if (this.wrap) {
this.disabled = true;
this.wrap.addClass(this.field.disabledClass);
@@ -2139,14 +2135,14 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
}
},
- doResize: function(w, h) {
+ doResize: function (w, h) {
if (typeof w == 'number') {
this.el.setWidth(w - this.trigger.getWidth());
}
this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
},
- doFocus: function() {
+ doFocus: function () {
if (!this.mimicing) {
this.wrap.addClass('x-trigger-wrap-focus');
this.mimicing = true;
@@ -2163,21 +2159,21 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
// private
- checkTab: function(e) {
+ checkTab: function (e) {
if (e.getKey() == e.TAB) {
this.triggerBlur();
}
},
// private
- mimicBlur: function(e) {
+ mimicBlur: function (e) {
if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
this.triggerBlur();
}
},
// private
- triggerBlur: function() {
+ triggerBlur: function () {
this.mimicing = false;
Ext.get(Ext.isIE ? document.body : document).un(
'mousedown',
@@ -2190,12 +2186,12 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.field.onBlur.call(this.field);
},
- initTrigger: function() {
+ initTrigger: function () {
this.trigger.addClassOnOver('x-form-trigger-over');
this.trigger.addClassOnClick('x-form-trigger-click');
},
- initSpinner: function() {
+ initSpinner: function () {
this.field.addEvents({
spin: true,
spinup: true,
@@ -2203,22 +2199,22 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
});
this.keyNav = new Ext.KeyNav(this.el, {
- up: function(e) {
+ up: function (e) {
e.preventDefault();
this.onSpinUp();
},
- down: function(e) {
+ down: function (e) {
e.preventDefault();
this.onSpinDown();
},
- pageUp: function(e) {
+ pageUp: function (e) {
e.preventDefault();
this.onSpinUpAlternate();
},
- pageDown: function(e) {
+ pageDown: function (e) {
e.preventDefault();
this.onSpinDownAlternate();
},
@@ -2252,7 +2248,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.dd.onDrag = this.onDrag.createDelegate(this);
},
- onMouseOver: function() {
+ onMouseOver: function () {
if (this.disabled) {
return;
}
@@ -2265,12 +2261,12 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onMouseOut: function() {
+ onMouseOut: function () {
this.trigger.removeClass(this.tmpHoverClass);
},
//private
- onMouseMove: function() {
+ onMouseMove: function () {
if (this.disabled) {
return;
}
@@ -2285,7 +2281,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onMouseDown: function() {
+ onMouseDown: function () {
if (this.disabled) {
return;
}
@@ -2298,12 +2294,12 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onMouseUp: function() {
+ onMouseUp: function () {
this.trigger.removeClass(this.tmpClickClass);
},
//private
- onTriggerClick: function() {
+ onTriggerClick: function () {
if (this.disabled || this.el.dom.readOnly) {
return;
}
@@ -2313,7 +2309,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- getMiddle: function() {
+ getMiddle: function () {
var t = this.trigger.getTop();
var h = this.trigger.getHeight();
var middle = t + h / 2;
@@ -2322,7 +2318,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
//private
//checks if control is allowed to spin
- isSpinnable: function() {
+ isSpinnable: function () {
if (this.disabled || this.el.dom.readOnly) {
Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
return false;
@@ -2330,7 +2326,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
return true;
},
- handleMouseWheel: function(e) {
+ handleMouseWheel: function (e) {
//disable scrolling when not focused
if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
return;
@@ -2347,18 +2343,18 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- startDrag: function() {
+ startDrag: function () {
this.proxy.show();
this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
},
//private
- endDrag: function() {
+ endDrag: function () {
this.proxy.hide();
},
//private
- onDrag: function() {
+ onDrag: function () {
if (this.disabled) {
return;
}
@@ -2379,7 +2375,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinUp: function() {
+ onSpinUp: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -2394,7 +2390,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinDown: function() {
+ onSpinDown: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -2409,7 +2405,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinUpAlternate: function() {
+ onSpinUpAlternate: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -2419,7 +2415,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinDownAlternate: function() {
+ onSpinDownAlternate: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -2428,7 +2424,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.field.fireEvent('spindown', this);
},
- spin: function(down, alternate) {
+ spin: function (down, alternate) {
var v = parseFloat(this.field.getValue());
var incr =
alternate == true
@@ -2441,7 +2437,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.field.setRawValue(v);
},
- fixBoundries: function(value) {
+ fixBoundries: function (value) {
var v = value;
if (this.field.minValue != undefined && v < this.field.minValue) {
@@ -2455,7 +2451,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
// private
- fixPrecision: function(value) {
+ fixPrecision: function (value) {
var nan = isNaN(value);
if (
!this.field.allowDecimals ||
@@ -2470,7 +2466,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
);
},
- doDestroy: function() {
+ doDestroy: function () {
if (this.trigger) {
this.trigger.remove();
}
@@ -2692,7 +2688,7 @@ sb.setStatus({
activeThreadId: 0,
// private
- initComponent: function() {
+ initComponent: function () {
if (this.statusAlign == 'right') {
this.cls += ' x-status-right';
}
@@ -2700,7 +2696,7 @@ sb.setStatus({
},
// private
- afterRender: function() {
+ afterRender: function () {
Ext.ux.StatusBar.superclass.afterRender.call(this);
var right = this.statusAlign == 'right';
@@ -2769,7 +2765,7 @@ statusBar.setStatus({
</code></pre>
* @return {Ext.ux.StatusBar} this
*/
- setStatus: function(o) {
+ setStatus: function (o) {
o = o || {};
if (typeof o == 'string') {
@@ -2816,7 +2812,7 @@ statusBar.setStatus({
* </ul>
* @return {Ext.ux.StatusBar} this
*/
- clearStatus: function(o) {
+ clearStatus: function (o) {
o = o || {};
if (o.threadId && o.threadId !== this.activeThreadId) {
@@ -2839,7 +2835,7 @@ statusBar.setStatus({
remove: false,
useDisplay: true,
scope: this,
- callback: function() {
+ callback: function () {
this.setStatus({
text: text,
iconCls: iconCls,
@@ -2865,7 +2861,7 @@ statusBar.setStatus({
* @param {String} text (optional) The text to set (defaults to '')
* @return {Ext.ux.StatusBar} this
*/
- setText: function(text) {
+ setText: function (text) {
this.activeThreadId++;
this.text = text || '';
if (this.rendered) {
@@ -2878,7 +2874,7 @@ statusBar.setStatus({
* Returns the current status text.
* @return {String} The status text
*/
- getText: function() {
+ getText: function () {
return this.text;
},
@@ -2888,7 +2884,7 @@ statusBar.setStatus({
* @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed)
* @return {Ext.ux.StatusBar} this
*/
- setIcon: function(cls) {
+ setIcon: function (cls) {
this.activeThreadId++;
cls = cls || '';
@@ -2917,7 +2913,7 @@ statusBar.setStatus({
* {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}.
* @return {Ext.ux.StatusBar} this
*/
- showBusy: function(o) {
+ showBusy: function (o) {
if (typeof o == 'string') {
o = { text: o };
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions.js b/deluge/ui/web/js/extjs/ext-extensions.js
new file mode 100644
index 0000000..e6cb62c
--- /dev/null
+++ b/deluge/ui/web/js/extjs/ext-extensions.js
@@ -0,0 +1,84 @@
+Ext.ns("Ext.ux.form");
+Ext.ux.form.FileUploadField=Ext.extend(Ext.form.TextField,{buttonText:"Browse...",buttonOnly:!1,buttonOffset:3,multiple:!1,readOnly:!0,autoSize:Ext.emptyFn,initComponent:function(){Ext.ux.form.FileUploadField.superclass.initComponent.call(this);this.addEvents("fileselected")},onRender:function(a,b){Ext.ux.form.FileUploadField.superclass.onRender.call(this,a,b);this.wrap=this.el.wrap({cls:"x-form-field-wrap x-form-file-wrap"});this.el.addClass("x-form-file-text");this.el.dom.removeAttribute("name");this.createFileInput();
+var c=Ext.applyIf(this.buttonCfg||{},{text:this.buttonText});this.button=new Ext.Button(Ext.apply(c,{renderTo:this.wrap,cls:"x-form-file-btn"+(c.iconCls?" x-btn-icon":"")}));this.buttonOnly&&(this.el.hide(),this.wrap.setWidth(this.button.getEl().getWidth()));this.bindListeners();this.resizeEl=this.positionEl=this.wrap},bindListeners:function(){this.fileInput.on({scope:this,mouseenter:function(){this.button.addClass(["x-btn-over","x-btn-focus"])},mouseleave:function(){this.button.removeClass(["x-btn-over",
+"x-btn-focus","x-btn-click"])},mousedown:function(){this.button.addClass("x-btn-click")},mouseup:function(){this.button.removeClass(["x-btn-over","x-btn-focus","x-btn-click"])},change:function(){var a=this.fileInput.dom.files;a||(a=this.fileInput.dom.value);this.setValue(a);this.fireEvent("fileselected",this,a)}})},createFileInput:function(){this.fileInput=this.wrap.createChild({id:this.getFileInputId(),name:this.name||this.getId(),cls:"x-form-file",tag:"input",type:"file",size:1});this.fileInput.dom.multiple=
+this.multiple},reset:function(){this.rendered&&(this.fileInput.remove(),this.createFileInput(),this.bindListeners());Ext.ux.form.FileUploadField.superclass.reset.call(this)},getFileInputId:function(){return this.id+"-file"},onResize:function(a,b){Ext.ux.form.FileUploadField.superclass.onResize.call(this,a,b);this.wrap.setWidth(a);this.buttonOnly||(a=this.wrap.getWidth()-this.button.getEl().getWidth()-this.buttonOffset,this.el.setWidth(a))},onDestroy:function(){Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
+Ext.destroy(this.fileInput,this.button,this.wrap)},onDisable:function(){Ext.ux.form.FileUploadField.superclass.onDisable.call(this);this.doDisable(!0)},onEnable:function(){Ext.ux.form.FileUploadField.superclass.onEnable.call(this);this.doDisable(!1)},doDisable:function(a){this.fileInput.dom.disabled=a;this.button.setDisabled(a)},preFocus:Ext.emptyFn,alignErrorIcon:function(){this.errorIcon.alignTo(this.wrap,"tl-tr",[2,0])}});Ext.reg("fileuploadfield",Ext.ux.form.FileUploadField);
+Ext.form.FileUploadField=Ext.ux.form.FileUploadField;
+Ext.override(Ext.form.RadioGroup,{afterRender:function(){this.items.each(function(a){this.relayEvents(a,["check"])},this);this.lazyValue&&(this.setValue(this.value),delete this.value,delete this.lazyValue);Ext.form.RadioGroup.superclass.afterRender.call(this)},getName:function(){return this.items.first().getName()},getValue:function(){return this.items.first().getGroupValue()},setValue:function(a){this.items.each?this.items.each(function(b){if(b.rendered){var c=b.el.getValue()==String(a);b.el.dom.checked=
+c;b.el.dom.defaultChecked=c;b.wrap[c?"addClass":"removeClass"](b.checkedCls)}}):(this.value=a,this.lazyValue=!0)}});Ext.ns("Ext.ux.form");
+Ext.ux.form.SpinnerField=Ext.extend(Ext.form.NumberField,{actionMode:"wrap",deferHeight:!0,autoSize:Ext.emptyFn,onBlur:Ext.emptyFn,adjustSize:Ext.BoxComponent.prototype.adjustSize,constructor:function(a){var b=Ext.copyTo({},a,"incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass"),b=this.spinner=new Ext.ux.Spinner(b),b=a.plugins?Ext.isArray(a.plugins)?a.plugins.push(b):[a.plugins,b]:b;Ext.ux.form.SpinnerField.superclass.constructor.call(this,Ext.apply(a,{plugins:b}))},
+getResizeEl:function(){return this.wrap},getPositionEl:function(){return this.wrap},alignErrorIcon:function(){this.wrap&&this.errorIcon.alignTo(this.wrap,"tl-tr",[2,0])},validateBlur:function(){return!0}});Ext.reg("spinnerfield",Ext.ux.form.SpinnerField);Ext.form.SpinnerField=Ext.ux.form.SpinnerField;Ext.override(Ext.ux.form.SpinnerField,{onBlur:Ext.form.Field.prototype.onBlur});Ext.ns("Ext.ux.form");
+Ext.ux.form.SpinnerGroup=Ext.extend(Ext.form.CheckboxGroup,{defaultType:"spinnerfield",anchor:"98%",groupCls:"x-form-spinner-group",colCfg:{},onRender:function(a,b){if(!this.el){var c={cls:this.groupCls,layout:"column",border:!1,renderTo:a},d=Ext.apply({defaultType:this.defaultType,layout:"form",border:!1,labelWidth:60,defaults:{hideLabel:!0,anchor:"60%"}},this.colCfg);if(this.items[0].items){Ext.apply(c,{layoutConfig:{columns:this.items.length},defaults:this.defaults,items:this.items});for(var e=
+0,g=this.items.length;e<g;e++)Ext.applyIf(this.items[e],d)}else{var f,h=[];"string"==typeof this.columns&&(this.columns=this.items.length);if(!Ext.isArray(this.columns)){f=[];for(e=0;e<this.columns;e++)f.push(0.01*(100/this.columns));this.columns=f}f=this.columns.length;for(e=0;e<f;e++)g=Ext.apply({items:[]},d),g[1>=this.columns[e]?"columnWidth":"width"]=this.columns[e],this.defaults&&(g.defaults=Ext.apply(g.defaults||{},this.defaults)),h.push(g);if(this.vertical)for(var d=Math.ceil(this.items.length/
+f),k=0,e=0,g=this.items.length;e<g;e++)0<e&&0==e%d&&k++,this.items[e].fieldLabel&&(this.items[e].hideLabel=!1),h[k].items.push(this.items[e]);else{e=0;for(g=this.items.length;e<g;e++)d=e%f,this.items[e].fieldLabel&&(this.items[e].hideLabel=!1),h[d].items.push(this.items[e])}Ext.apply(c,{layoutConfig:{columns:f},items:h})}this.panel=new Ext.Panel(c);this.el=this.panel.getEl();this.forId&&this.itemCls&&(c=this.el.up(this.itemCls).child("label",!0))&&c.setAttribute("htmlFor",this.forId);c=this.panel.findBy(function(a){return a.isFormField},
+this);this.items=new Ext.util.MixedCollection;this.items.addAll(c);this.items.each(function(a){a.on("spin",this.onFieldChange,this);a.on("change",this.onFieldChange,this)},this);this.lazyValueSet&&(this.setValue(this.value),delete this.value,delete this.lazyValueSet);this.lazyRawValueSet&&(this.setRawValue(this.rawValue),delete this.rawValue,delete this.lazyRawValueSet)}Ext.ux.form.SpinnerGroup.superclass.onRender.call(this,a,b)},onFieldChange:function(a){this.fireEvent("change",this,this.getValue())},
+initValue:Ext.emptyFn,getValue:function(){var a=[this.items.getCount()];this.items.each(function(b,c){a[c]=Number(b.getValue())});return a},getRawValue:function(){var a=[this.items.getCount()];this.items.each(function(b,c){a[c]=Number(b.getRawValue())});return a},setValue:function(a){this.rendered?this.items.each(function(b,c){b.setValue(a[c])}):(this.value=a,this.lazyValueSet=!0)},setRawValue:function(a){this.rendered?this.items.each(function(b,c){b.setRawValue(a[c])}):(this.rawValue=a,this.lazyRawValueSet=
+!0)}});Ext.reg("spinnergroup",Ext.ux.form.SpinnerGroup);Ext.namespace("Ext.ux.form");
+Ext.ux.form.ToggleField=Ext.extend(Ext.form.Field,{cls:"x-toggle-field",initComponent:function(){Ext.ux.form.ToggleField.superclass.initComponent.call(this);this.toggle=new Ext.form.Checkbox;this.toggle.on("check",this.onToggleCheck,this);this.input=new Ext.form.TextField({disabled:!0})},onRender:function(a,b){this.el||(this.panel=new Ext.Panel({cls:this.groupCls,layout:"table",layoutConfig:{columns:2},border:!1,renderTo:a}),this.panel.ownerCt=this,this.el=this.panel.getEl(),this.panel.add(this.toggle),
+this.panel.add(this.input),this.panel.doLayout(),this.toggle.getEl().parent().setStyle("padding-right","10px"));Ext.ux.form.ToggleField.superclass.onRender.call(this,a,b)},onResize:function(a,b){this.panel.setSize(a,b);this.panel.doLayout();var c=a-this.toggle.getSize().width-25;this.input.setSize(c,b)},onToggleCheck:function(a,b){this.input.setDisabled(!b)}});Ext.reg("togglefield",Ext.ux.form.ToggleField);Ext.ns("Ext.ux.grid");
+Ext.ux.grid.BufferView=Ext.extend(Ext.grid.GridView,{rowHeight:19,borderHeight:2,scrollDelay:100,cacheSize:20,cleanDelay:500,initTemplates:function(){Ext.ux.grid.BufferView.superclass.initTemplates.call(this);var a=this.templates;a.rowHolder=new Ext.Template('<div class="x-grid3-row {alt}" style="{tstyle}"></div>');a.rowHolder.disableFormats=!0;a.rowHolder.compile();a.rowBody=new Ext.Template('<table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',"<tbody><tr>{cells}</tr>",
+this.enableRowBody?'<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>':"","</tbody></table>");a.rowBody.disableFormats=!0;a.rowBody.compile()},getStyleRowHeight:function(){return Ext.isBorderBox?this.rowHeight+this.borderHeight:this.rowHeight},getCalculatedRowHeight:function(){return this.rowHeight+this.borderHeight},getVisibleRowCount:function(){var a=this.getCalculatedRowHeight(),
+b=this.scroller.dom.clientHeight;return 1>b?0:Math.ceil(b/a)},getVisibleRows:function(){var a=this.getVisibleRowCount(),b=this.scroller.dom.scrollTop,b=0===b?0:Math.floor(b/this.getCalculatedRowHeight())-1;return{first:Math.max(b,0),last:Math.min(b+a+2,this.ds.getCount()-1)}},doRender:function(a,b,c,d,e,g,f){for(var h=this.templates,k=h.cell,l=h.row,t=h.rowBody,p=e-1,u=this.getStyleRowHeight(),y=this.getVisibleRows(),x=[],n,m={},q={tstyle:"width:"+this.getTotalWidth()+";height:"+u+"px;"},r,w=0,A=
+b.length;w<A;w++){r=b[w];var u=[],v=w+d,z=v>=y.first&&v<=y.last;if(z)for(var s=0;s<e;s++){n=a[s];m.id=n.id;m.css=0===s?"x-grid3-cell-first ":s==p?"x-grid3-cell-last ":"";m.attr=m.cellAttr="";m.value=n.renderer(r.data[n.name],m,r,v,s,c);m.style=n.style;if(void 0===m.value||""===m.value)m.value="&#160;";r.dirty&&"undefined"!==typeof r.modified[n.name]&&(m.css+=" x-grid3-dirty-cell");u[u.length]=k.apply(m)}n=[];g&&0===(v+1)%2&&(n[0]="x-grid3-row-alt");r.dirty&&(n[1]=" x-grid3-dirty-row");q.cols=e;this.getRowClass&&
+(n[2]=this.getRowClass(r,v,q,c));q.alt=n.join(" ");q.cells=u.join("");x[x.length]=!z?h.rowHolder.apply(q):f?t.apply(q):l.apply(q)}return x.join("")},isRowRendered:function(a){return(a=this.getRow(a))&&0<a.childNodes.length},syncScroll:function(){Ext.ux.grid.BufferView.superclass.syncScroll.apply(this,arguments);this.update()},update:function(){this.scrollDelay?(this.renderTask||(this.renderTask=new Ext.util.DelayedTask(this.doUpdate,this)),this.renderTask.delay(this.scrollDelay)):this.doUpdate()},
+onRemove:function(a,b,c,d){Ext.ux.grid.BufferView.superclass.onRemove.apply(this,arguments);!0!==d&&this.update()},doUpdate:function(){if(0<this.getVisibleRowCount()){for(var a=this.grid,b=a.colModel,c=a.store,d=this.getColumnData(),e=this.getVisibleRows(),g,f=e.first;f<=e.last;f++)if(!this.isRowRendered(f)&&(g=this.getRow(f))){var h=this.doRender(d,[c.getAt(f)],c,f,b.getColumnCount(),a.stripeRows,!0);g.innerHTML=h}this.clean()}},clean:function(){this.cleanTask||(this.cleanTask=new Ext.util.DelayedTask(this.doClean,
+this));this.cleanTask.delay(this.cleanDelay)},doClean:function(){if(0<this.getVisibleRowCount()){var a=this.getVisibleRows();a.first-=this.cacheSize;a.last+=this.cacheSize;var b=0,c=this.getRows();0>=a.first&&(b=a.last+1);for(var d=this.ds.getCount();b<d;b++)if((b<a.first||b>a.last)&&c[b].innerHTML)c[b].innerHTML=""}},removeTask:function(a){var b=this[a];b&&b.cancel&&(b.cancel(),this[a]=null)},destroy:function(){this.removeTask("cleanTask");this.removeTask("renderTask");Ext.ux.grid.BufferView.superclass.destroy.call(this)},
+layout:function(){Ext.ux.grid.BufferView.superclass.layout.call(this);this.update()}});
+Ext.override(Ext.layout.FormLayout,{renderItem:function(a,b,c){if(a&&!a.rendered&&(a.isFormField||a.fieldLabel)&&"hidden"!=a.inputType){var d=this.getTemplateArgs(a);"number"==typeof b&&(b=c.dom.childNodes[b]||null);a.formItem=b?this.fieldTpl.insertBefore(b,d,!0):this.fieldTpl.append(c,d,!0);a.actionMode="formItem";a.render("x-form-el-"+a.id);a.container=a.formItem;a.actionMode="container"}else Ext.layout.FormLayout.superclass.renderItem.apply(this,arguments)}});
+Ext.override(Ext.tree.MultiSelectionModel,{onNodeClick:function(a,b){if(b.ctrlKey&&this.isSelected(a))this.unselect(a);else if(b.shiftKey&&!this.isSelected(a)){var c=a.parentNode;if(this.lastSelNode.parentNode.id==c.id){var d=c.indexOf(a),e=c.indexOf(this.lastSelNode);this.select(this.lastSelNode,b,!1,!0);d>e&&(d+=e,e=d-e,d-=e);c.eachChild(function(a){var f=c.indexOf(a);d<f&&f<e&&this.select(a,b,!0,!0)},this);this.select(a,b,!0)}}else this.select(a,b,b.ctrlKey)},select:function(a,b,c,d){!0!==c&&this.clearSelections(!0);
+if(this.isSelected(a))return this.lastSelNode=a;this.selNodes.push(a);this.lastSelNode=this.selMap[a.id]=a;a.ui.onSelectedChange(!0);!0!==d&&this.fireEvent("selectionchange",this,this.selNodes);return a}});Ext.ns("Ext.ux.tree");
+Ext.ux.tree.TreeGrid=Ext.extend(Ext.tree.TreePanel,{rootVisible:!1,useArrows:!0,lines:!1,borderWidth:Ext.isBorderBox?0:2,cls:"x-treegrid",columnResize:!0,enableSort:!0,reserveScrollOffset:!0,enableHdMenu:!0,columnsText:"Columns",initComponent:function(){this.root||(this.root=new Ext.tree.AsyncTreeNode({text:"Root"}));var a=this.loader;a?Ext.isObject(a)&&!a.load&&(a=new Ext.ux.tree.TreeGridLoader(a)):a=new Ext.ux.tree.TreeGridLoader({dataUrl:this.dataUrl,requestMethod:this.requestMethod,store:this.store});
+this.loader=a;Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);this.initColumns();this.enableSort&&(this.treeGridSorter=new Ext.ux.tree.TreeGridSorter(this,this.enableSort));this.columnResize&&(this.colResizer=new Ext.tree.ColumnResizer(this.columnResize),this.colResizer.init(this));this.internalTpl||(this.internalTpl=new Ext.XTemplate('<div class="x-grid3-header">','<div class="x-treegrid-header-inner">','<div class="x-grid3-header-offset">','<table style="table-layout: fixed;" cellspacing="0" cellpadding="0" border="0"><colgroup><tpl for="columns"><col /></tpl></colgroup>',
+'<thead><tr class="x-grid3-hd-row">','<tpl for="columns">','<td class="x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="',this.id,'-xlhd-{#}">','<div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on">',this.enableHdMenu?'<a class="x-grid3-hd-btn" href="#"></a>':"",'{header}<img class="x-grid3-sort-icon" src="',Ext.BLANK_IMAGE_URL,'" />',"</div>","</td></tpl>","</tr></thead>","</table>","</div></div>","</div>",'<div class="x-treegrid-root-node">','<table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"></table>',
+"</div>"));this.colgroupTpl||(this.colgroupTpl=new Ext.XTemplate('<colgroup><tpl for="columns"><col style="width: {width}px"/></tpl></colgroup>'))},initColumns:function(){var a=this.columns,b=a.length,c=[],d,e;for(d=0;d<b;d++)e=a[d],e.isColumn||(e.xtype=e.xtype?/^tg/.test(e.xtype)?e.xtype:"tg"+e.xtype:"tgcolumn",e=Ext.create(e)),e.init(this),c.push(e),!1!==this.enableSort&&!1!==e.sortable&&(this.enableSort=e.sortable=!0);this.columns=c},onRender:function(){Ext.tree.TreePanel.superclass.onRender.apply(this,
+arguments);this.el.addClass("x-treegrid");this.outerCt=this.body.createChild({cls:"x-tree-root-ct x-treegrid-ct "+(this.useArrows?"x-tree-arrows":this.lines?"x-tree-lines":"x-tree-no-lines")});this.internalTpl.overwrite(this.outerCt,{columns:this.columns});this.mainHd=Ext.get(this.outerCt.dom.firstChild);this.innerHd=Ext.get(this.mainHd.dom.firstChild);this.innerBody=Ext.get(this.outerCt.dom.lastChild);this.innerCt=Ext.get(this.innerBody.dom.firstChild);this.colgroupTpl.insertFirst(this.innerCt,{columns:this.columns});
+this.hideHeaders?this.el.child(".x-grid3-header").setDisplayed("none"):!1!==this.enableHdMenu&&(this.hmenu=new Ext.menu.Menu({id:this.id+"-hctx"}),!1!==this.enableColumnHide&&(this.colMenu=new Ext.menu.Menu({id:this.id+"-hcols-menu"}),this.colMenu.on({scope:this,beforeshow:this.beforeColMenuShow,itemclick:this.handleHdMenuClick}),this.hmenu.add({itemId:"columns",hideOnClick:!1,text:this.columnsText,menu:this.colMenu,iconCls:"x-cols-icon"})),this.hmenu.on("itemclick",this.handleHdMenuClick,this))},
+setRootNode:function(a){a.attributes.uiProvider=Ext.ux.tree.TreeGridRootNodeUI;a=Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this,a);this.innerCt&&this.colgroupTpl.insertFirst(this.innerCt,{columns:this.columns});return a},clearInnerCt:function(){if(Ext.isIE)for(var a=this.innerCt.dom;a.firstChild;)a.removeChild(a.firstChild);else Ext.ux.tree.TreeGrid.superclass.clearInnerCt.call(this)},initEvents:function(){Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this,arguments);this.mon(this.innerBody,
+"scroll",this.syncScroll,this);this.mon(this.innerHd,"click",this.handleHdDown,this);this.mon(this.mainHd,{scope:this,mouseover:this.handleHdOver,mouseout:this.handleHdOut})},onResize:function(a,b){Ext.ux.tree.TreeGrid.superclass.onResize.apply(this,arguments);var c=this.innerBody.dom,d=this.innerHd.dom;if(c&&(Ext.isNumber(b)&&(c.style.height=this.body.getHeight(!0)-d.offsetHeight+"px"),Ext.isNumber(a))){var e=Ext.num(this.scrollOffset,Ext.getScrollBarWidth());if(this.reserveScrollOffset||10<c.offsetWidth-
+c.clientWidth)this.setScrollOffset(e);else{var g=this;setTimeout(function(){g.setScrollOffset(10<c.offsetWidth-c.clientWidth?e:0)},10)}}},updateColumnWidths:function(){var a=this.columns,b=a.length,c=this.outerCt.query("colgroup"),d=c.length,e,g,f,h;for(f=0;f<b;f++){e=a[f];for(h=0;h<d;h++)g=c[h],g.childNodes[f].style.width=(e.hidden?0:e.width)+"px"}f=0;c=this.innerHd.query("td");for(len=c.length;f<len;f++)e=Ext.fly(c[f]),a[f]&&a[f].hidden?e.addClass("x-treegrid-hd-hidden"):e.removeClass("x-treegrid-hd-hidden");
+a=this.getTotalColumnWidth();Ext.fly(this.innerHd.dom.firstChild).setWidth(a+(this.scrollOffset||0));this.outerCt.select("table").setWidth(a);this.syncHeaderScroll()},getVisibleColumns:function(){var a=[],b=this.columns,c=b.length,d;for(d=0;d<c;d++)b[d].hidden||a.push(b[d]);return a},getTotalColumnWidth:function(){for(var a=0,b=0,c=this.getVisibleColumns(),d=c.length;b<d;b++)a+=c[b].width;return a},setScrollOffset:function(a){this.scrollOffset=a;this.updateColumnWidths()},handleHdDown:function(a,
+b){var c=a.getTarget(".x-treegrid-hd");if(c&&Ext.fly(b).hasClass("x-grid3-hd-btn")){var d=this.hmenu.items,e=this.columns,g=this.findHeaderIndex(c),e=e[g];a.stopEvent();Ext.fly(c).addClass("x-grid3-hd-menu-open");this.hdCtxIndex=g;this.fireEvent("headerbuttonclick",d,e,c,g);this.hmenu.on("hide",function(){Ext.fly(c).removeClass("x-grid3-hd-menu-open")},this,{single:!0});this.hmenu.show(b,"tl-bl?")}else c&&(g=this.findHeaderIndex(c),this.fireEvent("headerclick",this.columns[g],c,g))},handleHdOver:function(a,
+b){var c=a.getTarget(".x-treegrid-hd");if(c&&!this.headersDisabled){index=this.findHeaderIndex(c);this.activeHdRef=b;this.activeHdIndex=index;var d=Ext.get(c);this.activeHdRegion=d.getRegion();d.addClass("x-grid3-hd-over");if(this.activeHdBtn=d.child(".x-grid3-hd-btn"))this.activeHdBtn.dom.style.height=c.firstChild.offsetHeight-1+"px"}},handleHdOut:function(a,b){var c=a.getTarget(".x-treegrid-hd");if(c&&(!Ext.isIE||!a.within(c,!0)))this.activeHdRef=null,Ext.fly(c).removeClass("x-grid3-hd-over"),c.style.cursor=
+""},findHeaderIndex:function(a){a=a.dom||a;for(var b=a.parentNode.childNodes,c=0,d;d=b[c];c++)if(d==a)return c;return-1},beforeColMenuShow:function(){var a=this.columns,b=a.length,c,d;this.colMenu.removeAll();for(c=1;c<b;c++)d=a[c],!1!==d.hideable&&this.colMenu.add(new Ext.menu.CheckItem({itemId:"col-"+c,text:d.header,checked:!d.hidden,hideOnClick:!1,disabled:!1===d.hideable}))},handleHdMenuClick:function(a){var b=this.hdCtxIndex,c=a.getItemId();!1!==this.fireEvent("headermenuclick",this.columns[b],
+c,b)&&(b=c.substr(4),0<b&&this.columns[b]&&this.setColumnVisible(b,!a.checked));return!0},setColumnVisible:function(a,b){this.columns[a].hidden=!b;this.updateColumnWidths()},scrollToTop:function(){this.innerBody.dom.scrollTop=0;this.innerBody.dom.scrollLeft=0},syncScroll:function(){this.syncHeaderScroll();var a=this.innerBody.dom;this.fireEvent("bodyscroll",a.scrollLeft,a.scrollTop)},syncHeaderScroll:function(){var a=this.innerBody.dom;this.innerHd.dom.scrollLeft=a.scrollLeft;this.innerHd.dom.scrollLeft=
+a.scrollLeft},registerNode:function(a){Ext.ux.tree.TreeGrid.superclass.registerNode.call(this,a);!a.uiProvider&&(!a.isRoot&&!a.ui.isTreeGridNodeUI)&&(a.ui=new Ext.ux.tree.TreeGridNodeUI(a))}});Ext.reg("treegrid",Ext.ux.tree.TreeGrid);
+Ext.tree.ColumnResizer=Ext.extend(Ext.util.Observable,{minWidth:14,constructor:function(a){Ext.apply(this,a);Ext.tree.ColumnResizer.superclass.constructor.call(this)},init:function(a){this.tree=a;a.on("render",this.initEvents,this)},initEvents:function(a){a.mon(a.innerHd,"mousemove",this.handleHdMove,this);this.tracker=new Ext.dd.DragTracker({onBeforeStart:this.onBeforeStart.createDelegate(this),onStart:this.onStart.createDelegate(this),onDrag:this.onDrag.createDelegate(this),onEnd:this.onEnd.createDelegate(this),
+tolerance:3,autoStart:300});this.tracker.initEl(a.innerHd);a.on("beforedestroy",this.tracker.destroy,this.tracker)},handleHdMove:function(a,b){var c=a.getPageX(),d=a.getTarget(".x-treegrid-hd",3,!0);if(d){var e=d.getRegion(),g=d.dom.style,f=d.dom.parentNode;if(5>=c-e.left&&d.dom!==f.firstChild){for(c=d.dom.previousSibling;c&&Ext.fly(c).hasClass("x-treegrid-hd-hidden");)c=c.previousSibling;c&&(this.activeHd=Ext.get(c),g.cursor=Ext.isWebKit?"e-resize":"col-resize")}else if(5>=e.right-c){for(c=d.dom;c&&
+Ext.fly(c).hasClass("x-treegrid-hd-hidden");)c=c.previousSibling;c&&(this.activeHd=Ext.get(c),g.cursor=Ext.isWebKit?"w-resize":"col-resize")}else delete this.activeHd,g.cursor=""}},onBeforeStart:function(a){this.dragHd=this.activeHd;return!!this.dragHd},onStart:function(a){this.dragHeadersDisabled=this.tree.headersDisabled;this.tree.headersDisabled=!0;this.proxy=this.tree.body.createChild({cls:"x-treegrid-resizer"});this.proxy.setHeight(this.tree.body.getHeight());a=this.tracker.getXY()[0];this.hdX=
+this.dragHd.getX();this.hdIndex=this.tree.findHeaderIndex(this.dragHd);this.proxy.setX(this.hdX);this.proxy.setWidth(a-this.hdX);this.maxWidth=this.tree.outerCt.getWidth()-this.tree.innerBody.translatePoints(this.hdX).left},onDrag:function(a){a=this.tracker.getXY()[0];this.proxy.setWidth((a-this.hdX).constrain(this.minWidth,this.maxWidth))},onEnd:function(a){a=this.proxy.getWidth();var b=this.tree,c=this.dragHeadersDisabled;this.proxy.remove();delete this.dragHd;b.columns[this.hdIndex].width=a;b.updateColumnWidths();
+setTimeout(function(){b.headersDisabled=c},100)}});
+(function(){Ext.override(Ext.list.Column,{init:function(){var a=Ext.data.Types,b=this.sortType;this.type?Ext.isString(this.type)&&(this.type=Ext.data.Types[this.type.toUpperCase()]||a.AUTO):this.type=a.AUTO;Ext.isString(b)?this.sortType=Ext.data.SortTypes[b]:Ext.isEmpty(b)&&(this.sortType=this.type.sortType)}});Ext.tree.Column=Ext.extend(Ext.list.Column,{});Ext.tree.NumberColumn=Ext.extend(Ext.list.NumberColumn,{});Ext.tree.DateColumn=Ext.extend(Ext.list.DateColumn,{});Ext.tree.BooleanColumn=Ext.extend(Ext.list.BooleanColumn,
+{});Ext.reg("tgcolumn",Ext.tree.Column);Ext.reg("tgnumbercolumn",Ext.tree.NumberColumn);Ext.reg("tgdatecolumn",Ext.tree.DateColumn);Ext.reg("tgbooleancolumn",Ext.tree.BooleanColumn)})();Ext.ux.tree.TreeGridLoader=Ext.extend(Ext.tree.TreeLoader,{createNode:function(a){a.uiProvider||(a.uiProvider=Ext.ux.tree.TreeGridNodeUI);return Ext.tree.TreeLoader.prototype.createNode.call(this,a)}});
+Ext.ux.tree.TreeGridNodeUI=Ext.extend(Ext.tree.TreeNodeUI,{isTreeGridNodeUI:!0,renderElements:function(a,b,c,d){var e=a.getOwnerTree(),g=e.columns,f=g[0],h,k,l;this.indentMarkup=a.parentNode?a.parentNode.ui.getChildIndent():"";k=['<tbody class="x-tree-node">','<tr ext:tree-node-id="',a.id,'" class="x-tree-node-el x-tree-node-leaf ',b.cls,'">','<td class="x-treegrid-col">','<span class="x-tree-node-indent">',this.indentMarkup,"</span>",'<img src="',this.emptyIcon,'" class="x-tree-ec-icon x-tree-elbow" />',
+'<img src="',b.icon||this.emptyIcon,'" class="x-tree-node-icon',b.icon?" x-tree-node-inline-icon":"",b.iconCls?" "+b.iconCls:"",'" unselectable="on" />','<a hidefocus="on" class="x-tree-node-anchor" href="',b.href?b.href:"#",'" tabIndex="1" ',b.hrefTarget?' target="'+b.hrefTarget+'"':"",">",'<span unselectable="on">',f.tpl?f.tpl.apply(b):b[f.dataIndex]||f.text,"</span></a>","</td>"];h=1;for(l=g.length;h<l;h++)f=g[h],k.push('<td class="x-treegrid-col ',f.cls?f.cls:"",'">','<div unselectable="on" class="x-treegrid-text"',
+f.align?' style="text-align: '+f.align+';"':"",">",f.tpl?f.tpl.apply(b):b[f.dataIndex],"</div>","</td>");k.push('</tr><tr class="x-tree-node-ct"><td colspan="',g.length,'">','<table class="x-treegrid-node-ct-table" cellpadding="0" cellspacing="0" style="table-layout: fixed; display: none; width: ',e.innerCt.getWidth(),'px;"><colgroup>');h=0;for(l=g.length;h<l;h++)k.push('<col style="width: ',g[h].hidden?0:g[h].width,'px;" />');k.push("</colgroup></table></td></tr></tbody>");!0!==d&&a.nextSibling&&
+a.nextSibling.ui.getEl()?this.wrap=Ext.DomHelper.insertHtml("beforeBegin",a.nextSibling.ui.getEl(),k.join("")):this.wrap=Ext.DomHelper.insertHtml("beforeEnd",c,k.join(""));this.elNode=this.wrap.childNodes[0];this.ctNode=this.wrap.childNodes[1].firstChild.firstChild;a=this.elNode.firstChild.childNodes;this.indentNode=a[0];this.ecNode=a[1];this.iconNode=a[2];this.anchor=a[3];this.textNode=a[3].firstChild},animExpand:function(a){this.ctNode.style.display="";Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this,
+a)}});Ext.ux.tree.TreeGridRootNodeUI=Ext.extend(Ext.tree.TreeNodeUI,{isTreeGridNodeUI:!0,render:function(){this.rendered||(this.wrap=this.ctNode=this.node.ownerTree.innerCt.dom,this.node.expanded=!0);if(Ext.isWebKit){var a=this.ctNode;a.style.tableLayout=null;(function(){a.style.tableLayout="fixed"}).defer(1)}},destroy:function(){this.elNode&&Ext.dd.Registry.unregister(this.elNode.id);delete this.node},collapse:Ext.emptyFn,expand:Ext.emptyFn});
+Ext.override(Ext.ux.tree.TreeGridNodeUI,{updateColumns:function(){if(this.rendered){var a=this.node.attributes,b=this.node.getOwnerTree().columns,c=b[0];this.anchor.firstChild.innerHTML=c.tpl?c.tpl.apply(a):a[c.dataIndex]||c.text;i=1;for(len=b.length;i<len;i++)c=b[i],this.elNode.childNodes[i].firstChild.innerHTML=c.tpl?c.tpl.apply(a):a[c.dataIndex]||c.text}}});
+Ext.tree.RenderColumn=Ext.extend(Ext.tree.Column,{constructor:function(a){a.tpl=a.tpl||new Ext.XTemplate("{"+a.dataIndex+":this.format}");a.tpl.format=a.renderer;a.tpl.col=this;Ext.tree.RenderColumn.superclass.constructor.call(this,a)}});Ext.reg("tgrendercolumn",Ext.tree.RenderColumn);Ext.ns("Ext.ux.tree");
+Ext.ux.tree.TreeGridSorter=Ext.extend(Ext.tree.TreeSorter,{sortClasses:["sort-asc","sort-desc"],sortAscText:"Sort Ascending",sortDescText:"Sort Descending",constructor:function(a,b){Ext.isObject(b)||(b={property:a.columns[0].dataIndex||"text",folderSort:!0});Ext.ux.tree.TreeGridSorter.superclass.constructor.apply(this,arguments);this.tree=a;a.on("headerclick",this.onHeaderClick,this);a.ddAppendOnly=!0;var c=this;this.defaultSortFn=function(a,b){var g=c.dir&&"desc"==c.dir.toLowerCase(),f=c.property||
+"text",h=c.sortType,k=!0===c.caseSensitive,l=c.leafAttr||"leaf",t=a.attributes,p=b.attributes;if(c.folderSort){if(t[l]&&!p[l])return 1;if(!t[l]&&p[l])return-1}l=t[f];f=p[f];p=h?h(l):k?l:l.toUpperCase();v2=h?h(f):k?f:f.toUpperCase();return p<v2?g?1:-1:p>v2?g?-1:1:0};a.on("afterrender",this.onAfterTreeRender,this,{single:!0});a.on("headermenuclick",this.onHeaderMenuClick,this)},onAfterTreeRender:function(){this.tree.hmenu&&this.tree.hmenu.insert(0,{itemId:"asc",text:this.sortAscText,cls:"xg-hmenu-sort-asc"},
+{itemId:"desc",text:this.sortDescText,cls:"xg-hmenu-sort-desc"});this.updateSortIcon(0,"asc")},onHeaderMenuClick:function(a,b,c){if("asc"===b||"desc"===b)return this.onHeaderClick(a,null,c),!1},onHeaderClick:function(a,b,c){if(a&&!this.tree.headersDisabled){var d=this;d.property=a.dataIndex;d.dir=a.dir="desc"===a.dir?"asc":"desc";d.sortType=a.sortType;d.caseSensitive===Ext.isBoolean(a.caseSensitive)?a.caseSensitive:this.caseSensitive;d.sortFn=a.sortFn||this.defaultSortFn;this.tree.root.cascade(function(a){a.isLeaf()||
+d.updateSort(d.tree,a)});this.updateSortIcon(c,a.dir)}},updateSortIcon:function(a,b){var c=this.sortClasses;this.tree.innerHd.select("td").removeClass(c).item(a).addClass(c["desc"==b?1:0])}});
+Ext.ux.JSLoader=function(a){Ext.ux.JSLoader.scripts[++Ext.ux.JSLoader.index]={url:a.url,success:!0,jsLoadObj:null,options:a,onLoad:a.onLoad||Ext.emptyFn,onError:a.onError||Ext.ux.JSLoader.stdError,scope:a.scope||this};Ext.Ajax.request({url:a.url,scriptIndex:Ext.ux.JSLoader.index,success:function(a,c){var d=Ext.ux.JSLoader.scripts[c.scriptIndex];try{eval(a.responseText)}catch(e){d.success=!1,d.onError(d.options,e)}d.success&&d.onLoad.call(d.scope,d.options)},failure:function(a,c){var d=Ext.ux.JSLoader.scripts[c.scriptIndex];
+d.success=!1;d.onError(d.options,a.status)}})};Ext.ux.JSLoader.index=0;Ext.ux.JSLoader.scripts=[];Ext.ux.JSLoader.stdError=function(a,b){window.alert("Error loading script:\n\n"+a.url+"\n\nstatus: "+b)};
+Ext.ux.Spinner=Ext.extend(Ext.util.Observable,{incrementValue:1,alternateIncrementValue:5,triggerClass:"x-form-spinner-trigger",splitterClass:"x-form-spinner-splitter",alternateKey:Ext.EventObject.shiftKey,defaultValue:0,accelerate:!1,constructor:function(a){Ext.ux.Spinner.superclass.constructor.call(this,a);Ext.apply(this,a);this.mimicing=!1},init:function(a){this.field=a;a.afterMethod("onRender",this.doRender,this);a.afterMethod("onEnable",this.doEnable,this);a.afterMethod("onDisable",this.doDisable,
+this);a.afterMethod("afterRender",this.doAfterRender,this);a.afterMethod("onResize",this.doResize,this);a.afterMethod("onFocus",this.doFocus,this);a.beforeMethod("onDestroy",this.doDestroy,this)},doRender:function(a,b){var c=this.el=this.field.getEl(),d=this.field;d.wrap?this.wrap=d.wrap.addClass("x-form-field-wrap"):d.wrap=this.wrap=c.wrap({cls:"x-form-field-wrap"});this.trigger=this.wrap.createChild({tag:"img",src:Ext.BLANK_IMAGE_URL,cls:"x-form-trigger "+this.triggerClass});d.width||this.wrap.setWidth(c.getWidth()+
+this.trigger.getWidth());this.splitter=this.wrap.createChild({tag:"div",cls:this.splitterClass,style:"width:13px; height:2px;"});this.splitter.setRight(Ext.isIE?1:2).setTop(10).show();this.proxy=this.trigger.createProxy("",this.splitter,!0);this.proxy.addClass("x-form-spinner-proxy");this.proxy.setStyle("left","0px");this.proxy.setSize(14,1);this.proxy.hide();this.dd=new Ext.dd.DDProxy(this.splitter.dom.id,"SpinnerDrag",{dragElId:this.proxy.id});this.initTrigger();this.initSpinner()},doAfterRender:function(){var a;
+if(Ext.isIE&&this.el.getY()!=(a=this.trigger.getY()))this.el.position(),this.el.setY(a)},doEnable:function(){this.wrap&&(this.disabled=!1,this.wrap.removeClass(this.field.disabledClass))},doDisable:function(){this.wrap&&(this.disabled=!0,this.wrap.addClass(this.field.disabledClass),this.el.removeClass(this.field.disabledClass))},doResize:function(a,b){"number"==typeof a&&this.el.setWidth(a-this.trigger.getWidth());this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth())},doFocus:function(){this.mimicing||
+(this.wrap.addClass("x-trigger-wrap-focus"),this.mimicing=!0,Ext.get(Ext.isIE?document.body:document).on("mousedown",this.mimicBlur,this,{delay:10}),this.el.on("keydown",this.checkTab,this))},checkTab:function(a){a.getKey()==a.TAB&&this.triggerBlur()},mimicBlur:function(a){!this.wrap.contains(a.target)&&this.field.validateBlur(a)&&this.triggerBlur()},triggerBlur:function(){this.mimicing=!1;Ext.get(Ext.isIE?document.body:document).un("mousedown",this.mimicBlur,this);this.el.un("keydown",this.checkTab,
+this);this.field.beforeBlur();this.wrap.removeClass("x-trigger-wrap-focus");this.field.onBlur.call(this.field)},initTrigger:function(){this.trigger.addClassOnOver("x-form-trigger-over");this.trigger.addClassOnClick("x-form-trigger-click")},initSpinner:function(){this.field.addEvents({spin:!0,spinup:!0,spindown:!0});this.keyNav=new Ext.KeyNav(this.el,{up:function(a){a.preventDefault();this.onSpinUp()},down:function(a){a.preventDefault();this.onSpinDown()},pageUp:function(a){a.preventDefault();this.onSpinUpAlternate()},
+pageDown:function(a){a.preventDefault();this.onSpinDownAlternate()},scope:this});this.repeater=new Ext.util.ClickRepeater(this.trigger,{accelerate:this.accelerate});this.field.mon(this.repeater,"click",this.onTriggerClick,this,{preventDefault:!0});this.field.mon(this.trigger,{mouseover:this.onMouseOver,mouseout:this.onMouseOut,mousemove:this.onMouseMove,mousedown:this.onMouseDown,mouseup:this.onMouseUp,scope:this,preventDefault:!0});this.field.mon(this.wrap,"mousewheel",this.handleMouseWheel,this);
+this.dd.setXConstraint(0,0,10);this.dd.setYConstraint(1500,1500,10);this.dd.endDrag=this.endDrag.createDelegate(this);this.dd.startDrag=this.startDrag.createDelegate(this);this.dd.onDrag=this.onDrag.createDelegate(this)},onMouseOver:function(){if(!this.disabled){var a=this.getMiddle();this.tmpHoverClass=Ext.EventObject.getPageY()<a?"x-form-spinner-overup":"x-form-spinner-overdown";this.trigger.addClass(this.tmpHoverClass)}},onMouseOut:function(){this.trigger.removeClass(this.tmpHoverClass)},onMouseMove:function(){if(!this.disabled){var a=
+this.getMiddle();Ext.EventObject.getPageY()>a&&"x-form-spinner-overup"==this.tmpHoverClass||Ext.EventObject.getPageY()}},onMouseDown:function(){if(!this.disabled){var a=this.getMiddle();this.tmpClickClass=Ext.EventObject.getPageY()<a?"x-form-spinner-clickup":"x-form-spinner-clickdown";this.trigger.addClass(this.tmpClickClass)}},onMouseUp:function(){this.trigger.removeClass(this.tmpClickClass)},onTriggerClick:function(){if(!this.disabled&&!this.el.dom.readOnly){var a=this.getMiddle();this["onSpin"+
+(Ext.EventObject.getPageY()<a?"Up":"Down")]()}},getMiddle:function(){var a=this.trigger.getTop(),b=this.trigger.getHeight();return a+b/2},isSpinnable:function(){return this.disabled||this.el.dom.readOnly?(Ext.EventObject.preventDefault(),!1):!0},handleMouseWheel:function(a){if(!1!=this.wrap.hasClass("x-trigger-wrap-focus")){var b=a.getWheelDelta();0<b?(this.onSpinUp(),a.stopEvent()):0>b&&(this.onSpinDown(),a.stopEvent())}},startDrag:function(){this.proxy.show();this._previousY=Ext.fly(this.dd.getDragEl()).getTop()},
+endDrag:function(){this.proxy.hide()},onDrag:function(){if(!this.disabled){var a=Ext.fly(this.dd.getDragEl()).getTop(),b="";this._previousY>a&&(b="Up");this._previousY<a&&(b="Down");if(""!=b)this["onSpin"+b]();this._previousY=a}},onSpinUp:function(){if(!1!=this.isSpinnable())if(!0==Ext.EventObject.shiftKey)this.onSpinUpAlternate();else this.spin(!1,!1),this.field.fireEvent("spin",this),this.field.fireEvent("spinup",this)},onSpinDown:function(){if(!1!=this.isSpinnable())if(!0==Ext.EventObject.shiftKey)this.onSpinDownAlternate();
+else this.spin(!0,!1),this.field.fireEvent("spin",this),this.field.fireEvent("spindown",this)},onSpinUpAlternate:function(){!1!=this.isSpinnable()&&(this.spin(!1,!0),this.field.fireEvent("spin",this),this.field.fireEvent("spinup",this))},onSpinDownAlternate:function(){!1!=this.isSpinnable()&&(this.spin(!0,!0),this.field.fireEvent("spin",this),this.field.fireEvent("spindown",this))},spin:function(a,b){var c=parseFloat(this.field.getValue()),d=!0==b?this.alternateIncrementValue:this.incrementValue;
+!0==a?c-=d:c+=d;c=isNaN(c)?this.defaultValue:c;c=this.fixBoundries(c);this.field.setRawValue(c)},fixBoundries:function(a){void 0!=this.field.minValue&&a<this.field.minValue&&(a=this.field.minValue);void 0!=this.field.maxValue&&a>this.field.maxValue&&(a=this.field.maxValue);return this.fixPrecision(a)},fixPrecision:function(a){var b=isNaN(a);return!this.field.allowDecimals||-1==this.field.decimalPrecision||b||!a?b?"":a:parseFloat(parseFloat(a).toFixed(this.field.decimalPrecision))},doDestroy:function(){this.trigger&&
+this.trigger.remove();this.wrap&&(this.wrap.remove(),delete this.field.wrap);this.splitter&&this.splitter.remove();this.dd&&(this.dd.unreg(),this.dd=null);this.proxy&&this.proxy.remove();this.repeater&&this.repeater.purgeListeners();this.mimicing&&Ext.get(Ext.isIE?document.body:document).un("mousedown",this.mimicBlur,this)}});Ext.form.Spinner=Ext.ux.Spinner;
+Ext.ux.StatusBar=Ext.extend(Ext.Toolbar,{cls:"x-statusbar",busyIconCls:"x-status-busy",busyText:"Loading...",autoClear:5E3,emptyText:"&nbsp;",activeThreadId:0,initComponent:function(){"right"==this.statusAlign&&(this.cls+=" x-status-right");Ext.ux.StatusBar.superclass.initComponent.call(this)},afterRender:function(){Ext.ux.StatusBar.superclass.afterRender.call(this);var a="right"==this.statusAlign;this.currIconCls=this.iconCls||this.defaultIconCls;this.statusEl=new Ext.Toolbar.TextItem({cls:"x-status-text "+
+(this.currIconCls||""),text:this.text||this.defaultText||""});a?(this.add("->"),this.add(this.statusEl)):(this.insert(0,this.statusEl),this.insert(1,"->"));this.doLayout()},setStatus:function(a){a=a||{};"string"==typeof a&&(a={text:a});void 0!==a.text&&this.setText(a.text);void 0!==a.iconCls&&this.setIcon(a.iconCls);if(a.clear){a=a.clear;var b=this.autoClear,c={useDefaults:!0,anim:!0};"object"==typeof a?(a=Ext.applyIf(a,c),a.wait&&(b=a.wait)):"number"==typeof a?(b=a,a=c):"boolean"==typeof a&&(a=c);
+a.threadId=this.activeThreadId;this.clearStatus.defer(b,this,[a])}return this},clearStatus:function(a){a=a||{};if(a.threadId&&a.threadId!==this.activeThreadId)return this;var b=a.useDefaults?this.defaultText:this.emptyText,c=a.useDefaults?this.defaultIconCls?this.defaultIconCls:"":"";a.anim?this.statusEl.el.fadeOut({remove:!1,useDisplay:!0,scope:this,callback:function(){this.setStatus({text:b,iconCls:c});this.statusEl.el.show()}}):(this.statusEl.hide(),this.setStatus({text:b,iconCls:c}),this.statusEl.show());
+return this},setText:function(a){this.activeThreadId++;this.text=a||"";this.rendered&&this.statusEl.setText(this.text);return this},getText:function(){return this.text},setIcon:function(a){this.activeThreadId++;a=a||"";this.rendered?(this.currIconCls&&(this.statusEl.removeClass(this.currIconCls),this.currIconCls=null),0<a.length&&(this.statusEl.addClass(a),this.currIconCls=a)):this.currIconCls=a;return this},showBusy:function(a){"string"==typeof a&&(a={text:a});a=Ext.applyIf(a||{},{text:this.busyText,
+iconCls:this.busyIconCls});return this.setStatus(a)}});Ext.reg("statusbar",Ext.ux.StatusBar);
diff --git a/deluge/ui/web/js/extjs/ext-extensions/JSLoader.js b/deluge/ui/web/js/extjs/ext-extensions/JSLoader.js
index 9631fd8..e4691b0 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/JSLoader.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/JSLoader.js
@@ -1,4 +1,4 @@
-Ext.ux.JSLoader = function(options) {
+Ext.ux.JSLoader = function (options) {
Ext.ux.JSLoader.scripts[++Ext.ux.JSLoader.index] = {
url: options.url,
success: true,
@@ -12,7 +12,7 @@ Ext.ux.JSLoader = function(options) {
Ext.Ajax.request({
url: options.url,
scriptIndex: Ext.ux.JSLoader.index,
- success: function(response, options) {
+ success: function (response, options) {
var script = Ext.ux.JSLoader.scripts[options.scriptIndex];
try {
eval(response.responseText);
@@ -24,7 +24,7 @@ Ext.ux.JSLoader = function(options) {
script.onLoad.call(script.scope, script.options);
}
},
- failure: function(response, options) {
+ failure: function (response, options) {
var script = Ext.ux.JSLoader.scripts[options.scriptIndex];
script.success = false;
script.onError(script.options, response.status);
@@ -33,7 +33,7 @@ Ext.ux.JSLoader = function(options) {
};
Ext.ux.JSLoader.index = 0;
Ext.ux.JSLoader.scripts = [];
-Ext.ux.JSLoader.stdError = function(options, e) {
+Ext.ux.JSLoader.stdError = function (options, e) {
window.alert(
'Error loading script:\n\n' + options.url + '\n\nstatus: ' + e
);
diff --git a/deluge/ui/web/js/extjs/ext-extensions/Spinner.js b/deluge/ui/web/js/extjs/ext-extensions/Spinner.js
index ff272d2..ccef895 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/Spinner.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/Spinner.js
@@ -18,13 +18,13 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
defaultValue: 0,
accelerate: false,
- constructor: function(config) {
+ constructor: function (config) {
Ext.ux.Spinner.superclass.constructor.call(this, config);
Ext.apply(this, config);
this.mimicing = false;
},
- init: function(field) {
+ init: function (field) {
this.field = field;
field.afterMethod('onRender', this.doRender, this);
@@ -36,7 +36,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
field.beforeMethod('onDestroy', this.doDestroy, this);
},
- doRender: function(ct, position) {
+ doRender: function (ct, position) {
var el = (this.el = this.field.getEl());
var f = this.field;
@@ -81,7 +81,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.initSpinner();
},
- doAfterRender: function() {
+ doAfterRender: function () {
var y;
if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
this.el.position();
@@ -89,14 +89,14 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
}
},
- doEnable: function() {
+ doEnable: function () {
if (this.wrap) {
this.disabled = false;
this.wrap.removeClass(this.field.disabledClass);
}
},
- doDisable: function() {
+ doDisable: function () {
if (this.wrap) {
this.disabled = true;
this.wrap.addClass(this.field.disabledClass);
@@ -104,14 +104,14 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
}
},
- doResize: function(w, h) {
+ doResize: function (w, h) {
if (typeof w == 'number') {
this.el.setWidth(w - this.trigger.getWidth());
}
this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
},
- doFocus: function() {
+ doFocus: function () {
if (!this.mimicing) {
this.wrap.addClass('x-trigger-wrap-focus');
this.mimicing = true;
@@ -128,21 +128,21 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
// private
- checkTab: function(e) {
+ checkTab: function (e) {
if (e.getKey() == e.TAB) {
this.triggerBlur();
}
},
// private
- mimicBlur: function(e) {
+ mimicBlur: function (e) {
if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
this.triggerBlur();
}
},
// private
- triggerBlur: function() {
+ triggerBlur: function () {
this.mimicing = false;
Ext.get(Ext.isIE ? document.body : document).un(
'mousedown',
@@ -155,12 +155,12 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.field.onBlur.call(this.field);
},
- initTrigger: function() {
+ initTrigger: function () {
this.trigger.addClassOnOver('x-form-trigger-over');
this.trigger.addClassOnClick('x-form-trigger-click');
},
- initSpinner: function() {
+ initSpinner: function () {
this.field.addEvents({
spin: true,
spinup: true,
@@ -168,22 +168,22 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
});
this.keyNav = new Ext.KeyNav(this.el, {
- up: function(e) {
+ up: function (e) {
e.preventDefault();
this.onSpinUp();
},
- down: function(e) {
+ down: function (e) {
e.preventDefault();
this.onSpinDown();
},
- pageUp: function(e) {
+ pageUp: function (e) {
e.preventDefault();
this.onSpinUpAlternate();
},
- pageDown: function(e) {
+ pageDown: function (e) {
e.preventDefault();
this.onSpinDownAlternate();
},
@@ -217,7 +217,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.dd.onDrag = this.onDrag.createDelegate(this);
},
- onMouseOver: function() {
+ onMouseOver: function () {
if (this.disabled) {
return;
}
@@ -230,12 +230,12 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onMouseOut: function() {
+ onMouseOut: function () {
this.trigger.removeClass(this.tmpHoverClass);
},
//private
- onMouseMove: function() {
+ onMouseMove: function () {
if (this.disabled) {
return;
}
@@ -250,7 +250,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onMouseDown: function() {
+ onMouseDown: function () {
if (this.disabled) {
return;
}
@@ -263,12 +263,12 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onMouseUp: function() {
+ onMouseUp: function () {
this.trigger.removeClass(this.tmpClickClass);
},
//private
- onTriggerClick: function() {
+ onTriggerClick: function () {
if (this.disabled || this.el.dom.readOnly) {
return;
}
@@ -278,7 +278,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- getMiddle: function() {
+ getMiddle: function () {
var t = this.trigger.getTop();
var h = this.trigger.getHeight();
var middle = t + h / 2;
@@ -287,7 +287,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
//private
//checks if control is allowed to spin
- isSpinnable: function() {
+ isSpinnable: function () {
if (this.disabled || this.el.dom.readOnly) {
Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
return false;
@@ -295,7 +295,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
return true;
},
- handleMouseWheel: function(e) {
+ handleMouseWheel: function (e) {
//disable scrolling when not focused
if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
return;
@@ -312,18 +312,18 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- startDrag: function() {
+ startDrag: function () {
this.proxy.show();
this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
},
//private
- endDrag: function() {
+ endDrag: function () {
this.proxy.hide();
},
//private
- onDrag: function() {
+ onDrag: function () {
if (this.disabled) {
return;
}
@@ -344,7 +344,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinUp: function() {
+ onSpinUp: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -359,7 +359,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinDown: function() {
+ onSpinDown: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -374,7 +374,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinUpAlternate: function() {
+ onSpinUpAlternate: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -384,7 +384,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
//private
- onSpinDownAlternate: function() {
+ onSpinDownAlternate: function () {
if (this.isSpinnable() == false) {
return;
}
@@ -393,7 +393,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.field.fireEvent('spindown', this);
},
- spin: function(down, alternate) {
+ spin: function (down, alternate) {
var v = parseFloat(this.field.getValue());
var incr =
alternate == true
@@ -406,7 +406,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
this.field.setRawValue(v);
},
- fixBoundries: function(value) {
+ fixBoundries: function (value) {
var v = value;
if (this.field.minValue != undefined && v < this.field.minValue) {
@@ -420,7 +420,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
},
// private
- fixPrecision: function(value) {
+ fixPrecision: function (value) {
var nan = isNaN(value);
if (
!this.field.allowDecimals ||
@@ -435,7 +435,7 @@ Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
);
},
- doDestroy: function() {
+ doDestroy: function () {
if (this.trigger) {
this.trigger.remove();
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions/StatusBar.js b/deluge/ui/web/js/extjs/ext-extensions/StatusBar.js
index a12b8f9..1f6a5f0 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/StatusBar.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/StatusBar.js
@@ -183,7 +183,7 @@ sb.setStatus({
activeThreadId: 0,
// private
- initComponent: function() {
+ initComponent: function () {
if (this.statusAlign == 'right') {
this.cls += ' x-status-right';
}
@@ -191,7 +191,7 @@ sb.setStatus({
},
// private
- afterRender: function() {
+ afterRender: function () {
Ext.ux.StatusBar.superclass.afterRender.call(this);
var right = this.statusAlign == 'right';
@@ -260,7 +260,7 @@ statusBar.setStatus({
</code></pre>
* @return {Ext.ux.StatusBar} this
*/
- setStatus: function(o) {
+ setStatus: function (o) {
o = o || {};
if (typeof o == 'string') {
@@ -307,7 +307,7 @@ statusBar.setStatus({
* </ul>
* @return {Ext.ux.StatusBar} this
*/
- clearStatus: function(o) {
+ clearStatus: function (o) {
o = o || {};
if (o.threadId && o.threadId !== this.activeThreadId) {
@@ -330,7 +330,7 @@ statusBar.setStatus({
remove: false,
useDisplay: true,
scope: this,
- callback: function() {
+ callback: function () {
this.setStatus({
text: text,
iconCls: iconCls,
@@ -356,7 +356,7 @@ statusBar.setStatus({
* @param {String} text (optional) The text to set (defaults to '')
* @return {Ext.ux.StatusBar} this
*/
- setText: function(text) {
+ setText: function (text) {
this.activeThreadId++;
this.text = text || '';
if (this.rendered) {
@@ -369,7 +369,7 @@ statusBar.setStatus({
* Returns the current status text.
* @return {String} The status text
*/
- getText: function() {
+ getText: function () {
return this.text;
},
@@ -379,7 +379,7 @@ statusBar.setStatus({
* @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed)
* @return {Ext.ux.StatusBar} this
*/
- setIcon: function(cls) {
+ setIcon: function (cls) {
this.activeThreadId++;
cls = cls || '';
@@ -408,7 +408,7 @@ statusBar.setStatus({
* {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}.
* @return {Ext.ux.StatusBar} this
*/
- showBusy: function(o) {
+ showBusy: function (o) {
if (typeof o == 'string') {
o = { text: o };
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js b/deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js
index ca15073..3ab2347 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js
@@ -50,7 +50,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
autoSize: Ext.emptyFn,
// private
- initComponent: function() {
+ initComponent: function () {
Ext.ux.form.FileUploadField.superclass.initComponent.call(this);
this.addEvents(
@@ -66,7 +66,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
},
// private
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
Ext.ux.form.FileUploadField.superclass.onRender.call(
this,
ct,
@@ -97,30 +97,30 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
this.resizeEl = this.positionEl = this.wrap;
},
- bindListeners: function() {
+ bindListeners: function () {
this.fileInput.on({
scope: this,
- mouseenter: function() {
+ mouseenter: function () {
this.button.addClass(['x-btn-over', 'x-btn-focus']);
},
- mouseleave: function() {
+ mouseleave: function () {
this.button.removeClass([
'x-btn-over',
'x-btn-focus',
'x-btn-click',
]);
},
- mousedown: function() {
+ mousedown: function () {
this.button.addClass('x-btn-click');
},
- mouseup: function() {
+ mouseup: function () {
this.button.removeClass([
'x-btn-over',
'x-btn-focus',
'x-btn-click',
]);
},
- change: function() {
+ change: function () {
var value = this.fileInput.dom.files;
// Fallback to value.
if (!value) value = this.fileInput.dom.value;
@@ -130,7 +130,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
});
},
- createFileInput: function() {
+ createFileInput: function () {
this.fileInput = this.wrap.createChild({
id: this.getFileInputId(),
name: this.name || this.getId(),
@@ -142,7 +142,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
this.fileInput.dom.multiple = this.multiple;
},
- reset: function() {
+ reset: function () {
if (this.rendered) {
this.fileInput.remove();
this.createFileInput();
@@ -152,12 +152,12 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
},
// private
- getFileInputId: function() {
+ getFileInputId: function () {
return this.id + '-file';
},
// private
- onResize: function(w, h) {
+ onResize: function (w, h) {
Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);
this.wrap.setWidth(w);
@@ -172,23 +172,23 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
},
// private
- onDestroy: function() {
+ onDestroy: function () {
Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
Ext.destroy(this.fileInput, this.button, this.wrap);
},
- onDisable: function() {
+ onDisable: function () {
Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
this.doDisable(true);
},
- onEnable: function() {
+ onEnable: function () {
Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
this.doDisable(false);
},
// private
- doDisable: function(disabled) {
+ doDisable: function (disabled) {
this.fileInput.dom.disabled = disabled;
this.button.setDisabled(disabled);
},
@@ -197,7 +197,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
preFocus: Ext.emptyFn,
// private
- alignErrorIcon: function() {
+ alignErrorIcon: function () {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
},
});
diff --git a/deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js b/deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js
index 134e7a1..416c098 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js
@@ -10,8 +10,8 @@
// Allow radiogroups to be treated as a single form element.
Ext.override(Ext.form.RadioGroup, {
- afterRender: function() {
- this.items.each(function(i) {
+ afterRender: function () {
+ this.items.each(function (i) {
this.relayEvents(i, ['check']);
}, this);
if (this.lazyValue) {
@@ -22,21 +22,21 @@ Ext.override(Ext.form.RadioGroup, {
Ext.form.RadioGroup.superclass.afterRender.call(this);
},
- getName: function() {
+ getName: function () {
return this.items.first().getName();
},
- getValue: function() {
+ getValue: function () {
return this.items.first().getGroupValue();
},
- setValue: function(v) {
+ setValue: function (v) {
if (!this.items.each) {
this.value = v;
this.lazyValue = true;
return;
}
- this.items.each(function(item) {
+ this.items.each(function (item) {
if (item.rendered) {
var checked = item.el.getValue() == String(v);
item.el.dom.checked = checked;
diff --git a/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js
index d14f320..890fb5b 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js
@@ -19,7 +19,7 @@ Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
onBlur: Ext.emptyFn,
adjustSize: Ext.BoxComponent.prototype.adjustSize,
- constructor: function(config) {
+ constructor: function (config) {
var spinnerConfig = Ext.copyTo(
{},
config,
@@ -41,23 +41,23 @@ Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
},
// private
- getResizeEl: function() {
+ getResizeEl: function () {
return this.wrap;
},
// private
- getPositionEl: function() {
+ getPositionEl: function () {
return this.wrap;
},
// private
- alignErrorIcon: function() {
+ alignErrorIcon: function () {
if (this.wrap) {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
},
- validateBlur: function() {
+ validateBlur: function () {
return true;
},
});
diff --git a/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js
index eafc4e1..ee761aa 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js
@@ -23,7 +23,7 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
colCfg: {},
// private
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
if (!this.el) {
var panelCfg = {
cls: this.groupCls,
@@ -80,9 +80,8 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
// Generate the column configs with the correct width setting
for (var i = 0; i < numCols; i++) {
var cc = Ext.apply({ items: [] }, colCfg);
- cc[
- this.columns[i] <= 1 ? 'columnWidth' : 'width'
- ] = this.columns[i];
+ cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] =
+ this.columns[i];
if (this.defaults) {
cc.defaults = Ext.apply(
cc.defaults || {},
@@ -131,14 +130,14 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
}
}
- var fields = this.panel.findBy(function(c) {
+ var fields = this.panel.findBy(function (c) {
return c.isFormField;
}, this);
this.items = new Ext.util.MixedCollection();
this.items.addAll(fields);
- this.items.each(function(field) {
+ this.items.each(function (field) {
field.on('spin', this.onFieldChange, this);
field.on('change', this.onFieldChange, this);
}, this);
@@ -159,45 +158,45 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
Ext.ux.form.SpinnerGroup.superclass.onRender.call(this, ct, position);
},
- onFieldChange: function(spinner) {
+ onFieldChange: function (spinner) {
this.fireEvent('change', this, this.getValue());
},
initValue: Ext.emptyFn,
- getValue: function() {
+ getValue: function () {
var value = [this.items.getCount()];
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
value[i] = Number(item.getValue());
});
return value;
},
- getRawValue: function() {
+ getRawValue: function () {
var value = [this.items.getCount()];
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
value[i] = Number(item.getRawValue());
});
return value;
},
- setValue: function(value) {
+ setValue: function (value) {
if (!this.rendered) {
this.value = value;
this.lazyValueSet = true;
} else {
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
item.setValue(value[i]);
});
}
},
- setRawValue: function(value) {
+ setRawValue: function (value) {
if (!this.rendered) {
this.rawValue = value;
this.lazyRawValueSet = true;
} else {
- this.items.each(function(item, i) {
+ this.items.each(function (item, i) {
item.setRawValue(value[i]);
});
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js b/deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js
index 27eebf3..eb60c3b 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js
@@ -21,7 +21,7 @@ Ext.namespace('Ext.ux.form');
Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
cls: 'x-toggle-field',
- initComponent: function() {
+ initComponent: function () {
Ext.ux.form.ToggleField.superclass.initComponent.call(this);
this.toggle = new Ext.form.Checkbox();
@@ -32,7 +32,7 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
});
},
- onRender: function(ct, position) {
+ onRender: function (ct, position) {
if (!this.el) {
this.panel = new Ext.Panel({
cls: this.groupCls,
@@ -50,16 +50,13 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
this.panel.add(this.input);
this.panel.doLayout();
- this.toggle
- .getEl()
- .parent()
- .setStyle('padding-right', '10px');
+ this.toggle.getEl().parent().setStyle('padding-right', '10px');
}
Ext.ux.form.ToggleField.superclass.onRender.call(this, ct, position);
},
// private
- onResize: function(w, h) {
+ onResize: function (w, h) {
this.panel.setSize(w, h);
this.panel.doLayout();
@@ -68,7 +65,7 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
this.input.setSize(inputWidth, h);
},
- onToggleCheck: function(toggle, checked) {
+ onToggleCheck: function (toggle, checked) {
this.input.setDisabled(!checked);
},
});
diff --git a/deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js b/deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js
index e9f0e0c..0fce3b4 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js
@@ -46,7 +46,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
*/
cleanDelay: 500,
- initTemplates: function() {
+ initTemplates: function () {
Ext.ux.grid.BufferView.superclass.initTemplates.call(this);
var ts = this.templates;
// empty div to act as a place holder for a row
@@ -68,23 +68,23 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
ts.rowBody.compile();
},
- getStyleRowHeight: function() {
+ getStyleRowHeight: function () {
return Ext.isBorderBox
? this.rowHeight + this.borderHeight
: this.rowHeight;
},
- getCalculatedRowHeight: function() {
+ getCalculatedRowHeight: function () {
return this.rowHeight + this.borderHeight;
},
- getVisibleRowCount: function() {
+ getVisibleRowCount: function () {
var rh = this.getCalculatedRowHeight(),
visibleHeight = this.scroller.dom.clientHeight;
return visibleHeight < 1 ? 0 : Math.ceil(visibleHeight / rh);
},
- getVisibleRows: function() {
+ getVisibleRows: function () {
var count = this.getVisibleRowCount(),
sc = this.scroller.dom.scrollTop,
start =
@@ -97,7 +97,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
};
},
- doRender: function(cs, rs, ds, startRow, colCount, stripe, onlyBody) {
+ doRender: function (cs, rs, ds, startRow, colCount, stripe, onlyBody) {
var ts = this.templates,
ct = ts.cell,
rt = ts.row,
@@ -162,18 +162,18 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
return buf.join('');
},
- isRowRendered: function(index) {
+ isRowRendered: function (index) {
var row = this.getRow(index);
return row && row.childNodes.length > 0;
},
- syncScroll: function() {
+ syncScroll: function () {
Ext.ux.grid.BufferView.superclass.syncScroll.apply(this, arguments);
this.update();
},
// a (optionally) buffered method to update contents of gridview
- update: function() {
+ update: function () {
if (this.scrollDelay) {
if (!this.renderTask) {
this.renderTask = new Ext.util.DelayedTask(this.doUpdate, this);
@@ -184,14 +184,14 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
}
},
- onRemove: function(ds, record, index, isUpdate) {
+ onRemove: function (ds, record, index, isUpdate) {
Ext.ux.grid.BufferView.superclass.onRemove.apply(this, arguments);
if (isUpdate !== true) {
this.update();
}
},
- doUpdate: function() {
+ doUpdate: function () {
if (this.getVisibleRowCount() > 0) {
var g = this.grid,
cm = g.colModel,
@@ -219,14 +219,14 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
},
// a buffered method to clean rows
- clean: function() {
+ clean: function () {
if (!this.cleanTask) {
this.cleanTask = new Ext.util.DelayedTask(this.doClean, this);
}
this.cleanTask.delay(this.cleanDelay);
},
- doClean: function() {
+ doClean: function () {
if (this.getVisibleRowCount() > 0) {
var vr = this.getVisibleRows();
vr.first -= this.cacheSize;
@@ -249,7 +249,7 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
}
},
- removeTask: function(name) {
+ removeTask: function (name) {
var task = this[name];
if (task && task.cancel) {
task.cancel();
@@ -257,13 +257,13 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
}
},
- destroy: function() {
+ destroy: function () {
this.removeTask('cleanTask');
this.removeTask('renderTask');
Ext.ux.grid.BufferView.superclass.destroy.call(this);
},
- layout: function() {
+ layout: function () {
Ext.ux.grid.BufferView.superclass.layout.call(this);
this.update();
},
diff --git a/deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js b/deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js
index 14ac55a..3ccce2b 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js
@@ -12,7 +12,7 @@
// remove spaces for hidden elements and make show(), hide(), enable() and disable() act on
// the label. don't use hideLabel with this.
Ext.override(Ext.layout.FormLayout, {
- renderItem: function(c, position, target) {
+ renderItem: function (c, position, target) {
if (
c &&
!c.rendered &&
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js b/deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js
index 979bd2c..ba26a72 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js
@@ -13,7 +13,7 @@
* @author Damien Churchill <damoxc@gmail.com>
*/
Ext.override(Ext.tree.MultiSelectionModel, {
- onNodeClick: function(node, e) {
+ onNodeClick: function (node, e) {
if (e.ctrlKey && this.isSelected(node)) {
this.unselect(node);
} else if (e.shiftKey && !this.isSelected(node)) {
@@ -34,7 +34,7 @@ Ext.override(Ext.tree.MultiSelectionModel, {
}
// Select all the nodes
- parentNode.eachChild(function(n) {
+ parentNode.eachChild(function (n) {
var i = parentNode.indexOf(n);
if (fi < i && i < li) {
this.select(n, e, true, true);
@@ -48,7 +48,7 @@ Ext.override(Ext.tree.MultiSelectionModel, {
}
},
- select: function(node, e, keepExisting, suppressEvent) {
+ select: function (node, e, keepExisting, suppressEvent) {
if (keepExisting !== true) {
this.clearSelections(true);
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js
index d3d5fc3..7a74360 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js
@@ -26,7 +26,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
columnsText: 'Columns',
- initComponent: function() {
+ initComponent: function () {
if (!this.root) {
this.root = new Ext.tree.AsyncTreeNode({ text: 'Root' });
}
@@ -98,7 +98,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- initColumns: function() {
+ initColumns: function () {
var cs = this.columns,
len = cs.length,
columns = [],
@@ -127,7 +127,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.columns = columns;
},
- onRender: function() {
+ onRender: function () {
Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
this.el.addClass('x-treegrid');
@@ -176,7 +176,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- setRootNode: function(node) {
+ setRootNode: function (node) {
node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;
node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
if (this.innerCt) {
@@ -187,7 +187,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return node;
},
- clearInnerCt: function() {
+ clearInnerCt: function () {
if (Ext.isIE) {
var dom = this.innerCt.dom;
while (dom.firstChild) {
@@ -198,7 +198,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- initEvents: function() {
+ initEvents: function () {
Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);
this.mon(this.innerBody, 'scroll', this.syncScroll, this);
@@ -210,7 +210,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
});
},
- onResize: function(w, h) {
+ onResize: function (w, h) {
Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
var bd = this.innerBody.dom;
@@ -234,7 +234,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.setScrollOffset(sw);
} else {
var me = this;
- setTimeout(function() {
+ setTimeout(function () {
me.setScrollOffset(
bd.offsetWidth - bd.clientWidth > 10 ? sw : 0
);
@@ -243,7 +243,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- updateColumnWidths: function() {
+ updateColumnWidths: function () {
var cols = this.columns,
colCount = cols.length,
groups = this.outerCt.query('colgroup'),
@@ -282,7 +282,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.syncHeaderScroll();
},
- getVisibleColumns: function() {
+ getVisibleColumns: function () {
var columns = [],
cs = this.columns,
len = cs.length,
@@ -296,7 +296,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return columns;
},
- getTotalColumnWidth: function() {
+ getTotalColumnWidth: function () {
var total = 0;
for (
var i = 0, cs = this.getVisibleColumns(), len = cs.length;
@@ -308,13 +308,13 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return total;
},
- setScrollOffset: function(scrollOffset) {
+ setScrollOffset: function (scrollOffset) {
this.scrollOffset = scrollOffset;
this.updateColumnWidths();
},
// private
- handleHdDown: function(e, t) {
+ handleHdDown: function (e, t) {
var hd = e.getTarget('.x-treegrid-hd');
if (hd && Ext.fly(t).hasClass('x-grid3-hd-btn')) {
@@ -332,7 +332,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
this.hmenu.on(
'hide',
- function() {
+ function () {
Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
},
this,
@@ -347,7 +347,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- handleHdOver: function(e, t) {
+ handleHdOver: function (e, t) {
var hd = e.getTarget('.x-treegrid-hd');
if (hd && !this.headersDisabled) {
index = this.findHeaderIndex(hd);
@@ -365,7 +365,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- handleHdOut: function(e, t) {
+ handleHdOut: function (e, t) {
var hd = e.getTarget('.x-treegrid-hd');
if (hd && (!Ext.isIE || !e.within(hd, true))) {
this.activeHdRef = null;
@@ -374,7 +374,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
}
},
- findHeaderIndex: function(hd) {
+ findHeaderIndex: function (hd) {
hd = hd.dom || hd;
var cs = hd.parentNode.childNodes;
for (var i = 0, c; (c = cs[i]); i++) {
@@ -386,7 +386,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- beforeColMenuShow: function() {
+ beforeColMenuShow: function () {
var cols = this.columns,
colCount = cols.length,
i,
@@ -409,7 +409,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
},
// private
- handleHdMenuClick: function(item) {
+ handleHdMenuClick: function (item) {
var index = this.hdCtxIndex,
id = item.getItemId();
@@ -430,7 +430,7 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
return true;
},
- setColumnVisible: function(index, visible) {
+ setColumnVisible: function (index, visible) {
this.columns[index].hidden = !visible;
this.updateColumnWidths();
},
@@ -438,26 +438,26 @@ Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
/**
* Scrolls the grid to the top
*/
- scrollToTop: function() {
+ scrollToTop: function () {
this.innerBody.dom.scrollTop = 0;
this.innerBody.dom.scrollLeft = 0;
},
// private
- syncScroll: function() {
+ syncScroll: function () {
this.syncHeaderScroll();
var mb = this.innerBody.dom;
this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
},
// private
- syncHeaderScroll: function() {
+ syncHeaderScroll: function () {
var mb = this.innerBody.dom;
this.innerHd.dom.scrollLeft = mb.scrollLeft;
this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
},
- registerNode: function(n) {
+ registerNode: function (n) {
Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
if (!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js
index 870172e..de73608 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js
@@ -15,17 +15,17 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
*/
minWidth: 14,
- constructor: function(config) {
+ constructor: function (config) {
Ext.apply(this, config);
Ext.tree.ColumnResizer.superclass.constructor.call(this);
},
- init: function(tree) {
+ init: function (tree) {
this.tree = tree;
tree.on('render', this.initEvents, this);
},
- initEvents: function(tree) {
+ initEvents: function (tree) {
tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this);
this.tracker = new Ext.dd.DragTracker({
onBeforeStart: this.onBeforeStart.createDelegate(this),
@@ -39,7 +39,7 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
tree.on('beforedestroy', this.tracker.destroy, this.tracker);
},
- handleHdMove: function(e, t) {
+ handleHdMove: function (e, t) {
var hw = 5,
x = e.getPageX(),
hd = e.getTarget('.x-treegrid-hd', 3, true);
@@ -74,12 +74,12 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
}
},
- onBeforeStart: function(e) {
+ onBeforeStart: function (e) {
this.dragHd = this.activeHd;
return !!this.dragHd;
},
- onStart: function(e) {
+ onStart: function (e) {
this.dragHeadersDisabled = this.tree.headersDisabled;
this.tree.headersDisabled = true;
this.proxy = this.tree.body.createChild({ cls: 'x-treegrid-resizer' });
@@ -98,14 +98,14 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
this.tree.innerBody.translatePoints(this.hdX).left;
},
- onDrag: function(e) {
+ onDrag: function (e) {
var cursorX = this.tracker.getXY()[0];
this.proxy.setWidth(
(cursorX - this.hdX).constrain(this.minWidth, this.maxWidth)
);
},
- onEnd: function(e) {
+ onEnd: function (e) {
var nw = this.proxy.getWidth(),
tree = this.tree,
disabled = this.dragHeadersDisabled;
@@ -116,7 +116,7 @@ Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
tree.columns[this.hdIndex].width = nw;
tree.updateColumnWidths();
- setTimeout(function() {
+ setTimeout(function () {
tree.headersDisabled = disabled;
}, 100);
},
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js
index 312bf21..0c88f17 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js
@@ -4,9 +4,9 @@
* licensing@sencha.com
* http://www.sencha.com/license
*/
-(function() {
+(function () {
Ext.override(Ext.list.Column, {
- init: function() {
+ init: function () {
var types = Ext.data.Types,
st = this.sortType;
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js
index eb5156a..db14848 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js
@@ -9,7 +9,7 @@
* @extends Ext.tree.TreeLoader
*/
Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
- createNode: function(attr) {
+ createNode: function (attr) {
if (!attr.uiProvider) {
attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js
index e58a801..09b1718 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js
@@ -11,7 +11,7 @@
Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
- renderElements: function(n, a, targetNode, bulkRender) {
+ renderElements: function (n, a, targetNode, bulkRender) {
var t = n.getOwnerTree(),
cols = t.columns,
c = cols[0],
@@ -111,7 +111,7 @@ Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
},
// private
- animExpand: function(cb) {
+ animExpand: function (cb) {
this.ctNode.style.display = '';
Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb);
},
@@ -121,7 +121,7 @@ Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
// private
- render: function() {
+ render: function () {
if (!this.rendered) {
this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom;
this.node.expanded = true;
@@ -131,13 +131,13 @@ Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
// weird table-layout: fixed issue in webkit
var ct = this.ctNode;
ct.style.tableLayout = null;
- (function() {
+ (function () {
ct.style.tableLayout = 'fixed';
}.defer(1));
}
},
- destroy: function() {
+ destroy: function () {
if (this.elNode) {
Ext.dd.Registry.unregister(this.elNode.id);
}
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js
index 4c21bc3..7708bd7 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js
@@ -9,7 +9,7 @@
*/
Ext.override(Ext.ux.tree.TreeGridNodeUI, {
- updateColumns: function() {
+ updateColumns: function () {
if (!this.rendered) return;
var a = this.node.attributes,
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js
index 20bde8a..ed95d95 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js
@@ -1,5 +1,5 @@
Ext.tree.RenderColumn = Ext.extend(Ext.tree.Column, {
- constructor: function(c) {
+ constructor: function (c) {
c.tpl = c.tpl || new Ext.XTemplate('{' + c.dataIndex + ':this.format}');
c.tpl.format = c.renderer;
c.tpl.col = this;
diff --git a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js
index 376f414..fdf1f38 100644
--- a/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js
+++ b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js
@@ -40,7 +40,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
*/
sortDescText: 'Sort Descending',
- constructor: function(tree, config) {
+ constructor: function (tree, config) {
if (!Ext.isObject(config)) {
config = {
property: tree.columns[0].dataIndex || 'text',
@@ -58,7 +58,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
tree.ddAppendOnly = true;
var me = this;
- this.defaultSortFn = function(n1, n2) {
+ this.defaultSortFn = function (n1, n2) {
var desc = me.dir && me.dir.toLowerCase() == 'desc',
prop = me.property || 'text',
sortType = me.sortType,
@@ -101,7 +101,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
tree.on('headermenuclick', this.onHeaderMenuClick, this);
},
- onAfterTreeRender: function() {
+ onAfterTreeRender: function () {
if (this.tree.hmenu) {
this.tree.hmenu.insert(
0,
@@ -120,14 +120,14 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
this.updateSortIcon(0, 'asc');
},
- onHeaderMenuClick: function(c, id, index) {
+ onHeaderMenuClick: function (c, id, index) {
if (id === 'asc' || id === 'desc') {
this.onHeaderClick(c, null, index);
return false;
}
},
- onHeaderClick: function(c, el, i) {
+ onHeaderClick: function (c, el, i) {
if (c && !this.tree.headersDisabled) {
var me = this;
@@ -139,7 +139,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
: this.caseSensitive;
me.sortFn = c.sortFn || this.defaultSortFn;
- this.tree.root.cascade(function(n) {
+ this.tree.root.cascade(function (n) {
if (!n.isLeaf()) {
me.updateSort(me.tree, n);
}
@@ -150,7 +150,7 @@ Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
},
// private
- updateSortIcon: function(col, dir) {
+ updateSortIcon: function (col, dir) {
var sc = this.sortClasses,
hds = this.tree.innerHd.select('td').removeClass(sc);
hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]);
diff --git a/deluge/ui/web/js/gettext.js b/deluge/ui/web/js/gettext.js
index 9cc1c4f..559577a 100644
--- a/deluge/ui/web/js/gettext.js
+++ b/deluge/ui/web/js/gettext.js
@@ -55,6 +55,8 @@ GetText.add('Connection Manager','${escape(_("Connection Manager"))}')
GetText.add('Connection restored','${escape(_("Connection restored"))}')
GetText.add('Connections','${escape(_("Connections"))}')
GetText.add('Cookies','${escape(_("Cookies"))}')
+GetText.add('Copy','${escape(_("Copy"))}')
+GetText.add('Copy Magnet URI','${escape(_("Copy Magnet URI"))}')
GetText.add('Copy of .torrent files to:','${escape(_("Copy of .torrent files to:"))}')
GetText.add('Copyright 2007-2018 Deluge Team','${escape(_("Copyright 2007-2018 Deluge Team"))}')
GetText.add('Create','${escape(_("Create"))}')
@@ -92,6 +94,8 @@ GetText.add('Encryption','${escape(_("Encryption"))}')
GetText.add('Error','${escape(_("Error"))}')
GetText.add('Expand All','${escape(_("Expand All"))}')
GetText.add('External IP Address','${escape(_("External IP Address"))}')
+GetText.add('Failed to download torrent','${escape(_("Failed to download torrent"))}')
+GetText.add('Failed to upload torrent','${escape(_("Failed to upload torrent"))}')
GetText.add('File','${escape(_("File"))}')
GetText.add('File Browser','${escape(_("File Browser"))}')
GetText.add('Filename','${escape(_("Filename"))}')
diff --git a/deluge/ui/web/json_api.py b/deluge/ui/web/json_api.py
index bfacb58..3f25614 100644
--- a/deluge/ui/web/json_api.py
+++ b/deluge/ui/web/json_api.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009-2010 Damien Churchill <damoxc@gmail.com>
#
@@ -7,8 +6,7 @@
# See LICENSE for more details.
#
-from __future__ import division, unicode_literals
-
+import cgi
import json
import logging
import os
@@ -16,7 +14,6 @@ import shutil
import tempfile
from base64 import b64encode
from types import FunctionType
-from xml.sax.saxutils import escape as xml_escape
from twisted.internet import defer, reactor
from twisted.internet.defer import Deferred, DeferredList
@@ -39,7 +36,7 @@ log = logging.getLogger(__name__)
class JSONComponent(component.Component):
def __init__(self, name, interval=1, depend=None):
- super(JSONComponent, self).__init__(name, interval, depend)
+ super().__init__(name, interval, depend)
self._json = component.get('JSON')
self._json.register_object(self, name)
@@ -146,7 +143,7 @@ class JSON(resource.Resource, component.Component):
params = request_data['params']
request_id = request_data['id']
except KeyError as ex:
- message = 'Invalid JSON request, missing param %s in %s' % (
+ message = 'Invalid JSON request, missing param {} in {}'.format(
ex,
request_data,
)
@@ -167,7 +164,7 @@ class JSON(resource.Resource, component.Component):
except Exception as ex:
log.error('Error calling method `%s`: %s', method, ex)
log.exception(ex)
- error = {'message': '%s: %s' % (ex.__class__.__name__, str(ex)), 'code': 3}
+ error = {'message': f'{ex.__class__.__name__}: {str(ex)}', 'code': 3}
return request_id, result, error
@@ -184,7 +181,7 @@ class JSON(resource.Resource, component.Component):
"""
log.error(reason)
response['error'] = {
- 'message': '%s: %s' % (reason.__class__.__name__, str(reason)),
+ 'message': f'{reason.__class__.__name__}: {str(reason)}',
'code': 4,
}
return self._send_response(request, response)
@@ -194,7 +191,7 @@ class JSON(resource.Resource, component.Component):
Handler to take the json data as a string and pass it on to the
_handle_request method for further processing.
"""
- content_type = request.getHeader(b'content-type').decode()
+ content_type, _ = cgi.parse_header(request.getHeader(b'content-type').decode())
if content_type != 'application/json':
message = 'Invalid JSON request content-type: %s' % content_type
raise JSONException(message)
@@ -221,7 +218,7 @@ class JSON(resource.Resource, component.Component):
'id': None,
'error': {
'code': 5,
- 'message': '%s: %s' % (reason.__class__.__name__, str(reason)),
+ 'message': f'{reason.__class__.__name__}: {str(reason)}',
},
}
return self._send_response(request, response)
@@ -288,7 +285,7 @@ class JSON(resource.Resource, component.Component):
FILES_KEYS = ['files', 'file_progress', 'file_priorities']
-class EventQueue(object):
+class EventQueue:
"""
This class subscribes to events from the core and stores them until all
the subscribed listeners have received the events.
@@ -378,10 +375,8 @@ class WebApi(JSONComponent):
methods available from the core RPC.
"""
- XSS_VULN_KEYS = ['name', 'message', 'comment', 'tracker_status', 'peers']
-
def __init__(self):
- super(WebApi, self).__init__('Web', depend=['SessionProxy'])
+ super().__init__('Web', depend=['SessionProxy'])
self.hostlist = HostList()
self.core_config = CoreConfig()
self.event_queue = EventQueue()
@@ -472,7 +467,7 @@ class WebApi(JSONComponent):
The current connection state.
:returns: True if the client is connected
- :rtype: booleon
+ :rtype: boolean
"""
return client.connected()
@@ -498,7 +493,7 @@ class WebApi(JSONComponent):
:type keys: list
:param filter_dict: the filters to apply when selecting torrents.
:type filter_dict: dictionary
- :returns: The torrent and ui information.
+ :returns: The torrent and UI information.
:rtype: dictionary
"""
d = Deferred()
@@ -518,7 +513,7 @@ class WebApi(JSONComponent):
return d
def got_stats(stats):
- ui_info['stats']['num_connections'] = stats['num_peers']
+ ui_info['stats']['num_connections'] = stats['peer.num_peers_connected']
ui_info['stats']['upload_rate'] = stats['payload_upload_rate']
ui_info['stats']['download_rate'] = stats['payload_download_rate']
ui_info['stats']['download_protocol_rate'] = (
@@ -527,9 +522,9 @@ class WebApi(JSONComponent):
ui_info['stats']['upload_protocol_rate'] = (
stats['upload_rate'] - stats['payload_upload_rate']
)
- ui_info['stats']['dht_nodes'] = stats['dht_nodes']
+ ui_info['stats']['dht_nodes'] = stats['dht.dht_nodes']
ui_info['stats']['has_incoming_connections'] = stats[
- 'has_incoming_connections'
+ 'net.has_incoming_connections'
]
def got_filters(filters):
@@ -555,13 +550,13 @@ class WebApi(JSONComponent):
d3 = client.core.get_session_status(
[
- 'num_peers',
+ 'peer.num_peers_connected',
'payload_download_rate',
'payload_upload_rate',
'download_rate',
'upload_rate',
- 'dht_nodes',
- 'has_incoming_connections',
+ 'dht.dht_nodes',
+ 'net.has_incoming_connections',
]
)
d3.addCallback(got_stats)
@@ -584,7 +579,7 @@ class WebApi(JSONComponent):
paths = []
info = {}
for index, torrent_file in enumerate(files):
- path = xml_escape(torrent_file['path'])
+ path = torrent_file['path']
paths.append(path)
torrent_file['progress'] = file_progress[index]
torrent_file['priority'] = file_priorities[index]
@@ -621,25 +616,10 @@ class WebApi(JSONComponent):
file_tree.walk(walk)
d.callback(file_tree.get_tree())
- def _on_torrent_status(self, torrent, d):
- for key in self.XSS_VULN_KEYS:
- try:
- if key == 'peers':
- for peer in torrent[key]:
- peer['client'] = xml_escape(peer['client'])
- else:
- torrent[key] = xml_escape(torrent[key])
- except KeyError:
- pass
- d.callback(torrent)
-
@export
def get_torrent_status(self, torrent_id, keys):
"""Get the status for a torrent, filtered by status keys."""
- main_deferred = Deferred()
- d = component.get('SessionProxy').get_torrent_status(torrent_id, keys)
- d.addCallback(self._on_torrent_status, main_deferred)
- return main_deferred
+ return component.get('SessionProxy').get_torrent_status(torrent_id, keys)
@export
def get_torrent_files(self, torrent_id):
@@ -659,9 +639,9 @@ class WebApi(JSONComponent):
@export
def download_torrent_from_url(self, url, cookie=None):
"""
- Download a torrent file from a url to a temporary directory.
+ Download a torrent file from a URL to a temporary directory.
- :param url: the url of the torrent
+ :param url: the URL of the torrent
:type url: string
:returns: the temporary file name of the torrent file
:rtype: string
@@ -829,7 +809,7 @@ class WebApi(JSONComponent):
password (str): The password to login to the daemon with.
Returns:
- bool: True if succesful, False otherwise.
+ bool: True if successful, False otherwise.
"""
return self.hostlist.update_host(host_id, host, port, username, password)
@@ -842,7 +822,7 @@ class WebApi(JSONComponent):
host_id (str): The host identifying hash.
Returns:
- bool: True if succesful, False otherwise.
+ bool: True if successful, False otherwise.
"""
return self.hostlist.remove_host(host_id)
@@ -1002,11 +982,11 @@ class WebApi(JSONComponent):
class WebUtils(JSONComponent):
"""
- Utility functions for the webui that do not fit in the WebApi.
+ Utility functions for the Web UI that do not fit in the WebApi.
"""
def __init__(self):
- super(WebUtils, self).__init__('WebUtils')
+ super().__init__('WebUtils')
@export
def get_languages(self):
@@ -1014,6 +994,6 @@ class WebUtils(JSONComponent):
Get the available translated languages
Returns:
- list: of tuples [(lang-id, language-name), ...]
+ list: of tuples ``[(lang-id, language-name), ...]``
"""
return get_languages()
diff --git a/deluge/ui/web/pluginmanager.py b/deluge/ui/web/pluginmanager.py
index 24f20ce..2da5b61 100644
--- a/deluge/ui/web/pluginmanager.py
+++ b/deluge/ui/web/pluginmanager.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import logging
import os
@@ -74,22 +71,20 @@ class PluginManager(PluginManagerBase, component.Component):
scripts = component.get('Scripts')
for script in info['scripts']:
- scripts.remove_script(
- '%s/%s' % (name.lower(), os.path.basename(script).lower())
- )
+ scripts.remove_script(f'{name.lower()}/{os.path.basename(script).lower()}')
for script in info['debug_scripts']:
scripts.remove_script(
- '%s/%s' % (name.lower(), os.path.basename(script).lower()), 'debug'
+ f'{name.lower()}/{os.path.basename(script).lower()}', 'debug'
)
scripts.remove_script(
- '%s/%s' % (name.lower(), os.path.basename(script).lower()), 'dev'
+ f'{name.lower()}/{os.path.basename(script).lower()}', 'dev'
)
- super(PluginManager, self).disable_plugin(name)
+ super().disable_plugin(name)
def enable_plugin(self, name):
- super(PluginManager, self).enable_plugin(name)
+ super().enable_plugin(name)
# Get the plugin instance
try:
@@ -105,17 +100,15 @@ class PluginManager(PluginManagerBase, component.Component):
scripts = component.get('Scripts')
for script in info['scripts']:
log.debug('adding script %s for %s', name, os.path.basename(script))
- scripts.add_script(
- '%s/%s' % (name.lower(), os.path.basename(script)), script
- )
+ scripts.add_script(f'{name.lower()}/{os.path.basename(script)}', script)
for script in info['debug_scripts']:
log.debug('adding debug script %s for %s', name, os.path.basename(script))
scripts.add_script(
- '%s/%s' % (name.lower(), os.path.basename(script)), script, 'debug'
+ f'{name.lower()}/{os.path.basename(script)}', script, 'debug'
)
scripts.add_script(
- '%s/%s' % (name.lower(), os.path.basename(script)), script, 'dev'
+ f'{name.lower()}/{os.path.basename(script)}', script, 'dev'
)
def start(self):
@@ -151,11 +144,10 @@ class PluginManager(PluginManagerBase, component.Component):
info = gather_info(plugin)
info['name'] = name
info['scripts'] = [
- 'js/%s/%s' % (name.lower(), os.path.basename(s)) for s in info['scripts']
+ f'js/{name.lower()}/{os.path.basename(s)}' for s in info['scripts']
]
info['debug_scripts'] = [
- 'js/%s/%s' % (name.lower(), os.path.basename(s))
- for s in info['debug_scripts']
+ f'js/{name.lower()}/{os.path.basename(s)}' for s in info['debug_scripts']
]
del info['script_directories']
return info
diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py
index 192c2b7..f391a78 100644
--- a/deluge/ui/web/server.py
+++ b/deluge/ui/web/server.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009-2010 Damien Churchill <damoxc@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import unicode_literals
-
import fnmatch
import json
import logging
@@ -23,8 +20,7 @@ from twisted.web.resource import EncodingResourceWrapper
from deluge import common, component, configmanager
from deluge.common import is_ipv6
-from deluge.core.rpcserver import check_ssl_keys
-from deluge.crypto_utils import get_context_factory
+from deluge.crypto_utils import check_ssl_keys, get_context_factory
from deluge.i18n import set_language, setup_translation
from deluge.ui.tracker_icons import TrackerIcons
from deluge.ui.web.auth import Auth
@@ -191,7 +187,7 @@ class Tracker(resource.Resource):
request.finish()
def render(self, request):
- d = self.tracker_icons.fetch(request.tracker_name)
+ d = self.tracker_icons.fetch(request.tracker_name.decode())
d.addCallback(self.on_got_icon, request)
return server.NOT_DONE_YET
@@ -376,7 +372,7 @@ class ScriptResource(resource.Resource, component.Component):
order_file = os.path.join(root, '.order')
if os.path.isfile(order_file):
- with open(order_file, 'r') as _file:
+ with open(order_file) as _file:
for line in _file:
if line.startswith('+ '):
order_filename = line.split()[1]
@@ -592,13 +588,13 @@ class TopLevel(resource.Resource):
uri_false = ('false', 'no', 'off', '0')
debug_arg = None
- req_dbg_arg = request.args.get('debug', [b''])[-1].decode().lower()
+ req_dbg_arg = request.args.get(b'debug', [b''])[-1].decode().lower()
if req_dbg_arg in uri_true:
debug_arg = True
elif req_dbg_arg in uri_false:
debug_arg = False
- dev_arg = request.args.get('dev', [b''])[-1].decode().lower() in uri_true
+ dev_arg = request.args.get(b'dev', [b''])[-1].decode().lower() in uri_true
dev_ver = 'dev' in common.get_version()
script_type = 'normal'
@@ -653,7 +649,7 @@ class DelugeWeb(component.Component):
Args:
options (argparse.Namespace): The web server options.
- daemon (bool): If True run web server as a seperate daemon process (starts a twisted
+ daemon (bool): If True run web server as a separate daemon process (starts a twisted
reactor). If False shares the process and twisted reactor from WebUI plugin or tests.
"""
@@ -698,7 +694,7 @@ class DelugeWeb(component.Component):
self.auth = Auth(self.config)
self.daemon = daemon
- # Initalize the plugins
+ # Initialize the plugins
self.plugins = PluginManager()
def _on_language_changed(self, key, value):
diff --git a/deluge/ui/web/web.py b/deluge/ui/web/web.py
index 4d06247..f855bd0 100644
--- a/deluge/ui/web/web.py
+++ b/deluge/ui/web/web.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
@@ -7,8 +6,6 @@
# See LICENSE for more details.
#
-from __future__ import print_function, unicode_literals
-
import logging
from twisted.internet.error import CannotListenError
@@ -24,7 +21,7 @@ class Web(UI):
cmd_description = """Web-based user interface (http://localhost:8112)"""
def __init__(self, *args, **kwargs):
- super(Web, self).__init__(
+ super().__init__(
'web', *args, description='Starts the Deluge Web interface', **kwargs
)
self.__server = None
@@ -67,7 +64,7 @@ class Web(UI):
return self.__server
def start(self):
- super(Web, self).start()
+ super().start()
from deluge.ui.web import server