Commit 318da579 authored by Paolo Bacchilega's avatar Paolo Bacchilega
Browse files

drag&drop: move files by default

parent 0c3d7ea7
......@@ -34,6 +34,7 @@
#define BROWSER_DATA_KEY "file-manager-browser-data"
#define URI_LIST_ATOM (gdk_atom_intern_static_string ("text/uri-list"))
#define XDND_ACTION_DIRECT_SAVE_ATOM (gdk_atom_intern_static_string ("XdndDirectSave0"))
#define GTHUMB_REORDERABLE_LIST_ATOM (gdk_atom_intern_static_string ("gthumb/reorderable-list"))
#define TEXT_PLAIN_ATOM (gdk_atom_intern_static_string ("text/plain"))
#define SCROLL_TIMEOUT 30 /* autoscroll timeout in milliseconds */
......@@ -125,7 +126,13 @@ static const GthAccelerator accelerators[] = {
static GtkTargetEntry reorderable_drag_dest_targets[] = {
{ "text/uri-list", 0, 0 },
{ "text/uri-list", GTK_TARGET_SAME_WIDGET, 0 }
{ "text/uri-list", GTK_TARGET_SAME_WIDGET, 0 },
{ "gthumb/reorderable-list", 0, 0 }
};
static GtkTargetEntry reorderable_drag_source_targets[] = {
{ "gthumb/reorderable-list", 0, 0 }
};
......@@ -175,8 +182,6 @@ gth_file_list_drag_data_received (GtkWidget *file_view,
GList *selected_files;
GdkDragAction action;
g_signal_stop_emission_by_name (file_view, "drag-data-received");
action = gdk_drag_context_get_suggested_action (context);
if (action == GDK_ACTION_COPY || action == GDK_ACTION_MOVE) {
success = TRUE;
......@@ -435,10 +440,27 @@ gth_file_list_drag_motion (GtkWidget *file_view,
data->scroll_event = 0;
}
}
else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK)
else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) {
gdk_drag_status (context, GDK_ACTION_ASK, time);
else
gdk_drag_status (context, GDK_ACTION_COPY, time);
}
else {
gboolean source_is_reorderable = FALSE;
GList *targets = gdk_drag_context_list_targets (context);
GList *scan;
/* use COPY when dragging a file from a catalog to a directory */
for (scan = targets; scan; scan = scan->next) {
GdkAtom target = scan->data;
if (target == GTHUMB_REORDERABLE_LIST_ATOM) {
source_is_reorderable = TRUE;
break;
}
}
gdk_drag_status (context, source_is_reorderable ? GDK_ACTION_COPY : GDK_ACTION_MOVE, time);
}
return TRUE;
}
......@@ -596,8 +618,13 @@ fm__gth_browser_load_location_after_cb (GthBrowser *browser,
GthFileData *location_data,
const GError *error)
{
BrowserData *data;
GtkWidget *file_view;
BrowserData *data;
GtkWidget *file_list;
GtkWidget *file_view;
GtkTargetList *source_target_list;
GtkTargetEntry *source_targets;
int n_source_targets;
GdkDragAction source_actions;
if ((location_data == NULL) || (error != NULL))
return;
......@@ -605,38 +632,65 @@ fm__gth_browser_load_location_after_cb (GthBrowser *browser,
data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
file_manager_update_ui (data, browser);
source_target_list = gtk_target_list_new (NULL, 0);
gtk_target_list_add_uri_targets (source_target_list, 0);
gtk_target_list_add_text_targets (source_target_list, 0);
source_actions = GDK_ACTION_PRIVATE;
file_list = gth_browser_get_file_list (browser);
if (! g_file_info_get_attribute_boolean (location_data->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) {
file_view = gth_file_list_get_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)));
file_view = gth_file_list_get_view (GTH_FILE_LIST (file_list));
gth_file_view_unset_drag_dest (GTH_FILE_VIEW (file_view));
file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)));
file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (file_list));
gtk_drag_dest_unset (file_view);
source_actions = GDK_ACTION_COPY;
}
else if (gth_file_source_is_reorderable (gth_browser_get_location_source (browser))) {
file_view = gth_file_list_get_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)));
file_view = gth_file_list_get_view (GTH_FILE_LIST (file_list));
gth_file_view_enable_drag_dest (GTH_FILE_VIEW (file_view),
reorderable_drag_dest_targets,
G_N_ELEMENTS (reorderable_drag_dest_targets),
GDK_ACTION_COPY | GDK_ACTION_MOVE);
file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)));
file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (file_list));
gtk_drag_dest_set (file_view,
0,
reorderable_drag_dest_targets,
G_N_ELEMENTS (reorderable_drag_dest_targets),
GDK_ACTION_COPY | GDK_ACTION_MOVE);
gtk_target_list_add_table (source_target_list,
reorderable_drag_source_targets,
G_N_ELEMENTS (reorderable_drag_source_targets));
source_actions = GDK_ACTION_COPY | GDK_ACTION_MOVE;
}
else {
file_view = gth_file_list_get_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)));
file_view = gth_file_list_get_view (GTH_FILE_LIST (file_list));
gth_file_view_enable_drag_dest (GTH_FILE_VIEW (file_view),
non_reorderable_drag_dest_targets,
G_N_ELEMENTS (non_reorderable_drag_dest_targets),
GDK_ACTION_COPY);
file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)));
GDK_ACTION_COPY | GDK_ACTION_MOVE);
file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (file_list));
gtk_drag_dest_set (file_view,
0,
non_reorderable_drag_dest_targets,
G_N_ELEMENTS (non_reorderable_drag_dest_targets),
GDK_ACTION_COPY);
GDK_ACTION_COPY | GDK_ACTION_MOVE);
source_actions = GDK_ACTION_MOVE | GDK_ACTION_ASK;
}
/* set the drag source targets */
source_targets = gtk_target_table_new_from_list (source_target_list, &n_source_targets);
gth_file_view_enable_drag_source (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (file_list))),
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
source_targets,
n_source_targets,
source_actions);
gtk_target_list_unref (source_target_list);
gtk_target_table_free (source_targets, n_source_targets);
}
......
......@@ -73,11 +73,10 @@
#define MIN_SIDEBAR_SIZE 100
#define MIN_VIEWER_SIZE 256
#define STATUSBAR_SEPARATOR " · "
#define SHIRNK_WRAP_WIDTH_OFFSET 100
#define SHIRNK_WRAP_HEIGHT_OFFSET 125
#define FILE_PROPERTIES_MINIMUM_HEIGHT 100
#define HISTORY_FILE "history.xbel"
#define OVERLAY_MARGIN 10
#define AUTO_OPEN_FOLDER_DELAY 500
G_DEFINE_TYPE (GthBrowser, gth_browser, GTH_TYPE_WINDOW)
......@@ -182,6 +181,8 @@ struct _GthBrowserPrivate {
GthSidebarState viewer_sidebar;
BrowserState state;
GthICCProfile screen_profile;
GtkTreePath *folder_tree_last_dest_row; /* used to open a folder during D&D */
guint folder_tree_open_folder_id;
/* settings */
......@@ -2172,6 +2173,11 @@ _gth_browser_real_close (GthBrowser *browser)
browser->priv->selection_changed_event = 0;
}
if (browser->priv->folder_tree_open_folder_id != 0) {
g_source_remove (browser->priv->folder_tree_open_folder_id);
browser->priv->folder_tree_open_folder_id = 0;
}
/* cancel async operations */
_gth_browser_cancel (browser, _gth_browser_close_step3, browser);
......@@ -2602,6 +2608,7 @@ gth_browser_finalize (GObject *object)
_g_object_unref (browser->priv->folder_popup_file_data);
_g_object_unref (browser->priv->history_menu);
gth_icc_profile_free (browser->priv->screen_profile);
gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
G_OBJECT_CLASS (gth_browser_parent_class)->finalize (object);
}
......@@ -2672,6 +2679,130 @@ viewer_container_get_child_position_cb (GtkOverlay *overlay,
}
static gboolean
folder_tree_open_folder_cb (gpointer user_data)
{
GthBrowser *browser = user_data;
if (browser->priv->folder_tree_open_folder_id != 0) {
g_source_remove (browser->priv->folder_tree_open_folder_id);
browser->priv->folder_tree_open_folder_id = 0;
}
gtk_tree_view_expand_row (GTK_TREE_VIEW (browser->priv->folder_tree),
browser->priv->folder_tree_last_dest_row,
FALSE);
return FALSE;
}
static gboolean
folder_tree_drag_motion_cb (GtkWidget *file_view,
GdkDragContext *context,
gint x,
gint y,
guint time,
gpointer user_data)
{
GthBrowser *browser = user_data;
GtkTreePath *path;
GtkTreeViewDropPosition pos;
GdkDragAction action;
if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) {
gdk_drag_status (context, GDK_ACTION_ASK, time);
return FALSE;
}
if (! gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (file_view),
x,
y,
&path,
&pos))
{
gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
browser->priv->folder_tree_last_dest_row = NULL;
if (browser->priv->folder_tree_open_folder_id != 0) {
g_source_remove (browser->priv->folder_tree_open_folder_id);
browser->priv->folder_tree_open_folder_id = 0;
}
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (file_view), NULL, 0);
gdk_drag_status (context, 0, time);
return TRUE;
}
if (pos == GTK_TREE_VIEW_DROP_BEFORE)
pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
if (pos == GTK_TREE_VIEW_DROP_AFTER)
pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (file_view), path, pos);
action = GDK_ACTION_MOVE;
if ((browser->priv->folder_tree_last_dest_row == NULL) || gtk_tree_path_compare (path, browser->priv->folder_tree_last_dest_row) != 0) {
gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
browser->priv->folder_tree_last_dest_row = gtk_tree_path_copy (path);
if (browser->priv->folder_tree_open_folder_id != 0)
g_source_remove (browser->priv->folder_tree_open_folder_id);
browser->priv->folder_tree_open_folder_id = g_timeout_add (AUTO_OPEN_FOLDER_DELAY, folder_tree_open_folder_cb, browser);
}
/* use COPY if dropping a file in a catalog */
if (action == GDK_ACTION_MOVE) {
GthFileData *destination;
GthFileSource *file_source;
destination = gth_folder_tree_get_file (GTH_FOLDER_TREE (browser->priv->folder_tree), path);
if (destination != NULL) {
file_source = gth_main_get_file_source (destination->file);
_g_object_unref (destination);
if (file_source != NULL) {
if (gth_file_source_is_reorderable (file_source))
action = GDK_ACTION_COPY;
}
else
action = 0;
}
else
action = 0;
}
/* use COPY when dragging a file from a catalog to a directory */
if (action == GDK_ACTION_MOVE) {
gboolean source_is_reorderable;
GList *targets;
GList *scan;
source_is_reorderable = FALSE;
targets = gdk_drag_context_list_targets (context);
for (scan = targets; scan; scan = scan->next) {
GdkAtom target = scan->data;
if (target == gdk_atom_intern_static_string ("gthumb/reorderable-list")) {
source_is_reorderable = TRUE;
break;
}
}
if (source_is_reorderable)
action = GDK_ACTION_COPY;
}
gdk_drag_status (context, action, time);
gtk_tree_path_free (path);
return TRUE;
}
static void
folder_tree_drag_data_received (GtkWidget *tree_view,
GdkDragContext *context,
......@@ -2757,7 +2888,7 @@ folder_tree_drag_data_get_cb (GtkWidget *widget,
if (file_source == NULL)
return;
if (gdk_drag_context_get_actions (drag_context) && GDK_ACTION_MOVE) {
if (gdk_drag_context_get_actions (drag_context) & GDK_ACTION_MOVE) {
GdkDragAction action =
gth_file_source_can_cut (file_source, file_data->file) ?
GDK_ACTION_MOVE : GDK_ACTION_COPY;
......@@ -4131,6 +4262,8 @@ gth_browser_init (GthBrowser *browser)
browser->priv->file_properties_on_the_right = g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_PROPERTIES_ON_THE_RIGHT);
browser->priv->menu_managers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
browser->priv->screen_profile = NULL;
browser->priv->folder_tree_last_dest_row = NULL;
browser->priv->folder_tree_open_folder_id = 0;
browser_state_init (&browser->priv->state);
......@@ -4546,6 +4679,10 @@ gth_browser_init (GthBrowser *browser)
targets,
n_targets,
GDK_ACTION_MOVE | GDK_ACTION_COPY);
g_signal_connect (browser->priv->folder_tree,
"drag_motion",
G_CALLBACK (folder_tree_drag_motion_cb),
browser);
g_signal_connect (browser->priv->folder_tree,
"drag-data-received",
G_CALLBACK (folder_tree_drag_data_received),
......
......@@ -660,30 +660,13 @@ gth_file_list_construct (GthFileList *file_list,
"rows-reordered",
G_CALLBACK (file_store_rows_reordered_cb),
file_list);
g_signal_connect (G_OBJECT (file_list->priv->view),
"drag-data-get",
G_CALLBACK (file_view_drag_data_get_cb),
file_list);
if (enable_drag_drop) {
GtkTargetList *target_list;
GtkTargetEntry *targets;
int n_targets;
target_list = gtk_target_list_new (NULL, 0);
gtk_target_list_add_uri_targets (target_list, 0);
gtk_target_list_add_text_targets (target_list, 0);
targets = gtk_target_table_new_from_list (target_list, &n_targets);
gth_file_view_enable_drag_source (GTH_FILE_VIEW (file_list->priv->view),
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
targets,
n_targets,
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
gtk_target_list_unref (target_list);
gtk_target_table_free (targets, n_targets);
g_signal_connect (G_OBJECT (file_list->priv->view),
"drag-data-get",
G_CALLBACK (file_view_drag_data_get_cb),
file_list);
}
if (enable_drag_drop)
gth_file_list_enable_drag_source (file_list, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
gth_file_list_set_mode (file_list, list_type);
......@@ -2150,3 +2133,33 @@ gth_file_list_prev_file (GthFileList *file_list,
return (scan != NULL) ? pos : -1;
}
void
gth_file_list_enable_drag_source (GthFileList *file_list,
GdkDragAction actions)
{
GtkTargetList *target_list;
GtkTargetEntry *targets;
int n_targets;
target_list = gtk_target_list_new (NULL, 0);
gtk_target_list_add_uri_targets (target_list, 0);
gtk_target_list_add_text_targets (target_list, 0);
targets = gtk_target_table_new_from_list (target_list, &n_targets);
gth_file_view_enable_drag_source (GTH_FILE_VIEW (file_list->priv->view),
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
targets,
n_targets,
actions);
gtk_target_list_unref (target_list);
gtk_target_table_free (targets, n_targets);
}
void
gth_file_list_unset_drag_source (GthFileList *file_list)
{
gth_file_view_unset_drag_source (GTH_FILE_VIEW (file_list->priv->view));
}
......@@ -128,6 +128,11 @@ int gth_file_list_prev_file (GthFileList *file_li
gboolean only_selected,
gboolean wrap);
void gth_file_list_enable_drag_source (GthFileList *file_list,
GdkDragAction actions);
void gth_file_list_unset_drag_source (GthFileList *file_list);
G_END_DECLS
#endif /* GTH_FILE_LIST_H */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment