source: trunk/third/nautilus/src/nautilus-bookmark-list.c @ 18663

Revision 18663, 14.4 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18662, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3/*
4 * Nautilus
5 *
6 * Copyright (C) 1999, 2000 Eazel, Inc.
7 *
8 * Nautilus is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * Nautilus is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Authors: John Sullivan <sullivan@eazel.com>
23 */
24
25/* nautilus-bookmark-list.c - implementation of centralized list of bookmarks.
26 */
27
28#include <config.h>
29#include "nautilus-bookmark-list.h"
30
31#include "nautilus-bookmark-parsing.h"
32#include <eel/eel-glib-extensions.h>
33#include <eel/eel-gtk-macros.h>
34#include <eel/eel-string.h>
35#include <eel/eel-xml-extensions.h>
36#include <gtk/gtksignal.h>
37#include <libnautilus-private/nautilus-file-utilities.h>
38#include <libnautilus-private/nautilus-icon-factory.h>
39#include <libxml/parser.h>
40#include <libxml/tree.h>
41#include <stdlib.h>
42
43enum {
44        CONTENTS_CHANGED,
45        LAST_SIGNAL
46};
47
48static guint signals[LAST_SIGNAL];
49static char *window_geometry;
50
51/* forward declarations */
52static void        append_bookmark_node                 (gpointer              list_element,
53                                                         gpointer              user_data);
54static void        destroy                              (GtkObject            *object);
55static const char *nautilus_bookmark_list_get_file_path (NautilusBookmarkList *bookmarks);
56static void        nautilus_bookmark_list_load_file     (NautilusBookmarkList *bookmarks);
57static void        nautilus_bookmark_list_save_file     (NautilusBookmarkList *bookmarks);
58static void        set_window_geometry_internal         (const char           *string);
59static void        stop_monitoring_bookmark             (NautilusBookmarkList *bookmarks,
60                                                         NautilusBookmark     *bookmark);
61
62/* Initialization.  */
63
64static void
65nautilus_bookmark_list_class_init (NautilusBookmarkListClass *class)
66{
67        GtkObjectClass *object_class;
68
69        object_class = GTK_OBJECT_CLASS (class);
70
71        object_class->destroy = destroy;
72
73        signals[CONTENTS_CHANGED] =
74                g_signal_new ("contents_changed",
75                              G_TYPE_FROM_CLASS (object_class),
76                              G_SIGNAL_RUN_LAST,
77                              G_STRUCT_OFFSET (NautilusBookmarkListClass,
78                                                   contents_changed),
79                              NULL, NULL,
80                              g_cclosure_marshal_VOID__VOID,
81                              G_TYPE_NONE, 0);
82}
83
84static void
85nautilus_bookmark_list_init (NautilusBookmarkList *bookmarks)
86{
87        nautilus_bookmark_list_load_file (bookmarks);
88}
89
90EEL_CLASS_BOILERPLATE (NautilusBookmarkList, nautilus_bookmark_list, GTK_TYPE_OBJECT)
91
92static void
93stop_monitoring_one (gpointer data, gpointer user_data)
94{
95        g_assert (NAUTILUS_IS_BOOKMARK (data));
96        g_assert (NAUTILUS_IS_BOOKMARK_LIST (user_data));
97
98        stop_monitoring_bookmark (NAUTILUS_BOOKMARK_LIST (user_data),
99                                  NAUTILUS_BOOKMARK (data));
100}                 
101
102static void
103clear (NautilusBookmarkList *bookmarks)
104{
105        g_list_foreach (bookmarks->list, stop_monitoring_one, bookmarks);
106        eel_g_object_list_free (bookmarks->list);
107        bookmarks->list = NULL;
108}
109
110static void
111destroy (GtkObject *object)
112{
113        clear (NAUTILUS_BOOKMARK_LIST (object));
114}
115
116/**
117 * append_bookmark_node:
118 *
119 * Foreach function; add a single bookmark xml node to a root node.
120 * @data: a NautilusBookmark * that is the data of a GList node
121 * @user_data: the xmlNodePtr to add a node to.
122 **/
123static void
124append_bookmark_node (gpointer data, gpointer user_data)
125{
126        xmlNodePtr root_node, bookmark_node;
127        NautilusBookmark *bookmark;
128        char *icon;
129        char *bookmark_uri, *bookmark_name;
130
131        g_assert (NAUTILUS_IS_BOOKMARK (data));
132
133        bookmark = NAUTILUS_BOOKMARK (data);
134        root_node = (xmlNodePtr) user_data;     
135
136        bookmark_name = nautilus_bookmark_get_name (bookmark);
137        bookmark_uri = nautilus_bookmark_get_uri (bookmark);
138
139        bookmark_node = xmlNewChild (root_node, NULL, "bookmark", NULL);
140        xmlSetProp (bookmark_node, "name", bookmark_name);
141        xmlSetProp (bookmark_node, "uri", bookmark_uri);
142
143        g_free (bookmark_name);
144        g_free (bookmark_uri);
145
146        icon = nautilus_bookmark_get_icon (bookmark);
147        if (icon != NULL) {
148                /* Don't bother storing modifier or embedded text for bookmarks. */
149                xmlSetProp (bookmark_node, "icon_name", icon);
150        }
151}
152
153static void
154bookmark_in_list_changed_callback (NautilusBookmark *bookmark,
155                                   NautilusBookmarkList *bookmarks)
156{
157        g_assert (NAUTILUS_IS_BOOKMARK (bookmark));
158        g_assert (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
159
160        /* Save changes so we'll have the good icon next time. */
161        nautilus_bookmark_list_contents_changed (bookmarks);
162}                                 
163                                   
164static void
165stop_monitoring_bookmark (NautilusBookmarkList *bookmarks,
166                          NautilusBookmark *bookmark)
167{
168        g_signal_handlers_disconnect_by_func (bookmark,
169                                              bookmark_in_list_changed_callback,
170                                              bookmarks);
171}
172
173static void
174insert_bookmark_internal (NautilusBookmarkList *bookmarks,
175                          NautilusBookmark *bookmark,
176                          int index)
177{
178        bookmarks->list = g_list_insert (bookmarks->list, bookmark, index);
179
180        g_signal_connect_object (bookmark, "appearance_changed",
181                                 G_CALLBACK (bookmark_in_list_changed_callback), bookmarks, 0);
182        g_signal_connect_object (bookmark, "contents_changed",
183                                 G_CALLBACK (bookmark_in_list_changed_callback), bookmarks, 0);
184}
185
186/**
187 * nautilus_bookmark_list_append:
188 *
189 * Append a bookmark to a bookmark list.
190 * @bookmarks: NautilusBookmarkList to append to.
191 * @bookmark: Bookmark to append a copy of.
192 **/
193void
194nautilus_bookmark_list_append (NautilusBookmarkList *bookmarks,
195                               NautilusBookmark *bookmark)
196{
197        g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
198        g_return_if_fail (NAUTILUS_IS_BOOKMARK (bookmark));
199
200        insert_bookmark_internal (bookmarks,
201                                  nautilus_bookmark_copy (bookmark),
202                                  -1);
203
204        nautilus_bookmark_list_contents_changed (bookmarks);
205}
206
207/**
208 * nautilus_bookmark_list_contains:
209 *
210 * Check whether a bookmark with matching name and url is already in the list.
211 * @bookmarks: NautilusBookmarkList to check contents of.
212 * @bookmark: NautilusBookmark to match against.
213 *
214 * Return value: TRUE if matching bookmark is in list, FALSE otherwise
215 **/
216gboolean
217nautilus_bookmark_list_contains (NautilusBookmarkList *bookmarks,
218                                 NautilusBookmark *bookmark)
219{
220        g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), FALSE);
221        g_return_val_if_fail (NAUTILUS_IS_BOOKMARK (bookmark), FALSE);
222
223        return g_list_find_custom (bookmarks->list,
224                                   (gpointer)bookmark,
225                                   nautilus_bookmark_compare_with)
226                != NULL;
227}
228
229/**
230 * nautilus_bookmark_list_contents_changed:
231 *
232 * Save the bookmark list to disk, and emit the contents_changed signal.
233 * @bookmarks: NautilusBookmarkList whose contents have been modified.
234 **/
235void
236nautilus_bookmark_list_contents_changed (NautilusBookmarkList *bookmarks)
237{
238        g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
239
240        nautilus_bookmark_list_save_file (bookmarks);
241        g_signal_emit (bookmarks,
242                         signals[CONTENTS_CHANGED], 0);
243}
244
245
246/**
247 * nautilus_bookmark_list_delete_item_at:
248 *
249 * Delete the bookmark at the specified position.
250 * @bookmarks: the list of bookmarks.
251 * @index: index, must be less than length of list.
252 **/
253void                   
254nautilus_bookmark_list_delete_item_at (NautilusBookmarkList *bookmarks,
255                                      guint index)
256{
257        GList *doomed;
258
259        g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
260        g_return_if_fail (index < g_list_length (bookmarks->list));
261
262        doomed = g_list_nth (bookmarks->list, index);
263        bookmarks->list = g_list_remove_link (bookmarks->list, doomed);
264
265        g_assert (NAUTILUS_IS_BOOKMARK (doomed->data));
266        stop_monitoring_bookmark (bookmarks, NAUTILUS_BOOKMARK (doomed->data));
267        g_object_unref (doomed->data);
268       
269        g_list_free_1 (doomed);
270       
271        nautilus_bookmark_list_contents_changed (bookmarks);
272}
273
274/**
275 * nautilus_bookmark_list_delete_items_with_uri:
276 *
277 * Delete all bookmarks with the given uri.
278 * @bookmarks: the list of bookmarks.
279 * @uri: The uri to match.
280 **/
281void                   
282nautilus_bookmark_list_delete_items_with_uri (NautilusBookmarkList *bookmarks,
283                                              const char *uri)
284{
285        GList *node, *next;
286        gboolean list_changed;
287        char *bookmark_uri;
288
289        g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
290        g_return_if_fail (uri != NULL);
291
292        list_changed = FALSE;
293        for (node = bookmarks->list; node != NULL;  node = next) {
294                next = node->next;
295
296                bookmark_uri = nautilus_bookmark_get_uri (NAUTILUS_BOOKMARK (node->data));
297                if (eel_strcmp (bookmark_uri, uri) == 0) {
298                        bookmarks->list = g_list_remove_link (bookmarks->list, node);
299                        stop_monitoring_bookmark (bookmarks, NAUTILUS_BOOKMARK (node->data));
300                        g_object_unref (node->data);
301                        g_list_free_1 (node);
302                        list_changed = TRUE;
303                }
304                g_free (bookmark_uri);
305        }
306
307        if (list_changed) {
308                nautilus_bookmark_list_contents_changed (bookmarks);
309        }
310}
311
312static const char *
313nautilus_bookmark_list_get_file_path (NautilusBookmarkList *bookmarks)
314{
315        /* currently hardwired */
316
317        static char *file_path = NULL;
318        char *user_directory;
319
320        if (file_path == NULL) {
321                user_directory = nautilus_get_user_directory ();
322                file_path = g_build_filename (user_directory, "bookmarks.xml", NULL);
323                g_free (user_directory);
324        }
325
326        return file_path;
327}
328
329/**
330 * nautilus_bookmark_list_get_window_geometry:
331 *
332 * Get a string representing the bookmark_list's window's geometry.
333 * This is the value set earlier by nautilus_bookmark_list_set_window_geometry.
334 * @bookmarks: the list of bookmarks associated with the window.
335 * Return value: string representation of window's geometry, suitable for
336 * passing to gnome_parse_geometry(), or NULL if
337 * no window geometry has yet been saved for this bookmark list.
338 **/
339const char *
340nautilus_bookmark_list_get_window_geometry (NautilusBookmarkList *bookmarks)
341{
342        return window_geometry;
343}
344
345/**
346 * nautilus_bookmark_list_insert_item:
347 *
348 * Insert a bookmark at a specified position.
349 * @bookmarks: the list of bookmarks.
350 * @index: the position to insert the bookmark at.
351 * @new_bookmark: the bookmark to insert a copy of.
352 **/
353void                   
354nautilus_bookmark_list_insert_item (NautilusBookmarkList *bookmarks,
355                                    NautilusBookmark* new_bookmark,
356                                    guint index)
357{
358        g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
359        g_return_if_fail (index <= g_list_length (bookmarks->list));
360
361        insert_bookmark_internal (bookmarks,
362                                  nautilus_bookmark_copy (new_bookmark),
363                                  index);
364
365        nautilus_bookmark_list_contents_changed (bookmarks);
366}
367
368/**
369 * nautilus_bookmark_list_item_at:
370 *
371 * Get the bookmark at the specified position.
372 * @bookmarks: the list of bookmarks.
373 * @index: index, must be less than length of list.
374 *
375 * Return value: the bookmark at position @index in @bookmarks.
376 **/
377NautilusBookmark *
378nautilus_bookmark_list_item_at (NautilusBookmarkList *bookmarks, guint index)
379{
380        g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), NULL);
381        g_return_val_if_fail (index < g_list_length (bookmarks->list), NULL);
382
383        return NAUTILUS_BOOKMARK (g_list_nth_data (bookmarks->list, index));
384}
385
386/**
387 * nautilus_bookmark_list_length:
388 *
389 * Get the number of bookmarks in the list.
390 * @bookmarks: the list of bookmarks.
391 *
392 * Return value: the length of the bookmark list.
393 **/
394guint
395nautilus_bookmark_list_length (NautilusBookmarkList *bookmarks)
396{
397        g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST(bookmarks), 0);
398
399        return g_list_length (bookmarks->list);
400}
401
402/**
403 * nautilus_bookmark_list_load_file:
404 *
405 * Reads bookmarks from file, clobbering contents in memory.
406 * @bookmarks: the list of bookmarks to fill with file contents.
407 **/
408static void
409nautilus_bookmark_list_load_file (NautilusBookmarkList *bookmarks)
410{
411        xmlDocPtr doc;
412        xmlNodePtr node;
413
414        /* Wipe out old list. */
415        clear (bookmarks);
416
417        if (!g_file_test (nautilus_bookmark_list_get_file_path (bookmarks),
418                          G_FILE_TEST_EXISTS)) {
419                return;
420        }
421
422        /* Read new list from file */
423        doc = xmlParseFile (nautilus_bookmark_list_get_file_path (bookmarks));
424        for (node = eel_xml_get_root_children (doc);
425             node != NULL;
426             node = node->next) {
427
428                if (node->type != XML_ELEMENT_NODE) {
429                        continue;
430                }
431
432                if (strcmp (node->name, "bookmark") == 0) {
433                        insert_bookmark_internal (bookmarks,
434                                                  nautilus_bookmark_new_from_node (node),
435                                                  -1);
436                } else if (strcmp (node->name, "window") == 0) {
437                        xmlChar *geometry_string;
438                       
439                        geometry_string = xmlGetProp (node, "geometry");
440                        set_window_geometry_internal (geometry_string);
441                        xmlFree (geometry_string);
442                }
443        }
444       
445        xmlFreeDoc(doc);
446}
447
448/**
449 * nautilus_bookmark_list_new:
450 *
451 * Create a new bookmark_list, with contents read from disk.
452 *
453 * Return value: A pointer to the new widget.
454 **/
455NautilusBookmarkList *
456nautilus_bookmark_list_new (void)
457{
458        NautilusBookmarkList *list;
459
460        list = NAUTILUS_BOOKMARK_LIST (g_object_new (NAUTILUS_TYPE_BOOKMARK_LIST, NULL));
461        g_object_ref (list);
462        gtk_object_sink (GTK_OBJECT (list));
463
464        return list;
465}
466
467/**
468 * nautilus_bookmark_list_save_file:
469 *
470 * Save bookmarks to disk.
471 * @bookmarks: the list of bookmarks to save.
472 **/
473static void
474nautilus_bookmark_list_save_file (NautilusBookmarkList *bookmarks)
475{
476        xmlDocPtr doc;
477        xmlNodePtr root, node;
478
479        doc = xmlNewDoc ("1.0");
480        root = xmlNewDocNode (doc, NULL, "bookmarks", NULL);
481        xmlDocSetRootElement (doc, root);
482
483        /* save window position */
484        if (window_geometry != NULL) {
485                node = xmlNewChild (root, NULL, "window", NULL);
486                xmlSetProp (node, "geometry", window_geometry);
487        }
488
489        /* save bookmarks */
490        g_list_foreach (bookmarks->list, append_bookmark_node, root);
491
492        xmlSaveFile (nautilus_bookmark_list_get_file_path (bookmarks), doc);
493        xmlFreeDoc (doc);
494}
495
496/**
497 * nautilus_bookmark_list_set_window_geometry:
498 *
499 * Set a bookmarks window's geometry (position & size), in string form. This is
500 * stored to disk by this class, and can be retrieved later in
501 * the same session or in a future session.
502 * @bookmarks: the list of bookmarks associated with the window.
503 * @geometry: the new window geometry string.
504 **/
505void
506nautilus_bookmark_list_set_window_geometry (NautilusBookmarkList *bookmarks,
507                                            const char *geometry)
508{
509        g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
510        g_return_if_fail (geometry != NULL);
511
512        set_window_geometry_internal (geometry);
513
514        nautilus_bookmark_list_save_file(bookmarks);
515}
516
517static void
518set_window_geometry_internal (const char *string)
519{
520        g_free (window_geometry);
521        window_geometry = g_strdup (string);
522}
Note: See TracBrowser for help on using the repository browser.