5eab41b7e4bb0bd307364ef109bd349b47c07a26
[platform/upstream/python-gobject.git] / gi / overrides / Gtk.py
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
3 #
4 # Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
5 #               2010 Simon van der Linden <svdlinden@src.gnome.org>
6 #
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.
11 #
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.
16 #
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
20 # USA
21
22 import sys
23 from gi.repository import GObject
24 from ..overrides import override
25 from ..importer import modules
26
27 if sys.version_info >= (3, 0):
28     _basestring = str
29     _callable = lambda c: hasattr(c, '__call__')
30 else:
31     _basestring = basestring
32     _callable = callable
33
34 Gtk = modules['Gtk']._introspection_module
35 __all__ = []
36
37 if Gtk._version == '2.0':
38     import warnings
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"
45
46     warnings.warn(warn_msg, RuntimeWarning)
47
48
49 class Widget(Gtk.Widget):
50
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)
54         if success:
55             return (dest_x, dest_y,)
56
57     def render_icon(self, stock_id, size, detail=None):
58         return super(Widget, self).render_icon(stock_id, size, detail)
59
60 Widget = override(Widget)
61 __all__.append('Widget')
62
63
64 class Container(Gtk.Container, Widget):
65
66     def __len__(self):
67         return len(self.get_children())
68
69     def __contains__(self, child):
70         return child in self.get_children()
71
72     def __iter__(self):
73         return iter(self.get_children())
74
75     def __bool__(self):
76         return True
77
78     # alias for Python 2.x object protocol
79     __nonzero__ = __bool__
80
81     def get_focus_chain(self):
82         success, widgets = super(Container, self).get_focus_chain()
83         if success:
84             return widgets
85
86 Container = override(Container)
87 __all__.append('Container')
88
89
90 class Editable(Gtk.Editable):
91
92     def insert_text(self, text, position):
93         pos = super(Editable, self).insert_text(text, -1, position)
94
95         return pos
96
97     def get_selection_bounds(self):
98         success, start_pos, end_pos = super(Editable, self).get_selection_bounds()
99         if success:
100             return (start_pos, end_pos,)
101         else:
102             return tuple()
103
104 Editable = override(Editable)
105 __all__.append("Editable")
106
107
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)
111
112 Action = override(Action)
113 __all__.append("Action")
114
115
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)
119
120 RadioAction = override(RadioAction)
121 __all__.append("RadioAction")
122
123
124 class ActionGroup(Gtk.ActionGroup):
125     def __init__(self, name, **kwds):
126         super(ActionGroup, self).__init__(name=name, **kwds)
127
128     def add_actions(self, entries, user_data=None):
129         """
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:
135
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
144               None.
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.
150
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.
153         """
154         try:
155             iter(entries)
156         except (TypeError):
157             raise TypeError('entries must be iterable')
158
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)
164                 else:
165                     action.connect('activate', callback, user_data)
166
167             self.add_action_with_accel(action, accelerator)
168
169         for e in entries:
170             # using inner function above since entries can leave out optional arguments
171             _process_action(*e)
172
173     def add_toggle_actions(self, entries, user_data=None):
174         """
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:
180
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
189               None.
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.
197
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.
200         """
201
202         try:
203             iter(entries)
204         except (TypeError):
205             raise TypeError('entries must be iterable')
206
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)
213                 else:
214                     action.connect('activate', callback, user_data)
215
216             self.add_action_with_accel(action, accelerator)
217
218         for e in entries:
219             # using inner function above since entries can leave out optional arguments
220             _process_action(*e)
221
222     def add_radio_actions(self, entries, value=None, on_change=None, user_data=None):
223         """
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:
229
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
238               None.
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.
244
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.
249         """
250         try:
251             iter(entries)
252         except (TypeError):
253             raise TypeError('entries must be iterable')
254
255         first_action = None
256
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)
259
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
264             #        C module?
265             if hasattr(action, 'join_group'):
266                 action.join_group(group_source)
267
268             if value == entry_value:
269                 action.set_active(True)
270
271             self.add_action_with_accel(action, accelerator)
272             return action
273
274         for e in entries:
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
279
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)
283             else:
284                 first_action.connect('changed', on_change, user_data)
285
286 ActionGroup = override(ActionGroup)
287 __all__.append('ActionGroup')
288
289
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')
294
295         length = len(buffer)
296
297         return Gtk.UIManager.add_ui_from_string(self, buffer, length)
298
299     def insert_action_group(self, buffer, length=-1):
300         return Gtk.UIManager.insert_action_group(self, buffer, length)
301
302 UIManager = override(UIManager)
303 __all__.append('UIManager')
304
305
306 class ComboBox(Gtk.ComboBox, Container):
307
308     def get_active_iter(self):
309         success, aiter = super(ComboBox, self).get_active_iter()
310         if success:
311             return aiter
312
313 ComboBox = override(ComboBox)
314 __all__.append('ComboBox')
315
316
317 class Box(Gtk.Box):
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)
322
323 Box = override(Box)
324 __all__.append('Box')
325
326
327 class SizeGroup(Gtk.SizeGroup):
328     def __init__(self, mode=Gtk.SizeGroupMode.VERTICAL):
329         super(SizeGroup, self).__init__(mode=mode)
330
331 SizeGroup = override(SizeGroup)
332 __all__.append('SizeGroup')
333
334
335 class MenuItem(Gtk.MenuItem):
336     def __init__(self, label=None, **kwds):
337         if label:
338             super(MenuItem, self).__init__(label=label, **kwds)
339         else:
340             super(MenuItem, self).__init__(**kwds)
341
342 MenuItem = override(MenuItem)
343 __all__.append('MenuItem')
344
345
346 class Builder(Gtk.Builder):
347
348     def connect_signals(self, obj_or_map):
349         def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map):
350             handler = None
351             if isinstance(obj_or_map, dict):
352                 handler = obj_or_map.get(handler_name, None)
353             else:
354                 handler = getattr(obj_or_map, handler_name, None)
355
356             if handler is None:
357                 raise AttributeError('Handler %s not found' % handler_name)
358
359             if not _callable(handler):
360                 raise TypeError('Handler %s is not a method or function' % handler_name)
361
362             after = flags & GObject.ConnectFlags.AFTER
363             if connect_obj is not None:
364                 if after:
365                     gobj.connect_object_after(signal_name, handler, connect_obj)
366                 else:
367                     gobj.connect_object(signal_name, handler, connect_obj)
368             else:
369                 if after:
370                     gobj.connect_after(signal_name, handler)
371                 else:
372                     gobj.connect(signal_name, handler)
373
374         self.connect_signals_full(_full_callback, obj_or_map)
375
376     def add_from_string(self, buffer):
377         if not isinstance(buffer, _basestring):
378             raise TypeError('buffer must be a string')
379
380         length = len(buffer)
381
382         return Gtk.Builder.add_from_string(self, buffer, length)
383
384     def add_objects_from_string(self, buffer, object_ids):
385         if not isinstance(buffer, _basestring):
386             raise TypeError('buffer must be a string')
387
388         length = len(buffer)
389
390         return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids)
391
392 Builder = override(Builder)
393 __all__.append('Builder')
394
395
396 # NOTE: This must come before any other Window/Dialog subclassing, to ensure
397 # that we have a correct inheritance hierarchy.
398
399
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
404         try:
405             self.get_property('type')
406             Gtk.Window.__init__(self, **kwds)
407         except TypeError:
408             Gtk.Window.__init__(self, type=type, **kwds)
409
410 Window = override(Window)
411 __all__.append('Window')
412
413
414 class Dialog(Gtk.Dialog, Container):
415
416     def __init__(self,
417                  title=None,
418                  parent=None,
419                  flags=0,
420                  buttons=None,
421                  _buttons_property=None,
422                  **kwds):
423
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
429
430         Gtk.Dialog.__init__(self, **kwds)
431         if title:
432             self.set_title(title)
433         if parent:
434             self.set_transient_for(parent)
435         if flags & Gtk.DialogFlags.MODAL:
436             self.set_modal(True)
437         if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT:
438             self.set_destroy_with_parent(True)
439
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)
443             import warnings
444             warnings.warn("Gtk.DialogFlags.NO_SEPARATOR has been depricated since Gtk+-3.0", DeprecationWarning)
445
446         if buttons is not None:
447             self.add_buttons(*buttons)
448
449     action_area = property(lambda dialog: dialog.get_action_area())
450     vbox = property(lambda dialog: dialog.get_content_area())
451
452     def add_buttons(self, *args):
453         """
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:
459
460         >>> dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE)
461
462         will add "Open" and "Close" buttons to dialog.
463         """
464         def _button(b):
465             while b:
466                 t, r = b[0:2]
467                 b = b[2:]
468                 yield t, r
469
470         try:
471             for text, response in _button(args):
472                 self.add_button(text, response)
473         except (IndexError):
474             raise TypeError('Must pass an even number of arguments')
475
476 Dialog = override(Dialog)
477 __all__.append('Dialog')
478
479
480 class MessageDialog(Gtk.MessageDialog, Dialog):
481     def __init__(self,
482                  parent=None,
483                  flags=0,
484                  message_type=Gtk.MessageType.INFO,
485                  buttons=Gtk.ButtonsType.NONE,
486                  message_format=None,
487                  **kwds):
488
489         if message_format:
490             kwds['text'] = message_format
491
492         # type keyword is used for backwards compat with PyGTK
493         if 'type' in kwds:
494             import warnings
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')
497
498         Gtk.MessageDialog.__init__(self,
499                                    _buttons_property=buttons,
500                                    message_type=message_type,
501                                    parent=parent,
502                                    flags=flags,
503                                    **kwds)
504
505     def format_secondary_text(self, message_format):
506         self.set_property('secondary-use-markup', False)
507         self.set_property('secondary-text', message_format)
508
509     def format_secondary_markup(self, message_format):
510         self.set_property('secondary-use-markup', True)
511         self.set_property('secondary-text', message_format)
512
513 MessageDialog = override(MessageDialog)
514 __all__.append('MessageDialog')
515
516
517 class AboutDialog(Gtk.AboutDialog):
518     def __init__(self, **kwds):
519         Gtk.AboutDialog.__init__(self, **kwds)
520
521 AboutDialog = override(AboutDialog)
522 __all__.append('AboutDialog')
523
524
525 class ColorSelectionDialog(Gtk.ColorSelectionDialog):
526     def __init__(self, title=None, **kwds):
527         Gtk.ColorSelectionDialog.__init__(self, title=title, **kwds)
528
529 ColorSelectionDialog = override(ColorSelectionDialog)
530 __all__.append('ColorSelectionDialog')
531
532
533 class FileChooserDialog(Gtk.FileChooserDialog):
534     def __init__(self,
535                  title=None,
536                  parent=None,
537                  action=Gtk.FileChooserAction.OPEN,
538                  buttons=None,
539                  **kwds):
540         Gtk.FileChooserDialog.__init__(self,
541                                        action=action,
542                                        title=title,
543                                        parent=parent,
544                                        buttons=buttons,
545                                        **kwds)
546 FileChooserDialog = override(FileChooserDialog)
547 __all__.append('FileChooserDialog')
548
549
550 class FontSelectionDialog(Gtk.FontSelectionDialog):
551     def __init__(self, title=None, **kwds):
552         Gtk.FontSelectionDialog.__init__(self, title=title, **kwds)
553
554 FontSelectionDialog = override(FontSelectionDialog)
555 __all__.append('FontSelectionDialog')
556
557
558 class RecentChooserDialog(Gtk.RecentChooserDialog):
559     def __init__(self,
560                  title=None,
561                  parent=None,
562                  manager=None,
563                  buttons=None,
564                  **kwds):
565
566         Gtk.RecentChooserDialog.__init__(self,
567                                          recent_manager=manager,
568                                          title=title,
569                                          parent=parent,
570                                          buttons=buttons,
571                                          **kwds)
572
573 RecentChooserDialog = override(RecentChooserDialog)
574 __all__.append('RecentChooserDialog')
575
576
577 class IconView(Gtk.IconView):
578
579     def __init__(self, model=None, **kwds):
580         Gtk.IconView.__init__(self, model=model, **kwds)
581
582     def get_item_at_pos(self, x, y):
583         success, path, cell = super(IconView, self).get_item_at_pos(x, y)
584         if success:
585             return (path, cell,)
586
587     def get_visible_range(self):
588         success, start_path, end_path = super(IconView, self).get_visible_range()
589         if success:
590             return (start_path, end_path,)
591
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)
594         if success:
595             return path, pos
596
597 IconView = override(IconView)
598 __all__.append('IconView')
599
600
601 class ToolButton(Gtk.ToolButton):
602
603     def __init__(self, stock_id=None, **kwds):
604         Gtk.ToolButton.__init__(self, stock_id=stock_id, **kwds)
605
606 ToolButton = override(ToolButton)
607 __all__.append('ToolButton')
608
609
610 class IMContext(Gtk.IMContext):
611
612     def get_surrounding(self):
613         success, text, cursor_index = super(IMContext, self).get_surrounding()
614         if success:
615             return (text, cursor_index,)
616
617 IMContext = override(IMContext)
618 __all__.append('IMContext')
619
620
621 class RecentInfo(Gtk.RecentInfo):
622
623     def get_application_info(self, app_name):
624         success, app_exec, count, time = super(RecentInfo, self).get_application_info(app_name)
625         if success:
626             return (app_exec, count, time,)
627
628 RecentInfo = override(RecentInfo)
629 __all__.append('RecentInfo')
630
631
632 class TextBuffer(Gtk.TextBuffer):
633     def _get_or_create_tag_table(self):
634         table = self.get_tag_table()
635         if table is None:
636             table = Gtk.TextTagTable()
637             self.set_tag_table(table)
638
639         return table
640
641     def create_tag(self, tag_name=None, **properties):
642         """
643         @tag_name: name of the new tag, or None
644         @properties: keyword list of properties and their values
645
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.
650
651         If @tag_name is None, the tag is anonymous.
652
653         If @tag_name is not None, a tag called @tag_name must not already
654         exist in the tag table for this buffer.
655
656         Properties are passed as a keyword list of names and values (e.g.
657         foreground = 'DodgerBlue', weight = Pango.Weight.BOLD)
658
659         Return value: a new tag
660         """
661
662         tag = Gtk.TextTag(name=tag_name, **properties)
663         self._get_or_create_tag_table().add(tag)
664         return tag
665
666     def create_mark(self, mark_name, where, left_gravity=False):
667         return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity)
668
669     def set_text(self, text, length=-1):
670         Gtk.TextBuffer.set_text(self, text, length)
671
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))
675
676         Gtk.TextBuffer.insert(self, iter, text, length)
677
678     def insert_with_tags(self, iter, text, *tags):
679         start_offset = iter.get_offset()
680         self.insert(iter, text)
681
682         if not tags:
683             return
684
685         start = self.get_iter_at_offset(start_offset)
686
687         for tag in tags:
688             self.apply_tag(tag, start, iter)
689
690     def insert_with_tags_by_name(self, iter, text, *tags):
691         if not tags:
692             return
693
694         tag_objs = []
695
696         for tag in tags:
697             tag_obj = self.get_tag_table().lookup(tag)
698             if not tag_obj:
699                 raise ValueError('unknown text tag: %s' % tag)
700             tag_objs.append(tag_obj)
701
702         self.insert_with_tags(iter, text, *tag_objs)
703
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))
707
708         Gtk.TextBuffer.insert_at_cursor(self, text, length)
709
710     def get_selection_bounds(self):
711         success, start, end = super(TextBuffer, self).get_selection_bounds()
712         if success:
713             return (start, end)
714         else:
715             return ()
716
717 TextBuffer = override(TextBuffer)
718 __all__.append('TextBuffer')
719
720
721 class TextIter(Gtk.TextIter):
722
723     def forward_search(self, string, flags, limit):
724         success, match_start, match_end = super(TextIter, self).forward_search(string,
725                                                                                flags, limit)
726         if success:
727             return (match_start, match_end)
728         else:
729             return None
730
731     def backward_search(self, string, flags, limit):
732         success, match_start, match_end = super(TextIter, self).backward_search(string,
733                                                                                 flags, limit)
734         if success:
735             return (match_start, match_end)
736         else:
737             return None
738
739     def begins_tag(self, tag=None):
740         return super(TextIter, self).begins_tag(tag)
741
742     def ends_tag(self, tag=None):
743         return super(TextIter, self).ends_tag(tag)
744
745     def toggles_tag(self, tag=None):
746         return super(TextIter, self).toggles_tag(tag)
747
748 TextIter = override(TextIter)
749 __all__.append('TextIter')
750
751
752 class TreeModel(Gtk.TreeModel):
753     def __len__(self):
754         return self.iter_n_children(None)
755
756     def __bool__(self):
757         return True
758
759     # alias for Python 2.x object protocol
760     __nonzero__ = __bool__
761
762     def _getiter(self, key):
763         if isinstance(key, Gtk.TreeIter):
764             return key
765         elif isinstance(key, int) and key < 0:
766             index = len(self) + key
767             if index < 0:
768                 raise IndexError("row index is out of bounds: %d" % key)
769             try:
770                 aiter = self.get_iter(index)
771             except ValueError:
772                 raise IndexError("could not find tree path '%s'" % key)
773             return aiter
774         else:
775             try:
776                 aiter = self.get_iter(key)
777             except ValueError:
778                 raise IndexError("could not find tree path '%s'" % key)
779             return aiter
780
781     def __getitem__(self, key):
782         aiter = self._getiter(key)
783         return TreeModelRow(self, aiter)
784
785     def __setitem__(self, key, value):
786         row = self[key]
787         self.set_row(row.iter, value)
788
789     def __delitem__(self, key):
790         aiter = self._getiter(key)
791         self.remove(aiter)
792
793     def __iter__(self):
794         return TreeModelRowIter(self, self.get_iter_first())
795
796     def get_iter(self, path):
797         if not isinstance(path, Gtk.TreePath):
798             path = TreePath(path)
799
800         success, aiter = super(TreeModel, self).get_iter(path)
801         if not success:
802             raise ValueError("invalid tree path '%s'" % path)
803         return aiter
804
805     def get_iter_first(self):
806         success, aiter = super(TreeModel, self).get_iter_first()
807         if success:
808             return aiter
809
810     def get_iter_from_string(self, path_string):
811         success, aiter = super(TreeModel, self).get_iter_from_string(path_string)
812         if not success:
813             raise ValueError("invalid tree path '%s'" % path_string)
814         return aiter
815
816     def iter_next(self, aiter):
817         next_iter = aiter.copy()
818         success = super(TreeModel, self).iter_next(next_iter)
819         if success:
820             return next_iter
821
822     def iter_previous(self, aiter):
823         prev_iter = aiter.copy()
824         success = super(TreeModel, self).iter_previous(prev_iter)
825         if success:
826             return prev_iter
827
828     def iter_children(self, aiter):
829         success, child_iter = super(TreeModel, self).iter_children(aiter)
830         if success:
831             return child_iter
832
833     def iter_nth_child(self, parent, n):
834         success, child_iter = super(TreeModel, self).iter_nth_child(parent, n)
835         if success:
836             return child_iter
837
838     def iter_parent(self, aiter):
839         success, parent_iter = super(TreeModel, self).iter_parent(aiter)
840         if success:
841             return parent_iter
842
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')
848
849         n_columns = self.get_n_columns()
850         if len(row) != n_columns:
851             raise ValueError('row sequence has the incorrect number of elements')
852
853         result = []
854         columns = []
855         for cur_col, value in enumerate(row):
856             # do not try to set None values, they are causing warnings
857             if value is None:
858                 continue
859             result.append(self._convert_value(cur_col, value))
860             columns.append(cur_col)
861         return (result, columns)
862
863     def set_row(self, treeiter, row):
864         converted_row, columns = self._convert_row(row)
865         for column in columns:
866             value = row[column]
867             if value is None:
868                 continue  # None means skip this row
869
870             self.set_value(treeiter, column, value)
871
872     def _convert_value(self, column, value):
873         if value is None:
874             return None
875
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):
880                 value = str(value)
881             elif sys.version_info < (3, 0):
882                 if isinstance(value, unicode):
883                     value = value.encode('UTF-8')
884                 else:
885                     raise ValueError('Expected string or unicode for column %i but got %s%s' % (column, value, type(value)))
886             else:
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):
890                 value = float(value)
891             else:
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):
895                 value = int(value)
896             elif sys.version_info < (3, 0):
897                 if isinstance(value, long):
898                     value = long(value)
899                 else:
900                     raise ValueError('Expected an long for column %i but got %s' % (column, type(value)))
901             else:
902                 raise ValueError('Expected an integer for column %i but got %s' % (column, type(value)))
903         elif type_ == GObject.TYPE_BOOLEAN:
904             cmp_classes = [int]
905             if sys.version_info < (3, 0):
906                 cmp_classes.append(long)
907
908             if isinstance(value, tuple(cmp_classes)):
909                 value = bool(value)
910             else:
911                 raise ValueError('Expected a bool for column %i but got %s' % (column, type(value)))
912         else:
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:
925                 cmp_classes = [str]
926                 if sys.version_info < (3, 0):
927                     cmp_classes.append(unicode)
928
929                 if isinstance(value, tuple(cmp_classes)):
930                     value = ord(value[0])
931
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
949
950         return value
951
952     def get(self, treeiter, *columns):
953         n_columns = self.get_n_columns()
954
955         values = []
956         for col in columns:
957             if not isinstance(col, int):
958                 raise TypeError("column numbers must be ints")
959
960             if col < 0 or col >= n_columns:
961                 raise ValueError("column number is out of range")
962
963             values.append(self.get_value(treeiter, col))
964
965         return tuple(values)
966
967     def filter_new(self, root=None):
968         return super(TreeModel, self).filter_new(root)
969
970 TreeModel = override(TreeModel)
971 __all__.append('TreeModel')
972
973
974 class TreeSortable(Gtk.TreeSortable, ):
975
976     def get_sort_column_id(self):
977         success, sort_column_id, order = super(TreeSortable, self).get_sort_column_id()
978         if success:
979             return (sort_column_id, order,)
980         else:
981             return (None, None,)
982
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)
985
986     def set_default_sort_func(self, sort_func, user_data=None):
987         super(TreeSortable, self).set_default_sort_func(sort_func, user_data)
988
989 TreeSortable = override(TreeSortable)
990 __all__.append('TreeSortable')
991
992
993 class TreeModelSort(Gtk.TreeModelSort):
994     def __init__(self, model, **kwds):
995         Gtk.TreeModelSort.__init__(self, model=model, **kwds)
996
997 TreeModelSort = override(TreeModelSort)
998 __all__.append('TreeModelSort')
999
1000
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)
1005
1006     def _do_insert(self, position, row):
1007         if row is not None:
1008             row, columns = self._convert_row(row)
1009             treeiter = self.insert_with_valuesv(position, columns, row)
1010         else:
1011             treeiter = Gtk.ListStore.insert(self, position)
1012
1013         return treeiter
1014
1015     def append(self, row=None):
1016         if row:
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
1020         else:
1021             return Gtk.ListStore.append(self)
1022
1023     def prepend(self, row=None):
1024         return self._do_insert(0, row)
1025
1026     def insert(self, position, row=None):
1027         return self._do_insert(position, row)
1028
1029     # FIXME: sends two signals; check if this can use an atomic
1030     # insert_with_valuesv()
1031
1032     def insert_before(self, sibling, row=None):
1033         treeiter = Gtk.ListStore.insert_before(self, sibling)
1034
1035         if row is not None:
1036             self.set_row(treeiter, row)
1037
1038         return treeiter
1039
1040     # FIXME: sends two signals; check if this can use an atomic
1041     # insert_with_valuesv()
1042
1043     def insert_after(self, sibling, row=None):
1044         treeiter = Gtk.ListStore.insert_after(self, sibling)
1045
1046         if row is not None:
1047             self.set_row(treeiter, row)
1048
1049         return treeiter
1050
1051     def set_value(self, treeiter, column, value):
1052         value = self._convert_value(column, value)
1053         Gtk.ListStore.set_value(self, treeiter, column, value)
1054
1055     def set(self, treeiter, *args):
1056
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)
1064
1065         if args:
1066             if isinstance(args[0], int):
1067                 columns = args[::2]
1068                 values = args[1::2]
1069                 _set_lists(columns, values)
1070             elif isinstance(args[0], (tuple, list)):
1071                 if len(args) != 2:
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)
1078             else:
1079                 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}.  No -1 termination is needed.')
1080
1081 ListStore = override(ListStore)
1082 __all__.append('ListStore')
1083
1084
1085 class TreeModelRow(object):
1086
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__)
1090         self.model = model
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
1095         else:
1096             raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \
1097                 %s found" % type(iter_or_path).__name__)
1098
1099     @property
1100     def path(self):
1101         return self.model.get_path(self.iter)
1102
1103     @property
1104     def next(self):
1105         return self.get_next()
1106
1107     @property
1108     def previous(self):
1109         return self.get_previous()
1110
1111     @property
1112     def parent(self):
1113         return self.get_parent()
1114
1115     def get_next(self):
1116         next_iter = self.model.iter_next(self.iter)
1117         if next_iter:
1118             return TreeModelRow(self.model, next_iter)
1119
1120     def get_previous(self):
1121         prev_iter = self.model.iter_previous(self.iter)
1122         if prev_iter:
1123             return TreeModelRow(self.model, prev_iter)
1124
1125     def get_parent(self):
1126         parent_iter = self.model.iter_parent(self.iter)
1127         if parent_iter:
1128             return TreeModelRow(self.model, parent_iter)
1129
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)
1134             elif key < 0:
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())
1139             alist = []
1140             for i in range(start, stop, step):
1141                 alist.append(self.model.get_value(self.iter, i))
1142             return alist
1143         else:
1144             raise TypeError("indices must be integers, not %s" % type(key).__name__)
1145
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)
1150             elif key < 0:
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):
1157                 raise ValueError(
1158                     "attempt to assign sequence of size %d to slice of size %d"
1159                     % (len(value), len(indexList)))
1160
1161             for i, v in enumerate(indexList):
1162                 self.model.set_value(self.iter, v, value[i])
1163         else:
1164             raise TypeError("index must be an integer or slice, not %s" % type(key).__name__)
1165
1166     def _convert_negative_index(self, index):
1167         new_index = self.model.get_n_columns() + index
1168         if new_index < 0:
1169             raise IndexError("column index is out of bounds: %d" % index)
1170         return new_index
1171
1172     def iterchildren(self):
1173         child_iter = self.model.iter_children(self.iter)
1174         return TreeModelRowIter(self.model, child_iter)
1175
1176 __all__.append('TreeModelRow')
1177
1178
1179 class TreeModelRowIter(object):
1180
1181     def __init__(self, model, aiter):
1182         self.model = model
1183         self.iter = aiter
1184
1185     def __next__(self):
1186         if not self.iter:
1187             raise StopIteration
1188         row = TreeModelRow(self.model, self.iter)
1189         self.iter = self.model.iter_next(self.iter)
1190         return row
1191
1192     # alias for Python 2.x object protocol
1193     next = __next__
1194
1195     def __iter__(self):
1196         return self
1197
1198 __all__.append('TreeModelRowIter')
1199
1200
1201 class TreePath(Gtk.TreePath):
1202
1203     def __new__(cls, path=0):
1204         if isinstance(path, int):
1205             path = str(path)
1206         elif isinstance(path, tuple):
1207             path = ":".join(str(val) for val in path)
1208
1209         if len(path) == 0:
1210             raise TypeError("could not parse subscript '%s' as a tree path" % path)
1211         try:
1212             return TreePath.new_from_string(path)
1213         except TypeError:
1214             raise TypeError("could not parse subscript '%s' as a tree path" % path)
1215
1216     def __str__(self):
1217         return self.to_string()
1218
1219     def __lt__(self, other):
1220         return not other is None and self.compare(other) < 0
1221
1222     def __le__(self, other):
1223         return not other is None and self.compare(other) <= 0
1224
1225     def __eq__(self, other):
1226         return not other is None and self.compare(other) == 0
1227
1228     def __ne__(self, other):
1229         return other is None or self.compare(other) != 0
1230
1231     def __gt__(self, other):
1232         return other is None or self.compare(other) > 0
1233
1234     def __ge__(self, other):
1235         return other is None or self.compare(other) >= 0
1236
1237     def __iter__(self):
1238         return iter(self.get_indices())
1239
1240     def __len__(self):
1241         return self.get_depth()
1242
1243     def __getitem__(self, index):
1244         return self.get_indices()[index]
1245
1246 TreePath = override(TreePath)
1247 __all__.append('TreePath')
1248
1249
1250 class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
1251
1252     def __init__(self, *column_types):
1253         Gtk.TreeStore.__init__(self)
1254         self.set_column_types(column_types)
1255
1256     def _do_insert(self, parent, position, row):
1257         if row is not None:
1258             row, columns = self._convert_row(row)
1259             treeiter = self.insert_with_values(parent, position, columns, row)
1260         else:
1261             treeiter = Gtk.TreeStore.insert(self, parent, position)
1262
1263         return treeiter
1264
1265     def append(self, parent, row=None):
1266         return self._do_insert(parent, -1, row)
1267
1268     def prepend(self, parent, row=None):
1269         return self._do_insert(parent, 0, row)
1270
1271     def insert(self, parent, position, row=None):
1272         return self._do_insert(parent, position, row)
1273
1274     # FIXME: sends two signals; check if this can use an atomic
1275     # insert_with_valuesv()
1276
1277     def insert_before(self, parent, sibling, row=None):
1278         treeiter = Gtk.TreeStore.insert_before(self, parent, sibling)
1279
1280         if row is not None:
1281             self.set_row(treeiter, row)
1282
1283         return treeiter
1284
1285     # FIXME: sends two signals; check if this can use an atomic
1286     # insert_with_valuesv()
1287
1288     def insert_after(self, parent, sibling, row=None):
1289         treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
1290
1291         if row is not None:
1292             self.set_row(treeiter, row)
1293
1294         return treeiter
1295
1296     def set_value(self, treeiter, column, value):
1297         value = self._convert_value(column, value)
1298         Gtk.TreeStore.set_value(self, treeiter, column, value)
1299
1300     def set(self, treeiter, *args):
1301
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)
1309
1310         if args:
1311             if isinstance(args[0], int):
1312                 columns = args[::2]
1313                 values = args[1::2]
1314                 _set_lists(columns, values)
1315             elif isinstance(args[0], (tuple, list)):
1316                 if len(args) != 2:
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)
1323             else:
1324                 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}.  No -1 termination is needed.')
1325
1326 TreeStore = override(TreeStore)
1327 __all__.append('TreeStore')
1328
1329
1330 class TreeView(Gtk.TreeView, Container):
1331
1332     def __init__(self, model=None):
1333         Gtk.TreeView.__init__(self)
1334         if model:
1335             self.set_model(model)
1336
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)
1339         if success:
1340             return (path, column, cell_x, cell_y,)
1341
1342     def get_visible_range(self):
1343         success, start_path, end_path = super(TreeView, self).get_visible_range()
1344         if success:
1345             return (start_path, end_path,)
1346
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)
1349         if success:
1350             return (path, pos,)
1351
1352     def _construct_target_list(self, targets):
1353         # FIXME: this should most likely be part of Widget or a global helper
1354         #        function
1355         target_entries = []
1356         for t in targets:
1357             entry = Gtk.TargetEntry.new(*t)
1358             target_entries.append(entry)
1359         return target_entries
1360
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,
1364                                                        target_entries,
1365                                                        actions)
1366
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,
1370                                                      actions)
1371
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)
1376
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)
1381
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)
1386
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)
1393
1394 TreeView = override(TreeView)
1395 __all__.append('TreeView')
1396
1397
1398 class TreeViewColumn(Gtk.TreeViewColumn):
1399     def __init__(self, title='',
1400                  cell_renderer=None,
1401                  **attributes):
1402         Gtk.TreeViewColumn.__init__(self, title=title)
1403         if cell_renderer:
1404             self.pack_start(cell_renderer, True)
1405
1406         for (name, value) in attributes.items():
1407             self.add_attribute(cell_renderer, name, value)
1408
1409     def cell_get_position(self, cell_renderer):
1410         success, start_pos, width = super(TreeViewColumn, self).cell_get_position(cell_renderer)
1411         if success:
1412             return (start_pos, width,)
1413
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)
1416
1417     def set_attributes(self, cell_renderer, **attributes):
1418         Gtk.CellLayout.clear_attributes(self, cell_renderer)
1419
1420         for (name, value) in attributes.items():
1421             Gtk.CellLayout.add_attribute(self, cell_renderer, name, value)
1422
1423
1424 TreeViewColumn = override(TreeViewColumn)
1425 __all__.append('TreeViewColumn')
1426
1427
1428 class TreeSelection(Gtk.TreeSelection):
1429
1430     def select_path(self, path):
1431         if not isinstance(path, Gtk.TreePath):
1432             path = TreePath(path)
1433         super(TreeSelection, self).select_path(path)
1434
1435     def get_selected(self):
1436         success, model, aiter = super(TreeSelection, self).get_selected()
1437         if success:
1438             return (model, aiter)
1439         else:
1440             return (model, None)
1441
1442     # for compatibility with PyGtk
1443
1444     def get_selected_rows(self):
1445         rows, model = super(TreeSelection, self).get_selected_rows()
1446         return (model, rows)
1447
1448
1449 TreeSelection = override(TreeSelection)
1450 __all__.append('TreeSelection')
1451
1452
1453 class Button(Gtk.Button, Container):
1454     def __init__(self, label=None, stock=None, use_stock=False, use_underline=False, **kwds):
1455         if stock:
1456             label = stock
1457             use_stock = True
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')
1463
1464
1465 class LinkButton(Gtk.LinkButton):
1466     def __init__(self, uri, label=None, **kwds):
1467         Gtk.LinkButton.__init__(self, uri=uri, label=label, **kwds)
1468
1469 LinkButton = override(LinkButton)
1470 __all__.append('LinkButton')
1471
1472
1473 class Label(Gtk.Label):
1474     def __init__(self, label=None, **kwds):
1475         Gtk.Label.__init__(self, label=label, **kwds)
1476
1477 Label = override(Label)
1478 __all__.append('Label')
1479
1480
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)
1487
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)
1494
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'])
1500
1501 Adjustment = override(Adjustment)
1502 __all__.append('Adjustment')
1503
1504
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')
1509
1510         if 'n_columns' in kwds:
1511             columns = kwds.pop('n_columns')
1512
1513         Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, homogeneous=homogeneous, **kwds)
1514
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)
1517
1518 Table = override(Table)
1519 __all__.append('Table')
1520
1521
1522 class ScrolledWindow(Gtk.ScrolledWindow):
1523     def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1524         Gtk.ScrolledWindow.__init__(self, hadjustment=hadjustment, vadjustment=vadjustment, **kwds)
1525
1526 ScrolledWindow = override(ScrolledWindow)
1527 __all__.append('ScrolledWindow')
1528
1529
1530 class HScrollbar(Gtk.HScrollbar):
1531     def __init__(self, adjustment=None, **kwds):
1532         Gtk.HScrollbar.__init__(self, adjustment=adjustment, **kwds)
1533
1534 HScrollbar = override(HScrollbar)
1535 __all__.append('HScrollbar')
1536
1537
1538 class VScrollbar(Gtk.VScrollbar):
1539     def __init__(self, adjustment=None, **kwds):
1540         Gtk.VScrollbar.__init__(self, adjustment=adjustment, **kwds)
1541
1542 VScrollbar = override(VScrollbar)
1543 __all__.append('VScrollbar')
1544
1545
1546 class Paned(Gtk.Paned):
1547     def pack1(self, child, resize=False, shrink=True):
1548         super(Paned, self).pack1(child, resize, shrink)
1549
1550     def pack2(self, child, resize=True, shrink=True):
1551         super(Paned, self).pack2(child, resize, shrink)
1552
1553 Paned = override(Paned)
1554 __all__.append('Paned')
1555
1556
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,
1561                            **kwds)
1562
1563 Arrow = override(Arrow)
1564 __all__.append('Arrow')
1565
1566
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)
1571         else:
1572             iconset = Gtk.IconSet.__new__(cls)
1573         return iconset
1574
1575 IconSet = override(IconSet)
1576 __all__.append('IconSet')
1577
1578
1579 class Viewport(Gtk.Viewport):
1580     def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1581         Gtk.Viewport.__init__(self, hadjustment=hadjustment,
1582                               vadjustment=vadjustment,
1583                               **kwds)
1584
1585 Viewport = override(Viewport)
1586 __all__.append('Viewport')
1587
1588
1589 class TreeModelFilter(Gtk.TreeModelFilter):
1590     def set_visible_func(self, func, data=None):
1591         super(TreeModelFilter, self).set_visible_func(func, data)
1592
1593 TreeModelFilter = override(TreeModelFilter)
1594 __all__.append('TreeModelFilter')
1595
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')
1602
1603 _Gtk_main_quit = Gtk.main_quit
1604
1605
1606 @override(Gtk.main_quit)
1607 def main_quit(*args):
1608     _Gtk_main_quit()
1609
1610 _Gtk_stock_lookup = Gtk.stock_lookup
1611
1612
1613 @override(Gtk.stock_lookup)
1614 def stock_lookup(*args):
1615     success, item = _Gtk_stock_lookup(*args)
1616     if not success:
1617         return None
1618
1619     return item
1620
1621 initialized, argv = Gtk.init_check(sys.argv)
1622 sys.argv = list(argv)
1623 if not initialized:
1624     raise RuntimeError("Gtk couldn't be initialized")