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