Convert NASettings to a private singleton
[nautilus-actions.git] / src / nact / nact-sort-buttons.c
blob4758707bff86673ccce332afaa9beb81d1c080dc
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, 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.
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 <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"
42 /* private class data
44 struct _NactSortButtonsClassPrivate {
45 void *empty; /* so that gcc -pedantic is happy */
48 struct _NactSortButtonsPrivate {
49 gboolean dispose_has_run;
50 BaseWindow *window;
51 NAUpdater *updater;
52 gboolean toggling;
53 gint active;
54 guint count_items;
57 typedef struct {
58 gchar *btn_name;
59 guint order_mode;
60 GtkToggleButton *button;
62 ToggleGroup;
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 },
68 { 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 );
90 GType
91 nact_sort_buttons_get_type( void )
93 static GType type = 0;
95 if( !type ){
96 type = register_type();
99 return( type );
102 static GType
103 register_type( void )
105 static const gchar *thisfn = "nact_sort_buttons_register_type";
106 GType type;
108 static GTypeInfo info = {
109 sizeof( NactSortButtonsClass ),
110 ( GBaseInitFunc ) NULL,
111 ( GBaseFinalizeFunc ) NULL,
112 ( GClassInitFunc ) class_init,
113 NULL,
114 NULL,
115 sizeof( NactSortButtons ),
117 ( GInstanceInitFunc ) instance_init
120 g_debug( "%s", thisfn );
122 type = g_type_register_static( G_TYPE_OBJECT, "NactSortButtons", &info, 0 );
124 return( type );
127 static void
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 );
144 static void
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;
165 static void
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 );
187 static void
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.
213 NactSortButtons *
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 );
236 return( obj );
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 :
246 * - all off,
247 * - connected to a toggle handler,
248 * - enabled (sensitive) if sort order mode is modifiable.
250 static void
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;
255 gint i;
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
282 static void
283 on_toggle_button_toggled( GtkToggleButton *toggled_button, BaseWindow *window )
285 NactSortButtons *sort_buttons;
286 gint i, ibtn;
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
306 } else {
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
331 static void
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;
336 guint order_mode;
337 gint ibtn;
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 );
360 static void
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 );
375 if( reset ){
376 sort_buttons->private->count_items = menus_count + actions_count;
377 } else {
378 sort_buttons->private->count_items += menus_count + actions_count;
381 enable_buttons( sort_buttons, sort_buttons->private->count_items > 0 );
386 static void
387 enable_buttons( const NactSortButtons *sort_buttons, gboolean enabled )
389 gboolean level_zero_writable;
390 gboolean preferences_locked;
391 gboolean finally_enabled;
392 gint i;
393 guint order_mode;
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
412 * or -1 if not found
414 static gint
415 toggle_group_get_from_mode( guint mode )
417 guint i;
419 for( i = 0 ; st_toggle_group[i].btn_name ; ++ i ){
420 if( st_toggle_group[i].order_mode == mode ){
421 return( i );
425 return( -1 );
429 * returns the index of the toggle button, or -1
431 static gint
432 toggle_group_get_from_button( GtkToggleButton *toggled_button )
434 gint i;
436 for( i = 0 ; st_toggle_group[i].btn_name ; ++i ){
437 if( st_toggle_group[i].button == toggled_button ){
438 return( i );
442 return( -1 );