nautilus-view.c 272 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>
49 50 51
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
Alexander Larsson's avatar
Alexander Larsson committed
52

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

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

86 87 88
#define DEBUG_FLAG NAUTILUS_DEBUG_DIRECTORY_VIEW
#include <libnautilus-private/nautilus-debug.h>

89 90 91 92 93 94 95 96 97 98 99
/* 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

100
#define SILENT_WINDOW_OPEN_LIMIT 5
101

102 103 104
#define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
#define DUPLICATE_VERTICAL_ICON_OFFSET   30

105 106
#define MAX_QUEUED_UPDATES 500

107 108 109 110 111 112
#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"
113

114 115 116 117 118 119
#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
120

121 122 123
#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"
124

125
#define NAUTILUS_VIEW_POPUP_PATH_LOCATION			  "/location"
126

127
#define MAX_MENU_LEVELS 5
128
#define TEMPLATE_LIMIT 30
129

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

148
enum {
149
	PROP_WINDOW_SLOT = 1,
150
	PROP_SUPPORTS_ZOOMING,
151
	NUM_PROPERTIES
Alexander Larsson's avatar
Alexander Larsson committed
152 153
};

154
static guint signals[LAST_SIGNAL];
155
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
Ettore Perazzoli's avatar
Ettore Perazzoli committed
156

157 158
static GdkAtom copied_files_atom;

159
static char *scripts_directory_uri = NULL;
160 161
static int scripts_directory_uri_length;

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

173
	gboolean supports_zooming;
174

175
	GList *scripts_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
176 177 178
	GtkActionGroup *scripts_action_group;
	guint scripts_merge_id;
	
179
	GList *templates_directory_list;
Alexander Larsson's avatar
Alexander Larsson committed
180 181
	GtkActionGroup *templates_action_group;
	guint templates_merge_id;
182

Alexander Larsson's avatar
Alexander Larsson committed
183 184 185
	GtkActionGroup *extensions_menu_action_group;
	guint extensions_menu_merge_id;
	
186
	guint display_selection_idle_id;
187
	guint update_menus_timeout_id;
188
	guint update_status_idle_id;
189 190
	guint reveal_selection_idle_id;

191 192 193 194 195
	guint display_pending_source_id;
	guint changes_timeout_id;

	guint update_interval;
 	guint64 last_queued;
196
	
197 198
	guint files_added_handler_id;
	guint files_changed_handler_id;
199
	guint load_error_handler_id;
200
	guint done_loading_handler_id;
201
	guint file_changed_handler_id;
202

203 204
	guint delayed_rename_file_id;

205 206 207 208 209 210 211 212
	GList *new_added_files;
	GList *new_changed_files;

	GHashTable *non_ready_files;

	GList *old_added_files;
	GList *old_changed_files;

213
	GList *pending_selection;
214

215 216 217
	/* whether we are in the active slot */
	gboolean active;

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

229 230 231 232 233 234 235 236
	/* 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;

237 238
	gboolean is_renaming;

239 240
	gboolean sort_directories_first;

241
	gboolean show_foreign_files;
242
	gboolean show_hidden_files;
243
	gboolean ignore_hidden_file_preferences;
244 245 246

	gboolean batching_selection_level;
	gboolean selection_changed_while_batched;
247

248 249
	gboolean selection_was_removed;

250 251 252
	gboolean metadata_for_directory_as_file_pending;
	gboolean metadata_for_files_in_directory_pending;

253 254 255
	gboolean selection_change_is_due_to_shell;
	gboolean send_selection_change_to_shell;

Alexander Larsson's avatar
Alexander Larsson committed
256 257
	GtkActionGroup *open_with_action_group;
	guint open_with_merge_id;
Alexander Larsson's avatar
Alexander Larsson committed
258 259

	GList *subdirectory_list;
260 261

	GdkPoint context_menu_position;
262
};
Ettore Perazzoli's avatar
Ettore Perazzoli committed
263

264 265 266 267 268
typedef struct {
	NautilusFile *file;
	NautilusDirectory *directory;
} FileAndDirectory;

269
/* forward declarations */
270

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

311 312
static void     update_templates_directory                     (NautilusView *view);
static void     user_dirs_changed                              (NautilusView *view);
313

314 315
static gboolean file_list_all_are_folders                      (GList *file_list);

316 317 318 319 320
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

321
/* virtual methods (public and non-public) */
322

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

334
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->merge_menus (view);
335
}
336

337
static void
338
nautilus_view_unmerge_menus (NautilusView *view)
Alexander Larsson's avatar
Alexander Larsson committed
339
{
340
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
341

342
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->unmerge_menus (view);}
Alexander Larsson's avatar
Alexander Larsson committed
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 373 374 375
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
376
 * link and paste operations.
377 378 379 380 381 382 383
 */

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

384
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view);
385 386
}

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

398
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view);
Alexander Larsson's avatar
Alexander Larsson committed
399 400 401
}

static void
402
nautilus_view_call_set_selection (NautilusView *view, GList *selection)
Alexander Larsson's avatar
Alexander Larsson committed
403
{
404
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
405

406
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection);
407
}
408 409

static GList *
410
nautilus_view_get_selection_for_file_transfer (NautilusView *view)
411
{
412
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
413

414
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view);
415 416
}

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

429
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selected_icon_locations (view);
430 431 432
}

static void
433
nautilus_view_invert_selection (NautilusView *view)
434
{
435
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
436

437
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view);
438 439
}

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

450
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view);
451
}
452

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

464
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
465 466 467

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

468 469 470
	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,
471
						       NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT);
472 473 474 475
	}
}

static gboolean
476
nautilus_view_using_manual_layout (NautilusView  *view)
477
{
478
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
479

480
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->using_manual_layout (view);
481 482 483
}

static guint
484
nautilus_view_get_item_count (NautilusView *view)
485
{
486
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), 0);
487

488
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_item_count (view);
489 490
}

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

506
static gboolean
507
nautilus_view_is_read_only (NautilusView *view)
508
{
509
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
510

511
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_read_only (view);
512
}
513

514
static gboolean
515
showing_trash_directory (NautilusView *view)
516 517 518
{
	NautilusFile *file;

519
	file = nautilus_view_get_directory_as_file (view);
520 521 522 523 524 525
	if (file != NULL) {
		return nautilus_file_is_in_trash (file);
	}
	return FALSE;
}

526
static gboolean
527
nautilus_view_supports_creating_files (NautilusView *view)
528
{
529
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
530

531
	return !nautilus_view_is_read_only (view) && !showing_trash_directory (view);
532 533
}

534
static gboolean
535
nautilus_view_is_empty (NautilusView *view)
536
{
537
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
538

539
	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_empty (view);
540 541
}

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

554 555 556
	if (!nautilus_view_supports_zooming (view)) {
		return;
	}
Alexander Larsson's avatar
Alexander Larsson committed
557

558
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment);
Alexander Larsson's avatar
Alexander Larsson committed
559 560
}

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

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

577
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->zoom_to_level (view, zoom_level);
578
}
Alexander Larsson's avatar
Alexander Larsson committed
579

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

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

589
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_zoom_level (view);
590 591
}

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

606 607
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
608
	}
609

610
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view);
611 612
}

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

627 628
	if (!nautilus_view_supports_zooming (view)) {
		return FALSE;
629 630
	}

631
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view);
632 633
}

634
gboolean
635
nautilus_view_supports_zooming (NautilusView *view)
636
{
637
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
638

639
	return view->details->supports_zooming;
640 641
}

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

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

657
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_default_zoom_level (view);
Alexander Larsson's avatar
Alexander Larsson committed
658 659
}

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

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

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

679
/**
680
 * nautilus_view_get_selection:
681 682 683 684 685
 *
 * 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).
686
 * @view: NautilusView whose selected items are of interest.
687 688 689 690 691
 * 
 * Return value: GList of NautilusFile pointers representing the selection.
 * 
 **/
GList *
692
nautilus_view_get_selection (NautilusView *view)
693
{
694
	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
695

696
	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (view);
697 698
}

699 700 701 702
/**
 * nautilus_view_update_menus:
 * 
 * Update the sensitivity and wording of dynamic menu items.
703
 * @view: NautilusView in question.
704 705 706
 */
void
nautilus_view_update_menus (NautilusView *view)
707
{
708
	g_return_if_fail (NAUTILUS_IS_VIEW (view));
Alexander Larsson's avatar
Alexander Larsson committed
709

710 711
	if (!view->details->active) {
		return;
712
	}
713

714
	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_menus (view);
715

716 717
	view->details->menu_states_untrustworthy = FALSE;
}
718

719 720 721
typedef struct {
	GAppInfo *application;
	GList *files;
722
	NautilusView *directory_view;
723
} ApplicationLaunchParameters;
724

725 726
typedef struct {
	NautilusFile *file;
727
	NautilusView *directory_view;
728
} ScriptLaunchParameters;
729

730 731
typedef struct {
	NautilusFile *file;
732
	NautilusView *directory_view;
733
} CreateTemplateParameters;
734

735 736 737
static ApplicationLaunchParameters *
application_launch_parameters_new (GAppInfo *application,
			      	   GList *files,
738
			           NautilusView *directory_view)
739
{
740
	ApplicationLaunchParameters *result;
741

742 743 744
	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
745

746 747 748
	if (directory_view != NULL) {
		g_object_ref (directory_view);
		result->directory_view = directory_view;
749 750
	}

751
	return result;
752 753
}

754
static void
755
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
756
{
757 758
	g_object_unref (parameters->application);
	nautilus_file_list_free (parameters->files);
759

760 761
	if (parameters->directory_view != NULL) {
		g_object_unref (parameters->directory_view);
762 763
	}

764 765
	g_free (parameters);
}			      
766

767 768
static GList *
file_and_directory_list_to_files (GList *fad_list)
769
{
770 771
	GList *res, *l;
	FileAndDirectory *fad;
772

773 774 775 776 777 778 779
	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);
}
780 781


782 783 784 785 786
static GList *
file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
{
	GList *res, *l;
	FileAndDirectory *fad;
787

788 789 790 791 792 793 794 795
	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);
796 797 798
}

static void
799
file_and_directory_free (FileAndDirectory *fad)
800
{
801 802 803 804
	nautilus_directory_unref (fad->directory);
	nautilus_file_unref (fad->file);
	g_free (fad);
}
805 806


807 808 809 810
static void
file_and_directory_list_free (GList *list)
{
	GList *l;
811

812 813
	for (l = list; l != NULL; l = l->next) {
		file_and_directory_free (l->data);
814
	}
815

816
	g_list_free (list);
817 818
}

819 820 821
static gboolean
file_and_directory_equal (gconstpointer  v1,
			  gconstpointer  v2)
822
{
823 824 825
	const FileAndDirectory *fad1, *fad2;
	fad1 = v1;
	fad2 = v2;
826

827 828
	return (fad1->file == fad2->file &&
		fad1->directory == fad2->directory);
829 830
}

831 832
static guint
file_and_directory_hash  (gconstpointer  v)
833
{
834
	const FileAndDirectory *fad;
835

836 837
	fad = v;
	return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
838 839
}

840

Alexander Larsson's avatar
Alexander Larsson committed
841

842 843 844

static ScriptLaunchParameters *
script_launch_parameters_new (NautilusFile *file,
845
			      NautilusView *directory_view)
846
{
847 848 849 850 851 852 853 854 855
	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;
856 857
}

858
static void
859
script_launch_parameters_free (ScriptLaunchParameters *parameters)
860
{
861 862 863 864
	g_object_unref (parameters->directory_view);
	nautilus_file_unref (parameters->file);
	g_free (parameters);
}			      
865

866 867
static CreateTemplateParameters *
create_template_parameters_new (NautilusFile *file,
868
				NautilusView *directory_view)
869 870
{
	CreateTemplateParameters *result;
871

872 873 874 875 876
	result = g_new0 (CreateTemplateParameters, 1);
	g_object_ref (directory_view);
	result->directory_view = directory_view;
	nautilus_file_ref (file);
	result->file = file;
877

878
	return result;
879 880
}

881
static void
882
create_templates_parameters_free (CreateTemplateParameters *parameters)
883
{
884 885 886 887 888 889
	g_object_unref (parameters->directory_view);
	nautilus_file_unref (parameters->file);
	g_free (parameters);
}			      

NautilusWindow *
890
nautilus_view_get_nautilus_window (NautilusView  *view)
891 892 893 894
{
	g_assert (view->details->window != NULL);

	return view->details->window;
895 896
}

897
NautilusWindowSlot *
898
nautilus_view_get_nautilus_window_slot (NautilusView  *view)
899
{
900
	g_assert (view->details->slot != NULL);
901

902 903
	return view->details->slot;
}
904

905 906 907 908 909
/* 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 *
910
nautilus_view_get_containing_window (NautilusView *view)
911 912
{
	GtkWidget *window;
913

914
	g_assert (NAUTILUS_IS_VIEW (view));
915 916 917 918 919
	
	window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
	if (window == NULL) {
		return NULL;
	}
920

921
	return GTK_WINDOW (window);
922 923
}

Alexander Larsson's avatar
Alexander Larsson committed
924
static gboolean
925 926 927
nautilus_view_confirm_multiple (GtkWindow *parent_window,
				int count,
				gboolean tabs)
Alexander Larsson's avatar
Alexander Larsson committed
928
{
929 930 931 932
	GtkDialog *dialog;
	char *prompt;
	char *detail;
	int response;
933

934
	if (count <= SILENT_WINDOW_OPEN_LIMIT) {
935
		return TRUE;
Alexander Larsson's avatar
Alexander Larsson committed
936 937
	}