blob: 31ec6b32541bc03d41998a2c69d9490f1899cc30 [file] [log] [blame]
Stepan Salenikovichde896112015-05-11 16:46:33 -04001/*
Guillaume Roguez2a6150d2017-07-19 18:24:47 -04002 * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
Stepan Salenikovichde896112015-05-11 16:46:33 -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 Salenikovichde896112015-05-11 16:46:33 -040018 */
19
20#include "generalsettingsview.h"
21
Stepan Salenikovich5a127672016-09-13 11:19:50 -040022// GTK+ related
Stepan Salenikovichde896112015-05-11 16:46:33 -040023#include <gtk/gtk.h>
Stepan Salenikovicha1b8cb32015-09-11 14:58:35 -040024#include <glib/gi18n.h>
Nicolas Jager6f5e04a2016-05-18 15:04:59 -040025
Stepan Salenikovich5a127672016-09-13 11:19:50 -040026// LRC
Nicolas Jager6f5e04a2016-05-18 15:04:59 -040027#include <person.h>
28#include <profile.h>
29#include <profilemodel.h>
Stepan Salenikovich5a127672016-09-13 11:19:50 -040030#include <categorizedhistorymodel.h>
Stepan Salenikovich738e59a2016-09-16 15:36:11 -040031#include <media/recordingmodel.h>
Stepan Salenikovich5a127672016-09-13 11:19:50 -040032
33// Ring client
34#include "utils/files.h"
35#include "avatarmanipulation.h"
Stepan Salenikovichde896112015-05-11 16:46:33 -040036
37struct _GeneralSettingsView
38{
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -050039 GtkScrolledWindow parent;
Stepan Salenikovichde896112015-05-11 16:46:33 -040040};
41
42struct _GeneralSettingsViewClass
43{
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -050044 GtkScrolledWindowClass parent_class;
Stepan Salenikovichde896112015-05-11 16:46:33 -040045};
46
47typedef struct _GeneralSettingsViewPrivate GeneralSettingsViewPrivate;
48
49struct _GeneralSettingsViewPrivate
50{
Stepan Salenikovichfb7f2952015-05-25 16:44:19 -040051 GSettings *settings;
52
53 /* Rint settings */
54 GtkWidget *checkbutton_autostart;
Stepan Salenikovich982b2882016-06-15 13:13:37 -040055 GtkWidget *checkbutton_showstatusicon;
Stepan Salenikovichbc6c4be2015-07-31 16:07:54 -040056 GtkWidget *checkbutton_bringtofront;
Stepan Salenikovich5a127672016-09-13 11:19:50 -040057 GtkWidget *checkbutton_callnotifications;
58 GtkWidget *checkbutton_chatnotifications;
Sébastien Blin70dc0b72017-07-31 16:24:41 -040059 GtkWidget *checkbutton_chatdisplaylinks;
Stepan Salenikoviche9933242016-06-21 18:08:48 -040060 GtkWidget *checkbutton_searchentryplacescall;
Stepan Salenikovicha5e8e362015-11-05 16:50:48 -050061 GtkWidget *radiobutton_chatright;
62 GtkWidget *radiobutton_chatbottom;
Nicolas Jager6f5e04a2016-05-18 15:04:59 -040063 GtkWidget *box_profil_settings;
64 GtkWidget *avatarmanipulation;
65 GtkWidget *profile_name;
Stepan Salenikovichfb7f2952015-05-25 16:44:19 -040066
Stepan Salenikovichde896112015-05-11 16:46:33 -040067 /* history settings */
68 GtkWidget *adjustment_history_duration;
69 GtkWidget *button_clear_history;
70};
71
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -050072G_DEFINE_TYPE_WITH_PRIVATE(GeneralSettingsView, general_settings_view, GTK_TYPE_SCROLLED_WINDOW);
Stepan Salenikovichde896112015-05-11 16:46:33 -040073
74#define GENERAL_SETTINGS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GENERAL_SETTINGS_VIEW_TYPE, GeneralSettingsViewPrivate))
75
Nicolas Jager3807d982018-01-11 09:46:31 -050076enum {
77 CLEAR_ALL_HISTORY,
78 LAST_SIGNAL
79};
80
81static guint general_settings_view_signals[LAST_SIGNAL] = { 0 };
82
Stepan Salenikovichde896112015-05-11 16:46:33 -040083static void
84general_settings_view_dispose(GObject *object)
85{
Stepan Salenikovichfb7f2952015-05-25 16:44:19 -040086 GeneralSettingsViewPrivate *priv = GENERAL_SETTINGS_VIEW_GET_PRIVATE(object);
87
88 g_clear_object(&priv->settings);
89
Nicolas Jager6f5e04a2016-05-18 15:04:59 -040090 //make sure the VideoWidget is destroyed
91 general_settings_view_show_profile(GENERAL_SETTINGS_VIEW(object), FALSE);
92
Stepan Salenikovichde896112015-05-11 16:46:33 -040093 G_OBJECT_CLASS(general_settings_view_parent_class)->dispose(object);
94}
95
Stepan Salenikovichde896112015-05-11 16:46:33 -040096static gboolean
97clear_history_dialog(GeneralSettingsView *self)
98{
99 gboolean response = FALSE;
100 GtkWidget *dialog = gtk_message_dialog_new(NULL,
101 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
102 GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
Stepan Salenikovich738e59a2016-09-16 15:36:11 -0400103 _("This is a destructive operation. Are you sure you want to delete all of your chat and call history?"));
Stepan Salenikovichde896112015-05-11 16:46:33 -0400104
105 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
106
107 /* get parent window so we can center on it */
108 GtkWidget *parent = gtk_widget_get_toplevel(GTK_WIDGET(self));
109 if (gtk_widget_is_toplevel(parent)) {
110 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
111 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
112 }
113
114 switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
115 case GTK_RESPONSE_OK:
116 response = TRUE;
117 break;
118 default:
119 response = FALSE;
120 break;
121 }
122
123 gtk_widget_destroy(dialog);
124
125 return response;
126}
127
128static void
129clear_history(G_GNUC_UNUSED GtkWidget *button, GeneralSettingsView *self)
130{
131 g_return_if_fail(IS_GENERAL_SETTINGS_VIEW(self));
132
Nicolas Jager3807d982018-01-11 09:46:31 -0500133 if (clear_history_dialog(self) )
134 g_signal_emit(G_OBJECT(self), general_settings_view_signals[CLEAR_ALL_HISTORY], 0);
Stepan Salenikovichde896112015-05-11 16:46:33 -0400135}
136
137static void
138general_settings_view_init(GeneralSettingsView *self)
139{
140 gtk_widget_init_template(GTK_WIDGET(self));
141
142 GeneralSettingsViewPrivate *priv = GENERAL_SETTINGS_VIEW_GET_PRIVATE(self);
143
Stepan Salenikovichfb7f2952015-05-25 16:44:19 -0400144 priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL);
145
Stepan Salenikovichbc6c4be2015-07-31 16:07:54 -0400146 /* bind client option to gsettings */
Stepan Salenikovichfb7f2952015-05-25 16:44:19 -0400147 g_settings_bind(priv->settings, "start-on-login",
148 priv->checkbutton_autostart, "active",
149 G_SETTINGS_BIND_DEFAULT);
Stepan Salenikovich982b2882016-06-15 13:13:37 -0400150 g_settings_bind(priv->settings, "show-status-icon",
151 priv->checkbutton_showstatusicon, "active",
Stepan Salenikovichbc6c4be2015-07-31 16:07:54 -0400152 G_SETTINGS_BIND_DEFAULT);
153 g_settings_bind(priv->settings, "bring-window-to-front",
154 priv->checkbutton_bringtofront, "active",
155 G_SETTINGS_BIND_DEFAULT);
Stepan Salenikovich5a127672016-09-13 11:19:50 -0400156 g_settings_bind(priv->settings, "enable-call-notifications",
157 priv->checkbutton_callnotifications, "active",
158 G_SETTINGS_BIND_DEFAULT);
Sébastien Blin70dc0b72017-07-31 16:24:41 -0400159 g_settings_bind(priv->settings, "enable-display-links",
160 priv->checkbutton_chatdisplaylinks, "active",
161 G_SETTINGS_BIND_DEFAULT);
Stepan Salenikovich5a127672016-09-13 11:19:50 -0400162 g_settings_bind(priv->settings, "enable-chat-notifications",
163 priv->checkbutton_chatnotifications, "active",
164 G_SETTINGS_BIND_DEFAULT);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400165 g_settings_bind(priv->settings, "search-entry-places-call",
166 priv->checkbutton_searchentryplacescall, "active",
167 G_SETTINGS_BIND_DEFAULT);
Stepan Salenikovicha5e8e362015-11-05 16:50:48 -0500168 g_settings_bind(priv->settings, "chat-pane-horizontal",
169 priv->radiobutton_chatright, "active",
170 G_SETTINGS_BIND_DEFAULT);
171 g_settings_bind(priv->settings, "chat-pane-horizontal",
172 priv->radiobutton_chatbottom, "active",
173 (GSettingsBindFlags) (G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN));
Nicolas Jagerd27fdaa2018-01-16 14:24:31 -0500174 g_settings_bind(priv->settings, "history-limit",
175 priv->adjustment_history_duration, "value",
176 G_SETTINGS_BIND_DEFAULT);
Stepan Salenikovichde896112015-05-11 16:46:33 -0400177
178 /* clear history */
179 g_signal_connect(priv->button_clear_history, "clicked", G_CALLBACK(clear_history), self);
180}
181
182static void
183general_settings_view_class_init(GeneralSettingsViewClass *klass)
184{
185 G_OBJECT_CLASS(klass)->dispose = general_settings_view_dispose;
186
187 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
188 "/cx/ring/RingGnome/generalsettingsview.ui");
189
Stepan Salenikovichfb7f2952015-05-25 16:44:19 -0400190 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_autostart);
Stepan Salenikovich982b2882016-06-15 13:13:37 -0400191 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_showstatusicon);
Stepan Salenikovichbc6c4be2015-07-31 16:07:54 -0400192 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_bringtofront);
Stepan Salenikovich5a127672016-09-13 11:19:50 -0400193 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_callnotifications);
Sébastien Blin70dc0b72017-07-31 16:24:41 -0400194 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_chatdisplaylinks);
Stepan Salenikovich5a127672016-09-13 11:19:50 -0400195 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_chatnotifications);
Stepan Salenikoviche9933242016-06-21 18:08:48 -0400196 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, checkbutton_searchentryplacescall);
Stepan Salenikovicha5e8e362015-11-05 16:50:48 -0500197 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, radiobutton_chatright);
198 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, radiobutton_chatbottom);
Stepan Salenikovichde896112015-05-11 16:46:33 -0400199 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, adjustment_history_duration);
200 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, button_clear_history);
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400201 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), GeneralSettingsView, box_profil_settings);
Nicolas Jager3807d982018-01-11 09:46:31 -0500202
203 general_settings_view_signals[CLEAR_ALL_HISTORY] = g_signal_new (
204 "clear-all-history",
205 G_TYPE_FROM_CLASS(klass),
206 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
207 0,
208 nullptr,
209 nullptr,
210 g_cclosure_marshal_VOID__VOID,
211 G_TYPE_NONE, 0);
212
213
Stepan Salenikovichde896112015-05-11 16:46:33 -0400214}
215
216GtkWidget *
217general_settings_view_new()
218{
219 gpointer view = g_object_new(GENERAL_SETTINGS_VIEW_TYPE, NULL);
220
221 return (GtkWidget *)view;
222}
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400223
224static void
225change_profile_name(GtkEntry *entry)
226{
227 auto profile = ProfileModel::instance().selectedProfile();
228 profile->person()->setFormattedName(gtk_entry_get_text(entry));
229 profile->save();
230}
231
232void
233general_settings_view_show_profile(GeneralSettingsView *self, gboolean show_profile)
234{
235 g_return_if_fail(GENERAL_SETTINGS_VIEW(self));
236 GeneralSettingsViewPrivate *priv = GENERAL_SETTINGS_VIEW_GET_PRIVATE(self);
237
238 /* We will construct and destroy the profile (AvatarManipulation widget) each time the profile
239 * should be visible and hidden, respectively. It is not the "prettiest" way of doing things,
240 * but this way we ensure 1. that the profile is updated correctly when it is shown and 2. that
241 * the VideoWidget inside is destroyed when it is not being shown.
242 */
243 if (show_profile) {
244 /* avatar manipulation widget */
245 priv->avatarmanipulation = avatar_manipulation_new();
AmarOk436bd9b2017-07-13 15:02:48 -0400246 gtk_widget_set_halign(priv->box_profil_settings, GtkAlign::GTK_ALIGN_CENTER);
Nicolas Jager6f5e04a2016-05-18 15:04:59 -0400247 gtk_box_pack_start(GTK_BOX(priv->box_profil_settings), priv->avatarmanipulation, true, true, 0);
248 gtk_widget_set_visible(priv->avatarmanipulation, true);
249
250 /* print the profile name. as long as we have only one profil, profil name = person name (a.k.a formatedName) */
251 priv->profile_name = gtk_entry_new();
252 gtk_entry_set_text (GTK_ENTRY(priv->profile_name),
253 ProfileModel::instance().selectedProfile()->person()->formattedName().toUtf8().constData());
254 gtk_widget_set_visible(priv->profile_name, true);
255 gtk_entry_set_alignment(GTK_ENTRY(priv->profile_name), 0.5);
256 gtk_box_pack_start(GTK_BOX(priv->box_profil_settings), priv->profile_name, true, true, 0);
257 g_signal_connect(priv->profile_name, "changed", G_CALLBACK(change_profile_name), NULL);
258 } else {
259 if (priv->avatarmanipulation) {
260 gtk_container_remove(GTK_CONTAINER(priv->box_profil_settings), priv->avatarmanipulation);
261 priv->avatarmanipulation = nullptr;
262 }
263 if (priv->profile_name) {
264 gtk_container_remove(GTK_CONTAINER(priv->box_profil_settings), priv->profile_name);
265 priv->profile_name = nullptr;
266 }
267 }
268}