[nautilus-actions] Fix drag-and-drop from inside the tree
- From: Pierre Wieser <pwieser src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus-actions] Fix drag-and-drop from inside the tree
- Date: Fri, 5 Mar 2010 22:50:37 +0000 (UTC)
commit f1df49beb0fd7fe3169acf2a0cf44f5f92cc74fd
Author: Pierre Wieser <pwieser trychlos org>
Date: Fri Mar 5 23:50:02 2010 +0100
Fix drag-and-drop from inside the tree
ChangeLog | 5 +
TODO | 4 -
src/nact/nact-tree-model-dnd.c | 296 +++++++++++++++++++++++++++++-----------
3 files changed, 224 insertions(+), 81 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 70c9c78..daa7080 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2009-03-05 Pierre Wieser <pwieser trychlos org>
+ * nact/nact-tree-model-dnd.c (drop_inside):
+ Split to three functions to better readibility.
+ Fix drop inside an empty menu.
+ Fix drop into a non writable parent.
+
* src/api/na-iio-provider.h: Add a comment.
* src/core/na-io-provider.c:
diff --git a/TODO b/TODO
index 401d924..8392c33 100644
--- a/TODO
+++ b/TODO
@@ -162,7 +162,3 @@
- use NADataDef to automatically generate schemas
in data/nautilus-actions.schemas.in
and in src/utils/nautilus-actions-schemas
-
-- dnd to inside of a menu, by dropping while on the menu itself
- if menu is at path 3, we get a dest of 3:0 which means first child of parent at path 3
- if menu is new (never has been written), dnd says that parent is not writable ????
diff --git a/src/nact/nact-tree-model-dnd.c b/src/nact/nact-tree-model-dnd.c
index 9f2057a..2300e73 100644
--- a/src/nact/nact-tree-model-dnd.c
+++ b/src/nact/nact-tree-model-dnd.c
@@ -117,18 +117,23 @@ GtkTargetEntry tree_model_dnd_dest_formats[] = {
guint tree_model_dnd_dest_formats_count = G_N_ELEMENTS( tree_model_dnd_dest_formats );
-static const gchar *st_refuse_profile = N_( "Unable to drop a profile here" );
-static const gchar *st_refuse_action_menu = N_( "Unable to drop an action or a menu here" );
+static const gchar *st_refuse_drop_profile = N_( "Unable to drop a profile here" );
+static const gchar *st_refuse_drop_item = N_( "Unable to drop an action or a menu here" );
static const gchar *st_parent_not_writable = N_( "Unable to drop here as parent is not writable" );
static const gchar *st_level_zero_not_writable = N_( "Unable to drop here as level zero is not writable" );
static gboolean drop_inside( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selection_data );
+static gboolean is_drop_possible( NactTreeModel *model, GtkTreePath *dest, NAObjectItem **parent );
+static gboolean is_drop_possible_before_iter( NactTreeModel *model, GtkTreeIter *iter, NactMainWindow *window, NAObjectItem **parent );
+static gboolean is_drop_possible_into_dest( NactTreeModel *model, GtkTreePath *dest, NactMainWindow *window, NAObjectItem **parent );
+#if 0
static GtkTreePath *drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction **parent );
+#endif
static void drop_inside_move_dest( NactTreeModel *model, GList *rows, GtkTreePath **dest );
static gboolean drop_uri_list( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selection_data );
static NAObjectItem *is_dropped_already_exists( const NAObjectItem *importing, const NactMainWindow *window );
static char *get_xds_atom_value( GdkDragContext *context );
-static gboolean is_parent_accept_new_childs( NactTreeModel *model, GtkTreePath *path );
+static gboolean is_parent_accept_new_childs( NactApplication *application, NactMainWindow *window, NAObjectItem *parent );
static guint target_atom_to_id( GdkAtom atom );
/**
@@ -503,12 +508,11 @@ nact_tree_model_dnd_on_drag_end( GtkWidget *widget, GdkDragContext *context, Bas
static gboolean
drop_inside( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selection_data )
{
- static const gchar *thisfn = "nact_tree_model_inside_drag_and_drop";
- gboolean drop_done;
+ static const gchar *thisfn = "nact_tree_model_dnd_inside_drag_and_drop";
NactApplication *application;
NAUpdater *updater;
NactMainWindow *main_window;
- NAObjectAction *parent;
+ NAObjectItem *parent;
gboolean copy_data;
GList *rows;
GtkTreePath *new_dest;
@@ -529,66 +533,217 @@ drop_inside( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selecti
* with profiles: only valid dest is inside an action
* without profile: only valid dest is outside (besides of) an action
*/
- drop_done = FALSE;
parent = NULL;
rows = nact_clipboard_dnd_get_data( model->private->clipboard, ©_data );
- new_dest = drop_inside_adjust_dest( model, dest, &parent );
- if( new_dest && !copy_data ){
- drop_inside_move_dest( model, rows, &new_dest );
+ if( !is_drop_possible( model, dest, &parent )){
+ return( FALSE );
}
- if( new_dest ){
- 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( model ), &iter, path )){
- gtk_tree_model_get( GTK_TREE_MODEL( model ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, ¤t, -1 );
- g_object_unref( current );
+ new_dest = gtk_tree_path_copy( dest );
+ if( !copy_data ){
+ drop_inside_move_dest( model, rows, &new_dest );
+ }
- if( copy_data ){
- inserted = ( NAObject * ) na_object_duplicate( current );
- na_object_set_origin( inserted, NULL );
- na_object_check_status( inserted );
+ 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( model ), &iter, path )){
+ gtk_tree_model_get( GTK_TREE_MODEL( model ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, ¤t, -1 );
+ g_object_unref( current );
- } else {
- inserted = na_object_ref( current );
- deletable = g_list_prepend( NULL, inserted );
- nact_iactions_list_bis_delete( NACT_IACTIONS_LIST( main_window ), deletable );
- g_list_free( deletable );
- }
+ if( copy_data ){
+ inserted = ( NAObject * ) na_object_duplicate( current );
+ na_object_set_origin( inserted, NULL );
+ na_object_check_status( inserted );
- relabel = nact_main_menubar_is_pasted_object_relabeled( inserted, NA_PIVOT( updater ));
- na_object_prepare_for_paste( inserted, relabel, copy_data, parent );
- object_list = g_list_prepend( object_list, inserted );
- g_debug( "%s: dropped=%s", thisfn, na_object_get_label( inserted ));
+ } else {
+ inserted = na_object_ref( current );
+ deletable = g_list_prepend( NULL, inserted );
+ nact_iactions_list_bis_delete( NACT_IACTIONS_LIST( main_window ), deletable );
+ g_list_free( deletable );
}
- gtk_tree_path_free( path );
+
+ relabel = nact_main_menubar_is_pasted_object_relabeled( inserted, NA_PIVOT( updater ));
+ na_object_prepare_for_paste( inserted, relabel, copy_data, parent );
+ object_list = g_list_prepend( object_list, inserted );
+ g_debug( "%s: dropped=%s", thisfn, na_object_get_label( inserted ));
}
+ gtk_tree_path_free( path );
}
- object_list = g_list_reverse( object_list );
+ }
+ object_list = g_list_reverse( object_list );
+
+ nact_iactions_list_bis_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, new_dest );
+
+ if( !copy_data && gtk_tree_path_get_depth( new_dest ) == 1 ){
+ g_signal_emit_by_name( main_window, MAIN_WINDOW_SIGNAL_LEVEL_ZERO_ORDER_CHANGED, GINT_TO_POINTER( TRUE ));
+ }
+
+ g_list_foreach( object_list, ( GFunc ) na_object_object_unref, NULL );
+ g_list_free( object_list );
+ gtk_tree_path_free( new_dest );
+
+ g_list_foreach( rows, ( GFunc ) gtk_tree_row_reference_free, NULL );
+ g_list_free( rows );
+
+ return( TRUE );
+}
+
+/*
+ * is a drop possible at given dest ?
+ *
+ * the only case where we would be led to have to modify the dest if
+ * we'd want be able to drop a profile into another profile, accepting
+ * it, actually dropping the profile just before the target
+ *
+ * -> it appears both clearer for the user interface and easyer from a
+ * code point of view to just refuse to drop a profile into a profile
+ *
+ * so this function is just to check if a drop is possible at the given
+ * dest
+ */
+static gboolean
+is_drop_possible( NactTreeModel *model, GtkTreePath *dest, NAObjectItem **parent )
+{
+ gboolean drop_ok;
+ NactApplication *application;
+ NactMainWindow *main_window;
+ GtkTreeIter iter;
+ NAObjectItem *parent_dest;
- nact_iactions_list_bis_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, new_dest );
+ drop_ok = FALSE;
+ parent_dest = NULL;
+ application = NACT_APPLICATION( base_window_get_application( model->private->window ));
+ main_window = NACT_MAIN_WINDOW( base_application_get_main_window( BASE_APPLICATION( application )));
- if( !copy_data && gtk_tree_path_get_depth( new_dest ) == 1 ){
- g_signal_emit_by_name( main_window, MAIN_WINDOW_SIGNAL_LEVEL_ZERO_ORDER_CHANGED, GINT_TO_POINTER( TRUE ));
+ /* if we can have an iter on given dest, then the dest already exists
+ * so dropped items should be of the same type that already existing
+ */
+ if( gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, dest )){
+ drop_ok = is_drop_possible_before_iter( model, &iter, main_window, &parent_dest );
+
+ /* inserting at the end of the list
+ * parent_dest is NULL
+ */
+ } else if( gtk_tree_path_get_depth( dest ) == 1 ){
+
+ if( model->private->drag_has_profiles ){
+ nact_main_statusbar_display_with_timeout(
+ main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_drop_profile );
+
+ } else {
+ drop_ok = TRUE;
}
- g_list_foreach( object_list, ( GFunc ) na_object_object_unref, NULL );
- g_list_free( object_list );
- gtk_tree_path_free( new_dest );
+ /* we cannot have an iter on the dest: this means that we try to
+ * insert items into not-opened dest (an empty menu or an action with
+ * zero or one profile) : check what is the parent
+ */
+ } else {
+ drop_ok = is_drop_possible_into_dest( model, dest, main_window, &parent_dest );
+ }
- drop_done = TRUE;
+ if( drop_ok ){
+ drop_ok = is_parent_accept_new_childs( application, main_window, parent_dest );
}
- g_list_foreach( rows, ( GFunc ) gtk_tree_row_reference_free, NULL );
- g_list_free( rows );
+ if( drop_ok && parent ){
+ *parent = parent_dest;
+ }
- return( drop_done );
+ return( drop_ok );
}
+static gboolean
+is_drop_possible_before_iter( NactTreeModel *model, GtkTreeIter *iter, NactMainWindow *window, NAObjectItem **parent )
+{
+ static const gchar *thisfn = "nact_tree_model_dnd_is_drop_possible_before_iter";
+ gboolean drop_ok;
+ NAObject *object;
+
+ drop_ok = FALSE;
+ *parent = NULL;
+
+ gtk_tree_model_get( GTK_TREE_MODEL( model ), iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+ g_object_unref( object );
+ g_debug( "%s: current object at dest is %s", thisfn, G_OBJECT_TYPE_NAME( object ));
+
+ if( model->private->drag_has_profiles ){
+
+ if( NA_IS_OBJECT_PROFILE( object )){
+ drop_ok = TRUE;
+ *parent = na_object_get_parent( object );
+
+ } else {
+ /* unable to drop a profile here */
+ nact_main_statusbar_display_with_timeout(
+ window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_drop_profile );
+ }
+
+ } else if( NA_IS_OBJECT_ITEM( object )){
+ drop_ok = TRUE;
+ *parent = na_object_get_parent( object );
+
+ } else {
+ /* unable to drop an action or a menu here */
+ nact_main_statusbar_display_with_timeout(
+ window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_drop_item );
+ }
+
+ return( drop_ok );
+}
+
+static gboolean
+is_drop_possible_into_dest( NactTreeModel *model, GtkTreePath *dest, NactMainWindow *window, NAObjectItem **parent )
+{
+ static const gchar *thisfn = "nact_tree_model_dnd_is_drop_possible_into_dest";
+ gboolean drop_ok;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ NAObject *object;
+
+ drop_ok = FALSE;
+ *parent = NULL;
+
+ path = gtk_tree_path_copy( dest );
+
+ if( gtk_tree_path_up( path )){
+ if( gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, path )){
+ gtk_tree_model_get( GTK_TREE_MODEL( model ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+ g_object_unref( object );
+ g_debug( "%s: current object at parent dest is %s", thisfn, G_OBJECT_TYPE_NAME( object ));
+
+ if( model->private->drag_has_profiles ){
+
+ if( NA_IS_OBJECT_ACTION( object )){
+ drop_ok = TRUE;
+ *parent = NA_OBJECT_ITEM( object );
+
+ } else {
+ nact_main_statusbar_display_with_timeout(
+ window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_drop_profile );
+ }
+
+ } else if( NA_IS_OBJECT_MENU( object )){
+ drop_ok = TRUE;
+ *parent = na_object_get_parent( object );
+
+ } else {
+ nact_main_statusbar_display_with_timeout(
+ window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_drop_item );
+ }
+ }
+ }
+
+ gtk_tree_path_free( path );
+
+ return( drop_ok );
+}
+
+#if 0
/*
* is a drop possible at given dest ?
* may slightly adjust the dest to drop profile inside an action
@@ -596,7 +751,7 @@ drop_inside( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selecti
static GtkTreePath *
drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction **parent )
{
- static const gchar *thisfn = "nact_tree_model_drop_inside_adjust_dest";
+ static const gchar *thisfn = "nact_tree_model_dnd_drop_inside_adjust_dest";
GtkTreePath *new_dest;
gboolean drop_ok;
NactApplication *application;
@@ -704,6 +859,7 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
return( new_dest );
}
+#endif
static void
drop_inside_move_dest( NactTreeModel *model, GList *rows, GtkTreePath **dest )
@@ -753,15 +909,14 @@ drop_inside_move_dest( NactTreeModel *model, GList *rows, GtkTreePath **dest )
* Returns: %TRUE if the specified rows were successfully inserted at
* the given dest, %FALSE else.
*
- * URI format only involves actions
+ * URI format only involves actions or menus
* so ony valid dest in outside (besides of) an action
*/
static gboolean
drop_uri_list( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selection_data )
{
- /*static const gchar *thisfn = "nact_tree_model_drop_uri_list";*/
+ static const gchar *thisfn = "nact_tree_model_dnd_drop_uri_list";
gboolean drop_done;
- GtkTreePath *new_dest;
NactApplication *application;
NAUpdater *updater;
NactMainWindow *main_window;
@@ -769,12 +924,16 @@ drop_uri_list( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selec
GConfClient *gconf;
GList *it;
+ gchar *dest_str = gtk_tree_path_to_string( dest );
+ g_debug( "%s: model=%p, dest=%p (%s), selection_data=%p",
+ thisfn, ( void * ) model, ( void * ) dest, dest_str, ( void * ) selection_data );
+ g_free( dest_str );
+
drop_done = FALSE;
model->private->drag_has_profiles = FALSE;
- new_dest = drop_inside_adjust_dest( model, dest, NULL );
- if( !new_dest ){
- return( drop_done );
+ if( !is_drop_possible( model, dest, NULL )){
+ return( FALSE );
}
application = NACT_APPLICATION( base_window_get_application( model->private->window ));
@@ -830,10 +989,9 @@ drop_uri_list( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData *selec
drop_done = TRUE;
}
- nact_iactions_list_bis_insert_at_path( NACT_IACTIONS_LIST( main_window ), parms.imported, new_dest );
+ nact_iactions_list_bis_insert_at_path( NACT_IACTIONS_LIST( main_window ), parms.imported, dest );
nact_tree_model_dump( model );
- gtk_tree_path_free( new_dest );
na_object_unref_items( parms.imported );
na_core_utils_slist_free( parms.uris );
na_core_utils_slist_free( parms.messages );
@@ -991,51 +1149,35 @@ get_xds_atom_value( GdkDragContext *context )
* to register the new child
*/
static gboolean
-is_parent_accept_new_childs( NactTreeModel *model, GtkTreePath *path )
+is_parent_accept_new_childs( NactApplication *application, NactMainWindow *window, NAObjectItem *parent )
{
gboolean accept_ok;
- GtkTreePath *parent_path;
- GtkTreeIter iter;
- NAObjectItem *parent_item;
- NactApplication *application;
NAUpdater *updater;
- NactMainWindow *main_window;
accept_ok = FALSE;
- application = NACT_APPLICATION( base_window_get_application( model->private->window ));
updater = nact_application_get_updater( application );
- main_window = NACT_MAIN_WINDOW( base_application_get_main_window( BASE_APPLICATION( application )));
/* inserting as a level zero item
* ensure that level zero is writable
*/
- if( gtk_tree_path_get_depth( path ) == 1 ){
+ if( parent == NULL ){
if( na_pivot_is_level_zero_writable( NA_PIVOT( updater ))){
accept_ok = TRUE;
} else {
nact_main_statusbar_display_with_timeout(
- main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_level_zero_not_writable );
+ window, TREE_MODEL_STATUSBAR_CONTEXT, st_level_zero_not_writable );
}
/* see if the parent is writable
*/
- } else {
- parent_path = gtk_tree_path_copy( path );
- if( gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, parent_path )){
- gtk_tree_model_get( GTK_TREE_MODEL( model ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &parent_item, -1 );
- if( na_updater_is_item_writable( updater, parent_item, NULL )){
- accept_ok = TRUE;
- }
- g_object_unref( parent_item );
- }
- gtk_tree_path_free( parent_path );
+ } else if( na_updater_is_item_writable( updater, parent, NULL )){
+ accept_ok = TRUE;
- if( !accept_ok ){
+ } else {
nact_main_statusbar_display_with_timeout(
- main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_parent_not_writable );
- }
+ window, TREE_MODEL_STATUSBAR_CONTEXT, st_parent_not_writable );
}
return( accept_ok );
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]