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