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,
302 GtkAdjustment *vadjustment)
306 row_start = get_row_start_for_index (tree_view,
307 gtk_tree_path_get_indices (path)[0]);
309 if (row_start + row_height < gtk_adjustment_get_page_size (vadjustment))
312 if (row_start >= gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment))
319 test_position_with_align (GtkTreeView *tree_view,
326 gboolean passed = TRUE;
327 GtkAdjustment *vadjustment = 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 (gtk_adjustment_get_value (vadjustment) != 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 (gtk_adjustment_get_value (vadjustment) != gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment))
357 && row_start < gtk_adjustment_get_page_size (vadjustment) / 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 (gtk_adjustment_get_value (vadjustment) != 0)
365 } else if (pos == POS_BOTTOM
366 && row_start >= gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment) / 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 (gtk_adjustment_get_value (vadjustment) != gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment))
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 = gtk_adjustment_get_page_size (vadjustment) / 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 (gtk_adjustment_get_value (vadjustment) != 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 < gtk_adjustment_get_page_size (vadjustment)
409 && row_start + row_height < gtk_adjustment_get_page_size (vadjustment))
411 if (gtk_adjustment_get_value (vadjustment) <= 0)
413 if (row_y != gtk_adjustment_get_page_size (vadjustment) - row_height)
423 test_position_without_align (GtkTreeView *tree_view,
427 GtkAdjustment *vadjustment = 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 (gtk_adjustment_get_value (vadjustment) <= row_start
434 && gtk_adjustment_get_value (vadjustment) + gtk_adjustment_get_page_size (vadjustment) >= 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;
782 gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
783 cursor_path, NULL, &rect);
785 /* There are all in bin_window coordinates */
786 gtk_widget_get_allocation (editable, &allocation);
787 g_assert (allocation.y == rect.y + ((rect.height - allocation.height) / 2));
791 scroll_new_row (ScrollFixture *fixture,
792 gconstpointer test_data)
794 GtkTreeIter scroll_iter;
795 GtkTreePath *scroll_path;
798 GtkTreeViewColumn *column;
801 /* The aim of this test is creating a new row at several places,
802 * and immediately put the cursor on it. TreeView should correctly
803 * scroll to the row and show the editable widget.
808 g_test_bug ("81627");
810 gtk_widget_show_all (fixture->window);
812 while (gtk_events_pending ())
813 gtk_main_iteration ();
815 /* Create the new row and scroll to it */
816 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
817 create_new_row (GTK_LIST_STORE (model), GPOINTER_TO_INT (test_data),
820 /* Set up a signal handler to acquire the editable widget */
821 column = gtk_tree_view_get_column (GTK_TREE_VIEW (fixture->tree_view), 0);
822 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
824 g_signal_connect (G_OBJECT (renderers->data), "editing-started",
825 G_CALLBACK (scroll_new_row_editing_started),
828 /* Now set the cursor on the path and start editing */
829 scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
830 gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view),
835 while (gtk_events_pending ())
836 gtk_main_iteration ();
839 test_position (GTK_TREE_VIEW (fixture->tree_view), scroll_path,
841 test_editable_position (fixture->tree_view, editable, scroll_path);
843 gtk_tree_path_free (scroll_path);
847 scroll_new_row_tree (ScrollFixture *fixture,
848 gconstpointer test_data)
851 GtkAdjustment *vadjustment;
854 /* The goal of this test is to append new rows at the end of a tree
855 * store and immediately scroll to them. If there is a parent
856 * node with a couple of childs in the "area above" to explore,
857 * this used to lead to unexpected results due to a bug.
859 * This issue has been reported by Miroslav Rajcic on
860 * gtk-app-devel-list:
861 * http://mail.gnome.org/archives/gtk-app-devel-list/2008-December/msg00068.html
864 gtk_widget_show_all (fixture->window);
866 gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
868 while (gtk_events_pending ())
869 gtk_main_iteration ();
871 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
872 vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
874 for (i = 0; i < 5; i++) {
875 GtkTreeIter scroll_iter;
876 GtkTreePath *scroll_path;
878 gtk_tree_store_append (GTK_TREE_STORE (model), &scroll_iter,
880 gtk_tree_store_set (GTK_TREE_STORE (model), &scroll_iter,
883 scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
884 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
885 scroll_path, NULL, FALSE, 0.0, 0.0);
886 gtk_tree_path_free (scroll_path);
888 while (gtk_events_pending ())
889 gtk_main_iteration ();
891 /* Test position, the scroll bar must be at the end */
892 g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
896 /* Test for GNOME bugzilla bug 359231; tests "recovery when removing a bunch of
897 * rows at the bottom.
900 test_bug316689 (ScrollFixture *fixture,
901 gconstpointer test_data)
905 GtkAdjustment *vadjustment;
908 /* The aim of this test is to scroll to the bottom of a TreeView,
909 * remove at least one page_size of items and check if TreeView
910 * correctly corrects the scroll bar (else they will look "broken").
915 g_test_bug ("316689");
917 /* Scroll to some place close to the end */
918 path = gtk_tree_path_new_from_indices (N_ROWS - 4, -1);
919 scroll (fixture, path, FALSE, 0.0);
920 gtk_tree_path_free (path);
922 /* No need for a while events pending loop here, scroll() does this for us.
924 * We now remove a bunch of rows, wait for events to process and then
925 * check the adjustments to see if the TreeView gracefully recovered.
927 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
929 while (gtk_tree_model_iter_nth_child (model, &iter, NULL, N_ROWS - 15))
930 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
932 while (gtk_events_pending ())
933 gtk_main_iteration ();
935 vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
937 g_assert (gtk_adjustment_get_value (vadjustment) + gtk_adjustment_get_page_size (vadjustment) <= gtk_adjustment_get_upper (vadjustment));
938 g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
942 /* Test for GNOME bugzilla bug 359231 */
944 test_bug359231 (void)
947 int height1, height2;
949 GtkTreeIter iter, child;
952 ScrollFixture *fixture;
955 g_test_bug ("359231");
957 /* Create model (GtkTreeStore in this case) */
958 store = gtk_tree_store_new (1, G_TYPE_STRING);
960 gtk_tree_store_append (store, &iter, NULL);
961 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
963 for (i = 0; i < 4; i++) {
964 gtk_tree_store_append (store, &child, &iter);
965 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
968 fixture = g_new0 (ScrollFixture, 1);
969 scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), NULL);
970 gtk_widget_show_all (fixture->window);
972 while (gtk_events_pending ())
973 gtk_main_iteration ();
975 /* Prepend some rows at the top, expand */
976 gtk_tree_store_prepend (store, &iter, NULL);
977 gtk_tree_store_set (store, &iter, 0, "Foo", -1);
979 gtk_tree_store_prepend (store, &child, &iter);
980 gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
982 gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
984 while (gtk_events_pending ())
985 gtk_main_iteration ();
987 /* Test if height of row 0:0 is correct */
988 path = gtk_tree_path_new_from_indices (0, -1);
989 gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
991 height1 = rect.height;
993 gtk_tree_path_down (path);
994 gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
996 height2 = rect.height;
997 gtk_tree_path_free (path);
999 g_assert (height2 > height1);
1001 /* Clean up; the tear down also cleans up the model */
1002 scroll_fixture_teardown (fixture, NULL);
1005 /* Test for GNOME bugzilla bug 93584. We add 150 rows to an existing
1006 * small model, and scroll to one of these with alignment.
1009 test_bug93584 (ScrollFixture *fixture,
1010 gconstpointer test_data)
1013 GtkTreeStore *store;
1016 g_test_bug ("93584");
1018 /* Mimic state as in original test case */
1019 g_signal_connect (G_OBJECT (fixture->tree_view), "realize",
1020 G_CALLBACK (gtk_tree_view_expand_all), NULL);
1021 gtk_widget_show_all (fixture->window);
1023 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1026 for (i = 0; i < 150; i++) {
1029 gtk_tree_store_append (store, &iter, NULL);
1030 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1033 row = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1036 path = gtk_tree_path_new_from_indices (row, -1);
1037 scroll (fixture, path, TRUE, 0.5);
1038 gtk_tree_path_free (path);
1041 /* GNOME bugzilla bug 111500. Expand a row and immediately scroll
1042 * to its first child. Make sure that expansion happens in currently
1046 test_bug111500 (ScrollFixture *fixture,
1047 gconstpointer test_data)
1050 GtkTreeStore *store;
1054 g_test_bug ("111500");
1056 gtk_widget_show_all (fixture->window);
1058 /* Make sure all events have been processed and the window
1061 while (gtk_events_pending ())
1062 gtk_main_iteration ();
1064 /* Further prepare model */
1065 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1067 for (i = 0; i < 15; i++) {
1070 gtk_tree_store_append (store, &iter, NULL);
1071 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1074 len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1075 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
1078 for (i = 0; i < 5; i++) {
1081 gtk_tree_store_append (store, &iter, &parent);
1082 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1085 path = gtk_tree_path_new_from_indices (len - 1, -1);
1086 gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1089 gtk_tree_path_down (path);
1091 scroll (fixture, path, TRUE, 0.5);
1092 gtk_tree_path_free (path);
1096 test_bug111500_mixed (ScrollFixture *fixture,
1097 gconstpointer test_data)
1100 GtkTreeStore *store;
1104 g_test_bug ("111500");
1106 gtk_widget_show_all (fixture->window);
1108 /* Make sure all events have been processed and the window
1111 while (gtk_events_pending ())
1112 gtk_main_iteration ();
1114 /* Further prepare model */
1115 store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1117 for (i = 0; i < 15; i++) {
1120 gtk_tree_store_append (store, &iter, NULL);
1122 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1124 gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
1127 len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1128 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &parent,
1131 for (i = 0; i < 5; i++) {
1134 gtk_tree_store_append (store, &iter, &parent);
1136 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1138 gtk_tree_store_set (store, &iter, 0, "Row\nRow", -1);
1141 path = gtk_tree_path_new_from_indices (len - 1, -1);
1142 gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1145 gtk_tree_path_down (path);
1147 scroll (fixture, path, TRUE, 0.5);
1148 gtk_tree_path_free (path);
1151 /* Test for GNOME bugzilla bug 163214. Invalidate a couple of rows,
1152 * then scroll to one of these.
1155 test_bug163214 (ScrollFixture *fixture,
1156 gconstpointer test_data)
1159 GtkListStore *store;
1162 g_test_bug ("163214");
1164 gtk_widget_show_all (fixture->window);
1166 /* Make sure all events have been processed and the window
1169 while (gtk_events_pending ())
1170 gtk_main_iteration ();
1172 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1174 /* Invalidate a page of rows */
1175 for (i = 100; i < 110; i++) {
1178 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1180 gtk_list_store_set (store, &iter, 0, "Row", -1);
1183 /* Then scroll to that page. */
1184 path = gtk_tree_path_new_from_indices (105, -1);
1185 scroll (fixture, path, TRUE, 0.5);
1186 gtk_tree_path_free (path);
1188 /* Make sure all events have been processed and the window
1191 while (gtk_events_pending ())
1192 gtk_main_iteration ();
1194 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1196 /* Invalidate a page of rows */
1197 for (i = 300; i < 310; i++) {
1200 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1202 gtk_list_store_set (store, &iter, 0, "Row", -1);
1205 /* Then scroll to the first row */
1206 path = gtk_tree_path_new_from_indices (0, -1);
1207 scroll (fixture, path, TRUE, 0.5);
1208 gtk_tree_path_free (path);
1211 /* Infrastructure for automatically adding tests */
1220 test_type_string (int test_type)
1222 switch (test_type) {
1224 return "before-realize";
1227 return "after-realize";
1237 align_string (gboolean use_align,
1243 return g_strdup ("no-align");
1245 ret = g_strdup_printf ("align-%1.1f", row_align);
1250 add_test (const char *path,
1255 void (* setup) (ScrollFixture *, gconstpointer),
1256 void (* scroll_func) (ScrollFixture *, gconstpointer))
1261 align = align_string (use_align, row_align);
1263 test_path = g_strdup_printf ("/TreeView/scrolling/%s/%s-height/path-%s-%s",
1264 test_type_string (test_type),
1265 mixed ? "mixed" : "constant",
1269 g_test_add (test_path, ScrollFixture, path,
1270 setup, scroll_func, scroll_fixture_teardown);
1276 add_tests (gboolean mixed,
1280 void (*scroll_func) (ScrollFixture *, gconstpointer))
1282 void (* setup) (ScrollFixture *, gconstpointer);
1285 setup = scroll_fixture_mixed_setup;
1287 setup = scroll_fixture_constant_setup;
1289 add_test ("0", mixed, test_type, use_align, row_align, setup, scroll_func);
1290 add_test ("2", mixed, test_type, use_align, row_align, setup, scroll_func);
1291 add_test ("5", mixed, test_type, use_align, row_align, setup, scroll_func);
1292 /* We scroll to 8 to test a partial visible row. The 8 is
1293 * based on my font setting of "Vera Sans 11" and
1294 * the separators set to 0. (This should be made dynamic; FIXME).
1296 add_test ("8", mixed, test_type, use_align, row_align, setup, scroll_func);
1297 add_test ("10", mixed, test_type, use_align, row_align, setup, scroll_func);
1298 add_test ("250", mixed, test_type, use_align, row_align, setup, scroll_func);
1299 add_test ("500", mixed, test_type, use_align, row_align, setup, scroll_func);
1300 add_test ("750", mixed, test_type, use_align, row_align, setup, scroll_func);
1301 add_test ("990", mixed, test_type, use_align, row_align, setup, scroll_func);
1302 add_test ("991", mixed, test_type, use_align, row_align, setup, scroll_func);
1303 add_test ("995", mixed, test_type, use_align, row_align, setup, scroll_func);
1304 add_test ("997", mixed, test_type, use_align, row_align, setup, scroll_func);
1305 add_test ("999", mixed, test_type, use_align, row_align, setup, scroll_func);
1309 main (int argc, char **argv)
1311 gtk_test_init (&argc, &argv);
1313 /* Scrolls before realization */
1314 add_tests (FALSE, BEFORE, FALSE, 0.0, scroll_no_align);
1315 if (g_test_thorough ())
1316 add_tests (TRUE, BEFORE, FALSE, 0.0, scroll_no_align);
1318 add_tests (FALSE, BEFORE, TRUE, 0.0, scroll_align_0_0);
1319 if (g_test_thorough ())
1320 add_tests (TRUE, BEFORE, TRUE, 0.0, scroll_align_0_0);
1322 add_tests (FALSE, BEFORE, TRUE, 0.5, scroll_align_0_5);
1323 if (g_test_thorough ())
1324 add_tests (TRUE, BEFORE, TRUE, 0.5, scroll_align_0_5);
1326 add_tests (FALSE, BEFORE, TRUE, 1.0, scroll_align_1_0);
1327 if (g_test_thorough ())
1328 add_tests (TRUE, BEFORE, TRUE, 1.0, scroll_align_1_0);
1330 /* Scrolls after realization */
1331 add_tests (FALSE, AFTER, FALSE, 0.0, scroll_after_no_align);
1332 if (g_test_thorough ())
1333 add_tests (TRUE, AFTER, FALSE, 0.0, scroll_after_no_align);
1335 add_tests (FALSE, AFTER, TRUE, 0.0, scroll_after_align_0_0);
1336 if (g_test_thorough ())
1337 add_tests (TRUE, AFTER, TRUE, 0.0, scroll_after_align_0_0);
1339 add_tests (FALSE, AFTER, TRUE, 0.5, scroll_after_align_0_5);
1340 if (g_test_thorough ())
1341 add_tests (TRUE, AFTER, TRUE, 0.5, scroll_after_align_0_5);
1343 add_tests (FALSE, AFTER, TRUE, 1.0, scroll_after_align_1_0);
1344 if (g_test_thorough ())
1345 add_tests (TRUE, AFTER, TRUE, 1.0, scroll_after_align_1_0);
1347 /* Scroll to end before realization, to a real position after */
1348 if (g_test_thorough ()) {
1349 add_tests (FALSE, BOTH, FALSE, 0.0, scroll_both_no_align);
1350 add_tests (TRUE, BOTH, FALSE, 0.0, scroll_both_no_align);
1352 add_tests (FALSE, BOTH, TRUE, 0.0, scroll_both_align_0_0);
1353 add_tests (TRUE, BOTH, TRUE, 0.0, scroll_both_align_0_0);
1355 add_tests (FALSE, BOTH, TRUE, 0.5, scroll_both_align_0_5);
1356 add_tests (TRUE, BOTH, TRUE, 0.5, scroll_both_align_0_5);
1358 add_tests (FALSE, BOTH, TRUE, 1.0, scroll_both_align_1_0);
1359 add_tests (TRUE, BOTH, TRUE, 1.0, scroll_both_align_1_0);
1362 /* Test different alignments in view with single row */
1363 g_test_add ("/TreeView/scrolling/single-row/no-align",
1365 scroll_fixture_single_setup,
1367 scroll_fixture_teardown);
1368 g_test_add ("/TreeView/scrolling/single-row/align-0.0",
1370 scroll_fixture_single_setup,
1372 scroll_fixture_teardown);
1373 g_test_add ("/TreeView/scrolling/single-row/align-0.5",
1375 scroll_fixture_single_setup,
1377 scroll_fixture_teardown);
1378 g_test_add ("/TreeView/scrolling/single-row/align-1.0",
1380 scroll_fixture_single_setup,
1382 scroll_fixture_teardown);
1384 /* Test scrolling in a very large model; also very slow */
1385 if (g_test_slow ()) {
1386 g_test_add ("/TreeView/scrolling/large-model/constant-height/middle-no-align",
1387 ScrollFixture, "50000",
1388 scroll_fixture_constant_big_setup,
1390 scroll_fixture_teardown);
1391 g_test_add ("/TreeView/scrolling/large-model/constant-height/end-no-align",
1392 ScrollFixture, "99999",
1393 scroll_fixture_constant_big_setup,
1395 scroll_fixture_teardown);
1397 g_test_add ("/TreeView/scrolling/large-model/mixed-height/middle-no-align",
1398 ScrollFixture, "50000",
1399 scroll_fixture_mixed_big_setup,
1401 scroll_fixture_teardown);
1402 g_test_add ("/TreeView/scrolling/large-model/mixed-height/end-no-align",
1403 ScrollFixture, "99999",
1404 scroll_fixture_mixed_big_setup,
1406 scroll_fixture_teardown);
1409 /* Test scrolling to a newly created row */
1410 g_test_add ("/TreeView/scrolling/new-row/path-0", ScrollFixture,
1411 GINT_TO_POINTER (0),
1412 scroll_fixture_constant_setup,
1414 scroll_fixture_teardown);
1415 g_test_add ("/TreeView/scrolling/new-row/path-4", ScrollFixture,
1416 GINT_TO_POINTER (4),
1417 scroll_fixture_constant_setup,
1419 scroll_fixture_teardown);
1420 /* We scroll to 8 to test a partial visible row. The 8 is
1421 * based on my font setting of "Vera Sans 11" and
1422 * the separators set to 0. (This should be made dynamic; FIXME).
1424 g_test_add ("/TreeView/scrolling/new-row/path-8", ScrollFixture,
1425 GINT_TO_POINTER (8),
1426 scroll_fixture_constant_setup,
1428 scroll_fixture_teardown);
1429 g_test_add ("/TreeView/scrolling/new-row/path-500", ScrollFixture,
1430 GINT_TO_POINTER (500),
1431 scroll_fixture_constant_setup,
1433 scroll_fixture_teardown);
1434 g_test_add ("/TreeView/scrolling/new-row/path-999", ScrollFixture,
1435 GINT_TO_POINTER (999),
1436 scroll_fixture_constant_setup,
1438 scroll_fixture_teardown);
1440 g_test_add ("/TreeView/scrolling/new-row/tree", ScrollFixture,
1442 scroll_fixture_tree_setup,
1443 scroll_new_row_tree,
1444 scroll_fixture_teardown);
1446 /* Test scrolling to a newly created row, in a mixed height model */
1447 g_test_add ("/TreeView/scrolling/new-row-mixed/path-0", ScrollFixture,
1448 GINT_TO_POINTER (0),
1449 scroll_fixture_mixed_setup,
1451 scroll_fixture_teardown);
1452 g_test_add ("/TreeView/scrolling/new-row-mixed/path-3", ScrollFixture,
1453 GINT_TO_POINTER (3),
1454 scroll_fixture_mixed_setup,
1456 scroll_fixture_teardown);
1457 /* We scroll to 8 to test a partial visible row. The 8 is
1458 * based on my font setting of "Vera Sans 11" and
1459 * the separators set to 0. (This should be made dynamic; FIXME).
1461 g_test_add ("/TreeView/scrolling/new-row-mixed/path-5", ScrollFixture,
1462 GINT_TO_POINTER (5),
1463 scroll_fixture_mixed_setup,
1465 scroll_fixture_teardown);
1466 g_test_add ("/TreeView/scrolling/new-row-mixed/path-500", ScrollFixture,
1467 GINT_TO_POINTER (500),
1468 scroll_fixture_mixed_setup,
1470 scroll_fixture_teardown);
1471 g_test_add ("/TreeView/scrolling/new-row-mixed/path-999", ScrollFixture,
1472 GINT_TO_POINTER (999),
1473 scroll_fixture_mixed_setup,
1475 scroll_fixture_teardown);
1477 g_test_add ("/TreeView/scrolling/new-row-mixed/tree", ScrollFixture,
1479 scroll_fixture_mixed_tree_setup,
1480 scroll_new_row_tree,
1481 scroll_fixture_teardown);
1484 g_test_add ("/TreeView/scrolling/specific/bug-316689",
1485 ScrollFixture, NULL,
1486 scroll_fixture_constant_setup, test_bug316689,
1487 scroll_fixture_teardown);
1488 g_test_add_func ("/TreeView/scrolling/specific/bug-359231",
1490 g_test_add ("/TreeView/scrolling/specific/bug-93584",
1491 ScrollFixture, NULL,
1492 scroll_fixture_tree_setup, test_bug93584,
1493 scroll_fixture_teardown);
1494 g_test_add ("/TreeView/scrolling/specific/bug-111500",
1495 ScrollFixture, NULL,
1496 scroll_fixture_tree_setup, test_bug111500,
1497 scroll_fixture_teardown);
1498 g_test_add ("/TreeView/scrolling/specific/bug-111500-mixed",
1499 ScrollFixture, NULL,
1500 scroll_fixture_mixed_tree_setup, test_bug111500_mixed,
1501 scroll_fixture_teardown);
1502 g_test_add ("/TreeView/scrolling/specific/bug-163214",
1503 ScrollFixture, NULL,
1504 scroll_fixture_constant_setup, test_bug163214,
1505 scroll_fixture_teardown);
1507 return g_test_run ();