Change help menu item from Gtk default to Gnome (apparent) standard
[nautilus-actions.git] / src / nact / nact-add-capability-dialog.c
blobb8740e75b814dbe605f0a866725e5eaff6a095a7
1 /*
2 * Nautilus Actions
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.
24 * Authors:
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)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <gdk/gdkkeysyms.h>
36 #include <glib/gi18n.h>
38 #include <api/na-core-utils.h>
40 #include "nact-add-capability-dialog.h"
42 /* private class data
44 struct NactAddCapabilityDialogClassPrivate {
45 void *empty; /* so that gcc -pedantic is happy */
48 /* private instance data
50 struct NactAddCapabilityDialogPrivate {
51 gboolean dispose_has_run;
52 GSList *already_used;
53 gchar *capability;
56 /* column ordering in the model
58 enum {
59 CAPABILITY_KEYWORD_COLUMN = 0,
60 CAPABILITY_DESC_COLUMN,
61 CAPABILITY_ALREADY_USED_COLUMN,
62 CAPABILITY_N_COLUMN
65 typedef struct {
66 gchar *keyword;
67 gchar *desc;
69 CapabilityTextStruct;
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" ) },
77 { NULL },
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 );
109 GType
110 nact_add_capability_dialog_get_type( void )
112 static GType dialog_type = 0;
114 if( !dialog_type ){
115 dialog_type = register_type();
118 return( dialog_type );
121 static GType
122 register_type( void )
124 static const gchar *thisfn = "nact_add_capability_dialog_register_type";
125 GType type;
127 static GTypeInfo info = {
128 sizeof( NactAddCapabilityDialogClass ),
129 ( GBaseInitFunc ) NULL,
130 ( GBaseFinalizeFunc ) NULL,
131 ( GClassInitFunc ) class_init,
132 NULL,
133 NULL,
134 sizeof( NactAddCapabilityDialog ),
136 ( GInstanceInitFunc ) instance_init
139 g_debug( "%s", thisfn );
141 type = g_type_register_static( BASE_DIALOG_TYPE, "NactAddCapabilityDialog", &info, 0 );
143 return( type );
146 static void
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;
170 static void
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;
204 static void
205 instance_dispose( GObject *dialog )
207 static const gchar *thisfn = "nact_add_capability_dialog_instance_dispose";
208 NactAddCapabilityDialog *self;
209 GtkTreeView *listview;
210 GtkTreeModel *model;
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 );
234 static void
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.
278 gchar *
279 nact_add_capability_dialog_run( BaseWindow *parent, GSList *capabilities )
281 static const gchar *thisfn = "nact_add_capability_dialog_run";
282 NactAddCapabilityDialog *dialog;
283 gchar *capability;
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 );
301 static gchar *
302 base_get_iprefs_window_id( const BaseWindow *window )
304 return( g_strdup( "add-capability-dialog" ));
307 static gchar *
308 base_get_dialog_name( const BaseWindow *window )
310 return( g_strdup( "AddCapabilityDialog" ));
313 static gchar *
314 base_get_ui_filename( const BaseWindow *dialog )
316 return( g_strdup( PKGDATADIR "/nact-add-capability.ui" ));
319 static void
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;
324 GtkTreeModel *model;
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",
343 text_cell,
344 "text", CAPABILITY_KEYWORD_COLUMN,
345 NULL );
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",
354 text_cell,
355 "text", CAPABILITY_DESC_COLUMN,
356 NULL );
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 );
368 static void
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;
373 GtkListStore *model;
374 GtkTreeIter row;
375 guint i;
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,
391 -1 );
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 )),
406 "changed",
407 G_CALLBACK( on_selection_changed ));
409 base_window_signal_connect_by_name(
410 BASE_WINDOW( dialog ),
411 "CancelButton",
412 "clicked",
413 G_CALLBACK( on_cancel_clicked ));
415 base_window_signal_connect_by_name(
416 BASE_WINDOW( dialog ),
417 "OKButton",
418 "clicked",
419 G_CALLBACK( on_ok_clicked ));
423 static void
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;
428 GtkTreePath *path;
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 );
445 static gboolean
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 );
453 stop = TRUE;
456 return( stop );
459 static void
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 );
467 static void
468 on_ok_clicked( GtkButton *button, NactAddCapabilityDialog *dialog )
470 send_ok( dialog );
473 static void
474 on_selection_changed( GtkTreeSelection *selection, BaseWindow *window )
476 GList *rows;
477 GtkTreeModel *model;
478 GtkTreePath *path;
479 GtkTreeIter iter;
480 gboolean used;
481 GtkWidget *button;
483 rows = gtk_tree_selection_get_selected_rows( selection, &model );
484 used = FALSE;
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 );
496 static void
497 display_keyword( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window )
499 display_label( column, cell, model, iter, window, CAPABILITY_KEYWORD_COLUMN );
502 static void
503 display_description( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window )
505 display_label( column, cell, model, iter, window, CAPABILITY_DESC_COLUMN );
508 static void
509 display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window, guint column_id )
511 gboolean used;
513 gtk_tree_model_get( model, iter, CAPABILITY_ALREADY_USED_COLUMN, &used, -1 );
514 g_object_set( cell, "style-set", FALSE, NULL );
516 if( used ){
517 g_object_set( cell, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL );
521 static gboolean
522 setup_values_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter* iter, GSList *capabilities )
524 gchar *keyword;
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 );
537 g_free( keyword );
539 return( FALSE ); /* don't stop looping */
542 static void
543 try_for_send_ok( NactAddCapabilityDialog *dialog )
545 GtkWidget *button;
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 );
552 #else
553 is_sensitive = GTK_WIDGET_IS_SENSITIVE( button );
554 #endif
556 if( is_sensitive ){
557 send_ok( dialog );
561 static void
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 );
569 static void
570 validate_dialog( NactAddCapabilityDialog *dialog )
572 GtkTreeView *listview;
573 GtkTreeSelection *selection;
574 GtkTreeModel *model;
575 GList *rows;
576 GtkTreePath *path;
577 GtkTreeIter iter;
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 );
590 static gboolean
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 );
603 switch( code ){
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:
611 return( TRUE );
612 break;
616 return( FALSE );