summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clients/tui/newt/Makefile.am6
-rw-r--r--clients/tui/newt/nmt-newt-file-button.c291
-rw-r--r--clients/tui/newt/nmt-newt-file-button.h49
-rw-r--r--clients/tui/newt/nmt-newt-file-dialog.c525
-rw-r--r--clients/tui/newt/nmt-newt-file-dialog.h51
-rw-r--r--clients/tui/newt/nmt-newt-file-picker.c204
-rw-r--r--clients/tui/newt/nmt-newt-file-picker.h72
-rw-r--r--clients/tui/newt/nmt-newt-form.c4
-rw-r--r--clients/tui/newt/nmt-newt-types.h3
-rw-r--r--clients/tui/newt/nmt-newt-utils.c66
-rw-r--r--clients/tui/newt/nmt-newt-utils.h2
-rw-r--r--clients/tui/newt/nmt-newt.h3
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"