Compare commits

...

2 Commits

Author SHA1 Message Date
António Fernandes
aa3c12d7c6 listitemmanager: Really remove section boundary on insert
Complete the fix introduced by b05000d8bd

It was made to handle the case of inserting at a tracked position which
lies immediately after the a section boundary, of this kind:

  ][

where ']' and '[' are matched FOOTER and HEADER, as in the testsuite.

But it doesn't handle the other 2 cases:

  ](
  )[

where ')' is UNMATCHED_FOOTER and '(' is UNMATCHED_HEADER. Indeed, I
got testsuite/gtk/listitemmanager to crash on these 2 scenarios.

Note: the ')(' case doesn't exist because, at rest, there are no
boundary tiles (and no header widget) between untracked sections.

So, generalize the previous fix and add comments to make it easier
to understand the logic.
2024-01-26 16:30:08 +00:00
António Fernandes
5c819f75e5 testsuite: Also test removing items from section
This allowed me to find another bug.
2024-01-26 16:30:08 +00:00
2 changed files with 50 additions and 20 deletions

View File

@@ -963,31 +963,58 @@ gtk_list_item_manager_add_items (GtkListItemManager *self,
if (has_sections)
{
GtkListTile *section = gtk_list_tile_get_previous_skip (tile);
GtkListTile *header = gtk_list_tile_get_previous_skip (tile);
if (section != NULL && section->type == GTK_LIST_TILE_HEADER)
if (header != NULL && gtk_list_tile_is_header (header))
{
guint start, end;
GtkListTile *footer = gtk_list_tile_get_footer (self, section);
GtkListTile *previous_footer = gtk_list_tile_get_previous_skip (section);
GtkListTile *previous_footer = gtk_list_tile_get_previous_skip (header);
gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), position, &start, &end);
if (previous_footer != NULL && previous_footer->type == GTK_LIST_TILE_FOOTER &&
position > start && position < end)
/* We've inserted right after a header. The new items either don't
* belong in this section or change its length. In either case, we
* need to flag the section header and footer for rematching.
*/
if (header->type == GTK_LIST_TILE_HEADER)
{
gtk_list_item_change_clear_header (change, &section->widget);
gtk_list_tile_set_type (section, GTK_LIST_TILE_REMOVED);
gtk_list_tile_set_type (previous_footer, GTK_LIST_TILE_REMOVED);
section = gtk_list_tile_get_header (self, previous_footer);
gtk_list_item_change_clear_header (change, &header->widget);
gtk_list_tile_set_type (header,
GTK_LIST_TILE_UNMATCHED_HEADER);
gtk_list_tile_set_type (gtk_list_tile_get_footer (self, header),
GTK_LIST_TILE_UNMATCHED_FOOTER);
}
gtk_list_item_change_clear_header (change, &section->widget);
gtk_list_tile_set_type (section,
GTK_LIST_TILE_UNMATCHED_HEADER);
gtk_list_tile_set_type (footer,
GTK_LIST_TILE_UNMATCHED_FOOTER);
if (previous_footer != NULL && gtk_list_tile_is_footer (previous_footer))
{
guint start, end;
gtk_section_model_get_section (GTK_SECTION_MODEL (self->model),
position, &start, &end);
if (position != start)
{
/* At least one item belongs to the previous section, but the
* tile has been inserted after the section boundary. So, this
* boundary must be removed. But first, ensure the previous
* section is flagged for remathing.
*/
if (previous_footer->type == GTK_LIST_TILE_FOOTER)
{
GtkListTile *previous_header = gtk_list_tile_get_header (self, previous_footer);
gtk_list_item_change_clear_header (change, &previous_header->widget);
gtk_list_tile_set_type (previous_header,
GTK_LIST_TILE_UNMATCHED_HEADER);
}
/* Now actually remove the boundary before the inserted tile.
*/
gtk_list_tile_set_type (header, GTK_LIST_TILE_REMOVED);
gtk_list_tile_set_type (previous_footer, GTK_LIST_TILE_REMOVED);
/* We've already ensured the next footer is unmatched, so we
* are done here. gtk_list_item_manager_ensure_items() will
* reintroduce section boundaries where necessary.
*/
}
}
}
}

View File

@@ -501,7 +501,10 @@ test_exhaustive (void)
g_strv_builder_unref (builder);
j = g_test_rand_int_range (0, source_size + 1);
gtk_string_list_splice (GTK_STRING_LIST (source), j, 0, (const char * const *) inclusion);
gtk_string_list_splice (GTK_STRING_LIST (source),
j,
g_test_rand_bit () ? 0 : g_test_rand_int_range (0, source_size - j + 1),
(const char * const *) inclusion);
g_strfreev (inclusion);
if (g_test_verbose ())