]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/calctrlg.cpp
Fix typo in last commit
[wxWidgets.git] / src / generic / calctrlg.cpp
index 98b15213c55b4054297515ebc903519c01383eb7..f8a14221c67999cb66cb9d2894df4307beabbde2 100644 (file)
 // wxWin macros
 // ----------------------------------------------------------------------------
 
+#ifdef wxHAS_NATIVE_CALENDARCTRL
+
+wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxGenericCalendarCtrl, wxControl,"wx/calctrl.h")
+
+#endif
+
 BEGIN_EVENT_TABLE(wxGenericCalendarCtrl, wxControl)
     EVT_PAINT(wxGenericCalendarCtrl::OnPaint)
 
@@ -58,64 +64,6 @@ BEGIN_EVENT_TABLE(wxGenericCalendarCtrl, wxControl)
     EVT_SYS_COLOUR_CHANGED(wxGenericCalendarCtrl::OnSysColourChanged)
 END_EVENT_TABLE()
 
-#if wxUSE_EXTENDED_RTTI
-WX_DEFINE_FLAGS( wxCalendarCtrlStyle )
-
-wxBEGIN_FLAGS( wxCalendarCtrlStyle )
-    // new style border flags, we put them first to
-    // use them for streaming out
-    wxFLAGS_MEMBER(wxBORDER_SIMPLE)
-    wxFLAGS_MEMBER(wxBORDER_SUNKEN)
-    wxFLAGS_MEMBER(wxBORDER_DOUBLE)
-    wxFLAGS_MEMBER(wxBORDER_RAISED)
-    wxFLAGS_MEMBER(wxBORDER_STATIC)
-    wxFLAGS_MEMBER(wxBORDER_NONE)
-
-    // old style border flags
-    wxFLAGS_MEMBER(wxSIMPLE_BORDER)
-    wxFLAGS_MEMBER(wxSUNKEN_BORDER)
-    wxFLAGS_MEMBER(wxDOUBLE_BORDER)
-    wxFLAGS_MEMBER(wxRAISED_BORDER)
-    wxFLAGS_MEMBER(wxSTATIC_BORDER)
-    wxFLAGS_MEMBER(wxBORDER)
-
-    // standard window styles
-    wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
-    wxFLAGS_MEMBER(wxCLIP_CHILDREN)
-    wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
-    wxFLAGS_MEMBER(wxWANTS_CHARS)
-    wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
-    wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
-    wxFLAGS_MEMBER(wxVSCROLL)
-    wxFLAGS_MEMBER(wxHSCROLL)
-
-    wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST)
-    wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST)
-    wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS)
-    wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE)
-    wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE)
-    wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION)
-    wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS)
-
-wxEND_FLAGS( wxCalendarCtrlStyle )
-
-IMPLEMENT_DYNAMIC_CLASS_XTI(wxGenericCalendarCtrl, wxControl,"wx/calctrl.h")
-
-wxBEGIN_PROPERTIES_TABLE(wxGenericCalendarCtrl)
-    wxEVENT_RANGE_PROPERTY( Updated , wxEVT_CALENDAR_SEL_CHANGED , wxEVT_CALENDAR_WEEKDAY_CLICKED , wxCalendarEvent )
-    wxHIDE_PROPERTY( Children )
-    wxPROPERTY( Date,wxDateTime, SetDate , GetDate, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-    wxPROPERTY_FLAGS( WindowStyle , wxCalendarCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
-wxEND_PROPERTIES_TABLE()
-
-wxBEGIN_HANDLERS_TABLE(wxGenericCalendarCtrl)
-wxEND_HANDLERS_TABLE()
-
-wxCONSTRUCTOR_6( wxGenericCalendarCtrl , wxWindow* , Parent , wxWindowID , Id , wxDateTime , Date , wxPoint , Position , wxSize , Size , long , WindowStyle )
-#else
-IMPLEMENT_DYNAMIC_CLASS(wxGenericCalendarCtrl, wxControl)
-#endif
-
 // ============================================================================
 // implementation
 // ============================================================================
@@ -190,7 +138,8 @@ void wxGenericCalendarCtrl::Init()
     m_userChangedYear = false;
 
     m_widthCol =
-    m_heightRow = 0;
+    m_heightRow =
+    m_calendarWeekWidth = 0;
 
     wxDateTime::WeekDay wd;
     for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
@@ -246,11 +195,11 @@ bool wxGenericCalendarCtrl::Create(wxWindow *parent,
     if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
     {
         CreateYearSpinCtrl();
-        m_staticYear = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%Y")),
+        m_staticYear = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(wxT("%Y")),
                                         wxDefaultPosition, wxDefaultSize,
                                         wxALIGN_CENTRE);
         CreateMonthComboBox();
-        m_staticMonth = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%B")),
+        m_staticMonth = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(wxT("%B")),
                                          wxDefaultPosition, wxDefaultSize,
                                          wxALIGN_CENTRE);
     }
@@ -294,7 +243,7 @@ void wxGenericCalendarCtrl::SetWindowStyleFlag(long style)
     // created/shown/hidden accordingly
     wxASSERT_MSG( (style & wxCAL_SEQUENTIAL_MONTH_SELECTION) ==
                     (m_windowStyle & wxCAL_SEQUENTIAL_MONTH_SELECTION),
-                  _T("wxCAL_SEQUENTIAL_MONTH_SELECTION can't be changed after creation") );
+                  wxT("wxCAL_SEQUENTIAL_MONTH_SELECTION can't be changed after creation") );
 
     wxControl::SetWindowStyleFlag(style);
 }
@@ -333,14 +282,11 @@ void wxGenericCalendarCtrl::CreateMonthComboBox()
 void wxGenericCalendarCtrl::CreateYearSpinCtrl()
 {
     m_spinYear = new wxSpinCtrl(GetParent(), wxID_ANY,
-                                GetDate().Format(_T("%Y")),
+                                GetDate().Format(wxT("%Y")),
                                 wxDefaultPosition,
                                 wxDefaultSize,
                                 wxSP_ARROW_KEYS | wxCLIP_SIBLINGS,
                                 -4300, 10000, GetDate().GetYear());
-#ifdef __WXMAC__
-    m_spinYear->SetSize( 90, -1 );
-#endif
 
     m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_TEXT_UPDATED,
                         wxCommandEventHandler(wxGenericCalendarCtrl::OnYearTextChange),
@@ -518,7 +464,7 @@ bool wxGenericCalendarCtrl::SetDate(const wxDateTime& date)
                     if ( AllowYearChange() )
                     {
                         if ( !m_userChangedYear )
-                            m_spinYear->SetValue(m_date.Format(_T("%Y")));
+                            m_spinYear->SetValue(m_date.Format(wxT("%Y")));
                     }
                 }
 
@@ -646,8 +592,7 @@ wxDateTime wxGenericCalendarCtrl::GetStartDate() const
     wxDateTime date = wxDateTime(1, tm.mon, tm.year);
 
     // rewind back
-    date.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
-                          ? wxDateTime::Mon : wxDateTime::Sun);
+    date.SetToPrevWeekDay(GetWeekStart());
 
     if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS )
     {
@@ -680,69 +625,26 @@ bool wxGenericCalendarCtrl::IsDateInRange(const wxDateTime& date) const
         && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) );
 }
 
-bool wxGenericCalendarCtrl::ChangeYear(wxDateTime* target) const
+bool wxGenericCalendarCtrl::AdjustDateToRange(wxDateTime *date) const
 {
-    bool retval = false;
-
-    if ( !(IsDateInRange(*target)) )
-    {
-        if ( target->GetYear() < m_date.GetYear() )
-        {
-            if ( target->GetYear() >= GetLowerDateLimit().GetYear() )
-            {
-                *target = GetLowerDateLimit();
-                retval = true;
-            }
-            else
-            {
-                *target = m_date;
-            }
-        }
-        else
-        {
-            if ( target->GetYear() <= GetUpperDateLimit().GetYear() )
-            {
-                *target = GetUpperDateLimit();
-                retval = true;
-            }
-            else
-            {
-                *target = m_date;
-            }
-        }
-    }
-    else
+    if ( m_lowdate.IsValid() && *date < m_lowdate )
     {
-        retval = true;
+        *date = m_lowdate;
+        return true;
     }
 
-    return retval;
-}
-
-bool wxGenericCalendarCtrl::ChangeMonth(wxDateTime* target) const
-{
-    bool retval = true;
-
-    if ( !(IsDateInRange(*target)) )
+    if ( m_highdate.IsValid() && *date > m_highdate )
     {
-        retval = false;
-
-        if ( target->GetMonth() < m_date.GetMonth() )
-        {
-            *target = GetLowerDateLimit();
-        }
-        else
-        {
-            *target = GetUpperDateLimit();
-        }
+        *date = m_highdate;
+        return true;
     }
 
-    return retval;
+    return false;
 }
 
 size_t wxGenericCalendarCtrl::GetWeek(const wxDateTime& date) const
 {
-    size_t retval = date.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
+    size_t retval = date.GetWeekOfMonth(HasFlag(wxCAL_MONDAY_FIRST)
                                    ? wxDateTime::Monday_First
                                    : wxDateTime::Sunday_First);
 
@@ -754,8 +656,7 @@ size_t wxGenericCalendarCtrl::GetWeek(const wxDateTime& date) const
         wxDateTime datetest = wxDateTime(1, tm.mon, tm.year);
 
         // rewind back
-        datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
-                              ? wxDateTime::Mon : wxDateTime::Sun);
+        datetest.SetToPrevWeekDay(GetWeekStart());
 
         if ( datetest.GetDay() == 1 )
         {
@@ -772,7 +673,7 @@ size_t wxGenericCalendarCtrl::GetWeek(const wxDateTime& date) const
 
 // this is a composite control and it must arrange its parts each time its
 // size or position changes: the combobox and spinctrl are along the top of
-// the available area and the calendar takes up therest of the space
+// the available area and the calendar takes up the rest of the space
 
 // the static controls are supposed to be always smaller than combo/spin so we
 // always use the latter for size calculations and position the static to take
@@ -787,8 +688,8 @@ wxSize wxGenericCalendarCtrl::DoGetBestSize() const
     // calc the size of the calendar
     const_cast<wxGenericCalendarCtrl *>(this)->RecalcGeometry();
 
-    wxCoord width = 7*m_widthCol,
-            height = 7*m_heightRow + m_rowOffset;
+    wxCoord width = 7*m_widthCol + m_calendarWeekWidth,
+            height = 7*m_heightRow + m_rowOffset + VERT_MARGIN;
 
     if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
     {
@@ -796,12 +697,8 @@ wxSize wxGenericCalendarCtrl::DoGetBestSize() const
 
         height += wxMax(bestSizeCombo.y, m_spinYear->GetBestSize().y)
                     + VERT_MARGIN;
-#ifdef __WXMAC__
-        // the spin control get clipped otherwise
-        width += 10;
-#endif
 
-        wxCoord w2 = bestSizeCombo.x + HORZ_MARGIN + GetCharWidth()*6;
+        wxCoord w2 = bestSizeCombo.x + HORZ_MARGIN + GetCharWidth()*8;
         if ( width < w2 )
             width = w2;
     }
@@ -813,7 +710,7 @@ wxSize wxGenericCalendarCtrl::DoGetBestSize() const
     }
 
     CacheBestSize(best);
-    
+
     return best;
 }
 
@@ -829,12 +726,8 @@ void wxGenericCalendarCtrl::DoMoveWindow(int x, int y, int width, int height)
 
         int maxHeight = wxMax(sizeSpin.y, sizeCombo.y);
         int dy = (maxHeight - sizeStatic.y) / 2;
-#ifdef __WXMAC__
-        m_comboMonth->Move(x, y + (maxHeight - sizeCombo.y)/2 + 2); // FIXME, something is reporting the wrong size..
-#else
         m_comboMonth->Move(x, y + (maxHeight - sizeCombo.y)/2);
-#endif
-        m_staticMonth->SetSize(x, y + dy, sizeCombo.x, -1, sizeStatic.y);
+        m_staticMonth->SetSize(x, y + dy, sizeCombo.x, -1);
 
         int xDiff = sizeCombo.x + HORZ_MARGIN;
 
@@ -853,20 +746,7 @@ void wxGenericCalendarCtrl::DoMoveWindow(int x, int y, int width, int height)
 
 void wxGenericCalendarCtrl::DoGetSize(int *width, int *height) const
 {
-#ifdef __WXMAC__
-    wxControl::DoGetSize( width, height );
-    
-    if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && m_staticMonth && height )
-    {
-        wxSize sizeCombo = m_comboMonth->GetEffectiveMinSize();
-        wxSize sizeSpin = m_spinYear->GetSize();
-
-        int maxHeight = wxMax(sizeSpin.y, sizeCombo.y);
-        *height += maxHeight + VERT_MARGIN;
-    }
-#else
     wxControl::DoGetSize( width, height );
-#endif
 }
 
 void wxGenericCalendarCtrl::RecalcGeometry()
@@ -900,6 +780,9 @@ void wxGenericCalendarCtrl::RecalcGeometry()
         }
     }
 
+    m_calendarWeekWidth = HasFlag( wxCAL_SHOW_WEEK_NUMBERS )
+        ? dc.GetTextExtent( wxString::Format( wxT( "%d" ), 42 )).GetWidth() + 4 : 0;
+
     // leave some margins
     m_widthCol += 2;
     m_heightRow += 2;
@@ -926,7 +809,7 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
 #endif
 
     wxCoord y = 0;
-    wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 );
+    wxCoord x0 = m_calendarWeekWidth;
 
     if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
     {
@@ -1010,7 +893,7 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
         dc.SetPen(wxPen(m_colHeaderBg, 1, wxPENSTYLE_SOLID));
         dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
 
-        bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0;
+        bool startOnMonday = HasFlag(wxCAL_MONDAY_FIRST);
         for ( int wd = 0; wd < 7; wd++ )
         {
             size_t n;
@@ -1029,6 +912,24 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
     //dc.SetFont(*wxNORMAL_FONT);
 
     y += m_heightRow;
+
+    // draw column with calendar week nr
+    if ( HasFlag( wxCAL_SHOW_WEEK_NUMBERS ) && IsExposed( 0, y, m_calendarWeekWidth, m_heightRow * 6 ))
+    {
+        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
+        dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
+        dc.DrawRectangle( 0, y, m_calendarWeekWidth, m_heightRow * 6 );
+        wxDateTime date = GetStartDate();
+        for ( size_t i = 0; i < 6; ++i )
+        {
+            const int weekNr = date.GetWeekOfYear();
+            wxString text = wxString::Format( wxT( "%d" ), weekNr );
+            dc.DrawText( text, m_calendarWeekWidth - dc.GetTextExtent( text ).GetWidth() - 2, y + m_heightRow * i );
+            date += wxDateSpan::Week();
+        }
+    }
+
     wxDateTime date = GetStartDate();
 
 #if DEBUG_PAINT
@@ -1058,7 +959,7 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
             {
                 // don't use wxDate::Format() which prepends 0s
                 unsigned int day = date.GetDay();
-                wxString dayStr = wxString::Format(_T("%u"), day);
+                wxString dayStr = wxString::Format(wxT("%u"), day);
                 wxCoord width;
                 dc.GetTextExtent(dayStr, &width, NULL);
 
@@ -1101,13 +1002,13 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
                             colBg = attr->GetBackgroundColour();
                         }
 
-                        if ( colFg.Ok() )
+                        if ( colFg.IsOk() )
                         {
                             dc.SetTextForeground(colFg);
                             changedColours = true;
                         }
 
-                        if ( colBg.Ok() )
+                        if ( colBg.IsOk() )
                         {
                             dc.SetTextBackground(colBg);
                             changedColours = true;
@@ -1153,7 +1054,7 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
                             break;
 
                         default:
-                            wxFAIL_MSG(_T("unknown border type"));
+                            wxFAIL_MSG(wxT("unknown border type"));
                     }
                 }
 
@@ -1211,9 +1112,9 @@ void wxGenericCalendarCtrl::RefreshDate(const wxDateTime& date)
     wxRect rect;
 
     // always refresh the whole row at once because our OnPaint() will draw
-    // the whole row anyhow - and this allows the small optimisation in
+    // the whole row anyhow - and this allows the small optimization in
     // OnClick() below to work
-    rect.x = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 );
+    rect.x = m_calendarWeekWidth;
 
     rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset;
 
@@ -1279,7 +1180,7 @@ void wxGenericCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fro
             {
                 int numpoints;
                 wxPoint corners[8]; // potentially 8 corners in polygon
-                wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 );
+                wxCoord x0 = m_calendarWeekWidth;
 
                 if ( fw == tw )
                 {
@@ -1339,7 +1240,7 @@ bool wxGenericCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *
 
     if ( IsDateShown(date) )
     {
-        bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0;
+        bool startOnMonday = HasFlag(wxCAL_MONDAY_FIRST);
 
         // Find day
         *day = date.GetWeekDay();
@@ -1452,7 +1353,14 @@ void wxGenericCalendarCtrl::OnClick(wxMouseEvent& event)
                 // GenerateAllChangeEvents() here, we know which event to send
                 GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED);
             }
-            break;
+        break;
+
+        case wxCAL_HITTEST_WEEK:
+        {
+            wxCalendarEvent send( this, date, wxEVT_CALENDAR_WEEK_CLICKED );
+            HandleWindowEvent( send );
+        }
+        break;
 
         case wxCAL_HITTEST_HEADER:
             {
@@ -1470,7 +1378,7 @@ void wxGenericCalendarCtrl::OnClick(wxMouseEvent& event)
             break;
 
         default:
-            wxFAIL_MSG(_T("unknown hittest code"));
+            wxFAIL_MSG(wxT("unknown hittest code"));
             // fall through
 
         case wxCAL_HITTEST_NOWHERE:
@@ -1490,7 +1398,7 @@ wxCalendarHitTestResult wxGenericCalendarCtrl::HitTest(const wxPoint& pos,
     RecalcGeometry();
 
     // the position where the calendar really begins
-    wxCoord x0 = wxMax((GetSize().x - m_widthCol*7)/2, 0);
+    wxCoord x0 = m_calendarWeekWidth;
 
     if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
     {
@@ -1531,18 +1439,36 @@ wxCalendarHitTestResult wxGenericCalendarCtrl::HitTest(const wxPoint& pos,
 
             return wxCAL_HITTEST_INCMONTH;
         }
+    }
 
+    if ( pos.x - x0 < 0 )
+    {
+        if ( pos.x >= 0 && pos.y > m_rowOffset + m_heightRow && pos.y <= m_rowOffset + m_heightRow * 7 )
+        {
+            if ( date )
+            {
+                *date = GetStartDate();
+                *date += wxDateSpan::Week() * (( pos.y - m_rowOffset ) / m_heightRow - 1 );
+            }
+            if ( wd )
+                *wd = GetWeekStart();
+            return wxCAL_HITTEST_WEEK;
+        }
+        else    // early exit -> the rest of the function checks for clicks on days
+            return wxCAL_HITTEST_NOWHERE;
     }
 
     // header: week days
     int wday = (pos.x - x0) / m_widthCol;
-    if ( pos.y < (m_heightRow + m_rowOffset) )
+    if ( wday > 6 )
+        return wxCAL_HITTEST_NOWHERE;
+    if ( pos.y < (m_heightRow + m_rowOffset))
     {
         if ( pos.y > m_rowOffset )
         {
             if ( wd )
             {
-                if ( GetWindowStyle() & wxCAL_MONDAY_FIRST )
+                if ( HasFlag(wxCAL_MONDAY_FIRST) )
                 {
                     wday = wday == 6 ? 0 : wday + 1;
                 }
@@ -1601,10 +1527,15 @@ void wxGenericCalendarCtrl::OnMonthChange(wxCommandEvent& event)
         tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year);
     }
 
-    wxDateTime target = wxDateTime(tm.mday, mon, tm.year);
+    wxDateTime dt(tm.mday, mon, tm.year);
+    if ( AdjustDateToRange(&dt) )
+    {
+        // The date must have been changed to ensure it's in valid range,
+        // reflect this in the month choice control.
+        m_comboMonth->SetSelection(dt.GetMonth());
+    }
 
-    ChangeMonth(&target);
-    SetDateAndNotify(target);
+    SetDateAndNotify(dt);
 }
 
 void wxGenericCalendarCtrl::HandleYearChange(wxCommandEvent& event)
@@ -1623,18 +1554,15 @@ void wxGenericCalendarCtrl::HandleYearChange(wxCommandEvent& event)
         tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year);
     }
 
-    wxDateTime target = wxDateTime(tm.mday, tm.mon, year);
-
-    if ( ChangeYear(&target) )
-    {
-        SetDateAndNotify(target);
-    }
-    else
+    wxDateTime dt(tm.mday, tm.mon, year);
+    if ( AdjustDateToRange(&dt) )
     {
-        // In this case we don't want to change the date. That would put us
-        // inside the same year but a strange number of months forward/back..
-        m_spinYear->SetValue(target.GetYear());
+        // As above, if the date was changed to keep it in valid range, its
+        // possibly changed year must be shown in the GUI.
+        m_spinYear->SetValue(dt.GetYear());
     }
+
+    SetDateAndNotify(dt);
 }
 
 void wxGenericCalendarCtrl::OnYearChange(wxSpinEvent& event)
@@ -1668,49 +1596,31 @@ void wxGenericCalendarCtrl::OnSysColourChanged(wxSysColourChangedEvent& event)
 
 void wxGenericCalendarCtrl::OnChar(wxKeyEvent& event)
 {
-    wxDateTime target;
     switch ( event.GetKeyCode() )
     {
-        case _T('+'):
+        case wxT('+'):
         case WXK_ADD:
-            target = m_date + wxDateSpan::Year();
-            if ( ChangeYear(&target) )
-            {
-                SetDateAndNotify(target);
-            }
+            SetDateAndNotify(m_date + wxDateSpan::Year());
             break;
 
-        case _T('-'):
+        case wxT('-'):
         case WXK_SUBTRACT:
-            target = m_date - wxDateSpan::Year();
-            if ( ChangeYear(&target) )
-            {
-                SetDateAndNotify(target);
-            }
+            SetDateAndNotify(m_date - wxDateSpan::Year());
             break;
 
         case WXK_PAGEUP:
-            target = m_date - wxDateSpan::Month();
-            ChangeMonth(&target);
-            SetDateAndNotify(target); // always
+            SetDateAndNotify(m_date - wxDateSpan::Month());
             break;
 
         case WXK_PAGEDOWN:
-            target = m_date + wxDateSpan::Month();
-            ChangeMonth(&target);
-            SetDateAndNotify(target); // always
+            SetDateAndNotify(m_date + wxDateSpan::Month());
             break;
 
         case WXK_RIGHT:
             if ( event.ControlDown() )
             {
-                target = wxDateTime(m_date).SetToNextWeekDay(
-                                 GetWindowStyle() & wxCAL_MONDAY_FIRST
-                                 ? wxDateTime::Sun : wxDateTime::Sat);
-                if ( !IsDateInRange(target) )
-                {
-                    target = GetUpperDateLimit();
-                }
+                wxDateTime target = m_date.SetToNextWeekDay(GetWeekEnd());
+                AdjustDateToRange(&target);
                 SetDateAndNotify(target);
             }
             else
@@ -1720,13 +1630,8 @@ void wxGenericCalendarCtrl::OnChar(wxKeyEvent& event)
         case WXK_LEFT:
             if ( event.ControlDown() )
             {
-                target = wxDateTime(m_date).SetToPrevWeekDay(
-                                 GetWindowStyle() & wxCAL_MONDAY_FIRST
-                                 ? wxDateTime::Mon : wxDateTime::Sun);
-                if ( !IsDateInRange(target) )
-                {
-                    target = GetLowerDateLimit();
-                }
+                wxDateTime target = m_date.SetToPrevWeekDay(GetWeekStart());
+                AdjustDateToRange(&target);
                 SetDateAndNotify(target);
             }
             else
@@ -1767,7 +1672,7 @@ void wxGenericCalendarCtrl::OnChar(wxKeyEvent& event)
 
 void wxGenericCalendarCtrl::SetHoliday(size_t day)
 {
-    wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") );
+    wxCHECK_RET( day > 0 && day < 32, wxT("invalid day in SetHoliday") );
 
     wxCalendarDateAttr *attr = GetAttr(day);
     if ( !attr )
@@ -1794,7 +1699,7 @@ void wxGenericCalendarCtrl::ResetHolidayAttrs()
 
 void wxGenericCalendarCtrl::Mark(size_t day, bool mark)
 {
-    wxCHECK_RET( day > 0 && day < 32, _T("invalid day in Mark") );
+    wxCHECK_RET( day > 0 && day < 32, wxT("invalid day in Mark") );
 
     const wxCalendarDateAttr& m = wxCalendarDateAttr::GetMark();
     if (mark) {