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