home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-07-19 | 43.6 KB | 1,394 lines |
- /*
- Program: POPDATE.PRG
- System: GRUMPFISH LIBRARY
- Author: Greg Lief
- Copyright (c) 1988-90, Greg Lief
- Clipper 5.01 version
- Compile instructions: clipper popdate /n/w/a
- with special thanks to:
- - TOM WALDEN for the multiple user time blocks,
- weekly summary, and smashing weekly report
- - BOB SUMMERS for the text search and jump-to-
- current-date ideas
-
-
- Procs & Fncts: VIEWAPPTS()
- : LOCK_APPT()
- : APPT_MAINT()
- : APPT_RECUR()
- : APPT_NOTES()
- : GETDATE()
- : APPT_CDATE()
- : APPT_SHOW()
- : GRAB_DATES()
- : APPT_DAY()
- : APPT_WEEK()
- : NOCONFLICT()
- : APPTPRINTW()
- : APPT_HEADW()
- : APPTPRINTD()
- : APPT_HEADD()
- : APPT_MEET()
- : APPT_DOM()
-
- Calls: CALENDBOX() (function in $CALENDA.PRG)
- : NEXTMONTH() (function in $CALENDA.PRG)
-
- Uses: APPT.DBF
-
- 1 USERID Character 8
- 2 DATE Date 8
- 3 TIME Character 5
- 4 ENDTIME Character 5
- 5 BRIEF Character 50
- 6 COMMENTS Memo 10
-
- Indexes: APPTUSER.NTX (key: USERID + DTOS(DATE) + TIME)
- APPTDATE.NTX (key: DTOS(DATE) + USERID + TIME)
- */
-
- //───── begin preprocessor directives
-
- #include "grump.ch"
- #include "inkey.ch"
-
- //───── end preprocessor directives
-
- //───── begin global declarations
-
- static winbuff // buffer under appointment window
- static tdate // current highlighted date
-
- #define STARTDATE dates_[1]
- #define ENDDATE dates_[2]
- #define CURRENTYEAR substr(dtos(mdate), 1, 4)
- #define CURRENTDAY substr(dtos(mdate), 7)
-
-
- //───── end global declarations
-
- function popdate(gfproc, gfline, gfvar)
- local hotkey := 0, maincolor := ColorSet(C_CALENDAR, .T.), mdate, ;
- mtop := 0, mleft := 7, wk_area := select(), oldsoftseek, ;
- olddelete := set(_SET_DELETED, .T.), mfile, datecoords, getlist := {}, ;
- oldscore := set(_SET_SCOREBOARD, .F.), finds_ := {}, redraw, keypress, ;
- newrow, newcol, tempdate, buffer, xx, mstring, mtype, dates_, numappts
- memvar apptdir // global that may have been declared in calling program
- GFSaveEnv(.t., 0)
-
- //───── determine whether this was called via hot-key; if so, disable it
- if (gfproc != NIL)
- setkey(hotkey := lastkey(), NIL)
- endif
-
- //───── if monochrome monitor, clear the entire screen for clarity
- if ! iscolor()
- cls
- endif
- winbuff := savescreen(15, 02, 24, 79) && buffer underneath appt window
- mdate := date()
-
- //───── open appt.dbf... first determine path, then confirm existence of file
- mfile := if(type('apptdir') = 'U', '', apptdir + '\') + 'appt'
- if ! file(mfile + '.dbf')
- waiton('initializing appointment database... please wait')
- dbcreate(mfile + ".dbf", { {"USERID", "C", 8, 0} , ;
- {"DATE", "D", 8, 0} , ;
- {"TIME", "C", 5, 0} , ;
- {"ENDTIME", "C", 5, 0} , ;
- {"BRIEF", "C", 50, 0} , ;
- {"COMMENTS","M", 10, 0} } )
- waitoff()
- endif
- if ! file(mfile + 'user.ntx') .or. ! file(mfile + 'date.ntx')
- use (mfile) new exclusive
- index on appt->userid + dtos(appt->date) + appt->time to (mfile + 'user')
- index on dtos(appt->date) + appt->userid + appt->time to (mfile + 'date')
- use
- endif
- use (mfile) new index (mfile + 'date'), (mfile + 'user')
-
- //───── initial screen setup
- ColorSet(C_CALENDAR)
- ShadowBox(0, 39, 12, 72, 4)
-
- //───── draw menu options box
- @ 1, 45 ssay 'move by day'
- @ 1, 61 ssay 'by week'
- @ row()+1, 51 ssay 'move by month'
- @ row()+1, 51 ssay 'first/last day'
- @ row()+1, 45 ssay 'add/edit'
- @ row(), 62 ssay 'exit'
- @ row()+1, 45 ssay 'search for text'
- @ row()+1, 45 ssay 'print appointments'
- @ row()+1, 45 ssay 'delete appointments'
- @ row()+1, 45 ssay 'daily time blocks'
- @ row()+1, 45 ssay 'weekly appt summary'
- //───── a future enhancement made possible by dynamically sizeable arrays
- *@ row()+1, 45 ssay 'schedule a meeting'
- @ row()+1, 45 ssay 'current date: ' + dtoc(mdate)
- @ 0,46 ssay ' Calendar Options ' color '+' + setcolor()
- setcolor('I')
- @ 1, 41 ssay chr(27) + chr(26)
- @ row(), 58 ssay chr(24) + chr(25)
- @ row()+1, 41 ssay 'PgUp/PgDn'
- @ row()+1, 41 ssay 'Home/End'
- @ row()+1, 41 ssay chr(17) + chr(217)
- @ row(), 58 ssay 'Esc'
- @ row()+1, 41 ssay 'S'
- @ row()+1, 41 ssay 'P'
- @ row()+1, 41 ssay 'D'
- @ row()+1, 41 ssay 'T'
- @ row()+1, 41 ssay 'W'
- //───── a future enhancement made possible by dynamically sizeable arrays
- *@ row()+1, 41 ssay 'M'
- @ row()+1, 41 ssay 'C'
-
- datecoords := calendbox(.t., mtop, mleft, date(), maincolor, .t.)
-
- //───── commence main keypress loop
- do while .t.
- redraw := .f.
- tdate := mdate && store highlighted date
- Appt_Show(CURRENTAPPTS)
- keypress := ginkey(0)
- newrow := CURRENTDAY_ROW
- newcol := CURRENTDAY_COL
- do case
-
- case keypress == K_DOWN .or. keypress == K_UP // forward/backward one week
- mdate += if(keypress == 24, 7, -7)
- newrow += if(keypress == 24, 1, -1)
-
- case keypress == K_LEFT // go back one day
- mdate--
- //───── did we just go from sunday to saturday??
- newrow := if(dow(mdate) = 7, CURRENTDAY_ROW - 1, CURRENTDAY_ROW)
- newcol := if(dow(mdate) = 7, mleft + 19, CURRENTDAY_COL - 3)
-
- case keypress == K_RIGHT // go forward one day
- mdate++
- //───── did we just go from saturday to sunday??
- newrow := if(dow(mdate) = 1, CURRENTDAY_ROW + 1, CURRENTDAY_ROW)
- newcol := if(dow(mdate) = 1, mleft + 1, CURRENTDAY_COL + 3)
-
- case keypress == K_PGUP // go back one month
- if month(mdate) = 1 // going to december of previous year
- mdate := stod( str(val(CURRENTYEAR)-1, 4) + '12' + CURRENTDAY)
- else
- //───── check for validity of current date in previous month
- //───── i.e., cannot go from march 31 to february 31, etcetera
- tempdate := ctod('')
- do while empty(tempdate)
- tempdate := stod(CURRENTYEAR + if(month(mdate) < 11, '0', '') + ;
- ltrim(str(month(mdate) - 1)) + CURRENTDAY)
- mdate--
- enddo
- mdate := tempdate
- endif
-
- case keypress == K_PGDN // go forward one month
- mdate := NextMonth(mdate)
-
- case keypress == K_HOME // go to first day
- newrow := FIRSTDAY_ROW
- newcol := FIRSTDAY_COL
- mdate := stod(substr(dtos(mdate), 1, 6) + '01')
-
- case keypress == K_END // go to last day
- newrow := LASTDAY_ROW
- newcol := LASTDAY_COL
- mdate := stod(substr(dtos(mdate), 1, 6) + str(LASTDAY_NUMBER, 2))
-
- case keypress == K_ENTER // view appointments
- redraw := ViewAppts(! CURRENTAPPTS)
-
- case keypress == 115 .or. keypress == 83 // text search
- asize(finds_, 0)
- mtype := Alert("What would you like to search?", ;
- { "Who", "Description", "Notes" })
- if lastkey() != K_ESC
- xx := 0
- mstring := space(20)
- ColorSet(C_MESSAGE)
- buffer := shadowbox(11, 18, 13, 61, 2)
- @ 12, 20 ssay "Text to search for:"
- @ row(), col() + 1 get mstring
- setcursor(1)
- read
- setcursor(0)
- ByeByeBox(buffer)
- if lastkey() != K_ESC .and. ! empty(mstring)
- mstring := trim(mstring)
- go top
- locate for upper(mstring) $ ;
- upper({ appt->userid, appt->brief, appt->comments }[mtype])
- do while found() .and. xx < 12 // max of 12 finds for now
- aadd(finds_, dtoc(appt->date) + [ ] + appt->time + [ - ] + ;
- appt->endtime + [ ] + appt->brief + str(recno(), 6))
- xx++
- continue
- enddo
- if xx > 0
- ColorSet(C_ERRORMESSAGE)
- buffer := shadowbox(06, 2, 19, 78, 2, ;
- 'Finds for "' + mstring + '"')
- xx := achoice(07, 3, 18, 77, finds_)
- ByeByeBox(buffer)
- if xx > 0
- mdate := ctod(substr(finds_[xx], 1, 8))
- redraw := .t. && gotta redo the calendar screen
- //───── if we searched through notes, ask if they want to view 'em
- if mtype == 3
- if Yes_No("View these notes now")
- go val(substr(finds_[xx], 75))
- Appt_Notes()
- endif
- endif
- endif
- else
- Err_Msg('No finds for "' + mstring + '"')
- endif
- endif
- endif
-
- case keypress == 67 .or. keypress == 99 // jump to system date
- newrow := SYSTEMDATE_ROW
- newcol := SYSTEMDATE_COL
- mdate := date()
-
- case keypress == 80 .or. keypress == 112 // print appts
- if reccount() = 0
- Err_Msg('File is currently empty')
- else
- xx := Yes_No2("Print for week or selected dates", 12, ;
- " week ", " selected dates ")
- if lastkey() != K_ESC
- if xx
- ApptPrintW()
- else
- dates_ := Grab_Dates('print')
- if lastkey() != K_ESC
- ApptPrintD(STARTDATE, ENDDATE)
- endif
- endif
- endif
- endif
-
- case keypress == 68 .or. keypress == 100 // delete appts
- if reccount() = 0
- Err_Msg('File is currently empty')
- else
- dates_ := Grab_Dates('delete')
- if lastkey() != K_ESC
- oldsoftseek := set(_SET_SOFTSEEK, .t.)
- seek dtos(STARTDATE)
- if ! eof()
- xx := recno()
- count while appt->date >= STARTDATE .and. ;
- appt->date <= ENDDATE to numappts
- if numappts > 0
- if Yes_No('You are about to delete ' + ltrim(str(numappts)) + ;
- ' appointments between ' + dtoc(STARTDATE) + ;
- ' and ' + dtoc(ENDDATE), 'Do you want to continue')
- go xx
- delete while appt->date >= STARTDATE .and. ;
- appt->date <= ENDDATE .and. rlock()
- if appt->date <= ENDDATE .and. ! eof()
- Err_Msg('Only deleted appointments up to ' + dtoc(appt->date))
- endif
- redraw := .t. && gotta redo the calendar screen
- endif
- else
- Err_Msg('No appointments fall within the dates ' + ;
- dtoc(STARTDATE) + ' and ' + dtoc(ENDDATE))
- endif
- endif
- set(_SET_SOFTSEEK, oldsoftseek)
- endif
- endif
-
- case keypress == 84 .or. keypress == 116 // show daily time blocks
- Appt_Day()
- loop
-
- case keypress == 87 .or. keypress == 119 // show weekly time blocks
- Appt_Week()
- loop
-
- //───── a future enhancement made possible by dynamically sizeable arrays
- * case keypress == 77 .or. keypress == 109 && m - schedule meeting
- * appt_meet()
- * loop
-
- case keypress == K_ESC
- exit
-
- otherwise && any other keystroke
- loop
-
- endcase
- //───── if we changed months or a recurring appointment was added, redraw calendar
- if month(tdate) != month(mdate) .or. redraw
- datecoords := calendbox(.t., mtop, mleft, mdate, maincolor)
- else
- setcolor('+' + maincolor)
- //───── check to see if previous date had appointments (for display purposes)
- seek dtos(tdate)
- if found()
- setcolor('i')
- endif
- @ CURRENTDAY_ROW, CURRENTDAY_COL ssay str(day(tdate), 2)
- //───── check to see if new date has appointments (for display purposes)
- seek dtos(mdate)
- CURRENTAPPTS := (found())
- setcolor(if(CURRENTAPPTS, '*i', '*+' + maincolor))
- @ newrow, newcol ssay str(day(mdate),2)
- //───── store new row/column coordinates for highlighted date
- CURRENTDAY_ROW := newrow
- CURRENTDAY_COL := newcol
- endif
- enddo
- //───── clean up
- use
- select(wk_area)
-
- //───── restore hot-key
- if hotkey != 0
- setkey( hotkey, {|p, l, v| popdate(p, l, v)} )
- endif
- set(_SET_SCOREBOARD, oldscore) // in case you were keeping SCORE
- set(_SET_DELETED, olddelete)
- GFRestEnv()
- return NIL
-
- * end function PopDate()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: VIEWAPPTS
- */
- static function viewappts(newday)
- local browse, column, buffer_[3], key, mtime, mendtime, mdate, ;
- ele := 1, ret_val := .f., getlist := {}
- restscreen(15, 02, 24, 79, winbuff) // remove daily appt window first
- seek dtos(tdate)
- buffer_[1] := savescreen(22, 00, 24, 79)
- browse := TBrowseDB( 16, 3, 19, 75 )
- browse:headSep := "═"
- *browse:colSep := "│"
- browse:colorSpec := ColorSet(C_APPOINTMENT, .T.) + ',' + "+W/N"
- browse:skipBlock := { |SkipCnt| AwSkipIt(SkipCnt) }
- column := TBColumnNew( "Who", fieldblock( "USERID" ) )
- browse:addColumn(column)
- column := TBColumnNew( "Start", fieldblock( "TIME" ) )
- browse:addColumn(column)
- column := TBColumnNew( "End", fieldblock( "ENDTIME" ) )
- browse:addColumn(column)
- column := TBColumnNew( "Appointment Description", { || field->BRIEF + ;
- if(len(trim(field->comments)) > 2, chr(251), chr(32)) } )
- browse:addColumn(column)
- ColorSet(C_CALENDAR)
- scroll(22, 00, 24, 79, 0)
- @ 24,05 ssay "add"
- @ 24,13 ssay "edit"
- @ 24,22 ssay "delete"
- @ 24,33 ssay "move"
- @ 24,42 ssay "recurring appt"
- @ 24,61 ssay "notes"
- @ 24,73 ssay "exit"
- setcolor('I')
- @ 24, 3 ssay "A"
- @ 24,11 ssay "E"
- @ 24,20 ssay "D"
- @ 24,31 ssay "M"
- @ 24,40 ssay "R"
- @ 24,59 ssay "N"
- @ 24,69 ssay "Esc"
- seek dtos(tdate)
- ColorSet(C_APPOINTMENT)
- buffer_[2] := ShadowBox(15, 02, 20, 76, 2)
- if newday
- keyboard "A" // force immediate Add mode
- endif
- do while .t.
-
- //───── wait for the display to stabilize, which will
- //───── loop once for each row in the browse window.
- //───── allow a keypress to bust out of this loop
- do while ! browse:stabilize() .and. (key := inkey()) = 0
- enddo
-
- if browse:stable
- key := ginkey(0, "KEY")
- endif
-
- //───── deal with the keypress
- do case
-
- case key == K_UP
- browse:up()
-
- case key == K_LEFT
- browse:left()
-
- case key == K_RIGHT
- browse:right()
-
- case key == K_DOWN
- browse:down()
-
- case key == K_CTRL_PGUP
- browse:goTop()
-
- case key == K_CTRL_PGDN
- browse:goBottom()
-
- case key == K_PGUP .or. key == K_HOME
- browse:pageUp()
-
- case key == K_PGDN .or. key == K_END
- browse:pageDown()
-
- case key == K_ESC
- //───── if we forced an exit because they deleted or moved the
- //───── final appointment for this date, we must be sure to
- //───── return .T. to the calling routine so that the calendar
- //───── box will be redrawn
- if appt->date != tdate
- ret_val := .t.
- endif
- exit
-
- case key == 68 .or. key == 100 // Delete
- IF Yes_No('This appointment will be deleted', 'Continue')
- Lock_Appt(.T.)
- ENDIF
- browse:refreshAll()
-
- case key == 65 .or. key == 97 // Add Record
- if Appt_Maint('A', .f., newday)
- newday := .f.
- browse:refreshAll()
- endif
-
- case key == 77 .or. key == 109 // Move appt
- ColorSet(C_MESSAGE)
- mdate := ctod("")
- buffer_[3] := shadowbox(21, 26, 23, 53, 2, 'Move appointment')
- @ 22,28 ssay 'Enter new date:'
- @ row(), col() + 1 get mdate
- setcursor(1)
- read
- setcursor(0)
- ByeByeBox(buffer_[3])
- if lastkey() != K_ESC .and. ! empty(mdate)
- if NoConflict("E", mdate, appt->userid, appt->time, appt->endtime, .f.)
- Lock_Appt(mdate)
- browse:refreshAll()
- endif
- endif
-
- case key == 69 .or. key == 101 // Edit Record
- Appt_Maint('E', .F.)
- browse:refreshAll() // not just "Current" in case of network apps
-
- case key == 82 .or. key == 114 // Recurring appt
- Appt_Maint('A', .T.)
- //───── force a refresh of the calendar screen after we exit
- //───── the appointment window!
- ret_val := .t.
- browse:refreshAll()
-
- case key == 78 .or. key == 110 // view notes
- Appt_Notes()
- if lastkey() != K_ESC
- browse:refreshCurrent()
- endif
-
- endcase
- enddo
- ByeByeBox(buffer_[2])
- restscreen(22, 00, 24, 79, buffer_[1])
- return ret_val
-
- * end static function ViewAppts()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: AwSkipIt()
- Purpose: Pseudo-filter to only show appts for highlighted day
- */
- static function awskipit(skip_cnt)
- local movement := 0
- do case
- case skip_cnt == 0
- skip 0
-
- case skip_cnt > 0
- do while movement < skip_cnt .and. appt->date <= tdate
- skip 1
- movement++
- enddo
- //───── make sure that we are on the right date - if not, back up to it
- do while (appt->date > tdate .or. eof()) .and. ! bof()
- skip -1
- movement--
- enddo
- if bof() .or. appt->date != tdate // hey! no more appts for this date!!
- keyboard chr(K_ESC)
- endif
-
- case skip_cnt < 0
- do while movement > skip_cnt .and. appt->date >= tdate
- skip -1
- if bof()
- exit
- endif
- movement--
- enddo
- //───── make sure that we are on the right date - if not, move up to it
- do while appt->date < tdate .and. ! eof()
- skip
- movement++
- enddo
- if eof() .or. appt->date != tdate // hey! no more appts for this date!!
- keyboard chr(K_ESC)
- endif
-
- endcase
- return movement
-
- * end static function AwSkipIt()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: LOCK_APPT() -- used for moving and deleting appts
- */
- static function lock_appt(mdate)
- if rlock()
- if valtype(mdate) = "D"
- replace appt->date with mdate
- else // kill it
- delete
- skip
- endif
- unlock
- else
- err_msg(NETERR_MSG)
- endif
- return NIL
-
- * end static function Lock_Appt()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: APPT_MAINT
- */
- static function Appt_Maint(mode, recur_appt, newday)
- local oldscrn, muserid, mtime, mendtime, mbrief, ret_val := .t., marker, ;
- cur_row := row(), mstart := " : ", app_ok, getlist := {}
- gfsaveenv( { maxrow() - 2, 00, maxrow(), maxcol() } )
- default newday to .f.
- muserid := if(mode == 'A', space(8), appt->userid)
- mtime := if(mode == 'A', mstart, appt->time)
- mendtime := if(mode == 'A', mstart, appt->endtime)
- mbrief := if(mode == 'A', space(50), appt->brief)
- ColorSet(C_CALENDAR)
- scroll(22, 00, 24, 79, 0)
- @ 23,24 ssay 'save edits'
- @ 23,44 ssay 'exit without saving'
- @ 23,17 ssay 'Ctrl-W' color 'I'
- @ 23,40 ssay 'Esc' color 'I'
- setcolor('+w/bg,i')
- oldscrn := shadowbox(cur_row - 1, 1, cur_row + 1, maxcol() - 2, 4)
- @ cur_row, 3 get muserid picture '@!' valid ! empty(muserid)
- @ cur_row, 12 get mtime picture '##:##' ;
- valid val(substr(mtime,1,2)) < 24 .and. val(substr(mtime,4)) < 60
- @ cur_row, 18 get mendtime picture '##:##' valid mendtime == mstart .or. ;
- (val(substr(mendtime,1,2)) < 24 .and. val(substr(mendtime,4)) < 60 .and. ;
- mendtime >= mtime) .or. lastkey() == K_UP
- @ cur_row, 24 get mbrief
- setcursor(1)
- read
- setcursor(0)
- if (lastkey() != K_ESC .and. (val(mtime)>0 .or. ! empty(mbrief))) .and. ;
- noconflict(mode, tdate, muserid, mtime, mendtime, .f.)
- if recur_appt
- marker := recno()
- appt_recur(muserid, mtime, mendtime, mbrief)
- else
- if mode == 'A' // adding record
- append blank
- app_ok := ! neterr()
- else
- app_ok := rlock()
- endif
- if app_ok
- //───── note that if user left ending time blank, we will replace it
- //───── with the starting time
- replace appt->date with tdate, appt->time with mtime, ;
- appt->brief with mbrief, ;
- appt->endtime with if(mendtime == mstart, mtime, mendtime), ;
- appt->userid with muserid
- else
- err_msg(NETERR_MSG)
- endif
- unlock
- endif
- elseif newday
- //───── what this means is that either the user escaped without adding an
- //───── appt for a new day -- we must then bust out back to the calendar
- //───── window upon returning to the TBROWSE() section above
- ret_val := ! newday
- if ! ret_val
- keyboard chr(K_ESC)
- endif
- endif
- byebyebox(oldscrn)
- gfrestenv()
- return ret_val
-
- * end static function Appt_Maint()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_Recur()
- Calls: Appt_CDate()
- : MextMonth() (function in CALENDAR.PRG)
- */
- static function appt_recur(muserid, mtime, mendtime, mbrief)
- local oldscrn, oldcolor, end, start, curr_area, ;
- mdom := Appt_Dom(tdate), mmonth, sel, app_ok, getlist := {}
- //───── we only need the 6th option if current day is, in fact, a weekday
- local choices := {'Every ' + gfday(tdate), ;
- 'Every other ' + gfday(tdate), ;
- 'Every ' + appt_cdate(day(tdate)) + ' of the month', ;
- 'Every day', ;
- 'Every ' + appt_cdate(mdom) + ' ' + gfday(tdate) }
- if dow(tdate) > 1 .and. dow(tdate) < 7
- aadd(choices, 'Every weekday')
- endif
- oldcolor := setcolor('w/rb')
- oldscrn := shadowbox(16, 48, 17 + len(choices), 72, 2, 'Recurring appointment')
- setcolor('+w/rb')
- sel := achoice(17, 49, 16 + len(choices), 71, choices, '', 'sel_udf')
- if sel > 0
- clear gets
- ColorSet(C_CALENDAR)
- shadowbox(18, 49, 20, 71, 2)
- setcolor('+' + setcolor())
- end := tdate
- @ 19,50 ssay 'Ending date:'
- @ row(), col()+1 get end picture '@d' valid end >= tdate
- setcursor(1)
- read
- setcursor(0)
- waiton('Adding recurring appointments... please wait')
- start := tdate
- do while start <= end
- if noconflict("A", start, muserid, mtime, mendtime, .t.)
- append blank
- app_ok := ! neterr()
- if app_ok
- replace appt->date with start, appt->time with mtime, ;
- appt->endtime with mendtime, ;
- appt->brief with mbrief, appt->userid with muserid
- unlock
- else
- err_msg(NETERR_MSG)
- endif
- endif
- //───── increment date by appropriate interval
- do case
- case sel == 1 .or. sel == 2
- start += sel * 7
- case sel == 3
- start := nextmonth(start)
- case sel == 4
- start++
- case sel == 5
- start := nextmonth(start)
- do while start <= end
- //───── first determine 1st day of next month
- start := stod(substr(dtos(start), 1, 6) + "01")
- //───── go to the correct day of the week
- do while dow(start) != dow(tdate)
- start++
- enddo
- //───── add the appropriate number of weeks
- mmonth := cmonth(start)
- start += 7 * (mdom - 1)
- if cmonth(start) != mmonth
- err_msg("There is no " + appt_cdate(mdom) + " " + ;
- cdow(tdate) + " in " + mmonth)
- else
- exit
- endif
- enddo
-
- case sel == 6
- start += if(dow(start) < 6, 1, 3)
- endcase
-
- enddo
- waitoff()
- endif
- setcolor(oldcolor)
- byebyebox(oldscrn)
- return NIL
-
- * end static function Appt_Recur()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: APPT_NOTES()
- Calls: MEMEDIT() (function in MEMEDIT.PRG)
- */
- static function Appt_Notes(editing)
- local mcomments
- gfsaveenv( { 16, 00, maxrow(), maxcol() }, 1, '+w/' + if(iscolor(), 'rb', 'n'))
- shadowbox(16, 00, maxrow(), maxcol(), 2, 'Ctrl-W to save, Esc to exit')
- mcomments := memoedit(appt->comments, 17, 01, maxrow()-1, maxcol()-1, .t., ;
- 'memo_udf')
- gfrestenv()
- if lastkey() != K_ESC
- if rlock()
- replace appt->comments with mcomments
- unlock
- else
- err_msg(NETERR_MSG)
- endif
- endif
- return NIL
-
- * end static function Appt_Notes()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: MEMO_UDF()
- */
- function memo_udf(stat, line, col)
- local cur_row := row()
- if lastkey() == K_ESC
- setcursor(0)
- tone(MUSIC_ALERT, 1)
- tone(MUSIC_ALERT, 1)
- ColorSet(C_ERRORMESSAGE)
- shadowbox(cur_row + 2, 29, cur_row + 4, 50, 2)
- @ cur_row + 3, 31 ssay 'Notes not updated!'
- inkey(2)
- endif
- return 0
-
- * end function Memo_UDF()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: ApptPrintD()
- Calls: PRINTOK() (function in PRINTOK.PRG)
- : APPT_HEAD()
- */
- static function ApptPrintD(start, end)
- local page := 1, xx, oldsoftseek, lines, ;
- noteprint := yes_no('do you want to include comments')
- waiton()
- if printok()
- appt_headd(page, start, end)
- oldsoftseek := set(_SET_SOFTSEEK, .t.)
- set softseek on
- seek dtos(start)
- set(_SET_SOFTSEEK, oldsoftseek)
- do while appt->date >= start .and. appt->date <= end
- if prow() > 59
- appt_headd(page, start, end)
- endif
- if ! empty(appt->time) .or. ! empty(appt->brief) // weed out blanks
- @ prow()+2,01 say appt->userid
- @ prow(), 10 say dtoc(appt->date)
- @ prow(), 20 say appt->time
- @ prow(), 27 say appt->endtime
- @ prow(), 34 say substr(appt->brief, 1, 45)
- if noteprint // print memofield also
- lines := mlcount(appt->comments, 50)
- for xx := 1 to lines
- if prow() > 59
- appt_headd(page, start, end)
- endif
- @ prow()+1, 25 say trim(memoline(appt->comments, 50, xx))
- next
- endif
- endif
- skip
- enddo
- eject
- endif
- set device to screen
- waitoff()
- return []
-
- * end static function ApptPrintD()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_HeadD()
- Heading for appointment report (range of dates)
- */
- static function Appt_HeadD(page, start, end)
- @ 0,1 say dtoc(date())
- CENTER(0, 'Appointments for ' + dtoc(start) + ' through ' + dtoc(end))
- @ 0,71 say 'page ' + ltrim(str(++page))
- @ prow()+2,01 say 'Who'
- @ prow(), 12 say 'Date'
- @ prow(), 20 say 'Start'
- @ prow(), 28 say 'End'
- @ prow(), 47 say 'Appointment description'
- @ prow()+1,01 say '---'
- @ prow(), 10 say replicate('-',8)
- @ prow(), 20 say replicate('-',5) + ' ' + replicate('-',5)
- @ prow(), 34 say replicate('-',45)
- return NIL
-
- * end static function Appt_HeadD()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_CDate()
- Returns day # and 'st, th, nd' (e.g., '2nd, 3rd...')
- */
- static function Appt_CDate(mday)
- local mtag, mtagstr := {'st', 'nd', 'rd'}
- if (mday > 3 .and. mday < 21) .or. (mday > 23 .and. mday < 31)
- mtag := 'th'
- else
- mtag := mtagstr[mday % 10]
- endif
- return ltrim(str(mday)) + mtag
-
- * end static function Appt_CDate()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_Show()
- Displays appointments for highlighted date while in calendar
- */
- static function appt_show(show_em)
- local appts := {}, xx, oldcolor
- if show_em
- oldcolor := ColorSet(C_CALENDAR)
- shadowbox(15, 02, 23, 77, 1, 'appointments for ' + dtoc(tdate))
- seek dtos(tdate)
- xx := 16
- do while tdate == appt->date .and. xx < 23
- @ xx++, 03 ssay appt->userid + ' ' + appt->time + ' - ' + ;
- appt->endtime + ' ' + appt->brief
- skip
- enddo
- //───── there are more than seven appointments for this date
- if tdate == appt->date
- @ 23, 37 ssay ' more '
- endif
- setcolor(oldcolor)
- else
- restscreen(15, 02, 24, 79, winbuff)
- endif
- return NIL
-
- * end static function Appt_Show()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: GRAB_DATES()
- Get starting and ending date for printing/deleting appts
- */
- static function Grab_Dates(msg)
- local buffer, dates_ := { tdate, tdate }, oldcolor, getlist := {}
- oldcolor := ColorSet(C_MESSAGE)
- buffer := shadowbox(12, 27, 15, 52, 2, msg + ' appointments')
- @ 13,29 ssay 'Starting date: '
- @ 14,29 ssay 'Ending date: '
- @ 13,44 get STARTDATE
- @ 14,44 get ENDDATE valid ENDDATE >= STARTDATE
- setcursor(1)
- read
- setcursor(0)
- ByeByeBox(buffer)
- return dates_
-
- * end static function Grab_Dates()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_Day()
- Displays used and available time blocks for highlighted date
- */
- static function appt_day()
- static times[65]
- local buffer, minutes, xx, yy, zz, mrec, lastuser, oldcolor, muserid
- afill(times, 176)
- seek dtos(tdate)
- if found()
- mrec := recno()
- yy := 0
- lastuser := '%^@'
- do while appt->date == tdate .and. ! eof()
- if lastuser != appt->userid // employees for the array size
- yy++
- lastuser := appt->userid
- endif
- skip
- enddo
- goto mrec
- zz := 0
- oldcolor := ColorSet(C_WAITMESSAGE)
- buffer := shadowbox(0, 1, 4+yy, 77, 2, 'Appointment summary for ' + ;
- dtoc(tdate) + ' (' + chr(176) + chr(177) + ;
- ' = available, ' + chr(219) + ' = used)')
- @ 2, 11 ssay '6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10'
- @ 3+yy, 11 ssay '6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10'
- do while appt->date == tdate .and. ! eof()
- muserid := appt->userid
- zz++
- //───── we will alternate between two different background characters:
- //───── (ASCII 176 and 177) so that each employee's line is distinct
- afill(times, 176 + (zz % 2))
- do while muserid == appt->userid .and. appt->date == tdate .and. ! eof()
- if val(left(appt->time, 2)) > 5 .and. ;
- val(substr(appt->time, 1, 2)) < 22
- xx := (val(left(appt->time, 2)) - 6) * 4 + 1 + ;
- int(val(substr(appt->time, 4)) / 15)
- times[xx] := 219
- //───── determine time differential (in minutes) between
- //───── starting and ending times for this appointment
- minutes := val(left(appt->endtime,2)) * 60 + ;
- val(substr(appt->endtime, 4)) - ;
- val(left(appt->time, 2)) * 60 - ;
- val(substr(appt->time, 4))
- do while minutes > 15 .and. xx <= 64
- times[++xx] := 219
- minutes -= 15
- enddo
- endif
- skip
- enddo
- @ 2 + zz, 2 ssay muserid
- //───── use virtual windowing to make display smoother
- dispbegin()
- for xx = 1 to 65
- @ 2 + zz, 10 + xx ssay chr(times[xx])
- next
- dispend()
- enddo
- ginkey(0)
- ByeByeBox(buffer)
- setcolor(oldcolor)
- endif
- return NIL
-
- * end static function Appt_Day()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: NoConflict()
- Ensure that this appt is not creating a conflict with time
- */
- static function noconflict(mode, mdate, muserid, start, end, recurring)
- local ret_val := .t., marker := recno()
- field date, userid, time, endtime
- set order to 2 // make userid primary search field
- go top
- seek muserid + dtos(mdate)
- do while mdate = date .and. userid == muserid .and. ! eof()
- if (mode = 'A' .or. marker != recno()) .and. ;
- ( (start >= time .and. start < endtime) .or. ;
- (end > time .and. end <= endtime) .or. ;
- (start <= time .and. end >= endtime) )
- ret_val := .f.
- exit
- endif
- skip
- enddo
- set order to 1 // switch back to date as primary search field
- go marker
- if ! ret_val
- Err_Msg('This appointment creates a conflict' + if(recurring != NIL, ;
- ' on ' + dtoc(mdate), '') + ' and thus cannot be added')
- endif
- return ret_val
-
- * end static function NoConflict()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_Week()
- Displays summary of morning/afternoon appts for the next week
- */
- static function appt_week()
- local mfile, xx, yy, zz, num_recs, pdate, ndate, mcol := 11, mrow, muserid, ;
- oldcolor, buffer1, buffer2, wk_area := select(), times_[12], ;
- mstart, mend
- field userid, date, time, endtime
- ColorSet(C_MESSAGE)
-
- // we only want to look at this week, so reset date to monday.
- // note: if we are on a weekend day, we want to look at the upcoming week
- pdate := dow(tdate)
- do case
- case pdate = 1
- pdate := tdate + 1
- case pdate = 7
- pdate := tdate + 2
- otherwise
- pdate := tdate - (pdate - 2)
- endcase
-
- mfile := randfile("appt")
- copy to (mfile) for appt->date >= pdate .and. appt->date < pdate + 5
- use (mfile) new exclusive
- pack
- if lastrec() > 0
- index on userid to (mfile) unique
- count to num_recs
- index on userid + dtos(date) + time to (mfile)
- go top
- buffer1 := shadowbox(0, 1, 3+num_recs, 77, 1, ;
- 'Weekly appointment summary (' + chr(176) + chr(177) + ;
- ' = available, ' + chr(219) + ' = used)')
- ndate := pdate
- buffer2 := replicate('═',12)
-
- for xx = 0 to 4
- @ 1, mcol + (xx * 13) + 1 ssay left(cdow(ndate), 3) + ' ' + ;
- str(month(ndate), 2) + '/' + ;
- if(day(ndate) < 10, '0', '') + ;
- ltrim(str(day(ndate), 2))
- @ 2, mcol + (xx * 13) ssay buffer2
- ndate++
-
- if dow(ndate) = 1
- ndate++
- mcol += 2
- elseif dow(ndate) = 7
- ndate += 2
- mcol += 2
- endif
- next
-
- muserid := userid
-
- for mrow = 1 to num_recs
- if muserid != userid
- muserid := userid
- endif
-
- mcol := 11
- zz := -1
- @ mrow + 2, 2 ssay muserid
-
- if eof()
- exit
- endif
-
- for yy = 0 to 6
- if userid != muserid .or. eof()
- muserid := userid
- exit
- endif
- muserid := userid
-
- //───── if we are on a sunday, find the next weekday record and
- //───── leave an add'l space on screen to denote this break
- if dow(pdate + yy) = 1
- do while date == pdate + yy
- skip
- enddo
- mcol += 2
- loop
- endif
-
- //───── if we are on a saturday, find the next weekday record
- if dow(pdate + yy) = 7
- do while date = pdate + yy
- skip
- enddo
- loop
- endif
- zz++
- //───── again, alternate between two different background characters
- //───── (ascii 176 and 177) so that each employee's line is distinct
- afill(times_, 176 + (mrow % 2))
- if date = pdate + yy
- do while date = pdate + yy .and. ;
- muserid = userid .and. ! eof()
- if val(left(time, 2)) > 5
- mstart := val(left(time, 2)) - 5
- //───── the min() function ensures that we won't blow up
- //───── our array with a subscript greater than 12
- mend := min(val(left(endtime, 2)) - 5, 12)
- for xx = mstart to mend
- times_[xx] := 219
- next
- endif
- skip
- enddo
- dispbegin()
- setpos(mrow + 2, mcol + zz * 13)
- aeval(times_, { | hour | qqout(chr(hour)) })
- dispend()
- endif
- next
- next
- setcolor(oldcolor)
- use
- ginkey(0)
- byebyebox(buffer1)
- else
- Err_Msg("No appointments for the week of " + dtoc(pdate) + " - " + ;
- dtoc(pdate + 4))
- endif
- ferase(mfile + '.dbf')
- ferase(mfile + '.dbt')
- ferase(mfile + '.ntx')
- select(wk_area)
- return NIL
-
- * end static function Appt_Week()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: ApptPrintW()
- Calls: PRINTOK() (function in PRINTOK.PRG)
- : APPT_HEAD()
- */
- static function apptprintw()
- local page, xx, buffer, muserid := padr("ALL", 8), mfile, n, d, num_recs, ;
- mstart := tdate - (dow(tdate) - 2), wk_area, mdbf, mcol, mdate, ;
- maxrow, aday, arow, mbrief, puserid, adata[150], getlist := {}
- field userid, date, time, endtime, brief
- ColorSet(C_MESSAGE)
- buffer := shadowbox(12, 27, 14, 52, 2)
- @ 13, 29 ssay 'Employee ID:'
- @ row(), col() + 1 get muserid picture "@!" valid ! empty(muserid)
- setcursor(1)
- read
- setcursor(0)
- ByeByeBox(buffer)
- if lastkey() != K_ESC
- waiton()
- mdbf := randfile("appt")
- wk_area = select()
- mcol := 11
- if muserid = 'ALL'
- copy to (mdbf) for appt->date >= mstart .and. appt->date < mstart + 5
- else
- copy to (mdbf) for appt->date >= mstart .and. appt->date < mstart + 5 ;
- .and. appt->userid == muserid
- endif
- use (mdbf) new exclusive
- pack
- if lastrec() = 0
- err_msg('No records found!')
- else
- index on userid to (mdbf) unique
- count to num_recs
- index on userid + dtos(date) + time to (mdbf)
- go top
- if printok()
- page := maxrow := 0
- Appt_HeadW(@page, mstart)
- arow := 7
- for xx = 1 to num_recs
- muserid := userid
- maxrow := 0
- afill (adata,space(13))
- do while muserid == userid .and. ! eof()
- mdate := date
- d := 1
- aday := dow(date) - 1
- adata[aday] = ' ' + time + '-' + endtime
- do while mdate = date .and. ;
- muserid = userid .and. ! eof()
- mbrief := brief
- adata[++d * 5 - (5-aday)] = substr(mbrief, 1, 13)
- skip
- if mdate = date .and. muserid == userid
- adata[++d * 5 - (5-aday)] := replicate('─',13)
- adata[++d * 5 - (5-aday)] := ' ' + time + '-' + endtime
- endif
- enddo
- maxrow := max(maxrow, d)
- enddo
- @ arow,0 say '║' + muserid + '║'
- for n = 1 to 5
- @ arow, (n * 14) - 4 say adata[n]
- if n < 5
- @ arow, (n * 14) + 9 say '│'
- endif
- next
- puserid := '║' + space(8) + '║'
- for n = 6 to (maxrow * 5)
- d = n % 5
- if d = 0
- d = 5
- endif
- if d = 1
- @ arow, 79 say '║'
- arow++
- if arow > 56
- Appt_HeadW(@page, mstart)
- arow := 7
- puserid := '║ ' + muserid + ' ║'
- endif
- @ arow,0 say puserid
- puserid := '║' + space(8) + '║'
- else
- @ arow,(d*14)-5 say '│'
- endif
- @ arow,(d*14)-4 say left(adata[n], 13)
- next
- @ arow, 79 say '║'
- arow++
- if xx < num_recs .and. ! eof()
- if arow > 52
- Appt_HeadW(@page, mstart)
- arow := 7
- else
- @ arow++,0 say '╠════════╬' + replicate('═════════════╪',4) ;
- + '═════════════╣'
- endif
- endif
- next
- @ arow,0 say '╚════════╩' + replicate('═════════════╧',4) + ;
- '═════════════╝'
- eject
- endif
- set device to screen
- endif
- waitoff()
- use
- select(wk_area)
- ferase(mdbf + '.dbf')
- ferase(mdbf + '.dbt')
- ferase(mdbf + '.ntx')
- endif
- return NIL
-
- * end static function Appt_PrintW()
- *--------------------------------------------------------------------*
-
-
- /*
- Function: Appt_HeadW()
- Heading for appointment report (weekly)
- */
- static function appt_headw(page, mstart)
- local xx
- if page > 0
- @ row(),0 say '╚════════╩' + replicate('═════════════╧',4) + '═════════════╝'
- eject
- endif
- @ 1, 1 say dtoc(date())
- CENTER(1, 'Appointments for ' + dtoc(mstart) + ' through ' + dtoc(mstart + 4))
- @ 1,73 say 'page ' + ltrim(str(++page))
- @ 4, 0 say '╔════════╦' + replicate('═════════════╤',4) + '═════════════╗'
- @ 5, 0 say '║ Emp ID ║'
- for xx = 1 to 5
- @ 5, xx * 14 - 3 say left(gfday(mstart + xx - 1), 3) + '-'
- @ 5, xx * 14 + 2 say str(day(mstart + xx - 1), 2) + ' ' + ;
- left(gfmonth(mstart + xx - 1), 3)
- if xx < 5
- @ 5, xx * 14 + 9 say '│'
- endif
- next
- @ 5, 79 say '║'
- @ 6, 0 say '╠════════╬' + replicate('═════════════╪',4) + '═════════════╣'
- return NIL
-
- * end static function Appt_HeadW()
- *--------------------------------------------------------------------*
-
-
- //───── function under construction
- /*
-
- Function: Appt_Meet()
- Schedule a meeting
- static function appt_meet
- local buffer1, buffer2, oldcolor := setcolor("+gr/n"), muserid, getlist:={}, ;
- mtime := "00:00", mendtime := "00:00", mdescrip := space(50),
- buffer1 = shadowbox(12, 06, 15, 73, 2, 'Schedule Meeting')
- @ 13, 8 ssay 'Start time:'
- @ 13,30 ssay 'Ending time:'
- @ 14, 8 ssay 'Description:'
- @ 13,21 get mtime picture "##:##"
- @ 13,43 get mendtime picture "##:##" valid mendtime >= mtime .or. ;
- lastkey() = K_UP
- @ 14,21 get mdescrip
- setcursor(1)
- read
- setcursor(0)
- if ! empty(mtime)
- buffer2 = shadowbox(17, 27, 19, 52, 2)
- do while lastkey() != K_ESC
- muserid = space(8)
- @ 18, 29 ssay 'Employee ID:' get muserid picture "@!" ;
- valid ! empty(muserid)
- setcursor(1)
- read
- setcursor(0)
- if lastkey() != K_ESC
- if noconflict("A", tdate, muserid)
- append blank
- app_ok = ! neterr()
- if app_ok
- replace date with tdate, time with mtime, endtime with mendtime, ;
- brief with mdescrip, userid with muserid
- unlock
- else
- err_msg(NETERR_MSG)
- endif
- endif
- endif
- enddo
- byebyebox(buffer2)
- endif
- byebyebox(buffer1)
- setcolor(oldcolor)
- return NIL
-
- */
-
-
- /*
- Function: Appt_Dom()
- Determine which day of month, e.g., 2nd Monday, 3rd Tuesday, etc
- */
- static function Appt_Dom(mdate)
- local mday := cdow(mdate), ret_val := 0, mmonth := month(mdate)
- do while month(mdate) == mmonth
- mdate -= 7
- ret_val++
- enddo
- return ret_val
-
- * end static function Appt_Dom()
- *--------------------------------------------------------------------*
-
- * eof popdate.prg
-