nautilus-3.6.3/src/nautilus-canvas-view-container.c

No issues found

  1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
  2 
  3 /* fm-icon-container.h - the container widget for file manager icons
  4 
  5    Copyright (C) 2002 Sun Microsystems, Inc.
  6 
  7    The Gnome Library is free software; you can redistribute it and/or
  8    modify it under the terms of the GNU Library General Public License as
  9    published by the Free Software Foundation; either version 2 of the
 10    License, or (at your option) any later version.
 11 
 12    The Gnome Library is distributed in the hope that it will be useful,
 13    but WITHOUT ANY WARRANTY; without even the implied warranty of
 14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15    Library General Public License for more details.
 16 
 17    You should have received a copy of the GNU Library General Public
 18    License along with the Gnome Library; see the file COPYING.LIB.  If not,
 19    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 20    Boston, MA 02111-1307, USA.
 21 
 22    Author: Michael Meeks <michael@ximian.com>
 23 */
 24 #include <config.h>
 25 
 26 #include "nautilus-canvas-view-container.h"
 27 
 28 #include <string.h>
 29 #include <glib/gi18n.h>
 30 #include <gio/gio.h>
 31 #include <eel/eel-glib-extensions.h>
 32 #include <libnautilus-private/nautilus-global-preferences.h>
 33 #include <libnautilus-private/nautilus-file-attributes.h>
 34 #include <libnautilus-private/nautilus-thumbnails.h>
 35 #include <libnautilus-private/nautilus-desktop-icon-file.h>
 36 
 37 #define ICON_TEXT_ATTRIBUTES_NUM_ITEMS		3
 38 #define ICON_TEXT_ATTRIBUTES_DEFAULT_TOKENS	"size,date_modified,type"
 39 
 40 G_DEFINE_TYPE (NautilusCanvasViewContainer, nautilus_canvas_view_container, NAUTILUS_TYPE_CANVAS_CONTAINER);
 41 
 42 static GQuark attribute_none_q;
 43 
 44 static NautilusCanvasView *
 45 get_canvas_view (NautilusCanvasContainer *container)
 46 {
 47 	/* Type unsafe comparison for performance */
 48 	return ((NautilusCanvasViewContainer *)container)->view;
 49 }
 50 
 51 static NautilusIconInfo *
 52 nautilus_canvas_view_container_get_icon_images (NautilusCanvasContainer *container,
 53 					      NautilusCanvasIconData      *data,
 54 					      int                    size,
 55 					      char                 **embedded_text,
 56 					      gboolean               for_drag_accept,
 57 					      gboolean               need_large_embeddded_text,
 58 					      gboolean              *embedded_text_needs_loading,
 59 					      gboolean              *has_window_open)
 60 {
 61 	NautilusCanvasView *canvas_view;
 62 	NautilusFile *file;
 63 	gboolean use_embedding;
 64 	NautilusFileIconFlags flags;
 65 	NautilusIconInfo *icon_info;
 66 	GdkPixbuf *pixbuf;
 67 	GIcon *emblemed_icon;
 68 	GEmblem *emblem;
 69 	GList *emblem_icons, *l;
 70 
 71 	file = (NautilusFile *) data;
 72 
 73 	g_assert (NAUTILUS_IS_FILE (file));
 74 	canvas_view = get_canvas_view (container);
 75 	g_return_val_if_fail (canvas_view != NULL, NULL);
 76 
 77 	use_embedding = FALSE;
 78 	if (embedded_text) {
 79 		*embedded_text = nautilus_file_peek_top_left_text (file, need_large_embeddded_text, embedded_text_needs_loading);
 80 		use_embedding = *embedded_text != NULL;
 81 	}
 82 	
 83 	*has_window_open = nautilus_file_has_open_window (file);
 84 
 85 	flags = NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM |
 86 		NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS;
 87 
 88 	if (use_embedding) {
 89 		flags |= NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT;
 90 	}
 91 	if (for_drag_accept) {
 92 		flags |= NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT;
 93 	}
 94 
 95 	icon_info = nautilus_file_get_icon (file, size, flags);
 96 	emblem_icons = nautilus_file_get_emblem_icons (file);
 97 
 98 	/* apply emblems */
 99 	if (emblem_icons != NULL) {
100 		l = emblem_icons;
101 
102 		emblem = g_emblem_new (l->data);
103 		pixbuf = nautilus_icon_info_get_pixbuf (icon_info);
104 		emblemed_icon = g_emblemed_icon_new (G_ICON (pixbuf), emblem);
105 		g_object_unref (emblem);
106 
107 		for (l = l->next; l != NULL; l = l->next) {
108 			emblem = g_emblem_new (l->data);
109 			g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (emblemed_icon),
110 						    emblem);
111 			g_object_unref (emblem);
112 		}
113 
114 		g_clear_object (&icon_info);
115 		icon_info = nautilus_icon_info_lookup (emblemed_icon, size);
116 
117 		g_object_unref (pixbuf);
118 		g_object_unref (emblemed_icon);
119 	}
120 
121 	if (emblem_icons != NULL) {
122 		g_list_free_full (emblem_icons, g_object_unref);
123 	}
124 
125 	return icon_info;
126 }
127 
128 static char *
129 nautilus_canvas_view_container_get_icon_description (NautilusCanvasContainer *container,
130 						   NautilusCanvasIconData      *data)
131 {
132 	NautilusFile *file;
133 	char *mime_type;
134 	const char *description;
135 
136 	file = NAUTILUS_FILE (data);
137 	g_assert (NAUTILUS_IS_FILE (file));
138 
139 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
140 		return NULL;
141 	}
142 
143 	mime_type = nautilus_file_get_mime_type (file);
144 	description = g_content_type_get_description (mime_type);
145 	g_free (mime_type);
146 	return g_strdup (description);
147 }
148 
149 static void
150 nautilus_canvas_view_container_start_monitor_top_left (NautilusCanvasContainer *container,
151 						     NautilusCanvasIconData      *data,
152 						     gconstpointer          client,
153 						     gboolean               large_text)
154 {
155 	NautilusFile *file;
156 	NautilusFileAttributes attributes;
157 		
158 	file = (NautilusFile *) data;
159 
160 	g_assert (NAUTILUS_IS_FILE (file));
161 
162 	attributes = NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT;
163 	if (large_text) {
164 		attributes |= NAUTILUS_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT;
165 	}
166 	nautilus_file_monitor_add (file, client, attributes);
167 }
168 
169 static void
170 nautilus_canvas_view_container_stop_monitor_top_left (NautilusCanvasContainer *container,
171 						    NautilusCanvasIconData      *data,
172 						    gconstpointer          client)
173 {
174 	NautilusFile *file;
175 
176 	file = (NautilusFile *) data;
177 
178 	g_assert (NAUTILUS_IS_FILE (file));
179 
180 	nautilus_file_monitor_remove (file, client);
181 }
182 
183 static void
184 nautilus_canvas_view_container_prioritize_thumbnailing (NautilusCanvasContainer *container,
185 						      NautilusCanvasIconData      *data)
186 {
187 	NautilusFile *file;
188 	char *uri;
189 
190 	file = (NautilusFile *) data;
191 
192 	g_assert (NAUTILUS_IS_FILE (file));
193 
194 	if (nautilus_file_is_thumbnailing (file)) {
195 		uri = nautilus_file_get_uri (file);
196 		nautilus_thumbnail_prioritize (uri);
197 		g_free (uri);
198 	}
199 }
200 
201 static void
202 update_auto_strv_as_quarks (GSettings   *settings,
203 			    const gchar *key,
204 			    gpointer     user_data)
205 {
206 	GQuark **storage = user_data;
207 	int i = 0;
208 	char **value;
209 
210 	value = g_settings_get_strv (settings, key);
211 
212 	g_free (*storage);
213 	*storage = g_new (GQuark, g_strv_length (value) + 1);
214 
215 	for (i = 0; value[i] != NULL; ++i) {
216 		(*storage)[i] = g_quark_from_string (value[i]);
217 	}
218 	(*storage)[i] = 0;
219 
220 	g_strfreev (value);
221 }
222 
223 /*
224  * Get the preference for which caption text should appear
225  * beneath icons.
226  */
227 static GQuark *
228 nautilus_canvas_view_container_get_icon_text_attributes_from_preferences (void)
229 {
230 	static GQuark *attributes = NULL;
231 
232 	if (attributes == NULL) {
233 		update_auto_strv_as_quarks (nautilus_icon_view_preferences, 
234 					    NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS,
235 					    &attributes);
236 		g_signal_connect (nautilus_icon_view_preferences, 
237 				  "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS,
238 				  G_CALLBACK (update_auto_strv_as_quarks),
239 				  &attributes);
240 	}
241 
242 	/* We don't need to sanity check the attributes list even though it came
243 	 * from preferences.
244 	 *
245 	 * There are 2 ways that the values in the list could be bad.
246 	 *
247 	 * 1) The user picks "bad" values.  "bad" values are those that result in
248 	 *    there being duplicate attributes in the list.
249 	 *
250 	 * 2) Value stored in GConf are tampered with.  Its possible physically do
251 	 *    this by pulling the rug underneath GConf and manually editing its
252 	 *    config files.  Its also possible to use a third party GConf key
253 	 *    editor and store garbage for the keys in question.
254 	 *
255 	 * Thankfully, the Nautilus preferences machinery deals with both of
256 	 * these cases.
257 	 *
258 	 * In the first case, the preferences dialog widgetry prevents
259 	 * duplicate attributes by making "bad" choices insensitive.
260 	 *
261 	 * In the second case, the preferences getter (and also the auto storage) for
262 	 * string_array values are always valid members of the enumeration associated
263 	 * with the preference.
264 	 *
265 	 * So, no more error checking on attributes is needed here and we can return
266 	 * a the auto stored value.
267 	 */
268 	return attributes;
269 }
270 
271 static int
272 quarkv_length (GQuark *attributes)
273 {
274 	int i;
275 	i = 0;
276 	while (attributes[i] != 0) {
277 		i++;
278 	}
279 	return i;
280 }
281 
282 /**
283  * nautilus_canvas_view_get_icon_text_attribute_names:
284  *
285  * Get a list representing which text attributes should be displayed
286  * beneath an icon. The result is dependent on zoom level and possibly
287  * user configuration. Don't free the result.
288  * @view: NautilusCanvasView to query.
289  * 
290  **/
291 static GQuark *
292 nautilus_canvas_view_container_get_icon_text_attribute_names (NautilusCanvasContainer *container,
293 							    int *len)
294 {
295 	GQuark *attributes;
296 	int piece_count;
297 
298 	const int pieces_by_level[] = {
299 		0,	/* NAUTILUS_ZOOM_LEVEL_SMALLEST */
300 		0,	/* NAUTILUS_ZOOM_LEVEL_SMALLER */
301 		0,	/* NAUTILUS_ZOOM_LEVEL_SMALL */
302 		1,	/* NAUTILUS_ZOOM_LEVEL_STANDARD */
303 		2,	/* NAUTILUS_ZOOM_LEVEL_LARGE */
304 		2,	/* NAUTILUS_ZOOM_LEVEL_LARGER */
305 		3	/* NAUTILUS_ZOOM_LEVEL_LARGEST */
306 	};
307 
308 	piece_count = pieces_by_level[nautilus_canvas_container_get_zoom_level (container)];
309 
310 	attributes = nautilus_canvas_view_container_get_icon_text_attributes_from_preferences ();
311 
312 	*len = MIN (piece_count, quarkv_length (attributes));
313 
314 	return attributes;
315 }
316 
317 /* This callback returns the text, both the editable part, and the
318  * part below that is not editable.
319  */
320 static void
321 nautilus_canvas_view_container_get_icon_text (NautilusCanvasContainer *container,
322 					    NautilusCanvasIconData      *data,
323 					    char                 **editable_text,
324 					    char                 **additional_text,
325 					    gboolean               include_invisible)
326 {
327 	GQuark *attributes;
328 	char *text_array[4];
329 	int i, j, num_attributes;
330 	NautilusCanvasView *canvas_view;
331 	NautilusFile *file;
332 	gboolean use_additional;
333 
334 	file = NAUTILUS_FILE (data);
335 
336 	g_assert (NAUTILUS_IS_FILE (file));
337 	g_assert (editable_text != NULL);
338 	canvas_view = get_canvas_view (container);
339 	g_return_if_fail (canvas_view != NULL);
340 
341 	use_additional = (additional_text != NULL);
342 
343 	/* In the smallest zoom mode, no text is drawn. */
344 	if (nautilus_canvas_container_get_zoom_level (container) == NAUTILUS_ZOOM_LEVEL_SMALLEST &&
345             !include_invisible) {
346 		*editable_text = NULL;
347 	} else {
348 		/* Strip the suffix for nautilus object xml files. */
349 		*editable_text = nautilus_file_get_display_name (file);
350 	}
351 
352 	if (!use_additional) {
353 		return;
354 	}
355 
356 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file) ||
357 	    nautilus_file_is_nautilus_link (file)) {
358 		/* Don't show the normal extra information for desktop icons,
359 		 * or desktop files, it doesn't make sense. */
360  		*additional_text = NULL;
361 		return;
362 	}
363 
364 	/* Find out what attributes go below each icon. */
365 	attributes = nautilus_canvas_view_container_get_icon_text_attribute_names (container,
366 									   &num_attributes);
367 
368 	/* Get the attributes. */
369 	j = 0;
370 	for (i = 0; i < num_attributes; ++i) {
371 		char *text;
372 		if (attributes[i] == attribute_none_q) {
373 			continue;
374 		}
375 		text = nautilus_file_get_string_attribute_q (file, attributes[i]);
376 		if (text == NULL) {
377 			continue;
378 		}
379 		text_array[j++] = text;
380 	}
381 	text_array[j] = NULL;
382 
383 	/* Return them. */
384 	if (j == 0) {
385 		*additional_text = NULL;
386 	} else if (j == 1) {
387 		/* Only one item, avoid the strdup + free */
388 		*additional_text = text_array[0];
389 	} else {
390 		*additional_text = g_strjoinv ("\n", text_array);
391 		
392 		for (i = 0; i < j; i++) {
393 			g_free (text_array[i]);
394 		}
395 	}
396 }
397 
398 /* Sort as follows:
399  *   0) home link
400  *   1) network link
401  *   2) mount links
402  *   3) other
403  *   4) trash link
404  */
405 typedef enum {
406 	SORT_HOME_LINK,
407 	SORT_NETWORK_LINK,
408 	SORT_MOUNT_LINK,
409 	SORT_OTHER,
410 	SORT_TRASH_LINK
411 } SortCategory;
412 
413 static SortCategory
414 get_sort_category (NautilusFile *file)
415 {
416 	NautilusDesktopLink *link;
417 	SortCategory category;
418 
419 	category = SORT_OTHER;
420 	
421 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
422 		link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
423 		if (link != NULL) {
424 			switch (nautilus_desktop_link_get_link_type (link)) {
425 			case NAUTILUS_DESKTOP_LINK_HOME:
426 				category = SORT_HOME_LINK;
427 				break;
428 			case NAUTILUS_DESKTOP_LINK_MOUNT:
429 				category = SORT_MOUNT_LINK;
430 				break;
431 			case NAUTILUS_DESKTOP_LINK_TRASH:
432 				category = SORT_TRASH_LINK;
433 				break;
434 			case NAUTILUS_DESKTOP_LINK_NETWORK:
435 				category = SORT_NETWORK_LINK;
436 				break;
437 			default:
438 				category = SORT_OTHER;
439 				break;
440 			}
441 			g_object_unref (link);
442 		}
443 	} 
444 	
445 	return category;
446 }
447 
448 static int
449 fm_desktop_canvas_container_icons_compare (NautilusCanvasContainer *container,
450 					 NautilusCanvasIconData      *data_a,
451 					 NautilusCanvasIconData      *data_b)
452 {
453 	NautilusFile *file_a;
454 	NautilusFile *file_b;
455 	NautilusView *directory_view;
456 	SortCategory category_a, category_b;
457 
458 	file_a = (NautilusFile *) data_a;
459 	file_b = (NautilusFile *) data_b;
460 
461 	directory_view = NAUTILUS_VIEW (NAUTILUS_CANVAS_VIEW_CONTAINER (container)->view);
462 	g_return_val_if_fail (directory_view != NULL, 0);
463 	
464 	category_a = get_sort_category (file_a);
465 	category_b = get_sort_category (file_b);
466 
467 	if (category_a == category_b) {
468 		return nautilus_file_compare_for_sort 
469 			(file_a, file_b, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, 
470 			 nautilus_view_should_sort_directories_first (directory_view),
471 			 FALSE);
472 	}
473 
474 	if (category_a < category_b) {
475 		return -1;
476 	} else {
477 		return +1;
478 	}
479 }
480 
481 static int
482 nautilus_canvas_view_container_compare_icons (NautilusCanvasContainer *container,
483 					    NautilusCanvasIconData      *icon_a,
484 					    NautilusCanvasIconData      *icon_b)
485 {
486 	NautilusCanvasView *canvas_view;
487 
488 	canvas_view = get_canvas_view (container);
489 	g_return_val_if_fail (canvas_view != NULL, 0);
490 
491 	if (NAUTILUS_CANVAS_VIEW_CONTAINER (container)->sort_for_desktop) {
492 		return fm_desktop_canvas_container_icons_compare
493 			(container, icon_a, icon_b);
494 	}
495 
496 	/* Type unsafe comparisons for performance */
497 	return nautilus_canvas_view_compare_files (canvas_view,
498 					   (NautilusFile *)icon_a,
499 					   (NautilusFile *)icon_b);
500 }
501 
502 static int
503 nautilus_canvas_view_container_compare_icons_by_name (NautilusCanvasContainer *container,
504 						    NautilusCanvasIconData      *icon_a,
505 						    NautilusCanvasIconData      *icon_b)
506 {
507 	return nautilus_file_compare_for_sort
508 		(NAUTILUS_FILE (icon_a),
509 		 NAUTILUS_FILE (icon_b),
510 		 NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
511 		 FALSE, FALSE);
512 }
513 
514 static void
515 nautilus_canvas_view_container_freeze_updates (NautilusCanvasContainer *container)
516 {
517 	NautilusCanvasView *canvas_view;
518 	canvas_view = get_canvas_view (container);
519 	g_return_if_fail (canvas_view != NULL);
520 	nautilus_view_freeze_updates (NAUTILUS_VIEW (canvas_view));
521 }
522 
523 static void
524 nautilus_canvas_view_container_unfreeze_updates (NautilusCanvasContainer *container)
525 {
526 	NautilusCanvasView *canvas_view;
527 	canvas_view = get_canvas_view (container);
528 	g_return_if_fail (canvas_view != NULL);
529 	nautilus_view_unfreeze_updates (NAUTILUS_VIEW (canvas_view));
530 }
531 
532 static void
533 nautilus_canvas_view_container_class_init (NautilusCanvasViewContainerClass *klass)
534 {
535 	NautilusCanvasContainerClass *ic_class;
536 
537 	ic_class = &klass->parent_class;
538 
539 	attribute_none_q = g_quark_from_static_string ("none");
540 	
541 	ic_class->get_icon_text = nautilus_canvas_view_container_get_icon_text;
542 	ic_class->get_icon_images = nautilus_canvas_view_container_get_icon_images;
543 	ic_class->get_icon_description = nautilus_canvas_view_container_get_icon_description;
544 	ic_class->start_monitor_top_left = nautilus_canvas_view_container_start_monitor_top_left;
545 	ic_class->stop_monitor_top_left = nautilus_canvas_view_container_stop_monitor_top_left;
546 	ic_class->prioritize_thumbnailing = nautilus_canvas_view_container_prioritize_thumbnailing;
547 
548 	ic_class->compare_icons = nautilus_canvas_view_container_compare_icons;
549 	ic_class->compare_icons_by_name = nautilus_canvas_view_container_compare_icons_by_name;
550 	ic_class->freeze_updates = nautilus_canvas_view_container_freeze_updates;
551 	ic_class->unfreeze_updates = nautilus_canvas_view_container_unfreeze_updates;
552 }
553 
554 static void
555 nautilus_canvas_view_container_init (NautilusCanvasViewContainer *canvas_container)
556 {
557 	gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (canvas_container)),
558 				     GTK_STYLE_CLASS_VIEW);
559 
560 }
561 
562 NautilusCanvasContainer *
563 nautilus_canvas_view_container_construct (NautilusCanvasViewContainer *canvas_container, NautilusCanvasView *view)
564 {
565 	AtkObject *atk_obj;
566 
567 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL);
568 
569 	canvas_container->view = view;
570 	atk_obj = gtk_widget_get_accessible (GTK_WIDGET (canvas_container));
571 	atk_object_set_name (atk_obj, _("Icon View"));
572 
573 	return NAUTILUS_CANVAS_CONTAINER (canvas_container);
574 }
575 
576 NautilusCanvasContainer *
577 nautilus_canvas_view_container_new (NautilusCanvasView *view)
578 {
579 	return nautilus_canvas_view_container_construct
580 		(g_object_new (NAUTILUS_TYPE_CANVAS_VIEW_CONTAINER, NULL),
581 		 view);
582 }
583 
584 void
585 nautilus_canvas_view_container_set_sort_desktop (NautilusCanvasViewContainer *container,
586 					       gboolean         desktop)
587 {
588 	container->sort_for_desktop = desktop;
589 }