Screen Shots


Acknowledgements
Thanks to Keith Rule for his MemDC class. Thanks to all the CPians who offered
feedback and code for the DateEdit
and MiniCalendar
projects I posted earlier.
About date recurrence patterns
Many applications require the ability to schedule appointments, workshops or
applications, etc. The ability to schedule these items in a recurrence
pattern is a must when there is more than a few dates involved.
I have looked for source code to do this but I was not pleased with what I
found. There are numerous solutions available (search Google), but the
ones I looked at were either not worth the money asked, not written well, did
not work correctly or were too limited.
The biggest technical issue with date recurrence patterns is that there is
any number of possible patterns which each need to be programmed
separately. Most recurrence pattern code (including my own) chooses a set
of the most commonly used patterns and provides support for these. Also,
they rarely provide support for combining various patterns into one (ie. Occurs
on first, third and last Friday of each month). My implementation is based
on MS Outlook and includes support for the 7 patterns in MS Outlook. Also, my
implementation does not include support for combining patterns.
Technical problems aside, events rarely occur exactly along a specific
defined pattern. There are often situations where an event is schedule for
Friday, but is reschedule for Thursday. Also, holidays, vacation and other
events interfere with and modify the timing of these events. The users I
have worked with avoid using the MS Outlook recurrence patterns for precisely
this reason. Instead, they schedule individual appointments for the
various dates involved. This is often a tedious process and in some cases
highly error prone.
About this implementation
As mentioned above I based my implementation on MS Outlook. The way I
approached this project was to provide the same level of support as MS Outlook
as a basis for getting started. I then reviewed the various enhancements
that would benefit the users.
I researched the ability to combine date patterns and the problem with
this is not a technical one, but rather a question of user interface and
usability. How would the UI need to look and work? Would the average
user be able to understand it? Would I need to provide a secondary UI for
advanced mode? If someone sets up a combined pattern would others be able to
understand it? I decided not to implement combing support because I was
unable to adequately answer these questions. The engine which I developed
should be able to easily accommodate combining, though assuming I (or anyone
else) can satisfactorily answer these questions.
The next enhancement I reviewed was implementing support for skip patterns
within the main recurrence pattern. Skip patterns would allow for special
dates (ie. Holidays, vacations, etc.) to be automatically removed from the
resulting pattern and an appropriate date automatically added into the
pattern. An example of this would be "Skip Christmas and reschedule
for the following Monday". I have implemented support in the core
engine for this feature. However, I have not developed the UI to go with
this as it was a low priority (per my users.) I plan to add this in a
later release.
I also reviewed giving the user finite control over the dates included
in the pattern. This would allow the user to remove a specific date from
the pattern and add specific dates back into the pattern. After working
with my users I felt that this was the most important ability to provide.
My implementation includes support for this and the UI provides a simple means
for the user to control the pattern.
Implementation overview
The CFPSRecurringDates class provides the core date pattern generator
support. This is a utility class with no direct UI. Methods are
provided for accessing the details of the pattern and modifying it. This class
exposes a Serialize function so that it can be easily incorporated into many
projects. (You may need to implement support for persisting the
configuration data to a database, though.)
The CPrShtDateRecur, CPrPgDateRecurBasic, and CPrPgDateRecurPreview
classes provide a user interface for manipulating the pattern engine.
These classes require the IDD_DATE_RECUR_BASIC, IDD_DATE_RECUR_PREVIEW, and IDB_RECUR_IMAGES
resource objects.
Also, I use a mini calendar control and date edit/picker control I developed
earlier. These projects are available from Code Project at
http://www.codeproject.com/miscctrl/MiniCalendar.asp
and http://www.codeproject.com/editctrl/dateparser.asp.
Getting started
To include support for recurring dates in your project:
Copy the .cpp and .h files listed below and include them in your
project.
|
FPSDatePickerCtrl.h |
|
FPSDatePickerCtrl.cpp |
|
FPSDateTimeButtonCtrl.h |
|
FPSDateTimeButtonCtrl.cpp |
|
FPSDateTimeCtrl.h |
|
FPSDateTimeCtrl.cpp |
|
FPSDateTimePopupCtrl.h |
|
FPSDateTimePopupCtrl.cpp |
|
FPSMiniCalendarCtrl.h |
|
FPSMiniCalendarCtrl.cpp |
|
FPSMiniCalendarListCtrl.h |
|
FPSMiniCalendarListCtrl.cpp |
|
FPSRecurringDates.h |
|
FPSRecurringDates.cpp |
|
MemDC.h |
|
OleDateTimeEx.h |
|
OleDateTimeEx.cpp |
|
PrPgDateRecurPreview.h |
|
PrPgDateRecurPreview.cpp |
|
PrShtDateRecur.h |
|
PrShtDateRecur.cpp |
|
PrShtDateRecurBasic.h |
|
PrShtDateRecurBasic.cpp |
Copy the IDD_DATE_RECUR_BASIC, IDD_DATE_RECUR_PREVIEW, IDB_RECUR_IMAGE
and IDB_DATEPICKER_BUTTON resources from the DateRecur.rc file (in the demo
project) into your project.
Implementation Details
CFPSRecurringDates
Core date recurrence engine.
IMPORTANT METHODS:
GeneratePattern(CPtrList& List) |
Call
this function to execute the recurrence pattern and retrieve the
result set.
If the date pattern is configured for NO end, this function will only
generate the first 31 occurrences within the pattern. You will
need to use one of the other GeneratePattern functions if this is not
adequate. |
GeneratePattern(CPtrList& List, COleDateTime& dtEndBy) |
Call
this function to execute the recurrence pattern and retrieve the
result set up-to a cut off date specified by the dtEndBy
parameter. |
GeneratePattern(CPtrList& List, int iMaxOccurences) |
Call
this function to execute the recurrence pattern and retrieve the
result set up-to a cut off # of occurrences. |
CleanupDateList(CPtrList &List) |
The
GeneratePattern function takes a CPtrList& parameter which it
populates with pointers to COleDateTime objects. It is necessary
to cleanup this list before the list is deconstructed. |
IsDateInPattern(COleDateTime&
dtCheck) |
Call
this function to determine if the specified date exists in the
pattern.
This version of the function is provided for low-volume checks (ie.
once or twice) but should not be used within a loop as it can be quite
slow since it must regenerate the pattern on each call. |
IsDateInPattern(CPtrList& List, COleDateTime &dtCheck) |
Call
this function to determine if the specified date exists in the pattern
previously generated and stored in List.
This version of the function is preferred for performance over the
previous version. |
Ongoing development
This project is still under development, however the code posted here has
been tested and functions correctly to the best of my knowledge.
I am currently working on implementing support for skip patterns into the
UI. Also, I have wrapped the core engine into a COM component and added
support for database persistence. This work is being done to implement an
ASP (and hopefully an ASP.NET) version of the UI. When I have completed
the ASP (ASP.NET?) version of the project I will post it to Code Project.
I am also working with the users of this component to determine what other
features/enhancements need to be made. I do not know what this will
reveal, but if there are significant changes I will post them to Code Project.
Notes
You are free to use this code in your own projects both personal and
professional. It can be used in freeware, shareware or commercial software
without a license fee, etc. This code is provided AS-IS and may cause the
universe to implode so use with care. I assume no liability for the
results of this implosion. All I ask is that you include my name in the
credits for your app and that you leave the header comments intact within the
source code.
Change history
|
April 20, 2002
|
Thanks to Neville Franks for identifying an issue with how numeric values were being entered.
Also, thanks to Martin Bohring for pointing out some localization issues.
- Modified basic config dialog to filter input for numeric fields. This prevented a message box from being
displayed due to
DDX_ functions mapping to an integer.
- Modified
CFPSDateTimeCtrl to automatically set date format based on regional settings in Control Panel.
- Added functions to
COleDateTimeEx function to retrieve the date/time formats set in regional settings in Control
Panel and convert values to C style ones.
- Modified method used to populate start/end time combo boxes to use the appropriate time format as set in Control Panel.
|
|
April 22, 2002
|
Thanks to Michael A. Barnhart for suggesting a new monthly-type pattern.
- Added a new month pattern option. This option allows for [First|Second|Third|Fourth|Last] [Day|Weekday|Weekend day|Sunday|etc]
of Every X months [plus|minus] X days
|
|
April 23, 2002
|
Thanks to Michael A. Barnhart for identifying a bug involving duplicate entries in 2 combo boxes.
Thanks to Kwakkie for identifying a problem in the yearly pattern due to a localization issue (my laziness). Also, time
combo boxes not populated correctly (again localization issue) and unable to use numeric keypad for
numeric fields.
- Corrected problem w/duplicate entries in 2 combo boxes
- Corrected problem w/yearly pattern caused by using
ParseDateTime instead of SetDate.
- Corrected problem w/time combo boxes caused by incorrect functionality in the
ConvertVBFormatToCFormat function.
- Corrected problem w/numeric fields not allowing numeric keypad entry.
|