README: add deprecation notice
[nautilus-actions.git] / src / ui / fma-add-capability-dialog.c
blob8ea044765230279e32f9167c7ed4cdf665809d78
1 /*
2 * FileManager-Actions
3 * A file-manager extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2015 Pierre Wieser and others (see AUTHORS)
9 * FileManager-Actions 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 * FileManager-Actions 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 GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with FileManager-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
23 * Authors:
24 * Frederic Ruaudel <grumz@grumz.net>
25 * Rodrigo Moya <rodrigo@gnome-db.org>
26 * Pierre Wieser <pwieser@trychlos.org>
27 * ... and many others (see AUTHORS)
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
34 #include <gdk/gdkkeysyms.h>
35 #include <glib/gi18n.h>
36 #include <libintl.h>
38 #include <api/fma-core-utils.h>
40 #include <core/fma-settings.h>
42 #include "fma-add-capability-dialog.h"
44 /* private class data
46 struct _FMAAddCapabilityDialogClassPrivate {
47 void *empty; /* so that gcc -pedantic is happy */
50 /* private instance data
52 struct _FMAAddCapabilityDialogPrivate {
53 gboolean dispose_has_run;
54 GSList *already_used;
55 gchar *capability;
58 /* column ordering in the model
60 enum {
61 CAPABILITY_KEYWORD_COLUMN = 0,
62 CAPABILITY_DESC_COLUMN,
63 CAPABILITY_ALREADY_USED_COLUMN,
64 CAPABILITY_N_COLUMN
67 typedef struct {
68 gchar *keyword;
69 gchar *desc;
71 CapabilityTextStruct;
73 static CapabilityTextStruct st_caps[] = {
74 { "Owner", N_( "User is the owner of the item" ) },
75 { "Readable", N_( "Item is readable by the user" ) },
76 { "Writable", N_( "Item is writable by the user" ) },
77 { "Executable", N_( "Item is executable by the user" ) },
78 { "Local", N_( "Item is local" ) },
79 { NULL },
82 static const gchar *st_xmlui_filename = PKGUIDIR "/fma-add-capability.ui";
83 static const gchar *st_toplevel_name = "AddCapabilityDialog";
84 static const gchar *st_wsp_name = IPREFS_CAPABILITY_ADD_CAPABILITY_WSP;
86 static GObjectClass *st_parent_class = NULL;
88 static GType register_type( void );
89 static void class_init( FMAAddCapabilityDialogClass *klass );
90 static void instance_init( GTypeInstance *instance, gpointer klass );
91 static void instance_constructed( GObject *dialog );
92 static void instance_dispose( GObject *dialog );
93 static void instance_finalize( GObject *dialog );
95 static void on_base_initialize_gtk( FMAAddCapabilityDialog *editor, GtkDialog *toplevel, gpointer user_data );
96 static void on_base_initialize_window( FMAAddCapabilityDialog *editor, gpointer user_data );
97 static void on_base_show_widgets( FMAAddCapabilityDialog *editor, gpointer user_data );
98 static gboolean on_button_press_event( GtkWidget *widget, GdkEventButton *event, FMAAddCapabilityDialog *editor );
99 static void on_cancel_clicked( GtkButton *button, FMAAddCapabilityDialog *editor );
100 static void on_ok_clicked( GtkButton *button, FMAAddCapabilityDialog *editor );
101 static void on_selection_changed( GtkTreeSelection *selection, BaseWindow *window );
102 static void display_keyword( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window );
103 static void display_description( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window );
104 static void display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window, guint column_id );
105 static gboolean setup_values_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter* iter, GSList *capabilities );
106 static void try_for_send_ok( FMAAddCapabilityDialog *dialog );
107 static void send_ok( FMAAddCapabilityDialog *dialog );
108 static void on_dialog_ok( BaseDialog *dialog );
110 GType
111 fma_add_capability_dialog_get_type( void )
113 static GType dialog_type = 0;
115 if( !dialog_type ){
116 dialog_type = register_type();
119 return( dialog_type );
122 static GType
123 register_type( void )
125 static const gchar *thisfn = "fma_add_capability_dialog_register_type";
126 GType type;
128 static GTypeInfo info = {
129 sizeof( FMAAddCapabilityDialogClass ),
130 ( GBaseInitFunc ) NULL,
131 ( GBaseFinalizeFunc ) NULL,
132 ( GClassInitFunc ) class_init,
133 NULL,
134 NULL,
135 sizeof( FMAAddCapabilityDialog ),
137 ( GInstanceInitFunc ) instance_init
140 g_debug( "%s", thisfn );
142 type = g_type_register_static( BASE_TYPE_DIALOG, "FMAAddCapabilityDialog", &info, 0 );
144 return( type );
147 static void
148 class_init( FMAAddCapabilityDialogClass *klass )
150 static const gchar *thisfn = "fma_add_capability_dialog_class_init";
151 GObjectClass *object_class;
152 BaseDialogClass *dialog_class;
154 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
156 st_parent_class = g_type_class_peek_parent( klass );
158 object_class = G_OBJECT_CLASS( klass );
159 object_class->constructed = instance_constructed;
160 object_class->dispose = instance_dispose;
161 object_class->finalize = instance_finalize;
163 klass->private = g_new0( FMAAddCapabilityDialogClassPrivate, 1 );
165 dialog_class = BASE_DIALOG_CLASS( klass );
166 dialog_class->ok = on_dialog_ok;
169 static void
170 instance_init( GTypeInstance *instance, gpointer klass )
172 static const gchar *thisfn = "fma_add_capability_dialog_instance_init";
173 FMAAddCapabilityDialog *self;
175 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( instance ));
177 g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
179 self = FMA_ADD_CAPABILITY_DIALOG( instance );
181 self->private = g_new0( FMAAddCapabilityDialogPrivate, 1 );
183 self->private->dispose_has_run = FALSE;
184 self->private->capability = NULL;
187 static void
188 instance_constructed( GObject *dialog )
190 static const gchar *thisfn = "fma_add_capability_dialog_instance_constructed";
191 FMAAddCapabilityDialogPrivate *priv;
193 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( dialog ));
195 priv = FMA_ADD_CAPABILITY_DIALOG( dialog )->private;
197 if( !priv->dispose_has_run ){
199 /* chain up to the parent class */
200 if( G_OBJECT_CLASS( st_parent_class )->constructed ){
201 G_OBJECT_CLASS( st_parent_class )->constructed( dialog );
204 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
206 base_window_signal_connect(
207 BASE_WINDOW( dialog ),
208 G_OBJECT( dialog ),
209 BASE_SIGNAL_INITIALIZE_GTK,
210 G_CALLBACK( on_base_initialize_gtk ));
212 base_window_signal_connect(
213 BASE_WINDOW( dialog ),
214 G_OBJECT( dialog ),
215 BASE_SIGNAL_INITIALIZE_WINDOW,
216 G_CALLBACK( on_base_initialize_window ));
218 base_window_signal_connect(
219 BASE_WINDOW( dialog ),
220 G_OBJECT( dialog ),
221 BASE_SIGNAL_SHOW_WIDGETS,
222 G_CALLBACK( on_base_show_widgets ));
226 static void
227 instance_dispose( GObject *dialog )
229 static const gchar *thisfn = "fma_add_capability_dialog_instance_dispose";
230 FMAAddCapabilityDialog *self;
231 GtkTreeView *listview;
232 GtkTreeModel *model;
233 GtkTreeSelection *selection;
235 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( dialog ));
237 self = FMA_ADD_CAPABILITY_DIALOG( dialog );
239 if( !self->private->dispose_has_run ){
240 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
242 self->private->dispose_has_run = TRUE;
244 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
245 model = gtk_tree_view_get_model( listview );
246 selection = gtk_tree_view_get_selection( listview );
247 gtk_tree_selection_unselect_all( selection );
248 gtk_list_store_clear( GTK_LIST_STORE( model ));
250 /* chain up to the parent class */
251 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
252 G_OBJECT_CLASS( st_parent_class )->dispose( dialog );
257 static void
258 instance_finalize( GObject *dialog )
260 static const gchar *thisfn = "fma_add_capability_dialog_instance_finalize";
261 FMAAddCapabilityDialog *self;
263 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( dialog ));
265 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
267 self = FMA_ADD_CAPABILITY_DIALOG( dialog );
269 fma_core_utils_slist_free( self->private->already_used );
270 g_free( self->private->capability );
272 g_free( self->private );
274 /* chain call to parent class */
275 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
276 G_OBJECT_CLASS( st_parent_class )->finalize( dialog );
281 * fma_add_capability_dialog_run:
282 * @parent: the BaseWindow parent of this dialog
283 * (usually the FMAMainWindow).
284 * @capabilities: list of already used capabilities.
286 * Initializes and runs the dialog.
288 * Returns: the selected capability, as a newly allocated string which should
289 * be g_free() by the caller, or NULL.
291 gchar *
292 fma_add_capability_dialog_run( FMAMainWindow *parent, GSList *capabilities )
294 static const gchar *thisfn = "fma_add_capability_dialog_run";
295 FMAAddCapabilityDialog *dialog;
296 gchar *capability;
298 g_debug( "%s: parent=%p", thisfn, ( void * ) parent );
300 g_return_val_if_fail( GTK_IS_APPLICATION_WINDOW( parent ), NULL );
302 dialog = g_object_new( FMA_TYPE_ADD_CAPABILITY_DIALOG,
303 BASE_PROP_MAIN_WINDOW, parent,
304 BASE_PROP_XMLUI_FILENAME, st_xmlui_filename,
305 BASE_PROP_TOPLEVEL_NAME, st_toplevel_name,
306 BASE_PROP_WSP_NAME, st_wsp_name,
307 NULL );
309 dialog->private->already_used = fma_core_utils_slist_duplicate( capabilities );
310 capability = NULL;
312 if( base_window_run( BASE_WINDOW( dialog )) == GTK_RESPONSE_OK ){
313 capability = g_strdup( dialog->private->capability );
316 g_object_unref( dialog );
318 return( capability );
321 static void
322 on_base_initialize_gtk( FMAAddCapabilityDialog *dialog, GtkDialog *toplevel, gpointer user_data )
324 static const gchar *thisfn = "fma_add_capability_dialog_on_base_initialize_gtk";
325 GtkTreeView *listview;
326 GtkTreeModel *model;
327 GtkTreeViewColumn *column;
328 GtkCellRenderer *text_cell;
329 GtkTreeSelection *selection;
331 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( dialog ));
333 if( !dialog->private->dispose_has_run ){
335 g_debug( "%s: dialog=%p, toplevel=%p, user_data=%p",
336 thisfn, ( void * ) dialog, ( void * ) toplevel, ( void * ) user_data );
338 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
340 model = GTK_TREE_MODEL( gtk_list_store_new( CAPABILITY_N_COLUMN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ));
341 gtk_tree_view_set_model( listview, GTK_TREE_MODEL( model ));
342 g_object_unref( model );
344 text_cell = gtk_cell_renderer_text_new();
345 column = gtk_tree_view_column_new_with_attributes(
346 "capability-keyword",
347 text_cell,
348 "text", CAPABILITY_KEYWORD_COLUMN,
349 NULL );
350 gtk_tree_view_append_column( listview, column );
351 gtk_tree_sortable_set_sort_column_id( GTK_TREE_SORTABLE( model ), CAPABILITY_KEYWORD_COLUMN, GTK_SORT_ASCENDING );
352 gtk_tree_view_column_set_cell_data_func(
353 column, text_cell, ( GtkTreeCellDataFunc ) display_keyword, dialog, NULL );
355 text_cell = gtk_cell_renderer_text_new();
356 column = gtk_tree_view_column_new_with_attributes(
357 "capability-description",
358 text_cell,
359 "text", CAPABILITY_DESC_COLUMN,
360 NULL );
361 gtk_tree_view_append_column( listview, column );
362 gtk_tree_view_column_set_cell_data_func(
363 column, text_cell, ( GtkTreeCellDataFunc ) display_description, dialog, NULL );
365 gtk_tree_view_set_headers_visible( listview, FALSE );
367 selection = gtk_tree_view_get_selection( listview );
368 gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
372 static void
373 on_base_initialize_window( FMAAddCapabilityDialog *dialog, gpointer user_data )
375 static const gchar *thisfn = "fma_add_capability_dialog_on_base_initialize_window";
376 GtkTreeView *listview;
377 GtkListStore *model;
378 GtkTreeIter row;
379 guint i;
381 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( dialog ));
383 if( !dialog->private->dispose_has_run ){
385 g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
387 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
388 model = GTK_LIST_STORE( gtk_tree_view_get_model( listview ));
390 for( i = 0 ; st_caps[i].keyword ; i = i+1 ){
391 gtk_list_store_append( model, &row );
392 gtk_list_store_set( model, &row,
393 CAPABILITY_KEYWORD_COLUMN, st_caps[i].keyword,
394 CAPABILITY_DESC_COLUMN, gettext( st_caps[i].desc ),
395 CAPABILITY_ALREADY_USED_COLUMN, FALSE,
396 -1 );
399 gtk_tree_model_foreach( GTK_TREE_MODEL( model ), ( GtkTreeModelForeachFunc ) setup_values_iter, dialog->private->already_used );
401 /* catch double-click */
402 base_window_signal_connect( BASE_WINDOW( dialog ),
403 G_OBJECT( listview ), "button-press-event", G_CALLBACK( on_button_press_event ));
405 base_window_signal_connect( BASE_WINDOW( dialog ),
406 G_OBJECT( gtk_tree_view_get_selection( listview )), "changed", G_CALLBACK( on_selection_changed ));
408 base_window_signal_connect_by_name( BASE_WINDOW( dialog ),
409 "CancelButton", "clicked", G_CALLBACK( on_cancel_clicked ));
411 base_window_signal_connect_by_name( BASE_WINDOW( dialog ),
412 "OKButton", "clicked", G_CALLBACK( on_ok_clicked ));
416 static void
417 on_base_show_widgets( FMAAddCapabilityDialog *dialog, gpointer user_data )
419 static const gchar *thisfn = "fma_add_capability_dialog_on_base_show_widgets";
420 GtkTreeView *listview;
421 GtkTreePath *path;
422 GtkTreeSelection *selection;
424 g_return_if_fail( FMA_IS_ADD_CAPABILITY_DIALOG( dialog ));
426 if( !dialog->private->dispose_has_run ){
428 g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
430 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
431 path = gtk_tree_path_new_first();
432 selection = gtk_tree_view_get_selection( listview );
433 gtk_tree_selection_select_path( selection, path );
434 gtk_tree_path_free( path );
438 static gboolean
439 on_button_press_event( GtkWidget *widget, GdkEventButton *event, FMAAddCapabilityDialog *dialog )
441 gboolean stop = FALSE;
443 /* double-click of left button */
444 if( event->type == GDK_2BUTTON_PRESS && event->button == 1 ){
445 try_for_send_ok( dialog );
446 stop = TRUE;
449 return( stop );
452 static void
453 on_cancel_clicked( GtkButton *button, FMAAddCapabilityDialog *dialog )
455 GtkWindow *toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( dialog ));
457 gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_CLOSE );
460 static void
461 on_ok_clicked( GtkButton *button, FMAAddCapabilityDialog *dialog )
463 send_ok( dialog );
466 static void
467 on_selection_changed( GtkTreeSelection *selection, BaseWindow *window )
469 GList *rows;
470 GtkTreeModel *model;
471 GtkTreePath *path;
472 GtkTreeIter iter;
473 gboolean used;
474 GtkWidget *button;
476 rows = gtk_tree_selection_get_selected_rows( selection, &model );
477 used = FALSE;
479 if( g_list_length( rows ) == 1 ){
480 path = ( GtkTreePath * ) rows->data;
481 gtk_tree_model_get_iter( model, &iter, path );
482 gtk_tree_model_get( model, &iter, CAPABILITY_ALREADY_USED_COLUMN, &used, -1 );
485 button = base_window_get_widget( window, "OKButton" );
486 gtk_widget_set_sensitive( button, !used );
489 static void
490 display_keyword( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window )
492 display_label( column, cell, model, iter, window, CAPABILITY_KEYWORD_COLUMN );
495 static void
496 display_description( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window )
498 display_label( column, cell, model, iter, window, CAPABILITY_DESC_COLUMN );
501 static void
502 display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window, guint column_id )
504 gboolean used;
506 gtk_tree_model_get( model, iter, CAPABILITY_ALREADY_USED_COLUMN, &used, -1 );
507 g_object_set( cell, "style-set", FALSE, NULL );
509 if( used ){
510 g_object_set( cell, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL );
514 static gboolean
515 setup_values_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter* iter, GSList *capabilities )
517 gchar *keyword;
518 gchar *description, *new_description;
520 gtk_tree_model_get( model, iter, CAPABILITY_KEYWORD_COLUMN, &keyword, CAPABILITY_DESC_COLUMN, &description, -1 );
522 if( fma_core_utils_slist_find_negated( capabilities, keyword )){
523 /* i18n: add a comment when a capability is already used by current item */
524 new_description = g_strdup_printf( _( "%s (already inserted)"), description );
525 gtk_list_store_set( GTK_LIST_STORE( model ), iter, CAPABILITY_DESC_COLUMN, new_description, CAPABILITY_ALREADY_USED_COLUMN, TRUE, -1 );
526 g_free( new_description );
529 g_free( description );
530 g_free( keyword );
532 return( FALSE ); /* don't stop looping */
535 static void
536 try_for_send_ok( FMAAddCapabilityDialog *dialog )
538 GtkWidget *button;
539 gboolean is_sensitive;
541 button = base_window_get_widget( BASE_WINDOW( dialog ), "OKButton" );
543 is_sensitive = gtk_widget_is_sensitive( button );
545 if( is_sensitive ){
546 send_ok( dialog );
550 static void
551 send_ok( FMAAddCapabilityDialog *dialog )
553 GtkWindow *toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( dialog ));
555 gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_OK );
558 static void
559 on_dialog_ok( BaseDialog *dialog )
561 FMAAddCapabilityDialog *editor;
562 GtkTreeView *listview;
563 GtkTreeSelection *selection;
564 GtkTreeModel *model;
565 GList *rows;
566 GtkTreePath *path;
567 GtkTreeIter iter;
569 editor = FMA_ADD_CAPABILITY_DIALOG( dialog );
571 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "CapabilitiesTreeView" ));
572 selection = gtk_tree_view_get_selection( listview );
573 rows = gtk_tree_selection_get_selected_rows( selection, &model );
575 if( g_list_length( rows ) == 1 ){
576 path = ( GtkTreePath * ) rows->data;
577 gtk_tree_model_get_iter( model, &iter, path );
578 gtk_tree_model_get( model, &iter, CAPABILITY_KEYWORD_COLUMN, &editor->private->capability, -1 );