blob: 007d3c5f0bf50a5faf8e87d1254fa4270a49281a [file] [log] [blame]
Stepan Salenikovich61cbab02015-03-16 18:35:10 -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 "accountview.h"
32
33#include <gtk/gtk.h>
34#include <accountmodel.h>
35#include <audio/codecmodel.h>
Stepan Salenikovichc3fede22015-03-20 17:01:47 -040036#include <protocolmodel.h>
37#include <QtCore/QItemSelectionModel>
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040038#include "models/gtkqtreemodel.h"
Stepan Salenikovichc3fede22015-03-20 17:01:47 -040039#include "models/gtkqsortfiltertreemodel.h"
40#include "models/activeitemproxymodel.h"
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040041#include "accountgeneraltab.h"
42#include "accountaudiotab.h"
43#include "accountvideotab.h"
Stepan Salenikovichb7e6a732015-05-04 17:13:22 -040044#include "accountadvancedtab.h"
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -040045#include "accountsecuritytab.h"
Stepan Salenikovichbd029582015-03-24 11:00:56 -040046#include "dialogs.h"
Stepan Salenikovichd6a9ba92015-03-29 11:14:36 -040047#include <glib/gprintf.h>
Stepan Salenikovich9816a942015-04-22 17:49:16 -040048#include "utils/models.h"
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040049
50struct _AccountView
51{
52 GtkBox parent;
53};
54
55struct _AccountViewClass
56{
57 GtkBoxClass parent_class;
58};
59
60typedef struct _AccountViewPrivate AccountViewPrivate;
61
62struct _AccountViewPrivate
63{
64 GtkWidget *treeview_account_list;
65 GtkWidget *stack_account;
66 GtkWidget *current_account_notebook;
Stepan Salenikovichc3fede22015-03-20 17:01:47 -040067 GtkWidget *button_remove_account;
68 GtkWidget *button_add_account;
69 GtkWidget *combobox_account_type;
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040070
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040071 gint current_page; /* keeps track of current notebook page displayed */
Stepan Salenikovichc3fede22015-03-20 17:01:47 -040072
73 ActiveItemProxyModel *active_protocols;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040074 QMetaObject::Connection protocol_selection_changed;
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040075};
76
77G_DEFINE_TYPE_WITH_PRIVATE(AccountView, account_view, GTK_TYPE_BOX);
78
79#define ACCOUNT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_VIEW_TYPE, AccountViewPrivate))
80
81static void
82account_view_dispose(GObject *object)
83{
84 AccountView *view = ACCOUNT_VIEW(object);
85 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
86
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040087 QObject::disconnect(priv->protocol_selection_changed);
Stepan Salenikovich61cbab02015-03-16 18:35:10 -040088
89 G_OBJECT_CLASS(account_view_parent_class)->dispose(object);
90}
91
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -040092static void
93account_view_finalize(GObject *object)
94{
95 AccountView *view = ACCOUNT_VIEW(object);
96 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
97
98 delete priv->active_protocols;
99
100 G_OBJECT_CLASS(account_view_parent_class)->finalize(object);
101}
102
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400103static void
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400104update_account_model_selection(GtkTreeSelection *selection, G_GNUC_UNUSED gpointer user_data)
105{
106 QModelIndex current = get_index_from_selection(selection);
107 if (current.isValid())
108 AccountModel::instance()->selectionModel()->setCurrentIndex(current, QItemSelectionModel::ClearAndSelect);
109 else
110 AccountModel::instance()->selectionModel()->clearCurrentIndex();
111}
112
113static void
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400114account_selection_changed(GtkTreeSelection *selection, AccountView *view)
115{
116 g_return_if_fail(IS_ACCOUNT_VIEW(view));
117 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
118
119 GtkWidget *old_account_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
120
121 /* keep track of the last tab displayed */
122 if (priv->current_account_notebook)
123 priv->current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(priv->current_account_notebook));
124
125 if (priv->current_page < 0)
126 priv->current_page = 0;
127
128 QModelIndex account_idx = get_index_from_selection(selection);
129 if (!account_idx.isValid()) {
130 /* it nothing is slected, simply display something empty */
131 GtkWidget *empty_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
132 gtk_widget_show(empty_box);
133 gtk_stack_add_named(GTK_STACK(priv->stack_account), empty_box, "placeholder");
134 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), empty_box);
135 priv->current_account_notebook = NULL;
136 } else {
137 Account *account = AccountModel::instance()->getAccountByModelIndex(account_idx);
138
139 /* build new account view */
140 GtkWidget *hbox_account = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
141
142 /* create account notebook */
143 priv->current_account_notebook = gtk_notebook_new();
144 gtk_box_pack_start(GTK_BOX(hbox_account), priv->current_account_notebook, TRUE, TRUE, 0);
145
146 /* customize account view based on account */
147 GtkWidget *general_tab = account_general_tab_new(account);
148 gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
149 general_tab,
150 gtk_label_new("General"));
151 GtkWidget *audio_tab = account_audio_tab_new(account);
152 gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
153 audio_tab,
154 gtk_label_new("Audio"));
155 GtkWidget *video_tab = account_video_tab_new(account);
156 gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
157 video_tab,
158 gtk_label_new("Video"));
Stepan Salenikovichb7e6a732015-05-04 17:13:22 -0400159 GtkWidget *advanced_tab = account_advanced_tab_new(account);
160 gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
161 advanced_tab,
162 gtk_label_new("Advanced"));
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -0400163 GtkWidget *security_tab = account_security_tab_new(account);
164 gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
165 security_tab,
166 gtk_label_new("Security"));
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400167
168 /* set the tab displayed to the same as the prev account selected */
169 gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->current_account_notebook), priv->current_page);
170
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400171 gtk_widget_show_all(hbox_account);
172
173 /* set the new account view as visible */
174 char *account_view_name = g_strdup_printf("%p_account", account);
175 gtk_stack_add_named(GTK_STACK(priv->stack_account), hbox_account, account_view_name);
176 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), hbox_account);
177 g_free(account_view_name);
178 }
179
180 /* remove the old account view */
181 if (old_account_view)
182 gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_account_view);
183}
184
185static void
186account_active_toggled(GtkCellRendererToggle *renderer, gchar *path, AccountView *view)
187{
188 g_return_if_fail(IS_ACCOUNT_VIEW(view));
189 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
190
191 /* we want to set it to the opposite of the current value */
192 gboolean toggle = !gtk_cell_renderer_toggle_get_active(renderer);
193
194 /* get iter which was clicked */
195 GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
196 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_account_list));
197 GtkTreeIter iter;
198 gtk_tree_model_get_iter(model, &iter, tree_path);
199
200 /* get qmodelindex from iter and set the model data */
201 QModelIndex idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
202 if (idx.isValid()) {
203 /* check if it is the IP2IP account, as we don't want to be able to disable it */
204 QVariant alias = idx.data(static_cast<int>(Account::Role::Alias));
Stepan Salenikovich101f3102015-05-01 12:39:59 -0400205 if (strcmp(alias.value<QString>().toLocal8Bit().constData(), "IP2IP") != 0) {
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400206 AccountModel::instance()->setData(idx, QVariant(toggle), Qt::CheckStateRole);
Stepan Salenikovich101f3102015-05-01 12:39:59 -0400207 /* save the account to apply the changed state right away */
208 AccountModel::instance()->getAccountByModelIndex(idx)->performAction(Account::EditAction::SAVE);
209 }
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400210 }
211}
212
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400213static gboolean
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400214remove_account_dialog(AccountView *view, Account *account)
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400215{
216 gboolean response = FALSE;
217 GtkWidget *dialog = gtk_message_dialog_new(NULL,
218 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
219 GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
220 "Are you sure you want to delete account \"%s\"?",
221 account->alias().toLocal8Bit().constData());
222
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400223 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
224
225 /* get parent window so we can center on it */
226 GtkWidget *parent = gtk_widget_get_toplevel(GTK_WIDGET(view));
227 if (gtk_widget_is_toplevel(parent)) {
228 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
229 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
230 }
231
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400232 switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
233 case GTK_RESPONSE_OK:
234 response = TRUE;
235 break;
236 default:
237 response = FALSE;
238 break;
239 }
240
241 gtk_widget_destroy(dialog);
242
243 return response;
244}
245
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400246static gboolean
247save_account(GtkWidget *working_dialog)
248{
249 AccountModel::instance()->save();
250 if (working_dialog)
251 gtk_widget_destroy(working_dialog);
252
253 return G_SOURCE_REMOVE;
254}
255
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400256static void
257remove_account(G_GNUC_UNUSED GtkWidget *entry, AccountView *view)
258{
259 g_return_if_fail(IS_ACCOUNT_VIEW(view));
260 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
261
262 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
263 QModelIndex idx = get_index_from_selection(selection);
264
265 if (idx.isValid()) {
266 /* this is a destructive operation, ask the user if they are sure */
267 Account *account = AccountModel::instance()->getAccountByModelIndex(idx);
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400268 if (remove_account_dialog(view, account)) {
269 /* show working dialog in case save operation takes time */
270 GtkWidget *working = ring_dialog_working(GTK_WIDGET(view), NULL);
271 gtk_window_present(GTK_WINDOW(working));
272
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400273 AccountModel::instance()->remove(idx);
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400274
275 /* now save the time it takes to transition the account view to the new account (300ms)
276 * the save doesn't happen before the "working" dialog is presented
277 * the timeout function should destroy the "working" dialog when done saving
278 */
Stepan Salenikovich12fee942015-03-25 18:38:47 -0400279 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)save_account, working, NULL);
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400280 }
281 }
282}
283
284static void
285add_account(G_GNUC_UNUSED GtkWidget *entry, AccountView *view)
286{
287 g_return_if_fail(IS_ACCOUNT_VIEW(view));
288 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
289
290 GtkTreeIter protocol_iter;
291 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(priv->combobox_account_type), &protocol_iter)) {
292 /* get the qmodelindex of the protocol */
293 GtkTreeModel *protocol_model = gtk_combo_box_get_model(GTK_COMBO_BOX(priv->combobox_account_type));
294 QModelIndex protocol_idx = gtk_q_sort_filter_tree_model_get_source_idx(
295 GTK_Q_SORT_FILTER_TREE_MODEL(protocol_model),
296 &protocol_iter);
297 if (protocol_idx.isValid()) {
298 protocol_idx = priv->active_protocols->mapToSource(protocol_idx);
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400299
300 /* show working dialog in case save operation takes time */
301 GtkWidget *working = ring_dialog_working(GTK_WIDGET(view), NULL);
302 gtk_window_present(GTK_WINDOW(working));
303
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400304 AccountModel::instance()->add(QString("New Account"), protocol_idx);
Stepan Salenikovichbd029582015-03-24 11:00:56 -0400305
306 /* now save after a short timeout to make sure that
307 * the save doesn't happen before the "working" dialog is presented
308 * the timeout function should destroy the "working" dialog when done saving
309 */
Stepan Salenikovich12fee942015-03-25 18:38:47 -0400310 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)save_account, working, NULL);
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400311 }
312 }
313}
314
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400315static void
Stepan Salenikovichd6a9ba92015-03-29 11:14:36 -0400316state_to_string(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
317 GtkCellRenderer *cell,
318 GtkTreeModel *tree_model,
319 GtkTreeIter *iter,
320 G_GNUC_UNUSED gpointer data)
321{
322 GValue value = G_VALUE_INIT;
323 gtk_tree_model_get_value(tree_model, iter, 3, &value);
324 Account::RegistrationState state = (Account::RegistrationState)g_value_get_uint(&value);
325 g_value_unset(&value);
326
327 gchar *display_state = NULL;
328 switch (state) {
329 case Account::RegistrationState::READY:
330 display_state = g_strdup_printf("<span fgcolor=\"green\">ready</span>");
331 break;
332 case Account::RegistrationState::UNREGISTERED:
333 display_state = g_strdup_printf("<span fgcolor=\"gray\">unregistered</span>");
334 break;
335 case Account::RegistrationState::TRYING:
336 display_state = g_strdup_printf("<span fgcolor=\"orange\">trying</span>");
337 break;
338 case Account::RegistrationState::ERROR:
339 display_state = g_strdup_printf("<span fgcolor=\"red\">error</span>");
340 break;
341 case Account::RegistrationState::COUNT__:
342 g_warning("registration state should never be \"count\"");
343 break;
344 }
345 g_object_set(G_OBJECT(cell), "markup", display_state, NULL);
346 g_free(display_state);
347}
348
349static void
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400350account_view_init(AccountView *view)
351{
352 gtk_widget_init_template(GTK_WIDGET(view));
353
354 AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
355
356 /* account model */
357 GtkQTreeModel *account_model;
358 GtkCellRenderer *renderer;
359 GtkTreeViewColumn *column;
360
361 account_model = gtk_q_tree_model_new(AccountModel::instance(), 4,
362 Account::Role::Enabled, G_TYPE_BOOLEAN,
363 Account::Role::Alias, G_TYPE_STRING,
Stepan Salenikovichd6a9ba92015-03-29 11:14:36 -0400364 Account::Role::Proto, G_TYPE_STRING,
365 Account::Role::RegistrationState, G_TYPE_UINT);
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400366 gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_account_list), GTK_TREE_MODEL(account_model));
367
368 renderer = gtk_cell_renderer_toggle_new();
369 column = gtk_tree_view_column_new_with_attributes("Enabled", renderer, "active", 0, NULL);
370 gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_account_list), column);
371
372 g_signal_connect(renderer, "toggled", G_CALLBACK(account_active_toggled), view);
373
374 renderer = gtk_cell_renderer_text_new();
375 column = gtk_tree_view_column_new_with_attributes("Alias", renderer, "text", 1, NULL);
376 gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_account_list), column);
377
378 renderer = gtk_cell_renderer_text_new();
379 column = gtk_tree_view_column_new_with_attributes("Status", renderer, "text", 3, NULL);
380 gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_account_list), column);
381
Stepan Salenikovichd6a9ba92015-03-29 11:14:36 -0400382 /* the registration state is an enum, we want to display it as a string */
383 gtk_tree_view_column_set_cell_data_func(
384 column,
385 renderer,
386 (GtkTreeCellDataFunc)state_to_string,
387 NULL,
388 NULL);
389
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400390 /* add an empty box to the account stack initially, otherwise there will
391 * be no cool animation when the first account is selected */
392 GtkWidget *empty_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
393 gtk_widget_show(empty_box);
394 gtk_stack_add_named(GTK_STACK(priv->stack_account), empty_box, "placeholder");
395 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), empty_box);
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400396
397 /* populate account type combo box */
398 /* TODO: when to delete this model? */
399 priv->active_protocols = new ActiveItemProxyModel((QAbstractItemModel *)AccountModel::instance()->protocolModel());
400
401 GtkQSortFilterTreeModel *protocol_model = gtk_q_sort_filter_tree_model_new(
402 (QSortFilterProxyModel *)priv->active_protocols,
403 1,
404 Qt::DisplayRole, G_TYPE_STRING);
405
406 gtk_combo_box_set_model(GTK_COMBO_BOX(priv->combobox_account_type), GTK_TREE_MODEL(protocol_model));
407
408 renderer = gtk_cell_renderer_text_new();
409 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(priv->combobox_account_type), renderer, FALSE);
410 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(priv->combobox_account_type), renderer,
411 "text", 0, NULL);
412
413 /* connect signals to and from the selection model of the account model */
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400414 priv->protocol_selection_changed = QObject::connect(
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400415 AccountModel::instance()->selectionModel(),
416 &QItemSelectionModel::currentChanged,
417 [=](const QModelIndex & current, const QModelIndex & previous) {
418 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
419
420 /* first unselect the previous */
421 if (previous.isValid()) {
422 GtkTreeIter old_iter;
423 if (gtk_q_tree_model_source_index_to_iter(account_model, previous, &old_iter)) {
424 gtk_tree_selection_unselect_iter(selection, &old_iter);
425 } else {
426 g_warning("Trying to unselect invalid GtkTreeIter");
427 }
428 }
429
430 /* select the current */
431 if (current.isValid()) {
432 GtkTreeIter new_iter;
433 if (gtk_q_tree_model_source_index_to_iter(account_model, current, &new_iter)) {
434 gtk_tree_selection_select_iter(selection, &new_iter);
435 } else {
Stepan Salenikovichf903d1b2015-03-25 14:51:45 -0400436 g_warning("SelectionModel of AccountModel changed to invalid QModelIndex?");
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400437 }
438 }
439 }
440 );
441
442 GtkTreeSelection *account_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
443 g_signal_connect(account_selection, "changed", G_CALLBACK(update_account_model_selection), NULL);
444 g_signal_connect(account_selection, "changed", G_CALLBACK(account_selection_changed), view);
445
446 /* select the default protocol */
447 QModelIndex protocol_idx = AccountModel::instance()->protocolModel()->selectionModel()->currentIndex();
448 if (protocol_idx.isValid()) {
449 protocol_idx = priv->active_protocols->mapFromSource(protocol_idx);
450 GtkTreeIter protocol_iter;
451 if (gtk_q_sort_filter_tree_model_source_index_to_iter(
452 (GtkQSortFilterTreeModel *)protocol_model,
453 protocol_idx,
454 &protocol_iter)) {
455 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(priv->combobox_account_type), &protocol_iter);
456 }
457 }
458
459 /* connect signals to add/remove accounts */
460 g_signal_connect(priv->button_remove_account, "clicked", G_CALLBACK(remove_account), view);
461 g_signal_connect(priv->button_add_account, "clicked", G_CALLBACK(add_account), view);
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400462}
463
464static void
465account_view_class_init(AccountViewClass *klass)
466{
467 G_OBJECT_CLASS(klass)->dispose = account_view_dispose;
Stepan Salenikovich2d63d5e2015-03-22 23:23:54 -0400468 G_OBJECT_CLASS(klass)->finalize = account_view_finalize;
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400469
470 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
471 "/cx/ring/RingGnome/accountview.ui");
472
473 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, treeview_account_list);
474 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, stack_account);
Stepan Salenikovichc3fede22015-03-20 17:01:47 -0400475 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, button_remove_account);
476 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, button_add_account);
477 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, combobox_account_type);
Stepan Salenikovich61cbab02015-03-16 18:35:10 -0400478}
479
480GtkWidget *
481account_view_new(void)
482{
483 return (GtkWidget *)g_object_new(ACCOUNT_VIEW_TYPE, NULL);
484}