2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
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.
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/>.
25
#include "applet-struct.h"
26
#include "applet-task-editor.h"
27
#include "applet-calendar.h"
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))
37
void cd_clock_register_backend (CairoDockModuleInstance *myApplet, const gchar *cBackendName, CDClockTaskBackend *pBackend)
39
if (myData.pBackends == NULL)
40
myData.pBackends = g_hash_table_new_full (g_str_hash,
44
g_hash_table_insert (myData.pBackends, g_strdup (cBackendName), pBackend);
47
CDClockTaskBackend *cd_clock_get_backend (CairoDockModuleInstance *myApplet, const gchar *cBackendName)
49
CDClockTaskBackend *pBackend = NULL;
50
if (cBackendName != NULL)
51
pBackend = g_hash_table_lookup (myData.pBackends, cBackendName);
56
void cd_clock_set_current_backend (CairoDockModuleInstance *myApplet)
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);
72
static int _compare_task (CDClockTask *pTask1, CDClockTask *pTask2, gpointer data)
74
if (pTask1->iYear < pTask2->iYear)
76
if (pTask1->iYear > pTask2->iYear)
79
if (pTask1->iMonth < pTask2->iMonth)
81
if (pTask1->iMonth > pTask2->iMonth)
84
if (pTask1->iDay < pTask2->iDay)
86
if (pTask1->iDay > pTask2->iDay)
89
if (pTask1->iHour < pTask2->iHour)
91
if (pTask1->iHour > pTask2->iHour)
94
if (pTask1->iMinute < pTask2->iMinute)
96
if (pTask1->iMinute > pTask2->iMinute)
102
void cd_clock_list_tasks (CairoDockModuleInstance *myApplet)
104
cd_message ("%s ()", __func__);
105
if (myData.pTasks != NULL)
106
cd_clock_reset_tasks_list (myApplet);
108
myData.pTasks = myData.pBackend->get_tasks (myApplet);
111
for (t = myData.pTasks; t != NULL; t = t->next)
114
pTask->pApplet = myApplet;
116
myData.pTasks = g_list_sort_with_data (myData.pTasks,
117
(GCompareDataFunc) _compare_task,
119
myData.pNextTask = cd_clock_get_next_scheduled_task (myApplet);
120
myData.pNextAnniversary = cd_clock_get_next_anniversary (myApplet);
123
void cd_clock_add_task_to_list (CDClockTask *pTask, CairoDockModuleInstance *myApplet)
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);
131
void cd_clock_remove_task_from_list (CDClockTask *pTask, CairoDockModuleInstance *myApplet)
133
myData.pTasks = g_list_remove (myData.pTasks, pTask);
134
myData.pNextTask = cd_clock_get_next_scheduled_task (myApplet);
135
myData.pNextAnniversary = cd_clock_get_next_anniversary (myApplet);
138
void cd_clock_free_task (CDClockTask *pTask)
142
if (pTask->iSidWarning != 0)
143
g_source_remove (pTask->iSidWarning);
144
if (pTask->pWarningDialog != NULL)
145
cairo_dock_dialog_unreference (pTask->pWarningDialog);
146
g_free (pTask->cTitle);
147
g_free (pTask->cText);
148
g_free (pTask->cTags);
153
void cd_clock_reset_tasks_list (CairoDockModuleInstance *myApplet)
155
g_list_foreach (myData.pTasks, (GFunc)cd_clock_free_task, NULL);
156
g_list_free (myData.pTasks);
157
myData.pTasks = NULL;
158
myData.pNextTask = NULL;
161
CDClockTask *cd_clock_get_task_by_id (const gchar *cID, CairoDockModuleInstance *myApplet)
167
for (t = myData.pTasks; t != NULL; t = t->next)
170
if (strcmp (pTask->cID, cID) == 0)
176
gchar *cd_clock_get_tasks_for_today (CairoDockModuleInstance *myApplet)
178
guint iDay = myData.currentTime.tm_mday, iMonth = myData.currentTime.tm_mon, iYear = myData.currentTime.tm_year + 1900;
180
GString *sTaskString = NULL;
183
for (t = myData.pTasks; t != NULL; t = t->next)
186
if (_cd_task_matches_day (pTask, iDay, iMonth, iYear))
188
if (sTaskString == NULL)
189
sTaskString = g_string_new ("");
190
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:"");
194
if (sTaskString == NULL)
197
gchar *cTasks = sTaskString->str;
198
g_string_free (sTaskString, FALSE);
202
gchar *cd_clock_get_tasks_for_this_week (CairoDockModuleInstance *myApplet)
204
guint iDay = myData.currentTime.tm_mday, iMonth = myData.currentTime.tm_mon, iYear = myData.currentTime.tm_year + 1900;
206
GDate* pCurrentDate = g_date_new_dmy (iDay, iMonth + 1, iYear);
207
GDate* pDate = g_date_new ();
210
GString *sTaskString = NULL;
213
for (t = myData.pTasks; t != NULL; t = t->next)
216
switch (pTask->iFrequency)
218
case CD_TASK_DONT_REPEAT:
223
g_date_set_dmy (pDate, d, m, y);
224
iDelta = g_date_days_between (pCurrentDate, pDate);
227
case CD_TASK_EACH_MONTH:
231
g_date_set_dmy (pDate, d, m, y);
232
iDelta = g_date_days_between (pCurrentDate, pDate);
233
if (iDelta < 0) // pDate est avant pCurrentDate => on teste le mois d'apres.
238
g_date_set_dmy (pDate, d, m, y);
243
y = pTask->iYear + 1;
244
g_date_set_dmy (pDate, d, m, y);
246
iDelta = g_date_days_between (pCurrentDate, pDate);
250
case CD_TASK_EACH_YEAR:
254
g_date_set_dmy (pDate, d, m, y);
255
iDelta = g_date_days_between (pCurrentDate, pDate);
256
//g_print ("iDelta : %d/%d/%d -> %d (%s)\n", d, m, y, iDelta, pTask->cTitle);
257
if (iDelta < 0) // pDate est avant pCurrentDate => on teste l'annee d'apres.
260
g_date_set_dmy (pDate, d, m, y);
261
iDelta = g_date_days_between (pCurrentDate, pDate);
266
if (iDelta >= 0 && iDelta < 7)
268
if (sTaskString == NULL)
269
sTaskString = g_string_new ("");
270
g_string_append_printf (sTaskString, "<b><u>%s</u></b>\n <i>%d/%d/%d at %d:%02d</i>\n %s\n",
271
pTask->cTitle ? pTask->cTitle : D_("No title"),
272
(myConfig.bNormalDate ? d : y), m, (myConfig.bNormalDate ? y : d),
273
pTask->iHour, pTask->iMinute,
274
pTask->cText?pTask->cText:"");
275
} // on n'arrete pas le parcours si iDelta > 7 pour prendre en compte aussi les anniv.
277
g_date_free (pCurrentDate);
280
if (sTaskString == NULL)
283
gchar *cTasks = sTaskString->str;
284
g_string_free (sTaskString, FALSE);
288
#define _compute_index(y,m,d,h,mi) ((((y*12+m)*32+d)*24+h)*60+mi)
289
CDClockTask *cd_clock_get_next_scheduled_task (CairoDockModuleInstance *myApplet)
291
if (myData.pTasks == NULL)
294
guint iDay = myData.currentTime.tm_mday;
295
guint iMonth = myData.currentTime.tm_mon;
296
guint iYear = myData.currentTime.tm_year + 1900;
297
guint iHour = myData.currentTime.tm_hour;
298
guint iMinute = myData.currentTime.tm_min;
299
gulong iIndex = _compute_index (iYear, iMonth, iDay, iHour, iMinute);
300
gulong i, iNextIndex=0;
301
//g_print ("%s (%d/%d/%d -> %ld)\n", __func__, iDay, iMonth, iYear, iIndex);
303
CDClockTask *pNextTask = NULL;
306
for (t = myData.pTasks; t != NULL; t = t->next)
309
//g_print ("test de %s (%d/%d/%d)\n", pTask->cTitle, pTask->iDay, pTask->iMonth, pTask->iYear);
310
switch (pTask->iFrequency)
312
case CD_TASK_DONT_REPEAT:
314
i = _compute_index (pTask->iYear, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
315
//g_print (" normal : %ld\n", i);
318
case CD_TASK_EACH_MONTH:
319
i = _compute_index (iYear, iMonth, pTask->iDay, pTask->iHour, pTask->iMinute); // index pour le mois courant.
320
if (i < iIndex) // on tombe avant, on calcule l'index pour le mois suivant.
323
i = _compute_index (iYear, iMonth+1, pTask->iDay, pTask->iHour, pTask->iMinute);
325
i = _compute_index (iYear+1, 0, pTask->iDay, pTask->iHour, pTask->iMinute);
327
//g_print (" mensuel : %ld\n", i);
330
case CD_TASK_EACH_YEAR:
331
i = _compute_index (iYear, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
332
if (i < iIndex) // on tombe avant, on calcule l'index pour l'annee suivante.
333
i = _compute_index (iYear+1, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
334
//g_print (" annuel : %ld\n", i);
337
if (i >= iIndex && (iNextIndex == 0 || i < iNextIndex))
341
//g_print ("pNextTask <- %s, index <- %ld\n", pNextTask->cTitle, iNextIndex);
347
CDClockTask *cd_clock_get_next_anniversary (CairoDockModuleInstance *myApplet)
349
if (myData.pTasks == NULL)
352
guint iDay = myData.currentTime.tm_mday;
353
guint iMonth = myData.currentTime.tm_mon;
354
guint iYear = myData.currentTime.tm_year + 1900;
355
guint iHour = myData.currentTime.tm_hour;
356
guint iMinute = myData.currentTime.tm_min;
357
gulong iIndex = _compute_index (iYear, iMonth, iDay, iHour, iMinute);
358
gulong i, iNextIndex=0;
359
//g_print ("%s (%d/%d/%d -> %ld)\n", __func__, iDay, iMonth, iYear, iIndex);
361
CDClockTask *pNextAnniversary = NULL;
364
for (t = myData.pTasks; t != NULL; t = t->next)
367
if (pTask->iFrequency != CD_TASK_EACH_YEAR)
369
//g_print ("test de %s (%d/%d/%d)\n", pTask->cTitle, pTask->iDay, pTask->iMonth, pTask->iYear);
371
i = _compute_index (iYear, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
372
if (i < iIndex) // on tombe avant, on calcule l'index pour l'annee suivante.
373
i = _compute_index (iYear+1, pTask->iMonth, pTask->iDay, pTask->iHour, pTask->iMinute);
374
//g_print (" annuel : %ld\n", i);
376
if (i > iIndex && (iNextIndex == 0 || i < iNextIndex))
379
pNextAnniversary = pTask;
380
//g_print ("pNextTask <- %s, index <- %ld\n", pNextTask->cTitle, iNextIndex);
383
return pNextAnniversary;
391
static void _mark_days (GtkCalendar *pCalendar, CairoDockModuleInstance *myApplet)
393
guint iYear, iMonth, iDay;
394
gtk_calendar_get_date (GTK_CALENDAR (pCalendar),
401
for (t = myData.pTasks; t != NULL; t = t->next)
404
if (_cd_task_matches_month (pTask, iMonth, iYear))
406
gtk_calendar_mark_day (GTK_CALENDAR (pCalendar), pTask->iDay);
410
void cd_clock_update_calendar_marks (CairoDockModuleInstance *myApplet)
412
if (myData.pCalendarDialog != NULL)
414
gtk_calendar_clear_marks (GTK_CALENDAR (myData.pCalendarDialog->pInteractiveWidget));
415
_mark_days (GTK_CALENDAR (myData.pCalendarDialog->pInteractiveWidget), myApplet);
419
static gchar * _on_display_task_detail (GtkCalendar *calendar, guint iYear, guint iMonth, guint iDay, CairoDockModuleInstance *myApplet)
421
if (myData.pTasks == NULL)
424
//g_print ("%s (%d/%d/%d)\n", __func__, iDay, iMonth, iYear);
425
GString *sDetail = NULL;
428
for (t = myData.pTasks; t != NULL; t = t->next)
431
if (_cd_task_matches_day (pTask, iDay, iMonth, iYear))
434
sDetail = g_string_new ("");
435
if (pTask->iFrequency == CD_TASK_EACH_YEAR && iYear > pTask->iYear)
436
g_string_append_printf (sDetail, "<b><u>%s</u> (%d %s)</b>\n <i>at %d:%02d</i>\n %s\n",
437
pTask->cTitle ? pTask->cTitle : D_("No title"),
438
iYear - pTask->iYear, D_("years"),
439
pTask->iHour, pTask->iMinute,
440
pTask->cText?pTask->cText:"");
442
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"),
443
pTask->iHour, pTask->iMinute,
444
pTask->cText?pTask->cText:"");
450
gchar *cDetail= sDetail->str;
451
g_string_free (sDetail, FALSE);
452
//g_print ("* detail : %s\n", cDetail);
456
static void _on_day_selected (GtkCalendar *pCalendar, CairoDockModuleInstance *myApplet)
458
//g_print ("%s ()\n", __func__);
462
static void _on_day_selected_double_click (GtkCalendar *pCalendar, CairoDockModuleInstance *myApplet)
464
guint iDay, iMonth, iYear;
465
gtk_calendar_get_date (pCalendar,
469
cd_clock_build_task_editor (iDay, iMonth, iYear, myApplet);
472
static void _on_month_changed (GtkCalendar *pCalendar, CairoDockModuleInstance *myApplet)
474
gtk_calendar_clear_marks (pCalendar);
475
_mark_days (pCalendar, myApplet);
478
static void _on_year_changed (GtkCalendar *pCalendar, CairoDockModuleInstance *myApplet)
480
gtk_calendar_clear_marks (pCalendar);
481
_mark_days (pCalendar, myApplet);
484
static gboolean on_button_press_calendar (GtkWidget *widget,
485
GdkEventButton *pButton,
486
CairoDockModuleInstance *myApplet)
488
myData.iButtonPressTime = pButton->time;
492
static GtkWidget *cd_clock_build_calendar (CairoDockModuleInstance *myApplet)
494
cd_message ("%s ()", __func__);
495
GtkWidget *pCalendar = gtk_calendar_new ();
496
g_object_set (G_OBJECT (pCalendar), "show-details", FALSE, NULL);
498
_mark_days (GTK_CALENDAR (pCalendar), myApplet);
500
g_signal_connect (G_OBJECT (pCalendar), "day-selected" , G_CALLBACK (_on_day_selected), myApplet);
501
g_signal_connect (G_OBJECT (pCalendar), "day-selected-double-click" , G_CALLBACK (_on_day_selected_double_click), myApplet);
502
g_signal_connect (G_OBJECT (pCalendar), "prev-month" , G_CALLBACK (_on_month_changed), myApplet);
503
g_signal_connect (G_OBJECT (pCalendar), "next-month" , G_CALLBACK (_on_month_changed), myApplet);
504
g_signal_connect (G_OBJECT (pCalendar), "prev-year" , G_CALLBACK (_on_year_changed), myApplet);
505
g_signal_connect (G_OBJECT (pCalendar), "next-year" , G_CALLBACK (_on_year_changed), myApplet);
506
g_signal_connect (G_OBJECT (pCalendar),
507
"button-press-event",
508
G_CALLBACK (on_button_press_calendar),
511
#if (GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 14)
512
gtk_calendar_set_detail_func (GTK_CALENDAR (pCalendar),
513
(GtkCalendarDetailFunc) _on_display_task_detail,
515
(GDestroyNotify) NULL);
520
void cd_clock_hide_dialogs (CairoDockModuleInstance *myApplet)
522
cairo_dock_remove_dialog_if_any (myIcon);
523
myData.pCalendarDialog = NULL;
526
static gboolean on_button_press_dialog (GtkWidget *widget,
527
GdkEventButton *pButton,
528
CairoDockModuleInstance *myApplet)
531
if (pButton->time > myData.iButtonPressTime)
533
cairo_dock_dialog_unreference (myData.pCalendarDialog);
534
myData.pCalendarDialog = NULL;
536
CD_APPLET_LEAVE (FALSE);
538
void cd_clock_show_hide_calendar (CairoDockModuleInstance *myApplet)
540
if (myData.pCalendarDialog != NULL)
542
cairo_dock_dialog_unreference (myData.pCalendarDialog);
543
myData.pCalendarDialog = NULL;
544
if (myData.pTaskWindow != NULL)
546
gtk_widget_destroy (myData.pTaskWindow);
547
myData.pTaskWindow = NULL;
548
myData.pModel = NULL;
553
cairo_dock_remove_dialog_if_any (myIcon);
554
GtkWidget *pCalendar = cd_clock_build_calendar (myApplet);
555
myData.pCalendarDialog = cairo_dock_show_dialog_full (D_("Calendar and tasks"),
558
MY_APPLET_SHARE_DATA_DIR"/dates.svg",
561
g_signal_connect (G_OBJECT (myData.pCalendarDialog->container.pWidget),
562
"button-press-event",
563
G_CALLBACK (on_button_press_dialog),