diff options
Diffstat (limited to 'src/nautilus-desktop-item-properties.c')
-rw-r--r-- | src/nautilus-desktop-item-properties.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/src/nautilus-desktop-item-properties.c b/src/nautilus-desktop-item-properties.c new file mode 100644 index 000000000..aebd272b3 --- /dev/null +++ b/src/nautilus-desktop-item-properties.c @@ -0,0 +1,527 @@ +/* + * fm-ditem-page.c: Desktop item editing support + * + * Copyright (C) 2004 James Willcox + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: James Willcox <jwillcox@gnome.org> + * + */ + +#include <config.h> + +#include "nautilus-desktop-item-properties.h" + +#include <string.h> + +#include <eel/eel-glib-extensions.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <libnautilus-extension/nautilus-extension-types.h> +#include <libnautilus-extension/nautilus-file-info.h> +#include <libnautilus-private/nautilus-file.h> +#include <libnautilus-private/nautilus-file-attributes.h> + +#define MAIN_GROUP "Desktop Entry" + +typedef struct ItemEntry { + const char *field; + const char *description; + char *current_value; + gboolean localized; + gboolean filename; +} ItemEntry; + +enum { + TARGET_URI_LIST +}; + +static const GtkTargetEntry target_table[] = { + { "text/uri-list", 0, TARGET_URI_LIST } +}; + +static gboolean +_g_key_file_load_from_gfile (GKeyFile *key_file, + GFile *file, + GKeyFileFlags flags, + GError **error) +{ + char *data; + gsize len; + gboolean res; + + if (!g_file_load_contents (file, NULL, &data, &len, NULL, error)) { + return FALSE; + } + + res = g_key_file_load_from_data (key_file, data, len, flags, error); + + g_free (data); + + return res; +} + +static gboolean +_g_key_file_save_to_uri (GKeyFile *key_file, + const char *uri, + GError **error) +{ + GFile *file; + char *data; + gsize len; + + data = g_key_file_to_data (key_file, &len, error); + if (data == NULL) { + return FALSE; + } + file = g_file_new_for_uri (uri); + if (!g_file_replace_contents (file, + data, len, + NULL, FALSE, + G_FILE_CREATE_NONE, + NULL, NULL, error)) { + g_object_unref (file); + g_free (data); + return FALSE; + } + g_object_unref (file); + g_free (data); + return TRUE; +} + +static GKeyFile * +_g_key_file_new_from_file (GFile *file, + GKeyFileFlags flags, + GError **error) +{ + GKeyFile *key_file; + + key_file = g_key_file_new (); + if (!_g_key_file_load_from_gfile (key_file, file, flags, error)) { + g_key_file_free (key_file); + key_file = NULL; + } + return key_file; +} + +static GKeyFile * +_g_key_file_new_from_uri (const char *uri, + GKeyFileFlags flags, + GError **error) +{ + GKeyFile *key_file; + GFile *file; + + file = g_file_new_for_uri (uri); + key_file = _g_key_file_new_from_file (file, flags, error); + g_object_unref (file); + return key_file; +} + +static ItemEntry * +item_entry_new (const char *field, + const char *description, + gboolean localized, + gboolean filename) +{ + ItemEntry *entry; + + entry = g_new0 (ItemEntry, 1); + entry->field = field; + entry->description = description; + entry->localized = localized; + entry->filename = filename; + + return entry; +} + +static void +item_entry_free (ItemEntry *entry) +{ + g_free (entry->current_value); + g_free (entry); +} + +static void +fm_ditem_page_url_drag_data_received (GtkWidget *widget, GdkDragContext *context, + int x, int y, + GtkSelectionData *selection_data, + guint info, guint time, + GtkEntry *entry) +{ + char **uris; + gboolean exactly_one; + char *path; + + uris = g_strsplit (gtk_selection_data_get_data (selection_data), "\r\n", 0); + exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); + + if (!exactly_one) { + g_strfreev (uris); + return; + } + + path = g_filename_from_uri (uris[0], NULL, NULL); + if (path != NULL) { + gtk_entry_set_text (entry, path); + g_free (path); + } else { + gtk_entry_set_text (entry, uris[0]); + } + + g_strfreev (uris); +} + +static void +fm_ditem_page_exec_drag_data_received (GtkWidget *widget, GdkDragContext *context, + int x, int y, + GtkSelectionData *selection_data, + guint info, guint time, + GtkEntry *entry) +{ + char **uris; + gboolean exactly_one; + NautilusFile *file; + GKeyFile *key_file; + char *uri, *type, *exec; + + uris = g_strsplit (gtk_selection_data_get_data (selection_data), "\r\n", 0); + exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); + + if (!exactly_one) { + g_strfreev (uris); + return; + } + + file = nautilus_file_get_by_uri (uris[0]); + + g_return_if_fail (file != NULL); + + uri = nautilus_file_get_uri (file); + if (nautilus_file_is_mime_type (file, "application/x-desktop")) { + key_file = _g_key_file_new_from_uri (uri, G_KEY_FILE_NONE, NULL); + if (key_file != NULL) { + type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); + if (type != NULL && strcmp (type, "Application") == 0) { + exec = g_key_file_get_string (key_file, MAIN_GROUP, "Exec", NULL); + if (exec != NULL) { + g_free (uri); + uri = exec; + } + } + g_free (type); + g_key_file_free (key_file); + } + } + gtk_entry_set_text (entry, + uri?uri:""); + gtk_widget_grab_focus (GTK_WIDGET (entry)); + + g_free (uri); + + nautilus_file_unref (file); + + g_strfreev (uris); +} + +static void +save_entry (GtkEntry *entry, GKeyFile *key_file, const char *uri) +{ + GError *error; + ItemEntry *item_entry; + const char *val; + gchar **languages; + + item_entry = g_object_get_data (G_OBJECT (entry), "item_entry"); + val = gtk_entry_get_text (entry); + + if (strcmp (val, item_entry->current_value) == 0) { + return; /* No actual change, don't update file */ + } + + g_free (item_entry->current_value); + item_entry->current_value = g_strdup (val); + + if (item_entry->localized) { + languages = (gchar **) g_get_language_names (); + g_key_file_set_locale_string (key_file, MAIN_GROUP, item_entry->field, languages[0], val); + } else { + g_key_file_set_string (key_file, MAIN_GROUP, item_entry->field, val); + } + + error = NULL; + + if (!_g_key_file_save_to_uri (key_file, uri, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + } +} + +static void +entry_activate_cb (GtkWidget *entry, + GtkWidget *container) +{ + const char *uri; + GKeyFile *key_file; + + uri = g_object_get_data (G_OBJECT (container), "uri"); + key_file = g_object_get_data (G_OBJECT (container), "keyfile"); + save_entry (GTK_ENTRY (entry), key_file, uri); +} + +static gboolean +entry_focus_out_cb (GtkWidget *entry, + GdkEventFocus *event, + GtkWidget *container) +{ + const char *uri; + GKeyFile *key_file; + + uri = g_object_get_data (G_OBJECT (container), "uri"); + key_file = g_object_get_data (G_OBJECT (container), "keyfile"); + save_entry (GTK_ENTRY (entry), key_file, uri); + return FALSE; +} + +static GtkWidget * +build_table (GtkWidget *container, + GKeyFile *key_file, + GtkSizeGroup *label_size_group, + GList *entries) +{ + GtkWidget *table; + GtkWidget *label; + GtkWidget *entry; + GList *l; + char *val; + int i; + + table = gtk_table_new (g_list_length (entries) + 1, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 12); + i = 0; + + for (l = entries; l; l = l->next) { + ItemEntry *item_entry = (ItemEntry *)l->data; + char *label_text; + + label_text = g_strdup_printf ("%s:", item_entry->description); + label = gtk_label_new (label_text); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + g_free (label_text); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_size_group_add_widget (label_size_group, label); + + entry = gtk_entry_new (); + + if (item_entry->localized) { + val = g_key_file_get_locale_string (key_file, + MAIN_GROUP, + item_entry->field, + NULL, NULL); + } else { + val = g_key_file_get_string (key_file, + MAIN_GROUP, + item_entry->field, + NULL); + } + + item_entry->current_value = g_strdup (val?val:""); + gtk_entry_set_text (GTK_ENTRY (entry), item_entry->current_value); + g_free (val); + + gtk_table_attach (GTK_TABLE (table), label, + 0, 1, i, i+1, GTK_FILL, GTK_FILL, + 0, 0); + gtk_table_attach (GTK_TABLE (table), entry, + 1, 2, i, i+1, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, + 0, 0); + g_signal_connect (entry, "activate", + G_CALLBACK (entry_activate_cb), + container); + g_signal_connect (entry, "focus_out_event", + G_CALLBACK (entry_focus_out_cb), + container); + + g_object_set_data_full (G_OBJECT (entry), "item_entry", item_entry, + (GDestroyNotify)item_entry_free); + + if (item_entry->filename) { + gtk_drag_dest_set (GTK_WIDGET (entry), + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, + target_table, G_N_ELEMENTS (target_table), + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + g_signal_connect (entry, "drag_data_received", + G_CALLBACK (fm_ditem_page_url_drag_data_received), + entry); + } else if (strcmp (item_entry->field, "Exec") == 0) { + gtk_drag_dest_set (GTK_WIDGET (entry), + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, + target_table, G_N_ELEMENTS (target_table), + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + g_signal_connect (entry, "drag_data_received", + G_CALLBACK (fm_ditem_page_exec_drag_data_received), + entry); + } + + i++; + } + + /* append dummy row */ + label = gtk_label_new (""); + gtk_table_attach (GTK_TABLE (table), label, + 0, 1, i, i+1, GTK_FILL, GTK_FILL, + 0, 0); + gtk_size_group_add_widget (label_size_group, label); + + + gtk_widget_show_all (table); + return table; +} + +static void +create_page (GKeyFile *key_file, GtkWidget *box) +{ + GtkWidget *table; + GList *entries; + GtkSizeGroup *label_size_group; + char *type; + + entries = NULL; + + type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL); + + if (g_strcmp0 (type, "Link") == 0) { + entries = g_list_prepend (entries, + item_entry_new ("Comment", + _("Comment"), TRUE, FALSE)); + entries = g_list_prepend (entries, + item_entry_new ("URL", + _("URL"), FALSE, TRUE)); + entries = g_list_prepend (entries, + item_entry_new ("GenericName", + _("Description"), TRUE, FALSE)); + } else if (g_strcmp0 (type, "Application") == 0) { + entries = g_list_prepend (entries, + item_entry_new ("Comment", + _("Comment"), TRUE, FALSE)); + entries = g_list_prepend (entries, + item_entry_new ("Exec", + _("Command"), FALSE, FALSE)); + entries = g_list_prepend (entries, + item_entry_new ("GenericName", + _("Description"), TRUE, FALSE)); + } else { + /* we only handle launchers and links */ + + /* ensure that we build an empty table with a dummy row at the end */ + goto build_table; + } + g_free (type); + +build_table: + label_size_group = g_object_get_data (G_OBJECT (box), "label-size-group"); + + table = build_table (box, key_file, label_size_group, entries); + g_list_free (entries); + + gtk_box_pack_start (GTK_BOX (box), table, FALSE, TRUE, 0); + gtk_widget_show_all (GTK_WIDGET (box)); +} + + +static void +ditem_read_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GKeyFile *key_file; + GtkWidget *box; + gsize file_size; + char *file_contents; + + box = GTK_WIDGET (user_data); + + if (g_file_load_contents_finish (G_FILE (source_object), + res, + &file_contents, &file_size, + NULL, NULL)) { + key_file = g_key_file_new (); + g_object_set_data_full (G_OBJECT (box), "keyfile", key_file, (GDestroyNotify)g_key_file_free); + if (g_key_file_load_from_data (key_file, file_contents, file_size, 0, NULL)) { + create_page (key_file, box); + } + g_free (file_contents); + + } + g_object_unref (box); +} + +static void +fm_ditem_page_create_begin (const char *uri, + GtkWidget *box) +{ + GFile *location; + + location = g_file_new_for_uri (uri); + g_object_set_data_full (G_OBJECT (box), "uri", g_strdup (uri), g_free); + g_file_load_contents_async (location, NULL, ditem_read_cb, g_object_ref (box)); + g_object_unref (location); +} + +GtkWidget * +fm_ditem_page_make_box (GtkSizeGroup *label_size_group, + GList *files) +{ + NautilusFileInfo *info; + char *uri; + GtkWidget *box; + + g_assert (fm_ditem_page_should_show (files)); + + box = gtk_vbox_new (FALSE, 6); + g_object_set_data_full (G_OBJECT (box), "label-size-group", + label_size_group, (GDestroyNotify) g_object_unref); + + info = NAUTILUS_FILE_INFO (files->data); + + uri = nautilus_file_info_get_uri (info); + fm_ditem_page_create_begin (uri, box); + g_free (uri); + + return box; +} + +gboolean +fm_ditem_page_should_show (GList *files) +{ + NautilusFileInfo *info; + + if (!files || files->next) { + return FALSE; + } + + info = NAUTILUS_FILE_INFO (files->data); + + if (!nautilus_file_info_is_mime_type (info, "application/x-desktop")) { + return FALSE; + } + + return TRUE; +} + |