diff options
author | Benjamin Otte <otte@redhat.com> | 2020-06-14 06:41:05 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2020-06-26 07:13:32 +0200 |
commit | fa0295629bd155eaa82f6b25d2c3f97e2b0f9bb3 (patch) | |
tree | 45563a6cfaa582cd9dc0be23efa55dbcda549f7b | |
parent | 83956980907bcb886744b79209efce688f4cadf8 (diff) | |
download | gtk+-fa0295629bd155eaa82f6b25d2c3f97e2b0f9bb3.tar.gz |
selectionmodel: Add gtk_selection_model_set_selection()
Also port the testsuite.
-rw-r--r-- | docs/reference/gtk/gtk4-sections.txt | 1 | ||||
-rw-r--r-- | gtk/gtkmultiselection.c | 86 | ||||
-rw-r--r-- | gtk/gtkpropertyselection.c | 85 | ||||
-rw-r--r-- | gtk/gtkselectionmodel.c | 171 | ||||
-rw-r--r-- | gtk/gtkselectionmodel.h | 14 | ||||
-rw-r--r-- | testsuite/gtk/multiselection.c | 68 |
6 files changed, 240 insertions, 185 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 3af8dbedeb..85f2ef371a 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -397,6 +397,7 @@ gtk_selection_model_select_range gtk_selection_model_unselect_range gtk_selection_model_select_all gtk_selection_model_unselect_all +gtk_selection_model_set_selection GtkSelectionCallback gtk_selection_model_select_callback gtk_selection_model_unselect_callback diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c index 40fc3402a9..048be34cd4 100644 --- a/gtk/gtkmultiselection.c +++ b/gtk/gtkmultiselection.c @@ -107,73 +107,44 @@ gtk_multi_selection_is_selected (GtkSelectionModel *model, } static gboolean -gtk_multi_selection_select_range (GtkSelectionModel *model, - guint position, - guint n_items, - gboolean exclusive) +gtk_multi_selection_set_selection (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask) { GtkMultiSelection *self = GTK_MULTI_SELECTION (model); - guint min = G_MAXUINT; - guint max = 0; + GtkBitset *changes; + guint min, max, n_items; - if (exclusive) - { - min = gtk_bitset_get_minimum (self->selected); - max = gtk_bitset_get_maximum (self->selected); - gtk_bitset_remove_all (self->selected); - } - - gtk_bitset_add_range (self->selected, position, n_items); + /* changes = (self->selected XOR selected) AND mask + * But doing it this way avoids looking at all values outside the mask + */ + changes = gtk_bitset_copy (selected); + gtk_bitset_difference (changes, self->selected); + gtk_bitset_intersect (changes, mask); - min = MIN (position, min); - max = MAX (max, position + n_items - 1); + min = gtk_bitset_get_minimum (changes); + max = gtk_bitset_get_maximum (changes); - gtk_selection_model_selection_changed (model, min, max - min + 1); + /* sanity check */ + n_items = g_list_model_get_n_items (self->model); + if (max >= n_items) + { + gtk_bitset_remove_range_closed (changes, n_items, max); + max = gtk_bitset_get_maximum (changes); + } - return TRUE; -} + /* actually do the change */ + gtk_bitset_difference (self->selected, changes); -static gboolean -gtk_multi_selection_unselect_range (GtkSelectionModel *model, - guint position, - guint n_items) -{ - GtkMultiSelection *self = GTK_MULTI_SELECTION (model); + gtk_bitset_unref (changes); - gtk_bitset_remove_range (self->selected, position, n_items); - gtk_selection_model_selection_changed (model, position, n_items); + if (min <= max) + gtk_selection_model_selection_changed (model, min, max - min + 1); return TRUE; } static gboolean -gtk_multi_selection_select_item (GtkSelectionModel *model, - guint position, - gboolean exclusive) -{ - return gtk_multi_selection_select_range (model, position, 1, exclusive); -} - -static gboolean -gtk_multi_selection_unselect_item (GtkSelectionModel *model, - guint position) -{ - return gtk_multi_selection_unselect_range (model, position, 1); -} - -static gboolean -gtk_multi_selection_select_all (GtkSelectionModel *model) -{ - return gtk_multi_selection_select_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), FALSE); -} - -static gboolean -gtk_multi_selection_unselect_all (GtkSelectionModel *model) -{ - return gtk_multi_selection_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); -} - -static gboolean gtk_multi_selection_add_or_remove (GtkSelectionModel *model, gboolean unselect_rest, gboolean add, @@ -250,12 +221,7 @@ static void gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface) { iface->is_selected = gtk_multi_selection_is_selected; - iface->select_item = gtk_multi_selection_select_item; - iface->unselect_item = gtk_multi_selection_unselect_item; - iface->select_range = gtk_multi_selection_select_range; - iface->unselect_range = gtk_multi_selection_unselect_range; - iface->select_all = gtk_multi_selection_select_all; - iface->unselect_all = gtk_multi_selection_unselect_all; + iface->set_selection = gtk_multi_selection_set_selection; iface->select_callback = gtk_multi_selection_select_callback; iface->unselect_callback = gtk_multi_selection_unselect_callback; } diff --git a/gtk/gtkpropertyselection.c b/gtk/gtkpropertyselection.c index 2fa311091e..0430d0ed04 100644 --- a/gtk/gtkpropertyselection.c +++ b/gtk/gtkpropertyselection.c @@ -138,78 +138,36 @@ gtk_property_selection_is_selected (GtkSelectionModel *model, } static gboolean -gtk_property_selection_select_range (GtkSelectionModel *model, - guint position, - guint n_items, - gboolean exclusive) +gtk_property_selection_set_selection (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask) { GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model); - guint i; - guint n; + GtkBitsetIter iter; + guint i, n, min, max; + gboolean has_value; n = g_list_model_get_n_items (G_LIST_MODEL (self)); - if (exclusive) + min = G_MAXUINT; + max = 0; + + for (has_value = gtk_bitset_iter_init_first (&iter, mask, &i); + has_value && i < n; + has_value = gtk_bitset_iter_next (&iter, &i)) { - for (i = 0; i < n; i++) - set_selected (self, i, FALSE); + set_selected (self, i, gtk_bitset_contains (selected, i)); + /* XXX: Check if something changed? */ + min = MIN (min, i); + max = MAX (max, i); } - for (i = position; i < position + n_items; i++) - set_selected (self, i, TRUE); - - /* FIXME: do better here */ - if (exclusive) - gtk_selection_model_selection_changed (model, 0, n); - else - gtk_selection_model_selection_changed (model, position, n_items); - - return TRUE; -} - -static gboolean -gtk_property_selection_unselect_range (GtkSelectionModel *model, - guint position, - guint n_items) -{ - GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model); - guint i; - - for (i = position; i < position + n_items; i++) - set_selected (self, i, FALSE); - - gtk_selection_model_selection_changed (model, position, n_items); + if (min <= max) + gtk_selection_model_selection_changed (model, min, max - min + 1); return TRUE; } static gboolean -gtk_property_selection_select_item (GtkSelectionModel *model, - guint position, - gboolean exclusive) -{ - return gtk_property_selection_select_range (model, position, 1, exclusive); -} - -static gboolean -gtk_property_selection_unselect_item (GtkSelectionModel *model, - guint position) -{ - return gtk_property_selection_unselect_range (model, position, 1); -} - -static gboolean -gtk_property_selection_select_all (GtkSelectionModel *model) -{ - return gtk_property_selection_select_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), FALSE); -} - -static gboolean -gtk_property_selection_unselect_all (GtkSelectionModel *model) -{ - return gtk_property_selection_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); -} - -static gboolean gtk_property_selection_add_or_remove (GtkSelectionModel *model, gboolean unselect_rest, gboolean add, @@ -280,12 +238,7 @@ static void gtk_property_selection_selection_model_init (GtkSelectionModelInterface *iface) { iface->is_selected = gtk_property_selection_is_selected; - iface->select_item = gtk_property_selection_select_item; - iface->unselect_item = gtk_property_selection_unselect_item; - iface->select_range = gtk_property_selection_select_range; - iface->unselect_range = gtk_property_selection_unselect_range; - iface->select_all = gtk_property_selection_select_all; - iface->unselect_all = gtk_property_selection_unselect_all; + iface->set_selection = gtk_property_selection_set_selection; iface->select_callback = gtk_property_selection_select_callback; iface->unselect_callback = gtk_property_selection_unselect_callback; } diff --git a/gtk/gtkselectionmodel.c b/gtk/gtkselectionmodel.c index 24db61f739..c62efbb538 100644 --- a/gtk/gtkselectionmodel.c +++ b/gtk/gtkselectionmodel.c @@ -114,13 +114,48 @@ gtk_selection_model_default_select_item (GtkSelectionModel *model, guint position, gboolean unselect_rest) { - return FALSE; + GtkBitset *selected; + GtkBitset *mask; + gboolean result; + + selected = gtk_bitset_new_empty (); + gtk_bitset_add (selected, position); + if (unselect_rest) + { + mask = gtk_bitset_new_empty (); + gtk_bitset_add_range (mask, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); + } + else + { + mask = gtk_bitset_ref (selected); + } + + result = gtk_selection_model_set_selection (model, selected, mask); + + gtk_bitset_unref (selected); + gtk_bitset_unref (mask); + + return result; } + static gboolean gtk_selection_model_default_unselect_item (GtkSelectionModel *model, guint position) { - return FALSE; + GtkBitset *selected; + GtkBitset *mask; + gboolean result; + + selected = gtk_bitset_new_empty (); + mask = gtk_bitset_new_empty (); + gtk_bitset_add (mask, position); + + result = gtk_selection_model_set_selection (model, selected, mask); + + gtk_bitset_unref (selected); + gtk_bitset_unref (mask); + + return result; } static gboolean @@ -129,7 +164,28 @@ gtk_selection_model_default_select_range (GtkSelectionModel *model, guint n_items, gboolean unselect_rest) { - return FALSE; + GtkBitset *selected; + GtkBitset *mask; + gboolean result; + + selected = gtk_bitset_new_empty (); + gtk_bitset_add_range (selected, position, n_items); + if (unselect_rest) + { + mask = gtk_bitset_new_empty (); + gtk_bitset_add_range (mask, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); + } + else + { + mask = gtk_bitset_ref (selected); + } + + result = gtk_selection_model_set_selection (model, selected, mask); + + gtk_bitset_unref (selected); + gtk_bitset_unref (mask); + + return result; } static gboolean @@ -137,7 +193,20 @@ gtk_selection_model_default_unselect_range (GtkSelectionModel *model, guint position, guint n_items) { - return FALSE; + GtkBitset *selected; + GtkBitset *mask; + gboolean result; + + selected = gtk_bitset_new_empty (); + mask = gtk_bitset_new_empty (); + gtk_bitset_add_range (mask, position, n_items); + + result = gtk_selection_model_set_selection (model, selected, mask); + + gtk_bitset_unref (selected); + gtk_bitset_unref (mask); + + return result; } static gboolean @@ -169,6 +238,14 @@ gtk_selection_model_default_unselect_all (GtkSelectionModel *model) return gtk_selection_model_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); } +static gboolean +gtk_selection_model_default_set_selection (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask) +{ + return FALSE; +} + static void gtk_selection_model_default_init (GtkSelectionModelInterface *iface) { @@ -180,6 +257,7 @@ gtk_selection_model_default_init (GtkSelectionModelInterface *iface) iface->unselect_range = gtk_selection_model_default_unselect_range; iface->select_all = gtk_selection_model_default_select_all; iface->unselect_all = gtk_selection_model_default_unselect_all; + iface->set_selection = gtk_selection_model_default_set_selection; iface->select_callback = gtk_selection_model_default_select_callback; iface->unselect_callback = gtk_selection_model_default_unselect_callback; @@ -294,6 +372,9 @@ gtk_selection_model_get_selection_in_range (GtkSelectionModel *model, * @unselect_rest: whether previously selected items should be unselected * * Requests to select an item in the model. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean the item was selected. */ gboolean gtk_selection_model_select_item (GtkSelectionModel *model, @@ -302,7 +383,7 @@ gtk_selection_model_select_item (GtkSelectionModel *model, { GtkSelectionModelInterface *iface; - g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0); + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); iface = GTK_SELECTION_MODEL_GET_IFACE (model); return iface->select_item (model, position, unselect_rest); @@ -314,6 +395,9 @@ gtk_selection_model_select_item (GtkSelectionModel *model, * @position: the position of the item to unselect * * Requests to unselect an item in the model. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean the item was unselected. */ gboolean gtk_selection_model_unselect_item (GtkSelectionModel *model, @@ -321,7 +405,7 @@ gtk_selection_model_unselect_item (GtkSelectionModel *model, { GtkSelectionModelInterface *iface; - g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0); + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); iface = GTK_SELECTION_MODEL_GET_IFACE (model); return iface->unselect_item (model, position); @@ -335,6 +419,9 @@ gtk_selection_model_unselect_item (GtkSelectionModel *model, * @unselect_rest: whether previously selected items should be unselected * * Requests to select a range of items in the model. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean the range was selected. */ gboolean gtk_selection_model_select_range (GtkSelectionModel *model, @@ -344,7 +431,7 @@ gtk_selection_model_select_range (GtkSelectionModel *model, { GtkSelectionModelInterface *iface; - g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0); + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); iface = GTK_SELECTION_MODEL_GET_IFACE (model); return iface->select_range (model, position, n_items, unselect_rest); @@ -357,6 +444,9 @@ gtk_selection_model_select_range (GtkSelectionModel *model, * @n_items: the number of items to unselect * * Requests to unselect a range of items in the model. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean the range was unselected. */ gboolean gtk_selection_model_unselect_range (GtkSelectionModel *model, @@ -365,7 +455,7 @@ gtk_selection_model_unselect_range (GtkSelectionModel *model, { GtkSelectionModelInterface *iface; - g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0); + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); iface = GTK_SELECTION_MODEL_GET_IFACE (model); return iface->unselect_range (model, position, n_items); @@ -376,13 +466,16 @@ gtk_selection_model_unselect_range (GtkSelectionModel *model, * @model: a #GtkSelectionModel * * Requests to select all items in the model. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean that all items are now selected. */ gboolean gtk_selection_model_select_all (GtkSelectionModel *model) { GtkSelectionModelInterface *iface; - g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0); + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); iface = GTK_SELECTION_MODEL_GET_IFACE (model); return iface->select_all (model); @@ -393,19 +486,77 @@ gtk_selection_model_select_all (GtkSelectionModel *model) * @model: a #GtkSelectionModel * * Requests to unselect all items in the model. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean that all items are now unselected. */ gboolean gtk_selection_model_unselect_all (GtkSelectionModel *model) { GtkSelectionModelInterface *iface; - g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0); + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); iface = GTK_SELECTION_MODEL_GET_IFACE (model); return iface->unselect_all (model); } /** + * gtk_selection_model_set_selection: + * @model: a #GtkSelectionModel + * @selected: bitmask specifying if items should be selected or + * unselected + * @mask: bitmask specifying which items should be updated + * + * This is the most advanced selection updating method that allows + * the most fine-grained control over selection changes. + * If you can, you should try the simpler versions, as implementations + * are more likely to implement support for those. + * + * Requests that the selection state of all positions set in @mask be + * updated to the respecitve value in the @selected bitmask. + * + * In pseudocode, it would look something like this: + * + * |[<!-- language="C" --> + * for (i = 0; i < n_items; i++) + * { + * // don't change values not in the mask + * if (!gtk_bitset_contains (mask, i)) + * continue; + * + * if (gtk_bitset_contains (selected, i)) + * select_item (i); + * else + * unselect_item (i); + * } + * + * gtk_selection_model_selection_changed (model, first_changed_item, n_changed_items); + * ]| + * + * @mask and @selected must not be modified. They may refer to the same bitset, + * which would mean that every item in the set should be selected. + * + * Returns: %TRUE if this action was supported and no fallback should be + * tried. This does not mean that all items were updated according + * to the inputs. + **/ +gboolean +gtk_selection_model_set_selection (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask) +{ + GtkSelectionModelInterface *iface; + + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE); + g_return_val_if_fail (selected != NULL, FALSE); + g_return_val_if_fail (mask != NULL, FALSE); + + iface = GTK_SELECTION_MODEL_GET_IFACE (model); + return iface->set_selection (model, selected, mask); +} + +/** * gtk_selection_model_select_callback: * @model: a #GtkSelectionModel * @unselect_rest: whether previously selected items should be unselected diff --git a/gtk/gtkselectionmodel.h b/gtk/gtkselectionmodel.h index e48ce20fee..8b90fc6793 100644 --- a/gtk/gtkselectionmodel.h +++ b/gtk/gtkselectionmodel.h @@ -82,6 +82,9 @@ typedef void (* GtkSelectionCallback) (guint position, * unsupported or known to fail for all items, return %FALSE. * @unselect_all: Unselect all items in the model. If the operation is * unsupported or known to fail for all items, return %FALSE. + * @set_selection: Set selection state of all items in mask to selected. + * See gtk_selection_model_set_selection() for a detailed explanation + * of this function. * * The list of virtual functions for the #GtkSelectionModel interface. * No function must be implemented, but unless #GtkSelectionModel::is_selected() @@ -91,6 +94,10 @@ typedef void (* GtkSelectionCallback) (guint position, * selecting or unselecting items. Of course, if the model does not do that, * it means that users cannot select or unselect items in a list widget * using the model. + * + * All selection functions fall back to #GtkSelectionModel::set_selection() + * so it is sufficient to implement just that function for full selection + * support. */ struct _GtkSelectionModelInterface { @@ -118,6 +125,9 @@ struct _GtkSelectionModelInterface guint n_items); gboolean (* select_all) (GtkSelectionModel *model); gboolean (* unselect_all) (GtkSelectionModel *model); + gboolean (* set_selection) (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask); gboolean (* select_callback) (GtkSelectionModel *model, gboolean unselect_rest, GtkSelectionCallback callback, @@ -158,6 +168,10 @@ GDK_AVAILABLE_IN_ALL gboolean gtk_selection_model_select_all (GtkSelectionModel *model); GDK_AVAILABLE_IN_ALL gboolean gtk_selection_model_unselect_all (GtkSelectionModel *model); +GDK_AVAILABLE_IN_ALL +gboolean gtk_selection_model_set_selection (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask); GDK_AVAILABLE_IN_ALL gboolean gtk_selection_model_select_callback (GtkSelectionModel *model, diff --git a/testsuite/gtk/multiselection.c b/testsuite/gtk/multiselection.c index 3c59d307f3..c9ec1b3bc6 100644 --- a/testsuite/gtk/multiselection.c +++ b/testsuite/gtk/multiselection.c @@ -396,7 +396,7 @@ test_select_range (void) ret = gtk_selection_model_select_range (selection, 3, 2, FALSE); g_assert_true (ret); assert_selection (selection, "3 4 5"); - assert_selection_changes (selection, "3:2"); + assert_selection_changes (selection, "4:1"); ret = gtk_selection_model_select_range (selection, 0, 1, TRUE); g_assert_true (ret); @@ -438,56 +438,13 @@ test_readd (void) g_object_unref (selection); } -typedef struct { - guint start; - guint n; - gboolean in; -} SelectionData; - -static void -select_some (guint position, - guint *start, - guint *n, - gboolean *selected, - gpointer data) -{ - SelectionData *sdata = data; - guint i; - - for (i = 0; sdata[i].n != 0; i++) - { - if (sdata[i].start <= position && - position < sdata[i].start + sdata[i].n) - break; - } - - *start = sdata[i].start; - *n = sdata[i].n; - *selected = sdata[i].in; -} - static void -test_callback (void) +test_set_selection (void) { GtkSelectionModel *selection; gboolean ret; GListStore *store; - SelectionData data[] = { - { 0, 2, FALSE }, - { 2, 3, TRUE }, - { 5, 2, FALSE }, - { 6, 3, TRUE }, - { 9, 1, FALSE }, - { 0, 0, FALSE } - }; - - SelectionData more_data[] = { - { 0, 3, FALSE }, - { 3, 1, TRUE }, - { 4, 3, FALSE }, - { 7, 1, TRUE }, - { 0, 0, FALSE } - }; + GtkBitset *selected, *mask; store = new_store (1, 10, 1); @@ -496,13 +453,26 @@ test_callback (void) assert_selection (selection, ""); assert_selection_changes (selection, ""); - ret = gtk_selection_model_select_callback (selection, FALSE, select_some, data); + selected = gtk_bitset_new_empty (); + gtk_bitset_add_range (selected, 2, 3); + gtk_bitset_add_range (selected, 6, 3); + mask = gtk_bitset_new_empty (); + gtk_bitset_add_range (mask, 0, 100); /* too big on purpose */ + ret = gtk_selection_model_set_selection (selection, selected, mask); g_assert_true (ret); + gtk_bitset_unref (selected); + gtk_bitset_unref (mask); assert_selection (selection, "3 4 5 7 8 9"); assert_selection_changes (selection, "2:7"); - ret = gtk_selection_model_unselect_callback (selection, select_some, more_data); + selected = gtk_bitset_new_empty (); + mask = gtk_bitset_new_empty (); + gtk_bitset_add (mask, 3); + gtk_bitset_add (mask, 7); + ret = gtk_selection_model_set_selection (selection, selected, mask); g_assert_true (ret); + gtk_bitset_unref (selected); + gtk_bitset_unref (mask); assert_selection (selection, "3 5 7 9"); assert_selection_changes (selection, "3:5"); @@ -528,7 +498,7 @@ main (int argc, char *argv[]) g_test_add_func ("/multiselection/selection", test_selection); g_test_add_func ("/multiselection/select-range", test_select_range); g_test_add_func ("/multiselection/readd", test_readd); - g_test_add_func ("/multiselection/callback", test_callback); + g_test_add_func ("/multiselection/set_selection", test_set_selection); return g_test_run (); } |