nautilus-view.c 282 KB
Newer Older
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
Darin Adler's avatar
Darin Adler committed
2

3
/* nautilus-view.c
Ettore Perazzoli's avatar
Ettore Perazzoli committed
4
 *
5
 * Copyright (C) 1999, 2000  Free Software Foundation
6
 * Copyright (C) 2000, 2001  Eazel, Inc.
Ettore Perazzoli's avatar
Ettore Perazzoli committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
23 24
 * Authors: Ettore Perazzoli,
 *          John Sullivan <sullivan@eazel.com>,
25
 *          Darin Adler <darin@bentspoon.com>,
26 27
 *          Pavel Cisler <pavel@eazel.com>,
 *          David Emory Watson <dwatson@cs.ucr.edu>
Ettore Perazzoli's avatar
Ettore Perazzoli committed
28 29
 */

30
#include <config.h>
31

32 33
#include "nautilus-view.h"

34
#include "gedit-overlay.h"
35 36 37
#include "nautilus-actions.h"
#include "nautilus-desktop-icon-view.h"
#include "nautilus-error-reporting.h"
38
#include "nautilus-floating-bar.h"
39
#include "nautilus-list-view.h"
40
#include "nautilus-mime-actions.h"
41
#include "nautilus-properties-window.h"
42
#include "nautilus-src-marshal.h"
43 44 45 46 47 48 49

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <math.h>
Alexander Larsson's avatar
Alexander Larsson committed
50

Ramiro Estrugo's avatar
Ramiro Estrugo committed
51 52 53 54 55 56 57
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gnome-extensions.h>
#include <eel/eel-gtk-extensions.h>
#include <eel/eel-gtk-macros.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string.h>
#include <eel/eel-vfs-extensions.h>
58

59
#include <libnautilus-extension/nautilus-menu-provider.h>
60
#include <libnautilus-private/nautilus-clipboard.h>
61
#include <libnautilus-private/nautilus-clipboard-monitor.h>
Alexander Larsson's avatar
Alexander Larsson committed
62 63
#include <libnautilus-private/nautilus-desktop-icon-file.h>
#include <libnautilus-private/nautilus-desktop-directory.h>
64
#include <libnautilus-private/nautilus-search-directory.h>
65
#include <libnautilus-private/nautilus-directory.h>
66
#include <libnautilus-private/nautilus-dnd.h>
67
#include <libnautilus-private/nautilus-file-attributes.h>
68
#include <libnautilus-private/nautilus-file-changes-queue.h>
69 70 71
#include <libnautilus-private/nautilus-file-dnd.h>
#include <libnautilus-private/nautilus-file-operations.h>
#include <libnautilus-private/nautilus-file-utilities.h>
72
#include <libnautilus-private/nautilus-file-private.h>
73 74 75
#include <libnautilus-private/nautilus-global-preferences.h>
#include <libnautilus-private/nautilus-link.h>
#include <libnautilus-private/nautilus-metadata.h>
76
#include <libnautilus-private/nautilus-recent.h>
77
#include <libnautilus-private/nautilus-module.h>
78 79
#include <libnautilus-private/nautilus-program-choosing.h>
#include <libnautilus-private/nautilus-trash-monitor.h>
Alexander Larsson's avatar
Alexander Larsson committed
80
#include <libnautilus-private/nautilus-ui-utilities.h>
Alexander Larsson's avatar
Alexander Larsson committed
81
#include <libnautilus-private/nautilus-signaller.h>
Luca Ferretti's avatar
Luca Ferretti committed
82
#include <libnautilus-private/nautilus-icon-names.h>
83

84 85 86
#define DEBUG_FLAG NAUTILUS_DEBUG_DIRECTORY_VIEW
#include <libnautilus-private/nautilus-debug.h>

87 88 89 90 91 92 93 94 95 96 97
/* Minimum starting update inverval */
#define UPDATE_INTERVAL_MIN 100
/* Maximum update interval */
#define UPDATE_INTERVAL_MAX 2000
/* Amount of miliseconds the update interval is increased */
#define UPDATE_INTERVAL_INC 250
/* Interval at which the update interval is increased */
#define UPDATE_INTERVAL_TIMEOUT_INTERVAL 250
/* Milliseconds that have to pass without a change to reset the update interval */
#define UPDATE_INTERVAL_RESET 1000

98
#define SILENT_WINDOW_OPEN_LIMIT 5
99

100 101 102
#define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
#define DUPLICATE_VERTICAL_ICON_OFFSET   30

103 104
#define MAX_QUEUED_UPDATES 500

105 106 107 108 109 110
#define NAUTILUS_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER  "/MenuBar/File/Open Placeholder/Open With/Applications Placeholder"
#define NAUTILUS_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER    	  "/MenuBar/File/Open Placeholder/Applications Placeholder"
#define NAUTILUS_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER               "/MenuBar/File/Open Placeholder/Scripts/Scripts Placeholder"
#define NAUTILUS_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER     "/MenuBar/Edit/Extension Actions"
#define NAUTILUS_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER  	  "/MenuBar/File/New Items Placeholder/New Documents/New Documents Placeholder"
#define NAUTILUS_VIEW_MENU_PATH_OPEN				  "/MenuBar/File/Open Placeholder/Open"
111

112 113 114 115 116 117
#define NAUTILUS_VIEW_POPUP_PATH_SELECTION			  "/selection"
#define NAUTILUS_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/selection/Open Placeholder/Open With/Applications Placeholder"
#define NAUTILUS_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER    	  "/selection/Open Placeholder/Applications Placeholder"
#define NAUTILUS_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER    	  "/selection/Open Placeholder/Scripts/Scripts Placeholder"
#define NAUTILUS_VIEW_POPUP_PATH_EXTENSION_ACTIONS		  "/selection/Extension Actions"
#define NAUTILUS_VIEW_POPUP_PATH_OPEN				  "/selection/Open Placeholder/Open"
Alexander Larsson's avatar
Alexander Larsson committed
118

119 120 121
#define NAUTILUS_VIEW_POPUP_PATH_BACKGROUND			  "/background"
#define NAUTILUS_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER	  "/background/Before Zoom Items/New Object Items/Scripts/Scripts Placeholder"
#define NAUTILUS_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/New Documents/New Documents Placeholder"
122

123
#define NAUTILUS_VIEW_POPUP_PATH_LOCATION			  "/location"
124

125
#define MAX_MENU_LEVELS 5
126
#define TEMPLATE_LIMIT 30
127

Pavel Cisler's avatar
Pavel Cisler committed
128
enum {
129
	ADD_FILE,
130
	BEGIN_FILE_CHANGES,
131
	BEGIN_LOADING,
132
	CLEAR,
133 134
	END_FILE_CHANGES,
	END_LOADING,
135
	FILE_CHANGED,
136
	LOAD_ERROR,
Pavel Cisler's avatar
Pavel Cisler committed
137
	MOVE_COPY_ITEMS,
138
	REMOVE_FILE,
139
	ZOOM_LEVEL_CHANGED,
140
	SELECTION_CHANGED,
Alexander Larsson's avatar
Alexander Larsson committed
141 142
	TRASH,
	DELETE,
143 144 145
	LAST_SIGNAL
};

146
enum {
147 148 149
	PROP_WINDOW_SLOT = 1,
	PROP_SHOW_FLOATING_BAR,
	NUM_PROPERTIES
Alexander Larsson's avatar
Alexander Larsson committed
150 151
};

152
static guint signals[LAST_SIGNAL];
153
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
Ettore Perazzoli's avatar
Ettore Perazzoli committed
154

155 156
static GdkAtom copied_files_atom;

157 158 159
static char *scripts_directory_uri;
static int scripts_directory_uri_length;

160
struct NautilusViewDetails
Ettore Perazzoli's avatar
Ettore Perazzoli committed
161
{
162 163
	NautilusWindow *window;
	NautilusWindowSlot *slot;
164
	NautilusDirectory *model;
Darin Adler's avatar
Darin Adler committed
165
	NautilusFile *directory_as_file;
166 167
	NautilusFile *location_popup_directory_as_file;
	GdkEventButton *location_popup_event;
Alexander Larsson's avatar
Alexander Larsson committed
168 169
	GtkActionGroup *dir_action_group;
	guint dir_merge_id;
170

171 172
	GtkWidget *overlay;
	GtkWidget *floating_bar;
173
	gboolean show_floating_bar;
174

175
	GList *scripts_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
176 177 178
	GtkActionGroup *scripts_action_group;
	guint scripts_merge_id;
	
179
	GList *templates_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
180 181
	GtkActionGroup *templates_action_group;
	guint templates_merge_id;
182

Alexander Larsson's avatar
Alexander Larsson committed
183 184 185
	GtkActionGroup *extensions_menu_action_group;
	guint extensions_menu_merge_id;
	
186
	guint display_selection_idle_id;
187
	guint update_menus_timeout_id;
188
	guint update_status_idle_id;
189 190
	guint reveal_selection_idle_id;

191 192 193 194 195
	guint display_pending_source_id;
	guint changes_timeout_id;

	guint update_interval;
 	guint64 last_queued;
196
	
197 198
	guint files_added_handler_id;
	guint files_changed_handler_id;
199
	guint load_error_handler_id;
200
	guint done_loading_handler_id;
201
	guint file_changed_handler_id;
202

203 204
	guint delayed_rename_file_id;

205 206 207 208 209 210 211 212
	GList *new_added_files;
	GList *new_changed_files;

	GHashTable *non_ready_files;

	GList *old_added_files;
	GList *old_changed_files;

213
	GList *pending_selection;
214

215 216 217
	/* whether we are in the active slot */
	gboolean active;

218
	/* loading indicates whether this view has begun loading a directory.
219
	 * This flag should need not be set inside subclasses. NautilusView automatically
220 221 222
	 * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE
	 * after it finishes loading the directory and its view.
	 */
223
	gboolean loading;
224
	gboolean menu_states_untrustworthy;
225
	gboolean scripts_invalid;
226
	gboolean templates_invalid;
227
	gboolean reported_load_error;
228

229 230 231 232 233 234 235 236
	/* flag to indicate that no file updates should be dispatched to subclasses.
	 * This is a workaround for bug #87701 that prevents the list view from
	 * losing focus when the underlying GtkTreeView is updated.
	 */
	gboolean updates_frozen;
	guint	 updates_queued;
	gboolean needs_reload;

237 238
	gboolean sort_directories_first;

239
	gboolean show_foreign_files;
240
	gboolean show_hidden_files;
241
	gboolean ignore_hidden_file_preferences;
242 243 244

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
245

246 247
	gboolean selection_was_removed;

248 249 250
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

251 252 253
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

Alexander Larsson's avatar
Alexander Larsson committed
254 255
	GtkActionGroup *open_with_action_group;
	guint open_with_merge_id;
Alexander Larsson's avatar
Alexander Larsson committed
256 257

	GList *subdirectory_list;
258 259

	GdkPoint context_menu_position;
260
};
Ettore Perazzoli's avatar
Ettore Perazzoli committed
261

262 263 264 265 266
typedef struct {
	NautilusFile *file;
	NautilusDirectory *directory;
} FileAndDirectory;

267
/* forward declarations */
268

269
static gboolean display_selection_info_idle_callback           (gpointer              data);
270 271 272 273 274 275
static void     nautilus_view_duplicate_selection              (NautilusView      *view,
							        GList                *files,
							        GArray               *item_locations);
static void     nautilus_view_create_links_for_files           (NautilusView      *view,
							        GList                *files,
							        GArray               *item_locations);
Alexander Larsson's avatar
Alexander Larsson committed
276 277
static void     trash_or_delete_files                          (GtkWindow            *parent_window,
								const GList          *files,
278
								gboolean              delete_if_all_already_in_trash,
279 280
								NautilusView      *view);
static void     load_directory                                 (NautilusView      *view,
281
								NautilusDirectory    *directory);
282 283 284
static void     nautilus_view_merge_menus                      (NautilusView      *view);
static void     nautilus_view_unmerge_menus                    (NautilusView      *view);
static void     nautilus_view_init_show_hidden_files           (NautilusView      *view);
285
static void     clipboard_changed_callback                     (NautilusClipboardMonitor *monitor,
286
								NautilusView      *view);
287 288
static void     open_one_in_new_window                         (gpointer              data,
								gpointer              callback_data);
289 290
static void     open_one_in_folder_window                      (gpointer              data,
								gpointer              callback_data);
291
static void     schedule_update_menus                          (NautilusView      *view);
292
static void     schedule_update_menus_callback                 (gpointer              callback_data);
293 294 295 296 297 298 299
static void     remove_update_menus_timeout_callback           (NautilusView      *view);
static void     schedule_update_status                          (NautilusView      *view);
static void     remove_update_status_idle_callback             (NautilusView *view); 
static void     reset_update_interval                          (NautilusView      *view);
static void     schedule_idle_display_of_pending_files         (NautilusView      *view);
static void     unschedule_display_of_pending_files            (NautilusView      *view);
static void     disconnect_model_handlers                      (NautilusView      *view);
300 301 302 303 304
static void     metadata_for_directory_as_file_ready_callback  (NautilusFile         *file,
								gpointer              callback_data);
static void     metadata_for_files_in_directory_ready_callback (NautilusDirectory    *directory,
								GList                *files,
								gpointer              callback_data);
305 306 307 308 309
static void     nautilus_view_trash_state_changed_callback     (NautilusTrashMonitor *trash,
							        gboolean              state,
							        gpointer              callback_data);
static void     nautilus_view_select_file                      (NautilusView      *view,
							        NautilusFile         *file);
Alexander Larsson's avatar
Alexander Larsson committed
310

311 312
static void     update_templates_directory                     (NautilusView *view);
static void     user_dirs_changed                              (NautilusView *view);
313

314 315
static gboolean file_list_all_are_folders                      (GList *file_list);

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
static void unschedule_pop_up_location_context_menu (NautilusView *view);

G_DEFINE_TYPE (NautilusView, nautilus_view, GTK_TYPE_SCROLLED_WINDOW);
#define parent_class nautilus_view_parent_class

EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, add_file)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, bump_zoom_level)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, can_zoom_in)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, can_zoom_out)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, clear)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, file_changed)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, get_selection)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, get_selection_for_file_transfer)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, get_item_count)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, is_empty)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, reset_to_defaults)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, restore_default_zoom_level)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, select_all)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, set_selection)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, zoom_to_level)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, get_zoom_level)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (nautilus_view, invert_selection)
338

339
/* virtual methods (public and non-public) */
340

341
/**
342
 * nautilus_view_merge_menus:
343 344
 * 
 * Add this view's menus to the window's menu bar.
345
 * @view: NautilusView in question.
346 347
 */
static void
348
nautilus_view_merge_menus (NautilusView *view)
349
{
350
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
351

352
	EEL_CALL_METHOD
353
		(NAUTILUS_VIEW_CLASS, view,
354 355
		 merge_menus, (view));
}
356

357
static void
358
nautilus_view_unmerge_menus (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
359
{
360
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
361

362
	EEL_CALL_METHOD
363
		(NAUTILUS_VIEW_CLASS, view,
364 365
		 unmerge_menus, (view));
}
Alexander Larsson's avatar
Alexander Larsson committed
366

367
/**
368
 * nautilus_view_select_all:
369 370 371 372 373
 *
 * select all the items in the view
 * 
 **/
static void
374
nautilus_view_select_all (NautilusView *view)
375
{
376
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
377

378
	EEL_CALL_METHOD
379
		(NAUTILUS_VIEW_CLASS, view,
380
		 select_all, (view));
Alexander Larsson's avatar
Alexander Larsson committed
381 382 383
}

static void
384
nautilus_view_call_set_selection (NautilusView *view, GList *selection)
Alexander Larsson's avatar
Alexander Larsson committed
385
{
386
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
387

388
	EEL_CALL_METHOD
389
		(NAUTILUS_VIEW_CLASS, view,
390 391
		 set_selection, (view, selection));
}
392 393

static GList *
394
nautilus_view_get_selection_for_file_transfer (NautilusView *view)
395
{
396
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
397

398
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
399
		(NAUTILUS_VIEW_CLASS, view,
400
		 get_selection_for_file_transfer, (view));
401 402
}

403
/**
404
 * nautilus_view_get_selected_icon_locations:
405 406 407 408 409 410
 *
 * return an array of locations of selected icons if available
 * Return value: GArray of GdkPoints
 * 
 **/
static GArray *
411
nautilus_view_get_selected_icon_locations (NautilusView *view)
412
{
413
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
414

415
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
416
		(NAUTILUS_VIEW_CLASS, view,
417
		 get_selected_icon_locations, (view));
418 419 420
}

static void
421
nautilus_view_invert_selection (NautilusView *view)
422
{
423
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
424 425

	EEL_CALL_METHOD
426
		(NAUTILUS_VIEW_CLASS, view,
427
		 invert_selection, (view));
428 429
}

430
/**
431
 * nautilus_view_reveal_selection:
432 433 434 435
 *
 * Scroll as necessary to reveal the selected items.
 **/
static void
436
nautilus_view_reveal_selection (NautilusView *view)
437
{
438
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
439 440

	EEL_CALL_METHOD
441
		(NAUTILUS_VIEW_CLASS, view,
442 443
		 reveal_selection, (view));
}
444

445
/**
446
 * nautilus_view_reset_to_defaults:
447 448 449 450
 *
 * set sorting order, zoom level, etc. to match defaults
 * 
 **/
451
static void
452
nautilus_view_reset_to_defaults (NautilusView *view)
453
{
454
	NautilusWindowShowHiddenFilesMode mode;
455

456
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
457 458
	
	EEL_CALL_METHOD
459
		(NAUTILUS_VIEW_CLASS, view,
460 461 462 463
		 reset_to_defaults, (view));
	mode = nautilus_window_get_hidden_files_mode (view->details->window);
	if (mode != NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT) {
		nautilus_window_set_hidden_files_mode (view->details->window,
464
						       NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT);
465 466 467 468
	}
}

static gboolean
469
nautilus_view_using_manual_layout (NautilusView  *view)
470
{
471
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
472

473
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
474
		(NAUTILUS_VIEW_CLASS, view,
475
		 using_manual_layout, (view));
476 477 478
}

static guint
479
nautilus_view_get_item_count (NautilusView *view)
480
{
481
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), 0);
482

483
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
484
		(NAUTILUS_VIEW_CLASS, view,
485
		 get_item_count, (view));
486 487
}

488
/**
489
 * nautilus_view_can_rename_file
490 491 492 493 494 495 496 497
 *
 * Determine whether a file can be renamed.
 * @file: A NautilusFile
 * 
 * Return value: TRUE if @file can be renamed, FALSE otherwise.
 * 
 **/
static gboolean
498
nautilus_view_can_rename_file (NautilusView *view, NautilusFile *file)
499 500
{
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
501
		(NAUTILUS_VIEW_CLASS, view,
502 503
		 can_rename_file, (view, file));
}
504

505
static gboolean
506
nautilus_view_is_read_only (NautilusView *view)
507
{
508
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
509

510
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
511
		(NAUTILUS_VIEW_CLASS, view,
512 513
		 is_read_only, (view));
}
514

515
static gboolean
516
showing_trash_directory (NautilusView *view)
517 518 519
{
	NautilusFile *file;

520
	file = nautilus_view_get_directory_as_file (view);
521 522 523 524 525 526
	if (file != NULL) {
		return nautilus_file_is_in_trash (file);
	}
	return FALSE;
}

527
static gboolean
528
nautilus_view_supports_creating_files (NautilusView *view)
529
{
530
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
531

532
	return !nautilus_view_is_read_only (view) && !showing_trash_directory (view);
533 534
}

535
static gboolean
536
nautilus_view_is_empty (NautilusView *view)
537
{
538
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
539

540
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
541
		(NAUTILUS_VIEW_CLASS, view,
542
		 is_empty, (view));
543 544
}

545 546 547 548 549 550 551 552 553
/**
 * nautilus_view_bump_zoom_level:
 *
 * bump the current zoom level by invoking the relevant subclass through the slot
 * 
 **/
void
nautilus_view_bump_zoom_level (NautilusView *view,
			       int zoom_increment)
554
{
555
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
556

557 558 559
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}
Alexander Larsson's avatar
Alexander Larsson committed
560

561
	EEL_CALL_METHOD
562
		(NAUTILUS_VIEW_CLASS, view,
563
		 bump_zoom_level, (view, zoom_increment));
Alexander Larsson's avatar
Alexander Larsson committed
564 565
}

566 567 568 569 570 571 572 573 574
/**
 * nautilus_view_zoom_to_level:
 *
 * Set the current zoom level by invoking the relevant subclass through the slot
 * 
 **/
void
nautilus_view_zoom_to_level (NautilusView *view,
			     NautilusZoomLevel zoom_level)
575
{
576
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
577

578 579 580 581 582
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}

	EEL_CALL_METHOD
583
		(NAUTILUS_VIEW_CLASS, view,
584
		 zoom_to_level, (view, zoom_level));
585
}
Alexander Larsson's avatar
Alexander Larsson committed
586

587
NautilusZoomLevel
588
nautilus_view_get_zoom_level (NautilusView *view)
589
{
590
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
591

592 593
	if (!nautilus_view_supports_zooming (view)) {
		return NAUTILUS_ZOOM_LEVEL_STANDARD;
594 595
	}

596
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
597
		(NAUTILUS_VIEW_CLASS, view,
598
		 get_zoom_level, (view));
599 600
}

601 602 603 604
/**
 * nautilus_view_can_zoom_in:
 *
 * Determine whether the view can be zoomed any closer.
605
 * @view: The zoomable NautilusView.
606 607 608 609 610 611
 * 
 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_in (NautilusView *view)
612
{
613
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
614

615 616
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
617
	}
618

619
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
620
		(NAUTILUS_VIEW_CLASS, view,
621
		 can_zoom_in, (view));
622 623
}

624 625 626 627
/**
 * nautilus_view_can_zoom_out:
 *
 * Determine whether the view can be zoomed any further away.
628
 * @view: The zoomable NautilusView.
629 630 631 632 633 634
 * 
 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_out (NautilusView *view)
635
{
636
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
637

638 639
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
640 641
	}

642
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
643
		(NAUTILUS_VIEW_CLASS, view,
644
		 can_zoom_out, (view));
645 646
}

647
gboolean
648
nautilus_view_supports_zooming (NautilusView *view)
649
{
650
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
651

652
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
653
		(NAUTILUS_VIEW_CLASS, view,
654
		 supports_zooming, (view));
655 656
}

657 658 659 660 661 662 663 664
/**
 * nautilus_view_restore_default_zoom_level:
 *
 * restore to the default zoom level by invoking the relevant subclass through the slot
 * 
 **/
void
nautilus_view_restore_default_zoom_level (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
665
{
666
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
667 668 669

	if (!nautilus_view_supports_zooming (view)) {
		return;
Alexander Larsson's avatar
Alexander Larsson committed
670
	}
671 672

	EEL_CALL_METHOD
673
		(NAUTILUS_VIEW_CLASS, view,
674
		 restore_default_zoom_level, (view));
Alexander Larsson's avatar
Alexander Larsson committed
675 676
}

677 678
const char *
nautilus_view_get_view_id (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
679
{
680
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
681
		(NAUTILUS_VIEW_CLASS, view,
682 683
		 get_view_id, (view));
}
Alexander Larsson's avatar
Alexander Larsson committed
684

685 686 687 688
char *
nautilus_view_get_first_visible_file (NautilusView *view)
{
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
689
		(NAUTILUS_VIEW_CLASS, view,
690
		 get_first_visible_file, (view));
Alexander Larsson's avatar
Alexander Larsson committed
691 692 693
}

void
694 695
nautilus_view_scroll_to_file (NautilusView *view,
			      const char *uri)
Alexander Larsson's avatar
Alexander Larsson committed
696
{
697
	EEL_CALL_METHOD
698
		(NAUTILUS_VIEW_CLASS, view,
699 700
		 scroll_to_file, (view, uri));
}
Alexander Larsson's avatar
Alexander Larsson committed
701

702
char **
703
nautilus_view_get_emblem_names_to_exclude (NautilusView *view)
704
{
705 706 707
	char **excludes;
	int i;
	
708
	g_assert (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
709

710 711 712 713 714 715 716 717 718 719 720 721
	excludes = g_new (char *, 3);
	
	i = 0;
	excludes[i++] = g_strdup (NAUTILUS_FILE_EMBLEM_NAME_TRASH);

	if (!nautilus_file_can_write (view->details->directory_as_file)) {
		excludes[i++] = g_strdup (NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE);
	}

	excludes[i++] = NULL;

	return excludes;
Alexander Larsson's avatar
Alexander Larsson committed
722 723
}

724
void
725
nautilus_view_set_is_active (NautilusView *view,
726
			     gboolean is_active)
727
{
728
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
729

730
	EEL_CALL_METHOD (NAUTILUS_VIEW_CLASS, view,
731
			 set_is_active, (view, is_active));
732 733
}

734
/**
735
 * nautilus_view_get_selection:
736 737 738 739 740
 *
 * Get a list of NautilusFile pointers that represents the
 * currently-selected items in this view. Subclasses must override
 * the signal handler for the 'get_selection' signal. Callers are
 * responsible for g_free-ing the list (but not its data).
741
 * @view: NautilusView whose selected items are of interest.
742 743 744 745 746
 * 
 * Return value: GList of NautilusFile pointers representing the selection.
 * 
 **/
GList *
747
nautilus_view_get_selection (NautilusView *view)
748
{
749
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
750

751
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
752
		(NAUTILUS_VIEW_CLASS, view,
753
		 get_selection, (view));
754 755 756
}


757 758 759 760
/**
 * nautilus_view_update_menus:
 * 
 * Update the sensitivity and wording of dynamic menu items.
761
 * @view: NautilusView in question.
762 763 764
 */
void
nautilus_view_update_menus (NautilusView *view)
765
{
766
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
767

768 769
	if (!view->details->active) {
		return;
770
	}
771 772


773
	EEL_CALL_METHOD
774
		(NAUTILUS_VIEW_CLASS, view,
775
		 update_menus, (view));
776

777 778
	view->details->menu_states_untrustworthy = FALSE;
}
779

780 781 782
typedef struct {
	GAppInfo *application;
	GList *files;
783
	NautilusView *directory_view;
784
} ApplicationLaunchParameters;
785

786 787
typedef struct {
	NautilusFile *file;
788
	NautilusView *directory_view;
789
} ScriptLaunchParameters;
790

791 792
typedef struct {
	NautilusFile *file;
793
	NautilusView *directory_view;
794
} CreateTemplateParameters;
795

796 797 798
static ApplicationLaunchParameters *
application_launch_parameters_new (GAppInfo *application,
			      	   GList *files,
799
			           NautilusView *directory_view)
800
{
801
	ApplicationLaunchParameters *result;
802

803 804 805
	result = g_new0 (ApplicationLaunchParameters, 1);
	result->application = g_object_ref (application);
	result->files = nautilus_file_list_copy (files);
Alexander Larsson's avatar
Alexander Larsson committed
806

807 808 809
	if (directory_view != NULL) {
		g_object_ref (directory_view);
		result->directory_view = directory_view;
810 811
	}

812
	return result;
813 814
}

815
static void
816
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
817
{
818 819
	g_object_unref (parameters->application);
	nautilus_file_list_free (parameters->files);
820

821 822
	if (parameters->directory_view != NULL) {
		g_object_unref (parameters->directory_view);
823 824
	}

825 826
	g_free (parameters);
}			      
827

828 829
static GList *
file_and_directory_list_to_files (GList *fad_list)
830
{
831 832
	GList *res, *l;
	FileAndDirectory *fad;
833

834 835 836 837 838 839 840
	res = NULL;
	for (l = fad_list; l != NULL; l = l->next) {
		fad = l->data;
		res = g_list_prepend (res, nautilus_file_ref (fad->file));
	}
	return g_list_reverse (res);
}
841 842


843 844 845 846 847
static GList *
file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
{
	GList *res, *l;
	FileAndDirectory *fad;
848

849 850 851 852 853 854 855 856
	res = NULL;
	for (l = files; l != NULL; l = l->next) {
		fad = g_new0 (FileAndDirectory, 1);
		fad->directory = nautilus_directory_ref (directory);
		fad->file = nautilus_file_ref (l->data);
		res = g_list_prepend (res, fad);
	}
	return g_list_reverse (res);
857 858 859
}

static void
860
file_and_directory_free (FileAndDirectory *fad)
861
{
862 863 864 865
	nautilus_directory_unref (fad->directory);
	nautilus_file_unref (fad->file);
	g_free (fad);
}
866 867


868 869 870 871
static void
file_and_directory_list_free (GList *list)
{
	GList *l;
872

873 874
	for (l = list; l != NULL; l = l->next) {
		file_and_directory_free (l->data);
875
	}
876

877
	g_list_free (list);
878 879
}

880 881 882
static gboolean
file_and_directory_equal (gconstpointer  v1,
			  gconstpointer  v2)
883
{
884 885 886
	const FileAndDirectory *fad1, *fad2;
	fad1 = v1;
	fad2 = v2;
887

888 889
	return (fad1->file == fad2->file &&
		fad1->directory == fad2->directory);
890 891
}

892 893
static guint
file_and_directory_hash  (gconstpointer  v)
894
{
895
	const FileAndDirectory *fad;
896

897 898
	fad = v;
	return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
899 900
}

901

Alexander Larsson's avatar
Alexander Larsson committed
902

903 904 905

static ScriptLaunchParameters *
script_launch_parameters_new (NautilusFile *file,
906
			      NautilusView *directory_view)
907
{
908 909 910 911 912 913 914 915 916
	ScriptLaunchParameters *result;

	result = g_new0 (ScriptLaunchParameters, 1);
	g_object_ref (directory_view);
	result->directory_view = directory_view;
	nautilus_file_ref (file);
	result->file = file;

	return result;
917 918
}

919
static void
920
script_launch_parameters_free (ScriptLaunchParameters *parameters)
921
{
Cosimo Cecchi's avatar
<