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