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 sort_directories_first;

236
	gboolean show_foreign_files;
237
	gboolean show_hidden_files;
238
	gboolean ignore_hidden_file_preferences;
239 240 241

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
242

243 244
	gboolean selection_was_removed;

245 246 247
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

248 249 250
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

Alexander Larsson's avatar
Alexander Larsson committed
251 252
	GtkActionGroup *open_with_action_group;
	guint open_with_merge_id;
Alexander Larsson's avatar
Alexander Larsson committed
253 254

	GList *subdirectory_list;
255 256

	GdkPoint context_menu_position;
257
};
Ettore Perazzoli's avatar
Ettore Perazzoli committed
258

259 260 261 262 263
typedef struct {
	NautilusFile *file;
	NautilusDirectory *directory;
} FileAndDirectory;

264
/* forward declarations */
265

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

306 307
static void     update_templates_directory                     (NautilusView *view);
static void     user_dirs_changed                              (NautilusView *view);
308

309 310
static gboolean file_list_all_are_folders                      (GList *file_list);

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

334
/* virtual methods (public and non-public) */
335

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

347
	EEL_CALL_METHOD
348
		(NAUTILUS_VIEW_CLASS, view,
349 350
		 merge_menus, (view));
}
351

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

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

362 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
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
394
 * link and paste operations.
395 396 397 398 399 400 401 402 403 404 405 406
 */

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));
}

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

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

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

428
	EEL_CALL_METHOD
429
		(NAUTILUS_VIEW_CLASS, view,
430 431
		 set_selection, (view, selection));
}
432 433

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

438
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
439
		(NAUTILUS_VIEW_CLASS, view,
440
		 get_selection_for_file_transfer, (view));
441 442
}

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

455
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
456
		(NAUTILUS_VIEW_CLASS, view,
457
		 get_selected_icon_locations, (view));
458 459 460
}

static void
461
nautilus_view_invert_selection (NautilusView *view)
462
{
463
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
464 465

	EEL_CALL_METHOD
466
		(NAUTILUS_VIEW_CLASS, view,
467
		 invert_selection, (view));
468 469
}

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

	EEL_CALL_METHOD
481
		(NAUTILUS_VIEW_CLASS, view,
482 483
		 reveal_selection, (view));
}
484

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

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

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

513
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
514
		(NAUTILUS_VIEW_CLASS, view,
515
		 using_manual_layout, (view));
516 517 518
}

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

523
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
524
		(NAUTILUS_VIEW_CLASS, view,
525
		 get_item_count, (view));
526 527
}

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

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

550
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
551
		(NAUTILUS_VIEW_CLASS, view,
552 553
		 is_read_only, (view));
}
554

555
static gboolean
556
showing_trash_directory (NautilusView *view)
557 558 559
{
	NautilusFile *file;

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

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

572
	return !nautilus_view_is_read_only (view) && !showing_trash_directory (view);
573 574
}

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

580
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
581
		(NAUTILUS_VIEW_CLASS, view,
582
		 is_empty, (view));
583 584
}

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

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

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

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

618 619 620 621 622
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}

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

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

632 633
	if (!nautilus_view_supports_zooming (view)) {
		return NAUTILUS_ZOOM_LEVEL_STANDARD;
634 635
	}

636
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
637
		(NAUTILUS_VIEW_CLASS, view,
638
		 get_zoom_level, (view));
639 640
}

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

655 656
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
657
	}
658

659
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
660
		(NAUTILUS_VIEW_CLASS, view,
661
		 can_zoom_in, (view));
662 663
}

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

678 679
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
680 681
	}

682
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
683
		(NAUTILUS_VIEW_CLASS, view,
684
		 can_zoom_out, (view));
685 686
}

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

692
	return view->details->supports_zooming;
693 694
}

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

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

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

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

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

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

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

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

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

768
	EEL_CALL_METHOD (NAUTILUS_VIEW_CLASS, view,
769
			 set_is_active, (view, is_active));
770 771
}

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

789
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
790
		(NAUTILUS_VIEW_CLASS, view,
791
		 get_selection, (view));
792 793 794
}


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

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


811
	EEL_CALL_METHOD
812
		(NAUTILUS_VIEW_CLASS, view,
813
		 update_menus, (view));
814

815 816
	view->details->menu_states_untrustworthy = FALSE;
}
817

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

824 825
typedef struct {
	NautilusFile *file;
826
	NautilusView *directory_view;
827
} ScriptLaunchParameters;
828

829 830
typedef struct {
	NautilusFile *file;
831
	NautilusView *directory_view;
832
} CreateTemplateParameters;
833

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

841 842 843
	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
844

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

850
	return result;
851 852
}

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

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

863 864
	g_free (parameters);
}			      
865

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

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


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

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

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


906 907 908 909
static void
file_and_directory_list_free (GList *list)
{
	GList *l;
910

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

915
	g_list_free (list);
916 917
}

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

926 927
	return (fad1->file == fad2->file &&
		fad1->directory == fad2->directory);
928 929
}

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

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

939

Alexander Larsson's avatar
Alexander Larsson committed
940

941 942 943

static ScriptLaunchParameters *
script_launch_parameters_new (NautilusFile *file,
944
			      NautilusView