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
26 from gi.repository import GObject
27 from ..overrides import override, strip_boolean_result, deprecated_init
28 from ..module import get_introspection_module
29 from gi import PyGIDeprecationWarning
31 if sys.version_info >= (3, 0):
33 _callable = lambda c: hasattr(c, '__call__')
35 _basestring = basestring
38 Gtk = get_introspection_module('Gtk')
42 if Gtk._version == '2.0':
43 warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \
44 was not designed for use with introspection some of the \
45 interfaces and API will fail. As such this is not supported \
46 by the pygobject development team and we encourage you to \
47 port your app to Gtk 3 or greater. PyGTK is the recomended \
48 python module to use with Gtk 2.0"
50 warnings.warn(warn_msg, RuntimeWarning)
53 class PyGTKDeprecationWarning(PyGIDeprecationWarning):
56 __all__.append('PyGTKDeprecationWarning')
59 def _construct_target_list(targets):
60 """Create a list of TargetEntry items from a list of tuples in the form (target, flags, info)
62 The list can also contain existing TargetEntry items in which case the existing entry
63 is re-used in the return list.
67 if not isinstance(entry, Gtk.TargetEntry):
68 entry = Gtk.TargetEntry.new(*entry)
69 target_entries.append(entry)
72 __all__.append('_construct_target_list')
75 class Widget(Gtk.Widget):
77 translate_coordinates = strip_boolean_result(Gtk.Widget.translate_coordinates)
79 def drag_dest_set_target_list(self, target_list):
80 if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)):
81 target_list = Gtk.TargetList.new(_construct_target_list(target_list))
82 super(Widget, self).drag_dest_set_target_list(target_list)
84 def drag_source_set_target_list(self, target_list):
85 if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)):
86 target_list = Gtk.TargetList.new(_construct_target_list(target_list))
87 super(Widget, self).drag_source_set_target_list(target_list)
89 def style_get_property(self, property_name, value=None):
91 prop = self.find_style_property(property_name)
93 raise ValueError('Class "%s" does not contain style property "%s"' %
94 (self, property_name))
95 value = GObject.Value(prop.value_type)
97 Gtk.Widget.style_get_property(self, property_name, value)
98 return value.get_value()
101 Widget = override(Widget)
102 __all__.append('Widget')
105 class Container(Gtk.Container, Widget):
108 return len(self.get_children())
110 def __contains__(self, child):
111 return child in self.get_children()
114 return iter(self.get_children())
119 # alias for Python 2.x object protocol
120 __nonzero__ = __bool__
122 get_focus_chain = strip_boolean_result(Gtk.Container.get_focus_chain)
124 def child_get_property(self, child, property_name, value=None):
126 prop = self.find_child_property(property_name)
128 raise ValueError('Class "%s" does not contain child property "%s"' %
129 (self, property_name))
130 value = GObject.Value(prop.value_type)
132 Gtk.Container.child_get_property(self, child, property_name, value)
133 return value.get_value()
135 def child_get(self, child, *prop_names):
136 """Returns a list of child property values for the given names."""
137 return [self.child_get_property(child, name) for name in prop_names]
139 def child_set(self, child, **kwargs):
140 """Set a child properties on the given child to key/value pairs."""
141 for name, value in kwargs.items():
142 name = name.replace('_', '-')
143 self.child_set_property(child, name, value)
146 Container = override(Container)
147 __all__.append('Container')
150 class Editable(Gtk.Editable):
152 def insert_text(self, text, position):
153 return super(Editable, self).insert_text(text, -1, position)
155 get_selection_bounds = strip_boolean_result(Gtk.Editable.get_selection_bounds, fail_ret=())
158 Editable = override(Editable)
159 __all__.append("Editable")
162 class Action(Gtk.Action):
163 __init__ = deprecated_init(Gtk.Action.__init__,
164 arg_names=('name', 'label', 'tooltip', 'stock_id'),
165 category=PyGTKDeprecationWarning)
167 Action = override(Action)
168 __all__.append("Action")
171 class RadioAction(Gtk.RadioAction):
172 __init__ = deprecated_init(Gtk.RadioAction.__init__,
173 arg_names=('name', 'label', 'tooltip', 'stock_id', 'value'),
174 category=PyGTKDeprecationWarning)
176 RadioAction = override(RadioAction)
177 __all__.append("RadioAction")
180 class ActionGroup(Gtk.ActionGroup):
181 __init__ = deprecated_init(Gtk.ActionGroup.__init__,
183 category=PyGTKDeprecationWarning)
185 def add_actions(self, entries, user_data=None):
187 The add_actions() method is a convenience method that creates a number
188 of gtk.Action objects based on the information in the list of action
189 entry tuples contained in entries and adds them to the action group.
190 The entry tuples can vary in size from one to six items with the
191 following information:
193 * The name of the action. Must be specified.
194 * The stock id for the action. Optional with a default value of None
195 if a label is specified.
196 * The label for the action. This field should typically be marked
197 for translation, see the set_translation_domain() method. Optional
198 with a default value of None if a stock id is specified.
199 * The accelerator for the action, in the format understood by the
200 gtk.accelerator_parse() function. Optional with a default value of
202 * The tooltip for the action. This field should typically be marked
203 for translation, see the set_translation_domain() method. Optional
204 with a default value of None.
205 * The callback function invoked when the action is activated.
206 Optional with a default value of None.
208 The "activate" signals of the actions are connected to the callbacks and
209 their accel paths are set to <Actions>/group-name/action-name.
214 raise TypeError('entries must be iterable')
216 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None):
217 action = Action(name=name, label=label, tooltip=tooltip, stock_id=stock_id)
218 if callback is not None:
219 if user_data is None:
220 action.connect('activate', callback)
222 action.connect('activate', callback, user_data)
224 self.add_action_with_accel(action, accelerator)
227 # using inner function above since entries can leave out optional arguments
230 def add_toggle_actions(self, entries, user_data=None):
232 The add_toggle_actions() method is a convenience method that creates a
233 number of gtk.ToggleAction objects based on the information in the list
234 of action entry tuples contained in entries and adds them to the action
235 group. The toggle action entry tuples can vary in size from one to seven
236 items with the following information:
238 * The name of the action. Must be specified.
239 * The stock id for the action. Optional with a default value of None
240 if a label is specified.
241 * The label for the action. This field should typically be marked
242 for translation, see the set_translation_domain() method. Optional
243 with a default value of None if a stock id is specified.
244 * The accelerator for the action, in the format understood by the
245 gtk.accelerator_parse() function. Optional with a default value of
247 * The tooltip for the action. This field should typically be marked
248 for translation, see the set_translation_domain() method. Optional
249 with a default value of None.
250 * The callback function invoked when the action is activated.
251 Optional with a default value of None.
252 * A flag indicating whether the toggle action is active. Optional
253 with a default value of False.
255 The "activate" signals of the actions are connected to the callbacks and
256 their accel paths are set to <Actions>/group-name/action-name.
262 raise TypeError('entries must be iterable')
264 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False):
265 action = Gtk.ToggleAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id)
266 action.set_active(is_active)
267 if callback is not None:
268 if user_data is None:
269 action.connect('activate', callback)
271 action.connect('activate', callback, user_data)
273 self.add_action_with_accel(action, accelerator)
276 # using inner function above since entries can leave out optional arguments
279 def add_radio_actions(self, entries, value=None, on_change=None, user_data=None):
281 The add_radio_actions() method is a convenience method that creates a
282 number of gtk.RadioAction objects based on the information in the list
283 of action entry tuples contained in entries and adds them to the action
284 group. The entry tuples can vary in size from one to six items with the
285 following information:
287 * The name of the action. Must be specified.
288 * The stock id for the action. Optional with a default value of None
289 if a label is specified.
290 * The label for the action. This field should typically be marked
291 for translation, see the set_translation_domain() method. Optional
292 with a default value of None if a stock id is specified.
293 * The accelerator for the action, in the format understood by the
294 gtk.accelerator_parse() function. Optional with a default value of
296 * The tooltip for the action. This field should typically be marked
297 for translation, see the set_translation_domain() method. Optional
298 with a default value of None.
299 * The value to set on the radio action. Optional with a default
300 value of 0. Should be specified in applications.
302 The value parameter specifies the radio action that should be set
303 active. The "changed" signal of the first radio action is connected to
304 the on_change callback (if specified and not None) and the accel paths
305 of the actions are set to <Actions>/group-name/action-name.
310 raise TypeError('entries must be iterable')
314 def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
315 action = RadioAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value)
317 # FIXME: join_group is a patch to Gtk+ 3.0
318 # otherwise we can't effectively add radio actions to a
319 # group. Should we depend on 3.0 and error out here
320 # or should we offer the functionality via a compat
322 if hasattr(action, 'join_group'):
323 action.join_group(group_source)
325 if value == entry_value:
326 action.set_active(True)
328 self.add_action_with_accel(action, accelerator)
332 # using inner function above since entries can leave out optional arguments
333 action = _process_action(first_action, *e)
334 if first_action is None:
335 first_action = action
337 if first_action is not None and on_change is not None:
338 if user_data is None:
339 first_action.connect('changed', on_change)
341 first_action.connect('changed', on_change, user_data)
343 ActionGroup = override(ActionGroup)
344 __all__.append('ActionGroup')
347 class UIManager(Gtk.UIManager):
348 def add_ui_from_string(self, buffer):
349 if not isinstance(buffer, _basestring):
350 raise TypeError('buffer must be a string')
352 length = len(buffer.encode('UTF-8'))
354 return Gtk.UIManager.add_ui_from_string(self, buffer, length)
356 def insert_action_group(self, buffer, length=-1):
357 return Gtk.UIManager.insert_action_group(self, buffer, length)
359 UIManager = override(UIManager)
360 __all__.append('UIManager')
363 class ComboBox(Gtk.ComboBox, Container):
364 get_active_iter = strip_boolean_result(Gtk.ComboBox.get_active_iter)
366 ComboBox = override(ComboBox)
367 __all__.append('ComboBox')
371 __init__ = deprecated_init(Gtk.Box.__init__,
372 arg_names=('homogeneous', 'spacing'),
373 category=PyGTKDeprecationWarning)
376 __all__.append('Box')
379 class SizeGroup(Gtk.SizeGroup):
380 __init__ = deprecated_init(Gtk.SizeGroup.__init__,
382 deprecated_defaults={'mode': Gtk.SizeGroupMode.VERTICAL},
383 category=PyGTKDeprecationWarning)
385 SizeGroup = override(SizeGroup)
386 __all__.append('SizeGroup')
389 class MenuItem(Gtk.MenuItem):
390 __init__ = deprecated_init(Gtk.MenuItem.__init__,
391 arg_names=('label',),
392 category=PyGTKDeprecationWarning)
394 MenuItem = override(MenuItem)
395 __all__.append('MenuItem')
398 class Builder(Gtk.Builder):
400 def _extract_handler_and_args(obj_or_map, handler_name):
402 if isinstance(obj_or_map, collections.Mapping):
403 handler = obj_or_map.get(handler_name, None)
405 handler = getattr(obj_or_map, handler_name, None)
408 raise AttributeError('Handler %s not found' % handler_name)
411 if isinstance(handler, collections.Sequence):
412 if len(handler) == 0:
413 raise TypeError("Handler %s tuple can not be empty" % handler)
417 elif not _callable(handler):
418 raise TypeError('Handler %s is not a method, function or tuple' % handler)
422 def connect_signals(self, obj_or_map):
423 """Connect signals specified by this builder to a name, handler mapping.
425 Connect signal, name, and handler sets specified in the builder with
426 the given mapping "obj_or_map". The handler/value aspect of the mapping
427 can also contain a tuple in the form of (handler [,arg1 [,argN]])
428 allowing for extra arguments to be passed to the handler. For example:
430 .. code-block:: python
432 builder.connect_signals({'on_clicked': (on_clicked, arg1, arg2)})
434 def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map):
435 handler, args = self._extract_handler_and_args(obj_or_map, handler_name)
437 after = flags & GObject.ConnectFlags.AFTER
438 if connect_obj is not None:
440 gobj.connect_object_after(signal_name, handler, connect_obj, *args)
442 gobj.connect_object(signal_name, handler, connect_obj, *args)
445 gobj.connect_after(signal_name, handler, *args)
447 gobj.connect(signal_name, handler, *args)
449 self.connect_signals_full(_full_callback, obj_or_map)
451 def add_from_string(self, buffer):
452 if not isinstance(buffer, _basestring):
453 raise TypeError('buffer must be a string')
457 return Gtk.Builder.add_from_string(self, buffer, length)
459 def add_objects_from_string(self, buffer, object_ids):
460 if not isinstance(buffer, _basestring):
461 raise TypeError('buffer must be a string')
465 return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids)
467 Builder = override(Builder)
468 __all__.append('Builder')
471 # NOTE: This must come before any other Window/Dialog subclassing, to ensure
472 # that we have a correct inheritance hierarchy.
475 class Window(Gtk.Window):
476 __init__ = deprecated_init(Gtk.Window.__init__,
478 category=PyGTKDeprecationWarning)
480 Window = override(Window)
481 __all__.append('Window')
484 class Dialog(Gtk.Dialog, Container):
485 _old_arg_names = ('title', 'parent', 'flags', 'buttons', '_buttons_property')
486 _init = deprecated_init(Gtk.Dialog.__init__,
487 arg_names=('title', 'transient_for', 'flags',
488 'add_buttons', 'buttons'),
489 ignore=('flags', 'add_buttons'),
490 deprecated_aliases={'transient_for': 'parent',
491 'buttons': '_buttons_property'},
492 category=PyGTKDeprecationWarning)
494 def __init__(self, *args, **kwargs):
496 new_kwargs = kwargs.copy()
497 old_kwargs = dict(zip(self._old_arg_names, args))
498 old_kwargs.update(kwargs)
500 # Increment the warning stacklevel for sub-classes which implement their own __init__.
502 if self.__class__ != Dialog and self.__class__.__init__ != Dialog.__init__:
505 # buttons was overloaded by PyGtk but is needed for Gtk.MessageDialog
506 # as a pass through, so type check the argument and give a deprecation
507 # when it is not of type Gtk.ButtonsType
508 add_buttons = old_kwargs.get('buttons', None)
509 if add_buttons is not None and not isinstance(add_buttons, Gtk.ButtonsType):
510 warnings.warn('The "buttons" argument must be a Gtk.ButtonsType enum value. '
511 'Please use the "add_buttons" method for adding buttons. '
512 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
513 PyGTKDeprecationWarning, stacklevel=stacklevel)
514 if 'buttons' in new_kwargs:
515 del new_kwargs['buttons']
519 flags = old_kwargs.get('flags', 0)
521 warnings.warn('The "flags" argument for dialog construction is deprecated. '
522 'Please use initializer keywords: modal=True and/or destroy_with_parent=True. '
523 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations',
524 PyGTKDeprecationWarning, stacklevel=stacklevel)
526 if flags & Gtk.DialogFlags.MODAL:
527 new_kwargs['modal'] = True
529 if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT:
530 new_kwargs['destroy_with_parent'] = True
532 self._init(*args, **new_kwargs)
535 self.add_buttons(*add_buttons)
537 action_area = property(lambda dialog: dialog.get_action_area())
538 vbox = property(lambda dialog: dialog.get_content_area())
540 def add_buttons(self, *args):
542 The add_buttons() method adds several buttons to the Gtk.Dialog using
543 the button data passed as arguments to the method. This method is the
544 same as calling the Gtk.Dialog.add_button() repeatedly. The button data
545 pairs - button text (or stock ID) and a response ID integer are passed
546 individually. For example:
548 .. code-block:: python
550 dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE)
552 will add "Open" and "Close" buttons to dialog.
561 for text, response in _button(args):
562 self.add_button(text, response)
564 raise TypeError('Must pass an even number of arguments')
566 Dialog = override(Dialog)
567 __all__.append('Dialog')
570 class MessageDialog(Gtk.MessageDialog, Dialog):
571 __init__ = deprecated_init(Gtk.MessageDialog.__init__,
572 arg_names=('parent', 'flags', 'message_type',
573 'buttons', 'message_format'),
574 deprecated_aliases={'text': 'message_format',
575 'message_type': 'type'},
576 category=PyGTKDeprecationWarning)
578 def format_secondary_text(self, message_format):
579 self.set_property('secondary-use-markup', False)
580 self.set_property('secondary-text', message_format)
582 def format_secondary_markup(self, message_format):
583 self.set_property('secondary-use-markup', True)
584 self.set_property('secondary-text', message_format)
586 MessageDialog = override(MessageDialog)
587 __all__.append('MessageDialog')
590 class ColorSelectionDialog(Gtk.ColorSelectionDialog):
591 __init__ = deprecated_init(Gtk.ColorSelectionDialog.__init__,
592 arg_names=('title',),
593 category=PyGTKDeprecationWarning)
595 ColorSelectionDialog = override(ColorSelectionDialog)
596 __all__.append('ColorSelectionDialog')
599 class FileChooserDialog(Gtk.FileChooserDialog):
600 __init__ = deprecated_init(Gtk.FileChooserDialog.__init__,
601 arg_names=('title', 'parent', 'action', 'buttons'),
602 category=PyGTKDeprecationWarning)
604 FileChooserDialog = override(FileChooserDialog)
605 __all__.append('FileChooserDialog')
608 class FontSelectionDialog(Gtk.FontSelectionDialog):
609 __init__ = deprecated_init(Gtk.FontSelectionDialog.__init__,
610 arg_names=('title',),
611 category=PyGTKDeprecationWarning)
613 FontSelectionDialog = override(FontSelectionDialog)
614 __all__.append('FontSelectionDialog')
617 class RecentChooserDialog(Gtk.RecentChooserDialog):
618 # Note, the "manager" keyword must work across the entire 3.x series because
619 # "recent_manager" is not backwards compatible with PyGObject versions prior to 3.10.
620 __init__ = deprecated_init(Gtk.RecentChooserDialog.__init__,
621 arg_names=('title', 'parent', 'recent_manager', 'buttons'),
622 deprecated_aliases={'recent_manager': 'manager'},
623 category=PyGTKDeprecationWarning)
625 RecentChooserDialog = override(RecentChooserDialog)
626 __all__.append('RecentChooserDialog')
629 class IconView(Gtk.IconView):
630 __init__ = deprecated_init(Gtk.IconView.__init__,
631 arg_names=('model',),
632 category=PyGTKDeprecationWarning)
634 get_item_at_pos = strip_boolean_result(Gtk.IconView.get_item_at_pos)
635 get_visible_range = strip_boolean_result(Gtk.IconView.get_visible_range)
636 get_dest_item_at_pos = strip_boolean_result(Gtk.IconView.get_dest_item_at_pos)
638 IconView = override(IconView)
639 __all__.append('IconView')
642 class ToolButton(Gtk.ToolButton):
643 __init__ = deprecated_init(Gtk.ToolButton.__init__,
644 arg_names=('stock_id',),
645 category=PyGTKDeprecationWarning)
647 ToolButton = override(ToolButton)
648 __all__.append('ToolButton')
651 class IMContext(Gtk.IMContext):
652 get_surrounding = strip_boolean_result(Gtk.IMContext.get_surrounding)
654 IMContext = override(IMContext)
655 __all__.append('IMContext')
658 class RecentInfo(Gtk.RecentInfo):
659 get_application_info = strip_boolean_result(Gtk.RecentInfo.get_application_info)
661 RecentInfo = override(RecentInfo)
662 __all__.append('RecentInfo')
665 class TextBuffer(Gtk.TextBuffer):
666 def _get_or_create_tag_table(self):
667 table = self.get_tag_table()
669 table = Gtk.TextTagTable()
670 self.set_tag_table(table)
674 def create_tag(self, tag_name=None, **properties):
675 """Creates a tag and adds it to the tag table of the TextBuffer.
678 Name of the new tag, or None
680 Keyword list of properties and their values
682 This is equivalent to creating a Gtk.TextTag and then adding the
683 tag to the buffer's tag table. The returned tag is owned by
684 the buffer's tag table.
686 If ``tag_name`` is None, the tag is anonymous.
688 If ``tag_name`` is not None, a tag called ``tag_name`` must not already
689 exist in the tag table for this buffer.
691 Properties are passed as a keyword list of names and values (e.g.
692 foreground='DodgerBlue', weight=Pango.Weight.BOLD)
698 tag = Gtk.TextTag(name=tag_name, **properties)
699 self._get_or_create_tag_table().add(tag)
702 def create_mark(self, mark_name, where, left_gravity=False):
703 return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity)
705 def set_text(self, text, length=-1):
706 Gtk.TextBuffer.set_text(self, text, length)
708 def insert(self, iter, text, length=-1):
709 if not isinstance(text, _basestring):
710 raise TypeError('text must be a string, not %s' % type(text))
712 Gtk.TextBuffer.insert(self, iter, text, length)
714 def insert_with_tags(self, iter, text, *tags):
715 start_offset = iter.get_offset()
716 self.insert(iter, text)
721 start = self.get_iter_at_offset(start_offset)
724 self.apply_tag(tag, start, iter)
726 def insert_with_tags_by_name(self, iter, text, *tags):
733 tag_obj = self.get_tag_table().lookup(tag)
735 raise ValueError('unknown text tag: %s' % tag)
736 tag_objs.append(tag_obj)
738 self.insert_with_tags(iter, text, *tag_objs)
740 def insert_at_cursor(self, text, length=-1):
741 if not isinstance(text, _basestring):
742 raise TypeError('text must be a string, not %s' % type(text))
744 Gtk.TextBuffer.insert_at_cursor(self, text, length)
746 get_selection_bounds = strip_boolean_result(Gtk.TextBuffer.get_selection_bounds, fail_ret=())
748 TextBuffer = override(TextBuffer)
749 __all__.append('TextBuffer')
752 class TextIter(Gtk.TextIter):
753 forward_search = strip_boolean_result(Gtk.TextIter.forward_search)
754 backward_search = strip_boolean_result(Gtk.TextIter.backward_search)
756 TextIter = override(TextIter)
757 __all__.append('TextIter')
760 class TreeModel(Gtk.TreeModel):
762 return self.iter_n_children(None)
767 # alias for Python 2.x object protocol
768 __nonzero__ = __bool__
770 def _getiter(self, key):
771 if isinstance(key, Gtk.TreeIter):
773 elif isinstance(key, int) and key < 0:
774 index = len(self) + key
776 raise IndexError("row index is out of bounds: %d" % key)
778 aiter = self.get_iter(index)
780 raise IndexError("could not find tree path '%s'" % key)
784 aiter = self.get_iter(key)
786 raise IndexError("could not find tree path '%s'" % key)
789 def _coerce_path(self, path):
790 if isinstance(path, Gtk.TreePath):
793 return TreePath(path)
795 def __getitem__(self, key):
796 aiter = self._getiter(key)
797 return TreeModelRow(self, aiter)
799 def __setitem__(self, key, value):
801 self.set_row(row.iter, value)
803 def __delitem__(self, key):
804 aiter = self._getiter(key)
808 return TreeModelRowIter(self, self.get_iter_first())
810 get_iter_first = strip_boolean_result(Gtk.TreeModel.get_iter_first)
811 iter_children = strip_boolean_result(Gtk.TreeModel.iter_children)
812 iter_nth_child = strip_boolean_result(Gtk.TreeModel.iter_nth_child)
813 iter_parent = strip_boolean_result(Gtk.TreeModel.iter_parent)
814 get_iter_from_string = strip_boolean_result(Gtk.TreeModel.get_iter_from_string,
815 ValueError, 'invalid tree path')
817 def get_iter(self, path):
818 path = self._coerce_path(path)
819 success, aiter = super(TreeModel, self).get_iter(path)
821 raise ValueError("invalid tree path '%s'" % path)
824 def iter_next(self, aiter):
825 next_iter = aiter.copy()
826 success = super(TreeModel, self).iter_next(next_iter)
830 def iter_previous(self, aiter):
831 prev_iter = aiter.copy()
832 success = super(TreeModel, self).iter_previous(prev_iter)
836 def _convert_row(self, row):
837 # TODO: Accept a dictionary for row
838 # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name})
839 if isinstance(row, str):
840 raise TypeError('Expected a list or tuple, but got str')
842 n_columns = self.get_n_columns()
843 if len(row) != n_columns:
844 raise ValueError('row sequence has the incorrect number of elements')
848 for cur_col, value in enumerate(row):
849 # do not try to set None values, they are causing warnings
852 result.append(self._convert_value(cur_col, value))
853 columns.append(cur_col)
854 return (result, columns)
856 def set_row(self, treeiter, row):
857 converted_row, columns = self._convert_row(row)
858 for column in columns:
861 continue # None means skip this row
863 self.set_value(treeiter, column, value)
865 def _convert_value(self, column, value):
866 '''Convert value to a GObject.Value of the expected type'''
868 if isinstance(value, GObject.Value):
870 return GObject.Value(self.get_column_type(column), value)
872 def get(self, treeiter, *columns):
873 n_columns = self.get_n_columns()
877 if not isinstance(col, int):
878 raise TypeError("column numbers must be ints")
880 if col < 0 or col >= n_columns:
881 raise ValueError("column number is out of range")
883 values.append(self.get_value(treeiter, col))
888 # Signals supporting python iterables as tree paths
890 def row_changed(self, path, iter):
891 return super(TreeModel, self).row_changed(self._coerce_path(path), iter)
893 def row_inserted(self, path, iter):
894 return super(TreeModel, self).row_inserted(self._coerce_path(path), iter)
896 def row_has_child_toggled(self, path, iter):
897 return super(TreeModel, self).row_has_child_toggled(self._coerce_path(path),
900 def row_deleted(self, path):
901 return super(TreeModel, self).row_deleted(self._coerce_path(path))
903 def rows_reordered(self, path, iter, new_order):
904 return super(TreeModel, self).rows_reordered(self._coerce_path(path),
908 TreeModel = override(TreeModel)
909 __all__.append('TreeModel')
912 class TreeSortable(Gtk.TreeSortable, ):
914 get_sort_column_id = strip_boolean_result(Gtk.TreeSortable.get_sort_column_id, fail_ret=(None, None))
916 def set_sort_func(self, sort_column_id, sort_func, user_data=None):
917 super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data)
919 def set_default_sort_func(self, sort_func, user_data=None):
920 super(TreeSortable, self).set_default_sort_func(sort_func, user_data)
922 TreeSortable = override(TreeSortable)
923 __all__.append('TreeSortable')
926 class TreeModelSort(Gtk.TreeModelSort):
927 __init__ = deprecated_init(Gtk.TreeModelSort.__init__,
928 arg_names=('model',),
929 category=PyGTKDeprecationWarning)
931 TreeModelSort = override(TreeModelSort)
932 __all__.append('TreeModelSort')
935 class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
936 def __init__(self, *column_types):
937 Gtk.ListStore.__init__(self)
938 self.set_column_types(column_types)
940 def _do_insert(self, position, row):
942 row, columns = self._convert_row(row)
943 treeiter = self.insert_with_valuesv(position, columns, row)
945 treeiter = Gtk.ListStore.insert(self, position)
949 def append(self, row=None):
951 return self._do_insert(-1, row)
952 # gtk_list_store_insert() does not know about the "position == -1"
953 # case, so use append() here
955 return Gtk.ListStore.append(self)
957 def prepend(self, row=None):
958 return self._do_insert(0, row)
960 def insert(self, position, row=None):
961 return self._do_insert(position, row)
963 # FIXME: sends two signals; check if this can use an atomic
964 # insert_with_valuesv()
966 def insert_before(self, sibling, row=None):
967 treeiter = Gtk.ListStore.insert_before(self, sibling)
970 self.set_row(treeiter, row)
974 # FIXME: sends two signals; check if this can use an atomic
975 # insert_with_valuesv()
977 def insert_after(self, sibling, row=None):
978 treeiter = Gtk.ListStore.insert_after(self, sibling)
981 self.set_row(treeiter, row)
985 def set_value(self, treeiter, column, value):
986 value = self._convert_value(column, value)
987 Gtk.ListStore.set_value(self, treeiter, column, value)
989 def set(self, treeiter, *args):
991 def _set_lists(columns, values):
992 if len(columns) != len(values):
993 raise TypeError('The number of columns do not match the number of values')
994 for col_num, val in zip(columns, values):
995 if not isinstance(col_num, int):
996 raise TypeError('TypeError: Expected integer argument for column.')
997 self.set_value(treeiter, col_num, val)
1000 if isinstance(args[0], int):
1003 _set_lists(columns, values)
1004 elif isinstance(args[0], (tuple, list)):
1006 raise TypeError('Too many arguments')
1007 _set_lists(args[0], args[1])
1008 elif isinstance(args[0], dict):
1009 columns = args[0].keys()
1010 values = args[0].values()
1011 _set_lists(columns, values)
1013 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1015 ListStore = override(ListStore)
1016 __all__.append('ListStore')
1019 class TreeModelRow(object):
1021 def __init__(self, model, iter_or_path):
1022 if not isinstance(model, Gtk.TreeModel):
1023 raise TypeError("expected Gtk.TreeModel, %s found" % type(model).__name__)
1025 if isinstance(iter_or_path, Gtk.TreePath):
1026 self.iter = model.get_iter(iter_or_path)
1027 elif isinstance(iter_or_path, Gtk.TreeIter):
1028 self.iter = iter_or_path
1030 raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \
1031 %s found" % type(iter_or_path).__name__)
1035 return self.model.get_path(self.iter)
1039 return self.get_next()
1043 return self.get_previous()
1047 return self.get_parent()
1050 next_iter = self.model.iter_next(self.iter)
1052 return TreeModelRow(self.model, next_iter)
1054 def get_previous(self):
1055 prev_iter = self.model.iter_previous(self.iter)
1057 return TreeModelRow(self.model, prev_iter)
1059 def get_parent(self):
1060 parent_iter = self.model.iter_parent(self.iter)
1062 return TreeModelRow(self.model, parent_iter)
1064 def __getitem__(self, key):
1065 if isinstance(key, int):
1066 if key >= self.model.get_n_columns():
1067 raise IndexError("column index is out of bounds: %d" % key)
1069 key = self._convert_negative_index(key)
1070 return self.model.get_value(self.iter, key)
1071 elif isinstance(key, slice):
1072 start, stop, step = key.indices(self.model.get_n_columns())
1074 for i in range(start, stop, step):
1075 alist.append(self.model.get_value(self.iter, i))
1078 raise TypeError("indices must be integers, not %s" % type(key).__name__)
1080 def __setitem__(self, key, value):
1081 if isinstance(key, int):
1082 if key >= self.model.get_n_columns():
1083 raise IndexError("column index is out of bounds: %d" % key)
1085 key = self._convert_negative_index(key)
1086 self.model.set_value(self.iter, key, value)
1087 elif isinstance(key, slice):
1088 start, stop, step = key.indices(self.model.get_n_columns())
1089 indexList = range(start, stop, step)
1090 if len(indexList) != len(value):
1092 "attempt to assign sequence of size %d to slice of size %d"
1093 % (len(value), len(indexList)))
1095 for i, v in enumerate(indexList):
1096 self.model.set_value(self.iter, v, value[i])
1098 raise TypeError("index must be an integer or slice, not %s" % type(key).__name__)
1100 def _convert_negative_index(self, index):
1101 new_index = self.model.get_n_columns() + index
1103 raise IndexError("column index is out of bounds: %d" % index)
1106 def iterchildren(self):
1107 child_iter = self.model.iter_children(self.iter)
1108 return TreeModelRowIter(self.model, child_iter)
1110 __all__.append('TreeModelRow')
1113 class TreeModelRowIter(object):
1115 def __init__(self, model, aiter):
1122 row = TreeModelRow(self.model, self.iter)
1123 self.iter = self.model.iter_next(self.iter)
1126 # alias for Python 2.x object protocol
1132 __all__.append('TreeModelRowIter')
1135 class TreePath(Gtk.TreePath):
1137 def __new__(cls, path=0):
1138 if isinstance(path, int):
1140 elif not isinstance(path, _basestring):
1141 path = ":".join(str(val) for val in path)
1144 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1146 return TreePath.new_from_string(path)
1148 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1150 def __init__(self, *args, **kwargs):
1151 super(TreePath, self).__init__()
1154 return self.to_string()
1156 def __lt__(self, other):
1157 return other is not None and self.compare(other) < 0
1159 def __le__(self, other):
1160 return other is not None and self.compare(other) <= 0
1162 def __eq__(self, other):
1163 return other is not None and self.compare(other) == 0
1165 def __ne__(self, other):
1166 return other is None or self.compare(other) != 0
1168 def __gt__(self, other):
1169 return other is None or self.compare(other) > 0
1171 def __ge__(self, other):
1172 return other is None or self.compare(other) >= 0
1175 return iter(self.get_indices())
1178 return self.get_depth()
1180 def __getitem__(self, index):
1181 return self.get_indices()[index]
1183 TreePath = override(TreePath)
1184 __all__.append('TreePath')
1187 class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
1188 def __init__(self, *column_types):
1189 Gtk.TreeStore.__init__(self)
1190 self.set_column_types(column_types)
1192 def _do_insert(self, parent, position, row):
1194 row, columns = self._convert_row(row)
1195 treeiter = self.insert_with_values(parent, position, columns, row)
1197 treeiter = Gtk.TreeStore.insert(self, parent, position)
1201 def append(self, parent, row=None):
1202 return self._do_insert(parent, -1, row)
1204 def prepend(self, parent, row=None):
1205 return self._do_insert(parent, 0, row)
1207 def insert(self, parent, position, row=None):
1208 return self._do_insert(parent, position, row)
1210 # FIXME: sends two signals; check if this can use an atomic
1211 # insert_with_valuesv()
1213 def insert_before(self, parent, sibling, row=None):
1214 treeiter = Gtk.TreeStore.insert_before(self, parent, sibling)
1217 self.set_row(treeiter, row)
1221 # FIXME: sends two signals; check if this can use an atomic
1222 # insert_with_valuesv()
1224 def insert_after(self, parent, sibling, row=None):
1225 treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
1228 self.set_row(treeiter, row)
1232 def set_value(self, treeiter, column, value):
1233 value = self._convert_value(column, value)
1234 Gtk.TreeStore.set_value(self, treeiter, column, value)
1236 def set(self, treeiter, *args):
1238 def _set_lists(columns, values):
1239 if len(columns) != len(values):
1240 raise TypeError('The number of columns do not match the number of values')
1241 for col_num, val in zip(columns, values):
1242 if not isinstance(col_num, int):
1243 raise TypeError('TypeError: Expected integer argument for column.')
1244 self.set_value(treeiter, col_num, val)
1247 if isinstance(args[0], int):
1250 _set_lists(columns, values)
1251 elif isinstance(args[0], (tuple, list)):
1253 raise TypeError('Too many arguments')
1254 _set_lists(args[0], args[1])
1255 elif isinstance(args[0], dict):
1256 columns = args[0].keys()
1257 values = args[0].values()
1258 _set_lists(columns, values)
1260 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1262 TreeStore = override(TreeStore)
1263 __all__.append('TreeStore')
1266 class TreeView(Gtk.TreeView, Container):
1267 __init__ = deprecated_init(Gtk.TreeView.__init__,
1268 arg_names=('model',),
1269 category=PyGTKDeprecationWarning)
1271 get_path_at_pos = strip_boolean_result(Gtk.TreeView.get_path_at_pos)
1272 get_visible_range = strip_boolean_result(Gtk.TreeView.get_visible_range)
1273 get_dest_row_at_pos = strip_boolean_result(Gtk.TreeView.get_dest_row_at_pos)
1275 def enable_model_drag_source(self, start_button_mask, targets, actions):
1276 target_entries = _construct_target_list(targets)
1277 super(TreeView, self).enable_model_drag_source(start_button_mask,
1281 def enable_model_drag_dest(self, targets, actions):
1282 target_entries = _construct_target_list(targets)
1283 super(TreeView, self).enable_model_drag_dest(target_entries,
1286 def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0):
1287 if not isinstance(path, Gtk.TreePath):
1288 path = TreePath(path)
1289 super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align)
1291 def set_cursor(self, path, column=None, start_editing=False):
1292 if not isinstance(path, Gtk.TreePath):
1293 path = TreePath(path)
1294 super(TreeView, self).set_cursor(path, column, start_editing)
1296 def get_cell_area(self, path, column=None):
1297 if not isinstance(path, Gtk.TreePath):
1298 path = TreePath(path)
1299 return super(TreeView, self).get_cell_area(path, column)
1301 def insert_column_with_attributes(self, position, title, cell, **kwargs):
1302 column = TreeViewColumn()
1303 column.set_title(title)
1304 column.pack_start(cell, False)
1305 self.insert_column(column, position)
1306 column.set_attributes(cell, **kwargs)
1308 TreeView = override(TreeView)
1309 __all__.append('TreeView')
1312 class TreeViewColumn(Gtk.TreeViewColumn):
1313 def __init__(self, title='',
1316 Gtk.TreeViewColumn.__init__(self, title=title)
1318 self.pack_start(cell_renderer, True)
1320 for (name, value) in attributes.items():
1321 self.add_attribute(cell_renderer, name, value)
1323 cell_get_position = strip_boolean_result(Gtk.TreeViewColumn.cell_get_position)
1325 def set_cell_data_func(self, cell_renderer, func, func_data=None):
1326 super(TreeViewColumn, self).set_cell_data_func(cell_renderer, func, func_data)
1328 def set_attributes(self, cell_renderer, **attributes):
1329 Gtk.CellLayout.clear_attributes(self, cell_renderer)
1331 for (name, value) in attributes.items():
1332 Gtk.CellLayout.add_attribute(self, cell_renderer, name, value)
1335 TreeViewColumn = override(TreeViewColumn)
1336 __all__.append('TreeViewColumn')
1339 class TreeSelection(Gtk.TreeSelection):
1341 def select_path(self, path):
1342 if not isinstance(path, Gtk.TreePath):
1343 path = TreePath(path)
1344 super(TreeSelection, self).select_path(path)
1346 def get_selected(self):
1347 success, model, aiter = super(TreeSelection, self).get_selected()
1349 return (model, aiter)
1351 return (model, None)
1353 # for compatibility with PyGtk
1355 def get_selected_rows(self):
1356 rows, model = super(TreeSelection, self).get_selected_rows()
1357 return (model, rows)
1360 TreeSelection = override(TreeSelection)
1361 __all__.append('TreeSelection')
1364 class Button(Gtk.Button, Container):
1365 _init = deprecated_init(Gtk.Button.__init__,
1366 arg_names=('label', 'stock', 'use_stock', 'use_underline'),
1368 category=PyGTKDeprecationWarning,
1371 def __init__(self, *args, **kwargs):
1372 # Doubly deprecated initializer, the stock keyword is non-standard.
1373 # Simply give a warning that stock items are deprecated even though
1374 # we want to deprecate the non-standard keyword as well here from
1376 if 'stock' in kwargs and kwargs['stock']:
1377 warnings.warn('Stock items are deprecated. '
1378 'Please use: Gtk.Button.new_with_mnemonic(label)',
1379 PyGTKDeprecationWarning, stacklevel=2)
1380 new_kwargs = kwargs.copy()
1381 new_kwargs['label'] = new_kwargs['stock']
1382 new_kwargs['use_stock'] = True
1383 new_kwargs['use_underline'] = True
1384 del new_kwargs['stock']
1385 Gtk.Button.__init__(self, **new_kwargs)
1387 self._init(*args, **kwargs)
1389 Button = override(Button)
1390 __all__.append('Button')
1393 class LinkButton(Gtk.LinkButton):
1394 __init__ = deprecated_init(Gtk.LinkButton.__init__,
1395 arg_names=('uri', 'label'),
1396 category=PyGTKDeprecationWarning)
1398 LinkButton = override(LinkButton)
1399 __all__.append('LinkButton')
1402 class Label(Gtk.Label):
1403 __init__ = deprecated_init(Gtk.Label.__init__,
1404 arg_names=('label',),
1405 category=PyGTKDeprecationWarning)
1407 Label = override(Label)
1408 __all__.append('Label')
1411 class Adjustment(Gtk.Adjustment):
1412 _init = deprecated_init(Gtk.Adjustment.__init__,
1413 arg_names=('value', 'lower', 'upper',
1414 'step_increment', 'page_increment', 'page_size'),
1415 deprecated_aliases={'page_increment': 'page_incr',
1416 'step_increment': 'step_incr'},
1417 category=PyGTKDeprecationWarning,
1420 def __init__(self, *args, **kwargs):
1421 self._init(*args, **kwargs)
1423 # The value property is set between lower and (upper - page_size).
1424 # Just in case lower, upper or page_size was still 0 when value
1425 # was set, we set it again here.
1426 if 'value' in kwargs:
1427 self.set_value(kwargs['value'])
1429 Adjustment = override(Adjustment)
1430 __all__.append('Adjustment')
1433 class Table(Gtk.Table, Container):
1434 __init__ = deprecated_init(Gtk.Table.__init__,
1435 arg_names=('n_rows', 'n_columns', 'homogeneous'),
1436 deprecated_aliases={'n_rows': 'rows', 'n_columns': 'columns'},
1437 category=PyGTKDeprecationWarning)
1439 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):
1440 Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding)
1442 Table = override(Table)
1443 __all__.append('Table')
1446 class ScrolledWindow(Gtk.ScrolledWindow):
1447 __init__ = deprecated_init(Gtk.ScrolledWindow.__init__,
1448 arg_names=('hadjustment', 'vadjustment'),
1449 category=PyGTKDeprecationWarning)
1451 ScrolledWindow = override(ScrolledWindow)
1452 __all__.append('ScrolledWindow')
1455 class HScrollbar(Gtk.HScrollbar):
1456 __init__ = deprecated_init(Gtk.HScrollbar.__init__,
1457 arg_names=('adjustment',),
1458 category=PyGTKDeprecationWarning)
1460 HScrollbar = override(HScrollbar)
1461 __all__.append('HScrollbar')
1464 class VScrollbar(Gtk.VScrollbar):
1465 __init__ = deprecated_init(Gtk.VScrollbar.__init__,
1466 arg_names=('adjustment',),
1467 category=PyGTKDeprecationWarning)
1469 VScrollbar = override(VScrollbar)
1470 __all__.append('VScrollbar')
1473 class Paned(Gtk.Paned):
1474 def pack1(self, child, resize=False, shrink=True):
1475 super(Paned, self).pack1(child, resize, shrink)
1477 def pack2(self, child, resize=True, shrink=True):
1478 super(Paned, self).pack2(child, resize, shrink)
1480 Paned = override(Paned)
1481 __all__.append('Paned')
1484 class Arrow(Gtk.Arrow):
1485 __init__ = deprecated_init(Gtk.Arrow.__init__,
1486 arg_names=('arrow_type', 'shadow_type'),
1487 category=PyGTKDeprecationWarning)
1489 Arrow = override(Arrow)
1490 __all__.append('Arrow')
1493 class IconSet(Gtk.IconSet):
1494 def __new__(cls, pixbuf=None):
1495 if pixbuf is not None:
1496 warnings.warn('Gtk.IconSet(pixbuf) has been deprecated. Please use: '
1497 'Gtk.IconSet.new_from_pixbuf(pixbuf)',
1498 PyGTKDeprecationWarning, stacklevel=2)
1499 iconset = Gtk.IconSet.new_from_pixbuf(pixbuf)
1501 iconset = Gtk.IconSet.__new__(cls)
1504 def __init__(self, *args, **kwargs):
1505 return super(IconSet, self).__init__()
1507 IconSet = override(IconSet)
1508 __all__.append('IconSet')
1511 class Viewport(Gtk.Viewport):
1512 __init__ = deprecated_init(Gtk.Viewport.__init__,
1513 arg_names=('hadjustment', 'vadjustment'),
1514 category=PyGTKDeprecationWarning)
1516 Viewport = override(Viewport)
1517 __all__.append('Viewport')
1520 class TreeModelFilter(Gtk.TreeModelFilter):
1521 def set_visible_func(self, func, data=None):
1522 super(TreeModelFilter, self).set_visible_func(func, data)
1524 def set_value(self, iter, column, value):
1525 # Delegate to child model
1526 iter = self.convert_iter_to_child_iter(iter)
1527 self.get_model().set_value(iter, column, value)
1529 TreeModelFilter = override(TreeModelFilter)
1530 __all__.append('TreeModelFilter')
1532 if Gtk._version != '2.0':
1533 class Menu(Gtk.Menu):
1534 def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time):
1535 self.popup_for_device(None, parent_menu_shell, parent_menu_item, func, data, button, activate_time)
1536 Menu = override(Menu)
1537 __all__.append('Menu')
1539 _Gtk_main_quit = Gtk.main_quit
1542 @override(Gtk.main_quit)
1543 def main_quit(*args):
1546 stock_lookup = strip_boolean_result(Gtk.stock_lookup)
1547 __all__.append('stock_lookup')
1549 initialized, argv = Gtk.init_check(sys.argv)
1550 sys.argv = list(argv)