# Copyright (C) 2009 Lars Wirzenius # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . '''Helper class for writing PyGTK applications.''' import gobject import gtk class GtkApplication(object): '''Base class for GTK+ applications. This class provides some convenience functions for GTK+ applications. It makes some assumptions to simplify things: * The UI will be made with Glade and described with a .ui file, using GtkBuilder. * A dictionary of all widgets is created as the widgets attribute. It is indexed by the name of the widget, as defined in the .ui file. * Callbacks will be named on_widgetname_signalname. They will be connected automatically if this naming convention is followed. * Methods named widgetname_is_sensitive control the sensitivity of widgets that need to become sensitive or not based on the state of the program. * signal callbacks and *_is_sensitive are methods of "controllers", which are provided to setup_widgets as an argument, and which it stores into the controllers attribute. ''' def setup_widgets(self, glade_filename, controllers): '''Find all widgets and connect them to signal handlers. The list of controllers will be stored in the controllers attribute. ''' self.controllers = controllers if not hasattr(self, 'widgets'): self.widgets = {} builder = gtk.Builder() if builder.add_from_file(glade_filename) == 0: raise Exception('GtkBuilder.add_from_file failed for %s' % glade_filename) for widget in builder.get_objects(): if isinstance(widget, gtk.Widget): self.setup_a_widget(widget) def setup_a_widget(self, widget): name = widget.get_property('name') self.widgets[name] = widget for controller in self.controllers: for attr in dir(controller): prefix = 'on_%s_' % name if attr.startswith(prefix): signal_name = attr[len(prefix):] method = getattr(controller, attr) widget.connect(signal_name, method) def set_sensitive(self): '''Set all widgets to be sensitive or not. The sensitivity of each widget is tested with a method called widgetname_is_sensitive. The method must be in one of the controllers given to setup_widgets. You should call this whenever one of the conditions for sensitivity changes. ''' suffix = '_is_sensitive' for controller in self.controllers: for attrname in dir(controller): if attrname.endswith(suffix): widgetname = attrname[:-len(suffix)] if widgetname in self.widgets: widget = self.widgets[widgetname] method = getattr(controller, attrname) widget.set_sensitive(bool(method()))