Initial packaging to sync OBS with git/gerrit
[profile/ivi/gtk3.git] / gtk / tests / treeview-scrolling.c
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>
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 /* Original v1.0 -- December 26, 2006
21  * Conversion to GLib/GTK+ test framework during December, 2007
22  */
23
24
25 #include <gtk/gtk.h>
26 #include <unistd.h>
27 #include <math.h>
28
29 #define VIEW_WIDTH 320
30 #define VIEW_HEIGHT 240
31
32 #define N_ROWS 1000
33 #define BIG_N_ROWS N_ROWS * 100
34
35 /*
36  * To do:
37  *   - Test that nothing happens if the row is fully visible.
38  *   - The tests are dependent on the theme/font (size measurements,
39  *     chosen paths).
40  *   - Convert to proper GTK+ coding style.
41  *   - Briefly test scrolling in tree stores as well.
42  *
43  * Important:
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.
50  */
51
52
53 /* Constructing models for testing */
54 static GtkTreeModel *
55 create_model (gboolean constant)
56 {
57         int i;
58
59         GtkTreeIter iter;
60         GtkListStore *store;
61
62         store = gtk_list_store_new (1, G_TYPE_STRING);
63
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);
68                 else
69                         gtk_list_store_set (store, &iter, 0, "Sliff\nSloff\nBleh", -1);
70         }
71
72         return GTK_TREE_MODEL (store);
73 }
74
75 static GtkTreeModel *
76 create_big_model (gboolean constant)
77 {
78         int i;
79
80         GtkTreeIter iter;
81         GtkListStore *store;
82
83         store = gtk_list_store_new (1, G_TYPE_STRING);
84
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);
89                 else
90                         gtk_list_store_set (store, &iter, 0, "Sliff\nSloff\nBleh", -1);
91         }
92
93         return GTK_TREE_MODEL (store);
94 }
95
96 /*
97  * Fixtures
98  */
99
100 typedef struct
101 {
102         GtkWidget *window;
103         GtkWidget *tree_view;
104 }
105 ScrollFixture;
106
107 static void
108 scroll_fixture_setup (ScrollFixture *fixture,
109                       GtkTreeModel  *model,
110                       gconstpointer  test_data)
111 {
112         GtkWidget *sw;
113         GtkCellRenderer *renderer;
114         GtkTreeViewColumn *column;
115
116         fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
117
118         sw = gtk_scrolled_window_new (NULL, NULL);
119         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
120                                         GTK_POLICY_NEVER,
121                                         GTK_POLICY_ALWAYS);
122         gtk_container_add (GTK_CONTAINER (fixture->window), sw);
123
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);
129
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",
133                                                            renderer,
134                                                            "text", 0,
135                                                            NULL);
136
137         gtk_tree_view_append_column (GTK_TREE_VIEW (fixture->tree_view), column);
138         gtk_container_add (GTK_CONTAINER (sw), fixture->tree_view);
139 }
140
141 /* sets up a fixture with a model with constant row heights */
142 static void
143 scroll_fixture_constant_setup (ScrollFixture *fixture,
144                                gconstpointer  test_data)
145 {
146         scroll_fixture_setup (fixture, create_model (TRUE), test_data);
147 }
148
149 /* sets up a fixture with a model with varying row heights */
150 static void
151 scroll_fixture_mixed_setup (ScrollFixture *fixture,
152                             gconstpointer  test_data)
153 {
154         scroll_fixture_setup (fixture, create_model (FALSE), test_data);
155 }
156
157 /* sets up a fixture with a large model with constant row heights */
158 static void
159 scroll_fixture_constant_big_setup (ScrollFixture *fixture,
160                                    gconstpointer  test_data)
161 {
162         scroll_fixture_setup (fixture, create_big_model (TRUE), test_data);
163 }
164
165 /* sets up a fixture with a large model with varying row heights */
166 static void
167 scroll_fixture_mixed_big_setup (ScrollFixture *fixture,
168                                 gconstpointer  test_data)
169 {
170         scroll_fixture_setup (fixture, create_big_model (FALSE), test_data);
171 }
172
173 /* sets up a fixture with only a single row for the "single row scroll" test */
174 static void
175 scroll_fixture_single_setup (ScrollFixture *fixture,
176                              gconstpointer  test_data)
177 {
178         GtkTreeStore *store;
179         GtkTreeIter iter, child;
180
181         store = gtk_tree_store_new (1, G_TYPE_STRING);
182
183         gtk_tree_store_append (store, &iter, NULL);
184         gtk_tree_store_set (store, &iter, 0, "Foo", -1);
185
186         gtk_tree_store_append (store, &child, &iter);
187         gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
188
189         /* The teardown will also destroy the model */
190         scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
191 }
192
193 /* sets up a fixture with a tree store */
194 static void
195 scroll_fixture_tree_setup (ScrollFixture *fixture,
196                            gconstpointer   test_data)
197 {
198         GtkTreeStore *store;
199         GtkTreeIter iter, child;
200         int i;
201
202         store = gtk_tree_store_new (1, G_TYPE_STRING);
203
204         gtk_tree_store_append (store, &iter, NULL);
205         gtk_tree_store_set (store, &iter, 0, "Root node", -1);
206
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);
210         }
211
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);
215         }
216
217         /* The teardown will also destroy the model */
218         scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
219 }
220
221 static void
222 scroll_fixture_mixed_tree_setup (ScrollFixture *fixture,
223                                  gconstpointer   test_data)
224 {
225         GtkTreeStore *store;
226         GtkTreeIter iter, child;
227         int i;
228
229         store = gtk_tree_store_new (1, G_TYPE_STRING);
230
231         gtk_tree_store_append (store, &iter, NULL);
232         gtk_tree_store_set (store, &iter, 0, "Root\nnode", -1);
233
234         for (i = 0; i < 5; i++) {
235                 gtk_tree_store_append (store, &child, &iter);
236                 if (i % 2 != 0)
237                         gtk_tree_store_set (store, &child, 0, "Child node", -1);
238                 else
239                         gtk_tree_store_set (store, &child,
240                                             0, "Child\nnode", -1);
241         }
242
243         for (i = 0; i < 5; i++) {
244                 gtk_tree_store_append (store, &iter, NULL);
245                 if (i % 2 == 0)
246                         gtk_tree_store_set (store, &iter, 0, "Other node", -1);
247                 else
248                         gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
249         }
250
251         /* The teardown will also destroy the model */
252         scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
253 }
254
255 static void
256 scroll_fixture_teardown (ScrollFixture *fixture,
257                          gconstpointer  test_data)
258 {
259         gtk_widget_destroy (fixture->window);
260 }
261
262 /*
263  * Position check and helpers.
264  */
265 enum Pos
266 {
267         POS_TOP,
268         POS_CENTER,
269         POS_BOTTOM
270 };
271
272 static int
273 get_row_start_for_index (GtkTreeView *tree_view, int index)
274 {
275         gint height1, height2;
276         gint row_start;
277         GtkTreePath *path;
278         GdkRectangle rect;
279
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;
283
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);
288
289         row_start = (index / 2) * height1 + (index / 2) * height2;
290         if (index % 2)
291                 row_start += height1;
292
293         return row_start;
294 }
295
296 static enum Pos
297 get_pos_from_path (GtkTreeView   *tree_view,
298                    GtkTreePath   *path,
299                    gdouble        row_height,
300                    GtkAdjustment *vadjustment)
301 {
302         int row_start;
303
304         row_start = get_row_start_for_index (tree_view,
305                                              gtk_tree_path_get_indices (path)[0]);
306
307         if (row_start + row_height < gtk_adjustment_get_page_size (vadjustment))
308                 return POS_TOP;
309
310         if (row_start >= gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment))
311                 return POS_BOTTOM;
312
313         return POS_CENTER;
314 }
315
316 static void
317 assert_position_with_align (GtkTreeView  *tree_view,
318                             enum Pos      pos,
319                             gint          row_y,
320                             gint          row_start,
321                             gdouble       row_height,
322                             gdouble       row_align)
323 {
324         GtkAdjustment *vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
325
326         /* Switch on row-align: 0.0, 0.5, 1.0 */
327         switch ((int)(row_align * 2.)) {
328         case 0:
329                 if (pos == POS_TOP || pos == POS_CENTER) {
330                         /* The row in question is the first row
331                          * in the view.
332                          *    - rect.y should be zero
333                          *    - dy should be equal to the top
334                          *      y coordinate of the row.
335                          */
336                         g_assert (row_y == 0);
337                         g_assert (gtk_adjustment_get_value (vadjustment) == row_start);
338                 } else {
339                         /* The row can be anywhere at the last
340                          * page of the tree view.
341                          *   - dy is set to the start of the
342                          *     last page.
343                          */
344                         g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
345                 }
346                 break;
347
348         case 1:
349                 /* 0.5 */
350                 if (pos == POS_TOP
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
356                          */
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 
364                          *     last page.
365                          */
366                         g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
367                 } else {
368                         /* The row is located in the middle of
369                          * the view.
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).
375                          */
376                         gdouble middle = (gtk_adjustment_get_page_size (vadjustment) - row_height) / 2.0;
377                         g_assert (row_y == ceil (middle) || row_y == floor (middle));
378                 }
379                 break;
380
381         case 2:
382                 /* 1.0 */
383                 if (pos == POS_TOP) {
384                         /* The row can be anywhere on the
385                          * first page of the tree view.
386                          *   - dy is zero.
387                          */
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
391                          * view.
392                          *   - rect.y is set to the top of the
393                          *     last row.
394                          *   - row_start is greater than page_size
395                          *     (ie we are not on the first page).
396                          *   - dy is greater than zero
397                          */
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);
401                 }
402                 break;
403         }
404 }
405
406 static void
407 assert_position_without_align (GtkTreeView *tree_view,
408                                gdouble      row_start,
409                                gdouble      row_height)
410 {
411   GtkAdjustment *vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view));
412
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.
416    */
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);
419 }
420
421 static void
422 test_position (GtkTreeView *tree_view,
423                GtkTreePath *path,
424                gboolean     use_align,
425                gdouble      row_align)
426 {
427         gint pos;
428         gchar *path_str;
429         GdkRectangle rect;
430         GtkTreeModel *model;
431         gint row_start;
432
433         /* Get the location of the path we scrolled to */
434         gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
435                                            path, NULL, &rect);
436
437         row_start = get_row_start_for_index (GTK_TREE_VIEW (tree_view),
438                                              gtk_tree_path_get_indices (path)[0]);
439
440         /* Ugh */
441         pos = get_pos_from_path (GTK_TREE_VIEW (tree_view),
442                                  path, rect.height,
443                                  gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree_view)));
444
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;
450
451                 /* Test nothing is dangling at the bottom; read
452                  * description for test_single() for more information.
453                  */
454
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);
460                 }
461         }
462
463         path_str = gtk_tree_path_to_string (path);
464         if (use_align) {
465                 assert_position_with_align (tree_view, pos, rect.y,
466                                             row_start, rect.height, row_align);
467         } else {
468                 assert_position_without_align (tree_view, row_start, rect.height);
469         }
470
471         g_free (path_str);
472 }
473
474 /*
475  * Scrolling code
476  */
477
478
479 /* Testing scrolling to various positions with various alignments */
480
481 static void
482 scroll (ScrollFixture *fixture,
483         GtkTreePath   *path,
484         gboolean       use_align,
485         gdouble        row_align)
486 {
487         gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
488                                   NULL, FALSE);
489         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
490                                       path, NULL,
491                                       use_align, row_align, 0.0);
492
493         gtk_widget_show_all (fixture->window);
494
495         while (gtk_events_pending ())
496                 gtk_main_iteration ();
497
498         test_position (GTK_TREE_VIEW (fixture->tree_view), path,
499                        use_align, row_align);
500 }
501
502 static void
503 scroll_no_align (ScrollFixture *fixture,
504                  gconstpointer  test_data)
505 {
506         GtkTreePath *path;
507
508         path = gtk_tree_path_new_from_string (test_data);
509         scroll (fixture, path, FALSE, 0.0);
510         gtk_tree_path_free (path);
511 }
512
513 static void
514 scroll_align_0_0 (ScrollFixture *fixture,
515                   gconstpointer  test_data)
516 {
517         GtkTreePath *path;
518
519         path = gtk_tree_path_new_from_string (test_data);
520         scroll (fixture, path, TRUE, 0.0);
521         gtk_tree_path_free (path);
522 }
523
524 static void
525 scroll_align_0_5 (ScrollFixture *fixture,
526                   gconstpointer  test_data)
527 {
528         GtkTreePath *path;
529
530         path = gtk_tree_path_new_from_string (test_data);
531         scroll (fixture, path, TRUE, 0.5);
532         gtk_tree_path_free (path);
533 }
534
535 static void
536 scroll_align_1_0 (ScrollFixture *fixture,
537                   gconstpointer  test_data)
538 {
539         GtkTreePath *path;
540
541         path = gtk_tree_path_new_from_string (test_data);
542         scroll (fixture, path, TRUE, 1.0);
543         gtk_tree_path_free (path);
544 }
545
546
547 static void
548 scroll_after_realize (ScrollFixture *fixture,
549                       GtkTreePath   *path,
550                       gboolean       use_align,
551                       gdouble        row_align)
552 {
553         gtk_widget_show_all (fixture->window);
554
555         while (gtk_events_pending ())
556                 gtk_main_iteration ();
557
558         gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
559                                   NULL, FALSE);
560         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
561                                       path, NULL,
562                                       use_align, row_align, 0.0);
563
564         while (gtk_events_pending ())
565                 gtk_main_iteration ();
566
567         test_position (GTK_TREE_VIEW (fixture->tree_view), path,
568                        use_align, row_align);
569 }
570
571 static void
572 scroll_after_no_align (ScrollFixture *fixture,
573                        gconstpointer  test_data)
574 {
575         GtkTreePath *path;
576
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);
580 }
581
582 static void
583 scroll_after_align_0_0 (ScrollFixture *fixture,
584                         gconstpointer  test_data)
585 {
586         GtkTreePath *path;
587
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);
591 }
592
593 static void
594 scroll_after_align_0_5 (ScrollFixture *fixture,
595                         gconstpointer  test_data)
596 {
597         GtkTreePath *path;
598
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);
602 }
603
604 static void
605 scroll_after_align_1_0 (ScrollFixture *fixture,
606                         gconstpointer  test_data)
607 {
608         GtkTreePath *path;
609
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);
613 }
614
615
616 static void
617 scroll_both_realize (ScrollFixture *fixture,
618                      GtkTreePath   *path,
619                      gboolean       use_align,
620                      gdouble        row_align)
621 {
622         GtkTreePath *end;
623
624         gtk_widget_show_all (fixture->window);
625
626         /* Scroll to end */
627         end = gtk_tree_path_new_from_indices (999, -1);
628
629         gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), end,
630                                   NULL, FALSE);
631         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
632                                       end, NULL,
633                                       use_align, row_align, 0.0);
634         gtk_tree_path_free (end);
635
636         while (gtk_events_pending ())
637                 gtk_main_iteration ();
638
639         /* Scroll to final position */
640         gtk_tree_view_set_cursor (GTK_TREE_VIEW (fixture->tree_view), path,
641                                   NULL, FALSE);
642         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
643                                       path, NULL,
644                                       use_align, row_align, 0.0);
645
646         while (gtk_events_pending ())
647                 gtk_main_iteration ();
648
649         test_position (GTK_TREE_VIEW (fixture->tree_view), path,
650                        use_align, row_align);
651 }
652
653 static void
654 scroll_both_no_align (ScrollFixture *fixture,
655                       gconstpointer  test_data)
656 {
657         GtkTreePath *path;
658
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);
662 }
663
664 static void
665 scroll_both_align_0_0 (ScrollFixture *fixture,
666                        gconstpointer  test_data)
667 {
668         GtkTreePath *path;
669
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);
673 }
674
675 static void
676 scroll_both_align_0_5 (ScrollFixture *fixture,
677                        gconstpointer  test_data)
678 {
679         GtkTreePath *path;
680
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);
684 }
685
686 static void
687 scroll_both_align_1_0 (ScrollFixture *fixture,
688                        gconstpointer  test_data)
689 {
690         GtkTreePath *path;
691
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);
695 }
696
697 /* Testing scrolling to a newly created row */
698 static void
699 create_new_row (GtkListStore *store,
700                 int           n,
701                 GtkTreeIter  *iter)
702 {
703         switch (n) {
704                 case 0:
705                         /* Prepend a row */
706                         gtk_list_store_prepend (store, iter);
707                         break;
708
709                 case 3:
710                         /* Add a row in the middle of the visible area */
711                         gtk_list_store_insert (store, iter, 3);
712                         break;
713
714                 case 4:
715                         /* Add a row in the middle of the visible area */
716                         gtk_list_store_insert (store, iter, 4);
717                         break;
718
719                 case 5:
720                         /* Add a row which is not completely visible */
721                         gtk_list_store_insert (store, iter, 5);
722                         break;
723
724                 case 8:
725                         /* Add a row which is not completely visible */
726                         gtk_list_store_insert (store, iter, 8);
727                         break;
728
729                 case 500:
730                         /* Add a row in the middle */
731                         gtk_list_store_insert (store, iter, 500);
732                         break;
733
734                 case 999:
735                         /* Append a row */
736                         gtk_list_store_append (store, iter);
737                         break;
738         }
739
740         gtk_list_store_set (store, iter, 0, "New...", -1);
741 }
742
743 static void
744 scroll_new_row_editing_started (GtkCellRenderer *cell,
745                                 GtkCellEditable *editable,
746                                 const char      *path,
747                                 gpointer         user_data)
748 {
749         GtkWidget **widget = user_data;
750
751         *widget = GTK_WIDGET (editable);
752 }
753
754 static void
755 test_editable_position (GtkWidget   *tree_view,
756                         GtkWidget   *editable,
757                         GtkTreePath *cursor_path)
758 {
759         GtkAllocation allocation;
760         GdkRectangle rect;
761
762         gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view),
763                                            cursor_path, NULL, &rect);
764
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));
768 }
769
770 static void
771 scroll_new_row (ScrollFixture *fixture,
772                 gconstpointer  test_data)
773 {
774         GtkTreeIter scroll_iter;
775         GtkTreePath *scroll_path;
776         GtkTreeModel *model;
777         GList *renderers;
778         GtkTreeViewColumn *column;
779         GtkWidget *editable;
780
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.
784          *
785          * See #81627.
786          */
787
788         g_test_bug ("81627");
789
790         gtk_widget_show_all (fixture->window);
791
792         while (gtk_events_pending ())
793                 gtk_main_iteration ();
794
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),
798                         &scroll_iter);
799
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));
803
804         g_signal_connect (G_OBJECT (renderers->data), "editing-started",
805                           G_CALLBACK (scroll_new_row_editing_started),
806                           &editable);
807
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),
811                                   scroll_path,
812                                   column,
813                                   TRUE);
814
815         while (gtk_events_pending ())
816                 gtk_main_iteration ();
817
818         /* Test position */
819         test_position (GTK_TREE_VIEW (fixture->tree_view), scroll_path,
820                        FALSE, 0.0);
821         test_editable_position (fixture->tree_view, editable, scroll_path);
822
823         gtk_tree_path_free (scroll_path);
824 }
825
826 static void
827 scroll_new_row_tree (ScrollFixture *fixture,
828                      gconstpointer  test_data)
829 {
830         GtkTreeModel *model;
831         GtkAdjustment *vadjustment;
832         int i;
833
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.
838          *
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
842          */
843
844         gtk_widget_show_all (fixture->window);
845
846         gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
847
848         while (gtk_events_pending ())
849                 gtk_main_iteration ();
850
851         model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
852         vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
853
854         for (i = 0; i < 5; i++) {
855                 GtkTreeIter scroll_iter;
856                 GtkTreePath *scroll_path;
857
858                 gtk_tree_store_append (GTK_TREE_STORE (model), &scroll_iter,
859                                        NULL);
860                 gtk_tree_store_set (GTK_TREE_STORE (model), &scroll_iter,
861                                     0, "New node", -1);
862
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);
867
868                 while (gtk_events_pending ())
869                         gtk_main_iteration ();
870
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));
873         }
874 }
875
876 /* Test for GNOME bugzilla bug 359231; tests "recovery when removing a bunch of
877  * rows at the bottom.
878  */
879 static void
880 test_bug316689 (ScrollFixture *fixture,
881                 gconstpointer  test_data)
882 {
883         GtkTreeIter iter;
884         GtkTreePath *path;
885         GtkAdjustment *vadjustment;
886         GtkTreeModel *model;
887
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").
891          *
892          * See #316689.
893          */
894
895         g_test_bug ("316689");
896
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);
901
902         /* No need for a while events pending loop here, scroll() does this for us.
903          *
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.
906          */
907         model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
908
909         while (gtk_tree_model_iter_nth_child (model, &iter, NULL, N_ROWS - 15))
910                 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
911
912         while (gtk_events_pending ())
913                 gtk_main_iteration ();
914
915         vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (fixture->tree_view));
916
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));
919 }
920
921
922 /* Test for GNOME bugzilla bug 359231 */
923 static void
924 test_bug359231 (void)
925 {
926         int i;
927         int height1, height2;
928         GtkTreePath *path;
929         GtkTreeIter iter, child;
930         GtkTreeStore *store;
931         GdkRectangle rect;
932         ScrollFixture *fixture;
933
934         /* See #359231. */
935         g_test_bug ("359231");
936
937         /* Create model (GtkTreeStore in this case) */
938         store = gtk_tree_store_new (1, G_TYPE_STRING);
939
940         gtk_tree_store_append (store, &iter, NULL);
941         gtk_tree_store_set (store, &iter, 0, "Foo", -1);
942
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);
946         }
947         
948         fixture = g_new0 (ScrollFixture, 1);
949         scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), NULL);
950         gtk_widget_show_all (fixture->window);
951
952         while (gtk_events_pending ())
953                 gtk_main_iteration ();
954
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);
958
959         gtk_tree_store_prepend (store, &child, &iter);
960         gtk_tree_store_set (store, &child, 0, "Two\nLines", -1);
961
962         gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
963
964         while (gtk_events_pending ())
965                 gtk_main_iteration ();
966
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),
970                                            path, NULL, &rect);
971         height1 = rect.height;
972
973         gtk_tree_path_down (path);
974         gtk_tree_view_get_background_area (GTK_TREE_VIEW (fixture->tree_view),
975                                            path, NULL, &rect);
976         height2 = rect.height;
977         gtk_tree_path_free (path);
978
979         g_assert (height2 > height1);
980
981         /* Clean up; the tear down also cleans up the model */
982         scroll_fixture_teardown (fixture, NULL);
983 }
984
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.
987  */
988 static void
989 test_bug93584 (ScrollFixture *fixture,
990                gconstpointer  test_data)
991 {
992         int row, i;
993         GtkTreeStore *store;
994         GtkTreePath *path;
995
996         g_test_bug ("93584");
997
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);
1002
1003         store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1004
1005         /* Add 150 rows */
1006         for (i = 0; i < 150; i++) {
1007                 GtkTreeIter iter;
1008
1009                 gtk_tree_store_append (store, &iter, NULL);
1010                 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1011         }
1012
1013         row = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
1014         row -= 20;
1015
1016         path = gtk_tree_path_new_from_indices (row, -1);
1017         scroll (fixture, path, TRUE, 0.5);
1018         gtk_tree_path_free (path);
1019 }
1020
1021 /* GNOME bugzilla bug 111500.  Expand a row and immediately scroll
1022  * to its first child.  Make sure that expansion happens in currently
1023  * invisible area.
1024  */
1025 static void
1026 test_bug111500 (ScrollFixture *fixture,
1027                 gconstpointer  test_data)
1028 {
1029         int i, len;
1030         GtkTreeStore *store;
1031         GtkTreeIter parent;
1032         GtkTreePath *path;
1033
1034         g_test_bug ("111500");
1035
1036         gtk_widget_show_all (fixture->window);
1037
1038         /* Make sure all events have been processed and the window
1039          * is visible.
1040          */
1041         while (gtk_events_pending ())
1042                 gtk_main_iteration ();
1043
1044         /* Further prepare model */
1045         store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1046
1047         for (i = 0; i < 15; i++) {
1048                 GtkTreeIter iter;
1049
1050                 gtk_tree_store_append (store, &iter, NULL);
1051                 gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1052         }
1053
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,
1056                                        NULL, len - 1);
1057
1058         for (i = 0; i < 5; i++) {
1059                 GtkTreeIter iter;
1060
1061                 gtk_tree_store_append (store, &iter, &parent);
1062                 gtk_tree_store_set (store, &iter, 0, "Row", -1);
1063         }
1064
1065         path = gtk_tree_path_new_from_indices (len - 1, -1);
1066         gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1067                                   path, FALSE);
1068
1069         gtk_tree_path_down (path);
1070
1071         scroll (fixture, path, FALSE, 0.5);
1072         gtk_tree_path_free (path);
1073 }
1074
1075 static void
1076 test_bug111500_mixed (ScrollFixture *fixture,
1077                       gconstpointer  test_data)
1078 {
1079         int i, len;
1080         GtkTreeStore *store;
1081         GtkTreeIter parent;
1082         GtkTreePath *path;
1083
1084         g_test_bug ("111500");
1085
1086         gtk_widget_show_all (fixture->window);
1087
1088         /* Make sure all events have been processed and the window
1089          * is visible.
1090          */
1091         while (gtk_events_pending ())
1092                 gtk_main_iteration ();
1093
1094         /* Further prepare model */
1095         store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1096
1097         for (i = 0; i < 15; i++) {
1098                 GtkTreeIter iter;
1099
1100                 gtk_tree_store_append (store, &iter, NULL);
1101                 if (i % 2 == 0)
1102                         gtk_tree_store_set (store, &iter, 0, "Other node", -1);
1103                 else
1104                         gtk_tree_store_set (store, &iter, 0, "Other\nnode", -1);
1105         }
1106
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,
1109                                        NULL, len - 1);
1110
1111         for (i = 0; i < 5; i++) {
1112                 GtkTreeIter iter;
1113
1114                 gtk_tree_store_append (store, &iter, &parent);
1115                 if (i % 2 != 0)
1116                         gtk_tree_store_set (store, &iter, 0, "Row", -1);
1117                 else
1118                         gtk_tree_store_set (store, &iter, 0, "Row\nRow", -1);
1119         }
1120
1121         path = gtk_tree_path_new_from_indices (len - 1, -1);
1122         gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
1123                                   path, FALSE);
1124
1125         gtk_tree_path_down (path);
1126
1127         scroll (fixture, path, FALSE, 0.5);
1128         gtk_tree_path_free (path);
1129 }
1130
1131 /* Test for GNOME bugzilla bug 163214.  Invalidate a couple of rows,
1132  * then scroll to one of these.
1133  */
1134 static void
1135 test_bug163214 (ScrollFixture *fixture,
1136                 gconstpointer  test_data)
1137 {
1138         int i;
1139         GtkListStore *store;
1140         GtkTreePath *path;
1141
1142         g_test_bug ("163214");
1143
1144         gtk_widget_show_all (fixture->window);
1145
1146         /* Make sure all events have been processed and the window
1147          * is visible.
1148          */
1149         while (gtk_events_pending ())
1150                 gtk_main_iteration ();
1151
1152         store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1153
1154         /* Invalidate a page of rows */
1155         for (i = 100; i < 110; i++) {
1156                 GtkTreeIter iter;
1157
1158                 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1159                                                NULL, i);
1160                 gtk_list_store_set (store, &iter, 0, "Row", -1);
1161         }
1162
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);
1167
1168         /* Make sure all events have been processed and the window
1169          * is visible.
1170          */
1171         while (gtk_events_pending ())
1172                 gtk_main_iteration ();
1173
1174         store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)));
1175
1176         /* Invalidate a page of rows */
1177         for (i = 300; i < 310; i++) {
1178                 GtkTreeIter iter;
1179
1180                 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter,
1181                                                NULL, i);
1182                 gtk_list_store_set (store, &iter, 0, "Row", -1);
1183         }
1184
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);
1189 }
1190
1191 /* Infrastructure for automatically adding tests */
1192 enum
1193 {
1194         BEFORE,
1195         AFTER,
1196         BOTH
1197 };
1198
1199 static const char *
1200 test_type_string (int test_type)
1201 {
1202         switch (test_type) {
1203                 case BEFORE:
1204                         return "before-realize";
1205
1206                 case AFTER:
1207                         return "after-realize";
1208
1209                 case BOTH:
1210                         return "both";
1211         }
1212
1213         return "???";
1214 }
1215
1216 static char *
1217 align_string (gboolean use_align,
1218               gdouble  row_align)
1219 {
1220         char *ret;
1221
1222         if (!use_align)
1223                 return g_strdup ("no-align");
1224
1225         ret = g_strdup_printf ("align-%1.1f", row_align);
1226         return ret;
1227 }
1228
1229 static void
1230 add_test (const char *path,
1231           gboolean    mixed,
1232           int         test_type,
1233           gboolean    use_align,
1234           gdouble     row_align,
1235           void (* setup) (ScrollFixture *, gconstpointer),
1236           void (* scroll_func) (ScrollFixture *, gconstpointer))
1237 {
1238         gchar *test_path;
1239         gchar *align;
1240
1241         align = align_string (use_align, row_align);
1242
1243         test_path = g_strdup_printf ("/TreeView/scrolling/%s/%s-height/path-%s-%s",
1244                                      test_type_string (test_type),
1245                                      mixed ? "mixed" : "constant",
1246                                      path, align);
1247         g_free (align);
1248
1249         g_test_add (test_path, ScrollFixture, path,
1250                     setup, scroll_func, scroll_fixture_teardown);
1251
1252         g_free (test_path);
1253 }
1254
1255 static void
1256 add_tests (gboolean mixed,
1257            int test_type,
1258            gboolean use_align,
1259            gdouble  row_align,
1260            void (*scroll_func) (ScrollFixture *, gconstpointer))
1261 {
1262         void (* setup) (ScrollFixture *, gconstpointer);
1263
1264         if (mixed)
1265                 setup = scroll_fixture_mixed_setup;
1266         else
1267                 setup = scroll_fixture_constant_setup;
1268
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).
1275          */
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);
1286 }
1287
1288 int
1289 main (int argc, char **argv)
1290 {
1291         gtk_test_init (&argc, &argv);
1292
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);
1297
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);
1301
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);
1305
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);
1309
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);
1314
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);
1318
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);
1322
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);
1326
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);
1331
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);
1334
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);
1337
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);
1340         }
1341
1342         /* Test different alignments in view with single row */
1343         g_test_add ("/TreeView/scrolling/single-row/no-align",
1344                     ScrollFixture, "0",
1345                     scroll_fixture_single_setup,
1346                     scroll_no_align,
1347                     scroll_fixture_teardown);
1348         g_test_add ("/TreeView/scrolling/single-row/align-0.0",
1349                     ScrollFixture, "0",
1350                     scroll_fixture_single_setup,
1351                     scroll_align_0_0,
1352                     scroll_fixture_teardown);
1353         g_test_add ("/TreeView/scrolling/single-row/align-0.5",
1354                     ScrollFixture, "0",
1355                     scroll_fixture_single_setup,
1356                     scroll_align_0_5,
1357                     scroll_fixture_teardown);
1358         g_test_add ("/TreeView/scrolling/single-row/align-1.0",
1359                     ScrollFixture, "0",
1360                     scroll_fixture_single_setup,
1361                     scroll_align_1_0,
1362                     scroll_fixture_teardown);
1363
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,
1369                             scroll_no_align,
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,
1374                             scroll_no_align,
1375                             scroll_fixture_teardown);
1376
1377                 g_test_add ("/TreeView/scrolling/large-model/mixed-height/middle-no-align",
1378                             ScrollFixture, "50000",
1379                             scroll_fixture_mixed_big_setup,
1380                             scroll_no_align,
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,
1385                             scroll_no_align,
1386                             scroll_fixture_teardown);
1387         }
1388
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,
1393                     scroll_new_row,
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,
1398                     scroll_new_row,
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).
1403          */
1404         g_test_add ("/TreeView/scrolling/new-row/path-8", ScrollFixture,
1405                     GINT_TO_POINTER (8),
1406                     scroll_fixture_constant_setup,
1407                     scroll_new_row,
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,
1412                     scroll_new_row,
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,
1417                     scroll_new_row,
1418                     scroll_fixture_teardown);
1419
1420         g_test_add ("/TreeView/scrolling/new-row/tree", ScrollFixture,
1421                     NULL,
1422                     scroll_fixture_tree_setup,
1423                     scroll_new_row_tree,
1424                     scroll_fixture_teardown);
1425
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,
1430                     scroll_new_row,
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,
1435                     scroll_new_row,
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).
1440          */
1441         g_test_add ("/TreeView/scrolling/new-row-mixed/path-5", ScrollFixture,
1442                     GINT_TO_POINTER (5),
1443                     scroll_fixture_mixed_setup,
1444                     scroll_new_row,
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,
1449                     scroll_new_row,
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,
1454                     scroll_new_row,
1455                     scroll_fixture_teardown);
1456
1457         g_test_add ("/TreeView/scrolling/new-row-mixed/tree", ScrollFixture,
1458                     NULL,
1459                     scroll_fixture_mixed_tree_setup,
1460                     scroll_new_row_tree,
1461                     scroll_fixture_teardown);
1462
1463         /* Misc. tests */
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",
1469                         test_bug359231);
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);
1486
1487         return g_test_run ();
1488 }