Avoid "Creating new from file" messages
[gpodder.git] / src / gpodder / gtkui / base.py
blobeb117920f7e523a14c0cb1fe3522f5c14c74dee7
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()
111 # The following call looks ugly, but see Gnome bug 591085
112 scroll.set_name(gtk.Buildable.get_name(widget))
114 return scroll
116 def container_get_child_pos(container, widget):
117 for pos, child in enumerate(container.get_children()):
118 if child == widget:
119 return pos
120 return -1
122 if isinstance(parent, gtk.Paned):
123 scroll = create_fingerscroll()
124 child.reparent(scroll)
126 if parent.get_child1() == widget:
127 add_to_paned = parent.add1
128 else:
129 add_to_paned = parent.add2
131 parent.remove(widget)
132 add_to_paned(scroll)
133 elif isinstance(parent, gtk.Box):
134 scroll = create_fingerscroll()
135 child.reparent(scroll)
137 position = container_get_child_pos(parent, widget)
138 packing = parent.query_child_packing(widget)
140 parent.remove(widget)
141 parent.add(scroll)
142 parent.set_child_packing(scroll, *packing)
143 parent.reorder_child(scroll, position)
144 elif isinstance(parent, gtk.Table):
145 scroll = create_fingerscroll()
146 child.reparent(scroll)
148 attachment = parent.child_get(widget, 'left-attach', \
149 'right-attach', 'top-attach', 'bottom-attach', \
150 'x-options', 'y-options', 'x-padding', 'y-padding')
151 parent.remove(widget)
152 parent.attach(scroll, *attachment)
154 if scroll is not None:
155 if isinstance(child, gtk.TextView):
156 child.set_editable(False)
157 child.set_cursor_visible(False)
158 child.set_sensitive(False)
159 widget.destroy()
160 scroll.show()
161 return scroll
163 return widget
165 def set_attributes(self):
167 Convert widget names to attributes of this object.
169 It means a widget named vbox-dialog in GtkBuilder
170 is refered using self.vbox_dialog in the code.
172 for widget in self.builder.get_objects():
173 # Just to be safe - every widget from the builder is buildable
174 if not isinstance(widget, gtk.Buildable):
175 continue
177 if isinstance(widget, gtk.ScrolledWindow):
178 widget = self._handle_scrolledwindow(widget)
180 # The following call looks ugly, but see Gnome bug 591085
181 widget_name = gtk.Buildable.get_name(widget)
183 widget_api_name = '_'.join(re.findall(tokenize.Name, widget_name))
184 if hasattr(self, widget_api_name):
185 raise AttributeError("instance %s already has an attribute %s" % (self,widget_api_name))
186 else:
187 setattr(self, widget_api_name, widget)
189 @property
190 def main_window(self):
191 """Returns the main window of this GtkBuilderWidget"""
192 return getattr(self, self.__class__.__name__)
194 def new(self):
196 Method called when the user interface is loaded and ready to be used.
197 At this moment, the widgets are loaded and can be refered as self.widget_name
199 pass
201 def main(self):
203 Starts the main loop of processing events.
204 The default implementation calls gtk.main()
206 Useful for applications that needs a non gtk main loop.
207 For example, applications based on gstreamer needs to override
208 this method with gst.main()
210 Do not directly call this method in your programs.
211 Use the method run() instead.
213 gtk.main()
215 def quit(self):
217 Quit processing events.
218 The default implementation calls gtk.main_quit()
220 Useful for applications that needs a non gtk main loop.
221 For example, applications based on gstreamer needs to override
222 this method with gst.main_quit()
224 gtk.main_quit()
226 def run(self):
228 Starts the main loop of processing events checking for Control-C.
230 The default implementation checks wheter a Control-C is pressed,
231 then calls on_keyboard_interrupt().
233 Use this method for starting programs.
235 try:
236 self.main()
237 except KeyboardInterrupt:
238 self.on_keyboard_interrupt()
240 def on_keyboard_interrupt(self):
242 This method is called by the default implementation of run()
243 after a program is finished by pressing Control-C.
245 pass