Assamese translation updated
[platform/upstream/evolution-data-server.git] / libedataserverui / e-categories-editor.c
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 library is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU Lesser General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
24 #include <glib/gi18n-lib.h>
25
26 #include <libedataserver/libedataserver.h>
27 #include <libedataserver/libedataserver-private.h>
28
29 #include "e-categories-editor.h"
30 #include "e-categories-selector.h"
31 #include "e-category-completion.h"
32 #include "e-category-editor.h"
33
34 #define E_CATEGORIES_EDITOR_GET_PRIVATE(obj) \
35         (G_TYPE_INSTANCE_GET_PRIVATE \
36         ((obj), E_TYPE_CATEGORIES_EDITOR, ECategoriesEditorPrivate))
37
38 struct _ECategoriesEditorPrivate {
39         ECategoriesSelector *categories_list;
40         GtkWidget *categories_entry;
41         GtkWidget *categories_entry_label;
42         GtkWidget *new_button;
43         GtkWidget *edit_button;
44         GtkWidget *delete_button;
45
46         guint ignore_category_changes : 1;
47 };
48
49 enum {
50         COLUMN_ACTIVE,
51         COLUMN_ICON,
52         COLUMN_CATEGORY,
53         N_COLUMNS
54 };
55
56 enum {
57         PROP_0,
58         PROP_ENTRY_VISIBLE
59 };
60
61 enum {
62         ENTRY_CHANGED,
63         LAST_SIGNAL
64 };
65
66 static gint signals[LAST_SIGNAL] = {0};
67
68 G_DEFINE_TYPE (ECategoriesEditor, e_categories_editor, GTK_TYPE_GRID)
69
70 static void
71 entry_changed_cb (GtkEntry *entry,
72                   ECategoriesEditor *editor)
73 {
74         g_signal_emit (editor, signals[ENTRY_CHANGED], 0);
75 }
76
77 static void
78 categories_editor_selection_changed_cb (ECategoriesEditor *editor,
79                                         GtkTreeSelection *selection)
80 {
81         GtkWidget *widget;
82         gint n_rows;
83
84         n_rows = gtk_tree_selection_count_selected_rows (selection);
85
86         widget = editor->priv->edit_button;
87         gtk_widget_set_sensitive (widget, n_rows == 1);
88
89         widget = editor->priv->delete_button;
90         gtk_widget_set_sensitive (widget, n_rows >= 1);
91 }
92
93 static void
94 category_checked_cb (ECategoriesSelector *selector,
95                      const gchar *category,
96                      const gboolean checked,
97                      ECategoriesEditor *editor)
98 {
99         GtkEntry *entry;
100         gchar *categories;
101
102         entry = GTK_ENTRY (editor->priv->categories_entry);
103         categories = e_categories_selector_get_checked (selector);
104
105         gtk_entry_set_text (entry, categories);
106
107         g_free (categories);
108 }
109
110 static void
111 new_button_clicked_cb (GtkButton *button,
112                        ECategoriesEditor *editor)
113 {
114         ECategoryEditor *cat_editor = e_category_editor_new ();
115
116         e_category_editor_create_category (cat_editor);
117
118         gtk_widget_destroy (GTK_WIDGET (cat_editor));
119 }
120
121 static void
122 edit_button_clicked_cb (GtkButton *button,
123                         ECategoriesEditor *editor)
124 {
125         ECategoryEditor *cat_editor = e_category_editor_new ();
126         gchar *category;
127
128         category = e_categories_selector_get_selected (
129                 editor->priv->categories_list);
130
131         e_category_editor_edit_category (cat_editor, category);
132
133         gtk_widget_destroy (GTK_WIDGET (cat_editor));
134         g_free (category);
135 }
136
137 static void
138 categories_editor_set_property (GObject *object,
139                                 guint property_id,
140                                 const GValue *value,
141                                 GParamSpec *pspec)
142 {
143         switch (property_id) {
144                 case PROP_ENTRY_VISIBLE:
145                         e_categories_editor_set_entry_visible (
146                                 E_CATEGORIES_EDITOR (object),
147                                 g_value_get_boolean (value));
148                         return;
149         }
150
151         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
152 }
153
154 static void
155 categories_editor_get_property (GObject *object,
156                                 guint property_id,
157                                 GValue *value,
158                                 GParamSpec *pspec)
159 {
160         switch (property_id) {
161                 case PROP_ENTRY_VISIBLE:
162                         g_value_set_boolean (
163                                 value, e_categories_editor_get_entry_visible (
164                                 E_CATEGORIES_EDITOR (object)));
165                         return;
166         }
167
168         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
169 }
170
171 static void
172 e_categories_editor_class_init (ECategoriesEditorClass *class)
173 {
174         GObjectClass *object_class;
175
176         g_type_class_add_private (class, sizeof (ECategoriesEditorPrivate));
177
178         object_class = G_OBJECT_CLASS (class);
179         object_class->set_property = categories_editor_set_property;
180         object_class->get_property = categories_editor_get_property;
181
182         g_object_class_install_property (
183                 object_class,
184                 PROP_ENTRY_VISIBLE,
185                 g_param_spec_boolean (
186                         "entry-visible",
187                         NULL,
188                         NULL,
189                         TRUE,
190                         G_PARAM_READWRITE));
191
192         signals[ENTRY_CHANGED] = g_signal_new (
193                 "entry-changed",
194                 G_TYPE_FROM_CLASS (class),
195                 G_SIGNAL_RUN_FIRST,
196                 G_STRUCT_OFFSET (ECategoriesEditorClass, entry_changed),
197                 NULL, NULL,
198                 g_cclosure_marshal_VOID__VOID,
199                 G_TYPE_NONE, 0);
200 }
201
202 static void
203 e_categories_editor_init (ECategoriesEditor *editor)
204 {
205         GtkEntryCompletion *completion;
206         GtkGrid *grid;
207         GtkWidget *entry_categories;
208         GtkWidget *label_header;
209         GtkWidget *label2;
210         GtkWidget *scrolledwindow1;
211         GtkWidget *categories_list;
212         GtkWidget *hbuttonbox1;
213         GtkWidget *button_new;
214         GtkWidget *button_edit;
215         GtkWidget *button_delete;
216
217         gtk_widget_set_size_request (GTK_WIDGET (editor), -1, 400);
218
219         grid = GTK_GRID (editor);
220
221         gtk_grid_set_row_spacing (grid, 6);
222         gtk_grid_set_column_spacing (grid, 6);
223
224         label_header = gtk_label_new_with_mnemonic (
225                 _("Currently _used categories:"));
226         gtk_widget_set_halign (label_header, GTK_ALIGN_FILL);
227         gtk_grid_attach (grid, label_header, 0, 0, 1, 1);
228         gtk_label_set_justify (GTK_LABEL (label_header), GTK_JUSTIFY_CENTER);
229         gtk_misc_set_alignment (GTK_MISC (label_header), 0, 0.5);
230
231         entry_categories = gtk_entry_new ();
232         gtk_widget_set_hexpand (entry_categories, TRUE);
233         gtk_widget_set_halign (entry_categories, GTK_ALIGN_FILL);
234         gtk_grid_attach (grid, entry_categories, 0, 1, 1, 1);
235
236         label2 = gtk_label_new_with_mnemonic (_("_Available Categories:"));
237         gtk_widget_set_halign (label2, GTK_ALIGN_FILL);
238         gtk_grid_attach (grid, label2, 0, 2, 1, 1);
239         gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER);
240         gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
241
242         scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
243         g_object_set (G_OBJECT (scrolledwindow1),
244                 "hexpand", TRUE,
245                 "halign", GTK_ALIGN_FILL,
246                 "vexpand", TRUE,
247                 "valign", GTK_ALIGN_FILL,
248                 NULL);
249         gtk_grid_attach (grid, scrolledwindow1, 0, 3, 1, 1);
250         gtk_scrolled_window_set_policy (
251                 GTK_SCROLLED_WINDOW (scrolledwindow1),
252                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
253         gtk_scrolled_window_set_shadow_type (
254                 GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN);
255
256         categories_list = GTK_WIDGET (e_categories_selector_new ());
257         gtk_container_add (GTK_CONTAINER (scrolledwindow1), categories_list);
258         gtk_widget_set_size_request (categories_list, -1, 350);
259         gtk_tree_view_set_headers_visible (
260                 GTK_TREE_VIEW (categories_list), FALSE);
261         gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (categories_list), TRUE);
262         g_signal_connect (
263                 G_OBJECT (categories_list), "category-checked",
264                 G_CALLBACK (category_checked_cb), editor);
265
266         hbuttonbox1 = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
267         g_object_set (G_OBJECT (hbuttonbox1),
268                 "hexpand", TRUE,
269                 "halign", GTK_ALIGN_FILL,
270                 NULL);
271         gtk_grid_attach (grid, hbuttonbox1, 0, 4, 1, 1);
272         gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 6);
273
274         button_new = gtk_button_new_from_stock (GTK_STOCK_NEW);
275         gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_new);
276         gtk_widget_set_can_default (button_new, TRUE);
277
278         button_edit = gtk_button_new_from_stock (GTK_STOCK_EDIT);
279         gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_edit);
280         gtk_widget_set_can_default (button_edit, TRUE);
281
282         button_delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
283         gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_delete);
284         gtk_widget_set_can_default (button_delete, TRUE);
285
286         gtk_label_set_mnemonic_widget (
287                 GTK_LABEL (label_header), entry_categories);
288         gtk_label_set_mnemonic_widget (
289                 GTK_LABEL (label2), categories_list);
290
291         editor->priv = E_CATEGORIES_EDITOR_GET_PRIVATE (editor);
292
293         editor->priv->categories_list = E_CATEGORIES_SELECTOR (categories_list);
294         editor->priv->categories_entry = entry_categories;
295         editor->priv->categories_entry_label = label_header;
296
297         g_signal_connect_swapped (
298                 editor->priv->categories_list, "selection-changed",
299                 G_CALLBACK (categories_editor_selection_changed_cb), editor);
300
301         completion = e_category_completion_new ();
302         gtk_entry_set_completion (
303                 GTK_ENTRY (editor->priv->categories_entry), completion);
304         g_object_unref (completion);
305
306         editor->priv->new_button = button_new;
307         g_signal_connect (
308                 editor->priv->new_button, "clicked",
309                 G_CALLBACK (new_button_clicked_cb), editor);
310
311         editor->priv->edit_button = button_edit;
312         g_signal_connect (
313                 editor->priv->edit_button, "clicked",
314                 G_CALLBACK (edit_button_clicked_cb), editor);
315
316         editor->priv->delete_button = button_delete;
317         g_signal_connect_swapped (
318                 editor->priv->delete_button, "clicked",
319                 G_CALLBACK (e_categories_selector_delete_selection),
320                 editor->priv->categories_list);
321
322         g_signal_connect (
323                 editor->priv->categories_entry, "changed",
324                 G_CALLBACK (entry_changed_cb), editor);
325
326         gtk_widget_show_all (GTK_WIDGET (editor));
327 }
328
329 /**
330  * e_categories_editor_new:
331  *
332  * Creates a new #ECategoriesEditor widget.
333  *
334  * Returns: a new #ECategoriesEditor
335  *
336  * Since: 3.2
337  **/
338 GtkWidget *
339 e_categories_editor_new (void)
340 {
341         return g_object_new (E_TYPE_CATEGORIES_EDITOR, NULL);
342 }
343
344 /**
345  * e_categories_editor_get_categories:
346  * @editor: an #ECategoriesEditor
347  *
348  * Gets a comma-separated list of the categories currently selected
349  * in the editor.
350  *
351  * Returns: a comma-separated list of categories. Free returned
352  * pointer with g_free().
353  *
354  * Since: 3.2
355  **/
356 gchar *
357 e_categories_editor_get_categories (ECategoriesEditor *editor)
358 {
359         ECategoriesSelector *categories_list;
360
361         g_return_val_if_fail (E_IS_CATEGORIES_EDITOR (editor), NULL);
362
363         categories_list = editor->priv->categories_list;
364
365         return e_categories_selector_get_checked (categories_list);
366 }
367
368 /**
369  * e_categories_editor_set_categories:
370  * @editor: an #ECategoriesEditor
371  * @categories: comma-separated list of categories
372  *
373  * Sets the list of categories selected on the editor.
374  *
375  * Since: 3.2
376  **/
377 void
378 e_categories_editor_set_categories (ECategoriesEditor *editor,
379                                     const gchar *categories)
380 {
381         ECategoriesSelector *categories_list;
382
383         g_return_if_fail (E_IS_CATEGORIES_EDITOR (editor));
384
385         categories_list = editor->priv->categories_list;
386
387         e_categories_selector_set_checked (categories_list, categories);
388         category_checked_cb (categories_list, NULL, FALSE, editor);
389 }
390
391 /**
392  * e_categories_editor_get_entry_visible:
393  * @editor: an #ECategoriesEditor
394  *
395  * Return the visibility of the category input entry.
396  *
397  * Returns: whether the entry is visible
398  *
399  * Since: 3.2
400  **/
401 gboolean
402 e_categories_editor_get_entry_visible (ECategoriesEditor *editor)
403 {
404         g_return_val_if_fail (E_IS_CATEGORIES_EDITOR (editor), TRUE);
405
406         return gtk_widget_get_visible (editor->priv->categories_entry);
407 }
408
409 /**
410  * e_categories_editor_set_entry_visible:
411  * @editor: an #ECategoriesEditor
412  * @entry_visible: whether to make the entry visible
413  *
414  * Sets the visibility of the category input entry.
415  *
416  * Since: 3.2
417  **/
418 void
419 e_categories_editor_set_entry_visible (ECategoriesEditor *editor,
420                                        gboolean entry_visible)
421 {
422         g_return_if_fail (E_IS_CATEGORIES_EDITOR (editor));
423
424         if ((gtk_widget_get_visible (editor->priv->categories_entry) ? 1 : 0) ==
425             (entry_visible ? 1 : 0))
426                 return;
427
428         gtk_widget_set_visible (
429                 editor->priv->categories_entry, entry_visible);
430         gtk_widget_set_visible (
431                 editor->priv->categories_entry_label, entry_visible);
432         e_categories_selector_set_items_checkable (
433                 editor->priv->categories_list, entry_visible);
434
435         g_object_notify (G_OBJECT (editor), "entry-visible");
436 }