| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
from __future__ import nested_scopes |
|---|
| 7 |
|
|---|
| 8 |
import gtk |
|---|
| 9 |
|
|---|
| 10 |
from twisted import copyright |
|---|
| 11 |
from twisted.internet import defer |
|---|
| 12 |
from twisted.python import failure, log, util |
|---|
| 13 |
from twisted.spread import pb |
|---|
| 14 |
from twisted.cred.credentials import UsernamePassword |
|---|
| 15 |
|
|---|
| 16 |
from twisted.internet import error as netError |
|---|
| 17 |
|
|---|
| 18 |
def login(client=None, **defaults): |
|---|
| 19 |
""" |
|---|
| 20 |
@param host: |
|---|
| 21 |
@param port: |
|---|
| 22 |
@param identityName: |
|---|
| 23 |
@param password: |
|---|
| 24 |
@param serviceName: |
|---|
| 25 |
@param perspectiveName: |
|---|
| 26 |
|
|---|
| 27 |
@returntype: Deferred RemoteReference of Perspective |
|---|
| 28 |
""" |
|---|
| 29 |
d = defer.Deferred() |
|---|
| 30 |
LoginDialog(client, d, defaults) |
|---|
| 31 |
return d |
|---|
| 32 |
|
|---|
| 33 |
class GladeKeeper: |
|---|
| 34 |
""" |
|---|
| 35 |
@cvar gladefile: The file in which the glade GUI definition is kept. |
|---|
| 36 |
@type gladefile: str |
|---|
| 37 |
|
|---|
| 38 |
@cvar _widgets: Widgets that should be attached to me as attributes. |
|---|
| 39 |
@type _widgets: list of strings |
|---|
| 40 |
""" |
|---|
| 41 |
|
|---|
| 42 |
gladefile = None |
|---|
| 43 |
_widgets = () |
|---|
| 44 |
|
|---|
| 45 |
def __init__(self): |
|---|
| 46 |
from gtk import glade |
|---|
| 47 |
self.glade = glade.XML(self.gladefile) |
|---|
| 48 |
|
|---|
| 49 |
|
|---|
| 50 |
mold = {} |
|---|
| 51 |
for k in dir(self): |
|---|
| 52 |
mold[k] = getattr(self, k) |
|---|
| 53 |
self.glade.signal_autoconnect(mold) |
|---|
| 54 |
self._setWidgets() |
|---|
| 55 |
|
|---|
| 56 |
def _setWidgets(self): |
|---|
| 57 |
get_widget = self.glade.get_widget |
|---|
| 58 |
for widgetName in self._widgets: |
|---|
| 59 |
setattr(self, "_" + widgetName, get_widget(widgetName)) |
|---|
| 60 |
|
|---|
| 61 |
|
|---|
| 62 |
class LoginDialog(GladeKeeper): |
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
fields = ['host','port','identityName','password', |
|---|
| 72 |
'perspectiveName'] |
|---|
| 73 |
|
|---|
| 74 |
_widgets = ("hostEntry", "portEntry", "identityNameEntry", "passwordEntry", |
|---|
| 75 |
"perspectiveNameEntry", "statusBar", |
|---|
| 76 |
"loginDialog") |
|---|
| 77 |
|
|---|
| 78 |
_advancedControls = ['perspectiveLabel', 'perspectiveNameEntry', |
|---|
| 79 |
'protocolLabel', 'versionLabel'] |
|---|
| 80 |
|
|---|
| 81 |
gladefile = util.sibpath(__file__, "login2.glade") |
|---|
| 82 |
|
|---|
| 83 |
def __init__(self, client, deferred, defaults): |
|---|
| 84 |
self.client = client |
|---|
| 85 |
self.deferredResult = deferred |
|---|
| 86 |
|
|---|
| 87 |
GladeKeeper.__init__(self) |
|---|
| 88 |
|
|---|
| 89 |
self.setDefaults(defaults) |
|---|
| 90 |
self._loginDialog.show() |
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
def setDefaults(self, defaults): |
|---|
| 94 |
if not defaults.has_key('port'): |
|---|
| 95 |
defaults['port'] = str(pb.portno) |
|---|
| 96 |
elif isinstance(defaults['port'], (int, long)): |
|---|
| 97 |
defaults['port'] = str(defaults['port']) |
|---|
| 98 |
|
|---|
| 99 |
for k, v in defaults.iteritems(): |
|---|
| 100 |
if k in self.fields: |
|---|
| 101 |
widget = getattr(self, "_%sEntry" % (k,)) |
|---|
| 102 |
widget.set_text(v) |
|---|
| 103 |
|
|---|
| 104 |
def _setWidgets(self): |
|---|
| 105 |
GladeKeeper._setWidgets(self) |
|---|
| 106 |
self._statusContext = self._statusBar.get_context_id("Login dialog.") |
|---|
| 107 |
get_widget = self.glade.get_widget |
|---|
| 108 |
get_widget("versionLabel").set_text(copyright.longversion) |
|---|
| 109 |
get_widget("protocolLabel").set_text("Protocol PB-%s" % |
|---|
| 110 |
(pb.Broker.version,)) |
|---|
| 111 |
|
|---|
| 112 |
def _on_loginDialog_response(self, widget, response): |
|---|
| 113 |
handlers = {gtk.RESPONSE_NONE: self._windowClosed, |
|---|
| 114 |
gtk.RESPONSE_DELETE_EVENT: self._windowClosed, |
|---|
| 115 |
gtk.RESPONSE_OK: self._doLogin, |
|---|
| 116 |
gtk.RESPONSE_CANCEL: self._cancelled} |
|---|
| 117 |
handler = handlers.get(response) |
|---|
| 118 |
if handler is not None: |
|---|
| 119 |
handler() |
|---|
| 120 |
else: |
|---|
| 121 |
log.msg("Unexpected dialog response %r from %s" % (response, |
|---|
| 122 |
widget)) |
|---|
| 123 |
|
|---|
| 124 |
def _on_loginDialog_close(self, widget, userdata=None): |
|---|
| 125 |
self._windowClosed() |
|---|
| 126 |
|
|---|
| 127 |
def _on_loginDialog_destroy_event(self, widget, userdata=None): |
|---|
| 128 |
self._windowClosed() |
|---|
| 129 |
|
|---|
| 130 |
def _cancelled(self): |
|---|
| 131 |
if not self.deferredResult.called: |
|---|
| 132 |
self.deferredResult.errback(netError.UserError("User hit Cancel.")) |
|---|
| 133 |
self._loginDialog.destroy() |
|---|
| 134 |
|
|---|
| 135 |
def _windowClosed(self, reason=None): |
|---|
| 136 |
if not self.deferredResult.called: |
|---|
| 137 |
self.deferredResult.errback(netError.UserError("Window closed.")) |
|---|
| 138 |
|
|---|
| 139 |
def _doLogin(self): |
|---|
| 140 |
idParams = {} |
|---|
| 141 |
|
|---|
| 142 |
idParams['host'] = self._hostEntry.get_text() |
|---|
| 143 |
idParams['port'] = self._portEntry.get_text() |
|---|
| 144 |
idParams['identityName'] = self._identityNameEntry.get_text() |
|---|
| 145 |
idParams['password'] = self._passwordEntry.get_text() |
|---|
| 146 |
|
|---|
| 147 |
try: |
|---|
| 148 |
idParams['port'] = int(idParams['port']) |
|---|
| 149 |
except ValueError: |
|---|
| 150 |
pass |
|---|
| 151 |
|
|---|
| 152 |
f = pb.PBClientFactory() |
|---|
| 153 |
from twisted.internet import reactor |
|---|
| 154 |
reactor.connectTCP(idParams['host'], idParams['port'], f) |
|---|
| 155 |
creds = UsernamePassword(idParams['identityName'], idParams['password']) |
|---|
| 156 |
f.login(creds, self.client |
|---|
| 157 |
).addCallbacks(self._cbGotPerspective, self._ebFailedLogin |
|---|
| 158 |
).setTimeout(30 |
|---|
| 159 |
) |
|---|
| 160 |
self.statusMsg("Contacting server...") |
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 |
|
|---|
| 166 |
|
|---|
| 167 |
|
|---|
| 168 |
|
|---|
| 169 |
|
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 |
def _cbGotPerspective(self, perspective): |
|---|
| 173 |
self.statusMsg("Connected to server.") |
|---|
| 174 |
self.deferredResult.callback(perspective) |
|---|
| 175 |
|
|---|
| 176 |
self._loginDialog.destroy() |
|---|
| 177 |
|
|---|
| 178 |
def _ebFailedLogin(self, reason): |
|---|
| 179 |
if isinstance(reason, failure.Failure): |
|---|
| 180 |
reason = reason.value |
|---|
| 181 |
self.statusMsg(reason) |
|---|
| 182 |
if isinstance(reason, (unicode, str)): |
|---|
| 183 |
text = reason |
|---|
| 184 |
else: |
|---|
| 185 |
text = unicode(reason) |
|---|
| 186 |
msg = gtk.MessageDialog(self._loginDialog, |
|---|
| 187 |
gtk.DIALOG_DESTROY_WITH_PARENT, |
|---|
| 188 |
gtk.MESSAGE_ERROR, |
|---|
| 189 |
gtk.BUTTONS_CLOSE, |
|---|
| 190 |
text) |
|---|
| 191 |
msg.show_all() |
|---|
| 192 |
msg.connect("response", lambda *a: msg.destroy()) |
|---|
| 193 |
|
|---|
| 194 |
|
|---|
| 195 |
|
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 |
|
|---|
| 199 |
|
|---|
| 200 |
|
|---|
| 201 |
|
|---|
| 202 |
def _on_advancedButton_toggled(self, widget, userdata=None): |
|---|
| 203 |
active = widget.get_active() |
|---|
| 204 |
if active: |
|---|
| 205 |
op = "show" |
|---|
| 206 |
else: |
|---|
| 207 |
op = "hide" |
|---|
| 208 |
for widgetName in self._advancedControls: |
|---|
| 209 |
widget = self.glade.get_widget(widgetName) |
|---|
| 210 |
getattr(widget, op)() |
|---|
| 211 |
|
|---|
| 212 |
def statusMsg(self, text): |
|---|
| 213 |
if not isinstance(text, (unicode, str)): |
|---|
| 214 |
text = unicode(text) |
|---|
| 215 |
return self._statusBar.push(self._statusContext, text) |
|---|