3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
35 #include <gdk/gdkkeysyms.h>
36 #include <glib/gi18n.h>
38 #include <api/na-core-utils.h>
40 #include "nact-add-capability-dialog.h"
44 struct NactAddCapabilityDialogClassPrivate
{
45 void *empty
; /* so that gcc -pedantic is happy */
48 /* private instance data
50 struct NactAddCapabilityDialogPrivate
{
51 gboolean dispose_has_run
;
56 /* column ordering in the model
59 CAPABILITY_KEYWORD_COLUMN
= 0,
60 CAPABILITY_DESC_COLUMN
,
61 CAPABILITY_ALREADY_USED_COLUMN
,
71 static CapabilityTextStruct st_caps
[] = {
72 { "Owner", N_( "User is the owner of the item" ) },
73 { "Readable", N_( "Item is readable by the user" ) },
74 { "Writable", N_( "Item is writable by the user" ) },
75 { "Executable", N_( "Item is executable by the user" ) },
76 { "Local", N_( "Item is local" ) },
80 static GObjectClass
*st_parent_class
= NULL
;
82 static GType
register_type( void );
83 static void class_init( NactAddCapabilityDialogClass
*klass
);
84 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
85 static void instance_dispose( GObject
*dialog
);
86 static void instance_finalize( GObject
*dialog
);
88 static NactAddCapabilityDialog
*add_capability_dialog_new( BaseWindow
*parent
);
90 static gchar
*base_get_iprefs_window_id( const BaseWindow
*window
);
91 static gchar
*base_get_dialog_name( const BaseWindow
*window
);
92 static gchar
*base_get_ui_filename( const BaseWindow
*dialog
);
93 static void on_base_initial_load_dialog( NactAddCapabilityDialog
*editor
, gpointer user_data
);
94 static void on_base_runtime_init_dialog( NactAddCapabilityDialog
*editor
, gpointer user_data
);
95 static void on_base_all_widgets_showed( NactAddCapabilityDialog
*editor
, gpointer user_data
);
96 static gboolean
on_button_press_event( GtkWidget
*widget
, GdkEventButton
*event
, NactAddCapabilityDialog
*editor
);
97 static void on_cancel_clicked( GtkButton
*button
, NactAddCapabilityDialog
*editor
);
98 static void on_ok_clicked( GtkButton
*button
, NactAddCapabilityDialog
*editor
);
99 static void on_selection_changed( GtkTreeSelection
*selection
, BaseWindow
*window
);
100 static void display_keyword( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
);
101 static void display_description( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
);
102 static void display_label( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
, guint column_id
);
103 static gboolean
setup_values_iter( GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
* iter
, GSList
*capabilities
);
104 static void try_for_send_ok( NactAddCapabilityDialog
*dialog
);
105 static void send_ok( NactAddCapabilityDialog
*dialog
);
106 static void validate_dialog( NactAddCapabilityDialog
*editor
);
107 static gboolean
base_dialog_response( GtkDialog
*dialog
, gint code
, BaseWindow
*window
);
110 nact_add_capability_dialog_get_type( void )
112 static GType dialog_type
= 0;
115 dialog_type
= register_type();
118 return( dialog_type
);
122 register_type( void )
124 static const gchar
*thisfn
= "nact_add_capability_dialog_register_type";
127 static GTypeInfo info
= {
128 sizeof( NactAddCapabilityDialogClass
),
129 ( GBaseInitFunc
) NULL
,
130 ( GBaseFinalizeFunc
) NULL
,
131 ( GClassInitFunc
) class_init
,
134 sizeof( NactAddCapabilityDialog
),
136 ( GInstanceInitFunc
) instance_init
139 g_debug( "%s", thisfn
);
141 type
= g_type_register_static( BASE_DIALOG_TYPE
, "NactAddCapabilityDialog", &info
, 0 );
147 class_init( NactAddCapabilityDialogClass
*klass
)
149 static const gchar
*thisfn
= "nact_add_capability_dialog_class_init";
150 GObjectClass
*object_class
;
151 BaseWindowClass
*base_class
;
153 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
155 st_parent_class
= g_type_class_peek_parent( klass
);
157 object_class
= G_OBJECT_CLASS( klass
);
158 object_class
->dispose
= instance_dispose
;
159 object_class
->finalize
= instance_finalize
;
161 klass
->private = g_new0( NactAddCapabilityDialogClassPrivate
, 1 );
163 base_class
= BASE_WINDOW_CLASS( klass
);
164 base_class
->dialog_response
= base_dialog_response
;
165 base_class
->get_toplevel_name
= base_get_dialog_name
;
166 base_class
->get_iprefs_window_id
= base_get_iprefs_window_id
;
167 base_class
->get_ui_filename
= base_get_ui_filename
;
171 instance_init( GTypeInstance
*instance
, gpointer klass
)
173 static const gchar
*thisfn
= "nact_add_capability_dialog_instance_init";
174 NactAddCapabilityDialog
*self
;
176 g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( instance
));
177 g_debug( "%s: instance=%p, klass=%p", thisfn
, ( void * ) instance
, ( void * ) klass
);
178 self
= NACT_ADD_CAPABILITY_DIALOG( instance
);
180 self
->private = g_new0( NactAddCapabilityDialogPrivate
, 1 );
182 base_window_signal_connect(
183 BASE_WINDOW( instance
),
184 G_OBJECT( instance
),
185 BASE_WINDOW_SIGNAL_INITIAL_LOAD
,
186 G_CALLBACK( on_base_initial_load_dialog
));
188 base_window_signal_connect(
189 BASE_WINDOW( instance
),
190 G_OBJECT( instance
),
191 BASE_WINDOW_SIGNAL_RUNTIME_INIT
,
192 G_CALLBACK( on_base_runtime_init_dialog
));
194 base_window_signal_connect(
195 BASE_WINDOW( instance
),
196 G_OBJECT( instance
),
197 BASE_WINDOW_SIGNAL_ALL_WIDGETS_SHOWED
,
198 G_CALLBACK( on_base_all_widgets_showed
));
200 self
->private->dispose_has_run
= FALSE
;
201 self
->private->capability
= NULL
;
205 instance_dispose( GObject
*dialog
)
207 static const gchar
*thisfn
= "nact_add_capability_dialog_instance_dispose";
208 NactAddCapabilityDialog
*self
;
209 GtkTreeView
*listview
;
211 GtkTreeSelection
*selection
;
213 g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog
));
214 g_debug( "%s: dialog=%p", thisfn
, ( void * ) dialog
);
215 self
= NACT_ADD_CAPABILITY_DIALOG( dialog
);
217 if( !self
->private->dispose_has_run
){
219 self
->private->dispose_has_run
= TRUE
;
221 listview
= GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog
), "CapabilitiesTreeView" ));
222 model
= gtk_tree_view_get_model( listview
);
223 selection
= gtk_tree_view_get_selection( listview
);
224 gtk_tree_selection_unselect_all( selection
);
225 gtk_list_store_clear( GTK_LIST_STORE( model
));
227 /* chain up to the parent class */
228 if( G_OBJECT_CLASS( st_parent_class
)->dispose
){
229 G_OBJECT_CLASS( st_parent_class
)->dispose( dialog
);
235 instance_finalize( GObject
*dialog
)
237 static const gchar
*thisfn
= "nact_add_capability_dialog_instance_finalize";
238 NactAddCapabilityDialog
*self
;
240 g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog
));
241 g_debug( "%s: dialog=%p", thisfn
, ( void * ) dialog
);
242 self
= NACT_ADD_CAPABILITY_DIALOG( dialog
);
244 na_core_utils_slist_free( self
->private->already_used
);
245 g_free( self
->private->capability
);
247 g_free( self
->private );
249 /* chain call to parent class */
250 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
251 G_OBJECT_CLASS( st_parent_class
)->finalize( dialog
);
256 * Returns a newly allocated NactAddCapabilityDialog object.
258 * @parent: the BaseWindow parent of this dialog (usually, the main
259 * toplevel window of the application).
261 static NactAddCapabilityDialog
*
262 add_capability_dialog_new( BaseWindow
*parent
)
264 return( g_object_new( NACT_ADD_CAPABILITY_DIALOG_TYPE
, BASE_WINDOW_PROP_PARENT
, parent
, NULL
));
268 * nact_add_capability_dialog_run:
269 * @parent: the BaseWindow parent of this dialog
270 * (usually the NactMainWindow).
271 * @capabilities: list of already used capabilities.
273 * Initializes and runs the dialog.
275 * Returns: the selected capability, as a newly allocated string which should
276 * be g_free() by the caller, or NULL.
279 nact_add_capability_dialog_run( BaseWindow
*parent
, GSList
*capabilities
)
281 static const gchar
*thisfn
= "nact_add_capability_dialog_run";
282 NactAddCapabilityDialog
*dialog
;
285 g_debug( "%s: parent=%p", thisfn
, ( void * ) parent
);
287 g_return_val_if_fail( BASE_IS_WINDOW( parent
), NULL
);
289 dialog
= add_capability_dialog_new( parent
);
290 dialog
->private->already_used
= na_core_utils_slist_duplicate( capabilities
);
292 base_window_run( BASE_WINDOW( dialog
));
294 capability
= g_strdup( dialog
->private->capability
);
296 g_object_unref( dialog
);
298 return( capability
);
302 base_get_iprefs_window_id( const BaseWindow
*window
)
304 return( g_strdup( "add-capability-dialog" ));
308 base_get_dialog_name( const BaseWindow
*window
)
310 return( g_strdup( "AddCapabilityDialog" ));
314 base_get_ui_filename( const BaseWindow
*dialog
)
316 return( g_strdup( PKGDATADIR
"/nact-add-capability.ui" ));
320 on_base_initial_load_dialog( NactAddCapabilityDialog
*dialog
, gpointer user_data
)
322 static const gchar
*thisfn
= "nact_add_capability_dialog_on_initial_load_dialog";
323 GtkTreeView
*listview
;
325 GtkTreeViewColumn
*column
;
326 GtkCellRenderer
*text_cell
;
327 GtkTreeSelection
*selection
;
329 g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog
));
331 if( !dialog
->private->dispose_has_run
){
332 g_debug( "%s: dialog=%p, user_data=%p", thisfn
, ( void * ) dialog
, ( void * ) user_data
);
334 listview
= GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog
), "CapabilitiesTreeView" ));
336 model
= GTK_TREE_MODEL( gtk_list_store_new( CAPABILITY_N_COLUMN
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_BOOLEAN
));
337 gtk_tree_view_set_model( listview
, GTK_TREE_MODEL( model
));
338 g_object_unref( model
);
340 text_cell
= gtk_cell_renderer_text_new();
341 column
= gtk_tree_view_column_new_with_attributes(
342 "capability-keyword",
344 "text", CAPABILITY_KEYWORD_COLUMN
,
346 gtk_tree_view_append_column( listview
, column
);
347 gtk_tree_sortable_set_sort_column_id( GTK_TREE_SORTABLE( model
), CAPABILITY_KEYWORD_COLUMN
, GTK_SORT_ASCENDING
);
348 gtk_tree_view_column_set_cell_data_func(
349 column
, text_cell
, ( GtkTreeCellDataFunc
) display_keyword
, dialog
, NULL
);
351 text_cell
= gtk_cell_renderer_text_new();
352 column
= gtk_tree_view_column_new_with_attributes(
353 "capability-description",
355 "text", CAPABILITY_DESC_COLUMN
,
357 gtk_tree_view_append_column( listview
, column
);
358 gtk_tree_view_column_set_cell_data_func(
359 column
, text_cell
, ( GtkTreeCellDataFunc
) display_description
, dialog
, NULL
);
361 gtk_tree_view_set_headers_visible( listview
, FALSE
);
363 selection
= gtk_tree_view_get_selection( listview
);
364 gtk_tree_selection_set_mode( selection
, GTK_SELECTION_BROWSE
);
369 on_base_runtime_init_dialog( NactAddCapabilityDialog
*dialog
, gpointer user_data
)
371 static const gchar
*thisfn
= "nact_add_capability_dialog_on_runtime_init_dialog";
372 GtkTreeView
*listview
;
377 g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog
));
379 if( !dialog
->private->dispose_has_run
){
380 g_debug( "%s: dialog=%p, user_data=%p", thisfn
, ( void * ) dialog
, ( void * ) user_data
);
382 listview
= GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog
), "CapabilitiesTreeView" ));
383 model
= GTK_LIST_STORE( gtk_tree_view_get_model( listview
));
385 for( i
= 0 ; st_caps
[i
].keyword
; i
= i
+1 ){
386 gtk_list_store_append( model
, &row
);
387 gtk_list_store_set( model
, &row
,
388 CAPABILITY_KEYWORD_COLUMN
, st_caps
[i
].keyword
,
389 CAPABILITY_DESC_COLUMN
, st_caps
[i
].desc
,
390 CAPABILITY_ALREADY_USED_COLUMN
, FALSE
,
394 gtk_tree_model_foreach( GTK_TREE_MODEL( model
), ( GtkTreeModelForeachFunc
) setup_values_iter
, dialog
->private->already_used
);
396 /* catch double-click */
397 base_window_signal_connect(
398 BASE_WINDOW( dialog
),
399 G_OBJECT( listview
),
400 "button-press-event",
401 G_CALLBACK( on_button_press_event
));
403 base_window_signal_connect(
404 BASE_WINDOW( dialog
),
405 G_OBJECT( gtk_tree_view_get_selection( listview
)),
407 G_CALLBACK( on_selection_changed
));
409 base_window_signal_connect_by_name(
410 BASE_WINDOW( dialog
),
413 G_CALLBACK( on_cancel_clicked
));
415 base_window_signal_connect_by_name(
416 BASE_WINDOW( dialog
),
419 G_CALLBACK( on_ok_clicked
));
424 on_base_all_widgets_showed( NactAddCapabilityDialog
*dialog
, gpointer user_data
)
426 static const gchar
*thisfn
= "nact_add_capability_dialog_on_all_widgets_showed";
427 GtkTreeView
*listview
;
429 GtkTreeSelection
*selection
;
431 g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog
));
433 if( !dialog
->private->dispose_has_run
){
435 g_debug( "%s: dialog=%p, user_data=%p", thisfn
, ( void * ) dialog
, ( void * ) user_data
);
437 listview
= GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog
), "CapabilitiesTreeView" ));
438 path
= gtk_tree_path_new_first();
439 selection
= gtk_tree_view_get_selection( listview
);
440 gtk_tree_selection_select_path( selection
, path
);
441 gtk_tree_path_free( path
);
446 on_button_press_event( GtkWidget
*widget
, GdkEventButton
*event
, NactAddCapabilityDialog
*dialog
)
448 gboolean stop
= FALSE
;
450 /* double-click of left button */
451 if( event
->type
== GDK_2BUTTON_PRESS
&& event
->button
== 1 ){
452 try_for_send_ok( dialog
);
460 on_cancel_clicked( GtkButton
*button
, NactAddCapabilityDialog
*dialog
)
462 GtkWindow
*toplevel
= base_window_get_toplevel( BASE_WINDOW( dialog
));
464 gtk_dialog_response( GTK_DIALOG( toplevel
), GTK_RESPONSE_CLOSE
);
468 on_ok_clicked( GtkButton
*button
, NactAddCapabilityDialog
*dialog
)
474 on_selection_changed( GtkTreeSelection
*selection
, BaseWindow
*window
)
483 rows
= gtk_tree_selection_get_selected_rows( selection
, &model
);
486 if( g_list_length( rows
) == 1 ){
487 path
= ( GtkTreePath
* ) rows
->data
;
488 gtk_tree_model_get_iter( model
, &iter
, path
);
489 gtk_tree_model_get( model
, &iter
, CAPABILITY_ALREADY_USED_COLUMN
, &used
, -1 );
492 button
= base_window_get_widget( window
, "OKButton" );
493 gtk_widget_set_sensitive( button
, !used
);
497 display_keyword( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
)
499 display_label( column
, cell
, model
, iter
, window
, CAPABILITY_KEYWORD_COLUMN
);
503 display_description( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
)
505 display_label( column
, cell
, model
, iter
, window
, CAPABILITY_DESC_COLUMN
);
509 display_label( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
, guint column_id
)
513 gtk_tree_model_get( model
, iter
, CAPABILITY_ALREADY_USED_COLUMN
, &used
, -1 );
514 g_object_set( cell
, "style-set", FALSE
, NULL
);
517 g_object_set( cell
, "style", PANGO_STYLE_ITALIC
, "style-set", TRUE
, NULL
);
522 setup_values_iter( GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
* iter
, GSList
*capabilities
)
525 gchar
*description
, *new_description
;
527 gtk_tree_model_get( model
, iter
, CAPABILITY_KEYWORD_COLUMN
, &keyword
, CAPABILITY_DESC_COLUMN
, &description
, -1 );
529 if( na_core_utils_slist_find_negated( capabilities
, keyword
)){
530 /* i18n: add a comment when a capability is already used by current item */
531 new_description
= g_strdup_printf( _( "%s (already inserted)"), description
);
532 gtk_list_store_set( GTK_LIST_STORE( model
), iter
, CAPABILITY_DESC_COLUMN
, new_description
, CAPABILITY_ALREADY_USED_COLUMN
, TRUE
, -1 );
533 g_free( new_description
);
536 g_free( description
);
539 return( FALSE
); /* don't stop looping */
543 try_for_send_ok( NactAddCapabilityDialog
*dialog
)
546 gboolean is_sensitive
;
548 button
= base_window_get_widget( BASE_WINDOW( dialog
), "OKButton" );
550 #if(( GTK_MAJOR_VERSION > 2 ) || ( GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 18 ))
551 is_sensitive
= gtk_widget_is_sensitive( button
);
553 is_sensitive
= GTK_WIDGET_IS_SENSITIVE( button
);
562 send_ok( NactAddCapabilityDialog
*dialog
)
564 GtkWindow
*toplevel
= base_window_get_toplevel( BASE_WINDOW( dialog
));
566 gtk_dialog_response( GTK_DIALOG( toplevel
), GTK_RESPONSE_OK
);
570 validate_dialog( NactAddCapabilityDialog
*dialog
)
572 GtkTreeView
*listview
;
573 GtkTreeSelection
*selection
;
579 listview
= GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog
), "CapabilitiesTreeView" ));
580 selection
= gtk_tree_view_get_selection( listview
);
581 rows
= gtk_tree_selection_get_selected_rows( selection
, &model
);
583 if( g_list_length( rows
) == 1 ){
584 path
= ( GtkTreePath
* ) rows
->data
;
585 gtk_tree_model_get_iter( model
, &iter
, path
);
586 gtk_tree_model_get( model
, &iter
, CAPABILITY_KEYWORD_COLUMN
, &dialog
->private->capability
, -1 );
591 base_dialog_response( GtkDialog
*dialog_box
, gint code
, BaseWindow
*window
)
593 static const gchar
*thisfn
= "nact_add_capability_dialog_on_dialog_response";
594 NactAddCapabilityDialog
*dialog
;
596 g_return_val_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( window
), FALSE
);
598 dialog
= NACT_ADD_CAPABILITY_DIALOG( window
);
600 if( !dialog
->private->dispose_has_run
){
601 g_debug( "%s: dialog_box=%p, code=%d, window=%p", thisfn
, ( void * ) dialog_box
, code
, ( void * ) window
);
604 case GTK_RESPONSE_OK
:
605 validate_dialog( dialog
);
607 case GTK_RESPONSE_NONE
:
608 case GTK_RESPONSE_DELETE_EVENT
:
609 case GTK_RESPONSE_CLOSE
:
610 case GTK_RESPONSE_CANCEL
: