[almanah] Add progress reporting to import/export
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [almanah] Add progress reporting to import/export
- Date: Mon, 17 May 2010 23:38:55 +0000 (UTC)
commit 17e418195a79541755dc808574deb7924b409cd8
Author: Philip Withnall <philip tecnocode co uk>
Date: Sun May 16 18:30:01 2010 +0100
Add progress reporting to import/export
Add a progress bar to the import/export dialogue, reporting the operation's
activity. This makes the lifecycle of the import/export dialogue a lot more
complex.
data/almanah.ui | 14 +++++-
src/export-operation.c | 99 ++++++++++++++++++++++++++++++++++------
src/export-operation.h | 8 +++-
src/import-export-dialog.c | 108 +++++++++++++++++++++++++++++++-------------
src/import-operation.c | 69 ++++++++++++++++++++--------
src/import-operation.h | 2 +-
src/main-window.c | 18 ++++---
src/main.c | 4 --
src/main.h | 2 -
9 files changed, 239 insertions(+), 85 deletions(-)
---
diff --git a/data/almanah.ui b/data/almanah.ui
index a58af93..c190bbf 100644
--- a/data/almanah.ui
+++ b/data/almanah.ui
@@ -941,7 +941,6 @@
<column type="gchararray"/><!-- Name -->
<column type="gchararray"/><!-- Description -->
<column type="guint"/><!-- Action -->
- <column type="gchararray"/><!-- Title -->
</columns>
</object>
@@ -993,7 +992,7 @@
</child>
<child>
<object class="GtkAlignment" id="almanah_ied_alignment">
- <property name="top-padding">12</property>
+ <property name="bottom-padding">12</property>
<child>
<object class="GtkLabel" id="almanah_ied_description_label">
<property name="wrap">True</property>
@@ -1007,10 +1006,19 @@
</packing>
</child>
<child>
- <object class="GtkFileChooserButton" id="almanah_ied_file_chooser">
+ <object class="GtkFileChooserWidget" id="almanah_ied_file_chooser">
<signal name="selection-changed" handler="ied_file_chooser_selection_changed_cb"/>
<signal name="file-activated" handler="ied_file_chooser_file_activated_cb"/>
<property name="action">GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER</property>
+ <property name="do-overwrite-confirmation">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="almanah_ied_alignment2">
+ <property name="top-padding">12</property>
+ <child>
+ <object class="GtkProgressBar" id="almanah_ied_progress_bar"/>
+ </child>
</object>
<packing>
<property name="expand">False</property>
diff --git a/src/export-operation.c b/src/export-operation.c
index 032f55f..47ab893 100644
--- a/src/export-operation.c
+++ b/src/export-operation.c
@@ -27,30 +27,30 @@
#include "storage-manager.h"
#include "main.h"
-typedef gboolean (*ExportFunc) (AlmanahExportOperation *self, GFile *destination, GCancellable *cancellable, GError **error);
+typedef gboolean (*ExportFunc) (AlmanahExportOperation *self, GFile *destination, AlmanahExportProgressCallback progress_callback,
+ gpointer progress_user_data, GCancellable *cancellable, GError **error);
typedef struct {
const gchar *name; /* translatable */
const gchar *description; /* translatable */
GtkFileChooserAction action;
- const gchar *file_chooser_title; /* translatable */
ExportFunc export_func;
} ExportModeDetails;
-static gboolean export_text_files (AlmanahExportOperation *self, GFile *destination, GCancellable *cancellable, GError **error);
-static gboolean export_database (AlmanahExportOperation *self, GFile *destination, GCancellable *cancellable, GError **error);
+static gboolean export_text_files (AlmanahExportOperation *self, GFile *destination, AlmanahExportProgressCallback progress_callback,
+ gpointer progress_user_data, GCancellable *cancellable, GError **error);
+static gboolean export_database (AlmanahExportOperation *self, GFile *destination, AlmanahExportProgressCallback progress_callback,
+ gpointer progress_user_data, GCancellable *cancellable, GError **error);
static const ExportModeDetails export_modes[] = {
{ N_("Text Files"),
N_("Select a _folder to export the entries to as text files, one per entry, with names in the format 'yyyy-mm-dd', and no extension. "
"All entries will be exported, unencrypted in plain text format."),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
- N_("Select a Folder"),
export_text_files },
{ N_("Database"),
N_("Select a _filename for a complete copy of the unencrypted Almanah Diary database to be given."),
- GTK_FILE_CHOOSER_ACTION_SAVE, /* TODO: Need to change the file chooser for this */
- N_("Select a File"),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
export_database }
};
@@ -104,8 +104,51 @@ almanah_export_operation_new (AlmanahExportOperationType type_id, GFile *destina
return export_operation;
}
+typedef struct {
+ AlmanahExportProgressCallback callback;
+ gpointer user_data;
+ GDate *date;
+} ProgressData;
+
static gboolean
-export_text_files (AlmanahExportOperation *self, GFile *destination, GCancellable *cancellable, GError **error)
+progress_idle_callback_cb (ProgressData *data)
+{
+ g_assert (data->callback != NULL);
+ data->callback (data->date, data->user_data);
+
+ /* Free the data */
+ g_date_free (data->date);
+ g_slice_free (ProgressData, data);
+
+ return FALSE;
+}
+
+static void
+progress_idle_callback (AlmanahExportProgressCallback callback, gpointer user_data, const GDate *date)
+{
+ GSource *source;
+ ProgressData *data;
+
+ data = g_slice_new (ProgressData);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->date = g_date_new_dmy (g_date_get_day (date), g_date_get_month (date), g_date_get_year (date));
+
+ /* We can't just use g_idle_add() here, since GSimpleAsyncResult uses default priority, so the finished callback will skip any outstanding
+ * progress callbacks in the main loop's priority queue, causing Bad Things to happen. We need to guarantee that no more progress callbacks
+ * will occur after the finished callback has been called; this is one hacky way of achieving that. */
+ source = g_idle_source_new ();
+ g_source_set_priority (source, G_PRIORITY_DEFAULT);
+
+ g_source_set_callback (source, (GSourceFunc) progress_idle_callback_cb, data, NULL);
+ g_source_attach (source, NULL);
+
+ g_source_unref (source);
+}
+
+static gboolean
+export_text_files (AlmanahExportOperation *self, GFile *destination, AlmanahExportProgressCallback progress_callback, gpointer progress_user_data,
+ GCancellable *cancellable, GError **error)
{
AlmanahStorageManagerIter iter;
AlmanahEntry *entry;
@@ -152,8 +195,15 @@ export_text_files (AlmanahExportOperation *self, GFile *destination, GCancellabl
break;
}
+ /* Progress callback */
+ progress_idle_callback (progress_callback, progress_user_data, &date);
+
g_object_unref (file);
g_free (content);
+
+ /* Check for cancellation */
+ if (cancellable != NULL && g_cancellable_set_error_if_cancelled (cancellable, &child_error) == TRUE)
+ break;
}
/* Check if the loop was broken due to an error */
@@ -171,11 +221,14 @@ finish:
}
static gboolean
-export_database (AlmanahExportOperation *self, GFile *destination, GCancellable *cancellable, GError **error)
+export_database (AlmanahExportOperation *self, GFile *destination, AlmanahExportProgressCallback progress_callback, gpointer progress_user_data,
+ GCancellable *cancellable, GError **error)
{
GFile *source;
gboolean success;
+ /* We ignore the progress callbacks, since this is a fairly fast operation, and it exports all the entries at once. */
+
/* Get the input file (current unencrypted database) */
source = g_file_new_for_path (almanah_storage_manager_get_filename (almanah->storage_manager, TRUE));
@@ -187,10 +240,22 @@ export_database (AlmanahExportOperation *self, GFile *destination, GCancellable
return success;
}
+typedef struct {
+ AlmanahExportProgressCallback progress_callback;
+ gpointer progress_user_data;
+} ExportData;
+
+static void
+export_data_free (ExportData *data)
+{
+ g_slice_free (ExportData, data);
+}
+
static void
export_thread (GSimpleAsyncResult *result, AlmanahExportOperation *operation, GCancellable *cancellable)
{
GError *error = NULL;
+ ExportData *data = g_simple_async_result_get_op_res_gpointer (result);
/* Check to see if the operation's been cancelled already */
if (g_cancellable_set_error_if_cancelled (cancellable, &error) == TRUE) {
@@ -200,21 +265,29 @@ export_thread (GSimpleAsyncResult *result, AlmanahExportOperation *operation, GC
}
/* Export and return */
- if (export_modes[operation->priv->current_mode].export_func (operation, operation->priv->destination, cancellable, &error) == FALSE) {
+ if (export_modes[operation->priv->current_mode].export_func (operation, operation->priv->destination, data->progress_callback,
+ data->progress_user_data, cancellable, &error) == FALSE) {
g_simple_async_result_set_from_error (result, error);
g_error_free (error);
}
}
void
-almanah_export_operation_run (AlmanahExportOperation *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+almanah_export_operation_run (AlmanahExportOperation *self, GCancellable *cancellable, AlmanahExportProgressCallback progress_callback,
+ gpointer progress_user_data,GAsyncReadyCallback callback, gpointer user_data)
{
GSimpleAsyncResult *result;
+ ExportData *data;
g_return_if_fail (ALMANAH_IS_EXPORT_OPERATION (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ data = g_slice_new (ExportData);
+ data->progress_callback = progress_callback;
+ data->progress_user_data = progress_user_data;
+
result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, almanah_export_operation_run);
+ g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) export_data_free);
g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) export_thread, G_PRIORITY_DEFAULT, cancellable);
g_object_unref (result);
}
@@ -237,8 +310,7 @@ almanah_export_operation_finish (AlmanahExportOperation *self, GAsyncResult *asy
}
void
-almanah_export_operation_populate_model (GtkListStore *store, guint type_id_column, guint name_column, guint description_column, guint action_column,
- guint file_chooser_title_column)
+almanah_export_operation_populate_model (GtkListStore *store, guint type_id_column, guint name_column, guint description_column, guint action_column)
{
guint i;
@@ -251,7 +323,6 @@ almanah_export_operation_populate_model (GtkListStore *store, guint type_id_colu
name_column, _(export_modes[i].name),
description_column, _(export_modes[i].description),
action_column, export_modes[i].action,
- file_chooser_title_column, _(export_modes[i].file_chooser_title),
-1);
}
}
diff --git a/src/export-operation.h b/src/export-operation.h
index f0990c2..7292519 100644
--- a/src/export-operation.h
+++ b/src/export-operation.h
@@ -27,6 +27,8 @@ G_BEGIN_DECLS
typedef guint AlmanahExportOperationType;
+typedef void (*AlmanahExportProgressCallback) (const GDate *date, gpointer user_data);
+
#define ALMANAH_TYPE_EXPORT_OPERATION (almanah_export_operation_get_type ())
#define ALMANAH_EXPORT_OPERATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), ALMANAH_TYPE_EXPORT_OPERATION, AlmanahExportOperation))
#define ALMANAH_EXPORT_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), ALMANAH_TYPE_EXPORT_OPERATION, AlmanahExportOperationClass))
@@ -49,11 +51,13 @@ GType almanah_export_operation_get_type (void) G_GNUC_CONST;
AlmanahExportOperation *almanah_export_operation_new (AlmanahExportOperationType type_id, GFile *destination) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-void almanah_export_operation_run (AlmanahExportOperation *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void almanah_export_operation_run (AlmanahExportOperation *self, GCancellable *cancellable,
+ AlmanahExportProgressCallback progress_callback, gpointer progress_user_data,
+ GAsyncReadyCallback callback, gpointer user_data);
gboolean almanah_export_operation_finish (AlmanahExportOperation *self, GAsyncResult *async_result, GError **error);
void almanah_export_operation_populate_model (GtkListStore *list_store, guint type_id_column, guint name_column, guint description_column,
- guint action_column, guint file_chooser_title_column);
+ guint action_column);
G_END_DECLS
diff --git a/src/import-export-dialog.c b/src/import-export-dialog.c
index 4883c55..c7e25b3 100644
--- a/src/import-export-dialog.c
+++ b/src/import-export-dialog.c
@@ -44,15 +44,21 @@ struct _AlmanahImportExportDialogPrivate {
GtkFileChooser *file_chooser;
GtkWidget *import_export_button;
GtkLabel *description_label;
+ GtkProgressBar *progress_bar;
+ GCancellable *cancellable; /* non-NULL iff an operation is underway */
};
G_DEFINE_TYPE (AlmanahImportExportDialog, almanah_import_export_dialog, GTK_TYPE_DIALOG)
#define ALMANAH_IMPORT_EXPORT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ALMANAH_TYPE_IMPORT_EXPORT_DIALOG,\
AlmanahImportExportDialogPrivate))
+static void almanah_import_export_dialog_dispose (GObject *object);
+
static void
almanah_import_export_dialog_class_init (AlmanahImportExportDialogClass *klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->dispose = almanah_import_export_dialog_dispose;
g_type_class_add_private (klass, sizeof (AlmanahImportExportDialogPrivate));
}
@@ -63,9 +69,17 @@ almanah_import_export_dialog_init (AlmanahImportExportDialog *self)
self->priv->current_mode = -1; /* no mode selected */
g_signal_connect (self, "response", G_CALLBACK (response_cb), self);
- g_signal_connect (self, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), self);
gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
- gtk_window_set_transient_for (GTK_WINDOW (self), GTK_WINDOW (almanah->main_window));
+ gtk_window_set_default_size (GTK_WINDOW (self), 500, 400);
+}
+
+static void
+almanah_import_export_dialog_dispose (GObject *object)
+{
+ g_message ("almanah_import_export_dialog_dispose");
+
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS (almanah_import_export_dialog_parent_class)->dispose (object);
}
/**
@@ -124,6 +138,7 @@ almanah_import_export_dialog_new (gboolean import)
priv->import_export_button = GTK_WIDGET (gtk_builder_get_object (builder, "almanah_ied_import_export_button"));
priv->mode_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "almanah_ied_mode_store"));
priv->description_label = GTK_LABEL (gtk_builder_get_object (builder, "almanah_ied_description_label"));
+ priv->progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "almanah_ied_progress_bar"));
/* Set the mode label */
gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_builder_get_object (builder, "almanah_ied_mode_label")),
@@ -137,9 +152,9 @@ almanah_import_export_dialog_new (gboolean import)
/* Populate the mode combo box */
if (import == TRUE)
- almanah_import_operation_populate_model (priv->mode_store, 0, 1, 2, 3, 4);
+ almanah_import_operation_populate_model (priv->mode_store, 0, 1, 2, 3);
else
- almanah_export_operation_populate_model (priv->mode_store, 0, 1, 2, 3, 4);
+ almanah_export_operation_populate_model (priv->mode_store, 0, 1, 2, 3);
gtk_combo_box_set_active (priv->mode_combo_box, 0);
g_object_unref (builder);
@@ -150,7 +165,11 @@ almanah_import_export_dialog_new (gboolean import)
static void
import_progress_cb (const GDate *date, AlmanahImportStatus status, const gchar *message, AlmanahImportResultsDialog *results_dialog)
{
+ AlmanahImportExportDialog *self;
+g_message ("import_progress_cb");
+ self = ALMANAH_IMPORT_EXPORT_DIALOG (gtk_window_get_transient_for (GTK_WINDOW (results_dialog))); /* set in response_cb() */
almanah_import_results_dialog_add_result (results_dialog, date, status, message);
+ gtk_progress_bar_pulse (self->priv->progress_bar);
}
static void
@@ -158,21 +177,21 @@ import_cb (AlmanahImportOperation *operation, GAsyncResult *async_result, Almana
{
AlmanahImportExportDialog *self;
GError *error = NULL;
-
+g_message ("import_cb");
self = ALMANAH_IMPORT_EXPORT_DIALOG (gtk_window_get_transient_for (GTK_WINDOW (results_dialog))); /* set in response_cb() */
/* Check for errors (e.g. errors opening databases or files; not errors importing individual entries once we have the content to import) */
if (almanah_import_operation_finish (operation, async_result, &error) == FALSE) {
- /* Show an error */
- GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK, _("Import failed"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
- gtk_dialog_run (GTK_DIALOG (error_dialog));
- gtk_widget_destroy (error_dialog);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) == FALSE) {
+ /* Show an error if the operation wasn't cancelled */
+ GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK, _("Import failed"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+ gtk_widget_destroy (error_dialog);
+ }
g_error_free (error);
-
- gtk_widget_hide (GTK_WIDGET (self));
} else {
/* Show the results dialogue */
gtk_widget_hide (GTK_WIDGET (self));
@@ -181,6 +200,17 @@ import_cb (AlmanahImportOperation *operation, GAsyncResult *async_result, Almana
}
gtk_widget_destroy (GTK_WIDGET (results_dialog));
+
+ g_object_unref (self->priv->cancellable);
+ self->priv->cancellable = NULL;
+
+ gtk_widget_destroy (GTK_WIDGET (self));
+}
+
+static void
+export_progress_cb (const GDate *date, AlmanahImportExportDialog *self)
+{
+ gtk_progress_bar_pulse (self->priv->progress_bar);
}
static void
@@ -190,16 +220,16 @@ export_cb (AlmanahExportOperation *operation, GAsyncResult *async_result, Almana
/* Check for errors (e.g. errors opening databases or files; not errors importing individual entries once we have the content to import) */
if (almanah_export_operation_finish (operation, async_result, &error) == FALSE) {
- /* Show an error */
- GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK, _("Export failed"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
- gtk_dialog_run (GTK_DIALOG (error_dialog));
- gtk_widget_destroy (error_dialog);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) == FALSE) {
+ /* Show an error if the operation wasn't cancelled */
+ GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK, _("Export failed"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+ gtk_widget_destroy (error_dialog);
+ }
g_error_free (error);
-
- gtk_widget_hide (GTK_WIDGET (self));
} else {
/* Show a success message */
GtkWidget *message_dialog;
@@ -211,6 +241,11 @@ export_cb (AlmanahExportOperation *operation, GAsyncResult *async_result, Almana
gtk_dialog_run (GTK_DIALOG (message_dialog));
gtk_widget_destroy (message_dialog);
}
+
+ g_object_unref (self->priv->cancellable);
+ self->priv->cancellable = NULL;
+
+ gtk_widget_destroy (GTK_WIDGET (self));
}
static void
@@ -218,24 +253,37 @@ response_cb (GtkDialog *dialog, gint response_id, AlmanahImportExportDialog *sel
{
AlmanahImportExportDialogPrivate *priv = self->priv;
GFile *file;
-
- /* Just return if the user pressed Cancel */
+g_message ("response_cb");
+ /* If the user pressed Cancel, cancel the operation if we've started, and return otherwise */
if (response_id != GTK_RESPONSE_OK) {
- gtk_widget_hide (GTK_WIDGET (self));
+ if (priv->cancellable == NULL)
+ gtk_widget_destroy (GTK_WIDGET (self));
+ else
+ g_cancellable_cancel (priv->cancellable);
return;
}
+ /* Disable the widgets */
+ gtk_widget_set_sensitive (self->priv->import_export_button, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->priv->file_chooser), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->priv->mode_combo_box), FALSE);
+
+ /* Get the input/output file or folder */
file = gtk_file_chooser_get_file (priv->file_chooser);
g_assert (file != NULL);
+ /* Set up for cancellation */
+ g_assert (priv->cancellable == NULL);
+ priv->cancellable = g_cancellable_new ();
+
if (priv->import == TRUE) {
/* Import the entries according to the selected method.*/
AlmanahImportOperation *operation;
- AlmanahImportResultsDialog *results_dialog = almanah_import_results_dialog_new ();
+ AlmanahImportResultsDialog *results_dialog = almanah_import_results_dialog_new (); /* destroyed in import_cb() */
gtk_window_set_transient_for (GTK_WINDOW (results_dialog), GTK_WINDOW (self)); /* this is required in import_cb() */
operation = almanah_import_operation_new (priv->current_mode, file);
- almanah_import_operation_run (operation, NULL, (AlmanahImportProgressCallback) import_progress_cb, results_dialog,
+ almanah_import_operation_run (operation, priv->cancellable, (AlmanahImportProgressCallback) import_progress_cb, results_dialog,
(GAsyncReadyCallback) import_cb, results_dialog);
g_object_unref (operation);
} else {
@@ -243,7 +291,8 @@ response_cb (GtkDialog *dialog, gint response_id, AlmanahImportExportDialog *sel
AlmanahExportOperation *operation;
operation = almanah_export_operation_new (priv->current_mode, file);
- almanah_export_operation_run (operation, NULL, (GAsyncReadyCallback) export_cb, self);
+ almanah_export_operation_run (operation, priv->cancellable, (AlmanahExportProgressCallback) export_progress_cb, self,
+ (GAsyncReadyCallback) export_cb, self);
g_object_unref (operation);
}
@@ -257,7 +306,7 @@ ied_mode_combo_box_changed_cb (GtkComboBox *combo_box, AlmanahImportExportDialog
gint new_mode;
GtkTreeIter iter;
GtkTreeModel *model;
- gchar *description, *title;
+ gchar *description;
GtkFileChooserAction action;
new_mode = gtk_combo_box_get_active (combo_box);
@@ -272,14 +321,11 @@ ied_mode_combo_box_changed_cb (GtkComboBox *combo_box, AlmanahImportExportDialog
gtk_tree_model_get (model, &iter,
2, &description,
3, &action,
- 4, &title,
-1);
gtk_file_chooser_set_action (priv->file_chooser, action);
- gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (priv->file_chooser), title);
gtk_label_set_text_with_mnemonic (priv->description_label, description);
- g_free (title);
g_free (description);
}
diff --git a/src/import-operation.c b/src/import-operation.c
index 87d9b5a..44a04d6 100644
--- a/src/import-operation.c
+++ b/src/import-operation.c
@@ -34,7 +34,6 @@ typedef struct {
const gchar *name; /* translatable */
const gchar *description; /* translatable */
GtkFileChooserAction action;
- const gchar *file_chooser_title; /* translatable */
ImportFunc import_func;
} ImportModeDetails;
@@ -48,12 +47,10 @@ static const ImportModeDetails import_modes[] = {
N_("Select a _folder containing text files, one per entry, with names in the format 'yyyy-mm-dd', and no extension. "
"Any and all such files will be imported."),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
- N_("Select a Folder"),
import_text_files },
{ N_("Database"),
N_("Select a database _file created by Almanah Diary to import."),
GTK_FILE_CHOOSER_ACTION_OPEN,
- N_("Select a File"),
import_database }
};
@@ -120,7 +117,7 @@ progress_idle_callback_cb (ProgressData *data)
{
g_assert (data->callback != NULL);
data->callback (data->date, data->status, data->message, data->user_data);
-
+g_message ("progress_idle_callback_cb");
/* Free the data */
g_free (data->message);
g_date_free (data->date);
@@ -133,14 +130,27 @@ static void
progress_idle_callback (AlmanahImportProgressCallback callback, gpointer user_data, const GDate *date, AlmanahImportStatus status,
const gchar *message)
{
- ProgressData *data = g_slice_new (ProgressData);
+ GSource *source;
+ ProgressData *data;
+
+ data = g_slice_new (ProgressData);
data->callback = callback;
data->user_data = user_data;
data->date = g_date_new_dmy (g_date_get_day (date), g_date_get_month (date), g_date_get_year (date));
data->status = status;
data->message = g_strdup (message);
-
- g_idle_add ((GSourceFunc) progress_idle_callback_cb, data);
+g_message ("progress_idle_callback");
+
+ /* We can't just use g_idle_add() here, since GSimpleAsyncResult uses default priority, so the finished callback will skip any outstanding
+ * progress callbacks in the main loop's priority queue, causing Bad Things to happen. We need to guarantee that no more progress callbacks
+ * will occur after the finished callback has been called; this is one hacky way of achieving that. */
+ source = g_idle_source_new ();
+ g_source_set_priority (source, G_PRIORITY_DEFAULT);
+
+ g_source_set_callback (source, (GSourceFunc) progress_idle_callback_cb, data, NULL);
+ g_source_attach (source, NULL);
+
+ g_source_unref (source);
}
/**
@@ -170,7 +180,7 @@ set_entry (AlmanahImportOperation *self, AlmanahEntry *imported_entry, const gch
GtkTextIter existing_start, existing_end, imported_start, imported_end;
gchar *header_string;
GError *error = NULL;
-
+g_message ("set_entry");
/* Check to see if there's a conflict first */
almanah_entry_get_date (imported_entry, &entry_date);
existing_entry = almanah_storage_manager_get_entry (almanah->storage_manager, &entry_date);
@@ -197,7 +207,7 @@ set_entry (AlmanahImportOperation *self, AlmanahEntry *imported_entry, const gch
/* The two buffers have to use the same tag table for gtk_text_buffer_insert_range() to work */
existing_buffer = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (imported_buffer));
- if (almanah_entry_get_content (existing_entry, existing_buffer, FALSE, NULL) == FALSE) {
+ if (almanah_entry_get_content (existing_entry, existing_buffer, FALSE, &error) == FALSE) {
/* Deserialising the existing entry failed; use the imported entry instead */
almanah_storage_manager_set_entry (almanah->storage_manager, imported_entry);
@@ -277,7 +287,7 @@ import_text_files (AlmanahImportOperation *self, GFile *source, AlmanahImportPro
GFileEnumerator *enumerator;
GtkTextBuffer *buffer;
GError *child_error = NULL;
-
+g_message ("import_text_files");
enumerator = g_file_enumerate_children (source, "standard::name,standard::display-name,standard::is-hidden,time::modified",
G_FILE_QUERY_INFO_NONE, NULL, error);
if (enumerator == NULL)
@@ -343,6 +353,10 @@ import_text_files (AlmanahImportOperation *self, GFile *source, AlmanahImportPro
g_object_unref (entry);
g_object_unref (file_info);
+
+ /* Check for cancellation */
+ if (cancellable != NULL && g_cancellable_set_error_if_cancelled (cancellable, &child_error) == TRUE)
+ break;
}
/* Check if the loop was broken due to an error */
@@ -368,14 +382,19 @@ import_database (AlmanahImportOperation *self, GFile *source, AlmanahImportProgr
GFileInfo *file_info;
gchar *path;
const gchar *display_name;
- GSList *i, *definitions;
+ GSList *i, *definitions = NULL;
AlmanahEntry *entry;
AlmanahStorageManager *database;
AlmanahStorageManagerIter iter;
+ gboolean success = FALSE;
/* Get the display name for use with set_entry(), below */
- file_info = g_file_query_info (source, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ file_info = g_file_query_info (source, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, G_FILE_QUERY_INFO_NONE, cancellable, error);
+ if (file_info == NULL)
+ return FALSE;
+
display_name = g_file_info_get_display_name (file_info);
+ g_object_unref (file_info);
/* Open the database */
path = g_file_get_path (source);
@@ -402,6 +421,10 @@ import_database (AlmanahImportOperation *self, GFile *source, AlmanahImportProgr
g_free (message);
g_object_unref (entry);
+
+ /* Check for cancellation */
+ if (cancellable != NULL && g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE)
+ goto finish;
}
/* Query for every definition */
@@ -410,14 +433,22 @@ import_database (AlmanahImportOperation *self, GFile *source, AlmanahImportProgr
/* Add the definition to the proper database, ignoring failure */
almanah_storage_manager_add_definition (almanah->storage_manager, ALMANAH_DEFINITION (i->data));
g_object_unref (i->data);
+
+ /* Check for cancellation */
+ if (cancellable != NULL && g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE)
+ goto finish;
}
+
+ /* Success! */
+ success = TRUE;
+
+finish:
g_slist_free (definitions);
almanah_storage_manager_disconnect (database, NULL);
g_object_unref (database);
- g_object_unref (file_info);
- return TRUE;
+ return success;
}
typedef struct {
@@ -436,7 +467,7 @@ import_thread (GSimpleAsyncResult *result, AlmanahImportOperation *operation, GC
{
GError *error = NULL;
ImportData *data = g_simple_async_result_get_op_res_gpointer (result);
-
+g_message ("import_thread");
/* Check to see if the operation's been cancelled already */
if (g_cancellable_set_error_if_cancelled (cancellable, &error) == TRUE) {
g_simple_async_result_set_from_error (result, error);
@@ -458,7 +489,7 @@ almanah_import_operation_run (AlmanahImportOperation *self, GCancellable *cancel
{
GSimpleAsyncResult *result;
ImportData *data;
-
+g_message ("almanah_import_operation_run");
g_return_if_fail (ALMANAH_IS_IMPORT_OPERATION (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -476,7 +507,7 @@ gboolean
almanah_import_operation_finish (AlmanahImportOperation *self, GAsyncResult *async_result, GError **error)
{
GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (async_result);
-
+g_message ("almanah_import_operation_finish");
g_return_val_if_fail (ALMANAH_IS_IMPORT_OPERATION (self), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -490,8 +521,7 @@ almanah_import_operation_finish (AlmanahImportOperation *self, GAsyncResult *asy
}
void
-almanah_import_operation_populate_model (GtkListStore *store, guint type_id_column, guint name_column, guint description_column, guint action_column,
- guint file_chooser_title_column)
+almanah_import_operation_populate_model (GtkListStore *store, guint type_id_column, guint name_column, guint description_column, guint action_column)
{
guint i;
@@ -504,7 +534,6 @@ almanah_import_operation_populate_model (GtkListStore *store, guint type_id_colu
name_column, _(import_modes[i].name),
description_column, _(import_modes[i].description),
action_column, import_modes[i].action,
- file_chooser_title_column, _(import_modes[i].file_chooser_title),
-1);
}
}
diff --git a/src/import-operation.h b/src/import-operation.h
index 72c2c80..921f5fd 100644
--- a/src/import-operation.h
+++ b/src/import-operation.h
@@ -65,7 +65,7 @@ void almanah_import_operation_run (AlmanahImportOperation *self, GCancellable *c
gboolean almanah_import_operation_finish (AlmanahImportOperation *self, GAsyncResult *async_result, GError **error);
void almanah_import_operation_populate_model (GtkListStore *list_store, guint type_id_column, guint name_column, guint description_column,
- guint action_column, guint file_chooser_title_column);
+ guint action_column);
G_END_DECLS
diff --git a/src/main-window.c b/src/main-window.c
index 83ed2e8..7672211 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -713,21 +713,23 @@ mw_delete_event_cb (GtkWindow *window, gpointer user_data)
void
mw_import_activate_cb (GtkAction *action, AlmanahMainWindow *main_window)
{
- if (almanah->import_dialog == NULL)
- almanah->import_dialog = GTK_WIDGET (almanah_import_export_dialog_new (TRUE));
+ GtkWidget *dialog = GTK_WIDGET (almanah_import_export_dialog_new (TRUE));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
- gtk_widget_show_all (almanah->import_dialog);
- gtk_dialog_run (GTK_DIALOG (almanah->import_dialog));
+ /* The dialog destroys itself once done */
+ gtk_widget_show_all (dialog);
}
void
mw_export_activate_cb (GtkAction *action, AlmanahMainWindow *main_window)
{
- if (almanah->export_dialog == NULL)
- almanah->export_dialog = GTK_WIDGET (almanah_import_export_dialog_new (FALSE));
+ GtkWidget *dialog = GTK_WIDGET (almanah_import_export_dialog_new (FALSE));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
- gtk_widget_show_all (almanah->export_dialog);
- gtk_dialog_run (GTK_DIALOG (almanah->export_dialog));
+ /* The dialog destroys itself once done */
+ gtk_widget_show_all (dialog);
}
void
diff --git a/src/main.c b/src/main.c
index 77001fa..93200af 100644
--- a/src/main.c
+++ b/src/main.c
@@ -73,10 +73,6 @@ almanah_quit (void)
gtk_widget_destroy (almanah->search_dialog);
if (almanah->date_entry_dialog != NULL)
gtk_widget_destroy (almanah->date_entry_dialog);
- if (almanah->import_dialog != NULL)
- gtk_widget_destroy (almanah->import_dialog);
- if (almanah->export_dialog != NULL)
- gtk_widget_destroy (almanah->export_dialog);
#ifdef ENABLE_ENCRYPTION
if (almanah->preferences_dialog != NULL)
gtk_widget_destroy (almanah->preferences_dialog);
diff --git a/src/main.h b/src/main.h
index 085c3df..08f9d50 100644
--- a/src/main.h
+++ b/src/main.h
@@ -46,8 +46,6 @@ typedef struct {
GtkWidget *search_dialog;
GtkWidget *date_entry_dialog;
GtkWidget *definition_manager_window;
- GtkWidget *import_dialog;
- GtkWidget *export_dialog;
#ifdef ENABLE_ENCRYPTION
GtkWidget *preferences_dialog;
#endif /* ENABLE_ENCRYPTION */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]