[nautilus-actions] New 'Paste into' menu item
- From: Pierre Wieser <pwieser src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [nautilus-actions] New 'Paste into' menu item
- Date: Sun, 4 Oct 2009 19:49:44 +0000 (UTC)
commit 1e5abb37ae8e289e456608b58b6dec7a9a77b798
Author: Pierre Wieser <pwieser trychlos org>
Date: Sun Oct 4 21:35:28 2009 +0200
New 'Paste into' menu item
Also have rewrote the code which manages action sensitivities.
Also rewrote the insertion code in the treeview.
ChangeLog | 52 ++++
Makefile.am | 1 -
configure.ac | 5 +-
src/common/na-object-api.h | 2 +-
src/common/na-object-item-fn.h | 2 +
src/common/na-object-item.c | 49 +++-
src/nact/.gitignore | 2 +
src/nact/Makefile.am | 18 +-
src/nact/nact-iactions-list.c | 403 +++++++++++++++++--------
src/nact/nact-iactions-list.h | 15 +-
src/nact/nact-main-menubar.c | 355 +++++++++++++++-------
src/nact/nact-main-menubar.h | 4 +-
src/nact/nact-main-window.c | 38 ++-
src/nact/nact-main-window.h | 2 +
src/nact/nact-marshal.list | 1 +
src/nact/nact-tree-model.c | 383 +++++++-----------------
src/nact/nact-tree-model.h | 4 +-
src/nact/nautilus-actions-config-tool.actions | 1 +
18 files changed, 817 insertions(+), 520 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 11d48bb..79b59c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2009-10-04 Pierre Wieser <pwieser trychlos org>
+
+ Use some stored indicators to compute the action sensitivities
+ rather that all recomputing each time.
+ Rewrite insertion code in the treeview.
+
+ * Makefile.am:
+ * configure.ac: No more compile with --enable-iso-c not -pedantic
+ options as GLib-generated marshaling code is not compliant.
+
+ * src/common/na-object-api.h:
+ * src/common/na-object-item-fn.h:
+ * src/common/na-object-item.c (na_object_insert_item):
+ Now accepts a null object as sibling position.
+ (na_object_item_count_items): New function.
+
+ * src/nact/nact-marshal.c:
+ * src/nact/nact-marshal.h: New files.
+
+ * src/nact/Makefile.am: Updated accordingly.
+
+ * src/nact/nact-iactions-list.c:
+ Now maintains a count of menus, actions and profiles items.
+ Send a signal when the count is changed.
+ Rewrite insertion in the treeview.
+
+ * src/nact/nact-iactions-list.c:
+ * src/nact/nact-iactions-list.h
+ (nact_iactions_list_has_exportable): Removed function.
+ (nact_iactions_list_insert_into): New function.
+
+ * src/nact/nact-main-menubar.c:
+ * src/nact/nact-main-menubar.h:
+ Maintains its own counters to compute the actions sensitivities.
+ Define new menu item 'Paste into'.
+ nact_main_menubar_refresh_actions_sensitivity: Removed function.
+ nact_main_menubar_dispose: New function.
+
+ * src/nact/nact-main-window.c:
+ * src/nact/nact-main-window.h:
+ Connect to the iactions-list-selection-changed signal rather than
+ implement the corresponding virtual function.
+ Define new 'main-window-update-sensitivities' signal.
+
+ * src/nact/nact-tree-model.c:
+ * src/nact/nact-tree-model.h:
+ Rewrite insertion code in the tree store.
+ nact_tree_model_insert_into, nact_tree_model_object_at_path: New
+ functions.
+
+ * src/nact/nautilus-actions-config-tool.actions: new 'Paste into' item.
+
2009-10-02 Pierre Wieser <pwieser trychlos org>
Centralize plugin routines in a dedicated libna-runtime library.
diff --git a/Makefile.am b/Makefile.am
index 32b4216..fa24eaf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,7 +45,6 @@ DISTCHECK_CONFIGURE_FLAGS = \
# do not try to install schemas when making distcheck
DISTCHECK_CONFIGURE_FLAGS += \
--disable-schemas-install \
- --enable-iso-c \
$(NULL)
EXTRA_DIST = \
diff --git a/configure.ac b/configure.ac
index de2a35f..bc96794 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,13 +80,16 @@ AC_PROG_MAKE_SET
# Gnome stuff
GNOME_COMMON_INIT
GNOME_MAINTAINER_MODE_DEFINES
-NA_GNOME_COMPILE_WARNINGS([error],[-ansi -pedantic -Wno-overlength-strings])
+NA_GNOME_COMPILE_WARNINGS([error],[-ansi -Wno-overlength-strings])
AC_SUBST([AM_CPPFLAGS],["${AM_CPPFLAGS} ${DISABLE_DEPRECATED}"])
# unique 1.0.8 doesn't satisfy this
#AC_SUBST([AM_CPPFLAGS],["${AM_CPPFLAGS} \
# -DG_DISABLE_SINGLE_INCLUDES -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES -DGTK_DISABLE_SINGLE_INCLUDES"])
AC_SUBST([AM_CFLAGS],["${AM_CFLAGS} ${WARN_CFLAGS}"])
+# GLib marshaling
+AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+
# libtool
AM_PROG_LIBTOOL
diff --git a/src/common/na-object-api.h b/src/common/na-object-api.h
index cbebf29..c5e2a20 100644
--- a/src/common/na-object-api.h
+++ b/src/common/na-object-api.h
@@ -70,7 +70,7 @@ G_BEGIN_DECLS
/* NAObjectItem
*/
-#define na_object_insert_item( object, item, before ) na_object_item_insert_item( NA_OBJECT_ITEM( object ), NA_OBJECT( item ), NA_OBJECT( before ))
+#define na_object_insert_item( object, item, before ) na_object_item_insert_item( NA_OBJECT_ITEM( object ), NA_OBJECT( item ), ( NAObject * ) before )
#define na_object_remove_item( object, item ) na_object_item_remove_item( NA_OBJECT_ITEM( object ), NA_OBJECT( item ))
G_END_DECLS
diff --git a/src/common/na-object-item-fn.h b/src/common/na-object-item-fn.h
index 548251c..7a13d0a 100644
--- a/src/common/na-object-item-fn.h
+++ b/src/common/na-object-item-fn.h
@@ -54,6 +54,8 @@ GdkPixbuf *na_object_item_get_pixbuf( const NAObjectItem *item, GtkWidget *w
void na_object_item_insert_item( NAObjectItem *item, const NAObject *object, const NAObject *before );
void na_object_item_remove_item( NAObjectItem *item, const NAObject *object );
+void na_object_item_count_items( GList *items, gint *menus, gint *actions, gint *profiles, gboolean recurse );
+
G_END_DECLS
#endif /* __NA_COMMON_OBJECT_ITEM_FN_H__ */
diff --git a/src/common/na-object-item.c b/src/common/na-object-item.c
index c4aba9e..f4d503e 100644
--- a/src/common/na-object-item.c
+++ b/src/common/na-object-item.c
@@ -108,12 +108,18 @@ na_object_item_insert_item( NAObjectItem *item, const NAObject *object, const NA
g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
g_return_if_fail( NA_IS_OBJECT( object ));
- g_return_if_fail( NA_IS_OBJECT( before ));
+ g_return_if_fail( !before || NA_IS_OBJECT( before ));
if( !item->private->dispose_has_run ){
if( !g_list_find( item->private->items, ( gpointer ) object )){
- before_list = g_list_find( item->private->items, ( gconstpointer ) before );
+
+ before_list = NULL;
+
+ if( before ){
+ before_list = g_list_find( item->private->items, ( gconstpointer ) before );
+ }
+
if( before_list ){
item->private->items = g_list_insert_before( item->private->items, before_list, ( gpointer ) object );
} else {
@@ -153,3 +159,42 @@ na_object_item_remove_item( NAObjectItem *item, const NAObject *object )
}
}
}
+
+/**
+ * na_object_item_count_items:
+ * @items: a list if #NAObject to be counted.
+ * @menus: will be set to the count of menus.
+ * @actions: will be set to the count of actions.
+ * @profiles: will be set to the count of profiles.
+ * @recurse: whether to recursively count all items, or only those in
+ * level zero of the list.
+ *
+ * Count the numbers of items if the provided list.
+ *
+ * As this function is recursive, the counters should be initialized by
+ * the caller before calling it.
+ */
+void
+na_object_item_count_items( GList *items, gint *menus, gint *actions, gint *profiles, gboolean recurse )
+{
+ GList *it;
+
+ for( it = items ; it ; it = it->next ){
+
+ /*g_debug( "na_object_item_count_items: item is %s", G_OBJECT_TYPE_NAME( it->data ));*/
+ if( NA_IS_OBJECT_MENU( it->data )){
+ *menus += 1;
+ } else if( NA_IS_OBJECT_ACTION( it->data )){
+ *actions += 1;
+ } else if( NA_IS_OBJECT_PROFILE( it->data )){
+ *profiles += 1;
+ }
+
+ if( recurse ){
+ if( NA_IS_OBJECT_ITEM( it->data )){
+ na_object_item_count_items(
+ NA_OBJECT_ITEM( it->data )->private->items, menus, actions, profiles, recurse );
+ }
+ }
+ }
+}
diff --git a/src/nact/.gitignore b/src/nact/.gitignore
index 582b638..b6d766d 100644
--- a/src/nact/.gitignore
+++ b/src/nact/.gitignore
@@ -1,3 +1,5 @@
+nact-marshal.c
+nact-marshal.h
nact.desktop
nautilus-actions-config
nautilus-actions-config-tool
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index f6809a6..eb5024a 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -38,6 +38,11 @@ AM_CPPFLAGS += \
$(NAUTILUS_ACTIONS_CFLAGS) \
$(NULL)
+BUILT_SOURCES = \
+ nact-marshal.c \
+ nact-marshal.h \
+ $(NULL)
+
nautilus_actions_config_tool_SOURCES = \
base-application.c \
base-application.h \
@@ -89,8 +94,16 @@ nautilus_actions_config_tool_SOURCES = \
nact-window.h \
nact-xml-reader.c \
nact-xml-reader.h \
+ $(BUILT_SOURCES) \
$(NULL)
+nact-marshal.h: nact-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=nact_marshal > $@
+
+nact-marshal.c: nact-marshal.list $(GLIB_GENMARSHAL)
+ echo "#include \"nact-marshal.h\"" > $@ && \
+ $(GLIB_GENMARSHAL) $< --body --prefix=nact_marshal >> $@
+
nautilus_actions_config_tool_LDADD = \
$(top_builddir)/src/common/libna-common.la \
$(top_builddir)/src/runtime/libna-runtime.la \
@@ -114,11 +127,14 @@ applicationsdir = $(datadir)/applications
applications_DATA = $(applications_files)
CLEANFILES = \
- $(applications_files)
+ $(applications_files) \
+ $(BUILT_SOURCES) \
+ $(NULL)
EXTRA_DIST = \
$(applications_in_files) \
$(pkgdata_DATA) \
+ nact-marshal.list \
$(NULL)
uninstall-hook:
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 3a3c820..0586106 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -39,6 +39,7 @@
#include <common/na-iprefs.h>
#include "nact-application.h"
+#include "nact-marshal.h"
#include "nact-main-tab.h"
#include "nact-tree-model.h"
#include "nact-window.h"
@@ -53,6 +54,7 @@ struct NactIActionsListInterfacePrivate {
/* signals
*/
enum {
+ LIST_COUNT_UPDATED,
SELECTION_CHANGED,
LAST_SIGNAL
};
@@ -72,6 +74,15 @@ enum {
TOGGLE_EXPAND
};
+/* storing the counters
+ */
+typedef struct {
+ gint menus;
+ gint actions;
+ gint profiles;
+}
+ CountersStruct;
+
/* when iterating through a selection
*/
typedef struct {
@@ -102,6 +113,7 @@ typedef struct {
*/
#define SELECTION_CHANGED_SIGNAL_MODE "nact-iactions-list-selection-changed-signal-mode"
#define MANAGEMENT_MODE "nact-iactions-list-management-mode"
+#define LIST_COUNTERS "nact-iactions-list-counters"
static gint st_signals[ LAST_SIGNAL ] = { 0 };
static gboolean st_initialized = FALSE;
@@ -112,8 +124,13 @@ 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, gboolean inside );
-static GList *do_insert_items_add_parent( GList *parents, GtkTreeView *treeview, GtkTreeModel *model, NAObject *parent );
+static void decremente_counters( NactIActionsList *instance, GList *items );
+static GtkTreePath *get_selection_first_path( GtkTreeView *treeview );
+static void do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *path, GList **parents );
+static NAObject *do_insert_into_first( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *insert_path, GtkTreePath **new_path );
+static GtkTreePath *do_insert_into_second( GtkTreeView *treeview, GtkTreeModel *model, NAObject *object, GtkTreePath *insert_path, NAObject **parent );
+static void incremente_counters( NactIActionsList *instance, GList *items );
+static void update_parents_edition_status( GList *parents, GList *items );
static gchar *v_get_treeview_name( NactIActionsList *instance );
@@ -124,7 +141,6 @@ static void filter_selection_iter( GtkTreeModel *model, GtkTreePath *pat
static GtkTreeView *get_actions_list_treeview( NactIActionsList *instance );
static gboolean get_item_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, IdToObjectIter *ito );
static gboolean get_items_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, GList **items );
-static gboolean has_exportable_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, gboolean *has_exportable );
static gboolean has_modified_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, gboolean *has_modified );
static gboolean have_dnd_mode( NactIActionsList *instance );
static gboolean have_filter_selection_mode( NactIActionsList *instance );
@@ -142,6 +158,7 @@ static void on_tab_updatable_item_updated( NactIActionsList *instance, N
static void on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
static void select_first_row( NactIActionsList *instance );
static void select_row_at_path( NactIActionsList *instance, GtkTreeView *treeview, GtkTreeModel *model, GtkTreePath *path );
+static void send_list_count_updated_signal( NactIActionsList *instance, CountersStruct *cs );
static void set_selection_changed_mode( NactIActionsList *instance, gboolean authorized );
static void toggle_collapse( NactIActionsList *instance );
static gboolean toggle_collapse_iter( NactIActionsList *instance, GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *iter, NAObject *object, gpointer user_data );
@@ -197,6 +214,29 @@ interface_base_init( NactIActionsListInterface *klass )
klass->private = g_new0( NactIActionsListInterfacePrivate, 1 );
/**
+ * nact-iactions-list-count-updated:
+ *
+ * This signal is emitted byIActionsList to its implementor when
+ * it has been asked to refill the list.
+ *
+ * It sends as arguments to the connected handlers the total
+ * count of menus, actions and profiles in the stored list.
+ */
+ st_signals[ LIST_COUNT_UPDATED ] = g_signal_new(
+ IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED,
+ G_TYPE_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* no default handler */
+ NULL,
+ NULL,
+ nact_marshal_VOID__INT_INT_INT,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INT );
+
+ /**
* nact-iactions-list-selection-changed:
*
* This signal is emitted byIActionsList to its implementor,
@@ -329,6 +369,7 @@ nact_iactions_list_runtime_init_toplevel( NactIActionsList *instance, GList *ite
gboolean have_filter_selection;
gboolean is_proxy;
GtkTreeSelection *selection;
+ CountersStruct *cs;
g_debug( "%s: instance=%p, items=%p (%d items)",
thisfn, ( void * ) instance, ( void * ) items, g_list_length( items ));
@@ -348,6 +389,9 @@ nact_iactions_list_runtime_init_toplevel( NactIActionsList *instance, GList *ite
nact_tree_model_runtime_init( model, have_dnd );
+ cs = g_new0( CountersStruct, 1 );
+ g_object_set_data( G_OBJECT( instance ), LIST_COUNTERS, cs );
+
/* set up selection control */
base_window_signal_connect(
BASE_WINDOW( instance ),
@@ -383,8 +427,8 @@ nact_iactions_list_runtime_init_toplevel( NactIActionsList *instance, GList *ite
TAB_UPDATABLE_SIGNAL_ITEM_UPDATED,
G_CALLBACK( on_tab_updatable_item_updated ));
- /* records NactIActionsList as a proxy for edition status modification
- */
+ /* records NactIActionsList as a proxy for edition status
+ * modification */
is_proxy = is_iduplicable_proxy( instance );
if( is_proxy ){
na_iduplicable_register_consumer( G_OBJECT( instance ));
@@ -435,6 +479,7 @@ nact_iactions_list_dispose( NactIActionsList *instance )
static const gchar *thisfn = "nact_iactions_list_dispose";
GtkTreeView *treeview;
NactTreeModel *model;
+ CountersStruct *cs;
g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
@@ -445,6 +490,9 @@ nact_iactions_list_dispose( NactIActionsList *instance )
model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
nact_tree_model_dispose( model );
+
+ cs = ( CountersStruct * ) g_object_get_data( G_OBJECT( instance ), LIST_COUNTERS );
+ g_free( cs );
}
}
@@ -497,6 +545,8 @@ nact_iactions_list_delete( NactIActionsList *instance, GList *items )
set_selection_changed_mode( instance, FALSE );
+ decremente_counters( instance, items );
+
for( it = items ; it ; it = it->next ){
if( path ){
gtk_tree_path_free( path );
@@ -514,6 +564,25 @@ nact_iactions_list_delete( NactIActionsList *instance, GList *items )
}
}
+static void
+decremente_counters( NactIActionsList *instance, GList *items )
+{
+ gint menus, actions, profiles;
+ CountersStruct *cs;
+
+ menus = 0;
+ actions = 0;
+ profiles = 0;
+ na_object_item_count_items( items, &menus, &actions, &profiles, TRUE );
+
+ cs = ( CountersStruct * ) g_object_get_data( G_OBJECT( instance ), LIST_COUNTERS );
+ cs->menus -= menus;
+ cs->actions -= actions;
+ cs->profiles -= profiles;
+
+ send_list_count_updated_signal( instance, cs );
+}
+
/**
* nact_iactions_list_display_order_change:
* @instance: this #NactIActionsList implementation.
@@ -575,6 +644,7 @@ nact_iactions_list_fill( NactIActionsList *instance, GList *items )
GtkTreeView *treeview;
NactTreeModel *model;
gboolean only_actions;
+ CountersStruct *cs;
g_debug( "%s: instance=%p, items=%p", thisfn, ( void * ) instance, ( void * ) items );
g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
@@ -589,6 +659,13 @@ nact_iactions_list_fill( NactIActionsList *instance, GList *items )
nact_tree_model_fill( model, items, only_actions );
set_selection_changed_mode( instance, TRUE );
+ cs = ( CountersStruct * ) g_object_get_data( G_OBJECT( instance ), LIST_COUNTERS );
+ cs->menus = 0;
+ cs->actions = 0;
+ cs->profiles = 0;
+ na_object_item_count_items( items, &cs->menus, &cs->actions, &cs->profiles, TRUE );
+ send_list_count_updated_signal( instance, cs );
+
select_first_row( instance );
}
}
@@ -732,18 +809,15 @@ nact_iactions_list_get_selected_items( NactIActionsList *instance )
}
/**
- * nact_iactions_list_has_exportable:
- *
- * Returns: %TRUE if there is at least one action in the list, %FALSE
- * else.
+ * nact_iactions_list_has_modified_items:
+ * @window: this #NactIActionsList instance.
*
- * This is used to see if we can enable or not the "Export" item in the
- * menubar (as of 1.12.1, we only export actions).
+ * Returns: %TRUE if at least there is one modified item in the list.
*/
gboolean
-nact_iactions_list_has_exportable( NactIActionsList *instance )
+nact_iactions_list_has_modified_items( NactIActionsList *instance )
{
- gboolean has_exportable = FALSE;
+ gboolean has_modified = FALSE;
GtkTreeView *treeview;
NactTreeModel *model;
@@ -753,36 +827,53 @@ nact_iactions_list_has_exportable( NactIActionsList *instance )
treeview = get_actions_list_treeview( instance );
model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
- nact_tree_model_iter( model, ( FnIterOnStore ) has_exportable_iter, &has_exportable );
+
+ nact_tree_model_iter( model, ( FnIterOnStore ) has_modified_iter, &has_modified );
}
- return( has_exportable );
+ return( has_modified );
}
/**
- * nact_iactions_list_has_modified_items:
- * @window: this #NactIActionsList instance.
+ * 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.
*
- * Returns: %TRUE if at least there is one modified item in the list.
+ * Inserts the provided @items list in the treeview.
+ *
+ * This function takes care of repositionning a new selection if
+ * possible, and refilter the display model.
*/
-gboolean
-nact_iactions_list_has_modified_items( NactIActionsList *instance )
+void
+nact_iactions_list_insert_at_path( NactIActionsList *instance, GList *items, GtkTreePath *insert_path )
{
- gboolean has_modified = FALSE;
+ static const gchar *thisfn = "nact_iactions_list_insert_at_path";
GtkTreeView *treeview;
- NactTreeModel *model;
+ GtkTreeModel *model;
+ GList *parents;
- g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), FALSE );
+ 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 = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
+ model = gtk_tree_view_get_model( treeview );
+ g_return_if_fail( NACT_IS_TREE_MODEL( model ));
- nact_tree_model_iter( model, ( FnIterOnStore ) has_modified_iter, &has_modified );
- }
+ do_insert_items( treeview, model, items, insert_path, &parents );
- return( has_modified );
+ incremente_counters( instance, items );
+
+ update_parents_edition_status( parents, items );
+
+ gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( model ));
+
+ select_row_at_path( instance, treeview, model, insert_path );
+ }
}
/**
@@ -797,11 +888,11 @@ nact_iactions_list_has_modified_items( NactIActionsList *instance )
* The provided @items list is supposed to be homogeneous, i.e. referes
* to only profiles, or only actions or menus.
*
- * If the @items list contains only profiles, they can only be inserted
- * into an action, and the profiles will eventually be renumbered.
+ * If the @items list contains profiles, they can only be inserted
+ * into an action, or before another profile.
*
* If new item is a #NAActionMenu or a #NAAction, it will be inserted
- * before the current action or inside the current menu.
+ * before the current action or menu.
*
* This function takes care of repositionning a new selection if
* possible, and refilter the display model.
@@ -812,9 +903,8 @@ nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObj
static const gchar *thisfn = "nact_iactions_list_insert_items";
GtkTreeView *treeview;
GtkTreeModel *model;
- GtkTreeSelection *selection;
- GList *list_selected;
GtkTreePath *insert_path;
+ NAObject *object;
g_debug( "%s: instance=%p, items=%p (%d items)",
thisfn, ( void * ) instance, ( void * ) items, g_list_length( items ));
@@ -832,42 +922,54 @@ nact_iactions_list_insert_items( NactIActionsList *instance, GList *items, NAObj
insert_path = object_to_path( instance, NACT_TREE_MODEL( model ), sibling );
} else {
- selection = gtk_tree_view_get_selection( treeview );
- list_selected = gtk_tree_selection_get_selected_rows( selection, NULL );
- if( g_list_length( list_selected )){
- insert_path = gtk_tree_path_copy(( GtkTreePath * ) list_selected->data );
+ insert_path = get_selection_first_path( treeview );
+
+ /* as a particular case, insert profiles into current action */
+ object = nact_tree_model_object_at_path( NACT_TREE_MODEL( model ), insert_path );
+ /*g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+ g_debug( "%s: items->data is %s", thisfn, G_OBJECT_TYPE_NAME( items->data ));*/
+ if( NA_IS_OBJECT_ACTION( object ) &&
+ NA_IS_OBJECT_PROFILE( items->data )){
+
+ nact_iactions_list_insert_into( instance, items );
+ gtk_tree_path_free( insert_path );
+ return;
}
- g_list_foreach( list_selected, ( GFunc ) gtk_tree_path_free, NULL );
- g_list_free( list_selected );
}
- nact_iactions_list_insert_at_path( instance, items, insert_path, TRUE );
-
+ nact_iactions_list_insert_at_path( instance, items, insert_path );
gtk_tree_path_free( insert_path );
}
}
/**
- * nact_iactions_list_insert_at_path:
+ * nact_iactions_list_insert_into:
* @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.
+ * Inserts the provided @items list as first childs of the current item.
*
- * This function takes care of repositionning a new selection if
- * possible, and refilter the display model.
+ * The provided @items list is supposed to be homogeneous, i.e. referes
+ * to only profiles, or only actions or menus.
+ *
+ * If the @items list contains only profiles, they can only be inserted
+ * into an action, and the profiles will eventually be renumbered.
+ *
+ * If new item is a #NAActionMenu or a #NAAction, it will be inserted
+ * as first childs of the current menu.
+ *
+ * This function takes care of repositionning a new selection as the
+ * last inserted item, and refilter the display model.
*/
void
-nact_iactions_list_insert_at_path( NactIActionsList *instance, GList *items, GtkTreePath *insert_path, gboolean inside )
+nact_iactions_list_insert_into( NactIActionsList *instance, GList *items )
{
- static const gchar *thisfn = "nact_iactions_list_insert_at_path";
+ static const gchar *thisfn = "nact_iactions_list_insert_into";
GtkTreeView *treeview;
GtkTreeModel *model;
- GtkTreePath *last_path = NULL;
- GList *parents = NULL;
- GList *it;
+ GtkTreePath *insert_path;
+ GtkTreePath *new_path;
+ NAObject *parent;
g_debug( "%s: instance=%p, items=%p (%d items)",
thisfn, ( void * ) instance, ( void * ) items, g_list_length( items ));
@@ -876,97 +978,161 @@ nact_iactions_list_insert_at_path( NactIActionsList *instance, GList *items, Gtk
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 ));
+ insert_path = get_selection_first_path( treeview );
- last_path = do_insert_items( treeview, model, items, insert_path, 0, &parents, inside );
+ incremente_counters( instance, items );
- for( it = parents ; it ; it = it->next ){
- na_object_check_edition_status( it->data );
- }
+ parent = do_insert_into_first( treeview, model, items, insert_path, &new_path );
+
+ na_object_check_edition_status( parent );
gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( model ));
- select_row_at_path( instance, treeview, model, last_path );
- gtk_tree_path_free( last_path );
+ select_row_at_path( instance, treeview, model, new_path );
+
+ gtk_tree_path_free( new_path );
+ gtk_tree_path_free( insert_path );
}
}
static GtkTreePath *
-do_insert_items( GtkTreeView *treeview,
- GtkTreeModel *model,
- GList *items,
- GtkTreePath *path,
- gint level,
- GList **parents,
- gboolean inside )
+get_selection_first_path( GtkTreeView *treeview )
{
- static const gchar *thisfn = "nact_iactions_list_do_insert_items";
- guint nb_profiles, nb_actions, nb_menus;
+ GtkTreeSelection *selection;
+ GList *list_selected;
+ GtkTreePath *path;
+
+ path = NULL;
+ selection = gtk_tree_view_get_selection( treeview );
+ list_selected = gtk_tree_selection_get_selected_rows( selection, NULL );
+
+ if( g_list_length( list_selected )){
+ path = gtk_tree_path_copy(( GtkTreePath * ) list_selected->data );
+
+ } else {
+ path = gtk_tree_path_new_from_string( "0" );
+ }
+
+ g_list_foreach( list_selected, ( GFunc ) gtk_tree_path_free, NULL );
+ g_list_free( list_selected );
+
+ return( path );
+}
+
+static void
+do_insert_items( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *insert_path, GList **list_parents )
+{
+ /*static const gchar *thisfn = "nact_iactions_list_do_insert_items";*/
+ GList *reversed;
GList *it;
GList *subitems;
- gchar *inserted_path_str;
- GtkTreePath *inserted_path;
NAObject *obj_parent;
- GtkTreePath *returned_path;
- returned_path = NULL;
+ obj_parent = NULL;
+ if( list_parents ){
+ *list_parents = NULL;
+ }
- nact_window_count_level_zero_items( items, &nb_actions, &nb_profiles, &nb_menus );
+ reversed = g_list_reverse( items );
- g_debug( "%s: level=%d, actions=%d, profiles=%d, menus=%d", thisfn, level, nb_actions, nb_profiles, nb_menus );
+ for( it = reversed ; it ; it = it->next ){
- if( nb_actions || nb_profiles || nb_menus ){
- g_return_val_if_fail(( nb_profiles && !( nb_actions + nb_menus )) || ( !nb_profiles && ( nb_actions + nb_menus )), NULL );
- /*g_return_if_fail(( nb_profiles && ( NA_IS_OBJECT_ACTION( obj_selected ) || NA_IS_OBJECT_PROFILE( obj_selected ))) || !nb_profiles );*/
+ nact_tree_model_insert( NACT_TREE_MODEL( model ), NA_OBJECT( it->data ), insert_path, &obj_parent );
- for( it = items ; it ; it = it->next ){
+ if( list_parents && obj_parent ){
+ if( !g_list_find( *list_parents, obj_parent )){
+ *list_parents = g_list_prepend( *list_parents, obj_parent );
+ }
+ }
- /* note that returned iter may have became invalid after conversion
- * 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, inside );
- g_debug( "%s: inserted_path=%s", thisfn, inserted_path_str );
+ /* recursively insert subitems
+ */
+ if( NA_IS_OBJECT_ITEM( it->data ) && na_object_get_items_count( it->data )){
- inserted_path = gtk_tree_path_new_from_string( inserted_path_str );
+ subitems = na_object_get_items( it->data );
+ do_insert_into_first( treeview, model, subitems, insert_path, NULL );
+ na_object_free_items( subitems );
+ }
+ }
- if( level == 0 ){
- gtk_tree_view_expand_to_path( treeview, inserted_path );
- gtk_tree_path_free( returned_path );
- returned_path = gtk_tree_path_copy( inserted_path );
- }
+ /*g_list_free( reversed );*/
+}
- *parents = do_insert_items_add_parent( *parents, treeview, model, obj_parent );
+static NAObject *
+do_insert_into_first( GtkTreeView *treeview, GtkTreeModel *model, GList *items, GtkTreePath *insert_path, GtkTreePath **new_path )
+{
+ GList *last;
+ NAObject *parent;
+ GtkTreePath *inserted_path;
- /* recursively insert subitems
- */
- 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, inside );
- na_object_free_items( subitems );
- }
+ parent = NULL;
+ last = g_list_last( items );
+ items = g_list_remove_link( items, last );
- gtk_tree_path_free( inserted_path );
- g_free( inserted_path_str );
- }
+ inserted_path = do_insert_into_second( treeview, model, NA_OBJECT( last->data ), insert_path, &parent );
+ do_insert_items( treeview, model, items, inserted_path, NULL );
+
+ if( new_path ){
+ *new_path = gtk_tree_path_copy( inserted_path );
}
- return( level ? NULL : returned_path );
+ gtk_tree_path_free( inserted_path );
+
+ return( parent );
+}
+
+static GtkTreePath *
+do_insert_into_second( GtkTreeView *treeview, GtkTreeModel *model, NAObject *object, GtkTreePath *insert_path, NAObject **parent )
+{
+ /*static const gchar *thisfn = "nact_iactions_list_do_insert_into";*/
+ GtkTreePath *new_path;
+
+ new_path = nact_tree_model_insert_into( NACT_TREE_MODEL( model ), object, insert_path, parent );
+
+ gtk_tree_view_expand_to_path( treeview, new_path );
+
+ return( new_path );
}
-static GList *
-do_insert_items_add_parent( GList *parents, GtkTreeView *treeview, GtkTreeModel *model, NAObject *parent )
+static void
+incremente_counters( NactIActionsList *instance, GList *items )
{
- g_return_val_if_fail( parent, NULL );
+ gint menus, actions, profiles;
+ CountersStruct *cs;
+
+ menus = 0;
+ actions = 0;
+ profiles = 0;
+ na_object_item_count_items( items, &menus, &actions, &profiles, TRUE );
+ /*g_debug( "incremente_counters: counted: menus=%d, actions=%d, profiles=%d", menus, actions, profiles );*/
+
+ cs = ( CountersStruct * ) g_object_get_data( G_OBJECT( instance ), LIST_COUNTERS );
+ /*g_debug( "incremente_counters: cs before: menus=%d, actions=%d, profiles=%d", cs->menus, cs->actions, cs->profiles );*/
+ cs->menus += menus;
+ cs->actions += actions;
+ cs->profiles += profiles;
+ /*g_debug( "incremente_counters: cs after: menus=%d, actions=%d, profiles=%d", cs->menus, cs->actions, cs->profiles );*/
+
+ send_list_count_updated_signal( instance, cs );
+}
- if( !g_list_find( parents, parent )){
- parents = g_list_prepend( parents, parent );
+static void
+update_parents_edition_status( GList *parents, GList *items )
+{
+ GList *it;
+
+ /*if( !parents || !g_list_length( parents )){
+ parents = g_list_copy( items );
+ }*/
+
+ for( it = parents ; it ; it = it->next ){
+ na_object_check_edition_status( it->data );
}
- return( parents );
+ g_list_free( parents );
}
/**
@@ -1315,18 +1481,6 @@ get_items_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, GList
return( FALSE );
}
-static gboolean
-has_exportable_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, gboolean *has_exportable )
-{
- if( NA_IS_OBJECT_ACTION( object )){
- *has_exportable = TRUE;
- return( TRUE );
- }
-
- /* don't stop iteration while not found or not at end */
- return( FALSE );
-}
-
/*
* stop as soon as we have found a modified item
*/
@@ -1647,6 +1801,15 @@ select_row_at_path( NactIActionsList *instance, GtkTreeView *treeview, GtkTreeMo
}
}
+/*
+ * send a 'fill' signal with count of items
+ */
+static void
+send_list_count_updated_signal( NactIActionsList *instance, CountersStruct *cs )
+{
+ g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED, cs->menus, cs->actions, cs->profiles );
+}
+
static void
set_selection_changed_mode( NactIActionsList *instance, gboolean authorized )
{
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index ffb68b9..558596e 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -38,6 +38,16 @@
*
* This same interface is used in the main window (edition mode, default),
* and in the export assistant (export mode).
+ *
+ * Counting rows
+ *
+ * Counting rows is needed to maintain action sensitivities in the
+ * menubar : at least 'Tools\Export' menu item depends of the content
+ * of the IActionsList.
+ * Rows are first counted when the treeview is primarily filled, or
+ * refilled on demand.
+ * Counters are then incremented in nact_iactions_list_insert() and
+ * nact_iactions_list_delete() functions.
*/
#include <gtk/gtk.h>
@@ -93,6 +103,7 @@ typedef struct {
/* signals
*/
+#define IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED "nact-iactions-list-count-updated"
#define IACTIONS_LIST_SIGNAL_SELECTION_CHANGED "nact-iactions-list-selection-changed"
/* management modes
@@ -120,10 +131,10 @@ NAObject *nact_iactions_list_get_item( NactIActionsList *instance, const gchar *
GList *nact_iactions_list_get_items( NactIActionsList *instance );
gint nact_iactions_list_get_management_mode( NactIActionsList *instance );
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_at_path( NactIActionsList *instance, GList *items, GtkTreePath *path );
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 );
+void nact_iactions_list_insert_into( NactIActionsList *instance, GList *items );
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-menubar.c b/src/nact/nact-main-menubar.c
index 9144b9e..451f301 100644
--- a/src/nact/nact-main-menubar.c
+++ b/src/nact/nact-main-menubar.c
@@ -68,7 +68,29 @@
#define MENUBAR_PROP_ITEM_ACTION "nact-menubar-item-action"
#endif
-static void on_tab_updatable_selection_changed( NactMainWindow *window, gint count_selected );
+/* this structure is updated each time the user interacts in the
+ * interface ; it is then used to update action sensitivities
+ */
+typedef struct {
+ gint selected_menus;
+ gint selected_actions;
+ gint selected_profiles;
+ gint clipboard_menus;
+ gint clipboard_actions;
+ gint clipboard_profiles;
+ gint list_menus;
+ gint list_actions;
+ gint list_profiles;
+ gboolean is_modified;
+ gboolean have_exportables;
+}
+ MenubarIndicatorsStruct;
+
+#define MENUBAR_PROP_INDICATORS "nact-menubar-indicators"
+
+static void on_iactions_list_count_updated( NactMainWindow *window, gint menus, gint actions, gint profiles );
+static void on_iactions_list_selection_changed( NactMainWindow *window, GList *selected );
+static void on_update_sensitivities( NactMainWindow *window, gpointer user_data );
static void on_new_menu_activated( GtkAction *action, NactMainWindow *window );
static void on_new_action_activated( GtkAction *action, NactMainWindow *window );
@@ -81,8 +103,10 @@ static void on_quit_activated( GtkAction *action, NactMainWindow *window );
static void on_cut_activated( GtkAction *action, NactMainWindow *window );
static void on_copy_activated( GtkAction *action, NactMainWindow *window );
static void on_paste_activated( GtkAction *action, NactMainWindow *window );
+static void on_paste_into_activated( GtkAction *action, NactMainWindow *window );
static void on_duplicate_activated( GtkAction *action, NactMainWindow *window );
static void on_delete_activated( GtkAction *action, NactMainWindow *window );
+static void update_clipboard_counters( NactMainWindow *window );
static void on_reload_activated( GtkAction *action, NactMainWindow *window );
static void on_preferences_activated( GtkAction *action, NactMainWindow *window );
@@ -102,7 +126,6 @@ static void on_menu_item_selected( GtkMenuItem *proxy, NactMainWindow *windo
static void on_menu_item_deselected( GtkMenuItem *proxy, NactMainWindow *window );
static void on_proxy_connect( GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NactMainWindow *window );
static void on_proxy_disconnect( GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NactMainWindow *window );
-static void refresh_actions_sensitivity_with_count( NactMainWindow *window, gint count_selected );
static const GtkActionEntry entries[] = {
@@ -142,8 +165,12 @@ static const GtkActionEntry entries[] = {
G_CALLBACK( on_copy_activated ) },
{ "PasteItem" , GTK_STOCK_PASTE, NULL, NULL,
/* i18n: tooltip displayed in the status bar when selecting the Paste item */
- N_( "Insert the content of the clipboard at the current position" ),
+ N_( "Insert the content of the clipboard just before the current position" ),
G_CALLBACK( on_paste_activated ) },
+ { "PasteIntoItem" , NULL, N_( "Paste _into" ), "<Shift><Ctrl>V",
+ /* i18n: tooltip displayed in the status bar when selecting the Paste Into item */
+ N_( "Insert the content of the clipboard as first child of the current item" ),
+ G_CALLBACK( on_paste_into_activated ) },
{ "DuplicateItem" , NULL, N_( "D_uplicate" ), "",
/* i18n: tooltip displayed in the status bar when selecting the Duplicate item */
N_( "Duplicate the selected item(s)" ),
@@ -191,6 +218,8 @@ static const GtkActionEntry entries[] = {
* @window: the #NactMainWindow to which the menubar is attached.
*
* Creates the menubar.
+ * Connects to all possible signals which may have an impact on action
+ * sensitivities.
*/
void
nact_main_menubar_runtime_init( NactMainWindow *window )
@@ -203,6 +232,7 @@ nact_main_menubar_runtime_init( NactMainWindow *window )
GtkAccelGroup *accel_group;
GtkWidget *menubar, *vbox;
GtkWindow *toplevel;
+ MenubarIndicatorsStruct *mis;
g_debug( "%s: window=%p", thisfn, ( void * ) window );
@@ -260,50 +290,171 @@ nact_main_menubar_runtime_init( NactMainWindow *window )
base_window_signal_connect(
BASE_WINDOW( window ),
G_OBJECT( window ),
- TAB_UPDATABLE_SIGNAL_SELECTION_CHANGED,
- G_CALLBACK( on_tab_updatable_selection_changed ));
+ IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED,
+ G_CALLBACK( on_iactions_list_count_updated ));
+
+ base_window_signal_connect(
+ BASE_WINDOW( window ),
+ G_OBJECT( window ),
+ IACTIONS_LIST_SIGNAL_SELECTION_CHANGED,
+ G_CALLBACK( on_iactions_list_selection_changed ));
+
+ base_window_signal_connect(
+ BASE_WINDOW( window ),
+ G_OBJECT( window ),
+ MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES,
+ G_CALLBACK( on_update_sensitivities ));
+
+ mis = g_new0( MenubarIndicatorsStruct, 1 );
+ g_object_set_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS, mis );
}
/**
- * nact_main_menubar_refresh_actions_sensitivity:
- *
- * Sensitivity of items (whether they are activable of not) in the
- * menubar should be recomputed each time aaction in the user interface
- * may lead to a change in one of the menu actions.
- *
- * This consists in :
- * - when there is a change in the current selection in IActionsList
- * (new profile, cut, copy, duplicate, delete)
- * - when there is a change in the content of IActionsList
- * (export)
- * - when there is a change in the content of the clipboard
- * (paste)
- *
- * Note that the same actions are also used as toolbar actions ; we so
- * cannot rely on just recomputing the sensitivity e.g. when about to
- * open a popup menu in the menubar. Sensitivity of the actions need
- * to be updated as soon as the global context is changed.
+ * nact_main_menubar_dispose:
+ * @window: this #NactMainWindow window.
*
+ * Release internally allocated resources.
*/
void
-nact_main_menubar_refresh_actions_sensitivity( NactMainWindow *window )
+nact_main_menubar_dispose( NactMainWindow *window )
+{
+ static const gchar *thisfn = "nact_main_menubar_dispose";
+ MenubarIndicatorsStruct *mis;
+
+ g_debug( "%s: window=%p", thisfn, ( void * ) window );
+ g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+ mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
+ g_free( mis );
+}
+
+/*
+ * when the IActionsList is refilled, update our internal counters so
+ * that we are knowing if we have some exportables
+ */
+static void
+on_iactions_list_count_updated( NactMainWindow *window, gint menus, gint actions, gint profiles )
{
- GList *selected;
- guint count;
+ MenubarIndicatorsStruct *mis;
+
+ g_debug( "nact_main_menubar_on_iactions_list_count_updated: menus=%u, actions=%u, profiles=%u", menus, actions, profiles );
+ g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
- g_return_if_fail( NACT_MAIN_WINDOW( window ));
- g_return_if_fail( NACT_IS_IACTIONS_LIST( window ));
+ mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
+ mis->list_menus = menus;
+ mis->list_actions = actions;
+ mis->list_profiles = profiles;
+ mis->have_exportables = ( mis->list_actions > 0 );
- selected = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window ));
- count = g_list_length( selected );
- na_object_free_items( selected );
- refresh_actions_sensitivity_with_count( window, count );
+ g_signal_emit_by_name( window, MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES, NULL );
}
+/*
+ * when the selection changes in IActionsList, see what is selected
+ */
static void
-on_tab_updatable_selection_changed( NactMainWindow *window, gint count_selected )
+on_iactions_list_selection_changed( NactMainWindow *window, GList *selected )
{
- refresh_actions_sensitivity_with_count( window, count_selected );
+ MenubarIndicatorsStruct *mis;
+
+ g_debug( "nact_main_menubar_on_iactions_list_selection_changed: selected=%p (%d)",
+ ( void * ) selected, g_list_length( selected ));
+ g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+ mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
+ mis->selected_menus = 0;
+ mis->selected_actions = 0;
+ mis->selected_profiles = 0;
+ na_object_item_count_items( selected, &mis->selected_menus, &mis->selected_actions, &mis->selected_profiles, FALSE );
+ g_debug( "nact_main_menubar_on_iactions_list_selection_changed: menus=%d, actions=%d, profiles=%d",
+ mis->selected_menus, mis->selected_actions, mis->selected_profiles );
+
+ g_signal_emit_by_name( window, MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES, NULL );
+}
+
+static void
+on_update_sensitivities( NactMainWindow *window, gpointer user_data )
+{
+ static const gchar *thisfn = "nact_main_menubar_on_update_sensitivities";
+ MenubarIndicatorsStruct *mis;
+ NAObject *item;
+ NAObject *profile;
+ gboolean has_modified;
+ gint count_list;
+ gint count_selected;
+ gboolean paste_enabled;
+ gboolean paste_into_enabled;
+ gboolean clipboard_is_empty;
+
+ g_debug( "%s: window=%p", thisfn, ( void * ) window );
+ g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+ mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
+
+ g_object_get(
+ G_OBJECT( window ),
+ TAB_UPDATABLE_PROP_EDITED_ACTION, &item,
+ TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
+ NULL );
+ g_return_if_fail( !item || NA_IS_OBJECT_ITEM( item ));
+ g_return_if_fail( !profile || NA_IS_OBJECT_PROFILE( profile ));
+
+ has_modified = nact_main_window_has_modified_items( window );
+ count_list = mis->list_menus + mis->list_actions + mis->list_profiles;
+ count_selected = mis->selected_menus + mis->selected_actions + mis->selected_profiles;
+
+ clipboard_is_empty = ( mis->clipboard_menus + mis->clipboard_actions + mis->clipboard_profiles == 0 );
+
+ paste_enabled = FALSE;
+ if( !clipboard_is_empty ){
+ if( mis->clipboard_profiles ){
+ paste_enabled = profile && NA_IS_OBJECT_PROFILE( profile );
+ } else {
+ paste_enabled = ( item != NULL );
+ }
+ }
+
+ paste_into_enabled = FALSE;
+ if( !clipboard_is_empty ){
+ if( mis->clipboard_profiles ){
+ paste_into_enabled = item && NA_IS_OBJECT_ACTION( item );
+ } else {
+ paste_into_enabled = item && NA_IS_OBJECT_MENU( item );
+ }
+ }
+
+ /* new menu always enabled */
+ /* new action always enabled */
+ /* new profile enabled if selection is relative to only one action */
+ enable_item( window, "NewProfileItem", item != NULL && !NA_IS_OBJECT_MENU( item ));
+ /* save enabled if at least one item has been modified */
+ enable_item( window, "SaveItem", has_modified );
+ /* quit always enabled */
+ /* cut/copy enabled if selection not empty */
+ enable_item( window, "CutItem", count_selected > 0 );
+ enable_item( window, "CopyItem", count_selected > 0 );
+ /* paste enabled if
+ * - clipboard contains only profiles, and current selection is a profile
+ * - clipboard contains actions or menus, and current selection is a menu or an action */
+ enable_item( window, "PasteItem", count_selected <= 1 && paste_enabled );
+ /* paste into enabled if
+ * - clipboard has profiles and current item is an action
+ * - or current item is a menu */
+ enable_item( window, "PasteIntoItem", count_selected <= 1 && paste_into_enabled );
+ /* duplicate/delete enabled if selection not empty */
+ enable_item( window, "DuplicateItem", count_selected > 0 );
+ enable_item( window, "DeleteItem", count_selected > 0 );
+ /* reload items always enabled */
+ /* preferences always enabled */
+ /* expand all/collapse all requires at least one item in the list */
+ enable_item( window, "ExpandAllItem", count_list > 0 );
+ enable_item( window, "CollapseAllItem", count_list > 0 );
+ /* import item always enabled */
+ /* export item enabled if IActionsList store contains actions */
+ enable_item( window, "ExportItem", mis->have_exportables );
+ /* TODO: help temporarily disabled */
+ enable_item( window, "HelpItem", FALSE );
+ /* about always enabled */
}
static void
@@ -370,7 +521,7 @@ on_new_profile_activated( GtkAction *gtk_action, NactMainWindow *window )
* saving is not only saving modified items, but also saving hierarchy
* (and order if alpha order is not set)
*
- * note that we only go down in the hierarchy is parent is valid and not
+ * note that we only go down in the hierarchy if parent is valid and not
* modified (or has been successfully saved)
*/
static void
@@ -400,7 +551,7 @@ on_save_activated( GtkAction *gtk_action, NactMainWindow *window )
/* required as selection has not changed
*/
- nact_main_menubar_refresh_actions_sensitivity( window );
+ g_signal_emit_by_name( window, MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES, NULL );
/* get ride of notification messages of IOProviders
*/
@@ -504,6 +655,7 @@ on_cut_activated( GtkAction *gtk_action, NactMainWindow *window )
nact_main_window_move_to_deleted( window, items );
clipboard = nact_main_window_get_clipboard( window );
nact_clipboard_primary_set( clipboard, items, FALSE );
+ update_clipboard_counters( window );
nact_iactions_list_delete( NACT_IACTIONS_LIST( window ), items );
/* do not unref selected items as the ref has been moved to main_deleted
@@ -531,12 +683,15 @@ on_copy_activated( GtkAction *gtk_action, NactMainWindow *window )
items = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window ));
clipboard = nact_main_window_get_clipboard( window );
nact_clipboard_primary_set( clipboard, items, TRUE );
+ update_clipboard_counters( window );
na_object_free_items( items );
- nact_main_menubar_refresh_actions_sensitivity( window );
+
+ g_signal_emit_by_name( window, MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES, NULL );
}
/*
- * pastes the current content of the clipboard
+ * pastes the current content of the clipboard at the current position
+ * (same path, same level)
* - (menu) get from clipboard a copy of installed items
* the clipboard will return a new copy
* and renumber its own data for allowing a new paste
@@ -573,6 +728,44 @@ on_paste_activated( GtkAction *gtk_action, NactMainWindow *window )
}
/*
+ * pastes the current content of the clipboard as the first child of
+ * currently selected item
+ * - (menu) get from clipboard a copy of installed items
+ * the clipboard will return a new copy
+ * and renumber its own data for allowing a new paste
+ * - (tree) insert new items, the tree store will ref them
+ * attaching each item to its parent
+ * recursively checking edition status of the topmost parent
+ * selecting the first item at end
+ * - (menu) unreffing the copy got from clipboard
+ */
+static void
+on_paste_into_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+ GList *items, *it;
+ NactClipboard *clipboard;
+ NAObjectAction *action = NULL;
+
+ clipboard = nact_main_window_get_clipboard( window );
+ items = nact_clipboard_primary_get( clipboard );
+
+ /* if pasted items are profiles, then setup the action
+ */
+ for( it = items ; it ; it = it->next ){
+ if( NA_IS_OBJECT_PROFILE( it->data )){
+ if( !action ){
+ g_object_get( G_OBJECT( window ), TAB_UPDATABLE_PROP_EDITED_ACTION, &action, NULL );
+ g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
+ }
+ na_object_profile_set_action( NA_OBJECT_PROFILE( it->data ), action );
+ }
+ }
+
+ nact_iactions_list_insert_into( NACT_IACTIONS_LIST( window ), items );
+ na_object_free_items( items );
+}
+
+/*
* duplicate is just as paste, with the difference that content comes
* from the current selection, instead of coming from the clipboard
*
@@ -653,6 +846,27 @@ on_delete_activated( GtkAction *gtk_action, NactMainWindow *window )
/*g_list_free( items );*/
}
+/*
+ * as we are coming from cut or copy to clipboard, report selection
+ * counters to clipboard ones
+ */
+static void
+update_clipboard_counters( NactMainWindow *window )
+{
+ MenubarIndicatorsStruct *mis;
+
+ mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
+
+ mis->clipboard_menus = mis->selected_menus;
+ mis->clipboard_actions = mis->selected_actions;
+ mis->clipboard_profiles = mis->selected_profiles;
+
+ g_debug( "nact_main_menubar_update_clipboard_counters: menus=%d, actions=%d, profiles=%d",
+ mis->clipboard_menus, mis->clipboard_actions, mis->clipboard_profiles );
+
+ g_signal_emit_by_name( window, MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES, NULL );
+}
+
static void
on_reload_activated( GtkAction *gtk_action, NactMainWindow *window )
{
@@ -819,68 +1033,3 @@ on_proxy_disconnect( GtkActionGroup *action_group, GtkAction *action, GtkWidget
{
/* signal handlers will be automagically disconnected on NactWindow::dispose */
}
-
-static void
-refresh_actions_sensitivity_with_count( NactMainWindow *window, gint count_selected )
-{
- static const gchar *thisfn = "nact_main_menubar_refresh_actions_sensitivity_with_count";
- NAObjectItem *item;
- NAObjectProfile *profile;
- gboolean has_exportable;
- gboolean has_modified;
- guint nb_actions, nb_profiles, nb_menus;
- gboolean paste_enabled;
- NactClipboard *clipboard;
-
- g_debug( "%s: window=%p, count_selected=%d", thisfn, ( void * ) window, count_selected );
- g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
-
- g_object_get(
- G_OBJECT( window ),
- TAB_UPDATABLE_PROP_EDITED_ACTION, &item,
- TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
- NULL );
- g_debug( "%s: item=%p (%s), profile=%p", thisfn,
- ( void * ) item, item ? G_OBJECT_TYPE_NAME( item ) : "(nil)", ( void * ) profile );
-
- has_exportable = nact_iactions_list_has_exportable( NACT_IACTIONS_LIST( window ));
- g_debug( "%s: has_exportable=%s", thisfn, has_exportable ? "True":"False" );
- has_modified = nact_main_window_has_modified_items( window );
- g_debug( "%s: has_modified=%s", thisfn, has_modified ? "True":"False" );
-
- paste_enabled = FALSE;
- clipboard = nact_main_window_get_clipboard( window );
- nact_clipboard_primary_counts( clipboard, &nb_actions, &nb_profiles, &nb_menus );
- g_debug( "%s: actions=%d, profiles=%d, menus=%d", thisfn, nb_actions, nb_profiles, nb_menus );
- if( nb_profiles ){
- paste_enabled = NA_IS_OBJECT_ACTION( item );
- } else {
- paste_enabled = ( nb_actions + nb_menus > 0 );
- }
-
- /* new menu always enabled */
- /* new action always enabled */
- /* new profile enabled if selection is relative to only one action */
- enable_item( window, "NewProfileItem", item != NULL && !NA_IS_OBJECT_MENU( item ));
- /* save enabled if at least one item has been modified */
- enable_item( window, "SaveItem", has_modified );
- /* quit always enabled */
- /* cut/copy enabled if selection not empty */
- enable_item( window, "CutItem", count_selected > 0 );
- enable_item( window, "CopyItem", count_selected > 0 );
- /* paste enabled if
- * - clipboard contains only profiles, and current selection is action or profile
- * - clipboard contains actions or menus */
- enable_item( window, "PasteItem", paste_enabled );
- /* duplicate/delete enabled if selection not empty */
- enable_item( window, "DuplicateItem", count_selected > 0 );
- enable_item( window, "DeleteItem", count_selected > 0 );
- /* reload items always enabled */
- /* preferences always enabled */
- /* import item always enabled */
- /* export item enabled if IActionsList store contains actions */
- enable_item( window, "ExportItem", has_exportable );
- /* TODO: help temporarily disabled */
- enable_item( window, "HelpItem", FALSE );
- /* about always enabled */
-}
diff --git a/src/nact/nact-main-menubar.h b/src/nact/nact-main-menubar.h
index 7916a74..d5815fd 100644
--- a/src/nact/nact-main-menubar.h
+++ b/src/nact/nact-main-menubar.h
@@ -37,14 +37,12 @@
* @include: nact/nact-main-menubar.h
*/
-#include <gtk/gtk.h>
-
#include "nact-main-window.h"
G_BEGIN_DECLS
void nact_main_menubar_runtime_init( NactMainWindow *window );
-void nact_main_menubar_refresh_actions_sensitivity( NactMainWindow *window );
+void nact_main_menubar_dispose( NactMainWindow *window );
G_END_DECLS
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index 0539ce2..7a6edb8 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -111,6 +111,7 @@ enum {
enum {
SELECTION_CHANGED,
ITEM_UPDATED,
+ UPDATE_SENSITIVITIES,
LAST_SIGNAL
};
@@ -141,7 +142,7 @@ static void on_base_initial_load_toplevel( NactMainWindow *window, gpointer
static void on_base_runtime_init_toplevel( NactMainWindow *window, gpointer user_data );
static void on_base_all_widgets_showed( NactMainWindow *window, gpointer user_data );
-static void iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
+static void on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
static void set_current_object_item( NactMainWindow *window, GSList *selected_items );
static void set_current_profile( NactMainWindow *window, gboolean set_action, GSList *selected_items );
static gchar *iactions_list_get_treeview_name( NactIActionsList *instance );
@@ -343,6 +344,24 @@ class_init( NactMainWindowClass *klass )
G_TYPE_NONE,
1,
G_TYPE_POINTER );
+
+ /**
+ * main-window-update-sensitivities:
+ *
+ * This signal is emitted each time a user interaction may led the
+ * action sensitivities to be updated.
+ */
+ st_signals[ UPDATE_SENSITIVITIES ] = g_signal_new(
+ MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES,
+ G_TYPE_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* no default handler */
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER );
}
static void
@@ -352,7 +371,7 @@ iactions_list_iface_init( NactIActionsListInterface *iface )
g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
- iface->selection_changed = iactions_list_selection_changed;
+ iface->selection_changed = NULL;
iface->get_treeview_name = iactions_list_get_treeview_name;
}
@@ -542,6 +561,7 @@ instance_dispose( GObject *window )
nact_icommand_tab_dispose( NACT_ICOMMAND_TAB( window ));
nact_iconditions_tab_dispose( NACT_ICONDITIONS_TAB( window ));
nact_iadvanced_tab_dispose( NACT_IADVANCED_TAB( window ));
+ nact_main_menubar_dispose( self );
/* chain up to the parent class */
if( G_OBJECT_CLASS( st_parent_class )->dispose ){
@@ -890,6 +910,12 @@ on_base_runtime_init_toplevel( NactMainWindow *window, gpointer user_data )
if( !window->private->dispose_has_run ){
+ base_window_signal_connect(
+ BASE_WINDOW( window ),
+ G_OBJECT( window ),
+ IACTIONS_LIST_SIGNAL_SELECTION_CHANGED,
+ G_CALLBACK( on_iactions_list_selection_changed ));
+
application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
pivot = nact_application_get_pivot( application );
tree = na_pivot_get_items( pivot );
@@ -899,11 +925,11 @@ on_base_runtime_init_toplevel( NactMainWindow *window, gpointer user_data )
nact_icommand_tab_runtime_init_toplevel( NACT_ICOMMAND_TAB( window ));
nact_iconditions_tab_runtime_init_toplevel( NACT_ICONDITIONS_TAB( window ));
nact_iadvanced_tab_runtime_init_toplevel( NACT_IADVANCED_TAB( window ));
+ nact_main_menubar_runtime_init( window );
/* fill the IActionsList at last so that all signals are connected
*/
nact_iactions_list_runtime_init_toplevel( NACT_IACTIONS_LIST( window ), tree );
- nact_main_menubar_runtime_init( window );
/* forces a no-selection when the list is initially empty
*/
@@ -933,8 +959,6 @@ on_base_all_widgets_showed( NactMainWindow *window, gpointer user_data )
nact_icommand_tab_all_widgets_showed( NACT_ICOMMAND_TAB( window ));
nact_iconditions_tab_all_widgets_showed( NACT_ICONDITIONS_TAB( window ));
nact_iadvanced_tab_all_widgets_showed( NACT_IADVANCED_TAB( window ));
-
- nact_main_menubar_refresh_actions_sensitivity( window );
}
}
@@ -944,9 +968,9 @@ on_base_all_widgets_showed( NactMainWindow *window, gpointer user_data )
* @selected_items: the currently selected items in ActionsList
*/
static void
-iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
+on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
{
- static const gchar *thisfn = "nact_main_window_iactions_list_selection_changed";
+ static const gchar *thisfn = "nact_main_window_on_iactions_list_selection_changed";
NactMainWindow *window;
NAObject *object;
gint count;
diff --git a/src/nact/nact-main-window.h b/src/nact/nact-main-window.h
index 829013d..660b143 100644
--- a/src/nact/nact-main-window.h
+++ b/src/nact/nact-main-window.h
@@ -69,6 +69,8 @@ typedef struct {
}
NactMainWindowClass;
+#define MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES "main-window-update-sensitivities"
+
GType nact_main_window_get_type( void );
NactMainWindow *nact_main_window_new( BaseApplication *application );
diff --git a/src/nact/nact-marshal.list b/src/nact/nact-marshal.list
new file mode 100644
index 0000000..11ef833
--- /dev/null
+++ b/src/nact/nact-marshal.list
@@ -0,0 +1 @@
+VOID:INT,INT,INT
diff --git a/src/nact/nact-tree-model.c b/src/nact/nact-tree-model.c
index 1761dad..79e65ad 100644
--- a/src/nact/nact-tree-model.c
+++ b/src/nact/nact-tree-model.c
@@ -168,13 +168,6 @@ static void instance_finalize( GObject *application );
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, 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 );
static void remove_if_exists( NactTreeModel *model, GtkTreeModel *store, const NAObject *object );
static GList *add_parent( GList *parents, GtkTreeModel *store, GtkTreeIter *obj_iter );
@@ -733,316 +726,121 @@ fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview,
* nact_tree_model_insert:
* @model: this #NactTreeModel instance.
* @object: a #NAObject-derived object to be inserted.
- * @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.
+ * @path: the #GtkTreePath which specifies the insertion path.
+ * @parent: set to the parent or the object itself.
*
* Insert a new row at the given position.
*
- * Returns: the path string of the inserted row as a newly allocated
- * string. The returned path should be g_free() by the caller.
- *
- * +--------------------+----------------------+----------------------+----------------------+
- * | inserted object -> | action | profile | menu |
- * +--------------------+----------------------+----------------------+----------------------+
- * | currently selected | | | |
- * | | | | | |
- * | v | | | |
- * | (nil) | insert_before | n/a | insert_before |
- * | | | | |
- * | action | insert_before | insert_as_last_child | insert_before |
- * | | | | |
- * | profile | insert_before_parent | insert_before | insert_before_parent |
- * | | | | |
- * | menu | insert_before | n/a | insert_before |
- * | | insert_as_last_child | | insert_as_last_child |
- * +-----------------------------------------------------------------------------------------+
+ * Gtk API uses to returns iter ; but at least when inserting a new
+ * profile in an action, we may have store_iter_path="0:1" (good), but
+ * iter_path="0:0" (bad) - so we'd rather return a string path.
*
- * insert_before : parent=NULL , sibling_from_path (or null if path was null)
- * insert_before_parent: parent=NULL , sibling_from_parent_path
- * insert_as_last_child: parent_from_path, sibling=NULL
- *
- * Gtk API uses to returns iter ; but at least when inserting a new profile in an action, we
- * may have store_iter_path="0:1" (good), but iter_path="0:0" (bad) - so we return rather a
- * string path
+ * Note that we do not return anything here as the insertion path at
+ * the beginning of the function is always valid when the function
+ * returns; it points now to the newly inserted row.
*/
-gchar *
-nact_tree_model_insert( NactTreeModel *model,
- const NAObject *object,
- GtkTreePath *path,
- NAObject **obj_parent,
- gboolean inside )
+void
+nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **parent )
{
- static const gchar *thisfn = "nact_tree_model_insert";
- gchar *path_str = NULL;
+ /*static const gchar *thisfn = "nact_tree_model_insert";*/
GtkTreeModel *store;
- GtkTreeIter select_iter;
- NAObject *select_object;
+ GtkTreeIter iter;
GtkTreeIter parent_iter;
+ GtkTreePath *parent_path;
+ NAObject *parent_obj;
+ gboolean has_parent;
GtkTreeIter sibling_iter;
- GtkTreeIter store_iter;
- gboolean has_parent_iter;
- gboolean has_sibling_iter;
-
- path_str = path ? gtk_tree_path_to_string( path ) : NULL;
- g_debug( "%s: model=%p, object=%p (%s), path=%p (%s)",
- thisfn, ( void * ) model,
- ( void * ) object, G_OBJECT_TYPE_NAME( object ),
- ( void * ) path, path_str );
- g_free( path_str );
+ NAObject *sibling_obj;
+ gboolean has_sibling;
- g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), NULL );
- g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
+ g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+ g_return_if_fail( NA_IS_OBJECT( object ));
if( !model->private->dispose_has_run ){
store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
- has_parent_iter = FALSE;
- has_sibling_iter = FALSE;
- *obj_parent = NA_OBJECT( object );
+ has_parent = FALSE;
+ parent_obj = NULL;
+ sibling_obj = NULL;
remove_if_exists( model, store, object );
- if( path ){
- if( !gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &select_iter, path )){
- return( NULL );
- }
+ /* may be FALSE when store is empty */
+ has_sibling = gtk_tree_model_get_iter( store, &sibling_iter, path );
+ if( has_sibling ){
+ gtk_tree_model_get( store, &sibling_iter, IACTIONS_LIST_NAOBJECT_COLUMN, &sibling_obj, -1 );
+ g_object_unref( sibling_obj );
+ }
- gtk_tree_model_get( GTK_TREE_MODEL( model ), &select_iter, IACTIONS_LIST_NAOBJECT_COLUMN, &select_object, -1 );
+ if( gtk_tree_path_get_depth( path ) > 1 ){
- g_return_val_if_fail( select_object, NULL );
- g_return_val_if_fail( NA_IS_OBJECT( select_object ), NULL );
+ has_parent = TRUE;
+ parent_path = gtk_tree_path_copy( path );
+ gtk_tree_path_up( parent_path );
+ gtk_tree_model_get_iter( store, &parent_iter, parent_path );
+ gtk_tree_path_free( parent_path );
- 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, inside );
- }
+ gtk_tree_model_get( store, &parent_iter, IACTIONS_LIST_NAOBJECT_COLUMN, &parent_obj, -1 );
+ g_object_unref( parent_obj );
- 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, inside );
+ if( parent && !*parent ){
+ *parent = parent_obj;
}
- 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, inside );
+ if( has_sibling ){
+ na_object_insert_item( parent_obj, object, sibling_obj );
+ } else {
+ na_object_append_item( parent_obj, object );
}
-
- g_object_unref( select_object );
-
- } else {
- g_return_val_if_fail( NA_IS_OBJECT_ITEM( object ), NULL );
}
- gtk_tree_store_insert_before( GTK_TREE_STORE( store ), &store_iter, has_parent_iter ? &parent_iter : NULL, has_sibling_iter ? &sibling_iter : NULL );
- gtk_tree_store_set( GTK_TREE_STORE( store ), &store_iter, IACTIONS_LIST_NAOBJECT_COLUMN, object, -1 );
- display_item( GTK_TREE_STORE( store ), model->private->treeview, &store_iter, object );
-
- path_str = gtk_tree_model_get_string_from_iter( store, &store_iter );
+ gtk_tree_store_insert_before(
+ GTK_TREE_STORE( store ), &iter,
+ has_parent ? &parent_iter : NULL,
+ has_sibling ? &sibling_iter : NULL );
+ gtk_tree_store_set( GTK_TREE_STORE( store ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, object, -1 );
+ display_item( GTK_TREE_STORE( store ), model->private->treeview, &iter, object );
}
-
- return( path_str );
}
-/*
- * 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,
- gboolean inside )
-{
- gint count;
-
- g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
-
- /* (insert_before)
- * insert action before selected action
- * if selected action has a parent :
- * - set parent_object to parent of selected action
- * - add object to subitems of parent of selected action
- */
- if( NA_IS_OBJECT_ACTION( select_object )){
- insert_before_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
- }
-
- /* (insert_before_parent)
- * insert action before parent of selected profile
- * if parent of selected profile has itself a parent :
- * - set parent_object to parent of parent of selected profile
- * - add object to subitems of parent of parent of selected profile
- */
- if( NA_IS_OBJECT_PROFILE( select_object )){
- 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 )){
- 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 );
- }
- }
-}
-
-/*
- * 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,
- gboolean inside )
-{
- g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
-
- if( NA_IS_OBJECT_ACTION( select_object )){
- insert_as_last_child_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
- }
-
- if( NA_IS_OBJECT_PROFILE( select_object )){
- insert_before_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
- }
-
- if( NA_IS_OBJECT_MENU( select_object )){
- g_return_if_reached();
- }
-}
-
-/*
- * 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,
- gboolean inside )
-{
- gint count;
-
- g_return_if_fail( NA_IS_OBJECT_MENU( object ));
-
- if( NA_IS_OBJECT_ACTION( select_object )){
- insert_before_get_iters( model, select_path, object, parent_iter, has_parent_iter, sibling_iter, has_sibling_iter, parent_object );
- }
-
- if( NA_IS_OBJECT_PROFILE( select_object )){
- 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 )){
- 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 );
- }
- }
-}
-
-/*
- * insert an action or a menu when there is no current selection
- * insert an action or a menu when the selection is an action
- * insert a profile before a profile
- */
-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 )
+GtkTreePath *
+nact_tree_model_insert_into( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **parent )
{
- GtkTreePath *path;
+ static const gchar *thisfn = "nact_tree_model_insert_into";
+ GtkTreeModel *store;
GtkTreeIter iter;
- NAObject *sibling_obj;
+ GtkTreeIter parent_iter;
+ GtkTreePath *new_path;
+ gchar *path_str;
- g_debug( "nact_tree_model_insert_before_get_iters" );
+ g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), NULL );
+ g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
- gtk_tree_model_get_iter( model, sibling_iter, select_path );
- gtk_tree_model_get( model, sibling_iter, IACTIONS_LIST_NAOBJECT_COLUMN, &sibling_obj, -1 );
- *has_sibling_iter = TRUE;
+ new_path = NULL;
- if( gtk_tree_path_get_depth( select_path ) > 1 ){
- path = gtk_tree_path_copy( select_path );
- gtk_tree_path_up( path );
- gtk_tree_model_get_iter( model, &iter, path );
- gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, parent_object, -1 );
- g_return_if_fail( NA_IS_OBJECT_ITEM( *parent_object ));
- na_object_insert_item( *parent_object, object, sibling_obj );
- g_object_unref( *parent_object );
- gtk_tree_path_free( path );
- }
+ if( !model->private->dispose_has_run ){
- g_object_unref( sibling_obj );
-}
+ store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
-/*
- * insert an action or a menu when the selection is a profile
- */
-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 )
-{
- GtkTreePath *path;
- GtkTreeIter iter;
- NAObject *sibling_obj;
+ if( !gtk_tree_model_get_iter( store, &parent_iter, path )){
+ path_str = gtk_tree_path_to_string( path );
+ g_warning( "%s: unable to get iter at path %s", thisfn, path_str );
+ g_free( path_str );
+ return( NULL );
+ }
+ gtk_tree_model_get( store, &parent_iter, IACTIONS_LIST_NAOBJECT_COLUMN, parent, -1 );
+ g_object_unref( *parent );
- g_debug( "nact_tree_model_insert_before_parent_get_iters" );
+ na_object_insert_item( *parent, object, NULL );
- path = gtk_tree_path_copy( select_path );
- gtk_tree_path_up( path );
- gtk_tree_model_get_iter( model, sibling_iter, path );
- gtk_tree_model_get( model, sibling_iter, IACTIONS_LIST_NAOBJECT_COLUMN, &sibling_obj, -1 );
- *has_sibling_iter = TRUE;
+ gtk_tree_store_insert_after( GTK_TREE_STORE( store ), &iter, &parent_iter, NULL );
+ gtk_tree_store_set( GTK_TREE_STORE( store ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, object, -1 );
+ display_item( GTK_TREE_STORE( store ), model->private->treeview, &iter, object );
- if( gtk_tree_path_get_depth( path ) > 1 ){
- gtk_tree_path_up( path );
- gtk_tree_model_get_iter( model, &iter, path );
- gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, parent_object, -1 );
- g_return_if_fail( NA_IS_OBJECT_ITEM( *parent_object ));
- na_object_insert_item( *parent_object, object, sibling_obj );
- g_object_unref( *parent_object );
+ new_path = gtk_tree_model_get_path( store, &iter );
}
- g_object_unref( sibling_obj );
- gtk_tree_path_free( path );
-}
-
-/*
- * insert an action or a menu when the selection is a menu
- * insert a profile when the selection is an action
- */
-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 )
-{
- g_debug( "nact_tree_model_insert_as_last_child_get_iters" );
-
- gtk_tree_model_get_iter( model, parent_iter, select_path );
- *has_parent_iter = TRUE;
-
- gtk_tree_model_get( model, parent_iter, IACTIONS_LIST_NAOBJECT_COLUMN, parent_object, -1 );
- g_return_if_fail( NA_IS_OBJECT_ITEM( *parent_object ));
- na_object_append_item( *parent_object, object );
- g_object_unref( *parent_object );
+ return( new_path );
}
/*
@@ -1075,6 +873,35 @@ nact_tree_model_iter( NactTreeModel *model, FnIterOnStore fn, gpointer user_data
}
/**
+ * nact_tree_model_object_at_path:
+ * @model: this #NactTreeModel instance.
+ * @path: the #GtkTreePath to be searched.
+ *
+ * Returns: the #NAObject at the given @path if any, or NULL.
+ */
+NAObject *
+nact_tree_model_object_at_path( NactTreeModel *model, GtkTreePath *path )
+{
+ NAObject *object;
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), NULL );
+
+ object = NULL;
+
+ if( !model->private->dispose_has_run ){
+
+ 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 );
+ g_object_unref( object );
+ }
+
+ return( object );
+}
+
+/**
* nact_tree_model_remove:
* @model: this #NactTreeModel instance.
* @object: the #NAObject to be deleted.
@@ -1630,7 +1457,7 @@ idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, Gt
}
}
object_list = g_list_reverse( object_list );
- nact_iactions_list_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, dest, FALSE );
+ nact_iactions_list_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, dest );
if( !copy_data ){
nact_iactions_list_delete( NACT_IACTIONS_LIST( main_window ), object_list );
@@ -1675,7 +1502,7 @@ idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, Gt
} 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 );
+ nact_iactions_list_insert_at_path( NACT_IACTIONS_LIST( main_window ), object_list, dest );
g_list_free( object_list );
}
diff --git a/src/nact/nact-tree-model.h b/src/nact/nact-tree-model.h
index 781e918..9ea00ed 100644
--- a/src/nact/nact-tree-model.h
+++ b/src/nact/nact-tree-model.h
@@ -97,8 +97,10 @@ 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, gboolean inside );
+void nact_tree_model_insert( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **parent );
+GtkTreePath *nact_tree_model_insert_into( NactTreeModel *model, const NAObject *object, GtkTreePath *path, NAObject **parent );
void nact_tree_model_iter( NactTreeModel *model, FnIterOnStore fn, gpointer user_data );
+NAObject *nact_tree_model_object_at_path( NactTreeModel *model, GtkTreePath *path );
GtkTreePath *nact_tree_model_remove( NactTreeModel *model, NAObject *object );
G_END_DECLS
diff --git a/src/nact/nautilus-actions-config-tool.actions b/src/nact/nautilus-actions-config-tool.actions
index 2ef3596..4641274 100644
--- a/src/nact/nautilus-actions-config-tool.actions
+++ b/src/nact/nautilus-actions-config-tool.actions
@@ -13,6 +13,7 @@
<menuitem action="CutItem" />
<menuitem action="CopyItem" />
<menuitem action="PasteItem" />
+ <menuitem action="PasteIntoItem" />
<menuitem action="DuplicateItem" />
<menuitem action="DeleteItem" />
<separator />
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]