summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--deluge/core/core.py8
-rw-r--r--deluge/core/preferencesmanager.py7
-rw-r--r--deluge/path_chooser_common.py103
-rw-r--r--deluge/ui/gtkui/addtorrentdialog.py84
-rw-r--r--deluge/ui/gtkui/connectionmanager.py1
-rw-r--r--deluge/ui/gtkui/glade/add_torrent_dialog.ui216
-rw-r--r--deluge/ui/gtkui/glade/main_window.tabs.ui440
-rw-r--r--deluge/ui/gtkui/glade/move_storage_dialog.ui20
-rw-r--r--deluge/ui/gtkui/glade/path_combo_chooser.ui947
-rw-r--r--deluge/ui/gtkui/glade/preferences_dialog.ui91
-rw-r--r--deluge/ui/gtkui/menubar.py45
-rw-r--r--deluge/ui/gtkui/options_tab.py35
-rw-r--r--deluge/ui/gtkui/path_chooser.py191
-rwxr-xr-xdeluge/ui/gtkui/path_combo_chooser.py1543
-rw-r--r--deluge/ui/gtkui/preferences.py431
15 files changed, 3389 insertions, 773 deletions
diff --git a/deluge/core/core.py b/deluge/core/core.py
index dd8a76b2b..710993ad3 100644
--- a/deluge/core/core.py
+++ b/deluge/core/core.py
@@ -48,6 +48,7 @@ import twisted.web.client
import twisted.web.error
from deluge.httpdownloader import download_file
+from deluge import path_chooser_common
import deluge.configmanager
import deluge.common
@@ -858,6 +859,13 @@ class Core(component.Component):
"""
return lt.version
+ @export
+ def get_completion_paths(self, value, hidden_files=False):
+ """
+ Returns the available path completions for the input value.
+ """
+ return path_chooser_common.get_completion_paths(value, hidden_files)
+
@export(AUTH_LEVEL_ADMIN)
def get_known_accounts(self):
return self.authmanager.get_known_accounts()
diff --git a/deluge/core/preferencesmanager.py b/deluge/core/preferencesmanager.py
index a085d2c99..70d6d7113 100644
--- a/deluge/core/preferencesmanager.py
+++ b/deluge/core/preferencesmanager.py
@@ -101,6 +101,13 @@ DEFAULT_PREFS = {
"auto_managed": True,
"move_completed": False,
"move_completed_path": deluge.common.get_default_download_dir(),
+ "move_completed_paths_list": [],
+ "download_location_paths_list": [],
+ "path_chooser_show_chooser_button_on_localhost": True,
+ "path_chooser_auto_complete_enabled": True,
+ "path_chooser_accelerator_string": "Tab",
+ "path_chooser_max_popup_rows": 20,
+ "path_chooser_show_hidden_files": False,
"new_release_check": True,
"proxies": {
"peer": {
diff --git a/deluge/path_chooser_common.py b/deluge/path_chooser_common.py
new file mode 100644
index 000000000..f44d1fbd0
--- /dev/null
+++ b/deluge/path_chooser_common.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# path_chooser_common.py
+#
+# Copyright (C) 2013 Bro <bro.development@gmail.com>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+#
+
+import os
+
+def get_resource(filename):
+ import deluge
+ return deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", filename))
+
+def is_hidden(filepath):
+ def has_hidden_attribute(filepath):
+ import win32api, win32con
+ try:
+ attribute = win32api.GetFileAttributes(filepath)
+ return attribute & (win32con.FILE_ATTRIBUTE_HIDDEN | win32con.FILE_ATTRIBUTE_SYSTEM)
+ except (AttributeError, AssertionError):
+ return False
+
+ name = os.path.basename(os.path.abspath(filepath))
+ # Windows
+ if os.name== 'nt':
+ return has_hidden_attribute(filepath)
+ return name.startswith('.')
+
+def get_completion_paths(path_value, hidden_files=False):
+ """
+ Takes a path value and returns the available completions.
+ If the path_value is a valid path, return all sub-directories.
+ If the path_value is not a valid path, remove the basename from the
+ path and return all sub-directories of path that start with basename.
+
+ :param path_value: path to complete
+ :type path_value: string
+ :returns: a sorted list of available completions for the input value
+ :rtype: list
+
+ """
+ def get_subdirs(dirname):
+ try:
+ return os.walk(dirname).next()[1]
+ except StopIteration:
+ # Invalid dirname
+ return []
+
+ dirname = os.path.dirname(path_value)
+ basename = os.path.basename(path_value)
+
+ dirs = get_subdirs(dirname)
+ # No completions available
+ if not dirs:
+ return []
+
+ # path_value ends with path separator so
+ # we only want all the subdirectories
+ if not basename:
+ # Lets remove hidden files
+ if not hidden_files:
+ old_dirs = dirs
+ dirs = []
+ for d in old_dirs:
+ if not is_hidden(os.path.join(dirname, d)):
+ dirs.append(d)
+ matching_dirs = []
+ for s in dirs:
+ if s.startswith(basename):
+ p = os.path.join(dirname, s)
+ if not p.endswith(os.path.sep):
+ p += os.path.sep
+ matching_dirs.append(p)
+ return sorted(matching_dirs)
diff --git a/deluge/ui/gtkui/addtorrentdialog.py b/deluge/ui/gtkui/addtorrentdialog.py
index 13ac640d6..dd8663233 100644
--- a/deluge/ui/gtkui/addtorrentdialog.py
+++ b/deluge/ui/gtkui/addtorrentdialog.py
@@ -55,6 +55,8 @@ import deluge.ui.common
import dialogs
import common
+from deluge.ui.gtkui.path_chooser import PathChooser
+
log = logging.getLogger(__name__)
class AddTorrentDialog(component.Component):
@@ -144,6 +146,9 @@ class AddTorrentDialog(component.Component):
self.listview_torrents.get_selection().connect("changed",
self._on_torrent_changed)
+ self.setup_move_completed_path_chooser()
+ self.setup_download_location_path_chooser()
+
# Get default config values from the core
self.core_keys = [
"compact_allocation",
@@ -153,13 +158,15 @@ class AddTorrentDialog(component.Component):
"max_download_speed_per_torrent",
"prioritize_first_last_pieces",
"sequential_download",
- "download_location",
"add_paused",
+ "download_location",
+ "download_location_paths_list",
"move_completed",
- "move_completed_path"
+ "move_completed_path",
+ "move_completed_paths_list",
]
+ #self.core_keys += self.move_completed_path_chooser.get_config_keys()
self.core_config = {}
-
self.builder.get_object("notebook1").connect("switch-page", self._on_switch_page)
def start(self):
@@ -169,17 +176,6 @@ class AddTorrentDialog(component.Component):
return self.update_core_config(True, focus)
def _show(self, focus=False):
- if client.is_localhost():
- self.builder.get_object("button_location").show()
- self.builder.get_object("entry_download_path").hide()
- self.builder.get_object("button_move_completed_location").show()
- self.builder.get_object("entry_move_completed_path").hide()
- else:
- self.builder.get_object("button_location").hide()
- self.builder.get_object("entry_download_path").show()
- self.builder.get_object("button_move_completed_location").hide()
- self.builder.get_object("entry_move_completed_path").show()
-
if component.get("MainWindow").is_on_active_workspace():
self.dialog.set_transient_for(component.get("MainWindow").window)
else:
@@ -374,6 +370,23 @@ class AddTorrentDialog(component.Component):
ret += value[1]["size"]
return ret
+ def load_path_choosers_data(self):
+ self.move_completed_path_chooser.set_text(self.core_config["move_completed_path"], cursor_end=False, default_text=True)
+ self.download_location_path_chooser.set_text(self.core_config["download_location"], cursor_end=False, default_text=True)
+ self.builder.get_object("chk_move_completed").set_active(self.core_config["move_completed"])
+
+ def setup_move_completed_path_chooser(self):
+ self.move_completed_hbox = self.builder.get_object("hbox_move_completed_chooser")
+ self.move_completed_path_chooser = PathChooser("move_completed_paths_list")
+ self.move_completed_hbox.add(self.move_completed_path_chooser)
+ self.move_completed_hbox.show_all()
+
+ def setup_download_location_path_chooser(self):
+ self.download_location_hbox = self.builder.get_object("hbox_download_location_chooser")
+ self.download_location_path_chooser = PathChooser("download_location_paths_list")
+ self.download_location_hbox.add(self.download_location_path_chooser)
+ self.download_location_hbox.show_all()
+
def update_torrent_options(self, torrent_id):
if torrent_id not in self.options:
self.set_default_options()
@@ -381,16 +394,8 @@ class AddTorrentDialog(component.Component):
options = self.options[torrent_id]
- if client.is_localhost():
- self.builder.get_object("button_location").set_current_folder(
- options["download_location"])
- self.builder.get_object("button_move_completed_location").set_current_folder(
- options["move_completed_path"])
- else:
- self.builder.get_object("entry_download_path").set_text(
- options["download_location"])
- self.builder.get_object("entry_move_completed_path").set_text(
- options["move_completed_path"])
+ self.download_location_path_chooser.set_text(options["download_location"], cursor_end=True)
+ self.move_completed_path_chooser.set_text(options["move_completed_path"], cursor_end=True)
self.builder.get_object("radio_full").set_active(
not options["compact_allocation"])
@@ -430,18 +435,10 @@ class AddTorrentDialog(component.Component):
else:
options = {}
- if client.is_localhost():
- options["download_location"] = \
- self.builder.get_object("button_location").get_filename()
- options["move_completed_path"] = \
- self.builder.get_object("button_move_completed_location").get_filename()
- else:
- options["download_location"] = \
- self.builder.get_object("entry_download_path").get_text()
- options["move_completed_path"] = \
- self.builder.get_object("entry_move_completed_path").get_text()
- options["compact_allocation"] = \
- self.builder.get_object("radio_compact").get_active()
+ options["download_location"] = self.download_location_path_chooser.get_text()
+ options["move_completed_path"] = self.move_completed_path_chooser.get_text()
+ options["compact_allocation"] = self.builder.get_object("radio_compact").get_active()
+ options["move_completed"] = self.builder.get_object("chk_move_completed").get_active()
if options["compact_allocation"]:
# We need to make sure all the files are set to download
@@ -491,16 +488,7 @@ class AddTorrentDialog(component.Component):
return priorities
def set_default_options(self):
- if client.is_localhost():
- self.builder.get_object("button_location").set_current_folder(
- self.core_config["download_location"])
- self.builder.get_object("button_move_completed_location").set_current_folder(
- self.core_config["move_completed_path"])
- else:
- self.builder.get_object("entry_download_path").set_text(
- self.core_config["download_location"])
- self.builder.get_object("entry_move_completed_path").set_text(
- self.core_config["move_completed_path"])
+ self.load_path_choosers_data()
self.builder.get_object("radio_compact").set_active(
self.core_config["compact_allocation"])
@@ -814,7 +802,6 @@ class AddTorrentDialog(component.Component):
options)
row = self.torrent_liststore.iter_next(row)
-
self.hide()
def _on_button_apply_clicked(self, widget):
@@ -847,8 +834,7 @@ class AddTorrentDialog(component.Component):
def _on_chk_move_completed_toggled(self, widget):
value = widget.get_active()
- self.builder.get_object("button_move_completed_location").set_sensitive(value)
- self.builder.get_object("entry_move_completed_path").set_sensitive(value)
+ self.move_completed_path_chooser.set_sensitive(value)
def _on_delete_event(self, widget, event):
self.hide()
diff --git a/deluge/ui/gtkui/connectionmanager.py b/deluge/ui/gtkui/connectionmanager.py
index 28eab091a..f60cdfc85 100644
--- a/deluge/ui/gtkui/connectionmanager.py
+++ b/deluge/ui/gtkui/connectionmanager.py
@@ -311,7 +311,6 @@ class ConnectionManager(component.Component):
# Return if the deferred callback was done after the dialog was closed
if not self.running:
return
-
row = self.__get_host_row(host_id)
def on_info(info, c):
if not self.running:
diff --git a/deluge/ui/gtkui/glade/add_torrent_dialog.ui b/deluge/ui/gtkui/glade/add_torrent_dialog.ui
index e7c85d3d5..4a4b101bb 100644
--- a/deluge/ui/gtkui/glade/add_torrent_dialog.ui
+++ b/deluge/ui/gtkui/glade/add_torrent_dialog.ui
@@ -1,6 +1,6 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="gtk+" version="2.16"/>
+ <requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">-1</property>
@@ -27,6 +27,7 @@
<property name="page_increment">10</property>
</object>
<object class="GtkDialog" id="dialog_add_torrent">
+ <property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Add Torrents</property>
<property name="window_position">center-on-parent</property>
@@ -35,6 +36,7 @@
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkVPaned" id="vpaned1">
@@ -43,17 +45,20 @@
<child>
<object class="GtkFrame" id="frame2">
<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="alignment2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="left_padding">12</property>
<property name="right_padding">12</property>
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
@@ -71,27 +76,32 @@
</child>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="layout_style">center</property>
<child>
<object class="GtkButton" id="button_file">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_button_file_clicked"/>
+ <signal name="clicked" handler="on_button_file_clicked" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="border_width">2</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage" id="image3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-open</property>
<property name="icon-size">1</property>
</object>
@@ -104,6 +114,7 @@
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
</object>
@@ -127,15 +138,17 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_button_url_clicked"/>
+ <signal name="clicked" handler="on_button_url_clicked" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox4">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="border_width">2</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-network</property>
<property name="icon-size">1</property>
</object>
@@ -148,6 +161,7 @@
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">_URL</property>
<property name="use_underline">True</property>
</object>
@@ -171,15 +185,17 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_button_hash_clicked"/>
+ <signal name="clicked" handler="on_button_hash_clicked" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox5">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="border_width">2</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage" id="image5">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-revert-to-saved</property>
<property name="icon-size">1</property>
</object>
@@ -192,6 +208,7 @@
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Info_hash</property>
<property name="use_underline">True</property>
</object>
@@ -215,14 +232,16 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_button_remove_clicked"/>
+ <signal name="clicked" handler="on_button_remove_clicked" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-remove</property>
</object>
<packing>
@@ -234,6 +253,7 @@
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">_Remove</property>
<property name="use_underline">True</property>
</object>
@@ -266,6 +286,7 @@
<child type="label">
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Torrents</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -304,22 +325,29 @@
<child type="tab">
<object class="GtkHBox" id="hbox11">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image9">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-open</property>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<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="expand">True</property>
+ <property name="fill">True</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
@@ -332,41 +360,28 @@
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkFrame" id="frame7">
<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>
<property name="top_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
- <object class="GtkHBox" id="hbox14">
+ <object class="GtkHBox" id="hbox_download_location_chooser">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkFileChooserButton" id="button_location">
- <property name="action">select-folder</property>
- <property name="title" translatable="yes">Select A Folder</property>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_download_path">
- <property name="can_focus">True</property>
- <property name="truncate_multiline">True</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
</child>
@@ -375,6 +390,7 @@
<child type="label">
<object class="GtkLabel" id="label17">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Download Location</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -391,53 +407,36 @@
<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="alignment8">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
- <object class="GtkHBox" id="hbox1">
+ <object class="GtkHBox" id="hbox_move_completed_chooser">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="chk_move_completed">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_chk_move_completed_toggled"/>
+ <signal name="toggled" handler="on_chk_move_completed_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkFileChooserButton" id="button_move_completed_location">
- <property name="sensitive">False</property>
- <property name="show_hidden">True</property>
- <property name="action">select-folder</property>
- <property name="title" translatable="yes">Select A Folder</property>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_move_completed_path">
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">&#x25CF;</property>
- <property name="truncate_multiline">True</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="position">2</property>
- </packing>
+ <placeholder/>
</child>
</object>
</child>
@@ -446,6 +445,7 @@
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Move Complete Location</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -462,20 +462,24 @@
<child>
<object class="GtkHBox" id="hbox6">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="spacing">10</property>
<child>
<object class="GtkFrame" id="frame4">
<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="alignment4">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox4">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkRadioButton" id="radio_full">
<property name="label" translatable="yes">Full</property>
@@ -484,7 +488,7 @@
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_alocation_toggled"/>
+ <signal name="toggled" handler="on_alocation_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -500,7 +504,7 @@
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">radio_full</property>
- <signal name="toggled" handler="on_alocation_toggled"/>
+ <signal name="toggled" handler="on_alocation_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -515,6 +519,7 @@
<child type="label">
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Allocation</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -531,16 +536,19 @@
<child>
<object class="GtkFrame" id="frame5">
<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="alignment5">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="column_spacing">10</property>
@@ -549,6 +557,8 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="xalign">1</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment1</property>
@@ -556,24 +566,26 @@
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label11">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Down Speed:</property>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Up Speed:</property>
</object>
@@ -581,12 +593,13 @@
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Connections:</property>
</object>
@@ -594,12 +607,13 @@
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label14">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Upload Slots:</property>
</object>
@@ -607,7 +621,7 @@
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -615,6 +629,8 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="xalign">1</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment2</property>
@@ -625,8 +641,8 @@
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -634,6 +650,8 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="xalign">1</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment3</property>
@@ -643,8 +661,8 @@
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -652,6 +670,8 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="xalign">1</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment4</property>
@@ -661,8 +681,8 @@
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
</object>
@@ -672,6 +692,7 @@
<child type="label">
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Bandwidth</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -688,16 +709,19 @@
<child>
<object class="GtkFrame" id="frame6">
<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="alignment6">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox5">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="chk_prioritize">
<property name="label" translatable="yes">Prioritize First/Last Pieces</property>
@@ -755,6 +779,7 @@ used sparingly.</property>
<child type="label">
<object class="GtkLabel" id="label15">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">General</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -778,23 +803,28 @@ used sparingly.</property>
<child>
<object class="GtkHBox" id="hbox9">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
- <object class="GtkAlignment" id="alignment1">
+ <object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkButton" id="button_revert">
+ <object class="GtkButton" id="button_apply">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_button_revert_clicked"/>
+ <signal name="clicked" handler="on_button_apply_clicked" swapped="no"/>
<child>
- <object class="GtkHBox" id="hbox10">
+ <object class="GtkHBox" id="hbox7">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkImage" id="image8">
+ <object class="GtkImage" id="image7">
<property name="visible">True</property>
- <property name="stock">gtk-revert-to-saved</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="stock">gtk-apply</property>
</object>
<packing>
<property name="expand">False</property>
@@ -803,9 +833,11 @@ used sparingly.</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label19">
+ <object class="GtkLabel" id="label18">
<property name="visible">True</property>
- <property name="label" translatable="yes">Revert To Defaults</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Apply To All</property>
</object>
<packing>
<property name="expand">False</property>
@@ -823,26 +855,28 @@ used sparingly.</property>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkAlignment" id="alignment3">
+ <object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkButton" id="button_apply">
+ <object class="GtkButton" id="button_revert">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_button_apply_clicked"/>
+ <signal name="clicked" handler="on_button_revert_clicked" swapped="no"/>
<child>
- <object class="GtkHBox" id="hbox7">
+ <object class="GtkHBox" id="hbox10">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkImage" id="image7">
+ <object class="GtkImage" id="image8">
<property name="visible">True</property>
- <property name="xalign">1</property>
- <property name="stock">gtk-apply</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-revert-to-saved</property>
</object>
<packing>
<property name="expand">False</property>
@@ -851,10 +885,10 @@ used sparingly.</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label18">
+ <object class="GtkLabel" id="label19">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Apply To All</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Revert To Defaults</property>
</object>
<packing>
<property name="expand">False</property>
@@ -872,7 +906,7 @@ used sparingly.</property>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
@@ -890,22 +924,29 @@ used sparingly.</property>
<child type="tab">
<object class="GtkHBox" id="hbox12">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image10">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="stock">gtk-properties</property>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label20">
<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="expand">True</property>
+ <property name="fill">True</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
@@ -924,12 +965,15 @@ used sparingly.</property>
</child>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button_cancel">
@@ -938,7 +982,7 @@ used sparingly.</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
- <signal name="clicked" handler="on_button_cancel_clicked"/>
+ <signal name="clicked" handler="on_button_cancel_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -953,7 +997,7 @@ used sparingly.</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
- <signal name="clicked" handler="on_button_add_clicked"/>
+ <signal name="clicked" handler="on_button_add_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -964,6 +1008,7 @@ used sparingly.</property>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
@@ -975,4 +1020,5 @@ used sparingly.</property>
<action-widget response="0">button_add</action-widget>
</action-widgets>
</object>
+ <object class="GtkListStore" id="liststore1"/>
</interface>
diff --git a/deluge/ui/gtkui/glade/main_window.tabs.ui b/deluge/ui/gtkui/glade/main_window.tabs.ui
index 4b38cbbcb..e474cd865 100644
--- a/deluge/ui/gtkui/glade/main_window.tabs.ui
+++ b/deluge/ui/gtkui/glade/main_window.tabs.ui
@@ -805,6 +805,30 @@
<property name="column_spacing">5</property>
<property name="row_spacing">2</property>
<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>
<object class="GtkLabel" id="summary_comments">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -817,7 +841,7 @@
<property name="right_attach">4</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -835,7 +859,7 @@
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -850,7 +874,7 @@
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -868,7 +892,7 @@
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -885,7 +909,7 @@
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -902,7 +926,7 @@
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -918,7 +942,7 @@
<property name="right_attach">4</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -936,7 +960,7 @@
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -961,7 +985,7 @@
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -976,7 +1000,7 @@
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1000,7 +1024,7 @@
</object>
<packing>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1024,7 +1048,7 @@
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1041,7 +1065,7 @@
<property name="right_attach">4</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1059,7 +1083,7 @@
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1074,7 +1098,7 @@
<property name="right_attach">4</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1089,7 +1113,7 @@
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1107,7 +1131,7 @@
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1125,7 +1149,7 @@
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1141,7 +1165,7 @@
<property name="right_attach">2</property>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1157,33 +1181,9 @@
<property name="right_attach">2</property>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</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>
</object>
</child>
</object>
@@ -1351,9 +1351,10 @@
<property name="resize_mode">queue</property>
<property name="shadow_type">none</property>
<child>
- <object class="GtkHBox" id="hbox7">
+ <object class="GtkTable" id="table6">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="n_columns">3</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
@@ -1370,11 +1371,17 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">5</property>
- <property name="n_rows">5</property>
+ <property name="n_rows">4</property>
<property name="n_columns">3</property>
<property name="column_spacing">5</property>
<property name="row_spacing">2</property>
<child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
<object class="GtkSpinButton" id="spin_max_connections">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -1394,8 +1401,8 @@
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1419,8 +1426,8 @@
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1430,6 +1437,7 @@
<property name="invisible_char">•</property>
<property name="width_chars">6</property>
<property name="xalign">1</property>
+ <property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
@@ -1442,8 +1450,8 @@
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1457,7 +1465,7 @@
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1471,7 +1479,7 @@
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1483,7 +1491,7 @@
</object>
<packing>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1495,8 +1503,8 @@
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1510,8 +1518,8 @@
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1525,7 +1533,7 @@
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1548,25 +1556,10 @@
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="x_options"/>
+ <property name="y_options"/>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
</child>
</object>
@@ -1583,9 +1576,8 @@
</child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
+ <property name="x_options"/>
+ <property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
@@ -1610,7 +1602,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_chk_toggled" swapped="no"/>
</object>
@@ -1635,7 +1626,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_chk_stop_at_ratio_toggled" swapped="no"/>
</object>
@@ -1684,7 +1674,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_chk_toggled" swapped="no"/>
</object>
@@ -1696,67 +1685,6 @@
<property name="position">1</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="use_action_appearance">False</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">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkHBox" id="hbox5">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkFileChooserButton" id="filechooser_move_completed">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">False</property>
- <property name="action">select-folder</property>
- <property name="local_only">False</property>
- <property name="show_hidden">True</property>
- <property name="title" translatable="yes">Select A Folder</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_move_completed">
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">•</property>
- <property name="invisible_char_set">True</property>
- <property name="truncate_multiline">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">3</property>
- </packing>
- </child>
</object>
<packing>
<property name="expand">True</property>
@@ -1780,15 +1708,18 @@
</child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"/>
+ <property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
- <object class="GtkVBox" id="vbox4">
+ <object class="GtkTable" id="table5">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
@@ -1804,9 +1735,11 @@
<property name="top_padding">5</property>
<property name="left_padding">12</property>
<child>
- <object class="GtkVBox" id="vbox1">
+ <object class="GtkTable" id="table3">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
<child>
<object class="GtkCheckButton" id="chk_private">
<property name="label" translatable="yes">Private</property>
@@ -1814,14 +1747,26 @@
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</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>
+ <property name="y_options"/>
+ </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="draw_indicator">True</property>
+ <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1830,14 +1775,14 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</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">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"/>
</packing>
</child>
<child>
@@ -1846,60 +1791,148 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_chk_toggled" swapped="no"/>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"/>
</packing>
</child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame3">
+ <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="alignment1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">5</property>
+ <child>
+ <object class="GtkTable" id="table4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">2</property>
<child>
- <object class="GtkCheckButton" id="chk_shared">
- <property name="label" translatable="yes">Shared</property>
+ <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="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_chk_toggled" swapped="no"/>
+ <signal name="toggled" handler="on_chk_move_completed_toggled" swapped="no"/>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">3</property>
+ <property name="y_options"/>
</packing>
</child>
<child>
- <object class="GtkButton" id="button_edit_trackers">
+ <object class="GtkHBox" id="hbox_move_completed_path_chooser">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label_item">
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame5">
+ <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="alignment5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="button_apply">
+ <property name="label">gtk-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_stock">True</property>
+ <signal name="clicked" handler="on_button_apply_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_edit_trackers1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
- <signal name="clicked" handler="on_button_edit_trackers_clicked" swapped="no"/>
<child>
- <object class="GtkHBox" id="hbox8">
+ <object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
- <object class="GtkImage" id="image6">
+ <object class="GtkImage" id="image7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-edit</property>
</object>
<packing>
<property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label17">
+ <object class="GtkLabel" id="label25">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Edit Trackers</property>
@@ -1917,15 +1950,18 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">4</property>
+ <property name="position">1</property>
</packing>
</child>
+ <child>
+ <placeholder/>
+ </child>
</object>
</child>
</object>
</child>
<child type="label">
- <object class="GtkLabel" id="label16">
+ <object class="GtkLabel" id="label17">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">General</property>
@@ -1936,53 +1972,17 @@
</child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkFrame" id="frame3">
- <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="alignment5">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="xscale">0</property>
- <property name="left_padding">12</property>
- <child>
- <object class="GtkButton" id="button_apply">
- <property name="label">gtk-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_action_appearance">False</property>
- <property name="use_stock">True</property>
- <signal name="clicked" handler="on_button_apply_clicked" swapped="no"/>
- </object>
- </child>
- </object>
- </child>
- <child type="label_item">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"/>
+ <property name="y_options">GTK_FILL</property>
</packing>
</child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="y_options"/>
</packing>
</child>
</object>
diff --git a/deluge/ui/gtkui/glade/move_storage_dialog.ui b/deluge/ui/gtkui/glade/move_storage_dialog.ui
index cf505b751..30d633751 100644
--- a/deluge/ui/gtkui/glade/move_storage_dialog.ui
+++ b/deluge/ui/gtkui/glade/move_storage_dialog.ui
@@ -116,7 +116,7 @@
</packing>
</child>
<child>
- <object class="GtkHBox" id="hbox2">
+ <object class="GtkHBox" id="hbox_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
@@ -133,23 +133,7 @@
</packing>
</child>
<child>
- <object class="GtkEntry" id="entry_destination">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="is_focus">True</property>
- <property name="truncate_multiline">True</property>
- <property name="activates_default">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
<packing>
diff --git a/deluge/ui/gtkui/glade/path_combo_chooser.ui b/deluge/ui/gtkui/glade/path_combo_chooser.ui
new file mode 100644
index 000000000..330579f69
--- /dev/null
+++ b/deluge/ui/gtkui/glade/path_combo_chooser.ui
@@ -0,0 +1,947 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="2.18"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkAction" id="action1"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="lower">-1</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkDialog" id="completion_config_dialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Properties</property>
+ <property name="modal">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <signal name="key-release-event" handler="on_completion_config_dialog_key_release_event" swapped="no"/>
+ <signal name="delete-event" handler="on_completion_config_dialog_delete_event" swapped="no"/>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkFrame" id="config_general_frame">
+ <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="alignment1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="row_spacing">5</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_filechooser_checkbutton">
+ <property name="label" translatable="yes">Show file chooser</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_show_filechooser_checkbutton_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="visible_rows_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Max drop down rows</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="visible_rows_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">2</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <signal name="value-changed" handler="on_visible_rows_spinbutton_value_changed" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_EXPAND</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_path_entry_checkbutton">
+ <property name="label" translatable="yes">Show path entry</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_show_path_entry_checkbutton_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_folder_name_on_button_checkbutton">
+ <property name="label" translatable="yes">Show folder name</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_show_folder_name_on_button_checkbutton_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkButton" id="config_dialog_button_close">
+ <property name="label" translatable="yes">Close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_config_dialog_button_close_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">5</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="enable_auto_completion_checkbutton">
+ <property name="label" translatable="yes">Enable auto completion</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_enable_auto_completion_checkbutton_toggled" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="set_completion_accelerator_button">
+ <property name="label" translatable="yes">Set new key</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Press this key to set new key accelerators to trigger auto-complete</property>
+ <signal name="pressed" handler="on_set_completion_accelerator_button_pressed" swapped="no"/>
+ <signal name="clicked" handler="on_set_completion_accelerator_button_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_hidden_files_checkbutton">
+ <property name="label" translatable="yes">Show hidden files</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0.55000001192092896</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_show_hidden_files_checkbutton_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">&lt;b&gt;Auto completion&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="config_short_cuts_frame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">etched-out</property>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">5</property>
+ <property name="bottom_padding">7</property>
+ <property name="left_padding">23</property>
+ <child>
+ <object class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">6</property>
+ <property name="n_columns">2</property>
+ <property name="row_spacing">2</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Auto-complete accelerator</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Save selected entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Edit selected entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.019999999552965164</property>
+ <property name="label" translatable="yes">Remove selected entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Toggle display hidden files</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">CTRL-s</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="completion_accelerator_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">CTRL-e</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">CTRL-r</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">CTRL-h</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Set default text in entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</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">CTRL-d</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">&lt;b&gt;Short cuts&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">config_dialog_button_close</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkListStore" id="completion_tree_store">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkWindow" id="completion_popup_window">
+ <property name="can_focus">False</property>
+ <property name="type">popup</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">combo</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="skip_pager_hint">True</property>
+ <property name="decorated">False</property>
+ <property name="deletable">False</property>
+ <signal name="button-press-event" handler="on_completion_popup_window_button_press_event" swapped="no"/>
+ <signal name="key-press-event" handler="on_completion_popup_window_key_press_event" swapped="no"/>
+ <signal name="focus-out-event" handler="on_completion_popup_window_focus_out_event" swapped="no"/>
+ <child>
+ <object class="GtkVBox" id="popup_content_box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">3</property>
+ <property name="spacing">1</property>
+ <child>
+ <object class="GtkScrolledWindow" id="completion_scrolled_window">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="completion_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">completion_tree_store</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="enable_search">False</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <signal name="button-press-event" handler="on_completion_treeview_mouse_button_press_event" swapped="no"/>
+ <signal name="key-press-event" handler="on_completion_treeview_key_press_event" swapped="no"/>
+ <signal name="motion-notify-event" handler="on_completion_treeview_motion_notify_event" swapped="no"/>
+ <signal name="scroll-event" handler="on_completion_treeview_scroll_event" swapped="no"/>
+ <child>
+ <object class="GtkTreeViewColumn" id="completion_treeview_column">
+ <property name="sizing">autosize</property>
+ <property name="fixed_width">129</property>
+ <property name="title" translatable="yes">column</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="completion_cellrenderertext"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkFileChooserDialog" id="filechooserdialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="role">GtkFileChooserDialog</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="action">select-folder</property>
+ <property name="preview_widget_active">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="filechooser_button_cancel">
+ <property name="label" translatable="yes">Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="filechooser_button_open">
+ <property name="label" translatable="yes">Open</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="2">filechooser_button_cancel</action-widget>
+ <action-widget response="0">filechooser_button_open</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkListStore" id="stored_values_tree_store">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkWindow" id="stored_values_popup_window">
+ <property name="can_focus">False</property>
+ <property name="type">popup</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">popup-menu</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="skip_pager_hint">True</property>
+ <property name="decorated">False</property>
+ <property name="deletable">False</property>
+ <signal name="button-press-event" handler="on_stored_values_popup_window_button_press_event" swapped="no"/>
+ <signal name="focus-out-event" handler="on_stored_values_popup_window_focus_out_event" swapped="no"/>
+ <signal name="hide" handler="on_stored_values_popup_window_hide" swapped="no"/>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">3</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="stored_values_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">stored_values_tree_store</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <signal name="button-press-event" handler="on_stored_values_treeview_mouse_button_press_event" swapped="no"/>
+ <signal name="key-release-event" handler="on_stored_values_treeview_key_release_event" swapped="no"/>
+ <signal name="key-press-event" handler="on_stored_values_treeview_key_press_event" swapped="no"/>
+ <signal name="scroll-event" handler="on_stored_values_treeview_scroll_event" swapped="no"/>
+ <child>
+ <object class="GtkTreeViewColumn" id="stored_values_treeview_column">
+ <property name="sizing">autosize</property>
+ <property name="fixed_width">127</property>
+ <property name="title" translatable="yes">column</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="stored_values_cellrenderertext">
+ <signal name="edited" handler="on_cellrenderertext_edited" swapped="no"/>
+ </object>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkVButtonBox" id="buttonbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">1</property>
+ <property name="layout_style">start</property>
+ <signal name="key-press-event" handler="on_buttonbox_key_press_event" swapped="no"/>
+ <child>
+ <object class="GtkButton" id="button_add">
+ <property name="label" translatable="yes">Add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Add the current entry value to the list</property>
+ <signal name="clicked" handler="on_button_add_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_edit">
+ <property name="label" translatable="yes">Edit</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Edit the selected entry</property>
+ <signal name="clicked" handler="on_button_edit_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_remove">
+ <property name="label" translatable="yes">Remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Remove the selected entry</property>
+ <signal name="clicked" handler="on_button_remove_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_up">
+ <property name="label" translatable="yes">Up</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Move the selected entry up</property>
+ <signal name="clicked" handler="on_button_up_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_down">
+ <property name="label" translatable="yes">Down</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Move the selected entry down</property>
+ <signal name="clicked" handler="on_button_down_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_default">
+ <property name="label" translatable="yes">Default</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="tooltip_text" translatable="yes">No default path set</property>
+ <signal name="clicked" handler="on_button_default_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_properties">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Open properties dialog</property>
+ <signal name="clicked" handler="on_button_properties_clicked" swapped="no"/>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-properties</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">2</property>
+ <property name="position">0</property>
+ </packing>
+ </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>
+ <object class="GtkWindow" id="window1">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkHBox" id="entry_combobox_hbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">3</property>
+ <signal name="realize" handler="on_entry_combobox_hbox_realize" swapped="no"/>
+ <child>
+ <object class="GtkFileChooserButton" id="filechooser_button">
+ <property name="width_request">160</property>
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="action">select-folder</property>
+ <property name="local_only">False</property>
+ <property name="preview_widget_active">False</property>
+ <property name="title" translatable="yes">Select a Directory</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_open_dialog">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="xalign">0.50999999046325684</property>
+ <signal name="clicked" handler="on_button_open_dialog_clicked" swapped="no"/>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="xpad">1</property>
+ <property name="stock">gtk-open</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="folder_name_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="xpad">6</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry_text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <signal name="insert-text" handler="on_entry_text_insert_text" swapped="no"/>
+ <signal name="key-press-event" handler="on_entry_text_key_press_event" swapped="no"/>
+ <signal name="delete-text" handler="on_entry_text_delete_text" swapped="no"/>
+ <signal name="focus-out-event" handler="on_entry_text_focus_out_event" swapped="no"/>
+ <signal name="scroll-event" handler="on_entry_text_scroll_event" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="button_toggle_dropdown">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Saved paths</property>
+ <property name="focus_on_click">False</property>
+ <signal name="button-press-event" handler="on_button_toggle_dropdown_button_press_event" swapped="no"/>
+ <signal name="toggled" handler="on_button_toggle_dropdown_toggled" swapped="no"/>
+ <signal name="scroll-event" handler="on_button_toggle_dropdown_scroll_event" swapped="no"/>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="height_request">15</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkArrow" id="arrow1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="arrow_type">up</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkArrow" id="arrow2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="arrow_type">down</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/deluge/ui/gtkui/glade/preferences_dialog.ui b/deluge/ui/gtkui/glade/preferences_dialog.ui
index 2d2541d49..a774e29a0 100644
--- a/deluge/ui/gtkui/glade/preferences_dialog.ui
+++ b/deluge/ui/gtkui/glade/preferences_dialog.ui
@@ -1307,38 +1307,12 @@ status tab (&lt;b&gt;EXPERIMENTAL!!!&lt;/b&gt;)</property>
</packing>
</child>
<child>
- <object class="GtkHBox" id="hbox8">
+ <object class="GtkHBox" id="hbox_download_to_path_chooser">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
- <object class="GtkFileChooserButton" id="download_path_button">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">False</property>
- <property name="action">select-folder</property>
- <property name="title" translatable="yes">Select A Folder</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_download_path">
- <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>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
<packing>
@@ -1351,38 +1325,12 @@ status tab (&lt;b&gt;EXPERIMENTAL!!!&lt;/b&gt;)</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkHBox" id="hbox10">
+ <object class="GtkHBox" id="hbox_copy_torrent_files_path_chooser">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
- <object class="GtkFileChooserButton" id="torrent_files_button">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="action">select-folder</property>
- <property name="title" translatable="yes">Select A Folder</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_torrents_path">
- <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>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
</child>
@@ -1399,37 +1347,12 @@ status tab (&lt;b&gt;EXPERIMENTAL!!!&lt;/b&gt;)</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkHBox" id="hbox13">
+ <object class="GtkHBox" id="hbox_move_completed_to_path_chooser">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
- <object class="GtkFileChooserButton" id="move_completed_path_button">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="action">select-folder</property>
- <property name="title" translatable="yes">Select A Folder</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_move_completed_path">
- <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>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
</child>
@@ -1913,7 +1836,7 @@ used sparingly.</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="btn_testport">
+ <object class="GtkButton" id="button_testport">
<property name="label" translatable="yes">Test Active Port</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
diff --git a/deluge/ui/gtkui/menubar.py b/deluge/ui/gtkui/menubar.py
index aebab1466..4399af5a5 100644
--- a/deluge/ui/gtkui/menubar.py
+++ b/deluge/ui/gtkui/menubar.py
@@ -47,6 +47,7 @@ import deluge.common
import common
import dialogs
from deluge.configmanager import ConfigManager
+from deluge.ui.gtkui.path_chooser import PathChooser
log = logging.getLogger(__name__)
@@ -322,31 +323,9 @@ class MenuBar(component.Component):
def on_menuitem_move_activate(self, data=None):
log.debug("on_menuitem_move_activate")
- if client.is_localhost():
- from deluge.configmanager import ConfigManager
- config = ConfigManager("gtkui.conf")
- chooser = gtk.FileChooserDialog(
- _("Choose a directory to move files to"),
- component.get("MainWindow").window,
- gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_OK, gtk.RESPONSE_OK)
- )
- chooser.set_local_only(True)
- if not deluge.common.windows_check():
- chooser.set_icon(common.get_deluge_icon())
- chooser.set_property("skip-taskbar-hint", True)
- chooser.set_current_folder(config["choose_directory_dialog_path"])
- if chooser.run() == gtk.RESPONSE_OK:
- result = chooser.get_filename()
- config["choose_directory_dialog_path"] = result
- client.core.move_storage(
- component.get("TorrentView").get_selected_torrents(), result)
- chooser.destroy()
- else:
- component.get("SessionProxy").get_torrent_status(
- component.get("TorrentView").get_selected_torrent(),
- ["save_path"]).addCallback(self.show_move_storage_dialog)
+ component.get("SessionProxy").get_torrent_status(
+ component.get("TorrentView").get_selected_torrent(),
+ ["save_path"]).addCallback(self.show_move_storage_dialog)
def show_move_storage_dialog(self, status):
log.debug("show_move_storage_dialog")
@@ -358,22 +337,26 @@ class MenuBar(component.Component):
# https://bugzilla.gnome.org/show_bug.cgi?id=546802
self.move_storage_dialog = builder.get_object("move_storage_dialog")
self.move_storage_dialog.set_transient_for(self.window.window)
- self.move_storage_dialog_entry = builder.get_object("entry_destination")
- self.move_storage_dialog_entry.set_text(status["save_path"])
- def on_dialog_response_event(widget, response_id):
+ self.move_storage_dialog_hbox = builder.get_object("hbox_entry")
+ self.move_storage_path_chooser = PathChooser("move_completed_paths_list")
+ self.move_storage_dialog_hbox.add(self.move_storage_path_chooser)
+ self.move_storage_dialog_hbox.show_all()
+ self.move_storage_path_chooser.set_text(status["save_path"])
+ def on_dialog_response_event(widget, response_id):
def on_core_result(result):
# Delete references
del self.move_storage_dialog
- del self.move_storage_dialog_entry
+ del self.move_storage_dialog_hbox
if response_id == gtk.RESPONSE_OK:
log.debug("Moving torrents to %s",
- self.move_storage_dialog_entry.get_text())
- path = self.move_storage_dialog_entry.get_text()
+ self.move_storage_path_chooser.get_text())
+ path = self.move_storage_path_chooser.get_text()
client.core.move_storage(
component.get("TorrentView").get_selected_torrents(), path
).addCallback(on_core_result)
+ self.move_storage_path_chooser.save_config()
self.move_storage_dialog.hide()
self.move_storage_dialog.connect("response", on_dialog_response_event)
diff --git a/deluge/ui/gtkui/options_tab.py b/deluge/ui/gtkui/options_tab.py
index 746d361f5..7ddb72903 100644
--- a/deluge/ui/gtkui/options_tab.py
+++ b/deluge/ui/gtkui/options_tab.py
@@ -37,6 +37,7 @@ import gtk.gdk
import deluge.component as component
from deluge.ui.client import client
+from deluge.ui.gtkui.path_chooser import PathChooser
from deluge.ui.gtkui.torrentdetails import Tab
class OptionsTab(Tab):
@@ -60,11 +61,15 @@ class OptionsTab(Tab):
self.chk_remove_at_ratio = builder.get_object("chk_remove_at_ratio")
self.spin_stop_ratio = builder.get_object("spin_stop_ratio")
self.chk_move_completed = builder.get_object("chk_move_completed")
- self.filechooser_move_completed = builder.get_object("filechooser_move_completed")
self.entry_move_completed = builder.get_object("entry_move_completed")
self.chk_shared = builder.get_object("chk_shared")
self.button_apply = builder.get_object("button_apply")
+ self.move_completed_hbox = builder.get_object("hbox_move_completed_path_chooser")
+ self.move_completed_path_chooser = PathChooser("move_completed_paths_list")
+ self.move_completed_hbox.add(self.move_completed_path_chooser)
+ self.move_completed_hbox.show_all()
+
self.prev_torrent_id = None
self.prev_status = None
@@ -85,15 +90,7 @@ class OptionsTab(Tab):
self.spin_stop_ratio.connect("key-press-event", self._on_key_press_event)
def start(self):
- if client.is_localhost():
- self.filechooser_move_completed.show()
- self.entry_move_completed.hide()
- else:
- self.filechooser_move_completed.hide()
- self.entry_move_completed.show()
- self.entry_move_completed.connect(
- "changed", self._on_entry_move_completed_changed
- )
+ pass
def stop(self):
pass
@@ -169,10 +166,7 @@ class OptionsTab(Tab):
if status["move_on_completed"] != self.prev_status["move_on_completed"]:
self.chk_move_completed.set_active(status["move_on_completed"])
if status["move_on_completed_path"] != self.prev_status["move_on_completed_path"]:
- if client.is_localhost():
- self.filechooser_move_completed.set_current_folder(status["move_on_completed_path"])
- else:
- self.entry_move_completed.set_text(status["move_on_completed_path"])
+ self.move_completed_path_chooser.set_text(status["move_on_completed_path"], cursor_end=False, default_text=True)
if status["shared"] != self.prev_status["shared"]:
self.chk_shared.set_active(status["shared"])
@@ -249,10 +243,7 @@ class OptionsTab(Tab):
self.prev_torrent_id, self.chk_move_completed.get_active()
)
if self.chk_move_completed.get_active():
- if client.is_localhost():
- path = self.filechooser_move_completed.get_filename()
- else:
- path = self.entry_move_completed.get_text()
+ path = self.move_completed_path_chooser.get_text()
client.core.set_torrent_move_completed_path(self.prev_torrent_id, path)
if self.chk_shared.get_active() != self.prev_status["shared"]:
client.core.set_torrents_shared(
@@ -274,13 +265,7 @@ class OptionsTab(Tab):
def _on_chk_move_completed_toggled(self, widget):
value = self.chk_move_completed.get_active()
- if client.is_localhost():
- widget = self.filechooser_move_completed
- else:
- widget = self.entry_move_completed
-
- widget.set_sensitive(value)
-
+ self.move_completed_path_chooser.set_sensitive(value)
if not self.button_apply.is_sensitive():
self.button_apply.set_sensitive(True)
diff --git a/deluge/ui/gtkui/path_chooser.py b/deluge/ui/gtkui/path_chooser.py
new file mode 100644
index 000000000..533839c66
--- /dev/null
+++ b/deluge/ui/gtkui/path_chooser.py
@@ -0,0 +1,191 @@
+#
+# path_chooser.py
+#
+# Copyright (C) 2013 Bro <bro.development@gmail.com>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+#
+
+import logging
+
+from deluge.ui.client import client
+from deluge.ui.gtkui.path_combo_chooser import PathChooserComboBox
+import deluge.component as component
+
+log = logging.getLogger(__name__)
+
+def singleton(cls):
+ instances = {}
+ def getinstance():
+ if cls not in instances:
+ instances[cls] = cls()
+ return instances[cls]
+ return getinstance
+
+@singleton
+class PathChoosersHandler(component.Component):
+
+ def __init__(self, paths_config_key=None):
+ #self.chooser_name = "PathChooser_%d" % (len(PathChooser.path_choosers) +1)
+ component.Component.__init__(self, "PathChoosersHandler")
+ self.path_choosers = []
+ self.paths_list_keys = []
+ self.config_properties = {}
+ self.started = False
+ self.config_keys_to_funcs_mapping = {"path_chooser_show_chooser_button_on_localhost": "filechooser_button_visible",
+ "path_chooser_show_path_entry": "path_entry_visible",
+ "path_chooser_auto_complete_enabled": "auto_complete_enabled",
+ "path_chooser_show_folder_name": "show_folder_name_on_button",
+ "path_chooser_accelerator_string": "accelerator_string",
+ "path_chooser_show_hidden_files": "show_hidden_files",
+ "path_chooser_max_popup_rows": "max_popup_rows",
+ }
+ def start(self):
+ self.started = True
+ self.update_config_from_core()
+
+ def stop(self):
+ self.started = False
+
+ def update_config_from_core(self):
+ def _on_config_values(config):
+ self.config_properties.update(config)
+ for chooser in self.path_choosers:
+ chooser.set_config(config)
+ keys = self.config_keys_to_funcs_mapping.keys()
+ keys += self.paths_list_keys
+ client.core.get_config_values(keys).addCallback(_on_config_values)
+
+ def register_chooser(self, chooser):
+ chooser.config_key_funcs = {}
+ for key in self.config_keys_to_funcs_mapping:
+ chooser.config_key_funcs[key] = [None, None]
+ chooser.config_key_funcs[key][0] = getattr(chooser, "get_%s" % self.config_keys_to_funcs_mapping[key])
+ chooser.config_key_funcs[key][1] = getattr(chooser, "set_%s" % self.config_keys_to_funcs_mapping[key])
+
+ self.path_choosers.append(chooser)
+ if not chooser.paths_config_key in self.paths_list_keys:
+ self.paths_list_keys.append(chooser.paths_config_key)
+ if self.started:
+ self.update_config_from_core()
+ else:
+ chooser.set_config(self.config_properties)
+
+ def set_value_for_path_choosers(self, value, key):
+ for chooser in self.path_choosers:
+ chooser.config_key_funcs[key][1](value)
+
+ # Save to core
+ if not key is "path_chooser_max_popup_rows":
+ client.core.set_config({key: value})
+ else:
+ # Since the max rows value can be changed fast with a spinbutton, we
+ # delay saving to core until the values hasn't been changed in 1 second.
+ self.max_rows_value_set = value
+ def update(value_):
+ # The value hasn't been changed in one second, so save to core
+ if self.max_rows_value_set == value_:
+ client.core.set_config({"path_chooser_max_popup_rows": value})
+ from twisted.internet import reactor
+ reactor.callLater(1, update, value)
+
+ def on_list_values_changed(self, values, key, caller):
+ # Save to core
+ config = { key : values }
+ client.core.set_config(config)
+ # Set the values on all path choosers with that key
+ for chooser in self.path_choosers:
+ # Found chooser with values from 'key'
+ if chooser.paths_config_key == key:
+ chooser.set_values(values)
+
+ def get_config_keys(self):
+ keys = self.config_keys_to_funcs_mapping.keys()
+ keys += self.paths_list_keys
+ return keys
+
+class PathChooser(PathChooserComboBox):
+
+ def __init__(self, paths_config_key=None):
+ self.paths_config_key = paths_config_key
+ PathChooserComboBox.__init__(self)
+ self.chooser_handler = PathChoosersHandler()
+ self.chooser_handler.register_chooser(self)
+ self.set_auto_completer_func(self.on_completion)
+ self.connect("list-values-changed", self.on_list_values_changed_event)
+ self.connect("auto-complete-enabled-toggled", self.on_auto_complete_enabled_toggled)
+ self.connect("show-filechooser-toggled", self.on_show_filechooser_toggled)
+ self.connect("show-folder-name-on-button", self.on_show_folder_on_button_toggled)
+ self.connect("show-path-entry-toggled", self.on_show_path_entry_toggled)
+ self.connect("accelerator-set", self.on_accelerator_set)
+ self.connect("max-rows-changed", self.on_max_rows_changed)
+ self.connect("show-hidden-files-toggled", self.on_show_hidden_files_toggled)
+
+ def on_auto_complete_enabled_toggled(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_auto_complete_enabled")
+
+ def on_show_filechooser_toggled(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_show_chooser_button_on_localhost")
+
+ def on_show_folder_on_button_toggled(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_show_folder_name")
+
+ def on_show_path_entry_toggled(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_show_path_entry")
+
+ def on_accelerator_set(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_accelerator_string")
+
+ def on_show_hidden_files_toggled(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_show_hidden_files")
+
+ def on_max_rows_changed(self, widget, value):
+ self.chooser_handler.set_value_for_path_choosers(value, "path_chooser_max_popup_rows")
+
+ def on_list_values_changed_event(self, widget, values):
+ self.chooser_handler.on_list_values_changed(values, self.paths_config_key, self)
+
+ def set_config(self, config):
+ self.config = config
+ for key in self.config_key_funcs:
+ if key in config:
+ try:
+ self.config_key_funcs[key][1](config[key])
+ except TypeError, e:
+ log.warn("TypeError: %s" % str(e))
+
+ # Set the saved paths
+ if self.paths_config_key and self.paths_config_key in config:
+ self.set_values(config[self.paths_config_key])
+
+ def on_completion(self, value, hidden_files):
+ def on_paths_cb(paths):
+ self.complete(value, paths)
+ d = client.core.get_completion_paths(value, hidden_files=hidden_files)
+ d.addCallback(on_paths_cb)
diff --git a/deluge/ui/gtkui/path_combo_chooser.py b/deluge/ui/gtkui/path_combo_chooser.py
new file mode 100755
index 000000000..27a716f85
--- /dev/null
+++ b/deluge/ui/gtkui/path_combo_chooser.py
@@ -0,0 +1,1543 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# path_combo_chooser.py
+#
+# Copyright (C) 2013 Bro <bro.development@gmail.com>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with deluge. If not, write to:
+# The Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# exception, you may extend this exception to your version of the file(s),
+# but you are not obligated to do so. If you do not wish to do so, delete
+# this exception statement from your version. If you delete this exception
+# statement from all source files in the program, then also delete it here.
+#
+
+import os
+
+import gobject
+import gtk
+from gtk import gdk, keysyms
+
+from deluge.path_chooser_common import get_resource, get_completion_paths
+
+def is_ascii_value(keyval, ascii_key):
+ try:
+ # Set show/hide hidden files
+ if chr(keyval) == ascii_key:
+ return True
+ except ValueError:
+ # Not in ascii range
+ pass
+ return False
+
+def key_is_up(keyval):
+ return keyval == keysyms.Up or keyval == keysyms.KP_Up
+
+def key_is_down(keyval):
+ return keyval == keysyms.Down or keyval == keysyms.KP_Down
+
+def key_is_up_or_down(keyval):
+ return key_is_up(keyval) or key_is_down(keyval)
+
+def key_is_pgup_or_pgdown(keyval):
+ return keyval == keysyms.Page_Down or keyval == keysyms.Page_Up
+
+def key_is_enter(keyval):
+ return keyval == keysyms.Return or keyval == keysyms.KP_Enter
+
+def path_without_trailing_path_sep(path):
+ while path.endswith("/") or path.endswith("\\"):
+ if path == "/":
+ return path
+ path = path[0:-1]
+ return path
+
+class ValueList(object):
+
+ def get_values_count(self):
+ return len(self.tree_store)
+
+ def get_values(self):
+ """
+ Returns the values in the list.
+ """
+ values = []
+ for row in self.tree_store:
+ values.append(row[0])
+ return values
+
+ def add_values(self, paths, append=True, scroll_to_row=False,
+ clear=False, emit_signal=False):
+ """
+ Add paths to the liststore
+
+ :param paths: the paths to add
+ :type paths: list
+ :param append: if the values should be appended or inserted
+ :type append: boolean
+ :param scroll_to_row: if the treeview should scroll to the new row
+ :type scroll_to_row: boolean
+
+ """
+ if clear:
+ self.tree_store.clear()
+
+ for path in paths:
+ path = path_without_trailing_path_sep(path)
+ if append:
+ tree_iter = self.tree_store.append([path])
+ else:
+ tree_iter = self.tree_store.insert(0, [path])
+
+ if scroll_to_row:
+ self.treeview.grab_focus()
+ tree_path = self.tree_store.get_path(tree_iter)
+ # Scroll to path
+ self.handle_list_scroll(path=tree_path)
+
+ if emit_signal:
+ self.emit("list-value-added", paths)
+ self.emit("list-values-changed", self.get_values())
+
+ def set_values(self, paths, scroll_to_row=False, preserve_selection=True):
+ """
+ Add paths to the liststore
+
+ :param paths: the paths to add
+ :type paths: list
+ :param scroll_to_row: if the treeview should scroll to the new row
+ :type scroll_to_row: boolean
+
+ """
+ if not (type(paths) is list or type(paths) is tuple):
+ return
+ sel = None
+ if preserve_selection:
+ sel = self.get_selection_path()
+ self.add_values(paths, scroll_to_row=scroll_to_row, clear=True)
+ if sel:
+ self.treeview.get_selection().select_path(sel)
+
+ def get_selection_path(self):
+ """Returns the (first) selected path from a treeview"""
+ tree_selection = self.treeview.get_selection()
+ model, tree_paths = tree_selection.get_selected_rows()
+ if len(tree_paths) > 0:
+ return tree_paths[0]
+ return None
+
+ def get_selected_value(self):
+ path = self.get_selection_path()
+ if path:
+ return self.tree_store[path][0]
+ return None
+
+ def remove_selected_path(self):
+ path = self.get_selection_path()
+ if path:
+ path_value = self.tree_store[path][0]
+ del self.tree_store[path]
+ index = path[0]
+ # The last row was deleted
+ if index == len(self.tree_store):
+ index -= 1
+ if index >= 0:
+ path = (index, )
+ self.treeview.set_cursor(path)
+ self.set_path_selected(path)
+ self.emit("list-value-removed", path_value)
+ self.emit("list-values-changed", self.get_values())
+
+ def set_selected_value(self, value, select_first=False):
+ """
+ Select the row of the list with value
+
+ :param value: the value to be selected
+ :type value: str
+ :param select_first: if the first item should be selected if the value if not found.
+ :type select_first: boolean
+
+ """
+ for i, row in enumerate(self.tree_store):
+ if row[0] == value:
+ self.treeview.set_cursor((i))
+ return
+ # The value was not found
+ if select_first:
+ self.treeview.set_cursor((0,))
+ else:
+ self.treeview.get_selection().unselect_all()
+
+ def set_path_selected(self, path):
+ self.treeview.get_selection().select_path(path)
+
+ def on_value_list_treeview_key_press_event(self, widget, event):
+ """
+ Mimics Combobox behavior
+
+ Escape or Alt+Up: Close
+ Enter or Return : Select
+ """
+ keyval = event.keyval
+ state = event.state & gtk.accelerator_get_default_mod_mask()
+
+ if keyval == keysyms.Escape or\
+ (key_is_up(keyval) and
+ state == gdk.MOD1_MASK): # ALT Key
+ self.popdown()
+ return True
+ # Set entry value to the selected row
+ elif key_is_enter(keyval):
+ path = self.get_selection_path()
+ if path:
+ self.set_entry_value(path, popdown=True)
+ return True
+ return False
+
+ def on_treeview_mouse_button_press_event(self, treeview, event, double_click=False):
+ """
+ When left clicking twice, the row value is set for the text entry
+ and the popup is closed.
+
+ """
+ # This is left click
+ if event.button != 3:
+ # Double clicked a row, set this as the entry value
+ # and close the popup
+ if (double_click and event.type == gtk.gdk._2BUTTON_PRESS) or\
+ (not double_click and event.type == gtk.gdk.BUTTON_PRESS):
+ path = self.get_selection_path()
+ if path:
+ self.set_entry_value(path, popdown=True)
+ return True
+ return False
+
+ def handle_list_scroll(self, next=None, path=None, set_entry=False, swap=False, scroll_window=False):
+ """
+ Handles changes to the row selection.
+
+ :param next: the direction to change selection. None means no change. True means down
+ and False means up.
+ :type next: boolean/None
+ :param path: the current path. If None, the currently selected path is used.
+ :type path: tuple
+ :param set_entry: if the new value should be set in the text entry.
+ :type set_entry: boolean
+ :param swap: if the old and new value should be swapped
+ :type swap: boolean
+
+ """
+ if scroll_window:
+ adjustment = self.completion_scrolled_window.get_vadjustment()
+
+ visible_rows_height = self.get_values_count()
+ if visible_rows_height > self.max_visible_rows:
+ visible_rows_height = self.max_visible_rows
+
+ visible_rows_height *= self.row_height
+ value = adjustment.get_value()
+
+ # Max adjustment value
+ max_value = adjustment.get_upper() - visible_rows_height
+ # Set adjustment increment to 3 times the row height
+ adjustment.set_step_increment(self.row_height * 3)
+
+ if next:
+ # If number of values is less than max rows, no scroll
+ if self.get_values_count() < self.max_visible_rows:
+ return
+ value += adjustment.get_step_increment()
+ if value > max_value:
+ value = max_value
+ else:
+ value -= adjustment.get_step_increment()
+ if value < 0:
+ value = 0
+ adjustment.set_value(value)
+ return
+
+ if path is None:
+ path = self.get_selection_path()
+ if not path:
+ # These options require a selected path
+ if set_entry or swap:
+ return
+ # This is a regular scroll, not setting value in entry or swapping rows,
+ # so we find a path value anyways
+ path = (0, )
+ cursor = self.treeview.get_cursor()
+ if cursor is not None and cursor[0] is not None:
+ path = cursor[0]
+ else:
+ # Since cursor is none, we won't advance the index
+ next = None
+
+ # If next is None, we won't change the selection
+ if not next is None:
+ # We move the selection either one up or down.
+ # If we reach end of list, we wrap
+ index = path[0] if path else 0
+ index = index + 1 if next else index - 1
+ if index >= len(self.tree_store):
+ index = 0
+ elif index < 0:
+ index = len(self.tree_store) - 1
+
+ # We have the index for the new path
+ new_path = (index)
+ if swap:
+ p1 = self.tree_store[path][0]
+ p2 = self.tree_store[new_path][0]
+ self.tree_store.swap(self.tree_store.get_iter(path),
+ self.tree_store.get_iter(new_path))
+ self.emit("list-values-reordered", [p1, p2])
+ self.emit("list-values-changed", self.get_values())
+ path = new_path
+
+ self.treeview.set_cursor(path)
+ self.treeview.get_selection().select_path(path)
+ if set_entry:
+ self.set_entry_value(path)
+
+class StoredValuesList(ValueList):
+
+ def __init__(self):
+ self.tree_store = self.builder.get_object("stored_values_tree_store")
+ self.tree_column = self.builder.get_object("stored_values_treeview_column")
+ self.rendererText = self.builder.get_object("stored_values_cellrenderertext")
+
+ # Add signal handlers
+ self.signal_handlers["on_stored_values_treeview_mouse_button_press_event"] = \
+ self.on_treeview_mouse_button_press_event
+
+ self.signal_handlers["on_stored_values_treeview_key_press_event"] = \
+ self.on_stored_values_treeview_key_press_event
+ self.signal_handlers["on_stored_values_treeview_key_release_event"] = \
+ self.on_stored_values_treeview_key_release_event
+
+ self.signal_handlers["on_cellrenderertext_edited"] = self.on_cellrenderertext_edited
+
+ def on_cellrenderertext_edited(self, cellrenderertext, path, new_text):
+ """
+ Callback on the 'edited' signal.
+
+ Sets the new text in the path and disables editing on the renderer.
+ """
+ new_text = path_without_trailing_path_sep(new_text)
+ self.tree_store[path][0] = new_text
+ self.rendererText.set_property('editable', False)
+
+ def on_edit_path(self, path, column):
+ """
+ Starts editing on the provided path
+
+ :param path: the paths to edit
+ :type path: tuple
+ :param column: the column to edit
+ :type column: gtk.TreeViewColumn
+
+ """
+ self.rendererText.set_property('editable', True)
+ self.treeview.grab_focus()
+ self.treeview.set_cursor(path, focus_column=column, start_editing=True)
+
+ def on_treeview_mouse_button_press_event(self, treeview, event):
+ """
+ Shows popup on selected row when right clicking
+ When left clicking twice, the row value is set for the text entry
+ and the popup is closed.
+
+ """
+ # This is left click
+ if event.button != 3:
+ super(StoredValuesList, self).on_treeview_mouse_button_press_event(treeview, event, double_click=True)
+ return False
+
+ # This is right click, create popup menu for this row
+ x = int(event.x)
+ y = int(event.y)
+ time = event.time
+ pthinfo = treeview.get_path_at_pos(x, y)
+ if pthinfo is not None:
+ path, col, cellx, celly = pthinfo
+ treeview.grab_focus()
+ treeview.set_cursor(path, col, 0)
+
+ self.path_list_popup = gtk.Menu()
+ menuitem_edit = gtk.MenuItem("Edit path")
+ self.path_list_popup.append(menuitem_edit)
+ menuitem_remove = gtk.MenuItem("Remove path")
+ self.path_list_popup.append(menuitem_remove)
+
+ def on_edit_clicked(widget, path):
+ self.on_edit_path(path, self.tree_column)
+ def on_remove_clicked(widget, path):
+ self.remove_selected_path()
+
+ menuitem_edit.connect("activate", on_edit_clicked, path)
+ menuitem_remove.connect("activate", on_remove_clicked, path)
+ self.path_list_popup.popup(None, None, None, event.button, time, data=path)
+ self.path_list_popup.show_all()
+
+ def remove_selected_path(self):
+ ValueList.remove_selected_path(self)
+ # Resize popup
+ 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)
+ # Prevent the default event handler to move the cursor in the list
+ if key_is_up_or_down(event.keyval):
+ return True
+
+ def on_stored_values_treeview_key_release_event(self, widget, event):
+ """
+ Mimics Combobox behavior
+
+ Escape or Alt+Up: Close
+ Enter or Return : Select
+
+ """
+ keyval = event.keyval
+ state = event.state & gtk.accelerator_get_default_mod_mask()
+ ctrl = event.state & gtk.gdk.CONTROL_MASK
+
+ # Edit selected row
+ if (keyval in [keysyms.Left, keysyms.Right, keysyms.space]):
+ path = self.get_selection_path()
+ if path:
+ self.on_edit_path(path, self.tree_column)
+ elif key_is_up_or_down(keyval):
+ # Swap the row value
+ if event.state & gtk.gdk.CONTROL_MASK:
+ self.handle_list_scroll(next=key_is_down(keyval),
+ swap=True)
+ else:
+ self.handle_list_scroll(next=key_is_down(keyval))
+ elif key_is_pgup_or_pgdown(event.keyval):
+ # The cursor has been changed by the default key-press-event handler
+ # so set the path of the cursor selected
+ self.set_path_selected(self.treeview.get_cursor()[0])
+ elif ctrl:
+ # Handle key bindings for manipulating the list
+ # Remove the selected entry
+ if is_ascii_value(keyval, 'r'):
+ self.remove_selected_path()
+ return True
+ # Add current value to saved list
+ elif is_ascii_value(keyval, 's'):
+ super(PathChooserComboBox, self).add_current_value_to_saved_list()
+ return True
+ # Edit selected value
+ elif is_ascii_value(keyval, 'e'):
+ self.edit_selected_path()
+ return True
+
+class CompletionList(ValueList):
+
+ def __init__(self):
+ self.tree_store = self.builder.get_object("completion_tree_store")
+ self.tree_column = self.builder.get_object("completion_treeview_column")
+ self.rendererText = self.builder.get_object("completion_cellrenderertext")
+ self.completion_scrolled_window = self.builder.get_object("completion_scrolled_window")
+ self.signal_handlers["on_completion_treeview_key_press_event"] = \
+ self.on_completion_treeview_key_press_event
+ self.signal_handlers["on_completion_treeview_motion_notify_event"] = \
+ 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
+
+ def reduce_values(self, prefix):
+ """
+ Reduce the values in the liststore to those starting with the prefix.
+
+ :param prefix: the prefix to be matched
+ :type paths: string
+
+ """
+ values = self.get_values()
+ matching_values = []
+ for v in values:
+ if v.startswith(prefix):
+ matching_values.append(v)
+ 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)
+ if ret:
+ return ret
+ keyval = event.keyval
+ ctrl = event.state & gtk.gdk.CONTROL_MASK
+ if key_is_up_or_down(keyval):
+ self.handle_list_scroll(next=key_is_down(keyval))
+ return True
+ elif ctrl:
+ # Set show/hide hidden files
+ if is_ascii_value(keyval, 'h'):
+ self.path_entry.set_show_hidden_files(not self.path_entry.get_show_hidden_files(), do_completion=True)
+ return True
+
+ def on_completion_treeview_motion_notify_event(self, widget, event):
+ if event.is_hint:
+ x, y, state = event.window.get_pointer()
+ else:
+ x = event.x
+ y = event.y
+ state = event.state
+
+ path = self.treeview.get_path_at_pos(int(x), int(y))
+ if path:
+ self.handle_list_scroll(path=path[0], next=None)
+
+class PathChooserPopup(object):
+ """
+
+ This creates the popop window for the ComboEntry
+
+ """
+ def __init__(self, min_visible_rows, max_visible_rows, popup_alignment_widget):
+ self.min_visible_rows = min_visible_rows
+ # Maximum number of rows to display without scrolling
+ self.set_max_popup_rows(max_visible_rows)
+ self.popup_window.realize()
+ self.alignment_widget = popup_alignment_widget
+
+ def popup(self):
+ """
+ Makes the popup visible.
+
+ """
+ # Entry is not yet visible
+ if not (self.path_entry.flags() & gtk.REALIZED):
+ return
+ if not self.is_popped_up():
+ self.set_window_position_and_size()
+
+ def popdown(self):
+ if not self.is_popped_up():
+ return
+ if not (self.path_entry.flags() & gtk.REALIZED):
+ return
+ self.popup_window.grab_remove()
+ self.popup_window.hide_all()
+
+ def is_popped_up(self):
+ """
+ Return True if the window is popped up.
+ """
+ return bool(self.popup_window.flags() & gtk.MAPPED)
+
+ def set_window_position_and_size(self):
+ if len(self.tree_store) < self.min_visible_rows:
+ return False
+ x, y, width, height = self.get_position()
+ self.popup_window.set_size_request(width, height)
+ self.popup_window.resize(width, height)
+ self.popup_window.move(x, y)
+ self.popup_window.show_all()
+
+ def get_position(self):
+ """
+ Returns the size of the popup window and the coordinates on the screen.
+
+ """
+ self.popup_buttonbox = self.builder.get_object("buttonbox")
+
+ # Necessary for the first call, to make treeview.size_request give sensible values
+ #self.popup_window.realize()
+ self.treeview.realize()
+
+ # We start with the coordinates of the parent window
+ x, y = self.path_entry.window.get_origin()
+
+ # Add the position of the alignment_widget relative to the parent window.
+ x += self.alignment_widget.allocation.x
+ y += self.alignment_widget.allocation.y
+
+ height_extra = 8
+
+ height = self.popup_window.size_request()[1]
+ width = self.popup_window.size_request()[0]
+
+ treeview_height = self.treeview.size_request()[1]
+ treeview_width = self.treeview.size_request()[0]
+
+ if treeview_height > height:
+ height = treeview_height + height_extra
+
+ butonbox_height = max(self.popup_buttonbox.size_request()[1], self.popup_buttonbox.allocation.height)
+ butonbox_width = max(self.popup_buttonbox.size_request()[0], self.popup_buttonbox.allocation.width)
+
+ if treeview_height > butonbox_height and treeview_height < height :
+ height = treeview_height + height_extra
+
+ # After removing an element from the tree store, self.treeview.size_request()[0]
+ # returns -1 for some reason, so the requested width cannot be used until the treeview
+ # has been displayed once.
+ if treeview_width != -1:
+ width = treeview_width + butonbox_width
+ # The list is empty, so ignore initial popup width request
+ # Will be set to the minimum width next
+ elif len(self.tree_store) == 0:
+ width = 0
+
+ # Minimum width is the width of the path entry + width of buttonbox
+# if width < self.alignment_widget.allocation.width + butonbox_width:
+# width = self.alignment_widget.allocation.width + butonbox_width
+
+ if width < self.alignment_widget.allocation.width:
+ width = self.alignment_widget.allocation.width
+
+ # 10 is extra spacing
+ content_width = self.treeview.size_request()[0] + butonbox_width + 10
+
+ # If self.max_visible_rows is -1, not restriction is set
+ if len(self.tree_store) > 0 and self.max_visible_rows > 0:
+ # The height for one row in the list
+ self.row_height = self.treeview.size_request()[1] / len(self.tree_store)
+ # Adjust the height according to the max number of rows
+ max_height = self.row_height * self.max_visible_rows
+ # Restrict height to max_visible_rows
+ if max_height + height_extra < height:
+ height = max_height
+ height += height_extra
+ # Increase width because of vertical scrollbar
+ content_width += 15
+
+ # Minimum height is the height of the button box
+ if height < butonbox_height + height_extra:
+ height = butonbox_height + height_extra
+
+ if content_width > width:
+ width = content_width
+
+ screen = self.path_entry.get_screen()
+ monitor_num = screen.get_monitor_at_window(self.path_entry.window)
+ monitor = screen.get_monitor_geometry(monitor_num)
+
+ if x < monitor.x:
+ x = monitor.x
+ elif x + width > monitor.x + monitor.width:
+ x = monitor.x + monitor.width - width
+
+ # Set the position
+ if y + self.path_entry.allocation.height + height <= monitor.y + monitor.height:
+ y += self.path_entry.allocation.height
+ # Not enough space downwards on the screen
+ elif y - height >= monitor.y:
+ y -= height
+ elif (monitor.y + monitor.height - (y + self.path_entry.allocation.height) >
+ y - monitor.y):
+ y += self.path_entry.allocation.height
+ height = monitor.y + monitor.height - y
+ else:
+ height = y - monitor.y
+ y = monitor.y
+
+ return x, y, width, height
+
+ def popup_grab_window(self):
+ activate_time = 0L
+ if gdk.pointer_grab(self.popup_window.window, True,
+ (gdk.BUTTON_PRESS_MASK |
+ gdk.BUTTON_RELEASE_MASK |
+ gdk.POINTER_MOTION_MASK),
+ None, None, activate_time) == 0:
+ if gdk.keyboard_grab(self.popup_window.window, True, activate_time) == 0:
+ return True
+ else:
+ self.popup_window.window.get_display().pointer_ungrab(activate_time);
+ return False
+ return False
+
+ def set_entry_value(self, path, popdown=False):
+ """
+
+ Sets the text of the entry to the value in path
+ """
+ self.path_entry.set_text(self.tree_store[path][0], set_file_chooser_folder=True)
+ if popdown:
+ self.popdown()
+
+ def set_max_popup_rows(self, rows):
+ try:
+ int(rows)
+ except:
+ self.max_visible_rows = 20
+ return
+ self.max_visible_rows = rows
+
+ def get_max_popup_rows(self):
+ return self.max_visible_rows
+
+###################################################
+# Callbacks
+###################################################
+
+ def on_popup_window_button_press_event(self, window, event):
+ # If we're clicking outside of the window close the popup
+ hide = False
+ # Also if the intersection of self and the event is empty, hide
+ # the path_list
+ if (tuple(self.popup_window.allocation.intersect(
+ gdk.Rectangle(x=int(event.x), y=int(event.y),
+ width=1, height=1))) == (0, 0, 0, 0)):
+ hide = True
+ # Toplevel is the window that received the event, and parent is the
+ # path_list window. If they are not the same, means the popup should
+ # be hidden. This is necessary for when the event happens on another
+ # widget
+ toplevel = event.window.get_toplevel()
+ parent = self.popup_window.window
+
+ if toplevel != parent:
+ hide = True
+ if hide:
+ self.popdown()
+
+
+class StoredValuesPopup(StoredValuesList, PathChooserPopup):
+ """
+
+ The stored values popup
+
+ """
+ def __init__(self, builder, path_entry, max_visible_rows, popup_alignment_widget):
+ self.builder = builder
+ self.treeview = self.builder.get_object("stored_values_treeview")
+ self.popup_window = self.builder.get_object("stored_values_popup_window")
+ self.popup_buttonbox = self.builder.get_object("buttonbox")
+ self.button_default = self.builder.get_object("button_default")
+ self.path_entry = path_entry
+ self.text_entry = path_entry.text_entry
+
+ self.signal_handlers = {}
+ PathChooserPopup.__init__(self, 0, max_visible_rows, popup_alignment_widget)
+ StoredValuesList.__init__(self)
+
+ # Add signal handlers
+ self.signal_handlers["on_buttonbox_key_press_event"] = \
+ self.on_buttonbox_key_press_event
+ self.signal_handlers["on_stored_values_treeview_scroll_event"] = self.on_scroll_event
+ self.signal_handlers["on_button_toggle_dropdown_scroll_event"] = self.on_scroll_event
+ self.signal_handlers["on_entry_text_scroll_event"] = self.on_scroll_event
+ self.signal_handlers["on_stored_values_popup_window_focus_out_event"] = \
+ self.on_stored_values_popup_window_focus_out_event
+ # For when clicking outside the popup
+ self.signal_handlers["on_stored_values_popup_window_button_press_event"] = \
+ self.on_popup_window_button_press_event
+
+ # Buttons for manipulating the list
+ self.signal_handlers["on_button_add_clicked"] = self.on_button_add_clicked
+ self.signal_handlers["on_button_edit_clicked"] = self.on_button_edit_clicked
+ self.signal_handlers["on_button_remove_clicked"] = self.on_button_remove_clicked
+ self.signal_handlers["on_button_up_clicked"] = self.on_button_up_clicked
+ self.signal_handlers["on_button_down_clicked"] = self.on_button_down_clicked
+ self.signal_handlers["on_button_default_clicked"] = self.on_button_default_clicked
+ self.signal_handlers["on_button_properties_clicked"] = self.path_entry._on_button_properties_clicked
+
+ def popup(self):
+ """
+ Makes the popup visible.
+
+ """
+ # Calling super popup
+ PathChooserPopup.popup(self)
+ self.popup_window.grab_focus()
+
+ if not (self.treeview.flags() & gtk.HAS_FOCUS):
+ self.treeview.grab_focus()
+ if not self.popup_grab_window():
+ self.popup_window.hide()
+ return
+
+ self.popup_window.grab_add()
+ # Set value selected if it exists
+ self.set_selected_value(path_without_trailing_path_sep(self.path_entry.get_text()))
+
+###################################################
+# Callbacks
+###################################################
+
+ def on_stored_values_popup_window_focus_out_event(self, entry, event):
+ """
+ Popup sometimes loses the focus to the text entry, e.g. when right click
+ shows a popup menu on a row. This regains the focus.
+ """
+ self.popup_grab_window()
+ return True
+
+ def on_scroll_event(self, widget, event):
+ """
+ Handles scroll events from text entry, toggle button and treeview
+
+ """
+ swap = event.state & gtk.gdk.CONTROL_MASK
+ self.handle_list_scroll(next=event.direction == gdk.SCROLL_DOWN,
+ set_entry=widget != self.treeview, swap=swap)
+ return True
+
+ def on_buttonbox_key_press_event(self, widget, event):
+ """
+ Handles when Escape or ALT+arrow up is pressed when focus
+ is on any of the buttons in the popup
+ """
+ keyval = event.keyval
+ state = event.state & gtk.accelerator_get_default_mod_mask()
+ if (keyval == keysyms.Escape or
+ (key_is_up(keyval) and
+ state == gdk.MOD1_MASK)):
+ self.popdown()
+ return True
+ return False
+
+# --------------------------------------------------
+# Funcs and callbacks on the buttons to manipulate the list
+# --------------------------------------------------
+ def add_current_value_to_saved_list(self):
+ text = self.path_entry.get_text()
+ text = path_without_trailing_path_sep(text)
+ values = self.get_values()
+ if text in values:
+ # Make the matching value selected
+ self.set_selected_value(text)
+ self.handle_list_scroll()
+ return True
+ self.add_values([text], scroll_to_row=True, append=False, emit_signal=True)
+
+ def edit_selected_path(self):
+ path = self.get_selection_path()
+ if path:
+ self.on_edit_path(path, self.tree_column)
+
+ def on_button_add_clicked(self, widget):
+ self.add_current_value_to_saved_list()
+ self.popup()
+
+ def on_button_edit_clicked(self, widget):
+ self.edit_selected_path()
+
+ def on_button_remove_clicked(self, widget):
+ self.remove_selected_path()
+ return True
+
+ def on_button_up_clicked(self, widget):
+ self.handle_list_scroll(next=False, swap=True)
+
+ def on_button_down_clicked(self, widget):
+ self.handle_list_scroll(next=True, swap=True)
+
+ def on_button_default_clicked(self, widget):
+ if self.default_text:
+ self.set_text(self.default_text)
+
+class PathCompletionPopup(CompletionList, PathChooserPopup):
+ """
+
+ The auto completion popup
+
+ """
+ def __init__(self, builder, path_entry, max_visible_rows):
+ self.builder = builder
+ self.treeview = self.builder.get_object("completion_treeview")
+ self.popup_window = self.builder.get_object("completion_popup_window")
+ self.path_entry = path_entry
+ self.text_entry = path_entry.text_entry
+ self.show_hidden_files = False
+
+ self.signal_handlers = {}
+ PathChooserPopup.__init__(self, 1, max_visible_rows, self.text_entry)
+ CompletionList.__init__(self)
+
+ # Add signal handlers
+ self.signal_handlers["on_completion_treeview_scroll_event"] = self.on_scroll_event
+ self.signal_handlers["on_completion_popup_window_focus_out_event"] = \
+ self.on_completion_popup_window_focus_out_event
+
+ # For when clicking outside the popup
+ self.signal_handlers["on_completion_popup_window_button_press_event"] = \
+ self.on_popup_window_button_press_event
+
+ def popup(self):
+ """
+ Makes the popup visible.
+
+ """
+ PathChooserPopup.popup(self)
+ self.popup_window.grab_focus()
+
+ if not (self.treeview.flags() & gtk.HAS_FOCUS):
+ self.treeview.grab_focus()
+
+ if not self.popup_grab_window():
+ self.popup_window.hide()
+ return
+
+ self.popup_window.grab_add()
+ self.text_entry.grab_focus()
+ self.text_entry.set_position(len(self.path_entry.text_entry.get_text()))
+
+###################################################
+# Callbacks
+###################################################
+
+ def on_completion_popup_window_focus_out_event(self, entry, event):
+ """
+ Popup sometimes loses the focus to the text entry, e.g. when right click
+ shows a popup menu on a row. This regains the focus.
+ """
+ self.popup_grab_window()
+ return True
+
+ def on_scroll_event(self, widget, event):
+ """
+ Handles scroll events from the treeview
+
+ """
+ x, y, state = event.window.get_pointer()
+ self.handle_list_scroll(next=event.direction == gdk.SCROLL_DOWN,
+ set_entry=widget != self.treeview, scroll_window=True)
+ path = self.treeview.get_path_at_pos(int(x), int(y))
+ if path:
+ self.handle_list_scroll(path=path[0], next=None)
+ return True
+
+class PathAutoCompleter(object):
+
+ def __init__(self, builder, path_entry, max_visible_rows):
+ self.completion_popup = PathCompletionPopup(builder, path_entry, max_visible_rows)
+ self.path_entry = path_entry
+ self.dirs_cache = {}
+ self.use_popup = False
+ self.auto_complete_enabled = True
+ self.signal_handlers = self.completion_popup.signal_handlers
+
+ self.signal_handlers["on_completion_popup_window_key_press_event"] = \
+ self.on_completion_popup_window_key_press_event
+ self.signal_handlers["on_entry_text_delete_text"] = \
+ self.on_entry_text_delete_text
+ self.signal_handlers["on_entry_text_insert_text"] = \
+ self.on_entry_text_insert_text
+
+ self.accelerator_string = gtk.accelerator_name(keysyms.Tab, 0)
+
+ def on_entry_text_insert_text(self, entry, new_text, new_text_length, position):
+ if (self.path_entry.flags() & gtk.REALIZED):
+ cur_text = self.path_entry.get_text()
+ pos = entry.get_position()
+ new_complete_text = cur_text[:pos] + new_text + cur_text[pos:]
+ # Remove all values from the list that do not start with new_complete_text
+ self.completion_popup.reduce_values(new_complete_text)
+ if self.completion_popup.is_popped_up():
+ self.completion_popup.set_window_position_and_size()
+
+ def on_entry_text_delete_text(self, entry, start, end):
+ """
+ Remove the popup when characters are removed
+
+ """
+ if self.completion_popup.is_popped_up():
+ self.completion_popup.popdown()
+
+ def set_use_popup(self, use):
+ self.use_popup = use
+
+ def on_completion_popup_window_key_press_event(self, entry, event):
+ """
+ """
+ # If on_completion_treeview_key_press_event handles the event, do nothing
+ ret = self.completion_popup.on_completion_treeview_key_press_event(entry, event)
+ if ret:
+ return ret
+ keyval = event.keyval
+ state = event.state & gtk.accelerator_get_default_mod_mask()
+
+ if self.is_auto_completion_accelerator(keyval, state)\
+ and self.auto_complete_enabled:
+ values_count = self.completion_popup.get_values_count()
+ self.do_completion()
+ if values_count == 1:
+ self.completion_popup.popdown()
+ else:
+ #shift = event.state & gtk.gdk.SHIFT_MASK
+ #self.completion_popup.handle_list_scroll(next=False if shift else True)
+ self.completion_popup.handle_list_scroll(next=True)
+ return True
+ self.path_entry.text_entry.emit("key-press-event", event)
+
+ def is_auto_completion_accelerator(self, keyval, state):
+ return gtk.accelerator_name(keyval, state.numerator) == self.accelerator_string
+
+ def do_completion(self):
+ value = self.path_entry.get_text()
+ self.path_entry.text_entry.set_position(len(value))
+ paths = self._start_completion(value, hidden_files=self.completion_popup.show_hidden_files)
+
+ def _start_completion(self, value, hidden_files):
+ completion_paths = get_completion_paths(value, hidden_files)
+ self._end_completion(value, completion_paths)
+
+ def _end_completion(self, value, paths):
+ common_prefix = os.path.commonprefix(paths)
+ if len(common_prefix) > len(value):
+ self.path_entry.set_text(common_prefix, set_file_chooser_folder=True)
+
+ self.path_entry.text_entry.set_position(len(self.path_entry.get_text()))
+ self.completion_popup.set_values(paths, preserve_selection=True)
+ if self.use_popup and len(paths) > 1:
+ self.completion_popup.popup()
+ elif self.completion_popup.is_popped_up():
+ self.completion_popup.popdown()
+
+class PathChooserComboBox(gtk.HBox, StoredValuesPopup, gobject.GObject):
+
+ __gsignals__ = {
+ "list-value-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "list-value-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "list-values-reordered": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "list-values-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "auto-complete-enabled-toggled": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "show-filechooser-toggled": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "show-path-entry-toggled": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "show-folder-name-on-button": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "show-hidden-files-toggled": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "accelerator-set": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ "max-rows-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )),
+ }
+
+ def __init__(self, max_visible_rows=20, auto_complete=True, use_completer_popup=True):
+ gtk.HBox.__init__(self)
+ gobject.GObject.__init__(self)
+ self._stored_values_popping_down = False
+ self.filechooser_visible = True
+ self.filechooser_enabled = True
+ self.path_entry_visible = True
+ self.properties_enabled = True
+ self.show_folder_name_on_button = False
+ self.setting_accelerator_key = False
+ self.builder = gtk.Builder()
+ self.popup_buttonbox = self.builder.get_object("buttonbox")
+ self.builder.add_from_file(get_resource("path_combo_chooser.ui"))
+ self.button_toggle = self.builder.get_object("button_toggle_dropdown")
+ self.text_entry = self.builder.get_object("entry_text")
+ self.open_filechooser_dialog_button = self.builder.get_object("button_open_dialog")
+ self.filechooser_button = self.open_filechooser_dialog_button
+ self.filechooserdialog = self.builder.get_object("filechooserdialog")
+ self.folder_name_label = self.builder.get_object("folder_name_label")
+ self.default_text = None
+ self.button_properties = self.builder.get_object("button_properties")
+ self.combo_hbox = self.builder.get_object("entry_combobox_hbox")
+ # Change the parent of the hbox from the glade Window to this hbox.
+ self.combo_hbox.reparent(self)
+ StoredValuesPopup.__init__(self, self.builder, self, max_visible_rows, self.combo_hbox)
+ self.tooltips = gtk.Tooltips()
+
+ self.auto_completer = PathAutoCompleter(self.builder, self, max_visible_rows)
+ self.auto_completer.set_use_popup(use_completer_popup)
+ self.auto_completer.auto_complete_enabled = auto_complete
+ self._setup_config_dialog()
+
+ signal_handlers = {
+ "on_button_toggle_dropdown_toggled": self._on_button_toggle_dropdown_toggled,
+ 'on_entry_text_key_press_event': self._on_entry_text_key_press_event,
+ 'on_stored_values_popup_window_hide': self._on_stored_values_popup_window_hide,
+ "on_button_toggle_dropdown_button_press_event": self._on_button_toggle_dropdown_button_press_event,
+ "on_entry_combobox_hbox_realize": self._on_entry_combobox_hbox_realize,
+ "on_button_open_dialog_clicked": self._on_button_open_dialog_clicked,
+ "on_entry_text_focus_out_event": self._on_entry_text_focus_out_event,
+ }
+ signal_handlers.update(self.signal_handlers)
+ signal_handlers.update(self.auto_completer.signal_handlers)
+ signal_handlers.update(self.config_dialog_signal_handlers)
+ self.builder.connect_signals(signal_handlers)
+
+ def get_text(self):
+ """
+ Get the current text in the Entry
+ """
+ return self.text_entry.get_text()
+
+ def set_text(self, text, set_file_chooser_folder=True, cursor_end=True, default_text=False):
+ """
+ Set the text for the entry.
+
+ """
+ self.text_entry.set_text(text)
+ self.text_entry.select_region(0, 0)
+ self.text_entry.set_position(len(text) if cursor_end else 0)
+ self.set_selected_value(text, select_first=True)
+ self.tooltips.set_tip(self.combo_hbox, text)
+ if default_text:
+ self.default_text = text
+ self.tooltips.set_tip(self.button_default, "Restore the default value in the text entry:\n%s" % self.default_text)
+ self.button_default.set_sensitive(True)
+ # Set text for the filechooser dialog button
+ if not self.path_entry_visible:
+ # Show entire path
+ self.folder_name_label.set_text(text)
+ else:
+ if self.show_folder_name_on_button:
+ text = path_without_trailing_path_sep(text)
+ if not text is "/" and os.path.basename(text):
+ text = os.path.basename(text)
+ else:
+ text = ""
+ self.folder_name_label.set_text(text)
+
+ def set_sensitive(self, sensitive):
+ """
+ Set the path chooser widgets sensitive
+
+ :param sensitive: if the widget should be sensitive
+ :type sensitive: bool
+
+ """
+ self.text_entry.set_sensitive(sensitive)
+ self.filechooser_button.set_sensitive(sensitive)
+ self.button_toggle.set_sensitive(sensitive)
+
+ def get_accelerator_string(self):
+ return self.auto_completer.accelerator_string
+
+ def set_accelerator_string(self, accelerator):
+ """
+ Set the accelerator string to trigger auto-completion
+ """
+ if accelerator is None:
+ return
+ try:
+ # Verify that the accelerator can be parsed
+ keyval, mask = gtk.accelerator_parse(self.auto_completer.accelerator_string)
+ self.auto_completer.accelerator_string = accelerator
+ except TypeError, e:
+ raise TypeError("TypeError when setting accelerator string: %s" % str(e))
+
+ def get_auto_complete_enabled(self):
+ return self.auto_completer.auto_complete_enabled
+
+ def set_auto_complete_enabled(self, enable):
+ if not type(enable) is bool:
+ return
+ self.auto_completer.auto_complete_enabled = enable
+
+ def get_show_folder_name_on_button(self):
+ return self.show_folder_name_on_button
+
+ def set_show_folder_name_on_button(self, show):
+ if not type(show) is bool:
+ return
+ self.show_folder_name_on_button = show
+ self._set_path_entry_filechooser_widths()
+
+ def get_filechooser_button_enabled(self):
+ return self.filechooser_enabled
+
+ def set_filechooser_button_enabled(self, enable):
+ """
+ Enable/disable the filechooser button.
+
+ By setting filechooser disabled, in will not be possible
+ to change the settings in the properties.
+ """
+ if not type(enable) is bool:
+ return
+ self.filechooser_enabled = enable
+ if not enable:
+ self.set_filechooser_button_visible(False, update=False)
+
+ def get_filechooser_button_visible(self):
+ return self.filechooser_visible
+
+ def set_filechooser_button_visible(self, visible, update=True):
+ """
+ Set file chooser button entry visible
+ """
+ if not type(visible) is bool:
+ return
+ if update:
+ self.filechooser_visible = visible
+ if visible and not self.filechooser_enabled:
+ return
+ if visible:
+ self.filechooser_button.show()
+ else:
+ self.filechooser_button.hide()
+ # Update width properties
+ self._set_path_entry_filechooser_widths()
+
+ def get_path_entry_visible(self):
+ return self.path_entry_visible
+
+ def set_path_entry_visible(self, visible):
+ """
+ Set the path entry visible
+ """
+ if not type(visible) is bool:
+ return
+ self.path_entry_visible = visible
+ if visible:
+ self.text_entry.show()
+ else:
+ self.text_entry.hide()
+ self._set_path_entry_filechooser_widths()
+
+ def get_show_hidden_files(self):
+ return self.auto_completer.completion_popup.show_hidden_files
+
+ def set_show_hidden_files(self, show, do_completion=False, emit_event=False):
+ """
+ Enable/disable showing hidden files on path completion
+ """
+ if not type(show) is bool:
+ return
+ self.auto_completer.completion_popup.show_hidden_files = show
+ if do_completion:
+ self.auto_completer.do_completion()
+ if emit_event:
+ self.emit("show-hidden-files-toggled", show)
+
+ def set_enable_properties(self, enable):
+ """
+ Enable/disable the config properties
+ """
+ if not type(enable) is bool:
+ return
+ self.properties_enabled = enable
+ if self.properties_enabled:
+ self.popup_buttonbox.add(self.button_properties)
+ else:
+ self.popup_buttonbox.remove(self.button_properties)
+
+ def set_auto_completer_func(self, func):
+ """
+ Set the function to be called when the auto completion
+ accelerator is triggered.
+ """
+ self.auto_completer._start_completion = func
+
+ def complete(self, value, paths):
+ """
+ Perform the auto completion with the provided paths
+ """
+ self.auto_completer._end_completion(value, paths)
+
+######################################
+## Callbacks and internal functions
+######################################
+
+ def _on_entry_text_focus_out_event(self, widget, event):
+ self.set_text(self.get_text())
+
+ def _set_path_entry_filechooser_widths(self):
+ if self.path_entry_visible:
+ self.combo_hbox.set_child_packing(self.filechooser_button, 0, 0, 0, gtk.PACK_START)
+ width, height = self.folder_name_label.get_size_request()
+ width = 120
+ if not self.show_folder_name_on_button:
+ width = 0
+ self.folder_name_label.set_size_request(width, height)
+ self.combo_hbox.set_child_packing(self.filechooser_button, 0, 0, 0, gtk.PACK_START)
+ else:
+ self.combo_hbox.set_child_packing(self.filechooser_button, 1, 1, 0, gtk.PACK_START)
+ self.folder_name_label.set_size_request(-1, -1)
+ # Update text on the button label
+ self.set_text(self.get_text())
+
+ def _on_entry_combobox_hbox_realize(self, widget):
+ """ 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)
+
+ def _on_button_open_dialog_clicked(self, widget):
+ dialog = self.filechooserdialog
+ dialog.set_current_folder(self.get_text())
+ response_id = dialog.run()
+
+ if response_id == 0:
+ text = self.filechooserdialog.get_filename()
+ self.set_text(text)
+ dialog.hide()
+
+ def _on_entry_text_key_press_event(self, widget, event):
+ """
+ Listen to key events on the entry widget.
+
+ Arrow up/down will change the value of the entry according to the
+ current selection in the list.
+ Enter will show the popup.
+
+ Return True whenever we want no other event listeners to be called.
+
+ """
+ keyval = event.keyval
+ state = event.state & gtk.accelerator_get_default_mod_mask()
+ ctrl = event.state & gtk.gdk.CONTROL_MASK
+
+ # Select new row with arrow up/down is pressed
+ if key_is_up_or_down(keyval):
+ self.handle_list_scroll(next=key_is_down(keyval),
+ set_entry=True)
+ return True
+ elif self.auto_completer.is_auto_completion_accelerator(keyval, state):
+ if self.auto_completer.auto_complete_enabled:
+ self.auto_completer.do_completion()
+ return True
+ # Show popup when Enter is pressed
+ elif key_is_enter(keyval):
+ # This sets the toggle active which results in
+ # on_button_toggle_dropdown_toggled being called which initiates the popup
+ self.button_toggle.set_active(True)
+ return True
+ elif ctrl:
+ # Swap the show hidden files value on CTRL-h
+ if is_ascii_value(keyval, 'h'):
+ # Set show/hide hidden files
+ self.set_show_hidden_files(not self.get_show_hidden_files(), emit_event=True)
+ return True
+ elif is_ascii_value(keyval, 's'):
+ super(PathChooserComboBox, self).add_current_value_to_saved_list()
+ return True
+ elif is_ascii_value(keyval, 'd'):
+ # Set the default value in the text entry
+ self.set_text(self.default_text)
+ return True
+ return False
+
+
+ def _on_button_toggle_dropdown_toggled(self, button):
+ """
+ Shows the popup when clicking the toggle button.
+ """
+ if self._stored_values_popping_down:
+ return
+ self.popup()
+
+ def _on_stored_values_popup_window_hide(self, popup):
+ """Make sure the button toggle is removed when popup is closed"""
+ self._stored_values_popping_down = True
+ self.button_toggle.set_active(False)
+ self._stored_values_popping_down = False
+
+######################################
+## Config dialog
+######################################
+
+ def _on_button_toggle_dropdown_button_press_event(self, widget, event):
+ """Show config when right clicking dropdown toggle button"""
+ if not self.properties_enabled:
+ return False
+ # This is right click
+ if event.button == 3:
+ self._on_button_properties_clicked(widget)
+ return True
+
+ def _on_button_properties_clicked(self, widget):
+ self.popdown()
+ self.enable_completion.set_active(self.get_auto_complete_enabled())
+ # Set the value of the label to the current accelerator
+ keyval, mask = gtk.accelerator_parse(self.auto_completer.accelerator_string)
+ self.accelerator_label.set_text(gtk.accelerator_get_label(keyval, mask))
+ self.visible_rows.set_value(self.get_max_popup_rows())
+ self.show_filechooser_checkbutton.set_active(self.get_filechooser_button_visible())
+ self.show_path_entry_checkbutton.set_active(self.path_entry_visible)
+ self.show_hidden_files_checkbutton.set_active(self.get_show_hidden_files())
+ self.show_folder_name_on_button_checkbutton.set_active(self.get_show_folder_name_on_button())
+ self._set_properties_widgets_sensitive(True)
+ self.config_dialog.show_all()
+
+ def _set_properties_widgets_sensitive(self, val):
+ self.enable_completion.set_sensitive(val)
+ self.config_short_cuts_frame.set_sensitive(val)
+ self.config_general_frame.set_sensitive(val)
+ self.show_hidden_files_checkbutton.set_sensitive(val)
+
+ def _setup_config_dialog(self):
+ self.config_dialog = self.builder.get_object("completion_config_dialog")
+ close_button = self.builder.get_object("config_dialog_button_close")
+ self.enable_completion = self.builder.get_object("enable_auto_completion_checkbutton")
+ self.show_filechooser_checkbutton = self.builder.get_object("show_filechooser_checkbutton")
+ self.show_path_entry_checkbutton = self.builder.get_object("show_path_entry_checkbutton")
+ set_key_button = self.builder.get_object("set_completion_accelerator_button")
+ default_set_accelerator_tooltip = set_key_button.get_tooltip_text()
+ self.config_short_cuts_frame = self.builder.get_object("config_short_cuts_frame")
+ self.config_general_frame = self.builder.get_object("config_general_frame")
+ self.accelerator_label = self.builder.get_object("completion_accelerator_label")
+ self.visible_rows = self.builder.get_object("visible_rows_spinbutton")
+ self.visible_rows_label = self.builder.get_object("visible_rows_label")
+ self.show_hidden_files_checkbutton = self.builder.get_object("show_hidden_files_checkbutton")
+ self.show_folder_name_on_button_checkbutton = self.builder.get_object("show_folder_name_on_button_checkbutton")
+ self.config_dialog.set_transient_for(self.popup_window)
+
+ def on_close(widget, event=None):
+ if not self.setting_accelerator_key:
+ self.config_dialog.hide()
+ else:
+ stop_setting_accelerator()
+ return True
+
+ def on_enable_completion_toggled(widget):
+ self.set_auto_complete_enabled(self.enable_completion.get_active())
+ self.emit("auto-complete-enabled-toggled", self.enable_completion.get_active())
+
+ def on_show_filechooser_toggled(widget):
+ self.set_filechooser_button_visible(self.show_filechooser_checkbutton.get_active())
+ self.emit("show-filechooser-toggled", self.show_filechooser_checkbutton.get_active())
+ self.show_folder_name_on_button_checkbutton.set_sensitive(self.show_path_entry_checkbutton.get_active() and
+ self.show_filechooser_checkbutton.get_active())
+ if not self.filechooser_visible and not self.path_entry_visible:
+ self.show_path_entry_checkbutton.set_active(True)
+ on_show_path_entry_toggled(None)
+
+ def on_show_path_entry_toggled(widget):
+ self.set_path_entry_visible(self.show_path_entry_checkbutton.get_active())
+ self.emit("show-path-entry-toggled", self.show_path_entry_checkbutton.get_active())
+ self.show_folder_name_on_button_checkbutton.set_sensitive(self.show_path_entry_checkbutton.get_active() and
+ self.show_filechooser_checkbutton.get_active())
+ if not self.filechooser_visible and not self.path_entry_visible:
+ self.show_filechooser_checkbutton.set_active(True)
+ on_show_filechooser_toggled(None)
+
+ def on_show_folder_name_on_button(widget):
+ self.set_show_folder_name_on_button(self.show_folder_name_on_button_checkbutton.get_active())
+ self._set_path_entry_filechooser_widths()
+ self.emit("show-folder-name-on-button", self.show_folder_name_on_button_checkbutton.get_active())
+
+ def on_show_hidden_files_toggled(widget):
+ self.set_show_hidden_files(self.show_hidden_files_checkbutton.get_active(), emit_event=True)
+
+ def on_max_rows_changed(widget):
+ self.set_max_popup_rows(self.visible_rows.get_value_as_int())
+ self.emit("max-rows-changed", self.visible_rows.get_value_as_int())
+
+ def set_accelerator(widget):
+ self.setting_accelerator_key = True
+ self.tooltips.set_tip(set_key_button, "Press the accelerator keys for triggering auto-completion")
+ self._set_properties_widgets_sensitive(False)
+ return True
+
+ def stop_setting_accelerator():
+ self.setting_accelerator_key = False
+ self._set_properties_widgets_sensitive(True)
+ set_key_button.set_active(False)
+ # Restore default tooltip
+ self.tooltips.set_tip(set_key_button, default_set_accelerator_tooltip)
+
+ def on_completion_config_dialog_key_release_event(widget, event):
+ # We are listening for a new key
+ if set_key_button.get_active():
+ state = event.state & gtk.accelerator_get_default_mod_mask()
+ accelerator_mask = state.numerator
+ # If e.g. only CTRL key is pressed.
+ if not gtk.accelerator_valid(event.keyval, accelerator_mask):
+ accelerator_mask = 0
+ self.auto_completer.accelerator_string = gtk.accelerator_name(event.keyval, accelerator_mask)
+ self.accelerator_label.set_text(gtk.accelerator_get_label(event.keyval, accelerator_mask))
+ self.emit("accelerator-set", self.auto_completer.accelerator_string)
+ stop_setting_accelerator()
+ return True
+ else:
+ keyval = event.keyval
+ ctrl = event.state & gtk.gdk.CONTROL_MASK
+ if ctrl:
+ # Set show/hide hidden files
+ if is_ascii_value(keyval, 'h'):
+ self.show_hidden_files_checkbutton.set_active(not self.get_show_hidden_files())
+ return True
+
+ def on_set_completion_accelerator_button_clicked(widget):
+ if not set_key_button.get_active():
+ stop_setting_accelerator()
+ return True
+
+ self.config_dialog_signal_handlers = {
+ "on_enable_auto_completion_checkbutton_toggled": on_enable_completion_toggled,
+ "on_show_filechooser_checkbutton_toggled": on_show_filechooser_toggled,
+ "on_show_path_entry_checkbutton_toggled": on_show_path_entry_toggled,
+ "on_show_folder_name_on_button_checkbutton_toggled": on_show_folder_name_on_button,
+ "on_config_dialog_button_close_clicked": on_close,
+ "on_visible_rows_spinbutton_value_changed": on_max_rows_changed,
+ "on_completion_config_dialog_delete_event": on_close,
+ "on_set_completion_accelerator_button_pressed": set_accelerator,
+ "on_completion_config_dialog_key_release_event": on_completion_config_dialog_key_release_event,
+ "on_set_completion_accelerator_button_clicked": on_set_completion_accelerator_button_clicked,
+ "on_show_hidden_files_checkbutton_toggled": on_show_hidden_files_toggled,
+ }
+
+gobject.type_register(PathChooserComboBox)
+
+if __name__ == "__main__":
+ import sys
+ w = gtk.Window()
+ w.set_position(gtk.WIN_POS_CENTER)
+ w.set_size_request(600, -1)
+ w.set_title('ComboEntry example')
+ w.connect('delete-event', gtk.main_quit)
+
+ box1 = gtk.VBox(gtk.FALSE, 0)
+
+ def get_resource2(filename):
+ return "%s/glade/%s" % (os.path.abspath(os.path.dirname(sys.argv[0])), filename)
+
+ # Override get_resource which fetches from deluge install
+ get_resource = get_resource2
+
+ entry1 = PathChooserComboBox(max_visible_rows=15)
+ entry2 = PathChooserComboBox()
+
+ box1.add(entry1)
+ box1.add(entry2)
+
+ paths = [
+ "/home/bro/Downloads",
+ "/media/Movies-HD",
+ "/media/torrent/in",
+ "/media/Live-show/Misc",
+ "/media/Live-show/Consert",
+ "/media/Series/1/",
+ "/media/Series/2",
+ "/media/Series/17",
+ "/media/Series/18",
+ "/media/Series/19"
+ ]
+
+ entry1.add_values(paths)
+ entry1.set_text("/home/bro/", default_text=True)
+ entry2.set_text("/home/bro/programmer/deluge/deluge-yarss-plugin/build/lib/yarss2/include/bs4/tests/", cursor_end=False)
+
+ entry2.set_filechooser_button_visible(False)
+ #entry2.set_enable_properties(False)
+ entry2.set_filechooser_button_enabled(False)
+
+ def list_value_added_event(widget, values):
+ print "Current list values:", widget.get_values()
+
+ entry1.connect("list-value-added", list_value_added_event)
+ entry2.connect("list-value-added", list_value_added_event)
+ w.add(box1)
+ w.show_all()
+ gtk.main()
diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py
index e217f3925..b546b6fc3 100644
--- a/deluge/ui/gtkui/preferences.py
+++ b/deluge/ui/gtkui/preferences.py
@@ -42,6 +42,7 @@ import logging
import deluge.component as component
from deluge.ui.client import client
+from deluge.ui.gtkui.path_chooser import PathChooser
import deluge.common
import common
import dialogs
@@ -74,6 +75,7 @@ class Preferences(component.Component):
self.treeview = self.builder.get_object("treeview")
self.notebook = self.builder.get_object("notebook")
self.gtkui_config = ConfigManager("gtkui.conf")
+ self.window_open = False
self.load_pref_dialog_state()
@@ -190,6 +192,24 @@ class Preferences(component.Component):
self.all_plugins = []
self.enabled_plugins = []
+ self.setup_path_choosers()
+
+ def setup_path_choosers(self):
+ self.download_location_hbox = self.builder.get_object("hbox_download_to_path_chooser")
+ self.download_location_path_chooser = PathChooser("download_location_paths_list")
+ self.download_location_hbox.add(self.download_location_path_chooser)
+ self.download_location_hbox.show_all()
+
+ self.move_completed_hbox = self.builder.get_object("hbox_move_completed_to_path_chooser")
+ self.move_completed_path_chooser = PathChooser("move_completed_paths_list")
+ self.move_completed_hbox.add(self.move_completed_path_chooser)
+ self.move_completed_hbox.show_all()
+
+ self.copy_torrents_to_hbox = self.builder.get_object("hbox_copy_torrent_files_path_chooser")
+ self.copy_torrent_files_path_chooser = PathChooser("copy_torrent_files_to_paths_list")
+ self.copy_torrents_to_hbox.add(self.copy_torrent_files_path_chooser)
+ self.copy_torrents_to_hbox.show_all()
+
def __del__(self):
del self.gtkui_config
@@ -252,6 +272,7 @@ class Preferences(component.Component):
def show(self, page=None):
"""Page should be the string in the left list.. ie, 'Network' or
'Bandwidth'"""
+ self.window_open = True
if page != None:
for (index, string) in self.liststore:
if page == string:
@@ -260,7 +281,6 @@ class Preferences(component.Component):
component.get("PluginManager").run_on_show_prefs()
-
# Update the preferences dialog to reflect current config settings
self.core_config = {}
if client.connected():
@@ -291,253 +311,146 @@ class Preferences(component.Component):
else:
self._show()
- def _show(self):
- if self.core_config != {} and self.core_config != None:
- core_widgets = {
- "download_path_button": \
- ("filename", self.core_config["download_location"]),
- "chk_move_completed": \
- ("active", self.core_config["move_completed"]),
- "move_completed_path_button": \
- ("filename", self.core_config["move_completed_path"]),
- "chk_copy_torrent_file": \
- ("active", self.core_config["copy_torrent_file"]),
- "chk_del_copy_torrent_file": \
- ("active", self.core_config["del_copy_torrent_file"]),
- "torrent_files_button": \
- ("filename", self.core_config["torrentfiles_location"]),
- "radio_compact_allocation": \
- ("active", self.core_config["compact_allocation"]),
- "radio_full_allocation": \
- ("not_active", self.core_config["compact_allocation"]),
- "chk_prioritize_first_last_pieces": \
- ("active",
- self.core_config["prioritize_first_last_pieces"]),
- "chk_sequential_download": \
- ("active",
- self.core_config["sequential_download"]),
- "chk_add_paused": ("active", self.core_config["add_paused"]),
- "spin_port_min": ("value", self.core_config["listen_ports"][0]),
- "spin_port_max": ("value", self.core_config["listen_ports"][1]),
- "active_port_label": ("text", str(self.active_port)),
- "chk_random_port": ("active", self.core_config["random_port"]),
- "spin_outgoing_port_min": ("value", self.core_config["outgoing_ports"][0]),
- "spin_outgoing_port_max": ("value", self.core_config["outgoing_ports"][1]),
- "chk_random_outgoing_ports": ("active", self.core_config["random_outgoing_ports"]),
- "entry_interface": ("text", self.core_config["listen_interface"]),
- "entry_peer_tos": ("text", self.core_config["peer_tos"]),
- "chk_dht": ("active", self.core_config["dht"]),
- "chk_upnp": ("active", self.core_config["upnp"]),
- "chk_natpmp": ("active", self.core_config["natpmp"]),
- "chk_utpex": ("active", self.core_config["utpex"]),
- "chk_lt_tex": ("active", self.core_config["lt_tex"]),
- "chk_lsd": ("active", self.core_config["lsd"]),
- "chk_new_releases": ("active", self.core_config["new_release_check"]),
- "chk_send_info": ("active", self.core_config["send_info"]),
- "entry_geoip": ("text", self.core_config["geoip_db_location"]),
- "combo_encin": ("active", self.core_config["enc_in_policy"]),
- "combo_encout": ("active", self.core_config["enc_out_policy"]),
- "combo_enclevel": ("active", self.core_config["enc_level"]),
- "spin_max_connections_global": \
- ("value", self.core_config["max_connections_global"]),
- "spin_max_download": \
- ("value", self.core_config["max_download_speed"]),
- "spin_max_upload": \
- ("value", self.core_config["max_upload_speed"]),
- "spin_max_upload_slots_global": \
- ("value", self.core_config["max_upload_slots_global"]),
- "spin_max_half_open_connections": \
- ("value", self.core_config["max_half_open_connections"]),
- "spin_max_connections_per_second": \
- ("value", self.core_config["max_connections_per_second"]),
- "chk_ignore_limits_on_local_network": \
- ("active", self.core_config["ignore_limits_on_local_network"]),
- "chk_rate_limit_ip_overhead": \
- ("active", self.core_config["rate_limit_ip_overhead"]),
- "spin_max_connections_per_torrent": \
- ("value", self.core_config["max_connections_per_torrent"]),
- "spin_max_upload_slots_per_torrent": \
- ("value", self.core_config["max_upload_slots_per_torrent"]),
- "spin_max_download_per_torrent": \
- ("value", self.core_config["max_download_speed_per_torrent"]),
- "spin_max_upload_per_torrent": \
- ("value", self.core_config["max_upload_speed_per_torrent"]),
- "spin_daemon_port": \
- ("value", self.core_config["daemon_port"]),
- "chk_allow_remote_connections": \
- ("active", self.core_config["allow_remote"]),
- "spin_active": ("value", self.core_config["max_active_limit"]),
- "spin_seeding": ("value", self.core_config["max_active_seeding"]),
- "spin_downloading": ("value", self.core_config["max_active_downloading"]),
- "chk_dont_count_slow_torrents": ("active", self.core_config["dont_count_slow_torrents"]),
- "chk_auto_manage_prefer_seeds": ("active", self.core_config["auto_manage_prefer_seeds"]),
- "chk_queue_new_top": ("active", self.core_config["queue_new_to_top"]),
- "spin_share_ratio_limit": ("value", self.core_config["share_ratio_limit"]),
- "spin_seed_time_ratio_limit": \
- ("value", self.core_config["seed_time_ratio_limit"]),
- "spin_seed_time_limit": ("value", self.core_config["seed_time_limit"]),
- "chk_seed_ratio": ("active", self.core_config["stop_seed_at_ratio"]),
- "spin_share_ratio": ("value", self.core_config["stop_seed_ratio"]),
- "chk_remove_ratio": ("active", self.core_config["remove_seed_at_ratio"]),
- "spin_cache_size": ("value", self.core_config["cache_size"]),
- "spin_cache_expiry": ("value", self.core_config["cache_expiry"])
- }
- # Add proxy stuff
- for t in ("peer", "web_seed", "tracker", "dht"):
- core_widgets["spin_proxy_port_%s" % t] = (
- "value", self.core_config["proxies"][t]["port"]
- )
- core_widgets["combo_proxy_type_%s" % t] = (
- "active", self.core_config["proxies"][t]["type"]
- )
- core_widgets["txt_proxy_server_%s" % t] = (
- "text", self.core_config["proxies"][t]["hostname"]
- )
- core_widgets["txt_proxy_username_%s" % t] = (
- "text", self.core_config["proxies"][t]["username"]
- )
- core_widgets["txt_proxy_password_%s" % t] = (
- "text", self.core_config["proxies"][t]["password"]
- )
+ def start(self):
+ if self.window_open:
+ self.show()
- # Change a few widgets if we're connected to a remote host
- if not client.is_localhost():
- self.builder.get_object("entry_download_path").show()
- self.builder.get_object("download_path_button").hide()
- core_widgets.pop("download_path_button")
- core_widgets["entry_download_path"] = (
- "text", self.core_config["download_location"]
- )
+ def stop(self):
+ self.core_config = None
+ if self.window_open:
+ self._show()
- self.builder.get_object("entry_move_completed_path").show()
- self.builder.get_object("move_completed_path_button").hide()
- core_widgets.pop("move_completed_path_button")
- core_widgets["entry_move_completed_path"] = (
- "text", self.core_config["move_completed_path"]
- )
+ def _show(self):
+ self.is_connected = self.core_config != {} and self.core_config != None
+ core_widgets = {
+ "chk_move_completed": ("active", "move_completed"),
+ "chk_copy_torrent_file": ("active", "copy_torrent_file"),
+ "chk_del_copy_torrent_file": ("active", "del_copy_torrent_file"),
+ "radio_compact_allocation": ("active", "compact_allocation"),
+ "radio_full_allocation": ("not_active", "compact_allocation"),
+ "chk_prioritize_first_last_pieces": ("active", "prioritize_first_last_pieces"),
+ "chk_sequential_download": ("active", "sequential_download"),
+ "chk_add_paused": ("active", "add_paused"),
+ "active_port_label": ("text", lambda: str(self.active_port)),
+ "spin_port_min": ("value", lambda: self.core_config["listen_ports"][0]),
+ "spin_port_max": ("value", lambda: self.core_config["listen_ports"][1]),
+ "chk_random_port": ("active", "random_port"),
+ "spin_outgoing_port_min": ("value", lambda: self.core_config["outgoing_ports"][0]),
+ "spin_outgoing_port_max": ("value", lambda: self.core_config["outgoing_ports"][1]),
+ "chk_random_outgoing_ports": ("active", "random_outgoing_ports"),
+ "entry_interface": ("text", "listen_interface"),
+ "entry_peer_tos": ("text", "peer_tos"),
+ "chk_dht": ("active", "dht"),
+ "chk_upnp": ("active", "upnp"),
+ "chk_natpmp": ("active", "natpmp"),
+ "chk_utpex": ("active", "utpex"),
+ "chk_lt_tex": ("active", "lt_tex"),
+ "chk_lsd": ("active", "lsd"),
+ "chk_new_releases": ("active", "new_release_check"),
+ "chk_send_info": ("active", "send_info"),
+ "entry_geoip": ("text", "geoip_db_location"),
+ "combo_encin": ("active", "enc_in_policy"),
+ "combo_encout": ("active", "enc_out_policy"),
+ "combo_enclevel": ("active", "enc_level"),
+ "spin_max_connections_global": ("value", "max_connections_global"),
+ "spin_max_download": ("value", "max_download_speed"),
+ "spin_max_upload": ("value", "max_upload_speed"),
+ "spin_max_upload_slots_global": ("value", "max_upload_slots_global"),
+ "spin_max_half_open_connections": ("value", "max_connections_per_second"),
+ "spin_max_connections_per_second": ("value", "max_connections_per_second"),
+ "chk_ignore_limits_on_local_network": ("active", "ignore_limits_on_local_network"),
+ "chk_rate_limit_ip_overhead": ("active", "rate_limit_ip_overhead"),
+ "spin_max_connections_per_torrent": ("value", "max_connections_per_torrent"),
+ "spin_max_upload_slots_per_torrent": ("value", "max_upload_slots_per_torrent"),
+ "spin_max_download_per_torrent": ("value", "max_download_speed_per_torrent"),
+ "spin_max_upload_per_torrent": ("value", "max_upload_speed_per_torrent"),
+ "spin_daemon_port": ("value", "daemon_port"),
+ "chk_allow_remote_connections": ("active", "allow_remote"),
+ "spin_active": ("value", "max_active_limit"),
+ "spin_seeding": ("value", "max_active_seeding"),
+ "spin_downloading": ("value", "max_active_downloading"),
+ "chk_dont_count_slow_torrents": ("active", "dont_count_slow_torrents"),
+ "chk_auto_manage_prefer_seeds": ("active", "auto_manage_prefer_seeds"),
+ "chk_queue_new_top": ("active", "queue_new_to_top"),
+ "spin_share_ratio_limit": ("value", "share_ratio_limit"),
+ "spin_seed_time_ratio_limit": ("value", "seed_time_ratio_limit"),
+ "spin_seed_time_limit": ("value", "seed_time_limit"),
+ "chk_seed_ratio": ("active", "stop_seed_at_ratio"),
+ "spin_share_ratio": ("value", "stop_seed_ratio"),
+ "chk_remove_ratio": ("active", "remove_seed_at_ratio"),
+ "spin_cache_size": ("value", "cache_size"),
+ "spin_cache_expiry": ("value", "cache_expiry"),
+ "accounts_add": (None, None),
+ "accounts_listview": (None, None),
+ "button_cache_refresh": (None, None),
+ "button_plugin_install": (None, None),
+ "button_rescan_plugins": (None, None),
+ "button_find_plugins": (None, None),
+ "button_testport": (None, None),
+ "plugin_listview": (None, None),
+ }
+
+ # Add proxy stuff
+ for t in ("peer", "web_seed", "tracker", "dht"):
+ core_widgets["spin_proxy_port_%s" % t] = (
+ "value", lambda: self.core_config["proxies"][t]["port"]
+ )
+ core_widgets["combo_proxy_type_%s" % t] = (
+ "active", lambda: self.core_config["proxies"][t]["type"]
+ )
+ core_widgets["txt_proxy_server_%s" % t] = (
+ "text", lambda: self.core_config["proxies"][t]["hostname"]
+ )
+ core_widgets["txt_proxy_username_%s" % t] = (
+ "text", lambda: self.core_config["proxies"][t]["username"]
+ )
+ core_widgets["txt_proxy_password_%s" % t] = (
+ "text", lambda: self.core_config["proxies"][t]["password"]
+ )
- self.builder.get_object("entry_torrents_path").show()
- self.builder.get_object("torrent_files_button").hide()
- core_widgets.pop("torrent_files_button")
- core_widgets["entry_torrents_path"] = (
- "text", self.core_config["torrentfiles_location"]
- )
- else:
- self.builder.get_object("entry_download_path").hide()
- self.builder.get_object("download_path_button").show()
- self.builder.get_object("entry_move_completed_path").hide()
- self.builder.get_object("move_completed_path_button").show()
- self.builder.get_object("entry_torrents_path").hide()
- self.builder.get_object("torrent_files_button").show()
-
- # Update the widgets accordingly
- for key in core_widgets.keys():
- modifier = core_widgets[key][0]
- value = core_widgets[key][1]
+ core_widgets[self.download_location_path_chooser] = ("path_chooser", "download_location")
+ core_widgets[self.move_completed_path_chooser] = ("path_chooser", "move_completed_path")
+ core_widgets[self.copy_torrent_files_path_chooser] = ("path_chooser", "torrentfiles_location")
+
+ # Update the widgets accordingly
+ for key in core_widgets.keys():
+ modifier = core_widgets[key][0]
+ if type(key) is str:
widget = self.builder.get_object(key)
- if type(widget) == gtk.FileChooserButton:
- for child in widget.get_children():
- child.set_sensitive(True)
- widget.set_sensitive(True)
-
- if modifier == "filename":
- if value:
- try:
- widget.set_current_folder(value)
- except Exception, e:
- log.debug("Unable to set_current_folder: %s", e)
- elif modifier == "active":
- widget.set_active(value)
- elif modifier == "not_active":
- widget.set_active(not value)
- elif modifier == "value":
- widget.set_value(float(value))
- elif modifier == "text":
- widget.set_text(value)
+ else:
+ widget = key
+
+ widget.set_sensitive(self.is_connected)
+ if self.is_connected:
+ value = core_widgets[key][1]
+ from types import FunctionType
+ if type(value) is FunctionType:
+ value = value()
+ elif type(value) is str:
+ value = self.core_config[value]
+ elif modifier:
+ value = {"active": False, "not_active": False, "value": 0, "text": "", "path_chooser": "" }[modifier]
+
+ if modifier == "active":
+ widget.set_active(value)
+ elif modifier == "not_active":
+ widget.set_active(not value)
+ elif modifier == "value":
+ widget.set_value(float(value))
+ elif modifier == "text":
+ widget.set_text(value)
+ elif modifier == "path_chooser":
+ widget.set_text(value, cursor_end=False, default_text=True)
+
+ if self.is_connected:
for key in core_widgets.keys():
- widget = self.builder.get_object(key)
+ if type(key) is str:
+ widget = self.builder.get_object(key)
+ else:
+ widget = key
# Update the toggle status if necessary
self.on_toggle(widget)
- else:
- core_widget_list = [
- "download_path_button",
- "chk_move_completed",
- "move_completed_path_button",
- "chk_copy_torrent_file",
- "chk_del_copy_torrent_file",
- "torrent_files_button",
- "radio_compact_allocation",
- "radio_full_allocation",
- "chk_prioritize_first_last_pieces",
- "chk_sequential_download",
- "chk_add_paused",
- "spin_port_min",
- "spin_port_max",
- "active_port_label",
- "chk_random_port",
- "spin_outgoing_port_min",
- "spin_outgoing_port_max",
- "chk_random_outgoing_ports",
- "entry_interface",
- "entry_peer_tos",
- "chk_dht",
- "chk_upnp",
- "chk_natpmp",
- "chk_utpex",
- "chk_lt_tex",
- "chk_lsd",
- "chk_send_info",
- "chk_new_releases",
- "entry_geoip",
- "combo_encin",
- "combo_encout",
- "combo_enclevel",
- "spin_max_connections_global",
- "spin_max_download",
- "spin_max_upload",
- "spin_max_upload_slots_global",
- "spin_max_half_open_connections",
- "spin_max_connections_per_second",
- "chk_ignore_limits_on_local_network",
- "chk_rate_limit_ip_overhead",
- "spin_max_connections_per_torrent",
- "spin_max_upload_slots_per_torrent",
- "spin_max_download_per_torrent",
- "spin_max_upload_per_torrent",
- "spin_daemon_port",
- "chk_allow_remote_connections",
- "spin_seeding",
- "spin_downloading",
- "spin_active",
- "chk_dont_count_slow_torrents",
- "chk_auto_manage_prefer_seeds",
- "chk_queue_new_top",
- "chk_seed_ratio",
- "spin_share_ratio",
- "chk_remove_ratio",
- "spin_share_ratio_limit",
- "spin_seed_time_ratio_limit",
- "spin_seed_time_limit",
- "spin_cache_size",
- "spin_cache_expiry",
- "button_cache_refresh",
- "btn_testport"
- ]
- for t in ("peer", "web_seed", "tracker", "dht"):
- core_widget_list.append("spin_proxy_port_%s" % t)
- core_widget_list.append("combo_proxy_type_%s" % t)
- core_widget_list.append("txt_proxy_username_%s" % t)
- core_widget_list.append("txt_proxy_password_%s" % t)
- core_widget_list.append("txt_proxy_server_%s" % t)
-
- # We don't appear to be connected to a daemon
- for key in core_widget_list:
- widget = self.builder.get_object(key)
- if type(widget) == gtk.FileChooserButton:
- for child in widget.get_children():
- child.set_sensitive(False)
- widget.set_sensitive(False)
## Downloads tab ##
self.builder.get_object("chk_show_dialog").set_active(
@@ -576,7 +489,6 @@ class Preferences(component.Component):
self.builder.get_object("chk_show_new_releases").set_active(
self.gtkui_config["show_new_releases"])
-
## Cache tab ##
if client.connected():
self.__update_cache_status()
@@ -636,20 +548,10 @@ class Preferences(component.Component):
self.builder.get_object("chk_del_copy_torrent_file").get_active()
new_core_config["move_completed"] = \
self.builder.get_object("chk_move_completed").get_active()
- if client.is_localhost():
- new_core_config["download_location"] = \
- self.builder.get_object("download_path_button").get_filename()
- new_core_config["move_completed_path"] = \
- self.builder.get_object("move_completed_path_button").get_filename()
- new_core_config["torrentfiles_location"] = \
- self.builder.get_object("torrent_files_button").get_filename()
- else:
- new_core_config["download_location"] = \
- self.builder.get_object("entry_download_path").get_text()
- new_core_config["move_completed_path"] = \
- self.builder.get_object("entry_move_completed_path").get_text()
- new_core_config["torrentfiles_location"] = \
- self.builder.get_object("entry_torrents_path").get_text()
+
+ new_core_config["download_location"] = self.download_location_path_chooser.get_text()
+ new_core_config["move_completed_path"] = self.move_completed_path_chooser.get_text()
+ new_core_config["torrentfiles_location"] = self.copy_torrent_files_path_chooser.get_text()
new_core_config["compact_allocation"] = \
self.builder.get_object("radio_compact_allocation").get_active()
@@ -872,6 +774,7 @@ class Preferences(component.Component):
dialog.run()
def hide(self):
+ self.window_open = False
self.builder.get_object("port_img").hide()
self.pref_dialog.hide()
@@ -918,6 +821,11 @@ class Preferences(component.Component):
except:
return
+ path_choosers = {"download_location_path_chooser": self.download_location_path_chooser,
+ "move_completed_path_chooser": self.move_completed_path_chooser,
+ "torrentfiles_location_path_chooser": self.copy_torrent_files_path_chooser
+ }
+
dependents = {
"chk_show_dialog": {"chk_focus_dialog": True},
"chk_random_port": {"spin_port_min": False,
@@ -932,8 +840,8 @@ class Preferences(component.Component):
"password_label": True},
"radio_open_folder_custom": {"combo_file_manager": False,
"txt_open_folder_location": True},
- "chk_move_completed" : {"move_completed_path_button" : True},
- "chk_copy_torrent_file" : {"torrent_files_button" : True,
+ "chk_move_completed" : {"move_completed_path_chooser" : True},
+ "chk_copy_torrent_file" : {"torrentfiles_location_path_chooser" : True,
"chk_del_copy_torrent_file" : True},
"chk_seed_ratio" : {"spin_share_ratio": True,
"chk_remove_ratio" : True}
@@ -942,9 +850,12 @@ class Preferences(component.Component):
def update_dependent_widgets(name, value):
dependency = dependents[name]
for dep in dependency.keys():
- depwidget = self.builder.get_object(dep)
+ if dep in path_choosers:
+ depwidget = path_choosers[dep]
+ else:
+ depwidget = self.builder.get_object(dep)
sensitive = [not value, value][dependency[dep]]
- depwidget.set_sensitive(sensitive)
+ depwidget.set_sensitive(sensitive and self.is_connected)
if dep in dependents:
update_dependent_widgets(dep, depwidget.get_active() and sensitive)
@@ -1085,7 +996,7 @@ class Preferences(component.Component):
# If incoming and outgoing both set to disabled, disable level combobox
if combo_encin == 2 and combo_encout == 2:
combo_enclevel.set_sensitive(False)
- else:
+ elif self.is_connected:
combo_enclevel.set_sensitive(True)
def _on_combo_proxy_type_changed(self, widget):