blob: 2523e53869175c17f8f20235b4a58a00ee0b198f [file] [log] [blame]
Stepan Salenikovichbdb0ecd2016-05-18 13:30:55 -04001/*
2 * Copyright (C) 2016 Savoir-faire Linux Inc.
3 * 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));
126 if (priv->export_accounts_list && priv->export_accounts_list->data && strlen(password) > 0) {
127 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
145 // if password is set then we're ready for import
146 auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
147 if (strlen(password) > 0) {
148 gtk_widget_set_sensitive(priv->button_import, TRUE);
149 }
150}
151
152static void
153password_changed(AccountImportExportView *self)
154{
155 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
156
157 // clear any existing error
158 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
159
160 // if the password and other requirements are met then enable import/export
161 auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
162 if (strlen(password) > 0) {
163
164 // import
165 if (auto filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_import))) {
166 gtk_widget_set_sensitive(priv->button_import, TRUE);
167 g_free(filename);
168 }
169
170 // export
171 const auto filename = gtk_label_get_text(GTK_LABEL(priv->label_export_location));
172 if (strlen(filename) > 0) {
173 if (priv->export_accounts_list && priv->export_accounts_list->data) {
174 gtk_widget_set_sensitive(priv->button_export, TRUE);
175 }
176 }
177
178 } else {
179 gtk_widget_set_sensitive(priv->button_export, FALSE);
180 gtk_widget_set_sensitive(priv->button_import, FALSE);
181 }
182}
183
184static void
185cancel_clicked(AccountImportExportView *self)
186{
187 g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_CANCELED], 0);
188}
189
190static void
191import_account(AccountImportExportView *self)
192{
193 g_return_if_fail(IS_ACCOUNT_IMPORTEXPORT_VIEW(self));
194
195 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
196
197 // clear any existing error
198 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
199
200 if (auto filepath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_import))) {
201 const auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
202 if (strlen(password) > 0) {
203 auto ret = AccountModel::instance().importAccounts(filepath, password);
204 switch(ret) {
205 case 0:
206 // done
207 g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_COMPLETED], 0);
208 break;
209 default:
210 //failed
211 gtk_label_set_text(GTK_LABEL(priv->label_error), _("Error importing account(s)"));
212 g_warning("failed to import account(s), err: %d", ret);
213 break;
214 }
215 } else {
216 g_warning("no password set for account import");
217 }
218 g_free(filepath);
219 } else {
220 g_warning("no file selected for account import");
221 }
222}
223
224static void
225export_account(AccountImportExportView *self)
226{
227 g_return_if_fail(IS_ACCOUNT_IMPORTEXPORT_VIEW(self));
228
229 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
230
231 // clear any existing error
232 gtk_label_set_text(GTK_LABEL(priv->label_error), "");
233
234 // check that we have some accounts to export
235 if ( !(priv->export_accounts_list && priv->export_accounts_list->data)) {
236 g_warning("no accounts are selected for export");
237 return;
238 }
239
240 const auto filepath = gtk_label_get_text(GTK_LABEL(priv->label_export_location));
241 // validate filepath
242 if (strlen(filepath)) {
243 const auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
244 if (strlen(password) > 0) {
245
246 // get account id strings
247 auto account_ids = QStringList();
248 auto list = priv->export_accounts_list;
249 while (list != nullptr) {
250 auto account = static_cast<Account *>(list->data);
251 account_ids << account->id();
252 list = g_list_next(list);
253 }
254
255 auto ret = AccountModel::instance().exportAccounts(account_ids, filepath, password);
256 switch (ret) {
257 case 0:
258 // done
259 g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_COMPLETED], 0);
260 break;
261 default:
262 //failed
263 gtk_label_set_text(GTK_LABEL(priv->label_error), _("Error exporting account(s)"));
264 g_warning("failed to export account(s), err: %d", ret);
265 break;
266 }
267 } else {
268 g_warning("no password set for account export");
269 }
270 } else {
271 g_warning("no file selected for account export");
272 }
273}
274
275static void
276account_importexport_view_init(AccountImportExportView *self)
277{
278 gtk_widget_init_template(GTK_WIDGET(self));
279
280 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
281
282 g_signal_connect_swapped(priv->button_export_location, "clicked", G_CALLBACK(choose_export_location), self);
283 g_signal_connect_swapped(priv->filechooserbutton_import, "file-set", G_CALLBACK(import_file_set), self);
284 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(password_changed), self);
285 g_signal_connect_swapped(priv->button_cancel, "clicked", G_CALLBACK(cancel_clicked), self);
286 g_signal_connect_swapped(priv->button_import, "clicked", G_CALLBACK(import_account), self);
287 g_signal_connect_swapped(priv->button_export, "clicked", G_CALLBACK(export_account), self);
288}
289
290static void
291account_importexport_view_class_init(AccountImportExportViewClass *klass)
292{
293 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
294
295 gobject_class->dispose = account_importexport_view_dispose;
296 gobject_class->finalize = account_importexport_view_finalize;
297
298 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
299 "/cx/ring/RingGnome/accountimportexportview.ui");
300
301 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_export);
302 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_import);
303 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, hbox_export_location);
304 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_export_location);
305 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_export_location);
306 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, filechooserbutton_import);
307 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_export);
308 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_import);
309 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_cancel);
310 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, entry_password);
311 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_error);
312
313 /* add signals */
314 account_importexport_view_signals[IMPORT_EXPORT_CANCELED] = g_signal_new("import-export-canceled",
315 G_TYPE_FROM_CLASS(klass),
316 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
317 0,
318 nullptr,
319 nullptr,
320 g_cclosure_marshal_VOID__VOID,
321 G_TYPE_NONE, 0);
322
323 account_importexport_view_signals[IMPORT_EXPORT_COMPLETED] = g_signal_new("import-export-completed",
324 G_TYPE_FROM_CLASS(klass),
325 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
326 0,
327 nullptr,
328 nullptr,
329 g_cclosure_marshal_VOID__VOID,
330 G_TYPE_NONE, 0);
331}
332
333static void
334build_import_view(AccountImportExportView *self)
335{
336 g_return_if_fail(self);
337
338 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
339
340 gtk_widget_hide(priv->label_export);
341 gtk_widget_hide(priv->hbox_export_location);
342 gtk_widget_hide(priv->button_export);
343
344 gtk_widget_show(priv->label_import);
345 gtk_widget_show(priv->filechooserbutton_import);
346 gtk_widget_show(priv->button_import);
347}
348
349static void
350build_export_view(AccountImportExportView *self)
351{
352 g_return_if_fail(self);
353
354 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
355
356 gtk_widget_show(priv->label_export);
357 gtk_widget_show(priv->hbox_export_location);
358 gtk_widget_show(priv->button_export);
359
360 gtk_widget_hide(priv->label_import);
361 gtk_widget_hide(priv->filechooserbutton_import);
362 gtk_widget_hide(priv->button_import);
363}
364
365GtkWidget *
366account_import_view_new()
367{
368 gpointer view = g_object_new(ACCOUNT_IMPORTEXPORT_VIEW_TYPE, NULL);
369
370 build_import_view(ACCOUNT_IMPORTEXPORT_VIEW(view));
371
372 return (GtkWidget *)view;
373}
374
375GtkWidget *
376account_export_view_new()
377{
378 gpointer view = g_object_new(ACCOUNT_IMPORTEXPORT_VIEW_TYPE, NULL);
379
380 build_export_view(ACCOUNT_IMPORTEXPORT_VIEW(view));
381
382 return (GtkWidget *)view;
383}
384
385void
386account_export_view_set_accounts(AccountImportExportView *self, GList *accounts)
387{
388 g_return_if_fail(self);
389 AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
390
391 // replace current list
392 if (priv->export_accounts_list) {
393 g_list_free(priv->export_accounts_list);
394 priv->export_accounts_list = nullptr;
395 }
396
397 // make sure the new list isn't empty
398 if (accounts && accounts->data) {
399 priv->export_accounts_list = g_list_copy(accounts);
400
401 if (!accounts->next) {
402 auto location = g_strconcat(g_get_home_dir(), "/", static_cast<Account *>(priv->export_accounts_list->data)->alias().toUtf8().constData(), ".ring", NULL);
403 gtk_label_set_text(GTK_LABEL(priv->label_export_location), location);
404 g_free(location);
405 } else {
406 // TODO: handle multiple account export
407 }
408 } else {
409 // no accounts are selected... this case should not normally be ever displayed
410 }
411}