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 <glib/gi18n.h>
38 #include <api/na-object-api.h>
39 #include <api/na-timeout.h>
41 #include <core/na-iabout.h>
42 #include <core/na-iprefs.h>
43 #include <core/na-pivot.h>
45 #include "base-marshal.h"
46 #include "nact-iaction-tab.h"
47 #include "nact-icommand-tab.h"
48 #include "nact-ibasenames-tab.h"
49 #include "nact-imimetypes-tab.h"
50 #include "nact-ifolders-tab.h"
51 #include "nact-ischemes-tab.h"
52 #include "nact-icapabilities-tab.h"
53 #include "nact-ienvironment-tab.h"
54 #include "nact-iexecution-tab.h"
55 #include "nact-iproperties-tab.h"
56 #include "nact-main-tab.h"
57 #include "nact-main-statusbar.h"
58 #include "nact-main-window.h"
59 #include "nact-menubar.h"
60 #include "nact-tree-view.h"
61 #include "nact-confirm-logout.h"
62 #include "nact-sort-buttons.h"
66 struct _NactMainWindowClassPrivate
{
67 void *empty
; /* so that gcc -pedantic is happy */
70 /* private instance data
72 struct _NactMainWindowPrivate
{
73 gboolean dispose_has_run
;
78 * Current action or menu.
80 * This is the action or menu which is displayed in tabs Action/Menu
81 * and Properties ; it may be different of the exact row being currently
82 * selected, e.g. when a sub-profile is edited.
84 * Can be null, and this implies that @current_profile is also null,
85 * e.g. when the list is empty or in the case of a multiple selection.
87 * 'editable' property is set on selection change;
88 * This is the actual current writability status of the item at this time.
90 NAObjectItem
*current_item
;
97 * This is the profile which is displayed in tab Command;
98 * it may be different of the exact row being currently selected,
99 * e.g. when an action with only one profile is selected.
101 * Can be null if @current_item is a menu, or an action with more
102 * than one profile is selected, or the list is empty, or in the
103 * case of a multiple selection.
105 * In other words, it is not null if:
106 * a) a profile is selected,
107 * b) an action is selected and it has exactly one profile.
109 NAObjectProfile
*current_profile
;
114 * This is the #NAIContext data which corresponds to @current_profile
115 * or @current_item, depending of which one is actually selected.
117 NAIContext
*current_context
;
120 * Some convenience objects and data.
122 NactTreeView
*items_view
;
123 gboolean is_tree_modified
;
124 NactClipboard
*clipboard
;
125 NactMenubar
*menubar
;
127 gulong pivot_handler_id
;
128 NATimeout pivot_timeout
;
131 /* properties set against the main window
132 * these are set on selection changes
138 MAIN_PROP_PROFILE_ID
,
139 MAIN_PROP_CONTEXT_ID
,
140 MAIN_PROP_EDITABLE_ID
,
143 MAIN_PROP_N_PROPERTIES
155 static const gchar
*st_xmlui_filename
= PKGDATADIR
"/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
;
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 };
163 static GType
register_type( void );
164 static void class_init( NactMainWindowClass
*klass
);
165 static void iaction_tab_iface_init( NactIActionTabInterface
*iface
);
166 static void icommand_tab_iface_init( NactICommandTabInterface
*iface
);
167 static void ibasenames_tab_iface_init( NactIBasenamesTabInterface
*iface
);
168 static void imimetypes_tab_iface_init( NactIMimetypesTabInterface
*iface
);
169 static void ifolders_tab_iface_init( NactIFoldersTabInterface
*iface
);
170 static void ischemes_tab_iface_init( NactISchemesTabInterface
*iface
);
171 static void icapabilities_tab_iface_init( NactICapabilitiesTabInterface
*iface
);
172 static void ienvironment_tab_iface_init( NactIEnvironmentTabInterface
*iface
);
173 static void iexecution_tab_iface_init( NactIExecutionTabInterface
*iface
);
174 static void iproperties_tab_iface_init( NactIPropertiesTabInterface
*iface
);
175 static void iabout_iface_init( NAIAboutInterface
*iface
);
176 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
177 static void instance_get_property( GObject
*object
, guint property_id
, GValue
*value
, GParamSpec
*spec
);
178 static void instance_set_property( GObject
*object
, guint property_id
, const GValue
*value
, GParamSpec
*spec
);
179 static void instance_constructed( GObject
*application
);
180 static void instance_dispose( GObject
*application
);
181 static void instance_finalize( GObject
*application
);
183 static void on_base_initialize_gtk_toplevel( NactMainWindow
*window
, GtkWindow
*toplevel
, gpointer user_data
);
184 static void on_base_initialize_base_window( NactMainWindow
*window
, gpointer user_data
);
185 static void on_base_all_widgets_showed( NactMainWindow
*window
, gpointer user_data
);
187 static void on_block_items_changed_timeout( NactMainWindow
*window
);
188 static void on_tree_view_modified_status_changed( NactMainWindow
*window
, gboolean is_modified
, gpointer user_data
);
189 static void on_tree_view_selection_changed( NactMainWindow
*window
, GList
*selected_items
, gpointer user_data
);
190 static void on_selection_changed_cleanup_handler( BaseWindow
*window
, GList
*selected_items
);
191 static void on_tab_updatable_item_updated( NactMainWindow
*window
, NAIContext
*context
, guint data
, gpointer user_data
);
192 static void raz_selection_properties( NactMainWindow
*window
);
193 static void setup_current_selection( NactMainWindow
*window
, NAObjectId
*selected_row
);
194 static void setup_dialog_title( NactMainWindow
*window
);
195 static void setup_writability_status( NactMainWindow
*window
);
197 /* items have changed */
198 static void on_pivot_items_changed( NAUpdater
*updater
, NactMainWindow
*window
);
199 static gboolean
confirm_for_giveup_from_pivot( const NactMainWindow
*window
);
200 static gboolean
confirm_for_giveup_from_menu( const NactMainWindow
*window
);
201 static void load_or_reload_items( NactMainWindow
*window
);
203 /* application termination */
204 static gboolean
on_base_is_willing_to_quit( const BaseWindow
*window
, gconstpointer user_data
);
205 static gboolean
on_delete_event( GtkWidget
*toplevel
, GdkEvent
*event
, NactMainWindow
*window
);
206 static gboolean
warn_modified( NactMainWindow
*window
);
208 /* NAIAbout interface */
209 static gchar
*iabout_get_application_name( NAIAbout
*instance
);
210 static GtkWindow
*iabout_get_toplevel( NAIAbout
*instance
);
214 nact_main_window_get_type( void )
216 static GType window_type
= 0;
219 window_type
= register_type();
222 return( window_type
);
226 register_type( void )
228 static const gchar
*thisfn
= "nact_main_window_register_type";
231 static GTypeInfo info
= {
232 sizeof( NactMainWindowClass
),
233 ( GBaseInitFunc
) NULL
,
234 ( GBaseFinalizeFunc
) NULL
,
235 ( GClassInitFunc
) class_init
,
238 sizeof( NactMainWindow
),
240 ( GInstanceInitFunc
) instance_init
243 static const GInterfaceInfo iaction_tab_iface_info
= {
244 ( GInterfaceInitFunc
) iaction_tab_iface_init
,
249 static const GInterfaceInfo icommand_tab_iface_info
= {
250 ( GInterfaceInitFunc
) icommand_tab_iface_init
,
255 static const GInterfaceInfo ibasenames_tab_iface_info
= {
256 ( GInterfaceInitFunc
) ibasenames_tab_iface_init
,
261 static const GInterfaceInfo imimetypes_tab_iface_info
= {
262 ( GInterfaceInitFunc
) imimetypes_tab_iface_init
,
267 static const GInterfaceInfo ifolders_tab_iface_info
= {
268 ( GInterfaceInitFunc
) ifolders_tab_iface_init
,
273 static const GInterfaceInfo ischemes_tab_iface_info
= {
274 ( GInterfaceInitFunc
) ischemes_tab_iface_init
,
279 static const GInterfaceInfo icapabilities_tab_iface_info
= {
280 ( GInterfaceInitFunc
) icapabilities_tab_iface_init
,
285 static const GInterfaceInfo ienvironment_tab_iface_info
= {
286 ( GInterfaceInitFunc
) ienvironment_tab_iface_init
,
291 static const GInterfaceInfo iexecution_tab_iface_info
= {
292 ( GInterfaceInitFunc
) iexecution_tab_iface_init
,
297 static const GInterfaceInfo iproperties_tab_iface_info
= {
298 ( GInterfaceInitFunc
) iproperties_tab_iface_init
,
303 static const GInterfaceInfo iabout_iface_info
= {
304 ( GInterfaceInitFunc
) iabout_iface_init
,
309 g_debug( "%s", thisfn
);
311 type
= g_type_register_static( BASE_WINDOW_TYPE
, "NactMainWindow", &info
, 0 );
313 g_type_add_interface_static( type
, NACT_IACTION_TAB_TYPE
, &iaction_tab_iface_info
);
315 g_type_add_interface_static( type
, NACT_ICOMMAND_TAB_TYPE
, &icommand_tab_iface_info
);
317 g_type_add_interface_static( type
, NACT_IBASENAMES_TAB_TYPE
, &ibasenames_tab_iface_info
);
319 g_type_add_interface_static( type
, NACT_IMIMETYPES_TAB_TYPE
, &imimetypes_tab_iface_info
);
321 g_type_add_interface_static( type
, NACT_IFOLDERS_TAB_TYPE
, &ifolders_tab_iface_info
);
323 g_type_add_interface_static( type
, NACT_ISCHEMES_TAB_TYPE
, &ischemes_tab_iface_info
);
325 g_type_add_interface_static( type
, NACT_ICAPABILITIES_TAB_TYPE
, &icapabilities_tab_iface_info
);
327 g_type_add_interface_static( type
, NACT_IENVIRONMENT_TAB_TYPE
, &ienvironment_tab_iface_info
);
329 g_type_add_interface_static( type
, NACT_IEXECUTION_TAB_TYPE
, &iexecution_tab_iface_info
);
331 g_type_add_interface_static( type
, NACT_IPROPERTIES_TAB_TYPE
, &iproperties_tab_iface_info
);
333 g_type_add_interface_static( type
, NA_IABOUT_TYPE
, &iabout_iface_info
);
339 class_init( NactMainWindowClass
*klass
)
341 static const gchar
*thisfn
= "nact_main_window_class_init";
342 GObjectClass
*object_class
;
344 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
346 st_parent_class
= g_type_class_peek_parent( klass
);
348 object_class
= G_OBJECT_CLASS( klass
);
349 object_class
->set_property
= instance_set_property
;
350 object_class
->get_property
= instance_get_property
;
351 object_class
->constructed
= instance_constructed
;
352 object_class
->dispose
= instance_dispose
;
353 object_class
->finalize
= instance_finalize
;
355 g_object_class_install_property( object_class
, MAIN_PROP_ITEM_ID
,
356 g_param_spec_pointer(
358 "Current NAObjectItem",
359 "A pointer to the currently edited NAObjectItem, an action or a menu",
360 G_PARAM_STATIC_STRINGS
| G_PARAM_READWRITE
));
362 g_object_class_install_property( object_class
, MAIN_PROP_PROFILE_ID
,
363 g_param_spec_pointer(
365 "Current NAObjectProfile",
366 "A pointer to the currently edited NAObjectProfile",
367 G_PARAM_STATIC_STRINGS
| G_PARAM_READWRITE
));
369 g_object_class_install_property( object_class
, MAIN_PROP_CONTEXT_ID
,
370 g_param_spec_pointer(
372 "Current NAIContext",
373 "A pointer to the currently edited NAIContext",
374 G_PARAM_STATIC_STRINGS
| G_PARAM_READWRITE
));
376 g_object_class_install_property( object_class
, MAIN_PROP_EDITABLE_ID
,
377 g_param_spec_boolean(
380 "Whether the item will be able to be updated against its I/O provider", FALSE
,
381 G_PARAM_STATIC_STRINGS
| G_PARAM_READWRITE
));
383 g_object_class_install_property( object_class
, MAIN_PROP_REASON_ID
,
387 "Why is this item not editable", 0, 255, 0,
388 G_PARAM_STATIC_STRINGS
| G_PARAM_READWRITE
));
390 klass
->private = g_new0( NactMainWindowClassPrivate
, 1 );
393 * NactMainWindow::main-item-updated:
395 * This signal is emitted on the BaseWindow when the item has been modified
396 * elsewhere that in a tab. The tabs should so update accordingly their
400 * - an OR-ed list of the modified data, or 0 if not relevant.
402 st_signals
[ MAIN_ITEM_UPDATED
] = g_signal_new(
403 MAIN_SIGNAL_ITEM_UPDATED
,
406 0, /* no default handler */
409 nact_cclosure_marshal_VOID__POINTER_UINT
,
416 * nact-tab-updatable-item-updated:
418 * This signal is emitted by the notebook tabs, when any property
419 * of an item has been modified.
422 * - an OR-ed list of the modified data, or 0 if not relevant.
424 * This main window is rather the only consumer of this message,
425 * does its tricks (title, etc.), and then reforward an item-updated
426 * message to IActionsList.
428 st_signals
[ TAB_ITEM_UPDATED
] = g_signal_new(
429 TAB_UPDATABLE_SIGNAL_ITEM_UPDATED
,
432 0, /* no default handler */
435 nact_cclosure_marshal_VOID__POINTER_UINT
,
442 * NactMainWindow::main-selection-changed:
444 * This signal is emitted on the window parent each time the selection
445 * has changed in the treeview, after having set the current item/profile/
446 * context properties.
448 * This way, we are sure that notebook edition tabs which required to
449 * have a current item/profile/context will have it, whenever they have
450 * connected to the 'selection-changed' signal.
453 * - a #GList of currently selected #NAObjectItems.
456 * void ( *handler )( BaseWindow *window, GList *selected, gpointer user_data );
458 st_signals
[ SELECTION_CHANGED
] = g_signal_new_class_handler(
459 MAIN_SIGNAL_SELECTION_CHANGED
,
461 G_SIGNAL_RUN_CLEANUP
,
462 G_CALLBACK( on_selection_changed_cleanup_handler
),
465 g_cclosure_marshal_VOID__POINTER
,
472 iaction_tab_iface_init( NactIActionTabInterface
*iface
)
474 static const gchar
*thisfn
= "nact_main_window_iaction_tab_iface_init";
476 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
480 icommand_tab_iface_init( NactICommandTabInterface
*iface
)
482 static const gchar
*thisfn
= "nact_main_window_icommand_tab_iface_init";
484 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
488 ibasenames_tab_iface_init( NactIBasenamesTabInterface
*iface
)
490 static const gchar
*thisfn
= "nact_main_window_ibasenames_tab_iface_init";
492 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
496 imimetypes_tab_iface_init( NactIMimetypesTabInterface
*iface
)
498 static const gchar
*thisfn
= "nact_main_window_imimetypes_tab_iface_init";
500 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
504 ifolders_tab_iface_init( NactIFoldersTabInterface
*iface
)
506 static const gchar
*thisfn
= "nact_main_window_ifolders_tab_iface_init";
508 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
512 ischemes_tab_iface_init( NactISchemesTabInterface
*iface
)
514 static const gchar
*thisfn
= "nact_main_window_ischemes_tab_iface_init";
516 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
520 icapabilities_tab_iface_init( NactICapabilitiesTabInterface
*iface
)
522 static const gchar
*thisfn
= "nact_main_window_icapabilities_tab_iface_init";
524 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
528 ienvironment_tab_iface_init( NactIEnvironmentTabInterface
*iface
)
530 static const gchar
*thisfn
= "nact_main_window_ienvironment_tab_iface_init";
532 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
536 iexecution_tab_iface_init( NactIExecutionTabInterface
*iface
)
538 static const gchar
*thisfn
= "nact_main_window_iexecution_tab_iface_init";
540 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
544 iproperties_tab_iface_init( NactIPropertiesTabInterface
*iface
)
546 static const gchar
*thisfn
= "nact_main_window_iproperties_tab_iface_init";
548 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
552 iabout_iface_init( NAIAboutInterface
*iface
)
554 static const gchar
*thisfn
= "nact_main_window_iabout_iface_init";
556 g_debug( "%s: iface=%p", thisfn
, ( void * ) iface
);
558 iface
->get_application_name
= iabout_get_application_name
;
559 iface
->get_toplevel
= iabout_get_toplevel
;
563 instance_init( GTypeInstance
*instance
, gpointer klass
)
565 static const gchar
*thisfn
= "nact_main_window_instance_init";
566 NactMainWindow
*self
;
568 g_return_if_fail( NACT_IS_MAIN_WINDOW( instance
));
570 g_debug( "%s: instance=%p (%s), klass=%p",
571 thisfn
, ( void * ) instance
, G_OBJECT_TYPE_NAME( instance
), ( void * ) klass
);
573 self
= NACT_MAIN_WINDOW( instance
);
575 self
->private = g_new0( NactMainWindowPrivate
, 1 );
577 self
->private->dispose_has_run
= FALSE
;
579 /* initialize timeout parameters when blocking 'pivot-items-changed' handler
581 self
->private->pivot_timeout
.timeout
= st_burst_timeout
;
582 self
->private->pivot_timeout
.handler
= ( NATimeoutFunc
) on_block_items_changed_timeout
;
583 self
->private->pivot_timeout
.user_data
= self
;
584 self
->private->pivot_timeout
.source_id
= 0;
588 instance_get_property( GObject
*object
, guint property_id
, GValue
*value
, GParamSpec
*spec
)
590 NactMainWindow
*self
;
592 g_return_if_fail( NACT_IS_MAIN_WINDOW( object
));
593 self
= NACT_MAIN_WINDOW( object
);
595 if( !self
->private->dispose_has_run
){
597 switch( property_id
){
598 case MAIN_PROP_ITEM_ID
:
599 g_value_set_pointer( value
, self
->private->current_item
);
602 case MAIN_PROP_PROFILE_ID
:
603 g_value_set_pointer( value
, self
->private->current_profile
);
606 case MAIN_PROP_CONTEXT_ID
:
607 g_value_set_pointer( value
, self
->private->current_context
);
610 case MAIN_PROP_EDITABLE_ID
:
611 g_value_set_boolean( value
, self
->private->editable
);
614 case MAIN_PROP_REASON_ID
:
615 g_value_set_int( value
, self
->private->reason
);
619 G_OBJECT_WARN_INVALID_PROPERTY_ID( object
, property_id
, spec
);
626 instance_set_property( GObject
*object
, guint property_id
, const GValue
*value
, GParamSpec
*spec
)
628 NactMainWindow
*self
;
630 g_return_if_fail( NACT_IS_MAIN_WINDOW( object
));
631 self
= NACT_MAIN_WINDOW( object
);
633 if( !self
->private->dispose_has_run
){
635 switch( property_id
){
636 case MAIN_PROP_ITEM_ID
:
637 self
->private->current_item
= g_value_get_pointer( value
);
640 case MAIN_PROP_PROFILE_ID
:
641 self
->private->current_profile
= g_value_get_pointer( value
);
644 case MAIN_PROP_CONTEXT_ID
:
645 self
->private->current_context
= g_value_get_pointer( value
);
648 case MAIN_PROP_EDITABLE_ID
:
649 self
->private->editable
= g_value_get_boolean( value
);
652 case MAIN_PROP_REASON_ID
:
653 self
->private->reason
= g_value_get_int( value
);
657 G_OBJECT_WARN_INVALID_PROPERTY_ID( object
, property_id
, spec
);
664 instance_constructed( GObject
*window
)
666 static const gchar
*thisfn
= "nact_main_window_instance_constructed";
667 NactMainWindow
*self
;
668 NactApplication
*application
;
670 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
672 self
= NACT_MAIN_WINDOW( window
);
674 if( !self
->private->dispose_has_run
){
675 g_debug( "%s: window=%p (%s)", thisfn
, ( void * ) window
, G_OBJECT_TYPE_NAME( window
));
677 /* first connect to BaseWindow signals
678 * so that convenience objects instanciated later will have this same signal
679 * triggered after the one of NactMainWindow
681 base_window_signal_connect( BASE_WINDOW( window
),
682 G_OBJECT( window
), BASE_SIGNAL_INITIALIZE_GTK
, G_CALLBACK( on_base_initialize_gtk_toplevel
));
684 base_window_signal_connect( BASE_WINDOW( window
),
685 G_OBJECT( window
), BASE_SIGNAL_INITIALIZE_WINDOW
, G_CALLBACK( on_base_initialize_base_window
));
687 base_window_signal_connect( BASE_WINDOW( window
),
688 G_OBJECT( window
), BASE_SIGNAL_ALL_WIDGETS_SHOWED
, G_CALLBACK( on_base_all_widgets_showed
));
690 application
= NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window
)));
691 self
->private->updater
= nact_application_get_updater( application
);
693 self
->private->pivot_handler_id
= base_window_signal_connect( BASE_WINDOW( window
),
694 G_OBJECT( self
->private->updater
), PIVOT_SIGNAL_ITEMS_CHANGED
, G_CALLBACK( on_pivot_items_changed
));
696 base_window_signal_connect( BASE_WINDOW( window
),
697 G_OBJECT( window
), TAB_UPDATABLE_SIGNAL_ITEM_UPDATED
, G_CALLBACK( on_tab_updatable_item_updated
));
699 /* create the tree view which will create itself its own tree model
701 self
->private->items_view
= nact_tree_view_new( BASE_WINDOW( window
), "ActionsList", TREE_MODE_EDITION
);
703 base_window_signal_connect( BASE_WINDOW( window
),
704 G_OBJECT( window
), TREE_SIGNAL_SELECTION_CHANGED
, G_CALLBACK( on_tree_view_selection_changed
));
706 base_window_signal_connect( BASE_WINDOW( window
),
707 G_OBJECT( window
), TREE_SIGNAL_MODIFIED_STATUS_CHANGED
, G_CALLBACK( on_tree_view_modified_status_changed
));
709 /* create the menubar and other convenience objects
711 self
->private->menubar
= nact_menubar_new( BASE_WINDOW( window
));
712 self
->private->clipboard
= nact_clipboard_new( BASE_WINDOW( window
));
714 /* chain up to the parent class */
715 if( G_OBJECT_CLASS( st_parent_class
)->constructed
){
716 G_OBJECT_CLASS( st_parent_class
)->constructed( window
);
722 instance_dispose( GObject
*window
)
724 static const gchar
*thisfn
= "nact_main_window_instance_dispose";
725 NactMainWindow
*self
;
728 NASettings
*settings
;
730 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
732 self
= NACT_MAIN_WINDOW( window
);
734 if( !self
->private->dispose_has_run
){
735 g_debug( "%s: window=%p (%s)", thisfn
, ( void * ) window
, G_OBJECT_TYPE_NAME( window
));
737 self
->private->dispose_has_run
= TRUE
;
739 g_object_unref( self
->private->clipboard
);
740 g_object_unref( self
->private->menubar
);
742 settings
= na_pivot_get_settings( NA_PIVOT( self
->private->updater
));
744 pane
= base_window_get_widget( BASE_WINDOW( window
), "MainPaned" );
745 pos
= gtk_paned_get_position( GTK_PANED( pane
));
746 na_settings_set_uint( settings
, NA_IPREFS_MAIN_PANED
, pos
);
748 nact_iaction_tab_dispose( NACT_IACTION_TAB( window
));
749 nact_icommand_tab_dispose( NACT_ICOMMAND_TAB( window
));
750 nact_ibasenames_tab_dispose( NACT_IBASENAMES_TAB( window
));
751 nact_imimetypes_tab_dispose( NACT_IMIMETYPES_TAB( window
));
752 nact_ifolders_tab_dispose( NACT_IFOLDERS_TAB( window
));
753 nact_ischemes_tab_dispose( NACT_ISCHEMES_TAB( window
));
754 nact_icapabilities_tab_dispose( NACT_ICAPABILITIES_TAB( window
));
755 nact_ienvironment_tab_dispose( NACT_IENVIRONMENT_TAB( window
));
756 nact_iexecution_tab_dispose( NACT_IEXECUTION_TAB( window
));
757 nact_iproperties_tab_dispose( NACT_IPROPERTIES_TAB( window
));
759 /* unref items view at last as gtk_tree_model_store_clear() will
760 * finalize all objects, thus invaliditing all our references
762 g_object_unref( self
->private->items_view
);
764 /* chain up to the parent class */
765 if( G_OBJECT_CLASS( st_parent_class
)->dispose
){
766 G_OBJECT_CLASS( st_parent_class
)->dispose( window
);
772 instance_finalize( GObject
*window
)
774 static const gchar
*thisfn
= "nact_main_window_instance_finalize";
775 NactMainWindow
*self
;
777 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
779 g_debug( "%s: window=%p (%s)", thisfn
, ( void * ) window
, G_OBJECT_TYPE_NAME( window
));
781 self
= NACT_MAIN_WINDOW( window
);
783 g_free( self
->private );
785 /* chain call to parent class */
786 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
787 G_OBJECT_CLASS( st_parent_class
)->finalize( window
);
792 * Returns a newly allocated NactMainWindow object.
795 nact_main_window_new( const NactApplication
*application
)
797 NactMainWindow
*window
;
799 g_return_val_if_fail( NACT_IS_APPLICATION( application
), NULL
);
801 window
= g_object_new( NACT_MAIN_WINDOW_TYPE
,
802 BASE_PROP_APPLICATION
, application
,
803 BASE_PROP_XMLUI_FILENAME
, st_xmlui_filename
,
804 BASE_PROP_TOPLEVEL_NAME
, st_toplevel_name
,
805 BASE_PROP_WSP_NAME
, st_wsp_name
,
812 * note that for this NactMainWindow, on_base_initialize_gtk_toplevel() and
813 * on_base_initialize_base_window() are roughly equivalent, as there is only
814 * one occurrence on this window in the application: closing this window
815 * is the same than quitting the application
818 on_base_initialize_gtk_toplevel( NactMainWindow
*window
, GtkWindow
*toplevel
, gpointer user_data
)
820 static const gchar
*thisfn
= "nact_main_window_on_base_initialize_gtk_toplevel";
822 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
824 if( !window
->private->dispose_has_run
){
825 g_debug( "%s: window=%p, toplevel=%p, user_data=%p",
826 thisfn
, ( void * ) window
, ( void * ) toplevel
, ( void * ) user_data
);
828 nact_iaction_tab_initial_load_toplevel( NACT_IACTION_TAB( window
));
829 nact_icommand_tab_initial_load_toplevel( NACT_ICOMMAND_TAB( window
));
830 nact_ibasenames_tab_initial_load_toplevel( NACT_IBASENAMES_TAB( window
));
831 nact_imimetypes_tab_initial_load_toplevel( NACT_IMIMETYPES_TAB( window
));
832 nact_ifolders_tab_initial_load_toplevel( NACT_IFOLDERS_TAB( window
));
833 nact_ischemes_tab_initial_load_toplevel( NACT_ISCHEMES_TAB( window
));
834 nact_icapabilities_tab_initial_load_toplevel( NACT_ICAPABILITIES_TAB( window
));
835 nact_ienvironment_tab_initial_load_toplevel( NACT_IENVIRONMENT_TAB( window
));
836 nact_iexecution_tab_initial_load_toplevel( NACT_IEXECUTION_TAB( window
));
837 nact_iproperties_tab_initial_load_toplevel( NACT_IPROPERTIES_TAB( window
));
839 nact_main_statusbar_initialize_gtk_toplevel( window
);
844 on_base_initialize_base_window( NactMainWindow
*window
, gpointer user_data
)
846 static const gchar
*thisfn
= "nact_main_window_on_base_initialize_base_window";
847 NASettings
*settings
;
851 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
853 if( !window
->private->dispose_has_run
){
854 g_debug( "%s: window=%p, user_data=%p", thisfn
, ( void * ) window
, ( void * ) user_data
);
856 settings
= na_pivot_get_settings( NA_PIVOT( window
->private->updater
));
858 pos
= na_settings_get_uint( settings
, NA_IPREFS_MAIN_PANED
, NULL
, NULL
);
860 pane
= base_window_get_widget( BASE_WINDOW( window
), "MainPaned" );
861 gtk_paned_set_position( GTK_PANED( pane
), pos
);
864 nact_iaction_tab_runtime_init_toplevel( NACT_IACTION_TAB( window
));
865 nact_icommand_tab_runtime_init_toplevel( NACT_ICOMMAND_TAB( window
));
866 nact_ibasenames_tab_runtime_init_toplevel( NACT_IBASENAMES_TAB( window
));
867 nact_imimetypes_tab_runtime_init_toplevel( NACT_IMIMETYPES_TAB( window
));
868 nact_ifolders_tab_runtime_init_toplevel( NACT_IFOLDERS_TAB( window
));
869 nact_ischemes_tab_runtime_init_toplevel( NACT_ISCHEMES_TAB( window
));
870 nact_icapabilities_tab_runtime_init_toplevel( NACT_ICAPABILITIES_TAB( window
));
871 nact_ienvironment_tab_runtime_init_toplevel( NACT_IENVIRONMENT_TAB( window
));
872 nact_iexecution_tab_runtime_init_toplevel( NACT_IEXECUTION_TAB( window
));
873 nact_iproperties_tab_runtime_init_toplevel( NACT_IPROPERTIES_TAB( window
));
875 /* terminate the application by clicking the top right [X] button
877 base_window_signal_connect( BASE_WINDOW( window
),
878 G_OBJECT( base_window_get_gtk_toplevel( BASE_WINDOW( window
))),
879 "delete-event", G_CALLBACK( on_delete_event
));
881 /* is willing to quit ?
883 base_window_signal_connect( BASE_WINDOW( window
),
884 G_OBJECT( window
), BASE_SIGNAL_WILLING_TO_QUIT
, G_CALLBACK( on_base_is_willing_to_quit
));
889 on_base_all_widgets_showed( NactMainWindow
*window
, gpointer user_data
)
891 static const gchar
*thisfn
= "nact_main_window_on_base_all_widgets_showed";
893 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
894 g_return_if_fail( NACT_IS_IACTION_TAB( window
));
895 g_return_if_fail( NACT_IS_ICOMMAND_TAB( window
));
896 g_return_if_fail( NACT_IS_IBASENAMES_TAB( window
));
897 g_return_if_fail( NACT_IS_IMIMETYPES_TAB( window
));
898 g_return_if_fail( NACT_IS_IFOLDERS_TAB( window
));
899 g_return_if_fail( NACT_IS_ISCHEMES_TAB( window
));
900 g_return_if_fail( NACT_IS_IENVIRONMENT_TAB( window
));
901 g_return_if_fail( NACT_IS_IEXECUTION_TAB( window
));
902 g_return_if_fail( NACT_IS_IPROPERTIES_TAB( window
));
904 if( !window
->private->dispose_has_run
){
905 g_debug( "%s: window=%p, user_data=%p", thisfn
, ( void * ) window
, ( void * ) user_data
);
907 nact_iaction_tab_all_widgets_showed( NACT_IACTION_TAB( window
));
908 nact_icommand_tab_all_widgets_showed( NACT_ICOMMAND_TAB( window
));
909 nact_ibasenames_tab_all_widgets_showed( NACT_IBASENAMES_TAB( window
));
910 nact_imimetypes_tab_all_widgets_showed( NACT_IMIMETYPES_TAB( window
));
911 nact_ifolders_tab_all_widgets_showed( NACT_IFOLDERS_TAB( window
));
912 nact_ischemes_tab_all_widgets_showed( NACT_ISCHEMES_TAB( window
));
913 nact_icapabilities_tab_all_widgets_showed( NACT_ICAPABILITIES_TAB( window
));
914 nact_ienvironment_tab_all_widgets_showed( NACT_IENVIRONMENT_TAB( window
));
915 nact_iexecution_tab_all_widgets_showed( NACT_IEXECUTION_TAB( window
));
916 nact_iproperties_tab_all_widgets_showed( NACT_IPROPERTIES_TAB( window
));
918 load_or_reload_items( window
);
923 * nact_main_window_get_clipboard:
924 * @window: this #NactMainWindow instance.
926 * Returns: the #NactClipboard convenience object.
929 nact_main_window_get_clipboard( const NactMainWindow
*window
)
931 NactClipboard
*clipboard
;
933 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window
), NULL
);
937 if( !window
->private->dispose_has_run
){
939 clipboard
= window
->private->clipboard
;
946 * nact_main_window_get_items_view:
947 * @window: this #NactMainWindow instance.
949 * Returns: The #NactTreeView convenience object.
952 nact_main_window_get_items_view( const NactMainWindow
*window
)
956 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window
), NULL
);
960 if( !window
->private->dispose_has_run
){
962 view
= window
->private->items_view
;
969 * nact_main_window_reload:
970 * @window: this #NactMainWindow instance.
972 * Refresh the list of items.
973 * If there is some non-yet saved modifications, a confirmation is
974 * required before giving up with them.
977 nact_main_window_reload( NactMainWindow
*window
)
981 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
983 if( !window
->private->dispose_has_run
){
985 reload_ok
= confirm_for_giveup_from_menu( window
);
988 load_or_reload_items( window
);
994 * nact_main_window_block_reload:
995 * @window: this #NactMainWindow instance.
997 * Temporarily blocks the handling of pivot-items-changed signal.
1000 nact_main_window_block_reload( NactMainWindow
*window
)
1002 static const gchar
*thisfn
= "nact_main_window_block_reload";
1004 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
1006 if( !window
->private->dispose_has_run
){
1008 g_debug( "%s: blocking %s signal", thisfn
, PIVOT_SIGNAL_ITEMS_CHANGED
);
1009 g_signal_handler_block( window
->private->updater
, window
->private->pivot_handler_id
);
1010 na_timeout_event( &window
->private->pivot_timeout
);
1015 on_block_items_changed_timeout( NactMainWindow
*window
)
1017 static const gchar
*thisfn
= "nact_main_window_on_block_items_changed_timeout";
1019 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
1021 g_debug( "%s: unblocking %s signal", thisfn
, PIVOT_SIGNAL_ITEMS_CHANGED
);
1022 g_signal_handler_unblock( window
->private->updater
, window
->private->pivot_handler_id
);
1026 * the modification status of the items view has changed
1029 on_tree_view_modified_status_changed( NactMainWindow
*window
, gboolean is_modified
, gpointer user_data
)
1031 static const gchar
*thisfn
= "nact_main_window_on_tree_view_modified_status_changed";
1033 g_debug( "%s: window=%p, is_modified=%s, user_data=%p",
1034 thisfn
, ( void * ) window
, is_modified
? "True":"False", ( void * ) user_data
);
1036 if( !window
->private->dispose_has_run
){
1038 window
->private->is_tree_modified
= is_modified
;
1039 setup_dialog_title( window
);
1044 * tree view selection has changed
1047 on_tree_view_selection_changed( NactMainWindow
*window
, GList
*selected_items
, gpointer user_data
)
1049 static const gchar
*thisfn
= "nact_main_window_on_tree_view_selection_changed";
1052 count
= g_list_length( selected_items
);
1054 if( !window
->private->dispose_has_run
){
1055 g_debug( "%s: window=%p, selected_items=%p (count=%d), user_data=%p",
1056 thisfn
, ( void * ) window
,
1057 ( void * ) selected_items
, count
, ( void * ) user_data
);
1059 raz_selection_properties( window
);
1062 g_return_if_fail( NA_IS_OBJECT_ID( selected_items
->data
));
1063 setup_current_selection( window
, NA_OBJECT_ID( selected_items
->data
));
1064 setup_writability_status( window
);
1067 setup_dialog_title( window
);
1069 g_signal_emit_by_name( G_OBJECT( window
),
1070 MAIN_SIGNAL_SELECTION_CHANGED
, na_object_copyref_items( selected_items
));
1075 * cleanup handler for our MAIN_SIGNAL_SELECTION_CHANGED signal
1078 on_selection_changed_cleanup_handler( BaseWindow
*window
, GList
*selected_items
)
1080 static const gchar
*thisfn
= "nact_main_window_on_selection_changed_cleanup_handler";
1082 g_debug( "%s: window=%p, selected_items=%p (count=%u)",
1083 thisfn
, ( void * ) window
,
1084 ( void * ) selected_items
, g_list_length( selected_items
));
1086 na_object_free_items( selected_items
);
1090 on_tab_updatable_item_updated( NactMainWindow
*window
, NAIContext
*context
, guint data
, gpointer user_data
)
1092 static const gchar
*thisfn
= "nact_main_window_on_tab_updatable_item_updated";
1094 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
1096 if( !window
->private->dispose_has_run
){
1097 g_debug( "%s: window=%p, context=%p (%s), data=%u, user_data=%p",
1098 thisfn
, ( void * ) window
, ( void * ) context
, G_OBJECT_TYPE_NAME( context
),
1099 data
, ( void * ) user_data
);
1102 na_object_check_status( context
);
1108 raz_selection_properties( NactMainWindow
*window
)
1110 window
->private->current_item
= NULL
;
1111 window
->private->current_profile
= NULL
;
1112 window
->private->current_context
= NULL
;
1113 window
->private->editable
= FALSE
;
1114 window
->private->reason
= 0;
1116 nact_main_statusbar_set_locked( window
, FALSE
, 0 );
1120 * enter after raz_properties
1121 * only called when only one selected row
1124 setup_current_selection( NactMainWindow
*window
, NAObjectId
*selected_row
)
1129 if( NA_IS_OBJECT_PROFILE( selected_row
)){
1130 window
->private->current_profile
= NA_OBJECT_PROFILE( selected_row
);
1131 window
->private->current_item
= NA_OBJECT_ITEM( na_object_get_parent( selected_row
));
1134 g_return_if_fail( NA_IS_OBJECT_ITEM( selected_row
));
1135 window
->private->current_item
= NA_OBJECT_ITEM( selected_row
);
1136 window
->private->current_context
= NA_ICONTEXT( selected_row
);
1138 if( NA_IS_OBJECT_ACTION( selected_row
)){
1139 nb_profiles
= na_object_get_items_count( selected_row
);
1141 if( nb_profiles
== 1 ){
1142 profiles
= na_object_get_items( selected_row
);
1143 window
->private->current_profile
= NA_OBJECT_PROFILE( profiles
->data
);
1144 window
->private->current_context
= NA_ICONTEXT( profiles
->data
);
1151 * the title bar of the main window brings up three informations:
1152 * - the name of the application
1153 * - the name of the currently selected item if there is only one
1154 * - an asterisk if anything has been modified
1157 setup_dialog_title( NactMainWindow
*window
)
1159 static const gchar
*thisfn
= "nact_main_window_setup_dialog_title";
1160 GtkWindow
*toplevel
;
1161 NactApplication
*application
;
1165 gboolean is_modified
;
1167 g_debug( "%s: window=%p", thisfn
, ( void * ) window
);
1169 application
= NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window
)));
1170 title
= base_application_get_application_name( BASE_APPLICATION( application
));
1172 if( window
->private->current_item
){
1173 label
= na_object_get_label( window
->private->current_item
);
1174 is_modified
= na_object_is_modified( window
->private->current_item
);
1175 tmp
= g_strdup_printf( "%s%s - %s", is_modified
? "*" : "", label
, title
);
1181 toplevel
= base_window_get_gtk_toplevel( BASE_WINDOW( window
));
1182 gtk_window_set_title( toplevel
, title
);
1187 setup_writability_status( NactMainWindow
*window
)
1189 g_return_if_fail( NA_IS_OBJECT_ITEM( window
->private->current_item
));
1191 window
->private->editable
= na_updater_check_item_writability_status( window
->private->updater
, window
->private->current_item
, &window
->private->reason
);
1192 nact_main_statusbar_set_locked( window
, !window
->private->editable
, window
->private->reason
);
1196 * The handler of the signal sent by NAPivot when items have been modified
1197 * in the underlying storage subsystems
1200 on_pivot_items_changed( NAUpdater
*updater
, NactMainWindow
*window
)
1202 static const gchar
*thisfn
= "nact_main_window_on_pivot_items_changed";
1205 g_return_if_fail( NA_IS_UPDATER( updater
));
1206 g_return_if_fail( NACT_IS_MAIN_WINDOW( window
));
1208 if( !window
->private->dispose_has_run
){
1209 g_debug( "%s: updater=%p (%s), window=%p (%s)", thisfn
,
1210 ( void * ) updater
, G_OBJECT_TYPE_NAME( updater
),
1211 ( void * ) window
, G_OBJECT_TYPE_NAME( window
));
1213 reload_ok
= confirm_for_giveup_from_pivot( window
);
1216 load_or_reload_items( window
);
1222 * informs the user that the actions in underlying storage subsystem
1223 * have changed, and propose for reloading
1227 confirm_for_giveup_from_pivot( const NactMainWindow
*window
)
1230 gchar
*first
, *second
;
1233 _( "One or more actions have been modified in the filesystem.\n"
1234 "You could keep to work with your current list of actions, "
1235 "or you may want to reload a fresh one." ));
1237 if( window
->private->is_tree_modified
){
1239 gchar
*tmp
= g_strdup_printf( "%s\n\n%s", first
,
1240 _( "Note that reloading a fresh list of actions requires "
1241 "that you give up with your current modifications." ));
1246 second
= g_strdup( _( "Do you want to reload a fresh list of actions ?" ));
1248 reload_ok
= base_window_display_yesno_dlg( BASE_WINDOW( window
), first
, second
);
1253 return( reload_ok
);
1257 * requires a confirmation from the user when is has asked for reloading
1258 * the actions via the Edit menu
1261 confirm_for_giveup_from_menu( const NactMainWindow
*window
)
1263 gboolean reload_ok
= TRUE
;
1264 gchar
*first
, *second
;
1266 if( window
->private->is_tree_modified
){
1269 _( "Reloading a fresh list of actions requires "
1270 "that you give up with your current modifications." ));
1272 second
= g_strdup( _( "Do you really want to do this ?" ));
1274 reload_ok
= base_window_display_yesno_dlg( BASE_WINDOW( window
), first
, second
);
1280 return( reload_ok
);
1284 load_or_reload_items( NactMainWindow
*window
)
1286 static const gchar
*thisfn
= "nact_main_window_load_or_reload_items";
1289 g_debug( "%s: window=%p", thisfn
, ( void * ) window
);
1291 raz_selection_properties( window
);
1293 tree
= na_updater_load_items( window
->private->updater
);
1294 nact_tree_view_fill( window
->private->items_view
, tree
);
1296 g_debug( "%s: end of tree view filling", thisfn
);
1300 * nact_main_window_quit:
1301 * @window: the #NactMainWindow main window.
1303 * Quit the window, thus terminating the application.
1305 * Returns: %TRUE if the application will terminate, and the @window object
1306 * is no more valid; %FALSE if the application will continue to run.
1309 nact_main_window_quit( NactMainWindow
*window
)
1311 static const gchar
*thisfn
= "nact_main_window_quit";
1312 gboolean terminated
;
1314 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window
), FALSE
);
1318 if( !window
->private->dispose_has_run
){
1319 g_debug( "%s: window=%p (%s)", thisfn
, ( void * ) window
, G_OBJECT_TYPE_NAME( window
));
1321 if( !window
->private->is_tree_modified
|| warn_modified( window
)){
1322 g_object_unref( window
);
1327 return( terminated
);
1332 * should return %FALSE if it is not willing to quit
1333 * this will also stop the emission of the signal (i.e. the first FALSE wins)
1336 on_base_is_willing_to_quit( const BaseWindow
*window
, gconstpointer user_data
)
1338 static const gchar
*thisfn
= "nact_main_window_on_base_is_willing_to_quit";
1339 gboolean willing_to
;
1341 g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window
), TRUE
);
1345 if( !NACT_MAIN_WINDOW( window
)->private->dispose_has_run
){
1346 g_debug( "%s (virtual): window=%p", thisfn
, ( void * ) window
);
1348 if( NACT_MAIN_WINDOW( window
)->private->is_tree_modified
){
1349 willing_to
= nact_confirm_logout_run( NACT_MAIN_WINDOW( window
));
1353 return( willing_to
);
1357 * triggered when the user clicks on the top right [X] button
1358 * returns %TRUE to stop the signal to be propagated (which would cause the
1359 * window to be destroyed); instead we gracefully quit the application
1362 on_delete_event( GtkWidget
*toplevel
, GdkEvent
*event
, NactMainWindow
*window
)
1364 static const gchar
*thisfn
= "nact_main_window_on_delete_event";
1366 g_debug( "%s: toplevel=%p, event=%p, window=%p",
1367 thisfn
, ( void * ) toplevel
, ( void * ) event
, ( void * ) window
);
1369 nact_main_window_quit( window
);
1376 * @window: this #NactWindow instance.
1378 * Emits a warning if at least one item has been modified.
1380 * Returns: %TRUE if the user confirms he wants to quit.
1383 warn_modified( NactMainWindow
*window
)
1385 gboolean confirm
= FALSE
;
1389 first
= g_strdup_printf( _( "Some items have been modified." ));
1390 second
= g_strdup( _( "Are you sure you want to quit without saving them ?" ));
1392 confirm
= base_window_display_yesno_dlg( BASE_WINDOW( window
), first
, second
);
1401 iabout_get_application_name( NAIAbout
*instance
)
1403 BaseApplication
*application
;
1405 g_return_val_if_fail( NA_IS_IABOUT( instance
), NULL
);
1406 g_return_val_if_fail( BASE_IS_WINDOW( instance
), NULL
);
1408 application
= base_window_get_application( BASE_WINDOW( instance
));
1409 return( base_application_get_application_name( application
));
1413 iabout_get_toplevel( NAIAbout
*instance
)
1415 g_return_val_if_fail( NA_IS_IABOUT( instance
), NULL
);
1416 g_return_val_if_fail( BASE_IS_WINDOW( instance
), NULL
);
1418 return( base_window_get_gtk_toplevel( BASE_WINDOW( instance
)));