diff options
author | Mathieu Lacage <mathieu@eazel.com> | 2000-09-15 00:30:36 +0000 |
---|---|---|
committer | Mathieu Lacage <mathieu@src.gnome.org> | 2000-09-15 00:30:36 +0000 |
commit | 8ce8882da8cf7b30113bf5af8eab3a34cc04576f (patch) | |
tree | e1d307bc1aedc27ad049808e3179e93a6ffec60f /components/tree | |
parent | 570a1330584ffe9d128a3aa934adb4d4390f6268 (diff) | |
download | nautilus-8ce8882da8cf7b30113bf5af8eab3a34cc04576f.tar.gz |
fix bug 2937. Tree view now autocollapses when you drag. Not a small
2000-09-14 Mathieu Lacage <mathieu@eazel.com>
* components/tree/nautilus-tree-view.c: fix bug 2937.
Tree view now autocollapses when you drag. Not a small
task...
Diffstat (limited to 'components/tree')
-rw-r--r-- | components/tree/nautilus-tree-view.c | 392 |
1 files changed, 343 insertions, 49 deletions
diff --git a/components/tree/nautilus-tree-view.c b/components/tree/nautilus-tree-view.c index 2bdc4c071..2dcb8f011 100644 --- a/components/tree/nautilus-tree-view.c +++ b/components/tree/nautilus-tree-view.c @@ -62,7 +62,7 @@ /* timeout for the automatic expand in tree view */ #define EXPAND_TIMEOUT 800 - +#define COLLAPSE_TIMEOUT 1200 #define DISPLAY_TIMEOUT_INTERVAL_MSECS 500 @@ -86,7 +86,9 @@ struct _NautilusTreeViewDndDetails { GtkTargetList *target_list; /* data used by the drag_motion code */ - int current_x, current_y; + GSList *expanded_nodes; + GHashTable *collapsed_nodes; + /* row being highlighted */ NautilusCTreeNode *current_prelighted_node; GtkStyle *normal_style; @@ -227,13 +229,13 @@ static char *nautilus_tree_view_find_drop_target (NautilusTreeView int y); static char *nautilus_tree_view_get_drag_uri (NautilusTreeView *tree_view); -static void nautilus_tree_view_expand_or_collapse_row (NautilusCTree *tree, - int row); -static void nautilus_tree_view_expand_row (NautilusCTree *tree, +static void nautilus_tree_view_expand_or_collapse_row (NautilusCTree *tree, int row); +static gboolean nautilus_tree_view_expand_node (NautilusCTree *tree, + NautilusCTreeNode *node); static gboolean nautilus_tree_view_is_tree_node_directory (NautilusTreeView *tree_view, - NautilusCTreeNode *node); -static NautilusCTreeNode *nautilus_tree_view_tree_node_at (NautilusTreeView *tree_view, + NautilusCTreeNode *node); +static NautilusCTreeNode *nautilus_tree_view_tree_node_at (NautilusTreeView *tree_view, int x, int y); @@ -827,6 +829,8 @@ nautilus_tree_view_init_dnd (NautilusTreeView *view) { view->details->dnd = g_new0 (NautilusTreeViewDndDetails, 1); view->details->dnd->motion_queue = nautilus_queue_new (); + view->details->dnd->expanded_nodes = NULL; + view->details->dnd->collapsed_nodes = g_hash_table_new (g_direct_hash, g_direct_equal); view->details->dnd->target_list = gtk_target_list_new (nautilus_tree_view_dnd_target_table, NAUTILUS_N_ELEMENTS (nautilus_tree_view_dnd_target_table)); @@ -1070,7 +1074,7 @@ view_node_to_model_node (NautilusTreeView *view, NautilusTreeNode *tree_node; tree_node = (NautilusTreeNode *) nautilus_ctree_node_get_row_data (NAUTILUS_CTREE (view->details->tree), - node); + node); return tree_node; } @@ -1909,6 +1913,9 @@ nautilus_tree_view_make_prelight_if_keyword (NautilusTreeView *tree_view, int x, dnd = tree_view->details->dnd; node = nautilus_tree_view_tree_node_at (NAUTILUS_TREE_VIEW (tree_view), x, y); + if (node == NULL) { + return; + } if (node != dnd->current_prelighted_node && dnd->current_prelighted_node != NULL) { @@ -1935,9 +1942,10 @@ nautilus_tree_view_make_prelight_if_file_operation (NautilusTreeView *tree_view, dnd = tree_view->details->dnd; /* make the thing under us prelighted. */ - /* FIXME: we should do this only for certain kinds - of drags. ie: files, keywords... not colors or backgrounds */ node = nautilus_tree_view_tree_node_at (NAUTILUS_TREE_VIEW (tree_view), x, y); + if (node == NULL) { + return; + } is_directory = nautilus_tree_view_is_tree_node_directory (NAUTILUS_TREE_VIEW (tree_view), node); if (is_directory == FALSE) { @@ -1962,11 +1970,10 @@ nautilus_tree_view_make_prelight_if_file_operation (NautilusTreeView *tree_view, - -static void -nautilus_tree_view_expand_row (NautilusCTree *tree, int row) +/* return if it was expanded or not */ +static gboolean +nautilus_tree_view_expand_node (NautilusCTree *tree, NautilusCTreeNode *node) { - NautilusCTreeNode *node; char *node_text; guint8 node_spacing; GdkPixmap *pixmap_closed; @@ -1976,7 +1983,6 @@ nautilus_tree_view_expand_row (NautilusCTree *tree, int row) gboolean is_leaf; gboolean is_expanded; - node = nautilus_ctree_node_nth (NAUTILUS_CTREE(tree), row); nautilus_ctree_get_node_info (NAUTILUS_CTREE(tree), node, &node_text, &node_spacing, &pixmap_closed, &mask_closed, @@ -1988,9 +1994,57 @@ nautilus_tree_view_expand_row (NautilusCTree *tree, int row) node); } + return is_expanded; + } +/* returns if it was expanded or not */ +static gboolean +nautilus_tree_view_collapse_node (NautilusCTree *tree, NautilusCTreeNode *node) +{ + char *node_text; + guint8 node_spacing; + GdkPixmap *pixmap_closed; + GdkBitmap *mask_closed; + GdkPixmap *pixmap_opened; + GdkBitmap *mask_opened; + gboolean is_leaf; + gboolean is_expanded; + + nautilus_ctree_get_node_info (NAUTILUS_CTREE(tree), + node, &node_text, + &node_spacing, &pixmap_closed, &mask_closed, + &pixmap_opened, &mask_opened, + &is_leaf, &is_expanded); + if (is_expanded == TRUE) { + /* collapse */ + nautilus_ctree_collapse (NAUTILUS_CTREE(tree), + node); + } + + return is_expanded; +} + +static gboolean +nautilus_tree_view_is_tree_node_expanded (NautilusCTree *tree, NautilusCTreeNode *node) +{ + char *node_text; + guint8 node_spacing; + GdkPixmap *pixmap_closed; + GdkBitmap *mask_closed; + GdkPixmap *pixmap_opened; + GdkBitmap *mask_opened; + gboolean is_leaf; + gboolean is_expanded; + + nautilus_ctree_get_node_info (NAUTILUS_CTREE(tree), + node, &node_text, + &node_spacing, &pixmap_closed, &mask_closed, + &pixmap_opened, &mask_opened, + &is_leaf, &is_expanded); + return is_expanded; +} static void nautilus_tree_view_expand_or_collapse_row (NautilusCTree *tree, int row) { @@ -2061,6 +2115,9 @@ nautilus_tree_view_find_drop_target (NautilusTreeView *tree_view, NautilusTreeNode *current_node; node = nautilus_tree_view_tree_node_at (NAUTILUS_TREE_VIEW (tree_view), x, y); + if (node == NULL) { + return NULL; + } is_directory = nautilus_tree_view_is_tree_node_directory (NAUTILUS_TREE_VIEW (tree_view), node); current_node = view_node_to_model_node (tree_view, node); @@ -2137,11 +2194,12 @@ nautilus_tree_view_item_at (NautilusTreeView *tree_view, node = NULL; node = nautilus_tree_view_tree_node_at (tree_view, x, y); - - retval = NULL; - if (node != NULL) { - retval = g_strdup (view_node_to_uri(tree_view, node)); + if (node == NULL) { + return NULL; } + + retval = g_strdup (view_node_to_uri(tree_view, node)); + return retval; } @@ -2178,53 +2236,286 @@ nautilus_tree_view_ensure_drag_data (NautilusTreeView *tree_view, } -static int motion_time_callback (gpointer data); -static gint -motion_time_callback (gpointer data) -{ +/* hacks for automatic expand/collapse of tree view */ +typedef struct _NautilusTreeViewExpandHack NautilusTreeViewExpandHack; +struct _NautilusTreeViewExpandHack { + NautilusCTree *ctree; + NautilusTreeView *tree_view; + gboolean is_valid; + int org_x; + int org_y; + int refcount; +}; +typedef struct _NautilusTreeViewCollapseHack NautilusTreeViewCollapseHack; +struct _NautilusTreeViewCollapseHack { + NautilusCTree *ctree; NautilusTreeView *tree_view; - NautilusQueue *motion_queue; - int first_y; + NautilusCTreeNode *collapsed_node; + gboolean is_inside; + int refcount; +}; + + +static int expand_time_callback (gpointer data); +static void expand_hack_unref (NautilusTreeViewExpandHack * expand_hack); +static NautilusTreeViewExpandHack *expand_hack_new (int x, int y, NautilusTreeView *tree_view); + +static int collapse_time_callback (gpointer data); +static void collapse_hack_unref (NautilusTreeViewCollapseHack * collapse_hack); +static NautilusTreeViewCollapseHack *collapse_hack_new (NautilusTreeView *tree_view, + NautilusCTreeNode *collapsed_node); + + +static void +collapse_hack_unref (NautilusTreeViewCollapseHack * collapse_hack) +{ + collapse_hack->refcount--; + + if (collapse_hack->refcount == 0) { + g_free (collapse_hack); + } - tree_view = NAUTILUS_TREE_VIEW (data); +} + +static NautilusTreeViewCollapseHack * +collapse_hack_new (NautilusTreeView *tree_view, NautilusCTreeNode *collapsed_node) +{ + NautilusTreeViewCollapseHack *collapse_hack; + + collapse_hack = g_new0 (NautilusTreeViewCollapseHack, 1); + collapse_hack->is_inside = FALSE; + collapse_hack->collapsed_node = collapsed_node; + collapse_hack->refcount = 1; + collapse_hack->ctree = NAUTILUS_CTREE (tree_view->details->tree); + collapse_hack->tree_view = tree_view; + + g_timeout_add (COLLAPSE_TIMEOUT, collapse_time_callback, collapse_hack); - motion_queue = tree_view->details->dnd->motion_queue; + return collapse_hack; +} + + +static char * +nautilus_dump_info (NautilusTreeView *tree_view) +{ + char *retval, *temp; + GSList *list, *tmp; + list = tree_view->details->dnd->expanded_nodes; + + retval = NULL; + for (tmp = list; tmp != NULL;tmp = tmp->next) { + NautilusCTreeNode *node; + const char *uri; + node = (NautilusCTreeNode *) tmp->data; + uri = view_node_to_uri (tree_view, + node); + temp = g_strconcat (uri, ", ", retval, NULL); + g_free (retval); + retval = temp; + } + + return retval; +} + + + + +static gint +collapse_time_callback (gpointer data) +{ + NautilusTreeViewCollapseHack *collapse_hack; + gboolean was_expanded; + + collapse_hack = (NautilusTreeViewCollapseHack *) data; + + if (collapse_hack->is_inside == FALSE) { + was_expanded = nautilus_tree_view_collapse_node (NAUTILUS_CTREE (collapse_hack->ctree), + collapse_hack->collapsed_node); + if (was_expanded == TRUE) { + GHashTable *hash_table; + + /* remove this expanded node form the expanded nodes list */ + collapse_hack->tree_view->details->dnd->expanded_nodes = + g_slist_remove (collapse_hack->tree_view->details->dnd->expanded_nodes, + collapse_hack->collapsed_node); + + /* remove this collapse timeout from the general timeout hash table */ + hash_table = collapse_hack->tree_view->details->dnd->collapsed_nodes; + g_hash_table_remove (hash_table, collapse_hack->collapsed_node); + + { + const char *uri; + uri = view_node_to_uri (collapse_hack->tree_view, + collapse_hack->collapsed_node); + g_print ("collapsing %s in %s\n", uri, nautilus_dump_info (collapse_hack->tree_view)); + } + } + + } + collapse_hack_unref (collapse_hack); - first_y = GPOINTER_TO_INT (nautilus_queue_remove (motion_queue)); - if (abs (first_y - tree_view->details->dnd->current_y) <= 10) { - int row, column; - /* we have almost not moved. so we can say we want to - expand the place we are in. */ - gtk_clist_get_selection_info (GTK_CLIST (tree_view->details->tree), - tree_view->details->dnd->current_x, - tree_view->details->dnd->current_y, - &row, &column); - nautilus_tree_view_expand_row (NAUTILUS_CTREE (tree_view->details->tree), row); - } - - /* never be called again for this "y" value so return FALSE */ + /* never be called again. EVER */ return FALSE; } + +static void +expand_hack_unref (NautilusTreeViewExpandHack * expand_hack) +{ + expand_hack->refcount--; + + if (expand_hack->refcount == 0) { + g_free (expand_hack); + } + +} + +static NautilusTreeViewExpandHack * +expand_hack_new (int x, int y, NautilusTreeView *tree_view) +{ + NautilusTreeViewExpandHack *expand_hack; + + expand_hack = g_new0 (NautilusTreeViewExpandHack, 1); + expand_hack->is_valid = TRUE; + expand_hack->org_x = x; + expand_hack->org_y = y; + expand_hack->ctree = (NautilusCTree *)tree_view->details->tree; + expand_hack->tree_view = tree_view; + expand_hack->refcount = 2; + + g_timeout_add (EXPAND_TIMEOUT, expand_time_callback, expand_hack); + + return expand_hack; +} + +static gint +expand_time_callback (gpointer data) +{ + NautilusTreeViewExpandHack *expand_hack; + + expand_hack = (NautilusTreeViewExpandHack *) data; + + if (expand_hack->is_valid == TRUE) { + NautilusCTreeNode *current_node; + GSList *list; + gboolean was_expanded; + + current_node = nautilus_tree_view_tree_node_at (expand_hack->tree_view, + expand_hack->org_x, + expand_hack->org_y); + if (current_node == NULL) { + expand_hack_unref (expand_hack); + return FALSE; + } + was_expanded = nautilus_tree_view_expand_node (NAUTILUS_CTREE (expand_hack->ctree), + current_node); + if (was_expanded == FALSE) { + list = expand_hack->tree_view->details->dnd->expanded_nodes; + expand_hack->tree_view->details->dnd->expanded_nodes = + g_slist_prepend (list, current_node); + + { + const char *uri; + uri = view_node_to_uri (expand_hack->tree_view, + current_node); + g_print ("expanding %s in %s\n", uri, nautilus_dump_info (expand_hack->tree_view)); + } + } + + } + expand_hack_unref (expand_hack); + + + /* never be called again. EVER */ + return FALSE; +} + + + + + + + + static void nautilus_tree_view_expand_maybe_later (NautilusTreeView *tree_view, int x, int y, gpointer user_data) { - NautilusTreeViewDndDetails *dnd; + static NautilusTreeViewExpandHack *expand_hack = NULL; + NautilusTreeViewCollapseHack *collapse_hack; - g_assert (NAUTILUS_IS_TREE_VIEW (tree_view)); - dnd = tree_view->details->dnd; + NautilusCTreeNode *current_node, *expanded_node; + gboolean is_directory, is_expanded, is_ancestor; + GSList *expanded_list, *temp_list; + + current_node = nautilus_tree_view_tree_node_at (tree_view, + x, y); + if (current_node == NULL) { + return; + } + if (expand_hack == NULL) { + expand_hack = expand_hack_new (x, y, tree_view); + } + + is_directory = nautilus_tree_view_is_tree_node_directory (tree_view, current_node); + is_expanded = nautilus_tree_view_is_tree_node_expanded (NAUTILUS_CTREE (tree_view->details->tree), current_node); + + /* try to expand */ + if (is_directory == TRUE && is_expanded == FALSE) { + int squared_distance; + squared_distance = (abs(x - expand_hack->org_x)) + (abs(y - expand_hack->org_y)); + + if (squared_distance > 8) { + expand_hack->is_valid = FALSE; + expand_hack_unref (expand_hack); + expand_hack = expand_hack_new (x, y, tree_view); + } + } - dnd->current_x = x; - dnd->current_y = y; - /* add the current move to the list of moves to be tested by our - timeout handler later */ - nautilus_queue_add (dnd->motion_queue, GINT_TO_POINTER(y)); - g_timeout_add (EXPAND_TIMEOUT, motion_time_callback, user_data); + /* try to collapse */ + expanded_list = tree_view->details->dnd->expanded_nodes; + if (expanded_list == NULL) { + return; + } + + for (temp_list = expanded_list; temp_list != NULL; temp_list = temp_list->next) { + GHashTable *hash_table; + + expanded_node = (NautilusCTreeNode *) (temp_list->data); + is_ancestor = nautilus_ctree_is_ancestor (NAUTILUS_CTREE (tree_view->details->tree), + expanded_node, + current_node); + + if (is_ancestor == TRUE || current_node == expanded_node) { + /* do not try to collapse */ + hash_table = tree_view->details->dnd->collapsed_nodes; + collapse_hack = (NautilusTreeViewCollapseHack *)g_hash_table_lookup (hash_table, + expanded_node); + if (collapse_hack == NULL) { + return; + } + /* forget about this collapse timeout. */ + collapse_hack->is_inside = TRUE; + g_hash_table_remove (hash_table, collapse_hack->collapsed_node); + } else { + /* try to collapse */ + hash_table = tree_view->details->dnd->collapsed_nodes; + collapse_hack = (NautilusTreeViewCollapseHack *)g_hash_table_lookup (hash_table, + expanded_node); + /* should we start a new collapse timeout for this precise expanded node ? */ + if (collapse_hack == NULL) { + /* yes, a new collpase timeout */ + g_print ("new collpase\n"); + collapse_hack = collapse_hack_new (tree_view, expanded_node); + g_hash_table_insert (hash_table, expanded_node, collapse_hack); + } + collapse_hack->is_inside = FALSE; + } + } } @@ -2499,6 +2790,9 @@ nautilus_tree_view_receive_dropped_keyword (NautilusTreeView *tree_view, char* k /* find the item we hit with our drop, if any */ view_node = nautilus_tree_view_tree_node_at (tree_view, x, y); + if (view_node == NULL) { + return; + } model_node = view_node_to_model_node (tree_view, view_node); file = nautilus_tree_node_get_file (model_node); |