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_month.c,v 1.9 2003/02/22 15:34:26 rich Exp $
42 #include <ml_widget.h>
43 #include <ml_button.h>
44 #include <ml_text_label.h>
45 #include <ml_table_layout.h>
47 #include "ml_calendar_lib.h"
48 #include "ml_calendar_month.h"
50 static void repaint (void *, ml_session, const char *, io_handle);
52 struct ml_widget_operations calendar_month_ops =
57 struct ml_calendar_month
59 struct ml_widget_operations *ops;
60 pool pool; /* Pool for allocations. */
61 ml_session session; /* Current session. */
62 const char *conninfo; /* Database connection. */
63 ml_calendar calendar; /* Parent calendar. */
64 int yyyy, mm, dd; /* Current date. */
66 ml_table_layout tbl; /* Top-level table layout. */
67 ml_text_label days[7]; /* Days of the week labels. */
68 ml_button b[32]; /* Buttons (we reuse these). */
71 /* This structure is passed to the button callbacks. */
74 int dd; /* Day (1 - 31). */
75 ml_calendar_month w; /* Widget pointer. */
78 static void button_press (ml_session, void *);
79 static void update_buttons (ml_calendar_month w);
82 new_ml_calendar_month (pool pool, ml_session session, const char *conninfo,
85 ml_calendar_month w = pmalloc (pool, sizeof *w);
87 struct button_data *data;
89 w->ops = &calendar_month_ops;
92 w->conninfo = conninfo;
93 w->calendar = calendar;
95 /* The parent calendar must call ml_calendar_month_set_date to set these
96 * before using this widget.
98 w->yyyy = w->mm = w->dd = -1;
100 /* Create the days of the week labels and buttons. */
101 /* XXX Waiting for ml_text_label and ml_button to give us more control
102 * over the rendering of labels and buttons.
104 w->days[0] = new_ml_text_label (pool, "Su");
105 ml_widget_set_property (w->days[0], "font.weight", "bold");
106 w->days[1] = new_ml_text_label (pool, "Mo");
107 ml_widget_set_property (w->days[1], "font.weight", "bold");
108 w->days[2] = new_ml_text_label (pool, "Tu");
109 ml_widget_set_property (w->days[2], "font.weight", "bold");
110 w->days[3] = new_ml_text_label (pool, "We");
111 ml_widget_set_property (w->days[3], "font.weight", "bold");
112 w->days[4] = new_ml_text_label (pool, "Th");
113 ml_widget_set_property (w->days[4], "font.weight", "bold");
114 w->days[5] = new_ml_text_label (pool, "Fr");
115 ml_widget_set_property (w->days[5], "font.weight", "bold");
116 w->days[6] = new_ml_text_label (pool, "Sa");
117 ml_widget_set_property (w->days[6], "font.weight", "bold");
119 w->b[0] = 0; /* This is a dummy entry. */
121 for (i = 1; i <= 31; ++i)
123 data = pmalloc (pool, sizeof *data);
124 w->b[i] = new_ml_button (pool, pitoa (pool, i));
127 ml_button_set_callback (w->b[i], button_press, session, data);
130 /* Create the top-level table widget, also reused. */
131 w->tbl = new_ml_table_layout (pool, 7, 7);
132 for (i = 0; i < 7; ++i)
134 ml_table_layout_pack (w->tbl, w->days[i], 0, i);
135 ml_table_layout_set_align (w->tbl, 0, i, "center");
137 for (j = 1; j < 7; ++j)
138 for (i = 0; i < 7; ++i)
139 ml_table_layout_set_align (w->tbl, j, i, "right");
144 /* Update the date, then update the widget. */
146 ml_calendar_month_set_date (ml_calendar_month w, int yyyy, int mm, int dd)
150 /* Update the date. */
155 /* Clear the existing table of widgets. */
156 for (j = 1; j < 7; ++j)
157 for (i = 0; i < 7; ++i)
158 ml_table_layout_pack (w->tbl, 0, j, i);
160 /* Redraw the month. */
162 i = _ml_calendar_first_wday_of_month (mm, yyyy);
163 n = _ml_calendar_days_in_month (mm, yyyy);
165 for (d = 1; d <= n; ++d)
167 ml_table_layout_pack (w->tbl, w->b[d], j, i);
176 /* Update buttons from the database. */
180 /* This function is called when a button is pressed. */
182 button_press (ml_session session, void *vdata)
184 struct button_data *data = (struct button_data *) vdata;
186 /* This function, in the parent calendar, will eventually call our
187 * ml_calendar_month_set_date.
189 ml_calendar_set_date (data->w->calendar,
190 data->w->yyyy, data->w->mm, data->dd);
193 /* This function updates the state of the buttons from the database,
194 * and also highlights the currently selected day.
197 update_buttons (ml_calendar_month w)
201 unsigned char flags[32];
203 const vector resids = _ml_calendar_get_calendars (w->calendar);
205 dbh = get_db_handle (w->conninfo, DBI_THROW_ERRORS);
207 /* Find out which days contain data. Note how with PostgreSQL we
208 * can leave the database to take the strain of date munging. This
209 * is one of the great reasons to use and recommend PostgreSQL.
211 sth = st_prepare_cached
213 "select date_part ('day', start_time) from ml_calendar_events "
214 " where resid in (@) "
215 " and start_time >= date (? || '/' || ? || '/01') "
216 " and start_time < (date (? || '/' || ? || '/01') + "
217 " interval '1 month')",
218 DBI_VECTOR_INT, DBI_INT, DBI_INT, DBI_INT, DBI_INT);
219 st_execute (sth, resids, w->yyyy, w->mm, w->yyyy, w->mm);
221 st_bind (sth, 0, dd, DBI_INT);
223 memset (flags, 0, sizeof flags);
225 while (st_fetch (sth))
227 assert (0 < dd && dd < 32);
233 /* Depending on the flags, we now set the class of each button. */
234 for (dd = 1; dd <= 31; ++dd)
238 ml_widget_set_property (w->b[dd], "class", "ml_calendar_day");
241 ml_widget_set_property (w->b[dd], "class", "ml_calendar_day_events");
244 ml_widget_set_property (w->b[dd], "class", "ml_calendar_day_selected");
247 ml_widget_set_property (w->b[dd], "class",
248 "ml_calendar_day_events_selected");
257 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
259 ml_calendar_month w = (ml_calendar_month) vw;
261 ml_widget_repaint (w->tbl, session, windowid, io);