1 /* Scrolling test suite for GtkTreeView
2 * Copyright (C) 2006 Kristian Rietveld <kris@gtk.org>
3 * Copyright (C) 2007 Imendio AB, Kristian Rietveld
4 * Copyright (C) 2009 Kristian Rietveld <kris@gtk.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 /* Original v1.0 -- December 26, 2006
23 * Conversion to GLib/GTK+ test framework during December, 2007
31 #define VIEW_WIDTH 320
32 #define VIEW_HEIGHT 240
35 #define BIG_N_ROWS N_ROWS * 100
39 * - Test that nothing happens if the row is fully visible.
40 * - The tests are dependent on the theme/font (size measurements,
42 * - Convert to proper GTK+ coding style.
43 * - Briefly test scrolling in tree stores as well.
46 * - For tests with "mixed height" models, you must ensure that
47 * there are only two heights used in total and that the rows with
48 * height A and B are strictly alternating. The model creation
49 * functions already do this for you, but take this into account
50 * when you write a unit test that adds rows to such a created
51 * model, you must follow this rule otherwise things will break.
55 /* Constructing models for testing */
57 create_model (gboolean constant)
64 store = gtk_list_store_new (1, G_TYPE_STRING);
66 for (i = 0; i < N_ROWS; i++) {
67 gtk_list_store_append (store, &iter);
68 if (constant || i % 2 == 0)
69 gtk_list_store_set (store, &iter, 0, "Foo", -1);
71 gtk_list_store_set (store, &iter, 0, "Sliff\nSloff\nBleh", -1);
74 return GTK_TREE_MODEL (store);
78 create_big_model (gboolean constant)
85 store = gtk_list_store_new (1, G_TYPE_STRING);
87 for (i = 0; i < BIG_N_ROWS; i++) {
88 gtk_list_store_append (store, &iter);
89 if (constant || i % 2 == 0)
90 gtk_list_store_set (store, &iter, 0, "Foo", -1);
92 gtk_list_store_set (store, &iter, 0, "Sliff\nSloff\nBleh", -1);
95 return GTK_TREE_MODEL (store);
105 GtkWidget *tree_view;
110 scroll_fixture_setup (ScrollFixture *fixture,
112 gconstpointer test_data)
115 GtkCellRenderer *renderer;
116 GtkTreeViewColumn *column;
118 fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
120 sw = gtk_scrolled_window_new (NULL, NULL);
121 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
124 gtk_container_add (GTK_CONTAINER (fixture->window), sw);
126 fixture->tree_view = gtk_tree_view_new_with_model (model);
127 g_object_unref (model);
128 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (sw), VIEW_WIDTH);
129 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), VIEW_HEIGHT);
130 gtk_widget_set_size_request (fixture->tree_view, VIEW_WIDTH, VIEW_HEIGHT);
132 renderer = gtk_cell_renderer_text_new ();
133 g_object_set (renderer, "editable", TRUE, NULL);
134 column = gtk_tree_view_column_new_with_attributes ("Title",
139 gtk_tree_view_append_column (GTK_TREE_VIEW (fixture->tree_view), column);
140 gtk_container_add (GTK_CONTAINER (sw), fixture->tree_view);
143 /* sets up a fixture with a model with constant row heights */
145 scroll_fixture_constant_setup (ScrollFixture *fixture,
146 gconstpointer test_data)
148 scroll_fixture_setup (fixture, create_model (TRUE), test_data);
151 /* sets up a fixture with a model with varying row heights */
153 scroll_fixture_mixed_setup (ScrollFixture *fixture,
154 gconstpointer test_data)
156 scroll_fixture_setup (fixture, create_model (FALSE), test_data);
159 /* sets up a fixture with a large model with constant row heights */
161 scroll_fixture_constant_big_setup (ScrollFixture *fixture,
162 gconstpointer test_data)
164 scroll_fixture_setup (fixture, create_big_model (TRUE), test_data);
167 /* sets up a fixture with a large model with varying row heights */
169 scroll_fixture_mixed_big_setup (ScrollFixture *fixture,
170 gconstpointer test_data)
172 scroll_fixture_setup (fixture, create_big_model (FALSE), test_data);
175 /* sets up a fixture with only a single row for the "single row scroll" test */
177 scroll_fixture_single_setup (ScrollFixture *fixture,
178 gconstpointer test_data)
181 GtkTreeIter iter, child;
183 store = gtk_tree_store_new (1, G_TYPE_STRING);
185 gtk_tree_store_append (store, &iter, NULL);
186 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
188 gtk_tree_store_append (store, &child, &iter);
189 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
191 /* The teardown will also destroy the model */
192 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
195 /* sets up a fixture with a tree store */
197 scroll_fixture_tree_setup (ScrollFixture *fixture,
198 gconstpointer test_data)
201 GtkTreeIter iter, child;
204 store = gtk_tree_store_new (1, G_TYPE_STRING);
206 gtk_tree_store_append (store, &iter, NULL);
207 gtk_tree_store_set (store, &iter, 0, "Root node", -1);
209 for (i = 0; i < 5; i++) {
210 gtk_tree_store_append (store, &child, &iter);
211 gtk_tree_store_set (store, &child, 0, "Child node", -1);
214 for (i = 0; i < 5; i++) {
215 gtk_tree_store_append (store, &iter, NULL);
216 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
219 /* The teardown will also destroy the model */
220 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
224 scroll_fixture_mixed_tree_setup (ScrollFixture *fixture,
225 gconstpointer test_data)
228 GtkTreeIter iter, child;
231 store = gtk_tree_store_new (1, G_TYPE_STRING);
233 gtk_tree_store_append (store, &iter, NULL);
234 gtk_tree_store_set (store, &iter, 0, "Root\nnode", -1);
236 for (i = 0; i < 5; i++) {
237 gtk_tree_store_append (store, &child, &iter);
239 gtk_tree_store_set (store, &child, 0, "Child node", -1);
241 gtk_tree_store_set (store, &child,
242 0, "Child\nnode", -1);
245 for (i = 0; i < 5; i++) {
246 gtk_tree_store_append (store, &iter, NULL);
248 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
250 gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
253 /* The teardown will also destroy the model */
254 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
258 scroll_fixture_teardown (ScrollFixture *fixture,
259 gconstpointer test_data)
261 gtk_widget_destroy (fixture->window);
265 * Position check and helpers.
275 get_row_start_for_index (GtkTreeView *tree_view, int index)
277 gint height1, height2;
282 path = gtk_tree_path_new_from_indices (0, -1);
283 gtk_tree_view_get_background_area (tree_view, path, NULL, &rect);
284 height1 = rect.height;
286 gtk_tree_path_next (path);
287 gtk_tree_view_get_background_area (tree_view, path, NULL, &rect);
288 height2 = rect.height;
289 gtk_tree_path_free (path);
291 row_start = (index / 2) * height1 + (index / 2) * height2;
293 row_start += height1;
299 get_pos_from_path (GtkTreeView *tree_view,
306 row_start = get_row_start_for_index (tree_view,
307 gtk_tree_path_get_indices (path)[0]);
309 if (row_start + row_height < vadj->page_size)
312 if (row_start >= vadj->upper - vadj->page_size)
319 test_position_with_align (GtkTreeView *tree_view,
326 gboolean passed = TRUE;
327 GtkAdjustment *vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
329 /* Switch on row-align: 0.0, 0.5, 1.0 */
330 switch ((int)(row_align * 2.)) {
332 if (pos == POS_TOP || pos == POS_CENTER) {
333 /* The row in question is the first row
335 * - rect.y should be zero
336 * - dy should be equal to the top
337 * y coordinate of the row.
341 if (vadj->value != row_start)
344 /* The row can be anywhere at the last
345 * page of the tree view.
346 * - dy is set to the start of the
349 if (vadj->value != vadj->upper - vadj->page_size)
357 && row_start < vadj->page_size / 2) {
358 /* For the first half of the top view we can't
359 * center the row in the view, instead we
360 * show the first page.
361 * - dy should be zero
363 if (vadj->value != 0)
365 } else if (pos == POS_BOTTOM
366 && row_start >= vadj->upper - vadj->page_size / 2) {
367 /* For the last half of the bottom view we
368 * can't center the row in the view, instead
369 * we show the last page.
370 * - dy should be the start of the
373 if (vadj->value != vadj->upper - vadj->page_size)
376 /* The row is located in the middle of
378 * - top y coordinate is equal to
379 * middle of the view minus
380 * half the height of the row.
381 * (ie. the row's center is at the
382 * center of the view).
384 gdouble middle = vadj->page_size / 2 - row_height / 2;
385 if (row_y != ceil (middle) && row_y != floor (middle))
392 if (pos == POS_TOP) {
393 /* The row can be anywhere on the
394 * first page of the tree view.
397 if (vadj->value != 0)
399 } else if (pos == POS_CENTER || pos == POS_BOTTOM) {
400 /* The row is the last row visible in the
402 * - rect.y is set to the top of the
404 * - row_start is greater than page_size
405 * (ie we are not on the first page).
406 * - dy is greater than zero
408 if (row_start < vadj->page_size
409 && row_start + row_height < vadj->page_size)
411 if (vadj->value <= 0)
413 if (row_y != vadj->page_size - row_height)
423 test_position_without_align (GtkTreeView *tree_view,
427 GtkAdjustment *vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
429 /* Without align the tree view does as less work as possible,
430 * so basically we only have to check whether the row
431 * is visible on the screen.
433 if (vadj->value <= row_start
434 && vadj->value + vadj->page_size >= row_start + row_height)
441 test_position (GtkTreeView *tree_view,
453 /* Get the location of the path we scrolled to */
454 gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
457 row_start = get_row_start_for_index (GTK_TREE_VIEW (tree_view),
458 gtk_tree_path_get_indices (path)[0]);
461 pos = get_pos_from_path (GTK_TREE_VIEW (tree_view),
463 gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view)));
465 /* This is only tested for during test_single() */
466 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
467 if (gtk_tree_model_iter_n_children (model, NULL) == 1) {
468 GtkAllocation allocation;
469 GtkTreePath *tmppath;
471 /* Test nothing is dangling at the bottom; read
472 * description for test_single() for more information.
475 /* FIXME: hardcoded width */
476 gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
477 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), 0, allocation.height - 30, &tmppath, NULL, NULL, NULL)) {
478 g_assert_not_reached ();
479 gtk_tree_path_free (tmppath);
483 path_str = gtk_tree_path_to_string (path);
485 g_assert (test_position_with_align (tree_view, pos, rect.y,
486 row_start, rect.height, row_align));
488 g_assert (test_position_without_align (tree_view, row_start, rect.height));
499 /* Testing scrolling to various positions with various alignments */
502 scroll (ScrollFixture *fixture,
507 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
509 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
511 use_align, row_align, 0.0);
513 gtk_widget_show_all (fixture->window);
515 while (gtk_events_pending ())
516 gtk_main_iteration ();
518 test_position (GTK_TREE_VIEW (fixture->tree_view), path,
519 use_align, row_align, 0.0);
523 scroll_no_align (ScrollFixture *fixture,
524 gconstpointer test_data)
528 path = gtk_tree_path_new_from_string (test_data);
529 scroll (fixture, path, FALSE, 0.0);
530 gtk_tree_path_free (path);
534 scroll_align_0_0 (ScrollFixture *fixture,
535 gconstpointer test_data)
539 path = gtk_tree_path_new_from_string (test_data);
540 scroll (fixture, path, TRUE, 0.0);
541 gtk_tree_path_free (path);
545 scroll_align_0_5 (ScrollFixture *fixture,
546 gconstpointer test_data)
550 path = gtk_tree_path_new_from_string (test_data);
551 scroll (fixture, path, TRUE, 0.5);
552 gtk_tree_path_free (path);
556 scroll_align_1_0 (ScrollFixture *fixture,
557 gconstpointer test_data)
561 path = gtk_tree_path_new_from_string (test_data);
562 scroll (fixture, path, TRUE, 1.0);
563 gtk_tree_path_free (path);
568 scroll_after_realize (ScrollFixture *fixture,
573 gtk_widget_show_all (fixture->window);
575 while (gtk_events_pending ())
576 gtk_main_iteration ();
578 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
580 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
582 use_align, row_align, 0.0);
584 while (gtk_events_pending ())
585 gtk_main_iteration ();
587 test_position (GTK_TREE_VIEW (fixture->tree_view), path,
588 use_align, row_align, 0.0);
592 scroll_after_no_align (ScrollFixture *fixture,
593 gconstpointer test_data)
597 path = gtk_tree_path_new_from_string (test_data);
598 scroll_after_realize (fixture, path, FALSE, 0.0);
599 gtk_tree_path_free (path);
603 scroll_after_align_0_0 (ScrollFixture *fixture,
604 gconstpointer test_data)
608 path = gtk_tree_path_new_from_string (test_data);
609 scroll_after_realize (fixture, path, TRUE, 0.0);
610 gtk_tree_path_free (path);
614 scroll_after_align_0_5 (ScrollFixture *fixture,
615 gconstpointer test_data)
619 path = gtk_tree_path_new_from_string (test_data);
620 scroll_after_realize (fixture, path, TRUE, 0.5);
621 gtk_tree_path_free (path);
625 scroll_after_align_1_0 (ScrollFixture *fixture,
626 gconstpointer test_data)
630 path = gtk_tree_path_new_from_string (test_data);
631 scroll_after_realize (fixture, path, TRUE, 1.0);
632 gtk_tree_path_free (path);
637 scroll_both_realize (ScrollFixture *fixture,
644 gtk_widget_show_all (fixture->window);
647 end = gtk_tree_path_new_from_indices (999, -1);
649 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), end,
651 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
653 use_align, row_align, 0.0);
654 gtk_tree_path_free (end);
656 while (gtk_events_pending ())
657 gtk_main_iteration ();
659 /* Scroll to final position */
660 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
662 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
664 use_align, row_align, 0.0);
666 while (gtk_events_pending ())
667 gtk_main_iteration ();
669 test_position (GTK_TREE_VIEW (fixture->tree_view), path,
670 use_align, row_align, 0.0);
674 scroll_both_no_align (ScrollFixture *fixture,
675 gconstpointer test_data)
679 path = gtk_tree_path_new_from_string (test_data);
680 scroll_both_realize (fixture, path, FALSE, 0.0);
681 gtk_tree_path_free (path);
685 scroll_both_align_0_0 (ScrollFixture *fixture,
686 gconstpointer test_data)
690 path = gtk_tree_path_new_from_string (test_data);
691 scroll_both_realize (fixture, path, TRUE, 0.0);
692 gtk_tree_path_free (path);
696 scroll_both_align_0_5 (ScrollFixture *fixture,
697 gconstpointer test_data)
701 path = gtk_tree_path_new_from_string (test_data);
702 scroll_both_realize (fixture, path, TRUE, 0.5);
703 gtk_tree_path_free (path);
707 scroll_both_align_1_0 (ScrollFixture *fixture,
708 gconstpointer test_data)
712 path = gtk_tree_path_new_from_string (test_data);
713 scroll_both_realize (fixture, path, TRUE, 1.0);
714 gtk_tree_path_free (path);
717 /* Testing scrolling to a newly created row */
719 create_new_row (GtkListStore *store,
726 gtk_list_store_prepend (store, iter);
730 /* Add a row in the middle of the visible area */
731 gtk_list_store_insert (store, iter, 3);
735 /* Add a row in the middle of the visible area */
736 gtk_list_store_insert (store, iter, 4);
740 /* Add a row which is not completely visible */
741 gtk_list_store_insert (store, iter, 5);
745 /* Add a row which is not completely visible */
746 gtk_list_store_insert (store, iter, 8);
750 /* Add a row in the middle */
751 gtk_list_store_insert (store, iter, 500);
756 gtk_list_store_append (store, iter);
760 gtk_list_store_set (store, iter, 0, "New...", -1);
764 scroll_new_row_editing_started (GtkCellRenderer *cell,
765 GtkCellEditable *editable,
769 GtkWidget **widget = user_data;
771 *widget = GTK_WIDGET (editable);
775 test_editable_position (GtkWidget *tree_view,
777 GtkTreePath *cursor_path)
779 GtkAllocation allocation;
783 gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
784 cursor_path, NULL, &rect);
786 vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
788 /* There are all in bin_window coordinates */
789 gtk_widget_get_allocation (editable, &allocation);
790 g_assert (allocation.y == rect.y + ((rect.height - allocation.height) / 2));
794 scroll_new_row (ScrollFixture *fixture,
795 gconstpointer test_data)
797 GtkTreeIter scroll_iter;
798 GtkTreePath *scroll_path;
801 GtkTreeViewColumn *column;
804 /* The aim of this test is creating a new row at several places,
805 * and immediately put the cursor on it. TreeView should correctly
806 * scroll to the row and show the editable widget.
811 g_test_bug ("81627");
813 gtk_widget_show_all (fixture->window);
815 while (gtk_events_pending ())
816 gtk_main_iteration ();
818 /* Create the new row and scroll to it */
819 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
820 create_new_row (GTK_LIST_STORE (model), GPOINTER_TO_INT (test_data),
823 /* Set up a signal handler to acquire the editable widget */
824 column = gtk_tree_view_get_column (GTK_TREE_VIEW (fixture->tree_view), 0);
825 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
827 g_signal_connect (G_OBJECT (renderers->data), "editing-started",
828 G_CALLBACK (scroll_new_row_editing_started),
831 /* Now set the cursor on the path and start editing */
832 scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
833 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view),
838 while (gtk_events_pending ())
839 gtk_main_iteration ();
842 test_position (GTK_TREE_VIEW (fixture->tree_view), scroll_path,
844 test_editable_position (fixture->tree_view, editable, scroll_path);
846 gtk_tree_path_free (scroll_path);
850 scroll_new_row_tree (ScrollFixture *fixture,
851 gconstpointer test_data)
854 GtkAdjustment *vadjustment;
857 /* The goal of this test is to append new rows at the end of a tree
858 * store and immediately scroll to them. If there is a parent
859 * node with a couple of childs in the "area above" to explore,
860 * this used to lead to unexpected results due to a bug.
862 * This issue has been reported by Miroslav Rajcic on
863 * gtk-app-devel-list:
864 * http://mail.gnome.org/archives/gtk-app-devel-list/2008-December/msg00068.html
867 gtk_widget_show_all (fixture->window);
869 gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
871 while (gtk_events_pending ())
872 gtk_main_iteration ();
874 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
875 vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
877 for (i = 0; i < 5; i++) {
878 GtkTreeIter scroll_iter;
879 GtkTreePath *scroll_path;
881 gtk_tree_store_append (GTK_TREE_STORE (model), &scroll_iter,
883 gtk_tree_store_set (GTK_TREE_STORE (model), &scroll_iter,
886 scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
887 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
888 scroll_path, NULL, FALSE, 0.0, 0.0);
889 gtk_tree_path_free (scroll_path);
891 while (gtk_events_pending ())
892 gtk_main_iteration ();
894 /* Test position, the scroll bar must be at the end */
895 g_assert (vadjustment->value == vadjustment->upper - vadjustment->page_size);
899 /* Test for GNOME bugzilla bug 359231; tests "recovery when removing a bunch of
900 * rows at the bottom.
903 test_bug316689 (ScrollFixture *fixture,
904 gconstpointer test_data)
911 /* The aim of this test is to scroll to the bottom of a TreeView,
912 * remove at least one page_size of items and check if TreeView
913 * correctly corrects the scroll bar (else they will look "broken").
918 g_test_bug ("316689");
920 /* Scroll to some place close to the end */
921 path = gtk_tree_path_new_from_indices (N_ROWS - 4, -1);
922 scroll (fixture, path, FALSE, 0.0);
923 gtk_tree_path_free (path);
925 /* No need for a while events pending loop here, scroll() does this for us.
927 * We now remove a bunch of rows, wait for events to process and then
928 * check the adjustments to see if the TreeView gracefully recovered.
930 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
932 while (gtk_tree_model_iter_nth_child (model, &iter, NULL, N_ROWS - 15))
933 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
935 while (gtk_events_pending ())
936 gtk_main_iteration ();
938 vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
940 g_assert (vadj->value + vadj->page_size <= vadj->upper);
941 g_assert (vadj->value == vadj->upper - vadj->page_size);
945 /* Test for GNOME bugzilla bug 359231 */
947 test_bug359231 (void)
950 int height1, height2;
952 GtkTreeIter iter, child;
955 ScrollFixture *fixture;
958 g_test_bug ("359231");
960 /* Create model (GtkTreeStore in this case) */
961 store = gtk_tree_store_new (1, G_TYPE_STRING);
963 gtk_tree_store_append (store, &iter, NULL);
964 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
966 for (i = 0; i < 4; i++) {
967 gtk_tree_store_append (store, &child, &iter);
968 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
971 fixture = g_new0 (ScrollFixture, 1);
972 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), NULL);
973 gtk_widget_show_all (fixture->window);
975 while (gtk_events_pending ())
976 gtk_main_iteration ();
978 /* Prepend some rows at the top, expand */
979 gtk_tree_store_prepend (store, &iter, NULL);
980 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
982 gtk_tree_store_prepend (store, &child, &iter);
983 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
985 gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
987 while (gtk_events_pending ())
988 gtk_main_iteration ();
990 /* Test if height of row 0:0 is correct */
991 path = gtk_tree_path_new_from_indices (0, -1);
992 gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
994 height1 = rect.height;
996 gtk_tree_path_down (path);
997 gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
999 height2 = rect.height;
1000 gtk_tree_path_free (path);
1002 g_assert (height2 > height1);
1004 /* Clean up; the tear down also cleans up the model */
1005 scroll_fixture_teardown (fixture, NULL);
1008 /* Test for GNOME bugzilla bug 93584. We add 150 rows to an existing
1009 * small model, and scroll to one of these with alignment.
1012 test_bug93584 (ScrollFixture *fixture,
1013 gconstpointer test_data)
1016 GtkTreeStore *store;
1019 g_test_bug ("93584");
1021 /* Mimic state as in original test case */
1022 g_signal_connect (G_OBJECT (fixture->tree_view), "realize",
1023 G_CALLBACK (gtk_tree_view_expand_all), NULL);
1024 gtk_widget_show_all (fixture->window);
1026 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1029 for (i = 0; i < 150; i++) {
1032 gtk_tree_store_append (store, &iter, NULL);
1033 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1036 row = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1039 path = gtk_tree_path_new_from_indices (row, -1);
1040 scroll (fixture, path, TRUE, 0.5);
1041 gtk_tree_path_free (path);
1044 /* GNOME bugzilla bug 111500. Expand a row and immediately scroll
1045 * to its first child. Make sure that expansion happens in currently
1049 test_bug111500 (ScrollFixture *fixture,
1050 gconstpointer test_data)
1053 GtkTreeStore *store;
1057 g_test_bug ("111500");
1059 gtk_widget_show_all (fixture->window);
1061 /* Make sure all events have been processed and the window
1064 while (gtk_events_pending ())
1065 gtk_main_iteration ();
1067 /* Further prepare model */
1068 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1070 for (i = 0; i < 15; i++) {
1073 gtk_tree_store_append (store, &iter, NULL);
1074 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1077 len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1078 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
1081 for (i = 0; i < 5; i++) {
1084 gtk_tree_store_append (store, &iter, &parent);
1085 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1088 path = gtk_tree_path_new_from_indices (len - 1, -1);
1089 gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1092 gtk_tree_path_down (path);
1094 scroll (fixture, path, TRUE, 0.5);
1095 gtk_tree_path_free (path);
1099 test_bug111500_mixed (ScrollFixture *fixture,
1100 gconstpointer test_data)
1103 GtkTreeStore *store;
1107 g_test_bug ("111500");
1109 gtk_widget_show_all (fixture->window);
1111 /* Make sure all events have been processed and the window
1114 while (gtk_events_pending ())
1115 gtk_main_iteration ();
1117 /* Further prepare model */
1118 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1120 for (i = 0; i < 15; i++) {
1123 gtk_tree_store_append (store, &iter, NULL);
1125 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1127 gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
1130 len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1131 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
1134 for (i = 0; i < 5; i++) {
1137 gtk_tree_store_append (store, &iter, &parent);
1139 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1141 gtk_tree_store_set (store, &iter, 0, "Row\nRow", -1);
1144 path = gtk_tree_path_new_from_indices (len - 1, -1);
1145 gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1148 gtk_tree_path_down (path);
1150 scroll (fixture, path, TRUE, 0.5);
1151 gtk_tree_path_free (path);
1154 /* Test for GNOME bugzilla bug 163214. Invalidate a couple of rows,
1155 * then scroll to one of these.
1158 test_bug163214 (ScrollFixture *fixture,
1159 gconstpointer test_data)
1162 GtkListStore *store;
1165 g_test_bug ("163214");
1167 gtk_widget_show_all (fixture->window);
1169 /* Make sure all events have been processed and the window
1172 while (gtk_events_pending ())
1173 gtk_main_iteration ();
1175 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1177 /* Invalidate a page of rows */
1178 for (i = 100; i < 110; i++) {
1181 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1183 gtk_list_store_set (store, &iter, 0, "Row", -1);
1186 /* Then scroll to that page. */
1187 path = gtk_tree_path_new_from_indices (105, -1);
1188 scroll (fixture, path, TRUE, 0.5);
1189 gtk_tree_path_free (path);
1191 /* Make sure all events have been processed and the window
1194 while (gtk_events_pending ())
1195 gtk_main_iteration ();
1197 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1199 /* Invalidate a page of rows */
1200 for (i = 300; i < 310; i++) {
1203 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1205 gtk_list_store_set (store, &iter, 0, "Row", -1);
1208 /* Then scroll to the first row */
1209 path = gtk_tree_path_new_from_indices (0, -1);
1210 scroll (fixture, path, TRUE, 0.5);
1211 gtk_tree_path_free (path);
1214 /* Infrastructure for automatically adding tests */
1223 test_type_string (int test_type)
1225 switch (test_type) {
1227 return "before-realize";
1230 return "after-realize";
1240 align_string (gboolean use_align,
1246 return g_strdup ("no-align");
1248 ret = g_strdup_printf ("align-%1.1f", row_align);
1253 add_test (const char *path,
1258 void (* setup) (ScrollFixture *, gconstpointer),
1259 void (* scroll_func) (ScrollFixture *, gconstpointer))
1264 align = align_string (use_align, row_align);
1266 test_path = g_strdup_printf ("/TreeView/scrolling/%s/%s-height/path-%s-%s",
1267 test_type_string (test_type),
1268 mixed ? "mixed" : "constant",
1272 g_test_add (test_path, ScrollFixture, path,
1273 setup, scroll_func, scroll_fixture_teardown);
1279 add_tests (gboolean mixed,
1283 void (*scroll_func) (ScrollFixture *, gconstpointer))
1285 void (* setup) (ScrollFixture *, gconstpointer);
1288 setup = scroll_fixture_mixed_setup;
1290 setup = scroll_fixture_constant_setup;
1292 add_test ("0", mixed, test_type, use_align, row_align, setup, scroll_func);
1293 add_test ("2", mixed, test_type, use_align, row_align, setup, scroll_func);
1294 add_test ("5", mixed, test_type, use_align, row_align, setup, scroll_func);
1295 /* We scroll to 8 to test a partial visible row. The 8 is
1296 * based on my font setting of "Vera Sans 11" and
1297 * the separators set to 0. (This should be made dynamic; FIXME).
1299 add_test ("8", mixed, test_type, use_align, row_align, setup, scroll_func);
1300 add_test ("10", mixed, test_type, use_align, row_align, setup, scroll_func);
1301 add_test ("250", mixed, test_type, use_align, row_align, setup, scroll_func);
1302 add_test ("500", mixed, test_type, use_align, row_align, setup, scroll_func);
1303 add_test ("750", mixed, test_type, use_align, row_align, setup, scroll_func);
1304 add_test ("990", mixed, test_type, use_align, row_align, setup, scroll_func);
1305 add_test ("991", mixed, test_type, use_align, row_align, setup, scroll_func);
1306 add_test ("995", mixed, test_type, use_align, row_align, setup, scroll_func);
1307 add_test ("997", mixed, test_type, use_align, row_align, setup, scroll_func);
1308 add_test ("999", mixed, test_type, use_align, row_align, setup, scroll_func);
1312 main (int argc, char **argv)
1314 gtk_test_init (&argc, &argv);
1316 /* Scrolls before realization */
1317 add_tests (FALSE, BEFORE, FALSE, 0.0, scroll_no_align);
1318 if (g_test_thorough ())
1319 add_tests (TRUE, BEFORE, FALSE, 0.0, scroll_no_align);
1321 add_tests (FALSE, BEFORE, TRUE, 0.0, scroll_align_0_0);
1322 if (g_test_thorough ())
1323 add_tests (TRUE, BEFORE, TRUE, 0.0, scroll_align_0_0);
1325 add_tests (FALSE, BEFORE, TRUE, 0.5, scroll_align_0_5);
1326 if (g_test_thorough ())
1327 add_tests (TRUE, BEFORE, TRUE, 0.5, scroll_align_0_5);
1329 add_tests (FALSE, BEFORE, TRUE, 1.0, scroll_align_1_0);
1330 if (g_test_thorough ())
1331 add_tests (TRUE, BEFORE, TRUE, 1.0, scroll_align_1_0);
1333 /* Scrolls after realization */
1334 add_tests (FALSE, AFTER, FALSE, 0.0, scroll_after_no_align);
1335 if (g_test_thorough ())
1336 add_tests (TRUE, AFTER, FALSE, 0.0, scroll_after_no_align);
1338 add_tests (FALSE, AFTER, TRUE, 0.0, scroll_after_align_0_0);
1339 if (g_test_thorough ())
1340 add_tests (TRUE, AFTER, TRUE, 0.0, scroll_after_align_0_0);
1342 add_tests (FALSE, AFTER, TRUE, 0.5, scroll_after_align_0_5);
1343 if (g_test_thorough ())
1344 add_tests (TRUE, AFTER, TRUE, 0.5, scroll_after_align_0_5);
1346 add_tests (FALSE, AFTER, TRUE, 1.0, scroll_after_align_1_0);
1347 if (g_test_thorough ())
1348 add_tests (TRUE, AFTER, TRUE, 1.0, scroll_after_align_1_0);
1350 /* Scroll to end before realization, to a real position after */
1351 if (g_test_thorough ()) {
1352 add_tests (FALSE, BOTH, FALSE, 0.0, scroll_both_no_align);
1353 add_tests (TRUE, BOTH, FALSE, 0.0, scroll_both_no_align);
1355 add_tests (FALSE, BOTH, TRUE, 0.0, scroll_both_align_0_0);
1356 add_tests (TRUE, BOTH, TRUE, 0.0, scroll_both_align_0_0);
1358 add_tests (FALSE, BOTH, TRUE, 0.5, scroll_both_align_0_5);
1359 add_tests (TRUE, BOTH, TRUE, 0.5, scroll_both_align_0_5);
1361 add_tests (FALSE, BOTH, TRUE, 1.0, scroll_both_align_1_0);
1362 add_tests (TRUE, BOTH, TRUE, 1.0, scroll_both_align_1_0);
1365 /* Test different alignments in view with single row */
1366 g_test_add ("/TreeView/scrolling/single-row/no-align",
1368 scroll_fixture_single_setup,
1370 scroll_fixture_teardown);
1371 g_test_add ("/TreeView/scrolling/single-row/align-0.0",
1373 scroll_fixture_single_setup,
1375 scroll_fixture_teardown);
1376 g_test_add ("/TreeView/scrolling/single-row/align-0.5",
1378 scroll_fixture_single_setup,
1380 scroll_fixture_teardown);
1381 g_test_add ("/TreeView/scrolling/single-row/align-1.0",
1383 scroll_fixture_single_setup,
1385 scroll_fixture_teardown);
1387 /* Test scrolling in a very large model; also very slow */
1388 if (g_test_slow ()) {
1389 g_test_add ("/TreeView/scrolling/large-model/constant-height/middle-no-align",
1390 ScrollFixture, "50000",
1391 scroll_fixture_constant_big_setup,
1393 scroll_fixture_teardown);
1394 g_test_add ("/TreeView/scrolling/large-model/constant-height/end-no-align",
1395 ScrollFixture, "99999",
1396 scroll_fixture_constant_big_setup,
1398 scroll_fixture_teardown);
1400 g_test_add ("/TreeView/scrolling/large-model/mixed-height/middle-no-align",
1401 ScrollFixture, "50000",
1402 scroll_fixture_mixed_big_setup,
1404 scroll_fixture_teardown);
1405 g_test_add ("/TreeView/scrolling/large-model/mixed-height/end-no-align",
1406 ScrollFixture, "99999",
1407 scroll_fixture_mixed_big_setup,
1409 scroll_fixture_teardown);
1412 /* Test scrolling to a newly created row */
1413 g_test_add ("/TreeView/scrolling/new-row/path-0", ScrollFixture,
1414 GINT_TO_POINTER (0),
1415 scroll_fixture_constant_setup,
1417 scroll_fixture_teardown);
1418 g_test_add ("/TreeView/scrolling/new-row/path-4", ScrollFixture,
1419 GINT_TO_POINTER (4),
1420 scroll_fixture_constant_setup,
1422 scroll_fixture_teardown);
1423 /* We scroll to 8 to test a partial visible row. The 8 is
1424 * based on my font setting of "Vera Sans 11" and
1425 * the separators set to 0. (This should be made dynamic; FIXME).
1427 g_test_add ("/TreeView/scrolling/new-row/path-8", ScrollFixture,
1428 GINT_TO_POINTER (8),
1429 scroll_fixture_constant_setup,
1431 scroll_fixture_teardown);
1432 g_test_add ("/TreeView/scrolling/new-row/path-500", ScrollFixture,
1433 GINT_TO_POINTER (500),
1434 scroll_fixture_constant_setup,
1436 scroll_fixture_teardown);
1437 g_test_add ("/TreeView/scrolling/new-row/path-999", ScrollFixture,
1438 GINT_TO_POINTER (999),
1439 scroll_fixture_constant_setup,
1441 scroll_fixture_teardown);
1443 g_test_add ("/TreeView/scrolling/new-row/tree", ScrollFixture,
1445 scroll_fixture_tree_setup,
1446 scroll_new_row_tree,
1447 scroll_fixture_teardown);
1449 /* Test scrolling to a newly created row, in a mixed height model */
1450 g_test_add ("/TreeView/scrolling/new-row-mixed/path-0", ScrollFixture,
1451 GINT_TO_POINTER (0),
1452 scroll_fixture_mixed_setup,
1454 scroll_fixture_teardown);
1455 g_test_add ("/TreeView/scrolling/new-row-mixed/path-3", ScrollFixture,
1456 GINT_TO_POINTER (3),
1457 scroll_fixture_mixed_setup,
1459 scroll_fixture_teardown);
1460 /* We scroll to 8 to test a partial visible row. The 8 is
1461 * based on my font setting of "Vera Sans 11" and
1462 * the separators set to 0. (This should be made dynamic; FIXME).
1464 g_test_add ("/TreeView/scrolling/new-row-mixed/path-5", ScrollFixture,
1465 GINT_TO_POINTER (5),
1466 scroll_fixture_mixed_setup,
1468 scroll_fixture_teardown);
1469 g_test_add ("/TreeView/scrolling/new-row-mixed/path-500", ScrollFixture,
1470 GINT_TO_POINTER (500),
1471 scroll_fixture_mixed_setup,
1473 scroll_fixture_teardown);
1474 g_test_add ("/TreeView/scrolling/new-row-mixed/path-999", ScrollFixture,
1475 GINT_TO_POINTER (999),
1476 scroll_fixture_mixed_setup,
1478 scroll_fixture_teardown);
1480 g_test_add ("/TreeView/scrolling/new-row-mixed/tree", ScrollFixture,
1482 scroll_fixture_mixed_tree_setup,
1483 scroll_new_row_tree,
1484 scroll_fixture_teardown);
1487 g_test_add ("/TreeView/scrolling/specific/bug-316689",
1488 ScrollFixture, NULL,
1489 scroll_fixture_constant_setup, test_bug316689,
1490 scroll_fixture_teardown);
1491 g_test_add_func ("/TreeView/scrolling/specific/bug-359231",
1493 g_test_add ("/TreeView/scrolling/specific/bug-93584",
1494 ScrollFixture, NULL,
1495 scroll_fixture_tree_setup, test_bug93584,
1496 scroll_fixture_teardown);
1497 g_test_add ("/TreeView/scrolling/specific/bug-111500",
1498 ScrollFixture, NULL,
1499 scroll_fixture_tree_setup, test_bug111500,
1500 scroll_fixture_teardown);
1501 g_test_add ("/TreeView/scrolling/specific/bug-111500-mixed",
1502 ScrollFixture, NULL,
1503 scroll_fixture_mixed_tree_setup, test_bug111500_mixed,
1504 scroll_fixture_teardown);
1505 g_test_add ("/TreeView/scrolling/specific/bug-163214",
1506 ScrollFixture, NULL,
1507 scroll_fixture_constant_setup, test_bug163214,
1508 scroll_fixture_teardown);
1510 return g_test_run ();