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, 2011 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 <core/na-iprefs.h>
36 #include <core/na-updater.h>
38 #include "nact-application.h"
39 #include "nact-sort-buttons.h"
40 #include "nact-tree-view.h"
44 struct _NactSortButtonsClassPrivate
{
45 void *empty
; /* so that gcc -pedantic is happy */
48 struct _NactSortButtonsPrivate
{
49 gboolean dispose_has_run
;
60 GtkToggleButton
*button
;
64 static ToggleGroup st_toggle_group
[] = {
65 { "SortManualButton", IPREFS_ORDER_MANUAL
, NULL
},
66 { "SortUpButton", IPREFS_ORDER_ALPHA_ASCENDING
, NULL
},
67 { "SortDownButton", IPREFS_ORDER_ALPHA_DESCENDING
, NULL
},
71 #define WINDOW_DATA_SORT_BUTTONS "window-data-sort-buttons"
73 static GObjectClass
*st_parent_class
= NULL
;
75 static GType
register_type( void );
76 static void class_init( NactSortButtonsClass
*klass
);
77 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
78 static void instance_dispose( GObject
*application
);
79 static void instance_finalize( GObject
*application
);
81 static void on_base_initialize_buttons( BaseWindow
*window
, gpointer user_data
);
82 static void on_toggle_button_toggled( GtkToggleButton
*button
, BaseWindow
*window
);
83 static void on_settings_order_mode_changed( const gchar
*group
, const gchar
*key
, gconstpointer new_value
, gboolean mandatory
, NactSortButtons
*sort_buttons
);
84 static void on_tree_view_count_changed( BaseWindow
*window
, gboolean reset
, gint menus_count
, gint actions_count
, gint profiles_count
, gpointer user_data
);
86 static void enable_buttons( const NactSortButtons
*sort_buttons
, gboolean enabled
);
87 static gint
toggle_group_get_from_mode( guint mode
);
88 static gint
toggle_group_get_from_button( GtkToggleButton
*toggled_button
);
91 nact_sort_buttons_get_type( void )
93 static GType type
= 0;
96 type
= register_type();
103 register_type( void )
105 static const gchar
*thisfn
= "nact_sort_buttons_register_type";
108 static GTypeInfo info
= {
109 sizeof( NactSortButtonsClass
),
110 ( GBaseInitFunc
) NULL
,
111 ( GBaseFinalizeFunc
) NULL
,
112 ( GClassInitFunc
) class_init
,
115 sizeof( NactSortButtons
),
117 ( GInstanceInitFunc
) instance_init
120 g_debug( "%s", thisfn
);
122 type
= g_type_register_static( G_TYPE_OBJECT
, "NactSortButtons", &info
, 0 );
128 class_init( NactSortButtonsClass
*klass
)
130 static const gchar
*thisfn
= "nact_sort_buttons_class_init";
131 GObjectClass
*object_class
;
133 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
135 st_parent_class
= g_type_class_peek_parent( klass
);
137 object_class
= G_OBJECT_CLASS( klass
);
138 object_class
->dispose
= instance_dispose
;
139 object_class
->finalize
= instance_finalize
;
141 klass
->private = g_new0( NactSortButtonsClassPrivate
, 1 );
145 instance_init( GTypeInstance
*instance
, gpointer klass
)
147 static const gchar
*thisfn
= "nact_sort_buttons_instance_init";
148 NactSortButtons
*self
;
150 g_return_if_fail( NACT_IS_SORT_BUTTONS( instance
));
152 g_debug( "%s: instance=%p (%s), klass=%p",
153 thisfn
, ( void * ) instance
, G_OBJECT_TYPE_NAME( instance
), ( void * ) klass
);
155 self
= NACT_SORT_BUTTONS( instance
);
157 self
->private = g_new0( NactSortButtonsPrivate
, 1 );
159 self
->private->dispose_has_run
= FALSE
;
160 self
->private->toggling
= FALSE
;
161 self
->private->active
= -1;
162 self
->private->count_items
= 0;
166 instance_dispose( GObject
*object
)
168 static const gchar
*thisfn
= "nact_sort_buttons_instance_dispose";
169 NactSortButtons
*self
;
171 g_return_if_fail( NACT_IS_SORT_BUTTONS( object
));
173 self
= NACT_SORT_BUTTONS( object
);
175 if( !self
->private->dispose_has_run
){
176 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
178 self
->private->dispose_has_run
= TRUE
;
180 /* chain up to the parent class */
181 if( G_OBJECT_CLASS( st_parent_class
)->dispose
){
182 G_OBJECT_CLASS( st_parent_class
)->dispose( object
);
188 instance_finalize( GObject
*instance
)
190 static const gchar
*thisfn
= "nact_sort_buttons_instance_finalize";
191 NactSortButtons
*self
;
193 g_return_if_fail( NACT_IS_SORT_BUTTONS( instance
));
195 g_debug( "%s: instance=%p (%s)", thisfn
, ( void * ) instance
, G_OBJECT_TYPE_NAME( instance
));
197 self
= NACT_SORT_BUTTONS( instance
);
199 g_free( self
->private );
201 /* chain call to parent class */
202 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
203 G_OBJECT_CLASS( st_parent_class
)->finalize( instance
);
208 * nact_sort_buttons_new:
209 * @window: the main window.
211 * Returns: a new #NactSortButtons object.
214 nact_sort_buttons_new( BaseWindow
*window
)
216 NactSortButtons
*obj
;
217 NactApplication
*application
;
219 g_return_val_if_fail( BASE_IS_WINDOW( window
), NULL
);
221 obj
= g_object_new( NACT_SORT_BUTTONS_TYPE
, NULL
);
223 base_window_signal_connect( window
,
224 G_OBJECT( window
), BASE_SIGNAL_INITIALIZE_WINDOW
, G_CALLBACK( on_base_initialize_buttons
));
226 base_window_signal_connect( window
,
227 G_OBJECT( window
), TREE_SIGNAL_COUNT_CHANGED
, G_CALLBACK( on_tree_view_count_changed
));
229 g_object_set_data( G_OBJECT( window
), WINDOW_DATA_SORT_BUTTONS
, obj
);
231 obj
->private->window
= window
;
233 application
= NACT_APPLICATION( base_window_get_application( window
));
234 obj
->private->updater
= nact_application_get_updater( application
);
240 * on_base_initialize_buttons:
241 * @window: the #BaseWindow.
243 * Initialization of the UI each time it is displayed.
245 * At end, buttons are all :
247 * - connected to a toggle handler,
248 * - enabled (sensitive) if sort order mode is modifiable.
251 on_base_initialize_buttons( BaseWindow
*window
, gpointer user_data
)
253 static const gchar
*thisfn
= "nact_sort_buttons_on_base_initialize_buttons";
254 NactSortButtons
*sort_buttons
;
257 g_return_if_fail( BASE_IS_WINDOW( window
));
259 g_debug( "%s: window=%p, user_data=%p", thisfn
, ( void * ) window
, ( void * ) user_data
);
261 sort_buttons
= NACT_SORT_BUTTONS( g_object_get_data( G_OBJECT( window
), WINDOW_DATA_SORT_BUTTONS
));
263 for( i
= 0 ; st_toggle_group
[i
].btn_name
; ++i
){
264 st_toggle_group
[i
].button
=
265 GTK_TOGGLE_BUTTON( base_window_get_widget( window
, st_toggle_group
[i
].btn_name
));
266 base_window_signal_connect( window
,
267 G_OBJECT( st_toggle_group
[i
].button
), "toggled", G_CALLBACK( on_toggle_button_toggled
));
270 na_settings_register_key_callback(
271 NA_IPREFS_ITEMS_LIST_ORDER_MODE
, G_CALLBACK( on_settings_order_mode_changed
), sort_buttons
);
273 /* for now, disable the sort buttons
274 * they will be enabled as soon as we receive the count of displayed items
276 enable_buttons( sort_buttons
, FALSE
);
280 * if the user re-clicks on the already active buttons, reset it active
283 on_toggle_button_toggled( GtkToggleButton
*toggled_button
, BaseWindow
*window
)
285 NactSortButtons
*sort_buttons
;
288 g_return_if_fail( BASE_IS_WINDOW( window
));
290 sort_buttons
= NACT_SORT_BUTTONS( g_object_get_data( G_OBJECT( window
), WINDOW_DATA_SORT_BUTTONS
));
292 if( !sort_buttons
->private->dispose_has_run
){
293 if( !sort_buttons
->private->toggling
){
295 sort_buttons
->private->toggling
= TRUE
;
296 ibtn
= toggle_group_get_from_button( toggled_button
);
298 /* the user re-clicks on the already active button
299 * do not let it becomes false, but keep it active
301 if( ibtn
== sort_buttons
->private->active
){
302 gtk_toggle_button_set_active( st_toggle_group
[ibtn
].button
, TRUE
);
304 /* reset all buttons to false, then the clicked one to active
307 for( i
= 0 ; st_toggle_group
[i
].btn_name
; ++i
){
308 gtk_toggle_button_set_active( st_toggle_group
[i
].button
, FALSE
);
310 gtk_toggle_button_set_active( toggled_button
, TRUE
);
311 sort_buttons
->private->active
= ibtn
;
312 na_iprefs_set_order_mode( st_toggle_group
[ibtn
].order_mode
);
315 sort_buttons
->private->toggling
= FALSE
;
321 * NASettings callback for a change on NA_IPREFS_ITEMS_LIST_ORDER_MODE key
323 * activate the button corresponding to the new sort order
324 * desactivate the previous button
325 * do nothing if new button and previous button are the sames
327 * testing 'toggling' is useless here because NASettings slightly delay the
328 * notifications: when we toggle a button, and update the settings, then
329 * we already have reset 'toggling' to FALSE when we are coming here
332 on_settings_order_mode_changed( const gchar
*group
, const gchar
*key
, gconstpointer new_value
, gboolean mandatory
, NactSortButtons
*sort_buttons
)
334 static const gchar
*thisfn
= "nact_sort_buttons_on_settings_order_mode_changed";
335 const gchar
*order_mode_str
;
339 g_return_if_fail( NACT_IS_SORT_BUTTONS( sort_buttons
));
341 if( !sort_buttons
->private->dispose_has_run
){
343 order_mode_str
= ( const gchar
* ) new_value
;
344 order_mode
= na_iprefs_get_order_mode_by_label( order_mode_str
);
346 g_debug( "%s: group=%s, key=%s, order_mode=%u (%s), mandatory=%s, sort_buttons=%p (%s)",
347 thisfn
, group
, key
, order_mode
, order_mode_str
,
348 mandatory
? "True":"False", ( void * ) sort_buttons
, G_OBJECT_TYPE_NAME( sort_buttons
));
350 ibtn
= toggle_group_get_from_mode( order_mode
);
351 g_return_if_fail( ibtn
>= 0 );
353 if( sort_buttons
->private->active
== -1 || ibtn
!= sort_buttons
->private->active
){
354 sort_buttons
->private->active
= ibtn
;
355 gtk_toggle_button_set_active( st_toggle_group
[ibtn
].button
, TRUE
);
361 on_tree_view_count_changed( BaseWindow
*window
, gboolean reset
, gint menus_count
, gint actions_count
, gint profiles_count
, gpointer user_data
)
363 static const gchar
*thisfn
= "nact_sort_buttons_on_tree_view_count_changed";
364 NactSortButtons
*sort_buttons
;
366 g_return_if_fail( BASE_IS_WINDOW( window
));
368 sort_buttons
= NACT_SORT_BUTTONS( g_object_get_data( G_OBJECT( window
), WINDOW_DATA_SORT_BUTTONS
));
370 if( !sort_buttons
->private->dispose_has_run
){
371 g_debug( "%s: window=%p, reset=%s, nb_menus=%d, nb_actions=%d, nb_profiles=%d, user_data=%p",
372 thisfn
, ( void * ) window
, reset
? "True":"False",
373 menus_count
, actions_count
, profiles_count
, ( void * ) user_data
);
376 sort_buttons
->private->count_items
= menus_count
+ actions_count
;
378 sort_buttons
->private->count_items
+= menus_count
+ actions_count
;
381 enable_buttons( sort_buttons
, sort_buttons
->private->count_items
> 0 );
387 enable_buttons( const NactSortButtons
*sort_buttons
, gboolean enabled
)
389 gboolean level_zero_writable
;
390 gboolean preferences_locked
;
391 gboolean finally_enabled
;
395 level_zero_writable
= na_updater_is_level_zero_writable( sort_buttons
->private->updater
);
396 preferences_locked
= na_updater_are_preferences_locked( sort_buttons
->private->updater
);
397 finally_enabled
= level_zero_writable
&& !preferences_locked
&& enabled
;
399 for( i
=0 ; st_toggle_group
[i
].btn_name
; ++i
){
400 gtk_widget_set_sensitive( GTK_WIDGET( st_toggle_group
[i
].button
), finally_enabled
);
403 if( finally_enabled
&& sort_buttons
->private->active
== -1 ){
404 order_mode
= na_iprefs_get_order_mode( NULL
);
405 i
= toggle_group_get_from_mode( order_mode
);
406 gtk_toggle_button_set_active( st_toggle_group
[i
].button
, TRUE
);
411 * returns the index of the button for the given order mode
415 toggle_group_get_from_mode( guint mode
)
419 for( i
= 0 ; st_toggle_group
[i
].btn_name
; ++ i
){
420 if( st_toggle_group
[i
].order_mode
== mode
){
429 * returns the index of the toggle button, or -1
432 toggle_group_get_from_button( GtkToggleButton
*toggled_button
)
436 for( i
= 0 ; st_toggle_group
[i
].btn_name
; ++i
){
437 if( st_toggle_group
[i
].button
== toggled_button
){