Coverage Report

Created: 2026-04-12 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wt/src/Wt/WCalendar.h
Line
Count
Source
1
// This may look like C code, but it's really -*- C++ -*-
2
/*
3
 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4
 *
5
 * See the LICENSE file for terms of use.
6
 */
7
#ifndef WCALENDAR_H_
8
#define WCALENDAR_H_
9
10
#include <Wt/WCompositeWidget.h>
11
#include <Wt/WDate.h>
12
#include <set>
13
14
namespace Wt {
15
16
/*! \brief The calendar header format.
17
 */
18
enum class CalendarHeaderFormat {
19
  SingleLetterDayNames,  //!< First letter of a day (e.g. 'M' for Monday)
20
  ShortDayNames,         //!< First 3 letters of a day (e.g. 'Mon' for Monday)
21
  LongDayNames           //!< Full day name
22
    // NoHorizontalHeader  //No horizontal header (not yet implemented)
23
};
24
25
class WComboBox;
26
class WInPlaceEdit;
27
class WTemplate;
28
29
/*! \class WCalendar Wt/WCalendar.h Wt/WCalendar.h
30
 *  \brief A calendar.
31
 *
32
 * The calendar provides navigation by month and year, and indicates the
33
 * current day.
34
 *
35
 * You can listen for single click or double click events on a
36
 * calendar cell using the clicked() and activated() methods.
37
 *
38
 * The calendar may be configured to allow selection of single or
39
 * multiple days using setSelectionMode(), and you may listen for
40
 * changes in the selection using the selectionChanged()
41
 * signals. Selection can also be entirely disabled in which case you
42
 * can implement your own selection handling by listening for cell
43
 * click events.
44
 *
45
 * Cell rendering may be customized by reimplementing renderCell().
46
 *
47
 * Internationalization is provided by the internationalization
48
 * features of the Wt::WDate class.
49
 *
50
 * \if cpp
51
 * Usage example:
52
 * \code
53
 * Wt::WDate today = Wt::WDate::currentDate();
54
 *
55
 * Wt::WCalendar *calendar = addWidget(std::make_unique<Wt::WCalendar>());
56
 * calendar->browseTo(today.addMonths(1));
57
 * calendar->select(today.addMonths(1).addDays(3));
58
 * calendar->selected().connect(this, &MyWidget::daySelected);
59
 * \endcode
60
 * \endif
61
 *
62
 * Here is a snapshot, taken on 19/01/2010 (shown as
63
 * today), and 14/01/2010 currently selected.
64
 * <TABLE border="0" align="center"> <TR> <TD>
65
 * \image html WCalendar-default-1.png "WCalendar with default look"
66
 * </TD> <TD>
67
 * \image html WCalendar-polished-1.png "WCalendar with polished look"
68
 * </TD> </TR> </TABLE>
69
 *
70
 */
71
class WT_API WCalendar : public WCompositeWidget
72
{
73
public:
74
  /*! \brief Typedef for enum Wt::CalendarHeaderFormat */
75
  typedef CalendarHeaderFormat HeaderFormat;
76
77
  /*! \brief Creates a new calendar.
78
   *
79
   * Constructs a new calendar with English day/month names.  The
80
   * calendar shows the current day, and has an empty selection.
81
   */
82
  WCalendar();
83
84
  /*! \brief Sets the selection mode.
85
   *
86
   * The default selection mode is
87
   * \link Wt::SingleSelection SingleSelection\endlink.
88
   */
89
  void setSelectionMode(SelectionMode mode);
90
91
  /*! \brief Browses to the same month in the previous year.
92
   *
93
   * Displays the same month in the previous year. This does not
94
   * affect the selection.
95
   *
96
   * This will emit the currentPageChanged() singal.
97
   */
98
  void browseToPreviousYear();
99
100
  /*! \brief Browses to the previous month.
101
   *
102
   * Displays the previous month. This does not affect the selection.
103
   *
104
   * This will emit the currentPageChanged() singal.
105
   */
106
  void browseToPreviousMonth();
107
108
  /*! \brief Browses to the same month in the next year.
109
   *
110
   * Displays the same month in the next year. This does not change
111
   * the current selection.
112
   *
113
   * This will emit the currentPageChanged() singal.
114
   */
115
  void browseToNextYear();
116
117
  /*! \brief Browses to the next month.
118
   *
119
   * Displays the next month. This does not change the current selection.
120
   *
121
   * This will emit the currentPageChanged() singal.
122
   */
123
  void browseToNextMonth();
124
125
  /*! \brief Browses to a date.
126
   *
127
   * Displays the month which contains the given date. This does not change
128
   * the current selection.
129
   *
130
   * This will emit the currentPageChanged() signal if another month
131
   * is displayed.
132
   */
133
  void browseTo(const WDate& date);
134
135
  /*! \brief Returns the current month displayed
136
   *
137
   * Returns the month (1-12) that is currently displayed.
138
   */
139
0
  int currentMonth() const { return currentMonth_; }
140
141
  /*! \brief Returns the current year displayed
142
   *
143
   * Returns the year that is currently displayed.
144
   */
145
0
  int currentYear() const { return currentYear_; }
146
147
  /*! \brief Clears the current selection.
148
   *
149
   * Clears the current selection. Will result in a selection() that is
150
   * empty().
151
   */
152
  void clearSelection();
153
154
  /*! \brief Selects a date.
155
   *
156
   * Select one date. Both in single or multiple selection mode, this results
157
   * in a selection() that contains exactly one date.
158
   */
159
  void select(const WDate& date);
160
161
  /*! \brief Selects multiple dates.
162
   *
163
   * Select multiple dates. In multiple selection mode, this results
164
   * in a selection() that contains exactly the given dates. In single
165
   * selection mode, at most one date is set.
166
   */
167
  void select(const std::set<WDate>& dates);
168
169
  /*! \brief Sets the horizontal header format.
170
   *
171
   * The default horizontal header format is CalendarHeaderFormat::ShortDayNames.
172
   */
173
  void setHorizontalHeaderFormat(CalendarHeaderFormat format);
174
175
  /*! \brief Returns the horizontal header format.
176
   *
177
   * \sa setHorizontalHeaderFormat()
178
   */
179
0
  CalendarHeaderFormat horizontalHeaderFormat() {
180
0
    return horizontalHeaderFormat_;
181
0
  }
182
183
  /*! \brief Sets the first day of the week.
184
   *
185
   * Possible values are 1 to 7. The default value is 1 ("Monday").
186
   */
187
  void setFirstDayOfWeek(int dayOfWeek);
188
189
  /*! \brief Returns the current selection.
190
   *
191
   * Returns the set of dates currently selected. In single selection mode,
192
   * this set contains 0 or 1 dates.
193
   */
194
0
  const std::set<WDate>& selection() const { return selection_; }
195
196
  /*! \brief %Signal emitted when the user changes the selection.
197
   *
198
   * Emitted after the user has changed the current selection.
199
   */
200
0
  Signal<>& selectionChanged() { return selectionChanged_; }
201
202
  /*! \brief %Signal emitted when the user double-clicks a date.
203
   *
204
   * You may want to connect to this signal to treat a double click
205
   * as the selection of a date.
206
   */
207
0
  Signal<WDate>& activated() { return activated_; }
208
209
  /*! \brief %Signal emitted when the user clicks a date.
210
   *
211
   * You may want to connect to this signal if you want to provide a
212
   * custom selection handling.
213
   */
214
0
  Signal<WDate>& clicked() { return clicked_; }
215
216
  /*! \brief %Signal emitted when the current month is changed.
217
   *
218
   * The method is emitted both when the change is done through the
219
   * user interface or via the public API. The two parameters are
220
   * respectively the new year and month.
221
   */
222
0
  Signal<int, int>& currentPageChanged() { return currentPageChanged_; }
223
224
  /*! \brief Configures the calendar to use single click for activation
225
   *
226
   * By default, double click will trigger activate(). Use this method
227
   * if you want a single click to trigger activate() (and the now
228
   * deprecated selected() method). This only applies to a
229
   * single-selection calendar.
230
   *
231
   * If selectionMode() is set to \link Wt::SingleSelection SingleSelection\endlink,
232
   * this will cause the selection to change on a single click instead of a double click.
233
   *
234
   * Instead of enabling single click, you can also listen to the clicked()
235
   * signal to process a single click.
236
   *
237
   * \sa setSelectionMode()
238
   */
239
  void setSingleClickSelect(bool single);
240
241
  /*! \brief Sets the bottom of the valid date range.
242
   *
243
   * \if cpp
244
   * The default is a null date constructed using WDate().
245
   * \elseif java
246
   * The default bottom is null.
247
   * \endif
248
   */
249
  void setBottom(const WDate& bottom);
250
251
  /*! \brief Returns the bottom date of the valid range.
252
   */
253
0
  const WDate& bottom() const { return bottom_; }
254
255
  /*! \brief Sets the top of the valid date range.
256
   *
257
   * \if cpp
258
   * The default is a null date constructed using WDate().
259
   * \elseif java
260
   * The default top is null.
261
   * \endif
262
   */
263
  void setTop(const WDate& top);
264
265
  /*! \brief Returns the top date of the valid range.
266
   */
267
0
  const WDate& top() const { return top_; }
268
269
  virtual void load() override;
270
271
protected:
272
  virtual void render(WFlags<RenderFlag> renderFlags) override;
273
274
  /*! \brief Creates or updates a widget that renders a cell.
275
   *
276
   * The default implementation creates a WText
277
   *
278
   * You may want to reimplement this method if you wish to customize
279
   * how a cell is rendered. When \p widget is \c 0, a new widget
280
   * should be created and returned. Otherwise, you may either modify
281
   * the passed \p widget, or return a new widget. If you return a new
282
   * widget, the prevoius widget will be deleted.
283
   */
284
  virtual WWidget* renderCell(WWidget* widget, const WDate& date);
285
286
  /*! \brief Returns whether a date is selected.
287
   *
288
   * This is a convenience method that can be used when reimplementing
289
   * renderCell().
290
   */
291
  bool isSelected(const WDate& date) const;
292
293
  virtual void enableAjax() override;
294
295
private:
296
  SelectionMode     selectionMode_;
297
  bool              singleClickSelect_;
298
  int               currentYear_;
299
  int               currentMonth_;
300
  CalendarHeaderFormat horizontalHeaderFormat_;
301
  int               firstDayOfWeek_;
302
  std::set<WDate>   selection_;
303
  bool              needRenderMonth_;
304
305
  Signal<>          selectionChanged_;
306
  Signal<WDate>     activated_;
307
  Signal<WDate>     clicked_;
308
  Signal<int, int>  currentPageChanged_;
309
310
  WDate             bottom_, top_;
311
312
  struct Coordinate {
313
    int i, j;
314
315
0
    Coordinate() : i(0), j(0) { }
316
0
    Coordinate(int x, int y) { i = x; j = y; }
317
  };
318
319
  WTemplate *impl_;
320
  WComboBox *monthEdit_;
321
  WInPlaceEdit *yearEdit_;
322
323
  void create();
324
  void renderMonth();
325
326
  void emitCurrentPageChanged();
327
328
  void monthChanged(int newMonth);
329
  void yearChanged(WString newYear);
330
  WDate dateForCell(int week, int dayOfWeek);
331
332
  void selectInCurrentMonth(const WDate& d);
333
334
  bool isInvalid(const WDate& d);
335
  void cellClicked(Coordinate c);
336
  void cellDblClicked(Coordinate c);
337
};
338
339
}
340
341
#endif // WCALENDAR_H_