diff options
Diffstat (limited to 'lib/widgets')
-rw-r--r-- | lib/widgets/ephy-node-view.c | 284 |
1 files changed, 233 insertions, 51 deletions
diff --git a/lib/widgets/ephy-node-view.c b/lib/widgets/ephy-node-view.c index 1b4c91f3f..c49924b37 100644 --- a/lib/widgets/ephy-node-view.c +++ b/lib/widgets/ephy-node-view.c @@ -74,6 +74,11 @@ struct EphyNodeViewPrivate int drag_x; int drag_y; GtkTargetList *source_target_list; + + gboolean drop_occurred; + gboolean have_drag_data; + GtkSelectionData *drag_data; + guint scroll_id; }; enum @@ -92,6 +97,8 @@ enum PROP_FILTER }; +#define AUTO_SCROLL_MARGIN 20 + static GObjectClass *parent_class = NULL; static guint ephy_node_view_signals[LAST_SIGNAL] = { 0 }; @@ -224,6 +231,8 @@ get_node_from_path (EphyNodeView *view, GtkTreePath *path) EphyNode *node; GtkTreeIter iter, iter2; + if (path == NULL) return NULL; + gtk_tree_model_get_iter (view->priv->sortmodel, &iter, path); gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (view->priv->sortmodel), &iter2, &iter); @@ -234,99 +243,270 @@ get_node_from_path (EphyNodeView *view, GtkTreePath *path) return node; } -static gboolean -drag_motion_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time, - EphyNodeView *view) +static void +gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view) { - EphyNode *node; - GtkTreePath *path = NULL; - GtkTreeViewDropPosition pos; - gboolean res; - EphyNodeViewPriority priority; + GdkRectangle visible_rect; + GtkAdjustment *vadjustment; + GdkWindow *window; + int y; + int offset; + float value; + + window = gtk_tree_view_get_bin_window (tree_view); + vadjustment = gtk_tree_view_get_vadjustment (tree_view); + + gdk_window_get_pointer (window, NULL, &y, NULL); + + y += vadjustment->value; + + gtk_tree_view_get_visible_rect (tree_view, &visible_rect); + + offset = y - (visible_rect.y + 2 * AUTO_SCROLL_MARGIN); + if (offset > 0) + { + offset = y - (visible_rect.y + visible_rect.height - 2 * AUTO_SCROLL_MARGIN); + if (offset < 0) + { + return; + } + } - res = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), - x, y, &path, &pos); - if (!res) return TRUE; + value = CLAMP (vadjustment->value + offset, 0.0, + vadjustment->upper - vadjustment->page_size); + gtk_adjustment_set_value (vadjustment, value); +} - node = get_node_from_path (view, path); +static int +scroll_timeout (gpointer data) +{ + GtkTreeView *tree_view = GTK_TREE_VIEW (data); + + gtk_tree_view_vertical_autoscroll (tree_view); - priority = ephy_node_get_property_int (node, view->priv->priority_prop_id); + return TRUE; +} - if (priority != EPHY_NODE_VIEW_ALL_PRIORITY && - priority != EPHY_NODE_VIEW_SPECIAL_PRIORITY) +static void +remove_scroll_timeout (EphyNodeView *view) +{ + if (view->priv->scroll_id) + { + g_source_remove (view->priv->scroll_id); + view->priv->scroll_id = 0; + } +} +static void +set_drag_dest_row (EphyNodeView *view, + GtkTreePath *path) +{ + if (path) { - gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), path, - GTK_TREE_VIEW_DROP_INTO_OR_AFTER); - gdk_drag_status (context, context->suggested_action, time); + gtk_tree_view_set_drag_dest_row + (GTK_TREE_VIEW (view), + path, + GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); } else { - gdk_drag_status (context, 0, time); + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), + NULL, + 0); } +} - gtk_tree_path_free (path); +static void +clear_drag_dest_row (EphyNodeView *view) +{ + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), NULL, 0); +} - return TRUE; +static void +get_drag_data (EphyNodeView *view, + GdkDragContext *context, + guint32 time) +{ + GdkAtom target; + + target = gtk_drag_dest_find_target (GTK_WIDGET (view), + context, + NULL); + + gtk_drag_get_data (GTK_WIDGET (view), + context, target, time); +} + +static void +free_drag_data (EphyNodeView *view) +{ + view->priv->have_drag_data = FALSE; + + if (view->priv->drag_data) + { + gtk_selection_data_free (view->priv->drag_data); + view->priv->drag_data = NULL; + } } static gboolean -drag_drop_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time, - EphyNodeView *view) +drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + guint32 time, + EphyNodeView *view) { - GdkAtom target; + EphyNode *node; + GtkTreePath *path; + GtkTreeViewDropPosition pos; + guint action = 0; + int priority; - target = gtk_drag_dest_find_target (widget, context, - view->priv->drag_targets); + gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), + x, y, &path, &pos); + + if (!view->priv->have_drag_data) + { + get_drag_data (view, context, time); + } + + node = get_node_from_path (view, path); - if (target != GDK_NONE) + if (node) { - gtk_drag_get_data (widget, context, target, time); + priority = ephy_node_get_property_int + (node, view->priv->priority_prop_id); + + if (priority != EPHY_NODE_VIEW_ALL_PRIORITY && + priority != EPHY_NODE_VIEW_SPECIAL_PRIORITY) + { + action = context->suggested_action; + } } + + if (action) + { + set_drag_dest_row (view, path); + } + else + { + clear_drag_dest_row (view); + } + + if (path) + { + gtk_tree_path_free (path); + } + + if (view->priv->scroll_id == 0) + { + view->priv->scroll_id = + g_timeout_add (150, + scroll_timeout, + GTK_TREE_VIEW (view)); + } + + gdk_drag_status (context, action, time); return TRUE; } +static void +drag_leave_cb (GtkWidget *widget, + GdkDragContext *context, + guint32 time, + EphyNodeView *view) +{ + clear_drag_dest_row (view); + + free_drag_data (view); + + remove_scroll_timeout (view); +} + static gboolean drag_data_received_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint time, - EphyNodeView *view) + GdkDragContext *context, + int x, + int y, + GtkSelectionData *selection_data, + guint info, + guint32 time, + EphyNodeView *view) { - GtkTreePath *path = NULL; + GtkTreePath *path; GtkTreeViewDropPosition pos; + gboolean on_row; - if (gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), - x, y, &path, &pos)) + if (selection_data->length <= 0 || selection_data->data == NULL) + { + return FALSE; + } + + on_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), + x, y, &path, &pos); + + if (!view->priv->have_drag_data) + { + view->priv->have_drag_data = TRUE; + view->priv->drag_data = + gtk_selection_data_copy (selection_data); + } + + if (view->priv->drop_occurred) { EphyNode *node; GList *uris; + gboolean success = FALSE; + + g_return_val_if_fail (on_row || path != NULL, FALSE); node = get_node_from_path (view, path); uris = gnome_vfs_uri_list_parse (selection_data->data); - g_signal_emit (G_OBJECT (view), - ephy_node_view_signals[NODE_DROPPED], 0, - node, uris); - gnome_vfs_uri_list_free (uris); + + if (uris != NULL) + { + /* FIXME fill success */ + g_signal_emit (G_OBJECT (view), + ephy_node_view_signals[NODE_DROPPED], 0, + node, uris); + gnome_vfs_uri_list_free (uris); + } + + view->priv->drop_occurred = FALSE; + free_drag_data (view); + gtk_drag_finish (context, success, FALSE, time); + } + if (path) + { gtk_tree_path_free (path); } - g_signal_stop_emission_by_name (widget, "drag_data_received"); + /* appease GtkTreeView by preventing its drag_data_receive + * from being called */ + g_signal_stop_emission_by_name (GTK_TREE_VIEW (view), + "drag_data_received"); + + return TRUE; +} + +static gboolean +drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + guint32 time, + EphyNodeView *view) +{ + view->priv->drop_occurred = TRUE; + get_drag_data (view, context, time); + remove_scroll_timeout (view); + clear_drag_dest_row (view); + return TRUE; } @@ -352,6 +532,8 @@ ephy_node_view_enable_drag_dest (EphyNodeView *view, G_CALLBACK (drag_drop_cb), view); g_signal_connect (treeview, "drag_motion", G_CALLBACK (drag_motion_cb), view); + g_signal_connect (treeview, "drag_leave", + G_CALLBACK (drag_leave_cb), view); } static void |