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/>.
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)
34 #include <gdk/gdkkeysyms.h>
35 #include <glib/gi18n.h>
38 #include <api/fma-core-utils.h>
40 #include <core/fma-settings.h>
42 #include "fma-add-capability-dialog.h"
46 struct _FMAAddCapabilityDialogClassPrivate
{
47 void *empty
; /* so that gcc -pedantic is happy */
50 /* private instance data
52 struct _FMAAddCapabilityDialogPrivate
{
53 gboolean dispose_has_run
;
58 /* column ordering in the model
61 CAPABILITY_KEYWORD_COLUMN
= 0,
62 CAPABILITY_DESC_COLUMN
,
63 CAPABILITY_ALREADY_USED_COLUMN
,
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" ) },
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
);
111 fma_add_capability_dialog_get_type( void )
113 static GType dialog_type
= 0;
116 dialog_type
= register_type();
119 return( dialog_type
);
123 register_type( void )
125 static const gchar
*thisfn
= "fma_add_capability_dialog_register_type";
128 static GTypeInfo info
= {
129 sizeof( FMAAddCapabilityDialogClass
),
130 ( GBaseInitFunc
) NULL
,
131 ( GBaseFinalizeFunc
) NULL
,
132 ( GClassInitFunc
) class_init
,
135 sizeof( FMAAddCapabilityDialog
),
137 ( GInstanceInitFunc
) instance_init
140 g_debug( "%s", thisfn
);
142 type
= g_type_register_static( BASE_TYPE_DIALOG
, "FMAAddCapabilityDialog", &info
, 0 );
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
;
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
;
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
),
209 BASE_SIGNAL_INITIALIZE_GTK
,
210 G_CALLBACK( on_base_initialize_gtk
));
212 base_window_signal_connect(
213 BASE_WINDOW( dialog
),
215 BASE_SIGNAL_INITIALIZE_WINDOW
,
216 G_CALLBACK( on_base_initialize_window
));
218 base_window_signal_connect(
219 BASE_WINDOW( dialog
),
221 BASE_SIGNAL_SHOW_WIDGETS
,
222 G_CALLBACK( on_base_show_widgets
));
227 instance_dispose( GObject
*dialog
)
229 static const gchar
*thisfn
= "fma_add_capability_dialog_instance_dispose";
230 FMAAddCapabilityDialog
*self
;
231 GtkTreeView
*listview
;
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
);
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.
292 fma_add_capability_dialog_run( FMAMainWindow
*parent
, GSList
*capabilities
)
294 static const gchar
*thisfn
= "fma_add_capability_dialog_run";
295 FMAAddCapabilityDialog
*dialog
;
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
,
309 dialog
->private->already_used
= fma_core_utils_slist_duplicate( capabilities
);
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
);
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
;
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",
348 "text", CAPABILITY_KEYWORD_COLUMN
,
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",
359 "text", CAPABILITY_DESC_COLUMN
,
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
);
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
;
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
,
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
));
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
;
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
);
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
);
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
);
461 on_ok_clicked( GtkButton
*button
, FMAAddCapabilityDialog
*dialog
)
467 on_selection_changed( GtkTreeSelection
*selection
, BaseWindow
*window
)
476 rows
= gtk_tree_selection_get_selected_rows( selection
, &model
);
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
);
490 display_keyword( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
)
492 display_label( column
, cell
, model
, iter
, window
, CAPABILITY_KEYWORD_COLUMN
);
496 display_description( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
)
498 display_label( column
, cell
, model
, iter
, window
, CAPABILITY_DESC_COLUMN
);
502 display_label( GtkTreeViewColumn
*column
, GtkCellRenderer
*cell
, GtkTreeModel
*model
, GtkTreeIter
*iter
, BaseWindow
*window
, guint column_id
)
506 gtk_tree_model_get( model
, iter
, CAPABILITY_ALREADY_USED_COLUMN
, &used
, -1 );
507 g_object_set( cell
, "style-set", FALSE
, NULL
);
510 g_object_set( cell
, "style", PANGO_STYLE_ITALIC
, "style-set", TRUE
, NULL
);
515 setup_values_iter( GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
* iter
, GSList
*capabilities
)
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
);
532 return( FALSE
); /* don't stop looping */
536 try_for_send_ok( FMAAddCapabilityDialog
*dialog
)
539 gboolean is_sensitive
;
541 button
= base_window_get_widget( BASE_WINDOW( dialog
), "OKButton" );
543 is_sensitive
= gtk_widget_is_sensitive( button
);
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
);
559 on_dialog_ok( BaseDialog
*dialog
)
561 FMAAddCapabilityDialog
*editor
;
562 GtkTreeView
*listview
;
563 GtkTreeSelection
*selection
;
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 );