/* Monolith calendar widget. * - by Richard W.M. Jones * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ml_calendar.c,v 1.7 2003/02/22 15:34:25 rich Exp $ */ #include #include #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ml_calendar_lib.h" #include "ml_calendar_month.h" #include "ml_calendar_day.h" #include "ml_calendar_notes.h" #include "ml_calendar_visible.h" #include "ml_calendar.h" static void repaint (void *, ml_session, const char *, io_handle); struct ml_widget_operations calendar_ops = { repaint: repaint }; struct ml_calendar { struct ml_widget_operations *ops; pool pool; /* Pool for allocations. */ ml_session session; /* Current session. */ const char *conninfo; /* Database connection. */ vector calendars; /* Visible calendars (resource IDs). */ int yyyy, mm, dd; /* Currently visible year, month, day. */ ml_table_layout tbl; /* Top-level table layout. */ ml_button prev_month; /* Previous month button. */ ml_text_label month_lbl; /* Month label. */ ml_button next_month; /* Next month button. */ ml_button prev_year; /* Previous year button. */ ml_text_label year_lbl; /* Year label. */ ml_button next_year; /* Next year button. */ ml_calendar_month month; /* Month view (left hand side). */ ml_button prev_day; /* Previous day button. */ ml_button today; /* Today button. */ ml_button next_day; /* Next day button. */ ml_calendar_notes notes; /* Day notes. */ ml_calendar_day day; /* Day view (right hand side). */ ml_calendar_visible visible; /* Visible calendar controls. */ }; static void prev_month (ml_session, void *); static void next_month (ml_session, void *); static void prev_year (ml_session, void *); static void next_year (ml_session, void *); static void prev_day (ml_session, void *); static void today (ml_session, void *); static void next_day (ml_session, void *); ml_calendar new_ml_calendar (pool pool, ml_session session, const char *conninfo, const char *res_name) { ml_calendar w = pmalloc (pool, sizeof *w); ml_vertical_layout vert; ml_horizontal_layout horiz; w->ops = &calendar_ops; w->pool = pool; w->session = session; w->conninfo = conninfo; w->calendars = new_vector (pool, int); w->visible = 0; if (ml_calendar_add_calendar (w, res_name) == -1) return 0; /* We won't initialise these until the end of this function, so set * these to known bad values in case one of the constructors below * accidentally tries to use them. */ w->yyyy = w->mm = w->dd = -1; /* Create the calendar layout. */ w->tbl = new_ml_table_layout (pool, 2, 2); vert = new_ml_vertical_layout (pool); horiz = new_ml_horizontal_layout (pool); w->prev_month = new_ml_button (pool, "<<"); ml_button_set_callback (w->prev_month, prev_month, session, w); ml_widget_set_property (w->prev_month, "button.style", "link"); ml_horizontal_layout_pack (horiz, w->prev_month); w->month_lbl = new_ml_text_label (pool, 0); ml_horizontal_layout_pack (horiz, w->month_lbl); w->next_month = new_ml_button (pool, ">>"); ml_button_set_callback (w->next_month, next_month, session, w); ml_widget_set_property (w->next_month, "button.style", "link"); ml_horizontal_layout_pack (horiz, w->next_month); w->prev_year = new_ml_button (pool, "<<"); ml_button_set_callback (w->prev_year, prev_year, session, w); ml_widget_set_property (w->prev_year, "button.style", "link"); ml_horizontal_layout_pack (horiz, w->prev_year); w->year_lbl = new_ml_text_label (pool, 0); ml_horizontal_layout_pack (horiz, w->year_lbl); w->next_year = new_ml_button (pool, ">>"); ml_button_set_callback (w->next_year, next_year, session, w); ml_widget_set_property (w->next_year, "button.style", "link"); ml_horizontal_layout_pack (horiz, w->next_year); ml_vertical_layout_pack (vert, horiz); w->month = new_ml_calendar_month (pool, session, conninfo, w); ml_vertical_layout_pack (vert, w->month); horiz = new_ml_horizontal_layout (pool); w->prev_day = new_ml_button (pool, "Prev"); ml_button_set_callback (w->prev_day, prev_day, session, w); ml_horizontal_layout_pack (horiz, w->prev_day); w->today = new_ml_button (pool, "Today"); ml_button_set_callback (w->today, today, session, w); ml_horizontal_layout_pack (horiz, w->today); w->next_day = new_ml_button (pool, "Next"); ml_button_set_callback (w->next_day, next_day, session, w); ml_horizontal_layout_pack (horiz, w->next_day); ml_vertical_layout_pack (vert, horiz); w->notes = new_ml_calendar_notes (pool, session, conninfo, w); ml_vertical_layout_pack (vert, w->notes); ml_table_layout_pack (w->tbl, vert, 0, 0); ml_table_layout_set_align (w->tbl, 0, 0, "center"); ml_table_layout_set_valign (w->tbl, 0, 0, "top"); w->day = new_ml_calendar_day (pool, session, conninfo, w); ml_table_layout_pack (w->tbl, w->day, 0, 1); ml_table_layout_set_valign (w->tbl, 0, 1, "top"); w->visible = new_ml_calendar_visible (pool, session, conninfo, w); ml_table_layout_pack (w->tbl, w->visible, 1, 0); ml_table_layout_set_colspan (w->tbl, 1, 0, 2); ml_table_layout_set_valign (w->tbl, 1, 0, "top"); /* Update visible calendars. */ ml_calendar_visible_update (w->visible); /* Set the calendar to today's date. */ today (session, w); return w; } int ml_calendar_add_calendar (ml_calendar w, const char *res_name) { db_handle dbh; st_handle sth; int resid; dbh = get_db_handle (w->conninfo, DBI_THROW_ERRORS); /* Get the resource ID. */ sth = st_prepare_cached (dbh, "select r.resid from ml_resources r, ml_calendar c " "where r.name = ? and r.resid = c.resid", DBI_STRING); st_execute (sth, res_name); st_bind (sth, 0, resid, DBI_INT); if (!st_fetch (sth)) return -1; /* Not found. */ vector_push_back (w->calendars, resid); put_db_handle (dbh); if (w->visible) ml_calendar_visible_update (w->visible); return 0; } int ml_calendar_del_calendar (ml_calendar w, const char *res_name) { db_handle dbh; st_handle sth; int resid, i, r; /* Don't allow the last calendar to be deleted, no matter what. */ if (vector_size (w->calendars) == 1) return -1; dbh = get_db_handle (w->conninfo, DBI_THROW_ERRORS); /* Get the resource ID. */ sth = st_prepare_cached (dbh, "select r.resid from ml_resources r, ml_calendar c " "where r.name = ? and r.resid = c.resid", DBI_INT); st_execute (sth, res_name); st_bind (sth, 0, resid, DBI_INT); if (!st_fetch (sth)) return -1; /* Not found. */ /* Search for the resource in the list of calendars, and delete it. */ for (i = 0; i < vector_size (w->calendars); ++i) { vector_get (w->calendars, i, r); if (r == resid) { vector_erase (w->calendars, i); goto found; } } return -1; /* Not found. */ found: put_db_handle (dbh); if (w->visible) ml_calendar_visible_update (w->visible); return 0; } const vector _ml_calendar_get_calendars (ml_calendar w) { return w->calendars; } static void prev_month (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; int dd = w->dd, mm = w->mm, yyyy = w->yyyy; if (mm == 1 && yyyy == 1900) return; mm--; if (mm == 0) { yyyy--; mm = 12; } if (dd > _ml_calendar_days_in_month (mm, yyyy)) dd = _ml_calendar_days_in_month (mm, yyyy); ml_calendar_set_date (w, yyyy, mm, dd); } static void next_month (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; int dd = w->dd, mm = w->mm, yyyy = w->yyyy; mm++; if (mm == 13) { yyyy++; mm = 1; } if (dd > _ml_calendar_days_in_month (mm, yyyy)) dd = _ml_calendar_days_in_month (mm, yyyy); ml_calendar_set_date (w, yyyy, mm, dd); } static void prev_year (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; int dd = w->dd, mm = w->mm, yyyy = w->yyyy; if (yyyy == 1900) return; yyyy--; if (dd > _ml_calendar_days_in_month (mm, yyyy)) dd = _ml_calendar_days_in_month (mm, yyyy); ml_calendar_set_date (w, yyyy, mm, dd); } static void next_year (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; int dd = w->dd, mm = w->mm, yyyy = w->yyyy; yyyy++; if (dd > _ml_calendar_days_in_month (mm, yyyy)) dd = _ml_calendar_days_in_month (mm, yyyy); ml_calendar_set_date (w, yyyy, mm, dd); } static void prev_day (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; int dd = w->dd, mm = w->mm, yyyy = w->yyyy; if (dd == 1 && mm == 1 && yyyy == 1900) return; dd--; if (dd == 0) { mm--; if (mm == 0) { yyyy--; mm = 12; } dd = _ml_calendar_days_in_month (mm, yyyy); } ml_calendar_set_date (w, yyyy, mm, dd); } static void today (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; struct tm *tm; time_t t; time (&t); tm = localtime (&t); ml_calendar_set_date (w, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); } static void next_day (ml_session session, void *vw) { ml_calendar w = (ml_calendar) vw; int dd = w->dd, mm = w->mm, yyyy = w->yyyy; dd++; if (dd > _ml_calendar_days_in_month (mm, yyyy)) { mm++; if (mm == 13) { yyyy++; mm = 1; } dd = 1; } ml_calendar_set_date (w, yyyy, mm, dd); } extern void ml_calendar_set_date (ml_calendar w, int yyyy, int mm, int dd) { /* Verify that this is a correct date. */ assert (yyyy >= 1900); assert (1 <= mm && mm <= 12); assert (1 <= dd && dd <= _ml_calendar_days_in_month (mm, yyyy)); /* Set the date and update the widgets. */ w->yyyy = yyyy; w->mm = mm; w->dd = dd; ml_widget_set_property (w->month_lbl, "text", _ml_calendar_text_month (w->mm)); ml_widget_set_property (w->year_lbl, "text", pitoa (w->pool, w->yyyy)); ml_calendar_month_set_date (w->month, yyyy, mm, dd); ml_calendar_day_set_date (w->day, yyyy, mm, dd); ml_calendar_notes_set_date (w->notes, yyyy, mm, dd); } extern void ml_calendar_get_date (ml_calendar w, int *yyyy, int *mm, int *dd) { *yyyy = w->yyyy; *mm = w->mm; *dd = w->dd; } static void repaint (void *vw, ml_session session, const char *windowid, io_handle io) { ml_calendar w = (ml_calendar) vw; /* Repaint the top-level table layout widget. */ ml_widget_repaint (w->tbl, session, windowid, io); }