1 /* Monolith calendar widget.
2 * - by Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: ml_calendar.c,v 1.7 2003/02/22 15:34:25 rich Exp $
39 #include <ml_widget.h>
40 #include <ml_button.h>
41 #include <ml_table_layout.h>
42 #include <ml_vertical_layout.h>
43 #include <ml_horizontal_layout.h>
44 #include <ml_text_label.h>
46 #include <ml_form_input.h>
47 #include <ml_form_textarea.h>
48 #include <ml_form_select.h>
49 #include <ml_form_text.h>
50 #include <ml_form_submit.h>
52 #include "ml_calendar_lib.h"
53 #include "ml_calendar_month.h"
54 #include "ml_calendar_day.h"
55 #include "ml_calendar_notes.h"
56 #include "ml_calendar_visible.h"
57 #include "ml_calendar.h"
59 static void repaint (void *, ml_session, const char *, io_handle);
61 struct ml_widget_operations calendar_ops =
68 struct ml_widget_operations *ops;
69 pool pool; /* Pool for allocations. */
70 ml_session session; /* Current session. */
71 const char *conninfo; /* Database connection. */
72 vector calendars; /* Visible calendars (resource IDs). */
73 int yyyy, mm, dd; /* Currently visible year, month, day. */
75 ml_table_layout tbl; /* Top-level table layout. */
76 ml_button prev_month; /* Previous month button. */
77 ml_text_label month_lbl; /* Month label. */
78 ml_button next_month; /* Next month button. */
79 ml_button prev_year; /* Previous year button. */
80 ml_text_label year_lbl; /* Year label. */
81 ml_button next_year; /* Next year button. */
82 ml_calendar_month month; /* Month view (left hand side). */
83 ml_button prev_day; /* Previous day button. */
84 ml_button today; /* Today button. */
85 ml_button next_day; /* Next day button. */
86 ml_calendar_notes notes; /* Day notes. */
87 ml_calendar_day day; /* Day view (right hand side). */
88 ml_calendar_visible visible; /* Visible calendar controls. */
91 static void prev_month (ml_session, void *);
92 static void next_month (ml_session, void *);
93 static void prev_year (ml_session, void *);
94 static void next_year (ml_session, void *);
95 static void prev_day (ml_session, void *);
96 static void today (ml_session, void *);
97 static void next_day (ml_session, void *);
100 new_ml_calendar (pool pool, ml_session session, const char *conninfo,
101 const char *res_name)
103 ml_calendar w = pmalloc (pool, sizeof *w);
104 ml_vertical_layout vert;
105 ml_horizontal_layout horiz;
107 w->ops = &calendar_ops;
109 w->session = session;
110 w->conninfo = conninfo;
111 w->calendars = new_vector (pool, int);
114 if (ml_calendar_add_calendar (w, res_name) == -1)
117 /* We won't initialise these until the end of this function, so set
118 * these to known bad values in case one of the constructors below
119 * accidentally tries to use them.
121 w->yyyy = w->mm = w->dd = -1;
123 /* Create the calendar layout. */
124 w->tbl = new_ml_table_layout (pool, 2, 2);
126 vert = new_ml_vertical_layout (pool);
128 horiz = new_ml_horizontal_layout (pool);
129 w->prev_month = new_ml_button (pool, "<<");
130 ml_button_set_callback (w->prev_month, prev_month, session, w);
131 ml_widget_set_property (w->prev_month, "button.style", "link");
132 ml_horizontal_layout_pack (horiz, w->prev_month);
133 w->month_lbl = new_ml_text_label (pool, 0);
134 ml_horizontal_layout_pack (horiz, w->month_lbl);
135 w->next_month = new_ml_button (pool, ">>");
136 ml_button_set_callback (w->next_month, next_month, session, w);
137 ml_widget_set_property (w->next_month, "button.style", "link");
138 ml_horizontal_layout_pack (horiz, w->next_month);
139 w->prev_year = new_ml_button (pool, "<<");
140 ml_button_set_callback (w->prev_year, prev_year, session, w);
141 ml_widget_set_property (w->prev_year, "button.style", "link");
142 ml_horizontal_layout_pack (horiz, w->prev_year);
143 w->year_lbl = new_ml_text_label (pool, 0);
144 ml_horizontal_layout_pack (horiz, w->year_lbl);
145 w->next_year = new_ml_button (pool, ">>");
146 ml_button_set_callback (w->next_year, next_year, session, w);
147 ml_widget_set_property (w->next_year, "button.style", "link");
148 ml_horizontal_layout_pack (horiz, w->next_year);
149 ml_vertical_layout_pack (vert, horiz);
151 w->month = new_ml_calendar_month (pool, session, conninfo, w);
152 ml_vertical_layout_pack (vert, w->month);
154 horiz = new_ml_horizontal_layout (pool);
155 w->prev_day = new_ml_button (pool, "Prev");
156 ml_button_set_callback (w->prev_day, prev_day, session, w);
157 ml_horizontal_layout_pack (horiz, w->prev_day);
158 w->today = new_ml_button (pool, "Today");
159 ml_button_set_callback (w->today, today, session, w);
160 ml_horizontal_layout_pack (horiz, w->today);
161 w->next_day = new_ml_button (pool, "Next");
162 ml_button_set_callback (w->next_day, next_day, session, w);
163 ml_horizontal_layout_pack (horiz, w->next_day);
164 ml_vertical_layout_pack (vert, horiz);
166 w->notes = new_ml_calendar_notes (pool, session, conninfo, w);
167 ml_vertical_layout_pack (vert, w->notes);
169 ml_table_layout_pack (w->tbl, vert, 0, 0);
170 ml_table_layout_set_align (w->tbl, 0, 0, "center");
171 ml_table_layout_set_valign (w->tbl, 0, 0, "top");
173 w->day = new_ml_calendar_day (pool, session, conninfo, w);
174 ml_table_layout_pack (w->tbl, w->day, 0, 1);
175 ml_table_layout_set_valign (w->tbl, 0, 1, "top");
177 w->visible = new_ml_calendar_visible (pool, session, conninfo, w);
178 ml_table_layout_pack (w->tbl, w->visible, 1, 0);
179 ml_table_layout_set_colspan (w->tbl, 1, 0, 2);
180 ml_table_layout_set_valign (w->tbl, 1, 0, "top");
182 /* Update visible calendars. */
183 ml_calendar_visible_update (w->visible);
185 /* Set the calendar to today's date. */
192 ml_calendar_add_calendar (ml_calendar w, const char *res_name)
198 dbh = get_db_handle (w->conninfo, DBI_THROW_ERRORS);
200 /* Get the resource ID. */
201 sth = st_prepare_cached
203 "select r.resid from ml_resources r, ml_calendar c "
204 "where r.name = ? and r.resid = c.resid",
206 st_execute (sth, res_name);
208 st_bind (sth, 0, resid, DBI_INT);
210 if (!st_fetch (sth)) return -1; /* Not found. */
212 vector_push_back (w->calendars, resid);
217 ml_calendar_visible_update (w->visible);
223 ml_calendar_del_calendar (ml_calendar w, const char *res_name)
229 /* Don't allow the last calendar to be deleted, no matter what. */
230 if (vector_size (w->calendars) == 1)
233 dbh = get_db_handle (w->conninfo, DBI_THROW_ERRORS);
235 /* Get the resource ID. */
236 sth = st_prepare_cached
238 "select r.resid from ml_resources r, ml_calendar c "
239 "where r.name = ? and r.resid = c.resid",
241 st_execute (sth, res_name);
243 st_bind (sth, 0, resid, DBI_INT);
245 if (!st_fetch (sth)) return -1; /* Not found. */
247 /* Search for the resource in the list of calendars, and delete it. */
248 for (i = 0; i < vector_size (w->calendars); ++i)
250 vector_get (w->calendars, i, r);
253 vector_erase (w->calendars, i);
258 return -1; /* Not found. */
264 ml_calendar_visible_update (w->visible);
270 _ml_calendar_get_calendars (ml_calendar w)
276 prev_month (ml_session session, void *vw)
278 ml_calendar w = (ml_calendar) vw;
279 int dd = w->dd, mm = w->mm, yyyy = w->yyyy;
281 if (mm == 1 && yyyy == 1900) return;
289 if (dd > _ml_calendar_days_in_month (mm, yyyy))
290 dd = _ml_calendar_days_in_month (mm, yyyy);
292 ml_calendar_set_date (w, yyyy, mm, dd);
296 next_month (ml_session session, void *vw)
298 ml_calendar w = (ml_calendar) vw;
299 int dd = w->dd, mm = w->mm, yyyy = w->yyyy;
307 if (dd > _ml_calendar_days_in_month (mm, yyyy))
308 dd = _ml_calendar_days_in_month (mm, yyyy);
310 ml_calendar_set_date (w, yyyy, mm, dd);
314 prev_year (ml_session session, void *vw)
316 ml_calendar w = (ml_calendar) vw;
317 int dd = w->dd, mm = w->mm, yyyy = w->yyyy;
319 if (yyyy == 1900) return;
322 if (dd > _ml_calendar_days_in_month (mm, yyyy))
323 dd = _ml_calendar_days_in_month (mm, yyyy);
325 ml_calendar_set_date (w, yyyy, mm, dd);
329 next_year (ml_session session, void *vw)
331 ml_calendar w = (ml_calendar) vw;
332 int dd = w->dd, mm = w->mm, yyyy = w->yyyy;
335 if (dd > _ml_calendar_days_in_month (mm, yyyy))
336 dd = _ml_calendar_days_in_month (mm, yyyy);
338 ml_calendar_set_date (w, yyyy, mm, dd);
342 prev_day (ml_session session, void *vw)
344 ml_calendar w = (ml_calendar) vw;
345 int dd = w->dd, mm = w->mm, yyyy = w->yyyy;
347 if (dd == 1 && mm == 1 && yyyy == 1900) return;
358 dd = _ml_calendar_days_in_month (mm, yyyy);
361 ml_calendar_set_date (w, yyyy, mm, dd);
365 today (ml_session session, void *vw)
367 ml_calendar w = (ml_calendar) vw;
373 ml_calendar_set_date (w, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
377 next_day (ml_session session, void *vw)
379 ml_calendar w = (ml_calendar) vw;
380 int dd = w->dd, mm = w->mm, yyyy = w->yyyy;
383 if (dd > _ml_calendar_days_in_month (mm, yyyy))
394 ml_calendar_set_date (w, yyyy, mm, dd);
398 ml_calendar_set_date (ml_calendar w, int yyyy, int mm, int dd)
400 /* Verify that this is a correct date. */
401 assert (yyyy >= 1900);
402 assert (1 <= mm && mm <= 12);
403 assert (1 <= dd && dd <= _ml_calendar_days_in_month (mm, yyyy));
405 /* Set the date and update the widgets. */
410 ml_widget_set_property (w->month_lbl, "text",
411 _ml_calendar_text_month (w->mm));
412 ml_widget_set_property (w->year_lbl, "text", pitoa (w->pool, w->yyyy));
414 ml_calendar_month_set_date (w->month, yyyy, mm, dd);
415 ml_calendar_day_set_date (w->day, yyyy, mm, dd);
416 ml_calendar_notes_set_date (w->notes, yyyy, mm, dd);
420 ml_calendar_get_date (ml_calendar w, int *yyyy, int *mm, int *dd)
428 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
430 ml_calendar w = (ml_calendar) vw;
432 /* Repaint the top-level table layout widget. */
433 ml_widget_repaint (w->tbl, session, windowid, io);