I've been asked by a few people for a short .prg that shows how to use codejock extreme calendar with dbfcdx.
Below is a single short .prg that syncs "events" on the calendar to a dbf/fpt/cdx. I'm trying to keep the sample short. Keep in mind that each event on the calendar may have as many fields as you'd like for things such as "recurring", "reminder", "send email alert", "email address", "medical record", etc... each of these fields would be kept on each event as a custom property. On this short sample I'm implementing only a single custom property "id" to keep the corresponding primary key on file for each event on the calendar.
I hope it helps, but if there are more questions; please feel free to ask, I'm more than willing to help.
/*----------------------------------------------------------------------------*/
#include "fivewin.ch"
//---------- theme constants
#define xtpCalendarThemeOffice2000聽 0
#define xtpCalendarThemeOfficeXP聽 聽 聽 聽 1
#define xtpCalendarThemeOffice2003聽 2
#define xtpCalendarThemeOffice2007聽 3
//----------- views
#define xtpCalendarDayView聽 聽 聽 0
#define xtpCalendarWorkWeekView 聽 聽 1
#define xtpCalendarWeekView 聽 聽 2
#define xtpCalendarMonthView 聽 聽3
static cAlias
*--------------------------------------------------------------------------
function Main()
聽 聽 create_dbf()
聽 聽
聽 聽 MpCal():New()
聽 聽 (cAlias)->( dbCloseArea() )
聽 聽
return nil
//---------------------------------------------------//
static function create_dbf()
聽 聽 local astruc := { { "id", "C", 12, 0 },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 { "starttime"聽 聽, "C", 18, 0 },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 { "endtime"聽聽 聽 , "C", 18, 0 },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 { "subject"聽聽 聽 , "C", 50, 0 },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 { "body"聽 聽 聽 聽 聽 聽 , "M", 10, 0 } }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽
聽 聽 cAlias := "Calendar"
聽 聽 聽 聽
聽 聽 if !file( "calendar.dbf")
聽 聽 聽 聽
聽 聽 聽 聽 dbcreate( cAlias, aStruc, "DBFCDX", .t., cAlias )
聽 聽
聽 聽 聽 聽 (cAlias)->( OrdCreate( cAlias, "id", "id" ) )
聽 聽 聽 聽 (cAlias)->( OrdCreate( cAlias, "starttime", "starttime" ) )
聽 聽 else
聽 聽
聽 聽 聽 聽 dbuseArea( .t., "DBFCDX", cAlias, cAlias, .t. )
聽 聽 endif
聽 聽 (cAlias)->( OrdListAdd( cAlias ) )
聽 聽 聽 聽
Return Nil
聽 聽
//---------------------------------------------------//
CLASS MpCal
聽 聽DATA dCurrentDate AS DATE INIT Date()
聽 聽
聽 聽DATA oCalex, oCalexCapBar
聽 聽DATA oDtPick
聽 聽DATA oExBar 聽
聽 聽DATA oPanelExplorer
聽 聽DATA oPanelCalex
聽 聽DATA oWnd
聽 聽
聽 聽METHOD New()
聽 聽METHOD BuildCalex()
聽 聽METHOD BuildDatePicker()
聽 聽METHOD BuildPanels()
聽 聽METHOD SetSize( nType, nWidth, nHeight )
聽 聽
聽 聽 METHOD xTrmCalTriggeredEvents( Event, Parms )聽 聽
聽 聽 METHOD RetrieveDayEvents( aParms )
聽 聽 METHOD InsertEvent( oEvent )
聽 聽 METHOD UpdateEvent( oEvent )
聽 聽 METHOD DeleteEvent( oEvent )
ENDCLASS
//---------------------------------------------------//
METHOD New() CLASS MpCal
聽 聽
聽 聽local oMenu
聽 聽local oSelf := Self
聽 聽
聽 聽MENU oMenu
聽 聽ENDMENU
聽 聽 DEFINE WINDOW ::oWnd MDI MENU oMenu Title "CodeJock Xtrme Calendar FWH Sample"
聽 聽::BuildPanels()聽 聽 聽 聽 聽 //two panels -left and right
聽 聽::BuildCalex()聽 聽聽 聽 聽 聽 聽 聽 //CodeJock calendar on the right
聽 聽::BuildDatePicker()聽 聽 聽 //CodeJock DatePicker on the left
聽 聽ACTIVATE WINDOW ::oWnd MAXIMIZED;
聽 聽 聽 聽 聽 聽 ON RESIZE oSelf:SetSize( nSizeType, nWidth, nHeight )
聽 聽 聽 聽 聽 聽
RETURN Self
//-----------------------------------------------------------------------------------------------------//
METHOD xTrmCalTriggeredEvents( Event, aParms ) CLASS MpCal
聽 聽 if valType( Event ) == "C"
聽 聽 聽 聽 Do Case
聽 聽 聽 聽 Case Event == "DoRetrieveDayEvents"聽聽 聽 聽 聽
聽 聽 聽 聽 聽 聽 ::RetrieveDayEvents( aParms )
聽 聽 聽 聽 case Event == "EventAddedEx"
聽 聽 聽 聽 聽 聽 ::InsertEvent( aParms[ 1 ] )
聽 聽 聽 聽 case Event == "EventChangedEx" .and. aParms[ 1 ]:CustomProperties:Property( "id" ) != Nil
聽 聽 聽 聽 聽 聽 ::UpdateEvent( aParms[ 1 ] )
聽 聽 聽 聽 case Event == "EventDeletedEx" .and. aParms[ 1 ]:CustomProperties:Property( "id" ) != Nil
聽 聽 聽 聽 聽 聽 ::DeleteEvent( aParms[ 1 ] )
聽 聽 聽 聽 聽 聽
/*聽 聽 聽 other useful triggered events that may be catched.
聽 聽 聽 聽 Case Event == "DblClick"
聽 聽 聽 聽 Case Event == "MouseMove"
聽 聽 聽 聽 Case Event == "MouseDown"
聽 聽 聽 聽 case Event == "KeyDown"
聽 聽 聽 聽 case Event == "IsEditOperationDisabled"
聽 聽 聽 聽 case Event == "IsEditOperationDisabledV"
聽 聽 聽 聽 case Event == "DoUpdateEvent"
聽 聽 聽 聽 case Event == "BeforeEditOperation"
聽 聽 聽 聽 聽 聽 Return ::BeforeEditOperation( aParms[ 1 ] )
聽 聽 聽 聽 otherwise
聽 聽 聽 聽 聽 聽 Logfile( "trace.log", { EventInfo( event, aParms ) } ) */
聽 聽 聽 聽 聽 聽
聽 聽 聽 聽 End
聽 聽 endif
聽 聽
Return nil
//-----------------------------------------------------------------------------------------------------//
METHOD InsertEvent( oEvent ) CLASS MpCal
聽 聽 local cId := GetUniqueId()
聽 聽 (cAlias)->( dbappend() )
聽 聽 (cAlias)->( rLock() )
聽 聽
聽 聽 (cAlias)->id聽 聽 聽 聽 聽 聽 := cId
聽 聽 (cAlias)->Subject 聽 := oEvent:Subject()
聽 聽 (cAlias)->StartTime聽:= Left( TtoS( oEvent:StartTime() ), 14 )
聽 聽 (cAlias)->EndTime聽 聽聽 聽 := Left( TtoS( oEvent:EndTime() ), 14 )
聽 聽 (cAlias)->body聽 聽 聽 聽 聽 := oEvent:Body()
聽 聽 (cAlias)->( dbrUnlock() )
聽 聽 //load custom property for the newly created event with a unique id that will
聽 聽 //match field "id" on calendar.dbf
聽 聽 oEvent:CustomProperties:Property( "id", cId )
聽 聽 //every time a new appointment is added on the calendar control
聽 聽 //you could expand appntmnt details with a custom form where you may pickup
聽 聽 //other values.
聽 聽 //::EventDetails( oEvent )
聽 聽 聽 聽
Return oEvent
//-----------------------------------------------------------------------------------------------------//
METHOD UpdateEvent( oEvent ) CLASS MpCal
聽 聽 local cid := oEvent:CustomProperties:Property( "id" )
聽 聽 (cAlias)->( OrdSetFocus( "id" ) )
聽 聽 (cAlias)->( dbseek( cId ) )
聽 聽
聽 聽 if (cAlias)->( found() ) .and. (cAlias)->( rLock() )
聽 聽
聽 聽 聽 聽 (cAlias)->Subject := oEvent:Subject()
聽 聽 聽 聽 (cAlias)->StartTime := Left( TtoS( oEvent:StartTime() ),14 )
聽 聽 聽 聽 (cAlias)->EndTime := Left( TtoS( oEvent:EndTime() ), 14 )
聽 聽 聽 聽 (cAlias)->body := oEvent:body
聽 聽 聽 聽
聽 聽 聽 聽 (cAlias)->( dbrUnlock() )
聽 聽 聽 聽
聽 聽 endif
聽 聽 //if there is more data that's being pickedup as part of the calendar appointment聽 聽
聽 聽 //then call that screen to allow modification of those values also
聽 聽 //::EventDetails( oEvent )
return oEvent
//-----------------------------------------------------------------------------------------------------//
METHOD DeleteEvent( oEvent ) CLASS MpCal
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽
聽 聽 local cid := oEvent:CustomProperties:Property( "id" )
聽 聽 (cAlias)->( OrdSetFocus( "id" ) )
聽 聽 (cAlias)->( dbseek( cId ) )
聽 聽 if (cAlias)->( found() ) .and. (cAlias)->( rLock() )
聽 聽 聽 聽 (cAlias)->( delete() )
聽 聽 endif
聽 聽
return oEvent
//-----------------------------------------------------------------------------------------------------//
//aParms[ 1 ] contains a datetime value. This function should return all the events found on
//calendar.dbf for that date. 聽To extract only the date portion, we convert the datetime
//value to string and then pullout the first 8 chars asin YYYYMMDD.
//keep in mind that the control calls this function each time the control changes dates,
//or changes views or just about any time the control feels it needs to load data from
//file. So it gets called a lot!
METHOD RetrieveDayEvents( aParms ) CLASS MpCal
聽 聽 local oEvents := aParms[ 2 ]
聽 聽 local oEvent
聽 聽 local cDate 聽 聽 := Left( TtoS( aParms[ 1 ] ), 8 )
聽 聽 (cAlias)->( OrdSetFocus( "StartTime" ) )
聽 聽 (cAlias)->( dbSeek( cDate ) )
聽 聽 While !(cAlias)->( eof() ) .and. left( (cAlias)->StartTime, 8 ) == cDate
聽 聽
聽 聽 聽 聽 oEvent := ::oCalex:DataProvider:CreateEvent()
聽 聽 聽 聽
聽 聽 聽 聽 With Object oEvent
聽 聽 聽 聽 聽 聽 :Subject := (cAlias)->Subject
聽 聽 聽 聽 聽 聽 :StartTime := StoT( (cAlias)->StartTime )
聽 聽 聽 聽 聽 聽 :EndTime := StoT( (cAlias)->EndTime )
聽 聽 聽 聽 聽 聽 :body := (cAlias)->body
聽 聽 聽 聽 聽 聽 //custom property "id" will hold the contents of field "id" on calendar.dbf
聽 聽 聽 聽 聽 聽 //to help us match each event displayed on the calendar to a unique record
聽 聽 聽 聽 聽 聽 //on the calendar table.
聽 聽 聽 聽 聽 聽 :CustomProperties:Property( "id", (cAlias)->id )
聽 聽 聽 聽 End
聽 聽
聽 聽 聽 聽 oEvents:add( oEvent )
聽 聽 聽 聽 (cAlias)->( dbSkip() )
聽 聽 end
聽 聽
Retur Nil
聽 聽 聽 聽 聽 聽 聽 聽
//---------------------------------------------------------------------------------------------------//
METHOD BuildCalex() CLASS MpCal
local oErr
local cIni聽 聽 聽 聽 聽 := "patients.ini"
聽 聽 TRY 聽 聽
聽 聽 聽 聽 ::oCalex := tActiveX():New( ::oPanelCalex, "Codejock.CalendarControl.13.4.2" )
聽 聽 CATCH oErr
聽 聽 聽 聽 MsgStop( "Missing installation Components", "Aborting" )
聽 聽 聽 聽 Quit
聽 聽 END
聽 聽
聽 聽 with object ::oCalex
聽 聽
聽 聽 聽 聽 :VisualTheme( xtpCalendarThemeOffice2007 )
聽 聽 聽 聽 :bOnEvent = { | event, aParms | ::xTrmCalTriggeredEvents( Event, aParms ) }
聽 聽 聽 聽
聽 聽 聽 聽 :SetDataProvider( "Provider=custom" )
聽 聽 聽 聽 :DataProvider:open()
聽 聽 聽 聽 :ShowCaptionBar( .t. )
聽 聽 聽 聽 :ShowCaptionBarSwitchViewButtons( .t. )聽//switch from day, week, month view on capbar
聽 聽
聽 聽 聽 聽 :ViewType( xtpCalendarDayView )
聽 聽 聽 聽 :DayView:TimeScaleMinTime( [8:00:00 AM] )
聽 聽 聽 聽 :DayView:TimeScaleMaxTime( [6:00:00 PM] )
聽 聽 聽 聽 :DayView:TimeScale( 15 )
聽 聽 聽 聽 :DayView:ScrollToWorkDayBegin()聽聽 聽 //scroll the view to the work day starting time
聽 聽 聽 聽 :Options:DayViewTimeScaleShowMinutes( .t. )
聽 聽 end
聽 聽::oPanelCalex:oClient = ::oCalex
Return Nil
//---------------------------------------------------//
METHOD BuildDatePicker() CLASS MpCal
local nTmp
local oPanel, oErr, oWnd
聽 聽 TRY
聽 聽 聽 聽 ::oDtPick := tActiveX():New( ::oPanelExplorer,"Codejock.DatePicker.13.4.2" )
聽 聽 聽 聽
聽 聽 聽 聽 With Object ::oDtPick
聽 聽 聽 聽 聽 聽 :Enabled( .t. )
聽 聽 聽 聽 聽 聽 :ShowWeekNumbers( .t. )
聽 聽 聽 聽 聽 聽 :VisualTheme( xtpCalendarThemeOffice2007 )
聽 聽 聽 聽 聽 聽 :AttachToCalendar( TOleAuto():New( ActXPdisp( ::oCalex:hActiveX ) ) )
聽 聽 聽 聽 End
聽 聽 聽 聽
聽 聽 聽 聽 ::oPanelExplorer:oClient := ::oDtPick
聽 聽 CATCH oErr
聽 聽
聽 聽 END
聽 聽
RETURN nil
//---------------------------------------------------//
METHOD BuildPanels() CLASS MpCal
local oBrush
local nHeight := ::oWnd:nHeight
聽 聽::oPanelCalex 聽 聽= TPanel():New( 0, 175, nHeight, ::oWnd:nWidth, ::oWnd:oWndClient )
聽 聽::oPanelExplorer = TPanel():New( 0, 0, nHeight, ::oPanelCalex:nLeft, ::oWnd:oWndClient )
聽 聽
RETURN nil
//---------------------------------------------------//
METHOD SetSize( nType, nWidth, nHeight ) CLASS MpCal
聽 聽if nWidth != nil
聽 聽 聽 ::oPanelExplorer:Move( , , , nHeight )
聽 聽 聽 ::oPanelCalex:Move( , , nWidth - ::oPanelExplorer:nRight, nHeight )
聽 聽endif
聽 聽
RETURN nil
*-------------------------------------------------------------------------------------------------------------------------------
procedure RddInit()
聽 聽 Set Century 聽 聽 On
聽 聽 Set Deleted 聽 聽 On
聽 聽 Set SoftSeek 聽 聽On
聽 聽 Set Date Format "MM/DD/YYYY"
聽 聽 set epoch to 1950
聽 聽 rddsetdefault( "ADS" )
聽 聽 REQUEST HB_LANG_EN
聽 聽 REQUEST DBFCDX, DBFFPT
聽 聽
return
*-------------------------------------------------------------------------------------------------------------------------------
//I would recommend a better unique value to id each event saved to calendar.dbf
//A better choice of unique Id would be ADS's field defaulting to NewIdString( 'M' )
//but this will do for the this short sample
//
static Function GetUniqueId()
local cJulian聽 聽:= StrZero( DoY( date() ), 3 )
Local cId 聽 聽 聽 := Right( StrZero( Year( Date() ), 4 ), 2 ) + cJulian + StrTran( StrZero( Seconds(), 7, 1 ), ".", "" )
Return ( cId )Regards;
Reinaldo.

