home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power CD-ROM!! 7
/
POWERCD7.ISO
/
prgmming
/
clipper
/
dateplus.prg
< prev
next >
Wrap
Text File
|
1993-10-14
|
11KB
|
497 lines
/*
* File......: Dateplus.prg
* Author....: Niall Scott
* BBS.......: The Dark Knight Returns
* Net/Node..: 050/069
* User Name.: Niall Scott
* Date......: 23/06/93
* Revision..: 2.0
* Log file..: $Logfile$
*
* This is an original work by Niall R Scott and is placed in the
* public domain.
*
* Modification history:
* ---------------------
*
* Rev 1.0 8/3/93
* Initial Revision
* Rev 2.0 23/06/93
* Rewritten to avoid use of Clipper Date functions in key
* handler which caused problems when an invalid date was
* typed in.
* Added knock-on parameter and toggles
*/
/* $DOC$
* $FUNCNAME$
* DATEPLUS
* $CATEGORY$
* Get Reader
* $ONELINER$
* Allow + & - on date input
* $SYNTAX$
* @ <row>, <col> GET <var> [...] DATEPLUS ;
* [ADDDATE] [KEY <nkey] [....]
* $ARGUMENTS$
*
* $RETURNS$
*
* $DESCRIPTION$
* Get reader to allow incementation and decrementation on a
* date field.
*
* Use as per example. ADDDATE & KEY are optional features.
*
* When the user is in the date field the use of the +
* and - keys will scroll the section of the date in
* which the cursor is located. If ADDDATE is NOT used
* each section will be independant of the other apart from
* the number of days in a month. If ADDDATE is used then
* ALL fields will be affected, eg start date 31/12/93
* press + key result 01/01/94. If KEY <nkey> is defined,
* nkey will be mapped to allow the user to toggle the
* knock-on effect.
* TAB & SHIFT_TAB will move between elements of the date
*
* NOTE
* Allows use of all normal Get functions eg VALID,WHEN but
* DATEPLUS ADDKEY KEY must be in that order and not separated
* by any other clause.
* Zero in any field is invalid.
* $EXAMPLES$
* CLS
* @ 10,20 say "Enter date :"
* // Fully incremental date function
* @ 10,35 GET nDate DATEPLUS ADDDATE COLOR 'W+/R'
* // Non incremental date function + - only affect the
* // current section
* @ 10,35 GET nDate DATEPLUS COLOR 'W+/R'
* // Non incremental date function + - only affect the
* // current section but allow the user to toggle using
* // F10 key
* @ 10,35 GET nDate DATEPLUS KEY K_F10 COLOR 'W+/R'
* READ
*
* $SEEALSO$
*
* $INCLUDE$
* GT_Datep.ch
* $END$
*/
#include "gt_lib.ch"
#define K_PLUS 43
#define K_MINUS 45
#define DATE_UK 1
#define DATE_USA 2
#define DATE_JAPAN 3
#define DATESET SET(_SET_DATEFORMAT)
STATIC nDateFormat := DATE_UK
STATIC lKnockOn
PROCEDURE DateRead( oGet, lInc, nSwitch)
DEFAULT nSwitch to 999
lKnockOn := lInc
// Return if not a Date Memvar
IF oGet:Type != "D"
// RETURN
ENDIF
// Check which Date Format
IF UPPER(SUBSTR(DATESET,1,2)) =="DD"
nDateFormat := DATE_UK
ELSEIF UPPER(SUBSTR(DATESET,1,2)) =="MM"
nDateFormat := DATE_USA
ELSE
nDateFormat := DATE_JAPAN
ENDIF
// Read the GET if the WHEN condition is satisfied
IF ( GetPreValidate(oGet) )
// activate the GET for reading
oGet:SetFocus()
DO WHILE ( oGet:ExitState == GE_NOEXIT )
// Check for initial typeout
// (no editable positions)
IF ( oGet:TypeOut )
oGet:exitstate := GE_ENTER
END
// Apply keystrokes until exit
DO WHILE ( oGet:ExitState == GE_NOEXIT )
GetDateKey( oGet, INKEY(0), nSwitch)
ENDDO
// Disallow exit if the VALID condition
// is not satisfied
IF ( !GetPostValidate(oGet) )
oGet:ExitState := GE_NOEXIT
ENDIF
ENDDO
// de-activate the GET
oGet:KillFocus()
ENDIF
RETURN
STATIC PROCEDURE GetDateKey( oGet, nKey, nSwitchKey )
LOCAL cKey := ""
LOCAL bKeyBlock
LOCAL cDatePos := "D"
LOCAL nLoop := 0
LOCAL aDate := {}
LOCAL aDaysOfMonth := {31,28,31,30,31,30,31,31,30,31,30,31}
//Split date in buffer
aDate := Str2Date(oGet:Buffer)
// check for SET nKey first
IF ( (bKeyBlock := SETKEY(nKey)) <> NIL )
GetDoSetKey(bKeyBlock, oGet)
ENDIF
// This allows it to used with all date formats
// I HOPE!
DO CASE
// EUROPEAN DATE
CASE nDateFormat == DATE_UK
// Check which part of date field you are in
// and set cDatePos accordingly
IF oGet:Pos < 3
cDatePos := "D"
ELSEIF (oGet:pos > 3 .AND. oGet:pos < 6)
cDatePos := "M"
ELSE
cDatePos := "Y"
ENDIF
// AMERICAN DATE
CASE nDateFormat == DATE_USA
IF oGet:Pos < 3
cDatePos := "M"
ELSEIF (oGet:pos > 3 .AND. oGet:pos < 6)
cDatePos := "D"
ELSE
cDatePos := "Y"
ENDIF
// JAPAN or ANSI
OTHERWISE
IF LEN(DATESET) == 8
IF oGet:Pos < 3
cDatePos := "Y"
ELSEIF (oGet:pos > 3 .AND. oGet:pos < 6)
cDatePos := "M"
ELSE
cDatePos := "D"
ENDIF
ELSE
IF oGet:Pos < 5
cDatePos := "Y"
ELSEIF (oGet:pos > 5 .AND. oGet:pos < 8)
cDatePos := "M"
ELSE
cDatePos := "D"
ENDIF
ENDIF
ENDCASE
//Ensure that February has the correct number of days
aDaysOfMonth[2] := IIF(( aDate[3] %4 == 0) .AND. ;
(aDate[3] % 1000 > 0),29,28)
IF ( nKey == K_PLUS ) .OR. (nKey == K_MINUS)
DO CASE
CASE cDatePos == 'D'
// Make sure that month is within range
IF aDate[2] == 0
aDate[2] := 1
ELSEIF aDate[2] > 12
aDate[2] := 12
ENDIF
//Day must not be greater than the number of
// days of the month
IF aDate[1] > aDaysOfMonth[ aDate[2]]
aDate[1] := aDaysOfMonth[ aDate[2]]
ENDIF
// Add or subtract day
aDate[1] := IIF(nKey == K_PLUS, aDate[1]+1 , aDate[1]-1 )
// if less than 1 set days to end of month
IF aDate[1] < 1
// If incrementation of month & year required
If lKnockOn
aDate[2]--
IF aDate[2] < 1
aDate[3]--
aDate[2] := 12
ENDIF
ENDIF
aDate[1] := aDaysOfMonth[ aDate[2] ]
//If end of month reset to beginning
ELSEIF aDate[1] > aDaysOfMonth[ aDate[2] ]
// If incrementation of month & year required
IF lKnockOn
aDate[2]++
IF aDate[2] > 12
aDate[3]++
aDate[2] := 1
ENDIF
ENDIF
aDate[1] := 1
ENDIF
CASE cDatePos == 'M'
// Make sure of valid month
IF aDate[2] > 12
aDate[2] := 12
ELSEIF aDate[2] < 1
aDate[2] := 1
ENDIF
//Add or substract 1 month
aDate[2] := IIF(nKey == K_PLUS, aDate[2]+1 , aDate[2]-1 )
IF aDate[2] > 12
// If incrementation of month & year required
IF lKnockOn
aDate[3]++
ENDIF
aDate[2] := 1
ELSEIF aDate[2] < 1
// If incrementation of month & year required
IF lKnockOn
aDate[3]--
ENDIF
aDate[2] := 12
ENDIF
IF aDate[1] > aDaysOfMonth[ aDate[2] ]
aDate[1] := aDaysOfMonth[ aDate[2] ]
ENDIF
CASE cDatePos == 'Y'
aDate[3] := IIF(nKey == K_PLUS, aDate[3]+1 , aDate[3]-1 )
//Recalculate February
aDaysOfMonth[2] := IIF(( aDate[3] %4 == 0) .AND. ;
(aDate[3] % 1000 > 0),29,28)
IF aDate[2] == 2
IF aDate[1] > aDaysOfMonth[ 2 ]
aDate[1] := aDaysOfMonth[ 2]
ENDIF
ENDIF
ENDCASE
// Stuff day, month and year back into Get buffer
StuffDate( aDate, oGet)
ENDIF
DO CASE
//If the key pressed is the defined key
// toggle incremental ON/OFF
CASE (nKey == nSwitchKey )
lKnockOn := IIF(lKnockOn, .F., .T. )
CASE ( nKey == K_UP )
oGet:ExitState := GE_UP
CASE ( nKey == K_SH_TAB )
IF __SetCentury() .AND. ;
nDateFormat == DATE_JAPAN
IF oGet:Pos < 5
oGet:End()
ELSE
oGet:Left()
oGet:Left()
ENDIF
ELSE
IF oGet:pos < 3
oGet:End()
ELSEIF oGet:Pos < 6
oGet:Left()
oGet:Left()
ELSE
oGet:Left()
oGet:Left()
oGet:Left()
oGet:Left()
ENDIF
ENDIF
CASE ( nKey == K_DOWN )
oGet:ExitState := GE_DOWN
CASE ( nKey == K_TAB )
IF __SetCentury() .AND. ;
nDateFormat == DATE_JAPAN
IF oGet:Pos >7
oGet:Home()
ELSEIF oGet:Pos >4
FOR nLoop := oGet:Pos TO 8
oGet:Right()
NEXT
ELSE
FOR nLoop := oGet:Pos TO 5
oGet:Right()
NEXT
ENDIF
ELSE
IF oGet:pos > 6
oGet:home()
ELSE
oGet:RIGHT()
oGet:RIGHT()
ENDIF
ENDIF
CASE ( nKey == K_ENTER ) ; oGet:ExitState := GE_ENTER
CASE ( nKey == K_ESC )
IF ( SET(_SET_ESCAPE ) )
oGet:undo()
oGet:ExitState := GE_ESCAPE
ENDIF
CASE ( nKey == K_PGUP ) ; oGet:ExitState := GE_WRITE
CASE ( nKey == K_PGDN ) ; oGet:ExitState := GE_WRITE
CASE ( nKey == K_CTRL_HOME ) ; oGet:ExitState := GE_TOP
CASE (nKey == K_CTRL_W ) ; oGet:ExitState := GE_WRITE
CASE (nKey == K_INS )
SET( _SET_INSERT , !SET(_SET_INSERT ) )
CASE (nKey == K_UNDO) ; oGet:undo()
CASE (nKey == K_HOME ) ; oGet:home( )
CASE (nKey == K_END ) ; oGet:END( )
CASE (nKey == K_RIGHT ) ; oGet:Right( )
CASE (nKey == K_LEFT ) ; oGet:Left( )
CASE (nKey == K_CTRL_RIGHT ) ; oGet:WordRight( )
CASE (nKey == K_CTRL_LEFT ) ; oGet:WordLeft( )
CASE (nKey == K_BS ) ; oGet:BackSpace( )
CASE (nKey == K_DEL ) ; oGet:Delete( )
CASE (nKey == K_CTRL_T ) ; oGet:DelWordRight( )
CASE (nKey == K_CTRL_Y ) ; oGet:DelEnd( )
CASE (nKey == K_CTRL_BS ) ; oGet:DelWordLeft( )
OTHERWISE
IF (nKey >= 48 .AND. nKey <= 57 )
cKey := CHR(nKey )
IF ( SET(_SET_INSERT ) )
oGet:Insert(cKey )
ELSE
oGet:OverStrike(cKey )
END
IF ( oGet:TypeOut )
IF ( SET(_SET_BELL ) )
?? CHR(7 )
END
IF ( !SET(_SET_CONFIRM ) )
oGet:ExitState := GE_ENTER
END
END
END
ENDCASE
RETURN
STATIC FUNCTION StuffDate( aTmpDate, oGet)
// Do not allow a zero value
aTmpDate[1] := IIF(aTmpDate[1] == 0,1 ,aTmpDate[1] )
aTmpDate[2] := IIF(aTmpDate[2] == 0,1 ,aTmpDate[2] )
aTmpDate[3] := IIF(aTmpDate[3] == 0,1 ,aTmpDate[3] )
// Put Back date according to format
DO CASE
CASE nDateFormat == DATE_UK
oGet:VarPut( CTOD(ALLTRIM( STR(aTmpDate[1]) ) ;
+"/"+ ALLTRIM( STR( aTmpDate[2])) +"/"+;
ALLTRIM(STR(aTmpDate[3])) ) )
CASE nDateFormat == DATE_USA
oGet:VarPut( CTOD(ALLTRIM( STR(aTmpDate[2]) ) ;
+"/"+ ALLTRIM( STR( aTmpDate[1])) +"/"+;
ALLTRIM(STR(aTmpDate[3])) ) )
OTHERWISE
oGet:VarPut( CTOD(ALLTRIM( STR(aTmpDate[3]) ) ;
+"/"+ ALLTRIM( STR( aTmpDate[2])) +"/"+;
ALLTRIM(STR(aTmpDate[1])) ) )
ENDCASE
oGet:UpdateBuffer()
Return(NIL)
// Convert a date string into an array of form {dd,mm,yy[yy]}
STATIC FUNCTION Str2Date( cStr )
Local aDate1[3]
Local aDate2[3]
aDate1 := Str2Arr( cStr, '/')
/// make aDate2 according to Date Format
DO CASE
CASE nDateFormat == DATE_USA
aDate2[1] := VAL(aDate1[2])
aDate2[2] := VAL(aDate1[1])
aDate2[3] := VAL(aDate1[3])
CASE nDateFormat == DATE_JAPAN
aDate2[1] := VAL(aDate1[3])
aDate2[2] := VAL(aDate1[2])
aDate2[3] := VAL(aDate1[1])
OTHERWISE
aDate2[1] := VAL(aDate1[1])
aDate2[2] := VAL(aDate1[2])
aDate2[3] := VAL(aDate1[3])
ENDCASE
RETURN (aDate2)