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
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gnome-extensions.h>
#include <eel/eel-gtk-extensions.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>
80
#include <libnautilus-private/nautilus-icon-names.h>
Amos Brocco's avatar
Amos Brocco committed
81
#include <libnautilus-private/nautilus-file-undo-manager.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,
136
	MOVE_COPY_ITEMS,
137
	REMOVE_FILE,
138
	ZOOM_LEVEL_CHANGED,
139
	SELECTION_CHANGED,
Alexander Larsson's avatar
Alexander Larsson committed
140 141
	TRASH,
	DELETE,
142 143 144
	LAST_SIGNAL
};

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

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

154 155
static GdkAtom copied_files_atom;

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

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

170
	gboolean supports_zooming;
171

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

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

188 189 190 191 192
	guint display_pending_source_id;
	guint changes_timeout_id;

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

200 201
	guint delayed_rename_file_id;

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

	GHashTable *non_ready_files;

	GList *old_added_files;
	GList *old_changed_files;

210
	GList *pending_selection;
211

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

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

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

234 235
	gboolean is_renaming;

236 237
	gboolean sort_directories_first;

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

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
244

245 246
	gboolean selection_was_removed;

247 248 249
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

250 251 252
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

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

	GList *subdirectory_list;
257 258

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

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

266
/* forward declarations */
267

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

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

311 312
static gboolean file_list_all_are_folders                      (GList *file_list);

313 314 315 316 317
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

318
/* virtual methods (public and non-public) */
319

320
/**
321
 * nautilus_view_merge_menus:
322 323
 * 
 * Add this view's menus to the window's menu bar.
324
 * @view: NautilusView in question.
325 326
 */
static void
327
nautilus_view_merge_menus (NautilusView *view)
328
{
329
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
330

331
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->merge_menus (view);
332
}
333

334
static void
335
nautilus_view_unmerge_menus (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
336
{
337
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
338

339
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->unmerge_menus (view);}
Alexander Larsson's avatar
Alexander Larsson committed
340

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
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
373
 * link and paste operations.
374 375 376 377 378 379 380
 */

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

381
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view);
382 383
}

384
/**
385
 * nautilus_view_select_all:
386 387 388 389 390
 *
 * select all the items in the view
 * 
 **/
static void
391
nautilus_view_select_all (NautilusView *view)
392
{
393
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
394

395
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view);
Alexander Larsson's avatar
Alexander Larsson committed
396 397 398
}

static void
399
nautilus_view_call_set_selection (NautilusView *view, GList *selection)
Alexander Larsson's avatar
Alexander Larsson committed
400
{
401
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
402

403
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection);
404
}
405 406

static GList *
407
nautilus_view_get_selection_for_file_transfer (NautilusView *view)
408
{
409
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
410

411
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view);
412 413
}

414
/**
415
 * nautilus_view_get_selected_icon_locations:
416 417 418 419 420 421
 *
 * return an array of locations of selected icons if available
 * Return value: GArray of GdkPoints
 * 
 **/
static GArray *
422
nautilus_view_get_selected_icon_locations (NautilusView *view)
423
{
424
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
425

426
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selected_icon_locations (view);
427 428 429
}

static void
430
nautilus_view_invert_selection (NautilusView *view)
431
{
432
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
433

434
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view);
435 436
}

437
/**
438
 * nautilus_view_reveal_selection:
439 440 441 442
 *
 * Scroll as necessary to reveal the selected items.
 **/
static void
443
nautilus_view_reveal_selection (NautilusView *view)
444
{
445
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
446

447
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view);
448
}
449

450
/**
451
 * nautilus_view_reset_to_defaults:
452 453 454 455
 *
 * set sorting order, zoom level, etc. to match defaults
 * 
 **/
456
static void
457
nautilus_view_reset_to_defaults (NautilusView *view)
458
{
459
	NautilusWindowShowHiddenFilesMode mode;
460

461
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
462 463 464

	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reset_to_defaults (view);

465 466 467
	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,
468
						       NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT);
469 470 471 472
	}
}

static gboolean
473
nautilus_view_using_manual_layout (NautilusView  *view)
474
{
475
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
476

477
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->using_manual_layout (view);
478 479 480
}

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

485
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_item_count (view);
486 487
}

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

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

508
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_read_only (view);
509
}
510

511
static gboolean
512
showing_trash_directory (NautilusView *view)
513 514 515
{
	NautilusFile *file;

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

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

528
	return !nautilus_view_is_read_only (view) && !showing_trash_directory (view);
529 530
}

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

536
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->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
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment);
Alexander Larsson's avatar
Alexander Larsson committed
556 557
}

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

570 571 572 573
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}

574
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->zoom_to_level (view, zoom_level);
575
}
Alexander Larsson's avatar
Alexander Larsson committed
576

577
NautilusZoomLevel
578
nautilus_view_get_zoom_level (NautilusView *view)
579
{
580
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
581

582 583
	if (!nautilus_view_supports_zooming (view)) {
		return NAUTILUS_ZOOM_LEVEL_STANDARD;
584 585
	}

586
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_zoom_level (view);
587 588
}

589 590 591 592
/**
 * nautilus_view_can_zoom_in:
 *
 * Determine whether the view can be zoomed any closer.
593
 * @view: The zoomable NautilusView.
594 595 596 597 598 599
 * 
 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_in (NautilusView *view)
600
{
601
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
602

603 604
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
605
	}
606

607
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view);
608 609
}

610 611 612 613
/**
 * nautilus_view_can_zoom_out:
 *
 * Determine whether the view can be zoomed any further away.
614
 * @view: The zoomable NautilusView.
615 616 617 618 619 620
 * 
 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
 * 
 **/
gboolean
nautilus_view_can_zoom_out (NautilusView *view)
621
{
622
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
623

624 625
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
626 627
	}

628
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view);
629 630
}

631
gboolean
632
nautilus_view_supports_zooming (NautilusView *view)
633
{
634
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
635

636
	return view->details->supports_zooming;
637 638
}

639 640 641 642 643 644 645 646
/**
 * 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
647
{
648
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
649 650 651

	if (!nautilus_view_supports_zooming (view)) {
		return;
Alexander Larsson's avatar
Alexander Larsson committed
652
	}
653

654
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_default_zoom_level (view);
Alexander Larsson's avatar
Alexander Larsson committed
655 656
}

657 658
const char *
nautilus_view_get_view_id (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
659
{
660
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_view_id (view);
661
}
Alexander Larsson's avatar
Alexander Larsson committed
662

663 664 665
char *
nautilus_view_get_first_visible_file (NautilusView *view)
{
666
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_first_visible_file (view);
Alexander Larsson's avatar
Alexander Larsson committed
667 668 669
}

void
670 671
nautilus_view_scroll_to_file (NautilusView *view,
			      const char *uri)
Alexander Larsson's avatar
Alexander Larsson committed
672
{
673
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->scroll_to_file (view, uri);
674
}
Alexander Larsson's avatar
Alexander Larsson committed
675

676
char **
677
nautilus_view_get_emblem_names_to_exclude (NautilusView *view)
678
{
679 680 681
	char **excludes;
	int i;
	
682
	g_assert (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
683

684 685 686 687 688 689 690 691 692 693 694 695
	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
696 697
}

698
/**
699
 * nautilus_view_get_selection:
700 701 702 703 704
 *
 * 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).
705
 * @view: NautilusView whose selected items are of interest.
706 707 708 709 710
 * 
 * Return value: GList of NautilusFile pointers representing the selection.
 * 
 **/
GList *
711
nautilus_view_get_selection (NautilusView *view)
712
{
713
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
714

715
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (view);
716 717
}

718 719 720 721
/**
 * nautilus_view_update_menus:
 * 
 * Update the sensitivity and wording of dynamic menu items.
722
 * @view: NautilusView in question.
723 724 725
 */
void
nautilus_view_update_menus (NautilusView *view)
726
{
727
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
728

729 730
	if (!view->details->active) {
		return;
731
	}
732

733
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_menus (view);
734

735 736
	view->details->menu_states_untrustworthy = FALSE;
}
737

738 739 740
typedef struct {
	GAppInfo *application;
	GList *files;
741
	NautilusView *directory_view;
742
} ApplicationLaunchParameters;
743

744 745
typedef struct {
	NautilusFile *file;
746
	NautilusView *directory_view;
747
} ScriptLaunchParameters;
748

749 750
typedef struct {
	NautilusFile *file;
751
	NautilusView *directory_view;
752
} CreateTemplateParameters;
753

754 755 756
static ApplicationLaunchParameters *
application_launch_parameters_new (GAppInfo *application,
			      	   GList *files,
757
			           NautilusView *directory_view)
758
{
759
	ApplicationLaunchParameters *result;
760

761 762 763
	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
764

765 766 767
	if (directory_view != NULL) {
		g_object_ref (directory_view);
		result->directory_view = directory_view;
768 769
	}

770
	return result;
771 772
}

773
static void
774
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
775
{
776 777
	g_object_unref (parameters->application);
	nautilus_file_list_free (parameters->files);
778

779 780
	if (parameters->directory_view != NULL) {
		g_object_unref (parameters->directory_view);
781 782
	}

783 784
	g_free (parameters);
}			      
785

786 787
static GList *
file_and_directory_list_to_files (GList *fad_list)
788
{
789 790
	GList *res, *l;
	FileAndDirectory *fad;
791

792 793 794 795 796 797 798
	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);
}
799 800


801 802 803 804 805
static GList *
file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
{
	GList *res, *l;
	FileAndDirectory *fad;
806

807 808 809 810 811 812 813 814
	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);
815 816 817
}

static void
818
file_and_directory_free (FileAndDirectory *fad)
819
{
820 821 822 823
	nautilus_directory_unref (fad->directory);
	nautilus_file_unref (fad->file);
	g_free (fad);
}
824 825


826 827 828 829
static void
file_and_directory_list_free (GList *list)
{
	GList *l;
830

831 832
	for (l = list; l != NULL; l = l->next) {
		file_and_directory_free (l->data);
833
	}
834

835
	g_list_free (list);
836 837
}

838 839 840
static gboolean
file_and_directory_equal (gconstpointer  v1,
			  gconstpointer  v2)
841
{
842 843 844
	const FileAndDirectory *fad1, *fad2;
	fad1 = v1;
	fad2 = v2;
845

846 847
	return (fad1->file == fad2->file &&
		fad1->directory == fad2->directory);
848 849
}

850 851
static guint
file_and_directory_hash  (gconstpointer  v)
852
{
853
	const FileAndDirectory *fad;
854

855 856
	fad = v;
	return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
857 858
}

859

Alexander Larsson's avatar
Alexander Larsson committed
860

861 862 863

static ScriptLaunchParameters *
script_launch_parameters_new (NautilusFile *file,
864
			      NautilusView *directory_view)
865
{
866 867 868 869 870 871 872 873 874
	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;
875 876
}

877
static void
878
script_launch_parameters_free (ScriptLaunchParameters *parameters)
879
{
880 881 882 883
	g_object_unref (parameters->directory_view);
	nautilus_file_unref (parameters->file);
	g_free (parameters);
}			      
884

885 886
static CreateTemplateParameters *
create_template_parameters_new (NautilusFile *file,
887
				NautilusView *directory_view)
888 889
{
	CreateTemplateParameters *result;
890

891 892 893 894 895
	result = g_new0 (CreateTemplateParameters, 1);
	g_object_ref (directory_view);
	result->directory_view = directory_view;
	nautilus_file_ref (file);
	result->file = file;
896

897
	return result;
898 899
}

900
static void
901
create_templates_parameters_free (CreateTemplateParameters *parameters)
902
{
903 904 905 906 907 908
	g_object_unref (parameters->directory_view);
	nautilus_file_unref (parameters->file);
	g_free (parameters);
}			      

NautilusWindow *
909
nautilus_view_get_nautilus_window (NautilusView  *view)
910 911 912 913
{
	g_assert (view->details->window != NULL);

	return view->details->window;
914 915
}

916
NautilusWindowSlot *
917
nautilus_view_get_nautilus_window_slot (NautilusView  *view)
918
{
919
	g_assert (view->details->slot != NULL);
920

921 922
	return view->details->slot;
}
923

924 925 926 927 928
/* Returns the GtkWindow that this directory view occupies, or NULL
 * if at the moment this directory view is not in a GtkWindow or the
 * GtkWindow cannot be determined. Primarily used for parenting dialogs.
 */
static GtkWindow *
929
nautilus_view_get_containing_window (NautilusView *view)
930 931
{
	GtkWidget *window;
932

933
	g_assert (NAUTILUS_IS_VIEW (view));
934 935 936 937 938
	
	window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
	if (window == NULL) {
		return NULL;
	}
939

940
	return GTK_WINDOW (window);
941 942
}

Alexander Larsson's avatar
Alexander Larsson committed
943
static gboolean