1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
4 # Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
5 # 2010 Simon van der Linden <svdlinden@src.gnome.org>
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 from gi.repository import GObject
24 from ..overrides import override
25 from ..importer import modules
27 if sys.version_info >= (3, 0):
29 _callable = lambda c: hasattr(c, '__call__')
31 _basestring = basestring
34 Gtk = modules['Gtk']._introspection_module
37 if Gtk._version == '2.0':
39 warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \
40 was not designed for use with introspection some of the \
41 interfaces and API will fail. As such this is not supported \
42 by the pygobject development team and we encourage you to \
43 port your app to Gtk 3 or greater. PyGTK is the recomended \
44 python module to use with Gtk 2.0"
46 warnings.warn(warn_msg, RuntimeWarning)
49 class Widget(Gtk.Widget):
51 def translate_coordinates(self, dest_widget, src_x, src_y):
52 success, dest_x, dest_y = super(Widget, self).translate_coordinates(
53 dest_widget, src_x, src_y)
55 return (dest_x, dest_y,)
57 def render_icon(self, stock_id, size, detail=None):
58 return super(Widget, self).render_icon(stock_id, size, detail)
60 Widget = override(Widget)
61 __all__.append('Widget')
64 class Container(Gtk.Container, Widget):
67 return len(self.get_children())
69 def __contains__(self, child):
70 return child in self.get_children()
73 return iter(self.get_children())
78 # alias for Python 2.x object protocol
79 __nonzero__ = __bool__
81 def get_focus_chain(self):
82 success, widgets = super(Container, self).get_focus_chain()
86 Container = override(Container)
87 __all__.append('Container')
90 class Editable(Gtk.Editable):
92 def insert_text(self, text, position):
93 pos = super(Editable, self).insert_text(text, -1, position)
97 def get_selection_bounds(self):
98 success, start_pos, end_pos = super(Editable, self).get_selection_bounds()
100 return (start_pos, end_pos,)
104 Editable = override(Editable)
105 __all__.append("Editable")
108 class Action(Gtk.Action):
109 def __init__(self, name, label, tooltip, stock_id, **kwds):
110 Gtk.Action.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, **kwds)
112 Action = override(Action)
113 __all__.append("Action")
116 class RadioAction(Gtk.RadioAction):
117 def __init__(self, name, label, tooltip, stock_id, value, **kwds):
118 Gtk.RadioAction.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=value, **kwds)
120 RadioAction = override(RadioAction)
121 __all__.append("RadioAction")
124 class ActionGroup(Gtk.ActionGroup):
125 def __init__(self, name, **kwds):
126 super(ActionGroup, self).__init__(name=name, **kwds)
128 def add_actions(self, entries, user_data=None):
130 The add_actions() method is a convenience method that creates a number
131 of gtk.Action objects based on the information in the list of action
132 entry tuples contained in entries and adds them to the action group.
133 The entry tuples can vary in size from one to six items with the
134 following information:
136 * The name of the action. Must be specified.
137 * The stock id for the action. Optional with a default value of None
138 if a label is specified.
139 * The label for the action. This field should typically be marked
140 for translation, see the set_translation_domain() method. Optional
141 with a default value of None if a stock id is specified.
142 * The accelerator for the action, in the format understood by the
143 gtk.accelerator_parse() function. Optional with a default value of
145 * The tooltip for the action. This field should typically be marked
146 for translation, see the set_translation_domain() method. Optional
147 with a default value of None.
148 * The callback function invoked when the action is activated.
149 Optional with a default value of None.
151 The "activate" signals of the actions are connected to the callbacks and
152 their accel paths are set to <Actions>/group-name/action-name.
157 raise TypeError('entries must be iterable')
159 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None):
160 action = Action(name, label, tooltip, stock_id)
161 if callback is not None:
162 if user_data is None:
163 action.connect('activate', callback)
165 action.connect('activate', callback, user_data)
167 self.add_action_with_accel(action, accelerator)
170 # using inner function above since entries can leave out optional arguments
173 def add_toggle_actions(self, entries, user_data=None):
175 The add_toggle_actions() method is a convenience method that creates a
176 number of gtk.ToggleAction objects based on the information in the list
177 of action entry tuples contained in entries and adds them to the action
178 group. The toggle action entry tuples can vary in size from one to seven
179 items with the following information:
181 * The name of the action. Must be specified.
182 * The stock id for the action. Optional with a default value of None
183 if a label is specified.
184 * The label for the action. This field should typically be marked
185 for translation, see the set_translation_domain() method. Optional
186 with a default value of None if a stock id is specified.
187 * The accelerator for the action, in the format understood by the
188 gtk.accelerator_parse() function. Optional with a default value of
190 * The tooltip for the action. This field should typically be marked
191 for translation, see the set_translation_domain() method. Optional
192 with a default value of None.
193 * The callback function invoked when the action is activated.
194 Optional with a default value of None.
195 * A flag indicating whether the toggle action is active. Optional
196 with a default value of False.
198 The "activate" signals of the actions are connected to the callbacks and
199 their accel paths are set to <Actions>/group-name/action-name.
205 raise TypeError('entries must be iterable')
207 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False):
208 action = Gtk.ToggleAction(name, label, tooltip, stock_id)
209 action.set_active(is_active)
210 if callback is not None:
211 if user_data is None:
212 action.connect('activate', callback)
214 action.connect('activate', callback, user_data)
216 self.add_action_with_accel(action, accelerator)
219 # using inner function above since entries can leave out optional arguments
222 def add_radio_actions(self, entries, value=None, on_change=None, user_data=None):
224 The add_radio_actions() method is a convenience method that creates a
225 number of gtk.RadioAction objects based on the information in the list
226 of action entry tuples contained in entries and adds them to the action
227 group. The entry tuples can vary in size from one to six items with the
228 following information:
230 * The name of the action. Must be specified.
231 * The stock id for the action. Optional with a default value of None
232 if a label is specified.
233 * The label for the action. This field should typically be marked
234 for translation, see the set_translation_domain() method. Optional
235 with a default value of None if a stock id is specified.
236 * The accelerator for the action, in the format understood by the
237 gtk.accelerator_parse() function. Optional with a default value of
239 * The tooltip for the action. This field should typically be marked
240 for translation, see the set_translation_domain() method. Optional
241 with a default value of None.
242 * The value to set on the radio action. Optional with a default
243 value of 0. Should be specified in applications.
245 The value parameter specifies the radio action that should be set
246 active. The "changed" signal of the first radio action is connected to
247 the on_change callback (if specified and not None) and the accel paths
248 of the actions are set to <Actions>/group-name/action-name.
253 raise TypeError('entries must be iterable')
257 def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
258 action = RadioAction(name, label, tooltip, stock_id, entry_value)
260 # FIXME: join_group is a patch to Gtk+ 3.0
261 # otherwise we can't effectively add radio actions to a
262 # group. Should we depend on 3.0 and error out here
263 # or should we offer the functionality via a compat
265 if hasattr(action, 'join_group'):
266 action.join_group(group_source)
268 if value == entry_value:
269 action.set_active(True)
271 self.add_action_with_accel(action, accelerator)
275 # using inner function above since entries can leave out optional arguments
276 action = _process_action(first_action, *e)
277 if first_action is None:
278 first_action = action
280 if first_action is not None and on_change is not None:
281 if user_data is None:
282 first_action.connect('changed', on_change)
284 first_action.connect('changed', on_change, user_data)
286 ActionGroup = override(ActionGroup)
287 __all__.append('ActionGroup')
290 class UIManager(Gtk.UIManager):
291 def add_ui_from_string(self, buffer):
292 if not isinstance(buffer, _basestring):
293 raise TypeError('buffer must be a string')
297 return Gtk.UIManager.add_ui_from_string(self, buffer, length)
299 def insert_action_group(self, buffer, length=-1):
300 return Gtk.UIManager.insert_action_group(self, buffer, length)
302 UIManager = override(UIManager)
303 __all__.append('UIManager')
306 class ComboBox(Gtk.ComboBox, Container):
308 def get_active_iter(self):
309 success, aiter = super(ComboBox, self).get_active_iter()
313 ComboBox = override(ComboBox)
314 __all__.append('ComboBox')
318 def __init__(self, homogeneous=False, spacing=0, **kwds):
319 super(Box, self).__init__(**kwds)
320 self.set_homogeneous(homogeneous)
321 self.set_spacing(spacing)
324 __all__.append('Box')
327 class SizeGroup(Gtk.SizeGroup):
328 def __init__(self, mode=Gtk.SizeGroupMode.VERTICAL):
329 super(SizeGroup, self).__init__(mode=mode)
331 SizeGroup = override(SizeGroup)
332 __all__.append('SizeGroup')
335 class MenuItem(Gtk.MenuItem):
336 def __init__(self, label=None, **kwds):
338 super(MenuItem, self).__init__(label=label, **kwds)
340 super(MenuItem, self).__init__(**kwds)
342 MenuItem = override(MenuItem)
343 __all__.append('MenuItem')
346 class Builder(Gtk.Builder):
348 def connect_signals(self, obj_or_map):
349 def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map):
351 if isinstance(obj_or_map, dict):
352 handler = obj_or_map.get(handler_name, None)
354 handler = getattr(obj_or_map, handler_name, None)
357 raise AttributeError('Handler %s not found' % handler_name)
359 if not _callable(handler):
360 raise TypeError('Handler %s is not a method or function' % handler_name)
362 after = flags & GObject.ConnectFlags.AFTER
363 if connect_obj is not None:
365 gobj.connect_object_after(signal_name, handler, connect_obj)
367 gobj.connect_object(signal_name, handler, connect_obj)
370 gobj.connect_after(signal_name, handler)
372 gobj.connect(signal_name, handler)
374 self.connect_signals_full(_full_callback, obj_or_map)
376 def add_from_string(self, buffer):
377 if not isinstance(buffer, _basestring):
378 raise TypeError('buffer must be a string')
382 return Gtk.Builder.add_from_string(self, buffer, length)
384 def add_objects_from_string(self, buffer, object_ids):
385 if not isinstance(buffer, _basestring):
386 raise TypeError('buffer must be a string')
390 return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids)
392 Builder = override(Builder)
393 __all__.append('Builder')
396 # NOTE: This must come before any other Window/Dialog subclassing, to ensure
397 # that we have a correct inheritance hierarchy.
400 class Window(Gtk.Window):
401 def __init__(self, type=Gtk.WindowType.TOPLEVEL, **kwds):
402 # type is a construct-only property; if it is already set (e. g. by
403 # GtkBuilder), do not try to set it again and just ignore it
405 self.get_property('type')
406 Gtk.Window.__init__(self, **kwds)
408 Gtk.Window.__init__(self, type=type, **kwds)
410 Window = override(Window)
411 __all__.append('Window')
414 class Dialog(Gtk.Dialog, Container):
421 _buttons_property=None,
424 # buttons is overloaded by PyGtk so we have to do the same here
425 # this breaks some subclasses of Dialog so add a _buttons_property
426 # keyword to work around this
427 if _buttons_property is not None:
428 kwds['buttons'] = _buttons_property
430 Gtk.Dialog.__init__(self, **kwds)
432 self.set_title(title)
434 self.set_transient_for(parent)
435 if flags & Gtk.DialogFlags.MODAL:
437 if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT:
438 self.set_destroy_with_parent(True)
440 # NO_SEPARATOR has been removed from Gtk 3
441 if hasattr(Gtk.DialogFlags, "NO_SEPARATOR") and (flags & Gtk.DialogFlags.NO_SEPARATOR):
442 self.set_has_separator(False)
444 warnings.warn("Gtk.DialogFlags.NO_SEPARATOR has been depricated since Gtk+-3.0", DeprecationWarning)
446 if buttons is not None:
447 self.add_buttons(*buttons)
449 action_area = property(lambda dialog: dialog.get_action_area())
450 vbox = property(lambda dialog: dialog.get_content_area())
452 def add_buttons(self, *args):
454 The add_buttons() method adds several buttons to the Gtk.Dialog using
455 the button data passed as arguments to the method. This method is the
456 same as calling the Gtk.Dialog.add_button() repeatedly. The button data
457 pairs - button text (or stock ID) and a response ID integer are passed
458 individually. For example:
460 >>> dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE)
462 will add "Open" and "Close" buttons to dialog.
471 for text, response in _button(args):
472 self.add_button(text, response)
474 raise TypeError('Must pass an even number of arguments')
476 Dialog = override(Dialog)
477 __all__.append('Dialog')
480 class MessageDialog(Gtk.MessageDialog, Dialog):
484 message_type=Gtk.MessageType.INFO,
485 buttons=Gtk.ButtonsType.NONE,
490 kwds['text'] = message_format
492 # type keyword is used for backwards compat with PyGTK
495 warnings.warn("The use of the keyword type as a parameter of the Gtk.MessageDialog constructor has been depricated. Please use message_type instead.", DeprecationWarning)
496 message_type = kwds.pop('type')
498 Gtk.MessageDialog.__init__(self,
499 _buttons_property=buttons,
500 message_type=message_type,
505 def format_secondary_text(self, message_format):
506 self.set_property('secondary-use-markup', False)
507 self.set_property('secondary-text', message_format)
509 def format_secondary_markup(self, message_format):
510 self.set_property('secondary-use-markup', True)
511 self.set_property('secondary-text', message_format)
513 MessageDialog = override(MessageDialog)
514 __all__.append('MessageDialog')
517 class AboutDialog(Gtk.AboutDialog):
518 def __init__(self, **kwds):
519 Gtk.AboutDialog.__init__(self, **kwds)
521 AboutDialog = override(AboutDialog)
522 __all__.append('AboutDialog')
525 class ColorSelectionDialog(Gtk.ColorSelectionDialog):
526 def __init__(self, title=None, **kwds):
527 Gtk.ColorSelectionDialog.__init__(self, title=title, **kwds)
529 ColorSelectionDialog = override(ColorSelectionDialog)
530 __all__.append('ColorSelectionDialog')
533 class FileChooserDialog(Gtk.FileChooserDialog):
537 action=Gtk.FileChooserAction.OPEN,
540 Gtk.FileChooserDialog.__init__(self,
546 FileChooserDialog = override(FileChooserDialog)
547 __all__.append('FileChooserDialog')
550 class FontSelectionDialog(Gtk.FontSelectionDialog):
551 def __init__(self, title=None, **kwds):
552 Gtk.FontSelectionDialog.__init__(self, title=title, **kwds)
554 FontSelectionDialog = override(FontSelectionDialog)
555 __all__.append('FontSelectionDialog')
558 class RecentChooserDialog(Gtk.RecentChooserDialog):
566 Gtk.RecentChooserDialog.__init__(self,
567 recent_manager=manager,
573 RecentChooserDialog = override(RecentChooserDialog)
574 __all__.append('RecentChooserDialog')
577 class IconView(Gtk.IconView):
579 def __init__(self, model=None, **kwds):
580 Gtk.IconView.__init__(self, model=model, **kwds)
582 def get_item_at_pos(self, x, y):
583 success, path, cell = super(IconView, self).get_item_at_pos(x, y)
587 def get_visible_range(self):
588 success, start_path, end_path = super(IconView, self).get_visible_range()
590 return (start_path, end_path,)
592 def get_dest_item_at_pos(self, drag_x, drag_y):
593 success, path, pos = super(IconView, self).get_dest_item_at_pos(drag_x, drag_y)
597 IconView = override(IconView)
598 __all__.append('IconView')
601 class ToolButton(Gtk.ToolButton):
603 def __init__(self, stock_id=None, **kwds):
604 Gtk.ToolButton.__init__(self, stock_id=stock_id, **kwds)
606 ToolButton = override(ToolButton)
607 __all__.append('ToolButton')
610 class IMContext(Gtk.IMContext):
612 def get_surrounding(self):
613 success, text, cursor_index = super(IMContext, self).get_surrounding()
615 return (text, cursor_index,)
617 IMContext = override(IMContext)
618 __all__.append('IMContext')
621 class RecentInfo(Gtk.RecentInfo):
623 def get_application_info(self, app_name):
624 success, app_exec, count, time = super(RecentInfo, self).get_application_info(app_name)
626 return (app_exec, count, time,)
628 RecentInfo = override(RecentInfo)
629 __all__.append('RecentInfo')
632 class TextBuffer(Gtk.TextBuffer):
633 def _get_or_create_tag_table(self):
634 table = self.get_tag_table()
636 table = Gtk.TextTagTable()
637 self.set_tag_table(table)
641 def create_tag(self, tag_name=None, **properties):
643 @tag_name: name of the new tag, or None
644 @properties: keyword list of properties and their values
646 Creates a tag and adds it to the tag table of the TextBuffer.
647 Equivalent to creating a Gtk.TextTag and then adding the
648 tag to the buffer's tag table. The returned tag is owned by
649 the buffer's tag table.
651 If @tag_name is None, the tag is anonymous.
653 If @tag_name is not None, a tag called @tag_name must not already
654 exist in the tag table for this buffer.
656 Properties are passed as a keyword list of names and values (e.g.
657 foreground = 'DodgerBlue', weight = Pango.Weight.BOLD)
659 Return value: a new tag
662 tag = Gtk.TextTag(name=tag_name, **properties)
663 self._get_or_create_tag_table().add(tag)
666 def create_mark(self, mark_name, where, left_gravity=False):
667 return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity)
669 def set_text(self, text, length=-1):
670 Gtk.TextBuffer.set_text(self, text, length)
672 def insert(self, iter, text, length=-1):
673 if not isinstance(text, _basestring):
674 raise TypeError('text must be a string, not %s' % type(text))
676 Gtk.TextBuffer.insert(self, iter, text, length)
678 def insert_with_tags(self, iter, text, *tags):
679 start_offset = iter.get_offset()
680 self.insert(iter, text)
685 start = self.get_iter_at_offset(start_offset)
688 self.apply_tag(tag, start, iter)
690 def insert_with_tags_by_name(self, iter, text, *tags):
697 tag_obj = self.get_tag_table().lookup(tag)
699 raise ValueError('unknown text tag: %s' % tag)
700 tag_objs.append(tag_obj)
702 self.insert_with_tags(iter, text, *tag_objs)
704 def insert_at_cursor(self, text, length=-1):
705 if not isinstance(text, _basestring):
706 raise TypeError('text must be a string, not %s' % type(text))
708 Gtk.TextBuffer.insert_at_cursor(self, text, length)
710 def get_selection_bounds(self):
711 success, start, end = super(TextBuffer, self).get_selection_bounds()
717 TextBuffer = override(TextBuffer)
718 __all__.append('TextBuffer')
721 class TextIter(Gtk.TextIter):
723 def forward_search(self, string, flags, limit):
724 success, match_start, match_end = super(TextIter, self).forward_search(string,
727 return (match_start, match_end)
731 def backward_search(self, string, flags, limit):
732 success, match_start, match_end = super(TextIter, self).backward_search(string,
735 return (match_start, match_end)
739 def begins_tag(self, tag=None):
740 return super(TextIter, self).begins_tag(tag)
742 def ends_tag(self, tag=None):
743 return super(TextIter, self).ends_tag(tag)
745 def toggles_tag(self, tag=None):
746 return super(TextIter, self).toggles_tag(tag)
748 TextIter = override(TextIter)
749 __all__.append('TextIter')
752 class TreeModel(Gtk.TreeModel):
754 return self.iter_n_children(None)
759 # alias for Python 2.x object protocol
760 __nonzero__ = __bool__
762 def _getiter(self, key):
763 if isinstance(key, Gtk.TreeIter):
765 elif isinstance(key, int) and key < 0:
766 index = len(self) + key
768 raise IndexError("row index is out of bounds: %d" % key)
770 aiter = self.get_iter(index)
772 raise IndexError("could not find tree path '%s'" % key)
776 aiter = self.get_iter(key)
778 raise IndexError("could not find tree path '%s'" % key)
781 def __getitem__(self, key):
782 aiter = self._getiter(key)
783 return TreeModelRow(self, aiter)
785 def __setitem__(self, key, value):
787 self.set_row(row.iter, value)
789 def __delitem__(self, key):
790 aiter = self._getiter(key)
794 return TreeModelRowIter(self, self.get_iter_first())
796 def get_iter(self, path):
797 if not isinstance(path, Gtk.TreePath):
798 path = TreePath(path)
800 success, aiter = super(TreeModel, self).get_iter(path)
802 raise ValueError("invalid tree path '%s'" % path)
805 def get_iter_first(self):
806 success, aiter = super(TreeModel, self).get_iter_first()
810 def get_iter_from_string(self, path_string):
811 success, aiter = super(TreeModel, self).get_iter_from_string(path_string)
813 raise ValueError("invalid tree path '%s'" % path_string)
816 def iter_next(self, aiter):
817 next_iter = aiter.copy()
818 success = super(TreeModel, self).iter_next(next_iter)
822 def iter_previous(self, aiter):
823 prev_iter = aiter.copy()
824 success = super(TreeModel, self).iter_previous(prev_iter)
828 def iter_children(self, aiter):
829 success, child_iter = super(TreeModel, self).iter_children(aiter)
833 def iter_nth_child(self, parent, n):
834 success, child_iter = super(TreeModel, self).iter_nth_child(parent, n)
838 def iter_parent(self, aiter):
839 success, parent_iter = super(TreeModel, self).iter_parent(aiter)
843 def _convert_row(self, row):
844 # TODO: Accept a dictionary for row
845 # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name})
846 if isinstance(row, str):
847 raise TypeError('Expected a list or tuple, but got str')
849 n_columns = self.get_n_columns()
850 if len(row) != n_columns:
851 raise ValueError('row sequence has the incorrect number of elements')
855 for cur_col, value in enumerate(row):
856 # do not try to set None values, they are causing warnings
859 result.append(self._convert_value(cur_col, value))
860 columns.append(cur_col)
861 return (result, columns)
863 def set_row(self, treeiter, row):
864 converted_row, columns = self._convert_row(row)
865 for column in columns:
868 continue # None means skip this row
870 self.set_value(treeiter, column, value)
872 def _convert_value(self, column, value):
876 # we may need to convert to a basic type
877 type_ = self.get_column_type(column)
878 if type_ == GObject.TYPE_STRING:
879 if isinstance(value, str):
881 elif sys.version_info < (3, 0):
882 if isinstance(value, unicode):
883 value = value.encode('UTF-8')
885 raise ValueError('Expected string or unicode for column %i but got %s%s' % (column, value, type(value)))
887 raise ValueError('Expected a string for column %i but got %s' % (column, type(value)))
888 elif type_ == GObject.TYPE_FLOAT or type_ == GObject.TYPE_DOUBLE:
889 if isinstance(value, float):
892 raise ValueError('Expected a float for column %i but got %s' % (column, type(value)))
893 elif type_ == GObject.TYPE_LONG or type_ == GObject.TYPE_INT:
894 if isinstance(value, int):
896 elif sys.version_info < (3, 0):
897 if isinstance(value, long):
900 raise ValueError('Expected an long for column %i but got %s' % (column, type(value)))
902 raise ValueError('Expected an integer for column %i but got %s' % (column, type(value)))
903 elif type_ == GObject.TYPE_BOOLEAN:
905 if sys.version_info < (3, 0):
906 cmp_classes.append(long)
908 if isinstance(value, tuple(cmp_classes)):
911 raise ValueError('Expected a bool for column %i but got %s' % (column, type(value)))
913 # use GValues directly to marshal to the correct type
914 # standard object checks should take care of validation
915 # so we don't have to do it here
916 value_container = GObject.Value()
917 value_container.init(type_)
918 if type_ == GObject.TYPE_CHAR:
919 value_container.set_char(value)
920 value = value_container
921 elif type_ == GObject.TYPE_UCHAR:
922 value_container.set_uchar(value)
923 value = value_container
924 elif type_ == GObject.TYPE_UNICHAR:
926 if sys.version_info < (3, 0):
927 cmp_classes.append(unicode)
929 if isinstance(value, tuple(cmp_classes)):
930 value = ord(value[0])
932 value_container.set_uint(value)
933 value = value_container
934 elif type_ == GObject.TYPE_UINT:
935 value_container.set_uint(value)
936 value = value_container
937 elif type_ == GObject.TYPE_ULONG:
938 value_container.set_ulong(value)
939 value = value_container
940 elif type_ == GObject.TYPE_INT64:
941 value_container.set_int64(value)
942 value = value_container
943 elif type_ == GObject.TYPE_UINT64:
944 value_container.set_uint64(value)
945 value = value_container
946 elif type_ == GObject.TYPE_PYOBJECT:
947 value_container.set_boxed(value)
948 value = value_container
952 def get(self, treeiter, *columns):
953 n_columns = self.get_n_columns()
957 if not isinstance(col, int):
958 raise TypeError("column numbers must be ints")
960 if col < 0 or col >= n_columns:
961 raise ValueError("column number is out of range")
963 values.append(self.get_value(treeiter, col))
967 def filter_new(self, root=None):
968 return super(TreeModel, self).filter_new(root)
970 TreeModel = override(TreeModel)
971 __all__.append('TreeModel')
974 class TreeSortable(Gtk.TreeSortable, ):
976 def get_sort_column_id(self):
977 success, sort_column_id, order = super(TreeSortable, self).get_sort_column_id()
979 return (sort_column_id, order,)
983 def set_sort_func(self, sort_column_id, sort_func, user_data=None):
984 super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data)
986 def set_default_sort_func(self, sort_func, user_data=None):
987 super(TreeSortable, self).set_default_sort_func(sort_func, user_data)
989 TreeSortable = override(TreeSortable)
990 __all__.append('TreeSortable')
993 class TreeModelSort(Gtk.TreeModelSort):
994 def __init__(self, model, **kwds):
995 Gtk.TreeModelSort.__init__(self, model=model, **kwds)
997 TreeModelSort = override(TreeModelSort)
998 __all__.append('TreeModelSort')
1001 class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
1002 def __init__(self, *column_types):
1003 Gtk.ListStore.__init__(self)
1004 self.set_column_types(column_types)
1006 def _do_insert(self, position, row):
1008 row, columns = self._convert_row(row)
1009 treeiter = self.insert_with_valuesv(position, columns, row)
1011 treeiter = Gtk.ListStore.insert(self, position)
1015 def append(self, row=None):
1017 return self._do_insert(-1, row)
1018 # gtk_list_store_insert() does not know about the "position == -1"
1019 # case, so use append() here
1021 return Gtk.ListStore.append(self)
1023 def prepend(self, row=None):
1024 return self._do_insert(0, row)
1026 def insert(self, position, row=None):
1027 return self._do_insert(position, row)
1029 # FIXME: sends two signals; check if this can use an atomic
1030 # insert_with_valuesv()
1032 def insert_before(self, sibling, row=None):
1033 treeiter = Gtk.ListStore.insert_before(self, sibling)
1036 self.set_row(treeiter, row)
1040 # FIXME: sends two signals; check if this can use an atomic
1041 # insert_with_valuesv()
1043 def insert_after(self, sibling, row=None):
1044 treeiter = Gtk.ListStore.insert_after(self, sibling)
1047 self.set_row(treeiter, row)
1051 def set_value(self, treeiter, column, value):
1052 value = self._convert_value(column, value)
1053 Gtk.ListStore.set_value(self, treeiter, column, value)
1055 def set(self, treeiter, *args):
1057 def _set_lists(columns, values):
1058 if len(columns) != len(values):
1059 raise TypeError('The number of columns do not match the number of values')
1060 for col_num, val in zip(columns, values):
1061 if not isinstance(col_num, int):
1062 raise TypeError('TypeError: Expected integer argument for column.')
1063 self.set_value(treeiter, col_num, val)
1066 if isinstance(args[0], int):
1069 _set_lists(columns, values)
1070 elif isinstance(args[0], (tuple, list)):
1072 raise TypeError('Too many arguments')
1073 _set_lists(args[0], args[1])
1074 elif isinstance(args[0], dict):
1075 columns = args[0].keys()
1076 values = args[0].values()
1077 _set_lists(columns, values)
1079 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1081 ListStore = override(ListStore)
1082 __all__.append('ListStore')
1085 class TreeModelRow(object):
1087 def __init__(self, model, iter_or_path):
1088 if not isinstance(model, Gtk.TreeModel):
1089 raise TypeError("expected Gtk.TreeModel, %s found" % type(model).__name__)
1091 if isinstance(iter_or_path, Gtk.TreePath):
1092 self.iter = model.get_iter(iter_or_path)
1093 elif isinstance(iter_or_path, Gtk.TreeIter):
1094 self.iter = iter_or_path
1096 raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \
1097 %s found" % type(iter_or_path).__name__)
1101 return self.model.get_path(self.iter)
1105 return self.get_next()
1109 return self.get_previous()
1113 return self.get_parent()
1116 next_iter = self.model.iter_next(self.iter)
1118 return TreeModelRow(self.model, next_iter)
1120 def get_previous(self):
1121 prev_iter = self.model.iter_previous(self.iter)
1123 return TreeModelRow(self.model, prev_iter)
1125 def get_parent(self):
1126 parent_iter = self.model.iter_parent(self.iter)
1128 return TreeModelRow(self.model, parent_iter)
1130 def __getitem__(self, key):
1131 if isinstance(key, int):
1132 if key >= self.model.get_n_columns():
1133 raise IndexError("column index is out of bounds: %d" % key)
1135 key = self._convert_negative_index(key)
1136 return self.model.get_value(self.iter, key)
1137 elif isinstance(key, slice):
1138 start, stop, step = key.indices(self.model.get_n_columns())
1140 for i in range(start, stop, step):
1141 alist.append(self.model.get_value(self.iter, i))
1144 raise TypeError("indices must be integers, not %s" % type(key).__name__)
1146 def __setitem__(self, key, value):
1147 if isinstance(key, int):
1148 if key >= self.model.get_n_columns():
1149 raise IndexError("column index is out of bounds: %d" % key)
1151 key = self._convert_negative_index(key)
1152 self.model.set_value(self.iter, key, value)
1153 elif isinstance(key, slice):
1154 start, stop, step = key.indices(self.model.get_n_columns())
1155 indexList = range(start, stop, step)
1156 if len(indexList) != len(value):
1158 "attempt to assign sequence of size %d to slice of size %d"
1159 % (len(value), len(indexList)))
1161 for i, v in enumerate(indexList):
1162 self.model.set_value(self.iter, v, value[i])
1164 raise TypeError("index must be an integer or slice, not %s" % type(key).__name__)
1166 def _convert_negative_index(self, index):
1167 new_index = self.model.get_n_columns() + index
1169 raise IndexError("column index is out of bounds: %d" % index)
1172 def iterchildren(self):
1173 child_iter = self.model.iter_children(self.iter)
1174 return TreeModelRowIter(self.model, child_iter)
1176 __all__.append('TreeModelRow')
1179 class TreeModelRowIter(object):
1181 def __init__(self, model, aiter):
1188 row = TreeModelRow(self.model, self.iter)
1189 self.iter = self.model.iter_next(self.iter)
1192 # alias for Python 2.x object protocol
1198 __all__.append('TreeModelRowIter')
1201 class TreePath(Gtk.TreePath):
1203 def __new__(cls, path=0):
1204 if isinstance(path, int):
1206 elif isinstance(path, tuple):
1207 path = ":".join(str(val) for val in path)
1210 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1212 return TreePath.new_from_string(path)
1214 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1217 return self.to_string()
1219 def __lt__(self, other):
1220 return not other is None and self.compare(other) < 0
1222 def __le__(self, other):
1223 return not other is None and self.compare(other) <= 0
1225 def __eq__(self, other):
1226 return not other is None and self.compare(other) == 0
1228 def __ne__(self, other):
1229 return other is None or self.compare(other) != 0
1231 def __gt__(self, other):
1232 return other is None or self.compare(other) > 0
1234 def __ge__(self, other):
1235 return other is None or self.compare(other) >= 0
1238 return iter(self.get_indices())
1241 return self.get_depth()
1243 def __getitem__(self, index):
1244 return self.get_indices()[index]
1246 TreePath = override(TreePath)
1247 __all__.append('TreePath')
1250 class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
1252 def __init__(self, *column_types):
1253 Gtk.TreeStore.__init__(self)
1254 self.set_column_types(column_types)
1256 def _do_insert(self, parent, position, row):
1258 row, columns = self._convert_row(row)
1259 treeiter = self.insert_with_values(parent, position, columns, row)
1261 treeiter = Gtk.TreeStore.insert(self, parent, position)
1265 def append(self, parent, row=None):
1266 return self._do_insert(parent, -1, row)
1268 def prepend(self, parent, row=None):
1269 return self._do_insert(parent, 0, row)
1271 def insert(self, parent, position, row=None):
1272 return self._do_insert(parent, position, row)
1274 # FIXME: sends two signals; check if this can use an atomic
1275 # insert_with_valuesv()
1277 def insert_before(self, parent, sibling, row=None):
1278 treeiter = Gtk.TreeStore.insert_before(self, parent, sibling)
1281 self.set_row(treeiter, row)
1285 # FIXME: sends two signals; check if this can use an atomic
1286 # insert_with_valuesv()
1288 def insert_after(self, parent, sibling, row=None):
1289 treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
1292 self.set_row(treeiter, row)
1296 def set_value(self, treeiter, column, value):
1297 value = self._convert_value(column, value)
1298 Gtk.TreeStore.set_value(self, treeiter, column, value)
1300 def set(self, treeiter, *args):
1302 def _set_lists(columns, values):
1303 if len(columns) != len(values):
1304 raise TypeError('The number of columns do not match the number of values')
1305 for col_num, val in zip(columns, values):
1306 if not isinstance(col_num, int):
1307 raise TypeError('TypeError: Expected integer argument for column.')
1308 self.set_value(treeiter, col_num, val)
1311 if isinstance(args[0], int):
1314 _set_lists(columns, values)
1315 elif isinstance(args[0], (tuple, list)):
1317 raise TypeError('Too many arguments')
1318 _set_lists(args[0], args[1])
1319 elif isinstance(args[0], dict):
1320 columns = args[0].keys()
1321 values = args[0].values()
1322 _set_lists(columns, values)
1324 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1326 TreeStore = override(TreeStore)
1327 __all__.append('TreeStore')
1330 class TreeView(Gtk.TreeView, Container):
1332 def __init__(self, model=None):
1333 Gtk.TreeView.__init__(self)
1335 self.set_model(model)
1337 def get_path_at_pos(self, x, y):
1338 success, path, column, cell_x, cell_y = super(TreeView, self).get_path_at_pos(x, y)
1340 return (path, column, cell_x, cell_y,)
1342 def get_visible_range(self):
1343 success, start_path, end_path = super(TreeView, self).get_visible_range()
1345 return (start_path, end_path,)
1347 def get_dest_row_at_pos(self, drag_x, drag_y):
1348 success, path, pos = super(TreeView, self).get_dest_row_at_pos(drag_x, drag_y)
1352 def _construct_target_list(self, targets):
1353 # FIXME: this should most likely be part of Widget or a global helper
1357 entry = Gtk.TargetEntry.new(*t)
1358 target_entries.append(entry)
1359 return target_entries
1361 def enable_model_drag_source(self, start_button_mask, targets, actions):
1362 target_entries = self._construct_target_list(targets)
1363 super(TreeView, self).enable_model_drag_source(start_button_mask,
1367 def enable_model_drag_dest(self, targets, actions):
1368 target_entries = self._construct_target_list(targets)
1369 super(TreeView, self).enable_model_drag_dest(target_entries,
1372 def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0):
1373 if not isinstance(path, Gtk.TreePath):
1374 path = TreePath(path)
1375 super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align)
1377 def set_cursor(self, path, column=None, start_editing=False):
1378 if not isinstance(path, Gtk.TreePath):
1379 path = TreePath(path)
1380 super(TreeView, self).set_cursor(path, column, start_editing)
1382 def get_cell_area(self, path, column=None):
1383 if not isinstance(path, Gtk.TreePath):
1384 path = TreePath(path)
1385 return super(TreeView, self).get_cell_area(path, column)
1387 def insert_column_with_attributes(self, position, title, cell, **kwargs):
1388 column = TreeViewColumn()
1389 column.set_title(title)
1390 column.pack_start(cell, False)
1391 self.insert_column(column, position)
1392 column.set_attributes(cell, **kwargs)
1394 TreeView = override(TreeView)
1395 __all__.append('TreeView')
1398 class TreeViewColumn(Gtk.TreeViewColumn):
1399 def __init__(self, title='',
1402 Gtk.TreeViewColumn.__init__(self, title=title)
1404 self.pack_start(cell_renderer, True)
1406 for (name, value) in attributes.items():
1407 self.add_attribute(cell_renderer, name, value)
1409 def cell_get_position(self, cell_renderer):
1410 success, start_pos, width = super(TreeViewColumn, self).cell_get_position(cell_renderer)
1412 return (start_pos, width,)
1414 def set_cell_data_func(self, cell_renderer, func, func_data=None):
1415 super(TreeViewColumn, self).set_cell_data_func(cell_renderer, func, func_data)
1417 def set_attributes(self, cell_renderer, **attributes):
1418 Gtk.CellLayout.clear_attributes(self, cell_renderer)
1420 for (name, value) in attributes.items():
1421 Gtk.CellLayout.add_attribute(self, cell_renderer, name, value)
1424 TreeViewColumn = override(TreeViewColumn)
1425 __all__.append('TreeViewColumn')
1428 class TreeSelection(Gtk.TreeSelection):
1430 def select_path(self, path):
1431 if not isinstance(path, Gtk.TreePath):
1432 path = TreePath(path)
1433 super(TreeSelection, self).select_path(path)
1435 def get_selected(self):
1436 success, model, aiter = super(TreeSelection, self).get_selected()
1438 return (model, aiter)
1440 return (model, None)
1442 # for compatibility with PyGtk
1444 def get_selected_rows(self):
1445 rows, model = super(TreeSelection, self).get_selected_rows()
1446 return (model, rows)
1449 TreeSelection = override(TreeSelection)
1450 __all__.append('TreeSelection')
1453 class Button(Gtk.Button, Container):
1454 def __init__(self, label=None, stock=None, use_stock=False, use_underline=False, **kwds):
1458 use_underline = True
1459 Gtk.Button.__init__(self, label=label, use_stock=use_stock,
1460 use_underline=use_underline, **kwds)
1461 Button = override(Button)
1462 __all__.append('Button')
1465 class LinkButton(Gtk.LinkButton):
1466 def __init__(self, uri, label=None, **kwds):
1467 Gtk.LinkButton.__init__(self, uri=uri, label=label, **kwds)
1469 LinkButton = override(LinkButton)
1470 __all__.append('LinkButton')
1473 class Label(Gtk.Label):
1474 def __init__(self, label=None, **kwds):
1475 Gtk.Label.__init__(self, label=label, **kwds)
1477 Label = override(Label)
1478 __all__.append('Label')
1481 class Adjustment(Gtk.Adjustment):
1482 def __init__(self, *args, **kwds):
1483 arg_names = ('value', 'lower', 'upper',
1484 'step_increment', 'page_increment', 'page_size')
1485 new_args = dict(zip(arg_names, args))
1486 new_args.update(kwds)
1488 # PyGTK compatiblity
1489 if 'page_incr' in new_args:
1490 new_args['page_increment'] = new_args.pop('page_incr')
1491 if 'step_incr' in new_args:
1492 new_args['step_increment'] = new_args.pop('step_incr')
1493 Gtk.Adjustment.__init__(self, **new_args)
1495 # The value property is set between lower and (upper - page_size).
1496 # Just in case lower, upper or page_size was still 0 when value
1497 # was set, we set it again here.
1498 if 'value' in new_args:
1499 self.set_value(new_args['value'])
1501 Adjustment = override(Adjustment)
1502 __all__.append('Adjustment')
1505 class Table(Gtk.Table, Container):
1506 def __init__(self, rows=1, columns=1, homogeneous=False, **kwds):
1507 if 'n_rows' in kwds:
1508 rows = kwds.pop('n_rows')
1510 if 'n_columns' in kwds:
1511 columns = kwds.pop('n_columns')
1513 Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, homogeneous=homogeneous, **kwds)
1515 def attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, yoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, xpadding=0, ypadding=0):
1516 Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding)
1518 Table = override(Table)
1519 __all__.append('Table')
1522 class ScrolledWindow(Gtk.ScrolledWindow):
1523 def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1524 Gtk.ScrolledWindow.__init__(self, hadjustment=hadjustment, vadjustment=vadjustment, **kwds)
1526 ScrolledWindow = override(ScrolledWindow)
1527 __all__.append('ScrolledWindow')
1530 class HScrollbar(Gtk.HScrollbar):
1531 def __init__(self, adjustment=None, **kwds):
1532 Gtk.HScrollbar.__init__(self, adjustment=adjustment, **kwds)
1534 HScrollbar = override(HScrollbar)
1535 __all__.append('HScrollbar')
1538 class VScrollbar(Gtk.VScrollbar):
1539 def __init__(self, adjustment=None, **kwds):
1540 Gtk.VScrollbar.__init__(self, adjustment=adjustment, **kwds)
1542 VScrollbar = override(VScrollbar)
1543 __all__.append('VScrollbar')
1546 class Paned(Gtk.Paned):
1547 def pack1(self, child, resize=False, shrink=True):
1548 super(Paned, self).pack1(child, resize, shrink)
1550 def pack2(self, child, resize=True, shrink=True):
1551 super(Paned, self).pack2(child, resize, shrink)
1553 Paned = override(Paned)
1554 __all__.append('Paned')
1557 class Arrow(Gtk.Arrow):
1558 def __init__(self, arrow_type, shadow_type, **kwds):
1559 Gtk.Arrow.__init__(self, arrow_type=arrow_type,
1560 shadow_type=shadow_type,
1563 Arrow = override(Arrow)
1564 __all__.append('Arrow')
1567 class IconSet(Gtk.IconSet):
1568 def __new__(cls, pixbuf=None):
1569 if pixbuf is not None:
1570 iconset = Gtk.IconSet.new_from_pixbuf(pixbuf)
1572 iconset = Gtk.IconSet.__new__(cls)
1575 IconSet = override(IconSet)
1576 __all__.append('IconSet')
1579 class Viewport(Gtk.Viewport):
1580 def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1581 Gtk.Viewport.__init__(self, hadjustment=hadjustment,
1582 vadjustment=vadjustment,
1585 Viewport = override(Viewport)
1586 __all__.append('Viewport')
1589 class TreeModelFilter(Gtk.TreeModelFilter):
1590 def set_visible_func(self, func, data=None):
1591 super(TreeModelFilter, self).set_visible_func(func, data)
1593 TreeModelFilter = override(TreeModelFilter)
1594 __all__.append('TreeModelFilter')
1596 if Gtk._version != '2.0':
1597 class Menu(Gtk.Menu):
1598 def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time):
1599 self.popup_for_device(None, parent_menu_shell, parent_menu_item, func, data, button, activate_time)
1600 Menu = override(Menu)
1601 __all__.append('Menu')
1603 _Gtk_main_quit = Gtk.main_quit
1606 @override(Gtk.main_quit)
1607 def main_quit(*args):
1610 _Gtk_stock_lookup = Gtk.stock_lookup
1613 @override(Gtk.stock_lookup)
1614 def stock_lookup(*args):
1615 success, item = _Gtk_stock_lookup(*args)
1621 initialized, argv = Gtk.init_check(sys.argv)
1622 sys.argv = list(argv)
1624 raise RuntimeError("Gtk couldn't be initialized")