1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
4 *
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8 *
9 * Nautilus-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.
13 *
14 * Nautilus-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.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Nautilus-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
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)
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <glib/gi18n.h>
35 #include <stdlib.h>
36
37 #include <api/na-object-api.h>
38 #include <api/na-timeout.h>
39
40 #include <core/na-iprefs.h>
41 #include <core/na-pivot.h>
42
43 #include "base-isession.h"
44 #include "nact-iaction-tab.h"
45 #include "nact-icommand-tab.h"
46 #include "nact-ibasenames-tab.h"
47 #include "nact-imimetypes-tab.h"
48 #include "nact-ifolders-tab.h"
49 #include "nact-ischemes-tab.h"
50 #include "nact-icapabilities-tab.h"
51 #include "nact-ienvironment-tab.h"
52 #include "nact-iexecution-tab.h"
53 #include "nact-iproperties-tab.h"
54 #include "nact-main-tab.h"
55 #include "nact-main-statusbar.h"
56 #include "nact-main-window.h"
57 #include "nact-marshal.h"
58 #include "nact-menubar.h"
59 #include "nact-tree-view.h"
60 #include "nact-confirm-logout.h"
61 #include "nact-sort-buttons.h"
62
63 /* private class data
64 */
65 struct _NactMainWindowClassPrivate {
66 void *empty; /* so that gcc -pedantic is happy */
67 };
68
69 /* private instance data
70 */
71 struct _NactMainWindowPrivate {
72 gboolean dispose_has_run;
73
74 NAUpdater *updater;
75
76 /**
77 * Current action or menu.
78 *
79 * This is the action or menu which is displayed in tabs Action/Menu
80 * and Properties ; it may be different of the exact row being currently
81 * selected, e.g. when a sub-profile is edited.
82 *
83 * Can be null, and this implies that @current_profile is also null,
84 * e.g. when the list is empty or in the case of a multiple selection.
85 *
86 * 'editable' property is set on selection change;
87 * This is the actual current writability status of the item at this time.
88 */
89 NAObjectItem *current_item;
90 gboolean editable;
91 guint reason;
92
93 /**
94 * Current profile.
95 *
96 * This is the profile which is displayed in tab Command;
97 * it may be different of the exact row being currently selected,
98 * e.g. when an action with only one profile is selected.
99 *
100 * Can be null if @current_item is a menu, or an action with more
101 * than one profile is selected, or the list is empty, or in the
102 * case of a multiple selection.
103 *
104 * In other words, it is not null if:
105 * a) a profile is selected,
106 * b) an action is selected and it has exactly one profile.
107 */
108 NAObjectProfile *current_profile;
109
110 /**
111 * Current context.
112 *
113 * This is the #NAIContext data which corresponds to @current_profile
114 * or @current_item, depending of which one is actually selected.
115 */
116 NAIContext *current_context;
117
118 /**
119 * Some convenience objects and data.
120 */
121 NactTreeView *items_view;
122 gboolean is_tree_modified;
123 NactClipboard *clipboard;
124 NactMenubar *menubar;
125
126 gulong pivot_handler_id;
127 NATimeout pivot_timeout;
128 };
129
130 /* properties set against the main window
131 * these are set on selection changes
132 */
133 enum {
134 MAIN_PROP_0 = 0,
135
136 MAIN_PROP_ITEM_ID,
137 MAIN_PROP_PROFILE_ID,
138 MAIN_PROP_CONTEXT_ID,
139 MAIN_PROP_EDITABLE_ID,
140 MAIN_PROP_REASON_ID,
141
142 MAIN_PROP_N_PROPERTIES
143 };
144
145 /* signals
146 */
147 enum {
148 MAIN_ITEM_UPDATED,
149 TAB_ITEM_UPDATED,
150 SELECTION_CHANGED,
151 CONTEXT_MENU,
152 LAST_SIGNAL
153 };
154
155 static const gchar *st_xmlui_filename = PKGUIDIR "/nautilus-actions-config-tool.ui";
156 static const gchar *st_toplevel_name = "MainWindow";
157 static const gchar *st_wsp_name = NA_IPREFS_MAIN_WINDOW_WSP;
158
159 static gint st_burst_timeout = 2500; /* burst timeout in msec */
160 static BaseWindowClass *st_parent_class = NULL;
161 static gint st_signals[ LAST_SIGNAL ] = { 0 };
162
163 static GType register_type( void );
164 static void class_init( NactMainWindowClass *klass );
165 static void iaction_tab_iface_init( NactIActionTabInterface *iface, void *user_data );
166 static void icommand_tab_iface_init( NactICommandTabInterface *iface, void *user_data );
167 static void ibasenames_tab_iface_init( NactIBasenamesTabInterface *iface, void *user_data );
168 static void imimetypes_tab_iface_init( NactIMimetypesTabInterface *iface, void *user_data );
169 static void ifolders_tab_iface_init( NactIFoldersTabInterface *iface, void *user_data );
170 static void ischemes_tab_iface_init( NactISchemesTabInterface *iface, void *user_data );
171 static void icapabilities_tab_iface_init( NactICapabilitiesTabInterface *iface, void *user_data );
172 static void ienvironment_tab_iface_init( NactIEnvironmentTabInterface *iface, void *user_data );
173 static void iexecution_tab_iface_init( NactIExecutionTabInterface *iface, void *user_data );
174 static void iproperties_tab_iface_init( NactIPropertiesTabInterface *iface, void *user_data );
175 static void instance_init( GTypeInstance *instance, gpointer klass );
176 static void instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
177 static void instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
178 static void instance_constructed( GObject *window );
179 static void instance_dispose( GObject *window );
180 static void instance_finalize( GObject *window );
181
182 static void on_base_initialize_gtk( NactMainWindow *window, GtkWindow *toplevel, gpointer user_data );
183 static void on_base_initialize_window( NactMainWindow *window, gpointer user_data );
184 static void on_base_show_widgets( NactMainWindow *window, gpointer user_data );
185
186 static void on_block_items_changed_timeout( NactMainWindow *window );
187 static void on_tree_view_modified_status_changed( NactMainWindow *window, gboolean is_modified, gpointer user_data );
188 static void on_tree_view_selection_changed( NactMainWindow *window, GList *selected_items, gpointer user_data );
189 static void on_selection_changed_cleanup_handler( BaseWindow *window, GList *selected_items );
190 static void on_tab_updatable_item_updated( NactMainWindow *window, NAIContext *context, guint data, gpointer user_data );
191 static void raz_selection_properties( NactMainWindow *window );
192 static void setup_current_selection( NactMainWindow *window, NAObjectId *selected_row );
193 static void setup_dialog_title( NactMainWindow *window );
194 static void setup_writability_status( NactMainWindow *window );
195
196 /* items have changed */
197 static void on_pivot_items_changed( NAUpdater *updater, NactMainWindow *window );
198 static gboolean confirm_for_giveup_from_pivot( const NactMainWindow *window );
199 static gboolean confirm_for_giveup_from_menu( const NactMainWindow *window );
200 static void load_or_reload_items( NactMainWindow *window );
201
202 /* application termination */
203 static gboolean on_base_quit_requested( NactApplication *application, NactMainWindow *window );
204 static gboolean on_delete_event( GtkWidget *toplevel, GdkEvent *event, NactMainWindow *window );
205 static gboolean warn_modified( NactMainWindow *window );
206
207 GType
nact_main_window_get_type(void)208 nact_main_window_get_type( void )
209 {
210 static GType window_type = 0;
211
212 if( !window_type ){
213 window_type = register_type();
214 }
215
216 return( window_type );
217 }
218
219 static GType
register_type(void)220 register_type( void )
221 {
222 static const gchar *thisfn = "nact_main_window_register_type";
223 GType type;
224
225 static GTypeInfo info = {
226 sizeof( NactMainWindowClass ),
227 ( GBaseInitFunc ) NULL,
228 ( GBaseFinalizeFunc ) NULL,
229 ( GClassInitFunc ) class_init,
230 NULL,
231 NULL,
232 sizeof( NactMainWindow ),
233 0,
234 ( GInstanceInitFunc ) instance_init
235 };
236
237 static const GInterfaceInfo iaction_tab_iface_info = {
238 ( GInterfaceInitFunc ) iaction_tab_iface_init,
239 NULL,
240 NULL
241 };
242
243 static const GInterfaceInfo icommand_tab_iface_info = {
244 ( GInterfaceInitFunc ) icommand_tab_iface_init,
245 NULL,
246 NULL
247 };
248
249 static const GInterfaceInfo ibasenames_tab_iface_info = {
250 ( GInterfaceInitFunc ) ibasenames_tab_iface_init,
251 NULL,
252 NULL
253 };
254
255 static const GInterfaceInfo imimetypes_tab_iface_info = {
256 ( GInterfaceInitFunc ) imimetypes_tab_iface_init,
257 NULL,
258 NULL
259 };
260
261 static const GInterfaceInfo ifolders_tab_iface_info = {
262 ( GInterfaceInitFunc ) ifolders_tab_iface_init,
263 NULL,
264 NULL
265 };
266
267 static const GInterfaceInfo ischemes_tab_iface_info = {
268 ( GInterfaceInitFunc ) ischemes_tab_iface_init,
269 NULL,
270 NULL
271 };
272
273 static const GInterfaceInfo icapabilities_tab_iface_info = {
274 ( GInterfaceInitFunc ) icapabilities_tab_iface_init,
275 NULL,
276 NULL
277 };
278
279 static const GInterfaceInfo ienvironment_tab_iface_info = {
280 ( GInterfaceInitFunc ) ienvironment_tab_iface_init,
281 NULL,
282 NULL
283 };
284
285 static const GInterfaceInfo iexecution_tab_iface_info = {
286 ( GInterfaceInitFunc ) iexecution_tab_iface_init,
287 NULL,
288 NULL
289 };
290
291 static const GInterfaceInfo iproperties_tab_iface_info = {
292 ( GInterfaceInitFunc ) iproperties_tab_iface_init,
293 NULL,
294 NULL
295 };
296
297 g_debug( "%s", thisfn );
298
299 type = g_type_register_static( BASE_TYPE_WINDOW, "NactMainWindow", &info, 0 );
300
301 g_type_add_interface_static( type, NACT_TYPE_IACTION_TAB, &iaction_tab_iface_info );
302
303 g_type_add_interface_static( type, NACT_TYPE_ICOMMAND_TAB, &icommand_tab_iface_info );
304
305 g_type_add_interface_static( type, NACT_TYPE_IBASENAMES_TAB, &ibasenames_tab_iface_info );
306
307 g_type_add_interface_static( type, NACT_TYPE_IMIMETYPES_TAB, &imimetypes_tab_iface_info );
308
309 g_type_add_interface_static( type, NACT_TYPE_IFOLDERS_TAB, &ifolders_tab_iface_info );
310
311 g_type_add_interface_static( type, NACT_TYPE_ISCHEMES_TAB, &ischemes_tab_iface_info );
312
313 g_type_add_interface_static( type, NACT_TYPE_ICAPABILITIES_TAB, &icapabilities_tab_iface_info );
314
315 g_type_add_interface_static( type, NACT_TYPE_IENVIRONMENT_TAB, &ienvironment_tab_iface_info );
316
317 g_type_add_interface_static( type, NACT_TYPE_IEXECUTION_TAB, &iexecution_tab_iface_info );
318
319 g_type_add_interface_static( type, NACT_TYPE_IPROPERTIES_TAB, &iproperties_tab_iface_info );
320
321 return( type );
322 }
323
324 static void
class_init(NactMainWindowClass * klass)325 class_init( NactMainWindowClass *klass )
326 {
327 static const gchar *thisfn = "nact_main_window_class_init";
328 GObjectClass *object_class;
329
330 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
331
332 st_parent_class = g_type_class_peek_parent( klass );
333
334 object_class = G_OBJECT_CLASS( klass );
335 object_class->set_property = instance_set_property;
336 object_class->get_property = instance_get_property;
337 object_class->constructed = instance_constructed;
338 object_class->dispose = instance_dispose;
339 object_class->finalize = instance_finalize;
340
341 g_object_class_install_property( object_class, MAIN_PROP_ITEM_ID,
342 g_param_spec_pointer(
343 MAIN_PROP_ITEM,
344 _( "Current NAObjectItem" ),
345 _( "A pointer to the currently edited NAObjectItem, an action or a menu" ),
346 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
347
348 g_object_class_install_property( object_class, MAIN_PROP_PROFILE_ID,
349 g_param_spec_pointer(
350 MAIN_PROP_PROFILE,
351 _( "Current NAObjectProfile" ),
352 _( "A pointer to the currently edited NAObjectProfile" ),
353 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
354
355 g_object_class_install_property( object_class, MAIN_PROP_CONTEXT_ID,
356 g_param_spec_pointer(
357 MAIN_PROP_CONTEXT,
358 _( "Current NAIContext" ),
359 _( "A pointer to the currently edited NAIContext" ),
360 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
361
362 g_object_class_install_property( object_class, MAIN_PROP_EDITABLE_ID,
363 g_param_spec_boolean(
364 MAIN_PROP_EDITABLE,
365 _( "Editable item ?" ),
366 _( "Whether the item will be able to be updated against its I/O provider" ),
367 FALSE,
368 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
369
370 g_object_class_install_property( object_class, MAIN_PROP_REASON_ID,
371 g_param_spec_int(
372 MAIN_PROP_REASON,
373 _( "No edition reason" ),
374 _( "Why is this item not editable" ),
375 0, 255, 0,
376 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
377
378 klass->private = g_new0( NactMainWindowClassPrivate, 1 );
379
380 /**
381 * NactMainWindow::main-item-updated:
382 *
383 * This signal is emitted on the BaseWindow when the item has been modified
384 * elsewhere that in a tab. The tabs should so update accordingly their
385 * widgets.
386 *
387 * Args:
388 * - an OR-ed list of the modified data, or 0 if not relevant.
389 */
390 st_signals[ MAIN_ITEM_UPDATED ] = g_signal_new(
391 MAIN_SIGNAL_ITEM_UPDATED,
392 G_TYPE_OBJECT,
393 G_SIGNAL_RUN_LAST,
394 0, /* no default handler */
395 NULL,
396 NULL,
397 nact_cclosure_marshal_VOID__POINTER_UINT,
398 G_TYPE_NONE,
399 2,
400 G_TYPE_POINTER,
401 G_TYPE_UINT );
402
403 /**
404 * nact-tab-updatable-item-updated:
405 *
406 * This signal is emitted by the notebook tabs, when any property
407 * of an item has been modified.
408 *
409 * Args:
410 * - an OR-ed list of the modified data, or 0 if not relevant.
411 *
412 * This main window is rather the only consumer of this message,
413 * does its tricks (title, etc.), and then reforward an item-updated
414 * message to IActionsList.
415 */
416 st_signals[ TAB_ITEM_UPDATED ] = g_signal_new(
417 TAB_UPDATABLE_SIGNAL_ITEM_UPDATED,
418 G_TYPE_OBJECT,
419 G_SIGNAL_RUN_LAST,
420 0, /* no default handler */
421 NULL,
422 NULL,
423 nact_cclosure_marshal_VOID__POINTER_UINT,
424 G_TYPE_NONE,
425 2,
426 G_TYPE_POINTER,
427 G_TYPE_UINT );
428
429 /**
430 * NactMainWindow::main-selection-changed:
431 *
432 * This signal is emitted on the window parent each time the selection
433 * has changed in the treeview, after having set the current item/profile/
434 * context properties.
435 *
436 * This way, we are sure that notebook edition tabs which required to
437 * have a current item/profile/context will have it, whenever they have
438 * connected to the 'selection-changed' signal.
439 *
440 * Signal args:
441 * - a #GList of currently selected #NAObjectItems.
442 *
443 * Handler prototype:
444 * void ( *handler )( BaseWindow *window, GList *selected, gpointer user_data );
445 */
446 st_signals[ SELECTION_CHANGED ] = g_signal_new_class_handler(
447 MAIN_SIGNAL_SELECTION_CHANGED,
448 G_TYPE_OBJECT,
449 G_SIGNAL_RUN_CLEANUP,
450 G_CALLBACK( on_selection_changed_cleanup_handler ),
451 NULL,
452 NULL,
453 g_cclosure_marshal_VOID__POINTER,
454 G_TYPE_NONE,
455 1,
456 G_TYPE_POINTER );
457
458 /**
459 * NactMainWindow::main-signal-open-popup
460 *
461 * This signal is emitted on the BaseWindow parent when the user right
462 * clicks somewhere (on an active zone).
463 *
464 * Signal args:
465 * - the GdkEvent
466 * - the popup name to be opened.
467 *
468 * Handler prototype:
469 * void ( *handler )( BaseWindow *window, GdkEvent *event, const gchar *popup_name, gpointer user_data );
470 */
471 st_signals[ CONTEXT_MENU ] = g_signal_new(
472 MAIN_SIGNAL_CONTEXT_MENU,
473 G_TYPE_OBJECT,
474 G_SIGNAL_RUN_LAST,
475 0,
476 NULL,
477 NULL,
478 nact_cclosure_marshal_VOID__POINTER_STRING,
479 G_TYPE_NONE,
480 2,
481 G_TYPE_POINTER,
482 G_TYPE_STRING);
483 }
484
485 static void
iaction_tab_iface_init(NactIActionTabInterface * iface,void * user_data)486 iaction_tab_iface_init( NactIActionTabInterface *iface, void *user_data )
487 {
488 static const gchar *thisfn = "nact_main_window_iaction_tab_iface_init";
489
490 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
491 }
492
493 static void
icommand_tab_iface_init(NactICommandTabInterface * iface,void * user_data)494 icommand_tab_iface_init( NactICommandTabInterface *iface, void *user_data )
495 {
496 static const gchar *thisfn = "nact_main_window_icommand_tab_iface_init";
497
498 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
499 }
500
501 static void
ibasenames_tab_iface_init(NactIBasenamesTabInterface * iface,void * user_data)502 ibasenames_tab_iface_init( NactIBasenamesTabInterface *iface, void *user_data )
503 {
504 static const gchar *thisfn = "nact_main_window_ibasenames_tab_iface_init";
505
506 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
507 }
508
509 static void
imimetypes_tab_iface_init(NactIMimetypesTabInterface * iface,void * user_data)510 imimetypes_tab_iface_init( NactIMimetypesTabInterface *iface, void *user_data )
511 {
512 static const gchar *thisfn = "nact_main_window_imimetypes_tab_iface_init";
513
514 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
515 }
516
517 static void
ifolders_tab_iface_init(NactIFoldersTabInterface * iface,void * user_data)518 ifolders_tab_iface_init( NactIFoldersTabInterface *iface, void *user_data )
519 {
520 static const gchar *thisfn = "nact_main_window_ifolders_tab_iface_init";
521
522 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
523 }
524
525 static void
ischemes_tab_iface_init(NactISchemesTabInterface * iface,void * user_data)526 ischemes_tab_iface_init( NactISchemesTabInterface *iface, void *user_data )
527 {
528 static const gchar *thisfn = "nact_main_window_ischemes_tab_iface_init";
529
530 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
531 }
532
533 static void
icapabilities_tab_iface_init(NactICapabilitiesTabInterface * iface,void * user_data)534 icapabilities_tab_iface_init( NactICapabilitiesTabInterface *iface, void *user_data )
535 {
536 static const gchar *thisfn = "nact_main_window_icapabilities_tab_iface_init";
537
538 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
539 }
540
541 static void
ienvironment_tab_iface_init(NactIEnvironmentTabInterface * iface,void * user_data)542 ienvironment_tab_iface_init( NactIEnvironmentTabInterface *iface, void *user_data )
543 {
544 static const gchar *thisfn = "nact_main_window_ienvironment_tab_iface_init";
545
546 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
547 }
548
549 static void
iexecution_tab_iface_init(NactIExecutionTabInterface * iface,void * user_data)550 iexecution_tab_iface_init( NactIExecutionTabInterface *iface, void *user_data )
551 {
552 static const gchar *thisfn = "nact_main_window_iexecution_tab_iface_init";
553
554 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
555 }
556
557 static void
iproperties_tab_iface_init(NactIPropertiesTabInterface * iface,void * user_data)558 iproperties_tab_iface_init( NactIPropertiesTabInterface *iface, void *user_data )
559 {
560 static const gchar *thisfn = "nact_main_window_iproperties_tab_iface_init";
561
562 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
563 }
564
565 static void
instance_init(GTypeInstance * instance,gpointer klass)566 instance_init( GTypeInstance *instance, gpointer klass )
567 {
568 static const gchar *thisfn = "nact_main_window_instance_init";
569 NactMainWindow *self;
570 NactMainWindowPrivate *priv;
571
572 g_return_if_fail( NACT_IS_MAIN_WINDOW( instance ));
573
574 g_debug( "%s: instance=%p (%s), klass=%p",
575 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
576
577 self = NACT_MAIN_WINDOW( instance );
578 self->private = g_new0( NactMainWindowPrivate, 1 );
579 priv = self->private;
580 priv->dispose_has_run = FALSE;
581
582 /* initialize timeout parameters when blocking 'pivot-items-changed' handler
583 */
584 priv->pivot_timeout.timeout = st_burst_timeout;
585 priv->pivot_timeout.handler = ( NATimeoutFunc ) on_block_items_changed_timeout;
586 priv->pivot_timeout.user_data = self;
587 priv->pivot_timeout.source_id = 0;
588 }
589
590 static void
instance_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * spec)591 instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
592 {
593 NactMainWindow *self;
594
595 g_return_if_fail( NACT_IS_MAIN_WINDOW( object ));
596 self = NACT_MAIN_WINDOW( object );
597
598 if( !self->private->dispose_has_run ){
599
600 switch( property_id ){
601 case MAIN_PROP_ITEM_ID:
602 g_value_set_pointer( value, self->private->current_item );
603 break;
604
605 case MAIN_PROP_PROFILE_ID:
606 g_value_set_pointer( value, self->private->current_profile );
607 break;
608
609 case MAIN_PROP_CONTEXT_ID:
610 g_value_set_pointer( value, self->private->current_context );
611 break;
612
613 case MAIN_PROP_EDITABLE_ID:
614 g_value_set_boolean( value, self->private->editable );
615 break;
616
617 case MAIN_PROP_REASON_ID:
618 g_value_set_int( value, self->private->reason );
619 break;
620
621 default:
622 G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
623 break;
624 }
625 }
626 }
627
628 static void
instance_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * spec)629 instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
630 {
631 NactMainWindow *self;
632
633 g_return_if_fail( NACT_IS_MAIN_WINDOW( object ));
634 self = NACT_MAIN_WINDOW( object );
635
636 if( !self->private->dispose_has_run ){
637
638 switch( property_id ){
639 case MAIN_PROP_ITEM_ID:
640 self->private->current_item = g_value_get_pointer( value );
641 break;
642
643 case MAIN_PROP_PROFILE_ID:
644 self->private->current_profile = g_value_get_pointer( value );
645 break;
646
647 case MAIN_PROP_CONTEXT_ID:
648 self->private->current_context = g_value_get_pointer( value );
649 break;
650
651 case MAIN_PROP_EDITABLE_ID:
652 self->private->editable = g_value_get_boolean( value );
653 break;
654
655 case MAIN_PROP_REASON_ID:
656 self->private->reason = g_value_get_int( value );
657 break;
658
659 default:
660 G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
661 break;
662 }
663 }
664 }
665
666 static void
instance_constructed(GObject * window)667 instance_constructed( GObject *window )
668 {
669 static const gchar *thisfn = "nact_main_window_instance_constructed";
670 NactMainWindowPrivate *priv;
671 NactApplication *application;
672
673 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
674
675 priv = NACT_MAIN_WINDOW( window )->private;
676
677 if( !priv->dispose_has_run ){
678
679 /* chain up to the parent class */
680 if( G_OBJECT_CLASS( st_parent_class )->constructed ){
681 G_OBJECT_CLASS( st_parent_class )->constructed( window );
682 }
683
684 g_debug( "%s: window=%p (%s)", thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ));
685
686 /* connect to BaseWindow signals
687 * so that convenience objects instanciated later will have this same signal
688 * triggered after the one of NactMainWindow
689 */
690 base_window_signal_connect(
691 BASE_WINDOW( window ),
692 G_OBJECT( window ),
693 BASE_SIGNAL_INITIALIZE_GTK,
694 G_CALLBACK( on_base_initialize_gtk ));
695
696 base_window_signal_connect(
697 BASE_WINDOW( window ),
698 G_OBJECT( window ),
699 BASE_SIGNAL_INITIALIZE_WINDOW,
700 G_CALLBACK( on_base_initialize_window ));
701
702 base_window_signal_connect(
703 BASE_WINDOW( window ),
704 G_OBJECT( window ),
705 BASE_SIGNAL_SHOW_WIDGETS,
706 G_CALLBACK( on_base_show_widgets ));
707
708 /* monitor the items stored on the disk for modifications
709 * outside of this application
710 */
711 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
712 priv->updater = nact_application_get_updater( application );
713
714 priv->pivot_handler_id = base_window_signal_connect(
715 BASE_WINDOW( window ),
716 G_OBJECT( priv->updater ),
717 PIVOT_SIGNAL_ITEMS_CHANGED,
718 G_CALLBACK( on_pivot_items_changed ));
719
720 /* monitor the updates which originates from each property tab
721 */
722 base_window_signal_connect(
723 BASE_WINDOW( window ),
724 G_OBJECT( window ),
725 TAB_UPDATABLE_SIGNAL_ITEM_UPDATED,
726 G_CALLBACK( on_tab_updatable_item_updated ));
727
728 /* create the menubar and other convenience objects
729 */
730 priv->menubar = nact_menubar_new( BASE_WINDOW( window ));
731 priv->clipboard = nact_clipboard_new( BASE_WINDOW( window ));
732
733 /* initialize the notebook interfaces
734 */
735 nact_iaction_tab_init( NACT_IACTION_TAB( window ));
736 nact_icommand_tab_init( NACT_ICOMMAND_TAB( window ));
737 nact_ibasenames_tab_init( NACT_IBASENAMES_TAB( window ));
738 nact_imimetypes_tab_init( NACT_IMIMETYPES_TAB( window ));
739 nact_ifolders_tab_init( NACT_IFOLDERS_TAB( window ));
740 nact_ischemes_tab_init( NACT_ISCHEMES_TAB( window ));
741 nact_icapabilities_tab_init( NACT_ICAPABILITIES_TAB( window ));
742 nact_ienvironment_tab_init( NACT_IENVIRONMENT_TAB( window ));
743 nact_iexecution_tab_init( NACT_IEXECUTION_TAB( window ));
744 nact_iproperties_tab_init( NACT_IPROPERTIES_TAB( window ));
745 }
746 }
747
748 static void
instance_dispose(GObject * window)749 instance_dispose( GObject *window )
750 {
751 static const gchar *thisfn = "nact_main_window_instance_dispose";
752 NactMainWindow *self;
753 GtkWidget *pane;
754 gint pos;
755 GtkNotebook *notebook;
756
757 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
758
759 self = NACT_MAIN_WINDOW( window );
760
761 if( !self->private->dispose_has_run ){
762 g_debug( "%s: window=%p (%s)", thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ));
763
764 self->private->dispose_has_run = TRUE;
765
766 gtk_main_quit();
767
768 g_object_unref( self->private->clipboard );
769 g_object_unref( self->private->menubar );
770
771 pane = base_window_get_widget( BASE_WINDOW( window ), "MainPaned" );
772 pos = gtk_paned_get_position( GTK_PANED( pane ));
773 na_settings_set_uint( NA_IPREFS_MAIN_PANED, pos );
774
775 notebook = GTK_NOTEBOOK( base_window_get_widget( BASE_WINDOW( window ), "MainNotebook" ));
776 pos = gtk_notebook_get_tab_pos( notebook );
777 na_iprefs_set_tabs_pos( pos );
778
779 /* unref items view at last as gtk_tree_model_store_clear() will
780 * finalize all objects, thus invaliditing all our references
781 */
782 g_object_unref( self->private->items_view );
783
784 /* chain up to the parent class */
785 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
786 G_OBJECT_CLASS( st_parent_class )->dispose( window );
787 }
788 }
789 }
790
791 static void
instance_finalize(GObject * window)792 instance_finalize( GObject *window )
793 {
794 static const gchar *thisfn = "nact_main_window_instance_finalize";
795 NactMainWindow *self;
796
797 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
798
799 g_debug( "%s: window=%p (%s)", thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ));
800
801 self = NACT_MAIN_WINDOW( window );
802
803 g_free( self->private );
804
805 /* chain call to parent class */
806 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
807 G_OBJECT_CLASS( st_parent_class )->finalize( window );
808 }
809 }
810
811 /**
812 * Returns a newly allocated NactMainWindow object.
813 */
814 NactMainWindow *
nact_main_window_new(const NactApplication * application)815 nact_main_window_new( const NactApplication *application )
816 {
817 NactMainWindow *window;
818
819 g_return_val_if_fail( NACT_IS_APPLICATION( application ), NULL );
820
821 window = g_object_new( NACT_TYPE_MAIN_WINDOW,
822 BASE_PROP_APPLICATION, application,
823 BASE_PROP_XMLUI_FILENAME, st_xmlui_filename,
824 BASE_PROP_TOPLEVEL_NAME, st_toplevel_name,
825 BASE_PROP_WSP_NAME, st_wsp_name,
826 BASE_PROP_DESTROY_ON_DISPOSE, TRUE,
827 NULL );
828
829 if( !base_window_init( BASE_WINDOW( window ))){
830 g_object_unref( window );
831 window = NULL;
832 }
833
834 return( window );
835 }
836
837 /*
838 * note that for this NactMainWindow, on_base_initialize_gtk_toplevel() and
839 * on_base_initialize_base_window() are roughly equivalent, as there is only
840 * one occurrence on this window in the application: closing this window
841 * is the same than quitting the application
842 */
843 static void
on_base_initialize_gtk(NactMainWindow * window,GtkWindow * toplevel,gpointer user_data)844 on_base_initialize_gtk( NactMainWindow *window, GtkWindow *toplevel, gpointer user_data )
845 {
846 static const gchar *thisfn = "nact_main_window_on_base_initialize_gtk";
847 GtkWidget *tree_parent;
848 GtkNotebook *notebook;
849
850 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
851
852 if( !window->private->dispose_has_run ){
853
854 g_debug( "%s: window=%p, toplevel=%p, user_data=%p",
855 thisfn,
856 ( void * ) window,
857 ( void * ) toplevel,
858 ( void * ) user_data );
859
860 /* create the tree view which will create itself its own tree model
861 */
862 tree_parent = base_window_get_widget( BASE_WINDOW( window ), "MainVBox" );
863 g_debug( "%s: tree_parent=%p (%s)", thisfn, ( void * ) tree_parent, G_OBJECT_TYPE_NAME( tree_parent ));
864 window->private->items_view = nact_tree_view_new(
865 BASE_WINDOW( window ),
866 GTK_CONTAINER( tree_parent ),
867 "ActionsList",
868 TREE_MODE_EDITION );
869
870 nact_main_statusbar_initialize_gtk_toplevel( window );
871
872 /* enable popup menu on the notebook
873 */
874 notebook = GTK_NOTEBOOK( base_window_get_widget( BASE_WINDOW( window ), "MainNotebook" ));
875 gtk_notebook_popup_enable( notebook );
876 }
877 }
878
879 static void
on_base_initialize_window(NactMainWindow * window,gpointer user_data)880 on_base_initialize_window( NactMainWindow *window, gpointer user_data )
881 {
882 static const gchar *thisfn = "nact_main_window_on_base_initialize_window";
883 guint pos;
884 GtkWidget *pane;
885 NactApplication *application;
886 GtkNotebook *notebook;
887
888 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
889
890 if( !window->private->dispose_has_run ){
891
892 g_debug( "%s: window=%p, user_data=%p",
893 thisfn,
894 ( void * ) window,
895 ( void * ) user_data );
896
897 pos = na_settings_get_uint( NA_IPREFS_MAIN_PANED, NULL, NULL );
898 if( pos ){
899 pane = base_window_get_widget( BASE_WINDOW( window ), "MainPaned" );
900 gtk_paned_set_position( GTK_PANED( pane ), pos );
901 }
902
903 /* terminate the application by clicking the top right [X] button
904 */
905 base_window_signal_connect(
906 BASE_WINDOW( window ),
907 G_OBJECT( base_window_get_gtk_toplevel( BASE_WINDOW( window ))),
908 "delete-event",
909 G_CALLBACK( on_delete_event ));
910
911 /* is willing to quit ?
912 * connect to the signal of the BaseISession interface
913 */
914 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
915 base_window_signal_connect(
916 BASE_WINDOW( window ),
917 G_OBJECT( application ),
918 BASE_SIGNAL_QUIT_REQUESTED,
919 G_CALLBACK( on_base_quit_requested ));
920
921 /* connect to treeview signals
922 */
923 base_window_signal_connect(
924 BASE_WINDOW( window ),
925 G_OBJECT( window ),
926 MAIN_SIGNAL_SELECTION_CHANGED,
927 G_CALLBACK( on_tree_view_selection_changed ));
928
929 base_window_signal_connect(
930 BASE_WINDOW( window ),
931 G_OBJECT( window ),
932 TREE_SIGNAL_MODIFIED_STATUS_CHANGED,
933 G_CALLBACK( on_tree_view_modified_status_changed ));
934
935 /* restore the notebook tabs position
936 */
937 pos = na_iprefs_get_tabs_pos( NULL );
938 notebook = GTK_NOTEBOOK( base_window_get_widget( BASE_WINDOW( window ), "MainNotebook" ));
939 gtk_notebook_set_tab_pos( notebook, pos );
940 }
941 }
942
943 static void
on_base_show_widgets(NactMainWindow * window,gpointer user_data)944 on_base_show_widgets( NactMainWindow *window, gpointer user_data )
945 {
946 static const gchar *thisfn = "nact_main_window_on_base_show_widgets";
947
948 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
949
950 if( !window->private->dispose_has_run ){
951
952 g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
953
954 load_or_reload_items( window );
955 }
956 }
957
958 /**
959 * nact_main_window_get_clipboard:
960 * @window: this #NactMainWindow instance.
961 *
962 * Returns: the #NactClipboard convenience object.
963 */
964 NactClipboard *
nact_main_window_get_clipboard(const NactMainWindow * window)965 nact_main_window_get_clipboard( const NactMainWindow *window )
966 {
967 NactClipboard *clipboard;
968
969 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), NULL );
970
971 clipboard = NULL;
972
973 if( !window->private->dispose_has_run ){
974
975 clipboard = window->private->clipboard;
976 }
977
978 return( clipboard );
979 }
980
981 /**
982 * nact_main_window_get_items_view:
983 * @window: this #NactMainWindow instance.
984 *
985 * Returns: The #NactTreeView convenience object.
986 */
987 NactTreeView *
nact_main_window_get_items_view(const NactMainWindow * window)988 nact_main_window_get_items_view( const NactMainWindow *window )
989 {
990 NactTreeView *view;
991
992 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), NULL );
993
994 view = NULL;
995
996 if( !window->private->dispose_has_run ){
997
998 view = window->private->items_view;
999 }
1000
1001 return( view );
1002 }
1003
1004 /**
1005 * nact_main_window_reload:
1006 * @window: this #NactMainWindow instance.
1007 *
1008 * Refresh the list of items.
1009 * If there is some non-yet saved modifications, a confirmation is
1010 * required before giving up with them.
1011 */
1012 void
nact_main_window_reload(NactMainWindow * window)1013 nact_main_window_reload( NactMainWindow *window )
1014 {
1015 gboolean reload_ok;
1016
1017 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
1018
1019 if( !window->private->dispose_has_run ){
1020
1021 reload_ok = confirm_for_giveup_from_menu( window );
1022
1023 if( reload_ok ){
1024 load_or_reload_items( window );
1025 }
1026 }
1027 }
1028
1029 /**
1030 * nact_main_window_block_reload:
1031 * @window: this #NactMainWindow instance.
1032 *
1033 * Temporarily blocks the handling of pivot-items-changed signal.
1034 */
1035 void
nact_main_window_block_reload(NactMainWindow * window)1036 nact_main_window_block_reload( NactMainWindow *window )
1037 {
1038 static const gchar *thisfn = "nact_main_window_block_reload";
1039
1040 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
1041
1042 if( !window->private->dispose_has_run ){
1043
1044 g_debug( "%s: blocking %s signal", thisfn, PIVOT_SIGNAL_ITEMS_CHANGED );
1045 g_signal_handler_block( window->private->updater, window->private->pivot_handler_id );
1046 na_timeout_event( &window->private->pivot_timeout );
1047 }
1048 }
1049
1050 static void
on_block_items_changed_timeout(NactMainWindow * window)1051 on_block_items_changed_timeout( NactMainWindow *window )
1052 {
1053 static const gchar *thisfn = "nact_main_window_on_block_items_changed_timeout";
1054
1055 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
1056
1057 g_debug( "%s: unblocking %s signal", thisfn, PIVOT_SIGNAL_ITEMS_CHANGED );
1058 g_signal_handler_unblock( window->private->updater, window->private->pivot_handler_id );
1059 }
1060
1061 /*
1062 * the modification status of the items view has changed
1063 */
1064 static void
on_tree_view_modified_status_changed(NactMainWindow * window,gboolean is_modified,gpointer user_data)1065 on_tree_view_modified_status_changed( NactMainWindow *window, gboolean is_modified, gpointer user_data )
1066 {
1067 static const gchar *thisfn = "nact_main_window_on_tree_view_modified_status_changed";
1068
1069 g_debug( "%s: window=%p, is_modified=%s, user_data=%p",
1070 thisfn, ( void * ) window, is_modified ? "True":"False", ( void * ) user_data );
1071
1072 if( !window->private->dispose_has_run ){
1073
1074 window->private->is_tree_modified = is_modified;
1075 setup_dialog_title( window );
1076 }
1077 }
1078
1079 /*
1080 * tree view selection has changed
1081 */
1082 static void
on_tree_view_selection_changed(NactMainWindow * window,GList * selected_items,gpointer user_data)1083 on_tree_view_selection_changed( NactMainWindow *window, GList *selected_items, gpointer user_data )
1084 {
1085 static const gchar *thisfn = "nact_main_window_on_tree_view_selection_changed";
1086 guint count;
1087
1088 count = g_list_length( selected_items );
1089
1090 if( !window->private->dispose_has_run ){
1091 g_debug( "%s: window=%p, selected_items=%p (count=%d), user_data=%p",
1092 thisfn, ( void * ) window,
1093 ( void * ) selected_items, count, ( void * ) user_data );
1094
1095 raz_selection_properties( window );
1096
1097 if( count == 1 ){
1098 g_return_if_fail( NA_IS_OBJECT_ID( selected_items->data ));
1099 setup_current_selection( window, NA_OBJECT_ID( selected_items->data ));
1100 setup_writability_status( window );
1101 }
1102
1103 setup_dialog_title( window );
1104 }
1105 }
1106
1107 /*
1108 * cleanup handler for our MAIN_SIGNAL_SELECTION_CHANGED signal
1109 */
1110 static void
on_selection_changed_cleanup_handler(BaseWindow * window,GList * selected_items)1111 on_selection_changed_cleanup_handler( BaseWindow *window, GList *selected_items )
1112 {
1113 static const gchar *thisfn = "nact_main_window_on_selection_changed_cleanup_handler";
1114
1115 g_debug( "%s: window=%p, selected_items=%p (count=%u)",
1116 thisfn, ( void * ) window,
1117 ( void * ) selected_items, g_list_length( selected_items ));
1118
1119 na_object_free_items( selected_items );
1120 }
1121
1122 static void
on_tab_updatable_item_updated(NactMainWindow * window,NAIContext * context,guint data,gpointer user_data)1123 on_tab_updatable_item_updated( NactMainWindow *window, NAIContext *context, guint data, gpointer user_data )
1124 {
1125 static const gchar *thisfn = "nact_main_window_on_tab_updatable_item_updated";
1126
1127 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
1128
1129 if( !window->private->dispose_has_run ){
1130 g_debug( "%s: window=%p, context=%p (%s), data=%u, user_data=%p",
1131 thisfn, ( void * ) window, ( void * ) context, G_OBJECT_TYPE_NAME( context ),
1132 data, ( void * ) user_data );
1133
1134 if( context ){
1135 na_object_check_status( context );
1136 }
1137 }
1138 }
1139
1140 static void
raz_selection_properties(NactMainWindow * window)1141 raz_selection_properties( NactMainWindow *window )
1142 {
1143 window->private->current_item = NULL;
1144 window->private->current_profile = NULL;
1145 window->private->current_context = NULL;
1146 window->private->editable = FALSE;
1147 window->private->reason = 0;
1148
1149 nact_main_statusbar_set_locked( window, FALSE, 0 );
1150 }
1151
1152 /*
1153 * enter after raz_properties
1154 * only called when only one selected row
1155 */
1156 static void
setup_current_selection(NactMainWindow * window,NAObjectId * selected_row)1157 setup_current_selection( NactMainWindow *window, NAObjectId *selected_row )
1158 {
1159 guint nb_profiles;
1160 GList *profiles;
1161
1162 if( NA_IS_OBJECT_PROFILE( selected_row )){
1163 window->private->current_profile = NA_OBJECT_PROFILE( selected_row );
1164 window->private->current_context = NA_ICONTEXT( selected_row );
1165 window->private->current_item = NA_OBJECT_ITEM( na_object_get_parent( selected_row ));
1166
1167 } else {
1168 g_return_if_fail( NA_IS_OBJECT_ITEM( selected_row ));
1169 window->private->current_item = NA_OBJECT_ITEM( selected_row );
1170 window->private->current_context = NA_ICONTEXT( selected_row );
1171
1172 if( NA_IS_OBJECT_ACTION( selected_row )){
1173 nb_profiles = na_object_get_items_count( selected_row );
1174
1175 if( nb_profiles == 1 ){
1176 profiles = na_object_get_items( selected_row );
1177 window->private->current_profile = NA_OBJECT_PROFILE( profiles->data );
1178 window->private->current_context = NA_ICONTEXT( profiles->data );
1179 }
1180 }
1181 }
1182 }
1183
1184 /*
1185 * the title bar of the main window brings up three informations:
1186 * - the name of the application
1187 * - the name of the currently selected item if there is only one
1188 * - an asterisk if anything has been modified
1189 */
1190 static void
setup_dialog_title(NactMainWindow * window)1191 setup_dialog_title( NactMainWindow *window )
1192 {
1193 static const gchar *thisfn = "nact_main_window_setup_dialog_title";
1194 GtkWindow *toplevel;
1195 NactApplication *application;
1196 gchar *title;
1197 gchar *label;
1198 gchar *tmp;
1199 gboolean is_modified;
1200
1201 g_debug( "%s: window=%p", thisfn, ( void * ) window );
1202
1203 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
1204 title = base_application_get_application_name( BASE_APPLICATION( application ));
1205
1206 if( window->private->current_item ){
1207 label = na_object_get_label( window->private->current_item );
1208 is_modified = na_object_is_modified( window->private->current_item );
1209 tmp = g_strdup_printf( "%s%s - %s", is_modified ? "*" : "", label, title );
1210 g_free( label );
1211 g_free( title );
1212 title = tmp;
1213 }
1214
1215 toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( window ));
1216 gtk_window_set_title( toplevel, title );
1217 g_free( title );
1218 }
1219
1220 static void
setup_writability_status(NactMainWindow * window)1221 setup_writability_status( NactMainWindow *window )
1222 {
1223 g_return_if_fail( NA_IS_OBJECT_ITEM( window->private->current_item ));
1224
1225 window->private->editable = na_object_is_finally_writable( window->private->current_item, &window->private->reason );
1226 nact_main_statusbar_set_locked( window, !window->private->editable, window->private->reason );
1227 }
1228
1229 /*
1230 * The handler of the signal sent by NAPivot when items have been modified
1231 * in the underlying storage subsystems
1232 */
1233 static void
on_pivot_items_changed(NAUpdater * updater,NactMainWindow * window)1234 on_pivot_items_changed( NAUpdater *updater, NactMainWindow *window )
1235 {
1236 static const gchar *thisfn = "nact_main_window_on_pivot_items_changed";
1237 gboolean reload_ok;
1238
1239 g_return_if_fail( NA_IS_UPDATER( updater ));
1240 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
1241
1242 if( !window->private->dispose_has_run ){
1243 g_debug( "%s: updater=%p (%s), window=%p (%s)", thisfn,
1244 ( void * ) updater, G_OBJECT_TYPE_NAME( updater ),
1245 ( void * ) window, G_OBJECT_TYPE_NAME( window ));
1246
1247 reload_ok = confirm_for_giveup_from_pivot( window );
1248
1249 if( reload_ok ){
1250 load_or_reload_items( window );
1251 }
1252 }
1253 }
1254
1255 /*
1256 * informs the user that the actions in underlying storage subsystem
1257 * have changed, and propose for reloading
1258 *
1259 */
1260 static gboolean
confirm_for_giveup_from_pivot(const NactMainWindow * window)1261 confirm_for_giveup_from_pivot( const NactMainWindow *window )
1262 {
1263 gboolean reload_ok;
1264 gchar *first, *second;
1265
1266 first = g_strdup(
1267 _( "One or more actions have been modified in the filesystem.\n"
1268 "You could keep to work with your current list of actions, "
1269 "or you may want to reload a fresh one." ));
1270
1271 if( window->private->is_tree_modified){
1272
1273 gchar *tmp = g_strdup_printf( "%s\n\n%s", first,
1274 _( "Note that reloading a fresh list of actions requires "
1275 "that you give up with your current modifications." ));
1276 g_free( first );
1277 first = tmp;
1278 }
1279
1280 second = g_strdup( _( "Do you want to reload a fresh list of actions ?" ));
1281
1282 reload_ok = base_window_display_yesno_dlg( BASE_WINDOW( window ), first, second );
1283
1284 g_free( second );
1285 g_free( first );
1286
1287 return( reload_ok );
1288 }
1289
1290 /*
1291 * requires a confirmation from the user when is has asked for reloading
1292 * the actions via the Edit menu
1293 */
1294 static gboolean
confirm_for_giveup_from_menu(const NactMainWindow * window)1295 confirm_for_giveup_from_menu( const NactMainWindow *window )
1296 {
1297 gboolean reload_ok = TRUE;
1298 gchar *first, *second;
1299
1300 if( window->private->is_tree_modified ){
1301
1302 first = g_strdup(
1303 _( "Reloading a fresh list of actions requires "
1304 "that you give up with your current modifications." ));
1305
1306 second = g_strdup( _( "Do you really want to do this ?" ));
1307
1308 reload_ok = base_window_display_yesno_dlg( BASE_WINDOW( window ), first, second );
1309
1310 g_free( second );
1311 g_free( first );
1312 }
1313
1314 return( reload_ok );
1315 }
1316
1317 static void
load_or_reload_items(NactMainWindow * window)1318 load_or_reload_items( NactMainWindow *window )
1319 {
1320 static const gchar *thisfn = "nact_main_window_load_or_reload_items";
1321 GList *tree;
1322
1323 g_debug( "%s: window=%p", thisfn, ( void * ) window );
1324
1325 raz_selection_properties( window );
1326
1327 tree = na_updater_load_items( window->private->updater );
1328 nact_tree_view_fill( window->private->items_view, tree );
1329
1330 g_debug( "%s: end of tree view filling", thisfn );
1331 }
1332
1333 /**
1334 * nact_main_window_quit:
1335 * @window: the #NactMainWindow main window.
1336 *
1337 * Quit the window, thus terminating the application.
1338 *
1339 * Returns: %TRUE if the application will terminate, and the @window object
1340 * is no more valid; %FALSE if the application will continue to run.
1341 */
1342 gboolean
nact_main_window_quit(NactMainWindow * window)1343 nact_main_window_quit( NactMainWindow *window )
1344 {
1345 static const gchar *thisfn = "nact_main_window_quit";
1346 gboolean terminated;
1347
1348 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), FALSE );
1349
1350 terminated = FALSE;
1351
1352 if( !window->private->dispose_has_run ){
1353 g_debug( "%s: window=%p (%s)", thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ));
1354
1355 if( !window->private->is_tree_modified || warn_modified( window )){
1356 g_object_unref( window );
1357 terminated = TRUE;
1358 }
1359 }
1360
1361 return( terminated );
1362 }
1363
1364 /*
1365 * signal handler
1366 * should return %FALSE if it is not willing to quit
1367 * this will also stop the emission of the signal (i.e. the first FALSE wins)
1368 */
1369 static gboolean
on_base_quit_requested(NactApplication * application,NactMainWindow * window)1370 on_base_quit_requested( NactApplication *application, NactMainWindow *window )
1371 {
1372 static const gchar *thisfn = "nact_main_window_on_base_quit_requested";
1373 gboolean willing_to;
1374
1375 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), TRUE );
1376
1377 willing_to = TRUE;
1378
1379 if( !window->private->dispose_has_run ){
1380
1381 g_debug( "%s: application=%p, window=%p", thisfn, ( void * ) application, ( void * ) window );
1382
1383 if( window->private->is_tree_modified ){
1384 willing_to = nact_confirm_logout_run( window );
1385 }
1386 }
1387
1388 return( willing_to );
1389 }
1390
1391 /*
1392 * triggered when the user clicks on the top right [X] button
1393 * returns %TRUE to stop the signal to be propagated (which would cause the
1394 * window to be destroyed); instead we gracefully quit the application
1395 */
1396 static gboolean
on_delete_event(GtkWidget * toplevel,GdkEvent * event,NactMainWindow * window)1397 on_delete_event( GtkWidget *toplevel, GdkEvent *event, NactMainWindow *window )
1398 {
1399 static const gchar *thisfn = "nact_main_window_on_delete_event";
1400
1401 g_debug( "%s: toplevel=%p, event=%p, window=%p",
1402 thisfn, ( void * ) toplevel, ( void * ) event, ( void * ) window );
1403
1404 nact_main_window_quit( window );
1405
1406 return( TRUE );
1407 }
1408
1409 /*
1410 * warn_modified:
1411 * @window: this #NactWindow instance.
1412 *
1413 * Emits a warning if at least one item has been modified.
1414 *
1415 * Returns: %TRUE if the user confirms he wants to quit.
1416 */
1417 static gboolean
warn_modified(NactMainWindow * window)1418 warn_modified( NactMainWindow *window )
1419 {
1420 gboolean confirm = FALSE;
1421 gchar *first;
1422 gchar *second;
1423
1424 first = g_strdup_printf( _( "Some items have been modified." ));
1425 second = g_strdup( _( "Are you sure you want to quit without saving them ?" ));
1426
1427 confirm = base_window_display_yesno_dlg( BASE_WINDOW( window ), first, second );
1428
1429 g_free( second );
1430 g_free( first );
1431
1432 return( confirm );
1433 }
1434