No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Chris Lahey <clahey@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <ctype.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include <libxml/parser.h>
32 #include <libedataserver/libedataserver.h>
33
34 #include <glib/gi18n.h>
35 #include "e-util/e-util.h"
36 #include "libevolution-utils/e-xml-utils.h"
37 #include "e-util/e-unicode.h"
38
39 #include "gal-view-collection.h"
40
41 G_DEFINE_TYPE (GalViewCollection, gal_view_collection, G_TYPE_OBJECT)
42
43 #define d(x)
44
45 enum {
46 DISPLAY_VIEW,
47 CHANGED,
48 LAST_SIGNAL
49 };
50
51 static guint gal_view_collection_signals[LAST_SIGNAL] = { 0, };
52
53 /**
54 * gal_view_collection_display_view:
55 * @collection: The GalViewCollection to send the signal on.
56 * @view: The view to display.
57 *
58 */
59 void
60 gal_view_collection_display_view (GalViewCollection *collection,
61 GalView *view)
62 {
63 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
64 g_return_if_fail (GAL_IS_VIEW (view));
65
66 g_signal_emit (
67 collection,
68 gal_view_collection_signals[DISPLAY_VIEW], 0,
69 view);
70 }
71
72 static void
73 gal_view_collection_changed (GalViewCollection *collection)
74 {
75 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
76
77 g_signal_emit (
78 collection,
79 gal_view_collection_signals[CHANGED], 0);
80 }
81
82 static void
83 gal_view_collection_item_free (GalViewCollectionItem *item)
84 {
85 g_free (item->id);
86 if (item->view) {
87 if (item->view_changed_id)
88 g_signal_handler_disconnect (
89 item->view,
90 item->view_changed_id);
91 g_object_unref (item->view);
92 }
93 g_free (item);
94 }
95
96 static gchar *
97 gal_view_generate_string (GalViewCollection *collection,
98 GalView *view,
99 gint which)
100 {
101 gchar *ret_val;
102 gchar *pointer;
103
104 if (which == 1)
105 ret_val = g_strdup (gal_view_get_title (view));
106 else
107 ret_val = g_strdup_printf ("%s_%d", gal_view_get_title (view), which);
108 for (pointer = ret_val; *pointer; pointer = g_utf8_next_char (pointer)) {
109 if (!g_unichar_isalnum (g_utf8_get_char (pointer))) {
110 gchar *ptr = pointer;
111 for (; ptr < g_utf8_next_char (pointer); *ptr = '_', ptr++)
112 ;
113 }
114 }
115 return ret_val;
116 }
117
118 static gint
119 gal_view_check_string (GalViewCollection *collection,
120 gchar *string)
121 {
122 gint i;
123
124 if (!strcmp (string, "current_view"))
125 return FALSE;
126
127 for (i = 0; i < collection->view_count; i++) {
128 if (!strcmp (string, collection->view_data[i]->id))
129 return FALSE;
130 }
131 for (i = 0; i < collection->removed_view_count; i++) {
132 if (!strcmp (string, collection->removed_view_data[i]->id))
133 return FALSE;
134 }
135 return TRUE;
136 }
137
138 static gchar *
139 gal_view_generate_id (GalViewCollection *collection,
140 GalView *view)
141 {
142 gint i;
143 for (i = 1; TRUE; i++) {
144 gchar *try;
145
146 try = gal_view_generate_string (collection, view, i);
147 if (gal_view_check_string (collection, try))
148 return try;
149 g_free (try);
150 }
151 }
152
153 static void
154 gal_view_collection_dispose (GObject *object)
155 {
156 GalViewCollection *collection = GAL_VIEW_COLLECTION (object);
157 gint i;
158
159 for (i = 0; i < collection->view_count; i++) {
160 gal_view_collection_item_free (collection->view_data[i]);
161 }
162 g_free (collection->view_data);
163 collection->view_data = NULL;
164 collection->view_count = 0;
165
166 g_list_foreach (
167 collection->factory_list,
168 (GFunc) g_object_unref, NULL);
169 g_list_free (collection->factory_list);
170 collection->factory_list = NULL;
171
172 for (i = 0; i < collection->removed_view_count; i++) {
173 gal_view_collection_item_free (collection->removed_view_data[i]);
174 }
175 g_free (collection->removed_view_data);
176 collection->removed_view_data = NULL;
177 collection->removed_view_count = 0;
178
179 g_free (collection->system_dir);
180 collection->system_dir = NULL;
181
182 g_free (collection->local_dir);
183 collection->local_dir = NULL;
184
185 g_free (collection->default_view);
186 collection->default_view = NULL;
187
188 g_free (collection->title);
189 collection->title = NULL;
190
191 /* Chain up to parent's dispose() method. */
192 G_OBJECT_CLASS (gal_view_collection_parent_class)->dispose (object);
193 }
194
195 static void
196 gal_view_collection_class_init (GalViewCollectionClass *class)
197 {
198 GObjectClass *object_class = G_OBJECT_CLASS (class);
199
200 object_class->dispose = gal_view_collection_dispose;
201
202 gal_view_collection_signals[DISPLAY_VIEW] = g_signal_new (
203 "display_view",
204 G_OBJECT_CLASS_TYPE (object_class),
205 G_SIGNAL_RUN_LAST,
206 G_STRUCT_OFFSET (GalViewCollectionClass, display_view),
207 NULL, NULL,
208 g_cclosure_marshal_VOID__OBJECT,
209 G_TYPE_NONE, 1,
210 GAL_TYPE_VIEW);
211
212 gal_view_collection_signals[CHANGED] = g_signal_new (
213 "changed",
214 G_OBJECT_CLASS_TYPE (object_class),
215 G_SIGNAL_RUN_LAST,
216 G_STRUCT_OFFSET (GalViewCollectionClass, changed),
217 NULL, NULL,
218 g_cclosure_marshal_VOID__VOID,
219 G_TYPE_NONE, 0);
220
221 class->display_view = NULL;
222 class->changed = NULL;
223 }
224
225 static void
226 gal_view_collection_init (GalViewCollection *collection)
227 {
228 collection->view_data = NULL;
229 collection->view_count = 0;
230 collection->factory_list = NULL;
231
232 collection->removed_view_data = NULL;
233 collection->removed_view_count = 0;
234
235 collection->system_dir = NULL;
236 collection->local_dir = NULL;
237
238 collection->loaded = FALSE;
239 collection->default_view = NULL;
240 collection->default_view_built_in = TRUE;
241
242 collection->title = NULL;
243 }
244
245 /**
246 * gal_view_collection_new:
247 *
248 * A collection of views and view factories.
249 */
250 GalViewCollection *
251 gal_view_collection_new (void)
252 {
253 return g_object_new (GAL_VIEW_COLLECTION_TYPE, NULL);
254 }
255
256 void
257 gal_view_collection_set_title (GalViewCollection *collection,
258 const gchar *title)
259 {
260 g_free (collection->title);
261 collection->title = g_strdup (title);
262 }
263
264 /**
265 * gal_view_collection_set_storage_directories
266 * @collection: The view collection to initialize
267 * @system_dir: The location of the system built in views
268 * @local_dir: The location to store the users set up views
269 *
270 * Sets up the GalViewCollection.
271 */
272 void
273 gal_view_collection_set_storage_directories (GalViewCollection *collection,
274 const gchar *system_dir,
275 const gchar *local_dir)
276 {
277 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
278 g_return_if_fail (system_dir != NULL);
279 g_return_if_fail (local_dir != NULL);
280
281 g_free (collection->system_dir);
282 g_free (collection->local_dir);
283
284 collection->system_dir = g_strdup (system_dir);
285 collection->local_dir = g_strdup (local_dir);
286 }
287
288 /**
289 * gal_view_collection_add_factory
290 * @collection: The view collection to add a factory to
291 * @factory: The factory to add. The @collection will add a reference
292 * to the factory object, so you should unref it after calling this
293 * function if you no longer need it.
294 *
295 * Adds the given factory to this collection. This list is used both
296 * when loading views from their xml description as well as when the
297 * user tries to create a new view.
298 */
299 void
300 gal_view_collection_add_factory (GalViewCollection *collection,
301 GalViewFactory *factory)
302 {
303 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
304 g_return_if_fail (GAL_IS_VIEW_FACTORY (factory));
305
306 g_object_ref (factory);
307 collection->factory_list = g_list_prepend (collection->factory_list, factory);
308 }
309
310 static void
311 view_changed (GalView *view,
312 GalViewCollectionItem *item)
313 {
314 item->changed = TRUE;
315 item->ever_changed = TRUE;
316
317 g_signal_handler_block (item->view, item->view_changed_id);
318 gal_view_collection_changed (item->collection);
319 g_signal_handler_unblock (item->view, item->view_changed_id);
320 }
321
322 /* Use factory list to load a GalView file. */
323 static GalView *
324 gal_view_collection_real_load_view_from_file (GalViewCollection *collection,
325 const gchar *type,
326 const gchar *title,
327 const gchar *dir,
328 const gchar *filename)
329 {
330 GalViewFactory *factory;
331 GList *factories;
332
333 factory = NULL;
334 for (factories = collection->factory_list; factories; factories = factories->next) {
335 if (type && !strcmp (gal_view_factory_get_type_code (factories->data), type)) {
336 factory = factories->data;
337 break;
338 }
339 }
340 if (factory) {
341 GalView *view;
342
343 view = gal_view_factory_new_view (factory, title);
344 gal_view_set_title (view, title);
345 gal_view_load (view, filename);
346 return view;
347 }
348 return NULL;
349 }
350
351 GalView *
352 gal_view_collection_load_view_from_file (GalViewCollection *collection,
353 const gchar *type,
354 const gchar *filename)
355 {
356 return gal_view_collection_real_load_view_from_file (collection, type, "", collection->local_dir, filename);
357 }
358
359 static GalViewCollectionItem *
360 load_single_file (GalViewCollection *collection,
361 gchar *dir,
362 gboolean local,
363 xmlNode *node)
364 {
365 GalViewCollectionItem *item;
366 item = g_new (GalViewCollectionItem, 1);
367 item->ever_changed = local;
368 item->changed = FALSE;
369 item->built_in = !local;
370 item->id = e_xml_get_string_prop_by_name (node, (const guchar *)"id");
371 item->filename = e_xml_get_string_prop_by_name (node, (const guchar *)"filename");
372 item->title = e_xml_get_translated_utf8_string_prop_by_name (node, (const guchar *)"title");
373 item->type = e_xml_get_string_prop_by_name (node, (const guchar *)"type");
374 item->collection = collection;
375 item->view_changed_id = 0;
376
377 if (item->filename) {
378 gchar *fullpath;
379 fullpath = g_build_filename (dir, item->filename, NULL);
380 item->view = gal_view_collection_real_load_view_from_file (collection, item->type, item->title, dir, fullpath);
381 g_free (fullpath);
382 if (item->view) {
383 item->view_changed_id = g_signal_connect (
384 item->view, "changed",
385 G_CALLBACK (view_changed), item);
386 }
387 }
388 return item;
389 }
390
391 static void
392 load_single_dir (GalViewCollection *collection,
393 gchar *dir,
394 gboolean local)
395 {
396 xmlDoc *doc = NULL;
397 xmlNode *root;
398 xmlNode *child;
399 gchar *filename = g_build_filename (dir, "galview.xml", NULL);
400 gchar *default_view;
401
402 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
403 #ifdef G_OS_WIN32
404 gchar *locale_filename = g_win32_locale_filename_from_utf8 (filename);
405 if (locale_filename != NULL)
406 doc = xmlParseFile (locale_filename);
407 g_free (locale_filename);
408 #else
409 doc = xmlParseFile (filename);
410 #endif
411 }
412
413 if (!doc) {
414 g_free (filename);
415 return;
416 }
417 root = xmlDocGetRootElement (doc);
418 for (child = root->xmlChildrenNode; child; child = child->next) {
419 gchar *id;
420 gboolean found = FALSE;
421 gint i;
422
423 if (!strcmp ((gchar *) child->name, "text"))
424 continue;
425
426 id = e_xml_get_string_prop_by_name (child, (const guchar *)"id");
427 for (i = 0; i < collection->view_count; i++) {
428 if (!strcmp (id, collection->view_data[i]->id)) {
429 if (!local)
430 collection->view_data[i]->built_in = TRUE;
431 found = TRUE;
432 break;
433 }
434 }
435 if (!found) {
436 for (i = 0; i < collection->removed_view_count; i++) {
437 if (!strcmp (id, collection->removed_view_data[i]->id)) {
438 if (!local)
439 collection->removed_view_data[i]->built_in = TRUE;
440 found = TRUE;
441 break;
442 }
443 }
444 }
445
446 if (!found) {
447 GalViewCollectionItem *item = load_single_file (collection, dir, local, child);
448 if (item->filename && *item->filename) {
449 collection->view_data = g_renew (GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
450 collection->view_data[collection->view_count] = item;
451 collection->view_count++;
452 } else {
453 collection->removed_view_data = g_renew (GalViewCollectionItem *, collection->removed_view_data, collection->removed_view_count + 1);
454 collection->removed_view_data[collection->removed_view_count] = item;
455 collection->removed_view_count++;
456 }
457 }
458 g_free (id);
459 }
460
461 default_view = e_xml_get_string_prop_by_name (root, (const guchar *)"default-view");
462 if (default_view) {
463 if (local)
464 collection->default_view_built_in = FALSE;
465 else
466 collection->default_view_built_in = TRUE;
467 g_free (collection->default_view);
468 collection->default_view = default_view;
469 }
470
471 g_free (filename);
472 xmlFreeDoc (doc);
473 }
474
475 /**
476 * gal_view_collection_load
477 * @collection: The view collection to load information for
478 *
479 * Loads the data from the system and user directories specified in
480 * set storage directories. This is primarily for internal use by
481 * other parts of gal_view.
482 */
483 void
484 gal_view_collection_load (GalViewCollection *collection)
485 {
486 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
487 g_return_if_fail (collection->local_dir != NULL);
488 g_return_if_fail (collection->system_dir != NULL);
489 g_return_if_fail (!collection->loaded);
490
491 if ((g_mkdir_with_parents (collection->local_dir, 0777) == -1) && (errno != EEXIST))
492 g_warning ("Unable to create dir %s: %s", collection->local_dir, g_strerror (errno));
493
494 load_single_dir (collection, collection->local_dir, TRUE);
495 load_single_dir (collection, collection->system_dir, FALSE);
496 gal_view_collection_changed (collection);
497
498 collection->loaded = TRUE;
499 }
500
501 /**
502 * gal_view_collection_save
503 * @collection: The view collection to save information for
504 *
505 * Saves the data to the user directory specified in set storage
506 * directories. This is primarily for internal use by other parts of
507 * gal_view.
508 */
509 void
510 gal_view_collection_save (GalViewCollection *collection)
511 {
512 gint i;
513 xmlDoc *doc;
514 xmlNode *root;
515 gchar *filename;
516
517 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
518 g_return_if_fail (collection->local_dir != NULL);
519
520 doc = xmlNewDoc ((const guchar *)"1.0");
521 root = xmlNewNode (NULL, (const guchar *)"GalViewCollection");
522 xmlDocSetRootElement (doc, root);
523
524 if (collection->default_view && !collection->default_view_built_in) {
525 e_xml_set_string_prop_by_name (root, (const guchar *)"default-view", collection->default_view);
526 }
527
528 for (i = 0; i < collection->view_count; i++) {
529 xmlNode *child;
530 GalViewCollectionItem *item;
531
532 item = collection->view_data[i];
533 if (item->ever_changed) {
534 child = xmlNewChild (root, NULL, (const guchar *)"GalView", NULL);
535 e_xml_set_string_prop_by_name (child, (const guchar *)"id", item->id);
536 e_xml_set_string_prop_by_name (child, (const guchar *)"title", item->title);
537 e_xml_set_string_prop_by_name (child, (const guchar *)"filename", item->filename);
538 e_xml_set_string_prop_by_name (child, (const guchar *)"type", item->type);
539
540 if (item->changed) {
541 filename = g_build_filename (collection->local_dir, item->filename, NULL);
542 gal_view_save (item->view, filename);
543 g_free (filename);
544 }
545 }
546 }
547 for (i = 0; i < collection->removed_view_count; i++) {
548 xmlNode *child;
549 GalViewCollectionItem *item;
550
551 item = collection->removed_view_data[i];
552
553 child = xmlNewChild (root, NULL, (const guchar *)"GalView", NULL);
554 e_xml_set_string_prop_by_name (child, (const guchar *)"id", item->id);
555 e_xml_set_string_prop_by_name (child, (const guchar *)"title", item->title);
556 e_xml_set_string_prop_by_name (child, (const guchar *)"type", item->type);
557 }
558 filename = g_build_filename (collection->local_dir, "galview.xml", NULL);
559 if (e_xml_save_file (filename, doc) == -1)
560 g_warning ("Unable to save view to %s - %s", filename, g_strerror (errno));
561 xmlFreeDoc (doc);
562 g_free (filename);
563 }
564
565 /**
566 * gal_view_collection_get_count
567 * @collection: The view collection to count
568 *
569 * Calculates the number of views in the given collection.
570 *
571 * Returns: The number of views in the collection.
572 */
573 gint
574 gal_view_collection_get_count (GalViewCollection *collection)
575 {
576 g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), -1);
577
578 return collection->view_count;
579 }
580
581 /**
582 * gal_view_collection_get_view
583 * @collection: The view collection to query
584 * @n: The view to get.
585 *
586 * Returns: The nth view in the collection
587 */
588 GalView *
589 gal_view_collection_get_view (GalViewCollection *collection,
590 gint n)
591 {
592 g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
593 g_return_val_if_fail (n < collection->view_count, NULL);
594 g_return_val_if_fail (n >= 0, NULL);
595
596 return collection->view_data[n]->view;
597 }
598
599 /**
600 * gal_view_collection_get_view_item
601 * @collection: The view collection to query
602 * @n: The view item to get.
603 *
604 * Returns: The nth view item in the collection
605 */
606 GalViewCollectionItem *
607 gal_view_collection_get_view_item (GalViewCollection *collection,
608 gint n)
609 {
610 g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
611 g_return_val_if_fail (n < collection->view_count, NULL);
612 g_return_val_if_fail (n >= 0, NULL);
613
614 return collection->view_data[n];
615 }
616
617 gint
618 gal_view_collection_get_view_index_by_id (GalViewCollection *collection,
619 const gchar *view_id)
620 {
621 gint i;
622 for (i = 0; i < collection->view_count; i++) {
623 if (!strcmp (collection->view_data[i]->id, view_id))
624 return i;
625 }
626 return -1;
627 }
628
629 gchar *
630 gal_view_collection_get_view_id_by_index (GalViewCollection *collection,
631 gint n)
632 {
633 g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
634 g_return_val_if_fail (n < collection->view_count, NULL);
635 g_return_val_if_fail (n >= 0, NULL);
636
637 return g_strdup (collection->view_data[n]->id);
638 }
639
640 void
641 gal_view_collection_append (GalViewCollection *collection,
642 GalView *view)
643 {
644 GalViewCollectionItem *item;
645
646 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
647 g_return_if_fail (GAL_IS_VIEW (view));
648
649 item = g_new (GalViewCollectionItem, 1);
650 item->ever_changed = TRUE;
651 item->changed = TRUE;
652 item->built_in = FALSE;
653 item->title = g_strdup (gal_view_get_title (view));
654 item->type = g_strdup (gal_view_get_type_code (view));
655 item->id = gal_view_generate_id (collection, view);
656 item->filename = g_strdup_printf ("%s.galview", item->id);
657 item->view = view;
658 item->collection = collection;
659 g_object_ref (view);
660
661 item->view_changed_id = g_signal_connect (
662 item->view, "changed",
663 G_CALLBACK (view_changed), item);
664
665 collection->view_data = g_renew (GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
666 collection->view_data[collection->view_count] = item;
667 collection->view_count++;
668
669 gal_view_collection_changed (collection);
670 }
671
672 void
673 gal_view_collection_delete_view (GalViewCollection *collection,
674 gint i)
675 {
676 GalViewCollectionItem *item;
677
678 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
679 g_return_if_fail (i >= 0 && i < collection->view_count);
680
681 item = collection->view_data[i];
682 memmove (collection->view_data + i, collection->view_data + i + 1, (collection->view_count - i - 1) * sizeof (GalViewCollectionItem *));
683 collection->view_count--;
684 if (item->built_in) {
685 g_free (item->filename);
686 item->filename = NULL;
687
688 collection->removed_view_data = g_renew (GalViewCollectionItem *, collection->removed_view_data, collection->removed_view_count + 1);
689 collection->removed_view_data[collection->removed_view_count] = item;
690 collection->removed_view_count++;
691 } else {
692 gal_view_collection_item_free (item);
693 }
694
695 gal_view_collection_changed (collection);
696 }
697
698 void
699 gal_view_collection_copy_view (GalViewCollection *collection,
700 gint i)
701 {
702 GalViewCollectionItem *item;
703 GalView *view;
704
705 g_return_if_fail (GAL_IS_VIEW_COLLECTION (collection));
706 g_return_if_fail (i >= 0 && i < collection->view_count);
707
708 view = collection->view_data[i]->view;
709
710 item = g_new (GalViewCollectionItem, 1);
711 item->ever_changed = TRUE;
712 item->changed = FALSE;
713 item->built_in = FALSE;
714 item->title = g_strdup (gal_view_get_title (view));
715 item->type = g_strdup (gal_view_get_type_code (view));
716 item->id = gal_view_generate_id (collection, view);
717 item->filename = g_strdup_printf ("%s.galview", item->id);
718 item->view = gal_view_clone (view);
719 item->collection = collection;
720
721 item->view_changed_id = g_signal_connect (
722 item->view, "changed",
723 G_CALLBACK (view_changed), item);
724
725 collection->view_data = g_renew (GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
726 collection->view_data[collection->view_count] = item;
727 collection->view_count++;
728
729 gal_view_collection_changed (collection);
730 }
731
732 gboolean
733 gal_view_collection_loaded (GalViewCollection *collection)
734 {
735 return collection->loaded;
736 }
737
738 const gchar *
739 gal_view_collection_append_with_title (GalViewCollection *collection,
740 const gchar *title,
741 GalView *view)
742 {
743 GalViewCollectionItem *item;
744
745 g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
746 g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
747
748 gal_view_set_title (view, title);
749
750 d (g_print ("%s: %p\n", G_STRFUNC, view));
751
752 item = g_new (GalViewCollectionItem, 1);
753 item->ever_changed = TRUE;
754 item->changed = TRUE;
755 item->built_in = FALSE;
756 item->title = g_strdup (gal_view_get_title (view));
757 item->type = g_strdup (gal_view_get_type_code (view));
758 item->id = gal_view_generate_id (collection, view);
759 item->filename = g_strdup_printf ("%s.galview", item->id);
760 item->view = view;
761 item->collection = collection;
762 g_object_ref (view);
763
764 item->view_changed_id = g_signal_connect (
765 item->view, "changed",
766 G_CALLBACK (view_changed), item);
767
768 collection->view_data = g_renew (GalViewCollectionItem *, collection->view_data, collection->view_count + 1);
769 collection->view_data[collection->view_count] = item;
770 collection->view_count++;
771
772 gal_view_collection_changed (collection);
773 return item->id;
774 }
775
776 const gchar *
777 gal_view_collection_set_nth_view (GalViewCollection *collection,
778 gint i,
779 GalView *view)
780 {
781 GalViewCollectionItem *item;
782
783 g_return_val_if_fail (GAL_IS_VIEW_COLLECTION (collection), NULL);
784 g_return_val_if_fail (GAL_IS_VIEW (view), NULL);
785 g_return_val_if_fail (i >= 0, NULL);
786 g_return_val_if_fail (i < collection->view_count, NULL);
787
788 d (g_print ("%s: %p\n", G_STRFUNC, view));
789
790 item = collection->view_data[i];
791
792 gal_view_set_title (view, item->title);
793 g_object_ref (view);
794 if (item->view) {
795 g_signal_handler_disconnect (
796 item->view,
797 item->view_changed_id);
798 g_object_unref (item->view);
799 }
800 item->view = view;
801
802 item->ever_changed = TRUE;
803 item->changed = TRUE;
804 item->type = g_strdup (gal_view_get_type_code (view));
805
806 item->view_changed_id = g_signal_connect (
807 item->view, "changed",
808 G_CALLBACK (view_changed), item);
809
810 gal_view_collection_changed (collection);
811 return item->id;
812 }
813
814 const gchar *
815 gal_view_collection_get_default_view (GalViewCollection *collection)
816 {
817 return collection->default_view;
818 }
819
820 void
821 gal_view_collection_set_default_view (GalViewCollection *collection,
822 const gchar *id)
823 {
824 g_free (collection->default_view);
825 collection->default_view = g_strdup (id);
826 gal_view_collection_changed (collection);
827 collection->default_view_built_in = FALSE;
828 }