nautilus-view.c 275 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 35 36
#include "nautilus-actions.h"
#include "nautilus-desktop-icon-view.h"
#include "nautilus-error-reporting.h"
37
#include "nautilus-list-view.h"
38
#include "nautilus-mime-actions.h"
39
#include "nautilus-previewer.h"
40
#include "nautilus-properties-window.h"
41

42
#include <gdk/gdkx.h>
43 44 45 46 47 48
#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
49

Ramiro Estrugo's avatar
Ramiro Estrugo committed
50 51 52 53 54 55 56
#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>
57

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

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

86 87 88 89 90 91 92 93 94 95 96
/* 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

97
#define SILENT_WINDOW_OPEN_LIMIT 5
98

99 100 101
#define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
#define DUPLICATE_VERTICAL_ICON_OFFSET   30

102 103
#define MAX_QUEUED_UPDATES 500

104 105 106 107 108 109
#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"
110

111 112 113 114 115 116
#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
117

118 119 120
#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"
121

122
#define NAUTILUS_VIEW_POPUP_PATH_LOCATION			  "/location"
123

124
#define MAX_MENU_LEVELS 5
125
#define TEMPLATE_LIMIT 30
126

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

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

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

154 155
static GdkAtom copied_files_atom;

156
static char *scripts_directory_uri = NULL;
157 158
static int scripts_directory_uri_length;

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

170
	gboolean supports_zooming;
171

172
	GList *scripts_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
173 174 175
	GtkActionGroup *scripts_action_group;
	guint scripts_merge_id;
	
176
	GList *templates_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
177 178
	GtkActionGroup *templates_action_group;
	guint templates_merge_id;
179

Alexander Larsson's avatar
Alexander Larsson committed
180 181 182
	GtkActionGroup *extensions_menu_action_group;
	guint extensions_menu_merge_id;
	
183
	guint display_selection_idle_id;
184
	guint update_menus_timeout_id;
185
	guint update_status_idle_id;
186 187
	guint reveal_selection_idle_id;

188 189 190 191 192
	guint display_pending_source_id;
	guint changes_timeout_id;

	guint update_interval;
 	guint64 last_queued;
193
	
194 195
	guint files_added_handler_id;
	guint files_changed_handler_id;
196
	guint load_error_handler_id;
197
	guint done_loading_handler_id;
198
	guint file_changed_handler_id;
199

200 201
	guint delayed_rename_file_id;

202 203 204 205 206 207 208 209
	GList *new_added_files;
	GList *new_changed_files;

	GHashTable *non_ready_files;

	GList *old_added_files;
	GList *old_changed_files;

210
	GList *pending_selection;
211

212 213 214
	/* whether we are in the active slot */
	gboolean active;

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

226 227 228 229 230 231 232 233
	/* 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;

234 235
	gboolean is_renaming;

236 237
	gboolean sort_directories_first;

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

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
244

245 246
	gboolean selection_was_removed;

247 248 249
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

250 251 252
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

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

	GList *subdirectory_list;
257 258

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

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

266
/* forward declarations */
267

268
static gboolean display_selection_info_idle_callback           (gpointer              data);
269 270 271 272 273 274
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
275 276
static void     trash_or_delete_files                          (GtkWindow            *parent_window,
								const GList          *files,
277
								gboolean              delete_if_all_already_in_trash,
278 279
								NautilusView      *view);
static void     load_directory                                 (NautilusView      *view,
280
								NautilusDirectory    *directory);
281 282 283
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);
284
static void     clipboard_changed_callback                     (NautilusClipboardMonitor *monitor,
285
								NautilusView      *view);
286 287
static void     open_one_in_new_window                         (gpointer              data,
								gpointer              callback_data);
288
static void     schedule_update_menus                          (NautilusView      *view);
289
static void     schedule_update_menus_callback                 (gpointer              callback_data);
290 291 292 293 294 295 296
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);
297 298 299 300 301
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);
302 303 304 305 306
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
307

308 309
static void     update_templates_directory                     (NautilusView *view);
static void     user_dirs_changed                              (NautilusView *view);
310

311 312
static gboolean file_list_all_are_folders                      (GList *file_list);

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
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)
335

336
/* virtual methods (public and non-public) */
337

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

349
	EEL_CALL_METHOD
350
		(NAUTILUS_VIEW_CLASS, view,
351 352
		 merge_menus, (view));
}
353

354
static void
355
nautilus_view_unmerge_menus (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
356
{
357
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
358

359
	EEL_CALL_METHOD
360
		(NAUTILUS_VIEW_CLASS, view,
361 362
		 unmerge_menus, (view));
}
Alexander Larsson's avatar
Alexander Larsson committed
363

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
static char *
real_get_backing_uri (NautilusView *view)
{
	NautilusDirectory *directory;
	char *uri;
       
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);

	if (view->details->model == NULL) {
		return NULL;
	}
       
	directory = view->details->model;
       
	if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
		directory = nautilus_desktop_directory_get_real_directory (NAUTILUS_DESKTOP_DIRECTORY (directory));
	} else {
		nautilus_directory_ref (directory);
	}
       
	uri = nautilus_directory_get_uri (directory);

	nautilus_directory_unref (directory);

	return uri;
}

/**
 *
 * nautilus_view_get_backing_uri:
 *
 * Returns the URI for the target location of new directory, new file, new
396
 * link and paste operations.
397 398 399 400 401 402 403 404 405 406 407 408
 */

char *
nautilus_view_get_backing_uri (NautilusView *view)
{
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);

	return EEL_CALL_METHOD_WITH_RETURN_VALUE
		(NAUTILUS_VIEW_CLASS, view,
		 get_backing_uri, (view));
}

409
/**
410
 * nautilus_view_select_all:
411 412 413 414 415
 *
 * select all the items in the view
 * 
 **/
static void
416
nautilus_view_select_all (NautilusView *view)
417
{
418
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
419

420
	EEL_CALL_METHOD
421
		(NAUTILUS_VIEW_CLASS, view,
422
		 select_all, (view));
Alexander Larsson's avatar
Alexander Larsson committed
423 424 425
}

static void
426
nautilus_view_call_set_selection (NautilusView *view, GList *selection)
Alexander Larsson's avatar
Alexander Larsson committed
427
{
428
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
429

430
	EEL_CALL_METHOD
431
		(NAUTILUS_VIEW_CLASS, view,
432 433
		 set_selection, (view, selection));
}
434 435

static GList *
436
nautilus_view_get_selection_for_file_transfer (NautilusView *view)
437
{
438
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
439

440
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
441
		(NAUTILUS_VIEW_CLASS, view,
442
		 get_selection_for_file_transfer, (view));
443 444
}

445
/**
446
 * nautilus_view_get_selected_icon_locations:
447 448 449 450 451 452
 *
 * return an array of locations of selected icons if available
 * Return value: GArray of GdkPoints
 * 
 **/
static GArray *
453
nautilus_view_get_selected_icon_locations (NautilusView *view)
454
{
455
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
456

457
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
458
		(NAUTILUS_VIEW_CLASS, view,
459
		 get_selected_icon_locations, (view));
460 461 462
}

static void
463
nautilus_view_invert_selection (NautilusView *view)
464
{
465
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
466 467

	EEL_CALL_METHOD
468
		(NAUTILUS_VIEW_CLASS, view,
469
		 invert_selection, (view));
470 471
}

472
/**
473
 * nautilus_view_reveal_selection:
474 475 476 477
 *
 * Scroll as necessary to reveal the selected items.
 **/
static void
478
nautilus_view_reveal_selection (NautilusView *view)
479
{
480
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
481 482

	EEL_CALL_METHOD
483
		(NAUTILUS_VIEW_CLASS, view,
484 485
		 reveal_selection, (view));
}
486

487
/**
488
 * nautilus_view_reset_to_defaults:
489 490 491 492
 *
 * set sorting order, zoom level, etc. to match defaults
 * 
 **/
493
static void
494
nautilus_view_reset_to_defaults (NautilusView *view)
495
{
496
	NautilusWindowShowHiddenFilesMode mode;
497

498
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
499 500
	
	EEL_CALL_METHOD
501
		(NAUTILUS_VIEW_CLASS, view,
502 503 504 505
		 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,
506
						       NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT);
507 508 509 510
	}
}

static gboolean
511
nautilus_view_using_manual_layout (NautilusView  *view)
512
{
513
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
514

515
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
516
		(NAUTILUS_VIEW_CLASS, view,
517
		 using_manual_layout, (view));
518 519 520
}

static guint
521
nautilus_view_get_item_count (NautilusView *view)
522
{
523
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), 0);
524

525
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
526
		(NAUTILUS_VIEW_CLASS, view,
527
		 get_item_count, (view));
528 529
}

530
/**
531
 * nautilus_view_can_rename_file
532 533 534 535 536 537 538 539
 *
 * Determine whether a file can be renamed.
 * @file: A NautilusFile
 * 
 * Return value: TRUE if @file can be renamed, FALSE otherwise.
 * 
 **/
static gboolean
540
nautilus_view_can_rename_file (NautilusView *view, NautilusFile *file)
541 542
{
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
543
		(NAUTILUS_VIEW_CLASS, view,
544 545
		 can_rename_file, (view, file));
}
546

547
static gboolean
548
nautilus_view_is_read_only (NautilusView *view)
549
{
550
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
551

552
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
553
		(NAUTILUS_VIEW_CLASS, view,
554 555
		 is_read_only, (view));
}
556

557
static gboolean
558
showing_trash_directory (NautilusView *view)
559 560 561
{
	NautilusFile *file;

562
	file = nautilus_view_get_directory_as_file (view);
563 564 565 566 567 568
	if (file != NULL) {
		return nautilus_file_is_in_trash (file);
	}
	return FALSE;
}

569
static gboolean
570
nautilus_view_supports_creating_files (NautilusView *view)
571
{
572
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
573

574
	return !nautilus_view_is_read_only (view) && !showing_trash_directory (view);
575 576
}

577
static gboolean
578
nautilus_view_is_empty (NautilusView *view)
579
{
580
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
581

582
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
583
		(NAUTILUS_VIEW_CLASS, view,
584
		 is_empty, (view));
585 586
}

587 588 589 590 591 592 593 594 595
/**
 * 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)
596
{
597
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
598

599 600 601
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}
Alexander Larsson's avatar
Alexander Larsson committed
602

603
	EEL_CALL_METHOD
604
		(NAUTILUS_VIEW_CLASS, view,
605
		 bump_zoom_level, (view, zoom_increment));
Alexander Larsson's avatar
Alexander Larsson committed
606 607
}

608 609 610 611 612 613 614 615 616
/**
 * 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)
617
{
618
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
619

620 621 622 623 624
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}

	EEL_CALL_METHOD
625
		(NAUTILUS_VIEW_CLASS, view,
626
		 zoom_to_level, (view, zoom_level));
627
}
Alexander Larsson's avatar
Alexander Larsson committed
628

629
NautilusZoomLevel
630
nautilus_view_get_zoom_level (NautilusView *view)
631
{
632
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
633

634 635
	if (!nautilus_view_supports_zooming (view)) {
		return NAUTILUS_ZOOM_LEVEL_STANDARD;
636 637
	}

638
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
639
		(NAUTILUS_VIEW_CLASS, view,
640
		 get_zoom_level, (view));
641 642
}

643 644 645 646
/**
 * nautilus_view_can_zoom_in:
 *
 * Determine whether the view can be zoomed any closer.
647
 * @view: The zoomable NautilusView.
648 649 650 651 652 653
 * 
 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_in (NautilusView *view)
654
{
655
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
656

657 658
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
659
	}
660

661
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
662
		(NAUTILUS_VIEW_CLASS, view,
663
		 can_zoom_in, (view));
664 665
}

666 667 668 669
/**
 * nautilus_view_can_zoom_out:
 *
 * Determine whether the view can be zoomed any further away.
670
 * @view: The zoomable NautilusView.
671 672 673 674 675 676
 * 
 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_out (NautilusView *view)
677
{
678
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
679

680 681
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
682 683
	}

684
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
685
		(NAUTILUS_VIEW_CLASS, view,
686
		 can_zoom_out, (view));
687 688
}

689
gboolean
690
nautilus_view_supports_zooming (NautilusView *view)
691
{
692
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
693

694
	return view->details->supports_zooming;
695 696
}

697 698 699 700 701 702 703 704
/**
 * 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
705
{
706
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
707 708 709

	if (!nautilus_view_supports_zooming (view)) {
		return;
Alexander Larsson's avatar
Alexander Larsson committed
710
	}
711 712

	EEL_CALL_METHOD
713
		(NAUTILUS_VIEW_CLASS, view,
714
		 restore_default_zoom_level, (view));
Alexander Larsson's avatar
Alexander Larsson committed
715 716
}

717 718
const char *
nautilus_view_get_view_id (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
719
{
720
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
721
		(NAUTILUS_VIEW_CLASS, view,
722 723
		 get_view_id, (view));
}
Alexander Larsson's avatar
Alexander Larsson committed
724

725 726 727 728
char *
nautilus_view_get_first_visible_file (NautilusView *view)
{
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
729
		(NAUTILUS_VIEW_CLASS, view,
730
		 get_first_visible_file, (view));
Alexander Larsson's avatar
Alexander Larsson committed
731 732 733
}

void
734 735
nautilus_view_scroll_to_file (NautilusView *view,
			      const char *uri)
Alexander Larsson's avatar
Alexander Larsson committed
736
{
737
	EEL_CALL_METHOD
738
		(NAUTILUS_VIEW_CLASS, view,
739 740
		 scroll_to_file, (view, uri));
}
Alexander Larsson's avatar
Alexander Larsson committed
741

742
char **
743
nautilus_view_get_emblem_names_to_exclude (NautilusView *view)
744
{
745 746 747
	char **excludes;
	int i;
	
748
	g_assert (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
749

750 751 752 753 754 755 756 757 758 759 760 761
	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
762 763
}

764
void
765
nautilus_view_set_is_active (NautilusView *view,
766
			     gboolean is_active)
767
{
768
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
769

770
	EEL_CALL_METHOD (NAUTILUS_VIEW_CLASS, view,
771
			 set_is_active, (view, is_active));
772 773
}

774
/**
775
 * nautilus_view_get_selection:
776 777 778 779 780
 *
 * 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).
781
 * @view: NautilusView whose selected items are of interest.
782 783 784 785 786
 * 
 * Return value: GList of NautilusFile pointers representing the selection.
 * 
 **/
GList *
787
nautilus_view_get_selection (NautilusView *view)
788
{
789
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
790

791
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
792
		(NAUTILUS_VIEW_CLASS, view,
793
		 get_selection, (view));
794 795 796
}


797 798 799 800
/**
 * nautilus_view_update_menus:
 * 
 * Update the sensitivity and wording of dynamic menu items.
801
 * @view: NautilusView in question.
802 803 804
 */
void
nautilus_view_update_menus (NautilusView *view)
805
{
806
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
807

808 809
	if (!view->details->active) {
		return;
810
	}
811 812


813
	EEL_CALL_METHOD
814
		(NAUTILUS_VIEW_CLASS, view,
815
		 update_menus, (view));
816

817 818
	view->details->menu_states_untrustworthy = FALSE;
}
819

820 821 822
typedef struct {
	GAppInfo *application;
	GList *files;
823
	NautilusView *directory_view;
824
} ApplicationLaunchParameters;
825

826 827
typedef struct {
	NautilusFile *file;
828
	NautilusView *directory_view;
829
} ScriptLaunchParameters;
830

831 832
typedef struct {
	NautilusFile *file;
833
	NautilusView *directory_view;
834
} CreateTemplateParameters;
835

836 837 838
static ApplicationLaunchParameters *
application_launch_parameters_new (GAppInfo *application,
			      	   GList *files,
839
			           NautilusView *directory_view)
840
{
841
	ApplicationLaunchParameters *result;
842

843 844 845
	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
846

847 848 849
	if (directory_view != NULL) {
		g_object_ref (directory_view);
		result->directory_view = directory_view;
850 851
	}

852
	return result;
853 854
}

855
static void
856
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
857
{
858 859
	g_object_unref (parameters->application);
	nautilus_file_list_free (parameters->files);
860

861 862
	if (parameters->directory_view != NULL) {
		g_object_unref (parameters->directory_view);
863 864
	}

865 866
	g_free (parameters);
}			      
867

868 869
static GList *
file_and_directory_list_to_files (GList *fad_list)
870
{
871 872
	GList *res, *l;
	FileAndDirectory *fad;
873

874 875 876 877 878 879 880
	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);
}
881 882


883 884 885 886 887
static GList *
file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
{
	GList *res, *l;
	FileAndDirectory *fad;
888

889 890 891 892 893 894 895 896
	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);
897 898 899
}

static void
900
file_and_directory_free (FileAndDirectory *fad)
901
{
902 903 904 905
	nautilus_directory_unref (fad->directory);
	nautilus_file_unref (fad->file);
	g_free (fad);
}
906 907


908 909 910 911
static void
file_and_directory_list_free (GList *list)
{
	GList *l;
912

913 914
	for (l = list; l != NULL; l = l->next) {
		file_and_directory_free (l->data);
915
	}
916

917
	g_list_free (list);
918 919
}

920 921 922
static gboolean
file_and_directory_equal (gconstpointer  v1,
			  gconstpointer  v2)
923
{
924 925 926
	const FileAndDirectory *fad1, *fad2;
	fad1 = v1;
	fad2 = v2;
927

928 929
	return (fad1->file == fad2->file &&
		fad1->directory == fad2->directory);
930 931
}

932 933
static guint
file_and_directory_hash  (gconstpointer  v)
934
{
935
	const FileAndDirectory *fad;
936

937 938
	fad = v;
	return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
939 940
}

941

Alexander Larsson's avatar
Alexander Larsson committed
942

943 944 945

static ScriptLaunchParame