1 # -*- Mode: Python; py-indent-offset: 4 -*-
3 # vim: tabstop=4 shiftwidth=4 expandtab
11 from helper import ignore_gi_deprecation_warnings, capture_glib_warnings
15 from gi.repository import GLib, GObject
18 from gi.repository import Gtk, GdkPixbuf, Gdk
19 PyGTKDeprecationWarning = Gtk.PyGTKDeprecationWarning
22 PyGTKDeprecationWarning = None
27 @contextlib.contextmanager
29 """Makes sure the widget is realized.
36 if isinstance(widget, Gtk.Window):
39 toplevel = widget.get_parent_window()
46 while Gtk.events_pending():
48 assert widget.get_realized()
55 while Gtk.events_pending():
59 @unittest.skipUnless(Gtk, 'Gtk not available')
60 @ignore_gi_deprecation_warnings
61 class TestGtk(unittest.TestCase):
62 def test_container(self):
64 self.assertTrue(isinstance(box, Gtk.Box))
65 self.assertTrue(isinstance(box, Gtk.Container))
66 self.assertTrue(isinstance(box, Gtk.Widget))
72 self.assertTrue(label in box)
73 self.assertTrue(label2 in box)
74 self.assertEqual(len(box), 2)
76 labels = [x for x in box]
77 self.assertEqual(labels, [label, label2])
79 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
80 def test_actions(self):
81 self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action)
82 action = Gtk.Action(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY)
83 self.assertEqual(action.get_name(), "test")
84 self.assertEqual(action.get_label(), "Test")
85 self.assertEqual(action.get_tooltip(), "Test Action")
86 self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
88 self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction)
89 action = Gtk.RadioAction(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY, value=1)
90 self.assertEqual(action.get_name(), "test")
91 self.assertEqual(action.get_label(), "Test")
92 self.assertEqual(action.get_tooltip(), "Test Action")
93 self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
94 self.assertEqual(action.get_current_value(), 1)
96 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
97 def test_actiongroup(self):
98 self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup)
100 action_group = Gtk.ActionGroup(name='TestActionGroup')
101 callback_data = "callback data"
103 def test_action_callback_data(action, user_data):
104 self.assertEqual(user_data, callback_data)
106 def test_radio_action_callback_data(action, current, user_data):
107 self.assertEqual(user_data, callback_data)
109 action_group.add_actions([
110 ('test-action1', None, 'Test Action 1',
111 None, None, test_action_callback_data),
112 ('test-action2', Gtk.STOCK_COPY, 'Test Action 2',
113 None, None, test_action_callback_data)], callback_data)
114 action_group.add_toggle_actions([
115 ('test-toggle-action1', None, 'Test Toggle Action 1',
116 None, None, test_action_callback_data, False),
117 ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2',
118 None, None, test_action_callback_data, True)], callback_data)
119 action_group.add_radio_actions([
120 ('test-radio-action1', None, 'Test Radio Action 1'),
121 ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1,
122 test_radio_action_callback_data,
125 expected_results = [('test-action1', Gtk.Action),
126 ('test-action2', Gtk.Action),
127 ('test-toggle-action1', Gtk.ToggleAction),
128 ('test-toggle-action2', Gtk.ToggleAction),
129 ('test-radio-action1', Gtk.RadioAction),
130 ('test-radio-action2', Gtk.RadioAction)]
132 for action in action_group.list_actions():
133 a = (action.get_name(), type(action))
134 self.assertTrue(a in expected_results)
135 expected_results.remove(a)
138 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
139 def test_uimanager(self):
140 self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager)
142 ui.add_ui_from_string("""<ui>
143 <menubar name="menubar1"></menubar>
147 menubar = ui.get_widget("/menubar1")
148 self.assertEqual(type(menubar), Gtk.MenuBar)
150 ag = Gtk.ActionGroup(name="ag1")
151 ui.insert_action_group(ag)
152 ag2 = Gtk.ActionGroup(name="ag2")
153 ui.insert_action_group(ag2)
154 groups = ui.get_action_groups()
155 self.assertEqual(ag, groups[-2])
156 self.assertEqual(ag2, groups[-1])
158 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
159 def test_uimanager_nonascii(self):
161 ui.add_ui_from_string(b'<ui><menubar name="menub\xc3\xa6r1" /></ui>'.decode('UTF-8'))
162 mi = ui.get_widget("/menubær1")
163 self.assertEqual(type(mi), Gtk.MenuBar)
165 def test_window(self):
168 self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL)
170 # type works as keyword argument
171 w = Gtk.Window(type=Gtk.WindowType.POPUP)
172 self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
174 class TestWindow(Gtk.Window):
175 __gtype_name__ = "TestWindow"
178 builder = Gtk.Builder()
179 builder.add_from_string('''
181 <object class="GtkWindow" id="win">
182 <property name="type">popup</property>
184 <object class="TestWindow" id="testwin">
186 <object class="TestWindow" id="testpop">
187 <property name="type">popup</property>
190 self.assertEqual(builder.get_object('win').get_property('type'),
191 Gtk.WindowType.POPUP)
192 self.assertEqual(builder.get_object('testwin').get_property('type'),
193 Gtk.WindowType.TOPLEVEL)
194 self.assertEqual(builder.get_object('testpop').get_property('type'),
195 Gtk.WindowType.POPUP)
197 def test_dialog_classes(self):
198 self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
199 self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
200 self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
201 if Gtk._version != "4.0":
202 self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
203 self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
205 def test_dialog_base(self):
206 dialog = Gtk.Dialog(title='Foo', modal=True)
207 self.assertTrue(isinstance(dialog, Gtk.Dialog))
208 self.assertTrue(isinstance(dialog, Gtk.Window))
209 self.assertEqual('Foo', dialog.get_title())
210 self.assertTrue(dialog.get_modal())
212 def test_dialog_deprecations(self):
213 with warnings.catch_warnings(record=True) as warn:
214 warnings.simplefilter('always')
215 dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.MODAL)
216 self.assertTrue(dialog.get_modal())
217 self.assertEqual(len(warn), 1)
218 self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
219 self.assertRegexpMatches(str(warn[0].message),
222 with warnings.catch_warnings(record=True) as warn:
223 warnings.simplefilter('always')
224 dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.DESTROY_WITH_PARENT)
225 self.assertTrue(dialog.get_destroy_with_parent())
226 self.assertEqual(len(warn), 1)
227 self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
228 self.assertRegexpMatches(str(warn[0].message),
229 '.*flags.*destroy_with_parent.*')
231 def test_dialog_deprecation_stacklevels(self):
232 # Test warning levels are setup to give the correct filename for
233 # deprecations in different classes in the inheritance hierarchy.
236 self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
237 with warnings.catch_warnings(record=True) as warn:
238 warnings.simplefilter('always')
239 Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
240 self.assertEqual(len(warn), 1)
241 self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
243 # Validate overridden base with overridden sub-class.
244 self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
245 with warnings.catch_warnings(record=True) as warn:
246 warnings.simplefilter('always')
247 Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL)
248 self.assertEqual(len(warn), 1)
249 self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
251 # Validate overridden base with non-overridden sub-class.
252 self.assertEqual(Gtk.AboutDialog, gi.repository.Gtk.AboutDialog)
253 with warnings.catch_warnings(record=True) as warn:
254 warnings.simplefilter('always')
255 Gtk.AboutDialog(flags=Gtk.DialogFlags.MODAL)
256 self.assertEqual(len(warn), 1)
257 self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
259 def test_dialog_add_buttons(self):
260 # The overloaded "buttons" keyword gives a warning when attempting
261 # to use it for adding buttons as was available in PyGTK.
262 with warnings.catch_warnings(record=True) as warn:
263 warnings.simplefilter('always')
264 dialog = Gtk.Dialog(title='Foo', modal=True,
265 buttons=('test-button1', 1))
266 self.assertEqual(len(warn), 1)
267 self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
268 self.assertRegexpMatches(str(warn[0].message),
269 '.*ButtonsType.*add_buttons.*')
271 dialog.add_buttons('test-button2', 2, 'gtk-close', Gtk.ResponseType.CLOSE)
272 button = dialog.get_widget_for_response(1)
273 self.assertEqual('test-button1', button.get_label())
274 button = dialog.get_widget_for_response(2)
275 self.assertEqual('test-button2', button.get_label())
276 button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
277 self.assertEqual('gtk-close', button.get_label())
279 def test_about_dialog(self):
280 dialog = Gtk.AboutDialog()
281 self.assertTrue(isinstance(dialog, Gtk.Dialog))
282 self.assertTrue(isinstance(dialog, Gtk.Window))
284 # AboutDialog is not sub-classed in overrides, make sure
285 # the mro still injects the base class "add_buttons" override.
286 self.assertTrue(hasattr(dialog, 'add_buttons'))
288 def test_message_dialog(self):
289 dialog = Gtk.MessageDialog(title='message dialog test',
291 buttons=Gtk.ButtonsType.OK,
293 self.assertTrue(isinstance(dialog, Gtk.Dialog))
294 self.assertTrue(isinstance(dialog, Gtk.Window))
296 self.assertEqual('message dialog test', dialog.get_title())
297 self.assertTrue(dialog.get_modal())
298 text = dialog.get_property('text')
299 self.assertEqual('dude!', text)
301 dialog.format_secondary_text('2nd text')
302 self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
303 self.assertFalse(dialog.get_property('secondary-use-markup'))
305 dialog.format_secondary_markup('2nd markup')
306 self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
307 self.assertTrue(dialog.get_property('secondary-use-markup'))
309 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
310 def test_color_selection_dialog(self):
311 dialog = Gtk.ColorSelectionDialog(title="color selection dialog test")
312 self.assertTrue(isinstance(dialog, Gtk.Dialog))
313 self.assertTrue(isinstance(dialog, Gtk.Window))
314 self.assertEqual('color selection dialog test', dialog.get_title())
316 def test_file_chooser_dialog(self):
317 # might cause a GVFS warning, do not break on this
318 with capture_glib_warnings(allow_warnings=True):
319 dialog = Gtk.FileChooserDialog(title='file chooser dialog test',
320 action=Gtk.FileChooserAction.SAVE)
322 self.assertTrue(isinstance(dialog, Gtk.Dialog))
323 self.assertTrue(isinstance(dialog, Gtk.Window))
324 self.assertEqual('file chooser dialog test', dialog.get_title())
326 action = dialog.get_property('action')
327 self.assertEqual(Gtk.FileChooserAction.SAVE, action)
329 def test_file_chooser_dialog_default_action(self):
330 # might cause a GVFS warning, do not break on this
331 with capture_glib_warnings(allow_warnings=True):
332 dialog = Gtk.FileChooserDialog(title='file chooser dialog test')
334 action = dialog.get_property('action')
335 self.assertEqual(Gtk.FileChooserAction.OPEN, action)
337 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
338 def test_font_selection_dialog(self):
339 dialog = Gtk.FontSelectionDialog(title="font selection dialog test")
340 self.assertTrue(isinstance(dialog, Gtk.Dialog))
341 self.assertTrue(isinstance(dialog, Gtk.Window))
342 self.assertEqual('font selection dialog test', dialog.get_title())
344 def test_recent_chooser_dialog(self):
345 test_manager = Gtk.RecentManager()
346 dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test',
347 recent_manager=test_manager)
348 self.assertTrue(isinstance(dialog, Gtk.Dialog))
349 self.assertTrue(isinstance(dialog, Gtk.Window))
350 self.assertEqual('recent chooser dialog test', dialog.get_title())
352 class TestClass(GObject.GObject):
353 __gtype_name__ = "GIOverrideTreeAPITest"
355 def __init__(self, tester, int_value, string_value):
356 super(TestGtk.TestClass, self).__init__()
358 self.int_value = int_value
359 self.string_value = string_value
361 def check(self, int_value, string_value):
362 self.tester.assertEqual(int_value, self.int_value)
363 self.tester.assertEqual(string_value, self.string_value)
365 def test_buttons(self):
366 self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
369 button = Gtk.Button()
370 self.assertTrue(isinstance(button, Gtk.Button))
371 self.assertTrue(isinstance(button, Gtk.Container))
372 self.assertTrue(isinstance(button, Gtk.Widget))
374 if Gtk._version != "4.0":
375 # Using stock items causes hard warning in devel versions of GTK+.
376 with capture_glib_warnings(allow_warnings=True):
377 button = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE)
379 self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
380 self.assertTrue(button.get_use_stock())
381 self.assertTrue(button.get_use_underline())
383 # test Gtk.Button use_stock
384 button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True,
386 self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
387 self.assertTrue(button.get_use_stock())
388 self.assertTrue(button.get_use_underline())
390 # test Gtk.LinkButton
391 button = Gtk.LinkButton(uri='http://www.Gtk.org', label='Gtk')
392 self.assertTrue(isinstance(button, Gtk.Button))
393 self.assertTrue(isinstance(button, Gtk.Container))
394 self.assertTrue(isinstance(button, Gtk.Widget))
395 self.assertEqual('http://www.Gtk.org', button.get_uri())
396 self.assertEqual('Gtk', button.get_label())
398 def test_inheritance(self):
399 for name in gi.overrides.Gtk.__all__:
400 over = getattr(gi.overrides.Gtk, name)
401 for element in dir(Gtk):
403 klass = getattr(Gtk, element)
404 info = klass.__info__
405 except (NotImplementedError, AttributeError):
408 # Get all parent classes and interfaces klass inherits from
409 if isinstance(info, gi.types.ObjectInfo):
410 classes = list(info.get_interfaces())
411 parent = info.get_parent()
412 while parent.get_name() != "Object":
413 classes.append(parent)
414 parent = parent.get_parent()
415 classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
420 if kl.get_name() == name:
421 self.assertTrue(issubclass(klass, over,),
422 "%r does not inherit from override %r" % (klass, over,))
424 def test_editable(self):
425 self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable)
427 # need to use Gtk.Entry because Editable is an interface
429 pos = entry.insert_text('HeWorld', 0)
430 self.assertEqual(pos, 7)
431 pos = entry.insert_text('llo ', 2)
432 self.assertEqual(pos, 6)
433 text = entry.get_chars(0, 11)
434 self.assertEqual('Hello World', text)
436 def test_label(self):
437 label = Gtk.Label(label='Hello')
438 self.assertTrue(isinstance(label, Gtk.Widget))
439 self.assertEqual(label.get_text(), 'Hello')
441 def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0,
442 step_increment=0.0, page_increment=0.0, page_size=0.0):
443 self.assertEqual(adjustment.get_value(), value)
444 self.assertEqual(adjustment.get_lower(), lower)
445 self.assertEqual(adjustment.get_upper(), upper)
446 self.assertEqual(adjustment.get_step_increment(), step_increment)
447 self.assertEqual(adjustment.get_page_increment(), page_increment)
448 self.assertEqual(adjustment.get_page_size(), page_size)
450 def test_adjustment(self):
451 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
452 self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
454 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5)
455 self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5)
457 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4)
458 self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4)
460 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6)
461 self.adjustment_check(adjustment, value=1, lower=0, upper=6)
463 adjustment = Gtk.Adjustment()
464 self.adjustment_check(adjustment)
466 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
467 def test_table(self):
469 self.assertTrue(isinstance(table, Gtk.Table))
470 self.assertTrue(isinstance(table, Gtk.Container))
471 self.assertTrue(isinstance(table, Gtk.Widget))
472 self.assertEqual(table.get_size(), (1, 1))
473 self.assertEqual(table.get_homogeneous(), False)
475 table = Gtk.Table(n_rows=2, n_columns=3)
476 self.assertEqual(table.get_size(), (2, 3))
477 self.assertEqual(table.get_homogeneous(), False)
479 table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True)
480 self.assertEqual(table.get_size(), (2, 3))
481 self.assertEqual(table.get_homogeneous(), True)
483 label = Gtk.Label(label='Hello')
484 self.assertTrue(isinstance(label, Gtk.Widget))
485 table.attach(label, 0, 1, 0, 1)
486 self.assertEqual(label, table.get_children()[0])
488 def test_scrolledwindow(self):
489 sw = Gtk.ScrolledWindow()
490 self.assertTrue(isinstance(sw, Gtk.ScrolledWindow))
491 self.assertTrue(isinstance(sw, Gtk.Container))
492 self.assertTrue(isinstance(sw, Gtk.Widget))
493 sb = sw.get_hscrollbar()
494 self.assertEqual(sw.get_hadjustment(), sb.get_adjustment())
495 sb = sw.get_vscrollbar()
496 self.assertEqual(sw.get_vadjustment(), sb.get_adjustment())
498 def test_widget_drag_methods(self):
499 widget = Gtk.Button()
501 # here we are not checking functionality, only that the methods exist
502 # and except the right number of arguments
504 widget.drag_check_threshold(0, 0, 0, 0)
507 widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
508 widget.drag_dest_add_image_targets()
509 widget.drag_dest_add_text_targets()
510 widget.drag_dest_add_uri_targets()
511 widget.drag_dest_get_track_motion()
512 widget.drag_dest_set_track_motion(True)
513 widget.drag_dest_get_target_list()
514 widget.drag_dest_set_target_list(None)
515 widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
516 widget.drag_dest_unset()
518 widget.drag_highlight()
519 widget.drag_unhighlight()
521 # drag_source_ methods
522 widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
523 widget.drag_source_add_image_targets()
524 widget.drag_source_add_text_targets()
525 widget.drag_source_add_uri_targets()
526 widget.drag_source_set_icon_name("_About")
527 widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf())
528 if Gtk._version != "4.0":
529 widget.drag_source_set_icon_stock(Gtk.STOCK_ABOUT)
530 widget.drag_source_get_target_list()
531 widget.drag_source_set_target_list(None)
532 widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
533 widget.drag_source_unset()
535 # these methods cannot be called because they require a valid drag on
536 # a real GdkWindow. So we only check that they exist and are callable.
537 if Gtk._version != "4.0":
538 self.assertTrue(hasattr(widget, 'drag_dest_set_proxy'))
539 self.assertTrue(hasattr(widget, 'drag_get_data'))
541 def test_drag_target_list(self):
542 mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0),
544 Gtk.TargetEntry.new('test2', 2, 2),
547 def _test_target_list(targets):
548 for i, target in enumerate(targets):
549 self.assertTrue(isinstance(target, Gtk.TargetEntry))
550 self.assertEqual(target.target, 'test' + str(i))
551 self.assertEqual(target.flags, i)
552 self.assertEqual(target.info, i)
554 _test_target_list(Gtk._construct_target_list(mixed_target_list))
556 widget = Gtk.Button()
557 widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
558 widget.drag_dest_set_target_list(mixed_target_list)
559 widget.drag_dest_get_target_list()
561 widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
562 widget.drag_source_set_target_list(mixed_target_list)
563 widget.drag_source_get_target_list()
565 treeview = Gtk.TreeView()
566 treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
568 Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
570 treeview.enable_model_drag_dest(mixed_target_list,
571 Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
573 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
574 def test_scrollbar(self):
575 adjustment = Gtk.Adjustment()
577 hscrollbar = Gtk.HScrollbar()
578 vscrollbar = Gtk.VScrollbar()
579 self.assertNotEqual(hscrollbar.props.adjustment, adjustment)
580 self.assertNotEqual(vscrollbar.props.adjustment, adjustment)
582 hscrollbar = Gtk.HScrollbar(adjustment=adjustment)
583 vscrollbar = Gtk.VScrollbar(adjustment=adjustment)
584 self.assertEqual(hscrollbar.props.adjustment, adjustment)
585 self.assertEqual(vscrollbar.props.adjustment, adjustment)
587 def test_iconview(self):
589 iconview = Gtk.IconView()
590 self.assertEqual(iconview.props.model, None)
592 model = Gtk.ListStore(str)
593 iconview = Gtk.IconView(model=model)
594 self.assertEqual(iconview.props.model, model)
596 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
597 def test_toolbutton(self):
600 # Using stock items causes hard warning in devel versions of GTK+.
601 with capture_glib_warnings(allow_warnings=True):
602 button = Gtk.ToolButton()
603 self.assertEqual(button.props.stock_id, None)
605 button = Gtk.ToolButton(stock_id='gtk-new')
606 self.assertEqual(button.props.stock_id, 'gtk-new')
608 icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
609 button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
610 self.assertEqual(button.props.label, 'mylabel')
611 self.assertEqual(button.props.icon_widget, icon)
613 def test_toolbutton_gtk4(self):
614 icon = Gtk.Image.new()
615 button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
616 self.assertEqual(button.props.label, 'mylabel')
617 self.assertEqual(button.props.icon_widget, icon)
619 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
620 def test_iconset(self):
622 pixbuf = GdkPixbuf.Pixbuf()
623 Gtk.IconSet.new_from_pixbuf(pixbuf)
625 def test_viewport(self):
626 vadjustment = Gtk.Adjustment()
627 hadjustment = Gtk.Adjustment()
629 viewport = Gtk.Viewport(hadjustment=hadjustment,
630 vadjustment=vadjustment)
632 self.assertEqual(viewport.props.vadjustment, vadjustment)
633 self.assertEqual(viewport.props.hadjustment, hadjustment)
635 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
636 def test_stock_lookup(self):
637 stock_item = Gtk.stock_lookup('gtk-ok')
638 self.assertEqual(type(stock_item), Gtk.StockItem)
639 self.assertEqual(stock_item.stock_id, 'gtk-ok')
640 self.assertEqual(Gtk.stock_lookup('nosuchthing'), None)
642 def test_gtk_main(self):
644 GLib.idle_add(Gtk.main_quit)
647 # overridden function ignores its arguments
648 GLib.idle_add(Gtk.main_quit, 'hello')
651 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
652 def test_widget_render_icon(self):
653 button = Gtk.Button(label='OK')
654 pixbuf = button.render_icon(Gtk.STOCK_OK, Gtk.IconSize.BUTTON)
655 self.assertTrue(pixbuf is not None)
658 @unittest.skipUnless(Gtk, 'Gtk not available')
659 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
660 class TestWidget(unittest.TestCase):
661 def test_style_get_property_gvalue(self):
662 button = Gtk.Button()
663 value = GObject.Value(int, -42)
664 button.style_get_property('focus-padding', value)
665 # Test only that the style property changed since we can't actuall
667 self.assertNotEqual(value.get_int(), -42)
669 def test_style_get_property_return_with_explicit_gvalue(self):
670 button = Gtk.Button()
671 value = GObject.Value(int, -42)
672 result = button.style_get_property('focus-padding', value)
673 self.assertIsInstance(result, int)
674 self.assertNotEqual(result, -42)
676 def test_style_get_property_return_with_implicit_gvalue(self):
677 button = Gtk.Button()
678 result = button.style_get_property('focus-padding')
679 self.assertIsInstance(result, int)
680 self.assertNotEqual(result, -42)
682 def test_style_get_property_error(self):
683 button = Gtk.Button()
684 with self.assertRaises(ValueError):
685 button.style_get_property('not-a-valid-style-property')
688 @unittest.skipIf(sys.platform == "darwin", "hangs")
689 @unittest.skipUnless(Gtk, 'Gtk not available')
690 class TestSignals(unittest.TestCase):
691 def test_class_closure_override_with_aliased_type(self):
692 class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
693 __gsignals__ = {'size-allocate': 'override'}
696 Gtk.ScrolledWindow.__init__(self)
697 self._alloc_called = False
698 self._alloc_value = None
699 self._alloc_error = None
701 def do_size_allocate(self, alloc):
702 self._alloc_called = True
703 self._alloc_value = alloc
706 Gtk.ScrolledWindow.do_size_allocate(self, alloc)
707 except Exception as e:
708 self._alloc_error = e
710 win = WindowWithSizeAllocOverride()
711 rect = Gdk.Rectangle()
717 win.get_preferred_size()
718 win.size_allocate(rect)
719 self.assertTrue(win._alloc_called)
720 self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
721 self.assertTrue(win._alloc_error is None, win._alloc_error)
723 @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=735693
724 def test_overlay_child_position(self):
725 def get_child_position(overlay, widget, rect, user_data=None):
732 overlay = Gtk.Overlay()
733 overlay.connect('get-child-position', get_child_position)
735 rect = Gdk.Rectangle()
741 overlay.emit('get-child-position', None, rect)
742 self.assertEqual(rect.x, 1)
743 self.assertEqual(rect.y, 2)
744 self.assertEqual(rect.width, 3)
745 self.assertEqual(rect.height, 4)
748 @unittest.skipUnless(Gtk, 'Gtk not available')
749 class TestBuilder(unittest.TestCase):
750 class SignalTest(GObject.GObject):
751 __gtype_name__ = "GIOverrideSignalTest"
753 "test-signal": (GObject.SignalFlags.RUN_FIRST,
758 def test_extract_handler_and_args_object(self):
763 obj.foo = lambda: None
765 handler, args = Gtk._extract_handler_and_args(obj, 'foo')
766 self.assertEqual(handler, obj.foo)
767 self.assertEqual(len(args), 0)
769 def test_extract_handler_and_args_dict(self):
770 obj = {'foo': lambda: None}
772 handler, args = Gtk._extract_handler_and_args(obj, 'foo')
773 self.assertEqual(handler, obj['foo'])
774 self.assertEqual(len(args), 0)
776 def test_extract_handler_and_args_with_seq(self):
777 obj = {'foo': (lambda: None, 1, 2)}
779 handler, args = Gtk._extract_handler_and_args(obj, 'foo')
780 self.assertEqual(handler, obj['foo'][0])
781 self.assertSequenceEqual(args, [1, 2])
783 def test_extract_handler_and_args_no_handler_error(self):
784 obj = dict(foo=lambda: None)
785 self.assertRaises(AttributeError,
786 Gtk._extract_handler_and_args,
787 obj, 'not_a_handler')
789 def test_builder_with_handler_and_args(self):
790 builder = Gtk.Builder()
791 builder.add_from_string("""
793 <object class="GIOverrideSignalTest" id="object_sig_test">
794 <signal name="test-signal" handler="on_signal1" />
795 <signal name="test-signal" handler="on_signal2" after="yes" />
802 def on_signal(*args):
803 args_collector.append(args)
805 builder.connect_signals({'on_signal1': (on_signal, 1, 2),
806 'on_signal2': on_signal})
808 objects = builder.get_objects()
809 self.assertEqual(len(objects), 1)
811 obj.emit('test-signal')
813 self.assertEqual(len(args_collector), 2)
814 self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
815 self.assertSequenceEqual(args_collector[1], (obj, ))
817 def test_builder(self):
818 self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
823 self.after_sentinel = 0
825 def on_signal_1(self, *args):
827 self.after_sentinel += 1
829 def on_signal_3(self, *args):
832 def on_signal_after(self, *args):
833 if self.after_sentinel == 1:
834 self.after_sentinel += 1
836 signal_checker = SignalCheck()
837 builder = Gtk.Builder()
839 # add object1 to the builder
840 builder.add_from_string("""
842 <object class="GIOverrideSignalTest" id="object1">
843 <signal name="test-signal" after="yes" handler="on_signal_after" />
844 <signal name="test-signal" handler="on_signal_1" />
849 # only add object3 to the builder
850 builder.add_objects_from_string("""
852 <object class="GIOverrideSignalTest" id="object2">
853 <signal name="test-signal" handler="on_signal_2" />
855 <object class="GIOverrideSignalTest" id="object3">
856 <signal name="test-signal" handler="on_signal_3" />
858 <object class="GIOverrideSignalTest" id="object4">
859 <signal name="test-signal" handler="on_signal_4" />
865 builder.connect_signals(signal_checker)
867 # call their notify signals and check sentinel
868 objects = builder.get_objects()
869 self.assertEqual(len(objects), 2)
871 obj.emit('test-signal')
873 self.assertEqual(signal_checker.sentinel, 4)
874 self.assertEqual(signal_checker.after_sentinel, 2)
877 @ignore_gi_deprecation_warnings
878 @unittest.skipUnless(Gtk, 'Gtk not available')
879 class TestTreeModel(unittest.TestCase):
880 def test_tree_model_sort(self):
881 self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
882 model = Gtk.TreeStore(int, bool)
883 model_sort = Gtk.TreeModelSort(model=model)
884 self.assertEqual(model_sort.get_model(), model)
886 def test_tree_store(self):
887 self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore)
888 self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore)
889 self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel)
890 self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn)
892 class TestPyObject(object):
895 test_pyobj = TestPyObject()
896 test_pydict = {1: 1, "2": 2, "3": "3"}
897 test_pylist = [1, "2", "3"]
898 tree_store = Gtk.TreeStore(int,
901 GObject.TYPE_PYOBJECT,
916 label = 'this is child #%d' % i
917 testobj = TestGtk.TestClass(self, i, label)
918 parent = tree_store.append(parent, (i,
935 parent = tree_store.append(parent)
937 label = 'this is child #%d' % i
938 testobj = TestGtk.TestClass(self, i, label)
939 tree_store.set(parent,
952 12, 0xffffffffffffffff,
956 parent = tree_store.append(parent)
958 label = 'this is child #%d' % i
959 testobj = TestGtk.TestClass(self, i, label)
960 tree_store.set(parent, {0: i,
972 12: 0xffffffffffffffff,
976 parent = tree_store.append(parent)
978 label = 'this is child #%d' % i
979 testobj = TestGtk.TestClass(self, i, label)
980 tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
997 # len gets the number of children in the root node
998 # since we kept appending to the previous node
999 # there should only be one child of the root
1000 self.assertEqual(len(tree_store), 1)
1002 # walk the tree to see if the values were stored correctly
1006 treeiter = tree_store.iter_children(parent)
1008 i = tree_store.get_value(treeiter, 0)
1009 s = tree_store.get_value(treeiter, 1)
1010 obj = tree_store.get_value(treeiter, 2)
1012 obj2 = tree_store.get_value(treeiter, 3)
1013 self.assertEqual(obj, obj2)
1015 pyobj = tree_store.get_value(treeiter, 4)
1016 self.assertEqual(pyobj, test_pyobj)
1017 pydict = tree_store.get_value(treeiter, 5)
1018 self.assertEqual(pydict, test_pydict)
1019 pylist = tree_store.get_value(treeiter, 6)
1020 self.assertEqual(pylist, test_pylist)
1022 bool_1 = tree_store.get_value(treeiter, 7)
1023 bool_2 = tree_store.get_value(treeiter, 8)
1024 self.assertEqual(bool_1, bool_2)
1025 self.assertTrue(isinstance(bool_1, bool))
1026 self.assertTrue(isinstance(bool_2, bool))
1028 uint_ = tree_store.get_value(treeiter, 9)
1029 self.assertEqual(uint_, i)
1030 ulong_ = tree_store.get_value(treeiter, 10)
1031 self.assertEqual(ulong_, GLib.MAXULONG)
1032 int64_ = tree_store.get_value(treeiter, 11)
1033 self.assertEqual(int64_, GLib.MININT64)
1034 uint64_ = tree_store.get_value(treeiter, 12)
1035 self.assertEqual(uint64_, 0xffffffffffffffff)
1036 uchar_ = tree_store.get_value(treeiter, 13)
1037 self.assertEqual(ord(uchar_), 254)
1038 char_ = tree_store.get_value(treeiter, 14)
1039 self.assertEqual(char_, 'a')
1042 treeiter = tree_store.iter_children(parent)
1044 self.assertEqual(i, 99)
1046 def test_tree_store_signals(self):
1047 tree_store = Gtk.TreeStore(int, bool)
1049 def on_row_inserted(tree_store, tree_path, tree_iter, signal_list):
1050 signal_list.append('row-inserted')
1052 def on_row_changed(tree_store, tree_path, tree_iter, signal_list):
1053 signal_list.append('row-changed')
1056 tree_store.connect('row-inserted', on_row_inserted, signals)
1057 tree_store.connect('row-changed', on_row_changed, signals)
1059 # adding rows with and without data should only call one signal
1060 tree_store.append(None, (0, False))
1061 self.assertEqual(signals, ['row-inserted'])
1064 tree_store.append(None)
1065 self.assertEqual(signals, ['row-inserted'])
1068 tree_store.prepend(None, (0, False))
1069 self.assertEqual(signals, ['row-inserted'])
1072 tree_store.prepend(None)
1073 self.assertEqual(signals, ['row-inserted'])
1076 tree_store.insert(None, 1, (0, False))
1077 self.assertEqual(signals, ['row-inserted'])
1080 tree_store.insert(None, 1)
1081 self.assertEqual(signals, ['row-inserted'])
1083 def test_list_store(self):
1084 class TestPyObject(object):
1087 test_pyobj = TestPyObject()
1088 test_pydict = {1: 1, "2": 2, "3": "3"}
1089 test_pylist = [1, "2", "3"]
1091 list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool)
1092 for i in range(1, 93):
1093 label = 'this is row #%d' % i
1094 testobj = TestGtk.TestClass(self, i, label)
1095 list_store.append((i,
1105 label = u'this is row #93'
1106 treeiter = list_store.append()
1107 list_store.set_value(treeiter, 0, i)
1108 list_store.set_value(treeiter, 1, label)
1109 list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
1110 list_store.set_value(treeiter, 3, test_pyobj)
1111 list_store.set_value(treeiter, 4, test_pydict)
1112 list_store.set_value(treeiter, 5, test_pylist)
1113 list_store.set_value(treeiter, 6, 1)
1114 list_store.set_value(treeiter, 7, True)
1117 label = 'this is row #0'
1118 list_store.prepend((0,
1120 TestGtk.TestClass(self, 0, label),
1127 # test automatic unicode->str conversion
1129 label = u'this is row #94'
1130 treeiter = list_store.append((i,
1132 TestGtk.TestClass(self, i, label),
1139 # add sorted items out of order to test insert* apis
1140 # also test sending in None to not set a column
1142 label = 'this is row #97'
1143 treeiter = list_store.append((None,
1152 list_store.set_value(treeiter, 0, i)
1153 list_store.set_value(treeiter, 1, label)
1154 list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
1155 list_store.set_value(treeiter, 4, test_pydict)
1156 list_store.set_value(treeiter, 7, True)
1158 # this should append
1160 label = 'this is row #99'
1161 list_store.insert(9999, (i,
1163 TestGtk.TestClass(self, i, label),
1171 label = 'this is row #96'
1172 list_store.insert_before(treeiter, (i,
1174 TestGtk.TestClass(self, i, label),
1182 label = 'this is row #98'
1183 list_store.insert_after(treeiter, (i,
1185 TestGtk.TestClass(self, i, label),
1193 label = 'this is row #95'
1194 list_store.insert(95, (i,
1196 TestGtk.TestClass(self, i, label),
1204 label = 'this is row #100'
1205 treeiter = list_store.append()
1206 list_store.set(treeiter,
1209 2, TestGtk.TestClass(self, i, label),
1216 label = 'this is row #101'
1217 treeiter = list_store.append()
1218 list_store.set(treeiter, {1: label,
1220 2: TestGtk.TestClass(self, i, label),
1227 label = 'this is row #102'
1228 treeiter = list_store.append()
1229 list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7),
1232 TestGtk.TestClass(self, i, label),
1239 self.assertEqual(len(list_store), 103)
1241 # walk the list to see if the values were stored correctly
1243 treeiter = list_store.get_iter_first()
1247 i = list_store.get_value(treeiter, 0)
1248 self.assertEqual(i, counter)
1249 s = list_store.get_value(treeiter, 1)
1250 obj = list_store.get_value(treeiter, 2)
1253 pyobj = list_store.get_value(treeiter, 3)
1254 self.assertEqual(pyobj, test_pyobj)
1255 pydict = list_store.get_value(treeiter, 4)
1256 self.assertEqual(pydict, test_pydict)
1257 pylist = list_store.get_value(treeiter, 5)
1258 self.assertEqual(pylist, test_pylist)
1260 bool_1 = list_store.get_value(treeiter, 6)
1261 bool_2 = list_store.get_value(treeiter, 7)
1262 self.assertEqual(bool_1, bool_2)
1263 self.assertTrue(isinstance(bool_1, bool))
1264 self.assertTrue(isinstance(bool_2, bool))
1266 treeiter = list_store.iter_next(treeiter)
1270 self.assertEqual(i, 102)
1272 def test_list_store_sort(self):
1273 def comp1(model, row1, row2, user_data):
1277 # make "m" smaller than anything else
1278 if v1.startswith('m') and not v2.startswith('m'):
1280 if v2.startswith('m') and not v1.startswith('m'):
1282 return (v1 > v2) - (v1 < v2)
1284 list_store = Gtk.ListStore(int, str)
1285 list_store.set_sort_func(2, comp1, None)
1286 list_store.append((1, 'apples'))
1287 list_store.append((3, 'oranges'))
1288 list_store.append((2, 'mango'))
1290 # not sorted yet, should be original order
1291 self.assertEqual([list(i) for i in list_store],
1292 [[1, 'apples'], [3, 'oranges'], [2, 'mango']])
1294 # sort with our custom function
1295 list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING)
1296 self.assertEqual([list(i) for i in list_store],
1297 [[2, 'mango'], [1, 'apples'], [3, 'oranges']])
1299 list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING)
1300 self.assertEqual([list(i) for i in list_store],
1301 [[3, 'oranges'], [1, 'apples'], [2, 'mango']])
1303 def test_list_store_signals(self):
1304 list_store = Gtk.ListStore(int, bool)
1306 def on_row_inserted(list_store, tree_path, tree_iter, signal_list):
1307 signal_list.append('row-inserted')
1309 def on_row_changed(list_store, tree_path, tree_iter, signal_list):
1310 signal_list.append('row-changed')
1313 list_store.connect('row-inserted', on_row_inserted, signals)
1314 list_store.connect('row-changed', on_row_changed, signals)
1316 # adding rows with and without data should only call one signal
1317 list_store.append((0, False))
1318 self.assertEqual(signals, ['row-inserted'])
1322 self.assertEqual(signals, ['row-inserted'])
1325 list_store.prepend((0, False))
1326 self.assertEqual(signals, ['row-inserted'])
1329 list_store.prepend()
1330 self.assertEqual(signals, ['row-inserted'])
1333 list_store.insert(1, (0, False))
1334 self.assertEqual(signals, ['row-inserted'])
1337 list_store.insert(1)
1338 self.assertEqual(signals, ['row-inserted'])
1340 def test_tree_path(self):
1342 p2 = Gtk.TreePath.new_first()
1343 self.assertEqual(p1, p2)
1344 self.assertEqual(str(p1), '0')
1345 self.assertEqual(len(p1), 1)
1346 p1 = Gtk.TreePath(2)
1347 p2 = Gtk.TreePath.new_from_string('2')
1348 self.assertEqual(p1, p2)
1349 self.assertEqual(str(p1), '2')
1350 self.assertEqual(len(p1), 1)
1351 p1 = Gtk.TreePath('1:2:3')
1352 p2 = Gtk.TreePath.new_from_string('1:2:3')
1353 self.assertEqual(p1, p2)
1354 self.assertEqual(str(p1), '1:2:3')
1355 self.assertEqual(len(p1), 3)
1356 p1 = Gtk.TreePath((1, 2, 3))
1357 p2 = Gtk.TreePath.new_from_string('1:2:3')
1358 self.assertEqual(p1, p2)
1359 self.assertEqual(str(p1), '1:2:3')
1360 self.assertEqual(len(p1), 3)
1361 self.assertNotEqual(p1, None)
1362 self.assertTrue(p1 > None)
1363 self.assertTrue(p1 >= None)
1364 self.assertFalse(p1 < None)
1365 self.assertFalse(p1 <= None)
1367 self.assertEqual(tuple(p1), (1, 2, 3))
1368 self.assertEqual(p1[0], 1)
1369 self.assertEqual(p1[1], 2)
1370 self.assertEqual(p1[2], 3)
1371 self.assertRaises(IndexError, p1.__getitem__, 3)
1373 def test_tree_model(self):
1374 tree_store = Gtk.TreeStore(int, str)
1376 self.assertTrue(tree_store)
1377 self.assertEqual(len(tree_store), 0)
1378 self.assertEqual(tree_store.get_iter_first(), None)
1380 def get_by_index(row, col=None):
1382 return tree_store[row][col]
1384 return tree_store[row]
1386 self.assertRaises(TypeError, get_by_index, None)
1387 self.assertRaises(TypeError, get_by_index, "")
1388 self.assertRaises(TypeError, get_by_index, ())
1390 self.assertRaises(IndexError, get_by_index, "0")
1391 self.assertRaises(IndexError, get_by_index, 0)
1392 self.assertRaises(IndexError, get_by_index, (0,))
1394 self.assertRaises(ValueError, tree_store.get_iter, "0")
1395 self.assertRaises(ValueError, tree_store.get_iter, 0)
1396 self.assertRaises(ValueError, tree_store.get_iter, (0,))
1398 self.assertRaises(ValueError, tree_store.get_iter_from_string, "0")
1400 for row in tree_store:
1401 self.fail("Should not be reached")
1403 class DerivedIntType(int):
1406 class DerivedStrType(str):
1409 for i in range(100):
1410 label = 'this is row #%d' % i
1411 parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),))
1412 self.assertNotEqual(parent, None)
1414 label = 'this is child #%d of node #%d' % (j, i)
1415 child = tree_store.append(parent, (j, label,))
1416 self.assertNotEqual(child, None)
1418 self.assertTrue(tree_store)
1419 self.assertEqual(len(tree_store), 100)
1421 self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None)
1423 for i, row in enumerate(tree_store):
1424 self.assertEqual(row.model, tree_store)
1425 self.assertEqual(row.parent, None)
1427 self.assertEqual(tree_store[i].path, row.path)
1428 self.assertEqual(tree_store[str(i)].path, row.path)
1429 self.assertEqual(tree_store[(i,)].path, row.path)
1431 self.assertEqual(tree_store[i][0], i)
1432 self.assertEqual(tree_store[i][1], "this is row #%d" % i)
1434 aiter = tree_store.get_iter(i)
1435 self.assertEqual(tree_store.get_path(aiter), row.path)
1437 aiter = tree_store.get_iter(str(i))
1438 self.assertEqual(tree_store.get_path(aiter), row.path)
1440 aiter = tree_store.get_iter((i,))
1441 self.assertEqual(tree_store.get_path(aiter), row.path)
1443 self.assertEqual(tree_store.iter_parent(aiter), row.parent)
1445 next = tree_store.iter_next(aiter)
1446 if i < len(tree_store) - 1:
1447 self.assertEqual(tree_store.get_path(next), row.next.path)
1448 self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)),
1449 tree_store.get_path(aiter))
1451 self.assertEqual(next, None)
1453 self.assertEqual(tree_store.iter_n_children(row.iter), 20)
1455 child = tree_store.iter_children(row.iter)
1456 for j, childrow in enumerate(row.iterchildren()):
1457 child_path = tree_store.get_path(child)
1458 self.assertEqual(childrow.path, child_path)
1459 self.assertEqual(childrow.parent.path, row.path)
1460 self.assertEqual(childrow.path, tree_store[child].path)
1461 self.assertEqual(childrow.path, tree_store[child_path].path)
1463 self.assertEqual(childrow[0], tree_store[child][0])
1464 self.assertEqual(childrow[0], j)
1465 self.assertEqual(childrow[1], tree_store[child][1])
1466 self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i))
1468 self.assertRaises(IndexError, get_by_index, child, 2)
1470 tree_store[child][1] = 'this was child #%d of node #%d' % (j, i)
1471 self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i))
1473 nth_child = tree_store.iter_nth_child(row.iter, j)
1474 self.assertEqual(childrow.path, tree_store.get_path(nth_child))
1476 childrow2 = tree_store["%d:%d" % (i, j)]
1477 self.assertEqual(childrow.path, childrow2.path)
1479 childrow2 = tree_store[(i, j,)]
1480 self.assertEqual(childrow.path, childrow2.path)
1482 child = tree_store.iter_next(child)
1484 self.assertEqual(childrow.next.path, tree_store.get_path(child))
1486 self.assertEqual(child, childrow.next)
1487 self.assertEqual(child, None)
1489 self.assertEqual(j, 19)
1491 self.assertEqual(i, 99)
1494 for i in range(-1, -100, -1):
1496 self.assertEqual(tree_store[i][0], i_real)
1499 for j in range(-1, -20, -1):
1501 path = (i_real, j_real,)
1503 self.assertEqual(tree_store[path][-2], j_real)
1505 label = 'this was child #%d of node #%d' % (j_real, i_real)
1506 self.assertEqual(tree_store[path][-1], label)
1508 new_label = 'this still is child #%d of node #%d' % (j_real, i_real)
1509 tree_store[path][-1] = new_label
1510 self.assertEqual(tree_store[path][-1], new_label)
1512 self.assertRaises(IndexError, get_by_index, path, -3)
1514 self.assertRaises(IndexError, get_by_index, -101)
1516 last_row = tree_store[99]
1517 self.assertNotEqual(last_row, None)
1519 for i, childrow in enumerate(last_row.iterchildren()):
1521 self.assertTrue(tree_store.remove(childrow.iter))
1523 self.assertFalse(tree_store.remove(childrow.iter))
1525 self.assertEqual(i, 19)
1527 self.assertEqual(tree_store.iter_n_children(last_row.iter), 0)
1528 for childrow in last_row.iterchildren():
1529 self.fail("Should not be reached")
1531 aiter = tree_store.get_iter(10)
1532 self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a')
1533 self.assertRaises(ValueError, tree_store.get, aiter, 1, -1)
1534 self.assertRaises(ValueError, tree_store.get, aiter, 1, 100)
1535 self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10'))
1538 self.assertEqual(len(tree_store), 100)
1539 aiter = tree_store.get_iter(10)
1540 del tree_store[aiter]
1541 self.assertEqual(len(tree_store), 99)
1542 self.assertRaises(TypeError, tree_store.__delitem__, None)
1543 self.assertRaises(IndexError, tree_store.__delitem__, -101)
1544 self.assertRaises(IndexError, tree_store.__delitem__, 101)
1546 def test_tree_model_get_iter_fail(self):
1547 # TreeModel class with a failing get_iter()
1548 class MyTreeModel(GObject.GObject, Gtk.TreeModel):
1549 def do_get_iter(self, iter):
1550 return (False, None)
1553 self.assertEqual(tm.get_iter_first(), None)
1555 def test_tree_model_edit(self):
1556 model = Gtk.ListStore(int, str, float)
1557 model.append([1, "one", -0.1])
1558 model.append([2, "two", -0.2])
1563 self.assertRaises(TypeError, set_row, 3)
1564 self.assertRaises(TypeError, set_row, "three")
1565 self.assertRaises(ValueError, set_row, [])
1566 self.assertRaises(ValueError, set_row, [3, "three"])
1568 model[0] = (3, "three", -0.3)
1570 def test_tree_row_slice(self):
1571 model = Gtk.ListStore(int, str, float)
1572 model.append([1, "one", -0.1])
1574 self.assertEqual([1, "one", -0.1], model[0][:])
1575 self.assertEqual([1, "one"], model[0][:2])
1576 self.assertEqual(["one", -0.1], model[0][1:])
1577 self.assertEqual(["one"], model[0][1:-1])
1578 self.assertEqual([1], model[0][:-2])
1579 self.assertEqual([], model[0][5:])
1580 self.assertEqual([1, -0.1], model[0][0:3:2])
1582 model[0][:] = (2, "two", -0.2)
1583 self.assertEqual([2, "two", -0.2], model[0][:])
1585 model[0][:2] = (3, "three")
1586 self.assertEqual([3, "three", -0.2], model[0][:])
1588 model[0][1:] = ("four", -0.4)
1589 self.assertEqual([3, "four", -0.4], model[0][:])
1591 model[0][1:-1] = ("five",)
1592 self.assertEqual([3, "five", -0.4], model[0][:])
1594 model[0][0:3:2] = (6, -0.6)
1595 self.assertEqual([6, "five", -0.6], model[0][:])
1598 model[0][5:] = ("doesn't", "matter",)
1600 self.assertRaises(ValueError, set_row1)
1603 model[0][:1] = (0, "zero", 0)
1605 self.assertRaises(ValueError, set_row2)
1608 model[0][:2] = ("0", 0)
1610 self.assertRaises(TypeError, set_row3)
1612 def test_tree_row_sequence(self):
1613 model = Gtk.ListStore(int, str, float)
1614 model.append([1, "one", -0.1])
1616 self.assertEqual([1, "one", -0.1], model[0][0, 1, 2])
1617 self.assertEqual([1, "one"], model[0][0, 1])
1618 self.assertEqual(["one", -0.1], model[0][1, 2])
1619 self.assertEqual("one", model[0][1])
1620 self.assertEqual([1, -0.1], model[0][0, 2])
1621 self.assertEqual([-0.1, 1], model[0][2, 0])
1623 model[0][0, 1, 2] = (2, "two", -0.2)
1624 self.assertEqual([2, "two", -0.2], model[0][0, 1, 2])
1626 model[0][0, 1] = (3, "three")
1627 self.assertEqual([3, "three"], model[0][0, 1])
1629 model[0][1, 2] = ("four", -0.4)
1630 self.assertEqual(["four", -0.4], model[0][1, 2])
1632 model[0][0, 2] = (5, -0.5)
1633 self.assertEqual([5, -0.5], model[0][0, 2])
1635 model[0][0, 1, 2] = (6, "six", -0.6)
1636 self.assertEqual([-0.6, 6, "six"], model[0][2, 0, 1])
1639 model[0][4, 5] = ("shouldn't", "work",)
1641 self.assertRaises(IndexError, set_row1)
1644 model[0][0, 1] = (0, "zero", 0)
1646 self.assertRaises(ValueError, set_row2)
1649 model[0][0, 1] = ("shouldn't", 0)
1651 self.assertRaises(TypeError, set_row3)
1654 model[0][0, "two"] = (0, "zero")
1656 self.assertRaises(TypeError, set_row4)
1658 def test_tree_model_set_value_to_none(self):
1659 # Tests allowing the usage of None to set an empty value on a model.
1660 store = Gtk.ListStore(str)
1661 row = store.append(['test'])
1662 self.assertSequenceEqual(store[0][:], ['test'])
1663 store.set_value(row, 0, None)
1664 self.assertSequenceEqual(store[0][:], [None])
1666 def test_signal_emission_tree_path_coerce(self):
1667 class Model(GObject.Object, Gtk.TreeModel):
1673 def on_any_signal(model, path, *args):
1674 tree_paths.append(path.to_string())
1676 model.connect('row-changed', on_any_signal)
1677 model.connect('row-deleted', on_any_signal)
1678 model.connect('row-has-child-toggled', on_any_signal)
1679 model.connect('row-inserted', on_any_signal)
1681 model.row_changed('0', Gtk.TreeIter())
1682 self.assertEqual(tree_paths[-1], '0')
1684 model.row_deleted('1')
1685 self.assertEqual(tree_paths[-1], '1')
1687 model.row_has_child_toggled('2', Gtk.TreeIter())
1688 self.assertEqual(tree_paths[-1], '2')
1690 model.row_inserted('3', Gtk.TreeIter())
1691 self.assertEqual(tree_paths[-1], '3')
1693 def test_tree_model_filter(self):
1694 model = Gtk.ListStore(int, str, float)
1695 model.append([1, "one", -0.1])
1696 model.append([2, "two", -0.2])
1698 filtered = Gtk.TreeModelFilter(child_model=model)
1700 self.assertEqual(filtered[0][1], 'one')
1701 filtered[0][1] = 'ONE'
1702 self.assertEqual(filtered[0][1], 'ONE')
1704 def test_list_store_performance(self):
1705 model = Gtk.ListStore(int, str)
1708 start = time.clock()
1711 model.append([1, 'hello'])
1714 sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations))
1716 def test_filter_new_default(self):
1717 # Test filter_new accepts implicit default of None
1718 model = Gtk.ListStore(int)
1719 filt = model.filter_new()
1720 self.assertTrue(filt is not None)
1723 @unittest.skipIf(sys.platform == "darwin", "hangs")
1724 @unittest.skipUnless(Gtk, 'Gtk not available')
1725 class TestTreeView(unittest.TestCase):
1726 def test_tree_view(self):
1727 store = Gtk.ListStore(int, str)
1728 store.append((0, "foo"))
1729 store.append((1, "bar"))
1730 view = Gtk.TreeView()
1732 with realized(view):
1733 view.set_cursor(store[1].path)
1734 view.set_cursor(str(store[1].path))
1736 view.get_cell_area(store[1].path)
1737 view.get_cell_area(str(store[1].path))
1739 def test_tree_view_column(self):
1740 cell = Gtk.CellRendererText()
1741 col = Gtk.TreeViewColumn(title='This is just a test',
1746 # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=711173
1747 col.set_cell_data_func(cell, None, None)
1749 def test_tree_view_add_column_with_attributes(self):
1750 model = Gtk.ListStore(str, str, str)
1751 # deliberately use out-of-order sorting here; we assign column 0 to
1752 # model index 2, etc.
1753 model.append(['cell13', 'cell11', 'cell12'])
1754 model.append(['cell23', 'cell21', 'cell22'])
1756 tree = Gtk.TreeView(model=model)
1757 cell1 = Gtk.CellRendererText()
1758 cell2 = Gtk.CellRendererText()
1759 cell3 = Gtk.CellRendererText()
1760 cell4 = Gtk.CellRendererText()
1762 tree.insert_column_with_attributes(0, 'Head2', cell2, text=2)
1763 tree.insert_column_with_attributes(0, 'Head1', cell1, text=1)
1764 tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0)
1766 tree.insert_column_with_attributes(-1, 'Head4', cell4)
1768 with realized(tree):
1769 tree.set_cursor(model[0].path)
1770 while Gtk.events_pending():
1771 Gtk.main_iteration()
1773 self.assertEqual(tree.get_column(0).get_title(), 'Head1')
1774 self.assertEqual(tree.get_column(1).get_title(), 'Head2')
1775 self.assertEqual(tree.get_column(2).get_title(), 'Head3')
1776 self.assertEqual(tree.get_column(3).get_title(), 'Head4')
1778 # cursor should be at the first row
1779 self.assertEqual(cell1.props.text, 'cell11')
1780 self.assertEqual(cell2.props.text, 'cell12')
1781 self.assertEqual(cell3.props.text, 'cell13')
1782 self.assertEqual(cell4.props.text, None)
1784 def test_tree_view_column_set_attributes(self):
1785 store = Gtk.ListStore(int, str)
1786 directors = ['Fellini', 'Tarantino', 'Tarkovskiy']
1787 for i, director in enumerate(directors):
1788 store.append([i, director])
1790 treeview = Gtk.TreeView()
1791 treeview.set_model(store)
1793 column = Gtk.TreeViewColumn()
1794 treeview.append_column(column)
1796 cell = Gtk.CellRendererText()
1797 column.pack_start(cell, expand=True)
1798 column.set_attributes(cell, text=1)
1800 with realized(treeview):
1801 self.assertTrue(cell.props.text in directors)
1803 def test_tree_selection(self):
1804 store = Gtk.ListStore(int, str)
1806 store.append((i, "foo"))
1807 view = Gtk.TreeView()
1808 view.set_model(store)
1809 firstpath = store.get_path(store.get_iter_first())
1810 sel = view.get_selection()
1812 sel.select_path(firstpath)
1813 (m, s) = sel.get_selected()
1814 self.assertEqual(m, store)
1815 self.assertEqual(store.get_path(s), firstpath)
1818 (m, s) = sel.get_selected()
1819 self.assertEqual(m, store)
1820 self.assertEqual(store.get_path(s), firstpath)
1822 sel.select_path("0:0")
1823 (m, s) = sel.get_selected()
1824 self.assertEqual(m, store)
1825 self.assertEqual(store.get_path(s), firstpath)
1827 sel.select_path((0, 0))
1828 (m, s) = sel.get_selected()
1829 self.assertEqual(m, store)
1830 self.assertEqual(store.get_path(s), firstpath)
1833 @unittest.skipUnless(Gtk, 'Gtk not available')
1834 class TestTextBuffer(unittest.TestCase):
1835 def test_text_buffer(self):
1836 self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
1837 buffer = Gtk.TextBuffer()
1838 tag = buffer.create_tag('title', font='Sans 18')
1840 self.assertEqual(tag.props.name, 'title')
1841 self.assertEqual(tag.props.font, 'Sans 18')
1843 (start, end) = buffer.get_bounds()
1845 mark = buffer.create_mark(None, start)
1846 self.assertFalse(mark.get_left_gravity())
1848 buffer.set_text('Hello Jane Hello Bob')
1849 (start, end) = buffer.get_bounds()
1850 text = buffer.get_text(start, end, False)
1851 self.assertEqual(text, 'Hello Jane Hello Bob')
1854 (start, end) = buffer.get_bounds()
1855 text = buffer.get_text(start, end, False)
1856 self.assertEqual(text, '')
1858 buffer.insert(end, 'HelloHello')
1859 buffer.insert(end, ' Bob')
1861 cursor_iter = end.copy()
1862 cursor_iter.backward_chars(9)
1863 buffer.place_cursor(cursor_iter)
1864 buffer.insert_at_cursor(' Jane ')
1866 (start, end) = buffer.get_bounds()
1867 text = buffer.get_text(start, end, False)
1868 self.assertEqual(text, 'Hello Jane Hello Bob')
1870 sel = buffer.get_selection_bounds()
1871 self.assertEqual(sel, ())
1872 buffer.select_range(start, end)
1873 sel = buffer.get_selection_bounds()
1874 self.assertTrue(sel[0].equal(start))
1875 self.assertTrue(sel[1].equal(end))
1878 buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello')
1879 start, end = buffer.get_bounds()
1880 text = buffer.get_text(start, end, False)
1881 self.assertEqual(text, 'HelloHello')
1884 buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello')
1885 start, end = buffer.get_bounds()
1886 text = buffer.get_text(start, end, False)
1887 self.assertEqual(text, 'HelloHello')
1890 starts_tag = Gtk.TextIter.starts_tag
1891 except AttributeError:
1892 starts_tag = Gtk.TextIter.begins_tag
1895 buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag)
1896 (start, end) = buffer.get_bounds()
1897 self.assertTrue(starts_tag(start, tag))
1898 self.assertTrue(start.has_tag(tag))
1901 buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title')
1902 (start, end) = buffer.get_bounds()
1903 self.assertTrue(starts_tag(start, tag))
1904 self.assertTrue(start.has_tag(tag))
1906 self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
1907 buffer.get_start_iter(), 'HelloHello', 'unknowntag')
1909 def test_text_iter(self):
1911 starts_tag = Gtk.TextIter.starts_tag
1912 except AttributeError:
1913 starts_tag = Gtk.TextIter.begins_tag
1915 self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter)
1916 buffer = Gtk.TextBuffer()
1917 buffer.set_text('Hello Jane Hello Bob')
1918 tag = buffer.create_tag('title', font='Sans 18')
1919 (start, end) = buffer.get_bounds()
1920 start.forward_chars(10)
1921 buffer.apply_tag(tag, start, end)
1922 self.assertTrue(starts_tag(start))
1923 self.assertTrue(end.ends_tag())
1924 self.assertTrue(start.toggles_tag())
1925 self.assertTrue(end.toggles_tag())
1926 start.backward_chars(1)
1927 self.assertFalse(starts_tag(start))
1928 self.assertFalse(start.ends_tag())
1929 self.assertFalse(start.toggles_tag())
1931 def test_text_buffer_search(self):
1932 buffer = Gtk.TextBuffer()
1933 buffer.set_text('Hello World Hello GNOME')
1935 i = buffer.get_iter_at_offset(0)
1936 self.assertTrue(isinstance(i, Gtk.TextIter))
1938 self.assertEqual(i.forward_search('world', 0, None), None)
1940 (start, end) = i.forward_search('World', 0, None)
1941 self.assertEqual(start.get_offset(), 6)
1942 self.assertEqual(end.get_offset(), 11)
1944 (start, end) = i.forward_search('world',
1945 Gtk.TextSearchFlags.CASE_INSENSITIVE,
1947 self.assertEqual(start.get_offset(), 6)
1948 self.assertEqual(end.get_offset(), 11)
1950 def test_insert_text_signal_location_modification(self):
1951 # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=736175
1953 def callback(buffer, location, text, length):
1954 location.assign(buffer.get_end_iter())
1956 buffer = Gtk.TextBuffer()
1957 buffer.set_text('first line\n')
1958 buffer.connect('insert-text', callback)
1960 # attempt insertion at the beginning of the buffer, the callback will
1961 # modify the insert location to the end.
1962 buffer.place_cursor(buffer.get_start_iter())
1963 buffer.insert_at_cursor('second line\n')
1965 self.assertEqual(buffer.get_property('text'),
1966 'first line\nsecond line\n')
1968 def test_backward_find_char(self):
1969 buffer = Gtk.TextBuffer()
1970 buffer.set_text('abc')
1971 end = buffer.get_iter_at_line(99)
1975 def pred_func(ch, user_data):
1979 self.assertTrue(end.backward_find_char(pred_func))
1980 self.assertEqual(values, [u"c", u"b", u"a"])
1983 @unittest.skipUnless(Gtk, 'Gtk not available')
1984 class TestContainer(unittest.TestCase):
1986 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
1987 def test_child_set_property(self):
1989 child = Gtk.Button()
1990 box.pack_start(child, expand=False, fill=True, padding=0)
1992 box.child_set_property(child, 'padding', 42)
1994 value = GObject.Value(int)
1995 box.child_get_property(child, 'padding', value)
1996 self.assertEqual(value.get_int(), 42)
1998 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
1999 def test_child_get_property_gvalue(self):
2001 child = Gtk.Button()
2002 box.pack_start(child, expand=False, fill=True, padding=42)
2004 value = GObject.Value(int)
2005 box.child_get_property(child, 'padding', value)
2006 self.assertEqual(value.get_int(), 42)
2008 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
2009 def test_child_get_property_return_with_explicit_gvalue(self):
2011 child = Gtk.Button()
2012 box.pack_start(child, expand=False, fill=True, padding=42)
2014 value = GObject.Value(int)
2015 result = box.child_get_property(child, 'padding', value)
2016 self.assertEqual(result, 42)
2018 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
2019 def test_child_get_property_return_with_implicit_gvalue(self):
2021 child = Gtk.Button()
2022 box.pack_start(child, expand=False, fill=True, padding=42)
2024 result = box.child_get_property(child, 'padding')
2025 self.assertEqual(result, 42)
2027 def test_child_get_property_error(self):
2029 child = Gtk.Button()
2030 if Gtk._version == "4.0":
2031 box.pack_start(child, expand=False, fill=True)
2033 box.pack_start(child, expand=False, fill=True, padding=42)
2034 with self.assertRaises(ValueError):
2035 box.child_get_property(child, 'not-a-valid-child-property')
2037 @unittest.skipIf(Gtk._version == "4.0", "not in gtk4")
2038 def test_child_get_and_set(self):
2040 child = Gtk.Button()
2041 box.pack_start(child, expand=True, fill=True, padding=42)
2043 expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding')
2044 self.assertEqual(expand, True)
2045 self.assertEqual(fill, True)
2046 self.assertEqual(padding, 42)
2048 box.child_set(child, expand=False, fill=False, padding=21, pack_type=1)
2049 expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type')
2050 self.assertEqual(expand, False)
2051 self.assertEqual(fill, False)
2052 self.assertEqual(padding, 21)
2054 @unittest.skipIf(Gtk._version != "4.0", "only in gtk4")
2055 def test_child_get_and_set_gtk4(self):
2056 # padding got removed in gtk4
2058 child = Gtk.Button()
2059 box.pack_start(child, expand=True, fill=True)
2061 expand, fill = box.child_get(child, 'expand', 'fill')
2062 self.assertEqual(expand, True)
2063 self.assertEqual(fill, True)
2065 box.child_set(child, expand=False, fill=False, pack_type=1)
2066 expand, fill, pack_type = box.child_get(child, 'expand', 'fill', 'pack-type')
2067 self.assertEqual(expand, False)
2068 self.assertEqual(fill, False)