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