1 # -*- Mode: Python; py-indent-offset: 4 -*-
3 # vim: tabstop=4 shiftwidth=4 expandtab
11 from compathelper import _unicode, _bytes
12 from helper import ignore_gi_deprecation_warnings, capture_glib_warnings
17 from gi.repository import GLib, GObject
20 gi.require_version('Gtk', '3.0')
21 gi.require_version('GdkPixbuf', '2.0')
22 from gi.repository import Gtk, GdkPixbuf, Gdk
24 PyGTKDeprecationWarning = Gtk.PyGTKDeprecationWarning
25 except (ValueError, ImportError):
27 PyGTKDeprecationWarning = None
30 @contextlib.contextmanager
32 """Makes sure the widget is realized.
39 if isinstance(widget, Gtk.Window):
42 toplevel = widget.get_parent_window()
49 while Gtk.events_pending():
51 assert widget.get_realized()
58 while Gtk.events_pending():
62 @unittest.skipUnless(Gtk, 'Gtk not available')
63 @ignore_gi_deprecation_warnings
64 class TestGtk(unittest.TestCase):
65 def test_container(self):
67 self.assertTrue(isinstance(box, Gtk.Box))
68 self.assertTrue(isinstance(box, Gtk.Container))
69 self.assertTrue(isinstance(box, Gtk.Widget))
75 self.assertTrue(label in box)
76 self.assertTrue(label2 in box)
77 self.assertEqual(len(box), 2)
80 self.assertEqual(l, [label, label2])
82 def test_actions(self):
83 self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action)
84 action = Gtk.Action(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY)
85 self.assertEqual(action.get_name(), "test")
86 self.assertEqual(action.get_label(), "Test")
87 self.assertEqual(action.get_tooltip(), "Test Action")
88 self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
90 self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction)
91 action = Gtk.RadioAction(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY, value=1)
92 self.assertEqual(action.get_name(), "test")
93 self.assertEqual(action.get_label(), "Test")
94 self.assertEqual(action.get_tooltip(), "Test Action")
95 self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
96 self.assertEqual(action.get_current_value(), 1)
98 def test_actiongroup(self):
99 self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup)
101 action_group = Gtk.ActionGroup(name='TestActionGroup')
102 callback_data = "callback data"
104 def test_action_callback_data(action, user_data):
105 self.assertEqual(user_data, callback_data)
107 def test_radio_action_callback_data(action, current, user_data):
108 self.assertEqual(user_data, callback_data)
110 action_group.add_actions([
111 ('test-action1', None, 'Test Action 1',
112 None, None, test_action_callback_data),
113 ('test-action2', Gtk.STOCK_COPY, 'Test Action 2',
114 None, None, test_action_callback_data)], callback_data)
115 action_group.add_toggle_actions([
116 ('test-toggle-action1', None, 'Test Toggle Action 1',
117 None, None, test_action_callback_data, False),
118 ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2',
119 None, None, test_action_callback_data, True)], callback_data)
120 action_group.add_radio_actions([
121 ('test-radio-action1', None, 'Test Radio Action 1'),
122 ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1,
123 test_radio_action_callback_data,
126 expected_results = [('test-action1', Gtk.Action),
127 ('test-action2', Gtk.Action),
128 ('test-toggle-action1', Gtk.ToggleAction),
129 ('test-toggle-action2', Gtk.ToggleAction),
130 ('test-radio-action1', Gtk.RadioAction),
131 ('test-radio-action2', Gtk.RadioAction)]
133 for action in action_group.list_actions():
134 a = (action.get_name(), type(action))
135 self.assertTrue(a in expected_results)
136 expected_results.remove(a)
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 def test_uimanager_nonascii(self):
160 ui.add_ui_from_string(b'<ui><menubar name="menub\xc3\xa6r1" /></ui>'.decode('UTF-8'))
161 mi = ui.get_widget("/menubær1")
162 self.assertEqual(type(mi), Gtk.MenuBar)
164 def test_window(self):
167 self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL)
169 # type works as keyword argument
170 w = Gtk.Window(type=Gtk.WindowType.POPUP)
171 self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
173 class TestWindow(Gtk.Window):
174 __gtype_name__ = "TestWindow"
177 builder = Gtk.Builder()
178 builder.add_from_string('''
180 <object class="GtkWindow" id="win">
181 <property name="type">popup</property>
183 <object class="TestWindow" id="testwin">
185 <object class="TestWindow" id="testpop">
186 <property name="type">popup</property>
189 self.assertEqual(builder.get_object('win').get_property('type'),
190 Gtk.WindowType.POPUP)
191 self.assertEqual(builder.get_object('testwin').get_property('type'),
192 Gtk.WindowType.TOPLEVEL)
193 self.assertEqual(builder.get_object('testpop').get_property('type'),
194 Gtk.WindowType.POPUP)
196 def test_dialog_classes(self):
197 self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
198 self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
199 self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
200 self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
201 self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
203 def test_dialog_base(self):
204 dialog = Gtk.Dialog(title='Foo', modal=True)
205 self.assertTrue(isinstance(dialog, Gtk.Dialog))
206 self.assertTrue(isinstance(dialog, Gtk.Window))
207 self.assertEqual('Foo', dialog.get_title())
208 self.assertTrue(dialog.get_modal())
210 def test_dialog_deprecations(self):
211 with warnings.catch_warnings(record=True) as warn:
212 warnings.simplefilter('always')
213 dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.MODAL)
214 self.assertTrue(dialog.get_modal())
215 self.assertEqual(len(warn), 1)
216 self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
217 self.assertRegexpMatches(str(warn[0].message),
220 with warnings.catch_warnings(record=True) as warn:
221 warnings.simplefilter('always')
222 dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.DESTROY_WITH_PARENT)
223 self.assertTrue(dialog.get_destroy_with_parent())
224 self.assertEqual(len(warn), 1)
225 self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
226 self.assertRegexpMatches(str(warn[0].message),
227 '.*flags.*destroy_with_parent.*')
229 def test_dialog_deprecation_stacklevels(self):
230 # Test warning levels are setup to give the correct filename for
231 # deprecations in different classes in the inheritance hierarchy.
234 self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
235 with warnings.catch_warnings(record=True) as warn:
236 warnings.simplefilter('always')
237 Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
238 self.assertEqual(len(warn), 1)
239 self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
241 # Validate overridden base with overridden sub-class.
242 self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
243 with warnings.catch_warnings(record=True) as warn:
244 warnings.simplefilter('always')
245 Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL)
246 self.assertEqual(len(warn), 1)
247 self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
249 # Validate overridden base with non-overridden sub-class.
250 self.assertEqual(Gtk.AboutDialog, gi.repository.Gtk.AboutDialog)
251 with warnings.catch_warnings(record=True) as warn:
252 warnings.simplefilter('always')
253 Gtk.AboutDialog(flags=Gtk.DialogFlags.MODAL)
254 self.assertEqual(len(warn), 1)
255 self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
257 def test_dialog_add_buttons(self):
258 # The overloaded "buttons" keyword gives a warning when attempting
259 # to use it for adding buttons as was available in PyGTK.
260 with warnings.catch_warnings(record=True) as warn:
261 warnings.simplefilter('always')
262 dialog = Gtk.Dialog(title='Foo', modal=True,
263 buttons=('test-button1', 1))
264 self.assertEqual(len(warn), 1)
265 self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
266 self.assertRegexpMatches(str(warn[0].message),
267 '.*ButtonsType.*add_buttons.*')
269 dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
270 button = dialog.get_widget_for_response(1)
271 self.assertEqual('test-button1', button.get_label())
272 button = dialog.get_widget_for_response(2)
273 self.assertEqual('test-button2', button.get_label())
274 button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
275 self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
277 def test_about_dialog(self):
278 dialog = Gtk.AboutDialog()
279 self.assertTrue(isinstance(dialog, Gtk.Dialog))
280 self.assertTrue(isinstance(dialog, Gtk.Window))
282 # AboutDialog is not sub-classed in overrides, make sure
283 # the mro still injects the base class "add_buttons" override.
284 self.assertTrue(hasattr(dialog, 'add_buttons'))
286 def test_message_dialog(self):
287 dialog = Gtk.MessageDialog(title='message dialog test',
289 buttons=Gtk.ButtonsType.OK,
291 self.assertTrue(isinstance(dialog, Gtk.Dialog))
292 self.assertTrue(isinstance(dialog, Gtk.Window))
294 self.assertEqual('message dialog test', dialog.get_title())
295 self.assertTrue(dialog.get_modal())
296 text = dialog.get_property('text')
297 self.assertEqual('dude!', text)
299 dialog.format_secondary_text('2nd text')
300 self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
301 self.assertFalse(dialog.get_property('secondary-use-markup'))
303 dialog.format_secondary_markup('2nd markup')
304 self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
305 self.assertTrue(dialog.get_property('secondary-use-markup'))
307 def test_color_selection_dialog(self):
308 dialog = Gtk.ColorSelectionDialog(title="color selection dialog test")
309 self.assertTrue(isinstance(dialog, Gtk.Dialog))
310 self.assertTrue(isinstance(dialog, Gtk.Window))
311 self.assertEqual('color selection dialog test', dialog.get_title())
313 def test_file_chooser_dialog(self):
314 # might cause a GVFS warning, do not break on this
315 with capture_glib_warnings(allow_warnings=True):
316 dialog = Gtk.FileChooserDialog(title='file chooser dialog test',
317 action=Gtk.FileChooserAction.SAVE)
319 self.assertTrue(isinstance(dialog, Gtk.Dialog))
320 self.assertTrue(isinstance(dialog, Gtk.Window))
321 self.assertEqual('file chooser dialog test', dialog.get_title())
323 action = dialog.get_property('action')
324 self.assertEqual(Gtk.FileChooserAction.SAVE, action)
326 def test_file_chooser_dialog_default_action(self):
327 # might cause a GVFS warning, do not break on this
328 with capture_glib_warnings(allow_warnings=True):
329 dialog = Gtk.FileChooserDialog(title='file chooser dialog test')
331 action = dialog.get_property('action')
332 self.assertEqual(Gtk.FileChooserAction.OPEN, action)
334 def test_font_selection_dialog(self):
335 dialog = Gtk.FontSelectionDialog(title="font selection dialog test")
336 self.assertTrue(isinstance(dialog, Gtk.Dialog))
337 self.assertTrue(isinstance(dialog, Gtk.Window))
338 self.assertEqual('font selection dialog test', dialog.get_title())
340 def test_recent_chooser_dialog(self):
341 test_manager = Gtk.RecentManager()
342 dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test',
343 recent_manager=test_manager)
344 self.assertTrue(isinstance(dialog, Gtk.Dialog))
345 self.assertTrue(isinstance(dialog, Gtk.Window))
346 self.assertEqual('recent chooser dialog test', dialog.get_title())
348 class TestClass(GObject.GObject):
349 __gtype_name__ = "GIOverrideTreeAPITest"
351 def __init__(self, tester, int_value, string_value):
352 super(TestGtk.TestClass, self).__init__()
354 self.int_value = int_value
355 self.string_value = string_value
357 def check(self, int_value, string_value):
358 self.tester.assertEqual(int_value, self.int_value)
359 self.tester.assertEqual(string_value, self.string_value)
361 def test_buttons(self):
362 self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
365 button = Gtk.Button()
366 self.assertTrue(isinstance(button, Gtk.Button))
367 self.assertTrue(isinstance(button, Gtk.Container))
368 self.assertTrue(isinstance(button, Gtk.Widget))
370 # Using stock items causes hard warning in devel versions of GTK+.
371 with capture_glib_warnings(allow_warnings=True):
372 button = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE)
374 self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
375 self.assertTrue(button.get_use_stock())
376 self.assertTrue(button.get_use_underline())
378 # test Gtk.Button use_stock
379 button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True, use_underline=True)
380 self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
381 self.assertTrue(button.get_use_stock())
382 self.assertTrue(button.get_use_underline())
384 # test Gtk.LinkButton
385 button = Gtk.LinkButton(uri='http://www.Gtk.org', label='Gtk')
386 self.assertTrue(isinstance(button, Gtk.Button))
387 self.assertTrue(isinstance(button, Gtk.Container))
388 self.assertTrue(isinstance(button, Gtk.Widget))
389 self.assertEqual('http://www.Gtk.org', button.get_uri())
390 self.assertEqual('Gtk', button.get_label())
392 def test_inheritance(self):
393 for name in gi.overrides.Gtk.__all__:
394 over = getattr(gi.overrides.Gtk, name)
395 for element in dir(Gtk):
397 klass = getattr(Gtk, element)
398 info = klass.__info__
399 except (NotImplementedError, AttributeError):
402 # Get all parent classes and interfaces klass inherits from
403 if isinstance(info, gi.types.ObjectInfo):
404 classes = list(info.get_interfaces())
405 parent = info.get_parent()
406 while parent.get_name() != "Object":
407 classes.append(parent)
408 parent = parent.get_parent()
409 classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
414 if kl.get_name() == name:
415 self.assertTrue(issubclass(klass, over,),
416 "%r does not inherit from override %r" % (klass, over,))
418 def test_editable(self):
419 self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable)
421 # need to use Gtk.Entry because Editable is an interface
423 pos = entry.insert_text('HeWorld', 0)
424 self.assertEqual(pos, 7)
425 pos = entry.insert_text('llo ', 2)
426 self.assertEqual(pos, 6)
427 text = entry.get_chars(0, 11)
428 self.assertEqual('Hello World', text)
430 def test_label(self):
431 label = Gtk.Label(label='Hello')
432 self.assertTrue(isinstance(label, Gtk.Widget))
433 self.assertEqual(label.get_text(), 'Hello')
435 def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0,
436 step_increment=0.0, page_increment=0.0, page_size=0.0):
437 self.assertEqual(adjustment.get_value(), value)
438 self.assertEqual(adjustment.get_lower(), lower)
439 self.assertEqual(adjustment.get_upper(), upper)
440 self.assertEqual(adjustment.get_step_increment(), step_increment)
441 self.assertEqual(adjustment.get_page_increment(), page_increment)
442 self.assertEqual(adjustment.get_page_size(), page_size)
444 def test_adjustment(self):
445 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
446 self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
448 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5)
449 self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5)
451 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4)
452 self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4)
454 adjustment = Gtk.Adjustment(value=1, lower=0, upper=6)
455 self.adjustment_check(adjustment, value=1, lower=0, upper=6)
457 adjustment = Gtk.Adjustment()
458 self.adjustment_check(adjustment)
460 def test_table(self):
462 self.assertTrue(isinstance(table, Gtk.Table))
463 self.assertTrue(isinstance(table, Gtk.Container))
464 self.assertTrue(isinstance(table, Gtk.Widget))
465 self.assertEqual(table.get_size(), (1, 1))
466 self.assertEqual(table.get_homogeneous(), False)
468 table = Gtk.Table(n_rows=2, n_columns=3)
469 self.assertEqual(table.get_size(), (2, 3))
470 self.assertEqual(table.get_homogeneous(), False)
472 table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True)
473 self.assertEqual(table.get_size(), (2, 3))
474 self.assertEqual(table.get_homogeneous(), True)
476 label = Gtk.Label(label='Hello')
477 self.assertTrue(isinstance(label, Gtk.Widget))
478 table.attach(label, 0, 1, 0, 1)
479 self.assertEqual(label, table.get_children()[0])
481 def test_scrolledwindow(self):
482 sw = Gtk.ScrolledWindow()
483 self.assertTrue(isinstance(sw, Gtk.ScrolledWindow))
484 self.assertTrue(isinstance(sw, Gtk.Container))
485 self.assertTrue(isinstance(sw, Gtk.Widget))
486 sb = sw.get_hscrollbar()
487 self.assertEqual(sw.get_hadjustment(), sb.get_adjustment())
488 sb = sw.get_vscrollbar()
489 self.assertEqual(sw.get_vadjustment(), sb.get_adjustment())
491 def test_widget_drag_methods(self):
492 widget = Gtk.Button()
494 # here we are not checking functionality, only that the methods exist
495 # and except the right number of arguments
497 widget.drag_check_threshold(0, 0, 0, 0)
500 widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
501 widget.drag_dest_add_image_targets()
502 widget.drag_dest_add_text_targets()
503 widget.drag_dest_add_uri_targets()
504 widget.drag_dest_get_track_motion()
505 widget.drag_dest_set_track_motion(True)
506 widget.drag_dest_get_target_list()
507 widget.drag_dest_set_target_list(None)
508 widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
509 widget.drag_dest_unset()
511 widget.drag_highlight()
512 widget.drag_unhighlight()
514 # drag_source_ methods
515 widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
516 widget.drag_source_add_image_targets()
517 widget.drag_source_add_text_targets()
518 widget.drag_source_add_uri_targets()
519 widget.drag_source_set_icon_name("_About")
520 widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf())
521 widget.drag_source_set_icon_stock(Gtk.STOCK_ABOUT)
522 widget.drag_source_get_target_list()
523 widget.drag_source_set_target_list(None)
524 widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
525 widget.drag_source_unset()
527 # these methods cannot be called because they require a valid drag on
528 # a real GdkWindow. So we only check that they exist and are callable.
529 self.assertTrue(hasattr(widget, 'drag_dest_set_proxy'))
530 self.assertTrue(hasattr(widget, 'drag_get_data'))
532 def test_drag_target_list(self):
533 mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0),
535 Gtk.TargetEntry.new('test2', 2, 2),
538 def _test_target_list(targets):
539 for i, target in enumerate(targets):
540 self.assertTrue(isinstance(target, Gtk.TargetEntry))
541 self.assertEqual(target.target, 'test' + str(i))
542 self.assertEqual(target.flags, i)
543 self.assertEqual(target.info, i)
545 _test_target_list(Gtk._construct_target_list(mixed_target_list))
547 widget = Gtk.Button()
548 widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
549 widget.drag_dest_set_target_list(mixed_target_list)
550 widget.drag_dest_get_target_list()
552 widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
553 widget.drag_source_set_target_list(mixed_target_list)
554 widget.drag_source_get_target_list()
556 treeview = Gtk.TreeView()
557 treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
559 Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
561 treeview.enable_model_drag_dest(mixed_target_list,
562 Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
564 def test_scrollbar(self):
565 adjustment = Gtk.Adjustment()
567 hscrollbar = Gtk.HScrollbar()
568 vscrollbar = Gtk.VScrollbar()
569 self.assertNotEqual(hscrollbar.props.adjustment, adjustment)
570 self.assertNotEqual(vscrollbar.props.adjustment, adjustment)
572 hscrollbar = Gtk.HScrollbar(adjustment=adjustment)
573 vscrollbar = Gtk.VScrollbar(adjustment=adjustment)
574 self.assertEqual(hscrollbar.props.adjustment, adjustment)
575 self.assertEqual(vscrollbar.props.adjustment, adjustment)
577 def test_iconview(self):
579 iconview = Gtk.IconView()
580 self.assertEqual(iconview.props.model, None)
582 model = Gtk.ListStore(str)
583 iconview = Gtk.IconView(model=model)
584 self.assertEqual(iconview.props.model, model)
586 def test_toolbutton(self):
589 # Using stock items causes hard warning in devel versions of GTK+.
590 with capture_glib_warnings(allow_warnings=True):
591 button = Gtk.ToolButton()
592 self.assertEqual(button.props.stock_id, None)
594 button = Gtk.ToolButton(stock_id='gtk-new')
595 self.assertEqual(button.props.stock_id, 'gtk-new')
597 icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
598 button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
599 self.assertEqual(button.props.label, 'mylabel')
600 self.assertEqual(button.props.icon_widget, icon)
602 def test_iconset(self):
604 pixbuf = GdkPixbuf.Pixbuf()
605 Gtk.IconSet.new_from_pixbuf(pixbuf)
607 def test_viewport(self):
608 vadjustment = Gtk.Adjustment()
609 hadjustment = Gtk.Adjustment()
611 viewport = Gtk.Viewport(hadjustment=hadjustment,
612 vadjustment=vadjustment)
614 self.assertEqual(viewport.props.vadjustment, vadjustment)
615 self.assertEqual(viewport.props.hadjustment, hadjustment)
617 def test_stock_lookup(self):
618 l = Gtk.stock_lookup('gtk-ok')
619 self.assertEqual(type(l), Gtk.StockItem)
620 self.assertEqual(l.stock_id, 'gtk-ok')
621 self.assertEqual(Gtk.stock_lookup('nosuchthing'), None)
623 def test_gtk_main(self):
625 GLib.timeout_add(100, Gtk.main_quit)
628 # overridden function ignores its arguments
629 GLib.timeout_add(100, Gtk.main_quit, 'hello')
632 def test_widget_render_icon(self):
633 button = Gtk.Button(label='OK')
634 pixbuf = button.render_icon(Gtk.STOCK_OK, Gtk.IconSize.BUTTON)
635 self.assertTrue(pixbuf is not None)
638 @unittest.skipUnless(Gtk, 'Gtk not available')
639 class TestWidget(unittest.TestCase):
640 def test_style_get_property_gvalue(self):
641 button = Gtk.Button()
642 value = GObject.Value(int, -42)
643 button.style_get_property('focus-padding', value)
644 # Test only that the style property changed since we can't actuall
646 self.assertNotEqual(value.get_int(), -42)
648 def test_style_get_property_return_with_explicit_gvalue(self):
649 button = Gtk.Button()
650 value = GObject.Value(int, -42)
651 result = button.style_get_property('focus-padding', value)
652 self.assertIsInstance(result, int)
653 self.assertNotEqual(result, -42)
655 def test_style_get_property_return_with_implicit_gvalue(self):
656 button = Gtk.Button()
657 result = button.style_get_property('focus-padding')
658 self.assertIsInstance(result, int)
659 self.assertNotEqual(result, -42)
661 def test_style_get_property_error(self):
662 button = Gtk.Button()
663 with self.assertRaises(ValueError):
664 button.style_get_property('not-a-valid-style-property')
667 @unittest.skipUnless(Gtk, 'Gtk not available')
668 class TestSignals(unittest.TestCase):
669 def test_class_closure_override_with_aliased_type(self):
670 class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
671 __gsignals__ = {'size-allocate': 'override'}
674 Gtk.ScrolledWindow.__init__(self)
675 self._alloc_called = False
676 self._alloc_value = None
677 self._alloc_error = None
679 def do_size_allocate(self, alloc):
680 self._alloc_called = True
681 self._alloc_value = alloc
684 Gtk.ScrolledWindow.do_size_allocate(self, alloc)
685 except Exception as e:
686 self._alloc_error = e
688 win = WindowWithSizeAllocOverride()
689 rect = Gdk.Rectangle()
695 win.get_preferred_size()
696 win.size_allocate(rect)
697 self.assertTrue(win._alloc_called)
698 self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
699 self.assertTrue(win._alloc_error is None, win._alloc_error)
701 @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=735693
702 def test_overlay_child_position(self):
703 def get_child_position(overlay, widget, rect, user_data=None):
710 overlay = Gtk.Overlay()
711 overlay.connect('get-child-position', get_child_position)
713 rect = Gdk.Rectangle()
719 overlay.emit('get-child-position', None, rect)
720 self.assertEqual(rect.x, 1)
721 self.assertEqual(rect.y, 2)
722 self.assertEqual(rect.width, 3)
723 self.assertEqual(rect.height, 4)
726 @unittest.skipUnless(Gtk, 'Gtk not available')
727 class TestBuilder(unittest.TestCase):
728 class SignalTest(GObject.GObject):
729 __gtype_name__ = "GIOverrideSignalTest"
731 "test-signal": (GObject.SignalFlags.RUN_FIRST,
736 def test_extract_handler_and_args_object(self):
741 obj.foo = lambda: None
743 handler, args = Gtk._extract_handler_and_args(obj, 'foo')
744 self.assertEqual(handler, obj.foo)
745 self.assertEqual(len(args), 0)
747 def test_extract_handler_and_args_dict(self):
748 obj = {'foo': lambda: None}
750 handler, args = Gtk._extract_handler_and_args(obj, 'foo')
751 self.assertEqual(handler, obj['foo'])
752 self.assertEqual(len(args), 0)
754 def test_extract_handler_and_args_with_seq(self):
755 obj = {'foo': (lambda: None, 1, 2)}
757 handler, args = Gtk._extract_handler_and_args(obj, 'foo')
758 self.assertEqual(handler, obj['foo'][0])
759 self.assertSequenceEqual(args, [1, 2])
761 def test_extract_handler_and_args_no_handler_error(self):
762 obj = dict(foo=lambda: None)
763 self.assertRaises(AttributeError,
764 Gtk._extract_handler_and_args,
765 obj, 'not_a_handler')
767 def test_builder_with_handler_and_args(self):
768 builder = Gtk.Builder()
769 builder.add_from_string("""
771 <object class="GIOverrideSignalTest" id="object_sig_test">
772 <signal name="test-signal" handler="on_signal1" />
773 <signal name="test-signal" handler="on_signal2" after="yes" />
780 def on_signal(*args):
781 args_collector.append(args)
783 builder.connect_signals({'on_signal1': (on_signal, 1, 2),
784 'on_signal2': on_signal})
786 objects = builder.get_objects()
787 self.assertEqual(len(objects), 1)
789 obj.emit('test-signal')
791 self.assertEqual(len(args_collector), 2)
792 self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
793 self.assertSequenceEqual(args_collector[1], (obj, ))
795 def test_builder(self):
796 self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
801 self.after_sentinel = 0
803 def on_signal_1(self, *args):
805 self.after_sentinel += 1
807 def on_signal_3(self, *args):
810 def on_signal_after(self, *args):
811 if self.after_sentinel == 1:
812 self.after_sentinel += 1
814 signal_checker = SignalCheck()
815 builder = Gtk.Builder()
817 # add object1 to the builder
818 builder.add_from_string("""
820 <object class="GIOverrideSignalTest" id="object1">
821 <signal name="test-signal" after="yes" handler="on_signal_after" />
822 <signal name="test-signal" handler="on_signal_1" />
827 # only add object3 to the builder
828 builder.add_objects_from_string("""
830 <object class="GIOverrideSignalTest" id="object2">
831 <signal name="test-signal" handler="on_signal_2" />
833 <object class="GIOverrideSignalTest" id="object3">
834 <signal name="test-signal" handler="on_signal_3" />
836 <object class="GIOverrideSignalTest" id="object4">
837 <signal name="test-signal" handler="on_signal_4" />
843 builder.connect_signals(signal_checker)
845 # call their notify signals and check sentinel
846 objects = builder.get_objects()
847 self.assertEqual(len(objects), 2)
849 obj.emit('test-signal')
851 self.assertEqual(signal_checker.sentinel, 4)
852 self.assertEqual(signal_checker.after_sentinel, 2)
855 @ignore_gi_deprecation_warnings
856 @unittest.skipUnless(Gtk, 'Gtk not available')
857 class TestTreeModel(unittest.TestCase):
858 def test_tree_model_sort(self):
859 self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
860 model = Gtk.TreeStore(int, bool)
861 model_sort = Gtk.TreeModelSort(model=model)
862 self.assertEqual(model_sort.get_model(), model)
864 def test_tree_store(self):
865 self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore)
866 self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore)
867 self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel)
868 self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn)
870 class TestPyObject(object):
873 test_pyobj = TestPyObject()
874 test_pydict = {1: 1, "2": 2, "3": "3"}
875 test_pylist = [1, "2", "3"]
876 tree_store = Gtk.TreeStore(int,
879 GObject.TYPE_PYOBJECT,
894 label = 'this is child #%d' % i
895 testobj = TestGtk.TestClass(self, i, label)
896 parent = tree_store.append(parent, (i,
913 parent = tree_store.append(parent)
915 label = 'this is child #%d' % i
916 testobj = TestGtk.TestClass(self, i, label)
917 tree_store.set(parent,
930 12, 0xffffffffffffffff,
934 parent = tree_store.append(parent)
936 label = 'this is child #%d' % i
937 testobj = TestGtk.TestClass(self, i, label)
938 tree_store.set(parent, {0: i,
950 12: 0xffffffffffffffff,
954 parent = tree_store.append(parent)
956 label = 'this is child #%d' % i
957 testobj = TestGtk.TestClass(self, i, label)
958 tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
975 # len gets the number of children in the root node
976 # since we kept appending to the previous node
977 # there should only be one child of the root
978 self.assertEqual(len(tree_store), 1)
980 # walk the tree to see if the values were stored correctly
984 treeiter = tree_store.iter_children(parent)
986 i = tree_store.get_value(treeiter, 0)
987 s = tree_store.get_value(treeiter, 1)
988 obj = tree_store.get_value(treeiter, 2)
990 obj2 = tree_store.get_value(treeiter, 3)
991 self.assertEqual(obj, obj2)
993 pyobj = tree_store.get_value(treeiter, 4)
994 self.assertEqual(pyobj, test_pyobj)
995 pydict = tree_store.get_value(treeiter, 5)
996 self.assertEqual(pydict, test_pydict)
997 pylist = tree_store.get_value(treeiter, 6)
998 self.assertEqual(pylist, test_pylist)
1000 bool_1 = tree_store.get_value(treeiter, 7)
1001 bool_2 = tree_store.get_value(treeiter, 8)
1002 self.assertEqual(bool_1, bool_2)
1003 self.assertTrue(isinstance(bool_1, bool))
1004 self.assertTrue(isinstance(bool_2, bool))
1006 uint_ = tree_store.get_value(treeiter, 9)
1007 self.assertEqual(uint_, i)
1008 ulong_ = tree_store.get_value(treeiter, 10)
1009 self.assertEqual(ulong_, GLib.MAXULONG)
1010 int64_ = tree_store.get_value(treeiter, 11)
1011 self.assertEqual(int64_, GLib.MININT64)
1012 uint64_ = tree_store.get_value(treeiter, 12)
1013 self.assertEqual(uint64_, 0xffffffffffffffff)
1014 uchar_ = tree_store.get_value(treeiter, 13)
1015 self.assertEqual(ord(uchar_), 254)
1016 char_ = tree_store.get_value(treeiter, 14)
1017 self.assertEqual(char_, 'a')
1020 treeiter = tree_store.iter_children(parent)
1022 self.assertEqual(i, 99)
1024 def test_tree_store_signals(self):
1025 tree_store = Gtk.TreeStore(int, bool)
1027 def on_row_inserted(tree_store, tree_path, tree_iter, signal_list):
1028 signal_list.append('row-inserted')
1030 def on_row_changed(tree_store, tree_path, tree_iter, signal_list):
1031 signal_list.append('row-changed')
1034 tree_store.connect('row-inserted', on_row_inserted, signals)
1035 tree_store.connect('row-changed', on_row_changed, signals)
1037 # adding rows with and without data should only call one signal
1038 tree_store.append(None, (0, False))
1039 self.assertEqual(signals, ['row-inserted'])
1042 tree_store.append(None)
1043 self.assertEqual(signals, ['row-inserted'])
1046 tree_store.prepend(None, (0, False))
1047 self.assertEqual(signals, ['row-inserted'])
1050 tree_store.prepend(None)
1051 self.assertEqual(signals, ['row-inserted'])
1054 tree_store.insert(None, 1, (0, False))
1055 self.assertEqual(signals, ['row-inserted'])
1058 tree_store.insert(None, 1)
1059 self.assertEqual(signals, ['row-inserted'])
1061 def test_list_store(self):
1062 class TestPyObject(object):
1065 test_pyobj = TestPyObject()
1066 test_pydict = {1: 1, "2": 2, "3": "3"}
1067 test_pylist = [1, "2", "3"]
1069 list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool)
1070 for i in range(1, 93):
1071 label = 'this is row #%d' % i
1072 testobj = TestGtk.TestClass(self, i, label)
1073 list_store.append((i,
1083 label = _unicode('this is row #93')
1084 treeiter = list_store.append()
1085 list_store.set_value(treeiter, 0, i)
1086 list_store.set_value(treeiter, 1, label)
1087 list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
1088 list_store.set_value(treeiter, 3, test_pyobj)
1089 list_store.set_value(treeiter, 4, test_pydict)
1090 list_store.set_value(treeiter, 5, test_pylist)
1091 list_store.set_value(treeiter, 6, 1)
1092 list_store.set_value(treeiter, 7, True)
1095 label = 'this is row #0'
1096 list_store.prepend((0,
1098 TestGtk.TestClass(self, 0, label),
1105 # test automatic unicode->str conversion
1107 label = _unicode('this is row #94')
1108 treeiter = list_store.append((i,
1110 TestGtk.TestClass(self, i, label),
1117 # add sorted items out of order to test insert* apis
1118 # also test sending in None to not set a column
1120 label = 'this is row #97'
1121 treeiter = list_store.append((None,
1130 list_store.set_value(treeiter, 0, i)
1131 list_store.set_value(treeiter, 1, label)
1132 list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
1133 list_store.set_value(treeiter, 4, test_pydict)
1134 list_store.set_value(treeiter, 7, True)
1136 # this should append
1138 label = 'this is row #99'
1139 list_store.insert(9999, (i,
1141 TestGtk.TestClass(self, i, label),
1149 label = 'this is row #96'
1150 list_store.insert_before(treeiter, (i,
1152 TestGtk.TestClass(self, i, label),
1160 label = 'this is row #98'
1161 list_store.insert_after(treeiter, (i,
1163 TestGtk.TestClass(self, i, label),
1171 label = 'this is row #95'
1172 list_store.insert(95, (i,
1174 TestGtk.TestClass(self, i, label),
1182 label = 'this is row #100'
1183 treeiter = list_store.append()
1184 list_store.set(treeiter,
1187 2, TestGtk.TestClass(self, i, label),
1194 label = 'this is row #101'
1195 treeiter = list_store.append()
1196 list_store.set(treeiter, {1: label,
1198 2: TestGtk.TestClass(self, i, label),
1205 label = 'this is row #102'
1206 treeiter = list_store.append()
1207 list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7),
1210 TestGtk.TestClass(self, i, label),
1217 self.assertEqual(len(list_store), 103)
1219 # walk the list to see if the values were stored correctly
1221 treeiter = list_store.get_iter_first()
1225 i = list_store.get_value(treeiter, 0)
1226 self.assertEqual(i, counter)
1227 s = list_store.get_value(treeiter, 1)
1228 obj = list_store.get_value(treeiter, 2)
1231 pyobj = list_store.get_value(treeiter, 3)
1232 self.assertEqual(pyobj, test_pyobj)
1233 pydict = list_store.get_value(treeiter, 4)
1234 self.assertEqual(pydict, test_pydict)
1235 pylist = list_store.get_value(treeiter, 5)
1236 self.assertEqual(pylist, test_pylist)
1238 bool_1 = list_store.get_value(treeiter, 6)
1239 bool_2 = list_store.get_value(treeiter, 7)
1240 self.assertEqual(bool_1, bool_2)
1241 self.assertTrue(isinstance(bool_1, bool))
1242 self.assertTrue(isinstance(bool_2, bool))
1244 treeiter = list_store.iter_next(treeiter)
1248 self.assertEqual(i, 102)
1250 def test_list_store_sort(self):
1251 def comp1(model, row1, row2, user_data):
1255 # make "m" smaller than anything else
1256 if v1.startswith('m') and not v2.startswith('m'):
1258 if v2.startswith('m') and not v1.startswith('m'):
1260 return (v1 > v2) - (v1 < v2)
1262 list_store = Gtk.ListStore(int, str)
1263 list_store.set_sort_func(2, comp1, None)
1264 list_store.append((1, 'apples'))
1265 list_store.append((3, 'oranges'))
1266 list_store.append((2, 'mango'))
1268 # not sorted yet, should be original order
1269 self.assertEqual([list(i) for i in list_store],
1270 [[1, 'apples'], [3, 'oranges'], [2, 'mango']])
1272 # sort with our custom function
1273 list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING)
1274 self.assertEqual([list(i) for i in list_store],
1275 [[2, 'mango'], [1, 'apples'], [3, 'oranges']])
1277 list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING)
1278 self.assertEqual([list(i) for i in list_store],
1279 [[3, 'oranges'], [1, 'apples'], [2, 'mango']])
1281 def test_list_store_signals(self):
1282 list_store = Gtk.ListStore(int, bool)
1284 def on_row_inserted(list_store, tree_path, tree_iter, signal_list):
1285 signal_list.append('row-inserted')
1287 def on_row_changed(list_store, tree_path, tree_iter, signal_list):
1288 signal_list.append('row-changed')
1291 list_store.connect('row-inserted', on_row_inserted, signals)
1292 list_store.connect('row-changed', on_row_changed, signals)
1294 # adding rows with and without data should only call one signal
1295 list_store.append((0, False))
1296 self.assertEqual(signals, ['row-inserted'])
1300 self.assertEqual(signals, ['row-inserted'])
1303 list_store.prepend((0, False))
1304 self.assertEqual(signals, ['row-inserted'])
1307 list_store.prepend()
1308 self.assertEqual(signals, ['row-inserted'])
1311 list_store.insert(1, (0, False))
1312 self.assertEqual(signals, ['row-inserted'])
1315 list_store.insert(1)
1316 self.assertEqual(signals, ['row-inserted'])
1318 def test_tree_path(self):
1320 p2 = Gtk.TreePath.new_first()
1321 self.assertEqual(p1, p2)
1322 self.assertEqual(str(p1), '0')
1323 self.assertEqual(len(p1), 1)
1324 p1 = Gtk.TreePath(2)
1325 p2 = Gtk.TreePath.new_from_string('2')
1326 self.assertEqual(p1, p2)
1327 self.assertEqual(str(p1), '2')
1328 self.assertEqual(len(p1), 1)
1329 p1 = Gtk.TreePath('1:2:3')
1330 p2 = Gtk.TreePath.new_from_string('1:2:3')
1331 self.assertEqual(p1, p2)
1332 self.assertEqual(str(p1), '1:2:3')
1333 self.assertEqual(len(p1), 3)
1334 p1 = Gtk.TreePath((1, 2, 3))
1335 p2 = Gtk.TreePath.new_from_string('1:2:3')
1336 self.assertEqual(p1, p2)
1337 self.assertEqual(str(p1), '1:2:3')
1338 self.assertEqual(len(p1), 3)
1339 self.assertNotEqual(p1, None)
1340 self.assertTrue(p1 > None)
1341 self.assertTrue(p1 >= None)
1342 self.assertFalse(p1 < None)
1343 self.assertFalse(p1 <= None)
1345 self.assertEqual(tuple(p1), (1, 2, 3))
1346 self.assertEqual(p1[0], 1)
1347 self.assertEqual(p1[1], 2)
1348 self.assertEqual(p1[2], 3)
1349 self.assertRaises(IndexError, p1.__getitem__, 3)
1351 def test_tree_model(self):
1352 tree_store = Gtk.TreeStore(int, str)
1354 self.assertTrue(tree_store)
1355 self.assertEqual(len(tree_store), 0)
1356 self.assertEqual(tree_store.get_iter_first(), None)
1358 def get_by_index(row, col=None):
1360 return tree_store[row][col]
1362 return tree_store[row]
1364 self.assertRaises(TypeError, get_by_index, None)
1365 self.assertRaises(TypeError, get_by_index, "")
1366 self.assertRaises(TypeError, get_by_index, ())
1368 self.assertRaises(IndexError, get_by_index, "0")
1369 self.assertRaises(IndexError, get_by_index, 0)
1370 self.assertRaises(IndexError, get_by_index, (0,))
1372 self.assertRaises(ValueError, tree_store.get_iter, "0")
1373 self.assertRaises(ValueError, tree_store.get_iter, 0)
1374 self.assertRaises(ValueError, tree_store.get_iter, (0,))
1376 self.assertRaises(ValueError, tree_store.get_iter_from_string, "0")
1378 for row in tree_store:
1379 self.fail("Should not be reached")
1381 class DerivedIntType(int):
1384 class DerivedStrType(str):
1387 for i in range(100):
1388 label = 'this is row #%d' % i
1389 parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),))
1390 self.assertNotEqual(parent, None)
1392 label = 'this is child #%d of node #%d' % (j, i)
1393 child = tree_store.append(parent, (j, label,))
1394 self.assertNotEqual(child, None)
1396 self.assertTrue(tree_store)
1397 self.assertEqual(len(tree_store), 100)
1399 self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None)
1401 for i, row in enumerate(tree_store):
1402 self.assertEqual(row.model, tree_store)
1403 self.assertEqual(row.parent, None)
1405 self.assertEqual(tree_store[i].path, row.path)
1406 self.assertEqual(tree_store[str(i)].path, row.path)
1407 self.assertEqual(tree_store[(i,)].path, row.path)
1409 self.assertEqual(tree_store[i][0], i)
1410 self.assertEqual(tree_store[i][1], "this is row #%d" % i)
1412 aiter = tree_store.get_iter(i)
1413 self.assertEqual(tree_store.get_path(aiter), row.path)
1415 aiter = tree_store.get_iter(str(i))
1416 self.assertEqual(tree_store.get_path(aiter), row.path)
1418 aiter = tree_store.get_iter((i,))
1419 self.assertEqual(tree_store.get_path(aiter), row.path)
1421 self.assertEqual(tree_store.iter_parent(aiter), row.parent)
1423 next = tree_store.iter_next(aiter)
1424 if i < len(tree_store) - 1:
1425 self.assertEqual(tree_store.get_path(next), row.next.path)
1426 self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)),
1427 tree_store.get_path(aiter))
1429 self.assertEqual(next, None)
1431 self.assertEqual(tree_store.iter_n_children(row.iter), 20)
1433 child = tree_store.iter_children(row.iter)
1434 for j, childrow in enumerate(row.iterchildren()):
1435 child_path = tree_store.get_path(child)
1436 self.assertEqual(childrow.path, child_path)
1437 self.assertEqual(childrow.parent.path, row.path)
1438 self.assertEqual(childrow.path, tree_store[child].path)
1439 self.assertEqual(childrow.path, tree_store[child_path].path)
1441 self.assertEqual(childrow[0], tree_store[child][0])
1442 self.assertEqual(childrow[0], j)
1443 self.assertEqual(childrow[1], tree_store[child][1])
1444 self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i))
1446 self.assertRaises(IndexError, get_by_index, child, 2)
1448 tree_store[child][1] = 'this was child #%d of node #%d' % (j, i)
1449 self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i))
1451 nth_child = tree_store.iter_nth_child(row.iter, j)
1452 self.assertEqual(childrow.path, tree_store.get_path(nth_child))
1454 childrow2 = tree_store["%d:%d" % (i, j)]
1455 self.assertEqual(childrow.path, childrow2.path)
1457 childrow2 = tree_store[(i, j,)]
1458 self.assertEqual(childrow.path, childrow2.path)
1460 child = tree_store.iter_next(child)
1462 self.assertEqual(childrow.next.path, tree_store.get_path(child))
1464 self.assertEqual(child, childrow.next)
1465 self.assertEqual(child, None)
1467 self.assertEqual(j, 19)
1469 self.assertEqual(i, 99)
1472 for i in range(-1, -100, -1):
1474 self.assertEqual(tree_store[i][0], i_real)
1477 for j in range(-1, -20, -1):
1479 path = (i_real, j_real,)
1481 self.assertEqual(tree_store[path][-2], j_real)
1483 label = 'this was child #%d of node #%d' % (j_real, i_real)
1484 self.assertEqual(tree_store[path][-1], label)
1486 new_label = 'this still is child #%d of node #%d' % (j_real, i_real)
1487 tree_store[path][-1] = new_label
1488 self.assertEqual(tree_store[path][-1], new_label)
1490 self.assertRaises(IndexError, get_by_index, path, -3)
1492 self.assertRaises(IndexError, get_by_index, -101)
1494 last_row = tree_store[99]
1495 self.assertNotEqual(last_row, None)
1497 for i, childrow in enumerate(last_row.iterchildren()):
1499 self.assertTrue(tree_store.remove(childrow.iter))
1501 self.assertFalse(tree_store.remove(childrow.iter))
1503 self.assertEqual(i, 19)
1505 self.assertEqual(tree_store.iter_n_children(last_row.iter), 0)
1506 for childrow in last_row.iterchildren():
1507 self.fail("Should not be reached")
1509 aiter = tree_store.get_iter(10)
1510 self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a')
1511 self.assertRaises(ValueError, tree_store.get, aiter, 1, -1)
1512 self.assertRaises(ValueError, tree_store.get, aiter, 1, 100)
1513 self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10'))
1516 self.assertEqual(len(tree_store), 100)
1517 aiter = tree_store.get_iter(10)
1518 del tree_store[aiter]
1519 self.assertEqual(len(tree_store), 99)
1520 self.assertRaises(TypeError, tree_store.__delitem__, None)
1521 self.assertRaises(IndexError, tree_store.__delitem__, -101)
1522 self.assertRaises(IndexError, tree_store.__delitem__, 101)
1524 def test_tree_model_get_iter_fail(self):
1525 # TreeModel class with a failing get_iter()
1526 class MyTreeModel(GObject.GObject, Gtk.TreeModel):
1527 def do_get_iter(self, iter):
1528 return (False, None)
1531 self.assertEqual(tm.get_iter_first(), None)
1533 def test_tree_model_edit(self):
1534 model = Gtk.ListStore(int, str, float)
1535 model.append([1, "one", -0.1])
1536 model.append([2, "two", -0.2])
1541 self.assertRaises(TypeError, set_row, 3)
1542 self.assertRaises(TypeError, set_row, "three")
1543 self.assertRaises(ValueError, set_row, [])
1544 self.assertRaises(ValueError, set_row, [3, "three"])
1546 model[0] = (3, "three", -0.3)
1548 def test_tree_row_slice(self):
1549 model = Gtk.ListStore(int, str, float)
1550 model.append([1, "one", -0.1])
1552 self.assertEqual([1, "one", -0.1], model[0][:])
1553 self.assertEqual([1, "one"], model[0][:2])
1554 self.assertEqual(["one", -0.1], model[0][1:])
1555 self.assertEqual(["one"], model[0][1:-1])
1556 self.assertEqual([1], model[0][:-2])
1557 self.assertEqual([], model[0][5:])
1558 self.assertEqual([1, -0.1], model[0][0:3:2])
1560 model[0][:] = (2, "two", -0.2)
1561 self.assertEqual([2, "two", -0.2], model[0][:])
1563 model[0][:2] = (3, "three")
1564 self.assertEqual([3, "three", -0.2], model[0][:])
1566 model[0][1:] = ("four", -0.4)
1567 self.assertEqual([3, "four", -0.4], model[0][:])
1569 model[0][1:-1] = ("five",)
1570 self.assertEqual([3, "five", -0.4], model[0][:])
1572 model[0][0:3:2] = (6, -0.6)
1573 self.assertEqual([6, "five", -0.6], model[0][:])
1576 model[0][5:] = ("doesn't", "matter",)
1578 self.assertRaises(ValueError, set_row1)
1581 model[0][:1] = (0, "zero", 0)
1583 self.assertRaises(ValueError, set_row2)
1586 model[0][:2] = ("0", 0)
1588 self.assertRaises(TypeError, set_row3)
1590 def test_tree_row_sequence(self):
1591 model = Gtk.ListStore(int, str, float)
1592 model.append([1, "one", -0.1])
1594 self.assertEqual([1, "one", -0.1], model[0][0, 1, 2])
1595 self.assertEqual([1, "one"], model[0][0, 1])
1596 self.assertEqual(["one", -0.1], model[0][1, 2])
1597 self.assertEqual("one", model[0][1])
1598 self.assertEqual([1, -0.1], model[0][0, 2])
1599 self.assertEqual([-0.1, 1], model[0][2, 0])
1601 model[0][0, 1, 2] = (2, "two", -0.2)
1602 self.assertEqual([2, "two", -0.2], model[0][0, 1, 2])
1604 model[0][0, 1] = (3, "three")
1605 self.assertEqual([3, "three"], model[0][0, 1])
1607 model[0][1, 2] = ("four", -0.4)
1608 self.assertEqual(["four", -0.4], model[0][1, 2])
1610 model[0][0, 2] = (5, -0.5)
1611 self.assertEqual([5, -0.5], model[0][0, 2])
1613 model[0][0, 1, 2] = (6, "six", -0.6)
1614 self.assertEqual([-0.6, 6, "six"], model[0][2, 0, 1])
1617 model[0][4, 5] = ("shouldn't", "work",)
1619 self.assertRaises(IndexError, set_row1)
1622 model[0][0, 1] = (0, "zero", 0)
1624 self.assertRaises(ValueError, set_row2)
1627 model[0][0, 1] = ("shouldn't", 0)
1629 self.assertRaises(TypeError, set_row3)
1632 model[0][0, "two"] = (0, "zero")
1634 self.assertRaises(TypeError, set_row4)
1636 def test_tree_model_set_value_to_none(self):
1637 # Tests allowing the usage of None to set an empty value on a model.
1638 store = Gtk.ListStore(str)
1639 row = store.append(['test'])
1640 self.assertSequenceEqual(store[0][:], ['test'])
1641 store.set_value(row, 0, None)
1642 self.assertSequenceEqual(store[0][:], [None])
1644 def test_signal_emission_tree_path_coerce(self):
1645 class Model(GObject.Object, Gtk.TreeModel):
1651 def on_any_signal(model, path, *args):
1652 tree_paths.append(path.to_string())
1654 model.connect('row-changed', on_any_signal)
1655 model.connect('row-deleted', on_any_signal)
1656 model.connect('row-has-child-toggled', on_any_signal)
1657 model.connect('row-inserted', on_any_signal)
1659 model.row_changed('0', Gtk.TreeIter())
1660 self.assertEqual(tree_paths[-1], '0')
1662 model.row_deleted('1')
1663 self.assertEqual(tree_paths[-1], '1')
1665 model.row_has_child_toggled('2', Gtk.TreeIter())
1666 self.assertEqual(tree_paths[-1], '2')
1668 model.row_inserted('3', Gtk.TreeIter())
1669 self.assertEqual(tree_paths[-1], '3')
1671 def test_tree_model_filter(self):
1672 model = Gtk.ListStore(int, str, float)
1673 model.append([1, "one", -0.1])
1674 model.append([2, "two", -0.2])
1676 filtered = Gtk.TreeModelFilter(child_model=model)
1678 self.assertEqual(filtered[0][1], 'one')
1679 filtered[0][1] = 'ONE'
1680 self.assertEqual(filtered[0][1], 'ONE')
1682 def test_list_store_performance(self):
1683 model = Gtk.ListStore(int, str)
1686 start = time.clock()
1689 model.append([1, 'hello'])
1692 sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations))
1694 def test_filter_new_default(self):
1695 # Test filter_new accepts implicit default of None
1696 model = Gtk.ListStore(int)
1697 filt = model.filter_new()
1698 self.assertTrue(filt is not None)
1701 @unittest.skipUnless(Gtk, 'Gtk not available')
1702 class TestTreeView(unittest.TestCase):
1703 def test_tree_view(self):
1704 store = Gtk.ListStore(int, str)
1705 store.append((0, "foo"))
1706 store.append((1, "bar"))
1707 view = Gtk.TreeView()
1709 with realized(view):
1710 view.set_cursor(store[1].path)
1711 view.set_cursor(str(store[1].path))
1713 view.get_cell_area(store[1].path)
1714 view.get_cell_area(str(store[1].path))
1716 def test_tree_view_column(self):
1717 cell = Gtk.CellRendererText()
1718 col = Gtk.TreeViewColumn(title='This is just a test',
1723 # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=711173
1724 col.set_cell_data_func(cell, None, None)
1726 def test_tree_view_add_column_with_attributes(self):
1727 model = Gtk.ListStore(str, str, str)
1728 # deliberately use out-of-order sorting here; we assign column 0 to
1729 # model index 2, etc.
1730 model.append(['cell13', 'cell11', 'cell12'])
1731 model.append(['cell23', 'cell21', 'cell22'])
1733 tree = Gtk.TreeView(model=model)
1734 cell1 = Gtk.CellRendererText()
1735 cell2 = Gtk.CellRendererText()
1736 cell3 = Gtk.CellRendererText()
1737 cell4 = Gtk.CellRendererText()
1739 tree.insert_column_with_attributes(0, 'Head2', cell2, text=2)
1740 tree.insert_column_with_attributes(0, 'Head1', cell1, text=1)
1741 tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0)
1743 tree.insert_column_with_attributes(-1, 'Head4', cell4)
1745 with realized(tree):
1746 tree.set_cursor(model[0].path)
1747 while Gtk.events_pending():
1748 Gtk.main_iteration()
1750 self.assertEqual(tree.get_column(0).get_title(), 'Head1')
1751 self.assertEqual(tree.get_column(1).get_title(), 'Head2')
1752 self.assertEqual(tree.get_column(2).get_title(), 'Head3')
1753 self.assertEqual(tree.get_column(3).get_title(), 'Head4')
1755 # cursor should be at the first row
1756 self.assertEqual(cell1.props.text, 'cell11')
1757 self.assertEqual(cell2.props.text, 'cell12')
1758 self.assertEqual(cell3.props.text, 'cell13')
1759 self.assertEqual(cell4.props.text, None)
1761 def test_tree_view_column_set_attributes(self):
1762 store = Gtk.ListStore(int, str)
1763 directors = ['Fellini', 'Tarantino', 'Tarkovskiy']
1764 for i, director in enumerate(directors):
1765 store.append([i, director])
1767 treeview = Gtk.TreeView()
1768 treeview.set_model(store)
1770 column = Gtk.TreeViewColumn()
1771 treeview.append_column(column)
1773 cell = Gtk.CellRendererText()
1774 column.pack_start(cell, expand=True)
1775 column.set_attributes(cell, text=1)
1777 with realized(treeview):
1778 self.assertTrue(cell.props.text in directors)
1780 def test_tree_selection(self):
1781 store = Gtk.ListStore(int, str)
1783 store.append((i, "foo"))
1784 view = Gtk.TreeView()
1785 view.set_model(store)
1786 firstpath = store.get_path(store.get_iter_first())
1787 sel = view.get_selection()
1789 sel.select_path(firstpath)
1790 (m, s) = sel.get_selected()
1791 self.assertEqual(m, store)
1792 self.assertEqual(store.get_path(s), firstpath)
1795 (m, s) = sel.get_selected()
1796 self.assertEqual(m, store)
1797 self.assertEqual(store.get_path(s), firstpath)
1799 sel.select_path("0:0")
1800 (m, s) = sel.get_selected()
1801 self.assertEqual(m, store)
1802 self.assertEqual(store.get_path(s), firstpath)
1804 sel.select_path((0, 0))
1805 (m, s) = sel.get_selected()
1806 self.assertEqual(m, store)
1807 self.assertEqual(store.get_path(s), firstpath)
1810 @unittest.skipUnless(Gtk, 'Gtk not available')
1811 class TestTextBuffer(unittest.TestCase):
1812 def test_text_buffer(self):
1813 self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
1814 buffer = Gtk.TextBuffer()
1815 tag = buffer.create_tag('title', font='Sans 18')
1817 self.assertEqual(tag.props.name, 'title')
1818 self.assertEqual(tag.props.font, 'Sans 18')
1820 (start, end) = buffer.get_bounds()
1822 mark = buffer.create_mark(None, start)
1823 self.assertFalse(mark.get_left_gravity())
1825 buffer.set_text('Hello Jane Hello Bob')
1826 (start, end) = buffer.get_bounds()
1827 text = buffer.get_text(start, end, False)
1828 self.assertEqual(text, 'Hello Jane Hello Bob')
1831 (start, end) = buffer.get_bounds()
1832 text = buffer.get_text(start, end, False)
1833 self.assertEqual(text, '')
1835 buffer.insert(end, 'HelloHello')
1836 buffer.insert(end, ' Bob')
1838 cursor_iter = end.copy()
1839 cursor_iter.backward_chars(9)
1840 buffer.place_cursor(cursor_iter)
1841 buffer.insert_at_cursor(' Jane ')
1843 (start, end) = buffer.get_bounds()
1844 text = buffer.get_text(start, end, False)
1845 self.assertEqual(text, 'Hello Jane Hello Bob')
1847 sel = buffer.get_selection_bounds()
1848 self.assertEqual(sel, ())
1849 buffer.select_range(start, end)
1850 sel = buffer.get_selection_bounds()
1851 self.assertTrue(sel[0].equal(start))
1852 self.assertTrue(sel[1].equal(end))
1855 buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag)
1856 (start, end) = buffer.get_bounds()
1857 self.assertTrue(start.begins_tag(tag))
1858 self.assertTrue(start.has_tag(tag))
1861 buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title')
1862 (start, end) = buffer.get_bounds()
1863 self.assertTrue(start.begins_tag(tag))
1864 self.assertTrue(start.has_tag(tag))
1866 self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
1867 buffer.get_start_iter(), 'HelloHello', 'unknowntag')
1869 def test_text_iter(self):
1870 self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter)
1871 buffer = Gtk.TextBuffer()
1872 buffer.set_text('Hello Jane Hello Bob')
1873 tag = buffer.create_tag('title', font='Sans 18')
1874 (start, end) = buffer.get_bounds()
1875 start.forward_chars(10)
1876 buffer.apply_tag(tag, start, end)
1877 self.assertTrue(start.begins_tag())
1878 self.assertTrue(end.ends_tag())
1879 self.assertTrue(start.toggles_tag())
1880 self.assertTrue(end.toggles_tag())
1881 start.backward_chars(1)
1882 self.assertFalse(start.begins_tag())
1883 self.assertFalse(start.ends_tag())
1884 self.assertFalse(start.toggles_tag())
1886 def test_text_buffer_search(self):
1887 buffer = Gtk.TextBuffer()
1888 buffer.set_text('Hello World Hello GNOME')
1890 i = buffer.get_iter_at_offset(0)
1891 self.assertTrue(isinstance(i, Gtk.TextIter))
1893 self.assertEqual(i.forward_search('world', 0, None), None)
1895 (start, end) = i.forward_search('World', 0, None)
1896 self.assertEqual(start.get_offset(), 6)
1897 self.assertEqual(end.get_offset(), 11)
1899 (start, end) = i.forward_search('world',
1900 Gtk.TextSearchFlags.CASE_INSENSITIVE,
1902 self.assertEqual(start.get_offset(), 6)
1903 self.assertEqual(end.get_offset(), 11)
1905 def test_insert_text_signal_location_modification(self):
1906 # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=736175
1908 def callback(buffer, location, text, length):
1909 location.assign(buffer.get_end_iter())
1911 buffer = Gtk.TextBuffer()
1912 buffer.set_text('first line\n')
1913 buffer.connect('insert-text', callback)
1915 # attempt insertion at the beginning of the buffer, the callback will
1916 # modify the insert location to the end.
1917 buffer.place_cursor(buffer.get_start_iter())
1918 buffer.insert_at_cursor('second line\n')
1920 self.assertEqual(buffer.get_property('text'),
1921 'first line\nsecond line\n')
1924 @unittest.skipUnless(Gtk, 'Gtk not available')
1925 class TestContainer(unittest.TestCase):
1926 def test_child_set_property(self):
1928 child = Gtk.Button()
1929 box.pack_start(child, expand=False, fill=True, padding=0)
1931 box.child_set_property(child, 'padding', 42)
1933 value = GObject.Value(int)
1934 box.child_get_property(child, 'padding', value)
1935 self.assertEqual(value.get_int(), 42)
1937 def test_child_get_property_gvalue(self):
1939 child = Gtk.Button()
1940 box.pack_start(child, expand=False, fill=True, padding=42)
1942 value = GObject.Value(int)
1943 box.child_get_property(child, 'padding', value)
1944 self.assertEqual(value.get_int(), 42)
1946 def test_child_get_property_return_with_explicit_gvalue(self):
1948 child = Gtk.Button()
1949 box.pack_start(child, expand=False, fill=True, padding=42)
1951 value = GObject.Value(int)
1952 result = box.child_get_property(child, 'padding', value)
1953 self.assertEqual(result, 42)
1955 def test_child_get_property_return_with_implicit_gvalue(self):
1957 child = Gtk.Button()
1958 box.pack_start(child, expand=False, fill=True, padding=42)
1960 result = box.child_get_property(child, 'padding')
1961 self.assertEqual(result, 42)
1963 def test_child_get_property_error(self):
1965 child = Gtk.Button()
1966 box.pack_start(child, expand=False, fill=True, padding=42)
1967 with self.assertRaises(ValueError):
1968 box.child_get_property(child, 'not-a-valid-child-property')
1970 def test_child_get_and_set(self):
1972 child = Gtk.Button()
1973 box.pack_start(child, expand=True, fill=True, padding=42)
1975 expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding')
1976 self.assertEqual(expand, True)
1977 self.assertEqual(fill, True)
1978 self.assertEqual(padding, 42)
1980 box.child_set(child, expand=False, fill=False, padding=21, pack_type=1)
1981 expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type')
1982 self.assertEqual(expand, False)
1983 self.assertEqual(fill, False)
1984 self.assertEqual(padding, 21)