Fix invalid cast from NactMainWindow to NactTreeIEditable
[nautilus-actions.git] / src / nact / nact-menubar-edit.c
blob173d6369d09d59911709017b82ac0b2350e87f52
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 <glib/gi18n.h>
37 #include <api/na-core-utils.h>
39 #include <core/na-io-provider.h>
40 #include <core/na-iprefs.h>
42 #include "nact-application.h"
43 #include "nact-main-tab.h"
44 #include "nact-menubar-priv.h"
45 #include "nact-preferences-editor.h"
46 #include "nact-tree-ieditable.h"
48 static GList *prepare_for_paste( BaseWindow *window );
49 static GList *get_deletables( NAUpdater *updater, GList *tree, GSList **not_deletable );
50 static GSList *get_deletables_rec( NAUpdater *updater, GList *tree );
51 static gchar *add_non_deletable_msg( const NAObjectItem *item, gint reason );
52 static void update_clipboard_counters( BaseWindow *window );
54 /**
55 * nact_menubar_edit_on_update_sensitivities:
56 * @bar: this #NactMenubar object.
58 * Update sensitivity of items of the Edit menu.
60 * Each action (cut, copy, delete, etc.) takes itself care of whether it
61 * can safely apply to all the selection or not. The action can at least
62 * assume that at least one item will be a valid candidate (this is the
63 * Menubar rule).
65 void
66 nact_menubar_edit_on_update_sensitivities( const NactMenubar *bar )
68 gboolean cut_enabled;
69 gboolean copy_enabled;
70 gboolean paste_enabled;
71 gboolean paste_into_enabled;
72 gboolean duplicate_enabled;
73 gboolean delete_enabled;
74 NAObject *parent_item;
75 NAObject *selected_action;
76 NAObject *selected_item;
77 gboolean is_clipboard_empty;
79 is_clipboard_empty = ( bar->private->clipboard_menus + bar->private->clipboard_actions + bar->private->clipboard_profiles == 0 );
81 /* cut requires a non-empty selection
82 * and that the selection is writable (can be modified, i.e. is not read-only)
83 * and that all parents are writable (as implies a delete operation)
85 duplicate_enabled = bar->private->treeview_has_focus || bar->private->popup_handler;
86 duplicate_enabled &= bar->private->count_selected > 0;
87 duplicate_enabled &= bar->private->are_parents_writable;
88 cut_enabled = duplicate_enabled;
89 cut_enabled &= bar->private->are_items_writable;
90 nact_menubar_enable_item( bar, "CutItem", cut_enabled );
92 /* copy only requires a non-empty selection */
93 copy_enabled = bar->private->treeview_has_focus || bar->private->popup_handler;
94 copy_enabled &= bar->private->count_selected > 0;
95 nact_menubar_enable_item( bar, "CopyItem", copy_enabled );
97 /* paste enabled if
98 * - clipboard is not empty
99 * - current selection is not multiple
100 * - if clipboard contains only profiles,
101 * then current selection must be a profile or an action
102 * and the action must be writable
103 * - if clipboard contains actions or menus,
104 * then current selection (if any) must be a menu or an action
105 * and its parent must be writable
107 paste_enabled = bar->private->treeview_has_focus || bar->private->popup_handler;
108 paste_enabled &= !is_clipboard_empty;
109 paste_enabled &= bar->private->count_selected <= 1;
110 if( bar->private->clipboard_profiles ){
111 paste_enabled &= bar->private->count_selected == 1;
112 paste_enabled &= bar->private->is_action_writable;
113 } else {
114 paste_enabled &= bar->private->has_writable_providers;
115 if( bar->private->count_selected ){
116 paste_enabled &= bar->private->is_parent_writable;
117 } else {
118 paste_enabled &= bar->private->is_level_zero_writable;
121 nact_menubar_enable_item( bar, "PasteItem", paste_enabled );
123 /* paste into enabled if
124 * - clipboard is not empty
125 * - current selection is not multiple
126 * - if clipboard contains only profiles,
127 * then current selection must be an action
128 * and the action must be writable
129 * - if clipboard contains actions or menus,
130 * then current selection (if any) must be a menu
131 * and its parent must be writable
133 paste_into_enabled = bar->private->treeview_has_focus || bar->private->popup_handler;
134 paste_into_enabled &= !is_clipboard_empty;
135 paste_into_enabled &= bar->private->count_selected <= 1;
136 if( bar->private->clipboard_profiles ){
137 paste_into_enabled &= bar->private->count_selected == 1;
138 if( paste_into_enabled ){
139 selected_action = NA_OBJECT( bar->private->selected_items->data );
140 paste_into_enabled &= NA_IS_OBJECT_ACTION( selected_action );
141 paste_into_enabled &= na_object_is_finally_writable( selected_action, NULL );
143 } else {
144 paste_into_enabled &= bar->private->has_writable_providers;
145 if( bar->private->count_selected ){
146 selected_item = NA_OBJECT( bar->private->selected_items->data );
147 paste_into_enabled &= NA_IS_OBJECT_MENU( selected_item );
148 if( paste_into_enabled ){
149 parent_item = ( NAObject * ) na_object_get_parent( selected_item );
150 paste_into_enabled &= parent_item
151 ? na_object_is_finally_writable( parent_item, NULL )
152 : bar->private->is_level_zero_writable;
154 } else {
155 paste_into_enabled &= bar->private->is_level_zero_writable;
158 nact_menubar_enable_item( bar, "PasteIntoItem", paste_into_enabled );
160 /* duplicate items will be duplicated besides each one
161 * selection must be non-empty
162 * each parent must be writable
164 nact_menubar_enable_item( bar, "DuplicateItem", duplicate_enabled );
166 /* delete is same that cut
167 * but items themselves must be writable (because physically deleted)
168 * this will be checked on delete activated
170 delete_enabled = cut_enabled;
171 nact_menubar_enable_item( bar, "DeleteItem", delete_enabled );
173 /* reload items always enabled */
175 /* preferences always enabled */
179 * nact_menubar_edit_on_cut:
180 * @gtk_action: the #GtkAction action.
181 * @window: the #BaseWindow main window.
183 * Cut objects are installed both in the clipboard and in the deleted list.
184 * Parent pointer is reset to %NULL.
185 * Old parent status is re-checked by the tree model delete operation.
186 * When pasting later these cut objects:
187 * - the first time, we paste the very same object, removing it from the
188 * deleted list, attaching it to a new parent
189 * the object itself is not modified, but the parent is.
190 * - the following times, we paste a copy of this object with a new identifier
192 * cuts the visible selection
193 * - (tree) get new refs on selected items
194 * - (main) add selected items to main list of deleted,
195 * moving newref from list_from_tree to main_list_of_deleted
196 * - (menu) install in clipboard a copy of selected objects
197 * - (tree) remove selected items, unreffing objects
199 void
200 nact_menubar_edit_on_cut( GtkAction *gtk_action, BaseWindow *window )
202 static const gchar *thisfn = "nact_menubar_edit_on_cut";
203 GList *items;
204 NactClipboard *clipboard;
205 GList *to_delete;
206 GSList *non_deletables;
207 NactTreeView *view;
209 g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
210 g_return_if_fail( GTK_IS_ACTION( gtk_action ));
212 BAR_WINDOW_VOID( window );
214 items = na_object_copyref_items( bar->private->selected_items );
215 non_deletables = NULL;
216 to_delete = get_deletables( bar->private->updater, items, &non_deletables );
218 if( non_deletables ){
219 gchar *second = na_core_utils_slist_join_at_end( non_deletables, "\n" );
220 base_window_display_error_dlg(
221 BASE_WINDOW( window ),
222 _( "Not all items have been cut as following ones are not modifiable:" ),
223 second );
224 g_free( second );
225 na_core_utils_slist_free( non_deletables );
228 if( to_delete ){
229 clipboard = nact_main_window_get_clipboard( NACT_MAIN_WINDOW( window ));
230 nact_clipboard_primary_set( clipboard, to_delete, CLIPBOARD_MODE_CUT );
231 update_clipboard_counters( window );
232 view = nact_main_window_get_items_view( NACT_MAIN_WINDOW( window ));
233 nact_tree_ieditable_delete( NACT_TREE_IEDITABLE( view ), to_delete, TREE_OPE_DELETE );
236 na_object_free_items( items );
240 * nact_menubar_edit_on_copy:
241 * @gtk_action: the #GtkAction action.
242 * @window: the #BaseWindow main window.
244 * copies the visible selection
245 * - (tree) get new refs on selected items
246 * - (menu) install in clipboard a copy of selected objects
247 * renumbering actions/menus id to ensure unicity at paste time
248 * - (menu) release refs on selected items
249 * - (menu) refresh actions sensitivy (as selection doesn't change)
251 void
252 nact_menubar_edit_on_copy( GtkAction *gtk_action, BaseWindow *window )
254 static const gchar *thisfn = "nact_menubar_edit_on_copy";
255 GList *items;
256 NactClipboard *clipboard;
258 BAR_WINDOW_VOID( window );
260 g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
261 g_return_if_fail( GTK_IS_ACTION( gtk_action ));
262 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
264 items = na_object_copyref_items( bar->private->selected_items );
265 clipboard = nact_main_window_get_clipboard( NACT_MAIN_WINDOW( window ));
266 nact_clipboard_primary_set( clipboard, items, CLIPBOARD_MODE_COPY );
267 update_clipboard_counters( window );
268 na_object_free_items( items );
270 g_signal_emit_by_name( bar, MENUBAR_SIGNAL_UPDATE_SENSITIVITIES );
274 * nact_menubar_edit_on_paste:
275 * @gtk_action: the #GtkAction action.
276 * @window: the #BaseWindow main window.
278 * pastes the current content of the clipboard at the current position
279 * (same path, same level)
280 * - (menu) get from clipboard a copy of installed items
281 * the clipboard will return a new copy
282 * and renumber its own data for allowing a new paste
283 * - (tree) insert new items, the tree store will ref them
284 * attaching each item to its parent
285 * recursively checking edition status of the topmost parent
286 * selecting the first item at end
287 * - (menu) unreffing the copy got from clipboard
289 void
290 nact_menubar_edit_on_paste( GtkAction *gtk_action, BaseWindow *window )
292 static const gchar *thisfn = "nact_menubar_edit_on_paste";
293 GList *items;
294 NactTreeView *view;
296 g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
298 items = prepare_for_paste( window );
300 if( items ){
301 view = nact_main_window_get_items_view( NACT_MAIN_WINDOW( window ));
302 nact_tree_ieditable_insert_items( NACT_TREE_IEDITABLE( view ), items, NULL );
303 na_object_free_items( items );
308 * nact_menubar_edit_on_paste_into:
309 * @gtk_action: the #GtkAction action.
310 * @window: the #BaseWindow main window.
312 * pastes the current content of the clipboard as the first child of
313 * currently selected item
314 * - (menu) get from clipboard a copy of installed items
315 * the clipboard will return a new copy
316 * and renumber its own data for allowing a new paste
317 * - (tree) insert new items, the tree store will ref them
318 * attaching each item to its parent
319 * recursively checking edition status of the topmost parent
320 * selecting the first item at end
321 * - (menu) unreffing the copy got from clipboard
323 void
324 nact_menubar_edit_on_paste_into( GtkAction *gtk_action, BaseWindow *window )
326 static const gchar *thisfn = "nact_menubar_edit_on_paste_into";
327 GList *items;
328 NactTreeView *view;
330 g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
332 items = prepare_for_paste( window );
333 if( items ){
334 view = nact_main_window_get_items_view( NACT_MAIN_WINDOW( window ));
335 nact_tree_ieditable_insert_into( NACT_TREE_IEDITABLE( view ), items );
336 na_object_free_items( items );
340 static GList *
341 prepare_for_paste( BaseWindow *window )
343 static const gchar *thisfn = "nact_menubar_edit_prepare_for_paste";
344 GList *items, *it;
345 NactClipboard *clipboard;
346 NAObjectAction *action;
347 gboolean relabel;
348 gboolean renumber;
350 BAR_WINDOW_VALUE( window, NULL );
352 clipboard = nact_main_window_get_clipboard( NACT_MAIN_WINDOW( window ));
353 items = nact_clipboard_primary_get( clipboard, &renumber );
354 action = NULL;
356 /* if pasted items are profiles, then setup the target action
358 for( it = items ; it ; it = it->next ){
360 if( NA_IS_OBJECT_PROFILE( it->data )){
361 if( !action ){
362 g_object_get( G_OBJECT( window ), MAIN_PROP_ITEM, &action, NULL );
363 g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), NULL );
367 relabel = na_updater_should_pasted_be_relabeled( bar->private->updater, NA_OBJECT( it->data ));
368 na_object_prepare_for_paste( it->data, relabel, renumber, action );
369 na_object_check_status( it->data );
372 g_debug( "%s: action=%p (%s)",
373 thisfn, ( void * ) action, action ? G_OBJECT_TYPE_NAME( action ): "(null)" );
375 return( items );
379 * nact_menubar_edit_on_duplicate:
380 * @gtk_action: the #GtkAction action.
381 * @window: the #BaseWindow main window.
383 * duplicate is just as paste, with the difference that content comes
384 * from the current selection, instead of coming from the clipboard
386 * this is nonetheless a bit more complicated because when we duplicate
387 * some items (e.g. a multiple selection), we expect to see the new
388 * items just besides the original ones...
390 void
391 nact_menubar_edit_on_duplicate( GtkAction *gtk_action, BaseWindow *window )
393 static const gchar *thisfn = "nact_menubar_edit_on_duplicate";
394 NAObjectAction *action;
395 GList *items, *it;
396 GList *dup;
397 NAObject *obj;
398 gboolean relabel;
399 NactTreeView *view;
401 BAR_WINDOW_VOID( window );
403 g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
404 g_return_if_fail( GTK_IS_ACTION( gtk_action ));
405 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
407 items = na_object_copyref_items( bar->private->selected_items );
409 for( it = items ; it ; it = it->next ){
410 obj = NA_OBJECT( na_object_duplicate( it->data ));
411 action = NULL;
413 /* duplicating a profile
414 * as we insert in sibling mode, the parent doesn't change
416 if( NA_IS_OBJECT_PROFILE( obj )){
417 action = NA_OBJECT_ACTION( na_object_get_parent( it->data ));
420 relabel = na_updater_should_pasted_be_relabeled( bar->private->updater, obj );
421 na_object_prepare_for_paste( obj, relabel, TRUE, action );
422 na_object_set_origin( obj, NULL );
423 na_object_check_status( obj );
424 dup = g_list_prepend( NULL, obj );
425 view = nact_main_window_get_items_view( NACT_MAIN_WINDOW( window ));
426 nact_tree_ieditable_insert_items( NACT_TREE_IEDITABLE( view ), dup, it->data );
427 na_object_free_items( dup );
430 na_object_free_items( items );
434 * nact_menubar_edit_on_delete:
435 * @gtk_action: the #GtkAction action.
436 * @window: the #BaseWindow main window.
438 * deletes the visible selection
439 * - (tree) get new refs on selected items
440 * - (tree) remove selected items, unreffing objects
441 * - (main) add selected items to main list of deleted,
442 * moving newref from list_from_tree to main_list_of_deleted
443 * - (tree) select next row (if any, or previous if any, or none)
445 * note that we get from selection a list of trees, but we don't have
446 * yet ensured that each element of this tree is actually deletable
447 * each branch of this list must be recursively deletable in order
448 * this branch itself be deleted
450 void
451 nact_menubar_edit_on_delete( GtkAction *gtk_action, BaseWindow *window )
453 static const gchar *thisfn = "nact_menubar_edit_on_delete";
454 GList *items;
455 GList *to_delete;
456 GSList *non_deletables;
457 NactTreeView *view;
459 BAR_WINDOW_VOID( window );
461 g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
462 g_return_if_fail( GTK_IS_ACTION( gtk_action ));
463 g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
465 items = na_object_copyref_items( bar->private->selected_items );
466 non_deletables = NULL;
467 to_delete = get_deletables( bar->private->updater, items, &non_deletables );
469 if( non_deletables ){
470 gchar *second = na_core_utils_slist_join_at_end( non_deletables, "\n" );
471 base_window_display_error_dlg(
472 BASE_WINDOW( window ),
473 _( "Not all items have been deleted as following ones are not modifiable:" ),
474 second );
475 g_free( second );
476 na_core_utils_slist_free( non_deletables );
479 if( to_delete ){
480 view = nact_main_window_get_items_view( NACT_MAIN_WINDOW( window ));
481 nact_tree_ieditable_delete( NACT_TREE_IEDITABLE( view ), to_delete, TREE_OPE_DELETE );
484 na_object_free_items( items );
487 static GList *
488 get_deletables( NAUpdater *updater, GList *selected, GSList **non_deletables )
490 GList *to_delete;
491 GList *it;
492 GList *subitems;
493 GSList *sub_deletables;
494 guint reason;
496 to_delete = NULL;
497 for( it = selected ; it ; it = it->next ){
499 if( !na_updater_is_item_writable( updater, NA_OBJECT_ITEM( it->data ), &reason )){
500 *non_deletables = g_slist_prepend(
501 *non_deletables, add_non_deletable_msg( NA_OBJECT_ITEM( it->data ), reason ));
502 continue;
505 if( NA_IS_OBJECT_MENU( it->data )){
506 subitems = na_object_get_items( it->data );
507 sub_deletables = get_deletables_rec( updater, subitems );
509 if( sub_deletables ){
510 *non_deletables = g_slist_concat( *non_deletables, sub_deletables );
511 continue;
515 to_delete = g_list_prepend( to_delete, na_object_ref( it->data ));
518 return( to_delete );
521 static GSList *
522 get_deletables_rec( NAUpdater *updater, GList *tree )
524 GSList *msgs;
525 GList *it;
526 GList *subitems;
527 guint reason;
529 msgs = NULL;
530 for( it = tree ; it ; it = it->next ){
532 if( !na_updater_is_item_writable( updater, NA_OBJECT_ITEM( it->data ), &reason )){
533 msgs = g_slist_prepend(
534 msgs, add_non_deletable_msg( NA_OBJECT_ITEM( it->data ), reason ));
535 continue;
538 if( NA_IS_OBJECT_MENU( it->data )){
539 subitems = na_object_get_items( it->data );
540 msgs = g_slist_concat( msgs, get_deletables_rec( updater, subitems ));
544 return( msgs );
547 static gchar *
548 add_non_deletable_msg( const NAObjectItem *item, gint reason )
550 gchar *msg;
551 gchar *label;
552 gchar *reason_str;
554 label = na_object_get_label( item );
555 reason_str = na_io_provider_get_readonly_tooltip( reason );
557 msg = g_strdup_printf( "%s: %s", label, reason_str );
559 g_free( reason_str );
560 g_free( label );
562 return( msg );
566 * as we are coming from cut or copy to clipboard, report selection
567 * counters to clipboard ones
569 static void
570 update_clipboard_counters( BaseWindow *window )
572 BAR_WINDOW_VOID( window );
574 bar->private->clipboard_menus = bar->private->selected_menus;
575 bar->private->clipboard_actions = bar->private->selected_actions;
576 bar->private->clipboard_profiles = bar->private->selected_profiles;
578 g_debug( "nact_menubar_update_clipboard_counters: menus=%d, actions=%d, profiles=%d",
579 bar->private->clipboard_menus, bar->private->clipboard_actions, bar->private->clipboard_profiles );
581 g_signal_emit_by_name( bar, MENUBAR_SIGNAL_UPDATE_SENSITIVITIES );
585 * nact_menubar_edit_on_reload:
586 * @gtk_action: the #GtkAction action.
587 * @window: the #BaseWindow main window.
589 * Reload items from I/O storage subsystems.
591 void
592 nact_menubar_edit_on_reload( GtkAction *gtk_action, BaseWindow *window )
594 nact_main_window_reload( NACT_MAIN_WINDOW( window ));
598 * nact_menubar_edit_on_preferences:
599 * @gtk_action: the #GtkAction action.
600 * @window: the #BaseWindow main window.
602 * Edit preferences.
604 void
605 nact_menubar_edit_on_prefererences( GtkAction *gtk_action, BaseWindow *window )
607 nact_preferences_editor_run( window );