blob: 64a43fd577cd58da3c7979a8b49a08b98b2ac5a5 [file] [log] [blame]
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -04001/*
Stepan Salenikovichbe87d2c2016-01-25 14:14:34 -05002 * Copyright (C) 2015-2016 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"
27
28enum
29{
30 PERSON_SAVED,
31
32 LAST_SIGNAL
33};
34
35struct _EditContactView
36{
37 GtkGrid parent;
38};
39
40struct _EditContactViewClass
41{
42 GtkGridClass parent_class;
43};
44
45typedef struct _EditContactViewPrivate EditContactViewPrivate;
46
47struct _EditContactViewPrivate
48{
49 GtkWidget *button_save;
50 GtkWidget *combobox_addressbook;
51 GtkWidget *entry_name;
52 GtkWidget *combobox_detail;
53 GtkWidget *label_uri;
54
55 ContactMethod *cm;
56 Person *person;
57};
58
59static guint edit_contact_signals[LAST_SIGNAL] = { 0 };
60
61G_DEFINE_TYPE_WITH_PRIVATE(EditContactView, edit_contact_view, GTK_TYPE_GRID);
62
63#define EDIT_CONTACT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EDIT_CONTACT_VIEW_TYPE, EditContactViewPrivate))
64
65static void
66save_cb(EditContactView *self)
67{
68 g_return_if_fail(IS_EDIT_CONTACT_VIEW(self));
69 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
70
71 auto name = gtk_entry_get_text(GTK_ENTRY(priv->entry_name));
72 if (!priv->person) {
73 /* make sure that the entry is not empty */
74 if (!name or strlen(name) == 0) {
75 g_warning("new contact must have a name");
76 gtk_widget_grab_focus(priv->entry_name);
77 return;
78 }
79 }
80
81 /* get the selected number category */
82 const auto& idx = gtk_combo_box_get_index(GTK_COMBO_BOX(priv->combobox_detail));
83 if (idx.isValid()) {
Guillaume Roguez5d1514b2015-10-22 15:55:31 -040084 auto category = NumberCategoryModel::instance().getCategory(idx.data().toString());
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -040085 priv->cm->setCategory(category);
86 }
87
88 if (!priv->person) {
89 /* get the selected collection */
90 GtkTreeIter iter;
91 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->combobox_addressbook), &iter);
92 auto addressbook_model = gtk_combo_box_get_model(GTK_COMBO_BOX(priv->combobox_addressbook));
93 GValue value = G_VALUE_INIT;
94 gtk_tree_model_get_value(addressbook_model, &iter, 1, &value);
95 auto collection = (CollectionInterface *)g_value_get_pointer(&value);
96
97 /* create a new person */
98 priv->person = new Person(collection);
99 priv->person->setFormattedName(name);
100
101 /* associate the new person with the contact method */
102 Person::ContactMethods numbers;
103 numbers << priv->cm;
104 priv->person->setContactMethods(numbers);
105
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400106 PersonModel::instance().addNewPerson(priv->person, collection);
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400107 } else {
108 auto numbers = priv->person->phoneNumbers();
109 numbers << priv->cm;
110 priv->person->setContactMethods(numbers);
111 priv->person->save();
112 }
113
114 g_signal_emit(self, edit_contact_signals[PERSON_SAVED], 0);
115}
116
117static void
118name_changed(GtkEntry *entry_name, EditContactView *self)
119{
120 g_return_if_fail(IS_EDIT_CONTACT_VIEW(self));
121 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
122
123 auto name = gtk_entry_get_text(entry_name);
124 /* make sure that the entry is not empty */
125 if (!name or strlen(name) == 0) {
126 gtk_widget_set_sensitive(priv->button_save, FALSE);
127 } else {
128 gtk_widget_set_sensitive(priv->button_save, TRUE);
129 }
130}
131
132static void
133edit_contact_view_init(EditContactView *self)
134{
135 gtk_widget_init_template(GTK_WIDGET(self));
136
137 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
138
139 /* model for the combobox for the choice of addressbooks */
140 auto addressbook_model = gtk_list_store_new(
141 2, G_TYPE_STRING, G_TYPE_POINTER
142 );
143
144 gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_addressbook),
145 GTK_TREE_MODEL(addressbook_model));
146 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
147 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_addressbook),
148 renderer, FALSE);
149 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(priv->combobox_addressbook),
150 renderer, "text", 0, NULL);
151
152 /* get all the available contact backends (addressbooks) */
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400153 const auto& collections = PersonModel::instance().enabledCollections();
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400154 for (int i = 0; i < collections.size(); ++i) {
155 GtkTreeIter iter;
156 gtk_list_store_append(addressbook_model, &iter);
157 gtk_list_store_set(addressbook_model, &iter,
158 0, collections.at(i)->name().toUtf8().constData(),
159 1, collections.at(i),
160 -1);
161 }
162
163 /* set the first addressbook which is not the "vCard" to be used, unless its
164 * the only one */
165 GtkTreeIter iter_to_select;
166 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(addressbook_model), &iter_to_select)) {
167 GValue value = G_VALUE_INIT;
168 gtk_tree_model_get_value(GTK_TREE_MODEL(addressbook_model), &iter_to_select, 1, &value);
169 auto collection = (CollectionInterface *)g_value_get_pointer(&value);
170 GtkTreeIter iter = iter_to_select;
171 while ( (collection->name() == "vCard") && gtk_tree_model_iter_next(GTK_TREE_MODEL(addressbook_model), &iter)) {
172 iter_to_select = iter;
173 value = G_VALUE_INIT;
174 gtk_tree_model_get_value(GTK_TREE_MODEL(addressbook_model), &iter, 1, &value);
175 collection = (CollectionInterface *)g_value_get_pointer(&value);
176 }
177 }
178 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(priv->combobox_addressbook), &iter_to_select);
179
180 /* model for the available details to choose from */
181 gtk_combo_box_set_qmodel(GTK_COMBO_BOX(priv->combobox_detail),
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400182 (QAbstractItemModel *)&NumberCategoryModel::instance(), NULL);
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400183
184 /* set "home" as the default number category */
Guillaume Roguez5d1514b2015-10-22 15:55:31 -0400185 const auto& idx = NumberCategoryModel::instance().nameToIndex(C_("Phone number category", "home"));
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400186 if (idx.isValid())
187 gtk_combo_box_set_active_index(GTK_COMBO_BOX(priv->combobox_detail), idx);
188
189 /* disable save button until name is entered */
190 gtk_widget_set_sensitive(priv->button_save, FALSE);
191
192 /* connect to the button signals */
193 g_signal_connect_swapped(priv->button_save, "clicked", G_CALLBACK(save_cb), self);
194 g_signal_connect(priv->entry_name, "changed", G_CALLBACK(name_changed), self);
195}
196
197static void
198edit_contact_view_dispose(GObject *object)
199{
200 G_OBJECT_CLASS(edit_contact_view_parent_class)->dispose(object);
201}
202
203static void
204edit_contact_view_finalize(GObject *object)
205{
206 G_OBJECT_CLASS(edit_contact_view_parent_class)->finalize(object);
207}
208
209static void
210edit_contact_view_class_init(EditContactViewClass *klass)
211{
212 G_OBJECT_CLASS(klass)->finalize = edit_contact_view_finalize;
213 G_OBJECT_CLASS(klass)->dispose = edit_contact_view_dispose;
214
215 edit_contact_signals[PERSON_SAVED] =
216 g_signal_new("person-saved",
217 G_OBJECT_CLASS_TYPE(G_OBJECT_CLASS(klass)),
218 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
219 0, /* class offset */
220 NULL, /* accumulater */
221 NULL, /* accu data */
222 g_cclosure_marshal_VOID__VOID,
223 G_TYPE_NONE, 0);
224
225 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(klass),
226 "/cx/ring/RingGnome/editcontactview.ui");
227
228 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, button_save);
229 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, combobox_addressbook);
230 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, entry_name);
231 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, combobox_detail);
232 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), EditContactView, label_uri);
233}
234
235/**
236 * If a Person is specified, a view to edit the given Person will be created;
237 * if no Person is given (NULL), then a new Person object will be created when
238 * 'save' is clicked
239 */
240GtkWidget *
241edit_contact_view_new(ContactMethod *cm, Person *p)
242{
243 g_return_val_if_fail(cm, NULL);
244
245 gpointer self = g_object_new(EDIT_CONTACT_VIEW_TYPE, NULL);
246
247 EditContactViewPrivate *priv = EDIT_CONTACT_VIEW_GET_PRIVATE(self);
248
249 priv->cm = cm;
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400250 auto uri_escaped = g_markup_printf_escaped("<b>%s</b>", cm->uri().toUtf8().constData());
251 gtk_label_set_markup(GTK_LABEL(priv->label_uri), uri_escaped);
252 g_free(uri_escaped);
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400253
Stepan Salenikoviche371bd12015-09-09 15:45:11 -0400254 /* use the primaryName as the suggested name (usually the display name), unless it is the same
255 * as the uri */
256 if (cm->primaryName() != cm->uri())
257 gtk_entry_set_text(GTK_ENTRY(priv->entry_name), cm->primaryName().toUtf8().constData());
258
Stepan Salenikovich0cf247d2015-07-24 17:36:32 -0400259 if (p) {
260 priv->person = p;
261
262 /* select the proper addressbook and prevent it from being modified */
263 if (p->collection() != NULL) {
264 auto model = gtk_combo_box_get_model(GTK_COMBO_BOX(priv->combobox_addressbook));
265 GtkTreeIter iter;
266 if (gtk_tree_model_get_iter_first(model, &iter)) {
267 GValue value = G_VALUE_INIT;
268 gtk_tree_model_get_value(model, &iter, 1, &value);
269 auto collection = (CollectionInterface *)g_value_get_pointer(&value);
270 while (collection != p->collection() && gtk_tree_model_iter_next(model, &iter)) {
271 value = G_VALUE_INIT;
272 gtk_tree_model_get_value(model, &iter, 1, &value);
273 collection = (CollectionInterface *)g_value_get_pointer(&value);
274 }
275 }
276
277 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(priv->combobox_addressbook), &iter);
278 }
279 gtk_widget_set_sensitive(priv->combobox_addressbook, FALSE);
280
281 /* set the name of the person, and prevent it from being edited */
282 gtk_entry_set_text(GTK_ENTRY(priv->entry_name), p->formattedName().toUtf8().constData());
283 g_object_set(G_OBJECT(priv->entry_name), "editable", FALSE, NULL);
284 }
285
286 return (GtkWidget *)self;
287}