home *** CD-ROM | disk | FTP | other *** search
/ Total C++ 2 / TOTALCTWO.iso / vfp5.0 / vfp / genmenu.prg < prev    next >
Text File  |  1996-12-08  |  74KB  |  2,477 lines

  1. ******************************************************************************
  2. * GENMENU - Menu code generator.
  3. *
  4. * Copyright (c) 1990 - 1995 Microsoft Corp.
  5. * 1 Microsoft Way
  6. * Redmond, WA 98052
  7. *
  8. * Description:
  9. * This program generates menu code which was designed in the
  10. * FoxPro 3.0 MENU BUILDER.
  11. *
  12. * Modification History:
  13. * December 13, 1990        JAC        Program Created
  14. *
  15. * Modified for FoxPro 2.5 by WJK
  16. * Modified for FoxPro 3.0 by DTA
  17. * Modified for FoxPro 5.0 by RB
  18. *
  19. ******************************************************************************
  20. * MS SourceSafe Keywords:
  21. * $Workfile: GENMENU.PRG $
  22. *   $Author: Dta $
  23. *     $Date: 3/19/95 1:04a $
  24. *  $Logfile: /Genmenu/GENMENU.PRG $
  25. *  $Modtime: 3/19/95 1:04a $
  26. * $Revision: 8 $
  27. *
  28. * NOTE: Revisions history kept at end of file.
  29. ******************************************************************************
  30. ******************************************************************************
  31. *
  32. * Declare Constants
  33. *
  34. ******************************************************************************
  35. * Move constants above executable code [Rev: 3][BEG]
  36. #DEFINE c_DEBUG .F.  && Add debug mode [Rev: 4][ADD]
  37. *
  38. #DEFINE c_esc    CHR(27)
  39. #DEFINE c_null    CHR(0)
  40. #DEFINE c_CRLF  CHR(13) + CHR(10)   && Carriage return + Line feed constant [Rev: 6][ADD]
  41. #DEFINE c_aliaslen 255               && Support long file names [Rev: 7][MOD]
  42. *
  43. * Possible values of Objtype field in SCX database.
  44. *
  45. #DEFINE c_menu        1
  46. #DEFINE c_submenu    2
  47. #DEFINE c_item        3
  48. #DEFINE c_shortcut    4
  49. #DEFINE c_sdimenu    5
  50. *
  51. * Some of the values of Objcode field in SCX database.
  52. *
  53. #DEFINE    c_global         1
  54. #DEFINE c_proc          80
  55. #DEFINE c_maxsnippets   25
  56. #DEFINE c_maxpads        25
  57. #DEFINE c_pjx20flds        33
  58. #DEFINE c_pjxflds        28   && Changed from 31 [Rev: 2][MOD]
  59. #DEFINE c_mnxflds        23
  60. #DEFINE c_20mnxflds        22
  61. #DEFINE c_space         40   && Used by Thermfname 
  62. *
  63. * Developer Information
  64. *
  65. #DEFINE c_authorlen        45
  66. #DEFINE c_complen        45
  67. #DEFINE c_addrlen        45
  68. #DEFINE c_citylen        20
  69. #DEFINE c_statlen        5
  70. #DEFINE c_ziplen        10
  71. #DEFINE c_countrylen    40
  72. *
  73. * Menu / pad location
  74. *
  75. #DEFINE c_replace        0
  76. #DEFINE c_append        1
  77. #DEFINE c_before        2
  78. #DEFINE c_after            3
  79. *
  80. #DEFINE c_pathsep  "\"
  81. *
  82. * Add support for negotiate [Rev: 2][BEG]
  83. #DEFINE c_neg_flag      "LOCATION"
  84. #DEFINE c_neg_left          1
  85. #DEFINE c_neg_middle        2
  86. #DEFINE c_neg_right         3
  87. * Add support for negotiate [Rev: 2][BEG]
  88. *
  89. * Add localization support [Rev: 2][BEG]
  90. #DEFINE c_hdr_author_LOC    "Author's Name"
  91. #DEFINE c_hdr_company_LOC   "Company Name"
  92. #DEFINE c_hdr_address_LOC   "Address"
  93. #DEFINE c_hdr_city_LOC      "City"
  94. #DEFINE c_hdr_state_LOC     "  "
  95. #DEFINE c_hdr_zip_LOC       "Zip"
  96. #DEFINE c_hdr_ctry_LOC      "Country"
  97. #DEFINE c_hdr_copyright_LOC Copyright (C)
  98. #DEFINE c_hdr_descript_LOC  Description:
  99. #DEFINE c_hdr_string_LOC    This PROGRAM was automatically generated BY GENMENU.
  100. #DEFINE c_shortcutdef_LOC  "FoxShortcutMenu"
  101.  
  102. *
  103. #DEFINE c_snip_setup_LOC    " Setup Code"
  104. #DEFINE c_snip_cleanup_LOC  " Cleanup Code & Procedures"
  105. #DEFINE c_snip_init_LOC     " Initializing Code"
  106. #DEFINE c_snip_menu_LOC     " Menu Definition"
  107.  
  108. #DEFINE c_dlgface_mac_LOC       "Geneva"
  109. #DEFINE c_dlgface_nonmac_LOC    "MS Sans Serif"
  110. #DEFINE c_dlgstyle_mac_LOC       ""
  111. #DEFINE c_dlgstyle_nonmac_LOC     ""
  112.  
  113. *
  114. * Genmenu error types
  115. *
  116. #DEFINE c_error_1        "Minor"
  117. #DEFINE c_error_2        "Serious"
  118. #DEFINE c_error_3        "Fatal"
  119. #DEFINE c_error_1Icon   64   &&   Error icons [Rev: 6][ADD]
  120. #DEFINE c_error_2Icon   48   &&   Error icons [Rev: 6][ADD]
  121. #DEFINE c_error_3Icon   16   &&   Error icons [Rev: 6][ADD]
  122. #DEFINE c_err_invnumparm_LOC     "Invalid number of parameters passed to the generator."
  123. #DEFINE c_err_badgendate_LOC     "Generator out of date."
  124. #DEFINE c_err_badrechead_LOC     "Missing header record in "
  125. #DEFINE c_err_nocloseapp_LOC     "Unable to Close the Application File."
  126. #DEFINE c_err_badmnxpre_LOC      "Menu "
  127. #DEFINE c_err_badmnxpost_LOC     " is invalid"
  128. #DEFINE c_err_nofileopen_LOC     "Cannot open file "
  129. #DEFINE c_err_badnegoval_LOC     "Invalid negotiate value in field "
  130. #DEFINE c_err_title_LOC          "Genmenu Error"
  131. #DEFINE c_err_lineno_LOC         "Line Number: "
  132. #DEFINE c_err_presskey_LOC       "Press any key to cleanup and exit..."
  133. #DEFINE c_err_noopenerr_LOC      ".ERR could not be opened..."
  134. #DEFINE c_err_toomanymemvars_LOC "Too many memvars - GENMENU will terminate..."    && ERROR 22 [Rev: 4][ADD]
  135. #DEFINE c_err_nobangallowed_LOC  "Menu file name cannot contain the character " + [" ! "]   && ! in menu [Rev: 6][ADD]
  136. *
  137. #DEFINE c_msg_gencomplete_LOC    "Generation Complete"
  138. #DEFINE c_msg_genmenudefs_LOC    "Generating menu definitions..."
  139. #DEFINE c_msg_genpopdefs_LOC     "Generating popup definitions..."
  140. #DEFINE c_msg_genprocs_LOC       "Generating procedures..."
  141. #DEFINE c_msg_gensetup_LOC       "Generating Menu Setup Code..."
  142. #DEFINE c_msg_gencleanup_LOC     "Generating Menu Cleanup Code..."
  143. #DEFINE c_msg_genstopped_LOC     "Generation process stopped."
  144. #DEFINE c_msg_genmenucode_LOC    "Generating Menu Code..."
  145. *
  146. #DEFINE c_sdierrdisplay_loc        "[This menu can only be called from a Top-Level form. "+;
  147.                                 "Ensure that your form's ShowWindow property is set to 2. "+;
  148.                                 "Read the header section of the menu's MPR file for more details.]"
  149. *
  150. #DEFINE c_ui_whereis_LOC         WHERE is
  151. * Add localization support [Rev: 2][END]
  152. *
  153. #DEFINE c_key_padhotkey_LOC      "ALT+"   && Add support for intelligent Pad hotkeys. [Rev: 7][ADD]
  154. * Move constants above executable code [Rev: 3][END]
  155. ******************************************************************************
  156. *
  157. * Main program
  158. *
  159. ******************************************************************************
  160. PARAMETER m.projdbf, m.recno
  161. PRIVATE ALL
  162. *
  163. * Setup initial environment for GENMENU
  164. *
  165. IF SET("TALK") = "ON"
  166.    SET TALK OFF
  167.    m.talkstate = "ON"
  168. ELSE
  169.    m.talkstate = "OFF"
  170. ENDIF
  171. m.coveragefile = SET("COVERAGE")
  172. m.oldtextmerge = SET("TEXTMERGE")
  173. SET COVERAGE TO
  174. m.escape = SET("ESCAPE")
  175. IF NOT c_DEBUG   && Add debug mode [Rev: 4][ADD]
  176.    SET ESCAPE OFF
  177. ENDIF
  178. m.trbetween = SET("TRBET")
  179. IF NOT c_DEBUG   && Add debug mode [Rev: 4][ADD]
  180.    SET TRBET OFF
  181. ENDIF
  182. m.comp = SET("COMPATIBLE")
  183. SET COMPATIBLE OFF
  184. mdevice = SET("DEVICE")
  185. SET DEVICE TO SCREEN
  186. ******************************************************************************
  187. *
  188. * Declare Variables
  189. *
  190. ******************************************************************************
  191. STORE "" TO m.cursor, m.consol, m.bell, m.onerror, m.fields, mfieldsto, ;
  192.    m.exact, m.print, m.fixed, m.delimiters, m.mpoint, m.mcollate, m.mmacdesk, m.mcpdialog 
  193. STORE 0 TO m.deci, m.memowidth
  194. *
  195. * Fonts for thermometer bar / dialogs
  196. *
  197. * Change fonts to memvars [Rev: 4][BEG]
  198. * Translate the filename into Mac native format
  199. IF _MAC
  200.    m.g_dlgface    = c_dlgface_mac_LOC
  201.    m.g_dlgsize    = 10.000
  202.    m.g_dlgstyle    = c_dlgstyle_mac_LOC
  203.    m.g_pathsep    = ":"
  204. ELSE
  205.    m.g_dlgface    = c_dlgface_nonmac_LOC
  206.    m.g_dlgsize    = 8.000
  207.    m.g_dlgstyle    = c_dlgstyle_nonmac_LOC
  208.    m.g_pathsep    = "\"
  209. ENDIF
  210. m.g_error      = .F.
  211. m.g_errlog     = ""
  212. m.g_homedir    = ""
  213. m.g_location   = 0
  214. m.g_menucolor  = 0
  215. m.g_menumark   = ""
  216. m.g_nohandle   = .T.
  217. m.g_nsnippets  = 0
  218. m.g_outfile    = ""
  219. m.g_padloca    = ""
  220. m.g_projalias  = ""
  221. m.g_projdbf    = m.projdbf
  222. m.g_projpath   = ""
  223. m.g_status     = 0
  224. m.g_snippcnt   = 0
  225. m.g_thermwidth = 0
  226. m.g_workarea   = 0
  227. m.g_graphic    = .F.
  228. m.g_20mnx       = .F.
  229. m.g_shortcut   = .F.
  230. m.g_inform     = .F.
  231. m.g_shortcutname = ""
  232. m.g_prepopup = .F.
  233. *
  234. * Add localization support [Rev: 2][BEG]
  235. m.g_devauthor  = PADR( c_hdr_author_LOC ,45," ")
  236. m.g_devcompany = PADR( c_hdr_company_LOC ,45, " ")
  237. m.g_devaddress = PADR( c_hdr_address_LOC ,45," ")
  238. m.g_devcity    = PADR( c_hdr_city_LOC ,20," ")
  239. m.g_devstate   = c_hdr_state_LOC
  240. m.g_devzip     = PADR( c_hdr_zip_LOC ,10," ")
  241. m.g_devctry    = PADR( c_hdr_ctry_LOC ,40," ")
  242. * Add localization support [Rev: 2][END]
  243. *
  244. m.g_boxstrg = ['─','─','│','│','┌','┐','└','┘','─','─','│','│','┌','┐','└','┘']
  245. *
  246. STORE "" TO m.g_corn1, m.g_corn2, m.g_corn3, m.g_corn4, m.g_corn5, ;
  247.    m.g_corn6, m.g_verti2
  248. STORE "*" TO  m.g_horiz, m.g_verti1
  249. *
  250. *
  251. * Array Declarations
  252. *
  253. * g_mnxfile [1] - Normalized path + name
  254. * g_mnxfile [2] - Basename
  255. * g_mnxfile [3] - Opened originally?
  256. * g_mnxfile [4] - Alias
  257. *
  258. DIMENSION g_mnxfile[4]
  259. g_mnxfile[1] = ""
  260. g_mnxfile[2] = ""
  261. g_mnxfile[3] = .F.
  262. g_mnxfile[4] = ""
  263. *
  264. * g_pads - names of generated menu pads
  265. *
  266. DIMENSION g_pads(c_maxpads)
  267. *
  268. * g_snippets [*,1] - generated snippet procedure name
  269. * g_snippets [*,2] - recno()
  270. *
  271. DIMENSION g_snippets (c_maxsnippets,2)
  272. g_snippets = ""
  273.  
  274. DIMENSION g_aPops(1)
  275. g_aPops=""
  276.  
  277. IF AT("WINDOWS", UPPER(VERSION())) <> 0 OR ;
  278.       AT("MAC", UPPER(VERSION())) <> 0
  279.    m.g_graphic = .T.
  280. ELSE
  281.    m.g_graphic = .F.
  282. ENDIF
  283. *
  284. * Main program
  285. *
  286. m.onerror = ON("ERROR")
  287. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  288. *
  289. IF PARAMETERS()=2
  290.    DO setup
  291.    IF validparams()
  292.       ON ESCAPE DO eschandler
  293.       SET ESCAPE ON
  294.       DO refreshprefs
  295.       DO BUILD
  296.    ENDIF
  297.    DO cleanup
  298. ELSE
  299.    DO errorhandler WITH c_err_invnumparm_LOC, LINENO(),c_error_3  && Localization support [Rev: 2][MOD]
  300. ENDIF
  301. ON ERROR &onerror
  302. *
  303. RETURN m.g_status
  304.  
  305.  
  306. ******************************************************************************
  307. *
  308. * Setup, Cleanup, Validparams, and Refreshprefs of Main Program
  309. *
  310. ******************************************************************************
  311. *
  312. * STARTUP - Create program's environment.
  313. *
  314. * Description:
  315. * Save the user's environment so that we can set it back when
  316. * we are done, then issue various SET commands. The only state
  317. * we cannot conveniently save is SET TALK, because storing the
  318. * state involves an assignment statement, and assignments
  319. * generate unwanted output if TALK is set ON.
  320. *
  321. * Side Effects:
  322. * Creates a temporary file which is deleted in the Cleanup
  323. * procedure executed at the end of MENUGEN.
  324. *
  325. FUNCTION setup
  326. CLEAR PROGRAM
  327. CLEAR GETS
  328. m.g_workarea = SELECT()
  329. m.delimiters = SET('TEXTMERGE',1)
  330. SET TEXTMERGE DELIMITERS TO
  331. SET UDFPARMS TO VALUE
  332. m.mfieldsto = SET("FIELDS",1)
  333. m.fields = SET("FIELDS")
  334. SET FIELDS TO
  335. SET FIELDS OFF
  336. m.bell = SET("BELL")
  337. SET BELL OFF
  338. m.consol = SET("CONSOLE")
  339. SET CONSOLE OFF
  340. m.cursor = SET("CURSOR")
  341. SET CURSOR OFF
  342. m.deci = SET("DECIMALS")
  343. SET DECIMALS TO 0
  344. mdevice = SET("DEVICE")
  345. SET DEVICE TO SCREEN
  346. m.memowidth = SET("MEMOWIDTH")
  347. SET MEMOWIDTH TO 256
  348. m.exact = SET("EXACT")
  349. SET EXACT ON
  350. m.print = SET("PRINT")
  351. SET PRINT OFF
  352. m.fixed = SET("FIXED")
  353. SET FIXED ON
  354. mpoint = SET("POINT")
  355. SET POINT TO "."
  356. mcollate = SET("COLLATE")
  357. SET COLLATE TO "machine"
  358. mcpdialog = SET("CPDIALOG")
  359. SET CPDIALOG OFF
  360.  
  361. #IF "MAC" $ UPPER(VERSION(1))
  362. IF _MAC
  363.    m.mmacdesk = SET("MACDESKTOP")
  364.    SET MACDESKTOP ON
  365. ENDIF
  366. #ENDIF
  367.  
  368. *
  369. * CLEANUP - restore environment to pre-execution state.
  370. *
  371. * Description:
  372. * Close all databases opened in the course of the execution of MENUGEN.
  373. * Restore the environment to the pre-execution of MENUGEN.  Delete
  374. * the VIEW file since there is no further use for it.
  375. *
  376. * Side Effects:
  377. * Closes databases.
  378. * Deletes the temporary view file.
  379. *
  380. FUNCTION cleanup
  381. PRIVATE m.delilen, m.ldelimi, m.rdelimi
  382. IF EMPTY(m.g_projalias)
  383.    RETURN
  384. ENDIF
  385. SELECT (m.g_projalias)
  386. USE
  387. IF NOT EMPTY(g_mnxfile[3])
  388.    IF USED(g_mnxfile[4])
  389.       SELECT (g_mnxfile[4])
  390.       USE
  391.    ENDIF
  392. ENDIF
  393. SELECT (m.g_workarea)
  394. m.delilen = LEN(m.delimiters)
  395. m.ldelimi = SUBSTR(m.delimiters,1,;
  396.    IIF(MOD(m.delilen,2)=0,m.delilen/2,CEILING(m.delilen/2)))
  397. m.rdelimi = SUBSTR(m.delimiters,;
  398.    IIF(MOD(m.delilen,2)=0,m.delilen/2+1,CEILING(m.delilen/2)+1))
  399. SET TEXTMERGE DELIMITERS TO m.ldelimi, m.rdelimi
  400. IF (LEN(mfieldsto) > 2048)
  401.    SET FIELDS TO
  402. ELSE
  403.    SET FIELDS TO &mfieldsto
  404. ENDIF
  405. IF m.fields = "ON"
  406.    SET FIELDS ON
  407. ELSE
  408.    SET FIELDS OFF
  409. ENDIF
  410. IF m.bell = "ON"
  411.    SET BELL ON
  412. ENDIF
  413. IF m.cursor = "ON"
  414.    SET CURSOR ON
  415. ELSE
  416.    SET CURSOR OFF
  417. ENDIF
  418. IF m.consol = "ON"
  419.    SET CONSOLE ON
  420. ENDIF
  421. IF m.escape = "ON"
  422.    SET ESCAPE ON
  423. ELSE
  424.    SET ESCAPE OFF
  425. ENDIF
  426. IF m.print = "ON"
  427.    SET PRINT ON
  428. ENDIF
  429. IF m.exact = "OFF"
  430.    SET EXACT OFF
  431. ENDIF
  432. IF m.fixed = "OFF"
  433.    SET FIXED OFF
  434. ENDIF
  435. SET DECIMALS TO m.deci
  436. SET MEMOWIDTH TO m.memowidth
  437. SET DEVICE TO &mdevice
  438. IF m.trbetween = "ON"
  439.    SET TRBET ON
  440. ENDIF
  441. IF m.comp = "ON"
  442.    SET COMPATIBLE ON
  443. ENDIF
  444. IF m.talkstate = "ON"
  445.    SET TALK ON
  446. ENDIF
  447. SET POINT TO "&mpoint"
  448. SET COLLATE TO "&mcollate"
  449. IF m.mcpdialog = "ON"
  450.   SET CPDIALOG ON
  451. ENDIF
  452. SET MESSAGE TO
  453. #IF "MAC" $ UPPER(VERSION(1))
  454. IF _MAC
  455.    SET MACDESKTOP &mmacdesk
  456. ENDIF
  457. #ENDIF
  458.  
  459. ON ERROR &onerror
  460. IF !EMPTY(m.coveragefile)
  461.     SET COVERAGE TO (m.coveragefile) ADDITIVE
  462. ENDIF
  463. SET TEXTMERGE TO
  464. IF m.oldtextmerge = "ON"
  465.     SET TEXTMERGE ON
  466. ENDIF
  467.  
  468. *
  469. * VALIDPARAMS - Validate generator parameters.
  470. *
  471. * Description:
  472. * Attempt to open the project database.  If error encountered then
  473. * on error routine takes over and issues 'CANCEL'.  The output file
  474. * cannot be erased, name not known.
  475. *
  476. FUNCTION validparams
  477. SELECT 0
  478. m.g_projalias = IIF(USED("projdbf"),"P"+;
  479.    SUBSTR(LOWER(SYS(3)),2,8),"projdbf")
  480. USE (m.projdbf) ALIAS (m.g_projalias) AGAIN
  481. IF versnum() > "2.5"
  482.    SET NOCPTRANS TO devinfo, symbols, OBJECT
  483. ENDIF
  484. m.g_errlog = stripext(m.projdbf)
  485. m.g_projpath = SUBSTR(m.projdbf,1,RAT("\",m.projdbf))
  486. IF FCOUNT() <> c_pjxflds
  487.    DO errorhandler WITH c_err_badgendate_LOC,LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  488.    RETURN .F.
  489. ENDIF
  490. GOTO RECORD m.recno
  491. m.g_outfile = ALLTRIM(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  492. m.g_outfile = FULLPATH(m.g_outfile, m.g_projpath)
  493. IF _MAC AND RIGHT(m.g_outfile,1) = ":"
  494.    m.g_outfile = m.g_outfile + justfname(SUBSTR(outfile,1,AT(c_null,outfile)-1))
  495. ENDIF
  496. g_mnxfile[1] = FULLPATH(ALLTRIM(name), m.g_projpath)
  497. IF _MAC AND RIGHT(g_mnxfile[1],1) = ":"
  498.    g_mnxfile[1] = g_mnxfile[1] + justfname(name)
  499. ENDIF
  500. g_mnxfile[2] = basename(g_mnxfile[1])  
  501. * No ! in menu name [Rev: 6][BEG]
  502. IF "!" $ g_mnxfile[2]
  503.    DO errorhandler WITH c_err_nobangallowed_LOC, LINENO(), c_error_3 
  504. ENDIF   
  505. * No ! in menu name [Rev: 6][END]
  506.  
  507.  
  508. *
  509. * REFRESHPREFS - Refresh comment style and developer preferences.
  510. *
  511. * Description:
  512. * Get the newest preferences for documentation style and developer
  513. * data from the project database.
  514. *
  515. FUNCTION refreshprefs
  516. PRIVATE m.start, m.savrecno
  517. m.savrecno = RECNO()
  518. LOCATE FOR TYPE = "H"
  519. IF NOT FOUND ()
  520.    DO errorhandler WITH c_err_badrechead_LOC + m.g_projdbf,;
  521.       LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  522.    GOTO RECORD m.savrecno
  523.    RETURN
  524. ENDIF
  525. m.g_homedir = ALLTRIM(SUBSTR(homedir,1,AT(c_null,homedir)-1))
  526.  
  527. IF (RIGHT(m.g_homedir, 1) == "\")
  528.    m.g_homedir = m.g_homedir + "\"
  529. ENDIF
  530. m.start = 1
  531. m.g_devauthor = subdevinfo(m.start,c_authorlen,m.g_devauthor)
  532. m.start = m.start + c_authorlen + 1
  533. m.g_devcompany = subdevinfo(m.start,c_complen,m.g_devcompany)
  534. m.start = m.start + c_complen + 1
  535. m.g_devaddress = subdevinfo(m.start,c_addrlen,m.g_devaddress)
  536. m.start = m.start + c_addrlen + 1
  537. m.g_devcity = subdevinfo(m.start,c_citylen,m.g_devcity)
  538. m.start = m.start + c_citylen + 1
  539. m.g_devstate = subdevinfo(m.start,c_statlen,m.g_devstate)
  540. m.start = m.start + c_statlen + 1
  541. m.g_devzip = subdevinfo(m.start,c_ziplen,m.g_devzip)
  542. m.start = m.start + c_ziplen + 1
  543. m.g_devctry = subdevinfo(m.start,c_countrylen,m.g_devctry)
  544. IF cmntstyle = 0
  545.    m.g_corn1 = "╓"
  546.    m.g_corn2 = "╖"
  547.    m.g_corn3 = "╙"
  548.    m.g_corn4 = "╜"
  549.    m.g_corn5 = "╟"
  550.    m.g_corn6    = "╢"
  551.    m.g_horiz = "─"
  552.    m.g_verti1 = "║"
  553.    m.g_verti2 = "║"
  554. ENDIF
  555. GOTO RECORD m.savrecno
  556.  
  557. *
  558. * SUBDEVINFO - Substring the DEVINFO memo filed.
  559. *
  560. FUNCTION subdevinfo
  561. PARAMETER m.start, m.stop, m.default
  562. PRIVATE m.string
  563. m.string = SUBSTR(devinfo, m.start, m.stop+1)
  564. m.string = SUBSTR(m.string, 1, AT(c_null,m.string)-1)
  565. RETURN IIF(EMPTY(m.string), m.default, m.string)
  566.  
  567. ******************************************************************************
  568. *
  569. * Menu Code Generator's Main Module.
  570. *
  571. ******************************************************************************
  572.  
  573. *
  574. * BUILD - Generate code for a menu.
  575. *
  576. * Description:
  577. * Call BUILDENABLE to open .MNX database specified by the user.
  578. * If the above is successfully accomplished, then proceed to generate
  579. * the menu code.  After the menu code is generated, call BUILDDISABLE
  580. * to disable code generation between SET TEXTMERGE ON and
  581. * SET TEXTMERGE OFF.
  582. *
  583. FUNCTION BUILD
  584. IF NOT buildenable()
  585.    RETURN
  586. ENDIF
  587. DO acttherm WITH c_msg_genmenucode_LOC   && Localization support [Rev: 2][MOD]
  588. DO updtherm WITH 10
  589. DO getmenutype
  590. DO header
  591. DO gensetupcleanup WITH "setup"
  592. DO definemenu
  593. DO definepopups
  594. DO updtherm WITH 75
  595. DO globaldefaults
  596. DO updtherm WITH 95
  597. DO gensetupcleanup WITH "cleanup"
  598. DO genprocedures
  599.  
  600. IF m.g_graphic
  601.    SET MESSAGE TO c_msg_gencomplete_LOC   && Localization support [Rev: 2][MOD]
  602. ENDIF
  603. DO builddisable
  604. DO updtherm WITH 100
  605. DO deactthermo
  606.  
  607. *
  608. * BUILDENABLE - Enable code generation.
  609. *
  610. * Description:
  611. * Call opendb to open .MNX database.
  612. * Call openfile to open file to hold the generated program.
  613. * If error(s) encountered in opendb or openfile then don't do
  614. * anything and exit, otherwise enable code generation with the
  615. * SET TEXTMERGE ON command.
  616. *
  617. * Returns:
  618. * .T. on success; .F. on failure
  619. *
  620. FUNCTION buildenable
  621. PRIVATE m.stat, m.stat2
  622. m.stat = opendb(g_mnxfile[1]) AND openfile()
  623. IF m.stat
  624.    SET TEXTMERGE ON
  625. ENDIF
  626. RETURN m.stat
  627.  
  628. *
  629. * BUILDDISABLE - Disable code generation.
  630. *
  631. * Description:
  632. * Issue the command SET TEXTMERGE OFF.
  633. * Close the generated menu code output file.
  634. * If anything goes wrong display appropriate message to the user.
  635. *
  636. FUNCTION builddisable
  637. SET ESCAPE OFF
  638. ON ESCAPE
  639. SET TEXTMERGE OFF
  640. IF NOT FCLOSE(_TEXT)
  641.    DO errorhandler WITH c_err_nocloseapp_LOC, LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  642. ENDIF
  643.  
  644. *
  645. * OPENDB - Prepare database for processing.
  646. *
  647. * Description:
  648. * Attempt to USE a database.  If attempt fails and error is reported
  649. * call ERRORHANDLER routine to display a friendly message.  Return
  650. * with a status of .F..  If attempt succeeds, return with status of .T.
  651. *
  652. * Returns:
  653. * .T. on success; .F. on failure
  654. *
  655. FUNCTION opendb
  656. PARAMETER m.dbname
  657. PRIVATE m.dbalias
  658. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_2
  659. m.dbalias = LEFT(basename(m.dbname),c_aliaslen)
  660. IF USED (m.dbalias)
  661.    SELECT (m.dbalias)
  662.    IF RAT(".MNX",DBF())<>0
  663.       g_mnxfile[3] = .F.
  664.       g_mnxfile[4] = m.dbalias
  665.    ELSE
  666.       g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  667.       SELECT 0
  668.       USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  669.       g_mnxfile[3] = .T.
  670.    ENDIF
  671. ELSE
  672.    IF illegalname(m.dbalias)
  673.       g_mnxfile[4] = "M"+SUBSTR(LOWER(SYS(3)),2,8)
  674.    ELSE
  675.       g_mnxfile[4] = m.dbalias
  676.    ENDIF
  677.    SELECT 0
  678.    USE (m.dbname) AGAIN ALIAS (g_mnxfile[4])
  679.    g_mnxfile[3] = .T.
  680. ENDIF
  681. IF FCOUNT() <> c_mnxflds
  682.    IF FCOUNT() = c_20mnxflds
  683.       m.g_20mnx = .T.
  684.    ELSE
  685.       DO errorhandler WITH c_err_badmnxpre_LOC + m.dbalias + c_err_badmnxpost_LOC, ;
  686.          LINENO(), c_error_2   && Localization support [Rev: 2][MOD]
  687.       RETURN .F.
  688.    ENDIF
  689. ELSE
  690.    m.g_20mnx = .F.
  691. ENDIF
  692. ON ERROR DO errorhandler WITH MESSAGE(), LINENO(), c_error_3
  693. IF m.g_error = .T.
  694.    RETURN .F.
  695. ENDIF
  696.  
  697. *
  698. * ILLEGALNAME - Check if default alias will be used when this
  699. *               database is USEd. (i.e., 1st letter is not A-Z,
  700. *                a-z or '_', or any one of ramaining letters is not
  701. *                alphanumeric.)
  702. *
  703. FUNCTION illegalname
  704. PARAMETER m.menuname
  705. PRIVATE m.start, m.aschar, m.length
  706. m.length = LEN(m.menuname)
  707. m.start  = 0
  708. IF m.length = 1
  709.    *
  710.    * If length 1, then check if default alias can be used,
  711.    * i.e., name is different than A-J and a-j.
  712.    *
  713.    m.aschar = ASC(m.menuname)
  714.    IF (m.aschar >= 65 AND m.aschar <= 74) OR ;
  715.          (m.aschar >= 97 AND m.aschar <= 106)
  716.       RETURN .T.
  717.    ENDIF
  718. ENDIF
  719. DO WHILE m.start < m.length
  720.    m.start  = m.start + 1
  721.    m.aschar = ASC(SUBSTR(m.menuname, m.start, 1))
  722.    IF m.start<>1 AND (m.aschar >= 48 AND m.aschar <= 57)
  723.       LOOP
  724.    ENDIF
  725.    IF NOT ((m.aschar >= 65 AND m.aschar <= 90) OR ;
  726.          (m.aschar >= 97 AND m.aschar <= 122) OR m.aschar = 95)
  727.       RETURN .T.
  728.    ENDIF
  729. ENDDO
  730. RETURN .F.
  731.  
  732. *
  733. * OPENFILE - Create and open the application output file.
  734. *
  735. * Description:
  736. * Create a file that will hold the generated menu code.
  737. * Open the newly created file.  If error(s) encountered
  738. * at any time issue an error message and return .F.
  739. *
  740. * Returns:
  741. * .T. on success; .F. on failure
  742. *
  743. FUNCTION openfile
  744. PRIVATE m.msg
  745. _TEXT = FCREATE(m.g_outfile)
  746. IF (_TEXT = -1)
  747.    m.msg = c_err_nofileopen_LOC + m.g_outfile   && Localization support [Rev: 2][MOD]
  748.    DO errorhandler WITH m.msg, LINENO(), c_error_3
  749.    m.g_nohandle = .T.
  750.    RETURN .F.
  751. ENDIF
  752. m.g_nohandle = .F.
  753.  
  754. *
  755. * DEFINEMENU - Define main menu and its pads.
  756. *
  757. * Description:
  758. * Issue DEFINE MENU ... command.
  759. * Call a procedure to define all menu pads.
  760. * Call a procedure to generate ON PAD statements when appropriate.
  761. *
  762. FUNCTION definemenu
  763. IF m.g_graphic
  764.    SET MESSAGE TO c_msg_genmenudefs_LOC   && Localization support [Rev: 2][MOD]
  765. ENDIF
  766. DO commentblock WITH "menu"
  767. SELECT (g_mnxfile[4])
  768.  
  769. IF m.g_shortcut    
  770.     RETURN    && skip if shortcut menu
  771. ENDIF
  772.  
  773. LOCATE FOR objtype = c_menu
  774. IF EOF()
  775.     * using Top-Level menu instead
  776.     LOCATE FOR objtype = c_sdimenu
  777. ENDIF
  778. m.g_location = location
  779.  
  780. m.g_padloca  = ALLTRIM(name)
  781. LOCATE FOR objtype = c_submenu AND objcode = c_global
  782. m.g_menucolor = SCHEME
  783. m.g_menumark  = MARK
  784.  
  785. DO CASE
  786. CASE m.g_inform AND m.g_location = c_replace
  787.     \DEFINE MENU (m.cMenuName) IN (m.oFormRef.Name) BAR
  788. CASE m.g_inform
  789.     \LOCAL lHasNewMenu
  790.     \lHasNewMenu = (TYPE("CNTPAD(m.cMenuName)") # "N")
  791.     \IF m.lHasNewMenu
  792.     \    DEFINE MENU (m.cMenuName) IN (m.oFormRef.Name) BAR
  793.     \ENDIF
  794. CASE m.g_location = c_replace
  795.     \SET SYSMENU TO
  796.     \SET SYSMENU AUTOMATIC
  797. ENDCASE
  798.  
  799. \
  800. DO updtherm WITH 25
  801. DO defmenupads
  802. DO updtherm WITH 35
  803. DO defonpad
  804. \
  805. DO updtherm WITH 45
  806.  
  807. *
  808. * DEFMENUPADS - Define all pads for the menu bar.
  809. *
  810. * Description:
  811. * Scan the menu database for all objects of the type item which
  812. * have the levelname=_MSYSMENU.
  813. * For each such item, generate a statement DEFINE PAD... where
  814. * the name of the pad is the contents of NAME field or (if Name
  815. * field is empty) an automatically generated name.
  816. * Call procedures addkey, addskipfor, and mark to generate
  817. * KEY, SKIPFOR, or MARK clauses when appropriate.
  818. *
  819. FUNCTION defmenupads
  820. PRIVATE m.padname, m.prompt
  821. LOCAL lcNegotiate    && Add support for OLE2 Negotiate [Rev: 2][MOD]
  822. SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  823.    IF NOT EMPTY(ALLTRIM(name))
  824.       g_pads[VAL(Itemnum)] = name
  825.    ELSE
  826.       g_pads[VAL(Itemnum)] = LOWER(SYS(2015))
  827.    ENDIF
  828.    DO CASE 
  829.    CASE m.g_inform
  830.            \DEFINE PAD <<g_pads[VAL(Itemnum)]>> OF (m.cMenuName)
  831.    OTHERWISE
  832.            \DEFINE PAD <<g_pads[VAL(Itemnum)]>> OF _MSYSMENU
  833.    ENDCASE
  834.    IF MOD(VAL(itemnum),25)=0
  835.       DIMENSION g_pads[VAL(Itemnum)+25]
  836.    ENDIF
  837.    m.prompt = SUBSTR(PROMPT,1,LEN(PROMPT))
  838.    \\ PROMPT "<<m.prompt>>"
  839.    \\ COLOR SCHEME <<m.g_menucolor>>
  840.  
  841.    IF m.g_menumark<>c_null AND m.g_menumark<>""
  842.       \\ ;
  843.       \    MARK "<<m.g_menumark>>"
  844.    ENDIF
  845.  
  846.    DO CASE
  847.       CASE m.g_location = c_before
  848.          \\ ;
  849.          \    BEFORE <<m.g_padloca>>
  850.       CASE m.g_location = c_after
  851.          \\ ;
  852.          \    AFTER
  853.          IF VAL(itemnum) = 1
  854.             \\ <<m.g_padloca>>
  855.          ELSE
  856.             \\ <<g_pads[VAL(Itemnum)-1]>>
  857.          ENDIF
  858.    ENDCASE
  859.    * Add support for OLE2 Negotiate [Rev: 2][BEG]
  860.    *    c_neg_flag is a quote delimited constant for the field that must be evaluated
  861.    *    for a legal negotiate value.
  862.    lcNegotiate = EVAL( c_neg_flag )
  863.    IF NOT EMPTY( m.lcNegotiate )
  864.       DO CASE
  865.          CASE m.lcNegotiate = c_neg_left
  866.             \\ ;
  867.             \    NEGOTIATE LEFT
  868.          CASE m.lcNegotiate = c_neg_middle
  869.             \\ ;
  870.             \    NEGOTIATE MIDDLE
  871.          CASE m.lcNegotiate = c_neg_right
  872.             \\ ;
  873.             \    NEGOTIATE RIGHT
  874.          OTHERWISE
  875.             DO errorhandler WITH c_err_badnegoval_LOC + c_neg_flag ,;
  876.                LINENO(),c_error_2   && Localization support [Rev: 2][MOD]
  877.       ENDCASE
  878.    ENDIF
  879.    RELEASE m.negotiate
  880.    * Add support for OLE2 Negotiate [Rev: 2][END]
  881.    DO addkey
  882.    DO addskipfor
  883.    DO addmessage
  884. ENDSCAN
  885.  
  886.  
  887. *
  888. * DEFONPAD - Generate ON PAD... statements.
  889. *
  890. * Description:
  891. * Generate ON PAD statements for each pad off of the main menu which
  892. * has a submenu associated with it.
  893. * For pads which have no submenus, but there is a command associated
  894. * with them, issue ON SELECTION PAD... statements.  If the code
  895. * associated with a pad is a snippet, then issue a call to the
  896. * generated procedure and place the snippet code in it.
  897. *
  898. FUNCTION defonpad
  899. PRIVATE m.padname
  900. SCAN FOR objtype=c_item AND UPPER(levelname)="_MSYSMENU"
  901.    IF NOT EMPTY(ALLTRIM(name))
  902.       m.padname = name
  903.    ELSE
  904.       m.padname = g_pads[VAL(Itemnum)]
  905.    ENDIF
  906.    m.therec = RECNO()
  907.    SKIP
  908.    IF objtype=c_submenu AND numitems<>0
  909.        IF m.g_inform
  910.           \ON PAD <<m.padname>> OF (m.cMenuName)
  911.           \\ ACTIVATE POPUP (a_menupops[<<ASCAN(g_apops,LOWER(Name))>>])
  912.        ELSE
  913.           \ON PAD <<m.padname>> OF _MSYSMENU
  914.           \\ ACTIVATE POPUP <<LOWER(Name)>>
  915.        ENDIF
  916.       GOTO m.therec
  917.    ELSE
  918.       GOTO m.therec
  919.       DO onselection WITH "pad", m.padname, '_MSYSMENU'
  920.    ENDIF
  921. ENDSCAN
  922.  
  923.  
  924.  
  925. *
  926. * DEFINEPOPUPS - Define popups and their bars.
  927. *
  928. * Description:
  929. * Scan the Menu database to find all objecttypes = submenu.
  930. * They all correspond to popups.  For each such object found, issue
  931. * command DEFINE POPUP....  Add MARK, KEY, and SKIP FOR clauses
  932. * if appropriate by calling procedures to handle these tasks.  Call
  933. * procedure Defbars to define all bars of each popup.
  934. *
  935. FUNCTION definepopups
  936. PRIVATE m.savrecno, m.popname, m.sch, m.firstpop,m.newpopname
  937. m.firstpop = .T.
  938. IF m.g_graphic
  939.    SET MESSAGE TO c_msg_genpopdefs_LOC   && Localization support [Rev: 2][MOD]
  940. ENDIF
  941. SCAN FOR objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU" ;
  942.       AND numitems <> 0
  943.    m.savrecno = RECNO()
  944.    m.popname  = ALLTRIM(LOWER(levelname))
  945.    m.newpopname = m.popname
  946.    m.sch = SCHEME
  947.    DO CASE
  948.    CASE m.g_shortcut AND m.firstpop 
  949.            * safeguard against system popups used for top popup name
  950.            IF LOWER(LEFT(Name,2))="_m"
  951.                * Use default name
  952.             STORE c_shortcutdef_loc TO m.newpopname,m.g_shortcutname
  953.            ELSE
  954.                m.g_shortcutname = LOWER(Name)
  955.            ENDIF
  956.         m.firstpop = .F.
  957.        \DEFINE POPUP <<m.g_shortcutname>> SHORTCUT RELATIVE FROM MROW(),MCOL()
  958.    CASE m.g_shortcut
  959.        \DEFINE POPUP <<LOWER(Name)>> SHORTCUT RELATIVE
  960.   CASE m.g_inform
  961.        \DEFINE POPUP (a_menupops[<<ASCAN(g_apops,LOWER(Name))>>]) MARGIN RELATIVE SHADOW
  962.        \\ COLOR SCHEME <<m.sch>>
  963.    OTHERWISE
  964.        \DEFINE POPUP <<LOWER(Name)>> MARGIN RELATIVE SHADOW
  965.        \\ COLOR SCHEME <<m.sch>>
  966.    ENDCASE
  967.    DO addmark
  968.    DO addkey
  969.    DO defbars WITH m.popname, numitems, m.newpopname 
  970.    DO defonbar WITH m.popname, m.newpopname 
  971.    \
  972.    GOTO RECORD m.savrecno
  973. ENDSCAN
  974.  
  975.  
  976. *
  977. * DEFBARS - Define bars for each popup.
  978. *
  979. * Description:
  980. * Scan the menu database for all objects of the type item whose
  981. * name equals to the current popup name.
  982. * For each such item, generate a statement DEFINE BAR....
  983. * Call procedures addkey, addskipfor, and addmark to generate
  984. * KEY, SKIPFOR, or MARK clauses when appropriate.
  985. *
  986. FUNCTION defbars
  987. PARAMETER m.popname, m.howmany, m.newname
  988. IF EMPTY(m.newname)
  989.     m.newname = m.popname
  990. ENDIF
  991. PRIVATE m.itemno, m.prompt,m.name, m.cPopExpr
  992. SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  993.    m.itemno = ALLTRIM(itemnum)
  994.    m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,LOWER(m.newname))))+"])", LOWER(m.newname))
  995.    IF NOT EMPTY(ALLTRIM(name))
  996.       m.name = name
  997.       \DEFINE BAR <<m.name>> OF <<m.cPopExpr>>
  998.    ELSE
  999.       \DEFINE BAR <<m.itemno>> OF <<m.cPopExpr>>
  1000.    ENDIF
  1001.    m.prompt = SUBSTR(PROMPT, 1,LEN(PROMPT))
  1002.    \\ PROMPT "<<m.prompt>>"
  1003.    DO addmark
  1004.    DO addkey
  1005.    DO addskipfor
  1006.    DO addmessage
  1007.    IF VAL(m.itemno)=m.howmany
  1008.       RETURN
  1009.    ENDIF
  1010. ENDSCAN
  1011.  
  1012. *
  1013. * DEFONBAR - Generate ON BAR... statements.
  1014. *
  1015. * Description:
  1016. * Generate ON BAR statements for each popup.
  1017. * For bars which have no submenus, but there is a command associated
  1018. * with them, issue ON SELECTION BAR... statements.  If a snippet is
  1019. * associated with the code then generate a call statement to the
  1020. * generated procedure containing the snippet code.
  1021. *
  1022. FUNCTION defonbar
  1023. PARAMETER m.popname,m.newname
  1024. PRIVATE m.itemno,  m.cPopExpr ,  m.cPopExpr2 
  1025. IF EMPTY(m.newname)
  1026.     m.newname = m.popname
  1027. ENDIF
  1028. SCAN FOR objtype=c_item AND LOWER(levelname)=m.popname
  1029.    IF EMPTY(ALLTRIM(name))
  1030.       m.itemno = ALLTRIM(itemnum)
  1031.    ELSE
  1032.       m.itemno = name
  1033.    ENDIF
  1034.    SKIP
  1035.    m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,LOWER(m.newname))))+"])", LOWER(m.newname))
  1036.    m.cPopExpr2 = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,LOWER(name))))+"])", LOWER(name))
  1037.  
  1038.    IF objtype=c_submenu AND numitems<>0
  1039.       \ON BAR <<m.itemno>> OF <<m.cPopExpr>>
  1040.       \\ ACTIVATE POPUP <<m.cPopExpr2>>
  1041.       SKIP -1
  1042.    ELSE
  1043.       SKIP -1
  1044.       DO onselection WITH "BAR", m.itemno, m.newname
  1045.    ENDIF
  1046. ENDSCAN
  1047.  
  1048. *
  1049. * GLOBALDEFAULTS - Generate global default statements
  1050. *
  1051. * Description:
  1052. * Search the menu database for information needed to generate any of
  1053. * the following commands:
  1054. * ON SELECTION MENU <name> DO <action>
  1055. * ON SELECTION POPUP ALL DO <action>
  1056. * ON SELECTION POPUP <name> DO <action>
  1057. * It is possible that none of the above mentioned statements will be
  1058. * generated.  It is also possible that the action is a snippet of
  1059. * code and a call to the generated procedure containing the snippet
  1060. * will be generated.
  1061. *
  1062. * First try to generate ON SELECTION MENU...
  1063. * Then try to generate ON POPUP ALL...
  1064. * Lastly, try to generate ON SELECTION POPUP...
  1065. *
  1066. FUNCTION globaldefaults
  1067. LOCATE FOR objtype = c_menu
  1068. LOCAL m.cPopExpr
  1069. m.mrk = MARK
  1070. IF FOUND() AND MARK <> ""
  1071.    IF MARK = c_null
  1072.       \SET MARK OF MENU _MSYSMENU TO " "
  1073.    ELSE
  1074.       \SET MARK OF MENU _MSYSMENU TO "<<Mark>>"
  1075.    ENDIF
  1076. ENDIF
  1077. IF FOUND() AND NOT EMPTY(PROCEDURE)
  1078.    \ON SELECTION MENU _MSYSMENU
  1079.    DO genproccall
  1080. ENDIF
  1081. LOCATE FOR objtype = c_submenu AND objcode = c_global
  1082. IF FOUND() AND NOT EMPTY(PROCEDURE)
  1083.    \ON SELECTION POPUP ALL
  1084.    DO genproccall
  1085. ENDIF
  1086. SCAN FOR (objtype=c_submenu AND UPPER(levelname)<>"_MSYSMENU";
  1087.       AND NOT EMPTY(PROCEDURE))
  1088.   m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,ALLTRIM(LOWER(Levelname)))))+"])", ALLTRIM(LOWER(Levelname)))
  1089.    \ON SELECTION POPUP <<m.cPopExpr>>
  1090.    DO genproccall
  1091. ENDSCAN
  1092.  
  1093.  
  1094. ******************************************************************************
  1095. *
  1096. * Subroutines for processing menu clause options.
  1097. *
  1098. ******************************************************************************
  1099. *
  1100. * ADDMARK - Generate a MARK clause whenever appropriate.
  1101. *
  1102. * Description:
  1103. * Add a MARK clause to the current PAD or BAR definition.
  1104. * If a field named Mark is not empty, then add the continuation
  1105. * character, ";", to the previous line, and then add the MARK... clause.
  1106. *
  1107. FUNCTION addmark
  1108. IF MARK<>c_null AND MARK<>""
  1109.    \\ ;
  1110.    \    MARK "<<Mark>>"
  1111. ENDIF
  1112.  
  1113.  
  1114.  
  1115. *
  1116. * ADDKEY - Generate KEY... clause whenever appropriate.
  1117. *
  1118. * Description:
  1119. * Add a KEY clause to the current PAD or BAR definition.
  1120. * If a field named Keyname is not empty, then add the continuation
  1121. * character, ";", to the previous line, and then add the KEY... clause.
  1122. *
  1123. FUNCTION addkey
  1124. * Add support for intelligent Pad hotkeys. [Rev: 7][BEG]
  1125. * NOTE: For consistency, Pads no longer respect keyname and 
  1126. *       keylabel, they use the letter following "\<" or the 
  1127. *       first letter of the prompt of none is defined.
  1128. LOCAL cKeyname, cKeylabel, nPosition
  1129. IF objtype=c_item AND ;
  1130.    UPPER(levelname)="_MSYSMENU" AND ;
  1131.    EMPTY(keyname)                          
  1132.    nPosition = AT_C("\<",prompt)
  1133.    IF m.nPosition > 0 AND NOT EMPTY(SUBSTRC(prompt,m.nPosition+2,1))
  1134.       STORE c_key_padhotkey_LOC + UPPER(SUBSTRC(prompt,m.nPosition+2,1)) TO m.cKeyname
  1135.    ELSE
  1136.       IF !IsLeadByte(prompt)
  1137.           STORE c_key_padhotkey_LOC + UPPER(LEFT(prompt,1)) TO m.cKeyname
  1138.       ELSE
  1139.           STORE "" to m.cKeyname
  1140.       ENDIF
  1141.    ENDIF
  1142.    cKeylabel = ""
  1143. ELSE 
  1144.    cKeyname  = keyname
  1145.    cKeylabel = keylabel
  1146. ENDIF   
  1147. IF NOT EMPTY(m.cKeyname)
  1148.    \\ ;
  1149.    \    KEY <<m.cKeyname>>, "<<m.cKeylabel>>"
  1150. ENDIF
  1151. * Add support for intelligent Pad hotkeys. [Rev: 7][END]
  1152.  
  1153.  
  1154.  
  1155. *
  1156. * ADDSKIPFOR - Generate SKIP FOR... clause whenever appropriate.
  1157. *
  1158. * Description:
  1159. * Add a ADDSKIPFOR clause to the current PAD or BAR definition.
  1160. * If a field named Addskipfor is not empty, then add the continuation
  1161. * character, ";", to the previous line, and then add the SKIP FOR...
  1162. * clause.
  1163. *
  1164. FUNCTION addskipfor
  1165. PRIVATE m.skip
  1166. m.skip = skipfor
  1167. IF NOT EMPTY(skipfor)
  1168.    \\ ;
  1169.    \    SKIP FOR <<m.skip>>
  1170. ENDIF
  1171.  
  1172.  
  1173.  
  1174. *
  1175. * ADDMESSAGE - Generate MESSAGE clause whenever appropriate.
  1176. *
  1177. * Description:
  1178. * Add a MESSAGE clause to the current PAD or BAR definition.
  1179. * If a field named MESSAGE is not empty and it is not a 2.0 menu,
  1180. * then add the continuation character, ";", to the previous line,
  1181. * and then add the MESSAGE clause.
  1182. *
  1183. FUNCTION addmessage
  1184. IF !m.g_20mnx AND NOT EMPTY(MESSAGE)
  1185.    \\ ;
  1186.    \    MESSAGE <<Message>>
  1187. ENDIF
  1188.  
  1189.  
  1190.  
  1191. *
  1192. * HEADER - Generate generated program's header.
  1193. *
  1194. * Description:
  1195. * As a part of the automatically generated program's header generate
  1196. * program name, name of the author of the program, copyright notice,
  1197. * company name and address, and the word 'Description:' which will be
  1198. * followed with a short description of the generated code.
  1199. *
  1200. FUNCTION HEADER
  1201. \\*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1202. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1203. \*       <<m.g_verti1>> <<DATE()>>
  1204. \\<<PADC(UPPER(ALLTRIM(strippath(m.g_outfile))),IIF(SET("CENTURY")="ON",35,37))," ")>>
  1205. \\ <<TIME()>>  <<m.g_verti2>>
  1206. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1207. \*       <<m.g_corn5>><<REPLICATE(m.g_horiz,57)>><<m.g_corn6>>
  1208. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1209. \*       <<m.g_verti1>> <<m.g_devauthor>>
  1210. \\<<REPLICATE(" ",max(1,56-LEN(m.g_devauthor)))>><<m.g_verti2>>
  1211. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1212. \*       <<m.g_verti1>>
  1213. *- Localization support [Rev: 2][MOD]
  1214. \\ c_hdr_copyright_LOC <<YEAR(DATE())>>
  1215. IF LEN(ALLTRIM(m.g_devcompany)) <= 36
  1216.    \\ <<ALLTRIM(m.g_devcompany)>>
  1217.    \\<<REPLICATE(" ",max(1,37-LEN(ALLTRIM(m.g_devcompany))))>>
  1218.    \\<<m.g_verti2>>
  1219. ELSE
  1220.    \\ <<REPLICATE(" ",37)>><<m.g_verti2>>
  1221.    \*       <<m.g_verti1>> <<m.g_devcompany>>
  1222.    \\<<REPLICATE(" ",max(1,56-LEN(m.g_devcompany)))>><<m.g_verti2>>
  1223. ENDIF
  1224.  
  1225. \*       <<m.g_verti1>> <<m.g_devaddress>>
  1226. \\<<REPLICATE(" ",max(1,56-LEN(m.g_devaddress)))>><<m.g_verti2>>
  1227.  
  1228. \*       <<m.g_verti1>> <<ALLTRIM(m.g_devcity)>>, <<m.g_devstate>>
  1229. \\  <<ALLTRIM(m.g_devzip)>>
  1230. \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devcity)+ALLTRIM(m.g_devzip))))>>
  1231. \\<<m.g_verti2>>
  1232.  
  1233. IF !INLIST(ALLTRIM(UPPER(m.g_devctry)),"USA","COUNTRY") AND !EMPTY(m.g_devctry)
  1234.    \*       <<m.g_verti1>> <<ALLTRIM(m.g_devctry)>>
  1235.    \\<<REPLICATE(" ",50-(LEN(ALLTRIM(m.g_devctry))))>>
  1236.    \\<<m.g_verti2>>
  1237. ENDIF
  1238. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1239. *- Localization support [Rev: 2][MOD]
  1240. \*       <<m.g_verti1>> c_hdr_descript_LOC
  1241. \\                                            <<m.g_verti2>>
  1242. \*       <<m.g_verti1>>
  1243. *- Localization support [Rev: 2][MOD]
  1244. \\ c_hdr_string_LOC
  1245. \\    <<m.g_verti2>>
  1246. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1247. \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1248. \
  1249.  
  1250.  
  1251.  
  1252. *
  1253. * GENFUNCHEADER - Generate Comment for Function/Procedure.
  1254. *
  1255. FUNCTION genfuncheader
  1256. PARAMETER m.procname
  1257. PRIVATE m.place, m.prompt
  1258. m.g_snippcnt = m.g_snippcnt + 1
  1259. DO CASE
  1260.    CASE objtype = c_menu
  1261.       m.place = "ON SELECTION MENU _MSYSMENU"
  1262.    CASE objtype = c_submenu AND objcode = c_global
  1263.       m.place = "ON SELECTION POPUP ALL"
  1264.    CASE objtype = c_submenu AND objcode <> c_global
  1265.       m.place = "ON SELECTION POPUP "+LOWER(ALLTRIM(name))
  1266.    CASE objtype = c_item AND UPPER(levelname) = "_MSYSMENU"
  1267.       m.place = "ON SELECTION PAD "
  1268.    CASE objtype = c_item AND UPPER(levelname) <> "_MSYSMENU"
  1269.       m.place = "ON SELECTION BAR "+ALLTRIM(itemnum)+;
  1270.          +" OF POPUP "+LOWER(ALLTRIM(levelname))
  1271.    OTHERWISE
  1272.       m.place = ""
  1273. ENDCASE
  1274. \
  1275. \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1276. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1277. \*       <<m.g_verti1>> <<UPPER(PADR(m.procname,10))>>  <<m.place>>
  1278. \\<<REPLICATE(" ",max(1,max(1,44-LEN(m.place))))>><<m.g_verti2>>
  1279. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1280. \*       <<m.g_verti1>> Procedure Origin:
  1281. \\<<REPLICATE(" ",39)>><<m.g_verti2>>
  1282. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1283. \*       <<m.g_verti1>> From Menu:
  1284. \\  <<ALLTRIM(strippath(m.g_outfile))>>
  1285. \\,            Record:  <<STR(RECNO(),3)>>
  1286. \\<<REPLICATE(" ",max(1,max(1,22-LEN(ALLTRIM(strippath(m.g_outfile))+STR(RECNO(),3))))))>>
  1287. \\<<m.g_verti2>>
  1288. \*       <<m.g_verti1>> Called By:  <<m.place>>
  1289. \\<<REPLICATE(" ",max(1,max(1,44-LEN(m.place))))>><<m.g_verti2>>
  1290. IF NOT EMPTY(PROMPT)
  1291.    m.prompt = removemeta()
  1292.    \*       <<m.g_verti1>> Prompt:     <<ALLTRIM(m.prompt)>>
  1293.    \\<<REPLICATE(" ",max(1,44-LEN(ALLTRIM(m.prompt))))>><<m.g_verti2>>
  1294. ENDIF
  1295. \*       <<m.g_verti1>> Snippet:
  1296. \\    <<ALLTRIM(STR(m.g_snippcnt,2))>>
  1297. \\<<REPLICATE(" ",max(1,44-LEN(ALLTRIM(STR(m.g_snippcnt,2)))))>><<m.g_verti2>>
  1298. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1299. \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1300. \*
  1301.  
  1302.  
  1303.  
  1304. *
  1305. * REMOVEMETA - Remove meta characters for documentation.
  1306. *
  1307. FUNCTION removemeta
  1308. PRIVATE m.prompt, m.hotkey
  1309. m.prompt = PROMPT
  1310. m.hotkey = AT("\<",m.prompt)
  1311. IF m.hotkey <> 0
  1312.    m.prompt = STUFF(m.prompt,m.hotkey,2,"")
  1313. ENDIF
  1314. m.disabl = AT("\",m.prompt)
  1315. IF m.disabl <> 0
  1316.    m.prompt = STUFF(m.prompt,m.disabl,1,"")
  1317. ENDIF
  1318. RETURN m.prompt
  1319.  
  1320.  
  1321. *
  1322. * COMMENTBLOCK - Generate a comment block.
  1323. *
  1324. FUNCTION commentblock
  1325. PARAMETER m.snippet
  1326. \
  1327. \*       <<m.g_corn1>><<REPLICATE(m.g_horiz,57)>><<m.g_corn2>>
  1328. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1329. DO CASE
  1330.    CASE m.snippet == "setup"
  1331.       \*       <<m.g_verti1>>
  1332.       *- Localization support [Rev: 2][MOD]
  1333.       \\ <<PADC( c_snip_setup_LOC ,56," ")>>
  1334.    CASE m.snippet == "cleanup"
  1335.       \*       <<m.g_verti1>>
  1336.       *- Localization support [Rev: 2][MOD]
  1337.       \\ <<PADC( c_snip_cleanup_LOC ,56," ")>>
  1338.    CASE m.snippet == "init"
  1339.       \*       <<m.g_verti1>>
  1340.       *- Localization support [Rev: 2][MOD]
  1341.       \\ <<PADC( c_snip_init_LOC ,56," ")>>
  1342.    CASE m.snippet == "menu"
  1343.       \*       <<m.g_verti1>>
  1344.       *- Localization support [Rev: 2][MOD]
  1345.       \\ <<PADC( c_snip_menu_LOC ,56," ")>>
  1346. ENDCASE
  1347. \\<<m.g_verti2>>
  1348. \*       <<m.g_verti1>><<REPLICATE(" ",57)>><<m.g_verti2>>
  1349. \*       <<m.g_corn3>><<REPLICATE(m.g_horiz,57)>><<m.g_corn4>>
  1350. \*
  1351. \
  1352.  
  1353. *
  1354. * ONSELECTION - Generate ON SELECTION... statements for menu items.
  1355. *
  1356. * Description:
  1357. * For pads and bars which have no submenu associated with them but
  1358. * instead have a non-empty Command field in the database, issue
  1359. * the ON SELECTION <command> statements.  If a snippet is associated
  1360. * with a pad then issue a call statement to the generated procedure
  1361. * containing the snippet.  Generated snippet procedure will be
  1362. * appended to the end of the output file.
  1363. *
  1364. FUNCTION onselection
  1365. PARAMETER m.which, m.name, m.ofname
  1366. PRIVATE m.trimname, m.basename, m.commd, m.cPopExpr 
  1367. IF EMPTY(PROCEDURE) AND EMPTY(COMMAND)
  1368.    RETURN
  1369. ENDIF
  1370.  
  1371. DO CASE
  1372.    CASE m.which == "pad"
  1373.       \ON SELECTION PAD <<m.name>>
  1374.    CASE m.which == "BAR"
  1375.       \ON SELECTION <<m.which+" "+m.name>>
  1376. ENDCASE
  1377.  
  1378. IF m.g_inform AND !m.g_shortcut AND m.which#"BAR"
  1379.     \\ OF (m.cMenuName)
  1380. ELSE
  1381.     m.cPopExpr = IIF(m.g_inform, "(a_menupops["+ALLTRIM(STR(ASCAN(g_apops,m.ofname)))+"])",m.ofname)
  1382.     \\ OF <<m.cPopExpr>>
  1383. ENDIF
  1384.  
  1385. IF objcode = c_proc
  1386.    DO gensnippname
  1387.    m.trimname = SYS(2014,UPPER(m.g_outfile),UPPER(m.g_homedir))
  1388.    m.trimname = stripext(m.trimname)
  1389.    m.basename = basename(m.trimname)
  1390.    \\ ;
  1391.    \    DO <<g_snippets[g_nsnippets,1]>> ;
  1392.    \    IN LOCFILE("<<m.trimname>>"
  1393.    \\ ,"MPX;MPR|FXP;PRG"
  1394.    \\ ,"
  1395.    *- Localization support [Rev: 2][MOD]
  1396.    \\c_ui_whereis_LOC
  1397.    \\ <<m.basename>>?")
  1398. ELSE
  1399.    m.commd = COMMAND
  1400.    \\ <<m.commd>>
  1401. ENDIF
  1402.  
  1403.  
  1404.  
  1405. *
  1406. * GENSNIPPNAME - Generate a unique name for snippet procedure.
  1407. *
  1408. * Description:
  1409. * Lookup the #NAME name of this snippet, or alternatively
  1410. * provide a unique name for a snippet of code associated with the
  1411. * generated menu.  Save this name in an array g_snippets.
  1412. *
  1413. FUNCTION gensnippname
  1414. g_nsnippets = g_nsnippets + 1
  1415. g_snippets[g_nsnippets,1] = getcname(PROCEDURE)
  1416. g_snippets[g_nsnippets,2] = RECNO()
  1417. IF MOD(g_nsnippets,25) = 0
  1418.    DIMENSION g_snippets [g_nsnippets+25,2]
  1419. ENDIF
  1420.  
  1421.  
  1422.  
  1423. *
  1424. * GENPROCCALL - Generate a call statement to snippet procedure.
  1425. *
  1426. * Description:
  1427. * Generate a call to the snippet procedure in the menu definition
  1428. * code.
  1429. *
  1430. FUNCTION genproccall
  1431. PRIVATE m.trimname, m.basename, m.proc
  1432. IF singleline()
  1433.    m.proc = PROCEDURE
  1434.    \\ <<MLINE(m.proc,1)>>
  1435. ELSE
  1436.    DO gensnippname
  1437.    m.trimname = SYS(2014,UPPER(m.g_outfile),UPPER(m.g_homedir))
  1438.    m.trimname = stripext(m.trimname)
  1439.    m.basename = basename(m.trimname)
  1440.    \\ ;
  1441.    \    DO <<g_snippets[m.g_nsnippets,1]>> ;
  1442.    \    IN LOCFILE("<<m.trimname>>"
  1443.    \\ ,"MPX;MPR|FXP;PRG"
  1444.    \\ ,"
  1445.    *- Localization support [Rev: 2][MOD]
  1446.    \\c_ui_whereis_LOC
  1447.    \\ <<m.basename>>?")
  1448. ENDIF
  1449.  
  1450.  
  1451.  
  1452. *
  1453. * SINGLELINE - Determine if Memo contains only one line.
  1454. *
  1455. * Description:
  1456. * This procedure is used to decide if an ON SELECTION... statement
  1457. * and a snippet procedure will be needed (i.e., if more than one
  1458. * line of snippet code then its a snippet, otherwise its a command)
  1459. *
  1460. FUNCTION singleline
  1461. PRIVATE m.size, m.i
  1462. m.size = MEMLINES(PROCEDURE)
  1463. IF m.size = 1
  1464.    RETURN .T.
  1465. ENDIF
  1466. m.i = m.size
  1467. DO WHILE m.i > 1
  1468.    m.line = MLINE(PROCEDURE, m.i)
  1469.    IF NOT EMPTY(m.line)
  1470.       RETURN .F.
  1471.    ENDIF
  1472.    m.i = m.i - 1
  1473. ENDDO
  1474.  
  1475.  
  1476.  
  1477. *
  1478. * GENPROCEDURES - Generate procedure/snippet code.
  1479. *
  1480. * Description:
  1481. * Generate 'PROCEDURE procedurename' statement and its body.
  1482. *
  1483. FUNCTION genprocedures
  1484. PRIVATE m.i
  1485. IF m.g_graphic
  1486.    SET MESSAGE TO c_msg_genprocs_LOC   && Localization support [Rev: 2][MOD]
  1487. ENDIF
  1488. FOR m.i = 1 TO m.g_nsnippets
  1489.    GOTO RECORD (g_snippets[m.i,2])
  1490.    DO genfuncheader WITH g_snippets[m.i,1]
  1491.    \PROCEDURE <<g_snippets[m.i,1]>>
  1492.    DO writecode WITH PROCEDURE
  1493.    \
  1494. ENDFOR
  1495.  
  1496.  
  1497.  
  1498. *
  1499. * WRITECODE - Write contents of a memo to a low level file.
  1500. *
  1501. * Description:
  1502. * Receive a memo field as a parameter and write its contents out
  1503. * to the currently opened low level file whose handle is stored
  1504. * in the system memory variable _TEXT.  Contents of the system
  1505. * memory variable _pretext will affect the positioning of the
  1506. * generated text.
  1507. *
  1508. FUNCTION writecode
  1509. PARAMETER m.memo, m.codefield
  1510. PRIVATE m.lines, m.i, m.thisline, m.lHadActPopup
  1511. IF TYPE("m.codefield") # "C"
  1512.     m.codefield = ""
  1513. ENDIF
  1514. m.lHadActPopup = .F.
  1515. m.lines = MEMLINES(m.memo)
  1516. _MLINE = 0
  1517. FOR m.i = 1 TO m.lines
  1518.    m.thisline = MLINE(m.memo, 1, _MLINE)
  1519.    DO CASE
  1520.    CASE m.g_shortcut  AND m.codefield=="cleanup" AND  !m.lHadActPopup AND LEFT(UPPER(LTRIM(m.thisline)),5) == "#PREP"    && #PREPOPUP in Cleanup
  1521.     DO actpopup
  1522.     m.lHadActPopup = .T.
  1523.     m.g_prepopup = .F.
  1524.    CASE m.g_shortcut AND m.codefield#"cleanup" AND LEFT(UPPER(LTRIM(m.thisline)),5) == "#PREP"        && #PREPOPUP in Setup
  1525.     m.g_prepopup = .T.
  1526.    CASE LEFT(UPPER(LTRIM(m.thisline)),5) == "#INSE"   && #INSERT
  1527.         DO GenInsertCode WITH m.thisline
  1528.    CASE INLIST(LEFT(UPPER(LTRIM(m.thisline)),5) ,"#NAME","#PREP")    &&skip #PREP for non Shortcut menus
  1529.     * Do nothing
  1530.    OTHERWISE
  1531.          \<<m.thisline>>
  1532.    ENDCASE
  1533. ENDFOR
  1534.  
  1535.  
  1536.  
  1537. *
  1538. * GENSETUPCLEANUP - Generate setup/cleanup code.
  1539. *
  1540. FUNCTION GenSetupCleanup
  1541. PARAMETER m.choice
  1542. LOCATE FOR objtype = IIF(m.g_shortcut,c_shortcut,IIF(m.g_inform,c_sdimenu,c_menu))
  1543. DO CASE
  1544.    CASE m.choice == "setup"
  1545.       IF m.g_inform
  1546.          DO sdiheader
  1547.       ENDIF    
  1548.       IF EMPTY(setup)
  1549.          RETURN
  1550.       ENDIF
  1551.       IF m.g_graphic
  1552.          SET MESSAGE TO c_msg_gensetup_LOC   && Localization support [Rev: 2][MOD]
  1553.       ENDIF
  1554.       DO commentblock WITH m.choice
  1555.       DO writecode WITH setup
  1556.    CASE m.choice == "cleanup"
  1557.       IF !m.g_prepopup AND ATC("#PREP",cleanup)=0
  1558.               DO actpopup
  1559.       ENDIF
  1560.       IF !EMPTY(cleanup)
  1561.           IF m.g_graphic
  1562.              SET MESSAGE TO c_msg_gencleanup_LOC   && Localization support [Rev: 2][MOD]
  1563.           ENDIF
  1564.           DO commentblock WITH m.choice
  1565.           DO writecode WITH cleanup,m.choice
  1566.     ENDIF
  1567.       IF m.g_prepopup
  1568.               DO actpopup
  1569.       ENDIF
  1570. ENDCASE
  1571.  
  1572.  
  1573. *
  1574. * GENINSERTCODE - Emit code from the #insert file, if any
  1575. *
  1576. FUNCTION GenInsertCode
  1577. PARAMETER strg
  1578. PRIVATE m.word1, m.filname, m.ins_fp, m.buffer
  1579. IF UPPER(LEFT(LTRIM(m.strg),5)) == "#INSE"
  1580.    m.word1 = wordnum(m.strg,1)
  1581.    m.filname = SUBSTR(m.strg,LEN(m.word1)+1)
  1582.    m.filname = ALLTRIM(CHRTRAN(m.filname,CHR(9),""))
  1583.  
  1584.    * Bail out if we can't find the file either explicitly or on the DOS path
  1585.    IF !FILE(m.filname)
  1586.       filname = FULLPATH(m.filname,1)
  1587.       IF !FILE(m.filname)
  1588.          \*Insert file <<m.filname>> could not be found
  1589.          RETURN
  1590.       ENDIF
  1591.    ENDIF
  1592.  
  1593.    ins_fp = FOPEN(m.filname)
  1594.    IF ins_fp > 0
  1595.       \* Inserted from <<strippath(m.filname)>>
  1596.       DO WHILE !FEOF(ins_fp)
  1597.          m.buffer = FGETS(ins_fp)
  1598.          \<<m.buffer>>
  1599.       ENDDO
  1600.       =FCLOSE(m.ins_fp)
  1601.       \* End of inserted lines
  1602.    ENDIF
  1603. ENDIF
  1604.  
  1605.  
  1606. ******************************************************************************
  1607. *
  1608. * Code assocated with thermometer.
  1609. *
  1610. ******************************************************************************
  1611. *
  1612. * ACTTHERM(<text>) - Activate thermometer.
  1613. *
  1614. * Description:
  1615. * Activates thermometer.  Update the thermometer with UPDTHERM().
  1616. * Thermometer window is named "thermometer."  Be sure to RELEASE
  1617. * this window when done with thermometer.  Creates the global
  1618. * m.g_thermwidth.
  1619. *
  1620. FUNCTION acttherm
  1621. PARAMETER m.text
  1622. PRIVATE m.prompt
  1623. IF m.g_graphic
  1624.    m.prompt = m.g_outfile
  1625.    m.prompt = thermfname(m.prompt)
  1626.    DO CASE
  1627.       CASE _WINDOWS
  1628.            LOCAL cWinColor
  1629.            cWinColor = rgbscheme(1, 2)
  1630.          DEFINE WINDOW thermomete ;
  1631.             AT  INT((SROW() - (( 5.615 * ;
  1632.             FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1633.             FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  1634.             INT((SCOL() - (( 63.833 * ;
  1635.             FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1636.             FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  1637.             SIZE 5.615,63.833 ;
  1638.             FONT m.g_dlgface, m.g_dlgsize ;
  1639.             STYLE m.g_dlgstyle ;
  1640.             NOFLOAT ;
  1641.             NOCLOSE ;
  1642.             NONE ;
  1643.             COLOR &cWinColor 
  1644.          MOVE WINDOW thermomete CENTER
  1645.          ACTIVATE WINDOW thermomete NOSHOW
  1646.          @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
  1647.          @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
  1648.          @ 0.000,0.000 TO 0.000,63.833 ;
  1649.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1650.          @ 0.000,0.000 TO 5.615,0.000 ;
  1651.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1652.          @ 0.385,0.667 TO 5.231,0.667 ;
  1653.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1654.          @ 0.308,0.667 TO 0.308,63.167 ;
  1655.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1656.          @ 0.385,63.000 TO 5.308,63.000 ;
  1657.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1658.          @ 5.231,0.667 TO 5.231,63.167 ;
  1659.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1660.          @ 5.538,0.000 TO 5.538,63.833 ;
  1661.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1662.          @ 0.000,63.667 TO 5.615,63.667 ;
  1663.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1664.          @ 3.000,3.333 TO 4.231,3.333 ;
  1665.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1666.          @ 3.000,60.333 TO 4.308,60.333 ;
  1667.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1668.          @ 3.000,3.333 TO 3.000,60.333 ;
  1669.             COLOR RGB(128, 128, 128, 128, 128, 128)
  1670.          @ 4.231,3.333 TO 4.231,60.333 ;
  1671.             COLOR RGB(255, 255, 255, 255, 255, 255)
  1672.          m.g_thermwidth = 56.269
  1673.       CASE _MAC
  1674.          DEFINE WINDOW thermomete ;
  1675.             AT  INT((SROW() - (( 5.62 * ;
  1676.             FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1677.             FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
  1678.             INT((SCOL() - (( 63.83 * ;
  1679.             FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
  1680.             FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
  1681.             SIZE 5.62,63.83 ;
  1682.             FONT m.g_dlgface, m.g_dlgsize ;
  1683.             STYLE m.g_dlgstyle ;
  1684.             NOFLOAT ;
  1685.             NOCLOSE ;
  1686.             NONE ;
  1687.             COLOR RGB(0, 0, 0, 192, 192, 192)
  1688.          MOVE WINDOW thermomete CENTER
  1689.          ACTIVATE WINDOW thermomete NOSHOW
  1690.          @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
  1691.             COLOR RGB(192, 192, 192, 192, 192, 192)
  1692.          IF ISCOLOR()
  1693.             @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
  1694.                COLOR RGB(192, 192, 192, 192, 192, 192)
  1695.             @ 0.000,0.000 TO 0.000,63.83 ;
  1696.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1697.             @ 0.000,0.000 TO 5.62,0.000 ;
  1698.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1699.             @ 0.385,0.67 TO 5.23,0.67 ;
  1700.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1701.             @ 0.31,0.67 TO 0.31,63.17 ;
  1702.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1703.             @ 0.385,63.000 TO 5.31,63.000 ;
  1704.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1705.             @ 5.23,0.67 TO 5.23,63.17 ;
  1706.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1707.             @ 5.54,0.000 TO 5.54,63.83 ;
  1708.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1709.             @ 0.000,63.67 TO 5.62,63.67 ;
  1710.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1711.             @ 3.000,3.33 TO 4.23,3.33 ;
  1712.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1713.             @ 3.000,60.33 TO 4.31,60.33 ;
  1714.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1715.             @ 3.000,3.33 TO 3.000,60.33 ;
  1716.                COLOR RGB(128, 128, 128, 128, 128, 128)
  1717.             @ 4.23,3.33 TO 4.23,60.33 ;
  1718.                COLOR RGB(255, 255, 255, 255, 255, 255)
  1719.          ELSE
  1720.             @ 0.000, 0.000 TO 5.62, 63.830  PEN 2
  1721.             @ 0.230, 0.500 TO 5.39, 63.333  PEN 1
  1722.          ENDIF
  1723.          @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
  1724.             COLOR RGB(0,0,0,192,192,192)
  1725.          @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
  1726.             COLOR RGB(0,0,0,192,192,192)
  1727.  
  1728.          m.g_thermwidth = 56.27
  1729.          IF !ISCOLOR()
  1730.             @ 3.000,3.33 TO 4.23, (m.g_thermwidth + 1) + 3.33
  1731.          ENDIF
  1732.    ENDCASE
  1733.    SHOW WINDOW thermomete TOP
  1734. ELSE
  1735.    m.prompt = SUBSTR(SYS(2014,UPPER(m.g_outfile)),1,48)+;
  1736.       IIF(LEN(m.g_outfile)>48,"...","")
  1737.    DEFINE WINDOW thermomete;
  1738.       FROM INT((SROW()-6)/2), INT((SCOL()-57)/2) ;
  1739.       TO INT((SROW()-6)/2) + 6, INT((SCOL()-57)/2) + 57;
  1740.       DOUBLE COLOR SCHEME 5
  1741.    ACTIVATE WINDOW thermomete NOSHOW
  1742.    m.g_thermwidth = 50
  1743.    @ 0,3 SAY m.text
  1744.    @ 1,3 SAY UPPER(m.prompt)
  1745.    @ 2,1 TO 4,m.g_thermwidth+4 &g_boxstrg
  1746.    SHOW WINDOW thermomete TOP
  1747. ENDIF
  1748. RETURN
  1749.  
  1750.  
  1751. *
  1752. * UPDTHERM(<percent>) - Update thermometer.
  1753. *
  1754. FUNCTION updtherm
  1755. PARAMETER m.percent
  1756. PRIVATE m.nblocks, m.percent
  1757. ACTIVATE WINDOW thermomete
  1758. m.nblocks = (m.percent/100) * (m.g_thermwidth)
  1759. DO CASE
  1760.    CASE _WINDOWS
  1761.       @ 3.000,3.333 TO 4.231,m.nblocks + 3.333 ;
  1762.          PATTERN 1 COLOR RGB(128, 128, 128, 128, 128, 128)
  1763.    CASE _MAC
  1764.       @ 3.000,3.33 TO 4.23,m.nblocks + 3.33 ;
  1765.          PATTERN 1 COLOR RGB(0, 0, 128, 0, 0, 128)
  1766.    OTHERWISE
  1767.       @ 3,3 SAY REPLICATE("█",m.nblocks)
  1768. ENDCASE
  1769.  
  1770. *
  1771. * DEACTTHERMO - Deactivate and Release thermometer window.
  1772. *
  1773. FUNCTION deactthermo
  1774. RELEASE WINDOW thermomete
  1775.  
  1776.  
  1777. *
  1778. * Function: THERMFNAME
  1779. *
  1780. * [Rev: 8]
  1781. * Modified to use CutFileLoc() if name is too long.  
  1782. * Moved global variables to top of program.
  1783. * Merged thermometer window font info with dialogs.
  1784. FUNCTION thermfname
  1785. PARAMETER m.fname
  1786. IF TXTWIDTH(m.fname,m.g_dlgface,m.g_dlgsize,m.g_dlgstyle) > c_space
  1787.    m.fname = CutFileLoc(m.fname, c_space -1)
  1788. ENDIF
  1789. RETURN PROPER(m.fname)
  1790.  
  1791.  
  1792.  
  1793. ******************************************************************************
  1794. *
  1795. * Error Handling Code.
  1796. *
  1797. ******************************************************************************
  1798. *
  1799. * ERRORHANDLER - Error Processing Center.
  1800. *
  1801. FUNCTION errorhandler
  1802. PARAMETERS m.messg, m.lineno, m.code
  1803. IF ERROR() = 22  && Too many memory variables
  1804.    =MESSAGEBOX(c_err_toomanymemvars_LOC + REPL(c_CRLF,2) + c_msg_genstopped_LOC)    && Tell the user [Rev: 6][ADD]
  1805.    ON ERROR &onerror
  1806.    DO cleanup
  1807.    CANCEL       && Early exit
  1808. ENDIF
  1809. DO CASE
  1810.    CASE c_DEBUG   && Add debug mode [Rev: 4][BEG]
  1811.       =MESSAGEBOX(m.messg)
  1812.       SET DEBUG ON
  1813.       SET STEP ON
  1814.       * Add debug mode [Rev: 4][END]
  1815.    CASE m.code == c_error_1  && Minor
  1816.       DO errlog WITH m.messg, m.lineno
  1817.       DO errshow WITH m.messg, m.lineno, c_error_1Icon   && Show minor errors [Rev: 6][ADD]
  1818.       m.g_status = 1
  1819.    CASE m.code == c_error_2  && Serious
  1820.       DO errlog  WITH m.messg, m.lineno
  1821.       DO errshow WITH m.messg, m.lineno, c_error_2Icon   && Pass Error Icon [Rev: 6][ADD]
  1822.       m.g_error = .T.
  1823.       m.g_status = 2
  1824.       ON ERROR
  1825.    CASE m.code == c_error_3  && Fatal
  1826.       IF NOT m.g_nohandle
  1827.          DO errlog  WITH m.messg, m.lineno
  1828.       ENDIF
  1829.       WAIT WINDOW c_msg_genstopped_LOC NOWAIT   && Tell the user they are done. [Rev: 6][ADD]
  1830.       DO errshow WITH m.messg, m.lineno, c_error_3Icon   && Pass Error Icon [Rev: 6][ADD]
  1831.       WAIT CLEAR
  1832.       IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1833.          RELEASE WINDOW thermomete
  1834.       ENDIF
  1835.       ON ERROR
  1836.       DO cleanup
  1837.       CANCEL      && Early exit
  1838. ENDCASE
  1839. RETURN
  1840.  
  1841.  
  1842. *
  1843. * ESCHANDLER - Escape handler.
  1844. *
  1845. FUNCTION eschandler
  1846. ON ERROR
  1847. WAIT WINDOW c_msg_genstopped_LOC NOWAIT   && Localization support [Rev: 2][MOD]
  1848. DO builddisable
  1849. IF m.g_status > 0
  1850.    ERASE (m.g_outfile)
  1851. ENDIF
  1852. IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1853.    RELEASE WINDOW thermomete
  1854. ENDIF
  1855. DO cleanup
  1856. CANCEL      && Early exit
  1857.  
  1858.  
  1859. *
  1860. * ERRLOG - Insert error message into the error log.
  1861. *
  1862. FUNCTION errlog
  1863. PARAMETER m.messg, m.lineno
  1864. PRIVATE m.savehandle
  1865. m.savehandle = _TEXT
  1866. DO openerrfile
  1867. SET CONSOLE OFF
  1868.  
  1869. \\GENERATOR: <<ALLTRIM(m.messg)>>
  1870. IF NOT EMPTY(m.lineno)
  1871.    \\ LINE NUMBER: <<m.lineno>>
  1872. ENDIF
  1873. \
  1874. = FCLOSE(_TEXT)
  1875. _TEXT = m.savehandle
  1876. RETURN
  1877.  
  1878.  
  1879. *
  1880. * ERRSHOW - Display error message in the alert box.
  1881. *
  1882. FUNCTION errshow
  1883. PARAMETER m.msg, m.lineno, m.msgicon
  1884. PRIVATE m.curcursor
  1885. * Modify to utilize native MESSAGEBOX() function. [Rev: 6][BEG]
  1886. IF m.g_graphic
  1887.    m.msg = m.msg + REPL(c_CRLF,2) + ;
  1888.            c_err_lineno_LOC + STR(m.lineno, 4)  
  1889.    =MESSAGEBOX(m.msg, m.msgicon, c_err_title_LOC)
  1890. ELSE
  1891.    DEFINE WINDOW alert;
  1892.       FROM INT((SROW()-6)/2), INT((SCOL()-50)/2) TO INT((SROW()-6)/2) + 6, INT((SCOL()-50)/2) + 50 ;
  1893.       FLOAT NOGROW NOCLOSE NOZOOM    SHADOW DOUBLE;
  1894.       COLOR SCHEME 7
  1895.  
  1896.    ACTIVATE WINDOW alert
  1897.    @ 0,0 CLEAR
  1898.    @ 1,0 SAY PADC(SUBSTR(m.msg,1,44)+;
  1899.       IIF(LEN(m.msg)>44,"...",""), WCOLS())
  1900.    @ 2,0 SAY PADC(c_err_lineno_LOC + STR(m.lineno, 4), WCOLS())   && Localization support [Rev: 2][MOD]
  1901.    @ 3,0 SAY PADC(c_err_presskey_LOC, WCOLS())   && Localization support [Rev: 2][MOD]
  1902.    m.curcursor = SET( "CURSOR" )
  1903.    SET CURSOR OFF
  1904.    WAIT ""
  1905.    RELEASE WINDOW alert
  1906.    SET CURSOR &curcursor
  1907.    RELEASE WINDOW alert
  1908. ENDIF
  1909. * Modify to utilize native MESSAGEBOX() function. [Rev: 6][END]
  1910. RETURN
  1911.  
  1912.  
  1913.  
  1914. *
  1915. * OPENERRFILE - Open error file.
  1916. *
  1917. FUNCTION openerrfile
  1918. PRIVATE m.errfile, m.errhandle
  1919. m.errfile   = m.g_errlog+".ERR"
  1920. m.errhandle = FOPEN(m.errfile,2)
  1921. IF m.errhandle < 0
  1922.    m.errhandle = FCREATE(m.errfile)
  1923.    IF m.errhandle < 0
  1924.       DO errshow WITH c_err_noopenerr_LOC, LINENO()   && Localization support [Rev: 2][MOD]
  1925.       m.g_status = 2
  1926.       IF WEXIST("Thermomete") AND WVISIBLE("Thermomete")
  1927.          RELEASE WINDOW thermomete
  1928.       ENDIF
  1929.       ON ERROR
  1930.       RETURN TO MASTER
  1931.    ENDIF
  1932. ELSE
  1933.    = FSEEK(m.errhandle,0,2)
  1934. ENDIF
  1935. IF SET("TEXTMERGE") = "OFF"
  1936.    SET TEXTMERGE ON
  1937. ENDIF
  1938. _TEXT = m.errhandle
  1939.  
  1940.  
  1941.  
  1942. *
  1943. * GETCNAME - Manufacture a procedure name, unless there is a #NAME directive
  1944. *
  1945. FUNCTION getcname
  1946. PARAMETERS snippet
  1947. PRIVATE ALL
  1948. IF proctype = 1
  1949.    numlines = MEMLINES(snippet)
  1950.    IF m.numlines > 0
  1951.       _MLINE = 0
  1952.       m.i = 1
  1953.       DO WHILE m.i <= m.numlines
  1954.          m.thisline = UPPER(ALLTRIM(MLINE(snippet,1, _MLINE)))
  1955.          DO CASE
  1956.         CASE LEFT(m.thisline,5) == "#NAME"
  1957.                RETURN ALLTRIM(SUBSTR(m.thisline,6))
  1958.             CASE EMPTY(m.thisline) OR iscomment(m.thisline)
  1959.                * Do nothing.  Get next line.
  1960.             OTHERWISE
  1961.                EXIT
  1962.          ENDCASE
  1963.          m.i = m.i + 1
  1964.       ENDDO
  1965.    ENDIF
  1966. ENDIF
  1967. RETURN LOWER(SYS(2015))
  1968.  
  1969.  
  1970. *
  1971. * ISCOMMENT - Determine if textline is a comment line.
  1972. *
  1973. FUNCTION IsComment
  1974. PARAMETER m.textline
  1975. PRIVATE m.asterisk, m.isnote, m.ampersand, m.statement
  1976. IF EMPTY(m.textline)
  1977.    RETURN .F.
  1978. ENDIF
  1979. m.statement = UPPER(ALLTRIM(m.textline))
  1980.  
  1981. m.asterisk  = AT("*", LEFT(m.statement,1))
  1982. m.ampersand = AT(CHR(38)+CHR(38), LEFT(m.statement,2))
  1983. m.isnote    = AT("NOTE", LEFT(m.statement,4))
  1984. DO CASE
  1985.    CASE (m.asterisk = 1 OR m.ampersand = 1)
  1986.       RETURN .T.
  1987.    CASE (m.isnote = 1 ;
  1988.          AND (LEN(m.statement) <= 4 OR SUBSTR(m.statement,5,1) = ' '))
  1989.       * Don't be fooled by something like "notebook = 7"
  1990.       RETURN .T.
  1991. ENDCASE
  1992. RETURN .F.
  1993.  
  1994.  
  1995. *
  1996. * WORDNUM - Returns w_num-th word from string strg
  1997. *
  1998. FUNCTION wordnum
  1999. PARAMETERS strg,w_num
  2000. PRIVATE strg,s1,w_num,ret_str
  2001. m.s1 = ALLTRIM(m.strg)
  2002. * Replace tabs with spaces
  2003. m.s1 = CHRTRAN(m.s1,CHR(9)," ")
  2004. * Reduce multiple spaces to a single space
  2005. DO WHILE AT('  ',m.s1) > 0
  2006.    m.s1 = STRTRAN(m.s1,'  ',' ')
  2007. ENDDO
  2008. ret_str = ""
  2009. DO CASE
  2010.    CASE m.w_num > 1
  2011.       DO CASE
  2012.          CASE AT(" ",m.s1,m.w_num-1) = 0   && No word w_num.  Past end of string.
  2013.             m.ret_str = ""
  2014.          CASE AT(" ",m.s1,m.w_num) = 0     && Word w_num is last word in string.
  2015.             m.ret_str = SUBSTR(m.s1,AT(" ",m.s1,m.w_num-1)+1,255)
  2016.          OTHERWISE                         && Word w_num is in the middle.
  2017.             m.strt_pos = AT(" ",m.s1,m.w_num-1)
  2018.             m.ret_str  = SUBSTR(m.s1,strt_pos,AT(" ",m.s1,m.w_num)+1 - strt_pos)
  2019.       ENDCASE
  2020.    CASE m.w_num = 1
  2021.       IF AT(" ",m.s1) > 0               && Get first word.
  2022.          m.ret_str = SUBSTR(m.s1,1,AT(" ",m.s1)-1)
  2023.       ELSE                              && There is only one word.  Get it.
  2024.          m.ret_str = m.s1
  2025.       ENDIF
  2026. ENDCASE
  2027. RETURN ALLTRIM(m.ret_str)
  2028.  
  2029.  
  2030. *
  2031. * VERSNUM - Return string corresponding to FoxPro version number
  2032. *
  2033. FUNCTION versnum
  2034. RETURN STRTRAN(SUBS(VERS(),AT(".",VERS())-2),"0","",1,1)
  2035.  
  2036. PROCEDURE sdiheader
  2037. \* To attach this menu to your Top-Level form, 
  2038. \* call it from the Init event of the form:
  2039. \
  2040. \* Syntax: DO <mprname> WITH <oFormRef> [,<cMenuname>|<lRename>][<lUniquePopups>]
  2041. \
  2042. \*    oFormRef - form object reference (THIS)
  2043. \*    cMenuname - name for menu (this is required for Append menus - see below)
  2044. \*    lRename - renames Name property of your form
  2045. \*    lUniquePopups - determines whether to generate unique ids for popup names
  2046. \            
  2047. \*     example:
  2048. \
  2049. \*    PROCEDURE Init
  2050. \*        DO mymenu.mpr WITH THIS,.T.
  2051. \*    ENDPROC
  2052. \
  2053. \* Use the optional 2nd parameter if you plan on running multiple instances of your 
  2054. \* Top-Level form. The logical lRename parameter will change the name property 
  2055. \* of your form to the same name given the menu and may cause conflicts in your 
  2056. \* code if you directly reference the form by name.
  2057. \
  2058. \* You will also need to remove the menu when the form is destroyed so that it does 
  2059. \* not remain in memory unless you wish to reactivate it later in a new form.
  2060. \
  2061. \* If you passed the optional lRename parameter as .T. as in the above example, 
  2062. \* you can easily remove the menu in the form's Destroy event as shown below.
  2063. \* This strategy is ideal when using multiple instances of Top-Level forms.
  2064. \
  2065. \*    example:
  2066. \
  2067. \*    PROCEDURE Destroy
  2068. \*        RELEASE MENU (THIS.Name) EXTENDED
  2069. \*    ENDPROC
  2070. \
  2071. \* Using Append/Before/After location options:
  2072. \
  2073. \*   You might want to append a menu to an existing Top-Level form by setting 
  2074. \*   the Location option in the General Options dialog. In order to do this, you 
  2075. \*   must pass the name of the menu in which to attach the new one. The second
  2076. \*   parameter is required here. If you originally created the menu with the lRename 
  2077. \*   parameter = .T., then you can update the menu with code similar to the following:
  2078. \
  2079. \*    example:
  2080. \
  2081. \*    DO mymenu2.mpr WITH THISFORM,THISFORM.name
  2082. \*
  2083. \* Using lUniquePopups:
  2084. \
  2085. \*   If you are running this menu multiple times in your application, such as in multiple 
  2086. \*   instances of the same top-level form, you should pass .T. to the lUniquePopups 
  2087. \*   parameter so that unique popup names are generated to avoid possible conflicts.
  2088. \
  2089. \*    example:
  2090. \
  2091. \*    PROCEDURE Init
  2092. \*        DO mymenu.mpr WITH THIS,.T.,.T.
  2093. \*    ENDPROC
  2094. \*
  2095. \* Note: Parm4-Parm9 are not reserved and freely available for use with your menu code.
  2096. \*
  2097. \
  2098. \LPARAMETERS oFormRef, getMenuName, lUniquePopups, parm4, parm5, parm6, parm7, parm8, parm9
  2099. \LOCAL cMenuName, nTotPops, a_menupops
  2100. \IF TYPE("m.oFormRef") # "O" OR ;
  2101. \  LOWER(m.oFormRef.BaseClass) # 'form' OR ;
  2102. \  m.oFormRef.ShowWindow # 2
  2103. \    MESSAGEBOX(<<c_sdierrdisplay_loc>>)
  2104. \    RETURN
  2105. \ENDIF
  2106. \m.cMenuName = IIF(TYPE("m.getMenuName")="C",m.getMenuName,SYS(2015))
  2107. \IF TYPE("m.getMenuName")="L" AND m.getMenuName
  2108. \    m.oFormRef.Name = m.cMenuName 
  2109. \ENDIF
  2110. LOCAL ntotpops,cPopRef ,i
  2111. SELECT PADR(LOWER(name),25) FROM (DBF());
  2112.     WHERE numitems#0 AND objtype =2 AND ATC("_MSYSMENU",levelname)=0;
  2113.     INTO ARRAY g_aPops
  2114. m.ntotpops=_TALLY
  2115. IF m.ntotpops>0
  2116.     DIMENSION g_aPops[m.ntotpops]
  2117.     \DIMENSION a_menupops[<<m.ntotpops>>]
  2118.     \IF TYPE("m.lUniquePopups")="L" AND m.lUniquePopups
  2119.     \    FOR nTotPops = 1 TO ALEN(a_menupops)
  2120.     \        a_menupops[m.nTotPops]= SYS(2015)
  2121.     \    ENDFOR
  2122.     \ELSE
  2123.     FOR i = 1 TO ALEN(g_aPops)
  2124.         g_aPops[m.i] = ALLTRIM(g_aPops[m.i])
  2125.         \    a_menupops[<<m.i>>]="<<LOWER(g_aPops[m.i])>>"
  2126.     ENDFOR
  2127.     \ENDIF
  2128.     \
  2129. ENDIF
  2130. ENDFUNC
  2131.  
  2132.  
  2133. * GetMenuType
  2134. * Description: Determines which type of menu we have.
  2135. * Parameters:
  2136. * Return value:
  2137. *
  2138. PROCEDURE GetMenuType
  2139. * Determine if we have a shortcut menu
  2140. LOCATE FOR objtype = c_shortcut
  2141. IF FOUND()
  2142.     m.g_shortcut   = .T.
  2143.     RETURN
  2144. ENDIF
  2145.  
  2146. * Determine if we have SDI menu
  2147. LOCATE FOR objtype = c_sdimenu
  2148. IF FOUND()
  2149.     m.g_inform     = .T.
  2150. ENDIF
  2151. RETURN
  2152.  
  2153. * actpopup
  2154. * Description: writes out code to 
  2155. * activate popup if we have shortcut menu
  2156. * Parameters:
  2157. * Return value:
  2158. *
  2159. PROCEDURE actpopup
  2160. DO CASE
  2161. CASE m.g_shortcut
  2162.     \ACTIVATE POPUP <<m.g_shortcutname>>
  2163. CASE m.g_inform AND m.g_location = c_replace
  2164.     \ACTIVATE MENU (m.cMenuName) NOWAIT
  2165. CASE m.g_inform
  2166.     IF VAL(SUBSTR(VERS(),RAT(".",VERS())+1,4)) > 380
  2167.         \ACTIVATE MENU (m.cMenuName) NOWAIT
  2168.     ELSE
  2169.         * Temporary work-around for refresh issue with appended popups
  2170.         \KEYBOARD "{RIGHTARROW}"
  2171.         \ACTIVATE MENU  (m.cMenuName) PAD(GETPAD(m.cMenuName,CNTPAD(m.cMenuName)))
  2172.     ENDIF
  2173. ENDCASE
  2174. RETURN
  2175.  
  2176.  
  2177. ******************************************************************************
  2178. *
  2179. *  File and Path functions
  2180. *
  2181. ******************************************************************************
  2182. *
  2183. * CUTFILELOC - Return a chopped file and path
  2184. *
  2185. *
  2186. FUNCTION cutfileloc
  2187. LPARAMETERS cFile, nLength
  2188. LOCAL cString, cTempPath, cTempFile, nPlen, nFlen
  2189. IF LEN(m.cFile) > m.nLength
  2190.    * Get everything uppercase
  2191.    cFile = UPPER(m.cFile)
  2192.    * Get the filename and length
  2193.    cTempFile = justfname(m.cFile)
  2194.    nFlen = LEN(m.cTempFile)
  2195.    * Find the minimum path length (could be "c:\")
  2196.    cTempPath = cutfpath(STRTRAN(m.cFile,m.cTempFile,"",1),8)
  2197.    nPlen = LEN(m.cTempPath)
  2198.    * If the filename + the min path is longer than nLength, cut the file name.
  2199.    IF m.nFlen + m.nPlen > m.nLength
  2200.       cString = m.cTempPath + cutfname(m.cFile,m.nLength-m.nPlen)
  2201.    ELSE  
  2202.       cTempPath = STRTRAN(m.cFile,m.cTempfile,"",1)
  2203.       cString = cutfpath(m.cTempPath,(m.nLength-m.nFlen)) + m.cTempfile
  2204.    ENDIF
  2205. ELSE
  2206.    cString = m.cFile
  2207. ENDIF   
  2208. RETURN m.cString
  2209.  
  2210.  
  2211.  
  2212. *
  2213. * Function: PARTIALFNAME
  2214. *
  2215. FUNCTION partialfname
  2216. PARAMETER m.filname, m.fillen
  2217. * Return a filname no longer than m.fillen characters.  Take some chars
  2218. * out of the middle if necessary.  No matter what m.fillen is, this function
  2219. * always returns at least the file stem and extension.
  2220. PRIVATE m.bname, m.elipse, m.remain
  2221. m.elipse = "..." + m.g_pathsep
  2222. IF _MAC
  2223.     m.bname = SUBSTR(m.filname, RAT(":",m.filname)+1)
  2224. ELSE
  2225.     m.bname = justfname(m.filname)
  2226. ENDIF
  2227. DO CASE
  2228. CASE LEN(m.filname) <= m.fillen
  2229.    m.retstr = m.filname
  2230. CASE LEN(m.bname) + LEN(m.elipse) >= m.fillen
  2231.    m.retstr = m.bname
  2232. OTHERWISE
  2233.    m.remain = MAX(m.fillen - LEN(m.bname) - LEN(m.elipse), 0)
  2234.    IF _MAC
  2235.        m.retstr = LEFT(SUBSTR(m.filname,1,RAT(":",m.filname)-1),m.remain) ;
  2236.             +m.elipse+m.bname
  2237.    ELSE
  2238.          m.retstr = LEFT(justpath(m.filname),m.remain)+m.elipse+m.bname
  2239.    ENDIF
  2240. ENDCASE
  2241. RETURN m.retstr
  2242.  
  2243.  
  2244.  
  2245. *
  2246. * CUTFNAME - Return a chopped filename
  2247. *  ie: "REALLYLONGFILENAME.TXT" = "REALLYLONG..."
  2248. FUNCTION cutfname
  2249. LPARAMETERS cFilename, nLength
  2250. cFilename = ALLTRIM(m.cFilename)
  2251. IF RAT(m.g_pathsep,m.cFilename) > 0
  2252.    m.cFilename = SUBSTR(m.cFilename,RAT(m.g_pathsep,m.cFilename)+1)
  2253. ENDIF
  2254. IF LEN(m.cFilename) > m.nLength
  2255.    m.cFilename = LEFT(m.cFilename,m.nLength-4) + "..."
  2256. ENDIF
  2257. RETURN m.cFilename
  2258.  
  2259.  
  2260.  
  2261. *
  2262. * CUTFPATH - Return a chopped filepath
  2263. *
  2264. *  ie: "C:\REALLYLONGPATH\SUB\ETC\" = "C:\ ...\SUB\ETC\"
  2265. FUNCTION cutfpath
  2266. LPARAMETERS cFilepath, nLength
  2267. LOCAL cPre, cString, nRemain, nOccurs
  2268. IF _MAC OR LEN(m.cFilepath) > m.nLength
  2269.    cFilePath = SYS(2027, m.cFilePath)  && Remove relative paths
  2270. ENDIF   
  2271. IF LEN(m.cFilepath) > m.nLength
  2272.    cPre = LEFT(m.cFilePath,AT(m.g_pathsep,m.cFilePath)) + "... " + m.g_pathsep
  2273.    nRemain = nLength - LEN(m.cPre)
  2274.    cString = RIGHT(cFilepath,m.nRemain)
  2275.    IF OCCURS(m.g_pathsep,m.cString)>1
  2276.       cString = m.cPre + SUBS(cString,AT(m.g_pathsep,m.cString))
  2277.    ELSE
  2278.       cString = m.cPre  && last directory on path is too long
  2279.    ENDIF
  2280. ELSE
  2281.    cString = m.cFilepath
  2282. ENDIF   
  2283. RETURN m.cString
  2284.  
  2285.  
  2286.  
  2287. *
  2288. * JUSTFNAME - Return just a filename
  2289. *
  2290. FUNCTION justfname
  2291. PARAMETERS m.filname
  2292. PRIVATE ALL
  2293. IF RAT('\',m.filname) > 0
  2294.    m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
  2295. ENDIF
  2296. IF AT(':',m.filname) > 0
  2297.    m.filname = SUBSTR(m.filname,AT(':',m.filname)+1,255)
  2298. ENDIF
  2299. RETURN ALLTRIM(UPPER(m.filname))
  2300.  
  2301.  
  2302. *
  2303. * JUSTPATH - Return just the path name from "filname"
  2304. *
  2305. FUNCTION justpath
  2306. PARAMETERS m.filname
  2307. PRIVATE ALL
  2308. m.filname = ALLTRIM(UPPER(m.filname))
  2309. IF '\' $ m.filname
  2310.    m.filname = SUBSTR(m.filname,1,RAT('\',m.filname))
  2311.    IF RIGHT(m.filname,1) = '\' AND LEN(m.filname) > 1 ;
  2312.          AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> ':'
  2313.       filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
  2314.    ENDIF
  2315.    RETURN m.filname
  2316. ELSE
  2317.    RETURN ''
  2318. ENDIF
  2319.  
  2320.  
  2321. *
  2322. * STRIPEXT - Strip the extension from a file name.
  2323. *
  2324. * Description:
  2325. * Use the algorithm employed by FoxPRO itself to strip a
  2326. * file of an extension (if any): Find the rightmost dot in
  2327. * the filename.  If this dot occurs to the right of a "\"
  2328. * or ":", then treat everything from the dot rightward
  2329. * as an extension.  Of course, if we found no dot,
  2330. * we just hand back the filename unchanged.
  2331. *
  2332. * Parameters:
  2333. * filename - character string representing a file name
  2334. *
  2335. * Return value:
  2336. * The string "filename" with any extension removed
  2337. *
  2338. FUNCTION stripext
  2339. PARAMETER m.filename
  2340. PRIVATE m.dotpos, m.terminator
  2341. m.dotpos = RAT(".", m.filename)
  2342. m.terminator = MAX(RAT("\", m.filename), RAT(":", m.filename))
  2343. IF m.dotpos > m.terminator
  2344.    m.filename = LEFT(m.filename, m.dotpos-1)
  2345. ENDIF
  2346. RETURN m.filename
  2347.  
  2348.  
  2349. *
  2350. * STRIPPATH - Strip the path from a file name.
  2351. *
  2352. * Description:
  2353. * Find positions of backslash in the name of the file.  If there is one
  2354. * take everything to the right of its position and make it the new file
  2355. * name.  If there is no slash look for colon.  Again if found, take
  2356. * everything to the right of it as the new name.  If neither slash
  2357. * nor colon are found then return the name unchanged.
  2358. *
  2359. * Parameters:
  2360. * filename - character string representing a file name
  2361. *
  2362. * Return value:
  2363. * The string "filename" with any path removed
  2364. *
  2365. FUNCTION strippath
  2366. PARAMETER m.filename
  2367. PRIVATE m.slashpos, m.namelen, m.colonpos
  2368. m.slashpos = RAT("\", m.filename)
  2369. IF m.slashpos > 0
  2370.    m.namelen  = LEN(m.filename) - m.slashpos
  2371.    m.filename = RIGHT(m.filename, m.namelen)
  2372. ELSE
  2373.    m.colonpos = RAT(":", m.filename)
  2374.    IF m.colonpos > 0
  2375.       m.namelen  = LEN(m.filename) - m.colonpos
  2376.       m.filename = RIGHT(m.filename, m.namelen)
  2377.    ENDIF
  2378. ENDIF
  2379. RETURN m.filename
  2380.  
  2381.  
  2382. * BASENAME - returns strippath(stripext(filespec))
  2383. *
  2384. FUNCTION basename
  2385. PARAMETER m.filespec
  2386. RETURN strippath(stripext(m.filespec))
  2387.  
  2388.  
  2389.  
  2390. ******************************************************************************
  2391. * Revisions History
  2392. * $History: GENMENU.PRG $
  2393.  * 
  2394.  * *****************  Version 11  *****************
  2395.  * User: rb          Date: 11/30/96    Time: 1:04a
  2396.  * Updated in $/Genmenu
  2397.  * Enhanced #PREPOP for Cleanup snippet placeholder
  2398.  * Changed naming convention of menu popups in Top-Level
  2399.  *    form menus to avoid conflicts with RELEASE MENU...
  2400.  *    extended.
  2401.  * Fixed Top-Level Form - append menu problem.
  2402.  * Fixed Setup/Cleanup code not gen for Top-Level Form.
  2403.  * *****************  Version 10  *****************
  2404.  * User: rb          Date: 5/1/96    Time: 1:04a
  2405.  * Updated in $/Genmenu
  2406.  * Added #PREPOPUP generator directive to control whether
  2407.  * Cleanup code is placed before/after ACTIVATE POPUP
  2408.  * line for Shortcut menus. 
  2409.  * *****************  Version 9  *****************
  2410.  * User: rb          Date: 3/8/96    Time: 1:04a
  2411.  * Updated in $/Genmenu
  2412.  * Added support for new shortcut popup and SDI form menus
  2413.  * - actpopup() new proc to add shortcut activate code
  2414.  * - GetMenuType() new proc to determine menu type (shortcut, SDI, etc.)
  2415.  * - defbars () added new parameter to safeguard shortcut popup name
  2416.  * - defonbar () added new parameter to safeguard shortcut popup name
  2417.  * *****************  Version 8  *****************
  2418.  * User: Dta          Date: 3/19/95    Time: 1:04a
  2419.  * Updated in $/Genmenu
  2420.  * - Thermfname() modified to use new function CutFileLoc().
  2421.  * - CutFileLoc(), CutFPath() and CutFName() written to handle 
  2422.  *   formating for long file, path and directory names.
  2423.  * - Grouped similiar functions.
  2424.  * - Fixed release thermometer window bug.
  2425.  * - Merge dialog and thermometer fonts.
  2426.  * - Moved g_pathsep to globals definition area.
  2427.  * 
  2428.  * *****************  Version 7  *****************
  2429.  * User: Dta          Date: 3/18/95    Time: 7:36p
  2430.  * Updated in $/Genmenu
  2431.  * - Change c_aliaslen to 255 to support long file names.
  2432.  * - Add support for intelligent Pad hotkeys
  2433.  * 
  2434.  * *****************  Version 6  *****************
  2435.  * User: Dta          Date: 3/18/95    Time: 5:19p
  2436.  * Updated in $/Genmenu
  2437.  * - Add support for no "!" in menu file name.
  2438.  * - Modify error routine to utilize MESSAGEBOX()
  2439.  * 
  2440.  * *****************  Version 5  *****************
  2441.  * User: Dta          Date: 1/11/95    Time: 9:45a
  2442.  * Updated in $/Genmenu
  2443.  * - Beautified and documentation changes
  2444.  * - Branched for Localization
  2445.  *
  2446.  * *****************  Version 4  *****************
  2447.  * User: Dta          Date: 1/10/95    Time: 6:36p
  2448.  * Updated in $/Genmenu
  2449.  * - Add support for DEBUG mode
  2450.  * - Add message for ERROR 22
  2451.  * - #DEFINEs moved above executable code
  2452.  * - Dialog Fonts changed for localization
  2453.  *
  2454.  * *****************  Version 3  *****************
  2455.  * User: Dta          Date: 1/10/95    Time: 5:56p
  2456.  * Updated in $/Genmenu
  2457.  * - Change localization constants to support naming convention.
  2458.  *
  2459.  * *****************  Version 2  *****************
  2460.  * User: Dta          Date: 12/10/94    Time: 8:20a
  2461.  * Updated in $/Genmenu
  2462.  * - Change PJXFields constant to 3.0 value.
  2463.  * - Add AGAIN to USE command when opening project.
  2464.  * - Add constants for Localization support.
  2465.  * - Remove "arranged" from NOCPTRANS command.
  2466.  * - Modify VERSNUM() to support 3.0 VERS() convention.
  2467.  * - Add version control documentation.
  2468.  *
  2469.  * *****************  Version 1  *****************
  2470.  * User: Dta          Date: 12/1/95    Time: 3:13p
  2471.  * Added in $/Genmenu
  2472.  * - Orignial 2.6a GENMENU shipping version.
  2473.  *
  2474. *
  2475.  
  2476.