nautilus-view.c 279 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 34 35 36
#include "nautilus-view.h"

#include "file-manager/fm-list-view.h"
#include "file-manager/fm-properties-window.h"

37 38 39
#include "nautilus-actions.h"
#include "nautilus-desktop-icon-view.h"
#include "nautilus-error-reporting.h"
40
#include "nautilus-mime-actions.h"
41
#include "nautilus-src-marshal.h"
42 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 146 147
enum {
	PROP_0,
	PROP_WINDOW_SLOT
Alexander Larsson's avatar
Alexander Larsson committed
148 149 150
};


151
static guint signals[LAST_SIGNAL];
Ettore Perazzoli's avatar
Ettore Perazzoli committed
152

153 154
static GdkAtom copied_files_atom;

155 156 157
static char *scripts_directory_uri;
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
	GList *scripts_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
170 171 172
	GtkActionGroup *scripts_action_group;
	guint scripts_merge_id;
	
173
	GList *templates_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
174 175
	GtkActionGroup *templates_action_group;
	guint templates_merge_id;
176

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

185 186 187 188 189
	guint display_pending_source_id;
	guint changes_timeout_id;

	guint update_interval;
 	guint64 last_queued;
190
	
191 192
	guint files_added_handler_id;
	guint files_changed_handler_id;
193
	guint load_error_handler_id;
194
	guint done_loading_handler_id;
195
	guint file_changed_handler_id;
196

197 198
	guint delayed_rename_file_id;

199 200 201 202 203 204 205 206
	GList *new_added_files;
	GList *new_changed_files;

	GHashTable *non_ready_files;

	GList *old_added_files;
	GList *old_changed_files;

207
	GList *pending_selection;
208

209 210 211
	/* whether we are in the active slot */
	gboolean active;

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

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

231 232
	gboolean sort_directories_first;

233
	gboolean show_foreign_files;
234
	gboolean show_hidden_files;
235
	gboolean ignore_hidden_file_preferences;
236 237 238

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
239

240 241
	gboolean selection_was_removed;

242 243 244
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

245 246 247
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

Alexander Larsson's avatar
Alexander Larsson committed
248 249
	GtkActionGroup *open_with_action_group;
	guint open_with_merge_id;
Alexander Larsson's avatar
Alexander Larsson committed
250 251

	GList *subdirectory_list;
252 253

	GdkPoint context_menu_position;
254
};
Ettore Perazzoli's avatar
Ettore Perazzoli committed
255

256 257 258 259 260
typedef struct {
	NautilusFile *file;
	NautilusDirectory *directory;
} FileAndDirectory;

261
/* forward declarations */
262

263
static gboolean display_selection_info_idle_callback           (gpointer              data);
264 265 266 267 268 269
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
270 271
static void     trash_or_delete_files                          (GtkWindow            *parent_window,
								const GList          *files,
272
								gboolean              delete_if_all_already_in_trash,
273 274
								NautilusView      *view);
static void     load_directory                                 (NautilusView      *view,
275
								NautilusDirectory    *directory);
276 277 278
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);
279
static void     clipboard_changed_callback                     (NautilusClipboardMonitor *monitor,
280
								NautilusView      *view);
281 282
static void     open_one_in_new_window                         (gpointer              data,
								gpointer              callback_data);
283 284
static void     open_one_in_folder_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
 * nautilus_view_select_all:
363 364 365 366 367
 *
 * select all the items in the view
 * 
 **/
static void
368
nautilus_view_select_all (NautilusView *view)
369
{
370
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
371

372
	EEL_CALL_METHOD
373
		(NAUTILUS_VIEW_CLASS, view,
374
		 select_all, (view));
Alexander Larsson's avatar
Alexander Larsson committed
375 376 377
}

static void
378
nautilus_view_call_set_selection (NautilusView *view, GList *selection)
Alexander Larsson's avatar
Alexander Larsson committed
379
{
380
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
381

382
	EEL_CALL_METHOD
383
		(NAUTILUS_VIEW_CLASS, view,
384 385
		 set_selection, (view, selection));
}
386 387

static GList *
388
nautilus_view_get_selection_for_file_transfer (NautilusView *view)
389
{
390
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
391

392
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
393
		(NAUTILUS_VIEW_CLASS, view,
394
		 get_selection_for_file_transfer, (view));
395 396
}

397
/**
398
 * nautilus_view_get_selected_icon_locations:
399 400 401 402 403 404
 *
 * return an array of locations of selected icons if available
 * Return value: GArray of GdkPoints
 * 
 **/
static GArray *
405
nautilus_view_get_selected_icon_locations (NautilusView *view)
406
{
407
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
408

409
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
410
		(NAUTILUS_VIEW_CLASS, view,
411
		 get_selected_icon_locations, (view));
412 413 414
}

static void
415
nautilus_view_invert_selection (NautilusView *view)
416
{
417
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
418 419

	EEL_CALL_METHOD
420
		(NAUTILUS_VIEW_CLASS, view,
421
		 invert_selection, (view));
422 423
}

424
/**
425
 * nautilus_view_reveal_selection:
426 427 428 429
 *
 * Scroll as necessary to reveal the selected items.
 **/
static void
430
nautilus_view_reveal_selection (NautilusView *view)
431
{
432
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
433 434

	EEL_CALL_METHOD
435
		(NAUTILUS_VIEW_CLASS, view,
436 437
		 reveal_selection, (view));
}
438

439
/**
440
 * nautilus_view_reset_to_defaults:
441 442 443 444
 *
 * set sorting order, zoom level, etc. to match defaults
 * 
 **/
445
static void
446
nautilus_view_reset_to_defaults (NautilusView *view)
447
{
448
	NautilusWindowShowHiddenFilesMode mode;
449

450
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
451 452
	
	EEL_CALL_METHOD
453
		(NAUTILUS_VIEW_CLASS, view,
454 455 456 457
		 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,
458
						       NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT);
459 460 461 462
	}
}

static gboolean
463
nautilus_view_using_manual_layout (NautilusView  *view)
464
{
465
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
466

467
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
468
		(NAUTILUS_VIEW_CLASS, view,
469
		 using_manual_layout, (view));
470 471 472
}

static guint
473
nautilus_view_get_item_count (NautilusView *view)
474
{
475
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), 0);
476

477
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
478
		(NAUTILUS_VIEW_CLASS, view,
479
		 get_item_count, (view));
480 481
}

482
/**
483
 * nautilus_view_can_rename_file
484 485 486 487 488 489 490 491
 *
 * Determine whether a file can be renamed.
 * @file: A NautilusFile
 * 
 * Return value: TRUE if @file can be renamed, FALSE otherwise.
 * 
 **/
static gboolean
492
nautilus_view_can_rename_file (NautilusView *view, NautilusFile *file)
493 494
{
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
495
		(NAUTILUS_VIEW_CLASS, view,
496 497
		 can_rename_file, (view, file));
}
498

499
static gboolean
500
nautilus_view_is_read_only (NautilusView *view)
501
{
502
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
503

504
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
505
		(NAUTILUS_VIEW_CLASS, view,
506 507
		 is_read_only, (view));
}
508

509
static gboolean
510
showing_trash_directory (NautilusView *view)
511 512 513
{
	NautilusFile *file;

514
	file = nautilus_view_get_directory_as_file (view);
515 516 517 518 519 520
	if (file != NULL) {
		return nautilus_file_is_in_trash (file);
	}
	return FALSE;
}

521
static gboolean
522
nautilus_view_supports_creating_files (NautilusView *view)
523
{
524
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
525

526
	return !nautilus_view_is_read_only (view) && !showing_trash_directory (view);
527 528
}

529
static gboolean
530
nautilus_view_is_empty (NautilusView *view)
531
{
532
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
533

534
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
535
		(NAUTILUS_VIEW_CLASS, view,
536
		 is_empty, (view));
537 538
}

539 540 541 542 543 544 545 546 547
/**
 * 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)
548
{
549
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
550

551 552 553
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}
Alexander Larsson's avatar
Alexander Larsson committed
554

555
	EEL_CALL_METHOD
556
		(NAUTILUS_VIEW_CLASS, view,
557
		 bump_zoom_level, (view, zoom_increment));
Alexander Larsson's avatar
Alexander Larsson committed
558 559
}

560 561 562 563 564 565 566 567 568
/**
 * 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)
569
{
570
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
571

572 573 574 575 576
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}

	EEL_CALL_METHOD
577
		(NAUTILUS_VIEW_CLASS, view,
578
		 zoom_to_level, (view, zoom_level));
579
}
Alexander Larsson's avatar
Alexander Larsson committed
580

581
NautilusZoomLevel
582
nautilus_view_get_zoom_level (NautilusView *view)
583
{
584
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
585

586 587
	if (!nautilus_view_supports_zooming (view)) {
		return NAUTILUS_ZOOM_LEVEL_STANDARD;
588 589
	}

590
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
591
		(NAUTILUS_VIEW_CLASS, view,
592
		 get_zoom_level, (view));
593 594
}

595 596 597 598
/**
 * nautilus_view_can_zoom_in:
 *
 * Determine whether the view can be zoomed any closer.
599
 * @view: The zoomable NautilusView.
600 601 602 603 604 605
 * 
 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_in (NautilusView *view)
606
{
607
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
608

609 610
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
611
	}
612

613
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
614
		(NAUTILUS_VIEW_CLASS, view,
615
		 can_zoom_in, (view));
616 617
}

618 619 620 621
/**
 * nautilus_view_can_zoom_out:
 *
 * Determine whether the view can be zoomed any further away.
622
 * @view: The zoomable NautilusView.
623 624 625 626 627 628
 * 
 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_out (NautilusView *view)
629
{
630
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
631

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

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

641
gboolean
642
nautilus_view_supports_zooming (NautilusView *view)
643
{
644
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
645

646
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
647
		(NAUTILUS_VIEW_CLASS, view,
648
		 supports_zooming, (view));
649 650
}

651 652 653 654 655 656 657 658
/**
 * 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
659
{
660
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
661 662 663

	if (!nautilus_view_supports_zooming (view)) {
		return;
Alexander Larsson's avatar
Alexander Larsson committed
664
	}
665 666

	EEL_CALL_METHOD
667
		(NAUTILUS_VIEW_CLASS, view,
668
		 restore_default_zoom_level, (view));
Alexander Larsson's avatar
Alexander Larsson committed
669 670
}

671 672
const char *
nautilus_view_get_view_id (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
673
{
674
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
675
		(NAUTILUS_VIEW_CLASS, view,
676 677
		 get_view_id, (view));
}
Alexander Larsson's avatar
Alexander Larsson committed
678

679 680 681 682
char *
nautilus_view_get_first_visible_file (NautilusView *view)
{
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
683
		(NAUTILUS_VIEW_CLASS, view,
684
		 get_first_visible_file, (view));
Alexander Larsson's avatar
Alexander Larsson committed
685 686 687
}

void
688 689
nautilus_view_scroll_to_file (NautilusView *view,
			      const char *uri)
Alexander Larsson's avatar
Alexander Larsson committed
690
{
691
	EEL_CALL_METHOD
692
		(NAUTILUS_VIEW_CLASS, view,
693 694
		 scroll_to_file, (view, uri));
}
Alexander Larsson's avatar
Alexander Larsson committed
695

696
char **
697
nautilus_view_get_emblem_names_to_exclude (NautilusView *view)
698
{
699 700 701
	char **excludes;
	int i;
	
702
	g_assert (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
703

704 705 706 707 708 709 710 711 712 713 714 715
	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
716 717
}

718
void
719
nautilus_view_set_is_active (NautilusView *view,
720
			     gboolean is_active)
721
{
722
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
723

724
	EEL_CALL_METHOD (NAUTILUS_VIEW_CLASS, view,
725
			 set_is_active, (view, is_active));
726 727
}

728
/**
729
 * nautilus_view_get_selection:
730 731 732 733 734
 *
 * 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).
735
 * @view: NautilusView whose selected items are of interest.
736 737 738 739 740
 * 
 * Return value: GList of NautilusFile pointers representing the selection.
 * 
 **/
GList *
741
nautilus_view_get_selection (NautilusView *view)
742
{
743
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
744

745
	return EEL_CALL_METHOD_WITH_RETURN_VALUE
746
		(NAUTILUS_VIEW_CLASS, view,
747
		 get_selection, (view));
748 749 750
}


751 752 753 754
/**
 * nautilus_view_update_menus:
 * 
 * Update the sensitivity and wording of dynamic menu items.
755
 * @view: NautilusView in question.
756 757 758
 */
void
nautilus_view_update_menus (NautilusView *view)
759
{
760
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
761

762 763
	if (!view->details->active) {
		return;
764
	}
765 766


767
	EEL_CALL_METHOD
768
		(NAUTILUS_VIEW_CLASS, view,
769
		 update_menus, (view));
770

771 772
	view->details->menu_states_untrustworthy = FALSE;
}
773

774 775 776
typedef struct {
	GAppInfo *application;
	GList *files;
777
	NautilusView *directory_view;
778
} ApplicationLaunchParameters;
779

780 781
typedef struct {
	NautilusFile *file;
782
	NautilusView *directory_view;
783
} ScriptLaunchParameters;
784

785 786
typedef struct {
	NautilusFile *file;
787
	NautilusView *directory_view;
788
} CreateTemplateParameters;
789

790 791 792
static ApplicationLaunchParameters *
application_launch_parameters_new (GAppInfo *application,
			      	   GList *files,
793
			           NautilusView *directory_view)
794
{
795
	ApplicationLaunchParameters *result;
796

797 798 799
	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
800

801 802 803
	if (directory_view != NULL) {
		g_object_ref (directory_view);
		result->directory_view = directory_view;
804 805
	}

806
	return result;
807 808
}

809
static void
810
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
811
{
812 813
	g_object_unref (parameters->application);
	nautilus_file_list_free (parameters->files);
814

815 816
	if (parameters->directory_view != NULL) {
		g_object_unref (parameters->directory_view);
817 818
	}

819 820
	g_free (parameters);
}			      
821

822 823
static GList *
file_and_directory_list_to_files (GList *fad_list)
824
{
825 826
	GList *res, *l;
	FileAndDirectory *fad;
827

828 829 830 831 832 833 834
	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);
}
835 836


837 838 839 840 841
static GList *
file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
{
	GList *res, *l;
	FileAndDirectory *fad;
842

843 844 845 846 847 848 849 850
	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);
851 852 853
}

static void
854
file_and_directory_free (FileAndDirectory *fad)
855
{
856 857 858 859
	nautilus_directory_unref (fad->directory);
	nautilus_file_unref (fad->file);
	g_free (fad);
}
860 861


862 863 864 865
static void
file_and_directory_list_free (GList *list)
{
	GList *l;
866

867 868
	for (l = list; l != NULL; l = l->next) {
		file_and_directory_free (l->data);
869
	}
870

871
	g_list_free (list);
872 873
}

874 875 876
static gboolean
file_and_directory_equal (gconstpointer  v1,
			  gconstpointer  v2)
877
{
878 879 880
	const FileAndDirectory *fad1, *fad2;
	fad1 = v1;
	fad2 = v2;
881

882 883
	return (fad1->file == fad2->file &&
		fad1->directory == fad2->directory);
884 885
}

886 887
static guint
file_and_directory_hash  (gconstpointer  v)
888
{
889
	const FileAndDirectory *fad;
890

891 892
	fad = v;
	return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
893 894
}

895

Alexander Larsson's avatar
Alexander Larsson committed
896

897 898 899

static ScriptLaunchParameters *
script_launch_parameters_new (NautilusFile *file,
900
			      NautilusView *directory_view)
901
{
902 903 904 905 906 907 908 909 910
	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;
911 912
}

913
static void
914
script_launch_parameters_free (ScriptLaunchParameters *parameters)
915
{
916 917 918 919
	g_object_unref (parameters->directory_view);
	nautilus_file_unref (parameters->file);
	g_free (parameters);
}			      
920

921 922
static CreateTemplateParameters *
create_template_parameters_new (NautilusFile *file,
923
				NautilusView *directory_view)
924 925
{
	CreateTemplateParameters *result;
926

927 928 929 930 931
	result = g_new0 (CreateTemplateParameters, 1);
	g_object_ref (directory_view);
	result->directory_view = directory_view;
	nautilus_file_ref (file);
	result->file = file;