1 /*
2  * Osmo - a handy personal organizer
3  *
4  * Copyright (C) 2007-2009 Tomasz Maka <pasp@users.sourceforge.net>
5  *               2007-2009 Piotr Maka <silloz@users.sourceforge.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "calendar.h"
23 #include "i18n.h"
24 #include "options_prefs.h"
25 #include "stock_icons.h"
26 #include "tasks.h"
27 #include "tasks_preferences_gui.h"
28 #include "utils_gui.h"
29 
30 #ifdef TASKS_ENABLED
31 
32 /* ========================================================================== */
33 
34 static void
checkbutton_clicked_cb(GtkToggleButton * togglebutton,gint * option)35 checkbutton_clicked_cb (GtkToggleButton *togglebutton, gint *option)
36 {
37 	*option = gtk_toggle_button_get_active (togglebutton);
38 }
39 
40 /* ========================================================================== */
41 
42 static void
due_today_color_changed_cb(GtkColorChooser * color_button,GUI * appGUI)43 due_today_color_changed_cb (GtkColorChooser *color_button, GUI *appGUI)
44 {
45 	GdkRGBA color;
46 
47 	gtk_color_chooser_get_rgba (color_button, &color);
48 	utl_gui_convert_color_to_string (&color, config.due_today_color);
49 	refresh_tasks (appGUI);
50 }
51 
52 /* ========================================================================== */
53 
54 static void
due_7days_color_changed_cb(GtkColorChooser * color_button,GUI * appGUI)55 due_7days_color_changed_cb (GtkColorChooser *color_button, GUI *appGUI)
56 {
57 	GdkRGBA color;
58 
59 	gtk_color_chooser_get_rgba (color_button, &color);
60 	utl_gui_convert_color_to_string(&color, config.due_7days_color);
61 	refresh_tasks (appGUI);
62 }
63 
64 /* ========================================================================== */
65 
66 static void
past_due_color_changed_cb(GtkColorChooser * color_button,GUI * appGUI)67 past_due_color_changed_cb (GtkColorChooser *color_button, GUI *appGUI)
68 {
69 	GdkRGBA color;
70 
71 	gtk_color_chooser_get_rgba (color_button, &color);
72 	utl_gui_convert_color_to_string (&color, config.past_due_color);
73 	refresh_tasks (appGUI);
74 }
75 
76 /* ========================================================================== */
77 
78 static void
bold_items_cb(GtkToggleButton * widget,GUI * appGUI)79 bold_items_cb (GtkToggleButton *widget, GUI *appGUI)
80 {
81 	config.tasks_high_in_bold = gtk_toggle_button_get_active (widget);
82 	refresh_tasks (appGUI);
83 }
84 
85 /* ========================================================================== */
86 
87 static void
ti_font_select_cb(GtkWidget * widget,GUI * appGUI)88 ti_font_select_cb (GtkWidget *widget, GUI *appGUI)
89 {
90 	GtkWidget *font_selector;
91 	gchar *font_name;
92 	gint response;
93 
94 	font_selector = gtk_font_chooser_dialog_new (_("Select a font..."), GTK_WINDOW (appGUI->main_window));
95 	gtk_window_set_modal (GTK_WINDOW (font_selector), TRUE);
96 	gtk_window_set_position (GTK_WINDOW (font_selector), GTK_WIN_POS_MOUSE);
97 	gtk_window_set_transient_for (GTK_WINDOW (font_selector), GTK_WINDOW (appGUI->main_window));
98 	gtk_font_chooser_set_font (GTK_FONT_CHOOSER (font_selector), config.task_info_font);
99 	gtk_widget_show (font_selector);
100 	response = gtk_dialog_run (GTK_DIALOG (font_selector));
101 
102 	if (response == GTK_RESPONSE_OK) {
103 		font_name = gtk_font_chooser_get_font  (GTK_FONT_CHOOSER (font_selector));
104 		g_strlcpy (config.task_info_font, font_name, MAXFONTNAME);
105 		gtk_entry_set_text (GTK_ENTRY (appGUI->opt->ti_font_entry), font_name);
106 		g_free (font_name);
107 		g_object_set (G_OBJECT (appGUI->tsk->font_tag_object), "font", (gchar *) config.task_info_font, NULL);
108 	}
109 
110 	gtk_widget_destroy (font_selector);
111 }
112 
113 /* ========================================================================== */
114 
115 static void
create_appearance_section(GtkWidget * appearance_vbox,GUI * appGUI)116 create_appearance_section (GtkWidget *appearance_vbox, GUI *appGUI)
117 {
118 	GtkWidget *table, *colors_hbox;
119 	GtkWidget *checkbutton, *label, *color_button, *font_button;
120 	GdkRGBA color;
121 
122 	table = gtk_grid_new ();
123 	gtk_box_pack_start (GTK_BOX (appearance_vbox), table, FALSE, FALSE, 0);
124 	gtk_grid_set_column_spacing (GTK_GRID (table), 4);
125 	gtk_grid_set_row_spacing (GTK_GRID (table), 8);
126 
127 	colors_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
128 	gtk_grid_attach (GTK_GRID (table), colors_hbox, 1, 0, 1, 1);
129 
130 	color_button = gtk_color_button_new ();
131 	if (config.enable_tooltips)
132 		gtk_widget_set_tooltip_text (color_button, _("Color of items that are due today"));
133 	gdk_rgba_parse (&color, config.due_today_color);
134 	gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &color);
135 	gtk_box_pack_start (GTK_BOX (colors_hbox), color_button, FALSE, FALSE, 0);
136 	g_signal_connect (G_OBJECT (color_button), "color-set", G_CALLBACK (due_today_color_changed_cb), appGUI);
137 	appGUI->opt->due_today_color_picker = color_button;
138 
139 	color_button = gtk_color_button_new ();
140 	g_signal_connect (G_OBJECT (color_button), "color-set", G_CALLBACK (due_7days_color_changed_cb), appGUI);
141 	if (config.enable_tooltips)
142 		gtk_widget_set_tooltip_text (color_button, _("Color of items that are due in the next 7 days"));
143 	gdk_rgba_parse (&color, config.due_7days_color);
144 	gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &color);
145 	gtk_box_pack_start (GTK_BOX (colors_hbox), color_button, FALSE, FALSE, 0);
146 	appGUI->opt->due_7days_color_picker = color_button;
147 
148 	color_button = gtk_color_button_new ();
149 	if (config.enable_tooltips)
150 		gtk_widget_set_tooltip_text (color_button, _("Color of items that are past due"));
151 	gdk_rgba_parse(&color, config.past_due_color);
152 	gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &color);
153 	gtk_box_pack_start (GTK_BOX (colors_hbox), color_button, FALSE, FALSE, 0);
154 	g_signal_connect (G_OBJECT (color_button), "color-set", G_CALLBACK (past_due_color_changed_cb), appGUI);
155 	appGUI->opt->past_due_color_picker = color_button;
156 
157 	appGUI->opt->ti_font_entry = gtk_entry_new ();
158 	gtk_entry_set_text (GTK_ENTRY (appGUI->opt->ti_font_entry), config.task_info_font);
159 	gtk_widget_set_can_focus (appGUI->opt->ti_font_entry, FALSE);
160         gtk_widget_set_hexpand(appGUI->opt->ti_font_entry, TRUE);
161 	gtk_grid_attach (GTK_GRID (table), appGUI->opt->ti_font_entry, 1, 1, 1, 1);
162 
163 	font_button = gtk_button_new_from_icon_name ("gtk-select-font", GTK_ICON_SIZE_BUTTON);
164 	gtk_grid_attach (GTK_GRID (table), font_button, 2, 1, 1, 1);
165 	g_signal_connect (G_OBJECT (font_button), "clicked", G_CALLBACK (ti_font_select_cb), appGUI);
166 
167 	label = utl_gui_create_label ("%s:", _("Task info font"));
168 	gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
169 
170 	label = utl_gui_create_label ("%s:", _("Colors"));
171 	gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
172 
173 	checkbutton = gtk_check_button_new_with_mnemonic (_("Show in bold tasks with high priority"));
174 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.tasks_high_in_bold);
175 	gtk_grid_attach (GTK_GRID (table), checkbutton, 0, 3, 3, 1);
176 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (bold_items_cb), appGUI);
177 	appGUI->opt->ct_bold_items_checkbutton = checkbutton;
178 }
179 
180 /* ========================================================================== */
181 
182 static void
visible_columns_changed_cb(GtkToggleButton * widget,GUI * appGUI)183 visible_columns_changed_cb (GtkToggleButton *widget, GUI *appGUI)
184 {
185 	config.tsk_visible_due_date_column = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->vc_due_date_checkbutton));
186 	gtk_tree_view_column_set_visible (appGUI->tsk->tasks_columns[TA_COLUMN_DUE_DATE], config.tsk_visible_due_date_column);
187 	config.tsk_visible_type_column = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->vc_type_checkbutton));
188 	gtk_tree_view_column_set_visible (appGUI->tsk->tasks_columns[TA_COLUMN_TYPE], config.tsk_visible_type_column);
189 	config.tsk_visible_category_column = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->vc_category_checkbutton));
190 	gtk_tree_view_column_set_visible (appGUI->tsk->tasks_columns[TA_COLUMN_CATEGORY], config.tsk_visible_category_column);
191 	config.tsk_visible_priority_column = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->vc_priority_checkbutton));
192 	gtk_tree_view_column_set_visible (appGUI->tsk->tasks_columns[TA_COLUMN_PRIORITY], config.tsk_visible_priority_column);
193 
194 	set_tasks_columns_width (appGUI);
195 }
196 
197 /* ========================================================================== */
198 
199 static void
create_visible_columns_section(GtkWidget * visible_columns_vbox,GUI * appGUI)200 create_visible_columns_section (GtkWidget *visible_columns_vbox, GUI *appGUI)
201 {
202 	GtkWidget *table, *checkbutton;
203 
204 	table = gtk_grid_new ();
205 	gtk_box_pack_start (GTK_BOX (visible_columns_vbox), table, FALSE, FALSE, 0);
206 	gtk_grid_set_row_spacing (GTK_GRID (table), 4);
207 	gtk_grid_set_column_spacing (GTK_GRID (table), 8);
208 
209 	checkbutton = gtk_check_button_new_with_mnemonic (_("Due date"));
210 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.tsk_visible_due_date_column);
211         gtk_widget_set_hexpand(checkbutton, TRUE);
212 	gtk_grid_attach (GTK_GRID (table), checkbutton, 0, 0, 1, 1);
213 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (visible_columns_changed_cb), appGUI);
214 	appGUI->opt->vc_due_date_checkbutton = checkbutton;
215 
216 	checkbutton = gtk_check_button_new_with_mnemonic (_("Type"));
217 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.tsk_visible_type_column);
218         gtk_widget_set_hexpand(checkbutton, TRUE);
219 	gtk_grid_attach (GTK_GRID (table), checkbutton, 1, 0, 1, 1);
220 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (visible_columns_changed_cb), appGUI);
221 	appGUI->opt->vc_type_checkbutton = checkbutton;
222 
223 	checkbutton = gtk_check_button_new_with_mnemonic (_("Priority"));
224 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.tsk_visible_priority_column);
225         gtk_widget_set_hexpand(checkbutton, TRUE);
226 	gtk_grid_attach (GTK_GRID (table), checkbutton, 2, 0, 1, 1);
227 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (visible_columns_changed_cb), appGUI);
228 	appGUI->opt->vc_priority_checkbutton = checkbutton;
229 
230 	checkbutton = gtk_check_button_new_with_mnemonic (_("Category"));
231 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.tsk_visible_category_column);
232         gtk_widget_set_hexpand(checkbutton, TRUE);
233 	gtk_grid_attach (GTK_GRID (table), checkbutton, 3, 0, 1, 1);
234 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (visible_columns_changed_cb), appGUI);
235 	appGUI->opt->vc_category_checkbutton = checkbutton;
236 }
237 
238 /* ========================================================================== */
239 
240 static void
tasks_category_remove_cb(GtkWidget * widget,GUI * appGUI)241 tasks_category_remove_cb (GtkWidget *widget, GUI *appGUI)
242 {
243 	GtkTreePath *path;
244 	GtkTreeIter iter;
245 
246 	gtk_tree_view_get_cursor (GTK_TREE_VIEW (appGUI->opt->tasks_category_treeview), &path, NULL);
247 
248 	if (path != NULL) {
249 		gtk_tree_model_get_iter (GTK_TREE_MODEL (appGUI->opt->tasks_category_store), &iter, path);
250 		gtk_list_store_remove (appGUI->opt->tasks_category_store, &iter);
251 		gtk_tree_path_free (path);
252 		refresh_tasks (appGUI);
253 		set_categories (appGUI);
254 	}
255 }
256 
257 /* ========================================================================== */
258 
259 static void
tasks_category_add_cb(GtkWidget * widget,GUI * appGUI)260 tasks_category_add_cb (GtkWidget *widget, GUI *appGUI)
261 {
262 	GtkTreeIter iter;
263 	const gchar *category_name;
264 	gchar *item;
265 	gboolean has_next;
266 
267 	category_name = gtk_entry_get_text (GTK_ENTRY (appGUI->opt->tasks_category_entry));
268 	if (!strlen (category_name)) return;
269 
270 	has_next = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (appGUI->opt->tasks_category_store), &iter);
271 	while (has_next) {
272 		gtk_tree_model_get (GTK_TREE_MODEL (appGUI->opt->tasks_category_store), &iter, TC_COLUMN_NAME, &item, -1);
273 		if (!strcmp (category_name, item)) {
274 			g_free (item);
275 			return;
276 		}
277 		g_free (item);
278                 has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (appGUI->opt->tasks_category_store), &iter);
279 	}
280 
281 	gtk_list_store_append (appGUI->opt->tasks_category_store, &iter);
282 	gtk_list_store_set (appGUI->opt->tasks_category_store, &iter,
283 	                    TC_COLUMN_NAME, category_name,
284 	                    TC_COLUMN_CALENDAR, TRUE,
285 	                    TC_COLUMN_TASKS, TRUE, -1);
286 
287 	gtk_entry_set_text (GTK_ENTRY (appGUI->opt->tasks_category_entry), "");
288 	gtk_widget_set_sensitive (appGUI->opt->tasks_category_add_button, FALSE);
289 
290 	utl_gui_create_category_combobox (GTK_COMBO_BOX (appGUI->tsk->cf_combobox), appGUI->opt->tasks_category_store, FALSE);
291 	gtk_combo_box_set_active (GTK_COMBO_BOX (appGUI->tsk->cf_combobox), 0);
292 
293 	gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (appGUI->tsk->tasks_filter));
294 	set_categories (appGUI);
295 	refresh_tasks (appGUI);
296 }
297 
298 /* ========================================================================== */
299 
300 static void
tsk_show_in_tasks_list_toggled(GtkCellRendererToggle * cell,gchar * path_str,GUI * appGUI)301 tsk_show_in_tasks_list_toggled (GtkCellRendererToggle *cell, gchar *path_str, GUI *appGUI)
302 {
303 	GtkTreeModel *model;
304 	GtkTreePath *path;
305 	GtkTreeIter iter;
306 	gboolean done_status;
307 
308 	model = GTK_TREE_MODEL (appGUI->opt->tasks_category_store);
309 	path = gtk_tree_path_new_from_string (path_str);
310 
311 	if (path != NULL) {
312 		gtk_tree_model_get_iter (model, &iter, path);   /* get toggled iter */
313 		gtk_tree_model_get (model, &iter, TC_COLUMN_TASKS, &done_status, -1);
314 		gtk_list_store_set (GTK_LIST_STORE (model), &iter, TC_COLUMN_TASKS, !done_status, -1);
315 		refresh_tasks (appGUI);
316 		gtk_tree_path_free (path);
317 	}
318 }
319 
320 /* ========================================================================== */
321 
322 static void
tsk_show_in_calendar_toggled(GtkCellRendererToggle * cell,gchar * path_str,GUI * appGUI)323 tsk_show_in_calendar_toggled (GtkCellRendererToggle *cell, gchar *path_str, GUI *appGUI)
324 {
325 	GtkTreeModel *model;
326 	GtkTreePath *path;
327 	GtkTreeIter iter;
328 	gboolean done_status;
329 
330 	model = GTK_TREE_MODEL (appGUI->opt->tasks_category_store);
331 	path = gtk_tree_path_new_from_string (path_str);
332 
333 	if (path != NULL) {
334 		gtk_tree_model_get_iter (model, &iter, path);   /* get toggled iter */
335 		gtk_tree_model_get (model, &iter, TC_COLUMN_CALENDAR, &done_status, -1);
336 		gtk_list_store_set (GTK_LIST_STORE(model), &iter, TC_COLUMN_CALENDAR, !done_status, -1);
337 		cal_set_day_info (appGUI);
338 		cal_refresh_marks (appGUI);
339 		gtk_tree_path_free (path);
340 	}
341 }
342 
343 /* ========================================================================== */
344 
345 static void
tasks_category_cell_edited_cb(GtkCellRendererText * renderer,gchar * path,gchar * new_text,GUI * appGUI)346 tasks_category_cell_edited_cb (GtkCellRendererText *renderer, gchar *path, gchar *new_text, GUI *appGUI)
347 {
348 	GtkTreeModel *model;
349 	GtkTreeIter iter;
350 
351 	if (g_ascii_strcasecmp (new_text, "") != 0) {
352 		model = gtk_tree_view_get_model (GTK_TREE_VIEW (appGUI->opt->tasks_category_treeview));
353 		if (gtk_tree_model_get_iter_from_string (model, &iter, path)) {
354 			gtk_list_store_set (appGUI->opt->tasks_category_store, &iter, TC_COLUMN_NAME, new_text, -1);
355 		}
356 	}
357 }
358 
359 /* ========================================================================== */
360 
361 static void
tasks_category_selected_cb(GtkTreeSelection * selection,GUI * appGUI)362 tasks_category_selected_cb (GtkTreeSelection *selection, GUI *appGUI)
363 {
364 	GtkTreeModel *model;
365 	GtkTreeIter iter;
366 
367 	if (gtk_tree_selection_get_selected (selection, &model, &iter))
368 		gtk_widget_set_sensitive (appGUI->opt->tasks_category_remove_button, TRUE);
369 	else
370 		gtk_widget_set_sensitive (appGUI->opt->tasks_category_remove_button, FALSE);
371 }
372 
373 /* ========================================================================== */
374 
375 static gint
tasks_category_entry_key_release_cb(GtkEntry * widget,GdkEventKey * event,GUI * appGUI)376 tasks_category_entry_key_release_cb (GtkEntry *widget, GdkEventKey *event, GUI *appGUI)
377 {
378 	gboolean state = FALSE;
379 
380 	if (strlen (gtk_entry_get_text (widget)))
381 		state = TRUE;
382 
383 	gtk_widget_set_sensitive (appGUI->opt->tasks_category_add_button, state);
384 
385 	if (event->keyval == GDK_KEY_Return) {
386 		if (state) tasks_category_add_cb (NULL, appGUI);
387 		return TRUE;
388 	}
389 
390 	return FALSE;
391 }
392 
393 /* ========================================================================== */
394 
395 static void
create_categories_section(GtkWidget * categories_vbox,GUI * appGUI)396 create_categories_section (GtkWidget *categories_vbox, GUI *appGUI)
397 {
398 	GtkTreeViewColumn *column;
399 	GtkCellRenderer *renderer;
400 	GtkWidget *table, *scrolledwindow, *treeview;
401 
402 	table = gtk_grid_new ();
403 	gtk_box_pack_start (GTK_BOX (categories_vbox), table, TRUE, TRUE, 0);
404 	gtk_container_set_border_width (GTK_CONTAINER (table), 8);
405 	gtk_grid_set_row_spacing (GTK_GRID (table), 8);
406 	gtk_grid_set_column_spacing (GTK_GRID (table), 4);
407 
408 	appGUI->opt->tasks_category_entry = gtk_entry_new ();
409         gtk_widget_set_hexpand(appGUI->opt->tasks_category_entry, TRUE);
410 	gtk_grid_attach (GTK_GRID (table), appGUI->opt->tasks_category_entry, 0, 3, 1, 1);
411 	g_signal_connect (G_OBJECT (appGUI->opt->tasks_category_entry), "key_release_event",
412 	                  G_CALLBACK (tasks_category_entry_key_release_cb), appGUI);
413 
414 	scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
415 	gtk_widget_set_hexpand(scrolledwindow, TRUE);
416 	gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW (scrolledwindow), 120);
417 	gtk_grid_attach (GTK_GRID (table), scrolledwindow, 0, 0, 3, 3);
418 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
419 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
420 
421 	treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (appGUI->opt->tasks_category_store));
422 	gtk_container_add (GTK_CONTAINER (scrolledwindow), treeview);
423 	gtk_container_set_border_width (GTK_CONTAINER (treeview), 4);
424 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
425 	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), TRUE);
426 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
427 	appGUI->opt->tasks_category_treeview = treeview;
428 
429 	appGUI->opt->tasks_category_select = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
430 	g_signal_connect (G_OBJECT (appGUI->opt->tasks_category_select), "changed", G_CALLBACK (tasks_category_selected_cb), appGUI);
431 
432 	renderer = gtk_cell_renderer_text_new ();
433 	g_object_set (renderer, "editable", TRUE, "editable-set", TRUE, NULL);
434 	g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (tasks_category_cell_edited_cb), appGUI);
435 
436 	column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer, "text", TC_COLUMN_NAME, NULL);
437 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
438 	gtk_tree_view_column_set_expand (column, TRUE);
439 
440 	renderer = gtk_cell_renderer_toggle_new ();    /* Show in calendar */
441 	column = gtk_tree_view_column_new_with_attributes(_("Calendar"), renderer, "active", TC_COLUMN_CALENDAR, NULL);
442 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
443 	g_signal_connect (renderer, "toggled", G_CALLBACK (tsk_show_in_calendar_toggled), appGUI);
444 
445 	renderer = gtk_cell_renderer_toggle_new ();    /* Show in tasks list */
446 	column = gtk_tree_view_column_new_with_attributes (_("Tasks"), renderer, "active", TC_COLUMN_TASKS, NULL);
447 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
448 	g_signal_connect (renderer, "toggled", G_CALLBACK (tsk_show_in_tasks_list_toggled), appGUI);
449 
450 	appGUI->opt->tasks_category_add_button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_BUTTON);
451 	gtk_widget_set_sensitive (appGUI->opt->tasks_category_add_button, FALSE);
452 	gtk_grid_attach (GTK_GRID (table), appGUI->opt->tasks_category_add_button, 1, 3, 1, 1);
453 	g_signal_connect (appGUI->opt->tasks_category_add_button, "clicked", G_CALLBACK (tasks_category_add_cb), appGUI);
454 
455 	appGUI->opt->tasks_category_remove_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_BUTTON);
456 	gtk_widget_set_sensitive (appGUI->opt->tasks_category_remove_button, FALSE);
457 	gtk_grid_attach (GTK_GRID (table), appGUI->opt->tasks_category_remove_button, 2, 3, 1, 1);
458 	g_signal_connect (appGUI->opt->tasks_category_remove_button, "clicked", G_CALLBACK (tasks_category_remove_cb), appGUI);
459 }
460 
461 /* ========================================================================== */
462 
463 static void
delete_items_cb(GtkToggleButton * togglebutton,GUI * appGUI)464 delete_items_cb (GtkToggleButton *togglebutton, GUI *appGUI)
465 {
466 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->ct_delete_items_checkbutton)))
467 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appGUI->opt->ct_hide_items_checkbutton), FALSE);
468 }
469 
470 /* ========================================================================== */
471 
472 static void
hide_items_cb(GtkToggleButton * togglebutton,GUI * appGUI)473 hide_items_cb (GtkToggleButton *togglebutton, GUI *appGUI)
474 {
475 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->ct_hide_items_checkbutton)))
476 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appGUI->opt->ct_delete_items_checkbutton), FALSE);
477 }
478 
479 /* ========================================================================== */
480 
481 static void
hide_delete_changed_cb(GtkToggleButton * widget,GUI * appGUI)482 hide_delete_changed_cb (GtkToggleButton *widget, GUI *appGUI)
483 {
484 	config.hide_completed = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->ct_hide_items_checkbutton));
485 	gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (appGUI->tsk->tasks_filter));
486 	config.delete_completed = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->opt->ct_delete_items_checkbutton));
487 }
488 
489 /* ========================================================================== */
490 
491 static void
create_tasks_options_section(GtkWidget * tasks_opt_vbox,GUI * appGUI)492 create_tasks_options_section (GtkWidget *tasks_opt_vbox, GUI *appGUI)
493 {
494 	GtkWidget *checkbutton;
495 
496 	checkbutton = gtk_check_button_new_with_mnemonic (_("Hide completed tasks"));
497 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.hide_completed);
498 	gtk_box_pack_start (GTK_BOX (tasks_opt_vbox), checkbutton, FALSE, FALSE, 4);
499 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (hide_delete_changed_cb), appGUI);
500 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (hide_items_cb), appGUI);
501 	appGUI->opt->ct_hide_items_checkbutton = checkbutton;
502 
503 	checkbutton = gtk_check_button_new_with_mnemonic (_("Delete completed tasks without confirmation"));
504 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.delete_completed);
505 	gtk_box_pack_start (GTK_BOX (tasks_opt_vbox), checkbutton, FALSE, FALSE, 4);
506 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (hide_delete_changed_cb), appGUI);
507 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (delete_items_cb), appGUI);
508 	appGUI->opt->ct_delete_items_checkbutton = checkbutton;
509 
510 	checkbutton = gtk_check_button_new_with_mnemonic (_("Add new task when double clicked on tasks list"));
511 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.add_edit);
512 	gtk_box_pack_start (GTK_BOX (tasks_opt_vbox), checkbutton, FALSE, FALSE, 4);
513 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (checkbutton_clicked_cb), &(config.add_edit));
514 	appGUI->opt->ct_add_item_checkbutton = checkbutton;
515 
516 	checkbutton = gtk_check_button_new_with_mnemonic (_("Remember the last selected category"));
517 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), config.remember_category_in_tasks);
518 	gtk_box_pack_start (GTK_BOX (tasks_opt_vbox), checkbutton, FALSE, FALSE, 4);
519 	g_signal_connect (G_OBJECT (checkbutton), "toggled", G_CALLBACK (checkbutton_clicked_cb),
520 	                  &(config.remember_category_in_tasks));
521 	appGUI->opt->ct_remember_category_checkbutton = checkbutton;
522 }
523 /* ========================================================================== */
524 
525 static gint
global_notification_entry_changed_cb(GtkEditable * editable,GUI * appGUI)526 global_notification_entry_changed_cb(GtkEditable *editable, GUI *appGUI) {
527     gchar *text = gtk_editable_get_chars(editable, 0, -1);
528     utl_gui_update_command_status(editable, appGUI->opt->global_notification_valid_image, appGUI);
529     g_strlcpy(config.global_notification_command, text, MAXHELPERCMD);
530     g_free(text);
531     return FALSE;
532 }
533 
534 /* ========================================================================== */
535 
536 static void
sound_alarm_repeat_changed_cb(GtkSpinButton * spinbutton,GUI * appGUI)537 sound_alarm_repeat_changed_cb (GtkSpinButton *spinbutton, GUI *appGUI)
538 {
539 	config.sound_alarm_repeat = (gint) gtk_spin_button_get_value (spinbutton);
540 }
541 
542 /* ========================================================================== */
543 
544 static void
postpone_time_changed_cb(GtkSpinButton * spinbutton,GUI * appGUI)545 postpone_time_changed_cb (GtkSpinButton *spinbutton, GUI *appGUI)
546 {
547 	config.postpone_time = (gint) gtk_spin_button_get_value (spinbutton);
548 }
549 
550 /* ========================================================================== */
551 
552 static void
create_reminder_options_section(GtkWidget * reminder_opt_vbox,GUI * appGUI)553 create_reminder_options_section (GtkWidget *reminder_opt_vbox, GUI *appGUI)
554 {
555 	GtkWidget *table, *label, *spinbutton, *entry, *valid_hbox;
556 	GtkAdjustment *adjustment;
557 	gchar *str;
558 	gint i = 0;
559 
560 	table = gtk_grid_new ();
561 	gtk_box_pack_start (GTK_BOX (reminder_opt_vbox), table, FALSE, FALSE, 0);
562 	gtk_grid_set_column_spacing (GTK_GRID (table), 4);
563 	gtk_grid_set_row_spacing (GTK_GRID (table), 8);
564 
565 	label = utl_gui_create_label ("%s:", _("Postpone time"));
566 	gtk_grid_attach (GTK_GRID (table), label, 0, i, 1, 1);
567 
568 	adjustment = gtk_adjustment_new (0, 0, 1440, 1, 10, 0);
569 	spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 0);
570 	gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
571 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), config.postpone_time);
572 	gtk_grid_attach (GTK_GRID (table), spinbutton, 1, i, 1, 1);
573 	g_signal_connect (G_OBJECT (spinbutton), "value-changed", G_CALLBACK (postpone_time_changed_cb), appGUI);
574 	appGUI->opt->postpone_time_spinbutton = spinbutton;
575 
576 	str = g_strdup_printf ("%s (%s)", _("minutes"), _("0 for disable"));
577 	label = gtk_label_new (str);
578 	g_free (str);
579 	gtk_widget_set_valign(label, GTK_ALIGN_START);
580 	gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
581 	gtk_grid_attach (GTK_GRID (table), label, 2, i, 1, 1);
582 
583 	i++;
584 	label = utl_gui_create_label ("%s:", _("Repeat sound alarm"));
585 	gtk_grid_attach (GTK_GRID (table), label, 0, i, 1, 1);
586 
587 	adjustment = gtk_adjustment_new (0, 0, 100, 1, 10, 0);
588 	spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 0);
589 	gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
590 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), config.sound_alarm_repeat);
591 	gtk_grid_attach (GTK_GRID (table), spinbutton, 1, i, 1, 1);
592 	g_signal_connect (G_OBJECT (spinbutton), "value-changed", G_CALLBACK (sound_alarm_repeat_changed_cb), appGUI);
593 	appGUI->opt->sound_alarm_repeat_spinbutton = spinbutton;
594 
595 	str = g_strdup_printf ("%s (%s)", _("times"), _("0 for disable"));
596 	label = gtk_label_new (str);
597 	g_free (str);
598 	gtk_widget_set_valign(label, GTK_ALIGN_START);
599 	gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
600 	gtk_grid_attach (GTK_GRID (table), label, 2, i, 1, 1);
601 
602 	i++;
603 	label = utl_gui_create_label ("%s:", _("Global notification command"));
604 	gtk_grid_attach (GTK_GRID (table), label, 0, i, 1, 1);
605 
606 	valid_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
607 	gtk_grid_attach (GTK_GRID (table), valid_hbox, 1, i, 2, 1);
608 
609 	entry = gtk_entry_new ();
610 	gtk_entry_set_text (GTK_ENTRY (entry), config.global_notification_command);
611 	gtk_box_pack_start (GTK_BOX (valid_hbox), entry, TRUE, TRUE, 0);
612 	g_signal_connect (G_OBJECT (entry), "changed",
613 	                  G_CALLBACK (global_notification_entry_changed_cb), appGUI);
614 	appGUI->opt->global_notification_cmd_entry = entry;
615 
616 	appGUI->opt->global_notification_valid_image = gtk_image_new ();
617 	gtk_box_pack_start (GTK_BOX (valid_hbox), appGUI->opt->global_notification_valid_image, FALSE, FALSE, 0);
618 
619 	utl_gui_update_command_status (GTK_EDITABLE(entry), appGUI->opt->global_notification_valid_image, appGUI);
620 }
621 
622 /* ========================================================================== */
623 
624 GtkWidget *
tsk_create_preferences_page(GtkWidget * notebook,GUI * appGUI)625 tsk_create_preferences_page (GtkWidget *notebook, GUI *appGUI)
626 {
627 	GtkWidget *vbox_top, *vbox_icon, *vbox, *scrolledwindow;
628 
629 	vbox_top = gtk_box_new (GTK_ORIENTATION_VERTICAL, VBOX_SPACING);
630 	gtk_container_set_border_width (GTK_CONTAINER (vbox_top), BORDER_WIDTH);
631 	scrolledwindow = utl_gui_insert_in_scrolled_window (vbox_top, GTK_SHADOW_ETCHED_IN);
632 	gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow), 2);
633 	vbox_icon = utl_gui_create_icon_with_label (OSMO_STOCK_TASKS, _("Tasks"));
634 
635 	vbox = utl_gui_create_vbox_in_frame (vbox_top, _("Appearance"));
636 	create_appearance_section (vbox, appGUI);
637 
638 	vbox = utl_gui_create_vbox_in_frame (vbox_top, _("Visible columns"));
639 	create_visible_columns_section (vbox, appGUI);
640 
641 	vbox = utl_gui_create_vbox_in_frame (vbox_top, _("Categories"));
642 	create_categories_section (vbox, appGUI);
643 
644 	vbox = utl_gui_create_vbox_in_frame (vbox_top, _("Tasks options"));
645 	create_tasks_options_section (vbox, appGUI);
646 
647 	vbox = utl_gui_create_vbox_in_frame (vbox_top, _("Reminder options"));
648 	create_reminder_options_section (vbox, appGUI);
649 
650 	gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolledwindow, vbox_icon);
651 	gtk_widget_show_all (scrolledwindow);
652 
653 	return scrolledwindow;
654 }
655 
656 /* ========================================================================== */
657 
658 #endif /* TASKS_ENABLED */
659 
660