The GtkUi's connection manager now has the ability to edit existing host entries besides adding and deleting them.
It also asks for a password prior to attemting to connect in case the password is null, this alows host entries not to store the passwords on file like it has done so far. NOTE: This is not yet the desired behaviour, ie, the daemon should simply complain if the authentication details are incomplete and the client should act accordingly. I had an issue with this though, I catched the errback the daemon was sending, asked the user for the password and re-tried to authenticate again. However, twisted always locked when I tried this. I'm investigating it.
This commit is contained in:
parent
1794f09b21
commit
6c99204828
|
@ -54,6 +54,9 @@ AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL
|
|||
class BadLoginError(deluge.error.DelugeError):
|
||||
pass
|
||||
|
||||
class PasswordRequired(BadLoginError):
|
||||
pass
|
||||
|
||||
class AuthManager(component.Component):
|
||||
def __init__(self):
|
||||
component.Component.__init__(self, "AuthManager")
|
||||
|
@ -68,6 +71,16 @@ class AuthManager(component.Component):
|
|||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def peek(self, username):
|
||||
if username not in self.__auth:
|
||||
# Let's try to re-load the file.. Maybe it's been updated
|
||||
self.__load_auth_file()
|
||||
if username not in self.__auth:
|
||||
raise BadLoginError("Username does not exist")
|
||||
|
||||
return int(self.__auth[username][1])
|
||||
|
||||
|
||||
def authorize(self, username, password):
|
||||
"""
|
||||
Authorizes users based on username and password
|
||||
|
@ -80,16 +93,12 @@ class AuthManager(component.Component):
|
|||
:raises BadLoginError: if the username does not exist or password does not match
|
||||
|
||||
"""
|
||||
|
||||
if username not in self.__auth:
|
||||
# Let's try to re-load the file.. Maybe it's been updated
|
||||
self.__load_auth_file()
|
||||
if username not in self.__auth:
|
||||
raise BadLoginError("Username does not exist")
|
||||
|
||||
auth_level = self.peek(username)
|
||||
if self.__auth[username][0] == password:
|
||||
# Return the users auth level
|
||||
return int(self.__auth[username][1])
|
||||
return auth_level
|
||||
elif not password and self.__auth[username][0]:
|
||||
raise PasswordRequired("Password is required")
|
||||
else:
|
||||
raise BadLoginError("Password does not match")
|
||||
|
||||
|
|
|
@ -253,9 +253,25 @@ class DelugeRPCProtocol(Protocol):
|
|||
"".join(traceback.format_tb(exceptionTraceback)))
|
||||
))
|
||||
|
||||
if method == "daemon.login":
|
||||
if method == "daemon.peek":
|
||||
try:
|
||||
ret = component.get("AuthManager").peek(*args, **kwargs)
|
||||
if ret:
|
||||
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
||||
self.factory.session_protocols[self.transport.sessionno] = self
|
||||
except Exception, e:
|
||||
sendError()
|
||||
log.exception(e)
|
||||
else:
|
||||
self.sendData((RPC_RESPONSE, request_id, ret))
|
||||
if not ret:
|
||||
self.transport.loseConnection()
|
||||
finally:
|
||||
return
|
||||
elif method == "daemon.login":
|
||||
# This is a special case and used in the initial connection process
|
||||
# We need to authenticate the user here
|
||||
log.debug("RPC dispatch daemon.login")
|
||||
try:
|
||||
ret = component.get("AuthManager").authorize(*args, **kwargs)
|
||||
if ret:
|
||||
|
@ -271,6 +287,7 @@ class DelugeRPCProtocol(Protocol):
|
|||
finally:
|
||||
return
|
||||
elif method == "daemon.set_event_interest" and self.transport.sessionno in self.factory.authorized_sessions:
|
||||
log.debug("RPC dispatch daemon.set_event_interest")
|
||||
# This special case is to allow clients to set which events they are
|
||||
# interested in receiving.
|
||||
# We are expecting a sequence from the client.
|
||||
|
@ -286,6 +303,7 @@ class DelugeRPCProtocol(Protocol):
|
|||
return
|
||||
|
||||
if method in self.factory.methods and self.transport.sessionno in self.factory.authorized_sessions:
|
||||
log.debug("RPC dispatch %s", method)
|
||||
try:
|
||||
method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
|
||||
auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
|
||||
|
|
|
@ -261,6 +261,26 @@ class DaemonSSLProxy(DaemonProxy):
|
|||
self.disconnect_deferred = None
|
||||
self.disconnect_callback = None
|
||||
|
||||
def peek(self, host, port, username):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.__connector = reactor.connectSSL(self.host, self.port, self.__factory, ssl.ClientContextFactory())
|
||||
self.connect_deferred = defer.Deferred()
|
||||
self.peek_deferred = defer.Deferred()
|
||||
|
||||
def on_connect(result, username):
|
||||
self.__login_deferred = self.call("daemon.peek", username)
|
||||
self.__login_deferred.addCallback(self.__on_peek, username)
|
||||
self.__login_deferred.addErrback(self.__on_peek_fail)
|
||||
|
||||
def on_connect_fail(reason):
|
||||
log.debug("connect_fail: %s", reason)
|
||||
self.peek_deferred.errback(reason)
|
||||
|
||||
self.connect_deferred.addCallback(on_connect, username)
|
||||
self.connect_deferred.addErrback(on_connect_fail)
|
||||
return self.peek_deferred
|
||||
|
||||
def connect(self, host, port, username, password):
|
||||
"""
|
||||
Connects to a daemon at host:port
|
||||
|
@ -273,6 +293,7 @@ class DaemonSSLProxy(DaemonProxy):
|
|||
:returns: twisted.Deferred
|
||||
|
||||
"""
|
||||
log.debug("sslproxy.connect()")
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.__connector = reactor.connectSSL(self.host, self.port, self.__factory, ssl.ClientContextFactory())
|
||||
|
@ -286,6 +307,7 @@ class DaemonSSLProxy(DaemonProxy):
|
|||
return self.login_deferred
|
||||
|
||||
def disconnect(self):
|
||||
log.debug("sslproxy.disconnect()")
|
||||
self.disconnect_deferred = defer.Deferred()
|
||||
self.__connector.disconnect()
|
||||
return self.disconnect_deferred
|
||||
|
@ -397,15 +419,18 @@ class DaemonSSLProxy(DaemonProxy):
|
|||
return error_data
|
||||
|
||||
def __on_connect(self, result, username, password):
|
||||
log.debug("__on_connect called")
|
||||
self.__login_deferred = self.call("daemon.login", username, password)
|
||||
self.__login_deferred.addCallback(self.__on_login, username)
|
||||
self.__login_deferred.addErrback(self.__on_login_fail)
|
||||
|
||||
def __on_connect_fail(self, reason):
|
||||
log.debug("__on_connect_fail called")
|
||||
log.debug("connect_fail: %s", reason)
|
||||
self.login_deferred.errback(reason)
|
||||
|
||||
def __on_login(self, result, username):
|
||||
log.debug("__on_login called")
|
||||
self.username = username
|
||||
# We need to tell the daemon what events we're interested in receiving
|
||||
if self.__factory.event_handlers:
|
||||
|
@ -416,6 +441,15 @@ class DaemonSSLProxy(DaemonProxy):
|
|||
log.debug("_on_login_fail(): %s", result)
|
||||
self.login_deferred.errback(result)
|
||||
|
||||
def __on_peek(self, result, username):
|
||||
log.debug("__on_peek called. result: %s", result)
|
||||
self.username = username
|
||||
self.peek_deferred.callback(result)
|
||||
|
||||
def __on_peek_fail(self, result):
|
||||
log.debug("__on_peek_fail called. result: %s", result)
|
||||
self.peek_deferred.errback(result)
|
||||
|
||||
def set_disconnect_callback(self, cb):
|
||||
"""
|
||||
Set a function to be called when the connection to the daemon is lost
|
||||
|
@ -531,6 +565,7 @@ class Client(object):
|
|||
:returns: a Deferred object that will be called once the connection
|
||||
has been established or fails
|
||||
"""
|
||||
log.debug("real client connect")
|
||||
if not username and host in ("127.0.0.1", "localhost"):
|
||||
# No username was provided and it's the localhost, so we can try
|
||||
# to grab the credentials from the auth file.
|
||||
|
@ -548,6 +583,24 @@ class Client(object):
|
|||
d.addErrback(on_connect_fail)
|
||||
return d
|
||||
|
||||
def peek(self, host="127.0.0.1", port=58846, username=""):
|
||||
if not username and host in ("127.0.0.1", "localhost"):
|
||||
# No username was provided and it's the localhost, so we can try
|
||||
# to grab the credentials from the auth file.
|
||||
import common
|
||||
username, password = common.get_localhost_auth()
|
||||
|
||||
self._daemon_proxy = DaemonSSLProxy(dict(self.__event_handlers))
|
||||
self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
|
||||
d = self._daemon_proxy.peek(host, port, username)
|
||||
def on_connect_fail(result):
|
||||
log.debug("on_connect_fail: %s", result)
|
||||
self.disconnect()
|
||||
return result
|
||||
|
||||
d.addErrback(on_connect_fail)
|
||||
return d
|
||||
|
||||
def disconnect(self):
|
||||
"""
|
||||
Disconnects from the daemon.
|
||||
|
|
|
@ -133,6 +133,11 @@ class ConnectionManager(component.Component):
|
|||
|
||||
self.glade.get_widget("image1").set_from_pixbuf(common.get_logo(32))
|
||||
|
||||
self.askpassword_dialog = self.glade.get_widget("askpassword_dialog")
|
||||
self.askpassword_dialog.set_transient_for(self.connection_manager)
|
||||
self.askpassword_dialog.set_icon(common.get_deluge_icon())
|
||||
self.askpassword_dialog_entry = self.glade.get_widget("askpassword_dialog_entry")
|
||||
|
||||
self.hostlist = self.glade.get_widget("hostlist")
|
||||
|
||||
# Create status pixbufs
|
||||
|
@ -317,7 +322,7 @@ class ConnectionManager(component.Component):
|
|||
|
||||
# Create a new Client instance
|
||||
c = deluge.ui.client.Client()
|
||||
d = c.connect(host, port, user, password)
|
||||
d = c.peek(host, port, user)
|
||||
d.addCallback(on_connect, c, host_id)
|
||||
d.addErrback(on_connect_failed, host_id)
|
||||
|
||||
|
@ -352,8 +357,11 @@ class ConnectionManager(component.Component):
|
|||
|
||||
model, row = self.hostlist.get_selection().get_selected()
|
||||
if not row:
|
||||
self.glade.get_widget("button_edithost").set_sensitive(False)
|
||||
return
|
||||
|
||||
self.glade.get_widget("button_edithost").set_sensitive(True)
|
||||
|
||||
# Get some values about the selected host
|
||||
status = model[row][HOSTLIST_COL_STATUS]
|
||||
host = model[row][HOSTLIST_COL_HOST]
|
||||
|
@ -428,6 +436,7 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
|||
|
||||
# Signal handlers
|
||||
def __on_connected(self, connector, host_id):
|
||||
log.debug("__on_connected called")
|
||||
if self.gtkui_config["autoconnect"]:
|
||||
self.gtkui_config["autoconnect_host_id"] = host_id
|
||||
|
||||
|
@ -450,6 +459,10 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
|||
user = model[row][HOSTLIST_COL_USER]
|
||||
password = model[row][HOSTLIST_COL_PASS]
|
||||
|
||||
if not password:
|
||||
self.askpassword_dialog.run()
|
||||
password = self.askpassword_dialog_entry.get_text()
|
||||
|
||||
if status == _("Offline") and self.glade.get_widget("chk_autostart").get_active() and\
|
||||
host in ("127.0.0.1", "localhost"):
|
||||
# We need to start this localhost
|
||||
|
@ -475,7 +488,9 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
|||
|
||||
|
||||
def do_connect(*args):
|
||||
client.connect(host, port, user, password).addCallback(self.__on_connected, host_id)
|
||||
d = client.connect(host, port, user, password)
|
||||
d.addCallback(self.__on_connected, host_id)
|
||||
d.addErrback(self.__on_connected_failed, host_id, host, port, user)
|
||||
|
||||
if client.connected():
|
||||
client.disconnect().addCallback(do_connect)
|
||||
|
@ -496,6 +511,10 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
|||
port_spinbutton = self.glade.get_widget("spinbutton_port")
|
||||
username_entry = self.glade.get_widget("entry_username")
|
||||
password_entry = self.glade.get_widget("entry_password")
|
||||
button_addhost_save = self.glade.get_widget("button_addhost_save")
|
||||
button_addhost_save.hide()
|
||||
button_addhost_add = self.glade.get_widget("button_addhost_add")
|
||||
button_addhost_add.show()
|
||||
response = dialog.run()
|
||||
if response == 1:
|
||||
username = username_entry.get_text()
|
||||
|
@ -515,6 +534,54 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
|||
port_spinbutton.set_value(58846)
|
||||
dialog.hide()
|
||||
|
||||
def on_button_edithost_clicked(self, widget=None):
|
||||
log.debug("on_button_edithost_clicked")
|
||||
model, row = self.hostlist.get_selection().get_selected()
|
||||
status = model[row][HOSTLIST_COL_STATUS]
|
||||
if status == _("Connected"):
|
||||
def on_disconnect(reason):
|
||||
self.__update_list()
|
||||
client.disconnect().addCallback(on_disconnect)
|
||||
return
|
||||
|
||||
dialog = self.glade.get_widget("addhost_dialog")
|
||||
dialog.set_transient_for(self.connection_manager)
|
||||
dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||
hostname_entry = self.glade.get_widget("entry_hostname")
|
||||
port_spinbutton = self.glade.get_widget("spinbutton_port")
|
||||
username_entry = self.glade.get_widget("entry_username")
|
||||
password_entry = self.glade.get_widget("entry_password")
|
||||
button_addhost_save = self.glade.get_widget("button_addhost_save")
|
||||
button_addhost_save.show()
|
||||
button_addhost_add = self.glade.get_widget("button_addhost_add")
|
||||
button_addhost_add.hide()
|
||||
|
||||
username_entry.set_text(self.liststore[row][HOSTLIST_COL_USER])
|
||||
password_entry.set_text(self.liststore[row][HOSTLIST_COL_PASS])
|
||||
hostname_entry.set_text(self.liststore[row][HOSTLIST_COL_HOST])
|
||||
port_spinbutton.set_value(self.liststore[row][HOSTLIST_COL_PORT])
|
||||
|
||||
response = dialog.run()
|
||||
|
||||
if response == 2:
|
||||
self.liststore[row][HOSTLIST_COL_HOST] = hostname_entry.get_text()
|
||||
self.liststore[row][HOSTLIST_COL_PORT] = port_spinbutton.get_value_as_int()
|
||||
self.liststore[row][HOSTLIST_COL_USER] = username_entry.get_text()
|
||||
self.liststore[row][HOSTLIST_COL_PASS] = password_entry.get_text()
|
||||
self.liststore[row][HOSTLIST_COL_STATUS] = _("Offline")
|
||||
|
||||
# Save the host list to file
|
||||
self.__save_hostlist()
|
||||
|
||||
# Update the status of the hosts
|
||||
self.__update_list()
|
||||
|
||||
username_entry.set_text("")
|
||||
password_entry.set_text("")
|
||||
hostname_entry.set_text("")
|
||||
port_spinbutton.set_value(58846)
|
||||
dialog.hide()
|
||||
|
||||
def on_button_removehost_clicked(self, widget):
|
||||
log.debug("on_button_removehost_clicked")
|
||||
# Get the selected rows
|
||||
|
@ -579,3 +646,17 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
|||
|
||||
def on_hostlist_selection_changed(self, treeselection):
|
||||
self.__update_buttons()
|
||||
|
||||
def on_askpassword_dialog_connect_button_clicked(self, widget):
|
||||
log.debug("on on_askpassword_dialog_connect_button_clicked")
|
||||
self.askpassword_dialog.response(gtk.RESPONSE_OK)
|
||||
|
||||
def on_askpassword_dialog_entry_activate(self, entry):
|
||||
self.askpassword_dialog.response(gtk.RESPONSE_OK)
|
||||
|
||||
def __on_connected_failed(self, reason, host_id, host, port, user):
|
||||
log.exception(reason)
|
||||
log.debug(reason.value)
|
||||
log.debug(reason.value.__dict__)
|
||||
dialogs.ErrorDialog(_("Failed To Authenticate"),
|
||||
reason.value.exception_msg).run()
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--Generated with glade3 3.4.5 on Mon Jan 26 23:25:11 2009 -->
|
||||
<?xml version="1.0"?>
|
||||
<glade-interface>
|
||||
<!-- interface-requires gtk+ 2.6 -->
|
||||
<!-- interface-naming-policy toplevel-contextual -->
|
||||
<widget class="GtkDialog" id="addhost_dialog">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="title" translatable="yes">Add Host</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="has_separator">False</property>
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox3">
|
||||
|
@ -30,6 +30,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -159,38 +160,59 @@
|
|||
<widget class="GtkHButtonBox" id="dialog-action_area3">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_addhost_cancel">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_addhost_add">
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="response_id">1</property>
|
||||
<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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">1</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_addhost_save">
|
||||
<property name="label">gtk-save</property>
|
||||
<property name="response_id">2</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -203,11 +225,11 @@
|
|||
<property name="border_width">5</property>
|
||||
<property name="title" translatable="yes">Connection Manager</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="default_width">350</property>
|
||||
<property name="default_height">300</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="has_separator">False</property>
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox2">
|
||||
|
@ -228,6 +250,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -258,14 +281,14 @@
|
|||
<widget class="GtkViewport" id="viewport1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="resize_mode">GTK_RESIZE_QUEUE</property>
|
||||
<property name="resize_mode">queue</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="hostlist">
|
||||
<property name="visible">True</property>
|
||||
|
@ -277,6 +300,9 @@
|
|||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox3">
|
||||
|
@ -286,48 +312,69 @@
|
|||
<widget class="GtkHButtonBox" id="hbuttonbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_START</property>
|
||||
<property name="layout_style">start</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_addhost">
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_addhost_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_edithost">
|
||||
<property name="label">gtk-edit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_button_edithost_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_removehost">
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_removehost_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_refresh">
|
||||
<property name="label">gtk-refresh</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="label" translatable="no">gtk-refresh</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_refresh_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
|
@ -342,7 +389,6 @@
|
|||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_startdaemon_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox4">
|
||||
|
@ -355,6 +401,9 @@
|
|||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-execute</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label_startdaemon">
|
||||
|
@ -373,7 +422,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -409,22 +458,25 @@
|
|||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="chk_autoconnect">
|
||||
<property name="label" translatable="yes">Automatically connect to selected host on start-up</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Automatically connect to selected host on start-up</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_chk_autoconnect_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="chk_autostart">
|
||||
<property name="label" translatable="yes">Automatically start localhost if needed</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Automatically start localhost if needed</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_chk_autostart_toggled"/>
|
||||
</widget>
|
||||
|
@ -434,11 +486,11 @@
|
|||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="chk_donotshow">
|
||||
<property name="label" translatable="yes">Do not show this dialog on start-up</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Do not show this dialog on start-up</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_chk_donotshow_toggled"/>
|
||||
</widget>
|
||||
|
@ -469,31 +521,30 @@
|
|||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_close">
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">-7</property>
|
||||
<signal name="clicked" handler="on_button_close_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_connect">
|
||||
<property name="label">gtk-connect</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="label" translatable="yes">gtk-connect</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_button_connect_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
|
@ -513,12 +564,87 @@
|
|||
<widget class="GtkHButtonBox" id="dialog-action_area2">
|
||||
<property name="sensitive">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="layout_style">end</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkDialog" id="askpassword_dialog">
|
||||
<property name="border_width">5</property>
|
||||
<property name="title" translatable="yes">Password Required</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="default_width">320</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="has_separator">False</property>
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox5">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="askpassword_dialog_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon-size">6</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="askpassword_dialog_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">●</property>
|
||||
<signal name="activate" handler="on_askpassword_dialog_entry_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area5">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="askpassword_dialog_connect_button">
|
||||
<property name="label">gtk-connect</property>
|
||||
<property name="response_id">1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_askpassword_dialog_connect_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
|
|
Loading…
Reference in New Issue