506e8f9e3d5eead11573da7c39713932bf742826
[ptask-pkg-ubuntu.git] / src / ui_tasktree.c
1 /*
2  * Copyright (C) 2012-2013 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
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
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 General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #define _XOPEN_SOURCE
20 #include <time.h>
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <gtk/gtk.h>
26
27 #include <log.h>
28 #include <ptime.h>
29 #include <settings.h>
30 #include <ui.h>
31 #include <ui_projecttree.h>
32 #include <ui_taskpanel.h>
33 #include <ui_tasktree.h>
34
35 static const char * const MENU_NAMES[] = {
36         "menu_id_visible",
37         "menu_description_visible",
38         "menu_project_visible",
39         "menu_uuid_visible",
40         "menu_priority_visible",
41         "menu_urgency_visible",
42         "menu_creation_date_visible",
43         "menu_due_visible",
44         "menu_start_visible",
45 };
46
47 static GtkTreeView *w_treeview;
48 static GtkMenu *w_menu;
49 static struct task **current_tasks;
50
51 enum {
52         COL_ID,
53         COL_DESCRIPTION,
54         COL_PROJECT,
55         COL_UUID,
56         COL_PRIORITY,
57         COL_URGENCY,
58         COL_CREATION_DATE,
59         COL_DUE,
60         COL_START,
61         COL_COUNT
62 };
63
64 static GtkTreeViewColumn *w_cols[COL_COUNT];
65 static GtkCheckMenuItem *w_menus[COL_COUNT];
66
67 static int priority_to_int(const char *str)
68 {
69         switch (*str) {
70         case 'H':
71                 return 3;
72         case 'M':
73                 return 2;
74         case 'L':
75                 return 1;
76         default:
77                 return 0;
78         }
79 }
80
81 static gint priority_cmp(GtkTreeModel *model,
82                          GtkTreeIter *a,
83                          GtkTreeIter *b,
84                          gpointer user_data)
85 {
86         GValue v1 = {0,}, v2 = {0,};
87         const char *str1, *str2;
88         int i1, i2;
89
90         gtk_tree_model_get_value(model, a, COL_PRIORITY, &v1);
91         str1 = g_value_get_string(&v1);
92         i1 = priority_to_int(str1);
93
94         gtk_tree_model_get_value(model, b, COL_PRIORITY, &v2);
95         str2 = g_value_get_string(&v2);
96         i2 = priority_to_int(str2);
97
98         if (i1 < i2)
99                 return -1;
100         else if (i1 > i2)
101                 return 1;
102         else
103                 return 0;
104 }
105
106 int tasktree_cursor_changed_cbk(GtkTreeView *treeview, gpointer data)
107 {
108         log_fct_enter();
109
110         ui_taskpanel_update(ui_tasktree_get_selected_task());
111
112         log_fct_exit();
113
114         return FALSE;
115 }
116
117 void ui_tasktree_init(GtkBuilder *builder)
118 {
119         GtkTreeModel *model;
120         int i;
121
122         w_treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "tasktree"));
123         w_menu = GTK_MENU(gtk_builder_get_object(builder, "tasktree_menu"));
124         g_object_ref(w_menu);
125
126         model = gtk_tree_view_get_model(GTK_TREE_VIEW(w_treeview));
127         gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model),
128                                         COL_PRIORITY,
129                                         priority_cmp,
130                                         NULL,
131                                         NULL);
132
133         w_cols[COL_ID] = GTK_TREE_VIEW_COLUMN
134                 (gtk_builder_get_object(builder, "col_id"));
135         w_cols[COL_DESCRIPTION] = GTK_TREE_VIEW_COLUMN
136                 (gtk_builder_get_object(builder, "col_description"));
137         w_cols[COL_PROJECT] = GTK_TREE_VIEW_COLUMN
138                 (gtk_builder_get_object(builder, "col_project"));
139         w_cols[COL_UUID] = GTK_TREE_VIEW_COLUMN
140                 (gtk_builder_get_object(builder, "col_uuid"));
141         w_cols[COL_PRIORITY] = GTK_TREE_VIEW_COLUMN
142                 (gtk_builder_get_object(builder, "col_priority"));
143         w_cols[COL_URGENCY] = GTK_TREE_VIEW_COLUMN
144                 (gtk_builder_get_object(builder, "col_urgency"));
145         w_cols[COL_CREATION_DATE] = GTK_TREE_VIEW_COLUMN
146                 (gtk_builder_get_object(builder, "col_creation_date"));
147         w_cols[COL_DUE] = GTK_TREE_VIEW_COLUMN
148                 (gtk_builder_get_object(builder, "col_due"));
149         w_cols[COL_START] = GTK_TREE_VIEW_COLUMN
150                 (gtk_builder_get_object(builder, "col_start"));
151
152         for (i = 0; i < COL_COUNT; i++)
153                 w_menus[i] = GTK_CHECK_MENU_ITEM
154                         (gtk_builder_get_object(builder, MENU_NAMES[i]));
155 }
156
157 void ui_tasktree_load_settings()
158 {
159         int sort_col_id, i;
160         GtkSortType sort_order;
161         GtkTreeModel *model;
162         const char *key;
163         gboolean b;
164
165         sort_col_id = settings_get_int(SETTINGS_KEY_TASKS_SORT_COL);
166         sort_order = settings_get_int(SETTINGS_KEY_TASKS_SORT_ORDER);
167         model = gtk_tree_view_get_model(GTK_TREE_VIEW(w_treeview));
168         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
169                                              sort_col_id, sort_order);
170
171
172         for (i = 0; i < COL_COUNT; i++) {
173                 key = SETTINGS_VISIBLE_COL_KEYS[i];
174                 b = settings_get_boolean(key);
175                 gtk_tree_view_column_set_visible(w_cols[i], b);
176         }
177
178         for (i = 0; i < COL_COUNT; i++) {
179                 key = SETTINGS_VISIBLE_COL_KEYS[i];
180                 b = settings_get_boolean(key);
181                 gtk_check_menu_item_set_active(w_menus[i], b);
182         }
183 }
184
185 void ui_tasktree_save_settings()
186 {
187         int sort_col_id;
188         GtkTreeModel *model;
189         GtkSortType sort_order;
190
191         model = gtk_tree_view_get_model(GTK_TREE_VIEW(w_treeview));
192         gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model),
193                                              &sort_col_id,
194                                              &sort_order);
195         log_debug("ui_tasktree_save_settings(): sort_col_id=%d", sort_col_id);
196         log_debug("ui_tasktree_save_settings(): sort_col_order=%d", sort_order);
197
198         settings_set_int(SETTINGS_KEY_TASKS_SORT_COL, sort_col_id);
199         settings_set_int(SETTINGS_KEY_TASKS_SORT_ORDER, sort_order);
200 }
201
202 const char *ui_tasktree_get_task_uuid()
203 {
204         struct task *t;
205
206         t = ui_tasktree_get_selected_task();
207
208         if (t)
209                 return t->uuid;
210         else
211                 return NULL;
212 }
213
214 struct task *ui_tasktree_get_selected_task()
215 {
216         GtkTreePath *path;
217         GtkTreeViewColumn *cols;
218         struct task **tasks_cur, *result;
219         GtkTreeIter iter;
220         GtkTreeModel *model;
221         GValue value = {0,};
222         const char *uuid;
223
224         log_fct_enter();
225
226         result = NULL;
227
228         if (current_tasks) {
229                 gtk_tree_view_get_cursor(w_treeview, &path, &cols);
230
231                 if (path) {
232                         model = gtk_tree_view_get_model(w_treeview);
233                         gtk_tree_model_get_iter(model, &iter, path);
234                         gtk_tree_model_get_value(model,
235                                                  &iter,
236                                                  COL_UUID,
237                                                  &value);
238
239                         uuid = g_value_get_string(&value);
240
241                         for (tasks_cur = current_tasks; *tasks_cur; tasks_cur++)
242                                 if (!strcmp((*tasks_cur)->uuid, uuid))
243                                         result = *tasks_cur;
244
245                         gtk_tree_path_free(path);
246                 }
247         }
248
249         log_fct_exit();
250
251         return result;
252 }
253
254 void ui_tasktree_set_selected_task(const char *uuid)
255 {
256         GtkTreePath *path;
257         GtkTreeIter iter;
258         GtkTreeModel *model;
259         GValue value = {0,};
260         const char *c_uuid;
261
262         log_fct_enter();
263
264         if (current_tasks) {
265                 model = gtk_tree_view_get_model(w_treeview);
266
267                 if (!gtk_tree_model_get_iter_first(model, &iter))
268                         return ;
269
270                 path = NULL;
271                 while (gtk_tree_model_iter_next(model, &iter)) {
272                         gtk_tree_model_get_value(model,
273                                                  &iter,
274                                                  COL_UUID,
275                                                  &value);
276                         c_uuid = g_value_get_string(&value);
277
278                         if (!strcmp(uuid, c_uuid)) {
279                                 path = gtk_tree_model_get_path(model, &iter);
280                                 break;
281                         }
282
283                         g_value_unset(&value);
284                 }
285
286                 if (!path)
287                         path = gtk_tree_path_new_first();
288                 gtk_tree_view_set_cursor(w_treeview, path, NULL, FALSE);
289         }
290
291         log_fct_exit();
292 }
293
294
295 void ui_tasktree_update(struct task **tasks, const char *prj_filter)
296 {
297         GtkTreeModel *model;
298         struct task **tasks_cur;
299         struct task *task;
300         GtkTreeIter iter;
301         const char *prj;
302         char *s;
303
304         current_tasks = tasks;
305
306         model = gtk_tree_view_get_model(GTK_TREE_VIEW(w_treeview));
307         gtk_list_store_clear(GTK_LIST_STORE(model));
308
309         if (current_tasks) {
310                 for (tasks_cur = current_tasks; *tasks_cur; tasks_cur++) {
311                         task = (*tasks_cur);
312
313                         if (task->project)
314                                 prj = task->project;
315                         else
316                                 prj = "";
317
318                         if (prj_filter && strcmp(prj, prj_filter))
319                                 continue;
320
321                         gtk_list_store_append(GTK_LIST_STORE(model), &iter);
322
323                         gtk_list_store_set(GTK_LIST_STORE(model),
324                                            &iter,
325                                            COL_ID,
326                                            (*tasks_cur)->id,
327                                            COL_DESCRIPTION,
328                                            (*tasks_cur)->description,
329                                            COL_PROJECT,
330                                            prj,
331                                            COL_UUID,
332                                            (*tasks_cur)->uuid,
333                                            COL_PRIORITY,
334                                            (*tasks_cur)->priority,
335                                            COL_URGENCY,
336                                            (*tasks_cur)->urgency,
337                                            -1);
338
339                         if ((*tasks_cur)->start) {
340                                 s = tm_to_str((*tasks_cur)->start);
341                                 gtk_list_store_set
342                                         (GTK_LIST_STORE(model),
343                                          &iter,
344                                          COL_START,
345                                          s,
346                                          -1);
347                                 free(s);
348                         }
349
350                         if ((*tasks_cur)->due) {
351                                 s = tm_to_str((*tasks_cur)->due);
352                                 gtk_list_store_set
353                                         (GTK_LIST_STORE(model),
354                                          &iter,
355                                          COL_DUE,
356                                          s,
357                                          -1);
358                                 free(s);
359                         }
360
361                         if ((*tasks_cur)->entry) {
362                                 s = tm_to_str((*tasks_cur)->entry);
363                                 gtk_list_store_set
364                                         (GTK_LIST_STORE(model),
365                                          &iter,
366                                          COL_CREATION_DATE,
367                                          s,
368                                          -1);
369                                 free(s);
370                         }
371                 }
372         }
373
374 }
375
376 void ui_tasktree_update_filter(const char *prj_filter)
377 {
378         ui_tasktree_update(current_tasks, prj_filter);
379 }
380
381 gboolean tasktree_button_press_event_cbk(GtkWidget *widget,
382                                          GdkEventButton *evt,
383                                          gpointer data)
384 {
385         log_fct_enter();
386
387         if (evt->button == 3)
388                 gtk_menu_popup(w_menu,
389                                NULL, NULL, NULL, NULL, evt->button, evt->time);
390
391         log_fct_exit();
392
393         return FALSE;
394 }
395
396 void tasktree_visible_activate_cbk(GtkAction *action, gpointer data)
397 {
398         gboolean b;
399         int id;
400         const char *aname, *key;
401
402         aname = gtk_action_get_name(action);
403
404         if (!strcmp(aname, "tasktree_id_visible"))
405                 id = COL_ID;
406         else if (!strcmp(aname, "tasktree_description_visible"))
407                 id = COL_DESCRIPTION;
408         else if (!strcmp(aname, "tasktree_project_visible"))
409                 id = COL_PROJECT;
410         else if (!strcmp(aname, "tasktree_uuid_visible"))
411                 id = COL_UUID;
412         else if (!strcmp(aname, "tasktree_priority_visible"))
413                 id = COL_PRIORITY;
414         else if (!strcmp(aname, "tasktree_urgency_visible"))
415                 id = COL_URGENCY;
416         else if (!strcmp(aname, "tasktree_creation_date_visible"))
417                 id = COL_CREATION_DATE;
418         else if (!strcmp(aname, "tasktree_due_visible"))
419                 id = COL_DUE;
420         else if (!strcmp(aname, "tasktree_start_visible"))
421                 id = COL_START;
422         else
423                 id = -1;
424
425         if (id != -1) {
426                 key = SETTINGS_VISIBLE_COL_KEYS[id];
427                 b = settings_get_boolean(key);
428                 settings_set_boolean(key, !b);
429                 gtk_tree_view_column_set_visible(w_cols[id], !b);
430         }
431 }
432
433 void tasktree_done_activate_cbk(GtkAction *action, gpointer data)
434 {
435         struct task *t;
436
437         log_fct_enter();
438
439         t = ui_tasktree_get_selected_task();
440
441         if (t) {
442                 tw_task_done(t->uuid);
443                 refresh();
444         }
445
446         log_fct_exit();
447 }
448
449 void tasktree_start_activate_cbk(GtkAction *action, gpointer data)
450 {
451         struct task *t;
452
453         log_fct_enter();
454
455         t = ui_tasktree_get_selected_task();
456
457         if (t) {
458                 tw_task_start(t->uuid);
459                 refresh();
460         }
461
462         log_fct_exit();
463 }
464
465 void tasktree_stop_activate_cbk(GtkAction *action, gpointer data)
466 {
467         struct task *t;
468
469         log_fct_enter();
470
471         t = ui_tasktree_get_selected_task();
472
473         if (t) {
474                 tw_task_stop(t->uuid);
475                 refresh();
476         }
477
478         log_fct_exit();
479 }