diff options
-rw-r--r-- | clients/tui/newt/Makefile.am | 6 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-file-button.c | 291 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-file-button.h | 49 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-file-dialog.c | 525 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-file-dialog.h | 51 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-file-picker.c | 204 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-file-picker.h | 72 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-form.c | 4 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-types.h | 3 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-utils.c | 66 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt-utils.h | 2 | ||||
-rw-r--r-- | clients/tui/newt/nmt-newt.h | 3 |
12 files changed, 1274 insertions, 2 deletions
diff --git a/clients/tui/newt/Makefile.am b/clients/tui/newt/Makefile.am index e572238b2a..8d5327158c 100644 --- a/clients/tui/newt/Makefile.am +++ b/clients/tui/newt/Makefile.am @@ -24,6 +24,12 @@ libnmt_newt_a_SOURCES = \ nmt-newt-entry.h \ nmt-newt-entry-numeric.c \ nmt-newt-entry-numeric.h \ + nmt-newt-file-button.c \ + nmt-newt-file-button.h \ + nmt-newt-file-dialog.c \ + nmt-newt-file-dialog.h \ + nmt-newt-file-picker.c \ + nmt-newt-file-picker.h \ nmt-newt-form.c \ nmt-newt-form.h \ nmt-newt-grid.c \ diff --git a/clients/tui/newt/nmt-newt-file-button.c b/clients/tui/newt/nmt-newt-file-button.c new file mode 100644 index 0000000000..f54fcfd715 --- /dev/null +++ b/clients/tui/newt/nmt-newt-file-button.c @@ -0,0 +1,291 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program 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 program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-file-button + * @short_description: File-selection button + * + * #NmtNewtFileButton provides a label showing a filename, and a button that will + * pop up a dialog for selecting a new file. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-newt-file-button.h" +#include "nmt-newt-file-picker.h" + +static void nmt_newt_file_button_file_picker_interface_init (NmtNewtFilePickerInterface *iface, gpointer iface_data); + +G_DEFINE_TYPE_WITH_CODE (NmtNewtFileButton, nmt_newt_file_button, NMT_TYPE_NEWT_GRID, + G_IMPLEMENT_INTERFACE (NMT_TYPE_NEWT_FILE_PICKER, + nmt_newt_file_button_file_picker_interface_init); + ) + +#define NMT_NEWT_FILE_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_FILE_BUTTON, NmtNewtFileButtonPrivate)) + +typedef struct { + NmtNewtLabel *label; + NmtNewtButton *button; + NmtNewtFileDialog *dialog; +} NmtNewtFileButtonPrivate; + +enum { + PROP_0, + PROP_DIALOG_TITLE, + PROP_SENSITIVE, + PROP_CWD, + PROP_DISPLAY_CWD, + PROP_SELECTION, + PROP_DISPLAY_SELECTION, + + LAST_PROP +}; + +/** + * nmt_newt_file_button_new: + * @dialog_title: the title to use for the #NmtNewtFileDialog + * + * Creates a new #NmtNewtFileButton + * + * Returns: a new #NmtNewtFileButton + */ +NmtNewtWidget * +nmt_newt_file_button_new (const char *dialog_title) +{ + return g_object_new (NMT_TYPE_NEWT_FILE_BUTTON, + "dialog-title", dialog_title, + NULL); +} + +static void +dialog_notify (GObject *dialog, + GParamSpec *pspec, + gpointer button) +{ + if ( !strcmp (pspec->name, "cwd") + || !strcmp (pspec->name, "display-cwd") + || !strcmp (pspec->name, "selection") + || !strcmp (pspec->name, "display-selection")) + g_object_notify (button, pspec->name); +} + +static void +nmt_newt_file_button_init (NmtNewtFileButton *button) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (button); + + priv->dialog = NMT_NEWT_FILE_DIALOG (nmt_newt_file_dialog_new ()); + g_signal_connect (priv->dialog, "notify", G_CALLBACK (dialog_notify), button); +} + +static void +select_file (NmtNewtButton *select_button, + gpointer user_data) +{ + NmtNewtFileButton *button = user_data; + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (button); + + nmt_newt_form_run_sync (NMT_NEWT_FORM (priv->dialog)); +} + +static gboolean +transform_selection_for_label (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + const char *selection = g_value_get_string (from_value); + char *label; + + label = g_path_get_basename (selection); + g_value_take_string (to_value, label); + return TRUE; +} + +static void +nmt_newt_file_button_constructed (GObject *object) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (object); + NmtNewtGrid *grid = NMT_NEWT_GRID (object); + NmtNewtWidget *widget; + + widget = nmt_newt_label_new (""); + priv->label = NMT_NEWT_LABEL (widget); + nmt_newt_label_set_style (priv->label, NMT_NEWT_LABEL_PLAIN); + nmt_newt_grid_add (grid, widget, 0, 0); + + widget = nmt_newt_button_new (_("Select...")); + priv->button = NMT_NEWT_BUTTON (widget); + nmt_newt_grid_add (grid, widget, 1, 0); + nmt_newt_widget_set_padding (widget, 1, 0, 0, 0); + g_signal_connect (priv->button, "clicked", + G_CALLBACK (select_file), object); + + g_object_bind_property_full (priv->dialog, "display-selection", + priv->label, "text", + G_BINDING_SYNC_CREATE, + transform_selection_for_label, + NULL, NULL, NULL); + + G_OBJECT_CLASS (nmt_newt_file_button_parent_class)->constructed (object); +} + +static void +nmt_newt_file_button_dispose (GObject *object) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (object); + + g_clear_object (&priv->dialog); + + G_OBJECT_CLASS (nmt_newt_file_button_parent_class)->dispose (object); +} + +static void +nmt_newt_file_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_SENSITIVE: + g_object_set_property (G_OBJECT (priv->button), pspec->name, value); + break; + case PROP_DIALOG_TITLE: + g_object_set_property (G_OBJECT (priv->dialog), "title", value); + break; + case PROP_CWD: + case PROP_SELECTION: + g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_file_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_SENSITIVE: + g_object_get_property (G_OBJECT (priv->button), pspec->name, value); + break; + case PROP_DIALOG_TITLE: + g_object_get_property (G_OBJECT (priv->dialog), "title", value); + break; + case PROP_CWD: + case PROP_DISPLAY_CWD: + case PROP_SELECTION: + case PROP_DISPLAY_SELECTION: + g_object_get_property (G_OBJECT (priv->dialog), pspec->name, value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_file_button_class_init (NmtNewtFileButtonClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtNewtFileButtonPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_newt_file_button_constructed; + object_class->set_property = nmt_newt_file_button_set_property; + object_class->get_property = nmt_newt_file_button_get_property; + object_class->dispose = nmt_newt_file_button_dispose; + + /** + * NmtNewtFileButton:dialog-title: + * + * The title to use for the #NmtNewtFileDialog. + */ + g_object_class_install_property + (object_class, PROP_DIALOG_TITLE, + g_param_spec_string ("dialog-title", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtNewtFileButton:sensitive: + * + * Whether the widget is sensitive; this is just a proxy for the embedded + * #NmtNewtButton's #NmtNewtComponent:sensitive property. + */ + g_object_class_install_property + (object_class, PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_override_property (object_class, PROP_CWD, "cwd"); + g_object_class_override_property (object_class, PROP_DISPLAY_CWD, "display-cwd"); + g_object_class_override_property (object_class, PROP_SELECTION, "selection"); + g_object_class_override_property (object_class, PROP_DISPLAY_SELECTION, "display-selection"); +} + +static void +nmt_newt_file_button_set_filter (NmtNewtFilePicker *picker, + NmtNewtFilePickerFilter filter, + gpointer filter_data, + GDestroyNotify filter_destroy) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (picker); + + nmt_newt_file_picker_set_filter (NMT_NEWT_FILE_PICKER (priv->dialog), + filter, filter_data, filter_destroy); +} + +static const char * +nmt_newt_file_button_get_cwd (NmtNewtFilePicker *picker) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (picker); + + return nmt_newt_file_picker_get_cwd (NMT_NEWT_FILE_PICKER (priv->dialog)); +} + +static const char * +nmt_newt_file_button_get_selection (NmtNewtFilePicker *picker) +{ + NmtNewtFileButtonPrivate *priv = NMT_NEWT_FILE_BUTTON_GET_PRIVATE (picker); + + return nmt_newt_file_picker_get_selection (NMT_NEWT_FILE_PICKER (priv->dialog)); +} + +static void +nmt_newt_file_button_file_picker_interface_init (NmtNewtFilePickerInterface *iface, + gpointer iface_data) +{ + iface->set_filter = nmt_newt_file_button_set_filter; + iface->get_cwd = nmt_newt_file_button_get_cwd; + iface->get_selection = nmt_newt_file_button_get_selection; +} diff --git a/clients/tui/newt/nmt-newt-file-button.h b/clients/tui/newt/nmt-newt-file-button.h new file mode 100644 index 0000000000..3e19886a4a --- /dev/null +++ b/clients/tui/newt/nmt-newt-file-button.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program 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 program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 Red Hat, Inc. + */ + +#ifndef NMT_FILE_BUTTON_H +#define NMT_FILE_BUTTON_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_FILE_BUTTON (nmt_newt_file_button_get_type ()) +#define NMT_NEWT_FILE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_FILE_BUTTON, NmtFileButton)) +#define NMT_NEWT_FILE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_FILE_BUTTON, NmtFileButtonClass)) +#define NMT_IS_NEWT_FILE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_FILE_BUTTON)) +#define NMT_IS_NEWT_FILE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_FILE_BUTTON)) +#define NMT_NEWT_FILE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_FILE_BUTTON, NmtFileButtonClass)) + +struct _NmtNewtFileButton { + NmtNewtGrid parent; + +}; + +typedef struct { + NmtNewtGridClass parent; + +} NmtNewtFileButtonClass; + +GType nmt_newt_file_button_get_type (void); + +NmtNewtWidget *nmt_newt_file_button_new (const char *dialog_title); + +G_END_DECLS + +#endif /* NMT_NEWT_FILE_BUTTON_H */ diff --git a/clients/tui/newt/nmt-newt-file-dialog.c b/clients/tui/newt/nmt-newt-file-dialog.c new file mode 100644 index 0000000000..f788bbb01b --- /dev/null +++ b/clients/tui/newt/nmt-newt-file-dialog.c @@ -0,0 +1,525 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program 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 program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-file-dialog + * @short_description: File selection dialog + * + * #NmtNewtFileDialog implements a form for selecting an existing file from + * disk. At this time it does not support creating new files, or selecting + * directories. + * + * A #NmtNewtFileDialog can be reused, and remembers its state between uses. + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nm-glib-compat.h" + +#include "nmt-newt-file-dialog.h" +#include "nmt-newt-file-picker.h" +#include "nmt-newt-button.h" +#include "nmt-newt-grid.h" +#include "nmt-newt-label.h" +#include "nmt-newt-listbox.h" +#include "nmt-newt-utils.h" + +static void nmt_newt_file_dialog_file_picker_interface_init (NmtNewtFilePickerInterface *iface, gpointer iface_data); + +G_DEFINE_TYPE_WITH_CODE (NmtNewtFileDialog, nmt_newt_file_dialog, NMT_TYPE_NEWT_FORM, + G_IMPLEMENT_INTERFACE (NMT_TYPE_NEWT_FILE_PICKER, + nmt_newt_file_dialog_file_picker_interface_init); + ) + +#define NMT_NEWT_FILE_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_FILE_DIALOG, NmtNewtFileDialogPrivate)) + +static void path_selected (NmtNewtWidget *widget, gpointer user_data); + +typedef struct { + NmtNewtListbox *list; + + char *cwd; + char *display_cwd; + char *selection; + char *display_selection; + + NmtNewtFilePickerFilter filter; + gpointer filter_data; + GDestroyNotify filter_destroy; + +} NmtNewtFileDialogPrivate; + +enum { + PROP_0, + PROP_CWD, + PROP_DISPLAY_CWD, + PROP_SELECTION, + PROP_DISPLAY_SELECTION, + + LAST_PROP +}; + +/** + * nmt_newt_file_dialog_new: + * + * Creates a new #NmtNewtFileDialog. + * + * Returns: a new #NmtNewtFileDialog + */ +NmtNewtForm * +nmt_newt_file_dialog_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_FILE_DIALOG, + "escape-exits", TRUE, + NULL); +} + +static void +nmt_newt_file_dialog_init (NmtNewtFileDialog *dialog) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + int screen_height, screen_width, height; + NmtNewtWidget *list; + + newtGetScreenSize (&screen_width, &screen_height); + height = MAX (10, screen_height - 10); + list = nmt_newt_listbox_new (height, NMT_NEWT_LISTBOX_SCROLL | NMT_NEWT_LISTBOX_BORDER); + g_signal_connect (list, "activated", G_CALLBACK (path_selected), dialog); + priv->list = NMT_NEWT_LISTBOX (list); +} + +static gboolean +sort_fileinfos (gconstpointer a, gconstpointer b) +{ + GFileInfo *info_a = *(GFileInfo **) a; + GFileInfo *info_b = *(GFileInfo **) b; + GFileType type_a = g_file_info_get_file_type (info_a); + GFileType type_b = g_file_info_get_file_type (info_b); + const char *name_a = g_file_info_get_display_name (info_a); + const char *name_b = g_file_info_get_display_name (info_b); + + /* Sort directories before files */ + if (type_a == G_FILE_TYPE_DIRECTORY && type_b != G_FILE_TYPE_DIRECTORY) + return -1; + else if (type_b == G_FILE_TYPE_DIRECTORY && type_a != G_FILE_TYPE_DIRECTORY) + return 1; + + /* Sort dotfiles before non-dotfiles */ + if (*name_a == '.' && *name_b != '.') + return -1; + else if (*name_b == '.' && *name_a != '.') + return 1; + + /* Otherwise, use locale collation rules */ + return g_utf8_collate (name_a, name_b); +} + +static void +update_selection (NmtNewtFileDialog *dialog) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + char *dirname, *basename; + int i, num; + GFileInfo *info; + + if (!priv->selection) { + nmt_newt_listbox_set_active (priv->list, 0); + return; + } + + dirname = g_path_get_dirname (priv->selection); + if (strcmp (dirname, priv->cwd) != 0) { + g_free (dirname); + nmt_newt_listbox_set_active (priv->list, 0); + return; + } + g_free (dirname); + + basename = g_path_get_basename (priv->selection); + num = nmt_newt_listbox_get_num_rows (priv->list); + for (i = 0; i < num; i++) { + info = nmt_newt_listbox_get_key (priv->list, i); + if (info && !strcmp (basename, g_file_info_get_name (info))) { + g_free (basename); + nmt_newt_listbox_set_active (priv->list, i); + return; + } + } + + g_free (basename); + nmt_newt_listbox_set_active (priv->list, 0); +} + +static void +rebuild_dialog (NmtNewtFileDialog *dialog) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + GPtrArray *fileinfos; + GFile *dir; + GFileEnumerator *iter; + GFileInfo *info; + GFileType type; + GError *error = NULL; + const char *display_name; + int i; + + nmt_newt_listbox_clear (priv->list); + + fileinfos = g_ptr_array_new (); + + dir = g_file_new_for_path (priv->cwd); + iter = g_file_enumerate_children (dir, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, + NULL, &error); + /* FIXME */ + g_assert_no_error (error); + + while ((info = g_file_enumerator_next_file (iter, NULL, NULL))) { + type = g_file_info_get_file_type (info); + + if (type == G_FILE_TYPE_REGULAR || type == G_FILE_TYPE_SYMBOLIC_LINK) { + if (priv->filter) { + char *full_path; + gboolean keep; + + full_path = g_build_filename (priv->cwd, g_file_info_get_name (info), NULL); + keep = priv->filter (NMT_NEWT_FILE_PICKER (dialog), full_path, + info, priv->filter_data); + g_free (full_path); + if (!keep) { + g_object_unref (info); + continue; + } + } + g_ptr_array_add (fileinfos, info); + } else if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { + g_ptr_array_add (fileinfos, info); + } else + g_object_unref (info); + } + g_object_unref (iter); + + g_ptr_array_sort (fileinfos, sort_fileinfos); + + /* ".." goes first */ + if (g_file_get_parent (dir)) + nmt_newt_listbox_append (priv->list, "../", NULL); + + for (i = 0; i < fileinfos->len; i++) { + info = fileinfos->pdata[i]; + display_name = g_file_info_get_display_name (info); + + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { + char *dname; + + dname = g_strdup_printf ("%s/", display_name); + g_object_set_data_full (G_OBJECT (info), "NmtNewtFileDialog-display-name", + dname, g_free); + display_name = dname; + } + + nmt_newt_listbox_append (priv->list, display_name, info); + } + + update_selection (dialog); + + g_object_unref (dir); + g_ptr_array_unref (fileinfos); +} + +static void +path_selected (NmtNewtWidget *widget, + gpointer user_data) +{ + NmtNewtFileDialog *dialog = user_data; + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + GFileInfo *info; + const char *name; + char *selected_path; + + info = nmt_newt_listbox_get_active_key (priv->list); + if (info) { + name = g_file_info_get_name (info); + selected_path = g_build_filename (priv->cwd, name, NULL); + } else /* ".." */ + selected_path = g_path_get_dirname (priv->cwd); + + if (!info || g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { + nmt_newt_file_picker_set_cwd (NMT_NEWT_FILE_PICKER (dialog), selected_path); + } else { + nmt_newt_file_picker_set_selection (NMT_NEWT_FILE_PICKER (dialog), selected_path); + nmt_newt_form_quit (NMT_NEWT_FORM (dialog)); + } + + g_free (selected_path); +} + +#define LABEL_WIDTH 40 + +static gboolean +transform_cwd_for_label (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + const char *cwd = g_value_get_string (from_value); + const char *p; + char *label; + int len; + + len = strlen (cwd); + if (len < LABEL_WIDTH - 1) { + label = g_strdup_printf ("%s:%*s", cwd, LABEL_WIDTH - 1 - len, ""); + g_value_take_string (to_value, label); + return TRUE; + } + + for (p = strchr (cwd + 1, '/'); p; p = strchr (p + 1, '/')) { + len = strlen (p); + if (len < LABEL_WIDTH - 4) { + label = g_strdup_printf ("...%s:%*s", p, LABEL_WIDTH - 4 - len, ""); + g_value_take_string (to_value, label); + return TRUE; + } + } + + /* Even just the final path component is too long. Truncate it. */ + label = g_strdup_printf ("...%s:", cwd + strlen (cwd) - (LABEL_WIDTH - 4)); + g_value_take_string (to_value, label); + return TRUE; +} + +static void +nmt_newt_file_dialog_constructed (GObject *object) +{ + NmtNewtFileDialog *dialog = NMT_NEWT_FILE_DIALOG (object); + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + NmtNewtWidget *vbox, *cwd, *list, *buttons, *ok, *cancel; + + vbox = nmt_newt_grid_new (); + + cwd = nmt_newt_label_new (NULL); + g_object_bind_property_full (dialog, "display-cwd", + cwd, "text", + G_BINDING_SYNC_CREATE, + transform_cwd_for_label, + NULL, NULL, NULL); + + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), cwd, 0, 0); + + list = NMT_NEWT_WIDGET (priv->list); + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), list, 0, 1); + nmt_newt_widget_set_padding (list, 0, 1, 0, 1); + + buttons = nmt_newt_grid_new (); + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), buttons, 0, 2); + + cancel = g_object_ref_sink (nmt_newt_button_new (_("Cancel"))); + nmt_newt_widget_set_exit_on_activate (cancel, TRUE); + nmt_newt_grid_add (NMT_NEWT_GRID (buttons), cancel, 0, 0); + nmt_newt_grid_set_flags (NMT_NEWT_GRID (buttons), cancel, + NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_ANCHOR_RIGHT | + NMT_NEWT_GRID_FILL_Y); + + ok = g_object_ref_sink (nmt_newt_button_new (_("OK"))); + g_signal_connect (ok, "clicked", G_CALLBACK (path_selected), dialog); + nmt_newt_grid_add (NMT_NEWT_GRID (buttons), ok, 1, 0); + nmt_newt_widget_set_padding (ok, 1, 0, 0, 0); + + nmt_newt_form_set_content (NMT_NEWT_FORM (dialog), vbox); + + G_OBJECT_CLASS (nmt_newt_file_dialog_parent_class)->constructed (object); +} + +static void +nmt_newt_file_dialog_finalize (GObject *object) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (object); + + g_free (priv->cwd); + g_free (priv->display_cwd); + g_free (priv->selection); + g_free (priv->display_selection); + + if (priv->filter_destroy) + priv->filter_destroy (priv->filter_data); + + G_OBJECT_CLASS (nmt_newt_file_dialog_parent_class)->finalize (object); +} + +static void +nmt_newt_file_dialog_set_cwd (NmtNewtFileDialog *dialog, + const char *cwd) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + + if (cwd && priv->cwd && !strcmp (cwd, priv->cwd)) + return; + + g_free (priv->cwd); + g_free (priv->display_cwd); + + if (cwd) + priv->cwd = g_strdup (cwd); + else + priv->cwd = g_get_current_dir (); + priv->display_cwd = nmt_newt_filename_to_utf8 (priv->cwd); + + rebuild_dialog (dialog); + + g_object_notify (G_OBJECT (dialog), "cwd"); + g_object_notify (G_OBJECT (dialog), "display-cwd"); +} + +static void +nmt_newt_file_dialog_set_selection (NmtNewtFileDialog *dialog, + const char *selection) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (dialog); + + if (selection && !*selection) + selection = NULL; + if (!g_strcmp0 (selection, priv->selection) && priv->display_selection != NULL) + return; + + g_free (priv->selection); + priv->selection = g_strdup (selection); + + g_free (priv->display_selection); + if (selection) + priv->display_selection = nmt_newt_filename_to_utf8 (selection); + else + priv->display_selection = g_strdup (_("(none)")); + + update_selection (dialog); + + g_object_notify (G_OBJECT (dialog), "selection"); + g_object_notify (G_OBJECT (dialog), "display-selection"); +} + +static void +nmt_newt_file_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtFileDialog *dialog = NMT_NEWT_FILE_DIALOG (object); + + switch (prop_id) { + case PROP_CWD: + nmt_newt_file_dialog_set_cwd (dialog, g_value_get_string (value)); + break; + case PROP_SELECTION: + nmt_newt_file_dialog_set_selection (dialog, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_file_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CWD: + g_value_set_string (value, priv->cwd); + break; + case PROP_DISPLAY_CWD: + g_value_set_string (value, priv->display_cwd); + break; + case PROP_SELECTION: + g_value_set_string (value, priv->selection); + break; + case PROP_DISPLAY_SELECTION: + g_value_set_string (value, priv->display_selection); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_file_dialog_class_init (NmtNewtFileDialogClass *dialog_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (dialog_class); + + g_type_class_add_private (dialog_class, sizeof (NmtNewtFileDialogPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_newt_file_dialog_constructed; + object_class->set_property = nmt_newt_file_dialog_set_property; + object_class->get_property = nmt_newt_file_dialog_get_property; + object_class->finalize = nmt_newt_file_dialog_finalize; + + g_object_class_override_property (object_class, PROP_CWD, "cwd"); + g_object_class_override_property (object_class, PROP_DISPLAY_CWD, "display-cwd"); + g_object_class_override_property (object_class, PROP_SELECTION, "selection"); + g_object_class_override_property (object_class, PROP_DISPLAY_SELECTION, "display-selection"); +} + +static void +nmt_newt_file_dialog_set_filter (NmtNewtFilePicker *picker, + NmtNewtFilePickerFilter filter, + gpointer filter_data, + GDestroyNotify filter_destroy) +{ + NmtNewtFileDialogPrivate *priv = NMT_NEWT_FILE_DIALOG_GET_PRIVATE (picker); + + if (priv->filter_destroy) + priv->filter_destroy (priv->filter_data); + + priv->filter = filter; + priv->filter_data = filter_data; + priv->filter_destroy = filter_destroy; + + rebuild_dialog (NMT_NEWT_FILE_DIALOG (picker)); +} + +static const char * +nmt_newt_file_dialog_get_cwd (NmtNewtFilePicker *picker) +{ + return NMT_NEWT_FILE_DIALOG_GET_PRIVATE (picker)->cwd; +} + +static const char * +nmt_newt_file_dialog_get_selection (NmtNewtFilePicker *picker) +{ + return NMT_NEWT_FILE_DIALOG_GET_PRIVATE (picker)->selection; +} + +static void +nmt_newt_file_dialog_file_picker_interface_init (NmtNewtFilePickerInterface *iface, + gpointer iface_data) +{ + iface->set_filter = nmt_newt_file_dialog_set_filter; + iface->get_cwd = nmt_newt_file_dialog_get_cwd; + iface->get_selection = nmt_newt_file_dialog_get_selection; +} diff --git a/clients/tui/newt/nmt-newt-file-dialog.h b/clients/tui/newt/nmt-newt-file-dialog.h new file mode 100644 index 0000000000..d924f84866 --- /dev/null +++ b/clients/tui/newt/nmt-newt-file-dialog.h @@ -0,0 +1,51 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program 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 program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_FILE_DIALOG_H +#define NMT_NEWT_FILE_DIALOG_H + +#include <gio/gio.h> + +#include "nmt-newt-form.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_FILE_DIALOG (nmt_newt_file_dialog_get_type ()) +#define NMT_NEWT_FILE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_FILE_DIALOG, NmtNewtFileDialog)) +#define NMT_NEWT_FILE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_FILE_DIALOG, NmtNewtFileDialogClass)) +#define NMT_IS_NEWT_FILE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_FILE_DIALOG)) +#define NMT_IS_NEWT_FILE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_FILE_DIALOG)) +#define NMT_NEWT_FILE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_FILE_DIALOG, NmtNewtFileDialogClass)) + +struct _NmtNewtFileDialog { + NmtNewtForm parent; + +}; + +typedef struct { + NmtNewtFormClass parent; + +} NmtNewtFileDialogClass; + +GType nmt_newt_file_dialog_get_type (void); + +NmtNewtForm *nmt_newt_file_dialog_new (void); + +G_END_DECLS + +#endif /* NMT_NEWT_FILE_DIALOG_H */ diff --git a/clients/tui/newt/nmt-newt-file-picker.c b/clients/tui/newt/nmt-newt-file-picker.c new file mode 100644 index 0000000000..51aeb91ba3 --- /dev/null +++ b/clients/tui/newt/nmt-newt-file-picker.c @@ -0,0 +1,204 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program 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 program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-file-picker + * @short_description: Abstract interface for file selection widgets + * + * #NmtNewtFilePicker is the interface implemented by #NmtNewtFileButton and + * #NmtNewtFileDialog. + */ + +#include "config.h" + +#include "nmt-newt-file-picker.h" + +static void nmt_newt_file_picker_default_init (NmtNewtFilePickerInterface *iface); + +G_DEFINE_INTERFACE (NmtNewtFilePicker, nmt_newt_file_picker, NMT_TYPE_NEWT_WIDGET) + +/** + * NmtNewtFilePickerFilter: + * @picker: the #NmtNewtFilePicker + * @info: the #GFileInfo to possibly filter + * @user_data: the data passed to nmt_newt_file_picker_set_filter() + * + * Callback to decide whether to show a file in @picker. Currently this is only + * called for files, not directories, and @info is only guaranteed to have the + * information associated with %G_FILE_ATTRIBUTE_STANDARD_NAME, + * %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, and %G_FILE_ATTRIBUTE_STANDARD_TYPE. + * + * Returns: %TRUE if the file should be shown, %FALSE if not. + */ + +static void +nmt_newt_file_picker_default_init (NmtNewtFilePickerInterface *iface) +{ + /** + * NmtNewtFilePicker:cwd: + * + * The current working directory of the #NmtNewtFilePicker. Setting this + * property to %NULL will cause it to be set to the process's current + * working directory. + * + * Note that this is not guaranteed to be a UTF-8 string. + * + * You cannot change this while the widget is realized. + * + * Type: filename + */ + g_object_interface_install_property + (iface, + g_param_spec_string ("cwd", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtNewtFilePicker:display-cwd: + * + * The current working directory of the picker, in UTF-8. + * + * Type: utf8 + */ + g_object_interface_install_property + (iface, + g_param_spec_string ("display-cwd", "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtNewtFilePicker:selection: + * + * The selected file. If the user cancels the picker, this will be %NULL + * when the picker exits. + * + * Note that this is not guaranteed to be a UTF-8 string. + * + * You cannot change this while the widget is realized. + * + * Type: filename + */ + g_object_interface_install_property + (iface, + g_param_spec_string ("selection", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtNewtFilePicker:display-selection: + * + * The selected file, in UTF-8. + * + * Type: utf8 + */ + g_object_interface_install_property + (iface, + g_param_spec_string ("display-selection", "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +} + +/** + * nmt_newt_file_picker_set_filter: + * @picker: the #NmtNewtFilePicker + * @filter: the filter callback + * @filter_data: data to pass to @filter + * @filter_destroy: #GDestroyNotify for @filter_data + * + * Sets the filter used to determine what files to show in @picker. Note that + * the filter is only called for regular files; directories are always shown. + */ +void +nmt_newt_file_picker_set_filter (NmtNewtFilePicker *picker, + NmtNewtFilePickerFilter filter, + gpointer filter_data, + GDestroyNotify filter_destroy) +{ + NMT_NEWT_FILE_PICKER_GET_INTERFACE (picker)->set_filter (picker, filter, filter_data, filter_destroy); +} + + +/** + * nmt_newt_file_picker_set_cwd: + * @picker: the #NmtNewtFilePicker + * @cwd: (allow-none) (type filename): the new current working directory + * + * Sets @picker's current working directory. If @cwd is %NULL, it will be set + * to the process's current working directory. + * + * This will also clear #NmtNewtFilePicker:selection. + */ +void +nmt_newt_file_picker_set_cwd (NmtNewtFilePicker *picker, + const char *cwd) +{ + g_object_set (picker, + "cwd", cwd, + "selection", NULL, + NULL); +} + +/** + * nmt_newt_file_picker_get_cwd: + * @picker: the #NmtNewtFilePicker + * + * Gets @picker's current working directory. + * + * Returns: (type filename): @picker's current working directory. + */ +const char * +nmt_newt_file_picker_get_cwd (NmtNewtFilePicker *picker) +{ + return NMT_NEWT_FILE_PICKER_GET_INTERFACE (picker)->get_cwd (picker); +} + +/** + * nmt_newt_file_picker_set_selection: + * @picker: the #NmtNewtFilePicker + * @selection: (allow-none) (type filename): the selected file + * + * Sets @picker's current selection. + */ +void +nmt_newt_file_picker_set_selection (NmtNewtFilePicker *picker, + const char *selection) +{ + g_object_set (picker, + "selection", selection, + NULL); +} + +/** + * nmt_newt_file_picker_get_selection: + * @picker: the #NmtNewtFilePicker + * + * Gets @picker's current selection. + * + * Returns: (type filename): @picker's current selection. + */ +const char * +nmt_newt_file_picker_get_selection (NmtNewtFilePicker *picker) +{ + return NMT_NEWT_FILE_PICKER_GET_INTERFACE (picker)->get_selection (picker); +} diff --git a/clients/tui/newt/nmt-newt-file-picker.h b/clients/tui/newt/nmt-newt-file-picker.h new file mode 100644 index 0000000000..95731f4875 --- /dev/null +++ b/clients/tui/newt/nmt-newt-file-picker.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program 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 program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_FILE_PICKER_H +#define NMT_NEWT_FILE_PICKER_H + +#include <gio/gio.h> + +#include "nmt-newt-form.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_FILE_PICKER (nmt_newt_file_picker_get_type ()) +#define NMT_NEWT_FILE_PICKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_FILE_PICKER, NmtNewtFilePicker)) +#define NMT_NEWT_FILE_PICKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_FILE_PICKER, NmtNewtFilePickerClass)) +#define NMT_IS_NEWT_FILE_PICKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_FILE_PICKER)) +#define NMT_IS_NEWT_FILE_PICKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_FILE_PICKER)) +#define NMT_NEWT_FILE_PICKER_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NMT_TYPE_NEWT_FILE_PICKER, NmtNewtFilePickerInterface)) + +typedef gboolean (*NmtNewtFilePickerFilter) (NmtNewtFilePicker *picker, + const char *path, + GFileInfo *info, + gpointer user_data); + +typedef struct { + GTypeInterface parent; + + void (*set_filter) (NmtNewtFilePicker *picker, + NmtNewtFilePickerFilter filter, + gpointer filter_data, + GDestroyNotify filter_destroy); + + const char * (*get_cwd) (NmtNewtFilePicker *picker); + const char * (*get_selection) (NmtNewtFilePicker *picker); + +} NmtNewtFilePickerInterface; + +GType nmt_newt_file_picker_get_type (void); + +NmtNewtForm *nmt_newt_file_picker_new (const char *initial_directory); + +void nmt_newt_file_picker_set_filter (NmtNewtFilePicker *picker, + NmtNewtFilePickerFilter filter, + gpointer filter_data, + GDestroyNotify filter_destroy); + +void nmt_newt_file_picker_set_cwd (NmtNewtFilePicker *picker, + const char *cwd); +const char *nmt_newt_file_picker_get_cwd (NmtNewtFilePicker *picker); + +void nmt_newt_file_picker_set_selection (NmtNewtFilePicker *picker, + const char *selection); +const char *nmt_newt_file_picker_get_selection (NmtNewtFilePicker *picker); + +G_END_DECLS + +#endif /* NMT_NEWT_FILE_PICKER_H */ diff --git a/clients/tui/newt/nmt-newt-form.c b/clients/tui/newt/nmt-newt-form.c index 19bd39989e..8368e5a301 100644 --- a/clients/tui/newt/nmt-newt-form.c +++ b/clients/tui/newt/nmt-newt-form.c @@ -477,6 +477,7 @@ nmt_newt_form_set_property (GObject *object, switch (prop_id) { case PROP_TITLE: + g_free (priv->title_lc); if (g_value_get_string (value)) { priv->title_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value)); } else @@ -632,8 +633,7 @@ nmt_newt_form_class_init (NmtNewtFormClass *form_class) g_param_spec_string ("title", "", "", NULL, G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_STATIC_STRINGS)); /** * NmtNewtForm:fullscreen: * diff --git a/clients/tui/newt/nmt-newt-types.h b/clients/tui/newt/nmt-newt-types.h index 608f7ff6fa..81d18e480e 100644 --- a/clients/tui/newt/nmt-newt-types.h +++ b/clients/tui/newt/nmt-newt-types.h @@ -32,6 +32,9 @@ typedef struct _NmtNewtComponent NmtNewtComponent; typedef struct _NmtNewtContainer NmtNewtContainer; typedef struct _NmtNewtEntry NmtNewtEntry; typedef struct _NmtNewtEntryNumeric NmtNewtEntryNumeric; +typedef struct _NmtNewtFileButton NmtNewtFileButton; +typedef struct _NmtNewtFileDialog NmtNewtFileDialog; +typedef struct _NmtNewtFilePicker NmtNewtFilePicker; typedef struct _NmtNewtForm NmtNewtForm; typedef struct _NmtNewtGrid NmtNewtGrid; typedef struct _NmtNewtLabel NmtNewtLabel; diff --git a/clients/tui/newt/nmt-newt-utils.c b/clients/tui/newt/nmt-newt-utils.c index 70a65a8489..c66a96210c 100644 --- a/clients/tui/newt/nmt-newt-utils.c +++ b/clients/tui/newt/nmt-newt-utils.c @@ -29,6 +29,7 @@ #include <sys/wait.h> #include <glib/gi18n-lib.h> +#include <gio/gio.h> #include "nm-glib-compat.h" #include "nmt-newt-utils.h" @@ -391,3 +392,68 @@ nmt_newt_edit_string (const char *data) return new_data; } +/** + * nmt_newt_filename_to_utf8: + * @path: (type filename): an absolute filesystem path + * + * Converts @path to a UTF-8 string. + * + * Returns: a UTF-8 string corresponding to @path. Note that this operation + * is not reversible, and may have different results depending on whether + * @path does or does not refer to an actual file. + */ +char * +nmt_newt_filename_to_utf8 (const char *path) +{ + GString *display_name; + GSList *infos, *iter; + GFile *file, *parent; + GFileInfo *info; + + g_return_val_if_fail (g_path_is_absolute (path), NULL); + + if (g_utf8_validate (path, -1, NULL)) + return g_strdup (path); + + infos = NULL; + file = g_file_new_for_path (path); + while (file) { + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + if (!info) + break; + infos = g_slist_prepend (infos, info); + + parent = g_file_get_parent (file); + g_object_unref (file); + file = parent; + } + g_clear_object (&file); + + if (!infos) { + if (!g_get_charset (NULL)) { + char *utf8_path; + + utf8_path = g_locale_to_utf8 (path, -1, NULL, NULL, NULL); + if (utf8_path) + return utf8_path; + } + + /* @path is neither UTF-8 nor locale encoding, and does not refer to + * an actual file. Yay. + */ + return g_strdup ("???"); + } + + display_name = g_string_new (NULL); + for (iter = infos; iter; iter = iter->next) { + g_string_append (display_name, g_file_info_get_display_name (iter->data)); + if (iter->next) + g_string_append_c (display_name, '/'); + } + g_slist_free_full (infos, g_object_unref); + + return g_string_free (display_name, FALSE); +} diff --git a/clients/tui/newt/nmt-newt-utils.h b/clients/tui/newt/nmt-newt-utils.h index 3b37868a0d..312ecafa8a 100644 --- a/clients/tui/newt/nmt-newt-utils.h +++ b/clients/tui/newt/nmt-newt-utils.h @@ -37,6 +37,8 @@ typedef enum { char *nmt_newt_locale_to_utf8 (const char *str_lc); char *nmt_newt_locale_from_utf8 (const char *str_utf8); +char *nmt_newt_filename_to_utf8 (const char *path); + int nmt_newt_text_width (const char *str); void nmt_newt_message_dialog (const char *message, diff --git a/clients/tui/newt/nmt-newt.h b/clients/tui/newt/nmt-newt.h index 6a9c8d9fb5..34dd9d1299 100644 --- a/clients/tui/newt/nmt-newt.h +++ b/clients/tui/newt/nmt-newt.h @@ -24,6 +24,9 @@ #include "nmt-newt-checkbox.h" #include "nmt-newt-entry.h" #include "nmt-newt-entry-numeric.h" +#include "nmt-newt-file-button.h" +#include "nmt-newt-file-dialog.h" +#include "nmt-newt-file-picker.h" #include "nmt-newt-form.h" #include "nmt-newt-grid.h" #include "nmt-newt-label.h" |