1### Copyright (C) 2002-2008 Stephen Kennedy <stevek@gnome.org> 2### Copyright (C) 2010 Kai Willadsen <kai.willadsen@gmail.com> 3 4### This program is free software; you can redistribute it and/or modify 5### it under the terms of the GNU General Public License as published by 6### the Free Software Foundation; either version 2 of the License, or 7### (at your option) any later version. 8 9### This program is distributed in the hope that it will be useful, 10### but WITHOUT ANY WARRANTY; without even the implied warranty of 11### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12### GNU General Public License for more details. 13 14### You should have received a copy of the GNU General Public License 15### along with this program; if not, write to the Free Software 16### Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17### USA. 18 19import logging 20import re 21 22import gtk 23 24 25# FIXME: duplicate defn in bin/meld 26locale_domain = "meld" 27 28 29class Component(object): 30 """Base class for all glade objects. 31 32 This class handles loading the xml glade file and autoconnects 33 all signals in the glade file. 34 35 The handle to the xml file is stored in 'self.xml'. The 36 toplevel widget is stored in 'self.widget'. 37 38 In addition it calls widget.set_data("pyobject", self) - this 39 allows us to get the python object given only the 'raw' gtk+ 40 object, which is sadly sometimes necessary. 41 """ 42 43 def __init__(self, filename, root, extra=None): 44 """Load the widgets from the node 'root' in file 'filename'. 45 """ 46 self.builder = gtk.Builder() 47 self.builder.set_translation_domain(locale_domain) 48 objects = [root] + extra if extra else [root] 49 self.builder.add_objects_from_file(filename, objects) 50 self.builder.connect_signals(self) 51 self.widget = getattr(self, root) 52 self.widget.set_data("pyobject", self) 53 54 def __getattr__(self, key): 55 """Allow glade widgets to be accessed as self.widgetname. 56 """ 57 widget = self.builder.get_object(key) 58 if widget: # cache lookups 59 setattr(self, key, widget) 60 return widget 61 raise AttributeError(key) 62 63 def map_widgets_into_lists(self, widgetnames): 64 """Put sequentially numbered widgets into lists. 65 66 e.g. If an object had widgets self.button0, self.button1, ..., 67 then after a call to object._map_widgets_into_lists(["button"]) 68 object has an attribute self.button == [self.button0, self.button1, ...]." 69 """ 70 for item in widgetnames: 71 setattr(self,item, []) 72 lst = getattr(self,item) 73 i = 0 74 while 1: 75 key = "%s%i"%(item,i) 76 try: 77 val = getattr(self, key) 78 except AttributeError: 79 break 80 lst.append(val) 81 i += 1 82 83# Regular expression to match handler method names patterns 84# on_widget__signal and after_widget__signal. Note that we use two 85# underscores between the Glade widget name and the signal name. 86handler_re = re.compile(r'^(on|after)_(.*)__(.*)$') 87 88def connect_signal_handlers(obj): 89 log = logging.getLogger(__name__) 90 for attr in dir(obj): 91 match = handler_re.match(attr) 92 if match: 93 when, widgetname, signal = match.groups() 94 method = getattr(obj, attr) 95 assert hasattr(method, '__call__') 96 try: 97 widget = getattr(obj, widgetname) 98 except AttributeError: 99 log.warning("Widget '%s' not found in %s", widgetname, obj) 100 continue 101 if not isinstance(widget,list): 102 widget = [widget] 103 for w in widget: 104 try: 105 if when == 'on': 106 w.connect(signal, method) 107 elif when == 'after': 108 w.connect_after(signal, method) 109 except TypeError as e: 110 log.warning("%s in %s %s", e, obj, attr) 111 elif attr.startswith('on_') or attr.startswith('after_'): 112 continue # don't warn until all old code updated 113 # Warn about some possible typos like separating 114 # widget and signal name with _ instead of __. 115 log.warning("Warning: attribute %r not connected as a signal " 116 "handler", attr) 117 118 119from . import gladesupport 120