4
* Copyright (C) 1999, 2000 Eazel, Inc.
6
* Marlin is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) any later version.
11
* Marlin is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
* Authors: John Sullivan <sullivan@eazel.com>
21
* ammonkey <am.monkeyd@gmail.com>
24
/* nautilus-bookmark-list.c - implementation of centralized list of bookmarks.
27
#include "marlin-bookmark-list.h"
32
//#include "marlin-icons.h"
34
#define MAX_BOOKMARK_LENGTH 80
44
static guint signals[LAST_SIGNAL];
45
static char *window_geometry;
46
static MarlinBookmarkList *singleton = NULL;
48
/* forward declarations */
50
static void marlin_bookmark_list_load_file (MarlinBookmarkList *bookmarks);
51
static void marlin_bookmark_list_save_file (MarlinBookmarkList *bookmarks);
53
G_DEFINE_TYPE(MarlinBookmarkList, marlin_bookmark_list, G_TYPE_OBJECT)
55
static MarlinBookmark *
56
new_bookmark_from_uri (const char *uri, char *label)
58
MarlinBookmark *bookmark;
65
/*location = g_file_new_for_uri (uri);
72
name = g_strdup (label);
76
/*if (!g_file_is_native (location))
77
icon = g_themed_icon_new (MARLIN_ICON_FOLDER_REMOTE);*/
78
//file = gof_file_get (location);
79
file = gof_file_get_by_uri (uri);
82
name = g_strdup (file->display_name);
87
name = g_file_get_parse_name (location);*/
89
//new_bookmark = marlin_bookmark_new (location, name, has_label, icon);
90
bookmark = marlin_bookmark_new (file, label);
93
g_object_unref (file);
100
marlin_bookmark_list_get_file (void)
105
filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
106
file = g_file_new_for_path (filename);
113
/* Initialization. */
116
bookmark_in_list_changed_callback (MarlinBookmark *bookmark,
117
MarlinBookmarkList *bookmarks)
119
g_assert (MARLIN_IS_BOOKMARK (bookmark));
120
g_assert (MARLIN_IS_BOOKMARK_LIST (bookmarks));
122
/* Save changes so we'll have the good icon next time. */
123
marlin_bookmark_list_save_file (bookmarks);
127
bookmark_in_list_to_be_deleted_callback (MarlinBookmark *bookmark,
128
MarlinBookmarkList *bookmarks)
130
g_assert (MARLIN_IS_BOOKMARK (bookmark));
131
g_assert (MARLIN_IS_BOOKMARK_LIST (bookmarks));
133
g_debug ("%s - deleting %s from bookmark list",
135
g_file_get_uri (bookmark->file->location));
137
marlin_bookmark_list_delete_items_with_uri (bookmarks,
138
g_file_get_uri (bookmark->file->location));
142
stop_monitoring_bookmark (MarlinBookmarkList *bookmarks,
143
MarlinBookmark *bookmark)
145
g_signal_handlers_disconnect_by_func (bookmark,
146
bookmark_in_list_changed_callback,
148
g_signal_handlers_disconnect_by_func (bookmark,
149
bookmark_in_list_to_be_deleted_callback,
154
stop_monitoring_one (gpointer data, gpointer user_data)
156
g_assert (MARLIN_IS_BOOKMARK (data));
157
g_assert (MARLIN_IS_BOOKMARK_LIST (user_data));
159
stop_monitoring_bookmark (MARLIN_BOOKMARK_LIST (user_data),
160
MARLIN_BOOKMARK (data));
161
g_object_unref (MARLIN_BOOKMARK (data));
165
clear (MarlinBookmarkList *bookmarks)
167
g_list_foreach (bookmarks->list, stop_monitoring_one, bookmarks);
169
//g_list_foreach (bookmarks->list, (GFunc) g_object_unref, NULL);
170
g_list_free (bookmarks->list);
171
bookmarks->list = NULL;
175
do_finalize (GObject *object)
177
if (MARLIN_BOOKMARK_LIST (object)->monitor != NULL) {
178
g_file_monitor_cancel (MARLIN_BOOKMARK_LIST (object)->monitor);
179
MARLIN_BOOKMARK_LIST (object)->monitor = NULL;
182
g_queue_free (MARLIN_BOOKMARK_LIST (object)->pending_ops);
184
clear (MARLIN_BOOKMARK_LIST (object));
186
G_OBJECT_CLASS (marlin_bookmark_list_parent_class)->finalize (object);
190
do_constructor (GType type,
191
guint n_construct_params,
192
GObjectConstructParam *construct_params)
196
if (singleton != NULL) {
197
return g_object_ref (singleton);
200
retval = G_OBJECT_CLASS (marlin_bookmark_list_parent_class)->constructor
201
(type, n_construct_params, construct_params);
203
singleton = MARLIN_BOOKMARK_LIST (retval);
204
g_object_add_weak_pointer (retval, (gpointer) &singleton);
211
marlin_bookmark_list_class_init (MarlinBookmarkListClass *class)
213
GObjectClass *object_class = G_OBJECT_CLASS (class);
215
object_class->finalize = do_finalize;
216
object_class->constructor = do_constructor;
218
signals[CONTENTS_CHANGED] =
219
g_signal_new ("contents_changed",
220
G_TYPE_FROM_CLASS (object_class),
222
G_STRUCT_OFFSET (MarlinBookmarkListClass,
225
g_cclosure_marshal_VOID__VOID,
230
bookmark_monitor_changed_cb (GFileMonitor *monitor,
233
GFileMonitorEvent eflags,
236
if (eflags == G_FILE_MONITOR_EVENT_CHANGED ||
237
eflags == G_FILE_MONITOR_EVENT_CREATED) {
238
g_return_if_fail (MARLIN_IS_BOOKMARK_LIST (MARLIN_BOOKMARK_LIST (user_data)));
239
marlin_bookmark_list_load_file (MARLIN_BOOKMARK_LIST (user_data));
244
marlin_bookmark_list_init (MarlinBookmarkList *bookmarks)
248
bookmarks->pending_ops = g_queue_new ();
250
marlin_bookmark_list_load_file (bookmarks);
252
file = marlin_bookmark_list_get_file ();
253
bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL);
254
g_file_monitor_set_rate_limit (bookmarks->monitor, 1000);
256
g_signal_connect (bookmarks->monitor, "changed",
257
G_CALLBACK (bookmark_monitor_changed_cb), bookmarks);
258
g_object_unref (file);
262
insert_bookmark_internal (MarlinBookmarkList *bookmarks,
263
MarlinBookmark *bookmark,
266
bookmarks->list = g_list_insert (bookmarks->list, bookmark, index);
268
g_signal_connect_object (bookmark, "contents_changed",
269
G_CALLBACK (bookmark_in_list_changed_callback),
272
g_signal_connect_object (bookmark, "deleted",
273
G_CALLBACK (bookmark_in_list_to_be_deleted_callback),
278
* marlin_bookmark_list_append:
280
* Append a bookmark to a bookmark list.
281
* @bookmarks: MarlinBookmarkList to append to.
282
* @bookmark: Bookmark to append a copy of.
285
marlin_bookmark_list_append (MarlinBookmarkList *bookmarks,
286
MarlinBookmark *bookmark)
288
g_return_if_fail (MARLIN_IS_BOOKMARK_LIST (bookmarks));
289
g_return_if_fail (MARLIN_IS_BOOKMARK (bookmark));
291
insert_bookmark_internal (bookmarks,
292
marlin_bookmark_copy (bookmark),
295
marlin_bookmark_list_save_file (bookmarks);
299
* marlin_bookmark_list_contains:
301
* Check whether a bookmark with matching name and url is already in the list.
302
* @bookmarks: MarlinBookmarkList to check contents of.
303
* @bookmark: MarlinBookmark to match against.
305
* Return value: TRUE if matching bookmark is in list, FALSE otherwise
308
marlin_bookmark_list_contains (MarlinBookmarkList *bookmarks,
309
MarlinBookmark *bookmark)
311
g_return_val_if_fail (MARLIN_IS_BOOKMARK_LIST (bookmarks), FALSE);
312
g_return_val_if_fail (MARLIN_IS_BOOKMARK (bookmark), FALSE);
314
return g_list_find_custom (bookmarks->list,
316
marlin_bookmark_compare_with)
321
* marlin_bookmark_list_delete_item_at:
323
* Delete the bookmark at the specified position.
324
* @bookmarks: the list of bookmarks.
325
* @index: index, must be less than length of list.
328
marlin_bookmark_list_delete_item_at (MarlinBookmarkList *bookmarks,
333
g_return_if_fail (MARLIN_IS_BOOKMARK_LIST (bookmarks));
334
g_return_if_fail (index < g_list_length (bookmarks->list));
336
doomed = g_list_nth (bookmarks->list, index);
337
bookmarks->list = g_list_remove_link (bookmarks->list, doomed);
339
g_assert (MARLIN_IS_BOOKMARK (doomed->data));
340
stop_monitoring_bookmark (bookmarks, MARLIN_BOOKMARK (doomed->data));
342
g_object_unref (doomed->data);
343
/*g_object_unref (doomed->data);
344
g_object_unref (doomed->data);*/
346
g_list_free_1 (doomed);
348
marlin_bookmark_list_save_file (bookmarks);
352
* marlin_bookmark_list_move_item:
354
* Move the item from the given position to the destination.
355
* @index: the index of the first bookmark.
356
* @destination: the index of the second bookmark.
359
marlin_bookmark_list_move_item (MarlinBookmarkList *bookmarks,
363
GList *bookmark_item;
365
if (index == destination) {
369
bookmark_item = g_list_nth (bookmarks->list, index);
370
bookmarks->list = g_list_remove_link (bookmarks->list,
373
if (index < destination) {
374
bookmarks->list = g_list_insert (bookmarks->list,
378
bookmarks->list = g_list_insert (bookmarks->list,
383
marlin_bookmark_list_save_file (bookmarks);
387
* marlin_bookmark_list_delete_items_with_uri:
389
* Delete all bookmarks with the given uri.
390
* @bookmarks: the list of bookmarks.
391
* @uri: The uri to match.
394
marlin_bookmark_list_delete_items_with_uri (MarlinBookmarkList *bookmarks,
398
gboolean list_changed;
401
g_return_if_fail (MARLIN_IS_BOOKMARK_LIST (bookmarks));
402
g_return_if_fail (uri != NULL);
404
list_changed = FALSE;
405
for (node = bookmarks->list; node != NULL; node = next) {
408
bookmark_uri = marlin_bookmark_get_uri (MARLIN_BOOKMARK (node->data));
409
if (eel_strcmp (bookmark_uri, uri) == 0) {
410
bookmarks->list = g_list_remove_link (bookmarks->list, node);
411
stop_monitoring_bookmark (bookmarks, MARLIN_BOOKMARK (node->data));
412
g_object_unref (node->data);
413
g_list_free_1 (node);
416
g_free (bookmark_uri);
420
marlin_bookmark_list_save_file (bookmarks);
425
* marlin_bookmark_list_insert_item:
427
* Insert a bookmark at a specified position.
428
* @bookmarks: the list of bookmarks.
429
* @index: the position to insert the bookmark at.
430
* @new_bookmark: the bookmark to insert a copy of.
433
marlin_bookmark_list_insert_item (MarlinBookmarkList *bookmarks,
434
MarlinBookmark *new_bookmark,
437
g_return_if_fail (MARLIN_IS_BOOKMARK_LIST (bookmarks));
438
g_return_if_fail (index <= g_list_length (bookmarks->list));
440
insert_bookmark_internal (bookmarks,
441
marlin_bookmark_copy (new_bookmark),
444
marlin_bookmark_list_save_file (bookmarks);
448
* marlin_bookmark_list_item_at:
450
* Get the bookmark at the specified position.
451
* @bookmarks: the list of bookmarks.
452
* @index: index, must be less than length of list.
454
* Return value: the bookmark at position @index in @bookmarks.
457
marlin_bookmark_list_item_at (MarlinBookmarkList *bookmarks, guint index)
459
g_return_val_if_fail (MARLIN_IS_BOOKMARK_LIST (bookmarks), NULL);
460
g_return_val_if_fail (index < g_list_length (bookmarks->list), NULL);
462
return MARLIN_BOOKMARK (g_list_nth_data (bookmarks->list, index));
466
* marlin_bookmark_list_length:
468
* Get the number of bookmarks in the list.
469
* @bookmarks: the list of bookmarks.
471
* Return value: the length of the bookmark list.
474
marlin_bookmark_list_length (MarlinBookmarkList *bookmarks)
476
g_return_val_if_fail (MARLIN_IS_BOOKMARK_LIST(bookmarks), 0);
478
return g_list_length (bookmarks->list);
482
marlin_bookmark_list_get_gof_files (MarlinBookmarkList *bookmarks)
487
for (p = bookmarks->list; p!= NULL; p=p->next) {
488
GOFFile *gof = MARLIN_BOOKMARK (p->data)->file;
489
//g_message ("%s %s", G_STRFUNC, gof->uri);
490
files = g_list_prepend (files, gof);
496
static void bookmark_list_content_changed (GList *files, MarlinBookmarkList *bookmarks)
498
g_signal_emit (bookmarks, signals[CONTENTS_CHANGED], 0);
502
load_file_finish (MarlinBookmarkList *bookmarks,
506
GError *error = NULL;
507
gchar *contents = NULL;
509
g_file_load_contents_finish (G_FILE (source),
510
res, &contents, NULL, NULL, &error);
516
lines = g_strsplit (contents, "\n", -1);
517
for (i = 0; lines[i]; i++) {
518
/* Ignore empty or invalid lines that cannot be parsed properly */
519
if (lines[i][0] != '\0' && lines[i][0] != ' ') {
520
/* gtk 2.7/2.8 might have labels appended to bookmarks which are separated by a space */
521
/* we must seperate the bookmark uri and the potential label */
525
space = strchr (lines[i], ' ');
528
label = g_strdup (space + 1);
530
insert_bookmark_internal (bookmarks,
531
new_bookmark_from_uri (lines[i], label),
541
/* emit contents_changed once all bookmark are ready */
542
GList *files = marlin_bookmark_list_get_gof_files (bookmarks);
543
gof_call_when_ready_new (files, bookmark_list_content_changed, bookmarks);
545
g_signal_emit (bookmarks, signals[CONTENTS_CHANGED], 0);
546
} else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
547
g_warning ("Could not load bookmark file: %s\n", error->message);
548
g_error_free (error);
553
load_file_async (MarlinBookmarkList *self,
554
GAsyncReadyCallback callback)
558
file = marlin_bookmark_list_get_file ();
560
/* Wipe out old list. */
563
/* keep the bookmark list alive */
565
g_file_load_contents_async (file, NULL, callback, self);
567
g_object_unref (file);
571
save_file_finish (MarlinBookmarkList *bookmarks,
575
GError *error = NULL;
578
g_file_replace_contents_finish (G_FILE (source),
582
g_warning ("Unable to replace contents of the bookmarks file: %s",
584
g_error_free (error);
587
file = marlin_bookmark_list_get_file ();
589
/* re-enable bookmark file monitoring */
590
bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL);
591
g_file_monitor_set_rate_limit (bookmarks->monitor, 1000);
592
g_signal_connect (bookmarks->monitor, "changed",
593
G_CALLBACK (bookmark_monitor_changed_cb), bookmarks);
595
g_object_unref (file);
599
save_file_async (MarlinBookmarkList *bookmarks,
600
GAsyncReadyCallback callback)
604
GString *bookmark_string;
606
/* temporarily disable bookmark file monitoring when writing file */
607
if (bookmarks->monitor != NULL) {
608
g_file_monitor_cancel (bookmarks->monitor);
609
bookmarks->monitor = NULL;
612
file = marlin_bookmark_list_get_file ();
613
bookmark_string = g_string_new (NULL);
615
for (l = bookmarks->list; l; l = l->next) {
616
MarlinBookmark *bookmark;
618
bookmark = MARLIN_BOOKMARK (l->data);
620
/* make sure we save label if it has one for compatibility with GTK 2.7 and 2.8 */
621
if (marlin_bookmark_get_has_custom_name (bookmark)) {
623
label = marlin_bookmark_get_name (bookmark);
624
uri = marlin_bookmark_get_uri (bookmark);
625
g_string_append_printf (bookmark_string,
626
"%s %s\n", uri, label);
631
uri = marlin_bookmark_get_uri (bookmark);
632
g_string_append_printf (bookmark_string, "%s\n", uri);
637
/* keep the bookmark list alive */
638
g_object_ref (bookmarks);
639
g_file_replace_contents_async (file, bookmark_string->str,
640
bookmark_string->len, NULL,
641
FALSE, 0, NULL, callback,
644
g_object_unref (file);
648
process_next_op (MarlinBookmarkList *bookmarks);
651
op_processed_cb (GObject *source,
655
MarlinBookmarkList *self = user_data;
658
op = GPOINTER_TO_INT (g_queue_pop_tail (self->pending_ops));
660
if (op == LOAD_JOB) {
661
load_file_finish (self, source, res);
663
save_file_finish (self, source, res);
666
if (!g_queue_is_empty (self->pending_ops)) {
667
process_next_op (self);
670
/* release the reference acquired during the _async method */
671
g_object_unref (self);
675
process_next_op (MarlinBookmarkList *bookmarks)
679
op = GPOINTER_TO_INT (g_queue_peek_tail (bookmarks->pending_ops));
681
if (op == LOAD_JOB) {
682
load_file_async (bookmarks, op_processed_cb);
684
save_file_async (bookmarks, op_processed_cb);
689
* marlin_bookmark_list_load_file:
691
* Reads bookmarks from file, clobbering contents in memory.
692
* @bookmarks: the list of bookmarks to fill with file contents.
695
marlin_bookmark_list_load_file (MarlinBookmarkList *bookmarks)
697
g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (LOAD_JOB));
699
if (g_queue_get_length (bookmarks->pending_ops) == 1) {
700
process_next_op (bookmarks);
705
* marlin_bookmark_list_save_file:
707
* Save bookmarks to disk.
708
* @bookmarks: the list of bookmarks to save.
711
marlin_bookmark_list_save_file (MarlinBookmarkList *bookmarks)
713
g_signal_emit (bookmarks, signals[CONTENTS_CHANGED], 0);
715
g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (SAVE_JOB));
717
if (g_queue_get_length (bookmarks->pending_ops) == 1) {
718
process_next_op (bookmarks);
724
* marlin_bookmark_list_new:
726
* Create a new bookmark_list, with contents read from disk.
728
* Return value: A pointer to the new widget.
731
marlin_bookmark_list_new (void)
733
MarlinBookmarkList *list;
735
list = MARLIN_BOOKMARK_LIST (g_object_new (MARLIN_TYPE_BOOKMARK_LIST, NULL));