f9d21c2a83e818b9a33a947f9670d46e00013a33
[platform/upstream/pygobject2.git] / tests / test_overrides_gtk.py
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # coding: UTF-8
3 # vim: tabstop=4 shiftwidth=4 expandtab
4
5 import contextlib
6 import unittest
7 import time
8 import sys
9
10 from compathelper import _unicode, _bytes
11
12 import gi.overrides
13 import gi.types
14 from gi.repository import GLib, GObject
15
16 try:
17     from gi.repository import GdkPixbuf, Gdk, Gtk
18     Gtk  # pyflakes
19 except ImportError:
20     Gtk = None
21
22
23 @contextlib.contextmanager
24 def realized(widget):
25     """Makes sure the widget is realized.
26
27     view = Gtk.TreeView()
28     with realized(view):
29         do_something(view)
30     """
31
32     if isinstance(widget, Gtk.Window):
33         toplevel = widget
34     else:
35         toplevel = widget.get_parent_window()
36
37     if toplevel is None:
38         window = Gtk.Window()
39         window.add(widget)
40
41     widget.realize()
42     while Gtk.events_pending():
43         Gtk.main_iteration()
44     assert widget.get_realized()
45     yield widget
46
47     if toplevel is None:
48         window.remove(widget)
49         window.destroy()
50
51     while Gtk.events_pending():
52         Gtk.main_iteration()
53
54
55 @unittest.skipUnless(Gtk, 'Gtk not available')
56 class TestGtk(unittest.TestCase):
57     def test_container(self):
58         box = Gtk.Box()
59         self.assertTrue(isinstance(box, Gtk.Box))
60         self.assertTrue(isinstance(box, Gtk.Container))
61         self.assertTrue(isinstance(box, Gtk.Widget))
62         self.assertTrue(box)
63         label = Gtk.Label()
64         label2 = Gtk.Label()
65         box.add(label)
66         box.add(label2)
67         self.assertTrue(label in box)
68         self.assertTrue(label2 in box)
69         self.assertEqual(len(box), 2)
70         self.assertTrue(box)
71         l = [x for x in box]
72         self.assertEqual(l, [label, label2])
73
74     def test_actions(self):
75         self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action)
76         self.assertRaises(TypeError, Gtk.Action)
77         action = Gtk.Action("test", "Test", "Test Action", Gtk.STOCK_COPY)
78         self.assertEqual(action.get_name(), "test")
79         self.assertEqual(action.get_label(), "Test")
80         self.assertEqual(action.get_tooltip(), "Test Action")
81         self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
82
83         self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction)
84         self.assertRaises(TypeError, Gtk.RadioAction)
85         action = Gtk.RadioAction("test", "Test", "Test Action", Gtk.STOCK_COPY, 1)
86         self.assertEqual(action.get_name(), "test")
87         self.assertEqual(action.get_label(), "Test")
88         self.assertEqual(action.get_tooltip(), "Test Action")
89         self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
90         self.assertEqual(action.get_current_value(), 1)
91
92     def test_actiongroup(self):
93         self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup)
94         self.assertRaises(TypeError, Gtk.ActionGroup)
95
96         action_group = Gtk.ActionGroup(name='TestActionGroup')
97         callback_data = "callback data"
98
99         def test_action_callback_data(action, user_data):
100             self.assertEqual(user_data, callback_data)
101
102         def test_radio_action_callback_data(action, current, user_data):
103             self.assertEqual(user_data, callback_data)
104
105         action_group.add_actions([
106             ('test-action1', None, 'Test Action 1',
107              None, None, test_action_callback_data),
108             ('test-action2', Gtk.STOCK_COPY, 'Test Action 2',
109              None, None, test_action_callback_data)], callback_data)
110         action_group.add_toggle_actions([
111             ('test-toggle-action1', None, 'Test Toggle Action 1',
112              None, None, test_action_callback_data, False),
113             ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2',
114              None, None, test_action_callback_data, True)], callback_data)
115         action_group.add_radio_actions([
116             ('test-radio-action1', None, 'Test Radio Action 1'),
117             ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1,
118             test_radio_action_callback_data,
119             callback_data)
120
121         expected_results = [('test-action1', Gtk.Action),
122                             ('test-action2', Gtk.Action),
123                             ('test-toggle-action1', Gtk.ToggleAction),
124                             ('test-toggle-action2', Gtk.ToggleAction),
125                             ('test-radio-action1', Gtk.RadioAction),
126                             ('test-radio-action2', Gtk.RadioAction)]
127
128         for action in action_group.list_actions():
129             a = (action.get_name(), type(action))
130             self.assertTrue(a in expected_results)
131             expected_results.remove(a)
132             action.activate()
133
134     def test_uimanager(self):
135         self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager)
136         ui = Gtk.UIManager()
137         ui.add_ui_from_string("""<ui>
138     <menubar name="menubar1"></menubar>
139 </ui>
140 """
141 )
142         menubar = ui.get_widget("/menubar1")
143         self.assertEqual(type(menubar), Gtk.MenuBar)
144
145         ag = Gtk.ActionGroup(name="ag1")
146         ui.insert_action_group(ag)
147         ag2 = Gtk.ActionGroup(name="ag2")
148         ui.insert_action_group(ag2)
149         groups = ui.get_action_groups()
150         self.assertEqual(ag, groups[-2])
151         self.assertEqual(ag2, groups[-1])
152
153     def test_uimanager_nonascii(self):
154         ui = Gtk.UIManager()
155         ui.add_ui_from_string(b'<ui><menubar name="menub\xc3\xa6r1" /></ui>'.decode('UTF-8'))
156         mi = ui.get_widget("/menubær1")
157         self.assertEqual(type(mi), Gtk.MenuBar)
158
159     def test_window(self):
160         # standard Window
161         w = Gtk.Window()
162         self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL)
163
164         # type works as keyword argument
165         w = Gtk.Window(type=Gtk.WindowType.POPUP)
166         self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
167
168         # pygtk compatible positional argument
169         w = Gtk.Window(Gtk.WindowType.POPUP)
170         self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
171
172         class TestWindow(Gtk.Window):
173             __gtype_name__ = "TestWindow"
174
175         # works from builder
176         builder = Gtk.Builder()
177         builder.add_from_string('''
178 <interface>
179   <object class="GtkWindow" id="win">
180     <property name="type">popup</property>
181   </object>
182   <object class="TestWindow" id="testwin">
183   </object>
184   <object class="TestWindow" id="testpop">
185     <property name="type">popup</property>
186   </object>
187 </interface>''')
188         self.assertEqual(builder.get_object('win').get_property('type'),
189                          Gtk.WindowType.POPUP)
190         self.assertEqual(builder.get_object('testwin').get_property('type'),
191                          Gtk.WindowType.TOPLEVEL)
192         self.assertEqual(builder.get_object('testpop').get_property('type'),
193                          Gtk.WindowType.POPUP)
194
195     def test_dialogs(self):
196         self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
197         self.assertEqual(Gtk.AboutDialog, gi.overrides.Gtk.AboutDialog)
198         self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
199         self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
200         self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
201         self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
202         self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
203
204         # Gtk.Dialog
205         dialog = Gtk.Dialog(title='Foo',
206                             flags=Gtk.DialogFlags.MODAL,
207                             buttons=('test-button1', 1))
208         self.assertTrue(isinstance(dialog, Gtk.Dialog))
209         self.assertTrue(isinstance(dialog, Gtk.Window))
210
211         dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
212
213         self.assertEqual('Foo', dialog.get_title())
214         self.assertTrue(dialog.get_modal())
215         button = dialog.get_widget_for_response(1)
216         self.assertEqual('test-button1', button.get_label())
217         button = dialog.get_widget_for_response(2)
218         self.assertEqual('test-button2', button.get_label())
219         button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
220         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
221
222         # Gtk.AboutDialog
223         dialog = Gtk.AboutDialog()
224         self.assertTrue(isinstance(dialog, Gtk.Dialog))
225         self.assertTrue(isinstance(dialog, Gtk.Window))
226
227         # Gtk.MessageDialog
228         dialog = Gtk.MessageDialog(title='message dialog test',
229                                    flags=Gtk.DialogFlags.MODAL,
230                                    buttons=Gtk.ButtonsType.OK,
231                                    message_format='dude!')
232         self.assertTrue(isinstance(dialog, Gtk.Dialog))
233         self.assertTrue(isinstance(dialog, Gtk.Window))
234
235         self.assertEqual('message dialog test', dialog.get_title())
236         self.assertTrue(dialog.get_modal())
237         text = dialog.get_property('text')
238         self.assertEqual('dude!', text)
239
240         dialog.format_secondary_text('2nd text')
241         self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
242         self.assertFalse(dialog.get_property('secondary-use-markup'))
243
244         dialog.format_secondary_markup('2nd markup')
245         self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
246         self.assertTrue(dialog.get_property('secondary-use-markup'))
247
248         # Gtk.ColorSelectionDialog
249         dialog = Gtk.ColorSelectionDialog("color selection dialog test")
250         self.assertTrue(isinstance(dialog, Gtk.Dialog))
251         self.assertTrue(isinstance(dialog, Gtk.Window))
252         self.assertEqual('color selection dialog test', dialog.get_title())
253
254         # Gtk.FileChooserDialog
255         # might cause a GVFS warning, do not break on this
256         old_mask = GLib.log_set_always_fatal(
257             GLib.LogLevelFlags.LEVEL_CRITICAL | GLib.LogLevelFlags.LEVEL_ERROR)
258         try:
259             dialog = Gtk.FileChooserDialog(title='file chooser dialog test',
260                                            buttons=('test-button1', 1),
261                                            action=Gtk.FileChooserAction.SAVE)
262         finally:
263             GLib.log_set_always_fatal(old_mask)
264         self.assertTrue(isinstance(dialog, Gtk.Dialog))
265         self.assertTrue(isinstance(dialog, Gtk.Window))
266
267         dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
268         self.assertEqual('file chooser dialog test', dialog.get_title())
269         button = dialog.get_widget_for_response(1)
270         self.assertEqual('test-button1', button.get_label())
271         button = dialog.get_widget_for_response(2)
272         self.assertEqual('test-button2', button.get_label())
273         button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
274         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
275         action = dialog.get_property('action')
276         self.assertEqual(Gtk.FileChooserAction.SAVE, action)
277
278         # Gtk.FontSelectionDialog
279         dialog = Gtk.ColorSelectionDialog("font selection dialog test")
280         self.assertTrue(isinstance(dialog, Gtk.Dialog))
281         self.assertTrue(isinstance(dialog, Gtk.Window))
282         self.assertEqual('font selection dialog test', dialog.get_title())
283
284         # Gtk.RecentChooserDialog
285         test_manager = Gtk.RecentManager()
286         dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test',
287                                          buttons=('test-button1', 1),
288                                          manager=test_manager)
289         self.assertTrue(isinstance(dialog, Gtk.Dialog))
290         self.assertTrue(isinstance(dialog, Gtk.Window))
291
292         dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
293         self.assertEqual('recent chooser dialog test', dialog.get_title())
294         button = dialog.get_widget_for_response(1)
295         self.assertEqual('test-button1', button.get_label())
296         button = dialog.get_widget_for_response(2)
297         self.assertEqual('test-button2', button.get_label())
298         button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
299         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
300
301     class TestClass(GObject.GObject):
302         __gtype_name__ = "GIOverrideTreeAPITest"
303
304         def __init__(self, tester, int_value, string_value):
305             super(TestGtk.TestClass, self).__init__()
306             self.tester = tester
307             self.int_value = int_value
308             self.string_value = string_value
309
310         def check(self, int_value, string_value):
311             self.tester.assertEqual(int_value, self.int_value)
312             self.tester.assertEqual(string_value, self.string_value)
313
314     def test_buttons(self):
315         self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
316
317         # test Gtk.Button
318         button = Gtk.Button()
319         self.assertTrue(isinstance(button, Gtk.Button))
320         self.assertTrue(isinstance(button, Gtk.Container))
321         self.assertTrue(isinstance(button, Gtk.Widget))
322         button = Gtk.Button(stock=Gtk.STOCK_CLOSE)
323         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
324         self.assertTrue(button.get_use_stock())
325         self.assertTrue(button.get_use_underline())
326
327         # test Gtk.Button use_stock
328         button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True, use_underline=True)
329         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
330         self.assertTrue(button.get_use_stock())
331         self.assertTrue(button.get_use_underline())
332
333         # test Gtk.LinkButton
334         self.assertRaises(TypeError, Gtk.LinkButton)
335         button = Gtk.LinkButton('http://www.Gtk.org', 'Gtk')
336         self.assertTrue(isinstance(button, Gtk.Button))
337         self.assertTrue(isinstance(button, Gtk.Container))
338         self.assertTrue(isinstance(button, Gtk.Widget))
339         self.assertEqual('http://www.Gtk.org', button.get_uri())
340         self.assertEqual('Gtk', button.get_label())
341
342     def test_inheritance(self):
343         for name in gi.overrides.Gtk.__all__:
344             over = getattr(gi.overrides.Gtk, name)
345             for element in dir(Gtk):
346                 try:
347                     klass = getattr(Gtk, element)
348                     info = klass.__info__
349                 except (NotImplementedError, AttributeError):
350                     continue
351
352                 # Get all parent classes and interfaces klass inherits from
353                 if isinstance(info, gi.types.ObjectInfo):
354                     classes = list(info.get_interfaces())
355                     parent = info.get_parent()
356                     while parent.get_name() != "Object":
357                         classes.append(parent)
358                         parent = parent.get_parent()
359                     classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
360                 else:
361                     continue
362
363                 for kl in classes:
364                     if kl.get_name() == name:
365                         self.assertTrue(issubclass(klass, over,),
366                                         "%r does not inherit from override %r" % (klass, over,))
367
368     def test_editable(self):
369         self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable)
370
371         # need to use Gtk.Entry because Editable is an interface
372         entry = Gtk.Entry()
373         pos = entry.insert_text('HeWorld', 0)
374         self.assertEqual(pos, 7)
375         pos = entry.insert_text('llo ', 2)
376         self.assertEqual(pos, 6)
377         text = entry.get_chars(0, 11)
378         self.assertEqual('Hello World', text)
379
380     def test_label(self):
381         label = Gtk.Label(label='Hello')
382         self.assertTrue(isinstance(label, Gtk.Widget))
383         self.assertEqual(label.get_text(), 'Hello')
384
385     def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0,
386                          step_increment=0.0, page_increment=0.0, page_size=0.0):
387         self.assertEqual(adjustment.get_value(), value)
388         self.assertEqual(adjustment.get_lower(), lower)
389         self.assertEqual(adjustment.get_upper(), upper)
390         self.assertEqual(adjustment.get_step_increment(), step_increment)
391         self.assertEqual(adjustment.get_page_increment(), page_increment)
392         self.assertEqual(adjustment.get_page_size(), page_size)
393
394     def test_adjustment(self):
395         adjustment = Gtk.Adjustment(1, 0, 6, 4, 5, 3)
396         self.adjustment_check(adjustment, 1, 0, 6, 4, 5, 3)
397
398         adjustment = Gtk.Adjustment(1, 0, 6, 4, 5)
399         self.adjustment_check(adjustment, 1, 0, 6, 4, 5)
400
401         adjustment = Gtk.Adjustment(1, 0, 6, 4)
402         self.adjustment_check(adjustment, 1, 0, 6, 4)
403
404         adjustment = Gtk.Adjustment(1, 0, 6)
405         self.adjustment_check(adjustment, 1, 0, 6)
406
407         adjustment = Gtk.Adjustment()
408         self.adjustment_check(adjustment)
409
410         adjustment = Gtk.Adjustment(value=1, lower=0, upper=6,
411                                     step_increment=4, page_increment=5, page_size=3)
412         self.adjustment_check(adjustment, 1, 0, 6, 4, 5, 3)
413
414     def test_table(self):
415         table = Gtk.Table()
416         self.assertTrue(isinstance(table, Gtk.Table))
417         self.assertTrue(isinstance(table, Gtk.Container))
418         self.assertTrue(isinstance(table, Gtk.Widget))
419         self.assertEqual(table.get_size(), (1, 1))
420         self.assertEqual(table.get_homogeneous(), False)
421         table = Gtk.Table(2, 3)
422         self.assertEqual(table.get_size(), (2, 3))
423         self.assertEqual(table.get_homogeneous(), False)
424         table = Gtk.Table(2, 3, True)
425         self.assertEqual(table.get_size(), (2, 3))
426         self.assertEqual(table.get_homogeneous(), True)
427
428         # Test PyGTK interface
429         table = Gtk.Table(rows=3, columns=2)
430         self.assertEqual(table.get_size(), (3, 2))
431         # Test using the actual property names
432         table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True)
433         self.assertEqual(table.get_size(), (2, 3))
434         self.assertEqual(table.get_homogeneous(), True)
435
436         label = Gtk.Label(label='Hello')
437         self.assertTrue(isinstance(label, Gtk.Widget))
438         table.attach(label, 0, 1, 0, 1)
439         self.assertEqual(label, table.get_children()[0])
440
441     def test_scrolledwindow(self):
442         sw = Gtk.ScrolledWindow()
443         self.assertTrue(isinstance(sw, Gtk.ScrolledWindow))
444         self.assertTrue(isinstance(sw, Gtk.Container))
445         self.assertTrue(isinstance(sw, Gtk.Widget))
446         sb = sw.get_hscrollbar()
447         self.assertEqual(sw.get_hadjustment(), sb.get_adjustment())
448         sb = sw.get_vscrollbar()
449         self.assertEqual(sw.get_vadjustment(), sb.get_adjustment())
450
451     def test_widget_drag_methods(self):
452         widget = Gtk.Button()
453
454         # here we are not checking functionality, only that the methods exist
455         # and except the right number of arguments
456
457         widget.drag_check_threshold(0, 0, 0, 0)
458
459         # drag_dest_ methods
460         widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
461         widget.drag_dest_add_image_targets()
462         widget.drag_dest_add_text_targets()
463         widget.drag_dest_add_uri_targets()
464         widget.drag_dest_get_track_motion()
465         widget.drag_dest_set_track_motion(True)
466         widget.drag_dest_get_target_list()
467         widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
468         widget.drag_dest_unset()
469
470         widget.drag_highlight()
471         widget.drag_unhighlight()
472
473         # drag_source_ methods
474         widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
475         widget.drag_source_add_image_targets()
476         widget.drag_source_add_text_targets()
477         widget.drag_source_add_uri_targets()
478         widget.drag_source_set_icon_name("")
479         widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf())
480         widget.drag_source_set_icon_stock("")
481         widget.drag_source_get_target_list()
482         widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
483         widget.drag_source_unset()
484
485         # these methods cannot be called because they require a valid drag on
486         # a real GdkWindow. So we only check that they exist and are callable.
487         self.assertTrue(hasattr(widget, 'drag_dest_set_proxy'))
488         self.assertTrue(hasattr(widget, 'drag_get_data'))
489
490     def test_drag_target_list(self):
491         mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0),
492                              ('test1', 1, 1),
493                              Gtk.TargetEntry.new('test2', 2, 2),
494                              ('test3', 3, 3)]
495
496         def _test_target_list(targets):
497             for i, target in enumerate(targets):
498                 self.assertTrue(isinstance(target, Gtk.TargetEntry))
499                 self.assertEqual(target.target, 'test' + str(i))
500                 self.assertEqual(target.flags, i)
501                 self.assertEqual(target.info, i)
502
503         _test_target_list(Gtk._construct_target_list(mixed_target_list))
504
505         widget = Gtk.Button()
506         widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
507         widget.drag_dest_set_target_list(mixed_target_list)
508         widget.drag_dest_get_target_list()
509
510         widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
511         widget.drag_source_set_target_list(mixed_target_list)
512         widget.drag_source_get_target_list()
513
514         treeview = Gtk.TreeView()
515         treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
516                                           mixed_target_list,
517                                           Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
518
519         treeview.enable_model_drag_dest(mixed_target_list,
520                                         Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
521
522     def test_scrollbar(self):
523         # PyGTK compat
524         adjustment = Gtk.Adjustment()
525
526         hscrollbar = Gtk.HScrollbar()
527         vscrollbar = Gtk.VScrollbar()
528         self.assertNotEqual(hscrollbar.props.adjustment, adjustment)
529         self.assertNotEqual(vscrollbar.props.adjustment, adjustment)
530
531         hscrollbar = Gtk.HScrollbar(adjustment)
532         vscrollbar = Gtk.VScrollbar(adjustment)
533         self.assertEqual(hscrollbar.props.adjustment, adjustment)
534         self.assertEqual(vscrollbar.props.adjustment, adjustment)
535
536     def test_iconview(self):
537         # PyGTK compat
538         iconview = Gtk.IconView()
539         self.assertEqual(iconview.props.model, None)
540
541         model = Gtk.ListStore(str)
542         iconview = Gtk.IconView(model)
543         self.assertEqual(iconview.props.model, model)
544
545     def test_toolbutton(self):
546         # PyGTK compat
547         button = Gtk.ToolButton()
548         self.assertEqual(button.props.stock_id, None)
549
550         button = Gtk.ToolButton('gtk-new')
551         self.assertEqual(button.props.stock_id, 'gtk-new')
552
553         icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
554
555         button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
556         self.assertEqual(button.props.label, 'mylabel')
557         self.assertEqual(button.props.icon_widget, icon)
558
559     def test_iconset(self):
560         # PyGTK compat
561         Gtk.IconSet()
562         pixbuf = GdkPixbuf.Pixbuf()
563         Gtk.IconSet(pixbuf)
564
565     def test_viewport(self):
566         # PyGTK compat
567         vadjustment = Gtk.Adjustment()
568         hadjustment = Gtk.Adjustment()
569
570         viewport = Gtk.Viewport(hadjustment=hadjustment,
571                                 vadjustment=vadjustment)
572
573         self.assertEqual(viewport.props.vadjustment, vadjustment)
574         self.assertEqual(viewport.props.hadjustment, hadjustment)
575
576     def test_stock_lookup(self):
577         l = Gtk.stock_lookup('gtk-ok')
578         self.assertEqual(type(l), Gtk.StockItem)
579         self.assertEqual(l.stock_id, 'gtk-ok')
580         self.assertEqual(Gtk.stock_lookup('nosuchthing'), None)
581
582     def test_gtk_main(self):
583         # with no arguments
584         GLib.timeout_add(100, Gtk.main_quit)
585         Gtk.main()
586
587         # overridden function ignores its arguments
588         GLib.timeout_add(100, Gtk.main_quit, 'hello')
589         Gtk.main()
590
591
592 @unittest.skipUnless(Gtk, 'Gtk not available')
593 class TestBuilder(unittest.TestCase):
594     class SignalTest(GObject.GObject):
595         __gtype_name__ = "GIOverrideSignalTest"
596         __gsignals__ = {
597             "test-signal": (GObject.SignalFlags.RUN_FIRST,
598                             None,
599                             []),
600         }
601
602     def test_extract_handler_and_args_object(self):
603         class Obj():
604             pass
605
606         obj = Obj()
607         obj.foo = lambda: None
608
609         handler, args = Gtk.Builder._extract_handler_and_args(obj, 'foo')
610         self.assertEqual(handler, obj.foo)
611         self.assertEqual(len(args), 0)
612
613     def test_extract_handler_and_args_dict(self):
614         obj = {'foo': lambda: None}
615
616         handler, args = Gtk.Builder._extract_handler_and_args(obj, 'foo')
617         self.assertEqual(handler, obj['foo'])
618         self.assertEqual(len(args), 0)
619
620     def test_extract_handler_and_args_with_seq(self):
621         obj = {'foo': (lambda: None, 1, 2)}
622
623         handler, args = Gtk.Builder._extract_handler_and_args(obj, 'foo')
624         self.assertEqual(handler, obj['foo'][0])
625         self.assertSequenceEqual(args, [1, 2])
626
627     def test_extract_handler_and_args_no_handler_error(self):
628         obj = dict(foo=lambda: None)
629         self.assertRaises(AttributeError,
630                           Gtk.Builder._extract_handler_and_args,
631                           obj, 'not_a_handler')
632
633     def test_builder_with_handler_and_args(self):
634         builder = Gtk.Builder()
635         builder.add_from_string("""
636             <interface>
637               <object class="GIOverrideSignalTest" id="object_sig_test">
638                   <signal name="test-signal" handler="on_signal1" />
639                   <signal name="test-signal" handler="on_signal2" after="yes" />
640               </object>
641             </interface>
642             """)
643
644         args_collector = []
645
646         def on_signal(*args):
647             args_collector.append(args)
648
649         builder.connect_signals({'on_signal1': (on_signal, 1, 2),
650                                  'on_signal2': on_signal})
651
652         objects = builder.get_objects()
653         self.assertEqual(len(objects), 1)
654         obj, = objects
655         obj.emit('test-signal')
656
657         self.assertEqual(len(args_collector), 2)
658         self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
659         self.assertSequenceEqual(args_collector[1], (obj, ))
660
661     def test_builder(self):
662         self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
663
664         class SignalCheck:
665             def __init__(self):
666                 self.sentinel = 0
667                 self.after_sentinel = 0
668
669             def on_signal_1(self, *args):
670                 self.sentinel += 1
671                 self.after_sentinel += 1
672
673             def on_signal_3(self, *args):
674                 self.sentinel += 3
675
676             def on_signal_after(self, *args):
677                 if self.after_sentinel == 1:
678                     self.after_sentinel += 1
679
680         signal_checker = SignalCheck()
681         builder = Gtk.Builder()
682
683         # add object1 to the builder
684         builder.add_from_string("""
685 <interface>
686   <object class="GIOverrideSignalTest" id="object1">
687       <signal name="test-signal" after="yes" handler="on_signal_after" />
688       <signal name="test-signal" handler="on_signal_1" />
689   </object>
690 </interface>
691 """)
692
693         # only add object3 to the builder
694         builder.add_objects_from_string("""
695 <interface>
696   <object class="GIOverrideSignalTest" id="object2">
697       <signal name="test-signal" handler="on_signal_2" />
698   </object>
699   <object class="GIOverrideSignalTest" id="object3">
700       <signal name="test-signal" handler="on_signal_3" />
701   </object>
702   <object class="GIOverrideSignalTest" id="object4">
703       <signal name="test-signal" handler="on_signal_4" />
704   </object>
705 </interface>
706 """, ['object3'])
707
708         # hook up signals
709         builder.connect_signals(signal_checker)
710
711         # call their notify signals and check sentinel
712         objects = builder.get_objects()
713         self.assertEqual(len(objects), 2)
714         for obj in objects:
715             obj.emit('test-signal')
716
717         self.assertEqual(signal_checker.sentinel, 4)
718         self.assertEqual(signal_checker.after_sentinel, 2)
719
720
721 @unittest.skipUnless(Gtk, 'Gtk not available')
722 class TestTreeModel(unittest.TestCase):
723     def test_tree_model_sort(self):
724         self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
725         self.assertRaises(TypeError, Gtk.TreeModelSort)
726         model = Gtk.TreeStore(int, bool)
727         model_sort = Gtk.TreeModelSort(model)
728         self.assertEqual(model_sort.get_model(), model)
729
730     def test_tree_store(self):
731         self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore)
732         self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore)
733         self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel)
734         self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn)
735
736         class TestPyObject(object):
737             pass
738
739         test_pyobj = TestPyObject()
740         test_pydict = {1: 1, "2": 2, "3": "3"}
741         test_pylist = [1, "2", "3"]
742         tree_store = Gtk.TreeStore(int,
743                                    'gchararray',
744                                    TestGtk.TestClass,
745                                    GObject.TYPE_PYOBJECT,
746                                    object,
747                                    object,
748                                    object,
749                                    bool,
750                                    bool,
751                                    GObject.TYPE_UINT,
752                                    GObject.TYPE_ULONG,
753                                    GObject.TYPE_INT64,
754                                    GObject.TYPE_UINT64,
755                                    GObject.TYPE_UCHAR,
756                                    GObject.TYPE_CHAR)
757
758         parent = None
759         for i in range(97):
760             label = 'this is child #%d' % i
761             testobj = TestGtk.TestClass(self, i, label)
762             parent = tree_store.append(parent, (i,
763                                                 label,
764                                                 testobj,
765                                                 testobj,
766                                                 test_pyobj,
767                                                 test_pydict,
768                                                 test_pylist,
769                                                 i % 2,
770                                                 bool(i % 2),
771                                                 i,
772                                                 GObject.G_MAXULONG,
773                                                 GObject.G_MININT64,
774                                                 0xffffffffffffffff,
775                                                 254,
776                                                 _bytes('a')
777                                                 ))
778         # test set
779         parent = tree_store.append(parent)
780         i = 97
781         label = 'this is child #%d' % i
782         testobj = TestGtk.TestClass(self, i, label)
783         tree_store.set(parent,
784                        0, i,
785                        2, testobj,
786                        1, label,
787                        3, testobj,
788                        4, test_pyobj,
789                        5, test_pydict,
790                        6, test_pylist,
791                        7, i % 2,
792                        8, bool(i % 2),
793                        9, i,
794                        10, GObject.G_MAXULONG,
795                        11, GObject.G_MININT64,
796                        12, 0xffffffffffffffff,
797                        13, 254,
798                        14, _bytes('a'))
799
800         parent = tree_store.append(parent)
801         i = 98
802         label = 'this is child #%d' % i
803         testobj = TestGtk.TestClass(self, i, label)
804         tree_store.set(parent, {0: i,
805                                 2: testobj,
806                                 1: label,
807                                 3: testobj,
808                                 4: test_pyobj,
809                                 5: test_pydict,
810                                 6: test_pylist,
811                                 7: i % 2,
812                                 8: bool(i % 2),
813                                 9: i,
814                                 10: GObject.G_MAXULONG,
815                                 11: GObject.G_MININT64,
816                                 12: 0xffffffffffffffff,
817                                 13: 254,
818                                 14: _bytes('a')})
819
820         parent = tree_store.append(parent)
821         i = 99
822         label = 'this is child #%d' % i
823         testobj = TestGtk.TestClass(self, i, label)
824         tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
825                                (i,
826                                 testobj,
827                                 label,
828                                 testobj,
829                                 test_pyobj,
830                                 test_pydict,
831                                 test_pylist,
832                                 i % 2,
833                                 bool(i % 2),
834                                 i,
835                                 GObject.G_MAXULONG,
836                                 GObject.G_MININT64,
837                                 0xffffffffffffffff,
838                                 254,
839                                 _bytes('a')))
840
841         # len gets the number of children in the root node
842         # since we kept appending to the previous node
843         # there should only be one child of the root
844         self.assertEqual(len(tree_store), 1)
845
846         # walk the tree to see if the values were stored correctly
847         parent = None
848         i = 0
849
850         treeiter = tree_store.iter_children(parent)
851         while treeiter:
852             i = tree_store.get_value(treeiter, 0)
853             s = tree_store.get_value(treeiter, 1)
854             obj = tree_store.get_value(treeiter, 2)
855             obj.check(i, s)
856             obj2 = tree_store.get_value(treeiter, 3)
857             self.assertEqual(obj, obj2)
858
859             pyobj = tree_store.get_value(treeiter, 4)
860             self.assertEqual(pyobj, test_pyobj)
861             pydict = tree_store.get_value(treeiter, 5)
862             self.assertEqual(pydict, test_pydict)
863             pylist = tree_store.get_value(treeiter, 6)
864             self.assertEqual(pylist, test_pylist)
865
866             bool_1 = tree_store.get_value(treeiter, 7)
867             bool_2 = tree_store.get_value(treeiter, 8)
868             self.assertEqual(bool_1, bool_2)
869             self.assertTrue(isinstance(bool_1, bool))
870             self.assertTrue(isinstance(bool_2, bool))
871
872             uint_ = tree_store.get_value(treeiter, 9)
873             self.assertEqual(uint_, i)
874             ulong_ = tree_store.get_value(treeiter, 10)
875             self.assertEqual(ulong_, GObject.G_MAXULONG)
876             int64_ = tree_store.get_value(treeiter, 11)
877             self.assertEqual(int64_, GObject.G_MININT64)
878             uint64_ = tree_store.get_value(treeiter, 12)
879             self.assertEqual(uint64_, 0xffffffffffffffff)
880             uchar_ = tree_store.get_value(treeiter, 13)
881             self.assertEqual(ord(uchar_), 254)
882             char_ = tree_store.get_value(treeiter, 14)
883             self.assertEqual(char_, 'a')
884
885             parent = treeiter
886             treeiter = tree_store.iter_children(parent)
887
888         self.assertEqual(i, 99)
889
890     def test_tree_store_signals(self):
891         tree_store = Gtk.TreeStore(int, bool)
892
893         def on_row_inserted(tree_store, tree_path, tree_iter, signal_list):
894             signal_list.append('row-inserted')
895
896         def on_row_changed(tree_store, tree_path, tree_iter, signal_list):
897             signal_list.append('row-changed')
898
899         signals = []
900         tree_store.connect('row-inserted', on_row_inserted, signals)
901         tree_store.connect('row-changed', on_row_changed, signals)
902
903         # adding rows with and without data should only call one signal
904         tree_store.append(None, (0, False))
905         self.assertEqual(signals, ['row-inserted'])
906
907         signals.pop()
908         tree_store.append(None)
909         self.assertEqual(signals, ['row-inserted'])
910
911         signals.pop()
912         tree_store.prepend(None, (0, False))
913         self.assertEqual(signals, ['row-inserted'])
914
915         signals.pop()
916         tree_store.prepend(None)
917         self.assertEqual(signals, ['row-inserted'])
918
919         signals.pop()
920         tree_store.insert(None, 1, (0, False))
921         self.assertEqual(signals, ['row-inserted'])
922
923         signals.pop()
924         tree_store.insert(None, 1)
925         self.assertEqual(signals, ['row-inserted'])
926
927     def test_list_store(self):
928         class TestPyObject(object):
929             pass
930
931         test_pyobj = TestPyObject()
932         test_pydict = {1: 1, "2": 2, "3": "3"}
933         test_pylist = [1, "2", "3"]
934
935         list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool)
936         for i in range(1, 93):
937             label = 'this is row #%d' % i
938             testobj = TestGtk.TestClass(self, i, label)
939             list_store.append((i,
940                                label,
941                                testobj,
942                                test_pyobj,
943                                test_pydict,
944                                test_pylist,
945                                i % 2,
946                                bool(i % 2)))
947
948         i = 93
949         label = _unicode('this is row #93')
950         treeiter = list_store.append()
951         list_store.set_value(treeiter, 0, i)
952         list_store.set_value(treeiter, 1, label)
953         list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
954         list_store.set_value(treeiter, 3, test_pyobj)
955         list_store.set_value(treeiter, 4, test_pydict)
956         list_store.set_value(treeiter, 5, test_pylist)
957         list_store.set_value(treeiter, 6, 1)
958         list_store.set_value(treeiter, 7, True)
959
960         # test prepend
961         label = 'this is row #0'
962         list_store.prepend((0,
963                             label,
964                             TestGtk.TestClass(self, 0, label),
965                             test_pyobj,
966                             test_pydict,
967                             test_pylist,
968                             0,
969                             False))
970
971         # test automatic unicode->str conversion
972         i = 94
973         label = _unicode('this is row #94')
974         treeiter = list_store.append((i,
975                                       label,
976                                       TestGtk.TestClass(self, i, label),
977                                       test_pyobj,
978                                       test_pydict,
979                                       test_pylist,
980                                       0,
981                                       False))
982
983         # add sorted items out of order to test insert* apis
984         # also test sending in None to not set a column
985         i = 97
986         label = 'this is row #97'
987         treeiter = list_store.append((None,
988                                       None,
989                                       None,
990                                       test_pyobj,
991                                       None,
992                                       test_pylist,
993                                       1,
994                                       None))
995
996         list_store.set_value(treeiter, 0, i)
997         list_store.set_value(treeiter, 1, label)
998         list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
999         list_store.set_value(treeiter, 4, test_pydict)
1000         list_store.set_value(treeiter, 7, True)
1001
1002         # this should append
1003         i = 99
1004         label = 'this is row #99'
1005         list_store.insert(9999, (i,
1006                                  label,
1007                                  TestGtk.TestClass(self, i, label),
1008                                  test_pyobj,
1009                                  test_pydict,
1010                                  test_pylist,
1011                                  1,
1012                                  True))
1013
1014         i = 96
1015         label = 'this is row #96'
1016         list_store.insert_before(treeiter, (i,
1017                                             label,
1018                                             TestGtk.TestClass(self, i, label),
1019                                             test_pyobj,
1020                                             test_pydict,
1021                                             test_pylist,
1022                                             0,
1023                                             False))
1024
1025         i = 98
1026         label = 'this is row #98'
1027         list_store.insert_after(treeiter, (i,
1028                                            label,
1029                                            TestGtk.TestClass(self, i, label),
1030                                            test_pyobj,
1031                                            test_pydict,
1032                                            test_pylist,
1033                                            0,
1034                                            False))
1035
1036         i = 95
1037         label = 'this is row #95'
1038         list_store.insert(95, (i,
1039                                label,
1040                                TestGtk.TestClass(self, i, label),
1041                                test_pyobj,
1042                                test_pydict,
1043                                test_pylist,
1044                                1,
1045                                True))
1046
1047         i = 100
1048         label = 'this is row #100'
1049         treeiter = list_store.append()
1050         list_store.set(treeiter,
1051                        1, label,
1052                        0, i,
1053                        2, TestGtk.TestClass(self, i, label),
1054                        3, test_pyobj,
1055                        4, test_pydict,
1056                        5, test_pylist,
1057                        6, 0,
1058                        7, False)
1059         i = 101
1060         label = 'this is row #101'
1061         treeiter = list_store.append()
1062         list_store.set(treeiter, {1: label,
1063                                   0: i,
1064                                   2: TestGtk.TestClass(self, i, label),
1065                                   3: test_pyobj,
1066                                   4: test_pydict,
1067                                   5: test_pylist,
1068                                   6: 1,
1069                                   7: True})
1070         i = 102
1071         label = 'this is row #102'
1072         treeiter = list_store.append()
1073         list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7),
1074                                  (label,
1075                                   i,
1076                                   TestGtk.TestClass(self, i, label),
1077                                   test_pyobj,
1078                                   test_pydict,
1079                                   test_pylist,
1080                                   0,
1081                                   False))
1082
1083         self.assertEqual(len(list_store), 103)
1084
1085         # walk the list to see if the values were stored correctly
1086         i = 0
1087         treeiter = list_store.get_iter_first()
1088
1089         counter = 0
1090         while treeiter:
1091             i = list_store.get_value(treeiter, 0)
1092             self.assertEqual(i, counter)
1093             s = list_store.get_value(treeiter, 1)
1094             obj = list_store.get_value(treeiter, 2)
1095             obj.check(i, s)
1096
1097             pyobj = list_store.get_value(treeiter, 3)
1098             self.assertEqual(pyobj, test_pyobj)
1099             pydict = list_store.get_value(treeiter, 4)
1100             self.assertEqual(pydict, test_pydict)
1101             pylist = list_store.get_value(treeiter, 5)
1102             self.assertEqual(pylist, test_pylist)
1103
1104             bool_1 = list_store.get_value(treeiter, 6)
1105             bool_2 = list_store.get_value(treeiter, 7)
1106             self.assertEqual(bool_1, bool_2)
1107             self.assertTrue(isinstance(bool_1, bool))
1108             self.assertTrue(isinstance(bool_2, bool))
1109
1110             treeiter = list_store.iter_next(treeiter)
1111
1112             counter += 1
1113
1114         self.assertEqual(i, 102)
1115
1116     def test_list_store_sort(self):
1117         def comp1(model, row1, row2, user_data):
1118             v1 = model[row1][1]
1119             v2 = model[row2][1]
1120
1121             # make "m" smaller than anything else
1122             if v1.startswith('m') and not v2.startswith('m'):
1123                 return -1
1124             if v2.startswith('m') and not v1.startswith('m'):
1125                 return 1
1126             return (v1 > v2) - (v1 < v2)
1127
1128         list_store = Gtk.ListStore(int, str)
1129         list_store.set_sort_func(2, comp1, None)
1130         list_store.append((1, 'apples'))
1131         list_store.append((3, 'oranges'))
1132         list_store.append((2, 'mango'))
1133
1134         # not sorted yet, should be original order
1135         self.assertEqual([list(i) for i in list_store],
1136                          [[1, 'apples'], [3, 'oranges'], [2, 'mango']])
1137
1138         # sort with our custom function
1139         list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING)
1140         self.assertEqual([list(i) for i in list_store],
1141                          [[2, 'mango'], [1, 'apples'], [3, 'oranges']])
1142
1143         list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING)
1144         self.assertEqual([list(i) for i in list_store],
1145                          [[3, 'oranges'], [1, 'apples'], [2, 'mango']])
1146
1147     def test_list_store_signals(self):
1148         list_store = Gtk.ListStore(int, bool)
1149
1150         def on_row_inserted(list_store, tree_path, tree_iter, signal_list):
1151             signal_list.append('row-inserted')
1152
1153         def on_row_changed(list_store, tree_path, tree_iter, signal_list):
1154             signal_list.append('row-changed')
1155
1156         signals = []
1157         list_store.connect('row-inserted', on_row_inserted, signals)
1158         list_store.connect('row-changed', on_row_changed, signals)
1159
1160         # adding rows with and without data should only call one signal
1161         list_store.append((0, False))
1162         self.assertEqual(signals, ['row-inserted'])
1163
1164         signals.pop()
1165         list_store.append()
1166         self.assertEqual(signals, ['row-inserted'])
1167
1168         signals.pop()
1169         list_store.prepend((0, False))
1170         self.assertEqual(signals, ['row-inserted'])
1171
1172         signals.pop()
1173         list_store.prepend()
1174         self.assertEqual(signals, ['row-inserted'])
1175
1176         signals.pop()
1177         list_store.insert(1, (0, False))
1178         self.assertEqual(signals, ['row-inserted'])
1179
1180         signals.pop()
1181         list_store.insert(1)
1182         self.assertEqual(signals, ['row-inserted'])
1183
1184     def test_tree_path(self):
1185         p1 = Gtk.TreePath()
1186         p2 = Gtk.TreePath.new_first()
1187         self.assertEqual(p1, p2)
1188         self.assertEqual(str(p1), '0')
1189         self.assertEqual(len(p1), 1)
1190         p1 = Gtk.TreePath(2)
1191         p2 = Gtk.TreePath.new_from_string('2')
1192         self.assertEqual(p1, p2)
1193         self.assertEqual(str(p1), '2')
1194         self.assertEqual(len(p1), 1)
1195         p1 = Gtk.TreePath('1:2:3')
1196         p2 = Gtk.TreePath.new_from_string('1:2:3')
1197         self.assertEqual(p1, p2)
1198         self.assertEqual(str(p1), '1:2:3')
1199         self.assertEqual(len(p1), 3)
1200         p1 = Gtk.TreePath((1, 2, 3))
1201         p2 = Gtk.TreePath.new_from_string('1:2:3')
1202         self.assertEqual(p1, p2)
1203         self.assertEqual(str(p1), '1:2:3')
1204         self.assertEqual(len(p1), 3)
1205         self.assertNotEqual(p1, None)
1206         self.assertTrue(p1 > None)
1207         self.assertTrue(p1 >= None)
1208         self.assertFalse(p1 < None)
1209         self.assertFalse(p1 <= None)
1210
1211         self.assertEqual(tuple(p1), (1, 2, 3))
1212         self.assertEqual(p1[0], 1)
1213         self.assertEqual(p1[1], 2)
1214         self.assertEqual(p1[2], 3)
1215         self.assertRaises(IndexError, p1.__getitem__, 3)
1216
1217     def test_tree_model(self):
1218         tree_store = Gtk.TreeStore(int, str)
1219
1220         self.assertTrue(tree_store)
1221         self.assertEqual(len(tree_store), 0)
1222         self.assertEqual(tree_store.get_iter_first(), None)
1223
1224         def get_by_index(row, col=None):
1225             if col:
1226                 return tree_store[row][col]
1227             else:
1228                 return tree_store[row]
1229
1230         self.assertRaises(TypeError, get_by_index, None)
1231         self.assertRaises(TypeError, get_by_index, "")
1232         self.assertRaises(TypeError, get_by_index, ())
1233
1234         self.assertRaises(IndexError, get_by_index, "0")
1235         self.assertRaises(IndexError, get_by_index, 0)
1236         self.assertRaises(IndexError, get_by_index, (0,))
1237
1238         self.assertRaises(ValueError, tree_store.get_iter, "0")
1239         self.assertRaises(ValueError, tree_store.get_iter, 0)
1240         self.assertRaises(ValueError, tree_store.get_iter, (0,))
1241
1242         self.assertRaises(ValueError, tree_store.get_iter_from_string, "0")
1243
1244         for row in tree_store:
1245             self.fail("Should not be reached")
1246
1247         class DerivedIntType(int):
1248             pass
1249
1250         class DerivedStrType(str):
1251             pass
1252
1253         for i in range(100):
1254             label = 'this is row #%d' % i
1255             parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),))
1256             self.assertNotEqual(parent, None)
1257             for j in range(20):
1258                 label = 'this is child #%d of node #%d' % (j, i)
1259                 child = tree_store.append(parent, (j, label,))
1260                 self.assertNotEqual(child, None)
1261
1262         self.assertTrue(tree_store)
1263         self.assertEqual(len(tree_store), 100)
1264
1265         self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None)
1266
1267         for i, row in enumerate(tree_store):
1268             self.assertEqual(row.model, tree_store)
1269             self.assertEqual(row.parent, None)
1270
1271             self.assertEqual(tree_store[i].path, row.path)
1272             self.assertEqual(tree_store[str(i)].path, row.path)
1273             self.assertEqual(tree_store[(i,)].path, row.path)
1274
1275             self.assertEqual(tree_store[i][0], i)
1276             self.assertEqual(tree_store[i][1], "this is row #%d" % i)
1277
1278             aiter = tree_store.get_iter(i)
1279             self.assertEqual(tree_store.get_path(aiter), row.path)
1280
1281             aiter = tree_store.get_iter(str(i))
1282             self.assertEqual(tree_store.get_path(aiter), row.path)
1283
1284             aiter = tree_store.get_iter((i,))
1285             self.assertEqual(tree_store.get_path(aiter), row.path)
1286
1287             self.assertEqual(tree_store.iter_parent(aiter), row.parent)
1288
1289             next = tree_store.iter_next(aiter)
1290             if i < len(tree_store) - 1:
1291                 self.assertEqual(tree_store.get_path(next), row.next.path)
1292                 self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)),
1293                                  tree_store.get_path(aiter))
1294             else:
1295                 self.assertEqual(next, None)
1296
1297             self.assertEqual(tree_store.iter_n_children(row.iter), 20)
1298
1299             child = tree_store.iter_children(row.iter)
1300             for j, childrow in enumerate(row.iterchildren()):
1301                 child_path = tree_store.get_path(child)
1302                 self.assertEqual(childrow.path, child_path)
1303                 self.assertEqual(childrow.parent.path, row.path)
1304                 self.assertEqual(childrow.path, tree_store[child].path)
1305                 self.assertEqual(childrow.path, tree_store[child_path].path)
1306
1307                 self.assertEqual(childrow[0], tree_store[child][0])
1308                 self.assertEqual(childrow[0], j)
1309                 self.assertEqual(childrow[1], tree_store[child][1])
1310                 self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i))
1311
1312                 self.assertRaises(IndexError, get_by_index, child, 2)
1313
1314                 tree_store[child][1] = 'this was child #%d of node #%d' % (j, i)
1315                 self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i))
1316
1317                 nth_child = tree_store.iter_nth_child(row.iter, j)
1318                 self.assertEqual(childrow.path, tree_store.get_path(nth_child))
1319
1320                 childrow2 = tree_store["%d:%d" % (i, j)]
1321                 self.assertEqual(childrow.path, childrow2.path)
1322
1323                 childrow2 = tree_store[(i, j,)]
1324                 self.assertEqual(childrow.path, childrow2.path)
1325
1326                 child = tree_store.iter_next(child)
1327                 if j < 19:
1328                     self.assertEqual(childrow.next.path, tree_store.get_path(child))
1329                 else:
1330                     self.assertEqual(child, childrow.next)
1331                     self.assertEqual(child, None)
1332
1333             self.assertEqual(j, 19)
1334
1335         self.assertEqual(i, 99)
1336
1337         # negative indices
1338         for i in range(-1, -100, -1):
1339             i_real = i + 100
1340             self.assertEqual(tree_store[i][0], i_real)
1341
1342             row = tree_store[i]
1343             for j in range(-1, -20, -1):
1344                 j_real = j + 20
1345                 path = (i_real, j_real,)
1346
1347                 self.assertEqual(tree_store[path][-2], j_real)
1348
1349                 label = 'this was child #%d of node #%d' % (j_real, i_real)
1350                 self.assertEqual(tree_store[path][-1], label)
1351
1352                 new_label = 'this still is child #%d of node #%d' % (j_real, i_real)
1353                 tree_store[path][-1] = new_label
1354                 self.assertEqual(tree_store[path][-1], new_label)
1355
1356                 self.assertRaises(IndexError, get_by_index, path, -3)
1357
1358         self.assertRaises(IndexError, get_by_index, -101)
1359
1360         last_row = tree_store[99]
1361         self.assertNotEqual(last_row, None)
1362
1363         for i, childrow in enumerate(last_row.iterchildren()):
1364             if i < 19:
1365                 self.assertTrue(tree_store.remove(childrow.iter))
1366             else:
1367                 self.assertFalse(tree_store.remove(childrow.iter))
1368
1369         self.assertEqual(i, 19)
1370
1371         self.assertEqual(tree_store.iter_n_children(last_row.iter), 0)
1372         for childrow in last_row.iterchildren():
1373             self.fail("Should not be reached")
1374
1375         aiter = tree_store.get_iter(10)
1376         self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a')
1377         self.assertRaises(ValueError, tree_store.get, aiter, 1, -1)
1378         self.assertRaises(ValueError, tree_store.get, aiter, 1, 100)
1379         self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10'))
1380
1381         # check __delitem__
1382         self.assertEqual(len(tree_store), 100)
1383         aiter = tree_store.get_iter(10)
1384         del tree_store[aiter]
1385         self.assertEqual(len(tree_store), 99)
1386         self.assertRaises(TypeError, tree_store.__delitem__, None)
1387         self.assertRaises(IndexError, tree_store.__delitem__, -101)
1388         self.assertRaises(IndexError, tree_store.__delitem__, 101)
1389
1390     def test_tree_model_get_iter_fail(self):
1391         # TreeModel class with a failing get_iter()
1392         class MyTreeModel(GObject.GObject, Gtk.TreeModel):
1393             def do_get_iter(self, iter):
1394                 return (False, None)
1395
1396         tm = MyTreeModel()
1397         self.assertEqual(tm.get_iter_first(), None)
1398
1399     def test_tree_model_edit(self):
1400         model = Gtk.ListStore(int, str, float)
1401         model.append([1, "one", -0.1])
1402         model.append([2, "two", -0.2])
1403
1404         def set_row(value):
1405             model[1] = value
1406
1407         self.assertRaises(TypeError, set_row, 3)
1408         self.assertRaises(TypeError, set_row, "three")
1409         self.assertRaises(ValueError, set_row, [])
1410         self.assertRaises(ValueError, set_row, [3, "three"])
1411
1412         model[0] = (3, "three", -0.3)
1413
1414     def test_tree_row_slice(self):
1415         model = Gtk.ListStore(int, str, float)
1416         model.append([1, "one", -0.1])
1417
1418         self.assertEqual([1, "one", -0.1], model[0][:])
1419         self.assertEqual([1, "one"], model[0][:2])
1420         self.assertEqual(["one", -0.1], model[0][1:])
1421         self.assertEqual(["one"], model[0][1:-1])
1422         self.assertEqual([1], model[0][:-2])
1423         self.assertEqual([], model[0][5:])
1424         self.assertEqual([1, -0.1], model[0][0:3:2])
1425
1426         model[0][:] = (2, "two", -0.2)
1427         self.assertEqual([2, "two", -0.2], model[0][:])
1428
1429         model[0][:2] = (3, "three")
1430         self.assertEqual([3, "three", -0.2], model[0][:])
1431
1432         model[0][1:] = ("four", -0.4)
1433         self.assertEqual([3, "four", -0.4], model[0][:])
1434
1435         model[0][1:-1] = ("five",)
1436         self.assertEqual([3, "five", -0.4], model[0][:])
1437
1438         model[0][0:3:2] = (6, -0.6)
1439         self.assertEqual([6, "five", -0.6], model[0][:])
1440
1441         def set_row1():
1442             model[0][5:] = ("doesn't", "matter",)
1443
1444         self.assertRaises(ValueError, set_row1)
1445
1446         def set_row2():
1447             model[0][:1] = (0, "zero", 0)
1448
1449         self.assertRaises(ValueError, set_row2)
1450
1451         def set_row3():
1452             model[0][:2] = ("0", 0)
1453
1454         self.assertRaises(TypeError, set_row3)
1455
1456     def test_tree_model_set_value_to_none(self):
1457         # Tests allowing the usage of None to set an empty value on a model.
1458         store = Gtk.ListStore(str)
1459         row = store.append(['test'])
1460         self.assertSequenceEqual(store[0][:], ['test'])
1461         store.set_value(row, 0, None)
1462         self.assertSequenceEqual(store[0][:], [None])
1463
1464     def test_signal_emission_tree_path_coerce(self):
1465         class Model(GObject.Object, Gtk.TreeModel):
1466             pass
1467
1468         model = Model()
1469         tree_paths = []
1470
1471         def on_any_signal(model, path, *args):
1472             tree_paths.append(path.to_string())
1473
1474         model.connect('row-changed', on_any_signal)
1475         model.connect('row-deleted', on_any_signal)
1476         model.connect('row-has-child-toggled', on_any_signal)
1477         model.connect('row-inserted', on_any_signal)
1478
1479         model.row_changed('0', Gtk.TreeIter())
1480         self.assertEqual(tree_paths[-1], '0')
1481
1482         model.row_deleted('1')
1483         self.assertEqual(tree_paths[-1], '1')
1484
1485         model.row_has_child_toggled('2', Gtk.TreeIter())
1486         self.assertEqual(tree_paths[-1], '2')
1487
1488         model.row_inserted('3', Gtk.TreeIter())
1489         self.assertEqual(tree_paths[-1], '3')
1490
1491     def test_tree_model_filter(self):
1492         model = Gtk.ListStore(int, str, float)
1493         model.append([1, "one", -0.1])
1494         model.append([2, "two", -0.2])
1495
1496         filtered = Gtk.TreeModelFilter(child_model=model)
1497
1498         self.assertEqual(filtered[0][1], 'one')
1499         filtered[0][1] = 'ONE'
1500         self.assertEqual(filtered[0][1], 'ONE')
1501
1502     def test_list_store_performance(self):
1503         model = Gtk.ListStore(int, str)
1504
1505         iterations = 2000
1506         start = time.clock()
1507         i = iterations
1508         while i > 0:
1509             model.append([1, 'hello'])
1510             i -= 1
1511         end = time.clock()
1512         sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations))
1513
1514
1515 @unittest.skipUnless(Gtk, 'Gtk not available')
1516 class TestTreeView(unittest.TestCase):
1517     def test_tree_view(self):
1518         store = Gtk.ListStore(int, str)
1519         store.append((0, "foo"))
1520         store.append((1, "bar"))
1521         view = Gtk.TreeView()
1522
1523         with realized(view):
1524             view.set_cursor(store[1].path)
1525             view.set_cursor(str(store[1].path))
1526
1527             view.get_cell_area(store[1].path)
1528             view.get_cell_area(str(store[1].path))
1529
1530     def test_tree_view_column(self):
1531         cell = Gtk.CellRendererText()
1532         Gtk.TreeViewColumn(title='This is just a test',
1533                            cell_renderer=cell,
1534                            text=0,
1535                            style=2)
1536
1537     def test_tree_view_add_column_with_attributes(self):
1538         model = Gtk.ListStore(str, str, str)
1539         # deliberately use out-of-order sorting here; we assign column 0 to
1540         # model index 2, etc.
1541         model.append(['cell13', 'cell11', 'cell12'])
1542         model.append(['cell23', 'cell21', 'cell22'])
1543
1544         tree = Gtk.TreeView(model)
1545         cell1 = Gtk.CellRendererText()
1546         cell2 = Gtk.CellRendererText()
1547         cell3 = Gtk.CellRendererText()
1548         cell4 = Gtk.CellRendererText()
1549
1550         tree.insert_column_with_attributes(0, 'Head2', cell2, text=2)
1551         tree.insert_column_with_attributes(0, 'Head1', cell1, text=1)
1552         tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0)
1553         # unconnected
1554         tree.insert_column_with_attributes(-1, 'Head4', cell4)
1555
1556         with realized(tree):
1557             tree.set_cursor(model[0].path)
1558             while Gtk.events_pending():
1559                 Gtk.main_iteration()
1560
1561             self.assertEqual(tree.get_column(0).get_title(), 'Head1')
1562             self.assertEqual(tree.get_column(1).get_title(), 'Head2')
1563             self.assertEqual(tree.get_column(2).get_title(), 'Head3')
1564             self.assertEqual(tree.get_column(3).get_title(), 'Head4')
1565
1566             # cursor should be at the first row
1567             self.assertEqual(cell1.props.text, 'cell11')
1568             self.assertEqual(cell2.props.text, 'cell12')
1569             self.assertEqual(cell3.props.text, 'cell13')
1570             self.assertEqual(cell4.props.text, None)
1571
1572     def test_tree_view_column_set_attributes(self):
1573         store = Gtk.ListStore(int, str)
1574         directors = ['Fellini', 'Tarantino', 'Tarkovskiy']
1575         for i, director in enumerate(directors):
1576             store.append([i, director])
1577
1578         treeview = Gtk.TreeView()
1579         treeview.set_model(store)
1580
1581         column = Gtk.TreeViewColumn()
1582         treeview.append_column(column)
1583
1584         cell = Gtk.CellRendererText()
1585         column.pack_start(cell, expand=True)
1586         column.set_attributes(cell, text=1)
1587
1588         with realized(treeview):
1589             self.assertTrue(cell.props.text in directors)
1590
1591     def test_tree_selection(self):
1592         store = Gtk.ListStore(int, str)
1593         for i in range(10):
1594             store.append((i, "foo"))
1595         view = Gtk.TreeView()
1596         view.set_model(store)
1597         firstpath = store.get_path(store.get_iter_first())
1598         sel = view.get_selection()
1599
1600         sel.select_path(firstpath)
1601         (m, s) = sel.get_selected()
1602         self.assertEqual(m, store)
1603         self.assertEqual(store.get_path(s), firstpath)
1604
1605         sel.select_path(0)
1606         (m, s) = sel.get_selected()
1607         self.assertEqual(m, store)
1608         self.assertEqual(store.get_path(s), firstpath)
1609
1610         sel.select_path("0:0")
1611         (m, s) = sel.get_selected()
1612         self.assertEqual(m, store)
1613         self.assertEqual(store.get_path(s), firstpath)
1614
1615         sel.select_path((0, 0))
1616         (m, s) = sel.get_selected()
1617         self.assertEqual(m, store)
1618         self.assertEqual(store.get_path(s), firstpath)
1619
1620
1621 @unittest.skipUnless(Gtk, 'Gtk not available')
1622 class TestTextBuffer(unittest.TestCase):
1623     def test_text_buffer(self):
1624         self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
1625         buffer = Gtk.TextBuffer()
1626         tag = buffer.create_tag('title', font='Sans 18')
1627
1628         self.assertEqual(tag.props.name, 'title')
1629         self.assertEqual(tag.props.font, 'Sans 18')
1630
1631         (start, end) = buffer.get_bounds()
1632
1633         mark = buffer.create_mark(None, start)
1634         self.assertFalse(mark.get_left_gravity())
1635
1636         buffer.set_text('Hello Jane Hello Bob')
1637         (start, end) = buffer.get_bounds()
1638         text = buffer.get_text(start, end, False)
1639         self.assertEqual(text, 'Hello Jane Hello Bob')
1640
1641         buffer.set_text('')
1642         (start, end) = buffer.get_bounds()
1643         text = buffer.get_text(start, end, False)
1644         self.assertEqual(text, '')
1645
1646         buffer.insert(end, 'HelloHello')
1647         buffer.insert(end, ' Bob')
1648
1649         cursor_iter = end.copy()
1650         cursor_iter.backward_chars(9)
1651         buffer.place_cursor(cursor_iter)
1652         buffer.insert_at_cursor(' Jane ')
1653
1654         (start, end) = buffer.get_bounds()
1655         text = buffer.get_text(start, end, False)
1656         self.assertEqual(text, 'Hello Jane Hello Bob')
1657
1658         sel = buffer.get_selection_bounds()
1659         self.assertEqual(sel, ())
1660         buffer.select_range(start, end)
1661         sel = buffer.get_selection_bounds()
1662         self.assertTrue(sel[0].equal(start))
1663         self.assertTrue(sel[1].equal(end))
1664
1665         buffer.set_text('')
1666         buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag)
1667         (start, end) = buffer.get_bounds()
1668         self.assertTrue(start.begins_tag(tag))
1669         self.assertTrue(start.has_tag(tag))
1670
1671         buffer.set_text('')
1672         buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title')
1673         (start, end) = buffer.get_bounds()
1674         self.assertTrue(start.begins_tag(tag))
1675         self.assertTrue(start.has_tag(tag))
1676
1677         self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
1678                           buffer.get_start_iter(), 'HelloHello', 'unknowntag')
1679
1680     def test_text_iter(self):
1681         self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter)
1682         buffer = Gtk.TextBuffer()
1683         buffer.set_text('Hello Jane Hello Bob')
1684         tag = buffer.create_tag('title', font='Sans 18')
1685         (start, end) = buffer.get_bounds()
1686         start.forward_chars(10)
1687         buffer.apply_tag(tag, start, end)
1688         self.assertTrue(start.begins_tag())
1689         self.assertTrue(end.ends_tag())
1690         self.assertTrue(start.toggles_tag())
1691         self.assertTrue(end.toggles_tag())
1692         start.backward_chars(1)
1693         self.assertFalse(start.begins_tag())
1694         self.assertFalse(start.ends_tag())
1695         self.assertFalse(start.toggles_tag())
1696
1697     def test_text_buffer_search(self):
1698         buffer = Gtk.TextBuffer()
1699         buffer.set_text('Hello World Hello GNOME')
1700
1701         i = buffer.get_iter_at_offset(0)
1702         self.assertTrue(isinstance(i, Gtk.TextIter))
1703
1704         self.assertEqual(i.forward_search('world', 0, None), None)
1705
1706         (start, end) = i.forward_search('World', 0, None)
1707         self.assertEqual(start.get_offset(), 6)
1708         self.assertEqual(end.get_offset(), 11)
1709
1710         (start, end) = i.forward_search('world',
1711                                         Gtk.TextSearchFlags.CASE_INSENSITIVE,
1712                                         None)
1713         self.assertEqual(start.get_offset(), 6)
1714         self.assertEqual(end.get_offset(), 11)