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 }