nautilus-view.c 276 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-properties-window.h"
40
#include "nautilus-src-marshal.h"
41 42 43 44 45 46 47

#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
48

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

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

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

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

96
#define SILENT_WINDOW_OPEN_LIMIT 5
97

98 99 100
#define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
#define DUPLICATE_VERTICAL_ICON_OFFSET   30

101 102
#define MAX_QUEUED_UPDATES 500

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

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

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

121
#define NAUTILUS_VIEW_POPUP_PATH_LOCATION			  "/location"
122

123
#define MAX_MENU_LEVELS 5
124
#define TEMPLATE_LIMIT 30
125

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

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

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

153 154
static GdkAtom copied_files_atom;

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

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

169
	gboolean supports_zooming;
170

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

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

187 188 189 190 191
	guint display_pending_source_id;
	guint changes_timeout_id;

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

199 200
	guint delayed_rename_file_id;

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

	GHashTable *non_ready_files;

	GList *old_added_files;
	GList *old_changed_files;

209
	GList *pending_selection;
210

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

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

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

233 234
	gboolean sort_directories_first;

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

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
241

242 243
	gboolean selection_was_removed;

244 245 246
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

247 248 249
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

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

	GList *subdirectory_list;
254 255

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

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

263
/* forward declarations */
264

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

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

308 309
static gboolean file_list_all_are_folders                      (GList *file_list);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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


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

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

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

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

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

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

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

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

849
	return result;
850 851
}

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

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

862 863
	g_free (parameters);
}			      
864

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

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


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

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

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


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

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

914
	g_list_free (list);
915 916
}

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

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

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

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

938

Alexander Larsson's avatar
Alexander Larsson committed
939

940 941 942

static ScriptLaunchParameters *
script_launch_parameters_new (NautilusFile *file,
943
			      NautilusView *directory_view)
944
{
945 946 947 948 949 950 951 952 953
	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;
<