Package flumotion :: Package admin :: Package gtk :: Module greeter
[hide private]

Source Code for Module flumotion.admin.gtk.greeter

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  """greeter interface, displayed when the user first starts flumotion. 
 23  """ 
 24   
 25  import gettext 
 26  import os 
 27   
 28  import gobject 
 29  import gtk 
 30  from twisted.internet import reactor 
 31   
 32  from flumotion.admin.connections import hasRecentConnections 
 33  from flumotion.admin.gtk.dialogs import showConnectionErrorDialog 
 34  from flumotion.common.connection import parsePBConnectionInfo 
 35  from flumotion.common.errors import ConnectionFailedError 
 36  from flumotion.common.managerspawner import LocalManagerSpawner 
 37  from flumotion.common.netutils import tryPort 
 38  from flumotion.common.pygobject import gsignal 
 39  from flumotion.configure import configure 
 40  from flumotion.ui.simplewizard import SimpleWizard, WizardStep, \ 
 41       WizardCancelled 
 42   
 43  __version__ = "$Rev: 7032 $" 
 44  _ = gettext.gettext 
 45   
 46   
47 -class Initial(WizardStep):
48 name = 'initial' 49 title = _('Connect to Flumotion manager') 50 text = (_('Flumotion Admin needs to connect to a Flumotion manager.\n') + 51 _('Choose an option from the list and click "Forward" to begin.')) 52 connect_to_existing = None 53 next_pages = ['load_connection', 54 'connect_to_existing', 55 'start_new'] 56
57 - def __init__(self, wizard, parent):
58 super(Initial, self).__init__(wizard, parent) 59 60 for radio in self.load_connection.get_group(): 61 radio.connect('activate', self._on_radio__activiate)
62 63 # WizardSteps 64
65 - def setup(self, state, available_pages):
66 # the group of radio buttons is named after the first check button 67 for radio in self.load_connection.get_group(): 68 isAvailable = radio.get_name() in available_pages 69 radio.set_sensitive(isAvailable) 70 71 hasRecent = hasRecentConnections() 72 self.load_connection.set_sensitive(hasRecent) 73 if hasRecent: 74 self.load_connection.set_active(True) 75 else: 76 self.connect_to_existing.set_active(True) 77 78 # Find which radio button should be focused: 79 for radioName in available_pages: 80 radio = getattr(self, radioName) 81 if radio.get_active(): 82 break 83 else: 84 raise AssertionError("no button to focus") 85 radio.grab_focus()
86
87 - def on_next(self, state):
88 for radio in self.connect_to_existing.get_group(): 89 if radio.get_active(): 90 return radio.get_name() 91 raise AssertionError
92 93 # Callbacks 94
95 - def _on_radio__activiate(self, radio):
96 if not radio.get_active(): 97 return 98 self.button_next.clicked()
99 100
101 -class ConnectToExisting(WizardStep):
102 name = 'connect_to_existing' 103 title = _('Host information') 104 text = _('Please enter the address where the manager is running.') 105 next_pages = ['authenticate'] 106 open_connection = None 107 108 # WizardSteps 109
110 - def setup(self, state, available_pages):
111 try: 112 oc_state = [(k, state[k]) for k in ('host', 'port', 'use_insecure')] 113 self.open_connection.set_state(dict(oc_state)) 114 except KeyError: 115 pass 116 self.open_connection.grab_focus()
117 118 # Callbacks 119
120 - def on_can_activate(self, obj, *args):
121 self.button_next.set_sensitive(obj.get_property('can-activate'))
122
123 - def on_next(self, state):
124 for k, v in self.open_connection.get_state().items(): 125 state[k] = v 126 return 'authenticate'
127 128
129 -class Authenticate(WizardStep):
130 name = 'authenticate' 131 title = _('Authentication') 132 text = _('Please select among the following authentication methods.') 133 auth_method_combo = user_entry = passwd_entry = None 134 next_pages = [] 135 authenticate = None 136 137 # WizardStep 138
139 - def setup(self, state, available_pages):
140 try: 141 oc_state = [(k, state[k]) for k in ('user', 'passwd')] 142 self.authenticate.set_state(dict(oc_state)) 143 except KeyError: 144 self.authenticate.set_state(None) 145 self.authenticate.grab_focus() 146 self.on_can_activate(self.authenticate)
147
148 - def on_next(self, state):
149 for k, v in self.authenticate.get_state().items(): 150 state[k] = v 151 state['connectionInfo'] = parsePBConnectionInfo( 152 state['host'], 153 username=state['user'], 154 password=state['passwd'], 155 port=state['port'], 156 use_ssl=not state['use_insecure']) 157 return '*finished*'
158 159 # Callbacks 160
161 - def on_can_activate(self, obj, *args):
162 self.button_next.set_sensitive(obj.get_property('can-activate'))
163 164
165 -class LoadConnection(WizardStep):
166 name = 'load_connection' 167 title = _('Recent connections') 168 text = _('Please choose a connection from the box below.') 169 connections = None 170 next_pages = [] 171 172 # WizardStep 173
174 - def setup(self, state, available_pages):
175 self.connections.grab_focus() 176 self.button_next.set_label(gtk.STOCK_CONNECT)
177
178 - def on_next(self, state):
179 connection = self.connections.get_selected() 180 state['connection'] = connection 181 state['connectionInfo'] = connection.info 182 return '*finished*'
183 184 # Callbacks 185
186 - def on_connection_activated(self, widget, state):
187 self.button_next.emit('clicked')
188 189
190 -class StartNew(WizardStep):
191 name = 'start_new' 192 title = _('Start a new manager and worker') 193 text = _("""This will start a new manager and worker for you. 194 195 The manager and worker will run under your user account. 196 The manager will only accept connections from the local machine. 197 This mode is only useful for testing Flumotion. 198 """) 199 start_worker_check = None 200 next_pages = ['start_new_error', 'start_new_success'] 201 gsignal('finished', str) 202 203 _timeout_id = None 204 205 # WizardStep 206
207 - def setup(self, state, available_pages):
208 self.button_next.grab_focus()
209
210 - def on_next(self, state):
211 self.label_starting.show() 212 self.progressbar_starting.set_fraction(0.0) 213 self.progressbar_starting.show() 214 215 def pulse(): 216 self.progressbar_starting.pulse() 217 return True
218 self._timeout_id = gobject.timeout_add(200, pulse) 219 220 self._startManager(state) 221 return '*signaled*'
222 223 # Private 224
225 - def _startManager(self, state):
226 port = tryPort() 227 managerSpawner = LocalManagerSpawner(port) 228 managerSpawner.connect('error', self._on_spawner_error, state) 229 managerSpawner.connect('description-changed', 230 self._on_spawner_description_changed) 231 managerSpawner.connect('finished', self._on_spawner_finished, state) 232 managerSpawner.start()
233
234 - def _on_spawner_error(self, spawner, failure, msg, args, state):
235 # error should trigger going to next page with an overview 236 state.update({ 237 'command': ' '.join(args), 238 'error': msg, 239 'failure': failure, 240 }) 241 self._finished('start_new_error')
242
243 - def _on_spawner_description_changed(self, spawner, description):
244 self.label_starting.set_text(description)
245
246 - def _on_spawner_finished(self, spawner, state):
247 # because of the ugly call-by-reference passing of state, 248 # we have to update the existing dict, not re-bind with state = 249 state['connectionInfo'] = parsePBConnectionInfo( 250 'localhost', 251 username='user', 252 password='test', 253 port=spawner.getPort(), 254 use_ssl=True) 255 state.update(dict(confDir=spawner.getConfDir(), 256 logDir=spawner.getLogDir(), 257 runDir=spawner.getRunDir())) 258 self._finished('start_new_success')
259
260 - def _finished(self, result):
261 # result: start_new_error or start_new_success 262 self.label_starting.hide() 263 self.progressbar_starting.hide() 264 gobject.source_remove(self._timeout_id) 265 self.emit('finished', result)
266 267
268 -class StartNewError(WizardStep):
269 name = 'start_new_error' 270 title = _('Failed to start') 271 text = "" 272 start_worker_check = None 273 next_pages = [] 274 275 # WizardStep 276
277 - def setup(self, state, available_pages):
278 self.button_next.set_sensitive(False) 279 self.message.set_text(state['error']) 280 f = state['failure'] 281 result = "" 282 if f.value.exitCode is not None: 283 result = _('The command exited with an exit code of %d.' % 284 f.value.exitCode) 285 self.more.set_markup(_("""The command that failed was: 286 <i>%s</i> 287 %s""") % (state['command'], result))
288 289
290 -class StartNewSuccess(WizardStep):
291 name = 'start_new_success' 292 title = _('Started manager and worker') 293 start_worker_check = None 294 text = '' 295 next_pages = [] 296 297 # WizardStep 298
299 - def setup(self, state, available_pages):
300 self.button_prev.set_sensitive(False) 301 self.button_next.set_label(gtk.STOCK_CONNECT) 302 executable = os.path.join(configure.sbindir, 'flumotion') 303 confDir = state['confDir'] 304 logDir = state['logDir'] 305 runDir = state['runDir'] 306 stop = "%s -C %s -L %s -R %s stop" % ( 307 executable, confDir, logDir, runDir) 308 self.message.set_markup(_( 309 """The admin client will now connect to the manager. 310 311 Configuration files are stored in 312 <i>%s</i> 313 Log files are stored in 314 <i>%s</i> 315 316 You can shut down the manager and worker later with the following command: 317 318 <i>%s</i> 319 """) % (confDir, logDir, stop)) 320 self.button_next.grab_focus()
321
322 - def on_next(self, state):
323 return '*finished*'
324 325
326 -class Greeter(SimpleWizard):
327 name = 'greeter' 328 steps = [Initial, ConnectToExisting, Authenticate, LoadConnection, 329 StartNew, StartNewError, StartNewSuccess] 330
331 - def __init__(self, adminWindow):
332 self._adminWindow = adminWindow 333 SimpleWizard.__init__(self, 'initial', 334 parent=adminWindow.getWindow()) 335 # Set the name of the toplevel window, this is used by the 336 # ui unittest framework 337 self.window1.set_name('Greeter') 338 self.window1.set_size_request(-1, 450)
339 340 # SimpleWizard 341
342 - def runAsync(self):
343 d = SimpleWizard.runAsync(self) 344 d.addCallback(self._runAsyncFinished) 345 d.addErrback(self._wizardCancelledErrback) 346 return d
347 348 # Private 349
350 - def _runAsyncFinished(self, state):
351 connection = state.get('connection') 352 info = state['connectionInfo'] 353 354 def connected(unused): 355 if connection is not None: 356 connection.updateTimestamp()
357 358 def errorMessageDisplayed(unused): 359 return self.runAsync()
360 361 def connectionFailed(failure): 362 failure.trap(ConnectionFailedError) 363 self.hide() 364 d = showConnectionErrorDialog(failure, info, 365 parent=self.window) 366 d.addCallback(errorMessageDisplayed) 367 return d 368 369 d = self._adminWindow.openConnection(info) 370 d.addCallbacks(connected, connectionFailed) 371 self.set_sensitive(False) 372 return d 373
374 - def _wizardCancelledErrback(self, failure):
375 failure.trap(WizardCancelled) 376 reactor.stop()
377 378 379 # This is used by the gtk admin to connect to an existing manager
380 -class ConnectExisting(SimpleWizard):
381 name = 'greeter' 382 steps = [ConnectToExisting, Authenticate] 383
384 - def __init__(self, parent=None):
385 SimpleWizard.__init__(self, 'connect_to_existing', 386 parent=parent)
387