1. wxDateTimeHolidayAuthority class for calculating the holidays added

2. wxCalendarCtrl adjustments and some new features


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5182 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2000-01-02 23:17:55 +00:00
parent c88275cb7d
commit 4f6aed9c6a
11 changed files with 817 additions and 60 deletions

View File

@ -6,6 +6,11 @@ next release (2.1.12 or 2.2?)
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)
@ -22,10 +27,14 @@ wxBase:
- 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)

View File

@ -193,7 +193,8 @@ does exactly the same as \helpref{Item()}{wxarrayitem} method.
\membersection{Adding items}
\helpref{Add}{wxarrayadd}\\
\helpref{Insert}{wxarrayinsert}
\helpref{Insert}{wxarrayinsert}\\
\helpref{WX\_APPEND\_ARRAY}{wxappendarray}
\membersection{Removing items}
@ -311,6 +312,13 @@ public:
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}}
@ -385,6 +393,9 @@ to the array, however, the array will make a copy of the item and will not take
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}}

22
docs/latex/wx/calctrl.tex Normal file
View File

@ -0,0 +1,22 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 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}

View File

@ -19,6 +19,12 @@ make it easier to find the relevant one if a simple grep through all sources
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}

View File

@ -9,9 +9,18 @@
// 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
// ----------------------------------------------------------------------------
@ -24,17 +33,85 @@ enum wxCalendarHitTestResult
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;
@ -53,6 +130,17 @@ private:
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 },

View File

@ -38,9 +38,10 @@ class WXDLLEXPORT wxDateSpan;
* 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
*/
/*
@ -618,17 +619,21 @@ public:
// 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
@ -638,24 +643,35 @@ public:
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
//
@ -784,13 +800,12 @@ public:
// 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;
@ -891,9 +906,12 @@ public:
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
// ------------------------------------------------------------------------
@ -1098,7 +1116,12 @@ private:
// 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
@ -1210,10 +1233,75 @@ private:
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

View File

@ -16,8 +16,21 @@
#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
// ----------------------------------------------------------------------------
@ -138,6 +151,57 @@ bool wxDateTime::SetToLastWeekDay(WeekDay weekday,
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
// ----------------------------------------------------------------------------
@ -287,8 +351,7 @@ wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff)
wxDateTime wxDateTime::ToTimezone(const wxDateTime::TimeZone& tz,
bool noDST) const
{
wxDateTime dt(*this);
return dt.MakeTimezone(tz, noDST);
MODIFY_AND_RETURN( MakeTimezone(tz, noDST) );
}
// ----------------------------------------------------------------------------
@ -437,3 +500,5 @@ wxDateSpan& wxDateSpan::Neg()
}
#undef MILLISECONDS_PER_DAY
#undef MODIFY_AND_RETURN

View File

@ -448,6 +448,16 @@ WX_DEFINE_EXPORTED_ARRAY(void *, wxArrayPtrVoid);
// 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

View File

@ -18,9 +18,9 @@
#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")
@ -41,7 +41,7 @@ public:
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)
@ -56,15 +56,81 @@ public:
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)
@ -90,6 +156,7 @@ private:
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;
@ -119,16 +186,43 @@ private:
// 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;

View File

@ -67,6 +67,7 @@
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/module.h"
#endif // WX_PRECOMP
#include "wx/thread.h"
@ -99,6 +100,31 @@
#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
// ----------------------------------------------------------------------------
@ -160,6 +186,18 @@ wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown;
// 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)
@ -437,6 +475,9 @@ void wxDateTime::Tm::AddMonths(int monDiff)
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)
@ -1358,6 +1399,20 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
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);
@ -1372,6 +1427,23 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
// 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)
{
@ -1396,11 +1468,11 @@ wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday)
}
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));
}
}
@ -1425,7 +1497,7 @@ wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday)
diff = weekday - wdayThis;
}
return Add(wxTimeSpan::Days(diff));
return Add(wxDateSpan::Days(diff));
}
wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday)
@ -1449,7 +1521,7 @@ wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday)
diff = wdayThis - weekday;
}
return Substract(wxTimeSpan::Days(diff));
return Substract(wxDateSpan::Days(diff));
}
bool wxDateTime::SetToWeekDay(WeekDay weekday,
@ -3240,6 +3312,15 @@ const wxChar *wxDateTime::ParseTime(const wxChar *time)
return result;
}
// ----------------------------------------------------------------------------
// Workdays and holidays support
// ----------------------------------------------------------------------------
bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const
{
return !wxDateTimeHolidayAuthority::IsHoliday(*this);
}
// ============================================================================
// wxTimeSpan
// ============================================================================
@ -3325,3 +3406,121 @@ wxString wxTimeSpan::Format(const wxChar *format) const
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();
}

View File

@ -32,6 +32,7 @@
#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/brush.h"
#include "wx/combobox.h"
#endif //WX_PRECOMP
#include "wx/calctrl.h"
@ -79,6 +80,9 @@ BEGIN_EVENT_TABLE(wxCalendarCtrl, wxControl)
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)
@ -146,6 +150,21 @@ void wxCalendarCtrl::Init()
{
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),
@ -182,15 +201,17 @@ 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];
}
}
// ----------------------------------------------------------------------------
@ -285,7 +306,7 @@ void wxCalendarCtrl::SetDateAndNotify(const wxDateTime& date)
SetDate(date);
GenerateEvent(type);
GenerateEvents(type, wxEVT_CALENDAR_SEL_CHANGED);
}
// ----------------------------------------------------------------------------
@ -302,9 +323,6 @@ wxDateTime wxCalendarCtrl::GetStartDate() const
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;
}
@ -444,10 +462,10 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
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;
@ -495,24 +513,104 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
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
@ -560,7 +658,7 @@ void wxCalendarCtrl::OnDClick(wxMouseEvent& event)
}
else
{
GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED, FALSE);
GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
}
}
@ -573,7 +671,8 @@ void wxCalendarCtrl::OnClick(wxMouseEvent& event)
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:
@ -655,7 +754,7 @@ void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event)
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)
@ -670,7 +769,7 @@ 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);
}
// ----------------------------------------------------------------------------
@ -736,30 +835,96 @@ void wxCalendarCtrl::OnChar(wxKeyEvent& event)
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)
{
// 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);
SetHolidayAttrs();
if ( selChanged )
event.Skip();
}
void wxCalendarCtrl::EnableHolidayDisplay(bool display)
{
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 )
{
wxCalendarEvent event2(this, wxEVT_CALENDAR_SEL_CHANGED);
ResetHolidayAttrs();
(void)GetEventHandler()->ProcessEvent(event2);
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") );
wxCalendarDateAttr *attr = GetAttr(day);
if ( !attr )
{
attr = new wxCalendarDateAttr;
}
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;