1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
4
* Copyright (C) Philip Withnall 2009–2010 <philip@tecnocode.co.uk>
6
* Almanah is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* Almanah is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with Almanah. If not, see <http://www.gnu.org/licenses/>.
22
#include <glib/gi18n.h>
25
#include "import-export-dialog.h"
26
#include "import-operation.h"
27
#include "export-operation.h"
28
#include "interface.h"
30
#include "main-window.h"
32
static void response_cb (GtkDialog *dialog, gint response_id, AlmanahImportExportDialog *self);
34
/* GtkBuilder callbacks */
35
void ied_mode_combo_box_changed_cb (GtkComboBox *combo_box, AlmanahImportExportDialog *self);
36
void ied_file_chooser_selection_changed_cb (GtkFileChooser *file_chooser, AlmanahImportExportDialog *self);
37
void ied_file_chooser_file_activated_cb (GtkFileChooser *file_chooser, AlmanahImportExportDialog *self);
39
struct _AlmanahImportExportDialogPrivate {
40
gboolean import; /* TRUE if we're in import mode, FALSE otherwise */
41
GtkComboBox *mode_combo_box;
42
GtkListStore *mode_store;
44
GtkFileChooser *file_chooser;
45
GtkWidget *import_export_button;
46
GtkLabel *description_label;
47
GtkProgressBar *progress_bar;
48
GCancellable *cancellable; /* non-NULL iff an operation is underway */
51
G_DEFINE_TYPE (AlmanahImportExportDialog, almanah_import_export_dialog, GTK_TYPE_DIALOG)
52
#define ALMANAH_IMPORT_EXPORT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ALMANAH_TYPE_IMPORT_EXPORT_DIALOG,\
53
AlmanahImportExportDialogPrivate))
55
static void almanah_import_export_dialog_dispose (GObject *object);
58
almanah_import_export_dialog_class_init (AlmanahImportExportDialogClass *klass)
60
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
61
gobject_class->dispose = almanah_import_export_dialog_dispose;
62
g_type_class_add_private (klass, sizeof (AlmanahImportExportDialogPrivate));
66
almanah_import_export_dialog_init (AlmanahImportExportDialog *self)
68
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_IMPORT_EXPORT_DIALOG, AlmanahImportExportDialogPrivate);
69
self->priv->current_mode = -1; /* no mode selected */
71
g_signal_connect (self, "response", G_CALLBACK (response_cb), self);
72
gtk_window_set_default_size (GTK_WINDOW (self), 500, 400);
76
almanah_import_export_dialog_dispose (GObject *object)
78
/* Chain up to the parent class */
79
G_OBJECT_CLASS (almanah_import_export_dialog_parent_class)->dispose (object);
83
* almanah_import_export_dialog_new:
84
* @import: %TRUE to set the dialog up for importing, %FALSE to set it up for exporting
86
* Returns a new #AlmanahImportExportDialog, configured for importing if @import is %TRUE, and exporting otherwise.
88
* Return value: a new #AlmanahImportExportDialog; destroy with gtk_widget_destroy()
90
AlmanahImportExportDialog *
91
almanah_import_export_dialog_new (gboolean import)
94
AlmanahImportExportDialog *import_export_dialog;
95
AlmanahImportExportDialogPrivate *priv;
97
const gchar *interface_filename = almanah_get_interface_filename ();
98
const gchar *object_names[] = {
99
"almanah_ied_mode_store",
100
"almanah_import_export_dialog",
104
builder = gtk_builder_new ();
106
if (gtk_builder_add_objects_from_file (builder, interface_filename, (gchar**) object_names, &error) == FALSE) {
108
GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
109
_("UI file \"%s\" could not be loaded"), interface_filename);
110
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
111
gtk_dialog_run (GTK_DIALOG (dialog));
112
gtk_widget_destroy (dialog);
114
g_error_free (error);
115
g_object_unref (builder);
120
gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
121
import_export_dialog = ALMANAH_IMPORT_EXPORT_DIALOG (gtk_builder_get_object (builder, "almanah_import_export_dialog"));
122
gtk_builder_connect_signals (builder, import_export_dialog);
124
if (import_export_dialog == NULL) {
125
g_object_unref (builder);
129
priv = import_export_dialog->priv;
130
priv->import = import;
132
/* Grab our child widgets */
133
priv->mode_combo_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "almanah_ied_mode_combo_box"));
134
priv->file_chooser = GTK_FILE_CHOOSER (gtk_builder_get_object (builder, "almanah_ied_file_chooser"));
135
priv->import_export_button = GTK_WIDGET (gtk_builder_get_object (builder, "almanah_ied_import_export_button"));
136
priv->mode_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "almanah_ied_mode_store"));
137
priv->description_label = GTK_LABEL (gtk_builder_get_object (builder, "almanah_ied_description_label"));
138
priv->progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "almanah_ied_progress_bar"));
140
/* Set the mode label */
141
gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_builder_get_object (builder, "almanah_ied_mode_label")),
142
(import == TRUE) ? _("Import _mode: ") : _("Export _mode: "));
144
/* Set the window title */
145
gtk_window_set_title (GTK_WINDOW (import_export_dialog), (import == TRUE) ? _("Import Entries") : _("Export Entries"));
147
/* Set the button label */
148
gtk_button_set_label (GTK_BUTTON (priv->import_export_button), (import == TRUE) ? _("_Import") : _("_Export"));
150
/* Populate the mode combo box */
152
almanah_import_operation_populate_model (priv->mode_store, 0, 1, 2, 3);
154
almanah_export_operation_populate_model (priv->mode_store, 0, 1, 2, 3);
155
gtk_combo_box_set_active (priv->mode_combo_box, 0);
157
g_object_unref (builder);
159
return import_export_dialog;
163
import_progress_cb (const GDate *date, AlmanahImportStatus status, const gchar *message, AlmanahImportResultsDialog *results_dialog)
165
AlmanahImportExportDialog *self;
167
self = ALMANAH_IMPORT_EXPORT_DIALOG (gtk_window_get_transient_for (GTK_WINDOW (results_dialog))); /* set in response_cb() */
168
almanah_import_results_dialog_add_result (results_dialog, date, status, message);
169
gtk_progress_bar_pulse (self->priv->progress_bar);
173
import_cb (AlmanahImportOperation *operation, GAsyncResult *async_result, AlmanahImportResultsDialog *results_dialog)
175
AlmanahImportExportDialog *self;
176
GError *error = NULL;
178
self = ALMANAH_IMPORT_EXPORT_DIALOG (gtk_window_get_transient_for (GTK_WINDOW (results_dialog))); /* set in response_cb() */
180
/* Check for errors (e.g. errors opening databases or files; not errors importing individual entries once we have the content to import) */
181
if (almanah_import_operation_finish (operation, async_result, &error) == FALSE) {
182
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) == FALSE) {
183
/* Show an error if the operation wasn't cancelled */
184
GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
185
GTK_BUTTONS_OK, _("Import failed"));
186
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
187
gtk_dialog_run (GTK_DIALOG (error_dialog));
188
gtk_widget_destroy (error_dialog);
191
g_error_free (error);
193
/* Show the results dialogue */
194
gtk_widget_hide (GTK_WIDGET (self));
195
gtk_widget_show_all (GTK_WIDGET (results_dialog));
196
gtk_dialog_run (GTK_DIALOG (results_dialog));
199
gtk_widget_destroy (GTK_WIDGET (results_dialog));
201
g_object_unref (self->priv->cancellable);
202
self->priv->cancellable = NULL;
204
gtk_widget_destroy (GTK_WIDGET (self));
208
export_progress_cb (const GDate *date, AlmanahImportExportDialog *self)
210
gtk_progress_bar_pulse (self->priv->progress_bar);
214
export_cb (AlmanahExportOperation *operation, GAsyncResult *async_result, AlmanahImportExportDialog *self)
216
GError *error = NULL;
218
/* Check for errors (e.g. errors opening databases or files; not errors importing individual entries once we have the content to import) */
219
if (almanah_export_operation_finish (operation, async_result, &error) == FALSE) {
220
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) == FALSE) {
221
/* Show an error if the operation wasn't cancelled */
222
GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
223
GTK_BUTTONS_OK, _("Export failed"));
224
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
225
gtk_dialog_run (GTK_DIALOG (error_dialog));
226
gtk_widget_destroy (error_dialog);
229
g_error_free (error);
231
/* Show a success message */
232
GtkWidget *message_dialog;
234
gtk_widget_hide (GTK_WIDGET (self));
235
message_dialog = gtk_message_dialog_new (GTK_WINDOW (self), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
236
GTK_BUTTONS_OK, _("Export successful"));
237
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog), _("The diary was successfully exported."));
238
gtk_dialog_run (GTK_DIALOG (message_dialog));
239
gtk_widget_destroy (message_dialog);
242
g_object_unref (self->priv->cancellable);
243
self->priv->cancellable = NULL;
245
gtk_widget_destroy (GTK_WIDGET (self));
249
response_cb (GtkDialog *dialog, gint response_id, AlmanahImportExportDialog *self)
251
AlmanahImportExportDialogPrivate *priv = self->priv;
254
/* If the user pressed Cancel, cancel the operation if we've started, and return otherwise */
255
if (response_id != GTK_RESPONSE_OK) {
256
if (priv->cancellable == NULL)
257
gtk_widget_destroy (GTK_WIDGET (self));
259
g_cancellable_cancel (priv->cancellable);
263
/* Disable the widgets */
264
gtk_widget_set_sensitive (self->priv->import_export_button, FALSE);
265
gtk_widget_set_sensitive (GTK_WIDGET (self->priv->file_chooser), FALSE);
266
gtk_widget_set_sensitive (GTK_WIDGET (self->priv->mode_combo_box), FALSE);
268
/* Get the input/output file or folder */
269
file = gtk_file_chooser_get_file (priv->file_chooser);
270
g_assert (file != NULL);
272
/* Set up for cancellation */
273
g_assert (priv->cancellable == NULL);
274
priv->cancellable = g_cancellable_new ();
276
if (priv->import == TRUE) {
277
/* Import the entries according to the selected method.*/
278
AlmanahImportOperation *operation;
279
AlmanahImportResultsDialog *results_dialog = almanah_import_results_dialog_new (); /* destroyed in import_cb() */
280
gtk_window_set_transient_for (GTK_WINDOW (results_dialog), GTK_WINDOW (self)); /* this is required in import_cb() */
282
operation = almanah_import_operation_new (priv->current_mode, file);
283
almanah_import_operation_run (operation, priv->cancellable, (AlmanahImportProgressCallback) import_progress_cb, results_dialog,
284
(GAsyncReadyCallback) import_cb, results_dialog);
285
g_object_unref (operation);
287
/* Export the entries according to the selected method. */
288
AlmanahExportOperation *operation;
290
operation = almanah_export_operation_new (priv->current_mode, file);
291
almanah_export_operation_run (operation, priv->cancellable, (AlmanahExportProgressCallback) export_progress_cb, self,
292
(GAsyncReadyCallback) export_cb, self);
293
g_object_unref (operation);
296
g_object_unref (file);
300
ied_mode_combo_box_changed_cb (GtkComboBox *combo_box, AlmanahImportExportDialog *self)
302
AlmanahImportExportDialogPrivate *priv = self->priv;
307
GtkFileChooserAction action;
309
new_mode = gtk_combo_box_get_active (combo_box);
310
if (new_mode == -1 || new_mode == priv->current_mode)
313
priv->current_mode = new_mode;
315
/* Change the dialogue */
316
gtk_combo_box_get_active_iter (combo_box, &iter);
317
model = gtk_combo_box_get_model (combo_box);
318
gtk_tree_model_get (model, &iter,
323
gtk_file_chooser_set_action (priv->file_chooser, action);
324
gtk_label_set_text_with_mnemonic (priv->description_label, description);
326
g_free (description);
330
ied_file_chooser_selection_changed_cb (GtkFileChooser *file_chooser, AlmanahImportExportDialog *self)
334
/* Change the sensitivity of the dialogue's buttons based on whether a file is selected */
335
current_file = gtk_file_chooser_get_file (file_chooser);
336
if (current_file == NULL) {
337
gtk_widget_set_sensitive (self->priv->import_export_button, FALSE);
339
gtk_widget_set_sensitive (self->priv->import_export_button, TRUE);
340
g_object_unref (current_file);
345
ied_file_chooser_file_activated_cb (GtkFileChooser *file_chooser, AlmanahImportExportDialog *self)
347
/* Activate the dialogue's default button */
348
gtk_window_activate_default (GTK_WINDOW (self));
351
static gboolean filter_results_cb (GtkTreeModel *model, GtkTreeIter *iter, AlmanahImportResultsDialog *self);
352
static void results_selection_changed_cb (GtkTreeSelection *tree_selection, GtkWidget *button);
354
/* GtkBuilder callbacks */
355
void ird_results_tree_view_row_activated_cb (GtkTreeView *self, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data);
356
void ird_view_button_clicked_cb (GtkButton *button, AlmanahImportResultsDialog *self);
357
void ird_view_combo_box_changed_cb (GtkComboBox *combo_box, AlmanahImportResultsDialog *self);
359
struct _AlmanahImportResultsDialogPrivate {
360
GtkListStore *results_store;
361
GtkTreeSelection *results_selection;
362
GtkTreeModelFilter *filtered_results_store;
363
GtkComboBox *view_combo_box;
364
AlmanahImportStatus current_mode;
367
G_DEFINE_TYPE (AlmanahImportResultsDialog, almanah_import_results_dialog, GTK_TYPE_DIALOG)
368
#define ALMANAH_IMPORT_RESULTS_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ALMANAH_TYPE_IMPORT_RESULTS_DIALOG,\
369
AlmanahImportResultsDialogPrivate))
372
almanah_import_results_dialog_class_init (AlmanahImportResultsDialogClass *klass)
374
g_type_class_add_private (klass, sizeof (AlmanahImportResultsDialogPrivate));
378
almanah_import_results_dialog_init (AlmanahImportResultsDialog *self)
380
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_IMPORT_RESULTS_DIALOG, AlmanahImportResultsDialogPrivate);
382
g_signal_connect (self, "response", G_CALLBACK (response_cb), self);
383
g_signal_connect (self, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), self);
384
gtk_window_set_resizable (GTK_WINDOW (self), TRUE);
385
gtk_window_set_title (GTK_WINDOW (self), _("Import Results"));
386
gtk_window_set_default_size (GTK_WINDOW (self), 600, 400);
387
gtk_window_set_modal (GTK_WINDOW (self), FALSE);
390
AlmanahImportResultsDialog *
391
almanah_import_results_dialog_new (void)
394
AlmanahImportResultsDialog *results_dialog;
395
AlmanahImportResultsDialogPrivate *priv;
396
GError *error = NULL;
397
const gchar *interface_filename = almanah_get_interface_filename ();
398
const gchar *object_names[] = {
399
"almanah_ird_view_store",
400
"almanah_ird_results_store",
401
"almanah_ird_filtered_results_store",
402
"almanah_import_results_dialog",
406
builder = gtk_builder_new ();
408
if (gtk_builder_add_objects_from_file (builder, interface_filename, (gchar**) object_names, &error) == FALSE) {
410
GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
411
_("UI file \"%s\" could not be loaded"), interface_filename);
412
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
413
gtk_dialog_run (GTK_DIALOG (dialog));
414
gtk_widget_destroy (dialog);
416
g_error_free (error);
417
g_object_unref (builder);
422
gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
423
results_dialog = ALMANAH_IMPORT_RESULTS_DIALOG (gtk_builder_get_object (builder, "almanah_import_results_dialog"));
424
gtk_builder_connect_signals (builder, results_dialog);
426
if (results_dialog == NULL) {
427
g_object_unref (builder);
431
priv = results_dialog->priv;
433
/* Grab our child widgets */
434
priv->results_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "almanah_ird_results_store"));
435
priv->results_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gtk_builder_get_object (builder, "almanah_ird_results_tree_view")));
436
priv->filtered_results_store = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "almanah_ird_filtered_results_store"));
437
priv->view_combo_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "almanah_ird_view_combo_box"));
439
g_signal_connect (priv->results_selection, "changed", G_CALLBACK (results_selection_changed_cb),
440
gtk_builder_get_object (builder, "almanah_ird_view_button"));
442
/* Set up the tree filter */
443
gtk_tree_model_filter_set_visible_func (priv->filtered_results_store, (GtkTreeModelFilterVisibleFunc) filter_results_cb,
444
results_dialog, NULL);
446
/* Set up the combo box */
447
gtk_combo_box_set_active (priv->view_combo_box, ALMANAH_IMPORT_STATUS_MERGED);
449
g_object_unref (builder);
451
return results_dialog;
455
filter_results_cb (GtkTreeModel *model, GtkTreeIter *iter, AlmanahImportResultsDialog *self)
459
/* Compare the current mode to the row's status column */
460
gtk_tree_model_get (model, iter, 4, &status, -1);
462
return (self->priv->current_mode == status) ? TRUE : FALSE;
466
results_selection_changed_cb (GtkTreeSelection *tree_selection, GtkWidget *button)
468
gtk_widget_set_sensitive (button, gtk_tree_selection_count_selected_rows (tree_selection) == 0 ? FALSE : TRUE);
472
almanah_import_results_dialog_add_result (AlmanahImportResultsDialog *self, const GDate *date, AlmanahImportStatus status, const gchar *message)
475
gchar formatted_date[100];
477
/* Translators: This is a strftime()-format string for the dates displayed in import results. */
478
g_date_strftime (formatted_date, sizeof (formatted_date), _("%A, %e %B %Y"), date);
480
gtk_list_store_append (self->priv->results_store, &iter);
481
gtk_list_store_set (self->priv->results_store, &iter,
482
0, g_date_get_day (date),
483
1, g_date_get_month (date),
484
2, g_date_get_year (date),
492
select_date (GtkTreeModel *model, GtkTreeIter *iter)
494
guint day, month, year;
497
gtk_tree_model_get (model, iter,
503
g_date_set_dmy (&date, day, month, year);
504
almanah_main_window_select_date (ALMANAH_MAIN_WINDOW (almanah->main_window), &date);
508
ird_results_tree_view_row_activated_cb (GtkTreeView *self, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
513
model = gtk_tree_view_get_model (self);
514
gtk_tree_model_get_iter (model, &iter, path);
515
select_date (model, &iter);
519
ird_view_button_clicked_cb (GtkButton *button, AlmanahImportResultsDialog *self)
524
if (gtk_tree_selection_get_selected (self->priv->results_selection, &model, &iter) == TRUE)
525
select_date (model, &iter);
529
ird_view_combo_box_changed_cb (GtkComboBox *combo_box, AlmanahImportResultsDialog *self)
532
AlmanahImportResultsDialogPrivate *priv = self->priv;
534
new_mode = gtk_combo_box_get_active (combo_box);
535
if (new_mode == -1 || new_mode == (gint) priv->current_mode)
538
priv->current_mode = new_mode;
539
gtk_tree_model_filter_refilter (self->priv->filtered_results_store);