wxBase:
+- wxDateTime replaces and extends old wxDate and wxTime classes (still
+ available but strongly deprecated) with many new features
+
+- wxLongLong class provides support for (signed) 64 bit integers
+
- it is now possible to build wxBase under Win32 (using VC++ only so far)
and BeOS (without thread support yet)
- wxArray::RemoveAt() replaces deprectaed wxArray::Remove(index)
all (GUI):
+
+- new wxCalendarCtrl class for picking a date interactively
+
- wxMenu(Bar)::Insert() and Remove() functions for dynamic menu menagament
- wxToolBar supports arbitrary controls (not only buttons) and can be
dynamically changed (Delete/Insert functions)
- vertical toolbars supported by MSW and GTK native wxToolBar classes
+
- wxTreeCtrl and wxListCtrl allow setting colour/fonts for individual items
- "file open" dialog allows selecting multiple files at once (contributed by
John Norris)
\membersection{Adding items}
\helpref{Add}{wxarrayadd}\\
-\helpref{Insert}{wxarrayinsert}
+\helpref{Insert}{wxarrayinsert}\\
+\helpref{WX\_APPEND\_ARRAY}{wxappendarray}
\membersection{Removing items}
WX_DEFINE_OBJARRAY(wxArrayOfMyClass);
\end{verbatim}
+\membersection{WX\_APPEND\_ARRAY}\label{wxappendarray}
+
+\func{void}{WX\_APPEND\_ARRAY}{\param{wxArray\& }{array}, \param{wxArray\& }{other}}
+
+This macro may be used to append all elements of the {\it other} array to the
+{\it array}. The two arrays must be of the same type.
+
\membersection{WX\_CLEAR\_ARRAY}\label{wxcleararray}
\func{void}{WX\_CLEAR\_ARRAY}{\param{wxArray\& }{array}}
ownership of the original item. Once again, it only makes sense for wxObjArrays
because the other array types never take ownership of their elements.
+You may also use \helpref{WX\_APPEND\_ARRAY}{wxappendarray} macro to append all
+elements of one array to another one.
+
\membersection{wxArray::Alloc}\label{wxarrayalloc}
\func{void}{Alloc}{\param{size\_t }{count}}
--- /dev/null
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Name: calctrl.tex
+%% Purpose: wxCalendarCtrl documentation
+%% Author: Vadim Zeitlin
+%% Modified by:
+%% Created: 03.01.00
+%% RCS-ID: $Id$
+%% Copyright: (c) Vadim Zeitlin
+%% Licence: wxWindows licence
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{\class{wxCalendarCtrl}}\label{wxcalendarctrl}
+
+The calendar control allows the user to pick a date interactively.
+
+\wxheading{Include files}
+
+<wx/calctrl.h>
+
+\wxheading{See also:}
+
+\helpref{Calendar sample}{samplecalendar}
didn't help. They also provide some notes about using the samples and what
features of wxWindows are they supposed to test.
+\subsection{Calendar sample}\label{samplecalendar}
+
+This font shows the \helpref{calendar control}{wxcalendarctrl} in action. It
+shows how to configure the control (see the different options in the calendar
+menu) and also how to process the notifications from it.
+
\subsection{Checklist sample}\label{samplechecklist}
This sample demonstrates the use of the \helpref{wxCheckListBox}{wxchecklistbox}
// Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////////
+/*
+ TODO
+
+ 1. implement multiple selections for date ranges
+ 2. background bitmap for the calendar?
+ */
+
#ifndef _WX_CALCTRL_H
#define _WX_CALCTRL_H
+#include "wx/datetime.h"
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
wxCAL_HITTEST_DAY // on a day in the calendar
};
+// border types for a date
+enum wxCalendarDateBorder
+{
+ wxCAL_BORDER_NONE, // no border (default)
+ wxCAL_BORDER_SQUARE, // a rectangular border
+ wxCAL_BORDER_ROUND // a round border
+};
+
// ----------------------------------------------------------------------------
-// wxCalendarCtrl
+// wxCalendarDateAttr: custom attributes for a calendar date
// ----------------------------------------------------------------------------
-// so far we only have a generic version, so keep it simple
-#include "wx/generic/calctrl.h"
+class WXDLLEXPORT wxCalendarDateAttr
+{
+public:
+ // ctors
+ wxCalendarDateAttr() { Init(); }
+ wxCalendarDateAttr(const wxColour& colText,
+ const wxColour& colBack = wxNullColour,
+ const wxColour& colBorder = wxNullColour,
+ const wxFont& font = wxNullFont,
+ wxCalendarDateBorder border = wxCAL_BORDER_NONE)
+ : m_colText(colText), m_colBack(colBack),
+ m_colBorder(colBorder), m_font(font)
+ {
+ Init(border);
+ }
+ wxCalendarDateAttr(wxCalendarDateBorder border,
+ const wxColour& colBorder = wxNullColour)
+ : m_colBorder(colBorder)
+ {
+ Init(border);
+ }
+
+ // setters
+ void SetTextColour(const wxColour& colText) { m_colText = colText; }
+ void SetBackgroundColour(const wxColour& colBack) { m_colBack = colBack; }
+ void SetBorderColour(const wxColour& col) { m_colBorder = col; }
+ void SetFont(const wxFont& font) { m_font = font; }
+ void SetBorder(wxCalendarDateBorder border) { m_border = border; }
+ void SetHoliday(bool holiday) { m_holiday = holiday; }
+
+ // accessors
+ bool HasTextColour() const { return m_colText.Ok(); }
+ bool HasBackgroundColour() const { return m_colBack.Ok(); }
+ bool HasBorderColour() const { return m_colBorder.Ok(); }
+ bool HasFont() const { return m_font.Ok(); }
+ bool HasBorder() const { return m_border != wxCAL_BORDER_NONE; }
+
+ bool IsHoliday() const { return m_holiday; }
+
+ const wxColour& GetTextColour() const { return m_colText; }
+ const wxColour& GetBackgroundColour() const { return m_colBack; }
+ const wxColour& GetBorderColour() const { return m_colBorder; }
+ const wxFont& GetFont() const { return m_font; }
+ wxCalendarDateBorder GetBorder() const { return m_border; }
+
+protected:
+ void Init(wxCalendarDateBorder border = wxCAL_BORDER_NONE)
+ {
+ m_border = border;
+ m_holiday = FALSE;
+ }
+
+private:
+ wxColour m_colText,
+ m_colBack,
+ m_colBorder;
+ wxFont m_font;
+ wxCalendarDateBorder m_border;
+ bool m_holiday;
+};
// ----------------------------------------------------------------------------
// wxCalendarCtrl events
// ----------------------------------------------------------------------------
+class WXDLLEXPORT wxCalendarCtrl;
+
class WXDLLEXPORT wxCalendarEvent : public wxCommandEvent
{
friend class wxCalendarCtrl;
wxDateTime::WeekDay m_wday;
};
+// ----------------------------------------------------------------------------
+// wxCalendarCtrl
+// ----------------------------------------------------------------------------
+
+// so far we only have a generic version, so keep it simple
+#include "wx/generic/calctrl.h"
+
+// ----------------------------------------------------------------------------
+// calendar events macros
+// ----------------------------------------------------------------------------
+
#define EVT_CALENDAR(id, fn) { wxEVT_CALENDAR_DOUBLECLICKED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) & fn, (wxObject *) NULL },
#define EVT_CALENDAR_SEL_CHANGED(id, fn) { wxEVT_CALENDAR_SEL_CHANGED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) & fn, (wxObject *) NULL },
#define EVT_CALENDAR_DAY(id, fn) { wxEVT_CALENDAR_DAY_CHANGED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) & fn, (wxObject *) NULL },
* TODO Well, everything :-)
*
* + 1. Time zones with minutes (make TimeZone a class)
- * 2. getdate() function like under Solaris
+ * ? 2. getdate() function like under Solaris
* + 3. text conversion for wxDateSpan
- * 4. pluggable modules for the workdays calculations
+ * + 4. pluggable modules for the workdays calculations
+ * 5. wxDateTimeHolidayAuthority for Easter and other christian feasts
*/
/*
// default assignment operator is ok
// calendar calculations (functions which set the date only leave the time
- // unchanged, e.g. don't explictly zero it)
+ // unchanged, e.g. don't explictly zero it): SetXXX() functions modify the
+ // object itself, GetXXX() ones return a new object.
// ------------------------------------------------------------------------
// set to the given week day in the same week as this one
wxDateTime& SetToWeekDayInSameWeek(WeekDay weekday);
+ inline wxDateTime GetWeekDayInSameWeek(WeekDay weekday) const;
// set to the next week day following this one
wxDateTime& SetToNextWeekDay(WeekDay weekday);
+ inline wxDateTime GetNextWeekDay(WeekDay weekday) const;
// set to the previous week day before this one
wxDateTime& SetToPrevWeekDay(WeekDay weekday);
+ inline wxDateTime GetPrevWeekDay(WeekDay weekday) const;
// set to Nth occurence of given weekday in the given month of the
// given year (time is set to 0), return TRUE on success and FALSE on
int n = 1,
Month month = Inv_Month,
int year = Inv_Year);
+ inline wxDateTime GetWeekDay(WeekDay weekday,
+ int n = 1,
+ Month month = Inv_Month,
+ int year = Inv_Year) const;
// sets to the last weekday in the given month, year
inline bool SetToLastWeekDay(WeekDay weekday,
Month month = Inv_Month,
int year = Inv_Year);
+ inline wxDateTime GetLastWeekDay(WeekDay weekday,
+ Month month = Inv_Month,
+ int year = Inv_Year);
// sets the date to the given day of the given week in the year,
// returns TRUE on success and FALSE if given date doesn't exist (e.g.
// numWeek is > 53)
bool SetToTheWeek(wxDateTime_t numWeek, WeekDay weekday = Mon);
+ inline wxDateTime GetWeek(wxDateTime_t numWeek, WeekDay weekday = Mon) const;
// sets the date to the last day of the given (or current) month or the
// given (or current) year
wxDateTime& SetToLastMonthDay(Month month = Inv_Month,
int year = Inv_Year);
+ inline wxDateTime GetLastMonthDay(Month month = Inv_Month,
+ int year = Inv_Year) const;
// sets to the given year day (1..365 or 366)
wxDateTime& SetToYearDay(wxDateTime_t yday);
+ inline wxDateTime GetYearDay(wxDateTime_t yday) const;
// The definitions below were taken verbatim from
//
// is this date a work day? This depends on a country, of course,
// because the holidays are different in different countries
- bool IsWorkDay(Country country = Country_Default,
- const TimeZone& tz = Local) const;
+ bool IsWorkDay(Country country = Country_Default) const;
// is this date later than Gregorian calendar introduction for the
// given country (see enum GregorianAdoption)?
//
- // NB: this function shouldn't be considered as absolute authoiruty in
+ // NB: this function shouldn't be considered as absolute authority in
// the matter. Besides, for some countries the exact date of
// adoption of the Gregorian calendar is simply unknown.
bool IsGregorianDate(GregorianAdoption country = Gr_Standard) const;
wxString FormatDate() const { return Format(_T("%x")); }
// preferred time representation for the current locale
wxString FormatTime() const { return Format(_T("%X")); }
- // return the string representing the date in ISO 8601 format
+ // returns the string representing the date in ISO 8601 format
// (YYYY-MM-DD)
wxString FormatISODate() const { return Format(_T("%Y-%m-%d")); }
+ // returns the string representing the time in ISO 8601 format
+ // (HH:MM:SS)
+ wxString FormatISOTime() const { return Format(_T("%H:%M:%S")); }
// implementation
// ------------------------------------------------------------------------
// one month to Feb, 15 - we want to get Mar, 15, of course).
//
// When adding a month to the date, all lesser components (days, hours, ...)
-// won't be changed.
+// won't be changed unless the resulting date would be invalid: for example,
+// Jan 31 + 1 month will be Feb 28, not (non existing) Feb 31.
+//
+// Because of this feature, adding and substracting back again the same
+// wxDateSpan will *not*, in general give back the original date: Feb 28 - 1
+// month will be Jan 28, not Jan 31!
//
// wxDateSpan can be either positive or negative. They may be
// multiplied by scalars which multiply all deltas by the scalar: i.e. 2*(1
m_days;
};
-WXDLLEXPORT_DATA(extern wxDateSpan) wxYear;
-WXDLLEXPORT_DATA(extern wxDateSpan) wxMonth;
-WXDLLEXPORT_DATA(extern wxDateSpan) wxWeek;
-WXDLLEXPORT_DATA(extern wxDateSpan) wxDay;
+// ----------------------------------------------------------------------------
+// wxDateTimeArray: array of dates.
+// ----------------------------------------------------------------------------
+
+#include "wx/dynarray.h"
+
+WX_DECLARE_OBJARRAY(wxDateTime, wxDateTimeArray);
+
+// ----------------------------------------------------------------------------
+// wxDateTimeHolidayAuthority: an object of this class will decide whether a
+// given date is a holiday and is used by all functions working with "work
+// days".
+//
+// NB: the base class is an ABC, derived classes must implement the pure
+// virtual methods to work with the holidays they correspond to.
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxDateTimeHolidayAuthority;
+WX_DEFINE_ARRAY(wxDateTimeHolidayAuthority *, wxHolidayAuthoritiesArray);
+
+class WXDLLEXPORT wxDateTimeHolidayAuthority
+{
+public:
+ // returns TRUE if the given date is a holiday
+ static bool IsHoliday(const wxDateTime& dt);
+
+ // fills the provided array with all holidays in the given range, returns
+ // the number of them
+ static size_t GetHolidaysInRange(const wxDateTime& dtStart,
+ const wxDateTime& dtEnd,
+ wxDateTimeArray& holidays);
+
+ // clear the list of holiday authorities
+ static void ClearAllAuthorities();
+
+ // add a new holiday authority (the pointer will be deleted by
+ // wxDateTimeHolidayAuthority)
+ static void AddAuthority(wxDateTimeHolidayAuthority *auth);
+
+protected:
+ // this function is called to determine whether a given day is a holiday
+ virtual bool DoIsHoliday(const wxDateTime& dt) const = 0;
+
+ // this function should fill the array with all holidays between the two
+ // given dates - it is implemented in the base class, but in a very
+ // inefficient way (it just iterates over all days and uses IsHoliday() for
+ // each of them), so it must be overridden in the derived class where the
+ // base class version may be explicitly used if needed
+ //
+ // returns the number of holidays in the given range and fills holidays
+ // array
+ virtual size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
+ const wxDateTime& dtEnd,
+ wxDateTimeArray& holidays) const = 0;
+
+private:
+ // all holiday authorities
+ static wxHolidayAuthoritiesArray ms_authorities;
+};
+
+// the holidays for this class are all Saturdays and Sundays
+class WXDLLEXPORT wxDateTimeWorkDays : public wxDateTimeHolidayAuthority
+{
+protected:
+ virtual bool DoIsHoliday(const wxDateTime& dt) const;
+ virtual size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
+ const wxDateTime& dtEnd,
+ wxDateTimeArray& holidays) const;
+};
// ============================================================================
// inline functions implementation
#error "This file is only included by wx/datetime.h, don't include it manually!"
#endif
+// ----------------------------------------------------------------------------
+// private macros
+// ----------------------------------------------------------------------------
+
#define MILLISECONDS_PER_DAY 86400000l
+// some broken compilers (HP-UX CC) refuse to compile the "normal" version, but
+// using a temp variable always might prevent other compilers from optimising
+// it away - hence use of this ugly macro
+#ifndef __HPUX__
+ #define MODIFY_AND_RETURN(op) return wxDateTime(*this).op
+#else
+ #define MODIFY_AND_RETURN(op) wxDateTime dt(*this); dt.op; return dt
+#endif
+
// ----------------------------------------------------------------------------
// wxDateTime construction
// ----------------------------------------------------------------------------
return SetToWeekDay(weekday, -1, month, year);
}
+wxDateTime wxDateTime::GetWeekDayInSameWeek(WeekDay weekday) const
+{
+ MODIFY_AND_RETURN( SetToWeekDayInSameWeek(weekday) );
+}
+
+wxDateTime wxDateTime::GetNextWeekDay(WeekDay weekday) const
+{
+ MODIFY_AND_RETURN( SetToNextWeekDay(weekday) );
+}
+
+wxDateTime wxDateTime::GetPrevWeekDay(WeekDay weekday) const
+{
+ MODIFY_AND_RETURN( SetToPrevWeekDay(weekday) );
+}
+
+wxDateTime wxDateTime::GetWeekDay(WeekDay weekday,
+ int n,
+ Month month,
+ int year) const
+{
+ wxDateTime dt(*this);
+
+ return dt.SetToWeekDay(weekday, n, month, year) ? dt : wxInvalidDateTime;
+}
+
+wxDateTime wxDateTime::GetLastWeekDay(WeekDay weekday,
+ Month month,
+ int year)
+{
+ wxDateTime dt(*this);
+
+ return dt.SetToLastWeekDay(weekday, month, year) ? dt : wxInvalidDateTime;
+}
+
+wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, WeekDay weekday) const
+{
+ wxDateTime dt(*this);
+
+ return dt.SetToTheWeek(numWeek, weekday) ? dt : wxInvalidDateTime;
+}
+
+wxDateTime wxDateTime::GetLastMonthDay(Month month, int year) const
+{
+ MODIFY_AND_RETURN( SetToLastMonthDay(month, year) );
+}
+
+wxDateTime wxDateTime::GetYearDay(wxDateTime_t yday) const
+{
+ MODIFY_AND_RETURN( SetToYearDay(yday) );
+}
+
// ----------------------------------------------------------------------------
// wxDateTime comparison
// ----------------------------------------------------------------------------
wxDateTime wxDateTime::ToTimezone(const wxDateTime::TimeZone& tz,
bool noDST) const
{
- wxDateTime dt(*this);
- return dt.MakeTimezone(tz, noDST);
+ MODIFY_AND_RETURN( MakeTimezone(tz, noDST) );
}
// ----------------------------------------------------------------------------
}
#undef MILLISECONDS_PER_DAY
+
+#undef MODIFY_AND_RETURN
// convinience macros
// -----------------------------------------------------------------------------
+// append all element of one array to another one
+#define WX_APPEND_ARRAY(array, other) \
+ { \
+ size_t count = other.Count(); \
+ for ( size_t n = 0; n < count; n++ ) \
+ { \
+ array.Add(other[n]); \
+ } \
+ }
+
// delete all array elements
//
// NB: the class declaration of the array elements must be visible from the
#include "wx/control.h" // the base class
-#include "wx/datetime.h" // for m_date
-#include "wx/combobox.h" // for m_comboMonth
-#include "wx/spinctrl.h" // for m_spinYear
+#include "wx/spinctrl.h" // for wxSpinEvent
+
+class WXDLLEXPORT wxComboBox;
#define wxCalendarNameStr _T("CalendarCtrl")
const wxDateTime& date = wxDefaultDateTime,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
- long style = 0,
+ long style = wxCAL_SHOW_HOLIDAYS,
const wxString& name = wxCalendarNameStr)
: wxControl(parent, id, pos, size,
style | wxWANTS_CHARS, wxDefaultValidator, name)
const wxDateTime& date = wxDefaultDateTime,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
- long style = 0,
+ long style = wxCAL_SHOW_HOLIDAYS,
const wxString& name = wxCalendarNameStr);
virtual ~wxCalendarCtrl();
// set/get the current date
+ // ------------------------
+
void SetDate(const wxDateTime& date);
const wxDateTime& GetDate() const { return m_date; }
+ // customization
+ // -------------
+
+ // header colours are used for painting the weekdays at the top
+ void SetHeaderColours(const wxColour& colFg, const wxColour& colBg)
+ {
+ m_colHeaderFg = colFg;
+ m_colHeaderBg = colBg;
+ }
+
+ const wxColour& GetHeaderColourFg() const { return m_colHeaderFg; }
+ const wxColour& GetHeaderColourBg() const { return m_colHeaderBg; }
+
+ // highlight colour is used for the currently selected date
+ void SetHighlightColours(const wxColour& colFg, const wxColour& colBg)
+ {
+ m_colHighlightFg = colFg;
+ m_colHighlightBg = colBg;
+ }
+
+ const wxColour& GetHighlightColourFg() const { return m_colHighlightFg; }
+ const wxColour& GetHighlightColourBg() const { return m_colHighlightBg; }
+
+ // holiday colour is used for the holidays (if style & wxCAL_SHOW_HOLIDAYS)
+ void SetHolidayColours(const wxColour& colFg, const wxColour& colBg)
+ {
+ m_colHolidayFg = colFg;
+ m_colHolidayBg = colBg;
+ }
+
+ const wxColour& GetHolidayColourFg() const { return m_colHolidayFg; }
+ const wxColour& GetHolidayColourBg() const { return m_colHolidayBg; }
+
+ // this function should be called instead of directly changing the
+ // wxCAL_SHOW_HOLIDAYS bit in the control style after the control creation
+ // (this won't work)
+ void EnableHolidayDisplay(bool display = TRUE);
+
+ // an item without custom attributes is drawn with the default colours and
+ // font and without border, setting custom attributes allows to modify this
+ //
+ // the day parameter should be in 1..31 range, for days 29, 30, 31 the
+ // corresponding attribute is just unused if there is no such day in the
+ // current month
+
+ wxCalendarDateAttr *GetAttr(size_t day) const
+ {
+ wxCHECK_MSG( day > 0 && day < 32, NULL, _T("invalid day") );
+
+ return m_attrs[day - 1];
+ }
+
+ void SetAttr(size_t day, wxCalendarDateAttr *attr)
+ {
+ wxCHECK_RET( day > 0 && day < 32, _T("invalid day") );
+
+ delete m_attrs[day - 1];
+ m_attrs[day - 1] = attr;
+ }
+
+ void SetHoliday(size_t day);
+
+ void ResetAttr(size_t day) { SetAttr(day, (wxCalendarDateAttr *)NULL); }
+
// returns one of wxCAL_HITTEST_XXX constants and fills either date or wd
// with the corresponding value (none for NOWHERE, the date for DAY and wd
// for HEADER)
void OnChar(wxKeyEvent& event);
void OnMonthChange(wxCommandEvent& event);
void OnYearChange(wxSpinEvent& event);
+ void OnCalMonthChange(wxCalendarEvent& event);
// override some base class virtuals
virtual wxSize DoGetBestSize() const;
// change the date inside the same month/year
void ChangeDay(const wxDateTime& date);
- // generate the given calendar event and a "selection changed" one if
- // selChanged is TRUE
- void GenerateEvent(wxEventType type, bool selChanged = TRUE);
+ // set the attributes for the holidays if needed
+ void SetHolidayAttrs();
+
+ // reset all holidays
+ void ResetHolidayAttrs();
+
+ // generate the given calendar event(s)
+ void GenerateEvent(wxEventType type)
+ {
+ wxCalendarEvent event(this, type);
+ (void)GetEventHandler()->ProcessEvent(event);
+ }
+
+ void GenerateEvents(wxEventType type1, wxEventType type2)
+ {
+ GenerateEvent(type1);
+ GenerateEvent(type2);
+ }
// the subcontrols
wxComboBox *m_comboMonth;
wxSpinCtrl *m_spinYear;
+ // the current selection
wxDateTime m_date;
+ // default attributes
+ wxColour m_colHighlightFg,
+ m_colHighlightBg,
+ m_colHolidayFg,
+ m_colHolidayBg,
+ m_colHeaderFg,
+ m_colHeaderBg;
+
+ // the attributes for each of the month days
+ wxCalendarDateAttr *m_attrs[31];
+
// the width and height of one column/row in the calendar
wxCoord m_widthCol,
m_heightRow;
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/log.h"
+ #include "wx/module.h"
#endif // WX_PRECOMP
#include "wx/thread.h"
#endif
#endif // !WX_TIMEZONE
+// ----------------------------------------------------------------------------
+// private classes
+// ----------------------------------------------------------------------------
+
+class wxDateTimeHolidaysModule : public wxModule
+{
+public:
+ virtual bool OnInit()
+ {
+ wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays);
+
+ return TRUE;
+ }
+
+ virtual void OnExit()
+ {
+ wxDateTimeHolidayAuthority::ClearAllAuthorities();
+ }
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule)
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
+// debugger helper: shows what the date really is
+#ifdef __WXDEBUG__
+extern const wxChar *wxDumpDate(const wxDateTime* dt)
+{
+ static wxChar buf[20];
+
+ wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S")));
+
+ return buf;
+}
+#endif // Debug
+
// get the number of days in the given month of the given year
static inline
wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month)
mon = (wxDateTime::Month)(mon + monDiff);
wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") );
+
+ // NB: we don't check here that the resulting date is valid, this function
+ // is private and the caller must check it if needed
}
void wxDateTime::Tm::AddDays(int dayDiff)
tm.year += diff.GetYears();
tm.AddMonths(diff.GetMonths());
+
+ // check that the resulting date is valid
+ if ( tm.mday > GetNumOfDaysInMonth(tm.year, tm.mon) )
+ {
+ // We suppose that when adding one month to Jan 31 we want to get Feb
+ // 28 (or 29), i.e. adding a month to the last day of the month should
+ // give the last day of the next month which is quite logical.
+ //
+ // Unfortunately, there is no logic way to understand what should
+ // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)?
+ // We make it Feb 28 (last day too), but it is highly questionable.
+ tm.mday = GetNumOfDaysInMonth(tm.year, tm.mon);
+ }
+
tm.AddDays(diff.GetTotalDays());
Set(tm);
// Weekday and monthday stuff
// ----------------------------------------------------------------------------
+bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek, WeekDay weekday)
+{
+ int year = GetYear();
+
+ // Jan 4 always lies in the 1st week of the year
+ Set(4, Jan, year);
+ SetToWeekDayInSameWeek(weekday) += wxDateSpan::Weeks(numWeek);
+
+ if ( GetYear() != year )
+ {
+ // oops... numWeek was too big
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
int year)
{
}
else if ( weekday < wdayThis )
{
- return Substract(wxTimeSpan::Days(wdayThis - weekday));
+ return Substract(wxDateSpan::Days(wdayThis - weekday));
}
else // weekday > wdayThis
{
- return Add(wxTimeSpan::Days(weekday - wdayThis));
+ return Add(wxDateSpan::Days(weekday - wdayThis));
}
}
diff = weekday - wdayThis;
}
- return Add(wxTimeSpan::Days(diff));
+ return Add(wxDateSpan::Days(diff));
}
wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday)
diff = wdayThis - weekday;
}
- return Substract(wxTimeSpan::Days(diff));
+ return Substract(wxDateSpan::Days(diff));
}
bool wxDateTime::SetToWeekDay(WeekDay weekday,
return result;
}
+// ----------------------------------------------------------------------------
+// Workdays and holidays support
+// ----------------------------------------------------------------------------
+
+bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const
+{
+ return !wxDateTimeHolidayAuthority::IsHoliday(*this);
+}
+
// ============================================================================
// wxTimeSpan
// ============================================================================
return str;
}
+
+// ============================================================================
+// wxDateTimeHolidayAuthority and related classes
+// ============================================================================
+
+#include "wx/arrimpl.cpp"
+
+WX_DEFINE_OBJARRAY(wxDateTimeArray)
+
+static int wxCMPFUNC_CONV
+wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second)
+{
+ wxDateTime dt1 = **first,
+ dt2 = **second;
+
+ return dt1 == dt2 ? 0 : dt1 < dt2 ? -1 : +1;
+}
+
+// ----------------------------------------------------------------------------
+// wxDateTimeHolidayAuthority
+// ----------------------------------------------------------------------------
+
+wxHolidayAuthoritiesArray wxDateTimeHolidayAuthority::ms_authorities;
+
+/* static */
+bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime& dt)
+{
+ size_t count = ms_authorities.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ if ( ms_authorities[n]->DoIsHoliday(dt) )
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* static */
+size_t
+wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart,
+ const wxDateTime& dtEnd,
+ wxDateTimeArray& holidays)
+{
+ wxDateTimeArray hol;
+
+ holidays.Empty();
+
+ size_t count = ms_authorities.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ ms_authorities[n]->DoGetHolidaysInRange(dtStart, dtEnd, hol);
+
+ WX_APPEND_ARRAY(holidays, hol);
+ }
+
+ holidays.Sort(wxDateTimeCompareFunc);
+
+ return holidays.GetCount();
+}
+
+/* static */
+void wxDateTimeHolidayAuthority::ClearAllAuthorities()
+{
+ WX_CLEAR_ARRAY(ms_authorities);
+}
+
+/* static */
+void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority *auth)
+{
+ ms_authorities.Add(auth);
+}
+
+// ----------------------------------------------------------------------------
+// wxDateTimeWorkDays
+// ----------------------------------------------------------------------------
+
+bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime& dt) const
+{
+ wxDateTime::WeekDay wd = dt.GetWeekDay();
+
+ return (wd == wxDateTime::Sun) || (wd == wxDateTime::Sat);
+}
+
+size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart,
+ const wxDateTime& dtEnd,
+ wxDateTimeArray& holidays) const
+{
+ if ( dtStart > dtEnd )
+ {
+ wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") );
+
+ return 0u;
+ }
+
+ holidays.Empty();
+
+ // instead of checking all days, start with the first Sat after dtStart and
+ // end with the last Sun before dtEnd
+ wxDateTime dtSatFirst = dtStart.GetNextWeekDay(wxDateTime::Sat),
+ dtSatLast = dtEnd.GetPrevWeekDay(wxDateTime::Sat),
+ dtSunFirst = dtStart.GetNextWeekDay(wxDateTime::Sun),
+ dtSunLast = dtEnd.GetPrevWeekDay(wxDateTime::Sun),
+ dt;
+
+ for ( dt = dtSatFirst; dt <= dtSatLast; dt += wxDateSpan::Week() )
+ {
+ holidays.Add(dt);
+ }
+
+ for ( dt = dtSunFirst; dt <= dtSunLast; dt += wxDateSpan::Week() )
+ {
+ holidays.Add(dt);
+ }
+
+ return holidays.GetCount();
+}
#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/brush.h"
+ #include "wx/combobox.h"
#endif //WX_PRECOMP
#include "wx/calctrl.h"
EVT_LEFT_DOWN(wxCalendarCtrl::OnClick)
EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick)
+
+ EVT_CALENDAR_MONTH(-1, wxCalendarCtrl::OnCalMonthChange)
+ EVT_CALENDAR_YEAR(-1, wxCalendarCtrl::OnCalMonthChange)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxMonthComboBox, wxComboBox)
{
m_weekdays[wd] = wxDateTime::GetWeekDayName(wd, wxDateTime::Name_Abbr);
}
+
+ for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ )
+ {
+ m_attrs[n] = NULL;
+ }
+
+ wxSystemSettings ss;
+ m_colHighlightFg = ss.GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ m_colHighlightBg = ss.GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
+
+ m_colHolidayFg = *wxRED;
+ // don't set m_colHolidayBg - by default, same as our bg colour
+
+ m_colHeaderFg = *wxBLUE;
+ m_colHeaderBg = *wxLIGHT_GREY;
}
bool wxCalendarCtrl::Create(wxWindow * WXUNUSED(parent),
SetBackgroundColour(*wxWHITE);
SetFont(*wxSWISS_FONT);
+ SetHolidayAttrs();
+
return TRUE;
}
wxCalendarCtrl::~wxCalendarCtrl()
{
-#if 0
- m_comboMonth->PopEventHandler();
- m_spinYear->PopEventHandler();
-#endif // 0
+ for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ )
+ {
+ delete m_attrs[n];
+ }
}
// ----------------------------------------------------------------------------
SetDate(date);
- GenerateEvent(type);
+ GenerateEvents(type, wxEVT_CALENDAR_SEL_CHANGED);
}
// ----------------------------------------------------------------------------
date.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
? wxDateTime::Mon : wxDateTime::Sun);
- // be sure to do it or it might gain 1 hour if DST changed in between
- date.ResetTime();
-
return date;
}
puts("painting the header");
#endif
- dc.SetTextForeground(*wxBLUE);
- dc.SetBrush(wxBrush(*wxLIGHT_GREY, wxSOLID));
dc.SetBackgroundMode(wxTRANSPARENT);
- dc.SetPen(*wxLIGHT_GREY_PEN);
+ dc.SetTextForeground(m_colHeaderFg);
+ dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
+ dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
dc.DrawRectangle(0, 0, 7*m_widthCol, m_heightRow);
bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0;
if ( IsDateShown(date) )
{
// don't use wxDate::Format() which prepends 0s
- wxString day = wxString::Format(_T("%u"), date.GetDay());
+ unsigned int day = date.GetDay();
+ wxString dayStr = wxString::Format(_T("%u"), day);
wxCoord width;
- dc.GetTextExtent(day, &width, (wxCoord *)NULL);
+ dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL);
+
+ bool changedColours = FALSE,
+ changedFont = FALSE;
+
+ wxCalendarDateAttr *attr = m_attrs[day - 1];
bool isSel = m_date == date;
if ( isSel )
{
- dc.SetTextForeground(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
- dc.SetTextBackground(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT));
+ dc.SetTextForeground(m_colHighlightFg);
+ dc.SetTextBackground(m_colHighlightBg);
+
+ changedColours = TRUE;
+ }
+ else if ( attr )
+ {
+ wxColour colFg, colBg;
+
+ if ( attr->IsHoliday() )
+ {
+ colFg = m_colHolidayFg;
+ colBg = m_colHolidayBg;
+ }
+ else
+ {
+ colFg = attr->GetTextColour();
+ colBg = attr->GetBackgroundColour();
+ }
+
+ if ( colFg.Ok() )
+ {
+ dc.SetTextForeground(colFg);
+ changedColours = TRUE;
+ }
+
+ if ( colBg.Ok() )
+ {
+ dc.SetTextBackground(colBg);
+ changedColours = TRUE;
+ }
+
+ if ( attr->HasFont() )
+ {
+ dc.SetFont(attr->GetFont());
+ changedFont = TRUE;
+ }
}
- dc.DrawText(day, wd*m_widthCol + (m_widthCol - width) / 2, y);
+ wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2;
+ dc.DrawText(dayStr, x, y + 1);
- if ( isSel )
+ if ( !isSel && attr && attr->HasBorder() )
+ {
+ wxColour colBorder;
+ if ( attr->HasBorderColour() )
+ {
+ colBorder = attr->GetBorderColour();
+ }
+ else
+ {
+ colBorder = m_foregroundColour;
+ }
+
+ wxPen pen(colBorder, 1, wxSOLID);
+ dc.SetPen(pen);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
+
+ switch ( attr->GetBorder() )
+ {
+ case wxCAL_BORDER_SQUARE:
+ dc.DrawRectangle(x - 2, y,
+ width + 4, m_heightRow);
+ break;
+
+ case wxCAL_BORDER_ROUND:
+ dc.DrawEllipse(x - 2, y,
+ width + 4, m_heightRow);
+ break;
+
+ default:
+ wxFAIL_MSG(_T("unknown border type"));
+ }
+ }
+
+ if ( changedColours )
{
dc.SetTextForeground(m_foregroundColour);
dc.SetTextBackground(m_backgroundColour);
}
+
+ if ( changedFont )
+ {
+ dc.SetFont(m_font);
+ }
}
//else: just don't draw it
}
else
{
- GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED, FALSE);
+ GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
}
}
case wxCAL_HITTEST_DAY:
ChangeDay(date);
- GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED);
+ GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED,
+ wxEVT_CALENDAR_SEL_CHANGED);
break;
case wxCAL_HITTEST_HEADER:
SetDate(wxDateTime(tm.mday, mon, tm.year));
- GenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED);
+ GenerateEvents(wxEVT_CALENDAR_MONTH_CHANGED, wxEVT_CALENDAR_SEL_CHANGED);
}
void wxCalendarCtrl::OnYearChange(wxSpinEvent& event)
SetDate(wxDateTime(tm.mday, tm.mon, year));
- GenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED);
+ GenerateEvents(wxEVT_CALENDAR_YEAR_CHANGED, wxEVT_CALENDAR_SEL_CHANGED);
}
// ----------------------------------------------------------------------------
SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay());
break;
+ case WXK_RETURN:
+ GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
+ break;
+
default:
event.Skip();
}
}
// ----------------------------------------------------------------------------
-// wxCalendarEvent
+// holidays handling
// ----------------------------------------------------------------------------
-void wxCalendarCtrl::GenerateEvent(wxEventType type, bool selChanged)
+void wxCalendarCtrl::OnCalMonthChange(wxCalendarEvent& event)
+{
+ SetHolidayAttrs();
+
+ event.Skip();
+}
+
+void wxCalendarCtrl::EnableHolidayDisplay(bool display)
{
- // we're called for a change in some particular date field but we always
- // also generate a generic "changed" event
- wxCalendarEvent event(this, type);
- (void)GetEventHandler()->ProcessEvent(event);
+ long style = GetWindowStyle();
+ if ( display )
+ style |= wxCAL_SHOW_HOLIDAYS;
+ else
+ style &= ~wxCAL_SHOW_HOLIDAYS;
+
+ SetWindowStyle(style);
+
+ if ( display )
+ SetHolidayAttrs();
+ else
+ ResetHolidayAttrs();
+
+ Refresh();
+}
+
+void wxCalendarCtrl::SetHolidayAttrs()
+{
+ if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS )
+ {
+ ResetHolidayAttrs();
+
+ wxDateTime::Tm tm = m_date.GetTm();
+ wxDateTime dtStart(1, tm.mon, tm.year),
+ dtEnd = dtStart.GetLastMonthDay();
+
+ wxDateTimeArray hol;
+ wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol);
+
+ size_t count = hol.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ SetHoliday(hol[n].GetDay());
+ }
+ }
+}
+
+void wxCalendarCtrl::SetHoliday(size_t day)
+{
+ wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") );
- if ( selChanged )
+ wxCalendarDateAttr *attr = GetAttr(day);
+ if ( !attr )
{
- wxCalendarEvent event2(this, wxEVT_CALENDAR_SEL_CHANGED);
+ attr = new wxCalendarDateAttr;
+ }
- (void)GetEventHandler()->ProcessEvent(event2);
+ attr->SetHoliday(TRUE);
+
+ // can't use SetAttr() because it would delete this pointer
+ m_attrs[day - 1] = attr;
+}
+
+void wxCalendarCtrl::ResetHolidayAttrs()
+{
+ for ( size_t day = 0; day < 31; day++ )
+ {
+ if ( m_attrs[day] )
+ {
+ m_attrs[day]->SetHoliday(FALSE);
+ }
}
}
+// ----------------------------------------------------------------------------
+// wxCalendarEvent
+// ----------------------------------------------------------------------------
+
void wxCalendarEvent::Init()
{
m_wday = wxDateTime::Inv_WeekDay;