[nautilus-actions] Open a popup on right click in the treeview



commit b4717597cfab4b1ca066b9215307ba5b217bb8ff
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sun Oct 18 21:07:20 2009 +0200

    Open a popup on right click in the treeview

 ChangeLog                                     |   17 +++
 src/nact/nact-iactions-list.c                 |  145 ++++++++++++++++---------
 src/nact/nact-main-menubar.c                  |   26 +++++-
 src/nact/nact-main-menubar.h                  |    1 +
 src/nact/nautilus-actions-config-tool.actions |   19 ++++
 5 files changed, 155 insertions(+), 53 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e7ae1bd..0ffe0da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2009-10-18 Pierre Wieser <pwieser trychlos org>
+
+	Open a popup on right click on the treeview.
+
+	* src/nact/nact-iactions-list.c
+	(on_button_press_event): Manage right mouse click.
+	(open_popup): New function.
+	(on_key_pressed_event): Only manage acclerators when treeview has the
+	focus.
+
+	* src/nact/nact-main-menubar.c:
+	* src/nact/nact-main-menubar.h (nact_main_menubar_open_popup):
+	New function.
+
+	* src/nact/nautilus-actions-config-tool.actions:
+	Define the contextual popup menu.
+
 2009-10-17 Pierre Wieser <pwieser trychlos org>
 
 	* src/nact/nact-main-menubar.c (on_iactions_list_count_updated):
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 3eb99a3..94e6baa 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -41,8 +41,9 @@
 #include "nact-application.h"
 #include "nact-marshal.h"
 #include "nact-main-tab.h"
+#include "nact-main-menubar.h"
+#include "nact-main-window.h"
 #include "nact-tree-model.h"
-#include "nact-window.h"
 #include "nact-iactions-list.h"
 
 /* private interface data
@@ -174,13 +175,14 @@ static GtkTreePath *object_to_path( NactIActionsList *instance, NactTreeModel *m
 static gboolean     object_to_path_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, ObjectToPathIter *otp );
 static gboolean     on_button_press_event( GtkWidget *widget, GdkEventButton *event, NactIActionsList *instance );
 static void         on_edition_status_changed( NactIActionsList *instance, NAIDuplicable *object );
+static void         on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
 static gboolean     on_focus_in( GtkWidget *widget, GdkEventFocus *event, NactIActionsList *instance );
 static gboolean     on_focus_out( GtkWidget *widget, GdkEventFocus *event, NactIActionsList *instance );
 static gboolean     on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, NactIActionsList *instance );
 static void         on_label_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, NactIActionsList *instance );
-static void         on_treeview_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance );
 static void         on_tab_updatable_item_updated( NactIActionsList *instance, NAObject *object, gboolean force_display );
-static void         on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
+static void         on_treeview_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance );
+static void         open_popup( NactIActionsList *instance, GdkEventButton *event );
 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, IActionsListInstanceData *ialid );
@@ -1978,11 +1980,18 @@ on_button_press_event( GtkWidget *widget, GdkEventButton *event, NactIActionsLis
 
 	gboolean stop = FALSE;
 
-	if( event->type == GDK_2BUTTON_PRESS ){
+	/* double-click of left button */
+	if( event->type == GDK_2BUTTON_PRESS && event->button == 1 ){
 		toggle_collapse( instance );
 		stop = TRUE;
 	}
 
+	/* single click on right button */
+	if( event->type == GDK_BUTTON_PRESS && event->button == 3 ){
+		open_popup( instance, event );
+		stop = TRUE;
+	}
+
 	return( stop );
 }
 
@@ -2018,6 +2027,31 @@ on_edition_status_changed( NactIActionsList *instance, NAIDuplicable *object )
 	g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_STATUS_CHANGED, NULL );
 }
 
+/*
+ * our handler for "selection-changed" emitted by the interface
+ * this let us transform the signal in a virtual function
+ * so that our implementors have the best of two worlds ;-)
+ */
+static void
+on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
+{
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->selection_changed ){
+		NACT_IACTIONS_LIST_GET_INTERFACE( instance )->selection_changed( instance, selected_items );
+	}
+}
+
+/*
+ * focus is monitored to avoid an accelerator being pressed while on a tab
+ * triggers an unwaited operation on the list
+ * e.g. when editing an entry field on the tab, pressing Del should _not_
+ * delete current row in the list !
+ *
+ * this has the disadvantage that opening a popup menu makes the treeview
+ * loses its focus, and so the edit menu is all disabled
+ *
+ * to fix that, we consider in menubar that treeview always has the focus
+ * and we check it in on_key_pressed()
+ */
 static gboolean
 on_focus_in( GtkWidget *widget, GdkEventFocus *event, NactIActionsList *instance )
 {
@@ -2025,7 +2059,7 @@ on_focus_in( GtkWidget *widget, GdkEventFocus *event, NactIActionsList *instance
 	gboolean stop = FALSE;
 
 	/*g_debug( "%s: widget=%p, event=%p, instance=%p", thisfn, ( void * ) widget, ( void * ) event, ( void * ) instance );*/
-	g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_FOCUS_IN, instance );
+	/*g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_FOCUS_IN, instance );*/
 
 	return( stop );
 }
@@ -2037,7 +2071,7 @@ on_focus_out( GtkWidget *widget, GdkEventFocus *event, NactIActionsList *instanc
 	gboolean stop = FALSE;
 
 	/*g_debug( "%s: widget=%p, event=%p, instance=%p", thisfn, ( void * ) widget, ( void * ) event, ( void * ) instance );*/
-	g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_FOCUS_OUT, instance );
+	/*g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_FOCUS_OUT, instance );*/
 
 	return( stop );
 }
@@ -2047,27 +2081,31 @@ on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, NactIActionsList *i
 {
 	/*static const gchar *thisfn = "nact_iactions_list_v_on_key_pressed_event";
 	g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
-
+	GtkTreeView *treeview;
 	gboolean stop = FALSE;
 
-	if( event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ){
-		toggle_collapse( instance );
-		stop = TRUE;
-	}
+	treeview = get_actions_list_treeview( instance );
+	if( GTK_WIDGET_HAS_FOCUS( treeview )){
 
-	if( event->keyval == GDK_F2 ){
-		inline_edition( instance );
-		stop = TRUE;
-	}
+		if( event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ){
+			toggle_collapse( instance );
+			stop = TRUE;
+		}
 
-	if( event->keyval == GDK_Right ){
-		expand_to_first_child( instance );
-		stop = TRUE;
-	}
+		if( event->keyval == GDK_F2 ){
+			inline_edition( instance );
+			stop = TRUE;
+		}
 
-	if( event->keyval == GDK_Left ){
-		collapse_to_parent( instance );
-		stop = TRUE;
+		if( event->keyval == GDK_Right ){
+			expand_to_first_child( instance );
+			stop = TRUE;
+		}
+
+		if( event->keyval == GDK_Left ){
+			collapse_to_parent( instance );
+			stop = TRUE;
+		}
 	}
 
 	return( stop );
@@ -2100,6 +2138,32 @@ on_label_edited( GtkCellRendererText *renderer, const gchar *path_str, const gch
 }
 
 /*
+ * an item has been updated in one of the tabs
+ * update the treeview to reflects its new edition status
+ */
+static void
+on_tab_updatable_item_updated( NactIActionsList *instance, NAObject *object, gboolean force_display )
+{
+	static const gchar *thisfn = "nact_iactions_list_on_tab_updatable_item_updated";
+	GtkTreeView *treeview;
+	GtkTreeModel *model;
+
+	g_debug( "%s: instance=%p, object=%p (%s)", thisfn,
+			( void * ) instance, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
+	g_return_if_fail( NA_IS_OBJECT( object ));
+	g_return_if_fail( NA_IS_IDUPLICABLE( object ));
+
+	if( object ){
+		treeview = get_actions_list_treeview( instance );
+		model = gtk_tree_view_get_model( treeview );
+		if( !na_object_check_status_up( object ) && force_display ){
+			on_edition_status_changed( instance, NA_IDUPLICABLE( object ));
+		}
+	}
+}
+
+/*
  * this is our handler of "changed" signal emitted by the treeview
  * it is inhibited while filling the list (usually only at runtime init)
  * and while deleting a selection
@@ -2125,42 +2189,19 @@ on_treeview_selection_changed( GtkTreeSelection *selection, NactIActionsList *in
 	/* selection list if free in cleanup handler for the signal */
 }
 
-/*
- * an item has been updated in one of the tabs
- * update the treeview to reflects its new edition status
- */
 static void
-on_tab_updatable_item_updated( NactIActionsList *instance, NAObject *object, gboolean force_display )
+open_popup( NactIActionsList *instance, GdkEventButton *event )
 {
-	static const gchar *thisfn = "nact_iactions_list_on_tab_updatable_item_updated";
 	GtkTreeView *treeview;
 	GtkTreeModel *model;
+	GtkTreePath *path;
 
-	g_debug( "%s: instance=%p, object=%p (%s)", thisfn,
-			( void * ) instance, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
-	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
-	g_return_if_fail( NA_IS_OBJECT( object ));
-	g_return_if_fail( NA_IS_IDUPLICABLE( object ));
-
-	if( object ){
-		treeview = get_actions_list_treeview( instance );
+	treeview = get_actions_list_treeview( instance );
+	if( gtk_tree_view_get_path_at_pos( treeview, event->x, event->y, &path, NULL, NULL, NULL )){
 		model = gtk_tree_view_get_model( treeview );
-		if( !na_object_check_status_up( object ) && force_display ){
-			on_edition_status_changed( instance, NA_IDUPLICABLE( object ));
-		}
-	}
-}
-
-/*
- * our handler for "selection-changed" emitted by the interface
- * this let us transform the signal in a virtual function
- * so that our implementors have the best of two worlds ;-)
- */
-static void
-on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
-{
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->selection_changed ){
-		NACT_IACTIONS_LIST_GET_INTERFACE( instance )->selection_changed( instance, selected_items );
+		select_row_at_path( instance, treeview, model, path );
+		gtk_tree_path_free( path );
+		nact_main_menubar_open_popup( NACT_MAIN_WINDOW( instance ), event );
 	}
 }
 
diff --git a/src/nact/nact-main-menubar.c b/src/nact/nact-main-menubar.c
index 02a2c8c..dde5f59 100644
--- a/src/nact/nact-main-menubar.c
+++ b/src/nact/nact-main-menubar.c
@@ -259,7 +259,7 @@ nact_main_menubar_runtime_init( NactMainWindow *window )
 	 * - pack menu bar in the main window
 	 */
 	ui_manager = gtk_ui_manager_new();
-	g_object_set_data_full( G_OBJECT( window ), MENUBAR_PROP_UI_MANAGER, ui_manager, ( GDestroyNotify ) on_destroy_callback  );
+	g_object_set_data_full( G_OBJECT( window ), MENUBAR_PROP_UI_MANAGER, ui_manager, ( GDestroyNotify ) on_destroy_callback );
 	g_debug( "%s: ui_manager=%p", thisfn, ( void * ) ui_manager );
 
 	base_window_signal_connect(
@@ -368,6 +368,7 @@ nact_main_menubar_runtime_init( NactMainWindow *window )
 			G_CALLBACK( on_level_zero_order_changed ));
 
 	mis = g_new0( MenubarIndicatorsStruct, 1 );
+	mis->treeview_has_focus = TRUE;
 	g_object_set_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS, mis );
 }
 
@@ -390,6 +391,25 @@ nact_main_menubar_dispose( NactMainWindow *window )
 	g_free( mis );
 }
 
+/**
+ * nact_main_menubar_open_popup:
+ * @window: this #NactMainWindow window.
+ * @event: the mouse event.
+ *
+ * Opens a popup menu.
+ */
+void
+nact_main_menubar_open_popup( NactMainWindow *instance, GdkEventButton *event )
+{
+	GtkUIManager *ui_manager;
+	GtkWidget *menu;
+
+	ui_manager = ( GtkUIManager * ) g_object_get_data( G_OBJECT( instance ), MENUBAR_PROP_UI_MANAGER );
+	menu = gtk_ui_manager_get_widget( ui_manager, "/ui/Popup" );
+
+	gtk_menu_popup( GTK_MENU( menu ), NULL, NULL, NULL, NULL, event->button, event->time );
+}
+
 /*
  * when the IActionsList is refilled, update our internal counters so
  * that we are knowing if we have some exportables
@@ -439,6 +459,10 @@ on_iactions_list_selection_changed( NactMainWindow *window, GList *selected )
 	g_signal_emit_by_name( window, MAIN_WINDOW_SIGNAL_UPDATE_ACTION_SENSITIVITIES, NULL );
 }
 
+/*
+ * these two functions are no more used
+ * see comment in nact-iactions-list.c::on_focus_in().
+ */
 static void
 on_iactions_list_focus_in( NactMainWindow *window, gpointer user_data )
 {
diff --git a/src/nact/nact-main-menubar.h b/src/nact/nact-main-menubar.h
index d5815fd..e26a698 100644
--- a/src/nact/nact-main-menubar.h
+++ b/src/nact/nact-main-menubar.h
@@ -43,6 +43,7 @@ G_BEGIN_DECLS
 
 void  nact_main_menubar_runtime_init( NactMainWindow *window );
 void  nact_main_menubar_dispose( NactMainWindow *window );
+void  nact_main_menubar_open_popup( NactMainWindow *window, GdkEventButton *event );
 
 G_END_DECLS
 
diff --git a/src/nact/nautilus-actions-config-tool.actions b/src/nact/nautilus-actions-config-tool.actions
index 484fb40..812fe90 100644
--- a/src/nact/nautilus-actions-config-tool.actions
+++ b/src/nact/nautilus-actions-config-tool.actions
@@ -37,6 +37,25 @@
         </menu>
     </menubar>
 
+    <popup name="Popup">
+            <menuitem action="NewMenuItem" />
+            <menuitem action="NewActionItem" />
+            <menuitem action="NewProfileItem" />
+            <separator />
+            <menuitem action="CutItem" />
+            <menuitem action="CopyItem" />
+            <menuitem action="PasteItem" />
+            <menuitem action="PasteIntoItem" />
+            <menuitem action="DuplicateItem" />
+            <menuitem action="DeleteItem" />
+            <separator />
+            <menuitem action="ImportItem" />
+            <menuitem action="ExportItem" />
+            <separator />
+            <menuitem action="PreferencesItem" />
+            <menuitem action="AboutItem" />
+    </popup>
+
     <toolbar name="FileToolbar">
         <toolitem action="NewActionItem" />
         <toolitem action="SaveItem" />



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]