blob: 42dbe0a24a4ae4f204e2b9700d3e50bea15ce84c [file] [log] [blame]
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -04001/*
Guillaume Roguez2a6150d2017-07-19 18:24:47 -04002 * Copyright (C) 2016-2017 Savoir-faire Linux Inc.
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -04003 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include "accountimportexportview.h"
21
22#include <gtk/gtk.h>
23#include <account.h>
24#include <accountmodel.h>
25
26#include <glib/gi18n.h>
27
28struct _AccountImportExportView
29{
30 GtkBox parent;
31};
32
33struct _AccountImportExportViewClass
34{
35 GtkBoxClass parent_class;
36};
37
38typedef struct _AccountImportExportViewPrivate AccountImportExportViewPrivate;
39
40struct _AccountImportExportViewPrivate
41{
42 Account *account;
43
44 GtkWidget *label_export;
45 GtkWidget *label_import;
46 GtkWidget *hbox_export_location;
47 GtkWidget *label_export_location;
48 GtkWidget *button_export_location;
49 GtkWidget *filechooserbutton_import;
50 GtkWidget *button_export;
51 GtkWidget *button_import;
52 GtkWidget *button_cancel;
53 GtkWidget *entry_password;
54 GtkWidget *label_error;
55
56 GList *export_accounts_list;
57};
58
59G_DEFINE_TYPE_WITH_PRIVATE(AccountImportExportView, account_importexport_view, GTK_TYPE_BOX);
60
61#define ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_IMPORTEXPORT_VIEW_TYPE, AccountImportExportViewPrivate))
62
63/* signals */
64enum {
65 IMPORT_EXPORT_CANCELED,
66 IMPORT_EXPORT_COMPLETED,
67 LAST_SIGNAL
68};
69
70static guint account_importexport_view_signals[LAST_SIGNAL] = { 0 };
71
72static void
73account_importexport_view_dispose(GObject *object)
74{
75 G_OBJECT_CLASS(account_importexport_view_parent_class)->dispose(object);
76}
77
78static void
79account_importexport_view_finalize(GObject *object)
80{
81 AccountImportExportView *view = ACCOUNT_IMPORTEXPORT_VIEW(object);
82 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(view);
83
84 if (priv->export_accounts_list)
85 g_list_free(priv->export_accounts_list);
86
87 G_OBJECT_CLASS(account_importexport_view_parent_class)->finalize(object);
88}
89
90static void
91choose_export_location(AccountImportExportView *self)
92{
93 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
94
95 // clear any existing error
96 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
97
98 // create filechooser dialog and get export location
99 auto dialog = gtk_file_chooser_dialog_new(_("Select account export location"),
100 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))),
101 GTK_FILE_CHOOSER_ACTION_SAVE,
102 _("Cancel"),
103 GTK_RESPONSE_CANCEL,
104 _("Select"),
105 GTK_RESPONSE_ACCEPT,
106 NULL);
107
108 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
109 gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog), TRUE);
110
111 if (!priv->export_accounts_list->next) {
112 auto name = g_strconcat(static_cast<Account *>(priv->export_accounts_list->data)->alias().toUtf8().constData(), ".ring", NULL);
113 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), name);
114 g_free(name);
115 } else {
116 // TODO: handle multiple account export
117 }
118
119 /* start the file chooser */
120 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
121 if (auto filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog))) {
122 gtk_label_set_text(GTK_LABEL(priv->label_export_location), filename);
123
124 // if accounts and password are set then we're ready for export
125 auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
AmarOka85c1f82017-09-15 13:31:09 -0400126 if (priv->export_accounts_list && priv->export_accounts_list->data) {
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400127 gtk_widget_set_sensitive(priv->button_export, TRUE);
128 }
129 g_free (filename);
130 }
131 }
132
133 gtk_widget_destroy (dialog);
134}
135
136
137static void
138import_file_set(AccountImportExportView *self)
139{
140 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
141
142 // clear any existing error
143 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
144
AmarOka85c1f82017-09-15 13:31:09 -0400145 gtk_widget_set_sensitive(priv->button_import, TRUE);
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400146}
147
148static void
149password_changed(AccountImportExportView *self)
150{
151 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
152
153 // clear any existing error
154 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
155
AmarOka85c1f82017-09-15 13:31:09 -0400156 // import
157 if (auto filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_import))) {
158 gtk_widget_set_sensitive(priv->button_import, TRUE);
159 g_free(filename);
160 }
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400161
AmarOka85c1f82017-09-15 13:31:09 -0400162 // export
163 const auto filename = gtk_label_get_text(GTK_LABEL(priv->label_export_location));
164 if (strlen(filename) > 0
165 && priv->export_accounts_list
166 && priv->export_accounts_list->data) {
167 gtk_widget_set_sensitive(priv->button_export, TRUE);
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400168 }
169}
170
171static void
172cancel_clicked(AccountImportExportView *self)
173{
174 g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_CANCELED], 0);
175}
176
177static void
178import_account(AccountImportExportView *self)
179{
180 g_return_if_fail(IS_ACCOUNT_IMPORTEXPORT_VIEW(self));
181
182 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
183
184 // clear any existing error
185 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
186
187 if (auto filepath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_import))) {
188 const auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
AmarOka85c1f82017-09-15 13:31:09 -0400189
190 auto ret = AccountModel::instance().importAccounts(filepath, password);
191 switch(ret) {
192 case 0:
193 // done
194 g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_COMPLETED], 0);
195 break;
196 default:
197 //failed
198 gtk_label_set_text(GTK_LABEL(priv->label_error), _("Error importing account(s)"));
199 g_warning("failed to import account(s), err: %d", ret);
200 break;
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400201 }
202 g_free(filepath);
203 } else {
204 g_warning("no file selected for account import");
205 }
206}
207
208static void
209export_account(AccountImportExportView *self)
210{
211 g_return_if_fail(IS_ACCOUNT_IMPORTEXPORT_VIEW(self));
212
213 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
214
215 // clear any existing error
216 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
217
218 // check that we have some accounts to export
219 if ( !(priv->export_accounts_list && priv->export_accounts_list->data)) {
220 g_warning("no accounts are selected for export");
221 return;
222 }
223
224 const auto filepath = gtk_label_get_text(GTK_LABEL(priv->label_export_location));
225 // validate filepath
226 if (strlen(filepath)) {
227 const auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
AmarOka85c1f82017-09-15 13:31:09 -0400228 // get account id strings
229 auto account_ids = QStringList();
230 auto list = priv->export_accounts_list;
231 while (list != nullptr) {
232 auto account = static_cast<Account *>(list->data);
233 account_ids << account->id();
234 list = g_list_next(list);
235 }
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400236
AmarOka85c1f82017-09-15 13:31:09 -0400237 auto ret = AccountModel::instance().exportAccounts(account_ids, filepath, password);
238 switch (ret) {
239 case 0:
240 // done
241 g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_COMPLETED], 0);
242 break;
243 default:
244 //failed
245 gtk_label_set_text(GTK_LABEL(priv->label_error), _("Error exporting account(s)"));
246 g_warning("failed to export account(s), err: %d", ret);
247 break;
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -0400248 }
249 } else {
250 g_warning("no file selected for account export");
251 }
252}
253
254static void
255account_importexport_view_init(AccountImportExportView *self)
256{
257 gtk_widget_init_template(GTK_WIDGET(self));
258
259 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
260
261 g_signal_connect_swapped(priv->button_export_location, "clicked", G_CALLBACK(choose_export_location), self);
262 g_signal_connect_swapped(priv->filechooserbutton_import, "file-set", G_CALLBACK(import_file_set), self);
263 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(password_changed), self);
264 g_signal_connect_swapped(priv->button_cancel, "clicked", G_CALLBACK(cancel_clicked), self);
265 g_signal_connect_swapped(priv->button_import, "clicked", G_CALLBACK(import_account), self);
266 g_signal_connect_swapped(priv->button_export, "clicked", G_CALLBACK(export_account), self);
267}
268
269static void
270account_importexport_view_class_init(AccountImportExportViewClass *klass)
271{
272 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
273
274 gobject_class->dispose = account_importexport_view_dispose;
275 gobject_class->finalize = account_importexport_view_finalize;
276
277 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
278 "/cx/ring/RingGnome/accountimportexportview.ui");
279
280 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_export);
281 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_import);
282 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, hbox_export_location);
283 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_export_location);
284 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_export_location);
285 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, filechooserbutton_import);
286 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_export);
287 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_import);
288 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_cancel);
289 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, entry_password);
290 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_error);
291
292 /* add signals */
293 account_importexport_view_signals[IMPORT_EXPORT_CANCELED] = g_signal_new("import-export-canceled",
294 G_TYPE_FROM_CLASS(klass),
295 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
296 0,
297 nullptr,
298 nullptr,
299 g_cclosure_marshal_VOID__VOID,
300 G_TYPE_NONE, 0);
301
302 account_importexport_view_signals[IMPORT_EXPORT_COMPLETED] = g_signal_new("import-export-completed",
303 G_TYPE_FROM_CLASS(klass),
304 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
305 0,
306 nullptr,
307 nullptr,
308 g_cclosure_marshal_VOID__VOID,
309 G_TYPE_NONE, 0);
310}
311
312static void
313build_import_view(AccountImportExportView *self)
314{
315 g_return_if_fail(self);
316
317 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
318
319 gtk_widget_hide(priv->label_export);
320 gtk_widget_hide(priv->hbox_export_location);
321 gtk_widget_hide(priv->button_export);
322
323 gtk_widget_show(priv->label_import);
324 gtk_widget_show(priv->filechooserbutton_import);
325 gtk_widget_show(priv->button_import);
326}
327
328static void
329build_export_view(AccountImportExportView *self)
330{
331 g_return_if_fail(self);
332
333 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
334
335 gtk_widget_show(priv->label_export);
336 gtk_widget_show(priv->hbox_export_location);
337 gtk_widget_show(priv->button_export);
338
339 gtk_widget_hide(priv->label_import);
340 gtk_widget_hide(priv->filechooserbutton_import);
341 gtk_widget_hide(priv->button_import);
342}
343
344GtkWidget *
345account_import_view_new()
346{
347 gpointer view = g_object_new(ACCOUNT_IMPORTEXPORT_VIEW_TYPE, NULL);
348
349 build_import_view(ACCOUNT_IMPORTEXPORT_VIEW(view));
350
351 return (GtkWidget *)view;
352}
353
354GtkWidget *
355account_export_view_new()
356{
357 gpointer view = g_object_new(ACCOUNT_IMPORTEXPORT_VIEW_TYPE, NULL);
358
359 build_export_view(ACCOUNT_IMPORTEXPORT_VIEW(view));
360
361 return (GtkWidget *)view;
362}
363
364void
365account_export_view_set_accounts(AccountImportExportView *self, GList *accounts)
366{
367 g_return_if_fail(self);
368 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
369
370 // replace current list
371 if (priv->export_accounts_list) {
372 g_list_free(priv->export_accounts_list);
373 priv->export_accounts_list = nullptr;
374 }
375
376 // make sure the new list isn't empty
377 if (accounts && accounts->data) {
378 priv->export_accounts_list = g_list_copy(accounts);
379
380 if (!accounts->next) {
381 auto location = g_strconcat(g_get_home_dir(), "/", static_cast<Account *>(priv->export_accounts_list->data)->alias().toUtf8().constData(), ".ring", NULL);
382 gtk_label_set_text(GTK_LABEL(priv->label_export_location), location);
383 g_free(location);
384 } else {
385 // TODO: handle multiple account export
386 }
387 } else {
388 // no accounts are selected... this case should not normally be ever displayed
389 }
390}