Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ nemoCommon_sources = [
'nemo-application.c',
'nemo-blank-desktop-window.c',
'nemo-bookmark-list.c',
'nemo-bookmark-groups.c',
'nemo-bookmarks-window.c',
'nemo-config-base-widget.c',
'nemo-connect-server-dialog-nonmain.c',
Expand Down Expand Up @@ -146,6 +147,7 @@ nemo_autorun_software = executable('nemo-autorun-software',
nemo_connect_server = executable('nemo-connect-server',
[
'nemo-bookmark-list.c',
'nemo-bookmark-groups.c',
'nemo-connect-server-dialog.c',
'nemo-connect-server-dialog-main.c',
'nemo-connect-server-operation.c'
Expand Down
167 changes: 167 additions & 0 deletions src/nemo-bookmark-groups.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "nemo-bookmark-groups.h"
#include <glib/gstdio.h>
#include <errno.h>

char *
nemo_bookmark_groups_filename (void)
{
return g_build_filename (g_get_user_config_dir (), "nemo", "bookmark-groups", NULL);
}

GKeyFile *
nemo_bookmark_groups_load (const char *filename, GError **error)
{
GKeyFile *groups = g_key_file_new ();
GError *local_error = NULL;
if (!g_key_file_load_from_file (groups, filename, G_KEY_FILE_NONE, &local_error)) {
if (!g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
g_propagate_error (error, local_error);
g_key_file_unref (groups);
return NULL;
}
g_clear_error (&local_error);
}
return groups;
}

gboolean
nemo_bookmark_groups_save (GKeyFile *groups, const char *filename, GError **error)
{
char *directory = g_path_get_dirname (filename);
if (g_mkdir_with_parents (directory, 0700) < 0) {
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
"Could not create %s: %s", directory, g_strerror (errno));
g_free (directory);
return FALSE;
}
g_free (directory);
return g_key_file_save_to_file (groups, filename, error);
}

char **
nemo_bookmark_groups_get_ids (GKeyFile *groups)
{
char **ids = g_key_file_get_string_list (groups, "Groups", "Order", NULL, NULL);
return ids != NULL ? ids : g_new0 (char *, 1);
}

char *
nemo_bookmark_groups_create (GKeyFile *groups, const char *name)
{
char **ids = nemo_bookmark_groups_get_ids (groups);
guint length = g_strv_length (ids);
char *id = g_uuid_string_random ();
ids = g_realloc_n (ids, length + 2, sizeof (char *));
ids[length] = g_strdup (id);
ids[length + 1] = NULL;
g_key_file_set_string_list (groups, "Groups", "Order", (const char * const *) ids, length + 1);
g_key_file_set_string (groups, id, "Name", name);
g_key_file_set_boolean (groups, id, "Collapsed", FALSE);
g_strfreev (ids);
return id;
}

gboolean
nemo_bookmark_groups_rename (GKeyFile *groups, const char *id, const char *name)
{
if (!g_key_file_has_group (groups, id) || name == NULL || *name == '\0')
return FALSE;
g_key_file_set_string (groups, id, "Name", name);
return TRUE;
}
void
nemo_bookmark_groups_delete (GKeyFile *groups, const char *id)
{
char **ids = nemo_bookmark_groups_get_ids (groups);
GPtrArray *remaining = g_ptr_array_new ();
for (guint i = 0; ids[i] != NULL; i++) {
if (g_strcmp0 (ids[i], id) != 0)
g_ptr_array_add (remaining, ids[i]);
}
g_key_file_set_string_list (groups, "Groups", "Order",
(const char * const *) remaining->pdata, remaining->len);
g_key_file_remove_group (groups, id, NULL);
g_ptr_array_unref (remaining);
g_strfreev (ids);
}
char *
nemo_bookmark_groups_find (GKeyFile *groups, const char *uri)
{
char **ids = nemo_bookmark_groups_get_ids (groups);
char *result = NULL;
for (guint i = 0; ids[i] != NULL; i++) {
char **uris = g_key_file_get_string_list (groups, ids[i], "URIs", NULL, NULL);
if (uris != NULL && g_strv_contains ((const char * const *) uris, uri)) {
result = g_strdup (ids[i]);
g_strfreev (uris);
break;
}
g_strfreev (uris);
}
g_strfreev (ids);
return result;
}

void
nemo_bookmark_groups_move (GKeyFile *groups, const char *uri, const char *id, const char *before_uri)
{
if (g_strcmp0 (uri, before_uri) == 0) {
char *current_id = nemo_bookmark_groups_find (groups, uri);
gboolean same_group = g_strcmp0 (current_id, id) == 0;
g_free (current_id);
if (same_group)
return;
}
char **ids = nemo_bookmark_groups_get_ids (groups);
/* Never lose a membership because a stale menu targets a deleted group. */
if (id != NULL && !g_strv_contains ((const char * const *) ids, id)) {
g_strfreev (ids);
return;
}
for (guint i = 0; ids[i] != NULL; i++) {
char **uris = g_key_file_get_string_list (groups, ids[i], "URIs", NULL, NULL);
GPtrArray *ordered = g_ptr_array_new ();
gboolean inserted = FALSE;
for (guint j = 0; uris != NULL && uris[j] != NULL; j++) {
if (g_strcmp0 (uris[j], uri) == 0)
continue;
if (g_strcmp0 (ids[i], id) == 0 && g_strcmp0 (uris[j], before_uri) == 0) {
g_ptr_array_add (ordered, (gpointer) uri);
inserted = TRUE;
}
g_ptr_array_add (ordered, uris[j]);
}
if (g_strcmp0 (ids[i], id) == 0 && !inserted)
g_ptr_array_add (ordered, (gpointer) uri);
g_key_file_set_string_list (groups, ids[i], "URIs",
(const char * const *) ordered->pdata, ordered->len);
g_ptr_array_unref (ordered);
g_strfreev (uris);
}
g_strfreev (ids);
}
gboolean
nemo_bookmark_groups_prune (GKeyFile *groups, const char * const *uris)
{
char **ids = nemo_bookmark_groups_get_ids (groups);
gboolean changed = FALSE;
for (guint i = 0; ids[i] != NULL; i++) {
char **assigned = g_key_file_get_string_list (groups, ids[i], "URIs", NULL, NULL);
GPtrArray *remaining = g_ptr_array_new ();
guint length = assigned != NULL ? g_strv_length (assigned) : 0;
for (guint j = 0; j < length; j++) {
if (g_strv_contains (uris, assigned[j]))
g_ptr_array_add (remaining, assigned[j]);
}
if (remaining->len != length) {
g_key_file_set_string_list (groups, ids[i], "URIs",
(const char * const *) remaining->pdata, remaining->len);
changed = TRUE;
}
g_ptr_array_unref (remaining);
g_strfreev (assigned);
}
g_strfreev (ids);
return changed;
}
17 changes: 17 additions & 0 deletions src/nemo-bookmark-groups.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef NEMO_BOOKMARK_GROUPS_H
#define NEMO_BOOKMARK_GROUPS_H
#include <glib.h>

/* Private, GLib-only metadata. GTK's bookmarks remain authoritative. */
GKeyFile *nemo_bookmark_groups_load (const char *filename, GError **error);
gboolean nemo_bookmark_groups_save (GKeyFile *groups, const char *filename, GError **error);
char *nemo_bookmark_groups_filename (void);
char **nemo_bookmark_groups_get_ids (GKeyFile *groups);
char *nemo_bookmark_groups_create (GKeyFile *groups, const char *name);
gboolean nemo_bookmark_groups_rename (GKeyFile *groups, const char *id, const char *name);
void nemo_bookmark_groups_delete (GKeyFile *groups, const char *id);
char *nemo_bookmark_groups_find (GKeyFile *groups, const char *uri);
void nemo_bookmark_groups_move (GKeyFile *groups, const char *uri, const char *id, const char *before_uri);
gboolean nemo_bookmark_groups_prune (GKeyFile *groups, const char * const *uris);
#endif
39 changes: 39 additions & 0 deletions src/nemo-bookmark-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <config.h>
#include "nemo-bookmark-list.h"
#include "nemo-bookmark-groups.h"

#include <libnemo-private/nemo-file-utilities.h>
#include <libnemo-private/nemo-file.h>
Expand Down Expand Up @@ -424,6 +425,29 @@ nemo_bookmark_list_contains (NemoBookmarkList *bookmarks,
!= NULL;
}

static void
prune_bookmark_groups (NemoBookmarkList *bookmarks)
{
char *filename = nemo_bookmark_groups_filename ();
GKeyFile *groups = nemo_bookmark_groups_load (filename, NULL);
if (groups != NULL) {
GPtrArray *uris = g_ptr_array_new_with_free_func (g_free);
for (GList *l = bookmarks->list; l != NULL; l = l->next)
g_ptr_array_add (uris, nemo_bookmark_get_uri (l->data));
g_ptr_array_add (uris, NULL);
if (nemo_bookmark_groups_prune (groups, (const char * const *) uris->pdata)) {
GError *error = NULL;
if (!nemo_bookmark_groups_save (groups, filename, &error)) {
g_warning ("Could not prune bookmark groups: %s", error->message);
g_error_free (error);
}
}
g_ptr_array_unref (uris);
g_key_file_unref (groups);
}
g_free (filename);
}

/**
* nemo_bookmark_list_delete_item_at:
*
Expand Down Expand Up @@ -451,6 +475,7 @@ nemo_bookmark_list_delete_item_at (NemoBookmarkList *bookmarks,

g_list_free_1 (doomed);

prune_bookmark_groups (bookmarks);
nemo_bookmark_list_save_file (bookmarks);
}

Expand Down Expand Up @@ -556,6 +581,7 @@ nemo_bookmark_list_delete_items_with_uri (NemoBookmarkList *bookmarks,
}

if (list_changed) {
prune_bookmark_groups (bookmarks);
nemo_bookmark_list_save_file (bookmarks);
}
}
Expand Down Expand Up @@ -722,6 +748,9 @@ load_files_finish (NemoBookmarkList *bookmarks,

clear_bookmarks (bookmarks, old_list);

if (error == NULL && GPOINTER_TO_INT (g_task_get_task_data (G_TASK (res))))
prune_bookmark_groups (bookmarks);
g_clear_error (&error);
g_list_foreach (bookmarks->list, (GFunc) connect_bookmark_signals, bookmarks);
g_signal_emit (bookmarks, signals[CHANGED], 0);
}
Expand All @@ -745,8 +774,10 @@ load_files_thread (GTask *task,
GFile *file;

file = nemo_bookmark_list_get_file ();
gboolean authoritative = TRUE;

if (!g_file_query_exists (file, NULL)) {
authoritative = FALSE;
g_object_unref (file);
file = nemo_bookmark_list_get_legacy_file ();
}
Expand All @@ -767,8 +798,15 @@ load_files_thread (GTask *task,
gchar **lines;
gint i;

authoritative = authoritative && g_utf8_validate (contents, -1, NULL);
lines = g_strsplit (contents, "\n", -1);
for (i = 0; lines[i]; i++) {
if (lines[i][0] != '\0') {
char *scheme = g_uri_parse_scheme (lines[i]);
if (scheme == NULL || lines[i][0] == ' ')
authoritative = FALSE;
g_free (scheme);
}
/* Ignore empty or invalid lines that cannot be parsed properly */
if (lines[i][0] != '\0' && lines[i][0] != ' ') {
/* gtk 2.7/2.8 might have labels appended to bookmarks which are separated by a space */
Expand Down Expand Up @@ -805,6 +843,7 @@ load_files_thread (GTask *task,
g_free (contents);
g_strfreev (lines);

g_task_set_task_data (task, GINT_TO_POINTER (authoritative), NULL);
g_task_return_pointer (task, new_list, NULL);
} else {
g_task_return_error (task, error);
Expand Down
Loading