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, strip_boolean_result
25 from ..module import get_introspection_module
26 from gi import PyGIDeprecationWarning
28 if sys.version_info >= (3, 0):
30 _callable = lambda c: hasattr(c, '__call__')
32 _basestring = basestring
35 Gtk = get_introspection_module('Gtk')
39 if Gtk._version == '2.0':
41 warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \
42 was not designed for use with introspection some of the \
43 interfaces and API will fail. As such this is not supported \
44 by the pygobject development team and we encourage you to \
45 port your app to Gtk 3 or greater. PyGTK is the recomended \
46 python module to use with Gtk 2.0"
48 warnings.warn(warn_msg, RuntimeWarning)
51 def _construct_target_list(targets):
52 """Create a list of TargetEntry items from a list of tuples in the form (target, flags, info)
54 The list can also contain existing TargetEntry items in which case the existing entry
55 is re-used in the return list.
59 if not isinstance(entry, Gtk.TargetEntry):
60 entry = Gtk.TargetEntry.new(*entry)
61 target_entries.append(entry)
64 __all__.append('_construct_target_list')
67 class Widget(Gtk.Widget):
69 translate_coordinates = strip_boolean_result(Gtk.Widget.translate_coordinates)
71 def render_icon(self, stock_id, size, detail=None):
72 return super(Widget, self).render_icon(stock_id, size, detail)
74 def drag_dest_set_target_list(self, target_list):
75 if not isinstance(target_list, Gtk.TargetList):
76 target_list = Gtk.TargetList.new(_construct_target_list(target_list))
77 super(Widget, self).drag_dest_set_target_list(target_list)
79 def drag_source_set_target_list(self, target_list):
80 if not isinstance(target_list, Gtk.TargetList):
81 target_list = Gtk.TargetList.new(_construct_target_list(target_list))
82 super(Widget, self).drag_source_set_target_list(target_list)
85 Widget = override(Widget)
86 __all__.append('Widget')
89 class Container(Gtk.Container, Widget):
92 return len(self.get_children())
94 def __contains__(self, child):
95 return child in self.get_children()
98 return iter(self.get_children())
103 # alias for Python 2.x object protocol
104 __nonzero__ = __bool__
106 get_focus_chain = strip_boolean_result(Gtk.Container.get_focus_chain)
109 Container = override(Container)
110 __all__.append('Container')
113 class Editable(Gtk.Editable):
115 def insert_text(self, text, position):
116 return super(Editable, self).insert_text(text, -1, position)
118 get_selection_bounds = strip_boolean_result(Gtk.Editable.get_selection_bounds, fail_ret=())
121 Editable = override(Editable)
122 __all__.append("Editable")
125 class Action(Gtk.Action):
126 def __init__(self, name, label, tooltip, stock_id, **kwds):
127 Gtk.Action.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, **kwds)
129 Action = override(Action)
130 __all__.append("Action")
133 class RadioAction(Gtk.RadioAction):
134 def __init__(self, name, label, tooltip, stock_id, value, **kwds):
135 Gtk.RadioAction.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=value, **kwds)
137 RadioAction = override(RadioAction)
138 __all__.append("RadioAction")
141 class ActionGroup(Gtk.ActionGroup):
142 def __init__(self, name, **kwds):
143 super(ActionGroup, self).__init__(name=name, **kwds)
145 def add_actions(self, entries, user_data=None):
147 The add_actions() method is a convenience method that creates a number
148 of gtk.Action objects based on the information in the list of action
149 entry tuples contained in entries and adds them to the action group.
150 The entry tuples can vary in size from one to six items with the
151 following information:
153 * The name of the action. Must be specified.
154 * The stock id for the action. Optional with a default value of None
155 if a label is specified.
156 * The label for the action. This field should typically be marked
157 for translation, see the set_translation_domain() method. Optional
158 with a default value of None if a stock id is specified.
159 * The accelerator for the action, in the format understood by the
160 gtk.accelerator_parse() function. Optional with a default value of
162 * The tooltip for the action. This field should typically be marked
163 for translation, see the set_translation_domain() method. Optional
164 with a default value of None.
165 * The callback function invoked when the action is activated.
166 Optional with a default value of None.
168 The "activate" signals of the actions are connected to the callbacks and
169 their accel paths are set to <Actions>/group-name/action-name.
174 raise TypeError('entries must be iterable')
176 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None):
177 action = Action(name, label, tooltip, stock_id)
178 if callback is not None:
179 if user_data is None:
180 action.connect('activate', callback)
182 action.connect('activate', callback, user_data)
184 self.add_action_with_accel(action, accelerator)
187 # using inner function above since entries can leave out optional arguments
190 def add_toggle_actions(self, entries, user_data=None):
192 The add_toggle_actions() method is a convenience method that creates a
193 number of gtk.ToggleAction objects based on the information in the list
194 of action entry tuples contained in entries and adds them to the action
195 group. The toggle action entry tuples can vary in size from one to seven
196 items with the following information:
198 * The name of the action. Must be specified.
199 * The stock id for the action. Optional with a default value of None
200 if a label is specified.
201 * The label for the action. This field should typically be marked
202 for translation, see the set_translation_domain() method. Optional
203 with a default value of None if a stock id is specified.
204 * The accelerator for the action, in the format understood by the
205 gtk.accelerator_parse() function. Optional with a default value of
207 * The tooltip for the action. This field should typically be marked
208 for translation, see the set_translation_domain() method. Optional
209 with a default value of None.
210 * The callback function invoked when the action is activated.
211 Optional with a default value of None.
212 * A flag indicating whether the toggle action is active. Optional
213 with a default value of False.
215 The "activate" signals of the actions are connected to the callbacks and
216 their accel paths are set to <Actions>/group-name/action-name.
222 raise TypeError('entries must be iterable')
224 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False):
225 action = Gtk.ToggleAction(name, label, tooltip, stock_id)
226 action.set_active(is_active)
227 if callback is not None:
228 if user_data is None:
229 action.connect('activate', callback)
231 action.connect('activate', callback, user_data)
233 self.add_action_with_accel(action, accelerator)
236 # using inner function above since entries can leave out optional arguments
239 def add_radio_actions(self, entries, value=None, on_change=None, user_data=None):
241 The add_radio_actions() method is a convenience method that creates a
242 number of gtk.RadioAction objects based on the information in the list
243 of action entry tuples contained in entries and adds them to the action
244 group. The entry tuples can vary in size from one to six items with the
245 following information:
247 * The name of the action. Must be specified.
248 * The stock id for the action. Optional with a default value of None
249 if a label is specified.
250 * The label for the action. This field should typically be marked
251 for translation, see the set_translation_domain() method. Optional
252 with a default value of None if a stock id is specified.
253 * The accelerator for the action, in the format understood by the
254 gtk.accelerator_parse() function. Optional with a default value of
256 * The tooltip for the action. This field should typically be marked
257 for translation, see the set_translation_domain() method. Optional
258 with a default value of None.
259 * The value to set on the radio action. Optional with a default
260 value of 0. Should be specified in applications.
262 The value parameter specifies the radio action that should be set
263 active. The "changed" signal of the first radio action is connected to
264 the on_change callback (if specified and not None) and the accel paths
265 of the actions are set to <Actions>/group-name/action-name.
270 raise TypeError('entries must be iterable')
274 def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
275 action = RadioAction(name, label, tooltip, stock_id, entry_value)
277 # FIXME: join_group is a patch to Gtk+ 3.0
278 # otherwise we can't effectively add radio actions to a
279 # group. Should we depend on 3.0 and error out here
280 # or should we offer the functionality via a compat
282 if hasattr(action, 'join_group'):
283 action.join_group(group_source)
285 if value == entry_value:
286 action.set_active(True)
288 self.add_action_with_accel(action, accelerator)
292 # using inner function above since entries can leave out optional arguments
293 action = _process_action(first_action, *e)
294 if first_action is None:
295 first_action = action
297 if first_action is not None and on_change is not None:
298 if user_data is None:
299 first_action.connect('changed', on_change)
301 first_action.connect('changed', on_change, user_data)
303 ActionGroup = override(ActionGroup)
304 __all__.append('ActionGroup')
307 class UIManager(Gtk.UIManager):
308 def add_ui_from_string(self, buffer):
309 if not isinstance(buffer, _basestring):
310 raise TypeError('buffer must be a string')
312 length = len(buffer.encode('UTF-8'))
314 return Gtk.UIManager.add_ui_from_string(self, buffer, length)
316 def insert_action_group(self, buffer, length=-1):
317 return Gtk.UIManager.insert_action_group(self, buffer, length)
319 UIManager = override(UIManager)
320 __all__.append('UIManager')
323 class ComboBox(Gtk.ComboBox, Container):
324 get_active_iter = strip_boolean_result(Gtk.ComboBox.get_active_iter)
326 ComboBox = override(ComboBox)
327 __all__.append('ComboBox')
331 def __init__(self, homogeneous=False, spacing=0, **kwds):
332 super(Box, self).__init__(**kwds)
333 self.set_homogeneous(homogeneous)
334 self.set_spacing(spacing)
337 __all__.append('Box')
340 class SizeGroup(Gtk.SizeGroup):
341 def __init__(self, mode=Gtk.SizeGroupMode.VERTICAL):
342 super(SizeGroup, self).__init__(mode=mode)
344 SizeGroup = override(SizeGroup)
345 __all__.append('SizeGroup')
348 class MenuItem(Gtk.MenuItem):
349 def __init__(self, label=None, **kwds):
351 super(MenuItem, self).__init__(label=label, **kwds)
353 super(MenuItem, self).__init__(**kwds)
355 MenuItem = override(MenuItem)
356 __all__.append('MenuItem')
359 class Builder(Gtk.Builder):
361 def connect_signals(self, obj_or_map):
362 def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map):
364 if isinstance(obj_or_map, dict):
365 handler = obj_or_map.get(handler_name, None)
367 handler = getattr(obj_or_map, handler_name, None)
370 raise AttributeError('Handler %s not found' % handler_name)
372 if not _callable(handler):
373 raise TypeError('Handler %s is not a method or function' % handler_name)
375 after = flags & GObject.ConnectFlags.AFTER
376 if connect_obj is not None:
378 gobj.connect_object_after(signal_name, handler, connect_obj)
380 gobj.connect_object(signal_name, handler, connect_obj)
383 gobj.connect_after(signal_name, handler)
385 gobj.connect(signal_name, handler)
387 self.connect_signals_full(_full_callback, obj_or_map)
389 def add_from_string(self, buffer):
390 if not isinstance(buffer, _basestring):
391 raise TypeError('buffer must be a string')
395 return Gtk.Builder.add_from_string(self, buffer, length)
397 def add_objects_from_string(self, buffer, object_ids):
398 if not isinstance(buffer, _basestring):
399 raise TypeError('buffer must be a string')
403 return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids)
405 Builder = override(Builder)
406 __all__.append('Builder')
409 # NOTE: This must come before any other Window/Dialog subclassing, to ensure
410 # that we have a correct inheritance hierarchy.
413 class Window(Gtk.Window):
414 def __init__(self, type=Gtk.WindowType.TOPLEVEL, **kwds):
416 raise RuntimeError("Gtk couldn't be initialized")
418 # type is a construct-only property; if it is already set (e. g. by
419 # GtkBuilder), do not try to set it again and just ignore it
421 self.get_property('type')
422 Gtk.Window.__init__(self, **kwds)
424 Gtk.Window.__init__(self, type=type, **kwds)
426 Window = override(Window)
427 __all__.append('Window')
430 class Dialog(Gtk.Dialog, Container):
437 _buttons_property=None,
440 # buttons is overloaded by PyGtk so we have to do the same here
441 # this breaks some subclasses of Dialog so add a _buttons_property
442 # keyword to work around this
443 if _buttons_property is not None:
444 kwds['buttons'] = _buttons_property
446 Gtk.Dialog.__init__(self, **kwds)
448 self.set_title(title)
450 self.set_transient_for(parent)
451 if flags & Gtk.DialogFlags.MODAL:
453 if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT:
454 self.set_destroy_with_parent(True)
456 # NO_SEPARATOR has been removed from Gtk 3
457 if hasattr(Gtk.DialogFlags, "NO_SEPARATOR") and (flags & Gtk.DialogFlags.NO_SEPARATOR):
458 self.set_has_separator(False)
460 warnings.warn("Gtk.DialogFlags.NO_SEPARATOR has been depricated since Gtk+-3.0", PyGIDeprecationWarning)
462 if buttons is not None:
463 self.add_buttons(*buttons)
465 action_area = property(lambda dialog: dialog.get_action_area())
466 vbox = property(lambda dialog: dialog.get_content_area())
468 def add_buttons(self, *args):
470 The add_buttons() method adds several buttons to the Gtk.Dialog using
471 the button data passed as arguments to the method. This method is the
472 same as calling the Gtk.Dialog.add_button() repeatedly. The button data
473 pairs - button text (or stock ID) and a response ID integer are passed
474 individually. For example:
476 dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE)
478 will add "Open" and "Close" buttons to dialog.
487 for text, response in _button(args):
488 self.add_button(text, response)
490 raise TypeError('Must pass an even number of arguments')
492 Dialog = override(Dialog)
493 __all__.append('Dialog')
496 class MessageDialog(Gtk.MessageDialog, Dialog):
500 message_type=Gtk.MessageType.INFO,
501 buttons=Gtk.ButtonsType.NONE,
506 kwds['text'] = message_format
508 # type keyword is used for backwards compat with PyGTK
511 warnings.warn("The use of the keyword type as a parameter of the Gtk.MessageDialog constructor has been depricated. Please use message_type instead.", PyGIDeprecationWarning)
512 message_type = kwds.pop('type')
514 Gtk.MessageDialog.__init__(self,
515 _buttons_property=buttons,
516 message_type=message_type,
521 def format_secondary_text(self, message_format):
522 self.set_property('secondary-use-markup', False)
523 self.set_property('secondary-text', message_format)
525 def format_secondary_markup(self, message_format):
526 self.set_property('secondary-use-markup', True)
527 self.set_property('secondary-text', message_format)
529 MessageDialog = override(MessageDialog)
530 __all__.append('MessageDialog')
533 class AboutDialog(Gtk.AboutDialog):
534 def __init__(self, **kwds):
535 Gtk.AboutDialog.__init__(self, **kwds)
537 AboutDialog = override(AboutDialog)
538 __all__.append('AboutDialog')
541 class ColorSelectionDialog(Gtk.ColorSelectionDialog):
542 def __init__(self, title=None, **kwds):
543 Gtk.ColorSelectionDialog.__init__(self, title=title, **kwds)
545 ColorSelectionDialog = override(ColorSelectionDialog)
546 __all__.append('ColorSelectionDialog')
549 class FileChooserDialog(Gtk.FileChooserDialog):
553 action=Gtk.FileChooserAction.OPEN,
556 Gtk.FileChooserDialog.__init__(self,
562 FileChooserDialog = override(FileChooserDialog)
563 __all__.append('FileChooserDialog')
566 class FontSelectionDialog(Gtk.FontSelectionDialog):
567 def __init__(self, title=None, **kwds):
568 Gtk.FontSelectionDialog.__init__(self, title=title, **kwds)
570 FontSelectionDialog = override(FontSelectionDialog)
571 __all__.append('FontSelectionDialog')
574 class RecentChooserDialog(Gtk.RecentChooserDialog):
582 Gtk.RecentChooserDialog.__init__(self,
583 recent_manager=manager,
589 RecentChooserDialog = override(RecentChooserDialog)
590 __all__.append('RecentChooserDialog')
593 class IconView(Gtk.IconView):
595 def __init__(self, model=None, **kwds):
596 Gtk.IconView.__init__(self, model=model, **kwds)
598 get_item_at_pos = strip_boolean_result(Gtk.IconView.get_item_at_pos)
599 get_visible_range = strip_boolean_result(Gtk.IconView.get_visible_range)
600 get_dest_item_at_pos = strip_boolean_result(Gtk.IconView.get_dest_item_at_pos)
602 IconView = override(IconView)
603 __all__.append('IconView')
606 class ToolButton(Gtk.ToolButton):
608 def __init__(self, stock_id=None, **kwds):
609 Gtk.ToolButton.__init__(self, stock_id=stock_id, **kwds)
611 ToolButton = override(ToolButton)
612 __all__.append('ToolButton')
615 class IMContext(Gtk.IMContext):
616 get_surrounding = strip_boolean_result(Gtk.IMContext.get_surrounding)
618 IMContext = override(IMContext)
619 __all__.append('IMContext')
622 class RecentInfo(Gtk.RecentInfo):
623 get_application_info = strip_boolean_result(Gtk.RecentInfo.get_application_info)
625 RecentInfo = override(RecentInfo)
626 __all__.append('RecentInfo')
629 class TextBuffer(Gtk.TextBuffer):
630 def _get_or_create_tag_table(self):
631 table = self.get_tag_table()
633 table = Gtk.TextTagTable()
634 self.set_tag_table(table)
638 def create_tag(self, tag_name=None, **properties):
640 @tag_name: name of the new tag, or None
641 @properties: keyword list of properties and their values
643 Creates a tag and adds it to the tag table of the TextBuffer.
644 Equivalent to creating a Gtk.TextTag and then adding the
645 tag to the buffer's tag table. The returned tag is owned by
646 the buffer's tag table.
648 If @tag_name is None, the tag is anonymous.
650 If @tag_name is not None, a tag called @tag_name must not already
651 exist in the tag table for this buffer.
653 Properties are passed as a keyword list of names and values (e.g.
654 foreground = 'DodgerBlue', weight = Pango.Weight.BOLD)
656 Return value: a new tag
659 tag = Gtk.TextTag(name=tag_name, **properties)
660 self._get_or_create_tag_table().add(tag)
663 def create_mark(self, mark_name, where, left_gravity=False):
664 return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity)
666 def set_text(self, text, length=-1):
667 Gtk.TextBuffer.set_text(self, text, length)
669 def insert(self, iter, text, length=-1):
670 if not isinstance(text, _basestring):
671 raise TypeError('text must be a string, not %s' % type(text))
673 Gtk.TextBuffer.insert(self, iter, text, length)
675 def insert_with_tags(self, iter, text, *tags):
676 start_offset = iter.get_offset()
677 self.insert(iter, text)
682 start = self.get_iter_at_offset(start_offset)
685 self.apply_tag(tag, start, iter)
687 def insert_with_tags_by_name(self, iter, text, *tags):
694 tag_obj = self.get_tag_table().lookup(tag)
696 raise ValueError('unknown text tag: %s' % tag)
697 tag_objs.append(tag_obj)
699 self.insert_with_tags(iter, text, *tag_objs)
701 def insert_at_cursor(self, text, length=-1):
702 if not isinstance(text, _basestring):
703 raise TypeError('text must be a string, not %s' % type(text))
705 Gtk.TextBuffer.insert_at_cursor(self, text, length)
707 get_selection_bounds = strip_boolean_result(Gtk.TextBuffer.get_selection_bounds, fail_ret=())
709 TextBuffer = override(TextBuffer)
710 __all__.append('TextBuffer')
713 class TextIter(Gtk.TextIter):
715 forward_search = strip_boolean_result(Gtk.TextIter.forward_search)
716 backward_search = strip_boolean_result(Gtk.TextIter.backward_search)
718 def begins_tag(self, tag=None):
719 return super(TextIter, self).begins_tag(tag)
721 def ends_tag(self, tag=None):
722 return super(TextIter, self).ends_tag(tag)
724 def toggles_tag(self, tag=None):
725 return super(TextIter, self).toggles_tag(tag)
727 TextIter = override(TextIter)
728 __all__.append('TextIter')
731 class TreeModel(Gtk.TreeModel):
733 return self.iter_n_children(None)
738 # alias for Python 2.x object protocol
739 __nonzero__ = __bool__
741 def _getiter(self, key):
742 if isinstance(key, Gtk.TreeIter):
744 elif isinstance(key, int) and key < 0:
745 index = len(self) + key
747 raise IndexError("row index is out of bounds: %d" % key)
749 aiter = self.get_iter(index)
751 raise IndexError("could not find tree path '%s'" % key)
755 aiter = self.get_iter(key)
757 raise IndexError("could not find tree path '%s'" % key)
760 def _coerce_path(self, path):
761 if isinstance(path, Gtk.TreePath):
764 return TreePath(path)
766 def __getitem__(self, key):
767 aiter = self._getiter(key)
768 return TreeModelRow(self, aiter)
770 def __setitem__(self, key, value):
772 self.set_row(row.iter, value)
774 def __delitem__(self, key):
775 aiter = self._getiter(key)
779 return TreeModelRowIter(self, self.get_iter_first())
781 get_iter_first = strip_boolean_result(Gtk.TreeModel.get_iter_first)
782 iter_children = strip_boolean_result(Gtk.TreeModel.iter_children)
783 iter_nth_child = strip_boolean_result(Gtk.TreeModel.iter_nth_child)
784 iter_parent = strip_boolean_result(Gtk.TreeModel.iter_parent)
785 get_iter_from_string = strip_boolean_result(Gtk.TreeModel.get_iter_from_string,
786 ValueError, 'invalid tree path')
788 def get_iter(self, path):
789 path = self._coerce_path(path)
790 success, aiter = super(TreeModel, self).get_iter(path)
792 raise ValueError("invalid tree path '%s'" % path)
795 def iter_next(self, aiter):
796 next_iter = aiter.copy()
797 success = super(TreeModel, self).iter_next(next_iter)
801 def iter_previous(self, aiter):
802 prev_iter = aiter.copy()
803 success = super(TreeModel, self).iter_previous(prev_iter)
807 def _convert_row(self, row):
808 # TODO: Accept a dictionary for row
809 # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name})
810 if isinstance(row, str):
811 raise TypeError('Expected a list or tuple, but got str')
813 n_columns = self.get_n_columns()
814 if len(row) != n_columns:
815 raise ValueError('row sequence has the incorrect number of elements')
819 for cur_col, value in enumerate(row):
820 # do not try to set None values, they are causing warnings
823 result.append(self._convert_value(cur_col, value))
824 columns.append(cur_col)
825 return (result, columns)
827 def set_row(self, treeiter, row):
828 converted_row, columns = self._convert_row(row)
829 for column in columns:
832 continue # None means skip this row
834 self.set_value(treeiter, column, value)
836 def _convert_value(self, column, value):
837 '''Convert value to a GObject.Value of the expected type'''
839 if isinstance(value, GObject.Value):
841 return GObject.Value(self.get_column_type(column), value)
843 def get(self, treeiter, *columns):
844 n_columns = self.get_n_columns()
848 if not isinstance(col, int):
849 raise TypeError("column numbers must be ints")
851 if col < 0 or col >= n_columns:
852 raise ValueError("column number is out of range")
854 values.append(self.get_value(treeiter, col))
858 def filter_new(self, root=None):
859 return super(TreeModel, self).filter_new(root)
862 # Signals supporting python iterables as tree paths
864 def row_changed(self, path, iter):
865 return super(TreeModel, self).row_changed(self._coerce_path(path), iter)
867 def row_inserted(self, path, iter):
868 return super(TreeModel, self).row_inserted(self._coerce_path(path), iter)
870 def row_has_child_toggled(self, path, iter):
871 return super(TreeModel, self).row_has_child_toggled(self._coerce_path(path),
874 def row_deleted(self, path):
875 return super(TreeModel, self).row_deleted(self._coerce_path(path))
877 def rows_reordered(self, path, iter, new_order):
878 return super(TreeModel, self).rows_reordered(self._coerce_path(path),
882 TreeModel = override(TreeModel)
883 __all__.append('TreeModel')
886 class TreeSortable(Gtk.TreeSortable, ):
888 get_sort_column_id = strip_boolean_result(Gtk.TreeSortable.get_sort_column_id, fail_ret=(None, None))
890 def set_sort_func(self, sort_column_id, sort_func, user_data=None):
891 super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data)
893 def set_default_sort_func(self, sort_func, user_data=None):
894 super(TreeSortable, self).set_default_sort_func(sort_func, user_data)
896 TreeSortable = override(TreeSortable)
897 __all__.append('TreeSortable')
900 class TreeModelSort(Gtk.TreeModelSort):
901 def __init__(self, model, **kwds):
902 Gtk.TreeModelSort.__init__(self, model=model, **kwds)
904 TreeModelSort = override(TreeModelSort)
905 __all__.append('TreeModelSort')
908 class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
909 def __init__(self, *column_types):
910 Gtk.ListStore.__init__(self)
911 self.set_column_types(column_types)
913 def _do_insert(self, position, row):
915 row, columns = self._convert_row(row)
916 treeiter = self.insert_with_valuesv(position, columns, row)
918 treeiter = Gtk.ListStore.insert(self, position)
922 def append(self, row=None):
924 return self._do_insert(-1, row)
925 # gtk_list_store_insert() does not know about the "position == -1"
926 # case, so use append() here
928 return Gtk.ListStore.append(self)
930 def prepend(self, row=None):
931 return self._do_insert(0, row)
933 def insert(self, position, row=None):
934 return self._do_insert(position, row)
936 # FIXME: sends two signals; check if this can use an atomic
937 # insert_with_valuesv()
939 def insert_before(self, sibling, row=None):
940 treeiter = Gtk.ListStore.insert_before(self, sibling)
943 self.set_row(treeiter, row)
947 # FIXME: sends two signals; check if this can use an atomic
948 # insert_with_valuesv()
950 def insert_after(self, sibling, row=None):
951 treeiter = Gtk.ListStore.insert_after(self, sibling)
954 self.set_row(treeiter, row)
958 def set_value(self, treeiter, column, value):
959 value = self._convert_value(column, value)
960 Gtk.ListStore.set_value(self, treeiter, column, value)
962 def set(self, treeiter, *args):
964 def _set_lists(columns, values):
965 if len(columns) != len(values):
966 raise TypeError('The number of columns do not match the number of values')
967 for col_num, val in zip(columns, values):
968 if not isinstance(col_num, int):
969 raise TypeError('TypeError: Expected integer argument for column.')
970 self.set_value(treeiter, col_num, val)
973 if isinstance(args[0], int):
976 _set_lists(columns, values)
977 elif isinstance(args[0], (tuple, list)):
979 raise TypeError('Too many arguments')
980 _set_lists(args[0], args[1])
981 elif isinstance(args[0], dict):
982 columns = args[0].keys()
983 values = args[0].values()
984 _set_lists(columns, values)
986 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
988 ListStore = override(ListStore)
989 __all__.append('ListStore')
992 class TreeModelRow(object):
994 def __init__(self, model, iter_or_path):
995 if not isinstance(model, Gtk.TreeModel):
996 raise TypeError("expected Gtk.TreeModel, %s found" % type(model).__name__)
998 if isinstance(iter_or_path, Gtk.TreePath):
999 self.iter = model.get_iter(iter_or_path)
1000 elif isinstance(iter_or_path, Gtk.TreeIter):
1001 self.iter = iter_or_path
1003 raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \
1004 %s found" % type(iter_or_path).__name__)
1008 return self.model.get_path(self.iter)
1012 return self.get_next()
1016 return self.get_previous()
1020 return self.get_parent()
1023 next_iter = self.model.iter_next(self.iter)
1025 return TreeModelRow(self.model, next_iter)
1027 def get_previous(self):
1028 prev_iter = self.model.iter_previous(self.iter)
1030 return TreeModelRow(self.model, prev_iter)
1032 def get_parent(self):
1033 parent_iter = self.model.iter_parent(self.iter)
1035 return TreeModelRow(self.model, parent_iter)
1037 def __getitem__(self, key):
1038 if isinstance(key, int):
1039 if key >= self.model.get_n_columns():
1040 raise IndexError("column index is out of bounds: %d" % key)
1042 key = self._convert_negative_index(key)
1043 return self.model.get_value(self.iter, key)
1044 elif isinstance(key, slice):
1045 start, stop, step = key.indices(self.model.get_n_columns())
1047 for i in range(start, stop, step):
1048 alist.append(self.model.get_value(self.iter, i))
1051 raise TypeError("indices must be integers, not %s" % type(key).__name__)
1053 def __setitem__(self, key, value):
1054 if isinstance(key, int):
1055 if key >= self.model.get_n_columns():
1056 raise IndexError("column index is out of bounds: %d" % key)
1058 key = self._convert_negative_index(key)
1059 self.model.set_value(self.iter, key, value)
1060 elif isinstance(key, slice):
1061 start, stop, step = key.indices(self.model.get_n_columns())
1062 indexList = range(start, stop, step)
1063 if len(indexList) != len(value):
1065 "attempt to assign sequence of size %d to slice of size %d"
1066 % (len(value), len(indexList)))
1068 for i, v in enumerate(indexList):
1069 self.model.set_value(self.iter, v, value[i])
1071 raise TypeError("index must be an integer or slice, not %s" % type(key).__name__)
1073 def _convert_negative_index(self, index):
1074 new_index = self.model.get_n_columns() + index
1076 raise IndexError("column index is out of bounds: %d" % index)
1079 def iterchildren(self):
1080 child_iter = self.model.iter_children(self.iter)
1081 return TreeModelRowIter(self.model, child_iter)
1083 __all__.append('TreeModelRow')
1086 class TreeModelRowIter(object):
1088 def __init__(self, model, aiter):
1095 row = TreeModelRow(self.model, self.iter)
1096 self.iter = self.model.iter_next(self.iter)
1099 # alias for Python 2.x object protocol
1105 __all__.append('TreeModelRowIter')
1108 class TreePath(Gtk.TreePath):
1110 def __new__(cls, path=0):
1111 if isinstance(path, int):
1113 elif not isinstance(path, _basestring):
1114 path = ":".join(str(val) for val in path)
1117 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1119 return TreePath.new_from_string(path)
1121 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1124 return self.to_string()
1126 def __lt__(self, other):
1127 return not other is None and self.compare(other) < 0
1129 def __le__(self, other):
1130 return not other is None and self.compare(other) <= 0
1132 def __eq__(self, other):
1133 return not other is None and self.compare(other) == 0
1135 def __ne__(self, other):
1136 return other is None or self.compare(other) != 0
1138 def __gt__(self, other):
1139 return other is None or self.compare(other) > 0
1141 def __ge__(self, other):
1142 return other is None or self.compare(other) >= 0
1145 return iter(self.get_indices())
1148 return self.get_depth()
1150 def __getitem__(self, index):
1151 return self.get_indices()[index]
1153 TreePath = override(TreePath)
1154 __all__.append('TreePath')
1157 class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
1159 def __init__(self, *column_types):
1160 Gtk.TreeStore.__init__(self)
1161 self.set_column_types(column_types)
1163 def _do_insert(self, parent, position, row):
1165 row, columns = self._convert_row(row)
1166 treeiter = self.insert_with_values(parent, position, columns, row)
1168 treeiter = Gtk.TreeStore.insert(self, parent, position)
1172 def append(self, parent, row=None):
1173 return self._do_insert(parent, -1, row)
1175 def prepend(self, parent, row=None):
1176 return self._do_insert(parent, 0, row)
1178 def insert(self, parent, position, row=None):
1179 return self._do_insert(parent, position, row)
1181 # FIXME: sends two signals; check if this can use an atomic
1182 # insert_with_valuesv()
1184 def insert_before(self, parent, sibling, row=None):
1185 treeiter = Gtk.TreeStore.insert_before(self, parent, sibling)
1188 self.set_row(treeiter, row)
1192 # FIXME: sends two signals; check if this can use an atomic
1193 # insert_with_valuesv()
1195 def insert_after(self, parent, sibling, row=None):
1196 treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
1199 self.set_row(treeiter, row)
1203 def set_value(self, treeiter, column, value):
1204 value = self._convert_value(column, value)
1205 Gtk.TreeStore.set_value(self, treeiter, column, value)
1207 def set(self, treeiter, *args):
1209 def _set_lists(columns, values):
1210 if len(columns) != len(values):
1211 raise TypeError('The number of columns do not match the number of values')
1212 for col_num, val in zip(columns, values):
1213 if not isinstance(col_num, int):
1214 raise TypeError('TypeError: Expected integer argument for column.')
1215 self.set_value(treeiter, col_num, val)
1218 if isinstance(args[0], int):
1221 _set_lists(columns, values)
1222 elif isinstance(args[0], (tuple, list)):
1224 raise TypeError('Too many arguments')
1225 _set_lists(args[0], args[1])
1226 elif isinstance(args[0], dict):
1227 columns = args[0].keys()
1228 values = args[0].values()
1229 _set_lists(columns, values)
1231 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1233 TreeStore = override(TreeStore)
1234 __all__.append('TreeStore')
1237 class TreeView(Gtk.TreeView, Container):
1239 def __init__(self, model=None):
1240 Gtk.TreeView.__init__(self)
1242 self.set_model(model)
1244 get_path_at_pos = strip_boolean_result(Gtk.TreeView.get_path_at_pos)
1245 get_visible_range = strip_boolean_result(Gtk.TreeView.get_visible_range)
1246 get_dest_row_at_pos = strip_boolean_result(Gtk.TreeView.get_dest_row_at_pos)
1248 def enable_model_drag_source(self, start_button_mask, targets, actions):
1249 target_entries = _construct_target_list(targets)
1250 super(TreeView, self).enable_model_drag_source(start_button_mask,
1254 def enable_model_drag_dest(self, targets, actions):
1255 target_entries = _construct_target_list(targets)
1256 super(TreeView, self).enable_model_drag_dest(target_entries,
1259 def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0):
1260 if not isinstance(path, Gtk.TreePath):
1261 path = TreePath(path)
1262 super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align)
1264 def set_cursor(self, path, column=None, start_editing=False):
1265 if not isinstance(path, Gtk.TreePath):
1266 path = TreePath(path)
1267 super(TreeView, self).set_cursor(path, column, start_editing)
1269 def get_cell_area(self, path, column=None):
1270 if not isinstance(path, Gtk.TreePath):
1271 path = TreePath(path)
1272 return super(TreeView, self).get_cell_area(path, column)
1274 def insert_column_with_attributes(self, position, title, cell, **kwargs):
1275 column = TreeViewColumn()
1276 column.set_title(title)
1277 column.pack_start(cell, False)
1278 self.insert_column(column, position)
1279 column.set_attributes(cell, **kwargs)
1281 TreeView = override(TreeView)
1282 __all__.append('TreeView')
1285 class TreeViewColumn(Gtk.TreeViewColumn):
1286 def __init__(self, title='',
1289 Gtk.TreeViewColumn.__init__(self, title=title)
1291 self.pack_start(cell_renderer, True)
1293 for (name, value) in attributes.items():
1294 self.add_attribute(cell_renderer, name, value)
1296 cell_get_position = strip_boolean_result(Gtk.TreeViewColumn.cell_get_position)
1298 def set_cell_data_func(self, cell_renderer, func, func_data=None):
1299 super(TreeViewColumn, self).set_cell_data_func(cell_renderer, func, func_data)
1301 def set_attributes(self, cell_renderer, **attributes):
1302 Gtk.CellLayout.clear_attributes(self, cell_renderer)
1304 for (name, value) in attributes.items():
1305 Gtk.CellLayout.add_attribute(self, cell_renderer, name, value)
1308 TreeViewColumn = override(TreeViewColumn)
1309 __all__.append('TreeViewColumn')
1312 class TreeSelection(Gtk.TreeSelection):
1314 def select_path(self, path):
1315 if not isinstance(path, Gtk.TreePath):
1316 path = TreePath(path)
1317 super(TreeSelection, self).select_path(path)
1319 def get_selected(self):
1320 success, model, aiter = super(TreeSelection, self).get_selected()
1322 return (model, aiter)
1324 return (model, None)
1326 # for compatibility with PyGtk
1328 def get_selected_rows(self):
1329 rows, model = super(TreeSelection, self).get_selected_rows()
1330 return (model, rows)
1333 TreeSelection = override(TreeSelection)
1334 __all__.append('TreeSelection')
1337 class Button(Gtk.Button, Container):
1338 def __init__(self, label=None, stock=None, use_stock=False, use_underline=False, **kwds):
1342 use_underline = True
1343 Gtk.Button.__init__(self, label=label, use_stock=use_stock,
1344 use_underline=use_underline, **kwds)
1345 Button = override(Button)
1346 __all__.append('Button')
1349 class LinkButton(Gtk.LinkButton):
1350 def __init__(self, uri, label=None, **kwds):
1351 Gtk.LinkButton.__init__(self, uri=uri, label=label, **kwds)
1353 LinkButton = override(LinkButton)
1354 __all__.append('LinkButton')
1357 class Label(Gtk.Label):
1358 def __init__(self, label=None, **kwds):
1359 Gtk.Label.__init__(self, label=label, **kwds)
1361 Label = override(Label)
1362 __all__.append('Label')
1365 class Adjustment(Gtk.Adjustment):
1366 def __init__(self, *args, **kwds):
1367 arg_names = ('value', 'lower', 'upper',
1368 'step_increment', 'page_increment', 'page_size')
1369 new_args = dict(zip(arg_names, args))
1370 new_args.update(kwds)
1372 # PyGTK compatiblity
1373 if 'page_incr' in new_args:
1374 new_args['page_increment'] = new_args.pop('page_incr')
1375 if 'step_incr' in new_args:
1376 new_args['step_increment'] = new_args.pop('step_incr')
1377 Gtk.Adjustment.__init__(self, **new_args)
1379 # The value property is set between lower and (upper - page_size).
1380 # Just in case lower, upper or page_size was still 0 when value
1381 # was set, we set it again here.
1382 if 'value' in new_args:
1383 self.set_value(new_args['value'])
1385 Adjustment = override(Adjustment)
1386 __all__.append('Adjustment')
1389 class Table(Gtk.Table, Container):
1390 def __init__(self, rows=1, columns=1, homogeneous=False, **kwds):
1391 if 'n_rows' in kwds:
1392 rows = kwds.pop('n_rows')
1394 if 'n_columns' in kwds:
1395 columns = kwds.pop('n_columns')
1397 Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, homogeneous=homogeneous, **kwds)
1399 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):
1400 Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding)
1402 Table = override(Table)
1403 __all__.append('Table')
1406 class ScrolledWindow(Gtk.ScrolledWindow):
1407 def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1408 Gtk.ScrolledWindow.__init__(self, hadjustment=hadjustment, vadjustment=vadjustment, **kwds)
1410 ScrolledWindow = override(ScrolledWindow)
1411 __all__.append('ScrolledWindow')
1414 class HScrollbar(Gtk.HScrollbar):
1415 def __init__(self, adjustment=None, **kwds):
1416 Gtk.HScrollbar.__init__(self, adjustment=adjustment, **kwds)
1418 HScrollbar = override(HScrollbar)
1419 __all__.append('HScrollbar')
1422 class VScrollbar(Gtk.VScrollbar):
1423 def __init__(self, adjustment=None, **kwds):
1424 Gtk.VScrollbar.__init__(self, adjustment=adjustment, **kwds)
1426 VScrollbar = override(VScrollbar)
1427 __all__.append('VScrollbar')
1430 class Paned(Gtk.Paned):
1431 def pack1(self, child, resize=False, shrink=True):
1432 super(Paned, self).pack1(child, resize, shrink)
1434 def pack2(self, child, resize=True, shrink=True):
1435 super(Paned, self).pack2(child, resize, shrink)
1437 Paned = override(Paned)
1438 __all__.append('Paned')
1441 class Arrow(Gtk.Arrow):
1442 def __init__(self, arrow_type, shadow_type, **kwds):
1443 Gtk.Arrow.__init__(self, arrow_type=arrow_type,
1444 shadow_type=shadow_type,
1447 Arrow = override(Arrow)
1448 __all__.append('Arrow')
1451 class IconSet(Gtk.IconSet):
1452 def __new__(cls, pixbuf=None):
1453 if pixbuf is not None:
1454 iconset = Gtk.IconSet.new_from_pixbuf(pixbuf)
1456 iconset = Gtk.IconSet.__new__(cls)
1459 IconSet = override(IconSet)
1460 __all__.append('IconSet')
1463 class Viewport(Gtk.Viewport):
1464 def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1465 Gtk.Viewport.__init__(self, hadjustment=hadjustment,
1466 vadjustment=vadjustment,
1469 Viewport = override(Viewport)
1470 __all__.append('Viewport')
1473 class TreeModelFilter(Gtk.TreeModelFilter):
1474 def set_visible_func(self, func, data=None):
1475 super(TreeModelFilter, self).set_visible_func(func, data)
1477 def set_value(self, iter, column, value):
1478 # Delegate to child model
1479 iter = self.convert_iter_to_child_iter(iter)
1480 self.get_model().set_value(iter, column, value)
1482 TreeModelFilter = override(TreeModelFilter)
1483 __all__.append('TreeModelFilter')
1485 if Gtk._version != '2.0':
1486 class Menu(Gtk.Menu):
1487 def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time):
1488 self.popup_for_device(None, parent_menu_shell, parent_menu_item, func, data, button, activate_time)
1489 Menu = override(Menu)
1490 __all__.append('Menu')
1492 _Gtk_main_quit = Gtk.main_quit
1495 @override(Gtk.main_quit)
1496 def main_quit(*args):
1499 stock_lookup = strip_boolean_result(Gtk.stock_lookup)
1500 __all__.append('stock_lookup')
1502 initialized, argv = Gtk.init_check(sys.argv)
1503 sys.argv = list(argv)