1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "evolution-config.h"
19 
20 #include <string.h>
21 #include <gtk/gtk.h>
22 #include <glib/gi18n-lib.h>
23 
24 #include <libedataserver/libedataserver.h>
25 
26 #include "e-category-editor.h"
27 #include "e-dialog-widgets.h"
28 #include "e-misc-utils.h"
29 
30 #define E_CATEGORY_EDITOR_GET_PRIVATE(obj) \
31 	(G_TYPE_INSTANCE_GET_PRIVATE \
32 	((obj), E_TYPE_CATEGORY_EDITOR, ECategoryEditorPrivate))
33 
34 struct _ECategoryEditorPrivate {
35 	GtkWidget *category_name;
36 	GtkWidget *category_icon;
37 };
38 
G_DEFINE_TYPE(ECategoryEditor,e_category_editor,GTK_TYPE_DIALOG)39 G_DEFINE_TYPE (ECategoryEditor, e_category_editor, GTK_TYPE_DIALOG)
40 
41 static void
42 update_preview (GtkFileChooser *chooser,
43                 gpointer user_data)
44 {
45 	GtkImage *image;
46 	gchar *filename;
47 
48 	g_return_if_fail (chooser != NULL);
49 
50 	image = GTK_IMAGE (gtk_file_chooser_get_preview_widget (chooser));
51 	if (!image)
52 		return;
53 
54 	filename = gtk_file_chooser_get_preview_filename (chooser);
55 
56 	gtk_image_set_from_file (image, filename);
57 	gtk_file_chooser_set_preview_widget_active (chooser, filename != NULL);
58 
59 	g_free (filename);
60 }
61 
62 static void
file_chooser_response(GtkDialog * dialog,gint response_id,GtkFileChooser * button)63 file_chooser_response (GtkDialog *dialog,
64                        gint response_id,
65                        GtkFileChooser *button)
66 {
67 	g_return_if_fail (button != NULL);
68 
69 	if (response_id == GTK_RESPONSE_NO)
70 		gtk_file_chooser_unselect_all (button);
71 }
72 
73 static void
unset_icon_clicked_cb(GtkWidget * button,gpointer user_data)74 unset_icon_clicked_cb (GtkWidget *button,
75 		       gpointer user_data)
76 {
77 	GtkFileChooser *file_chooser = user_data;
78 
79 	g_return_if_fail (GTK_IS_FILE_CHOOSER (file_chooser));
80 
81 	gtk_file_chooser_unselect_all (file_chooser);
82 	gtk_widget_set_sensitive (button, FALSE);
83 }
84 
85 static void
chooser_button_file_set_cb(GtkFileChooser * chooser_button,gpointer user_data)86 chooser_button_file_set_cb (GtkFileChooser *chooser_button,
87 			    gpointer user_data)
88 {
89 	GtkWidget *unset_button = user_data;
90 	GSList *uris;
91 
92 	g_return_if_fail (GTK_IS_WIDGET (unset_button));
93 
94 	uris = gtk_file_chooser_get_uris (chooser_button);
95 
96 	gtk_widget_set_sensitive (unset_button, uris != NULL);
97 
98 	g_slist_free_full (uris, g_free);
99 }
100 
101 static void
category_editor_category_name_changed(GtkEntry * category_name_entry,ECategoryEditor * editor)102 category_editor_category_name_changed (GtkEntry *category_name_entry,
103                                        ECategoryEditor *editor)
104 {
105 	gchar *name;
106 
107 	g_return_if_fail (editor != NULL);
108 	g_return_if_fail (category_name_entry != NULL);
109 
110 	name = g_strdup (gtk_entry_get_text (category_name_entry));
111 	if (name != NULL)
112 		name = g_strstrip (name);
113 
114 	gtk_dialog_set_response_sensitive (
115 		GTK_DIALOG (editor), GTK_RESPONSE_OK, name && *name);
116 
117 	g_free (name);
118 }
119 
120 static gchar *
check_category_name(const gchar * name)121 check_category_name (const gchar *name)
122 {
123 	GString *str = NULL;
124 	gchar *p = (gchar *) name;
125 
126 	str = g_string_new ("");
127 	while (*p) {
128 		switch (*p) {
129 			case ',':
130 				break;
131 			default:
132 				g_string_append_c (str, *p);
133 		}
134 		p++;
135 	}
136 
137 	return g_strstrip (g_string_free (str, FALSE));
138 }
139 
140 static void
e_category_editor_class_init(ECategoryEditorClass * class)141 e_category_editor_class_init (ECategoryEditorClass *class)
142 {
143 	g_type_class_add_private (class, sizeof (ECategoryEditorPrivate));
144 }
145 
146 static void
e_category_editor_init(ECategoryEditor * editor)147 e_category_editor_init (ECategoryEditor *editor)
148 {
149 	GtkWidget *dialog_content;
150 	GtkWidget *dialog_action_area;
151 	GtkGrid *grid_category_properties;
152 	GtkWidget *label_name;
153 	GtkWidget *label_icon;
154 	GtkWidget *category_name;
155 	GtkWidget *chooser_button;
156 	GtkWidget *no_image_button;
157 	GtkWidget *chooser_dialog = NULL;
158 	GtkWidget *preview;
159 
160 	editor->priv = E_CATEGORY_EDITOR_GET_PRIVATE (editor);
161 
162 	gtk_window_set_resizable (GTK_WINDOW (editor), FALSE);
163 	gtk_container_set_border_width (GTK_CONTAINER (editor), 6);
164 
165 	if (!e_util_is_running_flatpak ()) {
166 		chooser_dialog = gtk_file_chooser_dialog_new (
167 			_("Category Icon"),
168 			NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
169 			_("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
170 
171 		no_image_button = e_dialog_button_new_with_icon ("window-close", _("_No Image"));
172 		gtk_dialog_add_action_widget (
173 			GTK_DIALOG (chooser_dialog),
174 			no_image_button, GTK_RESPONSE_NO);
175 		gtk_dialog_add_button (
176 			GTK_DIALOG (chooser_dialog),
177 			_("_Open"), GTK_RESPONSE_ACCEPT);
178 		gtk_file_chooser_set_local_only (
179 			GTK_FILE_CHOOSER (chooser_dialog), TRUE);
180 		gtk_widget_show (no_image_button);
181 
182 		g_signal_connect (
183 			chooser_dialog, "update-preview",
184 			G_CALLBACK (update_preview), NULL);
185 
186 		preview = gtk_image_new ();
187 		gtk_file_chooser_set_preview_widget (
188 			GTK_FILE_CHOOSER (chooser_dialog), preview);
189 		gtk_file_chooser_set_preview_widget_active (
190 			GTK_FILE_CHOOSER (chooser_dialog), TRUE);
191 		gtk_widget_show_all (preview);
192 	}
193 
194 	dialog_content = gtk_dialog_get_content_area (GTK_DIALOG (editor));
195 
196 	grid_category_properties = GTK_GRID (gtk_grid_new ());
197 	gtk_box_pack_start (
198 		GTK_BOX (dialog_content),
199 		GTK_WIDGET (grid_category_properties), TRUE, TRUE, 0);
200 	gtk_container_set_border_width (
201 		GTK_CONTAINER (grid_category_properties), 12);
202 	gtk_grid_set_row_spacing (grid_category_properties, 6);
203 	gtk_grid_set_column_spacing (grid_category_properties, 6);
204 
205 	label_name = gtk_label_new_with_mnemonic (_("Category _Name"));
206 	gtk_widget_set_halign (label_name, GTK_ALIGN_FILL);
207 	gtk_misc_set_alignment (GTK_MISC (label_name), 0, 0.5);
208 	gtk_grid_attach (grid_category_properties, label_name, 0, 0, 1, 1);
209 
210 	category_name = gtk_entry_new ();
211 	gtk_entry_set_activates_default (GTK_ENTRY (category_name), TRUE);
212 	gtk_widget_set_hexpand (category_name, TRUE);
213 	gtk_widget_set_halign (category_name, GTK_ALIGN_FILL);
214 	gtk_label_set_mnemonic_widget (GTK_LABEL (label_name), category_name);
215 	gtk_grid_attach (grid_category_properties, category_name, 1, 0, 1, 1);
216 	editor->priv->category_name = category_name;
217 
218 	label_icon = gtk_label_new_with_mnemonic (_("Category _Icon"));
219 	gtk_widget_set_halign (label_icon, GTK_ALIGN_FILL);
220 	gtk_misc_set_alignment (GTK_MISC (label_icon), 0, 0.5);
221 	gtk_grid_attach (grid_category_properties, label_icon, 0, 1, 1, 1);
222 
223 	if (chooser_dialog) {
224 		chooser_button = gtk_file_chooser_button_new_with_dialog (chooser_dialog);
225 
226 		g_signal_connect (
227 			chooser_dialog, "response",
228 			G_CALLBACK (file_chooser_response), chooser_button);
229 	} else {
230 		GtkWidget *unset_button;
231 
232 		chooser_button = gtk_file_chooser_button_new (_("Category Icon"), GTK_FILE_CHOOSER_ACTION_OPEN);
233 
234 		unset_button = gtk_button_new_with_mnemonic (_("_Unset icon"));
235 		gtk_widget_set_sensitive (unset_button, FALSE);
236 		gtk_grid_attach (grid_category_properties, unset_button, 1, 2, 1, 1);
237 
238 		g_signal_connect (unset_button, "clicked",
239 			G_CALLBACK (unset_icon_clicked_cb), chooser_button);
240 
241 		g_signal_connect (chooser_button, "file-set",
242 			G_CALLBACK (chooser_button_file_set_cb), unset_button);
243 	}
244 
245 	gtk_widget_set_hexpand (chooser_button, TRUE);
246 	gtk_widget_set_halign (chooser_button, GTK_ALIGN_FILL);
247 	gtk_label_set_mnemonic_widget (GTK_LABEL (label_icon), chooser_button);
248 	gtk_grid_attach (grid_category_properties, chooser_button, 1, 1, 1, 1);
249 	editor->priv->category_icon = chooser_button;
250 
251 	dialog_action_area = gtk_dialog_get_action_area (GTK_DIALOG (editor));
252 	gtk_button_box_set_layout (
253 		GTK_BUTTON_BOX (dialog_action_area), GTK_BUTTONBOX_END);
254 
255 	gtk_dialog_add_buttons (
256 		GTK_DIALOG (editor),
257 		_("_Cancel"), GTK_RESPONSE_CANCEL,
258 		_("_OK"), GTK_RESPONSE_OK, NULL);
259 	gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_OK);
260 	gtk_window_set_title (GTK_WINDOW (editor), _("Category Properties"));
261 	gtk_window_set_type_hint (
262 		GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_DIALOG);
263 
264 	gtk_widget_show_all (dialog_content);
265 
266 	g_signal_connect (
267 		category_name, "changed",
268 		G_CALLBACK (category_editor_category_name_changed), editor);
269 
270 	category_editor_category_name_changed (
271 		GTK_ENTRY (category_name), editor);
272 }
273 
274 /**
275  * e_categort_editor_new:
276  *
277  * Creates a new #ECategoryEditor widget.
278  *
279  * Returns: a new #ECategoryEditor
280  *
281  * Since: 3.2
282  **/
283 ECategoryEditor *
e_category_editor_new(void)284 e_category_editor_new (void)
285 {
286 	return g_object_new (E_TYPE_CATEGORY_EDITOR, NULL);
287 }
288 
289 /**
290  * e_category_editor_create_category:
291  *
292  * Since: 3.2
293  **/
294 const gchar *
e_category_editor_create_category(ECategoryEditor * editor)295 e_category_editor_create_category (ECategoryEditor *editor)
296 {
297 	GtkEntry *entry;
298 	GtkFileChooser *file_chooser;
299 
300 	g_return_val_if_fail (E_IS_CATEGORY_EDITOR (editor), NULL);
301 
302 	entry = GTK_ENTRY (editor->priv->category_name);
303 	file_chooser = GTK_FILE_CHOOSER (editor->priv->category_icon);
304 
305 	do {
306 		const gchar *category_name;
307 		const gchar *correct_category_name;
308 
309 		if (gtk_dialog_run (GTK_DIALOG (editor)) != GTK_RESPONSE_OK)
310 			return NULL;
311 
312 		category_name = gtk_entry_get_text (entry);
313 		correct_category_name = check_category_name (category_name);
314 
315 		if (e_categories_exist (correct_category_name)) {
316 			GtkWidget *error_dialog;
317 
318 			error_dialog = gtk_message_dialog_new (
319 				GTK_WINDOW (editor),
320 				0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
321 				_("There is already a category “%s” in the "
322 				"configuration. Please use another name"),
323 				category_name);
324 
325 			gtk_dialog_run (GTK_DIALOG (error_dialog));
326 			gtk_widget_destroy (error_dialog);
327 
328 			/* Now we loop and run the dialog again. */
329 
330 		} else {
331 			gchar *category_icon;
332 
333 			category_icon =
334 				gtk_file_chooser_get_filename (file_chooser);
335 			e_categories_add (
336 				correct_category_name, NULL,
337 				category_icon, TRUE);
338 			g_free (category_icon);
339 
340 			return correct_category_name;
341 		}
342 
343 	} while (TRUE);
344 }
345 
346 /**
347  * e_category_editor_edit_category:
348  *
349  * Since: 3.2
350  **/
351 gboolean
e_category_editor_edit_category(ECategoryEditor * editor,const gchar * category)352 e_category_editor_edit_category (ECategoryEditor *editor,
353                                  const gchar *category)
354 {
355 	GtkFileChooser *file_chooser;
356 	gchar *icon_file;
357 
358 	g_return_val_if_fail (E_IS_CATEGORY_EDITOR (editor), FALSE);
359 	g_return_val_if_fail (category != NULL, FALSE);
360 
361 	file_chooser = GTK_FILE_CHOOSER (editor->priv->category_icon);
362 
363 	gtk_entry_set_text (GTK_ENTRY (editor->priv->category_name), category);
364 	gtk_widget_set_sensitive (editor->priv->category_name, FALSE);
365 
366 	icon_file = e_categories_dup_icon_file_for (category);
367 	if (icon_file) {
368 		gtk_file_chooser_set_filename (file_chooser, icon_file);
369 		update_preview (file_chooser, NULL);
370 
371 		if (e_util_is_running_flatpak ())
372 			g_signal_emit_by_name (file_chooser, "file-set", NULL);
373 	}
374 	g_free (icon_file);
375 
376 	if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK) {
377 		gchar *category_icon;
378 
379 		category_icon = gtk_file_chooser_get_filename (file_chooser);
380 		e_categories_set_icon_file_for (category, category_icon);
381 
382 		gtk_dialog_set_response_sensitive (
383 			GTK_DIALOG (editor), GTK_RESPONSE_OK, TRUE);
384 
385 		g_free (category_icon);
386 
387 		return TRUE;
388 	}
389 
390 	return FALSE;
391 }
392