Commit f755bfc1 authored by Dave Camp's avatar Dave Camp Committed by Dave Camp

Implement the widget side drag and drop here instead of eggtreemultidnd.c.

2003-03-26  Dave Camp  <dave@ximian.com>

	* src/file-manager/fm-list-view.c: (activate_selected_items),
	(fm_list_view_did_not_drag), (drag_data_get_callback),
	(selection_foreach), (get_selection_refs), (ref_list_free),
	(stop_drag_check), (get_drag_pixbuf), (motion_notify_callback),
	(button_event_modifies_selection), (button_press_callback),
	(button_release_callback), (key_press_callback),
	(create_and_set_up_tree_view), (fm_list_view_finalize): Implement
	the widget side drag and drop here instead of eggtreemultidnd.c.
	Clean up mouse event handling to be more similar to the icon view.

	Fixes bug #48051, #89980, #90437, #105593, #108946, among others.

	Thanks to marten ter borgh <marten@terborgh.demon.nl> for help
	with this patch.
parent b793c9d6
2003-03-26 Dave Camp <dave@ximian.com>
* src/file-manager/fm-list-view.c: (activate_selected_items),
(fm_list_view_did_not_drag), (drag_data_get_callback),
(selection_foreach), (get_selection_refs), (ref_list_free),
(stop_drag_check), (get_drag_pixbuf), (motion_notify_callback),
(button_event_modifies_selection), (button_press_callback),
(button_release_callback), (key_press_callback),
(create_and_set_up_tree_view), (fm_list_view_finalize): Implement
the widget side drag and drop here instead of eggtreemultidnd.c.
Clean up mouse event handling to be more similar to the icon view.
Fixes bug #48051, #89980, #90437, #105593, #108946, among others.
Thanks to marten ter borgh <marten@terborgh.demon.nl> for help
with this patch.
2003-03-26 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/nautilus-icon-private.h:
......
......@@ -31,6 +31,7 @@
#include "fm-error-reporting.h"
#include "fm-list-model.h"
#include <eel/eel-cell-renderer-pixbuf-list.h>
#include <eel/eel-glib-extensions.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkcellrendererpixbuf.h>
#include <gtk/gtkcellrenderertext.h>
......@@ -67,6 +68,16 @@ struct FMListViewDetails {
NautilusScrollPositionable *positionable;
NautilusTreeViewDragDest *drag_dest;
GtkTargetList *source_target_list;
GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */
guint drag_button;
int drag_x;
int drag_y;
gboolean drag_started;
};
/*
......@@ -131,6 +142,218 @@ tree_view_has_selection (GtkTreeView *view)
return tree_selection_not_empty (gtk_tree_view_get_selection (view));
}
static void
activate_selected_items (FMListView *view)
{
GList *file_list;
file_list = fm_list_view_get_selection (FM_DIRECTORY_VIEW (view));
fm_directory_view_activate_files (FM_DIRECTORY_VIEW (view),
file_list);
nautilus_file_list_free (file_list);
}
static gboolean
button_event_modifies_selection (GdkEventButton *event)
{
return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
}
static void
fm_list_view_did_not_drag (FMListView *view,
GdkEventButton *event)
{
GtkTreeView *tree_view;
GtkTreeSelection *selection;
GtkTreePath *path;
tree_view = view->details->tree_view;
selection = gtk_tree_view_get_selection (tree_view);
if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y,
&path, NULL, NULL, NULL)) {
if(event->button == 1
&& (click_policy_auto_value == NAUTILUS_CLICK_POLICY_DOUBLE)
&& gtk_tree_selection_path_is_selected (selection, path)
&& !button_event_modifies_selection (event)) {
gtk_tree_selection_unselect_all (selection);
gtk_tree_selection_select_path (selection, path);
}
if ((event->button == 1)
&& (click_policy_auto_value == NAUTILUS_CLICK_POLICY_SINGLE)
&& !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) {
activate_selected_items (view);
}
gtk_tree_path_free (path);
}
}
static void
drag_data_get_callback (GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time)
{
GtkTreeView *tree_view;
GtkTreeModel *model;
GList *ref_list;
tree_view = GTK_TREE_VIEW (widget);
model = gtk_tree_view_get_model (tree_view);
if (model == NULL) {
return;
}
ref_list = g_object_get_data (G_OBJECT (context), "drag-info");
if (ref_list == NULL) {
return;
}
if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model))
{
egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model),
ref_list,
selection_data);
}
}
static void
selection_foreach (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
GList **list;
list = (GList**)data;
*list = g_list_prepend (*list,
gtk_tree_row_reference_new (model, path));
}
static GList *
get_selection_refs (GtkTreeView *tree_view)
{
GtkTreeSelection *selection;
GList *ref_list;
ref_list = NULL;
selection = gtk_tree_view_get_selection (tree_view);
gtk_tree_selection_selected_foreach (selection,
selection_foreach,
&ref_list);
ref_list = g_list_reverse (ref_list);
return ref_list;
}
static void
ref_list_free (GList *ref_list)
{
g_list_foreach (ref_list, (GFunc) gtk_tree_row_reference_free, NULL);
g_list_free (ref_list);
}
static void
stop_drag_check (FMListView *view)
{
view->details->drag_button = 0;
}
static GdkPixbuf *
get_drag_pixbuf (FMListView *view, int *offset_x, int *offset_y)
{
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
GdkPixbuf *ret;
GdkRectangle cell_area;
ret = NULL;
if (gtk_tree_view_get_path_at_pos (view->details->tree_view,
view->details->drag_x,
view->details->drag_y,
&path, NULL, NULL, NULL)) {
model = gtk_tree_view_get_model (view->details->tree_view);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter,
fm_list_model_get_column_id_from_zoom_level (view->details->zoom_level),
&ret,
-1);
gtk_tree_view_get_cell_area (view->details->tree_view,
path,
view->details->file_name_column,
&cell_area);
*offset_x = view->details->drag_x - cell_area.x;
*offset_y = view->details->drag_y - cell_area.y;
gtk_tree_path-free (path);
}
return ret;
}
static gboolean
motion_notify_callback (GtkWidget *widget,
GdkEventMotion *event,
gpointer callback_data)
{
FMListView *view;
GdkDragContext *context;
GList *ref_list;
GdkPixbuf *pixbuf;
int offset_x, offset_y;
view = FM_LIST_VIEW (callback_data);
if (view->details->drag_button != 0) {
if (gtk_drag_check_threshold (widget,
view->details->drag_x,
view->details->drag_y,
event->x,
event->y)) {
context = gtk_drag_begin
(widget,
view->details->source_target_list,
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK,
view->details->drag_button,
(GdkEvent*)event);
stop_drag_check (view);
view->details->drag_started = TRUE;
ref_list = get_selection_refs (GTK_TREE_VIEW (widget));
g_object_set_data_full (G_OBJECT (context),
"drag-info",
ref_list,
(GDestroyNotify)ref_list_free);
pixbuf = get_drag_pixbuf (view, &offset_x, &offset_y);
if (pixbuf) {
gtk_drag_set_icon_pixbuf (context,
pixbuf,
offset_x,
offset_y);
g_object_unref (pixbuf);
} else {
gtk_drag_set_icon_default (context);
}
}
}
return TRUE;
}
static gboolean
button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callback_data)
{
......@@ -138,12 +361,18 @@ button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callba
GtkTreeView *tree_view;
GtkTreePath *path;
gboolean call_parent;
gboolean allow_drag;
GtkTreeSelection *selection;
GtkWidgetClass *tree_view_class;
GList *file_list;
gint64 current_time;
static gint64 last_click_time = 0;
static int click_count = 0;
int double_click_time;
view = FM_LIST_VIEW (callback_data);
tree_view = GTK_TREE_VIEW (widget);
tree_view_class = GTK_WIDGET_GET_CLASS (tree_view);
selection = gtk_tree_view_get_selection(tree_view);
if (event->window != gtk_tree_view_get_bin_window (tree_view)) {
return FALSE;
......@@ -153,67 +382,118 @@ button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer callba
(FM_LIST_MODEL (gtk_tree_view_get_model (tree_view)),
tree_view,
event->x, event->y);
g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
"gtk-double-click-time", &double_click_time,
NULL);
/* Determine click count */
current_time = eel_get_system_time ();
if (current_time - last_click_time < double_click_time * 1000) {
click_count++;
} else {
click_count = 0;
}
/* Stash time for next compare */
last_click_time = current_time;
/* Ignore double click if we are in single click mode */
if (click_policy_auto_value == NAUTILUS_CLICK_POLICY_SINGLE && click_count >= 2) {
return TRUE;
}
call_parent = TRUE;
allow_drag = FALSE;
if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y,
&path, NULL, NULL, NULL)) {
if ((event->button == 3 ||
(event->button == 1 && click_policy_auto_value == NAUTILUS_CLICK_POLICY_SINGLE))
&& gtk_tree_selection_path_is_selected (gtk_tree_view_get_selection (tree_view), path)) {
/* Don't let the default code run because if
multiple rows are selected it will unselect
all but one row; but we- want the right
click menu or single click to apply to
everything that's currently selected. */
if (event->button == 1 &&
event->type == GDK_BUTTON_PRESS) {
if (view->details->double_click_path[1]) {
gtk_tree_path_free (view->details->double_click_path[1]);
}
view->details->double_click_path[1] = view->details->double_click_path[0];
view->details->double_click_path[0] = gtk_tree_path_copy (path);
}
if (event->type == GDK_2BUTTON_PRESS &&
(event->button == 1 || event->button == 3)) {
if (view->details->double_click_path[1] &&
gtk_tree_path_compare (view->details->double_click_path[0], view->details->double_click_path[1]) == 0
&& !button_event_modifies_selection (event)) {
activate_selected_items (view);
}
}
/* We're going to filter out some situations where
* we can't let the default code run because all
* but one row would be would be deselected. We don't
* want that; we want the right click menu or single
* click to apply to everything that's currently selected. */
if (event->button == 3 && gtk_tree_selection_path_is_selected (selection, path)) {
call_parent = FALSE;
}
if(!button_event_modifies_selection (event) && event->button == 1 && gtk_tree_selection_path_is_selected (selection, path)) {
call_parent = FALSE;
}
if (call_parent) {
tree_view_class->button_press_event (widget, event);
}
if (event->button == 1 || event->button == 2) {
view->details->drag_started = FALSE;
view->details->drag_button = event->button;
view->details->drag_x = event->x;
view->details->drag_y = event->y;
}
if (event->button == 3) {
if (tree_view_has_selection (tree_view)) {
fm_directory_view_pop_up_selection_context_menu (FM_DIRECTORY_VIEW (view), (GdkEventButton *) event);
} else {
fm_directory_view_pop_up_background_context_menu (FM_DIRECTORY_VIEW (view), (GdkEventButton *) event);
}
}
gtk_tree_path_free (path);
} else {
/* Deselect if people click outside any row. It's OK to
let default code run; it won't reselect anything. */
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (tree_view));
}
/* Instead of doing this, this list view should probably be a
* derived widget. I'm doing this quick hack because I'm hoping
* that gtktreeview will have the input modes thing in 2.4,
* getting rid of this altogether.
* If we still need this in 2.4, we should rewrite this widget
* as a derived class. */
if (call_parent) {
tree_view_class->button_press_event (widget, event);
}
if (event->button == 3) {
if (tree_view_has_selection (GTK_TREE_VIEW (widget))) {
fm_directory_view_pop_up_selection_context_menu (FM_DIRECTORY_VIEW (view), (GdkEventButton *) event);
} else {
fm_directory_view_pop_up_background_context_menu (FM_DIRECTORY_VIEW (view), (GdkEventButton *) event);
}
} else if (event->button == 1) {
if ((event->type == GDK_BUTTON_PRESS
&& click_policy_auto_value == NAUTILUS_CLICK_POLICY_SINGLE
&& !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
|| (event->type == GDK_2BUTTON_PRESS
&& click_policy_auto_value == NAUTILUS_CLICK_POLICY_DOUBLE)) {
file_list = fm_list_view_get_selection (FM_DIRECTORY_VIEW (view));
fm_directory_view_activate_files (FM_DIRECTORY_VIEW (view),
file_list);
nautilus_file_list_free (file_list);
}
}
/* We chained to the default handler in this method, so never
* let the default handler run */
return TRUE;
}
static gboolean
button_release_callback (GtkWidget *widget,
GdkEventButton *event,
gpointer callback_data)
{
FMListView *view;
view = FM_LIST_VIEW (callback_data);
if (event->button == view->details->drag_button) {
stop_drag_check (view);
if (!view->details->drag_started) {
fm_list_view_did_not_drag (view, event);
return TRUE;
}
}
return FALSE;
}
static gboolean
key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data)
{
FMDirectoryView *view;
GList *file_list;
view = FM_DIRECTORY_VIEW (callback_data);
......@@ -221,9 +501,7 @@ key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_dat
case GDK_space:
case GDK_Return:
case GDK_KP_Enter:
file_list = fm_list_view_get_selection (view);
fm_directory_view_activate_files (view, file_list);
nautilus_file_list_free (file_list);
activate_selected_items (FM_LIST_VIEW (view));
return TRUE;
default:
......@@ -359,16 +637,7 @@ create_and_set_up_tree_view (FMListView *view)
view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
fm_list_model_get_drag_types (&drag_types, &num_drag_types);
egg_tree_multi_drag_add_drag_support (view->details->tree_view);
gtk_tree_view_enable_model_drag_source
(view->details->tree_view,
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
drag_types,
num_drag_types,
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK);
view->details->drag_dest =
nautilus_tree_view_drag_dest_new (view->details->tree_view);
......@@ -389,8 +658,14 @@ create_and_set_up_tree_view (FMListView *view)
"changed",
G_CALLBACK (list_selection_changed_callback), view, 0);
g_signal_connect_object (view->details->tree_view, "drag_data_get",
G_CALLBACK (drag_data_get_callback), view, 0);
g_signal_connect_object (view->details->tree_view, "motion_notify_event",
G_CALLBACK (motion_notify_callback), view, 0);
g_signal_connect_object (view->details->tree_view, "button_press_event",
G_CALLBACK (button_press_callback), view, 0);
g_signal_connect_object (view->details->tree_view, "button_release_event",
G_CALLBACK (button_release_callback), view, 0);
g_signal_connect_object (view->details->tree_view, "key_press_event",
G_CALLBACK (key_press_callback), view, 0);
......@@ -400,6 +675,10 @@ create_and_set_up_tree_view (FMListView *view)
g_signal_connect_object (view->details->model, "sort_column_changed",
G_CALLBACK (sort_column_changed_callback), view, 0);
view->details->source_target_list =
gtk_target_list_new (drag_types, num_drag_types);
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view->details->tree_view), GTK_SELECTION_MULTIPLE);
gtk_tree_view_set_rules_hint (view->details->tree_view, TRUE);
......@@ -942,6 +1221,15 @@ fm_list_view_finalize (GObject *object)
list_view = FM_LIST_VIEW (object);
if (list_view->details->double_click_path[0]) {
gtk_tree_path_free (list_view->details->double_click_path[0]);
}
if (list_view->details->double_click_path[1]) {
gtk_tree_path_free (list_view->details->double_click_path[1]);
}
gtk_target_list_unref (list_view->details->source_target_list);
g_free (list_view->details);
G_OBJECT_CLASS (parent_class)->finalize (object);
......
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