1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (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 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <math.h>
22 #define __USE_POSIX
23 #include <signal.h>
24
25 #include "applet-struct.h"
26 #include "applet-task-editor.h"
27 #include "applet-calendar.h"
28
29 #define _cd_task_matches_month(pTask, iMonth, iYear) (((pTask)->iMonth == iMonth && ((pTask)->iYear == iYear || (pTask)->iFrequency == CD_TASK_EACH_YEAR)) || (pTask)->iFrequency == CD_TASK_EACH_MONTH)
30 #define _cd_task_matches_day(pTask, iDay, iMonth, iYear) ((pTask)->iDay == iDay && _cd_task_matches_month (pTask, iMonth, iYear))
31
32
33 /////////////
34 // BACKEND //
35 /////////////
36
cd_clock_register_backend(GldiModuleInstance * myApplet,const gchar * cBackendName,CDClockTaskBackend * pBackend)37 void cd_clock_register_backend (GldiModuleInstance *myApplet, const gchar *cBackendName, CDClockTaskBackend *pBackend)
38 {
39 if (myData.pBackends == NULL)
40 myData.pBackends = g_hash_table_new_full (g_str_hash,
41 g_str_equal,
42 g_free,
43 g_free);
44 g_hash_table_insert (myData.pBackends, g_strdup (cBackendName), pBackend);
45 }
46
cd_clock_get_backend(GldiModuleInstance * myApplet,const gchar * cBackendName)47 CDClockTaskBackend *cd_clock_get_backend (GldiModuleInstance *myApplet, const gchar *cBackendName)
48 {
49 CDClockTaskBackend *pBackend = NULL;
50 if (cBackendName != NULL)
51 pBackend = g_hash_table_lookup (myData.pBackends, cBackendName);
52
53 return pBackend;
54 }
55
cd_clock_set_current_backend(GldiModuleInstance * myApplet)56 void cd_clock_set_current_backend (GldiModuleInstance *myApplet)
57 {
58 if (myData.pBackend && myData.pBackend->stop)
59 myData.pBackend->stop (myApplet);
60 myData.pBackend = cd_clock_get_backend (myApplet, myConfig.cTaskMgrName);
61 if (myData.pBackend == NULL)
62 myData.pBackend = cd_clock_get_backend (myApplet, "Default");
63 if (myData.pBackend->init)
64 myData.pBackend->init (myApplet);
65 }
66
67
68 ///////////
69 // TASKS //
70 ///////////
71
_compare_task(CDClockTask * pTask1,CDClockTask * pTask2,gpointer data)72 static int _compare_task (CDClockTask *pTask1, CDClockTask *pTask2, gpointer data)
73 {
74 if (pTask1->iYear < pTask2->iYear)
75 return -1;
76 if (pTask1->iYear > pTask2->iYear)
77 return 1;
78
79 if (pTask1->iMonth < pTask2->iMonth)
80 return -1;
81 if (pTask1->iMonth > pTask2->iMonth)
82 return 1;
83
84 if (pTask1->iDay < pTask2->iDay)
85 return -1;
86 if (pTask1->iDay > pTask2->iDay)
87 return 1;
88
89 if (pTask1->iHour < pTask2->iHour)
90 return -1;
91 if (pTask1->iHour > pTask2->iHour)
92 return 1;
93
94 if (pTask1->iMinute < pTask2->iMinute)
95 return -1;
96 if (pTask1->iMinute > pTask2->iMinute)
97 return 1;
98
99 return 0;
100
101 }
cd_clock_list_tasks(GldiModuleInstance * myApplet)102 void cd_clock_list_tasks (GldiModuleInstance *myApplet)
103 {
104 cd_message ("%s ()", __func__);
105 if (myData.pTasks != NULL)
106 cd_clock_reset_tasks_list (myApplet);
107
108 myData.pTasks = myData.pBackend->get_tasks (myApplet);
109 CDClockTask *pTask;
110 GList *t;
111 for (t = myData.pTasks; t != NULL; t = t->next)
112 {
113 pTask = t->data;
114 pTask->pApplet = myApplet;
115 }
116 myData.pTasks = g_list_sort_with_data (myData.pTasks,
117 (GCompareDataFunc) _compare_task,
118 NULL);
119 myData.pNextTask = cd_clock_get_next_scheduled_task (myApplet);
120 myData.pNextAnniversary = cd_clock_get_next_anniversary (myApplet);
121 }
122
cd_clock_add_task_to_list(CDClockTask * pTask,GldiModuleInstance * myApplet)123 void cd_clock_add_task_to_list (CDClockTask *pTask, GldiModuleInstance *myApplet)
124 {
125 pTask->pApplet = myApplet;
126 myData.pTasks = g_list_insert_sorted (myData.pTasks, pTask, (GCompareFunc)_compare_task);
127 myData.pNextTask = cd_clock_get_next_scheduled_task (myApplet);
128 myData.pNextAnniversary = cd_clock_get_next_anniversary (myApplet);
129 }
130
cd_clock_remove_task_from_list(CDClockTask * pTask,GldiModuleInstance * myApplet)131 void cd_clock_remove_task_from_list (CDClockTask *pTask, GldiModuleInstance *myApplet)
132 {
133 myData.pTasks = g_list_remove (myData.pTasks, pTask);
134 myData.pMissedTasks = g_list_remove (myData.pMissedTasks, pTask);
135 myData.pNextTask = cd_clock_get_next_scheduled_task (myApplet);
136 myData.pNextAnniversary = cd_clock_get_next_anniversary (myApplet);
137 }
138
cd_clock_free_task(CDClockTask * pTask)139 void cd_clock_free_task (CDClockTask *pTask)
140 {
141 if (pTask == NULL)
142 return;
143 if (pTask->iSidWarning != 0)
144 g_source_remove (pTask->iSidWarning);
145 gldi_object_unref (GLDI_OBJECT(pTask->pWarningDialog));
146 g_free (pTask->cTitle);
147 g_free (pTask->cText);
148 g_free (pTask->cTags);
149 g_free (pTask->cID);
150 g_free (pTask);
151 }
152
cd_clock_reset_tasks_list(GldiModuleInstance * myApplet)153 void cd_clock_reset_tasks_list (GldiModuleInstance *myApplet)
154 {
155 g_list_foreach (myData.pTasks, (GFunc)cd_clock_free_task, NULL);
156 g_list_free (myData.pTasks);
157 g_list_free (myData.pMissedTasks);
158 myData.pTasks = NULL;
159 myData.pNextTask = NULL;
160 myData.pMissedTasks = NULL;
161 }
162
cd_clock_get_task_by_id(const gchar * cID,GldiModuleInstance * myApplet)163 CDClockTask *cd_clock_get_task_by_id (const gchar *cID, GldiModuleInstance *myApplet)
164 {
165 if (cID == NULL)
166 return NULL;
167 CDClockTask *pTask;
168 GList *t;
169 for (t = myData.pTasks; t != NULL; t = t->next)
170 {
171 pTask = t->data;
172 if (strcmp (pTask->cID, cID) == 0)
173 return pTask;
174 }
175 return NULL;
176 }
177
cd_clock_get_tasks_for_today(GldiModuleInstance * myApplet)178 gchar *cd_clock_get_tasks_for_today (GldiModuleInstance *myApplet)
179 {
180 guint iDay = myData.currentTime.tm_mday, iMonth = myData.currentTime.tm_mon, iYear = myData.currentTime.tm_year + 1900;
181
182 GString *sTaskString = NULL;
183 CDClockTask *pTask;
184 GList *t;
185 for (t = myData.pTasks; t != NULL; t = t->next)
186 {
187 pTask = t->data;
188 if (_cd_task_matches_day (pTask, iDay, iMonth, iYear))
189 {
190 if (sTaskString == NULL)
191 sTaskString = g_string_new ("");
192 g_string_append_printf (sTaskString, "<b><u>%s</u></b>\n <i>at %d:%02d</i>\n %s\n", pTask->cTitle ? pTask->cTitle : D_("No title"), pTask->iHour, pTask->iMinute, pTask->cText?pTask->cText:"");
193 }
194 }
195
196 if (sTaskString == NULL)
197 return NULL;
198
199 gchar *cTasks = sTaskString->str;
200 g_string_free (sTaskString, FALSE);
201 return cTasks;
202 }
203
cd_clock_get_tasks_for_this_week(GldiModuleInstance * myApplet)204 gchar *cd_clock_get_tasks_for_this_week (GldiModuleInstance *myApplet)
205 {
206 guint iDay = myData.currentTime.tm_mday, iMonth = myData.currentTime.tm_mon, iYear = myData.currentTime.tm_year + 1900;
207
208 GDate* pCurrentDate = g_date_new_dmy (iDay, iMonth + 1, iYear);
209 GDate* pDate = g_date_new ();
210 guint d, m, y;
211 int iDelta;
212 GString *sTaskString = NULL;
213 CDClockTask *pTask;
214 GList *t;
215 for (t = myData.pTasks; t != NULL; t = t->next)
216 {
217 pTask = t->data;
218 switch (pTask->iFrequency)
219 {
220 case CD_TASK_DONT_REPEAT:
221 default:
222 d = pTask->iDay;
223 m = pTask->iMonth+1;
224 y = pTask->iYear;
225 g_date_set_dmy (pDate, d, m, y);
226 iDelta = g_date_days_between (pCurrentDate, pDate);
227 break;
228
229 case CD_TASK_EACH_MONTH:
230 d = pTask->iDay;
231 m = iMonth+1;
232 y = iYear;
233 g_date_set_dmy (pDate, d, m, y);
234 iDelta = g_date_days_between (pCurrentDate, pDate);
235 if (iDelta < 0) // pDate est avant pCurrentDate => on teste le mois d'apres.
236 {
237 if (iMonth < 11)
238 {
239 m = iMonth+2;
240 g_date_set_dmy (pDate, d, m, y);
241 }
242 else
243 {
244 m = 1;
245 y = pTask->iYear + 1;
246 g_date_set_dmy (pDate, d, m, y);
247 }
248 iDelta = g_date_days_between (pCurrentDate, pDate);
249 }
250 break;
251
252 case CD_TASK_EACH_YEAR:
253 d = pTask->iDay;
254 m = pTask->iMonth+1;
255 y = iYear;
256 g_date_set_dmy (pDate, d, m, y);
257 iDelta = g_date_days_between (pCurrentDate, pDate);
258 //g_print ("iDelta : %d/%d/%d -> %d (%s)\n", d, m, y, iDelta, pTask->cTitle);
259 if (iDelta < 0) // pDate est avant pCurrentDate => on teste l'annee d'apres.
260 {
261 y = iYear + 1;
262 g_date_set_dmy (pDate, d, m, y);
263 iDelta = g_date_days_between (pCurrentDate, pDate);
264 }
265 break;
266 }
267
268 if (iDelta >= 0 && iDelta < 7)
269 {
270 if (sTaskString == NULL)
271 sTaskString = g_string_new ("");
272 g_string_append_printf (sTaskString, "<b><u>%s</u></b>\n <i>%d/%d/%d at %d:%02d</i>\n %s\n",
273 pTask->cTitle ? pTask->cTitle : D_("No title"),
274 (myConfig.bNormalDate ? d : y), m, (myConfig.bNormalDate ? y : d),
275 pTask->iHour, pTask->iMinute,
276 pTask->cText?pTask->cText:"");
277 } // on n'arrete pas le parcours si iDelta > 7 pour prendre en compte aussi les anniv.
278 }
279 g_date_free (pCurrentDate);
280 g_date_free (pDate);
281
282 if (sTaskString == NULL)
283 return NULL;
284
285 gchar *cTasks = sTaskString->str;
286 g_string_free (sTaskString, FALSE);
287 return cTasks;
288 }
289
290 #define _compute_index(y,m,d,h,mi) ((((y*12+m)*32+d)*24+h)*60+mi)
cd_clock_get_next_scheduled_task(GldiModuleInstance * myApplet)291 CDClockTask *cd_clock_get_next_scheduled_task (GldiModuleInstance *myApplet)
292 {
293 if (myData.pTasks == NULL)
294 return NULL;
295
296 guint iDay = myData.currentTime.tm_mday;
297 guint iMonth = myData.currentTime.tm_mon;
298 guint iYear = myData.currentTime.tm_year + 1900;
299 guint iHour = myData.currentTime.tm_hour;
300 guint iMinute = myData.currentTime.tm_min;
301 gulong iIndex = _compute_index (iYear, iMonth, iDay, iHour, iMinute);
302 gulong i, iNextIndex=0;
303 //g_print ("%s (%d/%d/%d -> %ld)\n", __func__, iDay, iMonth, iYear, iIndex);
304
305 CDClockTask *pNextTask = NULL;
306 CDClockTask *pTask;
307 GList *t;
308 for (t = myData.pTasks; t != NULL; t = t->next)
309 {
310 pTask = t->data;
311 //g_print ("test de %s (%d/%d/%d)\n", pTask->cTitle, pTask->iDay, pTask->iMonth, pTask->iYear);
312 switch (pTask->iFrequency)
313 {
314 case CD_TASK_DONT_REPEAT:
315 default:
316 i = _compute_index (pTask->iYear, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
317 //g_print (" normal : %ld\n", i);
318 break;
319
320 case CD_TASK_EACH_MONTH:
321 i = _compute_index (iYear, iMonth, pTask->iDay, pTask->iHour, pTask->iMinute); // index pour le mois courant.
322 if (i < iIndex) // on tombe avant, on calcule l'index pour le mois suivant.
323 {
324 if (iMonth < 11)
325 i = _compute_index (iYear, iMonth+1, pTask->iDay, pTask->iHour, pTask->iMinute);
326 else
327 i = _compute_index (iYear+1, 0, pTask->iDay, pTask->iHour, pTask->iMinute);
328 }
329 //g_print (" mensuel : %ld\n", i);
330 break;
331
332 case CD_TASK_EACH_YEAR:
333 i = _compute_index (iYear, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
334 if (i < iIndex) // on tombe avant, on calcule l'index pour l'annee suivante.
335 i = _compute_index (iYear+1, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
336 //g_print (" annuel : %ld\n", i);
337 break;
338 }
339 if (i >= iIndex && (iNextIndex == 0 || i < iNextIndex))
340 {
341 iNextIndex = i;
342 pNextTask = pTask;
343 //g_print ("pNextTask <- %s, index <- %ld\n", pNextTask->cTitle, iNextIndex);
344 }
345 }
346 return pNextTask;
347 }
348
cd_clock_get_next_anniversary(GldiModuleInstance * myApplet)349 CDClockTask *cd_clock_get_next_anniversary (GldiModuleInstance *myApplet)
350 {
351 if (myData.pTasks == NULL)
352 return NULL;
353
354 guint iDay = myData.currentTime.tm_mday;
355 guint iMonth = myData.currentTime.tm_mon;
356 guint iYear = myData.currentTime.tm_year + 1900;
357 guint iHour = myData.currentTime.tm_hour;
358 guint iMinute = myData.currentTime.tm_min;
359 gulong iIndex = _compute_index (iYear, iMonth, iDay, iHour, iMinute);
360 gulong i, iNextIndex=0;
361 //g_print ("%s (%d/%d/%d -> %ld)\n", __func__, iDay, iMonth, iYear, iIndex);
362
363 CDClockTask *pNextAnniversary = NULL;
364 CDClockTask *pTask;
365 GList *t;
366 for (t = myData.pTasks; t != NULL; t = t->next)
367 {
368 pTask = t->data;
369 if (pTask->iFrequency != CD_TASK_EACH_YEAR)
370 continue;
371 //g_print ("test de %s (%d/%d/%d)\n", pTask->cTitle, pTask->iDay, pTask->iMonth, pTask->iYear);
372
373 i = _compute_index (iYear, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
374 if (i < iIndex) // on tombe avant, on calcule l'index pour l'annee suivante.
375 i = _compute_index (iYear+1, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
376 //g_print (" annuel : %ld\n", i);
377
378 if (i > iIndex && (iNextIndex == 0 || i < iNextIndex))
379 {
380 iNextIndex = i;
381 pNextAnniversary = pTask;
382 //g_print ("pNextTask <- %s, index <- %ld\n", pNextTask->cTitle, iNextIndex);
383 }
384 }
385 return pNextAnniversary;
386 }
387
388
cd_clock_get_missed_tasks(GldiModuleInstance * myApplet)389 GList *cd_clock_get_missed_tasks (GldiModuleInstance *myApplet)
390 {
391 GList *pTaskList = NULL;
392 guint iDay = myData.currentTime.tm_mday;
393 guint iMonth = myData.currentTime.tm_mon;
394 guint iYear = myData.currentTime.tm_year + 1900;
395 guint iHour = myData.currentTime.tm_hour;
396 guint iMinute = myData.currentTime.tm_min;
397
398 GDate* pCurrentDate = g_date_new_dmy (iDay, iMonth + 1, iYear);
399 GDate* pDate = g_date_new ();
400 guint d, m, y;
401 int iDelta;
402 CDClockTask *pTask;
403 GList *t;
404 for (t = myData.pTasks; t != NULL; t = t->next)
405 {
406 pTask = t->data;
407 if (pTask->bAcknowledged)
408 continue;
409
410 switch (pTask->iFrequency)
411 {
412 case CD_TASK_DONT_REPEAT:
413 default:
414 d = pTask->iDay;
415 m = pTask->iMonth+1;
416 y = pTask->iYear;
417 g_date_set_dmy (pDate, d, m, y);
418 iDelta = g_date_days_between (pCurrentDate, pDate);
419 break;
420
421 case CD_TASK_EACH_MONTH:
422 d = pTask->iDay;
423 m = iMonth+1;
424 y = iYear;
425 g_date_set_dmy (pDate, d, m, y);
426 iDelta = g_date_days_between (pCurrentDate, pDate);
427 if (iDelta > 0) // pDate est apres pCurrentDate => on teste le mois d'avant.
428 {
429 if (iMonth > 0)
430 {
431 m = iMonth;
432 g_date_set_dmy (pDate, d, m, y);
433 }
434 else
435 {
436 m = 12;
437 y = pTask->iYear - 1;
438 g_date_set_dmy (pDate, d, m, y);
439 }
440 iDelta = g_date_days_between (pCurrentDate, pDate);
441 }
442 break;
443
444 case CD_TASK_EACH_YEAR:
445 d = pTask->iDay;
446 m = pTask->iMonth+1;
447 y = iYear;
448 g_date_set_dmy (pDate, d, m, y);
449 iDelta = g_date_days_between (pCurrentDate, pDate);
450 //g_print ("iDelta : %d/%d/%d -> %d (%s)\n", d, m, y, iDelta, pTask->cTitle);
451 if (iDelta > 0) // pDate est apres pCurrentDate => on teste l'annee d'avant.
452 {
453 y = iYear - 1;
454 g_date_set_dmy (pDate, d, m, y);
455 iDelta = g_date_days_between (pCurrentDate, pDate);
456 }
457 break;
458 }
459
460 if (iDelta <= 0 && iDelta > -7)
461 {
462 if (iDelta == 0) // today's task, check time
463 {
464 if (pTask->iHour > iHour || (pTask->iHour == iHour && pTask->iMinute > iMinute)) // it's in the future, skip it.
465 continue;
466 }
467 pTaskList = g_list_prepend (pTaskList, pTask);
468 } // on n'arrete pas le parcours si iDelta > 7 pour prendre en compte aussi les anniv.
469 }
470 g_date_free (pCurrentDate);
471 g_date_free (pDate);
472
473 return pTaskList;
474 }
475
476
477 //////////////
478 // CALENDAR //
479 //////////////
480
_mark_days(GtkCalendar * pCalendar,GldiModuleInstance * myApplet)481 static void _mark_days (GtkCalendar *pCalendar, GldiModuleInstance *myApplet)
482 {
483 guint iYear, iMonth, iDay;
484 gtk_calendar_get_date (GTK_CALENDAR (pCalendar),
485 &iYear,
486 &iMonth,
487 &iDay);
488
489 CDClockTask *pTask;
490 GList *t;
491 for (t = myData.pTasks; t != NULL; t = t->next)
492 {
493 pTask = t->data;
494 if (_cd_task_matches_month (pTask, iMonth, iYear))
495 {
496 gtk_calendar_mark_day (GTK_CALENDAR (pCalendar), pTask->iDay);
497 }
498 }
499 }
cd_clock_update_calendar_marks(GldiModuleInstance * myApplet)500 void cd_clock_update_calendar_marks (GldiModuleInstance *myApplet)
501 {
502 if (myData.pCalendarDialog != NULL)
503 {
504 gtk_calendar_clear_marks (GTK_CALENDAR (myData.pCalendarDialog->pInteractiveWidget));
505 _mark_days (GTK_CALENDAR (myData.pCalendarDialog->pInteractiveWidget), myApplet);
506 }
507 }
508
_on_display_task_detail(GtkCalendar * calendar,guint iYear,guint iMonth,guint iDay,GldiModuleInstance * myApplet)509 static gchar * _on_display_task_detail (GtkCalendar *calendar, guint iYear, guint iMonth, guint iDay, GldiModuleInstance *myApplet)
510 {
511 if (myData.pTasks == NULL)
512 return NULL;
513
514 //g_print ("%s (%d/%d/%d)\n", __func__, iDay, iMonth, iYear);
515 GString *sDetail = NULL;
516 CDClockTask *pTask;
517 GList *t;
518 for (t = myData.pTasks; t != NULL; t = t->next)
519 {
520 pTask = t->data;
521 if (_cd_task_matches_day (pTask, iDay, iMonth, iYear))
522 {
523 if (sDetail == NULL)
524 sDetail = g_string_new ("");
525 if (pTask->iFrequency == CD_TASK_EACH_YEAR && iYear > pTask->iYear)
526 g_string_append_printf (sDetail, "<b><u>%s</u> (%d %s)</b>\n <i>at %d:%02d</i>\n %s\n",
527 pTask->cTitle ? pTask->cTitle : D_("No title"),
528 iYear - pTask->iYear, D_("years"),
529 pTask->iHour, pTask->iMinute,
530 pTask->cText?pTask->cText:"");
531 else
532 g_string_append_printf (sDetail, "<b><u>%s</u></b>\n <i>at %d:%02d</i>\n %s\n", pTask->cTitle ? pTask->cTitle : D_("No title"),
533 pTask->iHour, pTask->iMinute,
534 pTask->cText?pTask->cText:"");
535 }
536 }
537
538 if (sDetail == NULL)
539 return NULL;
540 gchar *cDetail= sDetail->str;
541 g_string_free (sDetail, FALSE);
542 //g_print ("* detail : %s\n", cDetail);
543 return cDetail;
544 }
545
_on_day_selected_double_click(GtkCalendar * pCalendar,GldiModuleInstance * myApplet)546 static void _on_day_selected_double_click (GtkCalendar *pCalendar, GldiModuleInstance *myApplet)
547 {
548 guint iDay, iMonth, iYear;
549 gtk_calendar_get_date (pCalendar,
550 &iYear,
551 &iMonth,
552 &iDay);
553 cd_clock_build_task_editor (iDay, iMonth, iYear, myApplet);
554 }
555
_on_date_changed(GtkCalendar * pCalendar,GldiModuleInstance * myApplet)556 static void _on_date_changed (GtkCalendar *pCalendar, GldiModuleInstance *myApplet)
557 {
558 gtk_calendar_clear_marks (pCalendar);
559 _mark_days (pCalendar, myApplet);
560 }
561
_on_add_task(GtkWidget * pMenuItem,GldiModuleInstance * myApplet)562 static void _on_add_task (GtkWidget *pMenuItem, GldiModuleInstance *myApplet)
563 {
564 guint iDay, iMonth, iYear;
565 gtk_calendar_get_date (GTK_CALENDAR (myData.pCalendarDialog->pInteractiveWidget),
566 &iYear,
567 &iMonth,
568 &iDay);
569
570 CDClockTask *pTask = g_new0 (CDClockTask, 1);
571 pTask->iDay = iDay;
572 pTask->iMonth = iMonth;
573 pTask->iYear = iYear;
574 pTask->cTitle = g_strdup (D_("No title"));
575 pTask->iHour = 12;
576 gboolean bCreated = myData.pBackend->create_task (pTask, myApplet);
577 if (bCreated)
578 {
579 cd_clock_add_task_to_list (pTask, myApplet);
580
581 cd_clock_update_calendar_marks (myApplet);
582 }
583
584 cd_clock_build_task_editor (iDay, iMonth, iYear, myApplet);
585 }
_on_edit_tasks(GtkWidget * pMenuItem,GldiModuleInstance * myApplet)586 static void _on_edit_tasks (GtkWidget *pMenuItem, GldiModuleInstance *myApplet)
587 {
588 guint iDay, iMonth, iYear;
589 gtk_calendar_get_date (GTK_CALENDAR (myData.pCalendarDialog->pInteractiveWidget),
590 &iYear,
591 &iMonth,
592 &iDay);
593 cd_clock_build_task_editor (iDay, iMonth, iYear, myApplet);
594 }
on_button_released_calendar(GtkWidget * widget,GdkEventButton * pButton,GldiModuleInstance * myApplet)595 static gboolean on_button_released_calendar (GtkWidget *widget,
596 GdkEventButton *pButton,
597 GldiModuleInstance *myApplet)
598 {
599 if (pButton->button == 3) // right-click
600 {
601 GtkWidget *pMenu = gldi_menu_new (NULL);
602
603 // add a task
604 cairo_dock_add_in_menu_with_stock_and_data (D_("Add a new task"), GLDI_ICON_NAME_ADD, G_CALLBACK (_on_add_task), pMenu, myApplet);
605
606 // edit tasks
607 gchar *cLabel = g_strdup_printf ("%s (%s)", D_("Edit tasks"), D_("double-click"));
608 cairo_dock_add_in_menu_with_stock_and_data (cLabel, GLDI_ICON_NAME_EDIT, G_CALLBACK (_on_edit_tasks), pMenu, myApplet);
609 g_free (cLabel);
610
611 gtk_widget_show_all (GTK_WIDGET (pMenu));
612 gtk_menu_popup (GTK_MENU (pMenu),
613 NULL,
614 NULL,
615 NULL,
616 NULL, // data
617 1,
618 gtk_get_current_event_time ());
619 }
620 return FALSE;
621 }
622
cd_clock_build_calendar(GldiModuleInstance * myApplet)623 static GtkWidget *cd_clock_build_calendar (GldiModuleInstance *myApplet)
624 {
625 cd_message ("%s ()", __func__);
626 GtkWidget *pCalendar = gtk_calendar_new ();
627 g_object_set (G_OBJECT (pCalendar), "show-details", FALSE, NULL);
628
629 _mark_days (GTK_CALENDAR (pCalendar), myApplet);
630
631 // reload the marks when the month/year changes
632 g_signal_connect (G_OBJECT (pCalendar), "prev-month" , G_CALLBACK (_on_date_changed), myApplet);
633 g_signal_connect (G_OBJECT (pCalendar), "next-month" , G_CALLBACK (_on_date_changed), myApplet);
634 g_signal_connect (G_OBJECT (pCalendar), "prev-year" , G_CALLBACK (_on_date_changed), myApplet);
635 g_signal_connect (G_OBJECT (pCalendar), "next-year" , G_CALLBACK (_on_date_changed), myApplet);
636 // edit tasks on double-click or right-click
637 g_signal_connect (G_OBJECT (pCalendar), "day-selected-double-click" , G_CALLBACK (_on_day_selected_double_click), myApplet); // it's not a good idea to show the task-editor on left-click, because we can receve the 'click' event when clicking on the month/year buttons, and the 'day-selected' event when we change the month/year.
638 g_signal_connect (G_OBJECT (pCalendar),
639 "button-release-event",
640 G_CALLBACK (on_button_released_calendar),
641 myApplet);
642
643 gtk_calendar_set_detail_func (GTK_CALENDAR (pCalendar),
644 (GtkCalendarDetailFunc) _on_display_task_detail,
645 myApplet,
646 (GDestroyNotify) NULL);
647 return pCalendar;
648 }
649
cd_clock_hide_dialogs(GldiModuleInstance * myApplet)650 void cd_clock_hide_dialogs (GldiModuleInstance *myApplet)
651 {
652 gldi_dialogs_remove_on_icon (myIcon);
653 myData.pCalendarDialog = NULL;
654 }
655
656
_on_dialog_destroyed(GldiModuleInstance * myApplet)657 static void _on_dialog_destroyed (GldiModuleInstance *myApplet)
658 {
659 myData.pCalendarDialog = NULL;
660 }
cd_clock_show_hide_calendar(GldiModuleInstance * myApplet)661 void cd_clock_show_hide_calendar (GldiModuleInstance *myApplet)
662 {
663 cd_debug ("%s (%x)", __func__, myData.pCalendarDialog);
664 if (myData.pCalendarDialog != NULL)
665 {
666 gldi_object_unref (GLDI_OBJECT(myData.pCalendarDialog));
667 myData.pCalendarDialog = NULL;
668 if (myData.pTaskWindow != NULL)
669 {
670 gtk_widget_destroy (myData.pTaskWindow);
671 myData.pTaskWindow = NULL;
672 myData.pModel = NULL;
673 }
674 }
675 else
676 {
677 gldi_dialogs_remove_on_icon (myIcon);
678 GtkWidget *pCalendar = cd_clock_build_calendar (myApplet);
679 myData.pCalendarDialog = gldi_dialog_show (D_("Calendar and tasks"),
680 myIcon, myContainer,
681 0,
682 MY_APPLET_SHARE_DATA_DIR"/dates.svg",
683 pCalendar,
684 NULL,
685 myApplet,
686 (GFreeFunc)_on_dialog_destroyed);
687 }
688 }
689