blob: 36ae2ea0ec8b8050f91ad2754a58a42296a39855 [file] [log] [blame]
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -04001/*
Guillaume Roguez2a6150d2017-07-19 18:24:47 -04002 * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -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.
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -040018 */
19
20#include "editcontactview.h"
21
Stepan Salenikovicha1b8cb32015-09-11 14:58:35 -040022#include <glib/gi18n.h>
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -040023#include <contactmethod.h>
24#include <personmodel.h>
25#include <numbercategorymodel.h>
26#include "utils/models.h"
Sébastien Blinf3681aa2017-07-19 16:53:49 -040027#include "utils/accounts.h"
28
29// LRC
30#include <account.h>
31
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -040032
33enum
34{
35 PERSON_SAVED,
36
37 LAST_SIGNAL
38};
39
40struct _EditContactView
41{
42 GtkGrid parent;
43};
44
45struct _EditContactViewClass
46{
47 GtkGridClass parent_class;
48};
49
50typedef struct _EditContactViewPrivate EditContactViewPrivate;
51
52struct _EditContactViewPrivate
53{
54 GtkWidget *button_save;
55 GtkWidget *combobox_addressbook;
56 GtkWidget *entry_name;
57 GtkWidget *combobox_detail;
58 GtkWidget *label_uri;
59
60 ContactMethod *cm;
61 Person *person;
62};
63
64static guint edit_contact_signals[LAST_SIGNAL] = { 0 };
65
66G_DEFINE_TYPE_WITH_PRIVATE(EditContactView, edit_contact_view, GTK_TYPE_GRID);
67
68#define EDIT_CONTACT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EDIT_CONTACT_VIEW_TYPE, EditContactViewPrivate))
69
70static void
71save_cb(EditContactView *self)
72{
73 g_return_if_fail(IS_EDIT_CONTACT_VIEW(self));
74 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
75
76 auto name = gtk_entry_get_text(GTK_ENTRY(priv->entry_name));
77 if (!priv->person) {
78 /* make sure that the entry is not empty */
79 if (!name or strlen(name) == 0) {
80 g_warning("new contact must have a name");
81 gtk_widget_grab_focus(priv->entry_name);
82 return;
83 }
84 }
85
86 /* get the selected number category */
87 const auto& idx = gtk_combo_box_get_index(GTK_COMBO_BOX(priv->combobox_detail));
88 if (idx.isValid()) {
Guillaume Roguez5d1514b2015-10-22 15:55:31 -040089 auto category = NumberCategoryModel::instance().getCategory(idx.data().toString());
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -040090 priv->cm->setCategory(category);
91 }
92
93 if (!priv->person) {
94 /* get the selected collection */
95 GtkTreeIter iter;
96 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->combobox_addressbook), &iter);
97 auto addressbook_model = gtk_combo_box_get_model(GTK_COMBO_BOX(priv->combobox_addressbook));
98 GValue value = G_VALUE_INIT;
99 gtk_tree_model_get_value(addressbook_model, &iter, 1, &value);
100 auto collection = (CollectionInterface *)g_value_get_pointer(&value);
101
102 /* create a new person */
103 priv->person = new Person(collection);
104 priv->person->setFormattedName(name);
105
106 /* associate the new person with the contact method */
107 Person::ContactMethods numbers;
108 numbers << priv->cm;
109 priv->person->setContactMethods(numbers);
110
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400111 PersonModel::instance().addNewPerson(priv->person, collection);
Sébastien Blinf3681aa2017-07-19 16:53:49 -0400112
113 // Send a request to the new contact
114 auto account = priv->cm->account();
115 if (not account) {
116
117 // get the choosen account
118 account = get_active_ring_account();
119
120 if (not account) {
121 g_warning("invalid account, cannot send invitation!");
122 g_signal_emit(self, edit_contact_signals[PERSON_SAVED], 0);
123 return;
124 }
125 }
126
127 // perform the request
128 if (not account->sendContactRequest(priv->cm))
129 g_warning("contact request not forwarded, cannot send invitation!");
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400130 } else {
131 auto numbers = priv->person->phoneNumbers();
132 numbers << priv->cm;
133 priv->person->setContactMethods(numbers);
134 priv->person->save();
135 }
136
137 g_signal_emit(self, edit_contact_signals[PERSON_SAVED], 0);
138}
139
140static void
141name_changed(GtkEntry *entry_name, EditContactView *self)
142{
143 g_return_if_fail(IS_EDIT_CONTACT_VIEW(self));
144 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
145
146 auto name = gtk_entry_get_text(entry_name);
147 /* make sure that the entry is not empty */
148 if (!name or strlen(name) == 0) {
149 gtk_widget_set_sensitive(priv->button_save, FALSE);
150 } else {
151 gtk_widget_set_sensitive(priv->button_save, TRUE);
152 }
153}
154
155static void
156edit_contact_view_init(EditContactView *self)
157{
158 gtk_widget_init_template(GTK_WIDGET(self));
159
160 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
161
162 /* model for the combobox for the choice of addressbooks */
163 auto addressbook_model = gtk_list_store_new(
164 2, G_TYPE_STRING, G_TYPE_POINTER
165 );
166
167 gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_addressbook),
168 GTK_TREE_MODEL(addressbook_model));
169 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
170 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_addressbook),
171 renderer, FALSE);
172 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(priv->combobox_addressbook),
173 renderer, "text", 0, NULL);
174
175 /* get all the available contact backends (addressbooks) */
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400176 const auto& collections = PersonModel::instance().enabledCollections();
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400177 for (int i = 0; i < collections.size(); ++i) {
178 GtkTreeIter iter;
179 gtk_list_store_append(addressbook_model, &iter);
180 gtk_list_store_set(addressbook_model, &iter,
181 0, collections.at(i)->name().toUtf8().constData(),
182 1, collections.at(i),
183 -1);
184 }
185
186 /* set the first addressbook which is not the "vCard" to be used, unless its
187 * the only one */
188 GtkTreeIter iter_to_select;
189 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(addressbook_model), &iter_to_select)) {
190 GValue value = G_VALUE_INIT;
191 gtk_tree_model_get_value(GTK_TREE_MODEL(addressbook_model), &iter_to_select, 1, &value);
192 auto collection = (CollectionInterface *)g_value_get_pointer(&value);
193 GtkTreeIter iter = iter_to_select;
194 while ( (collection->name() == "vCard") && gtk_tree_model_iter_next(GTK_TREE_MODEL(addressbook_model), &iter)) {
195 iter_to_select = iter;
196 value = G_VALUE_INIT;
197 gtk_tree_model_get_value(GTK_TREE_MODEL(addressbook_model), &iter, 1, &value);
198 collection = (CollectionInterface *)g_value_get_pointer(&value);
199 }
200 }
201 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(priv->combobox_addressbook), &iter_to_select);
202
203 /* model for the available details to choose from */
Stepan Salenikovich4c31b212017-04-26 13:45:12 -0400204 gtk_combo_box_set_qmodel_text(GTK_COMBO_BOX(priv->combobox_detail),
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400205 (QAbstractItemModel *)&NumberCategoryModel::instance(), NULL);
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400206
207 /* set "home" as the default number category */
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400208 const auto& idx = NumberCategoryModel::instance().nameToIndex(C_("Phone number category", "home"));
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400209 if (idx.isValid())
210 gtk_combo_box_set_active_index(GTK_COMBO_BOX(priv->combobox_detail), idx);
211
212 /* disable save button until name is entered */
213 gtk_widget_set_sensitive(priv->button_save, FALSE);
214
215 /* connect to the button signals */
216 g_signal_connect_swapped(priv->button_save, "clicked", G_CALLBACK(save_cb), self);
217 g_signal_connect(priv->entry_name, "changed", G_CALLBACK(name_changed), self);
218}
219
220static void
221edit_contact_view_dispose(GObject *object)
222{
223 G_OBJECT_CLASS(edit_contact_view_parent_class)->dispose(object);
224}
225
226static void
227edit_contact_view_finalize(GObject *object)
228{
229 G_OBJECT_CLASS(edit_contact_view_parent_class)->finalize(object);
230}
231
232static void
233edit_contact_view_class_init(EditContactViewClass *klass)
234{
235 G_OBJECT_CLASS(klass)->finalize = edit_contact_view_finalize;
236 G_OBJECT_CLASS(klass)->dispose = edit_contact_view_dispose;
237
238 edit_contact_signals[PERSON_SAVED] =
239 g_signal_new("person-saved",
240 G_OBJECT_CLASS_TYPE(G_OBJECT_CLASS(klass)),
241 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
242 0, /* class offset */
243 NULL, /* accumulater */
244 NULL, /* accu data */
245 g_cclosure_marshal_VOID__VOID,
246 G_TYPE_NONE, 0);
247
248 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(klass),
249 "/cx/ring/RingGnome/editcontactview.ui");
250
251 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, button_save);
252 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, combobox_addressbook);
253 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, entry_name);
254 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, combobox_detail);
255 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, label_uri);
256}
257
258/**
259 * If a Person is specified, a view to edit the given Person will be created;
260 * if no Person is given (NULL), then a new Person object will be created when
261 * 'save' is clicked
262 */
263GtkWidget *
264edit_contact_view_new(ContactMethod *cm, Person *p)
265{
266 g_return_val_if_fail(cm, NULL);
267
268 gpointer self = g_object_new(EDIT_CONTACT_VIEW_TYPE, NULL);
269
270 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
271
272 priv->cm = cm;
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400273 auto uri_escaped = g_markup_printf_escaped("<b>%s</b>", cm->uri().toUtf8().constData());
274 gtk_label_set_markup(GTK_LABEL(priv->label_uri), uri_escaped);
275 g_free(uri_escaped);
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400276
Stepan Salenikoviche371bd12015-09-09 15:45:11 -0400277 /* use the primaryName as the suggested name (usually the display name), unless it is the same
278 * as the uri */
279 if (cm->primaryName() != cm->uri())
280 gtk_entry_set_text(GTK_ENTRY(priv->entry_name), cm->primaryName().toUtf8().constData());
281
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400282 if (p) {
283 priv->person = p;
284
285 /* select the proper addressbook and prevent it from being modified */
286 if (p->collection() != NULL) {
287 auto model = gtk_combo_box_get_model(GTK_COMBO_BOX(priv->combobox_addressbook));
288 GtkTreeIter iter;
289 if (gtk_tree_model_get_iter_first(model, &iter)) {
290 GValue value = G_VALUE_INIT;
291 gtk_tree_model_get_value(model, &iter, 1, &value);
292 auto collection = (CollectionInterface *)g_value_get_pointer(&value);
293 while (collection != p->collection() && gtk_tree_model_iter_next(model, &iter)) {
294 value = G_VALUE_INIT;
295 gtk_tree_model_get_value(model, &iter, 1, &value);
296 collection = (CollectionInterface *)g_value_get_pointer(&value);
297 }
298 }
299
300 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(priv->combobox_addressbook), &iter);
301 }
302 gtk_widget_set_sensitive(priv->combobox_addressbook, FALSE);
303
304 /* set the name of the person, and prevent it from being edited */
305 gtk_entry_set_text(GTK_ENTRY(priv->entry_name), p->formattedName().toUtf8().constData());
306 g_object_set(G_OBJECT(priv->entry_name), "editable", FALSE, NULL);
307 }
308
309 return (GtkWidget *)self;
310}