Add 2010 to the years in copyright notice
[gpodder.git] / src / gpodder / gtkui / base.py
blob8338c4c84bdb82d9f7256373464aedfed8c8e92b
1 # -*- coding: utf-8 -*-
2 """
3 UI Base Module for GtkBuilder
5 Based on SimpleGladeApp.py Copyright (C) 2004 Sandino Flores Moreno
6 """
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 # USA
23 import os
24 import sys
25 import re
27 import tokenize
29 import gtk
31 class GtkBuilderWidget(object):
32 # Other code can set this to True if it wants us to try and
33 # replace GtkScrolledWindow widgets with Finger Scroll widgets
34 use_fingerscroll = False
36 def __init__(self, ui_folders, textdomain, **kwargs):
37 """
38 Loads the UI file from the specified folder (with translations
39 from the textdomain) and initializes attributes.
41 ui_folders:
42 List of folders with GtkBuilder .ui files in search order
44 textdomain:
45 The textdomain to be used for translating strings
47 **kwargs:
48 Keyword arguments will be set as attributes to this window
49 """
50 for key, value in kwargs.items():
51 setattr(self, key, value)
53 self.builder = gtk.Builder()
54 self.builder.set_translation_domain(textdomain)
56 print >>sys.stderr, 'Creating new from file', self.__class__.__name__
58 ui_file = '%s.ui' % self.__class__.__name__.lower()
60 # Search for the UI file in the UI folders, stop after first match
61 for ui_folder in ui_folders:
62 filename = os.path.join(ui_folder, ui_file)
63 if os.path.exists(filename):
64 self.builder.add_from_file(filename)
65 break
67 self.builder.connect_signals(self)
68 self.set_attributes()
70 self.new()
72 def _handle_scrolledwindow(self, widget):
73 """Helper for replacing gtk.ScrolledWindow with finger scroll
75 This function tries to replace a gtk.ScrolledWindow
76 widget with a finger scroll widget if available, reparenting
77 the child widget and trying to place the finger scroll
78 widget exactly where the ScrolledWindow was.
80 This function needs use_fingerscroll to be set to True,
81 otherwise it won't do anything."""
82 if not self.use_fingerscroll:
83 return widget
85 # Check if we have mokoui OR hildon before continuing
86 mokoui, hildon = None, None
87 try:
88 import mokoui
89 except ImportError, ie:
90 try:
91 import hildon
92 except ImportError, ie:
93 return widget
94 if not hasattr(hildon, 'PannableArea'):
95 # Probably using an older version of Hildon
96 return widget
98 parent = widget.get_parent()
99 child = widget.get_child()
100 scroll = None
102 def create_fingerscroll():
103 if mokoui is not None:
104 scroll = mokoui.FingerScroll()
105 scroll.set_property('mode', 0)
106 scroll.set_property('spring-speed', 0)
107 scroll.set_property('deceleration', .975)
108 else:
109 scroll = hildon.PannableArea()
110 scroll.set_name(widget.get_name())
111 return scroll
113 def container_get_child_pos(container, widget):
114 for pos, child in enumerate(container.get_children()):
115 if child == widget:
116 return pos
117 return -1
119 if isinstance(parent, gtk.Paned):
120 scroll = create_fingerscroll()
121 child.reparent(scroll)
123 if parent.get_child1() == widget:
124 add_to_paned = parent.add1
125 else:
126 add_to_paned = parent.add2
128 parent.remove(widget)
129 add_to_paned(scroll)
130 elif isinstance(parent, gtk.Box):
131 scroll = create_fingerscroll()
132 child.reparent(scroll)
134 position = container_get_child_pos(parent, widget)
135 packing = parent.query_child_packing(widget)
137 parent.remove(widget)
138 parent.add(scroll)
139 parent.set_child_packing(scroll, *packing)
140 parent.reorder_child(scroll, position)
141 elif isinstance(parent, gtk.Table):
142 scroll = create_fingerscroll()
143 child.reparent(scroll)
145 attachment = parent.child_get(widget, 'left-attach', \
146 'right-attach', 'top-attach', 'bottom-attach', \
147 'x-options', 'y-options', 'x-padding', 'y-padding')
148 parent.remove(widget)
149 parent.attach(scroll, *attachment)
151 if scroll is not None:
152 if isinstance(child, gtk.TextView):
153 child.set_editable(False)
154 child.set_cursor_visible(False)
155 child.set_sensitive(False)
156 widget.destroy()
157 scroll.show()
158 return scroll
160 return widget
162 def set_attributes(self):
164 Convert widget names to attributes of this object.
166 It means a widget named vbox-dialog in GtkBuilder
167 is refered using self.vbox_dialog in the code.
169 for widget in self.builder.get_objects():
170 if not hasattr(widget, 'get_name'):
171 continue
173 if isinstance(widget, gtk.ScrolledWindow):
174 widget = self._handle_scrolledwindow(widget)
176 widget_name = widget.get_name()
177 widget_api_name = '_'.join(re.findall(tokenize.Name, widget_name))
178 widget.set_name(widget_api_name)
179 if hasattr(self, widget_api_name):
180 raise AttributeError("instance %s already has an attribute %s" % (self,widget_api_name))
181 else:
182 setattr(self, widget_api_name, widget)
184 @property
185 def main_window(self):
186 """Returns the main window of this GtkBuilderWidget"""
187 return getattr(self, self.__class__.__name__)
189 def new(self):
191 Method called when the user interface is loaded and ready to be used.
192 At this moment, the widgets are loaded and can be refered as self.widget_name
194 pass
196 def main(self):
198 Starts the main loop of processing events.
199 The default implementation calls gtk.main()
201 Useful for applications that needs a non gtk main loop.
202 For example, applications based on gstreamer needs to override
203 this method with gst.main()
205 Do not directly call this method in your programs.
206 Use the method run() instead.
208 gtk.main()
210 def quit(self):
212 Quit processing events.
213 The default implementation calls gtk.main_quit()
215 Useful for applications that needs a non gtk main loop.
216 For example, applications based on gstreamer needs to override
217 this method with gst.main_quit()
219 gtk.main_quit()
221 def run(self):
223 Starts the main loop of processing events checking for Control-C.
225 The default implementation checks wheter a Control-C is pressed,
226 then calls on_keyboard_interrupt().
228 Use this method for starting programs.
230 try:
231 self.main()
232 except KeyboardInterrupt:
233 self.on_keyboard_interrupt()
235 def on_keyboard_interrupt(self):
237 This method is called by the default implementation of run()
238 after a program is finished by pressing Control-C.
240 pass