home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 5 / 05.iso / a / a106 / 2.ddi / APPSCX.PR_ / APPSCX.bin
Encoding:
Text File  |  1994-04-28  |  101.3 KB  |  3,093 lines

  1. *       ╓─────────────────────────────────────────────────────────╖
  2. *       ║                                                         ║
  3. *       ║ 02/23/93             APPSCX.SPR                11:31:10 ║
  4. *       ║                                                         ║
  5. *       ╟─────────────────────────────────────────────────────────╢
  6. *       ║                                                         ║
  7. *       ║ Walter J. Kennamer                                      ║
  8. *       ║                                                         ║
  9. *       ║ Copyright (c) 1993 Microsoft Corp.                      ║
  10. *       ║ One Microsoft Way                                       ║
  11. *       ║ Redmond, WA  98027                                      ║
  12. *       ║                                                         ║
  13. *       ║ Description:                                            ║
  14. *       ║ This program was automatically generated by GENSCRN.    ║
  15. *       ║                                                         ║
  16. *       ╙─────────────────────────────────────────────────────────╜
  17.  
  18. PARAMETERS rscused, forceregen
  19.  
  20. *       ╓─────────────────────────────────────────────────────────╖
  21. *       ║                                                         ║
  22. *       ║          APPSCX/Windows Setup Code - SECTION 1          ║
  23. *       ║                                                         ║
  24. *       ╙─────────────────────────────────────────────────────────╜
  25. *
  26.  
  27. #REGION 1
  28. PRIVATE ALL
  29. m.app_platform = "WINDOWS"
  30.  
  31. * Parameter    Type     Description
  32. * ----------   ------   --------------------------------------------------
  33. * rscused      L        Determines whether the resource file
  34. *                          is checked for relations
  35. * forceregen   L or N   Determines whether FoxApp generates full or
  36. *                          abbreviated project files.  It can take these
  37. *                          values:
  38. *                          1 (or .T.)   Always generate full project
  39. *                          2 (or .F.)   Always generate abbreviated project
  40. *                          3            Check CONFIG.FP for instructions
  41.  
  42. * Record the status of TALK and SAFETY
  43. RELEASE app_talk, app_dele, app_safe
  44. PUBLIC app_talk, app_dele, app_safe
  45. IF SET('TALK') = 'ON'
  46.    SET TALK OFF
  47.    m.app_talk = 'ON'
  48. ELSE
  49.    m.app_talk = 'OFF'
  50. ENDIF
  51.  
  52. m.app_safe = SET("SAFETY")
  53. SET SAFETY OFF
  54. m.app_dele = SET("DELETED")
  55. SET DELETED ON
  56.  
  57. IF PARAMETERS() < 2
  58.    m.forceregen  = 3     && forces check of CONFIG.FP
  59. ENDIF
  60. IF PARAMETERS() < 1
  61.    m.rscused     = .T.   && store/restore relations from resource file?
  62. ENDIF
  63.  
  64. * Map the 'forceregen' variable into numeric form.
  65. IF TYPE('forceregen') = "L"
  66.    IF m.forceregen
  67.       m.forceregen = 1
  68.    ELSE
  69.       m.forceregen = 2
  70.    ENDIF
  71. ENDIF
  72.  
  73. #REGION 0
  74. REGIONAL m.currarea, m.talkstat, m.compstat
  75.  
  76. IF SET("TALK") = "ON"
  77.     SET TALK OFF
  78.     m.talkstat = "ON"
  79. ELSE
  80.     m.talkstat = "OFF"
  81. ENDIF
  82. m.compstat = SET("COMPATIBLE")
  83. SET COMPATIBLE FOXPLUS
  84.  
  85. m.rborder = SET("READBORDER")
  86. SET READBORDER ON
  87.  
  88. m.currarea = SELECT()
  89.  
  90.  
  91. *       ╓─────────────────────────────────────────────────────────╖
  92. *       ║                                                         ║
  93. *       ║               Windows Window definitions                ║
  94. *       ║                                                         ║
  95. *       ╙─────────────────────────────────────────────────────────╜
  96. *
  97.  
  98. IF NOT WEXIST("appgen") ;
  99.     OR UPPER(WTITLE("APPGEN")) == "APPGEN.PJX" ;
  100.     OR UPPER(WTITLE("APPGEN")) == "APPGEN.SCX" ;
  101.     OR UPPER(WTITLE("APPGEN")) == "APPGEN.MNX" ;
  102.     OR UPPER(WTITLE("APPGEN")) == "APPGEN.PRG" ;
  103.     OR UPPER(WTITLE("APPGEN")) == "APPGEN.FRX" ;
  104.     OR UPPER(WTITLE("APPGEN")) == "APPGEN.QPR"
  105.     DEFINE WINDOW appgen ;
  106.         AT  0.000, 0.000  ;
  107.         SIZE 24.308,66.833 ;
  108.         TITLE " FoxPro Application Generator " ;
  109.         FONT "MS Sans Serif", 8 ;
  110.         STYLE "B" ;
  111.         FLOAT ;
  112.         NOCLOSE ;
  113.         SHADOW ;
  114.         NOMINIMIZE ;
  115.         DOUBLE
  116.     MOVE WINDOW appgen CENTER
  117. ENDIF
  118.  
  119.  
  120. *       ╓─────────────────────────────────────────────────────────╖
  121. *       ║                                                         ║
  122. *       ║          APPSCX/Windows Setup Code - SECTION 2          ║
  123. *       ║                                                         ║
  124. *       ╙─────────────────────────────────────────────────────────╜
  125. *
  126.  
  127. #REGION 1
  128.  
  129. * Clear out any of these public variables that may already exist
  130. RELEASE appfile, mnuname, dbfname, scxname, repname, tmfname, ;
  131.    skipdbfbut, dbflist, firsttime,;
  132.    origname, app_error, app_escape
  133. PUBLIC  appfile, mnuname, dbfname, scxname, repname, tmfname, ;
  134.    skipdbfbut, origname, app_error, app_escape
  135.  
  136. * Store open databases, etc. for restoration at program termination
  137. CREATE VIEW foxapp
  138.  
  139. * Set screen font to something reasonable
  140. m.scrn_font   = WFONT(1,"")
  141. m.scrn_fsize  = WFONT(2,"")
  142. m.scrn_fstyle = WFONT(3,"")
  143. MODIFY WINDOW SCREEN FONT "MS Sans Serif",8 STYLE "B"
  144.  
  145. * Start with a clean slate--they will be restored at clean-up.
  146. CLOSE DATABASES
  147.  
  148. * Note the current ON ERROR routine so that we can restore it later.
  149. m.app_error = ON('ERROR')
  150.  
  151. * This ON ERROR routine is in the cleanup snippet
  152. ON ERROR DO apperror WITH PROGRAM(),MESSAGE(),MESSAGE(1),LINENO(),ERROR()
  153.  
  154. * Note the current ON ESCAPE routine so that we can restore it later.
  155. m.app_escape = ON('ESCAPE')
  156.  
  157. * This ON ESCAPE routine is in the cleanup snippet
  158. ON ESCAPE DO appescape WITH PROGRAM(),MESSAGE(),MESSAGE(1),LINENO(),ERROR()
  159.  
  160.  
  161. SET SYSMENU AUTOMATIC
  162. PUSH MENU _msysmenu
  163.  
  164. m.apppathlen = 79     && maximum file and path length for file names
  165.  
  166. m.dbfname  = SPACE(m.apppathlen)
  167. m.scxname  = SPACE(m.apppathlen)
  168. m.repname  = SPACE(m.apppathlen)
  169. m.mnuname  = 'APPMENU.MNX'
  170. m.generate = 0
  171. m.cancbut  = 0
  172. m.adddbf   = 0
  173. m.addscx   = 0
  174. m.modscx   = 0
  175. m.moddbf   = 0
  176.  
  177. m.dbfname  = UPPER(PADR(m.dbfname,m.apppathlen))
  178. m.scxname  = UPPER(PADR(m.scxname,m.apppathlen))
  179. m.repname  = UPPER(PADR(m.repname,m.apppathlen))
  180. m.mnuname  = UPPER(PADR(m.mnuname,m.apppathlen))
  181.  
  182. * Hide the command window--necessary if we're running from the system menu.
  183. IF WVISIBLE("COMMAND")
  184.    HIDE WINDOW COMMAND
  185. ENDIF
  186.  
  187. m.numcols   =  13   && number of columns in DBFLIST array, below
  188. m.numareas  =  25   && number of database areas supported.
  189.  
  190. * Set up definitions for DBFLIST array, declared when "Related" is pushed.
  191. * DBFLIST has One row per database in the FoxApp application
  192. * Row 1 contains data on the main database
  193. *
  194. * Column         Meaning
  195. *   1            Stem name for child database
  196. *   2            SET RELATION command
  197. *   3            Parent field name for relation
  198. *   4            Child field name for relation
  199. *   5            Full path/filename for this child database
  200. *   6            Name of parent database
  201. * column numbers in dbflist array
  202. m.cstemnum  =  1   && column number for child database stem
  203. m.relstrnum =  2   && column number for set relation string
  204. m.pfldnum   =  3   && column number for parent field in the relation
  205. m.cfldnum   =  4   && column number for child field in the relation
  206. m.cdbfnum   =  5   && column number for child database
  207. m.pdbfnum   =  6   && column number for parent database
  208. m.srownum   =  7   && column number for starting row position (str)
  209. m.scolnum   =  8   && column number for starting column position (str)
  210. m.erownum   =  9   && column number for ending row position (str)
  211. m.ecolnum   = 10   && column number for ending column position (str)
  212. m.arranged  = 11   && column number for arranged? flag
  213. m.thefont   = 12   && font for this browse window
  214. m.cascadenum= 13   && perform cascading deletes on this database?
  215.  
  216. m.ctrlrow   = MAX(ROUND(SROWS()-5.5,0),0)      && default row position for control panel
  217. m.ctrlcol   = MAX(ROUND(SCOLS()/2-74/2,0),0) && default column position for control panel
  218.  
  219. m.nextdbf   =  0        && next dbflist position, 0 at start
  220.  
  221. * Make the current font the default for new windows/browses
  222. m.defaultfont = WFONT(1,"")+","+ALLTRIM(STR(WFONT(2,""),3))+","+WFONT(3,"")
  223.  
  224. * Set the default for cascading deletes
  225. m.defaultcasc = 'N'
  226.  
  227. * Set default options for resource file handling
  228. m.rsc_check = .F.       && resource file checked for this database yet?
  229. m.rsc_stored= .F.       && have current choices been saved yet?
  230.  
  231. * These options can be reset on the advanced options screen.
  232. * Their default values are set based on the parameters passed to
  233. * FoxApp, or to the default value of rscused.
  234. m.retrieversc = rscused && retrieve relations from resource file?
  235. m.storersc    = rscused && store relations to resource file?
  236. m.rsctype     = "FOXAPP2.0A"    && type code for resource file entries
  237.  
  238. * Establish whether to put FoxApp SCX/SPR/MNX/MPR files into the
  239. * user's project, which makes the project organization easy to
  240. * understand and more "FoxPro-like," (called Full Projects) or PRG
  241. * files generated from the SCX/MNX files (Abbreviated Projects).
  242. * The latter approach is more confusing but is also much faster
  243. * since the FoxApp pieces (e.g., GETDEST() ) do not have to be
  244. * rebuilt whenever a user project is generated.
  245. DO CASE
  246. CASE m.forceregen = 1
  247.    m.regen = .T.
  248. CASE forceregen = 2
  249.    m.regen = .F.
  250. OTHERWISE
  251.    * Assume full project generation, but check CONFIG.FP
  252.    m.regen = .T.
  253.    IF FILE(SYS(2019))         && find CONFIG.FP, if one exists
  254.       m.fp = FOPEN(SYS(2019),0) && open CONFIG.FP read-only
  255.       IF m.fp > 0
  256.          DO WHILE !FEOF(fp)
  257.             m.buffer = ALLTRIM(UPPER(FGETS(m.fp)))
  258.             IF LEFT(buffer,6) == 'FOXAPP'
  259.                m.buffer = ALLTRIM(SUBSTR(m.buffer,AT('=',m.buffer)+1))
  260.                m.regen = ('GENERATE' $ m.buffer)
  261.             ENDIF
  262.          ENDDO
  263.          =FCLOSE(m.fp)
  264.       ELSE
  265.          WAIT WINDOW "Error opening CONFIG.FP." NOWAIT
  266.       ENDIF
  267.    ENDIF
  268. ENDCASE
  269.  
  270. * Defaults to \FOXAPP underneath FoxPro startup directory
  271. m.foxappdir = addbs(SYS(2004))+'FOXAPP'
  272.  
  273. * First make sure that the FoxApp source files have been installed.
  274. * If they haven't, I can't build a project.
  275. m.foxappdir = findsrc(m.foxappdir)
  276.  
  277. * It is important for the APPMENU.MPR and APPMENU.PRG files to be identical.
  278. * APPMENU relies on LOCFILE to find itself so that routines in it
  279. * can be executed, even when it is no longer in the calling chain.
  280. * The LOCFILE statements emitted by GENMENU look first for APPMENU.MPR
  281. * if it finds it, it tries to execute the procedure out of APPMENU.MPR
  282. * and reports an error if the procedure cannot be found.  Since the
  283. * procedure names are generated by GENMENU off the timer, if APPMENU.MPR
  284. * and APPMENU.PRG were generated at different times, the procedures will
  285. * have different names.  Thus, the files must be exact copies of each
  286. * other.  The following code assures this to be the case.
  287. IF m.regen
  288.    DO CASE
  289.    CASE FILE('MENUS\APPMENU.PRG') AND FILE('MENUS\APPMENU.MPR')
  290.       mpr_name = FULLPATH('MENUS\APPMENU.MPR')
  291.       COPY FILE MENUS\appmenu.prg TO &mpr_name
  292.    CASE FILE('appmenu.prg') AND FILE('appmenu.mpr')
  293.       m.mpr_name = FULLPATH('appmenu.mpr')
  294.       COPY FILE appmenu.prg TO &mpr_name
  295.    CASE FILE('FOXAPP\MENUS\APPMENU.PRG') AND FILE('FOXAPP\MENUS\APPMENU.MPR')
  296.       m.mpr_name = FULLPATH('FOXAPP\MENUS\APPMENU.MPR')
  297.       COPY FILE foxapp\MENUS\appmenu.prg TO &mpr_name
  298.    ENDCASE
  299. ELSE
  300.    IF FILE('MENUS\APPMENU.PRG') AND FILE('MENUS\APPMENU.MPR')
  301.       m.mpr_name = FULLPATH('MENUS\APPMENU.MPR')
  302.       DELETE FILE &mpr_name
  303.    ENDIF
  304.    IF FILE('appmenu.prg') AND FILE('appmenu.mpr')
  305.       m.mpr_name = FULLPATH('appmenu.mpr')
  306.       DELETE FILE &mpr_name
  307.    ENDIF
  308.    IF FILE('FOXAPP\MENUS\APPMENU.PRG') AND FILE('FOXAPP\MENUS\APPMENU.MPR')
  309.       m.mpr_name = FULLPATH('FOXAPP\MENUS\APPMENU.MPR')
  310.       DELETE FILE &mpr_name
  311.    ENDIF
  312.    * Get the MPX files too
  313.    IF FILE('MENUS\APPMENU.PRG') AND FILE('MENUS\APPMENU.MPX')
  314.       m.mpx_name = FULLPATH('MENUS\APPMENU.MPX')
  315.       DELETE FILE &mpx_name
  316.    ENDIF
  317.    IF FILE('appmenu.prg') AND FILE('appmenu.MPX')
  318.       m.mpx_name = FULLPATH('appmenu.MPX')
  319.       DELETE FILE &mpx_name
  320.    ENDIF
  321.    IF FILE('FOXAPP\MENUS\APPMENU.PRG') AND FILE('FOXAPP\MENUS\APPMENU.MPX')
  322.       m.mpx_name = FULLPATH('FOXAPP\MENUS\APPMENU.MPX')
  323.       DELETE FILE &mpx_name
  324.    ENDIF
  325. ENDIF
  326.  
  327. * Disable the Window pad while we're in the generation dialog.
  328. SET SKIP OF PAD _msm_windo OF _msysmenu .T.
  329. m.quitting = .F.   && set by cancel button
  330.  
  331.  
  332.  
  333. *       ╓─────────────────────────────────────────────────────────╖
  334. *       ║                                                         ║
  335. *       ║              APPSCX/Windows Screen Layout               ║
  336. *       ║                                                         ║
  337. *       ╙─────────────────────────────────────────────────────────╜
  338. *
  339.  
  340. #REGION 1
  341. IF WVISIBLE("appgen")
  342.     ACTIVATE WINDOW appgen SAME
  343. ELSE
  344.     ACTIVATE WINDOW appgen NOSHOW
  345. ENDIF
  346. @ 12.538,50.000 GET m.addscx ;
  347.     PICTURE "@*VN C\<reate" ;
  348.     SIZE 1.769,10.000,1.000 ;
  349.     DEFAULT 1 ;
  350.     FONT "MS Sans Serif", 8 ;
  351.     STYLE "B" ;
  352.     VALID _qdl0oozzo() ;
  353.     DISABLE
  354. @ 2.462,4.833 TO 9.539,61.666 ;
  355.     PEN 1, 8
  356. @ 12.154,4.833 TO 19.154,61.666 ;
  357.     PEN 1, 8
  358. @ 13.615,6.333 SAY "Screen name:"  ;
  359.     FONT "MS Sans Serif", 8 ;
  360.     STYLE "B"
  361. @ 4.077,6.333 SAY "Table name:"  ;
  362.     FONT "MS Sans Serif", 8 ;
  363.     STYLE "B"
  364. @ 11.615,6.167 SAY "Step 2 -- Create or Modify a Screen"  ;
  365.     FONT "MS Sans Serif", 8 ;
  366.     STYLE "B"
  367. @ 1.923,6.167 SAY "Step 1 -- Create or Modify a Table"  ;
  368.     FONT "MS Sans Serif", 8 ;
  369.     STYLE "B"
  370. @ 5.385,6.500 EDIT m.dbfname ;
  371.     SIZE 1.000,49.400,67.000 ;
  372.     PICTURE "@K!T" ;
  373.     DEFAULT " " ;
  374.     FONT "MS Sans Serif", 8 ;
  375.     WHEN _qdl0op0hz() ;
  376.     VALID DBFVALID()
  377. @ 2.846,50.167 GET m.adddbf ;
  378.     PICTURE "@*VN \<Create" ;
  379.     SIZE 1.769,10.000,1.000 ;
  380.     DEFAULT 1 ;
  381.     FONT "MS Sans Serif", 8 ;
  382.     STYLE "B" ;
  383.     VALID _qdl0op103() ;
  384.     DISABLE
  385. @ 4.923,50.167 GET m.moddbf ;
  386.     PICTURE "@*VN \<Modify" ;
  387.     SIZE 1.769,10.000,1.000 ;
  388.     DEFAULT 1 ;
  389.     FONT "MS Sans Serif", 8 ;
  390.     STYLE "B" ;
  391.     VALID _qdl0op18d() ;
  392.     DISABLE
  393. @ 7.462,6.333 GET m.Listdbf ;
  394.     PICTURE "@*VN From \<File..." ;
  395.     SIZE 1.615,13.000,1.000 ;
  396.     DEFAULT 1 ;
  397.     FONT "MS Sans Serif", 8 ;
  398.     STYLE "B" ;
  399.     WHEN _qdl0op1fe() ;
  400.     VALID _qdl0op1ik()
  401. @ 7.462,46.833 GET m.other ;
  402.     PICTURE "@*HN Re\<lated..." ;
  403.     SIZE 1.615,13.333,1.000 ;
  404.     DEFAULT 1 ;
  405.     FONT "MS Sans Serif", 8 ;
  406.     STYLE "B" ;
  407.     VALID _qdl0op1q5() ;
  408.     DISABLE
  409. @ 14.923,6.500 EDIT scxname ;
  410.     SIZE 1.000,49.400,67.000 ;
  411.     PICTURE "@K!T" ;
  412.     DEFAULT " " ;
  413.     FONT "MS Sans Serif", 8 ;
  414.     WHEN _qdl0op1y3() ;
  415.     VALID _qdl0op21x()
  416. @ 14.538,50.167 GET m.modscx ;
  417.     PICTURE "@*VN M\<odify" ;
  418.     SIZE 1.769,10.000,1.000 ;
  419.     DEFAULT 1 ;
  420.     FONT "MS Sans Serif", 8 ;
  421.     STYLE "B" ;
  422.     WHEN _qdl0op29j() ;
  423.     VALID _qdl0op2d6() ;
  424.     DISABLE
  425. @ 17.077,6.333 GET m.Listscx ;
  426.     PICTURE "@*VN From F\<ile..." ;
  427.     SIZE 1.615,13.000,1.000 ;
  428.     DEFAULT 1 ;
  429.     FONT "MS Sans Serif", 8 ;
  430.     STYLE "B" ;
  431.     VALID _qdl0op2jn()
  432. @ 21.154,6.333 GET m.generate ;
  433.     PICTURE "@*VN \!\<Generate" ;
  434.     SIZE 1.769,17.167,1.000 ;
  435.     DEFAULT 1 ;
  436.     FONT "MS Sans Serif", 8 ;
  437.     STYLE "B" ;
  438.     VALID _qdl0op2qf()
  439. @ 21.077,46.667 GET m.advanced ;
  440.     PICTURE "@*HN Ad\<vanced..." ;
  441.     SIZE 1.769,14.833,1.000 ;
  442.     DEFAULT 1 ;
  443.     FONT "MS Sans Serif", 8 ;
  444.     STYLE "B" ;
  445.     VALID _qdl0op7bf()
  446. @ 21.154,24.500 GET m.cancbut ;
  447.     PICTURE "@*VN \?\<Cancel" ;
  448.     SIZE 1.769,17.167,1.000 ;
  449.     DEFAULT 1 ;
  450.     FONT "MS Sans Serif", 8 ;
  451.     STYLE "B" ;
  452.     VALID _qdl0op7gh()
  453. @ 17.077,46.833 GET m.arrange ;
  454.     PICTURE "@*HN \<Arrange" ;
  455.     SIZE 1.615,13.333,0.667 ;
  456.     DEFAULT 1 ;
  457.     FONT "MS Sans Serif", 8 ;
  458.     STYLE "B" ;
  459.     VALID _qdl0op7lu() ;
  460.     DISABLE
  461.  
  462. IF NOT WVISIBLE("appgen")
  463.     ACTIVATE WINDOW appgen
  464. ENDIF
  465.  
  466. READ CYCLE MODAL ;
  467.     DEACTIVATE _qdl0op90p() ;
  468.     SHOW SCRNUPD()
  469.  
  470. RELEASE WINDOW appgen
  471. SELECT (m.currarea)
  472.  
  473.  
  474. #REGION 0
  475.  
  476. SET READBORDER &rborder
  477.  
  478. IF m.talkstat = "ON"
  479.     SET TALK ON
  480. ENDIF
  481. IF m.compstat = "ON"
  482.     SET COMPATIBLE ON
  483. ENDIF
  484.  
  485.  
  486. *       ╓─────────────────────────────────────────────────────────╖
  487. *       ║                                                         ║
  488. *       ║               APPSCX/Windows Cleanup Code               ║
  489. *       ║                                                         ║
  490. *       ╙─────────────────────────────────────────────────────────╜
  491. *
  492.  
  493. #REGION 1
  494. * Cleanup code to construct CDX file and start the application
  495.  
  496. * If cancel button pressed, quit now
  497. IF m.quitting
  498.    DO close_up
  499. ENDIF
  500.  
  501. * This SET TALK OFF is necessary because the screen generator restores
  502. * the original TALK setting before executing the cleanup snippet.
  503. SET TALK OFF
  504. m.scxname = ALLTRIM(UPPER(m.scxname))
  505. m.dbfname = ALLTRIM(UPPER(m.dbfname))
  506. IF !FILE(m.scxname)
  507.    WAIT WINDOW "The screen file is missing."
  508.    DO close_up
  509. ENDIF
  510. IF !FILE(m.dbfname)
  511.    WAIT WINDOW "The database file is missing."
  512.    DO close_up
  513. ENDIF
  514.  
  515. * Invert the database if there isn't a CDX file present already
  516. m.invstem = juststem(m.dbfname)
  517. m.cdxname = forceext(m.dbfname,'CDX')
  518. IF FILE(m.cdxname)
  519.    IF USED(m.invstem)
  520.       SELECT (m.invstem)
  521.    ELSE
  522.       SELECT 0
  523.       USE (LOCFILE(m.dbfname,'DBF','Locate '+m.dbfname+' please'))
  524.    ENDIF
  525.  
  526.    * Ensure that the database isn't empty
  527.    IF RECCOUNT() = 0
  528.       APPEND BLANK
  529.    ENDIF
  530. ELSE
  531.    DO invert WITH m.dbfname
  532. ENDIF
  533.  
  534. * Display a message telling the user how to run the
  535. * generated application in the future.
  536. CLEAR WINDOW
  537. GOTO TOP
  538. CLEAR
  539.  
  540. m.fnt_face  = "MS Sans Serif"
  541. m.fnt_size  = 8
  542. m.fnt_style = "B"
  543.  
  544. * Figure out how big the panel needs to be in the current screen font
  545. m.tr1 = 4    * FONTMETRIC(1,m.fnt_face, m.fnt_size, m.fnt_style) ;
  546.              / FONTMETRIC(1,WFONT(1,""),WFONT(2,""),WFONT(3,""))
  547. m.tr2 = 18   * FONTMETRIC(1,m.fnt_face, m.fnt_size, m.fnt_style) ;
  548.              / FONTMETRIC(1,WFONT(1,""),WFONT(2,""),WFONT(3,""))
  549. m.tc1 = 6    * FONTMETRIC(1,m.fnt_face, m.fnt_size, m.fnt_style) ;
  550.              / FONTMETRIC(1,WFONT(1,""),WFONT(2,""),WFONT(3,""))
  551. m.tc2 = 66   * FONTMETRIC(1,m.fnt_face, m.fnt_size, m.fnt_style) ;
  552.              / FONTMETRIC(1,WFONT(1,""),WFONT(2,""),WFONT(3,""))
  553.  
  554. DO putpanel WITH "appdoc",.T.,m.tr1,m.tc1,m.tr2,m.tc2,.5,.7
  555.  
  556. SET CURSOR OFF
  557. m.in_wrap = _WRAP
  558. m.in_lmargin = _LMARGIN
  559. m.in_rmargin = _RMARGIN
  560.  
  561.  
  562. @  3,1 SAY '   FoxApp has created an application named '+justfname(m.appfile) ;
  563.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  564. @  4,1 SAY '   in the '+justpath(m.appfile)+' directory.' ;
  565.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  566.  
  567. @  6,1 SAY '   You can run your application now by pressing any key.' ;
  568.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  569. @  7,1 SAY '   To run it in the future, simply select "Application"' ;
  570.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  571. @  8,1 SAY '   from the RUN menu, or enter FoxPro and type:' ;
  572.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  573. @  9,1 SAY '      SET DEFAULT TO '+justpath(m.appfile) ;
  574.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  575. @ 10,1 SAY '      DO '+justfname(m.appfile) ;
  576.    FONT m.fnt_face,m.fnt_size STYLE m.fnt_style
  577.  
  578. WAIT WINDOW "Press any key to start your application."
  579.  
  580. * Restore margin and wrap settings t
  581. _WRAP = m.in_wrap
  582. _RMARGIN = m.in_rmargin
  583. _LMARGIN = m.in_lmargin
  584.  
  585. RELEASE WINDOW appdoc
  586. SET CURSOR ON
  587.  
  588. * Release PUBLIC variables that are no longer needed
  589. RELEASE scxname, dbfname, invname, cdxname, repname, tmfname
  590. RELEASE bailout, skipdbfbut, origname, dbflist, mnuname
  591.  
  592. CLOSE DATABASES
  593.  
  594. CLEAR PROGRAM
  595.  
  596. POP MENU _msysmenu
  597.  
  598. * Appshell starts the m.appfile application.  Upon return from m.appfile,
  599. * it prompts for another application to run.
  600. DO appshell WITH m.appfile
  601.  
  602. DO close_up
  603. RETURN
  604.  
  605.  
  606.  
  607. *       ╓─────────────────────────────────────────────────────────╖
  608. *       ║                                                         ║
  609. *       ║   APPSCX/Windows Supporting Procedures and Functions    ║
  610. *       ║                                                         ║
  611. *       ╙─────────────────────────────────────────────────────────╜
  612. *
  613.  
  614. #REGION 1
  615. PROCEDURE close_up
  616. * Do closing housekeeping for FoxApp.
  617.  
  618. RELEASE scxname, dbfname, invname, cdxname, repname, tmfname, ;
  619.    bailout, skipdbfbut, origname, dbflist, mnuname, appfile
  620. RELEASE origdbflist
  621.  
  622. CLOSE DATABASES
  623.  
  624. CLEAR WINDOW
  625.  
  626. * Restore the PUSH-ed system menu
  627. POP MENU _msysmenu
  628.  
  629. CLEAR PROGRAM
  630. m.scrn_font   = WFONT(1,"")
  631. m.scrn_fsize  = WFONT(2,"")
  632. m.scrn_fstyle = WFONT(3,"")
  633. MODIFY WINDOW SCREEN FONT m.scrn_font,m.scrn_fsize STYLE m.scrn_fstyle
  634.  
  635. * Restore original ON ERROR & ON ESCAPE routines
  636. ON ERROR  &app_error
  637. ON ESCAPE &app_escape
  638. RELEASE app_error, app_escape
  639.  
  640. * Get rid of any vue files that might be hanging around
  641. IF FILE('qprview.vue')
  642.    DELETE FILE qprview.vue
  643. ENDIF
  644. IF FILE('appview.vue')
  645.    DELETE FILE appview.vue
  646. ENDIF
  647. IF FILE('dbfselec.vue')
  648.    DELETE FILE dbfselec.vue
  649. ENDIF
  650. IF FILE('foxapp.vue')
  651.    SET VIEW TO foxapp
  652.    DELETE FILE foxapp.vue
  653. ENDIF
  654.  
  655. IF m.app_talk = "ON"
  656.    SET TALK ON
  657. ENDIF
  658. IF m.app_dele = "OFF"
  659.    SET DELETED OFF
  660. ENDIF
  661. IF m.app_safe = "ON"
  662.    SET SAFETY ON
  663. ENDIF
  664.  
  665. RELEASE app_talk, app_safe, app_dele, dbflist
  666.  
  667. CANCEL
  668.  
  669. PROCEDURE copypiece
  670. * Copy FoxApp pieces to project directory
  671.  
  672. fxpath = addbs(foxappdir)         && probably C:\foxpro2\foxapp\
  673. projdir = addbs(justpath(m.appfile))
  674.  
  675. =putout('prgs\appproc.prg',m.fxpath,m.projdir)
  676. =putout('menus\appmenu.mnx',m.fxpath,m.projdir)
  677. =putout('menus\appmenu.mnt',m.fxpath,m.projdir)
  678. =putout('screens\getdest.scx',m.fxpath,m.projdir)
  679. =putout('screens\getdest.sct',m.fxpath,m.projdir)
  680. =putout('screens\getorder.scx',m.fxpath,m.projdir)
  681. =putout('screens\getorder.sct',m.fxpath,m.projdir)
  682. =putout('screens\appabout.scx',m.fxpath,m.projdir)
  683. =putout('screens\appabout.sct',m.fxpath,m.projdir)
  684. =putout('screens\appsrch.scx',m.fxpath,m.projdir)
  685. =putout('screens\appsrch.sct',m.fxpath,m.projdir)
  686. =putout('screens\prtsetup.scx',m.fxpath,m.projdir)
  687. =putout('screens\prtsetup.sct',m.fxpath,m.projdir)
  688. =putout('screens\prtopts.scx',m.fxpath,m.projdir)
  689. =putout('screens\prtopts.sct',m.fxpath,m.projdir)
  690. =putout('screens\appctrl.scx',m.fxpath,m.projdir)
  691. =putout('screens\appctrl.sct',m.fxpath,m.projdir)
  692.  
  693. FUNCTION putout
  694. * Copies a file with name "Pathname" from the path specified in "source"
  695. * the the "target" path.
  696.  
  697. PARAMETERS pathname, source, target
  698. PRIVATE pathname, source, target, filname, file1, file2
  699. m.filname = justfname(m.pathname)
  700. m.target = addbs(m.target)
  701. m.source = addbs(m.source)
  702. m.file1 = m.source + m.pathname
  703. m.file2 = m.target + m.filname
  704. IF FILE(m.file1)
  705.    COPY FILE &file1 TO &file2
  706. ENDIF
  707.  
  708.  
  709. FUNCTION findsrc
  710. parameter appdir
  711. * Make sure that the FoxApp source files have been installed.
  712. * If they haven't, I can't build a project.
  713. m.targfile = addbs(SYS(2004))+'FOXAPP\FOXAPP.SRC'
  714. IF !FILE(m.targfile)
  715.    m.targfile = addbs(SYS(2004))+'FOXAPPW\FOXAPP.SRC'
  716.    IF !FILE(m.targfile)
  717.       * See if we are in the FOXAPP directory itself then
  718.       m.targfile = addbs(SYS(2004))+'GOODIES\FOXAPP\FOXAPP.SRC'
  719.       IF !FILE(m.targfile)
  720.          * See if we are in the FOXAPP directory itself then
  721.          m.targfile = addbs(CURDIR())+'FOXAPP.SRC'
  722.          IF !FILE(m.targfile)
  723.             WAIT WINDOW "FoxApp source files must be available to build projects." NOWAIT
  724.             m.targfile = GETFILE('SRC','Please locate the FOXAPP.SRC file:')
  725.             IF EMPTY(m.targfile)
  726.                DO alert WITH "FoxApp cannot build a full project without its source files."
  727.                DO close_up
  728.                RETURN ''
  729.             ELSE
  730.                m.newpath = SET('PATH')+';'+justpath(m.targfile)
  731.                SET PATH TO (m.newpath)
  732.             ENDIF
  733.          ENDIF
  734.       ENDIF
  735.    ENDIF
  736. ENDIF
  737. RETURN justpath(m.targfile)
  738.  
  739. FUNCTION versiondate
  740. * Returns the FoxPro build date as a date value
  741.  
  742. * VERSION(1) returns a string like this:
  743. *     FoxPro/LAN 2.0 (X) [Nov 15 1991 16:16:06] Serial # DEV001296
  744. * We want to return 11/15/91 as a date value
  745.  
  746. m.v1 = VERSION(1)
  747.  
  748. * extract the portion of the VERSION(1) string between the brackets
  749. m.vdatestr = SUBSTR(m.v1,AT('[',m.v1)+1,RAT(']',m.v1)-AT('[',m.v1))
  750.  
  751. * extract just the date portion of the date/time string
  752. m.vdatestr = ALLTRIM(SUBSTR(m.vdatestr,1,AT(' ',m.vdatestr,3)-1))
  753.  
  754. * Pull out the month abbreviation and figure out which month number it is
  755. m.vmonthstr = UPPER(SUBSTR(m.vdatestr,1,3))
  756. DO CASE
  757. CASE INLIST(m.vmonthstr,'JANUARY','JAN')
  758.    m.vmonth = 1
  759. CASE INLIST(m.vmonthstr,'FEBRUARY','FEB')
  760.    m.vmonth = 2
  761. CASE INLIST(m.vmonthstr,'MARCH','MAR')
  762.    m.vmonth = 3
  763. CASE INLIST(m.vmonthstr,'APRIL','APR')
  764.    m.vmonth = 4
  765. CASE INLIST(m.vmonthstr,'MAY')
  766.    m.vmonth = 5
  767. CASE INLIST(m.vmonthstr,'JUNE','JUN')
  768.    m.vmonth = 6
  769. CASE INLIST(m.vmonthstr,'JULY','JUL')
  770.    m.vmonth = 7
  771. CASE INLIST(m.vmonthstr,'AUGUST','AUG')
  772.    m.vmonth = 8
  773. CASE INLIST(m.vmonthstr,'SEPTEMBER','SEP','SEPT')
  774.    m.vmonth = 9
  775. CASE INLIST(m.vmonthstr,'OCTOBER','OCT')
  776.    m.vmonth = 10
  777. CASE INLIST(m.vmonthstr,'NOVEMBER','NOV')
  778.    m.vmonth = 11
  779. CASE INLIST(m.vmonthstr,'DECEMBER','DEC')
  780.    m.vmonth = 12
  781. ENDCASE
  782.  
  783. * Reconstruct the string by using the month number
  784. m.vdatestr = STR(m.vmonth,2)+'/'+LTRIM(SUBSTR(m.vdatestr,AT(' ',m.vdatestr)))
  785.  
  786. * Replace spaces with slashes
  787. m.vdatestr = CHRTRAN(m.vdatestr,' ','/')
  788. RETURN CTOD(m.vdatestr)
  789. FUNCTION trimzero
  790. * Trims ASCII 0 characters from strg
  791. PARAMETER m.strg
  792. RETURN CHRTRAN(m.strg,CHR(0),"")
  793.  
  794. FUNCTION forceext
  795. * Force the extension of "filname" to be whatever ext is.
  796. PARAMETERS filname,ext
  797. PRIVATE ALL
  798. IF SUBSTR(m.ext,1,1) = "."
  799.    m.ext = SUBSTR(m.ext,2,3)
  800. ENDIF
  801.  
  802. m.pname = justpath(m.filname)
  803. m.filname = justfname(UPPER(ALLTRIM(m.filname)))
  804. IF AT('.',m.filname) > 0
  805.    m.filname = SUBSTR(m.filname,1,AT('.',m.filname)-1) + '.' + m.ext
  806. ELSE
  807.    m.filname = m.filname + '.' + m.ext
  808. ENDIF
  809. RETURN addbs(m.pname) + m.filname
  810. FUNCTION defaultext
  811. * Force the extension of "filname" to be whatever ext is, unless it
  812. * already has an extension.
  813. PARAMETERS filname,ext
  814. PRIVATE ALL
  815. IF EMPTY(justext(m.filname))
  816.    RETURN forceext(m.filname,m.ext)
  817. ELSE
  818.    RETURN m.filname
  819. ENDIF
  820. FUNCTION justfname
  821. * Return just the filename (i.e., no path) from "filname"
  822. PARAMETERS filname
  823. PRIVATE ALL
  824. IF RAT('\',m.filname) > 0
  825.    m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
  826. ENDIF
  827. IF AT(':',m.filname) > 0
  828.    m.filname = SUBSTR(m.filname,AT(':',m.filname)+1,255)
  829. ENDIF
  830. RETURN ALLTRIM(UPPER(m.filname))
  831.  
  832. FUNCTION juststem
  833. * Return just the stem name from "filname"
  834. PARAMETERS m.filname
  835. PRIVATE ALL
  836. IF RAT('\',m.filname) > 0
  837.    m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
  838. ENDIF
  839. IF AT(':',m.filname) > 0
  840.    m.filname = SUBSTR(m.filname,AT(':',m.filname)+1,255)
  841. ENDIF
  842. IF AT('.',m.filname) > 0
  843.    m.filname = SUBSTR(m.filname,1,AT('.',m.filname)-1)
  844. ENDIF
  845. RETURN ALLTRIM(UPPER(m.filname))
  846.  
  847. FUNCTION justext
  848. * Return just the extension from "filname"
  849. PARAMETERS m.filname
  850. PRIVATE ALL
  851. filname = JustFname(m.filname)   && prevents problems with ..\ paths
  852. m.ext = ""
  853. IF AT('.',m.filname) > 0
  854.    m.ext = SUBSTR(m.filname,AT('.',m.filname)+1,3)
  855. ENDIF
  856. RETURN UPPER(m.ext)
  857.  
  858.  
  859. FUNCTION justpath
  860. * Return just the path name from "filname"
  861. PARAMETERS m.filname
  862. PRIVATE ALL
  863. m.filname = ALLTRIM(UPPER(m.filname))
  864. IF '\' $ m.filname
  865.    m.filname = SUBSTR(m.filname,1,RAT('\',m.filname))
  866.    IF RIGHT(m.filname,1) = '\' AND LEN(m.filname) > 1 ;
  867.          AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> ':'
  868.       m.filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
  869.    ENDIF
  870.    RETURN m.filname
  871. ELSE
  872.    RETURN ''
  873. ENDIF
  874.  
  875. FUNCTION addbs
  876. * Add a backslash to a path name if there isn't already one there
  877. PARAMETER m.pathname
  878. PRIVATE ALL
  879. m.pathname = ALLTRIM(UPPER(m.pathname))
  880. IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname)
  881.    m.pathname = m.pathname + '\'
  882. ENDIF
  883. RETURN m.pathname
  884.  
  885. FUNCTION term
  886. * Returns the item-th term from string strg, where a term is a set of characters
  887. * separated by commas.
  888.  
  889. PARAMETERS m.strg, m.item
  890. m.numcommas = OCCURS(",",strg)
  891. IF m.item > m.numcommas + 1
  892.    RETURN ""
  893. ELSE
  894.     DO CASE
  895.     CASE m.item = 1
  896.        RETURN LEFT(m.strg,AT(",",m.strg)-1)
  897.     CASE m.item = m.numcommas + 1
  898.        RETURN SUBSTR(m.strg,RAT(",",m.strg)+1)
  899.     OTHERWISE
  900.        RETURN SUBSTR(m.strg,AT(",",m.strg,m.item-1)+1,;
  901.           AT(",",m.strg,m.item) - AT(",",m.strg,m.item-1) - 1)
  902.     ENDCASE
  903. ENDIF    
  904. PROCEDURE invert
  905. * Completely invert the "filname" database into a CDX file, creating
  906. * an index tag on each field.
  907.  
  908. PARAMETERS m.filname
  909. PRIVATE m.filname, m.i, m.safe_stat, m.comp_stat, m.in_area, m.fldname
  910.  
  911. m.comp_stat = SET("COMPATIBLE")
  912. m.safe_stat = SET("SAFETY")
  913. SET COMPATIBLE TO FOXPLUS
  914. SET SAFETY OFF
  915.  
  916. m.in_area = SELECT()            && currently selected area
  917.  
  918. m.fstem = juststem(m.filname)
  919. IF USED(m.fstem)
  920.    SELECT (m.fstem)
  921. ELSE
  922.    SELECT 0
  923.    USE (m.filname)
  924. ENDIF
  925.  
  926. FOR m.i = 1 TO FCOUNT()
  927.    m.fldname = FIELD(m.i)
  928.    WAIT WINDOW "Indexing on "+m.fldname + "." NOWAIT
  929.    IF TYPE(m.fldname) <> "M" AND TYPE(m.fldname) <> "G"
  930.       IF TYPE(m.fldname) = "C" AND LEN(&fldname) >= 99
  931.          INDEX ON SUBSTR(&fldname,1,99) TO (m.fldname)
  932.       ELSE
  933.          INDEX ON &fldname TAG (m.fldname)
  934.       ENDIF
  935.    ENDIF
  936. ENDFOR
  937. WAIT WINDOW "Indexing for "+m.fstem+" is complete!" NOWAIT
  938.  
  939. IF m.in_area <> SELECT()
  940.    USE
  941. ENDIF
  942. SELECT (m.in_area)
  943. IF m.comp_stat = "ON" OR m.comp_stat = "DB4"
  944.    SET COMPATIBLE TO DB4
  945. ENDIF
  946. IF m.safe_stat = "ON"
  947.    SET SAFETY ON
  948. ENDIF
  949. RETURN
  950.  
  951.  
  952. PROCEDURE mergectrl
  953. * Merge the FoxApp control panel into user's screen to create a
  954. * screen set.  This routine also forces all other screens to be
  955. * modal.
  956.  
  957. PARAMETERS m.pjxname, m.scxname, m.ctrl_y, m.ctrl_x
  958. PRIVATE pjxname, scxname, in_area, ctrl_y, ctrl_x, sname, ctrl_name
  959.  
  960. m.in_area = SELECT()
  961.  
  962. * name of the control panel screen, as it exists inside FOXAPP.APP
  963. * (or copied onto the disk, if regen is in effect)
  964. IF m.regen
  965.    m.ctrl_scx   = addbs(justpath(m.pjxname))+'APPCTRL.SCX'
  966. ELSE
  967.    m.ctrl_scx   = addbs(SYS(2004))+'FOXAPP\SCREENS\APPCTRL.SCX'
  968. ENDIF
  969. SELECT 0
  970. USE (m.ctrl_scx) AGAIN ALIAS ctrlscx
  971. REPLACE ctrlscx.hpos WITH m.ctrl_x, ctrlscx.vpos WITH m.ctrl_y
  972. USE
  973.  
  974. * Quit now if the project file is hiding.
  975. IF !FILE(m.pjxname)
  976.    RETURN
  977. ENDIF
  978.  
  979. IF USED(juststem(m.pjxname))
  980.    * Open it again with the 'pjxfile' alias.
  981.    m.sname = juststem(m.pjxname)
  982.    SELECT &sname
  983. ELSE
  984.    SELECT 0
  985. ENDIF
  986. USE (m.pjxname) ALIAS pjxfile
  987.  
  988. * Find the home directory
  989. LOCATE FOR UPPER(pjxfile.type) == "H"
  990. IF FOUND()
  991.    m.homename = pjxfile.homedir
  992. ELSE
  993.    m.homename = CURDIR()
  994. ENDIF
  995.  
  996. * Locate the master screen set record
  997. LOCATE FOR UPPER(justfname(trimzero(pjxfile.name))) ;
  998.    == UPPER(forceext(justfname(m.scxname),'SPR')) AND pjxfile.type = 'S'
  999. IF FOUND()
  1000.    m.setnum = pjxfile.setid
  1001.    * Now locate the user screen SCX record
  1002.    GOTO TOP
  1003.    LOCATE FOR UPPER(justfname(trimzero(pjxfile.name))) == UPPER(justfname(m.scxname)) ;
  1004.       AND setid = m.setnum
  1005.    IF FOUND()
  1006.       * Use the coordinates stored in the screen file itself.  These
  1007.       * reflect the changes that the user made to the screen location
  1008.       * while inside FoxApp.
  1009.       REPLACE pjxfile.arranged  WITH "WINDOWS"+CHR(0)+"N"+"N";
  1010.          +PADL(LTRIM(STR(m.ctrl_y,4)),8)+PADL(LTRIM(STR(m.ctrl_x,4)),8)
  1011.       REPLACE pjxfile.scrnorder WITH 0
  1012.    ENDIF
  1013.  
  1014.    * Figure out how many screens are in this screen set (usually 1
  1015.    * if this is a FoxApp generated app, but perhaps the user has
  1016.    * added some more screens).
  1017.    GOTO TOP
  1018.    COUNT FOR pjxfile.setid = m.setnum TO m.ctrl_order
  1019.  
  1020.    * Put the control panel into the project as a screen set member
  1021.    * of the user's screen set.  If it is already there, update it.
  1022.    * If not, create a new record and insert it.
  1023.    GOTO TOP
  1024.    LOCATE FOR justfname(UPPER(ALLTRIM(trimzero(pjxfile.name)))) ;
  1025.       == UPPER(justfname(m.ctrl_scx))
  1026.  
  1027.    IF !FOUND()
  1028.       APPEND BLANK
  1029.    ELSE
  1030.       m.ctrl_order = m.ctrl_order - 1   && don't count existing one
  1031.    ENDIF
  1032.  
  1033.    * Update the project file to point to the control panel as part of the
  1034.    * user screen set.
  1035.    IF m.regen
  1036.       m.user_scx =   m.ctrl_scx
  1037.    ELSE
  1038.       m.user_scx =   SYS(2014,m.ctrl_scx,m.pjxname)
  1039.    ENDIF
  1040.    REPLACE pjxfile.name WITH m.user_scx, ;
  1041.       pjxfile.TYPE      WITH 's',        ;
  1042.       pjxfile.setid     WITH m.setnum,   ;
  1043.       pjxfile.timestamp WITH 0,          ;
  1044.       pjxfile.exclude   WITH .F.,        ;
  1045.       pjxfile.scrnorder WITH m.ctrl_order
  1046. ELSE
  1047.    * This means that something went badly wrong during BUILD PROJECT
  1048.    WAIT WINDOW "FoxApp could not complete this application."
  1049.    SET DEFAULT TO &c_path
  1050.    DO close_up
  1051.    CANCEL
  1052. ENDIF
  1053.  
  1054. USE
  1055. SELECT (in_area)
  1056.  
  1057.  
  1058. PROCEDURE initdbflist
  1059. * Initialize the DBFLIST array
  1060. PRIVATE m.i,m.j
  1061.  
  1062. PUBLIC dbflist[m.numareas,m.numcols]
  1063.  
  1064. * Format the stem names for the popup
  1065. FOR m.i = 1 TO m.numareas
  1066.    dbflist[m.i,m.cstemnum]   = '\'   && start everything off disabled
  1067.    dbflist[m.i,m.arranged]   = "N"   && user hasn't arranged the screen yet
  1068.    dbflist[m.i,m.theFont]    = defaultfont
  1069.    dbflist[m.i,m.cascadenum] = defaultcasc
  1070. ENDFOR
  1071.  
  1072. * Initialize the other columns in the dbflist array, except screen
  1073. * positions
  1074. FOR m.i = 1 TO m.numareas
  1075.    FOR m.j = 2 TO m.srownum - 1
  1076.       dbflist[m.i,m.j] = ''
  1077.    ENDFOR
  1078. ENDFOR
  1079.  
  1080. * Initialize the screen positions
  1081. FOR m.i = 1 TO m.numareas
  1082.    dbflist[m.i,m.srownum] = ALLTRIM(STR(m.i,3))
  1083.    dbflist[m.i,m.scolnum] = ALLTRIM(STR(m.i,3))
  1084.    dbflist[m.i,m.erownum] = "6"                     && 6 rows high
  1085.    dbflist[m.i,m.ecolnum] = ALLTRIM(STR(76-m.i,3))  && width
  1086. ENDFOR
  1087.  
  1088. FUNCTION opendbf
  1089. * Open a DBF and return the alias, or blanks if the database could
  1090. *   not be opened.
  1091. PARAMETERS fname
  1092. PRIVATE fname, stem
  1093. IF FILE(m.fname)
  1094.    m.stem = juststem(m.fname)
  1095.    IF USED(m.stem)
  1096.       SELECT (m.stem)
  1097.    ELSE
  1098.       SELECT 0
  1099.       m.fname = LOCFILE(m.fname,'DBF','Please locate the database')
  1100.       IF EMPTY(m.fname)
  1101.          RETURN ''
  1102.       ELSE
  1103.          USE (m.fname)
  1104.       ENDIF
  1105.    ENDIF
  1106.    RETURN ALIAS()
  1107. ELSE
  1108.    RETURN ''
  1109. ENDIF
  1110.  
  1111. PROCEDURE createscx
  1112. PRIVATE maxh, maxv, s_name
  1113. * Create a quick-screen SCX file from the named database
  1114. m.scxname = ALLTRIM(m.scxname)
  1115. IF !EMPTY(opendbf(m.dbfname))
  1116.    m.s_name = addbs(justpath(m.scxname)) + juststem(m.scxname)   && don't need extension
  1117.    WAIT WINDOW "Creating screen "+m.s_name NOWAIT
  1118.    CREATE SCREEN (m.s_name) FROM (m.dbfname) ROW
  1119.    m.scxname = forceext(m.scxname,"SCX")
  1120.    IF FILE(m.scxname)
  1121.       SHOW GET addscx DISABLE
  1122.       SHOW GET modscx ENABLE
  1123.    ENDIF
  1124.    IF !EMPTY(m.scxname)
  1125.       SELECT 0
  1126.       USE (m.scxname) ALIAS fxscxname
  1127.       REPLACE fxscxname.width WITH MIN(SCOLS(),fxscxname.width)
  1128.       m.maxh = width
  1129.       m.maxv = height
  1130.  
  1131.       IF relateddbfs() AND UPPER(dbflist[1,m.arranged]) = "N"
  1132.          * No screen position yet defined for the main database.  Center it,
  1133.          * unless there are lots of related databases.  If there are, put
  1134.          * it closer to the top of the screen.
  1135.          IF m.nextdbf < 3  && just one database used in app
  1136.             m.start_row = MAX(INT(SROWS()/2-height/2),0)
  1137.             m.start_col = MAX(INT(SCOLS()/2-width/2),0)
  1138.          ELSE
  1139.             m.start_row = 1
  1140.             m.start_col = MAX(INT(SCOLS()/2-width/2),0)
  1141.          ENDIF
  1142.       ELSE   && center the screen horizontally if it hasn't been arranged.
  1143.          m.start_row = 1
  1144.          m.start_col = MAX(INT(SCOLS()/2-width/2),0)
  1145.       ENDIF
  1146.       m.start_row = MAX(0,m.start_row)
  1147.       m.start_col = MAX(0,m.start_col)
  1148.  
  1149.       REPLACE ALL fxscxname.vpos WITH m.start_row, fxscxname.hpos WITH m.start_col;
  1150.          FOR objtype = 1 AND platform = "WINDOWS"
  1151.  
  1152.       * Make some space around the fields
  1153.       REPLACE ALL fxscxname.hpos WITH fxscxname.hpos + 1,;
  1154.          fxscxname.vpos WITH fxscxname.vpos + 1 ;
  1155.          FOR objtype > 4 AND objtype <> 23 AND platform = "WINDOWS"
  1156.  
  1157.       SCAN FOR objtype > 4 and objtype <> 23
  1158.          m.thish = fxscxname.hpos + fxscxname.width ;
  1159.           * FONTMETRIC(6,fxscxname.fontface,fxscxname.fontsize, ;
  1160.              whatstyle(fxscxname.fontstyle)) ;
  1161.           /  FONTMETRIC(6,WFONT(1,""),WFONT(2,""),WFONT(3,""))
  1162.          m.thisv = fxscxname.vpos + fxscxname.height ;
  1163.           * FONTMETRIC(1,fxscxname.fontface,fxscxname.fontsize, ;
  1164.              whatstyle(fxscxname.fontstyle)) ;
  1165.           /  FONTMETRIC(1,WFONT(1,""),WFONT(2,""),WFONT(3,""))
  1166.          m.maxh = MAX(m.thish,m.maxh)
  1167.          m.maxv = MAX(m.thisv,m.maxv)
  1168.       ENDSCAN
  1169.       GOTO TOP
  1170.       REPLACE fxscxname.center WITH .T.,;
  1171.          fxscxname.width WITH m.maxh + 6, ;
  1172.          fxscxname.height WITH m.maxv + 1,;
  1173.          fxscxname.name WITH juststem(m.scxname), ;
  1174.          fxscxname.style WITH 2,;
  1175.          fxscxname.border WITH 1,;
  1176.          fxscxname.tag WITH '" '+juststem(m.scxname)+' "'
  1177.  
  1178.       IF relateddbfs()
  1179.          dbflist[1,m.srownum] = ALLTRIM(STR(m.start_row,4))
  1180.          dbflist[1,m.scolnum] = ALLTRIM(STR(m.start_col,4))
  1181.          dbflist[1,m.erownum] = ALLTRIM(STR(fxscxname.height,4))
  1182.          dbflist[1,m.ecolnum] = ALLTRIM(STR(fxscxname.width,4))
  1183.       ENDIF
  1184.  
  1185.       USE
  1186.    ENDIF
  1187.    WAIT WINDOW "Screen has been created." NOWAIT
  1188. ELSE
  1189.    DO errshow WITH "Database could not be opened.",10
  1190. ENDIF
  1191. SHOW GETS
  1192. RETURN
  1193.  
  1194.  
  1195. FUNCTION filattr
  1196. * Return file attributes of "filname"
  1197. PARAMETER m.filname
  1198. PRIVATE filarray, m.filpos
  1199. m.filname = UPPER(ALLTRIM(m.filname))
  1200. IF ADIR(filarray,m.filname) > 0
  1201.    m.filpos = ASCAN(filarray,justfname(m.filname))
  1202.    IF m.filpos > 0
  1203.       RETURN filarray[m.filpos,5]
  1204.    ENDIF
  1205. ENDIF
  1206. RETURN ''
  1207. FUNCTION relateddbfs
  1208. * RETURN T if related DBF files have been defined through FoxApp
  1209. RETURN m.nextdbf > 2
  1210.  
  1211. FUNCTION getdbflist
  1212. * Retrieve dbflist from resource file
  1213.  
  1214. PARAMETERS cstem
  1215. PRIVATE m.nextdbf, m.in_area, m.cstem, m.i, m.j, m.j1_at, m.j2_at
  1216.  
  1217. IF !FILE(SYS(2005))    && resource file not found.
  1218.    RETURN 0
  1219. ENDIF
  1220.  
  1221. m.nextdbf = 0
  1222. m.in_area = SELECT(0)
  1223.  
  1224. m.cstem = UPPER(ALLTRIM(m.cstem))
  1225. IF EMPTY(m.cstem)
  1226.    RETURN 0
  1227. ENDIF
  1228.  
  1229. m.memwidth = SET('MEMOWIDTH')
  1230. SET MEMOWIDTH TO 255
  1231.  
  1232. SELECT 0
  1233. USE (SYS(2005)) AGAIN ALIAS rsc
  1234.  
  1235. LOCATE FOR UPPER(ALLTRIM(rsc.type)) == m.rsctype;
  1236.    AND UPPER(ALLTRIM(rsc.id)) == 'DBFLIST' ;
  1237.    AND UPPER(ALLTRIM(rsc.name)) == m.cstem ;
  1238.    AND !DELETED()
  1239.  
  1240. IF FOUND() AND !EMPTY(rsc.data)
  1241.    WAIT WINDOW "Retrieving stored relationships." NOWAIT
  1242.  
  1243.    IF TYPE("dbflist") = "U"
  1244.       DO initdbflist
  1245.    ENDIF
  1246.  
  1247.    * First get the position of the control panel
  1248.    m.ctrlline = MLINE(rsc.data,1)
  1249.    m.ctrlrow  = VAL(SUBSTR(m.ctrlline,1,AT(';',m.ctrlline)-1))
  1250.    m.ctrlcol  = VAL(SUBSTR(m.ctrlline,AT(';',m.ctrlline)+1))
  1251.  
  1252.    FOR m.i = 1 TO m.numareas
  1253.       m.this_dbf = MLINE(rsc.data,m.i+1)
  1254.       FOR m.j = 1 TO m.numcols
  1255.          DO CASE
  1256.          CASE m.j = 1
  1257.             IF AT(';',m.this_dbf) = 1
  1258.                dbflist[m.i,m.j] = '\'   && make this empty area disabled in the list
  1259.             ELSE
  1260.                dbflist[m.i,m.j] = SUBSTR(m.this_dbf,1,AT(';',m.this_dbf)-1)
  1261.             ENDIF
  1262.          CASE m.j = m.numcols
  1263.             dbflist[m.i,m.j] = SUBSTR(m.this_dbf,AT(';',m.this_dbf,m.numcols-1)+1)
  1264.          OTHERWISE
  1265.             m.j1_at = AT(';',m.this_dbf,m.j-1)
  1266.             m.j2_at = AT(';',m.this_dbf,m.j)
  1267.             dbflist[m.i,m.j] = SUBSTR(m.this_dbf,m.j1_at + 1,m.j2_at - m.j1_at - 1)
  1268.          ENDCASE
  1269.  
  1270.       ENDFOR
  1271.  
  1272.       IF !EMPTY(dbflist[m.i,m.cstemnum])       ;
  1273.             AND dbflist[m.i,m.cstemnum] <> '\' ;
  1274.             AND !USED(dbflist[m.i,m.cstemnum])
  1275.  
  1276.          IF !FILE(dbflist[m.i,m.cdbfnum])
  1277.             * See if we can find it anywhere along the path
  1278.             IF FILE(FULLPATH(dbflist[m.i,m.cdbfnum]))
  1279.                dbflist[m.i,m.cdbfnum] = FULLPATH(dbflist[m.i,m.cdbfnum])
  1280.                dbflist[m.i,m.cstemnum] = juststem(dbflist[m.i,m.cdbfnum])
  1281.             ELSE   && it is nowhere to be found.  Ask where it is.
  1282.                dbflist[m.i,m.cdbfnum] = GETFILE('DBF',;
  1283.                   'Where is '+juststem(dbflist[m.i,m.cdbfnum])+'?')
  1284.                IF EMPTY(dbflist[m.i,m.cdbfnum]) OR !FILE(dbflist[m.i,m.cdbfnum])
  1285.                   DO alert WITH dbflist[m.i,m.cstemnum]+" could not be found!"
  1286.                   DO close_up
  1287.                ENDIF
  1288.             ENDIF
  1289.          ENDIF
  1290.  
  1291.          dbflist[m.i,m.cstemnum] = juststem(dbflist[i,m.cdbfnum])
  1292.  
  1293.          IF FILE(dbflist[m.i,m.cdbfnum])
  1294.             * full name of database including path
  1295.             SELECT 0
  1296.             USE (dbflist[m.i,m.cdbfnum]) AGAIN
  1297.          ENDIF
  1298.  
  1299.          * Ensure that this database has a corresponding CDX file
  1300.          DO makecdx WITH dbflist[m.i,m.cdbfnum], dbflist[m.i,m.cfldnum]
  1301.       ENDIF
  1302.  
  1303.       * Record the first open database area
  1304.       IF !EMPTY(dbflist[m.i,m.cstemnum]) AND dbflist[m.i,m.cstemnum] <> '\'
  1305.          m.nextdbf = m.i+1
  1306.       ENDIF
  1307.  
  1308.    ENDFOR
  1309.    WAIT CLEAR
  1310. ENDIF
  1311. SELECT rsc
  1312. USE
  1313. SELECT (m.in_area)
  1314. SET MEMOWIDTH TO m.memwidth
  1315.  
  1316. RETURN m.nextdbf
  1317.  
  1318.  
  1319. FUNCTION putdbflist
  1320. PARAMETERS cstem
  1321. PRIVATE m.cstem, m.in_area, m.i, m.j, m.repl_str
  1322.  
  1323. * Store the dbflist array in the resource file
  1324. *
  1325. * The format for storing the dbflist array in the data memo field is:
  1326. *    string;string;string;string... CHR(13)+CHR(10)
  1327.  
  1328. IF !FILE(SYS(2005)) OR EMPTY(m.cstem)
  1329.    RETURN 0
  1330. ENDIF
  1331.  
  1332. * Don't update if this is a read-only file
  1333. * SYS(2026,filename) is a last-minute function that returns 'Y' if the
  1334. * file is both open and marked read-only, for any reason (e.g., it's in an APP, it's
  1335. * the resource file for another instance of FoxPro, etc.)
  1336. IF 'R' $ filattr(SYS(2005)) OR SYS(2026,SYS(2005)) <> "N"
  1337.    WAIT WINDOW "Resource file is read-only.  Not updated." NOWAIT
  1338.    m.storersc = .F.
  1339.    =INKEY(2)
  1340.    RETURN 0
  1341. ENDIF
  1342.  
  1343. m.cstem = UPPER(ALLTRIM(m.cstem))
  1344. m.in_area = SELECT()
  1345.  
  1346. SELECT 0
  1347. USE (SYS(2005)) AGAIN ALIAS rsc
  1348. LOCATE FOR UPPER(ALLTRIM(rsc.type)) == m.rsctype ;
  1349.    AND UPPER(ALLTRIM(rsc.id)) == 'DBFLIST' ;
  1350.    AND UPPER(ALLTRIM(rsc.name)) == m.cstem
  1351. IF !FOUND()
  1352.    APPEND BLANK
  1353. ELSE
  1354.    IF rsc.readonly
  1355.       WAIT WINDOW "Existing resource record is read-only.  Not updated." NOWAIT
  1356.       =INKEY(1)   && wait 1 second
  1357.       USE
  1358.       SELECT (m.in_area)
  1359.       RETURN 0
  1360.    ENDIF
  1361. ENDIF
  1362.  
  1363. * Write out the control panel upper left coordinates first
  1364. m.repl_str = ALLTRIM(STR(m.ctrlrow,7,3))+';';
  1365.    +ALLTRIM(STR(m.ctrlcol,7,3))+CHR(13)+CHR(10)
  1366.  
  1367. * Write the dbflist data for each row/col
  1368. FOR m.i = 1 TO m.numareas
  1369.    FOR m.j = 1 TO m.numcols
  1370.       m.repl_str = m.repl_str +IIF(m.j=1,'',';') ;
  1371.          + IIF(INLIST(TYPE("dbflist[m.i,m.j]"),'U','L'),'',TRIM(dbflist[m.i,m.j]));
  1372.          + IIF(m.j=m.numcols,CHR(13)+CHR(10),'')
  1373.    ENDFOR
  1374. ENDFOR
  1375. REPLACE rsc.data WITH m.repl_str, ;
  1376.    rsc.type      WITH m.rsctype, ;
  1377.    rsc.id        WITH 'DBFLIST',  ;
  1378.    rsc.name      WITH m.cstem,    ;
  1379.    rsc.ckval     WITH VAL(SYS(2007,rsc.data)),;
  1380.    rsc.updated   WITH DATE(),;
  1381.    rsc.readonly  WITH .F.
  1382.  
  1383. * Set the flag that notifies the rest of the program that the
  1384. * relations have been stored in the resource file.
  1385. rsc_stored = .T.
  1386.  
  1387. USE
  1388. SELECT (m.in_area)
  1389. RETURN 0
  1390.  
  1391. PROCEDURE makecdx
  1392. parameter filname, tagname
  1393. * Ensure that filename has a CDX file with a tag name of tagname
  1394. PRIVATE m.filname, m.tagname, m.cdxname, m.i, m.justtag
  1395.  
  1396. justtag = m.tagname
  1397. * Strip off alias names from fields like parent.fldname
  1398. IF AT('.',m.justtag) > 0
  1399.    m.justtag = ALLTRIM(UPPER(SUBSTR(m.justtag,AT('.',m.justtag)+1)))
  1400. ENDIF
  1401.  
  1402. cdxname = forceext(m.filname,'CDX')
  1403. =opendbf(m.filname)
  1404. DO CASE
  1405. CASE !FILE(m.cdxname)
  1406.    DO invert WITH m.filname
  1407. OTHERWISE
  1408.    * Cycle through the tags looking for one to match the key field
  1409.    m.i = 1
  1410.    DO WHILE (TAG(m.cdxname,m.i) != m.justtag) ;
  1411.          AND !EMPTY(TAG(m.cdxname,m.i))
  1412.       m.i = m.i + 1
  1413.    ENDDO
  1414.    IF EMPTY(TAG(m.cdxname,m.i))
  1415.       DO invert WITH m.filname
  1416.    ENDIF
  1417. ENDCASE
  1418.  
  1419.  
  1420.  
  1421. PROCEDURE definewindow
  1422. * Defines a window for use by the error reporting routines
  1423.  
  1424. parameter m.hight, m.width, m.name, m.scheme
  1425. PRIVATE m.fromrow, m.fromcol, m.torow, m.tocol
  1426.  
  1427. m.fromrow = INT((srow()-m.hight)/2)
  1428. m.fromcol = INT((scol()-m.width)/2)
  1429. m.torow   = m.fromrow + m.hight
  1430. m.tocol   = m.fromcol + m.width
  1431.  
  1432. DEFINE WINDOW (m.name);
  1433.    FROM m.fromrow, m.fromcol TO m.torow, m.tocol;
  1434.    FLOAT NOGROW NOCLOSE NOZOOM SHADOW DOUBLE;
  1435.    COLOR SCHEME (m.scheme)
  1436.  
  1437. RETURN
  1438. FUNCTION maptochar
  1439. * Maps the numeric values used in SCX files to the string that FONTMETRIC needs
  1440. PARAMETERS stylenum
  1441. DO CASE
  1442. CASE m.stylenum = 0
  1443.    RETURN ""
  1444. CASE m.stylenum = 1
  1445.    RETURN "B"
  1446. CASE m.stylenum = 2
  1447.    RETURN "I"
  1448. CASE m.stylenum = 3
  1449.    RETURN "BI"
  1450. OTHERWISE
  1451.    RETURN ""
  1452. ENDCASE
  1453.  
  1454. FUNCTION tranfont
  1455. * Translates coordinates from one font to another
  1456. PARAMETERS units, code, fromfont, fromsize, fromstyle, tofont, tosize, tostyle
  1457. * Units is the width/height term
  1458. * code = 1 for height, 6 for width
  1459. PRIVATE strflag, retval
  1460.  
  1461. IF PARAMETERS() < 8
  1462.    m.tostyle = WFONT(3,"")
  1463. ENDIF
  1464. IF PARAMETERS() < 7
  1465.    m.tosize = WFONT(2,"")
  1466. ENDIF
  1467. IF PARAMETERS() < 6
  1468.    m.tofont = WFONT(1,"")
  1469. ENDIF
  1470. m.strflag = .F.
  1471. IF TYPE("units") = "C"
  1472.    m.units = VAL(m.units)
  1473.    m.strflag = .T.
  1474. ENDIF
  1475. IF TYPE("fromstyle") = "N"
  1476.    m.fromstyle = MapToChar(m.fromstyle)
  1477. ENDIF
  1478. IF TYPE("tostyle") = "N"
  1479.    m.tostyle = MapToChar(m.tostyle)
  1480. ENDIF
  1481. IF TYPE("tosize") = "C"
  1482.    m.tosize = VAL(m.tosize)
  1483. ENDIF
  1484. IF TYPE("fromsize") = "C"
  1485.    m.fromsize = VAL(m.fromsize)
  1486. ENDIF
  1487.  
  1488. m.tofont = FONTMETRIC(m.code,m.tofont, m.tosize, m.tostyle)
  1489. m.fromfont = FONTMETRIC(m.code,m.fromfont,m.fromsize,m.fromstyle)
  1490. IF m.tofont <> 0     && avoid division by zero
  1491.    retval =  m.units *  m.fromfont / m.tofont * 1.00
  1492.    IF strflag
  1493.       retval = ALLTRIM(STR(retval,10))
  1494.    ENDIF
  1495. ELSE
  1496.    retval = IIF(strflag,"0",0)
  1497. ENDIF
  1498. RETURN retval
  1499. PROCEDURE arrsave
  1500. * Save arrangement of windows and return to dbfselect screen
  1501.  
  1502. * Set exit flag for READ VALID--can't be PRIVATE
  1503. m.arrexflg = .T.
  1504.  
  1505. * Record window coordinates and release all the application windows
  1506. m.ctrlrow = WLROW('CTRL')
  1507. m.ctrlcol = WLCOL('CTRL')
  1508. RELEASE WINDOW ctrl
  1509.  
  1510. * Store the coordinates for the main window
  1511. IF !EMPTY(dbflist[1,m.cstemnum]) AND dbflist[1,m.cstemnum] <> '\'
  1512.    dbflist[1,m.srownum] = ALLTRIM(STR(WLROW(dbflist[1,m.cstemnum]),7,3))
  1513.    dbflist[1,m.scolnum] = ALLTRIM(STR(WLCOL(dbflist[1,m.cstemnum]),7,3))
  1514.    dbflist[1,m.erownum] = ALLTRIM(STR(WROWS(dbflist[1,m.cstemnum]),7,3))
  1515.    dbflist[1,m.ecolnum] = ALLTRIM(STR(WCOLS(dbflist[1,m.cstemnum]),7,3))
  1516.    RELEASE WINDOW (dbflist[1,m.cstemnum])
  1517. ENDIF
  1518. dbflist[1,m.arranged] = "Y"
  1519.  
  1520. FOR m.i = 2 TO m.numareas
  1521.    IF !EMPTY(dbflist[m.i,m.cstemnum]) AND dbflist[m.i,m.cstemnum] <> '\'
  1522.       dbflist[m.i,m.srownum] = ALLTRIM(STR(WLROW(dbflist[m.i,m.cstemnum]),7,3))
  1523.       dbflist[m.i,m.scolnum] = ALLTRIM(STR(WLCOL(dbflist[m.i,m.cstemnum]),7,3))
  1524.       * WROWS() reports one more pixel than we want.
  1525.       dbflist[m.i,m.erownum] = ALLTRIM(STR(WROWS(dbflist[m.i,m.cstemnum]) - 1/FONTMETRIC(1),7,3))
  1526.       dbflist[m.i,m.ecolnum] = ALLTRIM(STR(WCOLS(dbflist[m.i,m.cstemnum]),7,3))
  1527.       RELEASE WINDOW (dbflist[m.i,m.cstemnum])
  1528.    ENDIF
  1529.    dbflist[m.i,m.arranged] = "Y"
  1530. ENDFOR
  1531.  
  1532. * Store relations into resource file if needed
  1533. IF TYPE("DBFLIST") <> "U" AND !rsc_stored AND m.storersc
  1534.    WAIT WINDOW "Saving window positions." NOWAIT
  1535.    DO putdbflist WITH dbflist[1,1]
  1536. ENDIF
  1537.  
  1538. * Restore environment
  1539. POP MENU _msysmenu
  1540. SHOW WINDOW appgen
  1541. ACTIVATE WINDOW appgen
  1542.  
  1543. CLEAR READ
  1544.  
  1545. RETURN
  1546.  
  1547. FUNCTION putfontval
  1548. PARAMETER m.value, m.code, m.i
  1549.  
  1550. RETURN TRANFONT(m.value, m.code, WFONT(1,""), WFONT(2,""), WFONT(3,""), ;
  1551.    term(dbflist[m.i,m.thefont],1), VAL(term(dbflist[m.i,m.thefont],2)), ;
  1552.    term(dbflist[m.i,m.thefont],3) )
  1553.  
  1554. PROCEDURE arrexit
  1555. * Exit without saving window positions
  1556. PRIVATE m.i
  1557. * Set exit flag for READ VALID--can't be PRIVATE
  1558. m.arrexflg = .T.
  1559.  
  1560. * Release all the application windows
  1561. RELEASE WINDOW ctrl
  1562. FOR m.i = 1 TO m.numareas
  1563.    IF !EMPTY(dbflist[m.i,m.cstemnum]) AND dbflist[m.i,m.cstemnum] <> '\'
  1564.       RELEASE WINDOW (dbflist[m.i,m.cstemnum])
  1565.    ENDIF
  1566. ENDFOR
  1567.  
  1568. * Restore environment
  1569. POP MENU _msysmenu
  1570. SHOW WINDOW appgen
  1571.  
  1572. ACTIVATE WINDOW appgen
  1573.  
  1574. CLEAR READ
  1575.  
  1576. RETURN
  1577.  
  1578.  
  1579. FUNCTION haschild
  1580. * Does the database at position "dbfnum" of DBFLIST have a child
  1581. * table?
  1582. parameter dbfnum
  1583. PRIVATE m.dbfnum, m.i
  1584.  
  1585. * See if another database has this one as its parent
  1586. FOR m.i = 1 TO m.numareas
  1587.    IF ALLTRIM(dbflist[m.i,m.pdbfnum]) ;
  1588.          == ALLTRIM(dbflist[m.dbfnum,m.cstemnum])
  1589.       RETURN .T.
  1590.    ENDIF
  1591. ENDFOR
  1592. RETURN .F.
  1593.  
  1594.  
  1595. FUNCTION actwin
  1596. * Activate window wind_name
  1597.  
  1598. parameter wind_name
  1599. PRIVATE ALL
  1600. wind_name = UPPER(ALLTRIM(m.wind_name))
  1601. IF !EMPTY(m.wind_name) AND WEXIST(m.wind_name)
  1602.    ACTIVATE WINDOW (m.wind_name)
  1603. ENDIF
  1604. RETURN ''
  1605.  
  1606. PROCEDURE errshow
  1607. * Procedure to display an error message
  1608.  
  1609. parameter m.messg, m.lineno
  1610. PRIVATE ALL
  1611. DO definewindow WITH 4, 70, "ALERT", 7
  1612. ACTIVATE WINDOW alert
  1613.  
  1614. SET CURSOR OFF
  1615. @ 0,0 CLEAR
  1616. @ 1,0 SAY PADC(ALLTRIM(m.messg), WCOLS())
  1617. WAIT ""
  1618. SET CURSOR ON
  1619.  
  1620. RELEASE WINDOW alert
  1621. RETURN
  1622.  
  1623. PROCEDURE alert
  1624. * Display an error message, automatically sizing the message window
  1625. *    as necessary.  Semicolons in "strg" mean "new line".
  1626. PARAMETERS strg
  1627. PRIVATE ALL
  1628.  
  1629. m.in_talk = SET('TALK')
  1630. SET TALK OFF
  1631. m.in_cons = SET('CONSOLE')
  1632.  
  1633. m.numlines = OCCURS(';',m.strg) + 1
  1634.  
  1635. DIMENSION alert_arry[m.numlines]
  1636. m.remain = m.strg
  1637. m.maxlen = 0
  1638. FOR i = 1 TO m.numlines
  1639.    IF AT(';',m.remain) > 0
  1640.       alert_arry[i] = SUBSTR(m.remain,1,AT(';',m.remain)-1)
  1641.       alert_arry[i] = CHRTRAN(alert_arry[i],';','')
  1642.       m.remain = SUBSTR(m.remain,AT(';',m.remain)+1)
  1643.    ELSE
  1644.       alert_arry[i] = m.remain
  1645.       m.remain = ''
  1646.    ENDIF
  1647.    IF LEN(alert_arry[i]) > SCOLS() - 6
  1648.       alert_arry[i] = SUBSTR(alert_arry[i],1,SCOLS()-6)
  1649.    ENDIF
  1650.    IF LEN(alert_arry[i]) > m.maxlen
  1651.       m.maxlen = LEN(alert_arry[i])
  1652.    ENDIF
  1653. ENDFOR
  1654.  
  1655. m.top_row = INT( (SROWS() - 4 - m.numlines) / 2)
  1656. m.bot_row = m.top_row + 3 + m.numlines
  1657.  
  1658. m.top_col = INT((SCOLS() - m.maxlen - 6) / 2)
  1659. m.bot_col = m.top_col + m.maxlen + 6
  1660.  
  1661. DEFINE WINDOW alert FROM m.top_row,m.top_col TO m.bot_row,m.bot_col;
  1662.    DOUBLE COLOR SCHEME 7
  1663. ACTIVATE WINDOW alert
  1664.  
  1665. FOR m.i = 1 TO m.numlines
  1666.    @ m.i,3 SAY PADC(alert_arry[m.i],m.maxlen)
  1667. ENDFOR
  1668.  
  1669. CLEAR TYPEAHEAD
  1670. SET CONSOLE OFF
  1671. m.keycode = 0
  1672. DO WHILE m.keycode = 0
  1673.    m.keycode = INKEY(0,'HM')
  1674. ENDDO
  1675. SET CONSOLE ON
  1676.  
  1677. RELEASE WINDOW alert
  1678.  
  1679. IF m.in_talk = "ON"
  1680.    SET TALK ON
  1681. ENDIF
  1682. IF m.in_cons = "OFF"
  1683.    SET CONSOLE OFF
  1684. ENDIF
  1685.  
  1686. PROCEDURE apperror
  1687. * Simple ON ERROR routine for FoxApp application
  1688.  
  1689. PARAMETERS e_program,e_message,e_source,e_lineno,e_error
  1690. ON ERROR
  1691. m.e_source = ALLTRIM(m.e_source)
  1692. DO CASE
  1693. CASE m.e_error = 1707     && CDX not found.  Ignore it.
  1694.    RETURN
  1695. OTHERWISE
  1696.    DO alert WITH 'Line No.: '+ALLTRIM(STR(m.e_lineno,5))+';' ;
  1697.       +'Program: '+m.e_program +';' ;
  1698.       +'  Error: '+m.e_message +';' ;
  1699.       +' Source: '+IIF(LEN(m.e_source)<50,;
  1700.       m.e_source,SUBSTR(m.e_source,1,50)+'...')
  1701.  
  1702.    DO close_up
  1703. ENDCASE
  1704. RETURN
  1705.  
  1706. PROCEDURE appescape
  1707. * Simple ON ESCAPE routine for FoxApp application
  1708.  
  1709. PARAMETERS e_program,e_message,e_source,e_lineno,e_error
  1710. WAIT WINDOW "Escape pressed.  FoxApp is terminating." NOWAIT
  1711. =INKEY(1.5)
  1712. m.m_quitting = .T.
  1713. * Enable the Window pad
  1714. SET SKIP OF PAD _msm_windo OF _msysmenu .F.
  1715.  
  1716. CLEAR READ
  1717. DO close_up
  1718. RETURN
  1719.  
  1720. FUNCTION whatstyle
  1721. PARAMETER m.stylenum
  1722. IF NOT EMPTY(m.stylenum)
  1723.    DO CASE
  1724.    CASE m.stylenum = 1
  1725.       RETURN "B"
  1726.    CASE m.stylenum = 2
  1727.       RETURN "I"
  1728.    CASE m.stylenum = 3
  1729.       RETURN "BI"
  1730.    ENDCASE
  1731. ELSE
  1732.    RETURN ""
  1733. ENDIF
  1734.  
  1735.  
  1736.  
  1737.  
  1738. *       ╓─────────────────────────────────────────────────────────╖
  1739. *       ║                                                         ║
  1740. *       ║ _QDL0OOZZO           m.addscx VALID                     ║
  1741. *       ║                                                         ║
  1742. *       ║ Function Origin:                                        ║
  1743. *       ║                                                         ║
  1744. *       ║ From Platform:       Windows                            ║
  1745. *       ║ From Screen:         APPSCX,     Record Number:    2    ║
  1746. *       ║ Variable:            m.addscx                           ║
  1747. *       ║ Called By:           VALID Clause                       ║
  1748. *       ║ Snippet Number:      1                                  ║
  1749. *       ║                                                         ║
  1750. *       ╙─────────────────────────────────────────────────────────╜
  1751. *
  1752. FUNCTION _qdl0oozzo     &&  m.addscx VALID
  1753. #REGION 1
  1754. IF EMPTY(m.scxname)
  1755.    m.scxname = PUTFILE('Screen file name','','SCX')
  1756.    IF EMPTY(m.scxname)
  1757.       m.scxname = 'UNTITLED.SCX'
  1758.    ENDIF
  1759. ELSE
  1760.    IF FILE(m.scxname)
  1761.       MODIFY SCREEN (m.scxname)
  1762.    ELSE
  1763.       DO createscx
  1764.    ENDIF
  1765. ENDIF
  1766. SHOW GETS
  1767. RETURN .T.
  1768.  
  1769.  
  1770. *       ╓─────────────────────────────────────────────────────────╖
  1771. *       ║                                                         ║
  1772. *       ║ _QDL0OP0HZ           m.dbfname WHEN                     ║
  1773. *       ║                                                         ║
  1774. *       ║ Function Origin:                                        ║
  1775. *       ║                                                         ║
  1776. *       ║ From Platform:       Windows                            ║
  1777. *       ║ From Screen:         APPSCX,     Record Number:    9    ║
  1778. *       ║ Variable:            m.dbfname                          ║
  1779. *       ║ Called By:           WHEN Clause                        ║
  1780. *       ║ Snippet Number:      2                                  ║
  1781. *       ║                                                         ║
  1782. *       ╙─────────────────────────────────────────────────────────╜
  1783. *
  1784. FUNCTION _qdl0op0hz     &&  m.dbfname WHEN
  1785. #REGION 1
  1786. m.origname = m.dbfname
  1787. m.dbfname  = PADR(m.dbfname,m.apppathlen)
  1788. m.skipdbfbut = .T.
  1789. SHOW GETS
  1790. SET CURSOR ON
  1791. RETURN .T.
  1792.  
  1793.  
  1794. *       ╓─────────────────────────────────────────────────────────╖
  1795. *       ║                                                         ║
  1796. *       ║ DBFVALID           m.dbfname VALID                      ║
  1797. *       ║                                                         ║
  1798. *       ║ Function Origin:                                        ║
  1799. *       ║                                                         ║
  1800. *       ║ From Platform:       Windows                            ║
  1801. *       ║ From Screen:         APPSCX,     Record Number:    9    ║
  1802. *       ║ Variable:            m.dbfname                          ║
  1803. *       ║ Called By:           VALID Clause                       ║
  1804. *       ║ Snippet Number:      3                                  ║
  1805. *       ║                                                         ║
  1806. *       ╙─────────────────────────────────────────────────────────╜
  1807. *
  1808. FUNCTION DBFVALID     &&  m.dbfname VALID
  1809. #REGION 1
  1810. m.dbfname = UPPER(ALLTRIM(m.dbfname))
  1811. IF m.dbfname == m.origname
  1812.    * do nothing--make sure comparison is "==" however.
  1813. ELSE
  1814.    * Database name changed.  Check resource file again.
  1815.    rsc_check = .F.
  1816. ENDIF
  1817.  
  1818. SET CURSOR OFF
  1819.  
  1820. IF !EMPTY(m.dbfname)
  1821.    m.dbfname = FULLPATH(m.dbfname)
  1822. ENDIF
  1823.  
  1824. SHOW GETS
  1825. DO CASE
  1826. CASE EMPTY(juststem(m.dbfname)) AND !EMPTY(m.dbfname)
  1827.    WAIT WINDOW "Invalid database name."
  1828.    RETURN 0
  1829. CASE (EMPTY(justext(m.dbfname)) OR justext(m.dbfname) = 'DBF')   ;
  1830.       AND (justfname(m.dbfname) >= 'A' AND justfname(m.dbfname) <= 'Z') ;
  1831.       AND LEN(justfname(m.dbfname))<=1
  1832.    * Don't allow single letter database names--they get confused with areas
  1833.    WAIT WINDOW "Invalid database name."
  1834.    RETURN 0
  1835. CASE INLIST(justext(m.dbfname),'SCX','SCT','SPR')
  1836.    WAIT WINDOW "A screen file name is not allowed here."
  1837.    RETURN 0
  1838. CASE INLIST(justext(m.dbfname),'MNX','MNT','MPR')
  1839.    WAIT WINDOW "A menu file name is not allowed here."
  1840.    RETURN 0
  1841. OTHERWISE
  1842.    IF !('.' $ justfname(m.dbfname)) AND !EMPTY(m.dbfname)
  1843.       m.dbfname = forceext(m.dbfname,'DBF')
  1844.    ENDIF
  1845.  
  1846.    dbfname = UPPER(ALLTRIM(m.dbfname))
  1847.    IF !EMPTY(m.dbfname)
  1848.       m.dbfalias = opendbf(m.dbfname)
  1849.       IF EMPTY(m.scxname)
  1850.          m.scxname = forceext(m.dbfname,'SCX')
  1851.       ENDIF
  1852.    ENDIF
  1853.  
  1854.    skipdbfbut = .F.
  1855.  
  1856.    * Poke this database into the first position of DBFLIST
  1857.    IF TYPE('DBFLIST') <> 'U'
  1858.       dbflist[1,m.cstemnum] = juststem(m.dbfname)
  1859.    ENDIF
  1860.  
  1861.    SHOW GETS
  1862.    RETURN .T.
  1863. ENDCASE
  1864.  
  1865.  
  1866. *       ╓─────────────────────────────────────────────────────────╖
  1867. *       ║                                                         ║
  1868. *       ║ _QDL0OP103           m.adddbf VALID                     ║
  1869. *       ║                                                         ║
  1870. *       ║ Function Origin:                                        ║
  1871. *       ║                                                         ║
  1872. *       ║ From Platform:       Windows                            ║
  1873. *       ║ From Screen:         APPSCX,     Record Number:   10    ║
  1874. *       ║ Variable:            m.adddbf                           ║
  1875. *       ║ Called By:           VALID Clause                       ║
  1876. *       ║ Snippet Number:      4                                  ║
  1877. *       ║                                                         ║
  1878. *       ╙─────────────────────────────────────────────────────────╜
  1879. *
  1880. FUNCTION _qdl0op103     &&  m.adddbf VALID
  1881. #REGION 1
  1882. IF EMPTY(m.dbfname)
  1883.    m.dbfname = PUTFILE('Database name:','','DBF')
  1884.    IF EMPTY(m.dbfname)
  1885.       RETURN .F.   && don't do anything
  1886.    ENDIF
  1887. ENDIF
  1888. IF !FILE(m.dbfname)
  1889.    * This window controls the colors used by CREATE
  1890.    DEFINE WINDOW mywin FROM INT((srow()-20)/2),INT((scol()-71)/2);
  1891.       TO INT((srow()-20)/2)+19,INT((scol()-71)/2)+70 ;
  1892.       FLOAT CLOSE SHADOW MINIMIZE SYSTEM COLOR SCHEME 8
  1893.    ACTIVATE WINDOW mywin NOSHOW
  1894.  
  1895.    CREATE (m.dbfname)
  1896.    DEACTIVATE WINDOW mywin
  1897.    RELEASE WINDOW mywin
  1898. ELSE    && this shouldn't be possible since the control should be disabled
  1899.    m.dname = opendbf(m.dbfname)
  1900.    IF !EMPTY(m.dname)
  1901.       MODIFY STRUCTURE
  1902.    ENDIF
  1903.    SHOW GET adddbf DISABLE
  1904.    SHOW GET moddbf ENABLE
  1905. ENDIF
  1906. SHOW GETS
  1907. RETURN .T.
  1908.  
  1909.  
  1910. *       ╓─────────────────────────────────────────────────────────╖
  1911. *       ║                                                         ║
  1912. *       ║ _QDL0OP18D           m.moddbf VALID                     ║
  1913. *       ║                                                         ║
  1914. *       ║ Function Origin:                                        ║
  1915. *       ║                                                         ║
  1916. *       ║ From Platform:       Windows                            ║
  1917. *       ║ From Screen:         APPSCX,     Record Number:   11    ║
  1918. *       ║ Variable:            m.moddbf                           ║
  1919. *       ║ Called By:           VALID Clause                       ║
  1920. *       ║ Snippet Number:      5                                  ║
  1921. *       ║                                                         ║
  1922. *       ╙─────────────────────────────────────────────────────────╜
  1923. *
  1924. FUNCTION _qdl0op18d     &&  m.moddbf VALID
  1925. #REGION 1
  1926. IF !EMPTY(m.dbfname)
  1927.    IF !EMPTY(opendbf(m.dbfname))
  1928.       MODIFY STRUCTURE
  1929.    ELSE
  1930.       SHOW GET moddbf DISABLE
  1931.       RETURN -2
  1932.    ENDIF
  1933. ENDIF
  1934. RETURN .T.
  1935.  
  1936.  
  1937. *       ╓─────────────────────────────────────────────────────────╖
  1938. *       ║                                                         ║
  1939. *       ║ _QDL0OP1FE           m.Listdbf WHEN                     ║
  1940. *       ║                                                         ║
  1941. *       ║ Function Origin:                                        ║
  1942. *       ║                                                         ║
  1943. *       ║ From Platform:       Windows                            ║
  1944. *       ║ From Screen:         APPSCX,     Record Number:   12    ║
  1945. *       ║ Variable:            m.Listdbf                          ║
  1946. *       ║ Called By:           WHEN Clause                        ║
  1947. *       ║ Snippet Number:      6                                  ║
  1948. *       ║                                                         ║
  1949. *       ╙─────────────────────────────────────────────────────────╜
  1950. *
  1951. FUNCTION _qdl0op1fe     &&  m.Listdbf WHEN
  1952. #REGION 1
  1953. origname = ALLTRIM(UPPER(m.dbfname))
  1954.  
  1955.  
  1956. *       ╓─────────────────────────────────────────────────────────╖
  1957. *       ║                                                         ║
  1958. *       ║ _QDL0OP1IK           m.Listdbf VALID                    ║
  1959. *       ║                                                         ║
  1960. *       ║ Function Origin:                                        ║
  1961. *       ║                                                         ║
  1962. *       ║ From Platform:       Windows                            ║
  1963. *       ║ From Screen:         APPSCX,     Record Number:   12    ║
  1964. *       ║ Variable:            m.Listdbf                          ║
  1965. *       ║ Called By:           VALID Clause                       ║
  1966. *       ║ Snippet Number:      7                                  ║
  1967. *       ║                                                         ║
  1968. *       ╙─────────────────────────────────────────────────────────╜
  1969. *
  1970. FUNCTION _qdl0op1ik     &&  m.Listdbf VALID
  1971. #REGION 1
  1972. IF UPPER(ALLTRIM(m.dbfname)) <> UPPER(ALLTRIM(origname))
  1973.    rsc_check = .F.
  1974. ENDIF
  1975.  
  1976. origname = m.dbfname
  1977. CLOSE DATABASES
  1978. dbfname = GETFILE('DBF','Database name:')
  1979. IF EMPTY(m.dbfname)
  1980.    dbfname = m.origname
  1981. ELSE
  1982.    =opendbf(m.dbfname)
  1983.    IF EMPTY(m.scxname)
  1984.       scxname = forceext(m.dbfname,'SCX')
  1985.    ENDIF
  1986. ENDIF
  1987.  
  1988. * Poke this database into the first position of DBFLIST
  1989. IF TYPE('DBFLIST') <> 'U'
  1990.    dbflist[1,m.cstemnum] = juststem(m.dbfname)
  1991. ENDIF
  1992.  
  1993. SHOW GETS
  1994. RETURN .T.
  1995.  
  1996.  
  1997. *       ╓─────────────────────────────────────────────────────────╖
  1998. *       ║                                                         ║
  1999. *       ║ _QDL0OP1Q5           m.other VALID                      ║
  2000. *       ║                                                         ║
  2001. *       ║ Function Origin:                                        ║
  2002. *       ║                                                         ║
  2003. *       ║ From Platform:       Windows                            ║
  2004. *       ║ From Screen:         APPSCX,     Record Number:   13    ║
  2005. *       ║ Variable:            m.other                            ║
  2006. *       ║ Called By:           VALID Clause                       ║
  2007. *       ║ Snippet Number:      8                                  ║
  2008. *       ║                                                         ║
  2009. *       ╙─────────────────────────────────────────────────────────╜
  2010. *
  2011. FUNCTION _qdl0op1q5     &&  m.other VALID
  2012. #REGION 1
  2013. DO opendbf WITH m.dbfname
  2014.  
  2015. DO dbfselec.spr
  2016.  
  2017. * Leave the main database open when through with picking subsidiary
  2018. *   databases.
  2019. m.dbfalias = opendbf(m.dbfname)
  2020. IF relateddbfs()
  2021.    SHOW GET arrange ENABLE
  2022. ELSE
  2023.    SHOW GET arrange DISABLE
  2024. ENDIF
  2025.  
  2026. *       ╓─────────────────────────────────────────────────────────╖
  2027. *       ║                                                         ║
  2028. *       ║ _QDL0OP1Y3           scxname WHEN                       ║
  2029. *       ║                                                         ║
  2030. *       ║ Function Origin:                                        ║
  2031. *       ║                                                         ║
  2032. *       ║ From Platform:       Windows                            ║
  2033. *       ║ From Screen:         APPSCX,     Record Number:   14    ║
  2034. *       ║ Variable:            scxname                            ║
  2035. *       ║ Called By:           WHEN Clause                        ║
  2036. *       ║ Snippet Number:      9                                  ║
  2037. *       ║                                                         ║
  2038. *       ╙─────────────────────────────────────────────────────────╜
  2039. *
  2040. FUNCTION _qdl0op1y3     &&  scxname WHEN
  2041. #REGION 1
  2042. m.scxname = PADR(m.scxname,m.apppathlen)
  2043. SHOW GET modscx DISABLE
  2044. SHOW GET addscx DISABLE
  2045. SET CURSOR ON
  2046. RETURN .T.
  2047.  
  2048.  
  2049. *       ╓─────────────────────────────────────────────────────────╖
  2050. *       ║                                                         ║
  2051. *       ║ _QDL0OP21X           scxname VALID                      ║
  2052. *       ║                                                         ║
  2053. *       ║ Function Origin:                                        ║
  2054. *       ║                                                         ║
  2055. *       ║ From Platform:       Windows                            ║
  2056. *       ║ From Screen:         APPSCX,     Record Number:   14    ║
  2057. *       ║ Variable:            scxname                            ║
  2058. *       ║ Called By:           VALID Clause                       ║
  2059. *       ║ Snippet Number:      10                                 ║
  2060. *       ║                                                         ║
  2061. *       ╙─────────────────────────────────────────────────────────╜
  2062. *
  2063. FUNCTION _qdl0op21x     &&  scxname VALID
  2064. #REGION 1
  2065. SET CURSOR OFF
  2066. IF !EMPTY(m.scxname)
  2067.    m.scxname = FULLPATH(m.scxname)
  2068. ENDIF
  2069.  
  2070. scxname = ALLTRIM(m.scxname)
  2071. IF !('.' $ justfname(m.scxname)) AND !EMPTY(m.scxname)
  2072.    scxname = forceext(m.scxname,'SCX')
  2073. ENDIF
  2074. m.scxname = UPPER(m.scxname)
  2075.  
  2076. DO CASE
  2077. CASE EMPTY(juststem(m.scxname)) AND !EMPTY(m.scxname)
  2078.    WAIT WINDOW "Invalid screen name."
  2079.    RETURN 0
  2080. ENDCASE
  2081. SHOW GETS
  2082.  
  2083.  
  2084. *       ╓─────────────────────────────────────────────────────────╖
  2085. *       ║                                                         ║
  2086. *       ║ _QDL0OP29J           m.modscx WHEN                      ║
  2087. *       ║                                                         ║
  2088. *       ║ Function Origin:                                        ║
  2089. *       ║                                                         ║
  2090. *       ║ From Platform:       Windows                            ║
  2091. *       ║ From Screen:         APPSCX,     Record Number:   15    ║
  2092. *       ║ Variable:            m.modscx                           ║
  2093. *       ║ Called By:           WHEN Clause                        ║
  2094. *       ║ Snippet Number:      11                                 ║
  2095. *       ║                                                         ║
  2096. *       ╙─────────────────────────────────────────────────────────╜
  2097. *
  2098. FUNCTION _qdl0op29j     &&  m.modscx WHEN
  2099. #REGION 1
  2100. IF !FILE(m.scxname)
  2101.    WAIT WINDOW 'Creating screen file' NOWAIT
  2102.    DO createscx
  2103. ENDIF
  2104. RETURN .T.
  2105.  
  2106.  
  2107. *       ╓─────────────────────────────────────────────────────────╖
  2108. *       ║                                                         ║
  2109. *       ║ _QDL0OP2D6           m.modscx VALID                     ║
  2110. *       ║                                                         ║
  2111. *       ║ Function Origin:                                        ║
  2112. *       ║                                                         ║
  2113. *       ║ From Platform:       Windows                            ║
  2114. *       ║ From Screen:         APPSCX,     Record Number:   15    ║
  2115. *       ║ Variable:            m.modscx                           ║
  2116. *       ║ Called By:           VALID Clause                       ║
  2117. *       ║ Snippet Number:      12                                 ║
  2118. *       ║                                                         ║
  2119. *       ╙─────────────────────────────────────────────────────────╜
  2120. *
  2121. FUNCTION _qdl0op2d6     &&  m.modscx VALID
  2122. #REGION 1
  2123. IF FILE(m.scxname) AND !EMPTY(m.scxname)
  2124.    MODIFY SCREEN (m.scxname)
  2125. ELSE
  2126.    WAIT WINDOW "Creating screen" NOWAIT
  2127.    DO createscx
  2128. ENDIF
  2129. SHOW GET addscx DISABLE
  2130. SHOW GETS
  2131. RETURN .T.
  2132.  
  2133.  
  2134. *       ╓─────────────────────────────────────────────────────────╖
  2135. *       ║                                                         ║
  2136. *       ║ _QDL0OP2JN           m.Listscx VALID                    ║
  2137. *       ║                                                         ║
  2138. *       ║ Function Origin:                                        ║
  2139. *       ║                                                         ║
  2140. *       ║ From Platform:       Windows                            ║
  2141. *       ║ From Screen:         APPSCX,     Record Number:   16    ║
  2142. *       ║ Variable:            m.Listscx                          ║
  2143. *       ║ Called By:           VALID Clause                       ║
  2144. *       ║ Snippet Number:      13                                 ║
  2145. *       ║                                                         ║
  2146. *       ╙─────────────────────────────────────────────────────────╜
  2147. *
  2148. FUNCTION _qdl0op2jn     &&  m.Listscx VALID
  2149. #REGION 1
  2150. origname = scxname
  2151. scxname = GETFILE('SCX','Screen file name:')
  2152. IF EMPTY(scxname)
  2153.    scxname = origname
  2154. ENDIF
  2155. SHOW GETS
  2156. RETURN .T.
  2157.  
  2158.  
  2159. *       ╓─────────────────────────────────────────────────────────╖
  2160. *       ║                                                         ║
  2161. *       ║ _QDL0OP2QF           m.generate VALID                   ║
  2162. *       ║                                                         ║
  2163. *       ║ Function Origin:                                        ║
  2164. *       ║                                                         ║
  2165. *       ║ From Platform:       Windows                            ║
  2166. *       ║ From Screen:         APPSCX,     Record Number:   17    ║
  2167. *       ║ Variable:            m.generate                         ║
  2168. *       ║ Called By:           VALID Clause                       ║
  2169. *       ║ Snippet Number:      14                                 ║
  2170. *       ║                                                         ║
  2171. *       ╙─────────────────────────────────────────────────────────╜
  2172. *
  2173. FUNCTION _qdl0op2qf     &&  m.generate VALID
  2174. #REGION 1
  2175. #define fa_european 0
  2176. PRIVATE m.win_string, m.dname, m.quoted, m.sc_file, m.i, m.j
  2177. IF m.generate = 1
  2178.  
  2179.    IF EMPTY(m.dbfname) OR !FILE(m.dbfname)
  2180.       SHOW GETS
  2181.       RETURN -9   && bounce out of generate and return to the dbfname field
  2182.    ENDIF
  2183.  
  2184.    SET CURSOR OFF
  2185.  
  2186.    * Create a default input screen if the one the user specified doesn't
  2187.    * exist.
  2188.    IF EMPTY(m.scxname)
  2189.       m.scxname = forceext(m.dbfname,'SCX')
  2190.    ENDIF
  2191.    IF !FILE(m.scxname)
  2192.       DO createscx
  2193.    ENDIF
  2194.  
  2195.    CLOSE DATABASES
  2196.    m.scxname  = UPPER(ALLTRIM(m.scxname))
  2197.    m.dbfname  = UPPER(ALLTRIM(m.dbfname))
  2198.    m.mnuname  = UPPER(ALLTRIM(m.mnuname))
  2199.  
  2200.    SET CURSOR ON
  2201.  
  2202.    * Note the current directory and path
  2203.    m.c_path = SET('DEFAULT') + CURDIR()
  2204.  
  2205.    m.appfile = forceext(m.scxname,'APP')
  2206.    m.userapp_dir = justpath(m.scxname)
  2207.    SET DEFAULT TO (m.userapp_dir)
  2208.  
  2209.    m.mpoint = SET("POINT")
  2210.    SET POINT TO "."
  2211.  
  2212.    valid_name = .F.
  2213.    DO WHILE !valid_name
  2214.       m.appfile = PUTFILE('Name your application:',forceext(m.appfile,'APP'),'APP')
  2215.       DO CASE
  2216.       CASE UPPER(ALLTRIM(justfname(m.appfile))) == 'FOXAPP.APP'
  2217.          DO ALERT WITH "I named my program FoxApp.  You have to name yours something else."
  2218.          m.valid_name = .F.
  2219.       OTHERWISE
  2220.          valid_name = .T.
  2221.       ENDCASE
  2222.    ENDDO
  2223.  
  2224.    IF EMPTY(m.appfile)   && user pressed 'cancel'.  Return to top screen.
  2225.       SHOW GETS
  2226.    ELSE                  && time to create the APP
  2227.       SET CONSOLE OFF
  2228.  
  2229.       * Store relations into resource file if needed
  2230.       IF TYPE("DBFLIST") <> "U" AND !m.rsc_stored AND m.storersc
  2231.          WAIT WINDOW "Saving database relations and window positions." NOWAIT
  2232.          DO putdbflist WITH dbflist[1,1]
  2233.       ENDIF
  2234.  
  2235.       m.win_string = "Generating application "+PROPER(juststem(m.appfile))+'.'
  2236.       WAIT WINDOW m.win_string NOWAIT
  2237.       HIDE WINDOW (WOUTPUT())
  2238.  
  2239.       * tmfname is the name of the scaffolding program that pulls all the
  2240.       * FoxApp application modules together.
  2241.       tmfname = addbs(justpath(m.appfile))+'scaffold.prg'
  2242.       SET TEXTMERGE TO (m.tmfname)
  2243.  
  2244.       SET TEXTMERGE ON
  2245.  
  2246.       \\*       ╓─────────────────────────────────────────────────────────╖
  2247.       \*       ║                                                         ║
  2248.       \*       ║ <<DATE()>>               scaffold.prg            <<TIME()>> ║
  2249.       \*       ║                                                         ║
  2250.       \*       ╟─────────────────────────────────────────────────────────╢
  2251.       \*       ║                                                         ║
  2252.       \*       ║ Description:                                            ║
  2253.       \*       ║ This program was automatically generated by FoxApp.     ║
  2254.       \*       ║                                                         ║
  2255.       \*       ╙─────────────────────────────────────────────────────────╜
  2256.       \*
  2257.       \*       To run this application, type DO <<UPPER(justfname(m.appfile))>>
  2258.       \*
  2259.       \* Set up runtime environment
  2260.       \CREATE VIEW appview
  2261.       \SET TALK OFF
  2262.       \PUSH MENU _msysmenu
  2263.       \PUSH KEY CLEAR
  2264.       \fxapp_error = ON('ERROR')
  2265.       \fxapp_esc   = ON('ESCAPE')
  2266.  
  2267.       \SET SAFETY OFF
  2268.       \SAVE MACROS TO foxapp
  2269.       \SET SAFETY ON
  2270.       \SET DELETED ON
  2271.       \SET ESCAPE OFF
  2272.       \SET STEP OFF
  2273.       \SET ECHO OFF
  2274.       \SET PROCEDURE TO appproc.prg
  2275.       \SET CURSOR ON
  2276.  
  2277.       \m.set_point = SET("POINT")
  2278.  
  2279.       #IF fa_european
  2280.       \SET POINT TO ","
  2281.       #endif
  2282.  
  2283.       \CLOSE DATABASES
  2284.       \ON ERROR DO apperror WITH PROGRAM(),MESSAGE(),MESSAGE(1),LINENO(),ERROR()
  2285.       \
  2286.       \IF _WINDOWS OR _MAC
  2287.       \   * Store current screen font and set it to MS Sans Serif.  This ensures that
  2288.       \   * functions like SROWS() and SCOLS() return values we can use.
  2289.       \   m.scrn_font   = WFONT(1,"")
  2290.       \   m.scrn_fsize  = WFONT(2,"")
  2291.       \   m.scrn_fstyle = WFONT(3,"")
  2292.       \   MODIFY WINDOW SCREEN FONT "MS Sans Serif",8 STYLE "B"
  2293.       \ENDIF
  2294.       \
  2295.       \IF TYPE("BAILOUT") <> "U"
  2296.       \   RELEASE bailout
  2297.       \ENDIF
  2298.       \IF TYPE("DBFNAME") <> "U"
  2299.       \   RELEASE dbfname
  2300.       \ENDIF
  2301.       \IF TYPE("WIN_NAME") <> "U"
  2302.       \   RELEASE win_name
  2303.       \ENDIF
  2304.       \IF TYPE("FILT_EXPR") <> "U"
  2305.       \   RELEASE filt_expr
  2306.       \ENDIF
  2307.       \IF TYPE("SRCHTERM") <> "U"
  2308.       \   RELEASE srchterm
  2309.       \ENDIF
  2310.       IF regen
  2311.          \regen = .T.   && use SPR/MPR files instead of PRGs
  2312.          \EXTERNAL SCREEN    getdest, getorder, appabout, ;
  2313.          \                    appsrch, prtopts, prtsetup
  2314.       ELSE
  2315.          \regen = .F.
  2316.          \EXTERNAL PROCEDURE getdest, getorder, appabout, ;
  2317.          \                    appsrch, prtopts, prtsetup
  2318.       ENDIF
  2319.       \
  2320.       \PUBLIC bailout, dbfname, win_name, filt_expr, srchterm
  2321.       \m.bailout = .F.
  2322.       \m.dbfname = "<<m.dbfname>>"     && database name
  2323.       \m.qprpath = justpath(m.dbfname) && query file path
  2324.       \m.filt_expr = ""                && filter expression, if any
  2325.       \m.srchterm = SPACE(60)          && search term
  2326.       \
  2327.       \* Define constants for addressing DBFLIST
  2328.       \m.numareas   = <<m.numareas>>
  2329.       \m.numcols    = <<m.numcols>>
  2330.       \m.cstemnum   = <<m.cstemnum>>
  2331.       \m.relstrnum  = <<m.relstrnum>>
  2332.       \m.pfldnum    = <<m.pfldnum>>
  2333.       \m.cfldnum    = <<m.cfldnum>>
  2334.       \m.cdbfnum    = <<m.cdbfnum>>
  2335.       \m.pdbfnum    = <<m.pdbfnum>>
  2336.       \m.srownum    = <<m.srownum>>
  2337.       \m.scolnum    = <<m.scolnum>>
  2338.       \m.erownum    = <<m.erownum>>
  2339.       \m.ecolnum    = <<m.ecolnum>>
  2340.       \m.arranged   = <<m.arranged>>
  2341.       \m.thefont    = <<m.thefont>>
  2342.       \m.cascadenum = <<m.cascadenum>>
  2343.       \m.ctrlrow    = <<INT(m.ctrlrow)>>
  2344.       \m.ctrlcol    = <<INT(m.ctrlcol)>>
  2345.       \m.nextdbf    = <<m.nextdbf>>
  2346.       \DO DefineDbf                    && define the DBFLIST array
  2347.       \
  2348.       \
  2349.       \* Summon the main application menu
  2350.       _mname = forceext(juststem(m.mnuname),IIF(regen,'MPR','PRG'))
  2351.       \DO <<_mname>>
  2352.       \
  2353.       \* Open the main database
  2354.       \m.stem = juststem(m.dbfname)
  2355.       \IF USED(m.stem)
  2356.       \   SELECT (m.stem)
  2357.       \ELSE
  2358.       \   SELECT 0
  2359.       \   IF !FILE(m.dbfname)
  2360.       \      m.dbfname = GETFILE('DBF','Please locate the '+JustStem(m.dbfname)+' database')
  2361.       \   ENDIF
  2362.       \   IF EMPTY(m.dbfname) OR !FILE(m.dbfname)
  2363.       \      DO alert WITH "The "+m.stem+" database could not be found."
  2364.       \      DO cleanup
  2365.       \      RETURN
  2366.       \   ELSE
  2367.       \      USE (m.dbfname)
  2368.       \   ENDIF
  2369.       \ENDIF
  2370.       \* Make sure the index exists and is hooked up
  2371.       \IF EMPTY(CDX(1))
  2372.       \   IF !FILE(forceext(m.dbfname,'CDX'))
  2373.       \      DO invert WITH m.dbfname
  2374.       \   ELSE
  2375.       \      SET INDEX TO (forceext(m.dbfname,'CDX'))
  2376.       \   ENDIF
  2377.       \ENDIF
  2378.       \SET ORDER TO 1
  2379.       \
  2380.       \IF RECCOUNT() = 0
  2381.       \   APPEND BLANK
  2382.       \ELSE
  2383.       \   IF RECCOUNT() < 10
  2384.       \      COUNT FOR !DELETED() TO notdel
  2385.       \      IF m.notdel = 0
  2386.       \         APPEND BLANK  && all records were deleted!
  2387.       \      ENDIF
  2388.       \   ENDIF
  2389.       \ENDIF
  2390.       \GOTO TOP
  2391.       \
  2392.       \CLEAR
  2393.  
  2394.       sc_file = LOWER(forceext(juststem(m.scxname),'SPR'))
  2395.  
  2396.       * Force user screen into a window and figure out its size
  2397.       m.vcoord = 0
  2398.       m.hcoord = 0
  2399.       IF FILE(m.scxname)
  2400.          SELECT 0
  2401.          USE (m.scxname) ALIAS scrnfile
  2402.  
  2403.          LOCATE FOR objtype == 1 ;
  2404.             AND UPPER(ALLTRIM(platform)) == m.app_platform
  2405.          IF FOUND()
  2406.  
  2407.             * Make sure that user screen goes into a window
  2408.             IF EMPTY(scrnfile.name)
  2409.                win_msg = "Putting "+juststem(m.scxname)+" screen into window."
  2410.                WAIT WINDOW win_msg TIMEOUT 1
  2411.                m.scrn_face  = scrnfile.fontface
  2412.                m.scrn_size  = scrnfile.fontsize
  2413.                m.scrn_style = scrnfile.fontstyle
  2414.                REPLACE scrnfile.name WITH juststem(m.appfile), ;
  2415.                   scrnfile.style WITH 2,                  ;
  2416.                   scrnfile.border WITH 1,                 ;
  2417.                   scrnfile.center WITH .F.,               ;
  2418.                   scrnfile.vpos WITH 1,                   ;
  2419.                   scrnfile.hpos WITH 3
  2420.                WAIT CLEAR
  2421.             ENDIF
  2422.             win_name = UPPER(ALLTRIM(scrnfile.name))
  2423.  
  2424.             * Figure out where to put the screen and control panel
  2425.             IF relateddbfs()
  2426.                m.scrn_face  = scrnfile.fontface
  2427.                m.scrn_size  = scrnfile.fontsize
  2428.                m.scrn_style = scrnfile.fontstyle
  2429.  
  2430.                m.vcoord = m.ctrlrow   && bottom of the screen
  2431.                m.hcoord = m.ctrlcol
  2432.                REPLACE scrnfile.center   WITH .F.
  2433.                IF dbflist[1,m.arranged] = 'Y'
  2434.                   REPLACE scrnfile.vpos WITH VAL(dbflist[1,m.srownum])
  2435.                   REPLACE scrnfile.hpos WITH VAL(dbflist[1,m.scolnum])
  2436.                ELSE
  2437.                   * Set default placement of browse windows if user hasn't arranged them
  2438.                   FOR m.i = 2 to m.numareas
  2439.                      * Position it below the previous browse or screen
  2440.                      m.rnum = MIN(VAL(dbflist[m.i-1,m.srownum]);
  2441.                         + VAL(dbflist[m.i-1,m.erownum]) + 2.5, SROWS())
  2442.                      dbflist[m.i,m.srownum] = ALLTRIM(STR(m.rnum,4))
  2443.                      * Center it horizontally
  2444.                      m.cnum = (SCOLS() - VAL(dbflist[m.i,m.ecolnum])) / 2
  2445.                      dbflist[m.i,m.scolnum] = ALLTRIM(STR(m.cnum,4))
  2446.                   ENDFOR
  2447.                ENDIF
  2448.             ELSE
  2449.                * Use the screen coordinates in the SCX file to figure out
  2450.                * where to put the control panel
  2451.                IF scrnfile.center
  2452.                   m.vcoord = (SROWS() + scrnfile.height) / 2 + 2
  2453.                ELSE
  2454.                   m.vcoord = scrnfile.vpos + scrnfile.height + 1
  2455.                ENDIF
  2456.                m.hcoord = INT((SCOLS()-tranfont(73,6,"MS Sans Serif",8,"B"))/2)
  2457.                IF m.vcoord + 3 > SROWS()
  2458.                   m.vcoord = SROWS()-3
  2459.                ENDIF
  2460.                m.vcoord = INT(m.vcoord)
  2461.                m.hcoord = INT(m.hcoord)
  2462.             ENDIF
  2463.             REPLACE FLOAT WITH .T., CLOSE WITH .T.
  2464.  
  2465.             * Force a select of the dbfname database whenever the screen
  2466.             * is activated.  This is necessary for the 1-to-many operations,
  2467.             * where clicking on a browse window will select some other
  2468.             * database.  We have to reselect dbfname when the user clicks in
  2469.             * on the dbfname screen.  This code stuffs a "SELECT dbfname"
  2470.             * into the activate snippet of the user screen, but only if there
  2471.             * isn't one there already.
  2472.             found_line = .F.
  2473.  
  2474.             * First scan for a previous FoxApp inserted line
  2475.             _MLINE = 0
  2476.             m.numlines = MEMLINES(scrnfile.activate)
  2477.             m.i = 1
  2478.             newact = ""
  2479.             DO WHILE m.i <= m.numlines
  2480.                m.theline   = MLINE(scrnfile.activate,1,_MLINE)
  2481.                m.theline = ALLTRIM(UPPER(m.theline))
  2482.                DO CASE
  2483.                CASE UPPER("SELECT ") $ theline AND "**FOXAPP**" $ theline
  2484.                   * We found a previous FoxApp 2.5 insert.  Is it the right one?
  2485.                   * It might not be if the user renamed the database.
  2486.                   IF UPPER("SELECT "+juststem(m.dbfname))+" " $ m.theline
  2487.                      m.found_line = .T.
  2488.                      m.newact = m.newact + CHR(13) + CHR(10) + m.theline
  2489.                   ELSE
  2490.                      * FoxApp statement, but the wrong one.  Ignore it.
  2491.                   ENDIF
  2492.                CASE "THE FOLLOWING LINE WAS ADDED BY FOXAPP" $ theline
  2493.                   * FoxApp 2.0 insert.  Drop this comment and the line that
  2494.                   * follows it, unless the following line doesn't look like
  2495.                   * one of mine.  The insert should always be a SELECT
  2496.                   * statement.
  2497.                   m.theline   = MLINE(scrnfile.activate,1,_MLINE)
  2498.                   m.theline = ALLTRIM(UPPER(m.theline))
  2499.                   IF !("SELECT " $ m.theline)
  2500.                      newact = m.newact + CHR(13) + CHR(10) + m.theline
  2501.                   ENDIF
  2502.                OTHERWISE   && not a FoxApp statement
  2503.                   m.newact = m.newact + CHR(13) + CHR(10) + m.theline
  2504.                ENDCASE
  2505.                m.i = m.i + 1
  2506.             ENDDO
  2507.             IF !m.found_line
  2508.                m.newact = m.newact  ;
  2509.                   + CHR(13) + CHR(10) + "SELECT "+juststem(m.dbfname)+"   "+CHR(38)+CHR(38)+" Added by **FOXAPP**"
  2510.             ENDIF
  2511.             REPLACE scrnfile.activate WITH m.newact
  2512.             USE
  2513.          ENDIF
  2514.       ENDIF
  2515.  
  2516.  
  2517.       \m.win_name = "<<m.win_name>>"
  2518.       * This is the main loop to display the screen and any related browses.
  2519.       \DO WHILE !bailout
  2520.       \   * Set up any related databases
  2521.       \   DO setrelat
  2522.       \   * Display the main screen file
  2523.       \   DO <<m.sc_file>>
  2524.       \ENDDO
  2525.       \DO cleanup
  2526.       \RETURN
  2527.       \
  2528.       \
  2529.       \*******************************************************************
  2530.       \PROCEDURE cleanup
  2531.       \* Clean up after the application
  2532.       \SET PROCEDURE TO
  2533.       \CLOSE DATABASES
  2534.       \CLEAR WINDOWS
  2535.       \IF _WINDOWS OR _MAC
  2536.       \   MODIFY WINDOW SCREEN FONT m.scrn_font, m.scrn_fsize STYLE m.scrn_fstyle
  2537.       \ENDIF
  2538.  
  2539.       \IF SET('TALK') = 'ON'
  2540.       \   SET TALK OFF
  2541.       \   m.t_stat = 'ON'
  2542.       \ELSE
  2543.       \   m.t_stat = 'OFF'
  2544.       \ENDIF
  2545.       \SET TALK OFF
  2546.       \* Restore databases, indexes and environment
  2547.       \IF FILE("appview.vue")
  2548.       \   SET VIEW TO appview
  2549.       \   SET TALK OFF
  2550.       \   DELETE FILE appview.vue
  2551.       \ENDIF
  2552.  
  2553.       \IF FILE("foxapp.fky")
  2554.       \   RESTORE MACROS FROM foxapp
  2555.       \   DELETE FILE foxapp.fky
  2556.       \ENDIF
  2557.       \IF m.t_stat = "ON"
  2558.       \   SET TALK ON
  2559.       \ENDIF
  2560.  
  2561.       \SET POINT TO "&set_point"
  2562.       \POP KEY ALL
  2563.       \POP MENU _msysmenu
  2564.       \CLEAR PROGRAM
  2565.       \
  2566.       \*Restore original error and escape routines
  2567.       \IF TYPE('fxapp_error') = 'C'
  2568.       \   ON ERROR &fxapp_error
  2569.       \ENDIF
  2570.       \
  2571.       \IF TYPE('fxapp_esc') = 'C'
  2572.       \   ON ESCAPE &fxapp_esc
  2573.       \ENDIF
  2574.       \
  2575.  
  2576.       \SET SAFETY ON
  2577.       \RELEASE m.bailout, m.dbfname, m.win_name, m.filt_expr, m.srchterm, m.skipvar, m.act3
  2578.       \RELEASE dbflist
  2579.       \RETURN
  2580.  
  2581.       \
  2582.       \*******************************************************************
  2583.       \PROCEDURE setrelat
  2584.       \* This procedure opens subsidiary databases (if any) and establishes
  2585.       \* the relations between the main database and the subsidiary
  2586.       \* databases.  It will be empty if there are no subsidiary databases.
  2587.       IF TYPE("DBFLIST") <> "U"
  2588.          m.i = 2
  2589.          DO WHILE !EMPTY(dbflist[m.i,m.cstemnum]) AND dbflist[m.i,m.cstemnum] <> '\'
  2590.             m.b_font = dbflist[m.i,m.thefont]
  2591.             \SELECT <<m.i>>
  2592.             tagname = SUBSTR(dbflist[m.i,m.cfldnum],AT('.',dbflist[m.i,m.cfldnum])+1)
  2593.             \dname = "<<dbflist[m.i,m.cdbfnum]>>"
  2594.             \IF !FILE(m.dname)
  2595.             \   m.dname = GETFILE('DBF','Please locate the '+Juststem(m.dname)+ ' database:')
  2596.             \   IF EMPTY(m.dname) OR !FILE(m.dname)
  2597.             \      DO alert WITH "The "+ALLTRIM(m.dname+" database could not be found.")
  2598.             \      DO cleanup
  2599.             \      CANCEL
  2600.             \   ELSE
  2601.             \      SET PATH TO (SET('PATH') + ';' + Justpath(m.dname))
  2602.             \      dbflist[<<m.i>>,m.cdbfnum]  = m.dname
  2603.             \      dbflist[<<m.i>>,m.cstemnum] = juststem(m.dname)
  2604.             \   ENDIF
  2605.             \ENDIF
  2606.             \USE (m.dname) ALIAS <<dbflist[m.i,m.cstemnum]>> ;
  2607.             \   ORDER TAG <<m.tagname>>
  2608.             \DEFINE WINDOW <<"W_"+dbflist[m.i,m.cstemnum]>> ;
  2609.             \   AT   <<CHRTRAN(dbflist[m.i,m.srownum],",",".")>>, ;
  2610.             \        <<CHRTRAN(dbflist[m.i,m.scolnum],",",".")>>  ;
  2611.             \   SIZE <<CHRTRAN(dbflist[m.i,m.erownum],",",".")>>, ;
  2612.             \        <<CHRTRAN(dbflist[m.i,m.ecolnum],",",".")>> ;
  2613.             \   FLOAT GROW ZOOM NOCLOSE MINIMIZE ;
  2614.             \   FONT "MS Sans Serif",8 ;
  2615.             \   STYLE "B" ;
  2616.             \   HALF ;
  2617.             \   COLOR SCHEME 10
  2618.             \BROWSE LAST NOWAIT;
  2619.             \   WINDOW <<"W_"+dbflist[m.i,m.cstemnum]>> ;
  2620.             \   NOAPPEND ;
  2621.             \   <<IIF(m.nextdbf>1,"NODELETE","")>> ;
  2622.             \   COLOR SCHEME 10
  2623.  
  2624.             m.i = m.i + 1
  2625.          ENDDO
  2626.  
  2627.          m.i = 2
  2628.          DO WHILE !EMPTY(dbflist[m.i,m.cstemnum]) AND dbflist[m.i,m.cstemnum] <> '\'
  2629.             \SELECT <<Juststem(dbflist[m.i,m.pdbfnum])>>
  2630.             \<<dbflist[m.i,m.relstrnum]>> ADDITIVE
  2631.             \
  2632.             \* Restore the following line if you only want to see records in the
  2633.             \* parent file that have related records in the child file.
  2634.             \*SET FILTER TO FOUND('<<dbflist[m.i,m.cstemnum]>>')
  2635.             \
  2636.             m.i = m.i + 1
  2637.          ENDDO
  2638.          \SELECT <<Juststem(m.dbfname)>>
  2639.       ENDIF
  2640.       \RETURN
  2641.       \
  2642.       \
  2643.       \*******************************************************************
  2644.       \PROCEDURE definedbf
  2645.       \* Define the dbflist array
  2646.       \PUBLIC dbflist[m.numareas,m.numcols]
  2647.       FOR m.i = 1 TO m.numareas
  2648.          FOR m.j = 1 TO m.numcols
  2649.             IF TYPE("DBFLIST") <> "U"
  2650.                IF TYPE("dbflist[m.i,m.j]") = "C"
  2651.                   \DBFLIST[<<m.i>>,<<m.j>>] = <<'"'+dbflist[m.i,m.j]+'"'>>
  2652.                ELSE
  2653.                   \DBFLIST[<<m.i>>,<<m.j>>] = <<dbflist[m.i,m.j]>>
  2654.                ENDIF
  2655.             ELSE
  2656.                \DBFLIST[<<m.i>>,<<m.j>>] = ''
  2657.             ENDIF
  2658.          ENDFOR
  2659.       ENDFOR
  2660.       \
  2661.       \
  2662.       \*******************************************************************
  2663.  
  2664.       SET TEXTMERGE TO
  2665.       SET TEXTMERGE OFF
  2666.       SET CONSOLE ON
  2667.       SET NOTIFY OFF
  2668.  
  2669.       SET POINT TO &mpoint
  2670.  
  2671.       * Release the large dbflist array so that we don't run out of
  2672.       * memory and/or other system resources during project generation
  2673.       RELEASE dbflist
  2674.  
  2675.       m.appname  = UPPER(ALLTRIM(m.appfile))
  2676.       m.projname = forceext(m.appname,'PJX')
  2677.  
  2678.       * Compute the mimimum path between the project home directory
  2679.       * and the SCX file. We'll want the mimimum path stored in the
  2680.       * project file we are about to build so that the project will
  2681.       * be portable across directories.
  2682.       m.sc_name = SYS(2014,m.scxname,m.appname)
  2683.  
  2684.       m.p_path = justpath(m.projname)
  2685.       SET DEFAULT TO &p_path
  2686.  
  2687.       * Clear any existing project files.  Start with a clean slate.
  2688.       IF FILE(m.projname)
  2689.          DELETE FILE (m.projname)
  2690.       ENDIF
  2691.       pjtname = forceext(m.projname,'PJT')
  2692.       IF FILE(m.pjtname)
  2693.          DELETE FILE (m.pjtname)
  2694.       ENDIF
  2695.  
  2696.       * One last check to make sure that the user didn't leave a
  2697.       * poisonous MPR hanging around.
  2698.       m.mpr_name = FULLPATH(addbs(justpath(m.projname))+'APPMENU.MPR')
  2699.       IF FILE(m.mpr_name)
  2700.          DELETE FILE &mpr_name
  2701.          m.mpx_name = FULLPATH(addbs(justpath(m.projname))+'APPMENU.MPX')
  2702.          IF FILE(m.mpx_name)
  2703.             DELETE FILE &mpx_name
  2704.          ENDIF
  2705.       ENDIF
  2706.  
  2707.       * Build the actual application project file and APP now
  2708.       SET MESSAGE TO "Building project"
  2709.       IF m.regen
  2710.          DO copypiece   && copy FoxApp pieces to project directory
  2711.          BUILD PROJECT (m.projname) FROM ;
  2712.             (m.tmfname),    ;
  2713.             (m.scxname),    ;
  2714.             appproc.prg,    ;
  2715.             appmenu.mnx,    ;
  2716.             prtsetup.scx,   ;
  2717.             getdest.scx,    ;
  2718.             getorder.scx,   ;
  2719.             appabout.scx,   ;
  2720.             appsrch.scx
  2721.       ELSE
  2722.          BUILD PROJECT (m.projname) FROM              ;
  2723.             (m.tmfname),                              ;
  2724.             (addbs(foxappdir)+'PRGS\appproc.prg'),    ;
  2725.             (addbs(foxappdir)+'MENUS\appmenu.prg'),   ;
  2726.             (addbs(foxappdir)+'SCREENS\prtsetup.prg'),;
  2727.             (addbs(foxappdir)+'SCREENS\getdest.prg'), ;
  2728.             (addbs(foxappdir)+'SCREENS\getorder.prg'),;
  2729.             (addbs(foxappdir)+'SCREENS\appabout.prg'),;
  2730.             (addbs(foxappdir)+'SCREENS\appsrch.prg'), ;
  2731.             (m.sc_name)
  2732.       ENDIF
  2733.  
  2734.       * Modify the new project to merge the FoxApp control panel
  2735.       * with the user screen (SCXNAME) into one screen set.
  2736.       SET MESSAGE TO "Adding control panel"
  2737.  
  2738.       DO mergectrl WITH m.projname, m.scxname, m.vcoord, m.hcoord
  2739.  
  2740.       SET MESSAGE TO "Building application"
  2741.       BUILD APP (m.appname) FROM (m.projname)
  2742.  
  2743.       * Set the default path back to what it was
  2744.       SET DEFAULT TO &c_path
  2745.  
  2746.       SET NOTIFY ON
  2747.  
  2748.       CLEAR READ
  2749.    ENDIF
  2750. ENDIF
  2751. RETURN .T.
  2752.  
  2753.  
  2754. *       ╓─────────────────────────────────────────────────────────╖
  2755. *       ║                                                         ║
  2756. *       ║ _QDL0OP7BF           m.advanced VALID                   ║
  2757. *       ║                                                         ║
  2758. *       ║ Function Origin:                                        ║
  2759. *       ║                                                         ║
  2760. *       ║ From Platform:       Windows                            ║
  2761. *       ║ From Screen:         APPSCX,     Record Number:   18    ║
  2762. *       ║ Variable:            m.advanced                         ║
  2763. *       ║ Called By:           VALID Clause                       ║
  2764. *       ║ Snippet Number:      15                                 ║
  2765. *       ║                                                         ║
  2766. *       ╙─────────────────────────────────────────────────────────╜
  2767. *
  2768. FUNCTION _qdl0op7bf     &&  m.advanced VALID
  2769. #REGION 1
  2770. DO advance.spr
  2771.  
  2772.  
  2773. *       ╓─────────────────────────────────────────────────────────╖
  2774. *       ║                                                         ║
  2775. *       ║ _QDL0OP7GH           m.cancbut VALID                    ║
  2776. *       ║                                                         ║
  2777. *       ║ Function Origin:                                        ║
  2778. *       ║                                                         ║
  2779. *       ║ From Platform:       Windows                            ║
  2780. *       ║ From Screen:         APPSCX,     Record Number:   19    ║
  2781. *       ║ Variable:            m.cancbut                          ║
  2782. *       ║ Called By:           VALID Clause                       ║
  2783. *       ║ Snippet Number:      16                                 ║
  2784. *       ║                                                         ║
  2785. *       ╙─────────────────────────────────────────────────────────╜
  2786. *
  2787. FUNCTION _qdl0op7gh     &&  m.cancbut VALID
  2788. #REGION 1
  2789. quitting = .T.
  2790. CLEAR READ
  2791.  
  2792.  
  2793. *       ╓─────────────────────────────────────────────────────────╖
  2794. *       ║                                                         ║
  2795. *       ║ _QDL0OP7LU           m.arrange VALID                    ║
  2796. *       ║                                                         ║
  2797. *       ║ Function Origin:                                        ║
  2798. *       ║                                                         ║
  2799. *       ║ From Platform:       Windows                            ║
  2800. *       ║ From Screen:         APPSCX,     Record Number:   20    ║
  2801. *       ║ Variable:            m.arrange                          ║
  2802. *       ║ Called By:           VALID Clause                       ║
  2803. *       ║ Snippet Number:      17                                 ║
  2804. *       ║                                                         ║
  2805. *       ╙─────────────────────────────────────────────────────────╜
  2806. *
  2807. FUNCTION _qdl0op7lu     &&  m.arrange VALID
  2808. #REGION 1
  2809. DO opendbf WITH m.dbfname
  2810.  
  2811. PUSH MENU _msysmenu
  2812.  
  2813. RELEASE arrexflg   && causes upcoming Foundation read to terminate
  2814. PUBLIC  arrexflg
  2815. m.arrexflg = .F.
  2816.  
  2817. m.tree_up = WVISIBLE('treewind')
  2818.  
  2819. HIDE WINDOW appgen
  2820. IF WEXIST('dbfselec')
  2821.    HIDE WINDOW dbfselec
  2822. ENDIF
  2823. IF WEXIST('treewind')
  2824.    HIDE WINDOW treewind
  2825. ENDIF
  2826.  
  2827. DEFINE PAD a_save OF _msysmenu PROMPT "\<Save Arrangement!" KEY ALT+S,"" COLOR SCHEME 3
  2828. DEFINE PAD a_cancel OF _msysmenu PROMPT "\<Cancel!" KEY ALT+C,"" COLOR SCHEME 3
  2829. ON SELECTION PAD a_save   OF _msysmenu DO arrsave
  2830. ON SELECTION PAD a_cancel OF _msysmenu DO arrexit
  2831.  
  2832. RELEASE PAD _MSM_SYSTM  OF _msysmenu
  2833. RELEASE PAD _MSM_FILE   OF _msysmenu
  2834. RELEASE PAD _MSM_EDIT   OF _msysmenu
  2835. RELEASE PAD _MSM_DATA   OF _msysmenu
  2836. RELEASE PAD _MSM_RECRD  OF _msysmenu
  2837. RELEASE PAD _MSM_PROG   OF _msysmenu
  2838. RELEASE PAD _MSM_WINDO  OF _msysmenu
  2839. RELEASE PAD RUN         OF _msysmenu
  2840.  
  2841. * Save the screen and start the arranging from a blank screen
  2842. SAVE SCREEN TO arr_scrn
  2843. ACTIVATE SCREEN
  2844. CLEAR
  2845.  
  2846. * See how wide and tall the actual control panel is.
  2847. m.dname = addbs(m.foxappdir)+'screens\appctrl.scx'
  2848. IF FILE(m.dname)
  2849.    m.in_area = SELECT()
  2850.    SELECT 0
  2851.    USE (dname) AGAIN ALIAS ctrl
  2852.    LOCATE FOR platform = "WINDOWS" AND objtype = 1
  2853.    IF FOUND()
  2854.       m.ctrl_width     = ctrl.width
  2855.       m.ctrl_height    = ctrl.height
  2856.    ELSE
  2857.       m.ctrl_width = 73.167
  2858.       m.ctrl_height = 3.846
  2859.    ENDIF
  2860.    USE
  2861.    SELECT (m.in_area)
  2862. ELSE
  2863.    m.ctrl_width = 73.167
  2864.    m.ctrl_height = 3.846
  2865. ENDIF
  2866. m.ctrlrow = MAX(0,m.ctrlrow)
  2867. m.ctrlcol = MAX(0,m.ctrlcol)
  2868.  
  2869. * Define window for control panel
  2870. DEFINE WINDOW ctrl ;
  2871.    AT m.ctrlrow,m.ctrlcol ;
  2872.    SIZE m.ctrl_height, m.ctrl_width ;
  2873.    TITLE "Control panel" ;
  2874.    HALF ;
  2875.    FONT "MS Sans Serif",8 ;
  2876.    STYLE "B" ;
  2877.    FLOAT NOZOOM NOCLOSE
  2878. ACTIVATE WINDOW ctrl
  2879.  
  2880. * Figure out how tall and wide the main database screen will be
  2881. IF EMPTY(m.scxname) OR !FILE(m.scxname)
  2882.    * If a screen hasn't been defined yet, look at the database fields
  2883.    SELECT (dbflist[1,m.cstemnum])
  2884.    m.maxlen  = 0
  2885.    m.maxheight = FCOUNT() + 4
  2886.    m.maxcapt = 0
  2887.    FOR m.i = 1 TO FCOUNT()
  2888.       m.maxlen  = MAX(m.maxlen,FSIZE(FIELD(m.i)))  && max field length
  2889.       m.maxcapt = MAX(m.maxcapt,LEN(FIELD(m.i))+2) && max field name length
  2890.    ENDFOR
  2891.    m.maxlen = m.maxlen + m.maxcapt + 4   && allow for borders
  2892.    m.sheight   = m.maxheight
  2893.    m.swidth    = m.maxlen
  2894. ELSE         && otherwise, look to the SCX itself
  2895.    SELECT 0
  2896.    USE (m.scxname) AGAIN ALIAS fxscxnme
  2897.    LOCATE FOR platform = "WINDOWS" AND Objtype = 1
  2898.    IF FOUND()
  2899.       m.dbf_fontface  = fxscxnme.fontface
  2900.       m.dbf_fontsize  = fxscxnme.fontsize
  2901.       m.dbf_fontstyle = fxscxnme.fontstyle
  2902.       m.sheight       = fxscxnme.height
  2903.       m.swidth        = fxscxnme.width
  2904.    ELSE
  2905.       WAIT WINDOW "FoxApp couldn't find any Windows records for this screen."
  2906.       m.sheight = 23
  2907.       m.swidth = 74
  2908.    ENDIF
  2909.    USE
  2910. ENDIF
  2911.  
  2912. * Determine position for main database window and define window
  2913. DO CASE
  2914. CASE UPPER(dbflist[1,m.arranged]) = "N"
  2915.    * No screen position yet defined for the main database.  Center it,
  2916.    * unless there are lots of related databases.  If there are, put
  2917.    * it closer to the top of the screen.
  2918.    IF m.nextdbf < 3  && just one database used in app
  2919.       m.start_row = MAX(INT(SROWS()/2-m.sheight/2),0)
  2920.       m.start_col = MAX(INT(SCOLS()/2-m.swidth/2),0)
  2921.    ELSE
  2922.       m.start_row = 1
  2923.       m.start_col = MAX(INT(SCOLS()/2-m.swidth/2),0)
  2924.    ENDIF
  2925. OTHERWISE   && show it where the user put it last
  2926.    m.start_row    = VAL(dbflist[1,m.srownum])
  2927.    m.start_col    = VAL(dbflist[1,m.scolnum])
  2928. ENDCASE
  2929. m.start_row = MAX(0,m.start_row)
  2930. m.start_col = MAX(0,m.start_col)
  2931.  
  2932. * Define the blank window for the main database
  2933. DEFINE WINDOW (dbflist[1,m.cstemnum]) ;
  2934.    AT m.start_row,m.start_col ;
  2935.    SIZE m.sheight,m.swidth ;
  2936.    TITLE dbflist[1,m.cstemnum] ;
  2937.    FONT "MS Sans Serif",8 ;
  2938.    STYLE "B" ;
  2939.    NOGROW FLOAT NOZOOM NOCLOSE ;
  2940.    COLOR SCHEME 1
  2941.  
  2942. * Define windows for child databases
  2943. FOR m.i = 2 TO m.numareas
  2944.    IF !EMPTY(dbflist[m.i,m.cstemnum]) AND dbflist[m.i,m.cstemnum] <> '\'
  2945.       IF dbflist[m.i,m.arranged] = "N"
  2946.          * Try to place browse windows immediately beneath main screen
  2947.          m.win_height = 8      && minimum height of a BROWSE window
  2948.          IF m.start_row + m.sheight + (m.i-2)*(m.win_height+1) + 2 < SROWS() - 3
  2949.             m.ws_row = m.start_row + m.sheight + (m.i-2)*(m.win_height+1) + 2
  2950.             m.ws_col = 1
  2951.             m.we_row = m.win_height
  2952.             m.we_col = 74                     && width
  2953.          ELSE     && put the browse windows in the upper left of the screen
  2954.             m.ws_row = m.i
  2955.             m.ws_col = m.i
  2956.             m.we_row = MIN(m.win_height,SROWS()-m.ws_row-1)   && height
  2957.             m.we_col = 74                     && width
  2958.          ENDIF
  2959.       ELSE
  2960.          m.fontstrg = dbflist[m.i,m.thefont]
  2961.          m.ws_row = VAL(dbflist[m.i,m.srownum])
  2962.          m.ws_col = VAL(dbflist[m.i,m.scolnum])
  2963.          m.we_row = VAL(dbflist[m.i,m.erownum])
  2964.          m.we_col = VAL(dbflist[m.i,m.ecolnum])
  2965.  
  2966.       ENDIF
  2967.       DEFINE WINDOW (dbflist[m.i,m.cstemnum]) ;
  2968.          AT m.ws_row,m.ws_col ;
  2969.             SIZE m.we_row,m.we_col ;
  2970.          SYSTEM ;
  2971.          TITLE dbflist[m.i,m.cstemnum] ;
  2972.          GROW FLOAT NOZOOM NOCLOSE ;
  2973.          HALF ;
  2974.          FONT "MS Sans Serif",8 ;
  2975.          STYLE "B" ;
  2976.          COLOR SCHEME 10
  2977.       ACTIVATE WINDOW (dbflist[m.i,m.cstemnum])
  2978.    ENDIF
  2979. ENDFOR
  2980.  
  2981. * Activate the main window and let user move things around.
  2982. ACTIVATE WINDOW (dbflist[1,m.cstemnum])
  2983.  
  2984. * The foundation read terminates when the user selects "Save" or "Exit" from the menu
  2985. READ VALID m.arrexflg
  2986.  
  2987. IF m.tree_up AND WEXIST('treewind')
  2988.    SHOW WINDOW treewind
  2989. ENDIF
  2990. RELEASE arrexflg
  2991.  
  2992. RESTORE SCREEN FROM arr_scrn
  2993.  
  2994.  
  2995.  
  2996. *       ╓─────────────────────────────────────────────────────────╖
  2997. *       ║                                                         ║
  2998. *       ║ _QDL0OP90P           Read Level Deactivate              ║
  2999. *       ║                                                         ║
  3000. *       ║ Function Origin:                                        ║
  3001. *       ║                                                         ║
  3002. *       ║                                                         ║
  3003. *       ║ From Platform:       Windows                            ║
  3004. *       ║ From Screen:         APPSCX                             ║
  3005. *       ║ Called By:           READ Statement                     ║
  3006. *       ║ Snippet Number:      18                                 ║
  3007. *       ║                                                         ║
  3008. *       ╙─────────────────────────────────────────────────────────╜
  3009. *
  3010. FUNCTION _qdl0op90p     && Read Level Deactivate
  3011. *
  3012. * Deactivate Code from screen: APPSCX
  3013. *
  3014. #REGION 1
  3015. ?? CHR(7)
  3016. RETURN .F.
  3017.  
  3018.  
  3019. *       ╓─────────────────────────────────────────────────────────╖
  3020. *       ║                                                         ║
  3021. *       ║ SCRNUPD           Read Level Show                       ║
  3022. *       ║                                                         ║
  3023. *       ║ Function Origin:                                        ║
  3024. *       ║                                                         ║
  3025. *       ║                                                         ║
  3026. *       ║ From Platform:       Windows                            ║
  3027. *       ║ From Screen:         APPSCX                             ║
  3028. *       ║ Called By:           READ Statement                     ║
  3029. *       ║ Snippet Number:      19                                 ║
  3030. *       ║                                                         ║
  3031. *       ╙─────────────────────────────────────────────────────────╜
  3032. *
  3033. FUNCTION SCRNUPD     && Read Level Show
  3034. PRIVATE currwind
  3035. STORE WOUTPUT() TO currwind
  3036. *
  3037. * Show Code from screen: APPSCX
  3038. *
  3039. #REGION 1
  3040. DO CASE
  3041. CASE EMPTY(m.dbfname) OR skipdbfbut
  3042.    SHOW GET generate DISABLE
  3043.    SHOW GET other    DISABLE
  3044.    SHOW GET adddbf   DISABLE
  3045.    SHOW GET moddbf   DISABLE
  3046. CASE !FILE(m.dbfname)
  3047.    SHOW GET generate DISABLE
  3048.    SHOW GET other    DISABLE
  3049.    SHOW GET adddbf   ENABLE
  3050.    SHOW GET moddbf   DISABLE
  3051. OTHERWISE   && everything is ok
  3052.    SHOW GET generate ENABLE
  3053.    SHOW GET other    ENABLE
  3054.    SHOW GET adddbf   DISABLE
  3055.    SHOW GET moddbf   ENABLE
  3056. ENDCASE
  3057.  
  3058. DO CASE
  3059. CASE EMPTY(m.scxname)
  3060.    SHOW GET addscx   DISABLE
  3061.    SHOW GET modscx   DISABLE
  3062.    SHOW GET arrange  DISABLE
  3063. CASE !FILE(m.scxname)
  3064.    SHOW GET addscx   ENABLE
  3065.    SHOW GET modscx   DISABLE
  3066.    SHOW GET arrange  DISABLE
  3067. OTHERWISE   && everything is ok
  3068.    SHOW GET addscx   DISABLE
  3069.    SHOW GET modscx   ENABLE
  3070.    SHOW GET arrange  ENABLE
  3071. ENDCASE
  3072.  
  3073. * See if there is a stored resource for this database in the current
  3074. *    resource file.  This is in the SHOW snippet instead of in the
  3075. *    VALID for the "related" button since we want to get this information
  3076. *    even if the user never presses "related" in this session.
  3077. IF !EMPTY(m.dbfname) AND !m.rsc_check AND m.retrieversc
  3078.    IF !EMPTY(ALIAS())
  3079.       m.nextdbf = getdbflist(ALIAS())
  3080.       * Only check the resource file once
  3081.       m.rsc_check = .T.
  3082.    ENDIF
  3083. ENDIF
  3084.  
  3085. IF relateddbfs() AND !EMPTY(m.scxname) AND FILE(m.scxname)
  3086.    SHOW GET arrange  ENABLE
  3087. ELSE
  3088.    SHOW GET arrange  DISABLE
  3089. ENDIF
  3090.  
  3091. IF NOT EMPTY(currwind)
  3092.     ACTIVATE WINDOW (currwind) SAME
  3093. ENDIF