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, see <http://www.gnu.org/licenses/>.
20 /* Original v1.0 -- December 26, 2006
21 * Conversion to GLib/GTK+ test framework during December, 2007
29 #define VIEW_WIDTH 320
30 #define VIEW_HEIGHT 240
33 #define BIG_N_ROWS N_ROWS * 100
37 * - Test that nothing happens if the row is fully visible.
38 * - The tests are dependent on the theme/font (size measurements,
40 * - Convert to proper GTK+ coding style.
41 * - Briefly test scrolling in tree stores as well.
44 * - For tests with "mixed height" models, you must ensure that
45 * there are only two heights used in total and that the rows with
46 * height A and B are strictly alternating. The model creation
47 * functions already do this for you, but take this into account
48 * when you write a unit test that adds rows to such a created
49 * model, you must follow this rule otherwise things will break.
53 /* Constructing models for testing */
55 create_model (gboolean constant)
62 store = gtk_list_store_new (1, G_TYPE_STRING);
64 for (i = 0; i < N_ROWS; i++) {
65 gtk_list_store_append (store, &iter);
66 if (constant || i % 2 == 0)
67 gtk_list_store_set (store, &iter, 0, "Foo", -1);
69 gtk_list_store_set (store, &iter, 0, "Sliff\nSloff\nBleh", -1);
72 return GTK_TREE_MODEL (store);
76 create_big_model (gboolean constant)
83 store = gtk_list_store_new (1, G_TYPE_STRING);
85 for (i = 0; i < BIG_N_ROWS; i++) {
86 gtk_list_store_append (store, &iter);
87 if (constant || i % 2 == 0)
88 gtk_list_store_set (store, &iter, 0, "Foo", -1);
90 gtk_list_store_set (store, &iter, 0, "Sliff\nSloff\nBleh", -1);
93 return GTK_TREE_MODEL (store);
103 GtkWidget *tree_view;
108 scroll_fixture_setup (ScrollFixture *fixture,
110 gconstpointer test_data)
113 GtkCellRenderer *renderer;
114 GtkTreeViewColumn *column;
116 fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
118 sw = gtk_scrolled_window_new (NULL, NULL);
119 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
122 gtk_container_add (GTK_CONTAINER (fixture->window), sw);
124 fixture->tree_view = gtk_tree_view_new_with_model (model);
125 g_object_unref (model);
126 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (sw), VIEW_WIDTH);
127 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), VIEW_HEIGHT);
128 gtk_widget_set_size_request (fixture->tree_view, VIEW_WIDTH, VIEW_HEIGHT);
130 renderer = gtk_cell_renderer_text_new ();
131 g_object_set (renderer, "editable", TRUE, NULL);
132 column = gtk_tree_view_column_new_with_attributes ("Title",
137 gtk_tree_view_append_column (GTK_TREE_VIEW (fixture->tree_view), column);
138 gtk_container_add (GTK_CONTAINER (sw), fixture->tree_view);
141 /* sets up a fixture with a model with constant row heights */
143 scroll_fixture_constant_setup (ScrollFixture *fixture,
144 gconstpointer test_data)
146 scroll_fixture_setup (fixture, create_model (TRUE), test_data);
149 /* sets up a fixture with a model with varying row heights */
151 scroll_fixture_mixed_setup (ScrollFixture *fixture,
152 gconstpointer test_data)
154 scroll_fixture_setup (fixture, create_model (FALSE), test_data);
157 /* sets up a fixture with a large model with constant row heights */
159 scroll_fixture_constant_big_setup (ScrollFixture *fixture,
160 gconstpointer test_data)
162 scroll_fixture_setup (fixture, create_big_model (TRUE), test_data);
165 /* sets up a fixture with a large model with varying row heights */
167 scroll_fixture_mixed_big_setup (ScrollFixture *fixture,
168 gconstpointer test_data)
170 scroll_fixture_setup (fixture, create_big_model (FALSE), test_data);
173 /* sets up a fixture with only a single row for the "single row scroll" test */
175 scroll_fixture_single_setup (ScrollFixture *fixture,
176 gconstpointer test_data)
179 GtkTreeIter iter, child;
181 store = gtk_tree_store_new (1, G_TYPE_STRING);
183 gtk_tree_store_append (store, &iter, NULL);
184 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
186 gtk_tree_store_append (store, &child, &iter);
187 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
189 /* The teardown will also destroy the model */
190 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
193 /* sets up a fixture with a tree store */
195 scroll_fixture_tree_setup (ScrollFixture *fixture,
196 gconstpointer test_data)
199 GtkTreeIter iter, child;
202 store = gtk_tree_store_new (1, G_TYPE_STRING);
204 gtk_tree_store_append (store, &iter, NULL);
205 gtk_tree_store_set (store, &iter, 0, "Root node", -1);
207 for (i = 0; i < 5; i++) {
208 gtk_tree_store_append (store, &child, &iter);
209 gtk_tree_store_set (store, &child, 0, "Child node", -1);
212 for (i = 0; i < 5; i++) {
213 gtk_tree_store_append (store, &iter, NULL);
214 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
217 /* The teardown will also destroy the model */
218 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
222 scroll_fixture_mixed_tree_setup (ScrollFixture *fixture,
223 gconstpointer test_data)
226 GtkTreeIter iter, child;
229 store = gtk_tree_store_new (1, G_TYPE_STRING);
231 gtk_tree_store_append (store, &iter, NULL);
232 gtk_tree_store_set (store, &iter, 0, "Root\nnode", -1);
234 for (i = 0; i < 5; i++) {
235 gtk_tree_store_append (store, &child, &iter);
237 gtk_tree_store_set (store, &child, 0, "Child node", -1);
239 gtk_tree_store_set (store, &child,
240 0, "Child\nnode", -1);
243 for (i = 0; i < 5; i++) {
244 gtk_tree_store_append (store, &iter, NULL);
246 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
248 gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
251 /* The teardown will also destroy the model */
252 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
256 scroll_fixture_teardown (ScrollFixture *fixture,
257 gconstpointer test_data)
259 gtk_widget_destroy (fixture->window);
263 * Position check and helpers.
273 get_row_start_for_index (GtkTreeView *tree_view, int index)
275 gint height1, height2;
280 path = gtk_tree_path_new_from_indices (0, -1);
281 gtk_tree_view_get_background_area (tree_view, path, NULL, &rect);
282 height1 = rect.height;
284 gtk_tree_path_next (path);
285 gtk_tree_view_get_background_area (tree_view, path, NULL, &rect);
286 height2 = rect.height;
287 gtk_tree_path_free (path);
289 row_start = (index / 2) * height1 + (index / 2) * height2;
291 row_start += height1;
297 get_pos_from_path (GtkTreeView *tree_view,
300 GtkAdjustment *vadjustment)
304 row_start = get_row_start_for_index (tree_view,
305 gtk_tree_path_get_indices (path)[0]);
307 if (row_start + row_height < gtk_adjustment_get_page_size (vadjustment))
310 if (row_start >= gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment))
317 assert_position_with_align (GtkTreeView *tree_view,
324 GtkAdjustment *vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
326 /* Switch on row-align: 0.0, 0.5, 1.0 */
327 switch ((int)(row_align * 2.)) {
329 if (pos == POS_TOP || pos == POS_CENTER) {
330 /* The row in question is the first row
332 * - rect.y should be zero
333 * - dy should be equal to the top
334 * y coordinate of the row.
336 g_assert (row_y == 0);
337 g_assert (gtk_adjustment_get_value (vadjustment) == row_start);
339 /* The row can be anywhere at the last
340 * page of the tree view.
341 * - dy is set to the start of the
344 g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
351 && row_start < (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2) {
352 /* For the first half of the top view we can't
353 * center the row in the view, instead we
354 * show the first page.
355 * - dy should be zero
357 g_assert (gtk_adjustment_get_value (vadjustment) == 0);
358 } else if (pos == POS_BOTTOM
359 && row_start + row_height >= gtk_adjustment_get_upper (vadjustment) - (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2) {
360 /* For the last half of the bottom view we
361 * can't center the row in the view, instead
362 * we show the last page.
363 * - dy should be the start of the
366 g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
368 /* The row is located in the middle of
370 * - top y coordinate is equal to
371 * middle of the view minus
372 * half the height of the row.
373 * (ie. the row's center is at the
374 * center of the view).
376 gdouble middle = (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2.0;
377 g_assert (row_y == ceil (middle) || row_y == floor (middle));
383 if (pos == POS_TOP) {
384 /* The row can be anywhere on the
385 * first page of the tree view.
388 g_assert (gtk_adjustment_get_value (vadjustment) == 0);
389 } else if (pos == POS_CENTER || pos == POS_BOTTOM) {
390 /* The row is the last row visible in the
392 * - rect.y is set to the top of the
394 * - row_start is greater than page_size
395 * (ie we are not on the first page).
396 * - dy is greater than zero
398 g_assert (row_start >= gtk_adjustment_get_page_size (vadjustment)
399 || row_start + row_height >= gtk_adjustment_get_page_size (vadjustment));
400 g_assert (row_y == gtk_adjustment_get_page_size (vadjustment) - row_height);
407 assert_position_without_align (GtkTreeView *tree_view,
411 GtkAdjustment *vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
413 /* Without align the tree view does as less work as possible,
414 * so basically we only have to check whether the row
415 * is visible on the screen.
417 g_assert (gtk_adjustment_get_value (vadjustment) <= row_start);
418 g_assert (gtk_adjustment_get_value (vadjustment) + gtk_adjustment_get_page_size (vadjustment) >= row_start + row_height);
422 test_position (GtkTreeView *tree_view,
433 /* Get the location of the path we scrolled to */
434 gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
437 row_start = get_row_start_for_index (GTK_TREE_VIEW (tree_view),
438 gtk_tree_path_get_indices (path)[0]);
441 pos = get_pos_from_path (GTK_TREE_VIEW (tree_view),
443 gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view)));
445 /* This is only tested for during test_single() */
446 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
447 if (gtk_tree_model_iter_n_children (model, NULL) == 1) {
448 GtkAllocation allocation;
449 GtkTreePath *tmppath;
451 /* Test nothing is dangling at the bottom; read
452 * description for test_single() for more information.
455 /* FIXME: hardcoded width */
456 gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
457 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), 0, allocation.height - 30, &tmppath, NULL, NULL, NULL)) {
458 g_assert_not_reached ();
459 gtk_tree_path_free (tmppath);
463 path_str = gtk_tree_path_to_string (path);
465 assert_position_with_align (tree_view, pos, rect.y,
466 row_start, rect.height, row_align);
468 assert_position_without_align (tree_view, row_start, rect.height);
479 /* Testing scrolling to various positions with various alignments */
482 scroll (ScrollFixture *fixture,
487 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
489 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
491 use_align, row_align, 0.0);
493 gtk_widget_show_all (fixture->window);
495 while (gtk_events_pending ())
496 gtk_main_iteration ();
498 test_position (GTK_TREE_VIEW (fixture->tree_view), path,
499 use_align, row_align);
503 scroll_no_align (ScrollFixture *fixture,
504 gconstpointer test_data)
508 path = gtk_tree_path_new_from_string (test_data);
509 scroll (fixture, path, FALSE, 0.0);
510 gtk_tree_path_free (path);
514 scroll_align_0_0 (ScrollFixture *fixture,
515 gconstpointer test_data)
519 path = gtk_tree_path_new_from_string (test_data);
520 scroll (fixture, path, TRUE, 0.0);
521 gtk_tree_path_free (path);
525 scroll_align_0_5 (ScrollFixture *fixture,
526 gconstpointer test_data)
530 path = gtk_tree_path_new_from_string (test_data);
531 scroll (fixture, path, TRUE, 0.5);
532 gtk_tree_path_free (path);
536 scroll_align_1_0 (ScrollFixture *fixture,
537 gconstpointer test_data)
541 path = gtk_tree_path_new_from_string (test_data);
542 scroll (fixture, path, TRUE, 1.0);
543 gtk_tree_path_free (path);
548 scroll_after_realize (ScrollFixture *fixture,
553 gtk_widget_show_all (fixture->window);
555 while (gtk_events_pending ())
556 gtk_main_iteration ();
558 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
560 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
562 use_align, row_align, 0.0);
564 while (gtk_events_pending ())
565 gtk_main_iteration ();
567 test_position (GTK_TREE_VIEW (fixture->tree_view), path,
568 use_align, row_align);
572 scroll_after_no_align (ScrollFixture *fixture,
573 gconstpointer test_data)
577 path = gtk_tree_path_new_from_string (test_data);
578 scroll_after_realize (fixture, path, FALSE, 0.0);
579 gtk_tree_path_free (path);
583 scroll_after_align_0_0 (ScrollFixture *fixture,
584 gconstpointer test_data)
588 path = gtk_tree_path_new_from_string (test_data);
589 scroll_after_realize (fixture, path, TRUE, 0.0);
590 gtk_tree_path_free (path);
594 scroll_after_align_0_5 (ScrollFixture *fixture,
595 gconstpointer test_data)
599 path = gtk_tree_path_new_from_string (test_data);
600 scroll_after_realize (fixture, path, TRUE, 0.5);
601 gtk_tree_path_free (path);
605 scroll_after_align_1_0 (ScrollFixture *fixture,
606 gconstpointer test_data)
610 path = gtk_tree_path_new_from_string (test_data);
611 scroll_after_realize (fixture, path, TRUE, 1.0);
612 gtk_tree_path_free (path);
617 scroll_both_realize (ScrollFixture *fixture,
624 gtk_widget_show_all (fixture->window);
627 end = gtk_tree_path_new_from_indices (999, -1);
629 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), end,
631 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
633 use_align, row_align, 0.0);
634 gtk_tree_path_free (end);
636 while (gtk_events_pending ())
637 gtk_main_iteration ();
639 /* Scroll to final position */
640 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
642 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
644 use_align, row_align, 0.0);
646 while (gtk_events_pending ())
647 gtk_main_iteration ();
649 test_position (GTK_TREE_VIEW (fixture->tree_view), path,
650 use_align, row_align);
654 scroll_both_no_align (ScrollFixture *fixture,
655 gconstpointer test_data)
659 path = gtk_tree_path_new_from_string (test_data);
660 scroll_both_realize (fixture, path, FALSE, 0.0);
661 gtk_tree_path_free (path);
665 scroll_both_align_0_0 (ScrollFixture *fixture,
666 gconstpointer test_data)
670 path = gtk_tree_path_new_from_string (test_data);
671 scroll_both_realize (fixture, path, TRUE, 0.0);
672 gtk_tree_path_free (path);
676 scroll_both_align_0_5 (ScrollFixture *fixture,
677 gconstpointer test_data)
681 path = gtk_tree_path_new_from_string (test_data);
682 scroll_both_realize (fixture, path, TRUE, 0.5);
683 gtk_tree_path_free (path);
687 scroll_both_align_1_0 (ScrollFixture *fixture,
688 gconstpointer test_data)
692 path = gtk_tree_path_new_from_string (test_data);
693 scroll_both_realize (fixture, path, TRUE, 1.0);
694 gtk_tree_path_free (path);
697 /* Testing scrolling to a newly created row */
699 create_new_row (GtkListStore *store,
706 gtk_list_store_prepend (store, iter);
710 /* Add a row in the middle of the visible area */
711 gtk_list_store_insert (store, iter, 3);
715 /* Add a row in the middle of the visible area */
716 gtk_list_store_insert (store, iter, 4);
720 /* Add a row which is not completely visible */
721 gtk_list_store_insert (store, iter, 5);
725 /* Add a row which is not completely visible */
726 gtk_list_store_insert (store, iter, 8);
730 /* Add a row in the middle */
731 gtk_list_store_insert (store, iter, 500);
736 gtk_list_store_append (store, iter);
740 gtk_list_store_set (store, iter, 0, "New...", -1);
744 scroll_new_row_editing_started (GtkCellRenderer *cell,
745 GtkCellEditable *editable,
749 GtkWidget **widget = user_data;
751 *widget = GTK_WIDGET (editable);
755 test_editable_position (GtkWidget *tree_view,
757 GtkTreePath *cursor_path)
759 GtkAllocation allocation;
762 gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
763 cursor_path, NULL, &rect);
765 /* There are all in bin_window coordinates */
766 gtk_widget_get_allocation (editable, &allocation);
767 g_assert (allocation.y == rect.y + ((rect.height - allocation.height) / 2));
771 scroll_new_row (ScrollFixture *fixture,
772 gconstpointer test_data)
774 GtkTreeIter scroll_iter;
775 GtkTreePath *scroll_path;
778 GtkTreeViewColumn *column;
781 /* The aim of this test is creating a new row at several places,
782 * and immediately put the cursor on it. TreeView should correctly
783 * scroll to the row and show the editable widget.
788 g_test_bug ("81627");
790 gtk_widget_show_all (fixture->window);
792 while (gtk_events_pending ())
793 gtk_main_iteration ();
795 /* Create the new row and scroll to it */
796 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
797 create_new_row (GTK_LIST_STORE (model), GPOINTER_TO_INT (test_data),
800 /* Set up a signal handler to acquire the editable widget */
801 column = gtk_tree_view_get_column (GTK_TREE_VIEW (fixture->tree_view), 0);
802 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
804 g_signal_connect (G_OBJECT (renderers->data), "editing-started",
805 G_CALLBACK (scroll_new_row_editing_started),
808 /* Now set the cursor on the path and start editing */
809 scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
810 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view),
815 while (gtk_events_pending ())
816 gtk_main_iteration ();
819 test_position (GTK_TREE_VIEW (fixture->tree_view), scroll_path,
821 test_editable_position (fixture->tree_view, editable, scroll_path);
823 gtk_tree_path_free (scroll_path);
827 scroll_new_row_tree (ScrollFixture *fixture,
828 gconstpointer test_data)
831 GtkAdjustment *vadjustment;
834 /* The goal of this test is to append new rows at the end of a tree
835 * store and immediately scroll to them. If there is a parent
836 * node with a couple of childs in the "area above" to explore,
837 * this used to lead to unexpected results due to a bug.
839 * This issue has been reported by Miroslav Rajcic on
840 * gtk-app-devel-list:
841 * http://mail.gnome.org/archives/gtk-app-devel-list/2008-December/msg00068.html
844 gtk_widget_show_all (fixture->window);
846 gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
848 while (gtk_events_pending ())
849 gtk_main_iteration ();
851 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
852 vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
854 for (i = 0; i < 5; i++) {
855 GtkTreeIter scroll_iter;
856 GtkTreePath *scroll_path;
858 gtk_tree_store_append (GTK_TREE_STORE (model), &scroll_iter,
860 gtk_tree_store_set (GTK_TREE_STORE (model), &scroll_iter,
863 scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
864 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
865 scroll_path, NULL, FALSE, 0.0, 0.0);
866 gtk_tree_path_free (scroll_path);
868 while (gtk_events_pending ())
869 gtk_main_iteration ();
871 /* Test position, the scroll bar must be at the end */
872 g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
876 /* Test for GNOME bugzilla bug 359231; tests "recovery when removing a bunch of
877 * rows at the bottom.
880 test_bug316689 (ScrollFixture *fixture,
881 gconstpointer test_data)
885 GtkAdjustment *vadjustment;
888 /* The aim of this test is to scroll to the bottom of a TreeView,
889 * remove at least one page_size of items and check if TreeView
890 * correctly corrects the scroll bar (else they will look "broken").
895 g_test_bug ("316689");
897 /* Scroll to some place close to the end */
898 path = gtk_tree_path_new_from_indices (N_ROWS - 4, -1);
899 scroll (fixture, path, FALSE, 0.0);
900 gtk_tree_path_free (path);
902 /* No need for a while events pending loop here, scroll() does this for us.
904 * We now remove a bunch of rows, wait for events to process and then
905 * check the adjustments to see if the TreeView gracefully recovered.
907 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
909 while (gtk_tree_model_iter_nth_child (model, &iter, NULL, N_ROWS - 15))
910 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
912 while (gtk_events_pending ())
913 gtk_main_iteration ();
915 vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
917 g_assert (gtk_adjustment_get_value (vadjustment) + gtk_adjustment_get_page_size (vadjustment) <= gtk_adjustment_get_upper (vadjustment));
918 g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
922 /* Test for GNOME bugzilla bug 359231 */
924 test_bug359231 (void)
927 int height1, height2;
929 GtkTreeIter iter, child;
932 ScrollFixture *fixture;
935 g_test_bug ("359231");
937 /* Create model (GtkTreeStore in this case) */
938 store = gtk_tree_store_new (1, G_TYPE_STRING);
940 gtk_tree_store_append (store, &iter, NULL);
941 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
943 for (i = 0; i < 4; i++) {
944 gtk_tree_store_append (store, &child, &iter);
945 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
948 fixture = g_new0 (ScrollFixture, 1);
949 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), NULL);
950 gtk_widget_show_all (fixture->window);
952 while (gtk_events_pending ())
953 gtk_main_iteration ();
955 /* Prepend some rows at the top, expand */
956 gtk_tree_store_prepend (store, &iter, NULL);
957 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
959 gtk_tree_store_prepend (store, &child, &iter);
960 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
962 gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
964 while (gtk_events_pending ())
965 gtk_main_iteration ();
967 /* Test if height of row 0:0 is correct */
968 path = gtk_tree_path_new_from_indices (0, -1);
969 gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
971 height1 = rect.height;
973 gtk_tree_path_down (path);
974 gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
976 height2 = rect.height;
977 gtk_tree_path_free (path);
979 g_assert (height2 > height1);
981 /* Clean up; the tear down also cleans up the model */
982 scroll_fixture_teardown (fixture, NULL);
985 /* Test for GNOME bugzilla bug 93584. We add 150 rows to an existing
986 * small model, and scroll to one of these with alignment.
989 test_bug93584 (ScrollFixture *fixture,
990 gconstpointer test_data)
996 g_test_bug ("93584");
998 /* Mimic state as in original test case */
999 g_signal_connect (G_OBJECT (fixture->tree_view), "realize",
1000 G_CALLBACK (gtk_tree_view_expand_all), NULL);
1001 gtk_widget_show_all (fixture->window);
1003 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1006 for (i = 0; i < 150; i++) {
1009 gtk_tree_store_append (store, &iter, NULL);
1010 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1013 row = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1016 path = gtk_tree_path_new_from_indices (row, -1);
1017 scroll (fixture, path, TRUE, 0.5);
1018 gtk_tree_path_free (path);
1021 /* GNOME bugzilla bug 111500. Expand a row and immediately scroll
1022 * to its first child. Make sure that expansion happens in currently
1026 test_bug111500 (ScrollFixture *fixture,
1027 gconstpointer test_data)
1030 GtkTreeStore *store;
1034 g_test_bug ("111500");
1036 gtk_widget_show_all (fixture->window);
1038 /* Make sure all events have been processed and the window
1041 while (gtk_events_pending ())
1042 gtk_main_iteration ();
1044 /* Further prepare model */
1045 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1047 for (i = 0; i < 15; i++) {
1050 gtk_tree_store_append (store, &iter, NULL);
1051 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1054 len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1055 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
1058 for (i = 0; i < 5; i++) {
1061 gtk_tree_store_append (store, &iter, &parent);
1062 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1065 path = gtk_tree_path_new_from_indices (len - 1, -1);
1066 gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1069 gtk_tree_path_down (path);
1071 scroll (fixture, path, FALSE, 0.5);
1072 gtk_tree_path_free (path);
1076 test_bug111500_mixed (ScrollFixture *fixture,
1077 gconstpointer test_data)
1080 GtkTreeStore *store;
1084 g_test_bug ("111500");
1086 gtk_widget_show_all (fixture->window);
1088 /* Make sure all events have been processed and the window
1091 while (gtk_events_pending ())
1092 gtk_main_iteration ();
1094 /* Further prepare model */
1095 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1097 for (i = 0; i < 15; i++) {
1100 gtk_tree_store_append (store, &iter, NULL);
1102 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1104 gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
1107 len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1108 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
1111 for (i = 0; i < 5; i++) {
1114 gtk_tree_store_append (store, &iter, &parent);
1116 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1118 gtk_tree_store_set (store, &iter, 0, "Row\nRow", -1);
1121 path = gtk_tree_path_new_from_indices (len - 1, -1);
1122 gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1125 gtk_tree_path_down (path);
1127 scroll (fixture, path, FALSE, 0.5);
1128 gtk_tree_path_free (path);
1131 /* Test for GNOME bugzilla bug 163214. Invalidate a couple of rows,
1132 * then scroll to one of these.
1135 test_bug163214 (ScrollFixture *fixture,
1136 gconstpointer test_data)
1139 GtkListStore *store;
1142 g_test_bug ("163214");
1144 gtk_widget_show_all (fixture->window);
1146 /* Make sure all events have been processed and the window
1149 while (gtk_events_pending ())
1150 gtk_main_iteration ();
1152 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1154 /* Invalidate a page of rows */
1155 for (i = 100; i < 110; i++) {
1158 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1160 gtk_list_store_set (store, &iter, 0, "Row", -1);
1163 /* Then scroll to that page. */
1164 path = gtk_tree_path_new_from_indices (105, -1);
1165 scroll (fixture, path, TRUE, 0.5);
1166 gtk_tree_path_free (path);
1168 /* Make sure all events have been processed and the window
1171 while (gtk_events_pending ())
1172 gtk_main_iteration ();
1174 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1176 /* Invalidate a page of rows */
1177 for (i = 300; i < 310; i++) {
1180 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1182 gtk_list_store_set (store, &iter, 0, "Row", -1);
1185 /* Then scroll to the first row */
1186 path = gtk_tree_path_new_from_indices (0, -1);
1187 scroll (fixture, path, TRUE, 0.5);
1188 gtk_tree_path_free (path);
1191 /* Infrastructure for automatically adding tests */
1200 test_type_string (int test_type)
1202 switch (test_type) {
1204 return "before-realize";
1207 return "after-realize";
1217 align_string (gboolean use_align,
1223 return g_strdup ("no-align");
1225 ret = g_strdup_printf ("align-%1.1f", row_align);
1230 add_test (const char *path,
1235 void (* setup) (ScrollFixture *, gconstpointer),
1236 void (* scroll_func) (ScrollFixture *, gconstpointer))
1241 align = align_string (use_align, row_align);
1243 test_path = g_strdup_printf ("/TreeView/scrolling/%s/%s-height/path-%s-%s",
1244 test_type_string (test_type),
1245 mixed ? "mixed" : "constant",
1249 g_test_add (test_path, ScrollFixture, path,
1250 setup, scroll_func, scroll_fixture_teardown);
1256 add_tests (gboolean mixed,
1260 void (*scroll_func) (ScrollFixture *, gconstpointer))
1262 void (* setup) (ScrollFixture *, gconstpointer);
1265 setup = scroll_fixture_mixed_setup;
1267 setup = scroll_fixture_constant_setup;
1269 add_test ("0", mixed, test_type, use_align, row_align, setup, scroll_func);
1270 add_test ("2", mixed, test_type, use_align, row_align, setup, scroll_func);
1271 add_test ("5", mixed, test_type, use_align, row_align, setup, scroll_func);
1272 /* We scroll to 8 to test a partial visible row. The 8 is
1273 * based on my font setting of "Vera Sans 11" and
1274 * the separators set to 0. (This should be made dynamic; FIXME).
1276 add_test ("8", mixed, test_type, use_align, row_align, setup, scroll_func);
1277 add_test ("10", mixed, test_type, use_align, row_align, setup, scroll_func);
1278 add_test ("250", mixed, test_type, use_align, row_align, setup, scroll_func);
1279 add_test ("500", mixed, test_type, use_align, row_align, setup, scroll_func);
1280 add_test ("750", mixed, test_type, use_align, row_align, setup, scroll_func);
1281 add_test ("990", mixed, test_type, use_align, row_align, setup, scroll_func);
1282 add_test ("991", mixed, test_type, use_align, row_align, setup, scroll_func);
1283 add_test ("995", mixed, test_type, use_align, row_align, setup, scroll_func);
1284 add_test ("997", mixed, test_type, use_align, row_align, setup, scroll_func);
1285 add_test ("999", mixed, test_type, use_align, row_align, setup, scroll_func);
1289 main (int argc, char **argv)
1291 gtk_test_init (&argc, &argv);
1293 /* Scrolls before realization */
1294 add_tests (FALSE, BEFORE, FALSE, 0.0, scroll_no_align);
1295 if (g_test_thorough ())
1296 add_tests (TRUE, BEFORE, FALSE, 0.0, scroll_no_align);
1298 add_tests (FALSE, BEFORE, TRUE, 0.0, scroll_align_0_0);
1299 if (g_test_thorough ())
1300 add_tests (TRUE, BEFORE, TRUE, 0.0, scroll_align_0_0);
1302 add_tests (FALSE, BEFORE, TRUE, 0.5, scroll_align_0_5);
1303 if (g_test_thorough ())
1304 add_tests (TRUE, BEFORE, TRUE, 0.5, scroll_align_0_5);
1306 add_tests (FALSE, BEFORE, TRUE, 1.0, scroll_align_1_0);
1307 if (g_test_thorough ())
1308 add_tests (TRUE, BEFORE, TRUE, 1.0, scroll_align_1_0);
1310 /* Scrolls after realization */
1311 add_tests (FALSE, AFTER, FALSE, 0.0, scroll_after_no_align);
1312 if (g_test_thorough ())
1313 add_tests (TRUE, AFTER, FALSE, 0.0, scroll_after_no_align);
1315 add_tests (FALSE, AFTER, TRUE, 0.0, scroll_after_align_0_0);
1316 if (g_test_thorough ())
1317 add_tests (TRUE, AFTER, TRUE, 0.0, scroll_after_align_0_0);
1319 add_tests (FALSE, AFTER, TRUE, 0.5, scroll_after_align_0_5);
1320 if (g_test_thorough ())
1321 add_tests (TRUE, AFTER, TRUE, 0.5, scroll_after_align_0_5);
1323 add_tests (FALSE, AFTER, TRUE, 1.0, scroll_after_align_1_0);
1324 if (g_test_thorough ())
1325 add_tests (TRUE, AFTER, TRUE, 1.0, scroll_after_align_1_0);
1327 /* Scroll to end before realization, to a real position after */
1328 if (g_test_thorough ()) {
1329 add_tests (FALSE, BOTH, FALSE, 0.0, scroll_both_no_align);
1330 add_tests (TRUE, BOTH, FALSE, 0.0, scroll_both_no_align);
1332 add_tests (FALSE, BOTH, TRUE, 0.0, scroll_both_align_0_0);
1333 add_tests (TRUE, BOTH, TRUE, 0.0, scroll_both_align_0_0);
1335 add_tests (FALSE, BOTH, TRUE, 0.5, scroll_both_align_0_5);
1336 add_tests (TRUE, BOTH, TRUE, 0.5, scroll_both_align_0_5);
1338 add_tests (FALSE, BOTH, TRUE, 1.0, scroll_both_align_1_0);
1339 add_tests (TRUE, BOTH, TRUE, 1.0, scroll_both_align_1_0);
1342 /* Test different alignments in view with single row */
1343 g_test_add ("/TreeView/scrolling/single-row/no-align",
1345 scroll_fixture_single_setup,
1347 scroll_fixture_teardown);
1348 g_test_add ("/TreeView/scrolling/single-row/align-0.0",
1350 scroll_fixture_single_setup,
1352 scroll_fixture_teardown);
1353 g_test_add ("/TreeView/scrolling/single-row/align-0.5",
1355 scroll_fixture_single_setup,
1357 scroll_fixture_teardown);
1358 g_test_add ("/TreeView/scrolling/single-row/align-1.0",
1360 scroll_fixture_single_setup,
1362 scroll_fixture_teardown);
1364 /* Test scrolling in a very large model; also very slow */
1365 if (g_test_slow ()) {
1366 g_test_add ("/TreeView/scrolling/large-model/constant-height/middle-no-align",
1367 ScrollFixture, "50000",
1368 scroll_fixture_constant_big_setup,
1370 scroll_fixture_teardown);
1371 g_test_add ("/TreeView/scrolling/large-model/constant-height/end-no-align",
1372 ScrollFixture, "99999",
1373 scroll_fixture_constant_big_setup,
1375 scroll_fixture_teardown);
1377 g_test_add ("/TreeView/scrolling/large-model/mixed-height/middle-no-align",
1378 ScrollFixture, "50000",
1379 scroll_fixture_mixed_big_setup,
1381 scroll_fixture_teardown);
1382 g_test_add ("/TreeView/scrolling/large-model/mixed-height/end-no-align",
1383 ScrollFixture, "99999",
1384 scroll_fixture_mixed_big_setup,
1386 scroll_fixture_teardown);
1389 /* Test scrolling to a newly created row */
1390 g_test_add ("/TreeView/scrolling/new-row/path-0", ScrollFixture,
1391 GINT_TO_POINTER (0),
1392 scroll_fixture_constant_setup,
1394 scroll_fixture_teardown);
1395 g_test_add ("/TreeView/scrolling/new-row/path-4", ScrollFixture,
1396 GINT_TO_POINTER (4),
1397 scroll_fixture_constant_setup,
1399 scroll_fixture_teardown);
1400 /* We scroll to 8 to test a partial visible row. The 8 is
1401 * based on my font setting of "Vera Sans 11" and
1402 * the separators set to 0. (This should be made dynamic; FIXME).
1404 g_test_add ("/TreeView/scrolling/new-row/path-8", ScrollFixture,
1405 GINT_TO_POINTER (8),
1406 scroll_fixture_constant_setup,
1408 scroll_fixture_teardown);
1409 g_test_add ("/TreeView/scrolling/new-row/path-500", ScrollFixture,
1410 GINT_TO_POINTER (500),
1411 scroll_fixture_constant_setup,
1413 scroll_fixture_teardown);
1414 g_test_add ("/TreeView/scrolling/new-row/path-999", ScrollFixture,
1415 GINT_TO_POINTER (999),
1416 scroll_fixture_constant_setup,
1418 scroll_fixture_teardown);
1420 g_test_add ("/TreeView/scrolling/new-row/tree", ScrollFixture,
1422 scroll_fixture_tree_setup,
1423 scroll_new_row_tree,
1424 scroll_fixture_teardown);
1426 /* Test scrolling to a newly created row, in a mixed height model */
1427 g_test_add ("/TreeView/scrolling/new-row-mixed/path-0", ScrollFixture,
1428 GINT_TO_POINTER (0),
1429 scroll_fixture_mixed_setup,
1431 scroll_fixture_teardown);
1432 g_test_add ("/TreeView/scrolling/new-row-mixed/path-3", ScrollFixture,
1433 GINT_TO_POINTER (3),
1434 scroll_fixture_mixed_setup,
1436 scroll_fixture_teardown);
1437 /* We scroll to 8 to test a partial visible row. The 8 is
1438 * based on my font setting of "Vera Sans 11" and
1439 * the separators set to 0. (This should be made dynamic; FIXME).
1441 g_test_add ("/TreeView/scrolling/new-row-mixed/path-5", ScrollFixture,
1442 GINT_TO_POINTER (5),
1443 scroll_fixture_mixed_setup,
1445 scroll_fixture_teardown);
1446 g_test_add ("/TreeView/scrolling/new-row-mixed/path-500", ScrollFixture,
1447 GINT_TO_POINTER (500),
1448 scroll_fixture_mixed_setup,
1450 scroll_fixture_teardown);
1451 g_test_add ("/TreeView/scrolling/new-row-mixed/path-999", ScrollFixture,
1452 GINT_TO_POINTER (999),
1453 scroll_fixture_mixed_setup,
1455 scroll_fixture_teardown);
1457 g_test_add ("/TreeView/scrolling/new-row-mixed/tree", ScrollFixture,
1459 scroll_fixture_mixed_tree_setup,
1460 scroll_new_row_tree,
1461 scroll_fixture_teardown);
1464 g_test_add ("/TreeView/scrolling/specific/bug-316689",
1465 ScrollFixture, NULL,
1466 scroll_fixture_constant_setup, test_bug316689,
1467 scroll_fixture_teardown);
1468 g_test_add_func ("/TreeView/scrolling/specific/bug-359231",
1470 g_test_add ("/TreeView/scrolling/specific/bug-93584",
1471 ScrollFixture, NULL,
1472 scroll_fixture_tree_setup, test_bug93584,
1473 scroll_fixture_teardown);
1474 g_test_add ("/TreeView/scrolling/specific/bug-111500",
1475 ScrollFixture, NULL,
1476 scroll_fixture_tree_setup, test_bug111500,
1477 scroll_fixture_teardown);
1478 g_test_add ("/TreeView/scrolling/specific/bug-111500-mixed",
1479 ScrollFixture, NULL,
1480 scroll_fixture_mixed_tree_setup, test_bug111500_mixed,
1481 scroll_fixture_teardown);
1482 g_test_add ("/TreeView/scrolling/specific/bug-163214",
1483 ScrollFixture, NULL,
1484 scroll_fixture_constant_setup, test_bug163214,
1485 scroll_fixture_teardown);
1487 return g_test_run ();