[nautilus-actions] Drag and drop code - not entirely ok yet
- From: Pierre Wieser <pwieser src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [nautilus-actions] Drag and drop code - not entirely ok yet
- Date: Fri, 2 Oct 2009 22:42:45 +0000 (UTC)
commit 8c3cf421152cb5868de16d4e4738a4ca0b5d0f73
Author: Pierre Wieser <pwieser trychlos org>
Date: Fri Oct 2 01:11:01 2009 +0200
Drag and drop code - not entirely ok yet
ChangeLog | 24 +
src/nact/base-application.c | 28 ++
src/nact/base-application.h | 1 +
src/nact/nact-clipboard.c | 486 ++++++++++++-------
src/nact/nact-clipboard.h | 23 +-
src/nact/nact-iactions-list.c | 63 +++-
src/nact/nact-iactions-list.h | 3 +
src/nact/nact-main-statusbar.c | 17 +
src/nact/nact-main-statusbar.h | 1 +
src/nact/nact-main-window.c | 26 +
src/nact/nact-main-window.h | 1 +
src/nact/nact-tree-model.c | 752 ++++++++++++++++++++++--------
src/nact/nact-tree-model.h | 2 +-
src/nact/nact-xml-reader.c | 2 +-
src/nact/nautilus-actions-config-tool.ui | 12 +-
15 files changed, 1042 insertions(+), 399 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 6b87967..05475c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2009-10-02 Pierre Wieser <pwieser trychlos org>
+
+ * src/nact/base-application.c:
+ * src/nact/base-application.h (base_application_message_dlg):
+ New function.
+
+ * src/nact/nact-clipboard.c:
+ * src/nact/nact-clipboard.h (nact_clipboard_dnd_set,
+ nact_clipboard_dnd_get_data, nact_clipboard_dnd_get_text,
+ nact_clipboard_dnd_drag_end, nact_clipboard_dnd_clear): New functions.
+
+ * src/nact/nact-iactions-list.c:
+ * src/nact/nact-iactions-list.h (nact_iactions_list_insert_at_path):
+ New function.
+
+ * src/nact/nact-main-statusbar.c:
+ * src/nact/nact-main-statusbar.h
+ (nact_main_statusbar_display_with_timeout): New function.
+
+ * nact/nact-main-window.c:
+ * nact/nact-main-window.h (nact_main_window_prepare_object_for_copy):
+ New function. This is a temporary place, waiting for (another)
+ reorganization of the code.
+
2009-10-01 Pierre Wieser <pwieser trychlos org>
* src/common/na-utils.c:
diff --git a/src/nact/base-application.c b/src/nact/base-application.c
index c504ce5..4db4243 100644
--- a/src/nact/base-application.c
+++ b/src/nact/base-application.c
@@ -644,6 +644,34 @@ base_application_get_main_window( BaseApplication *application )
}
/**
+ * base_application_message_dlg:
+ * @application: this #BaseApplication instance.
+ * @message: the message to be displayed.
+ *
+ * Displays a dialog with only an OK button.
+ */
+void
+base_application_message_dlg( BaseApplication *application, GSList *msg )
+{
+ GString *string;
+ GSList *im;
+
+ if( !application->private->dispose_has_run ){
+
+ string = g_string_new( "" );
+ for( im = msg ; im ; im = im->next ){
+ if( g_utf8_strlen( string->str, -1 )){
+ string = g_string_append( string, "\n" );
+ }
+ string = g_string_append( string, ( gchar * ) im->data );
+ }
+ display_dlg( application, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, string->str, NULL );
+
+ g_string_free( string, TRUE );
+ }
+}
+
+/**
* base_application_error_dlg:
* @application: this #BaseApplication instance.
* @type:
diff --git a/src/nact/base-application.h b/src/nact/base-application.h
index 6bb5c75..e18521c 100644
--- a/src/nact/base-application.h
+++ b/src/nact/base-application.h
@@ -119,6 +119,7 @@ gchar *base_application_get_ui_filename( BaseApplication *application );
BaseBuilder *base_application_get_builder( BaseApplication *application );
BaseWindow *base_application_get_main_window( BaseApplication *application );
+void base_application_message_dlg( BaseApplication *application, GSList *message );
void base_application_error_dlg( BaseApplication *application, GtkMessageType type, const gchar *first, const gchar *second );
gboolean base_application_yesno_dlg( BaseApplication *application, GtkMessageType type, const gchar *first, const gchar *second );
diff --git a/src/nact/nact-clipboard.c b/src/nact/nact-clipboard.c
index 4e3aed9..2da9583 100644
--- a/src/nact/nact-clipboard.c
+++ b/src/nact/nact-clipboard.c
@@ -41,8 +41,10 @@
#include <common/na-object-profile.h>
#include <common/na-xml-names.h>
#include <common/na-xml-writer.h>
+#include <common/na-utils.h>
#include "base-iprefs.h"
+#include "nact-tree-model.h"
#include "nact-clipboard.h"
/* private class data
@@ -55,6 +57,7 @@ struct NactClipboardClassPrivate {
*/
struct NactClipboardPrivate {
gboolean dispose_has_run;
+ GtkClipboard *dnd;
GtkClipboard *primary;
};
@@ -68,7 +71,8 @@ enum {
};
/* clipboard formats
- * - a special XdndNautilusAction format for internal move/copy
+ * - a special ClipboardNautilusAction format for internal move/copy
+ * and also used by drag and drop operations
* - a XdndDirectSave, suitable for exporting to a file manager
* (note that Nautilus recognized the "XdndDirectSave0" format as XDS
* protocol)
@@ -81,31 +85,38 @@ static GtkTargetEntry clipboard_formats[] = {
};
typedef struct {
+ guint target;
+ gchar *folder;
+ GList *rows;
+ gboolean copy;
+}
+ NactClipboardDndData;
+
+typedef struct {
guint nb_actions;
guint nb_profiles;
guint nb_menus;
GList *items;
}
- NactClipboardData;
+ NactClipboardPrimaryData;
static GObjectClass *st_parent_class = NULL;
-static GType register_type( void );
-static void class_init( NactClipboardClass *klass );
-static void iprefs_base_iface_init( BaseIPrefsInterface *iface );
-static void instance_init( GTypeInstance *instance, gpointer klass );
-static void instance_dispose( GObject *application );
-static void instance_finalize( GObject *application );
-
-static GtkClipboard *get_nact_clipboard( void );
-static GtkClipboard *get_primary_clipboard( void );
-static void add_item_to_clipboard0( NAObject *object, gboolean copy_data, gboolean only_profiles, GList **copied );
-/*static void add_item_to_clipboard( NAObject *object, GList **copied );*/
-static void export_action( const gchar *uri, const NAObject *action, GSList **exported );
-static gchar *get_action_xml_buffer( const NAObject *action, GSList **exported );
-static void get_from_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, guchar *data );
-static void clear_clipboard_callback( GtkClipboard *clipboard, NactClipboardData *data );
-static void renumber_items( NactClipboard *clipboard, GList *items );
+static GType register_type( void );
+static void class_init( NactClipboardClass *klass );
+static void iprefs_iface_init( BaseIPrefsInterface *iface );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *application );
+static void instance_finalize( GObject *application );
+
+static void get_from_dnd_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, guchar *data );
+static void clear_dnd_clipboard_callback( GtkClipboard *clipboard, NactClipboardDndData *data );
+static gchar *get_action_xml_buffer( const NAObject *object, GList **exported, NAObjectAction **action );
+static void export_rows( NactClipboard *clipboard, NactClipboardDndData *data );
+
+static void get_from_primary_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, guchar *data );
+static void clear_primary_clipboard_callback( GtkClipboard *clipboard, NactClipboardPrimaryData *data );
+static void renumber_items( NactClipboard *clipboard, GList *items );
GType
nact_clipboard_get_type( void )
@@ -137,8 +148,8 @@ register_type( void )
( GInstanceInitFunc ) instance_init
};
- static const GInterfaceInfo iprefs_base_iface_info = {
- ( GInterfaceInitFunc ) iprefs_base_iface_init,
+ static const GInterfaceInfo iprefs_iface_info = {
+ ( GInterfaceInitFunc ) iprefs_iface_init,
NULL,
NULL
};
@@ -147,7 +158,7 @@ register_type( void )
type = g_type_register_static( G_TYPE_OBJECT, "NactClipboard", &info, 0 );
- g_type_add_interface_static( type, BASE_IPREFS_TYPE, &iprefs_base_iface_info );
+ g_type_add_interface_static( type, BASE_IPREFS_TYPE, &iprefs_iface_info );
return( type );
}
@@ -170,9 +181,9 @@ class_init( NactClipboardClass *klass )
}
static void
-iprefs_base_iface_init( BaseIPrefsInterface *iface )
+iprefs_iface_init( BaseIPrefsInterface *iface )
{
- static const gchar *thisfn = "nact_main_window_iprefs_base_iface_init";
+ static const gchar *thisfn = "nact_main_window_iprefs_iface_init";
g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
}
@@ -182,6 +193,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
{
static const gchar *thisfn = "nact_clipboard_instance_init";
NactClipboard *self;
+ GdkDisplay *display;
g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
g_assert( NACT_IS_CLIPBOARD( instance ));
@@ -190,7 +202,10 @@ instance_init( GTypeInstance *instance, gpointer klass )
self->private = g_new0( NactClipboardPrivate, 1 );
self->private->dispose_has_run = FALSE;
- self->private->primary = get_primary_clipboard();
+
+ display = gdk_display_get_default();
+ self->private->dnd = gtk_clipboard_get_for_display( display, NACT_CLIPBOARD_ATOM );
+ self->private->primary = gtk_clipboard_get_for_display( display, GDK_SELECTION_PRIMARY );
}
static void
@@ -207,6 +222,7 @@ instance_dispose( GObject *window )
self->private->dispose_has_run = TRUE;
+ gtk_clipboard_clear( self->private->dnd );
gtk_clipboard_clear( self->private->primary );
/* chain up to the parent class */
@@ -250,42 +266,103 @@ nact_clipboard_new( void )
}
/**
- * nact_clipboard_get_data_for_intern_use:
- *
- * Set the selected items into our custom clipboard.
+ * nact_clipboard_dnd_set:
+ * @clipboard: this #NactClipboard instance.
+ * @rows: the list of row references of dragged items.
+ * @folder: the target folder if any (XDS protocol to outside).
+ * @copy_data: %TRUE if data is to be copied, %FALSE else
+ * (only relevant when drag and drop occurs inside of the tree view).
*
- * Note that we take a copy of the selected items, so that we will be
- * able to paste them when needed.
+ * Set the selected items into our dnd clipboard.
*/
void
-nact_clipboard_get_data_for_intern_use( GList *selected_items, gboolean copy_data )
+nact_clipboard_dnd_set( NactClipboard *clipboard, guint target, GList *rows, const gchar *folder, gboolean copy_data )
{
- static const gchar *thisfn = "nact_clipboard_get_data_for_intern_use";
- GtkClipboard *clipboard;
- NactClipboardData *data;
+ static const gchar *thisfn = "nact_clipboard_dnd_set";
+ NactClipboardDndData *data;
+ GtkTreeModel *model;
GList *it;
- clipboard = get_nact_clipboard();
+ g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
+ g_return_if_fail( rows && g_list_length( rows ));
+
+ if( !clipboard->private->dispose_has_run ){
- data = g_new0( NactClipboardData, 1 );
- /*data->only_profiles = have_only_profiles( selected_items );*/
+ data = g_new0( NactClipboardDndData, 1 );
- for( it = selected_items ; it ; it = it->next ){
- NAObject *item_object = NA_OBJECT( it->data );
- add_item_to_clipboard0( item_object, copy_data, FALSE /*data->only_profiles*/, &data->items );
- }
- data->items = g_list_reverse( data->items );
+ data->target = target;
+ data->folder = g_strdup( folder );
+ data->rows = NULL;
+ data->copy = copy_data;
- gtk_clipboard_set_with_data( clipboard,
- clipboard_formats, G_N_ELEMENTS( clipboard_formats ),
- ( GtkClipboardGetFunc ) get_from_clipboard_callback,
- ( GtkClipboardClearFunc ) clear_clipboard_callback,
- data );
+ model = gtk_tree_row_reference_get_model(( GtkTreeRowReference * ) rows->data );
- g_debug( "%s: clipboard=%p, data=%p", thisfn, ( void * ) clipboard, ( void * ) data );
+ for( it = rows ; it ; it = it->next ){
+ data->rows = g_list_append(
+ data->rows,
+ gtk_tree_row_reference_copy(( GtkTreeRowReference * ) it->data ));
+ }
+
+ gtk_clipboard_set_with_data( clipboard->private->dnd,
+ clipboard_formats, G_N_ELEMENTS( clipboard_formats ),
+ ( GtkClipboardGetFunc ) get_from_dnd_clipboard_callback,
+ ( GtkClipboardClearFunc ) clear_dnd_clipboard_callback,
+ data );
+
+ g_debug( "%s: clipboard=%p, data=%p", thisfn, ( void * ) clipboard, ( void * ) data );
+ }
}
/**
+ * nact_clipboard_dnd_get_data:
+ * @clipboard: this #NactClipboard instance.
+ * @copy_data: will be set to the original value of the drag and drop.
+ *
+ * Returns the list of rows references privously stored.
+ *
+ * The returned list should be gtk_tree_row_reference_free() by the
+ * caller.
+ */
+GList *
+nact_clipboard_dnd_get_data( NactClipboard *clipboard, gboolean *copy_data )
+{
+ static const gchar *thisfn = "nact_clipboard_dnd_get_data";
+ GList *rows = NULL;
+ GtkSelectionData *selection;
+ NactClipboardDndData *data;
+ GtkTreeModel *model;
+ GList *it;
+
+ g_debug( "%s: clipboard=%p", thisfn, ( void * ) clipboard );
+ g_return_val_if_fail( NACT_IS_CLIPBOARD( clipboard ), NULL );
+
+ if( copy_data ){
+ *copy_data = FALSE;
+ }
+
+ if( !clipboard->private->dispose_has_run ){
+
+ selection = gtk_clipboard_wait_for_contents( clipboard->private->dnd, NACT_CLIPBOARD_NACT_ATOM );
+ if( selection ){
+
+ data = ( NactClipboardDndData * ) selection->data;
+ if( data->target == NACT_XCHANGE_FORMAT_NACT ){
+
+ model = gtk_tree_row_reference_get_model(( GtkTreeRowReference * ) data->rows->data );
+
+ for( it = data->rows ; it ; it = it->next ){
+ rows = g_list_append( rows,
+ gtk_tree_row_reference_copy(( GtkTreeRowReference * ) it->data ));
+ }
+ *copy_data = data->copy;
+ }
+ }
+ }
+
+ return( rows );
+}
+
+/*
* Get text/plain from selected actions.
*
* This is called when we drop or paste a selection onto an application
@@ -293,41 +370,166 @@ nact_clipboard_get_data_for_intern_use( GList *selected_items, gboolean copy_dat
* mime types.
*
* Selected items may include menus, actions and profiles.
- * For now, we only exports actions as XML files.
+ * For now, we only exports actions (and profiles) as XML files.
+ *
+ * FIXME: na_xml_writer_get_xml_buffer() returns a valid XML document,
+ * which includes the <?xml ...?> header. Concatenating several valid
+ * XML documents doesn't provide a valid global XML doc, because of
+ * the presence of several <?xml ?> headers inside.
*/
-char *
-nact_clipboard_get_data_for_extern_use( GList *selected_items )
+gchar *
+nact_clipboard_dnd_get_text( NactClipboard *clipboard, GList *rows )
{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ NAObject *object;
+ NAObjectAction *action;
GList *it;
- GSList *exported = NULL;
+ GList *exported;
GString *data;
gchar *chunk;
+ g_return_val_if_fail( NACT_IS_CLIPBOARD( clipboard ), NULL );
+ g_return_val_if_fail( rows && g_list_length( rows ), NULL );
+
data = g_string_new( "" );
- for( it = selected_items ; it ; it = it->next ){
- NAObject *item_object = NA_OBJECT( it->data );
- chunk = NULL;
+ if( !clipboard->private->dispose_has_run ){
- if( NA_IS_OBJECT_ACTION( item_object )){
- chunk = get_action_xml_buffer( item_object, &exported );
+ exported = NULL;
+ model = gtk_tree_row_reference_get_model(( GtkTreeRowReference * ) rows->data );
- } else if( NA_IS_OBJECT_PROFILE( item_object )){
- NAObjectAction *action = na_object_profile_get_action( NA_OBJECT_PROFILE( item_object ));
- chunk = get_action_xml_buffer( NA_OBJECT( action ), &exported );
- }
+ for( it = rows ; it ; it = it->next ){
+
+ path = gtk_tree_row_reference_get_path(( GtkTreeRowReference * ) it->data );
+ if( path ){
+ gtk_tree_model_get_iter( model, &iter, path );
+ gtk_tree_path_free( path );
+
+ gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+ chunk = NULL;
+
+ if( NA_IS_OBJECT_ACTION( object )){
+ chunk = get_action_xml_buffer( object, &exported, &action );
+
+ } else if( NA_IS_OBJECT_PROFILE( object )){
+ chunk = get_action_xml_buffer( object, &exported, &action );
+ }
- if( chunk && strlen( chunk )){
- data = g_string_append( data, chunk );
+ if( chunk ){
+ g_assert( strlen( chunk ));
+ data = g_string_append( data, chunk );
+ g_free( chunk );
+ }
+
+ g_object_unref( object );
+ }
}
- g_free( chunk );
+
+ g_list_free( exported );
}
- g_slist_free( exported );
return( g_string_free( data, FALSE ));
}
/**
+ * nact_clipboard_dnd_drag_end:
+ * @clipboard: this #NactClipboard instance.
+ *
+ * On drag-end, exports the objects if needed.
+ */
+void
+nact_clipboard_dnd_drag_end( NactClipboard *clipboard )
+{
+ static const gchar *thisfn = "nact_clipboard_dnd_drag_end";
+ GtkSelectionData *selection;
+ NactClipboardDndData *data;
+
+ g_debug( "%s: clipboard=%p", thisfn, ( void * ) clipboard );
+ g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
+
+ if( !clipboard->private->dispose_has_run ){
+
+ selection = gtk_clipboard_wait_for_contents( clipboard->private->dnd, NACT_CLIPBOARD_NACT_ATOM );
+ if( selection ){
+
+ data = ( NactClipboardDndData * ) selection->data;
+ if( data->target == NACT_XCHANGE_FORMAT_XDS ){
+ export_rows( clipboard, data );
+ }
+ }
+ }
+}
+
+/**
+ * nact_clipboard_dnd_clear:
+ * @clipboard: this #NactClipboard instance.
+ *
+ * Clears the drag-and-drop clipboard.
+ *
+ * At least called on drag-begin.
+ */
+void
+nact_clipboard_dnd_clear( NactClipboard *clipboard )
+{
+ gtk_clipboard_clear( clipboard->private->dnd );
+}
+
+static void
+get_from_dnd_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, guchar *data )
+{
+ static const gchar *thisfn = "nact_clipboard_get_from_dnd_clipboard_callback";
+
+ g_debug( "%s: clipboard=%p, selection_data=%p, target=%s, info=%d, data=%p",
+ thisfn, ( void * ) clipboard,
+ ( void * ) selection_data, gdk_atom_name( selection_data->target ), info, ( void * ) data );
+
+ gtk_selection_data_set( selection_data, selection_data->target, 8, data, sizeof( NactClipboardDndData ));
+}
+
+static void
+clear_dnd_clipboard_callback( GtkClipboard *clipboard, NactClipboardDndData *data )
+{
+ static const gchar *thisfn = "nact_clipboard_clear_dnd_clipboard_callback";
+
+ g_debug( "%s: clipboard=%p, data=%p", thisfn, ( void * ) clipboard, ( void * ) data );
+
+ g_free( data->folder );
+ g_list_foreach( data->rows, ( GFunc ) gtk_tree_row_reference_free, NULL );
+ g_list_free( data->rows );
+ g_free( data );
+}
+
+static gchar *
+get_action_xml_buffer( const NAObject *object, GList **exported, NAObjectAction **action )
+{
+ gchar *buffer = NULL;
+ gint index;
+
+ g_return_val_if_fail( action, NULL );
+
+ *action = NULL;
+
+ if( NA_IS_OBJECT_ACTION( object )){
+ *action = NA_OBJECT_ACTION( object );
+ }
+ if( NA_IS_OBJECT_PROFILE( object )){
+ *action = na_object_profile_get_action( NA_OBJECT_PROFILE( object ));
+ }
+
+ if( *action ){
+ index = g_list_index( *exported, ( gconstpointer ) *action );
+ if( index == -1 ){
+ buffer = na_xml_writer_get_xml_buffer( *action, FORMAT_GCONFENTRY );
+ *exported = g_list_prepend( *exported, ( gpointer ) *action );
+ }
+ }
+
+ return( buffer );
+}
+
+/*
* Exports selected actions.
*
* This is called when we drop or paste a selection onto an application
@@ -336,25 +538,44 @@ nact_clipboard_get_data_for_extern_use( GList *selected_items )
* Selected items may include menus, actions and profiles.
* For now, we only exports actions as XML files.
*/
-void
-nact_clipboard_export_items( const gchar *uri, GList *items )
+static void
+export_rows( NactClipboard *clipboard, NactClipboardDndData *data )
{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ NAObject *object;
+ NAObjectAction *action;
GList *it;
- GSList *exported = NULL;
+ GList *exported;
+ gchar *buffer;
+ gchar *fname;
- for( it = items ; it ; it = it->next ){
- NAObject *item_object = NA_OBJECT( it->data );
+ exported = NULL;
+ model = gtk_tree_row_reference_get_model(( GtkTreeRowReference * ) data->rows->data );
+
+ for( it = data->rows ; it ; it = it->next ){
- if( NA_IS_OBJECT_ACTION( item_object )){
- export_action( uri, item_object, &exported );
+ path = gtk_tree_row_reference_get_path(( GtkTreeRowReference * ) it->data );
+ if( path ){
+ gtk_tree_model_get_iter( model, &iter, path );
+ gtk_tree_path_free( path );
+ gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
- } else if( NA_IS_OBJECT_PROFILE( item_object )){
- NAObjectAction *action = na_object_profile_get_action( NA_OBJECT_PROFILE( item_object ));
- export_action( uri, NA_OBJECT( action ), &exported );
+ buffer = get_action_xml_buffer( object, &exported, &action );
+ if( buffer ){
+
+ fname = na_xml_writer_get_output_fname( NA_OBJECT_ACTION( action ), data->folder, FORMAT_GCONFENTRY );
+ na_xml_writer_output_xml( buffer, fname );
+ g_free( fname );
+ g_free( buffer );
+ }
+
+ g_object_unref( object );
}
}
- g_slist_free( exported );
+ g_list_free( exported );
}
/**
@@ -381,14 +602,14 @@ nact_clipboard_export_items( const gchar *uri, GList *items )
void
nact_clipboard_primary_set( NactClipboard *clipboard, GList *items, gboolean renumber )
{
- NactClipboardData *data;
+ NactClipboardPrimaryData *data;
GList *it;
g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
if( !clipboard->private->dispose_has_run ){
- data = g_new0( NactClipboardData, 1 );
+ data = g_new0( NactClipboardPrimaryData, 1 );
for( it = items ; it ; it = it->next ){
data->items = g_list_prepend( data->items, na_object_duplicate( it->data ));
@@ -411,8 +632,8 @@ nact_clipboard_primary_set( NactClipboard *clipboard, GList *items, gboolean ren
gtk_clipboard_set_with_data( clipboard->private->primary,
clipboard_formats, G_N_ELEMENTS( clipboard_formats ),
- ( GtkClipboardGetFunc ) get_from_clipboard_callback,
- ( GtkClipboardClearFunc ) clear_clipboard_callback,
+ ( GtkClipboardGetFunc ) get_from_primary_clipboard_callback,
+ ( GtkClipboardClearFunc ) clear_primary_clipboard_callback,
data );
}
}
@@ -431,7 +652,7 @@ GList *
nact_clipboard_primary_get( NactClipboard *clipboard )
{
GtkSelectionData *selection;
- NactClipboardData *data;
+ NactClipboardPrimaryData *data;
GList *items = NULL;
GList *it;
NAObject *obj;
@@ -443,7 +664,7 @@ nact_clipboard_primary_get( NactClipboard *clipboard )
selection = gtk_clipboard_wait_for_contents( clipboard->private->primary, NACT_CLIPBOARD_NACT_ATOM );
if( selection ){
- data = ( NactClipboardData * ) selection->data;
+ data = ( NactClipboardPrimaryData * ) selection->data;
for( it = data->items ; it ; it = it->next ){
obj = na_object_duplicate( it->data );
@@ -469,7 +690,7 @@ void
nact_clipboard_primary_counts( NactClipboard *clipboard, guint *actions, guint *profiles, guint *menus )
{
GtkSelectionData *selection;
- NactClipboardData *data;
+ NactClipboardPrimaryData *data;
g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
g_return_if_fail( actions && profiles && menus );
@@ -483,7 +704,7 @@ nact_clipboard_primary_counts( NactClipboard *clipboard, guint *actions, guint *
selection = gtk_clipboard_wait_for_contents( clipboard->private->primary, NACT_CLIPBOARD_NACT_ATOM );
if( selection ){
- data = ( NactClipboardData * ) selection->data;
+ data = ( NactClipboardPrimaryData * ) selection->data;
*actions = data->nb_actions;
*profiles = data->nb_profiles;
@@ -492,111 +713,22 @@ nact_clipboard_primary_counts( NactClipboard *clipboard, guint *actions, guint *
}
}
-static GtkClipboard *
-get_nact_clipboard( void )
-{
- GdkDisplay *display;
- GtkClipboard *clipboard;
-
- display = gdk_display_get_default();
- clipboard = gtk_clipboard_get_for_display( display, NACT_CLIPBOARD_ATOM );
-
- return( clipboard );
-}
-
-static GtkClipboard *
-get_primary_clipboard( void )
-{
- GdkDisplay *display;
- GtkClipboard *clipboard;
-
- display = gdk_display_get_default();
- clipboard = gtk_clipboard_get_for_display( display, GDK_SELECTION_PRIMARY );
-
- return( clipboard );
-}
-
-static void
-add_item_to_clipboard0( NAObject *object, gboolean copy_data, gboolean only_profiles, GList **items_list )
-{
- NAObject *source;
- gint index;
-
- source = object;
- if( !only_profiles && NA_IS_OBJECT_PROFILE( object )){
- source = NA_OBJECT( na_object_profile_get_action( NA_OBJECT_PROFILE( object )));
- }
-
- index = g_list_index( *items_list, ( gconstpointer ) source );
- if( index != -1 ){
- return;
- }
-
- *items_list = g_list_prepend( *items_list, na_object_ref( source ));
-}
-
-/*static void
-add_item_to_clipboard( NAObject *object, GList **items_list )
-{
- *items_list = g_list_prepend( *items_list, na_object_ref( object ));
-}*/
-
-static void
-export_action( const gchar *uri, const NAObject *action, GSList **exported )
-{
- gint index;
- gchar *fname, *buffer;
-
- index = g_slist_index( *exported, ( gconstpointer ) action );
- if( index != -1 ){
- return;
- }
-
- fname = na_xml_writer_get_output_fname( NA_OBJECT_ACTION( action ), uri, FORMAT_GCONFENTRY );
- buffer = na_xml_writer_get_xml_buffer( NA_OBJECT_ACTION( action ), FORMAT_GCONFENTRY );
-
- na_xml_writer_output_xml( buffer, fname );
-
- g_free( buffer );
- g_free( fname );
-
- *exported = g_slist_prepend( *exported, ( gpointer ) action );
-}
-
-static gchar *
-get_action_xml_buffer( const NAObject *action, GSList **exported )
-{
- gint index;
- gchar *buffer;
-
- index = g_slist_index( *exported, ( gconstpointer ) action );
- if( index != -1 ){
- return( NULL );
- }
-
- buffer = na_xml_writer_get_xml_buffer( NA_OBJECT_ACTION( action ), FORMAT_GCONFENTRY );
-
- *exported = g_slist_prepend( *exported, ( gpointer ) action );
-
- return( buffer );
-}
-
static void
-get_from_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, guchar *data )
+get_from_primary_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, guchar *data )
{
- static const gchar *thisfn = "nact_clipboard_get_from_clipboard_callback";
+ static const gchar *thisfn = "nact_clipboard_get_from_primary_clipboard_callback";
g_debug( "%s: clipboard=%p, selection_data=%p, target=%s, info=%d, data=%p",
thisfn, ( void * ) clipboard,
( void * ) selection_data, gdk_atom_name( selection_data->target ), info, ( void * ) data );
- gtk_selection_data_set( selection_data, selection_data->target, 8, data, sizeof( NactClipboardData ));
+ gtk_selection_data_set( selection_data, selection_data->target, 8, data, sizeof( NactClipboardPrimaryData ));
}
static void
-clear_clipboard_callback( GtkClipboard *clipboard, NactClipboardData *data )
+clear_primary_clipboard_callback( GtkClipboard *clipboard, NactClipboardPrimaryData *data )
{
- static const gchar *thisfn = "nact_clipboard_clear_clipboard_callback";
+ static const gchar *thisfn = "nact_clipboard_clear_primary_clipboard_callback";
g_debug( "%s: clipboard=%p, data=%p", thisfn, ( void * ) clipboard, ( void * ) data );
diff --git a/src/nact/nact-clipboard.h b/src/nact/nact-clipboard.h
index 0092226..c3aa459 100644
--- a/src/nact/nact-clipboard.h
+++ b/src/nact/nact-clipboard.h
@@ -41,7 +41,7 @@
* clipboard buffers.
*/
-#include <glib-object.h>
+#include <gtk/gtk.h>
G_BEGIN_DECLS
@@ -68,21 +68,30 @@ typedef struct {
}
NactClipboardClass;
+/* drag and drop formats
+ */
+enum {
+ NACT_XCHANGE_FORMAT_NACT = 0,
+ NACT_XCHANGE_FORMAT_XDS,
+ NACT_XCHANGE_FORMAT_APPLICATION_XML,
+ NACT_XCHANGE_FORMAT_TEXT_PLAIN,
+ NACT_XCHANGE_FORMAT_URI_LIST
+};
+
GType nact_clipboard_get_type( void );
NactClipboard *nact_clipboard_new( void );
-void nact_clipboard_get_data_for_intern_use( GList *selected_items, gboolean copy_data );
-char *nact_clipboard_get_data_for_extern_use( GList *selected_items );
+void nact_clipboard_dnd_set( NactClipboard *clipboard, guint target, GList *rows, const gchar *folder, gboolean copy );
+GList *nact_clipboard_dnd_get_data( NactClipboard *clipboard, gboolean *copy );
+gchar *nact_clipboard_dnd_get_text( NactClipboard *clipboard, GList *rows );
+void nact_clipboard_dnd_drag_end( NactClipboard *clipboard );
+void nact_clipboard_dnd_clear( NactClipboard *clipboard );
void nact_clipboard_primary_set( NactClipboard *clipboard, GList *items, gboolean renumber_items );
GList *nact_clipboard_primary_get( NactClipboard *clipboard );
void nact_clipboard_primary_counts( NactClipboard *clipboard, guint *actions, guint *profiles, guint *menus );
-void nact_clipboard_free_items( GSList *items );
-
-void nact_clipboard_export_items( const gchar *uri, GList *items );
-
G_END_DECLS
#endif /* __NACT_CLIPBOARD_H__ */
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index e6550a0..87e093e 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -116,7 +116,7 @@ static void interface_base_init( NactIActionsListInterface *klass );
static void interface_base_finalize( NactIActionsListInterface *klass );
static void free_items_callback( NactIActionsList *instance, GList *items );
-static GtkTreePath *do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *path, gint level, GList **parents );
+static GtkTreePath *do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *path, gint level, GList **parents, gboolean inside );
static GList *do_insert_items_add_parent( GList *parents, GtkTreeView *treeview, GtkTreeModel *model, NAObject *parent );
static gchar *v_get_treeview_name( NactIActionsList *instance );
@@ -818,10 +818,7 @@ nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObj
GtkTreeModel *model;
GtkTreeSelection *selection;
GList *list_selected;
- GtkTreePath *insert_path = NULL;
- GtkTreePath *last_path = NULL;
- GList *parents = NULL;
- GList *it;
+ GtkTreePath *insert_path;
g_debug( "%s: instance=%p, items=%p (%d items)",
thisfn, ( void * ) instance, ( void * ) items, g_list_length( items ));
@@ -830,6 +827,7 @@ nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObj
if( st_initialized && !st_finalized ){
+ insert_path = NULL;
treeview = get_actions_list_treeview( instance );
model = gtk_tree_view_get_model( treeview );
g_return_if_fail( NACT_IS_TREE_MODEL( model ));
@@ -847,7 +845,46 @@ nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObj
g_list_free( list_selected );
}
- last_path = do_insert_items( treeview, model, items, insert_path, 0, &parents );
+ nact_iactions_list_insert_at_path( instance, items, insert_path, TRUE );
+
+ gtk_tree_path_free( insert_path );
+ }
+}
+
+/**
+ * nact_iactions_list_insert_at_path:
+ * @instance: this #NactIActionsList instance.
+ * @items: a list of items to be inserted (e.g. from a paste).
+ * @path: insertion path.
+ * @inside: %TRUE if the item may be inserted inside of the give path.
+ *
+ * Inserts the provided @items list in the treeview.
+ *
+ * This function takes care of repositionning a new selection if
+ * possible, and refilter the display model.
+ */
+void
+nact_iactions_list_insert_at_path( NactIActionsList *instance, GList *items, GtkTreePath *insert_path, gboolean inside )
+{
+ static const gchar *thisfn = "nact_iactions_list_insert_at_path";
+ GtkTreeView *treeview;
+ GtkTreeModel *model;
+ GtkTreePath *last_path = NULL;
+ GList *parents = NULL;
+ GList *it;
+
+ g_debug( "%s: instance=%p, items=%p (%d items)",
+ thisfn, ( void * ) instance, ( void * ) items, g_list_length( items ));
+ g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
+ g_return_if_fail( NACT_IS_WINDOW( instance ));
+
+ if( st_initialized && !st_finalized ){
+
+ treeview = get_actions_list_treeview( instance );
+ model = gtk_tree_view_get_model( treeview );
+ g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+ last_path = do_insert_items( treeview, model, items, insert_path, 0, &parents, inside );
for( it = parents ; it ; it = it->next ){
na_object_check_edition_status( it->data );
@@ -857,12 +894,17 @@ nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObj
select_row_at_path( instance, treeview, model, last_path );
gtk_tree_path_free( last_path );
- gtk_tree_path_free( insert_path );
}
}
static GtkTreePath *
-do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *path, gint level, GList **parents )
+do_insert_items( GtkTreeView *treeview,
+ GtkTreeModel *model,
+ GList *items,
+ GtkTreePath *path,
+ gint level,
+ GList **parents,
+ gboolean inside )
{
static const gchar *thisfn = "nact_iactions_list_do_insert_items";
guint nb_profiles, nb_actions, nb_menus;
@@ -889,7 +931,8 @@ do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTr
* from store to filter_model, and ran through filter_visible function
* we so cannot rely on it if object is a profile inserted at level > 0
*/
- inserted_path_str = nact_tree_model_insert( NACT_TREE_MODEL( model ), NA_OBJECT( it->data ), path, &obj_parent );
+ inserted_path_str = nact_tree_model_insert(
+ NACT_TREE_MODEL( model ), NA_OBJECT( it->data ), path, &obj_parent, inside );
g_debug( "%s: inserted_path=%s", thisfn, inserted_path_str );
inserted_path = gtk_tree_path_new_from_string( inserted_path_str );
@@ -906,7 +949,7 @@ do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTr
*/
if( NA_IS_OBJECT_ITEM( it->data )){
subitems = na_object_get_items( it->data );
- do_insert_items( treeview, model, subitems, inserted_path, level+1, parents );
+ do_insert_items( treeview, model, subitems, inserted_path, level+1, parents, inside );
na_object_free_items( subitems );
}
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index 36d8af9..da5e2cf 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -40,6 +40,8 @@
* and in the export assistant (export mode).
*/
+#include <gtk/gtk.h>
+
#include <common/na-object-class.h>
G_BEGIN_DECLS
@@ -121,6 +123,7 @@ GList *nact_iactions_list_get_selected_items( NactIActionsList *instance );
gboolean nact_iactions_list_has_exportable( NactIActionsList *instance );
gboolean nact_iactions_list_has_modified_items( NactIActionsList *instance );
void nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObject *sibling );
+void nact_iactions_list_insert_at_path( NactIActionsList *instance, GList *items, GtkTreePath *path, gboolean inside );
gboolean nact_iactions_list_is_expanded( NactIActionsList *instance, const NAObject *item );
void nact_iactions_list_set_management_mode( NactIActionsList *instance, gint mode );
void nact_iactions_list_toggle_collapse( NactIActionsList *instance, const NAObject *item );
diff --git a/src/nact/nact-main-statusbar.c b/src/nact/nact-main-statusbar.c
index 2ae4346..064ebef 100644
--- a/src/nact/nact-main-statusbar.c
+++ b/src/nact/nact-main-statusbar.c
@@ -54,6 +54,23 @@ nact_main_statusbar_display_status( NactMainWindow *window, const gchar *context
}
void
+nact_main_statusbar_display_with_timeout( NactMainWindow *window, const gchar *context, const gchar *status )
+{
+ GtkStatusbar *bar;
+
+ if( !status || !g_utf8_strlen( status, -1 )){
+ return;
+ }
+
+ bar = get_statusbar( window );
+
+ if( bar ){
+ guint context_id = gtk_statusbar_get_context_id( bar, context );
+ gtk_statusbar_push( bar, context_id, status );
+ }
+}
+
+void
nact_main_statusbar_hide_status( NactMainWindow *window, const gchar *context )
{
GtkStatusbar *bar;
diff --git a/src/nact/nact-main-statusbar.h b/src/nact/nact-main-statusbar.h
index 35f8cb1..83c4854 100644
--- a/src/nact/nact-main-statusbar.h
+++ b/src/nact/nact-main-statusbar.h
@@ -42,6 +42,7 @@
G_BEGIN_DECLS
void nact_main_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status );
+void nact_main_statusbar_display_with_timeout( NactMainWindow *window, const gchar *context, const gchar *status );
void nact_main_statusbar_hide_status( NactMainWindow *window, const gchar *context );
G_END_DECLS
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index 624e24c..55db4d4 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -765,6 +765,32 @@ nact_main_window_remove_deleted( NactMainWindow *window )
}
}
+/**
+ * nact_main_window_prepare_object_for_copy:
+ * @window: this #NactMainWindow instance.
+ * @object: the #NAObject to be prepared.
+ * @new_parent: if @object is a profile, then the new id will be computed
+ * depending of already existing profiles in the @new_parent.
+ *
+ * Gives a new id to the object,
+ * possibly relabeling it depending on current preferences.
+ */
+void
+nact_main_window_prepare_object_for_copy( NactMainWindow *window, NAObject *object, NAObjectAction *new_parent )
+{
+ gboolean relabel = FALSE;
+
+ if( NA_IS_OBJECT_MENU( object )){
+ relabel = base_iprefs_get_bool( BASE_IPREFS( window ), BASE_IPREFS_RELABEL_MENUS );
+ } else if( NA_IS_OBJECT_ACTION( object )){
+ relabel = base_iprefs_get_bool( BASE_IPREFS( window ), BASE_IPREFS_RELABEL_ACTIONS );
+ } else if( NA_IS_OBJECT_PROFILE( object )){
+ relabel = base_iprefs_get_bool( BASE_IPREFS( window ), BASE_IPREFS_RELABEL_PROFILES );
+ }
+
+ na_object_set_new_id( object );
+}
+
/*
* If the deleted item is a profile, then do nothing because the parent
* action has been marked as modified when the profile has been deleted,
diff --git a/src/nact/nact-main-window.h b/src/nact/nact-main-window.h
index 15b1b8f..bbadbc0 100644
--- a/src/nact/nact-main-window.h
+++ b/src/nact/nact-main-window.h
@@ -77,6 +77,7 @@ gboolean nact_main_window_has_modified_items( const NactMainWindow *windo
void nact_main_window_move_to_deleted( NactMainWindow *window, GList *items );
void nact_main_window_reload( NactMainWindow *window );
void nact_main_window_remove_deleted( NactMainWindow *window );
+void nact_main_window_prepare_object_for_copy( NactMainWindow *window, NAObject *object, NAObjectAction *new_parent );
G_END_DECLS
diff --git a/src/nact/nact-tree-model.c b/src/nact/nact-tree-model.c
index d879d19..2bb423e 100644
--- a/src/nact/nact-tree-model.c
+++ b/src/nact/nact-tree-model.c
@@ -40,12 +40,16 @@
#include <common/na-object-profile.h>
#include <common/na-iprefs.h>
#include <common/na-utils.h>
+#include <common/na-xml-writer.h>
#include "egg-tree-multi-dnd.h"
#include "nact-application.h"
#include "nact-iactions-list.h"
+#include "nact-main-statusbar.h"
+#include "nact-main-window.h"
#include "nact-clipboard.h"
#include "nact-tree-model.h"
+#include "nact-xml-reader.h"
/*
* call once egg_tree_multi_drag_add_drag_support( treeview ) at init time (before gtk_main)
@@ -61,10 +65,17 @@
* call once nact_clipboard_on_drag_begin( treeview, context, main_window )
*
* when we drop (e.g. in Nautilus)
- * call once egg_tree_multi_drag_drag_data_get( treeview, context, selection_data, info=0, time )
+ * call once egg_tree_multi_dnd_on_drag_data_get( treeview, context, selection_data, info=0, time )
* call once nact_tree_model_imulti_drag_source_drag_data_get( drag_source, context, selection_data, path_list, atom=XdndDirectSave0 )
* call once nact_tree_model_idrag_dest_drag_data_received
* call once nact_clipboard_on_drag_end( treeview, context, main_window )
+ *
+ * when we drop in Nautilus Actions
+ * call once egg_tree_multi_dnd_on_drag_data_get( treeview, context, selection_data, info=0, time )
+ * call once nact_tree_model_imulti_drag_source_drag_data_get( drag_source, context, selection_data, path_list, atom=XdndNautilusActions )
+ * call once nact_clipboard_get_data_for_intern_use
+ * call once nact_tree_model_idrag_dest_drag_data_received
+ * call once nact_clipboard_on_drag_end( treeview, context, main_window )
*/
/* private class data
@@ -76,13 +87,15 @@ struct NactTreeModelClassPrivate {
/* private instance data
*/
struct NactTreeModelPrivate {
- gboolean dispose_has_run;
- BaseWindow *window;
- GtkTreeView *treeview;
- gboolean have_dnd;
- gboolean only_actions;
- gchar *drag_dest_uri;
- GList *drag_items;
+ gboolean dispose_has_run;
+ BaseWindow *window;
+ GtkTreeView *treeview;
+ gboolean have_dnd;
+ gboolean only_actions;
+ NactClipboard *clipboard;
+ gboolean drag_has_profiles;
+ gboolean drag_highlight; /* defined for on_drag_motion handler */
+ gboolean drag_drop; /* defined for on_drag_motion handler */
};
#define MAX_XDS_ATOM_VAL_LEN 4096
@@ -90,15 +103,7 @@ struct NactTreeModelPrivate {
#define XDS_ATOM gdk_atom_intern( "XdndDirectSave0", FALSE )
#define XDS_FILENAME "xds.txt"
-#define TREE_MODEL_ORDER_MODE "nact-tree-model-order-mode"
-
-enum {
- NACT_XCHANGE_FORMAT_NACT = 0,
- NACT_XCHANGE_FORMAT_XDS,
- NACT_XCHANGE_FORMAT_APPLICATION_XML,
- NACT_XCHANGE_FORMAT_TEXT_PLAIN,
- NACT_XCHANGE_FORMAT_URI_LIST
-};
+#define NACT_ATOM gdk_atom_intern( "XdndNautilusActions", FALSE )
/* as a dnd source, we provide
* - a special XdndNautilusAction format for internal move/copy
@@ -114,8 +119,12 @@ static GtkTargetEntry dnd_source_formats[] = {
{ "text/plain", GTK_TARGET_OTHER_APP, NACT_XCHANGE_FORMAT_TEXT_PLAIN },
};
-#define NACT_ATOM gdk_atom_intern( "XdndNautilusActions", FALSE )
-
+/* as a dnd dest, we accept
+ * - of course, the same special XdndNautilusAction format for internal move/copy
+ * - a list of uris, to be imported
+ * - a XML buffer, to be imported
+ * - a plain text, which we are goint to try to import as a XML description
+ */
static GtkTargetEntry dnd_dest_targets[] = {
{ "XdndNautilusActions", 0, NACT_XCHANGE_FORMAT_NACT },
{ "text/uri-list", 0, NACT_XCHANGE_FORMAT_URI_LIST },
@@ -145,6 +154,10 @@ typedef struct {
}
ntmSearchIdStruct;
+#define TREE_MODEL_ORDER_MODE "nact-tree-model-order-mode"
+
+#define TREE_MODEL_STATUSBAR_CONTEXT "nact-tree-model-statusbar-context"
+
static GtkTreeModelFilterClass *st_parent_class = NULL;
static GType register_type( void );
@@ -159,9 +172,9 @@ static NactTreeModel *tree_model_new( BaseWindow *window, GtkTreeView *treeview
static void fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview, GList *items, gboolean only_actions, GtkTreeIter *parent );
-static void insert_get_iters_action( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object );
-static void insert_get_iters_profile( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object );
-static void insert_get_iters_menu( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object );
+static void insert_get_iters_action( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object, gboolean inside );
+static void insert_get_iters_profile( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object, gboolean inside );
+static void insert_get_iters_menu( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object, gboolean inside );
static void insert_before_get_iters( GtkTreeModel *model, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object );
static void insert_before_parent_get_iters( GtkTreeModel *model, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object );
static void insert_as_last_child_get_iters( GtkTreeModel *model, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object );
@@ -188,15 +201,16 @@ static GdkDragAction imulti_drag_source_get_drag_actions( EggTreeMultiDragSourc
static gboolean idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data );
static gboolean idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data );
-static gboolean on_drag_begin( GtkWidget *widget, GdkDragContext *context, BaseWindow *window );
+static void on_drag_begin( GtkWidget *widget, GdkDragContext *context, BaseWindow *window );
+/*static gboolean on_drag_motion( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window );*/
+/*static gboolean on_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window );*/
static void on_drag_end( GtkWidget *widget, GdkDragContext *context, BaseWindow *window );
-/*static gboolean on_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window );
-static void on_drag_data_received( GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, BaseWindow *window );*/
+static char *get_xds_atom_value( GdkDragContext *context );
+static guint target_atom_to_id( GdkAtom atom );
static gint sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data );
static gboolean filter_visible( GtkTreeModel *store, GtkTreeIter *iter, NactTreeModel *model );
-static char *get_xds_atom_value( GdkDragContext *context );
GType
nact_tree_model_get_type( void )
@@ -323,6 +337,8 @@ instance_dispose( GObject *object )
self->private->dispose_has_run = TRUE;
+ g_object_unref( self->private->clipboard );
+
/* chain up to the parent class */
if( G_OBJECT_CLASS( st_parent_class )->dispose ){
G_OBJECT_CLASS( st_parent_class )->dispose( object );
@@ -340,9 +356,6 @@ instance_finalize( GObject *object )
g_return_if_fail( NACT_IS_TREE_MODEL( object ));
self = NACT_TREE_MODEL( object );
- g_free( self->private->drag_dest_uri );
- g_list_free( self->private->drag_items );
-
g_free( self->private );
/* chain call to parent class */
@@ -396,6 +409,7 @@ tree_model_new( BaseWindow *window, GtkTreeView *treeview )
model->private->window = window;
model->private->treeview = treeview;
+ model->private->clipboard = nact_clipboard_new();
return( model );
}
@@ -470,23 +484,26 @@ nact_tree_model_runtime_init( NactTreeModel *model, gboolean have_dnd )
"drag-begin",
G_CALLBACK( on_drag_begin ));
+ /* connect: implies that we have to do all hard stuff
+ * connect_after: no more triggers drag-drop signal
+ */
+ /*base_window_signal_connect_after(
+ BASE_WINDOW( model->private->window ),
+ G_OBJECT( model->private->treeview ),
+ "drag-motion",
+ G_CALLBACK( on_drag_motion ));*/
+
+ /*base_window_signal_connect(
+ BASE_WINDOW( model->private->window ),
+ G_OBJECT( model->private->treeview ),
+ "drag-drop",
+ G_CALLBACK( on_drag_drop ));*/
+
base_window_signal_connect(
BASE_WINDOW( model->private->window ),
G_OBJECT( model->private->treeview ),
"drag-end",
G_CALLBACK( on_drag_end ));
-
- /*nact_window_signal_connect(
- NACT_WINDOW( window ),
- G_OBJECT( treeview ),
- "drag_drop",
- G_CALLBACK( on_drag_drop ));
-
- nact_window_signal_connect(
- NACT_WINDOW( window ),
- G_OBJECT( treeview ),
- "drag_data-received",
- G_CALLBACK( on_drag_data_received ));*/
}
}
}
@@ -562,7 +579,7 @@ nact_tree_model_display_order_change( NactTreeModel *model, gint order_mode )
switch( order_mode ){
- case PREFS_ORDER_ALPHA_ASCENDING:
+ case IPREFS_ORDER_ALPHA_ASCENDING:
gtk_tree_sortable_set_sort_column_id(
GTK_TREE_SORTABLE( store ),
@@ -577,7 +594,7 @@ nact_tree_model_display_order_change( NactTreeModel *model, gint order_mode )
NULL );
break;
- case PREFS_ORDER_ALPHA_DESCENDING:
+ case IPREFS_ORDER_ALPHA_DESCENDING:
gtk_tree_sortable_set_sort_column_id(
GTK_TREE_SORTABLE( store ),
@@ -592,7 +609,7 @@ nact_tree_model_display_order_change( NactTreeModel *model, gint order_mode )
NULL );
break;
- case PREFS_ORDER_MANUAL:
+ case IPREFS_ORDER_MANUAL:
default:
gtk_tree_sortable_set_sort_column_id(
@@ -722,6 +739,7 @@ fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview,
* @path: the #GtkTreePath of the beginning of the current selection,
* or NULL.
* @obj_parent: set to the parent or the object itself.
+ * @inside: %TRUE if the item may be inserted inside of the given path.
*
* Insert a new row at the given position.
*
@@ -740,7 +758,8 @@ fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview,
* | | | | |
* | profile | insert_before_parent | insert_before | insert_before_parent |
* | | | | |
- * | menu | insert_as_last_child | n/a | insert_as_last_child |
+ * | menu | insert_before | n/a | insert_before |
+ * | | insert_as_last_child | | insert_as_last_child |
* +-----------------------------------------------------------------------------------------+
*
* insert_before : parent=NULL , sibling_from_path (or null if path was null)
@@ -752,7 +771,11 @@ fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview,
* string path
*/
gchar *
-nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **obj_parent )
+nact_tree_model_insert( NactTreeModel *model,
+ const NAObject *object,
+ GtkTreePath *path,
+ NAObject **obj_parent,
+ gboolean inside )
{
static const gchar *thisfn = "nact_tree_model_insert";
gchar *path_str = NULL;
@@ -785,22 +808,25 @@ nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePat
remove_if_exists( model, store, object );
if( path ){
- gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &select_iter, path );
+ if( !gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &select_iter, path )){
+ return( NULL );
+ }
+
gtk_tree_model_get( GTK_TREE_MODEL( model ), &select_iter, IACTIONS_LIST_NAOBJECT_COLUMN, &select_object, -1 );
g_return_val_if_fail( select_object, NULL );
g_return_val_if_fail( NA_IS_OBJECT( select_object ), NULL );
if( NA_IS_OBJECT_ACTION( object )){
- insert_get_iters_action( store, select_object, path, object, &parent_iter, &has_parent_iter, &sibling_iter, &has_sibling_iter, obj_parent );
+ insert_get_iters_action( store, select_object, path, object, &parent_iter, &has_parent_iter, &sibling_iter, &has_sibling_iter, obj_parent, inside );
}
if( NA_IS_OBJECT_PROFILE( object )){
- insert_get_iters_profile( store, select_object, path, object, &parent_iter, &has_parent_iter, &sibling_iter, &has_sibling_iter, obj_parent );
+ insert_get_iters_profile( store, select_object, path, object, &parent_iter, &has_parent_iter, &sibling_iter, &has_sibling_iter, obj_parent, inside );
}
if( NA_IS_OBJECT_MENU( object )){
- insert_get_iters_menu( store, select_object, path, object, &parent_iter, &has_parent_iter, &sibling_iter, &has_sibling_iter, obj_parent );
+ insert_get_iters_menu( store, select_object, path, object, &parent_iter, &has_parent_iter, &sibling_iter, &has_sibling_iter, obj_parent, inside );
}
g_object_unref( select_object );
@@ -823,8 +849,19 @@ nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePat
* inserts an action
*/
static void
-insert_get_iters_action( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object )
+insert_get_iters_action( GtkTreeModel *model,
+ const NAObject *select_object,
+ GtkTreePath *select_path,
+ const NAObject *object,
+ GtkTreeIter *parent_iter,
+ gboolean *has_parent_iter,
+ GtkTreeIter *sibling_iter,
+ gboolean *has_sibling_iter,
+ NAObject **parent_object,
+ gboolean inside )
{
+ gint count;
+
g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
/* (insert_before)
@@ -847,10 +884,16 @@ insert_get_iters_action( GtkTreeModel *model, const NAObject *select_object, Gtk
insert_before_parent_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
}
- /* (insert_as_last_child)
+ /* insert_as_last_child if there is no child at all
+ * insert_before else
*/
if( NA_IS_OBJECT_MENU( select_object )){
- insert_as_last_child_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
+ count = na_object_get_items_count( select_object );
+ if( count == 0 && inside ){
+ insert_as_last_child_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
+ } else {
+ insert_before_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
+ }
}
}
@@ -858,7 +901,16 @@ insert_get_iters_action( GtkTreeModel *model, const NAObject *select_object, Gtk
* insert a profile
*/
static void
-insert_get_iters_profile( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object )
+insert_get_iters_profile( GtkTreeModel *model,
+ const NAObject *select_object,
+ GtkTreePath *select_path,
+ const NAObject *object,
+ GtkTreeIter *parent_iter,
+ gboolean *has_parent_iter,
+ GtkTreeIter *sibling_iter,
+ gboolean *has_sibling_iter,
+ NAObject **parent_object,
+ gboolean inside )
{
g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
@@ -879,8 +931,19 @@ insert_get_iters_profile( GtkTreeModel *model, const NAObject *select_object, Gt
* insert a menu
*/
static void
-insert_get_iters_menu( GtkTreeModel *model, const NAObject *select_object, GtkTreePath *select_path, const NAObject *object, GtkTreeIter *parent_iter, gboolean *has_parent_iter, GtkTreeIter *sibling_iter, gboolean *has_sibling_iter, NAObject **parent_object )
+insert_get_iters_menu( GtkTreeModel *model,
+ const NAObject *select_object,
+ GtkTreePath *select_path,
+ const NAObject *object,
+ GtkTreeIter *parent_iter,
+ gboolean *has_parent_iter,
+ GtkTreeIter *sibling_iter,
+ gboolean *has_sibling_iter,
+ NAObject **parent_object,
+ gboolean inside )
{
+ gint count;
+
g_return_if_fail( NA_IS_OBJECT_MENU( object ));
if( NA_IS_OBJECT_ACTION( select_object )){
@@ -891,8 +954,16 @@ insert_get_iters_menu( GtkTreeModel *model, const NAObject *select_object, GtkTr
insert_before_parent_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
}
+ /* insert_as_last_child if there is no child at all
+ * insert_before else
+ */
if( NA_IS_OBJECT_MENU( select_object )){
- insert_as_last_child_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
+ count = na_object_get_items_count( select_object );
+ if( count == 0 && inside ){
+ insert_as_last_child_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
+ } else {
+ insert_before_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
+ }
}
}
@@ -1265,71 +1336,94 @@ search_for_object_id_iter( NactTreeModel *model, GtkTreePath *path, NAObject *ob
}
/*
- * all rows are draggable
+ * all selectable rows are draggable
+ * nonetheless, it's a good place to store the dragged row references
+ * we only make use of them in on_drag_motion handler
*/
static gboolean
-imulti_drag_source_row_draggable( EggTreeMultiDragSource *drag_source, GList *path_list )
+imulti_drag_source_row_draggable( EggTreeMultiDragSource *drag_source, GList *rows )
{
static const gchar *thisfn = "nact_tree_model_imulti_drag_source_row_draggable";
- /*FrWindow *window;
- GtkTreeModel *model;
- GList *scan;*/
+ NactTreeModel *model;
+ GtkTreeModel *store;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ NAObject *object;
+ GList *it;
- g_debug( "%s: drag_source=%p, path_list=%p", thisfn, ( void * ) drag_source, ( void * ) path_list );
+ g_debug( "%s: drag_source=%p, rows=%p (%d items)",
+ thisfn, ( void * ) drag_source, ( void * ) rows, g_list_length( rows ));
- /*window = g_object_get_data (G_OBJECT (drag_source), "FrWindow");
- g_return_val_if_fail (window != NULL, FALSE);
+ g_return_val_if_fail( NACT_IS_TREE_MODEL( drag_source ), FALSE );
+ model = NACT_TREE_MODEL( drag_source );
- model = fr_window_get_list_store (window);
+ if( !model->private->dispose_has_run ){
- for (scan = path_list; scan; scan = scan->next) {
- GtkTreeRowReference *reference = scan->data;
- GtkTreePath *path;
- GtkTreeIter iter;
- FileData *fdata;
+ model->private->drag_has_profiles = FALSE;
+ store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
- path = gtk_tree_row_reference_get_path (reference);
- if (path == NULL)
- continue;
+ for( it = rows ; it && !model->private->drag_has_profiles ; it = it->next ){
- if (! gtk_tree_model_get_iter (model, &iter, path))
- continue;
+ path = gtk_tree_row_reference_get_path(( GtkTreeRowReference * ) it->data );
+ gtk_tree_model_get_iter( store, &iter, path );
+ gtk_tree_model_get( store, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
- gtk_tree_model_get (model, &iter,
- COLUMN_FILE_DATA, &fdata,
- -1);
+ if( NA_IS_OBJECT_PROFILE( object )){
+ model->private->drag_has_profiles = TRUE;
+ }
- if (fdata != NULL)
- return TRUE;
- }*/
+ g_object_unref( object );
+ gtk_tree_path_free( path );
+ }
+ }
return( TRUE );
}
/*
- * drag_data_get is called when we release the selected items onto the
+ * imulti_drag_source_drag_data_get:
+ * @context: contains
+ * - the suggested action, as choosen by the drop site,
+ * between those we have provided in imulti_drag_source_get_drag_actions()
+ * - the target folder (XDS protocol)
+ * @selection_data:
+ * @rows: list of row references which are to be dropped
+ * @info: the suggested format, as choosen by the drop site, between those
+ * we have provided in imulti_drag_source_get_target_list()
+ *
+ * This function is called when we release the selected items onto the
* destination
*
- * if some rows are selected
- * here, we only provide id. of dragged rows :
- * M:uuid
- * A:uuid
- * P:uuid/name
- * this is suitable and sufficient for the internal clipboard
+ * NACT_XCHANGE_FORMAT_NACT:
+ * internal format for drag and drop inside the treeview:
+ * - copy in the clipboard the list of row references
+ * - selection data is empty
*
- * when exporting to the outside, we should prepare to export the items
+ * NACT_XCHANGE_FORMAT_XDS:
+ * exchange format to drop to outside:
+ * - copy in the clipboard the list of row references
+ * - set the destination folder
+ * - selection data is 'success' or 'failure'
+ *
+ * NACT_XCHANGE_FORMAT_APPLICATION_XML:
+ * NACT_XCHANGE_FORMAT_TEXT_PLAIN:
+ * exchange format to export to outside:
+ * - do not use dnd clipboard
+ * - selection data receives the export in text format
+ *
+ * Returns: %TRUE if required data was actually provided by the source,
+ * %FALSE else.
*/
static gboolean
imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
GdkDragContext *context,
GtkSelectionData *selection_data,
- GList *path_list,
+ GList *rows,
guint info )
{
static const gchar *thisfn = "nact_tree_model_imulti_drag_source_drag_data_get";
gchar *atom_name;
NactTreeModel *model;
- GList *selected_items;
gchar *data;
gboolean ret = FALSE;
gchar *dest_folder, *folder;
@@ -1337,67 +1431,63 @@ imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
gboolean copy_data;
atom_name = gdk_atom_name( selection_data->target );
- g_debug( "%s: drag_source=%p, context=%p, action=%d, selection_data=%p, path_list=%p, atom=%s",
- thisfn, ( void * ) drag_source, ( void * ) context, ( int ) context->suggested_action, ( void * ) selection_data, ( void * ) path_list,
+ g_debug( "%s: drag_source=%p, context=%p, action=%d, selection_data=%p, rows=%p, atom=%s",
+ thisfn, ( void * ) drag_source, ( void * ) context, ( int ) context->suggested_action, ( void * ) selection_data, ( void * ) rows,
atom_name );
g_free( atom_name );
model = NACT_TREE_MODEL( drag_source );
- g_assert( model->private->window );
+ g_return_val_if_fail( model->private->window, FALSE );
- selected_items = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( model->private->window ));
- if( !selected_items ){
- return( FALSE );
- }
- if( !g_list_length( selected_items )){
- g_list_free( selected_items );
- return( FALSE );
- }
+ if( !model->private->dispose_has_run ){
- switch( info ){
- case NACT_XCHANGE_FORMAT_NACT:
- copy_data = ( context->suggested_action == GDK_ACTION_COPY );
- nact_clipboard_get_data_for_intern_use( selected_items, copy_data );
- gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) "", 0 );
- ret = TRUE;
- break;
+ if( !rows || !g_list_length( rows )){
+ return( FALSE );
+ }
- case NACT_XCHANGE_FORMAT_XDS:
- folder = get_xds_atom_value( context );
- dest_folder = na_utils_remove_last_level_from_path( folder );
- g_free( folder );
- is_writable = na_utils_is_writable_dir( dest_folder );
- gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * )( is_writable ? "S" : "F" ), 1 );
- if( is_writable ){
- model->private->drag_dest_uri = g_strdup( dest_folder );
- model->private->drag_items = g_list_copy( selected_items );
- }
- g_free( dest_folder );
- ret = TRUE;
- break;
+ switch( info ){
+ case NACT_XCHANGE_FORMAT_NACT:
+ copy_data = ( context->action == GDK_ACTION_COPY );
+ gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) "", 0 );
+ nact_clipboard_dnd_set( model->private->clipboard, info, rows, NULL, copy_data );
+ ret = TRUE;
+ break;
- case NACT_XCHANGE_FORMAT_APPLICATION_XML:
- case NACT_XCHANGE_FORMAT_TEXT_PLAIN:
- data = nact_clipboard_get_data_for_extern_use( selected_items );
- gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) data, strlen( data ));
- g_free( data );
- ret = TRUE;
- break;
+ case NACT_XCHANGE_FORMAT_XDS:
+ folder = get_xds_atom_value( context );
+ dest_folder = na_utils_remove_last_level_from_path( folder );
+ g_free( folder );
+ is_writable = na_utils_is_writable_dir( dest_folder );
+ gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * )( is_writable ? "S" : "F" ), 1 );
+ if( is_writable ){
+ nact_clipboard_dnd_set( model->private->clipboard, info, rows, dest_folder, TRUE );
+ }
+ g_free( dest_folder );
+ ret = is_writable;
+ break;
- default:
- break;
+ case NACT_XCHANGE_FORMAT_APPLICATION_XML:
+ case NACT_XCHANGE_FORMAT_TEXT_PLAIN:
+ data = nact_clipboard_dnd_get_text( model->private->clipboard, rows );
+ gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) data, strlen( data ));
+ g_free( data );
+ ret = TRUE;
+ break;
+
+ default:
+ break;
+ }
}
- na_object_free_items( selected_items );
return( ret );
}
static gboolean
-imulti_drag_source_drag_data_delete( EggTreeMultiDragSource *drag_source, GList *path_list )
+imulti_drag_source_drag_data_delete( EggTreeMultiDragSource *drag_source, GList *rows )
{
static const gchar *thisfn = "nact_tree_model_imulti_drag_source_drag_data_delete";
- g_debug( "%s: drag_source=%p, path_list=%p", thisfn, ( void * ) drag_source, ( void * ) path_list );
+ g_debug( "%s: drag_source=%p, path_list=%p", thisfn, ( void * ) drag_source, ( void * ) rows );
return( TRUE );
}
@@ -1419,18 +1509,199 @@ imulti_drag_source_get_drag_actions( EggTreeMultiDragSource *drag_source )
}
/*
- * TODO: empty the internal clipboard at drop time
+ * called when a drop from the outside occurs in the treeview
+ * this may be an import action, or a move/copy inside of the tree
+ *
+ * Returns: %TRUE if the specified rows were successfully inserted at
+ * the given dest, %FALSE else.
+ *
+ * When importing:
+ * - selection=XdndSelection
+ * - target=text/uri-list
+ * - type=text/uri-list
+ *
+ * When moving/copy from the treeview to the treeview:
+ * - selection=XdndSelection
+ * - target=XdndNautilusActions
+ * - type=XdndNautilusActions
*/
static gboolean
idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data )
{
static const gchar *thisfn = "nact_tree_model_idrag_dest_drag_data_received";
+ gboolean result = FALSE;
+ NactApplication *application;
+ NAPivot *pivot;
+ gchar *atom_name;
+ guint info;
+ GList *rows;
+ gboolean copy_data;
+ GSList *uri_list, *is, *msg;
+ gint import_mode;
+ NAObjectAction *action;
+ gchar *path_str;
+ GtkTreeIter iter;
+ NAObject *current;
+ gboolean inside_an_action;
+ GList *object_list, *it;
+ NactMainWindow *main_window;
+ gboolean drop_ok = TRUE;
+ NAObjectAction *parent = NULL;
+ GtkTreePath *path;
g_debug( "%s: drag_dest=%p, dest=%p, selection_data=%p", thisfn, ( void * ) drag_dest, ( void * ) dest, ( void * ) selection_data );
+ g_return_val_if_fail( NACT_IS_TREE_MODEL( drag_dest ), FALSE );
- return( FALSE );
+ atom_name = gdk_atom_name( selection_data->selection );
+ g_debug( "%s: selection=%s", thisfn, atom_name );
+ g_free( atom_name );
+
+ atom_name = gdk_atom_name( selection_data->target );
+ g_debug( "%s: target=%s", thisfn, atom_name );
+ g_free( atom_name );
+
+ atom_name = gdk_atom_name( selection_data->type );
+ g_debug( "%s: type=%s", thisfn, atom_name );
+ g_free( atom_name );
+
+ g_debug( "%s: format=%d, length=%d", thisfn, selection_data->format, selection_data->length );
+
+ info = target_atom_to_id( selection_data->type );
+ g_debug( "%s: info=%u", thisfn, info );
+
+ application = NACT_APPLICATION( base_window_get_application( NACT_TREE_MODEL( drag_dest )->private->window ));
+ pivot = nact_application_get_pivot( application );
+ main_window = NACT_MAIN_WINDOW( base_application_get_main_window( BASE_APPLICATION( application )));
+
+ path_str = gtk_tree_path_to_string( dest );
+ g_debug( "%s: dest_path=%s", thisfn, path_str );
+ g_free( path_str );
+
+ /*
+ * NACT format (may embed profiles, or not)
+ * with profiles: only valid dest is inside an action
+ * without profile: only valid dest is outside (besides of) an action
+ * URI format only involves actions
+ * ony valid dest in outside (besides of) an action
+ */
+ inside_an_action = FALSE;
+ if( gtk_tree_model_get_iter( GTK_TREE_MODEL( drag_dest ), &iter, dest )){
+ gtk_tree_model_get( GTK_TREE_MODEL( drag_dest ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, ¤t, -1 );
+ g_debug( "%s: current object at dest is %s", thisfn, G_OBJECT_TYPE_NAME( current ));
+ if( NA_IS_OBJECT_PROFILE( current )){
+ inside_an_action = TRUE;
+ parent = na_object_profile_get_action( NA_OBJECT_PROFILE( current ));
+ }
+ g_object_unref( current );
+ }
+
+ switch( info ){
+ case NACT_XCHANGE_FORMAT_NACT:
+ if( NACT_TREE_MODEL( drag_dest )->private->drag_has_profiles ){
+ if( !inside_an_action ){
+ drop_ok = FALSE;
+ nact_main_statusbar_display_with_timeout(
+ main_window,
+ TREE_MODEL_STATUSBAR_CONTEXT,
+ _( "Unable to drop a profile outside of an action" ));
+ }
+ } else {
+ if( inside_an_action ){
+ drop_ok = FALSE;
+ nact_main_statusbar_display_with_timeout(
+ main_window,
+ TREE_MODEL_STATUSBAR_CONTEXT,
+ _( "Unable to drop an action or a menu inside of an action" ));
+ }
+ }
+ if( drop_ok ){
+ rows = nact_clipboard_dnd_get_data( NACT_TREE_MODEL( drag_dest )->private->clipboard, ©_data );
+ g_debug( "%s: rows has %d items, copy_data=%s", thisfn, g_list_length( rows ), copy_data ? "True":"False" );
+ object_list = NULL;
+ for( it = rows ; it ; it = it->next ){
+ path = gtk_tree_row_reference_get_path(( GtkTreeRowReference * ) it->data );
+ if( path ){
+ if( gtk_tree_model_get_iter( GTK_TREE_MODEL( drag_dest ), &iter, path )){
+ gtk_tree_model_get( GTK_TREE_MODEL( drag_dest ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, ¤t, -1 );
+ if( copy_data ){
+ nact_main_window_prepare_object_for_copy( main_window, current, parent );
+ }
+ object_list = g_list_prepend( object_list, current );
+ g_object_unref( current );
+ }
+ gtk_tree_path_free( path );
+ }
+ }
+ object_list = g_list_reverse( object_list );
+ nact_iactions_list_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, dest, FALSE );
+
+ if( !copy_data ){
+ nact_iactions_list_delete( NACT_IACTIONS_LIST( main_window ), object_list );
+ }
+
+ g_list_free( object_list );
+ g_list_foreach( rows, ( GFunc ) gtk_tree_row_reference_free, NULL );
+ g_list_free( rows );
+ result = TRUE;
+ }
+ break;
+
+ /* drop some actions from outside
+ * most probably from the file manager as a list of uris
+ */
+ case NACT_XCHANGE_FORMAT_URI_LIST:
+ if( inside_an_action ){
+
+ nact_main_statusbar_display_with_timeout(
+ main_window,
+ TREE_MODEL_STATUSBAR_CONTEXT,
+ _( "Unable to drop an action inside of another one" ));
+
+ } else {
+ uri_list = na_utils_lines_to_string_list(( const gchar * ) selection_data->data );
+ import_mode = na_iprefs_get_import_mode( NA_IPREFS( pivot ));
+ for( is = uri_list ; is ; is = is->next ){
+
+ action = nact_xml_reader_import(
+ NACT_TREE_MODEL( drag_dest )->private->window,
+ ( const gchar * ) is->data,
+ import_mode,
+ &msg );
+
+ if( msg ){
+ nact_main_statusbar_display_with_timeout(
+ main_window,
+ TREE_MODEL_STATUSBAR_CONTEXT,
+ msg->data );
+ na_utils_free_string_list( msg );
+
+ } else {
+ g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), FALSE );
+ object_list = g_list_prepend( NULL, action );
+ nact_iactions_list_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, dest, FALSE );
+ g_list_free( object_list );
+ }
+
+ if( action ){
+ g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), FALSE );
+ g_object_unref( action );
+ }
+ }
+ na_utils_free_string_list( uri_list );
+ result = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return( result );
}
+/*
+ * called when the source and the dest are not at the same tree level ?
+ */
static gboolean
idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data )
{
@@ -1441,77 +1712,187 @@ idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path
return( TRUE );
}
-static gboolean
+static void
on_drag_begin( GtkWidget *widget, GdkDragContext *context, BaseWindow *window )
{
- static const gchar *thisfn = "nact_clipboard_on_drag_begin";
+ static const gchar *thisfn = "nact_tree_model_on_drag_begin";
NactTreeModel *model;
g_debug( "%s: widget=%p, context=%p, window=%p",
thisfn, ( void * ) widget, ( void * ) context, ( void * ) window );
model = NACT_TREE_MODEL( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
+ g_return_if_fail( NACT_IS_TREE_MODEL( model ));
- g_free( model->private->drag_dest_uri );
- model->private->drag_dest_uri = NULL;
+ if( !model->private->dispose_has_run ){
- g_list_free( model->private->drag_items );
- model->private->drag_items = NULL;
+ model->private->drag_highlight = FALSE;
+ model->private->drag_drop = FALSE;
- gdk_property_change(
- context->source_window,
- XDS_ATOM, TEXT_ATOM, 8, GDK_PROP_MODE_REPLACE, ( guchar * ) XDS_FILENAME, strlen( XDS_FILENAME ));
+ nact_clipboard_dnd_clear( model->private->clipboard );
- return( FALSE );
+ gdk_property_change(
+ context->source_window,
+ XDS_ATOM, TEXT_ATOM, 8, GDK_PROP_MODE_REPLACE, ( guchar * ) XDS_FILENAME, strlen( XDS_FILENAME ));
+ }
}
-static void
-on_drag_end( GtkWidget *widget, GdkDragContext *context, BaseWindow *window )
+/*
+ * this function works well, but only called from on_drag_motion handler...
+ */
+/*static gboolean
+is_row_drop_possible( NactTreeModel *model, GtkTreePath *path, GtkTreeViewDropPosition pos )
{
- static const gchar *thisfn = "nact_clipboard_on_drag_end";
- NactTreeModel *model;
+ gboolean ok = FALSE;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ NAObject *object;
- g_debug( "%s: widget=%p, context=%p, window=%p",
- thisfn, ( void * ) widget, ( void * ) context, ( void * ) window );
+ store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
+ gtk_tree_model_get_iter( store, &iter, path );
+ gtk_tree_model_get( store, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+
+ if( model->private->drag_has_profiles ){
+ if( NA_IS_OBJECT_PROFILE( object )){
+ ok = TRUE;
+ } else if( NA_IS_OBJECT_ACTION( object )){
+ ok = ( pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER );
+ }
+ } else {
+ if( NA_IS_OBJECT_ITEM( object )){
+ ok = TRUE;
+ }
+ }
+
+ g_object_unref( object );
+ return( ok );
+}*/
+
+/*
+ * called when the user moves into the target widget
+ * returns TRUE if a drop zone
+ */
+#if 0
+static gboolean
+on_drag_motion( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window )
+{
+ NactTreeModel *model;
+ gboolean ok = FALSE;
+ GtkTreePath *path;
+ GtkTreeViewDropPosition pos;
model = NACT_TREE_MODEL( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
+ g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), FALSE );
- if( model->private->drag_dest_uri && model->private->drag_items && g_list_length( model->private->drag_items )){
- nact_clipboard_export_items( model->private->drag_dest_uri, model->private->drag_items );
- }
+ if( !model->private->dispose_has_run ){
+
+ if( !model->private->drag_highlight ){
+ model->private->drag_highlight = TRUE;
+ gtk_drag_highlight( widget );
+ }
- g_free( model->private->drag_dest_uri );
- model->private->drag_dest_uri = NULL;
+ /*target = gtk_drag_dest_find_target( widget, context, NULL );
+ if( target == GDK_NONE ){
+ gdk_drag_status( context, 0, time );
+ } else {
+ gtk_drag_get_data( widget, context, target, time );
+ }*/
- g_list_free( model->private->drag_items );
- model->private->drag_items = NULL;
+ if( gtk_tree_view_get_dest_row_at_pos( GTK_TREE_VIEW( widget ), x, y, &path, &pos )){
+ ok = is_row_drop_possible( model, path, pos );
+ if( ok ){
+ gdk_drag_status( context, 0, time );
+ }
+ }
- gdk_property_delete( context->source_window, XDS_ATOM );
+ gtk_tree_path_free( path );
+ g_debug( "nact_tree_model_on_drag_motion: ok=%s, pos=%d", ok ? "True":"False", pos );
+ }
+
+ return( ok );
}
+#endif
+/*
+ * called when the user drops the data
+ * returns TRUE if a drop zone
+ */
/*static gboolean
on_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window )
{
- static const gchar *thisfn = "nact_clipboard_on_drag_drop";
+ NactTreeModel *model;
- g_debug( "%s: widget=%p, context=%p, x=%d, y=%d, time=%d, window=%p",
- thisfn, ( void * ) widget, ( void * ) context, x, y, time, ( void * ) window );
-*/
- /*No!*/
- /*gtk_drag_get_data( widget, context, NACT_ATOM, time );*/
+ model = NACT_TREE_MODEL( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
+ g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), FALSE );
- /* return TRUE is the mouse pointer is on a drop zone, FALSE else */
- /*return( TRUE );
+ if( !model->private->dispose_has_run ){
+
+ model->private->drag_drop = TRUE;
+ }
+
+ return( TRUE );
}*/
-/*static void
-on_drag_data_received( GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, BaseWindow *window )
+static void
+on_drag_end( GtkWidget *widget, GdkDragContext *context, BaseWindow *window )
{
- static const gchar *thisfn = "nact_tree_model_on_drag_data_received";
+ static const gchar *thisfn = "nact_tree_model_on_drag_end";
+ NactTreeModel *model;
- g_debug( "%s: widget=%p, drag_context=%p, x=%d, y=%d, selection_data=%p, info=%d, time=%d, window=%p",
- thisfn, ( void * ) widget, ( void * ) drag_context, x, y, ( void * ) data, info, time, ( void * ) window );
-}*/
+ g_debug( "%s: widget=%p, context=%p, window=%p",
+ thisfn, ( void * ) widget, ( void * ) context, ( void * ) window );
+
+ model = NACT_TREE_MODEL( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
+ g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+ if( !model->private->dispose_has_run ){
+
+ nact_clipboard_dnd_drag_end( model->private->clipboard );
+ nact_clipboard_dnd_clear( model->private->clipboard );
+ gdk_property_delete( context->source_window, XDS_ATOM );
+ }
+}
+
+/* The following function taken from bugzilla
+ * (http://bugzilla.gnome.org/attachment.cgi?id=49362&action=view)
+ * Author: Christian Neumair
+ * Copyright: 2005 Free Software Foundation, Inc
+ * License: GPL
+ */
+static char *
+get_xds_atom_value( GdkDragContext *context )
+{
+ char *ret;
+
+ g_return_val_if_fail (context != NULL, NULL);
+ g_return_val_if_fail (context->source_window != NULL, NULL);
+
+ gdk_property_get (context->source_window,
+ XDS_ATOM, TEXT_ATOM,
+ 0, MAX_XDS_ATOM_VAL_LEN,
+ FALSE, NULL, NULL, NULL,
+ (unsigned char **) &ret);
+
+ return ret;
+}
+
+static guint
+target_atom_to_id( GdkAtom atom )
+{
+ gint i;
+ guint info = 0;
+ gchar *atom_name;
+
+ atom_name = gdk_atom_name( atom );
+ for( i = 0 ; i < G_N_ELEMENTS( dnd_dest_targets ) ; ++i ){
+ if( !g_ascii_strcasecmp( dnd_dest_targets[i].target, atom_name )){
+ info = dnd_dest_targets[i].info;
+ break;
+ }
+ }
+ g_free( atom_name );
+ return( info );
+}
static gint
sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data )
@@ -1581,26 +1962,3 @@ filter_visible( GtkTreeModel *store, GtkTreeIter *iter, NactTreeModel *model )
return( FALSE );
}
-
-/* The following function taken from bugzilla
- * (http://bugzilla.gnome.org/attachment.cgi?id=49362&action=view)
- * Author: Christian Neumair
- * Copyright: 2005 Free Software Foundation, Inc
- * License: GPL
- */
-static char *
-get_xds_atom_value (GdkDragContext *context)
-{
- char *ret;
-
- g_return_val_if_fail (context != NULL, NULL);
- g_return_val_if_fail (context->source_window != NULL, NULL);
-
- gdk_property_get (context->source_window,
- XDS_ATOM, TEXT_ATOM,
- 0, MAX_XDS_ATOM_VAL_LEN,
- FALSE, NULL, NULL, NULL,
- (unsigned char **) &ret);
-
- return ret;
-}
diff --git a/src/nact/nact-tree-model.h b/src/nact/nact-tree-model.h
index bf5f4ff..781e918 100644
--- a/src/nact/nact-tree-model.h
+++ b/src/nact/nact-tree-model.h
@@ -97,7 +97,7 @@ void nact_tree_model_display( NactTreeModel *model, NAObject *object );
void nact_tree_model_display_order_change( NactTreeModel *model, gint order_mode );
void nact_tree_model_dump( NactTreeModel *model );
void nact_tree_model_fill( NactTreeModel *model, GList *items, gboolean only_actions);
-gchar *nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **parent );
+gchar *nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **parent, gboolean inside );
void nact_tree_model_iter( NactTreeModel *model, FnIterOnStore fn, gpointer user_data );
GtkTreePath *nact_tree_model_remove( NactTreeModel *model, NAObject *object );
diff --git a/src/nact/nact-xml-reader.c b/src/nact/nact-xml-reader.c
index 939d367..59b171c 100644
--- a/src/nact/nact-xml-reader.c
+++ b/src/nact/nact-xml-reader.c
@@ -317,7 +317,7 @@ nact_xml_reader_import( BaseWindow *window, const gchar *uri, gint import_mode,
reader->private->window = window;
reader->private->import_mode = import_mode;
- g_return_val_if_fail( BASE_IS_ASSISTANT( window ), NULL );
+ g_return_val_if_fail( BASE_IS_WINDOW( window ), NULL );
doc = xmlParseFile( uri );
diff --git a/src/nact/nautilus-actions-config-tool.ui b/src/nact/nautilus-actions-config-tool.ui
index 29f3107..62c0444 100644
--- a/src/nact/nautilus-actions-config-tool.ui
+++ b/src/nact/nautilus-actions-config-tool.ui
@@ -1799,7 +1799,7 @@ If there is no root submenu, a 'Nautilus Actions' one is created.</property>
<object class="GtkLabel" id="label45">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">What to do when pasting, duplicating or importing an action or a menu which already exists in the tree ?</property>
+ <property name="label" translatable="yes">What to do when pasting or duplicating an item in the tree ?</property>
<property name="wrap">True</property>
</object>
<packing>
@@ -1941,7 +1941,7 @@ If there is no root submenu, a 'Nautilus Actions' one is created.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="tooltip_text" translatable="yes">Imported actions whose UUID already exists will be renumbered. Depending on UI preferences, they may also be relabeled. Existing action will remain unchanged.</property>
+ <property name="tooltip_text" translatable="yes">Imported actions whose UUID already exists will be renumbered. A 'renumbered' mention will be added to the label of the item. Existing action will remain unchanged.</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">PrefsNoImportButton</property>
@@ -2058,16 +2058,16 @@ Be warned: you will not be prompted another time. This mode may be dangerous. </
</object>
<object class="GtkSizeGroup" id="CommandLabelSizeGroup">
<widgets>
- <widget name="CommandExamplePreLabel"/>
- <widget name="CommandParametersLabel"/>
- <widget name="CommandPathLabel"/>
<widget name="ProfileLabelLabel"/>
+ <widget name="CommandPathLabel"/>
+ <widget name="CommandParametersLabel"/>
+ <widget name="CommandExamplePreLabel"/>
</widgets>
</object>
<object class="GtkSizeGroup" id="CommandButtonSizeGroup">
<widgets>
- <widget name="CommandLegendButton"/>
<widget name="CommandPathButton"/>
+ <widget name="CommandLegendButton"/>
</widgets>
</object>
</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]