def showCalibrationDialog(self): """ Shows the calibration dialog. The first time this method is called, the dialog is created """ if self._calibrationDialogHandler == None: self._calibrationDialogHandler = CalibrationDialogHandler( self._system) self._calibrationDialogHandler.present()
class MainWindowHandler(object): """ A class that handles the creation of the application's main window and implements its functionality. There can be any number of main windows, which are each responsible for a different system, although the program currently uses only a single main window. """ # The actual gtk.Window. _window = None # The gtk.VBox that serves as the top-level container of the widgets that # make up the main window. _mainBox = None # A gtk.Label on the status bar that shows the current heating temperature. _temperatureLabel = None # The system the user can interact with using the main window. # TODO: This cannot currently be safely changed. _system = None # The gui.calibration.dialog.CalibrationDialogHandler associated with this # main window. This remains set even if the dialog is closed. Saved here to # prevent multiple copies of the dialog from being shown, and to prevent it # from being collected prematurely. _calibrationDialogHandler = None # A list of gui.action.NoseAction objects for the actions that can be # activated from the main window's menu bar. Saved here to prevent them # from being collected prematurely. _actions = None def __init__(self, mediator, system): """ Creates a handler for a main window that allows the user to interact with the given system. """ # TOOD: What is the mediator used for? Why both mediator and system? self.mediator = mediator self._system = system self._actions = [] self._createWidgets() self._systemPropertiesDialogHandler = lambda: None def start(self): """ Shows the gtk.Window and starts GTK's main loop if this is the first MainWindowHandler whose start method has been called. """ self._window.show_all() MAIN_WINDOW_HANDLERS.append(self) if len(MAIN_WINDOW_HANDLERS) == 1: gtk.main() def destroy(self, window=None, options=None): """ Destroys the gtk.Window and quits GTK's main loop if this is the last MainWindowHandler whise destroy method has not yet been called. """ self._window.destroy() MAIN_WINDOW_HANDLERS.remove(self) if len(MAIN_WINDOW_HANDLERS) == 0: gtk.main_quit() ########################################################################### # WINDOW CREATION # ########################################################################### def _createWidgets(self): """ Creates the window and its contents. """ self._createWindow() self._createMenu() self._createStatusBar() def _createWindow(self): """ Creates the gtk.Window object itself, but not its nontrivial contents. """ self._window = gtk.Window() self._window.set_title(PROGRAM_NAME) self._window.set_default_size(*self._getPreferredSize()) self._window.connect('destroy', util.WeakMethod(self.destroy)) self._mainBox = gtk.VBox(homogeneous=False) self._window.add(self._mainBox) def _createMenu(self): """ Creates the window's menu. Its layout can be found in menu.xml, and implementation of the actions taken when a menu item is activated as well as i18n is in the actions package. """ actionGroup = gui.actions.createActionGroup(self) uiManager = gtk.UIManager() uiManager.insert_action_group(actionGroup, 0) uiManager.add_ui_from_file(MENU_DEFINITION_PATH) self._window.add_accel_group(uiManager.get_accel_group()) self._mainBox.pack_start( uiManager.get_widget('/MenuBar'), expand=False) def _createStatusBar(self): """ Creates the status bar at the bottom of the window. """ self._temperatureLabel = gtk.Label() self._mainBox.pack_end(self._temperatureLabel, expand=False) self._mainBox.pack_end(gtk.HSeparator(), expand=False) gobject.timeout_add(STATUS_BAR_UPDATE_INTERVAL, util.WeakMethod(self._updateStatusBar)) ########################################################################### # SUBORDINATE DIALOGS # ########################################################################### def showCalibrationDialog(self): """ Shows the calibration dialog. The first time this method is called, the dialog is created """ if self._calibrationDialogHandler == None: self._calibrationDialogHandler = CalibrationDialogHandler( self._system) self._calibrationDialogHandler.present() def showSystemPropertiesDialog(self): dialog = self._systemPropertiesDialogHandler() if dialog == None: dialog = SystemPropertiesDialogHandler(self._system) self._systemPropertiesDialogHandler = weakref.ref(dialog) dialog.present() ########################################################################### # UPDATES # ########################################################################### def _updateStatusBar(self): """ Updates the information shown in the window's status bar. This method is called by GTK in the main event loop. """ temperature = self._system.temperature voltage = self._system.temperatureSensorVoltage if temperature != None: text = u'%d °C' % temperature else: text = u'%s V' % util.stringFromFloat(voltage, 4, False) self._temperatureLabel.set_text(text) # TODO: The timeout is never properly removed. return True # Yes, this method should be called again. ########################################################################### # UTILITY METHODS # ########################################################################### def _getPreferredSize(self, screen=None): """ Figures out an appropriate size for the main window. Its size is set to MAIN_WINDOW_SIZE, unless this would cause the window's width or height to exceed a fraction of the available width or height that exceeds MAIN_WINDOW_MAX_SCREEN_FRACTION. The parameter screen is the gtk.gdk.Screen the window needs to fit on. If it is None, the window's current screen is used, which should be the desired behavior in all cases; the parameter is chiefly provided for testing purposes. This method jumps through some hoops to properly handle the corner case of a virtual screens that is made up of multiple small monitors. """ MSF = MAIN_WINDOW_MAX_SCREEN_FRACTION width, height = MAIN_WINDOW_SIZE screen = screen or self._window.get_screen() if screen: # Find the smallest width and height among the monitors that # make up the screen. for n in range(screen.get_n_monitors()): geometry = screen.get_monitor_geometry(n) width = min(width, int(MSF * geometry.width)) height = min(height, int(MSF * geometry.height)) return width, height