home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 5 / 05.iso / a / a009 / 6.ddi / DBU.LIF / DBUVIEW.PRG < prev   
Encoding:
Text File  |  1991-04-14  |  65.7 KB  |  3,264 lines

  1. ************
  2. *
  3. *    Program....:  DBU
  4. *    Filename...:  DBUVIEW.PRG
  5. *    Author.....:  Dennis L. Dias
  6. *    Date.......:  06/18/86, 06/18/90
  7. *    Purpose....:  View Maintenance Module
  8. *
  9. *    Copyright (c) 1986-1990 Nantucket Corp., All Rights Reserved.
  10. *
  11. ************
  12.  
  13.  
  14. ******
  15. *    set_view
  16. *
  17. *    select files, set fields, relations, filters
  18. *
  19. *    note: only data files are opened and closed when
  20. *          requested..all other aspects of the View are
  21. *          set when needed by calling the setup() function
  22. *          in the utilities module
  23. ******
  24. PROCEDURE set_view
  25. local saveColor
  26. PRIVATE bar_line,empty_line,ntx,field_n,el,cur_row,t_row,ch_draw,;
  27.         strn,is_redraw,is_insert,horiz_keys,prev_area,i
  28.  
  29. saveColor := SetColor(M->color1)
  30.  
  31. * establish local array for index file names (no path or extension)
  32. DECLARE d_array[LEN(M->ntx1)]
  33.  
  34. * initialize local variables
  35. horiz_keys = CHR(4) + CHR(19) + CHR(1) + CHR(6)    && quick return from bar_menu
  36. bar_line = ""        && built by bline()
  37. empty_line = ""        && ditto
  38. prev_area = 0        && detect horizontal movement (zero to initialize)
  39. ch_draw = .F.        && switch for channel function
  40.  
  41. * global help code
  42. help_code = 1
  43.  
  44. * global key value..zero is convenient for branch to "otherwise" case below
  45. keystroke = 0
  46.  
  47. * special attention for open and create menu defaults
  48. set_deflt()
  49.  
  50. IF .NOT. EMPTY(M->view_err)
  51.     * with soap it's loaded
  52.     error_msg(M->view_err)
  53.     view_err = ""
  54.  
  55. ENDIF
  56.  
  57. DO WHILE .NOT. q_check()
  58.     * one big switch..exit condition determined elsewhere
  59.  
  60.     DO CASE
  61.  
  62.         CASE M->cur_area = 0
  63.             * draw View screen..see if complete reset needed
  64.             cur_area = aseek(M->dbf, M->cur_dbf)
  65.  
  66.             IF M->cur_area = 0
  67.                 * complete reset needed
  68.  
  69.                 FOR i = 1 TO 3
  70.                     * current rows and current elements
  71.                     STORE row_a[M->i] TO cr1[M->i],cr2[M->i],cr3[M->i],;
  72.                                          cr4[M->i],cr5[M->i],cr6[M->i]
  73.                     STORE 1 TO el1[M->i],el2[M->i],el3[M->i],el4[M->i],;
  74.                                el5[M->i],el6[M->i]
  75.  
  76.                 NEXT
  77.  
  78.                 * global variables
  79.                 cur_dbf = dbf[1]
  80.                 STORE 1 TO cur_area, page
  81.  
  82.                 * set default for open and create menus
  83.                 set_deflt()
  84.  
  85.             ENDIF
  86.  
  87.             * draw the main View screen
  88.             draw_view(0)
  89.  
  90.         CASE M->cur_area <> M->prev_area
  91.             * horizontal movement detected (or initial entry)
  92.             cur_dbf = dbf[M->cur_area]    && current data file
  93.  
  94.             * save on function calls
  95.             strn = SUBSTR("123456", M->cur_area, 1)
  96.  
  97.             * set variables to matrix into current data channel
  98.             ntx = "ntx" + strn
  99.             field_n = "field_n" + strn
  100.             el = "el" + strn
  101.  
  102.             * use temporary variable for adjustment
  103.             t_row = "cr" + strn
  104.  
  105.             IF M->page > 1 .AND. M->prev_area <> 0
  106.                 * adjust element by (old row - new row)
  107.                 &el[M->page] = &el[M->page] +;
  108.                                &cur_row[M->page] - &t_row[M->page]
  109.  
  110.                 * new row = old row
  111.                 &t_row[M->page] = &cur_row[M->page]
  112.  
  113.             ENDIF
  114.  
  115.             * set to current data channel
  116.             cur_row = M->t_row
  117.  
  118.             * clear for next loop
  119.             prev_area = M->cur_area
  120.  
  121.         CASE M->keystroke = 19
  122.             * left arrow..move one channel to the left
  123.  
  124.             IF M->cur_area > 1
  125.                 * ok to move left
  126.                 cur_area = M->cur_area - 1
  127.  
  128.             ENDIF
  129.  
  130.             keystroke = 0
  131.  
  132.         CASE M->keystroke = 1
  133.             * home key..extreme left
  134.             cur_area = 1
  135.             keystroke = 0
  136.  
  137.         CASE M->keystroke = 4
  138.             * right arrow..move one channel to the right
  139.  
  140.             IF M->cur_area < 6 .AND. .NOT. EMPTY(M->cur_dbf)
  141.                 * ok to move right..next channel
  142.                 cur_area = M->cur_area + 1
  143.  
  144.                 IF EMPTY(dbf[M->cur_area])
  145.                     * inactive channel..cannot enter indexes or fields
  146.                     page = 1
  147.                     set_deflt()
  148.  
  149.                 ENDIF
  150.             ENDIF
  151.  
  152.             keystroke = 0
  153.  
  154.         CASE M->keystroke = 6
  155.             * end key..move to extreme right
  156.  
  157.             IF M->cur_area < 6 .AND. .NOT. EMPTY(M->cur_dbf)
  158.                 * ok to move right..determine last active channel
  159.                 i = afull(M->dbf)
  160.  
  161.                 IF M->i < 6 .AND. (M->page = 1 .OR. M->cur_area = M->i)
  162.                     * move to inactive channel
  163.                     cur_area = M->i + 1
  164.  
  165.                     * cannot enter indexes or fields
  166.                     page = 1
  167.                     set_deflt()
  168.  
  169.                 ELSE
  170.                     * move to last active channel
  171.                     cur_area = M->i
  172.  
  173.                 ENDIF
  174.  
  175.             ENDIF
  176.  
  177.             keystroke = 0
  178.  
  179.         CASE M->keystroke = 18 .OR. M->keystroke = 5
  180.             * PgUp or up arrow
  181.  
  182.             IF M->page > 1
  183.                 * ok to move up
  184.                 page = M->page - 1
  185.                 set_deflt()
  186.  
  187.             ENDIF
  188.  
  189.             keystroke = 0
  190.  
  191.         CASE M->keystroke = 3 .OR. M->keystroke = 24
  192.             * PgDn or down arrow
  193.  
  194.             IF M->page < 3 .AND. .NOT. EMPTY(M->cur_dbf)
  195.                 * ok to move down
  196.                 page = M->page + 1
  197.                 set_deflt()
  198.  
  199.                 * adjust row and element for smooth cursor movement
  200.                 &el[M->page] = &el[M->page] -;
  201.                                (&cur_row[M->page] - row_a[M->page])
  202.                 &cur_row[M->page] = row_a[M->page]
  203.  
  204.             ENDIF
  205.  
  206.             keystroke = 0
  207.  
  208.         CASE M->keystroke = 22 .OR. M->keystroke = 13 .OR.;
  209.              isdata(M->keystroke) .OR. (M->local_func = 2 .AND.;
  210.              (M->local_sel = 1 .OR. M->local_sel = 2)) .OR.;
  211.              (M->local_func = 8 .AND. M->local_sel = 3)
  212.             * insert or enter or local menu item
  213.  
  214.             IF M->local_func <> 0
  215.                 * local menu item..set page to menu selection
  216.                 page = M->local_sel
  217.                 set_deflt()
  218.  
  219.                 * menu select behaves like insert
  220.                 keystroke = 22
  221.  
  222.             ENDIF
  223.  
  224.             IF M->page = 1 .AND. M->n_files < 14
  225.                 * open a data file
  226.                 is_redraw = M->cur_area < 6 .AND. (M->keystroke = 22 .OR.;
  227.                                                   EMPTY(M->cur_dbf))
  228.  
  229.                 is_insert = (M->keystroke = 22 .AND.;
  230.                             .NOT. EMPTY(M->cur_dbf) .AND. M->cur_area < 6)
  231.  
  232.                 IF M->is_redraw
  233.                     * open up dummy channel on screen
  234.                     draw_view(M->cur_area)
  235.  
  236.                     * a dummy for a dummy
  237.                     SetColor(M->color2)
  238.                     @ row_a[1], column[M->cur_area] + 2 SAY SPACE(8)
  239.                     SetColor(M->color1)
  240.  
  241.                 ELSE
  242.                     * hilite the affected View item
  243.                     hi_cur()
  244.  
  245.                 ENDIF
  246.  
  247.                 * call the open function and save the return status
  248.                 ch_draw = open_dbf(M->is_insert, .F.)
  249.  
  250.                 IF M->ch_draw
  251.                     * update screen with "channel" function
  252.                     channel(&ntx, &field_n, &el, &cur_row,;
  253.                             M->cur_area, M->cur_area)
  254.  
  255.                     * new current data file
  256.                     cur_dbf = dbf[M->cur_area]
  257.  
  258.                 ELSE
  259.                     * put the screen back the way it was
  260.  
  261.                     IF M->is_redraw
  262.                         * kill the dummy
  263.                         draw_view(0)
  264.  
  265.                     ELSE
  266.                         * un-hilite
  267.                         dehi_cur()
  268.  
  269.                     ENDIF
  270.                 ENDIF
  271.  
  272.             ELSE
  273.  
  274.                 IF M->page > 1
  275.                     * pages 2 and 3 handled by channel function
  276.                     channel(&ntx, &field_n, &el, &cur_row,;
  277.                             M->cur_area, M->cur_area)
  278.  
  279.                 ELSE
  280.                     error_msg("Too many files open")
  281.  
  282.                 ENDIF
  283.             ENDIF
  284.  
  285.             keystroke = 0
  286.  
  287.         CASE M->keystroke = 7
  288.             * delete
  289.  
  290.             IF M->page = 1 .AND. .NOT. EMPTY(M->cur_dbf)
  291.                 * close this work area and shift subsequent ones down
  292.                 stat_msg("Closing File")
  293.                 clear_dbf(M->cur_area, 2)
  294.  
  295.                 IF M->cur_area = 6
  296.                     * no need to re-write screen..clear windows
  297.                     ch_draw = .T.
  298.                     channel(&ntx, &field_n, &el, &cur_row,;
  299.                             M->cur_area, M->cur_area)
  300.  
  301.                 ELSE
  302.                     * re-write screen
  303.                     draw_view(0)
  304.  
  305.                 ENDIF
  306.  
  307.                 * new current data file
  308.                 cur_dbf = dbf[M->cur_area]
  309.  
  310.                 * clear status message
  311.                 stat_msg("")
  312.  
  313.             ELSE
  314.  
  315.                 IF M->page > 1
  316.                     * pages 2 and 3 handled by channel function
  317.                     channel(&ntx, &field_n, &el, &cur_row,;
  318.                             M->cur_area, M->cur_area)
  319.  
  320.                 ENDIF
  321.             ENDIF
  322.  
  323.             keystroke = 0
  324.  
  325.         CASE M->local_func = 8 .AND. M->local_sel = 1
  326.             * "set_relation" selected from pull-down menu
  327.             set_relation()
  328.             keystroke = 0
  329.  
  330.         CASE M->local_func = 8 .AND. M->local_sel = 2
  331.             * "set filter" selected from pull-down menu
  332.             get_filter()
  333.             keystroke = 0
  334.  
  335.         CASE M->local_func = 2 .AND. M->local_sel = 3
  336.             * "restore View from .VEW file" selected from pull-down menu
  337.             set_from(.T.)
  338.  
  339.             IF .NOT. EMPTY(M->view_file) .AND. M->keystroke = 13
  340.                 * View set..re-write screen
  341.                 cur_area = 0
  342.                 cur_dbf = ""
  343.  
  344.             ENDIF
  345.  
  346.             keystroke = 0
  347.  
  348.         CASE M->local_func = 4
  349.             * "save View" selected from pull-down menu
  350.             save_view()
  351.             keystroke = 0
  352.  
  353.         CASE M->local_func = 1
  354.             * "help" selected from pull-down menu
  355.             DO syshelp
  356.             keystroke = 0
  357.  
  358.         OTHERWISE
  359.             * all pending cases have been processed
  360.  
  361.             DO CASE
  362.  
  363.                 CASE M->page = 1
  364.                     * get keystroke if pending
  365.  
  366.                     IF .NOT. key_ready()
  367.                         * no key pending..hilite the current item
  368.                         hi_cur()
  369.  
  370.                         * wait for keystroke
  371.                         read_key()
  372.  
  373.                         * re-write the current item as normal
  374.                         dehi_cur()
  375.  
  376.                     ENDIF
  377.  
  378.                 CASE M->page = 2
  379.                     * copy index file names to "name only" array
  380.                     d_copy(&ntx)
  381.  
  382.                     * do the menu selection on the main View screen
  383.                     bar_menu(column[M->cur_area] + 2,;
  384.                              column[M->cur_area] + 9, M->d_array)
  385.  
  386.                 CASE M->page = 3
  387.                     * do the menu selection on the main View screen
  388.                     bar_menu(column[M->cur_area] + 1,;
  389.                              column[M->cur_area] + 10, &field_n)
  390.  
  391.             ENDCASE
  392.  
  393.             IF M->keystroke = 27
  394.  
  395.                 IF rsvp("Exit to DOS? (Y/N)") <> "Y"
  396.                     keystroke = 0
  397.  
  398.                 ENDIF
  399.             ENDIF
  400.     ENDCASE
  401. ENDDO
  402.  
  403. IF M->sysfunc = 3 .AND. M->func_sel = 1 .AND. EMPTY(M->cur_dbf)
  404.     * indicate create structure by opening a dummy channel
  405.     draw_view(M->cur_area)
  406.  
  407. ENDIF
  408.  
  409. RETURN
  410.  
  411.  
  412. ******
  413. *    channel()
  414. *
  415. *    process one channel for "set view"
  416. *
  417. *    note: the array identifiers associated with the current
  418. *          channel are passed to this function in order to
  419. *          avoid the repeated macro expansion inherent in
  420. *          constructs like &ntx[&el[]]
  421. ******
  422. FUNCTION channel
  423.  
  424. PARAMETERS ch_ntx, ch_field_n, ch_el, ch_cur_row, n, dbf_num
  425. local saveColor
  426. PRIVATE f_n, is_ins, temp_buff, d_item
  427.  
  428. saveColor := SetColor(M->color1)
  429.  
  430. DO CASE
  431.  
  432.     CASE M->ch_draw
  433.         * update the screen for channel "n"..clear windows
  434.         scroll(row_a[2], column[M->n], row_x[2], column[M->n] + 11, 0)
  435.         scroll(row_a[3], column[M->n], row_x[3], column[M->n] + 11, 0)
  436.  
  437.         * display the specified file name "dbf_num"
  438.         @ row_a[1],column[M->n] + 2 SAY pad(name(dbf[M->dbf_num]), 8)
  439.  
  440.         IF .NOT. EMPTY(ch_ntx[1])
  441.             * list the index files if any
  442.             d_copy(M->ch_ntx)
  443.             list_array(row_a[2],column[M->n] + 2,row_x[2],column[M->n] + 9,;
  444.                        M->d_array,ch_el[2] - (ch_cur_row[2] - row_a[2]))
  445.  
  446.         ENDIF
  447.  
  448.         * display field list
  449.         list_array(row_a[3], column[M->n] + 1, row_x[3], column[M->n] + 10,;
  450.                    M->ch_field_n, ch_el[3] - (ch_cur_row[3] - row_a[3]))
  451.  
  452.         ch_draw = .F.                && reset the screen update flag
  453.  
  454.     CASE M->keystroke = 22 .OR. M->keystroke = 13 .OR. isdata(M->keystroke)
  455.         * insert or enter or character key
  456.  
  457.         IF isdata(M->keystroke)
  458.             * forward character to GET system
  459.             KEYBOARD CHR(M->keystroke)
  460.  
  461.         ENDIF
  462.  
  463.         * remember if insert
  464.         is_ins = (M->keystroke = 22)
  465.  
  466.         DO CASE
  467.  
  468.             CASE M->page = 2 .AND. (M->n_files < 14 .OR. (M->keystroke <> 22;
  469.                  .AND. .NOT. EMPTY(ch_ntx[ch_el[2]])))
  470.                 * add or change an index file in the current list..save window
  471.                 temp_buff = SAVESCREEN(row_a[2], column[M->n] + 1,;
  472.                                        row_x[2], column[M->n] + 11)
  473.  
  474.                 IF M->is_ins
  475.                     * insert
  476.  
  477.                     IF ch_el[2] + row_x[2] - ch_cur_row[2] = afull(M->ch_ntx)
  478.                         * last filename will scroll off the window
  479.                         @ row_x[2], column[M->n] + 11 SAY M->more_down
  480.  
  481.                     ENDIF
  482.  
  483.                     IF ch_cur_row[2] < row_x[2]
  484.                         * open a blank row..scroll down
  485.                         scroll(ch_cur_row[2], column[M->n] + 1,;
  486.                                     row_x[2], column[M->n] + 10, -1)
  487.  
  488.                     ENDIF
  489.  
  490.                     * show entry blank
  491.                     d_item = SPACE(8)
  492.  
  493.                 ELSE
  494.                     * show the affected View item
  495.                     d_item = pad(name(ch_ntx[ch_el[2]]), 8)
  496.  
  497.                 ENDIF
  498.  
  499.                 * hilite the affected View item
  500.                 SetColor(M->color2)
  501.                 @ ch_cur_row[2],column[M->n] + 2 SAY M->d_item
  502.                 SetColor(M->color1)
  503.  
  504.                 * get selection
  505.                 f_n = get_ntx(ch_cur_row[2], column[M->n] + 2,;
  506.                               ch_ntx[ch_el[2]], M->is_ins)
  507.  
  508.                 IF .NOT. M->f_n == ch_ntx[ch_el[2]] .AND. .NOT. EMPTY(M->f_n)
  509.                     * index file added to list
  510.                     need_ntx = .T.
  511.  
  512.                     IF M->is_ins
  513.                         * make room for new index file name
  514.                         array_ins(M->ch_ntx,ch_el[2])
  515.  
  516.                     ENDIF
  517.  
  518.                     * assign filename to array element
  519.                     ch_ntx[ch_el[2]] = M->f_n
  520.  
  521.                     IF ch_el[2] = 1
  522.                         * controlling index..remove relations where target
  523.                         not_target(M->n, .T.)
  524.  
  525.                     ENDIF
  526.  
  527.                     * display the name of the newly selected index file
  528.                     @ ch_cur_row[2],column[M->n] + 2;
  529.                     SAY pad(name(ch_ntx[ch_el[2]]), 8)
  530.  
  531.                 ELSE
  532.                     * aborted entry..restore the window as it was
  533.                     RESTSCREEN(row_a[2], column[M->n] + 1,;
  534.                                row_x[2], column[M->n] + 11, M->temp_buff)
  535.  
  536.                 ENDIF
  537.  
  538.             CASE M->page = 3
  539.                 * add or change a fieldname in the current list..save window
  540.                 temp_buff = SAVESCREEN(row_a[3], column[M->n] + 1,;
  541.                                        row_x[3], column[M->n] + 11)
  542.  
  543.                 IF M->is_ins
  544.                     * insert
  545.  
  546.                     IF ch_el[3] + row_x[3] - ch_cur_row[3] = afull(M->ch_field_n)
  547.                         * last fieldname will scroll off the window
  548.                         @ row_x[3], column[M->n] + 11 SAY M->more_down
  549.  
  550.                     ENDIF
  551.  
  552.                     IF ch_cur_row[3] < row_x[3]
  553.                         * open a blank row..scroll down
  554.                         scroll(ch_cur_row[3], column[M->n] + 1,;
  555.                                     row_x[3], column[M->n] + 10, -1)
  556.  
  557.                     ENDIF
  558.  
  559.                     * show entry blank
  560.                     d_item = SPACE(10)
  561.  
  562.                 ELSE
  563.                     * show the affected View item
  564.                     d_item = pad(ch_field_n[ch_el[3]], 10)
  565.  
  566.                 ENDIF
  567.  
  568.                 * hilite the affected View item
  569.                 SetColor(M->color2)
  570.                 @ ch_cur_row[3],column[M->n] + 1 SAY M->d_item
  571.                 SetColor(M->color1)
  572.  
  573.                 * get selection
  574.                 f_n = get_field(ch_cur_row[3], column[M->n] + 1, M->n,;
  575.                                 ch_field_n[ch_el[3]])
  576.  
  577.                 IF (M->is_ins .OR. .NOT. M->f_n == ch_field_n[ch_el[3]]);
  578.                    .AND. .NOT. EMPTY(M->f_n)
  579.                     * fieldname added to list
  580.                     need_field = .T.
  581.  
  582.                     IF M->is_ins
  583.                         * make room for new field name
  584.                         array_ins(M->ch_field_n,ch_el[3])
  585.  
  586.                     ENDIF
  587.  
  588.                     * assign fieldname to array element
  589.                     ch_field_n[ch_el[3]] = M->f_n
  590.  
  591.                     * display the name of the newly selected field
  592.                     @ ch_cur_row[3],column[M->n] + 1;
  593.                     SAY pad(ch_field_n[ch_el[3]], 10)
  594.  
  595.                 ELSE
  596.                     * aborted entry..restore the window as it was
  597.                     RESTSCREEN(row_a[3], column[M->n] + 1,;
  598.                                row_x[3], column[M->n] + 11, M->temp_buff)
  599.  
  600.                 ENDIF
  601.         ENDCASE
  602.  
  603.     CASE M->keystroke = 7
  604.         * delete
  605.  
  606.         DO CASE
  607.  
  608.             CASE M->page = 2 .AND. .NOT. EMPTY(ch_ntx[ch_el[2]])
  609.                 * remove index file from list
  610.                 need_ntx = .T.    && must reset
  611.  
  612.                 IF ch_el[2] = 1
  613.                     * primary index..remove relations where target
  614.                     not_target(M->n, .T.)
  615.  
  616.                 ENDIF
  617.  
  618.                 * select work area n
  619.                 SELECT (M->n)
  620.  
  621.                 * ensure that n_files does not exceed actual open files
  622.                 CLOSE INDEX
  623.  
  624.                 * remove the filename from the list
  625.                 array_del(M->ch_ntx,ch_el[2])
  626.  
  627.                 * decrement global file counter
  628.                 n_files = M->n_files - 1
  629.  
  630.                 IF ch_cur_row[2] < row_x[2]
  631.                     * scroll up to remove filename from screen
  632.                     scroll(ch_cur_row[2],column[M->n] + 1,;
  633.                                 row_x[2],column[M->n] + 9,1)
  634.  
  635.                 ENDIF
  636.  
  637.                 * fill in blank row at bottom of window
  638.                 @ row_x[2],column[M->n] + 2;
  639.                 SAY pad(name(ch_ntx[ch_el[2] + row_x[2] - ch_cur_row[2]]), 8)
  640.  
  641.                 IF afull(M->ch_ntx) - ch_el[2] = row_x[2] - ch_cur_row[2]
  642.                     * remove the "more_down" indicator from the screen
  643.                     @ row_x[2],column[M->n] + 11 SAY " "
  644.  
  645.                 ENDIF
  646.  
  647.             CASE M->page = 3 .AND. .NOT. EMPTY(ch_field_n[ch_el[3]])
  648.                 * delete a fieldname from the current list
  649.                 need_field = .T.    && must reset
  650.  
  651.                 * remove the fieldname from the list
  652.                 array_del(M->ch_field_n,ch_el[3])
  653.  
  654.                 IF ch_cur_row[3] < row_x[3]
  655.                     * scroll up to remove fieldname from screen
  656.                     scroll(ch_cur_row[3],column[M->n] + 1,;
  657.                                 row_x[3],column[M->n] + 10,1)
  658.  
  659.                 ENDIF
  660.  
  661.                 * fill in blank row at bottom of window
  662.                 @ row_x[3],column[M->n] + 1;
  663.                 SAY pad(ch_field_n[ch_el[3] + row_x[3] - ch_cur_row[3]], 10)
  664.  
  665.                 IF afull(M->ch_field_n) - ch_el[3] = row_x[3] - ch_cur_row[3]
  666.                     * remove the "more_down" indicator from the screen
  667.                     @ row_x[3],column[M->n] + 11 SAY " "
  668.  
  669.                 ENDIF
  670.         ENDCASE
  671. ENDCASE
  672.  
  673. SetColor(saveColor)
  674. RETURN 0
  675.  
  676.  
  677. ******
  678. *    bar_menu()
  679. *
  680. *    verticle light bar selection menu for the main View screen
  681. *
  682. *    note: this routine is expected to return a value in "keystroke"
  683. *          to be processed by "set_view"
  684. ******
  685. FUNCTION bar_menu
  686.  
  687. PARAMETERS l, r, array
  688. local saveColor
  689. PRIVATE num_d, num_full, cur_el, rel_row, x, t, b
  690.  
  691. * look ahead at next keystroke
  692. keystroke = NEXTKEY()
  693.  
  694. IF CHR(M->keystroke) $ M->horiz_keys
  695.     * improve performance of horizontal cursor movement with quick return
  696.     INKEY()        && remove character from typeahead buffer
  697.     RETURN 0
  698.  
  699. ENDIF
  700.  
  701. * avoid costly array access by getting top and bottom of window to "t" and "b"
  702. t = row_a[M->page]
  703. b = row_x[M->page]
  704.  
  705. * get the number of active elements
  706. num_full = afull(M->array)
  707.  
  708. * and the number of displayable elements
  709. num_d = M->num_full
  710.  
  711. IF M->num_d < LEN(M->array)
  712.     * first empty element is included
  713.     num_d = M->num_d + 1
  714.  
  715.     * achoice() won't display a null string
  716.     array[M->num_d] = " "
  717.  
  718. ENDIF
  719.  
  720. * determine column offset to put "more_up" and "more_down" indicators
  721. x = IF(M->r - M->l > 7, 1, 2)
  722.  
  723. * it's all relative to achoice()
  724. rel_row = &cur_row[M->page] - M->t
  725.  
  726. * discard returned value
  727. saveColor := SetColor(M->color4)
  728. achoice(M->t, M->l, M->b, M->r, M->array, .T.,;
  729.         "bar_func", &el[M->page], M->rel_row)
  730. SetColor(saveColor)
  731.  
  732. * change back to absolute
  733. &cur_row[M->page] = M->rel_row + M->t
  734.  
  735. IF array[M->num_d] == " "
  736.     * kill the dummy
  737.     array[M->num_d] = ""
  738.  
  739. ENDIF
  740.  
  741. * check for menu request
  742. sysmenu()
  743.  
  744. RETURN 0
  745.  
  746.  
  747. ******
  748. *    bar_func()
  749. *
  750. *    function to be called from achoice() specifically for bar_menu()
  751. ******
  752. FUNCTION bar_func
  753.  
  754. PARAMETERS mode, bar_el, row
  755. PRIVATE ret_code
  756.  
  757. * get keystroke
  758. keystroke = LASTKEY()
  759.  
  760. * assume continue
  761. ret_code = 2
  762.  
  763. * maintain variables from above
  764. &el[M->page] = M->bar_el
  765. rel_row = M->row
  766.  
  767. IF M->error_on
  768.     * erase error message
  769.     error_off()
  770.  
  771. ENDIF
  772.  
  773. DO CASE
  774.  
  775.     CASE M->mode = 0
  776.         * idle..maintain correct "more_up" and "more_down" indicators
  777.         @ M->t, M->r + M->x SAY IF(M->bar_el > M->row + 1, M->more_up, " ")
  778.         @ M->b, M->r + M->x SAY IF(M->num_full >;
  779.                                    (M->bar_el + M->b - M->t - M->row),;
  780.                                 M->more_down, " ")
  781.  
  782.     CASE M->mode = 1 .OR. M->mode = 2
  783.         * attempt to cursor past top or end of list
  784.         ret_code = 0
  785.  
  786.     CASE M->mode = 3
  787.         * keystroke exception
  788.  
  789.         DO CASE
  790.  
  791.             CASE CHR(M->keystroke) $ M->horiz_keys
  792.                 * horizontal cursor key
  793.                 ret_code = 0
  794.  
  795.             CASE M->keystroke = 27
  796.                 * abort selection
  797.                 ret_code = 0
  798.  
  799.             CASE M->keystroke = 13
  800.                 * replace a View item
  801.                 ret_code = 1
  802.  
  803.             CASE isdata(M->keystroke)
  804.                 * character key...entry in place
  805.                 ret_code = 1
  806.  
  807.             CASE M->keystroke = 22 .OR. M->keystroke = 7
  808.                 * ins, del
  809.                 ret_code = 1
  810.  
  811.             CASE menu_key() <> 0
  812.                 * menu request
  813.                 ret_code = 0
  814.  
  815.         ENDCASE
  816.  
  817.     CASE M->mode = 4
  818.         * nothing selectable
  819.         ret_code = 0
  820.  
  821. ENDCASE
  822.  
  823. RETURN M->ret_code
  824.  
  825.  
  826. ******
  827. *    list_array()
  828. *
  829. *    list array elements vertically in window
  830. ******
  831. FUNCTION list_array
  832.  
  833. PARAMETERS t, l, b, r, array, top_el
  834. local saveColor
  835. PRIVATE bottom_el, num_full, x
  836.  
  837. saveColor := SetColor(M->color4)
  838. IF .NOT. EMPTY(array[M->top_el])
  839.     * something to list..calculate number of last element in window
  840.     bottom_el = M->top_el + M->b - M->t
  841.  
  842.     * get number of non-empty elements
  843.     num_full = afull(M->array)
  844.  
  845.     * determine column offset of "more_up" and "more_down" indicators
  846.     x = IF(M->r - M->l > 7, 1, 2)
  847.  
  848.     IF M->top_el > 1 .AND. M->bottom_el = M->num_full + 1
  849.         * prevent achoice() from making adjustments
  850.         array[M->bottom_el] = " "
  851.  
  852.     ENDIF
  853.  
  854.     * display only and return without waiting for a keystroke
  855.     achoice(M->t, M->l, M->b, M->r, M->array, .F., "", M->top_el)
  856.     SetColor(M->color1)
  857.  
  858.     * update status of "more_up" and "more_down" indicators
  859.     @ M->t, M->r + M->x SAY IF(M->top_el > 1, M->more_up, " ")
  860.     @ M->b, M->r + M->x SAY IF(M->bottom_el < M->num_full, M->more_down, " ")
  861.  
  862.     IF array[M->bottom_el] == " "
  863.         * restore to null string
  864.         array[M->bottom_el] = ""
  865.  
  866.     ENDIF
  867. ENDIF
  868.  
  869. SetColor(saveColor)
  870. RETURN 0
  871.  
  872.  
  873. ******
  874. *    set_deflt()
  875. *
  876. *    set defaults for open and create pull-down menus
  877. ******
  878. FUNCTION set_deflt
  879.  
  880. IF M->page = 2
  881.     * cursor in index file list..default to open index and create index
  882.     STORE 2 TO menu_deflt[2], menu_deflt[3]
  883.  
  884. ELSE
  885.     * default to open database and create database
  886.     STORE 1 TO menu_deflt[2], menu_deflt[3]
  887.  
  888. ENDIF
  889.  
  890. RETURN 0
  891.  
  892.  
  893. ******
  894. *    bline()
  895. *
  896. *    build a new bar line for the main View screen
  897. ******
  898. FUNCTION bline
  899.  
  900. PARAMETERS num_slots
  901. PRIVATE i, k
  902.  
  903. IF num_slots < 6
  904.     * add one empty slot
  905.     num_slots = num_slots + 1
  906.  
  907. ENDIF
  908.  
  909. * the first slot is diferent than the rest
  910. bar_line = "════════════"
  911. empty_line = ""
  912.  
  913. k = 1
  914.  
  915. DO WHILE M->k < M->num_slots
  916.     * each new slot separated from previous by a vertical line
  917.     bar_line = M->bar_line + "╤════════════"
  918.     empty_line = M->empty_line + SPACE(12) + "│"
  919.  
  920.     * next
  921.     k = M->k + 1
  922.  
  923. ENDDO
  924.  
  925. * calculate value to center the entire View screen
  926. i = INT((80 - LEN(M->bar_line)) / 2)
  927.  
  928. FOR k = 1 TO M->num_slots
  929.     * establish screen columns for all active slots
  930.     column[M->k] = M->i + (13 * (M->k - 1))
  931.  
  932. NEXT
  933.  
  934. RETURN 0
  935.  
  936.  
  937. ******
  938. *    draw_view()
  939. *
  940. *    fill the main View screen
  941. *
  942. *    note: the parameter indicates which channel is to be the
  943. *          dummy for operations in progress, zero for no dummy
  944. ******
  945. FUNCTION draw_view
  946.  
  947. PARAMETERS blank_area
  948. PRIVATE i, j, ntx, field_n, el, cur_row, strnum
  949.  
  950. * get number of active work areas
  951. i = afull(M->dbf)
  952.  
  953. IF M->i < 6 .AND. blank_area <> 0
  954.     * add one for the dummy
  955.     i = M->i + 1
  956.  
  957. ENDIF
  958.  
  959. * build the bar_line and empty_line strings
  960. bline(M->i)
  961.  
  962. * clear the deck and draw a blank template
  963. @ 4,0 CLEAR
  964.  
  965. * page 1..names of data files
  966. @ row_a[1] - 2,37 SAY "Files"
  967. @ row_a[1] - 1,column[1] SAY M->bar_line
  968. @ row_a[1],column[1] SAY M->empty_line
  969.  
  970. * page 2..names of index files
  971. @ row_a[2] - 2,36 SAY "Indexes"
  972. @ row_a[2] - 1,column[1] SAY M->bar_line
  973. @ row_a[2],column[1] SAY M->empty_line
  974. @ row_a[2] + 1,column[1] SAY M->empty_line
  975. @ row_a[2] + 2,column[1] SAY M->empty_line
  976.  
  977. * page 3..active fields lists
  978. @ row_a[3] - 2,37 SAY "Fields"
  979. @ row_a[3] - 1,column[1] SAY M->bar_line
  980.  
  981. FOR i = row_a[3] TO row_x[3]
  982.     * complete the blank template
  983.     @ M->i,column[1] SAY M->empty_line
  984.  
  985. NEXT
  986.  
  987. i = 1
  988. j = 1
  989.  
  990. DO WHILE M->j <= 6
  991.  
  992.     IF EMPTY(dbf[M->i])
  993.         * no more active work areas
  994.         EXIT
  995.  
  996.     ENDIF
  997.  
  998.     IF M->j <> M->blank_area
  999.         * channel needs filling
  1000.         strnum = SUBSTR("123456", M->i, 1)
  1001.  
  1002.         * set to channel "i"
  1003.         ntx = "ntx" + strnum
  1004.         field_n = "field_n" + strnum
  1005.         el = "el" + strnum
  1006.         cur_row = "cr" + strnum
  1007.  
  1008.         * fill the channel
  1009.         ch_draw = .T.
  1010.         channel(&ntx, &field_n, &el, &cur_row, M->j, M->i)
  1011.  
  1012.         * next real channel
  1013.         i = M->i + 1
  1014.  
  1015.     ENDIF
  1016.  
  1017.     * next display channel
  1018.     j = M->j + 1
  1019.  
  1020. ENDDO
  1021.  
  1022. RETURN 0
  1023.  
  1024.  
  1025. ******
  1026. *    d_copy()
  1027. *
  1028. *    create a filename only array (no paths or extensions)
  1029. ******
  1030. FUNCTION d_copy
  1031.  
  1032. PARAMETERS array
  1033. PRIVATE i
  1034.  
  1035. * clear the dedicated array
  1036. afill(M->d_array, "")
  1037.  
  1038. i = 1
  1039.  
  1040. DO WHILE M->i <= LEN(M->array)
  1041.  
  1042.     IF EMPTY(array[M->i])
  1043.         * end of active list
  1044.         EXIT
  1045.  
  1046.     ENDIF
  1047.  
  1048.     * assign the extracted name
  1049.     d_array[M->i] = name(array[M->i])
  1050.  
  1051.     * next
  1052.     i = M->i + 1
  1053.  
  1054. ENDDO
  1055.  
  1056. RETURN 0
  1057.  
  1058.  
  1059. ******
  1060. *    open_dbf()
  1061. *
  1062. *    open data file in the specified work area
  1063. ******
  1064. FUNCTION open_dbf
  1065.  
  1066. PARAMETERS is_insert, not_view
  1067. PRIVATE shift, filename, a_temp, f_row, d_col, ret_val, old_help
  1068.  
  1069. IF M->n_files >= 14
  1070.     error_msg("Too many files open")
  1071.     RETURN .F.
  1072.  
  1073. ENDIF
  1074.  
  1075. * save old and set new help codes
  1076. old_help = M->help_code
  1077. help_code = 6
  1078.  
  1079. * initialize private variables
  1080. filename = ""
  1081.  
  1082. * coordinate of filename on View screen
  1083. f_row = cr1[1]
  1084. d_col = column[M->cur_area] + 2
  1085.  
  1086. * shift = 1 for major insertion
  1087. shift = IF(M->is_insert, 1, 0)
  1088.  
  1089. * select the current work area
  1090. SELECT (M->cur_area)
  1091.  
  1092. IF M->not_view
  1093.     * not called from "set_view"
  1094.     filename = M->cur_dbf
  1095.     ret_val = do_opendbf()
  1096.  
  1097. ELSE
  1098.     * assume file not opened
  1099.     ret_val = .F.
  1100.  
  1101.     IF isdata(M->keystroke)
  1102.         * forward the data character to the GET system
  1103.         KEYBOARD CHR(M->keystroke)
  1104.  
  1105.         * entry in place
  1106.         filename = enter_rc(dbf[M->cur_area],M->f_row,M->d_col,64,"@K!S8",;
  1107.                             M->color1)
  1108.  
  1109.         IF .NOT. EMPTY(M->filename)
  1110.             * something entered
  1111.  
  1112.             IF .NOT. (RAT(".", M->filename) > RAT("\", M->filename))
  1113.                 * no extension entered..provide default
  1114.                 filename = M->filename + ".DBF"
  1115.  
  1116.             ENDIF
  1117.  
  1118.             * try to open the file
  1119.             ret_val = do_opendbf()
  1120.  
  1121.             IF .NOT. M->ret_val
  1122.                 * failed..restore the screen
  1123.                 @ M->f_row, M->d_col SAY pad(name(M->cur_dbf), 8)
  1124.  
  1125.             ENDIF
  1126.  
  1127.         ELSE
  1128.             * aborted entry..restore the screen
  1129.             @ M->f_row, M->d_col SAY pad(name(M->cur_dbf), 8)
  1130.  
  1131.         ENDIF
  1132.  
  1133.         IF menu_key() <> 0
  1134.             * forward menu key to "set_view"
  1135.             KEYBOARD CHR(M->keystroke)
  1136.  
  1137.         ELSE
  1138.             * avoid confusion
  1139.             keystroke = 0
  1140.  
  1141.         ENDIF
  1142.  
  1143.     ELSE
  1144.         * insert or enter or menu selection..use filebox
  1145.         ret_val = filebox(".DBF", "dbf_list", "dopen_titl",;
  1146.                           "do_opendbf", .F., 8) <> 0
  1147.  
  1148.     ENDIF
  1149. ENDIF
  1150.  
  1151. IF M->ret_val
  1152.     * default field arrays to all fields
  1153.     a_temp = "field_n" + SUBSTR("123456", M->cur_area, 1)
  1154.     all_fields(M->cur_area, &a_temp)
  1155.  
  1156.     * re-set current row for indexes and fields
  1157.     a_temp = "cr" + SUBSTR("123456", M->cur_area, 1)
  1158.     &a_temp[2] = row_a[2]
  1159.     &a_temp[3] = row_a[3]
  1160.  
  1161.     * re-set current elements
  1162.     a_temp = "el" + SUBSTR("123456", M->cur_area, 1)
  1163.     afill(&a_temp, 1)
  1164.  
  1165. ENDIF
  1166.  
  1167. * restore help code
  1168. help_code = M->old_help
  1169.  
  1170. RETURN M->ret_val
  1171.  
  1172.  
  1173. ******
  1174. *    dopen_titl()
  1175. *
  1176. *    display title for data file to open
  1177. ******
  1178. FUNCTION dopen_titl
  1179.  
  1180. PARAMETERS sysparam
  1181.  
  1182. RETURN box_title(M->sysparam, "Open data file...")
  1183.  
  1184.  
  1185. ******
  1186. *    do_opendbf()
  1187. *
  1188. *    set up and open a data file
  1189. ******
  1190. FUNCTION do_opendbf
  1191.  
  1192. PRIVATE done
  1193.  
  1194. DO CASE
  1195.  
  1196.     CASE EMPTY(M->filename)
  1197.         error_msg("Data file not selected")
  1198.         done = .F.
  1199.  
  1200.     CASE .NOT. FILE(M->filename)
  1201.         error_msg("Can't open " + M->filename)
  1202.         done = .F.
  1203.  
  1204.     CASE aseek(M->dbf, M->filename) > 0 .AND.;
  1205.          .NOT. (dbf[M->cur_area] == M->filename .AND. M->shift = 0)
  1206.         error_msg("Data file would be open in two areas")
  1207.         done = .F.
  1208.  
  1209.     OTHERWISE
  1210.         stat_msg("Opening File")
  1211.  
  1212.         IF .NOT. EMPTY(dbf[M->cur_area])
  1213.             * clear the current work area
  1214.             clear_dbf(M->cur_area, M->shift)
  1215.  
  1216.         ENDIF
  1217.  
  1218.         * adjust global variable
  1219.         n_files = M->n_files + 1
  1220.  
  1221.         * assign the filename to global array
  1222.         dbf[M->cur_area] = M->filename
  1223.  
  1224.         * open the file in the current area
  1225.         SELECT (M->cur_area)
  1226.         USE &filename
  1227.  
  1228.         * clear the message
  1229.         stat_msg("")
  1230.  
  1231.         done = .T.
  1232.  
  1233. ENDCASE
  1234.  
  1235. RETURN M->done
  1236.  
  1237.  
  1238. ******
  1239. *    get_ntx()
  1240. *
  1241. *    select index files for the current work area
  1242. ******
  1243. FUNCTION get_ntx
  1244.  
  1245. PARAMETERS d_row, d_col, org_file, is_ins
  1246. PRIVATE filename, old_help
  1247.  
  1248. IF M->n_files >= 14
  1249.     error_msg("Too many files open")
  1250.     RETURN ""
  1251.  
  1252. ENDIF
  1253.  
  1254. * save old and set new help codes
  1255. old_help = M->help_code
  1256. help_code = 8
  1257.  
  1258. * initialize private variable
  1259. filename = ""
  1260.  
  1261. IF isdata(M->keystroke)
  1262.     * forward data keystroke to GET system
  1263.     KEYBOARD CHR(M->keystroke)
  1264.  
  1265.     * entry in place
  1266.     filename = enter_rc(M->org_file,M->d_row,M->d_col,64,"@K!S8",M->color1)
  1267.  
  1268.     IF .NOT. EMPTY(M->filename)
  1269.         * something entered
  1270.  
  1271.         IF .NOT. (RAT(".", M->filename) > RAT("\", M->filename))
  1272.             * extension not entered..provide default
  1273.             filename = filename + INDEXEXT()
  1274.  
  1275.         ENDIF
  1276.  
  1277.         IF .NOT. do_openntx()
  1278.             * failed..return null string
  1279.             filename = ""
  1280.  
  1281.         ENDIF
  1282.     ENDIF
  1283.  
  1284.     IF menu_key() <> 0
  1285.         * forward menu request to "set_view"
  1286.         KEYBOARD CHR(M->keystroke)
  1287.  
  1288.     ELSE
  1289.         * avoid confusion
  1290.         keystroke = 0
  1291.  
  1292.     ENDIF
  1293.  
  1294. ELSE
  1295.  
  1296.     IF filebox(INDEXEXT(),"ntx_list","xopen_titl","do_openntx",.F.,13) = 0
  1297.         * no selection..return null string
  1298.         filename = ""
  1299.  
  1300.     ENDIF
  1301. ENDIF
  1302.  
  1303. * restore help code
  1304. help_code = M->old_help
  1305.  
  1306. RETURN M->filename
  1307.  
  1308.  
  1309. ******
  1310. *    xopen_titl()
  1311. *
  1312. *    display title for index file to open
  1313. ******
  1314. FUNCTION xopen_titl
  1315.  
  1316. PARAMETERS sysparam
  1317.  
  1318. RETURN box_title(M->sysparam, "Open index file...")
  1319.  
  1320.  
  1321. ******
  1322. *    do_openntx()
  1323. *
  1324. *    verify the selectability of an index file
  1325. ******
  1326. FUNCTION do_openntx
  1327.  
  1328. PRIVATE done
  1329.  
  1330. DO CASE
  1331.  
  1332.     CASE EMPTY(M->filename)
  1333.         error_msg("Index file not selected")
  1334.         done = .F.
  1335.  
  1336.     CASE .NOT. FILE(M->filename)
  1337.         error_msg("Can't open " + M->filename)
  1338.         done = .F.
  1339.  
  1340.     CASE dup_ntx(M->filename) <> 0 .AND.;
  1341.          (M->is_ins .OR. .NOT. M->filename == M->org_file)
  1342.         error_msg("Index file already open")
  1343.         done = .F.
  1344.  
  1345.     OTHERWISE
  1346.         * filename may be selected
  1347.  
  1348.         IF EMPTY(M->org_file) .OR. M->is_ins
  1349.             * adjust global variable
  1350.             n_files = M->n_files + 1
  1351.  
  1352.         ENDIF
  1353.  
  1354.         done = .T.
  1355.  
  1356. ENDCASE
  1357.  
  1358. RETURN M->done
  1359.  
  1360.  
  1361. ******
  1362. *    get_field()
  1363. *
  1364. *    add a field to an individual field list
  1365. ******
  1366. FUNCTION get_field
  1367.  
  1368. PARAMETERS f_row, d_col, work_area, org_field
  1369. PRIVATE field_mvar, rel_row, cur_el, okee_dokee, fi_disp, old_help
  1370.  
  1371. * save old and set new help codes
  1372. old_help = M->help_code
  1373. help_code = 2
  1374.  
  1375. * initialize variable to contain fieldname
  1376. field_mvar = ""
  1377.  
  1378. * select the specified work area
  1379. SELECT (M->work_area)
  1380.  
  1381. * get master field list into local array for selection
  1382. DECLARE field_m[FCOUNT()]
  1383. all_fields(M->work_area, M->field_m)
  1384.  
  1385. IF isdata(M->keystroke)
  1386.     * forward the data keystroke to the GET system
  1387.     KEYBOARD CHR(M->keystroke)
  1388.  
  1389.     * entry in place
  1390.     field_mvar = enter_rc(M->org_field,M->f_row,M->d_col,10,"@K!",M->color1)
  1391.  
  1392.     IF .NOT. EMPTY(M->field_mvar)
  1393.         * something entered
  1394.  
  1395.         IF .NOT. do_fsel()
  1396.             * failed..return null string
  1397.             field_mvar = ""
  1398.  
  1399.         ENDIF
  1400.  
  1401.     ENDIF
  1402.  
  1403.     IF menu_key() <> 0
  1404.         * forward the menu request to "set_view"
  1405.         KEYBOARD CHR(M->keystroke)
  1406.  
  1407.     ELSE
  1408.         * avoid confusion
  1409.         keystroke = 0
  1410.  
  1411.     ENDIF
  1412.  
  1413. ELSE
  1414.     * establish arrays for multibox
  1415.     DECLARE boxarray[5]
  1416.  
  1417.     boxarray[1] = "fsel_title(sysparam)"
  1418.     boxarray[2] = "getfield(sysparam)"
  1419.     boxarray[3] = "ok_button(sysparam)"
  1420.     boxarray[4] = "can_button(sysparam)"
  1421.     boxarray[5] = "fieldlist(sysparam)"
  1422.  
  1423.     * initialize private variables
  1424.     cur_el = 1
  1425.     rel_row = 0
  1426.  
  1427.     * where the action is
  1428.     okee_dokee = "do_fsel()"
  1429.     fi_disp = "getfield(3)"
  1430.  
  1431.     IF multibox(7, 17, 5, 5, M->boxarray) = 0
  1432.         * failed or aborted..return null string
  1433.         field_mvar = ""
  1434.  
  1435.     ENDIF
  1436. ENDIF
  1437.  
  1438. * restore help code
  1439. help_code = M->old_help
  1440.  
  1441. RETURN M->field_mvar
  1442.  
  1443.  
  1444. ******
  1445. *    getfield()
  1446. *
  1447. *    process fieldname entry blank (called from multibox)
  1448. ******
  1449. FUNCTION getfield
  1450.  
  1451. PARAMETERS sysparam
  1452.  
  1453. RETURN genfield(M->sysparam, .F.)
  1454.  
  1455.  
  1456. ******
  1457. *    fsel_title()
  1458. *
  1459. *    display title for field selection
  1460. ******
  1461. FUNCTION fsel_title
  1462.  
  1463. PARAMETERS sysparam
  1464.  
  1465. RETURN box_title(M->sysparam, "Select field...")
  1466.  
  1467.  
  1468. ******
  1469. *    do_fsel()
  1470. *
  1471. *    validate field selection
  1472. ******
  1473. FUNCTION do_fsel
  1474.  
  1475. PRIVATE done
  1476.  
  1477. DO CASE
  1478.  
  1479.     CASE EMPTY(M->field_mvar)
  1480.         error_msg("Field name not selected")
  1481.         done = .F.
  1482.  
  1483.     CASE aseek(M->field_m, M->field_mvar) = 0
  1484.         * needed for entry in place
  1485.         error_msg(M->field_mvar + " does not exist")
  1486.         done = .F.
  1487.  
  1488.     OTHERWISE
  1489.         * field exists..no problem
  1490.         done = .T.
  1491.  
  1492. ENDCASE
  1493.  
  1494. RETURN M->done
  1495.  
  1496.  
  1497. ******
  1498. *    set_relation()
  1499. *
  1500. *    interface for editing the list of relations
  1501. *
  1502. *    note: the relations window can display a maximum
  1503. *          of six (6) relationships at one time
  1504. ******
  1505. FUNCTION set_relation
  1506. local saveColor
  1507. PRIVATE c_row, c_el, rel_buff, pos_r, width, old_help, k, n_area, ls, lk, lt,;
  1508.         cNorm, cHilite
  1509.  
  1510. cNorm := color7
  1511. cHilite:= color2
  1512. saveColor := SetColor(M->cNorm)
  1513.  
  1514. * save old and set new help codes
  1515. old_help = M->help_code
  1516. help_code = 9
  1517.  
  1518. * prevent certain menu selections with multibox mechanism
  1519. box_open = .T.
  1520.  
  1521. IF EMPTY(M->bar_line)
  1522.     * need bar line for vertical reference
  1523.     bline(afull(M->dbf))
  1524.  
  1525. ENDIF
  1526.  
  1527. * window has variable width
  1528. width = LEN(M->bar_line) - 1
  1529.  
  1530. * establish easy reference to right most column
  1531. pos_r = column[1] + M->width
  1532.  
  1533. * save the window
  1534. rel_buff = SAVESCREEN(8, column[1] - 1, 23, M->pos_r + 1)
  1535.  
  1536. * clear and frame the window
  1537. scroll(8, column[1] - 1, 23, M->pos_r + 1, 0)
  1538. @ 8, column[1] - 1, 23, M->pos_r + 1 BOX M->frame
  1539.  
  1540. * display the heading and bar line
  1541. @ 9,35 SAY "Relations"
  1542. @ 10,column[1] SAY M->bar_line
  1543.  
  1544. * initialize current row and element
  1545. c_row = 11
  1546. c_el = 1
  1547.  
  1548. * initial window fill
  1549. draw_relat(1)
  1550.  
  1551. * global key value..zero is convenient for branch to "otherwise" case below
  1552. keystroke = 0
  1553.  
  1554. DO WHILE .NOT. q_check()
  1555.     * one big switch..exit condition determined elsewhere
  1556.  
  1557.     DO CASE
  1558.  
  1559.         CASE M->keystroke = 18
  1560.             * PgUp
  1561.  
  1562.             IF M->c_el > ((M->c_row - 11) / 2) + 1
  1563.                 * elements off screen..move up one page
  1564.                 c_el = M->c_el - 5
  1565.  
  1566.                 IF M->c_el < ((M->c_row - 11) / 2) + 1
  1567.                     * minimum element for this row
  1568.                     c_el = ((M->c_row - 11) / 2) + 1
  1569.  
  1570.                 ENDIF
  1571.  
  1572.                 * re-write relations window
  1573.                 draw_relat(M->c_el - ((M->c_row - 11) / 2))
  1574.  
  1575.             ELSE
  1576.                 * first element is on screen
  1577.  
  1578.                 IF M->c_el > 1
  1579.                     * move to top of list
  1580.                     c_el = 1
  1581.                     c_row = 11
  1582.  
  1583.                 ENDIF
  1584.             ENDIF
  1585.  
  1586.             keystroke = 0
  1587.  
  1588.         CASE M->keystroke = 3
  1589.             * PgDn..determine maximum allowable cursor element
  1590.             k = afull(M->k_relate)
  1591.  
  1592.             IF M->k < LEN(M->k_relate)
  1593.                 * first empty element is allowed
  1594.                 k = M->k + 1
  1595.  
  1596.             ENDIF
  1597.  
  1598.             IF M->c_el < M->k - ((21 - M->c_row) / 2)
  1599.                 * elements off screen..down one page
  1600.                 c_el = M->c_el + 5
  1601.  
  1602.                 IF M->c_el > M->k - ((21 - M->c_row) / 2)
  1603.                     * maximum element for this row
  1604.                     c_el = M->k - ((21 - M->c_row) / 2)
  1605.  
  1606.                 ENDIF
  1607.  
  1608.                 * re-write relations window
  1609.                 draw_relat(M->c_el - ((M->c_row - 11) / 2))
  1610.  
  1611.             ELSE
  1612.                 * last allowable element is on screen
  1613.  
  1614.                 IF M->c_el < M->k
  1615.                     * move to bottom of list
  1616.                     c_row = M->c_row + ((M->k - M->c_el) * 2)
  1617.                     c_el = M->k
  1618.  
  1619.                 ENDIF
  1620.             ENDIF
  1621.  
  1622.             keystroke = 0
  1623.  
  1624.         CASE M->keystroke = 22 .OR. isdata(M->keystroke)
  1625.             * insert or character key..insert a relation
  1626.  
  1627.             * k = number of first relation off screen
  1628.             k = M->c_el + ((21 - M->c_row) / 2 ) + 1
  1629.  
  1630.             * save the last relationship
  1631.             ls = s_relate[LEN(M->s_relate)]
  1632.             lk = k_relate[LEN(M->k_relate)]
  1633.             lt = t_relate[LEN(M->t_relate)]
  1634.  
  1635.             * do the insert..assume relation will be entered
  1636.             array_ins(M->s_relate, M->c_el)
  1637.             array_ins(M->k_relate, M->c_el)
  1638.             array_ins(M->t_relate, M->c_el)
  1639.  
  1640.             IF M->c_row < 21
  1641.                 * make room on screen..scroll down 2 lines
  1642.                 scroll(M->c_row, column[1], 22, M->pos_r - 1, -2)
  1643.  
  1644.             ELSE
  1645.                 * clear the last row
  1646.                 @ M->c_row + 1,column[1] SAY SPACE(M->width)
  1647.  
  1648.             ENDIF
  1649.  
  1650.             IF M->k <= LEN(M->k_relate)
  1651.                 * k is within subscript range
  1652.  
  1653.                 IF .NOT. EMPTY(k_relate[M->k])
  1654.                     * off-screen element is active
  1655.                     @ 22, M->pos_r SAY M->more_down
  1656.  
  1657.                 ENDIF
  1658.             ENDIF
  1659.  
  1660.             * accept input of new relation
  1661.             get_relation(M->c_row, M->c_el)
  1662.  
  1663.             IF .NOT. EMPTY(k_relate[M->c_el])
  1664.                 * relation has been entered..show it
  1665.                 disp_relation(M->c_row, M->c_el, color7)
  1666.  
  1667.             ELSE
  1668.                 * relation not entered..cannot delete a null string
  1669.                 STORE "x" TO s_relate[M->c_el],;
  1670.                              k_relate[M->c_el], t_relate[M->c_el]
  1671.  
  1672.                 * restore arrays
  1673.                 array_del(M->s_relate, M->c_el)
  1674.                 array_del(M->k_relate, M->c_el)
  1675.                 array_del(M->t_relate, M->c_el)
  1676.  
  1677.                 * restore last relationship
  1678.                 s_relate[LEN(M->s_relate)] = M->ls
  1679.                 k_relate[LEN(M->k_relate)] = M->lk
  1680.                 t_relate[LEN(M->t_relate)] = M->lt
  1681.  
  1682.                 IF M->c_row < 21
  1683.                     * close the gap on the screen..scroll up 2 lines
  1684.                     scroll(M->c_row, column[1], 22, M->pos_r - 1, 2)
  1685.  
  1686.                 ELSE
  1687.                     * erase the deleted relation from screen
  1688.                     @ 21,column[1] SAY SPACE(M->width)
  1689.                     @ 22,column[1] SAY SPACE(M->width)
  1690.  
  1691.                 ENDIF
  1692.  
  1693.                 * fill in the last relation on screen
  1694.                 disp_relation(21,M->c_el+((21-M->c_row)/2),color7)
  1695.  
  1696.             ENDIF
  1697.  
  1698.             IF M->k <= LEN(M->k_relate)
  1699.                 * k is within subscript range
  1700.  
  1701.                 IF EMPTY(k_relate[M->k])
  1702.                     * off-screen element not active
  1703.                     @ 22, M->pos_r SAY " "
  1704.  
  1705.                 ENDIF
  1706.             ENDIF
  1707.  
  1708.             keystroke = 0
  1709.  
  1710.         CASE M->keystroke = 13
  1711.             * enter key..change a relationship
  1712.             get_relation(M->c_row, M->c_el)
  1713.  
  1714.             * display the change
  1715.             disp_relation(M->c_row, M->c_el, color7)
  1716.  
  1717.             keystroke = 0
  1718.  
  1719.         CASE M->keystroke = 7 .AND. .NOT. EMPTY(k_relate[M->c_el])
  1720.             * remove a relation from the list
  1721.             need_relat = .T.    && will need to reset
  1722.  
  1723.             * select the source work area
  1724.             n_area = ASC(s_relate[M->c_el]) - ASC("A") + 1
  1725.             SELECT (M->n_area)
  1726.  
  1727.             * turn off relations from this work area
  1728.             SET RELATION TO
  1729.  
  1730.             * remove the relation from list
  1731.             array_del(M->s_relate, M->c_el)
  1732.             array_del(M->k_relate, M->c_el)
  1733.             array_del(M->t_relate, M->c_el)
  1734.  
  1735.             IF M->c_row < 21
  1736.                 * close the gap on the screen
  1737.                 scroll(M->c_row, column[1], 22, M->pos_r - 1, 2)
  1738.  
  1739.             ELSE
  1740.                 * last row erase the deleted relation from screen
  1741.                 @ 21,column[1] SAY SPACE(M->width)
  1742.                 @ 22,column[1] SAY SPACE(M->width)
  1743.  
  1744.             ENDIF
  1745.  
  1746.             * fill in the last relation on screen
  1747.             disp_relation(21, M->c_el + ((21 - M->c_row) / 2), color7)
  1748.  
  1749.             IF M->c_el < LEN(M->k_relate) - ((21 - M->c_row) / 2)
  1750.                 * off-screen element is within subscript range
  1751.  
  1752.                 IF EMPTY(k_relate[M->c_el + ((21 - M->c_row) / 2) + 1])
  1753.                     * remove "more_down" indicator from screen
  1754.                     @ 22, M->pos_r SAY " "
  1755.  
  1756.                 ENDIF
  1757.             ENDIF
  1758.  
  1759.             keystroke = 0
  1760.  
  1761.         CASE M->keystroke = 5 .AND. M->c_el > 1
  1762.             * up arrow..move up one element
  1763.             c_el = M->c_el - 1
  1764.  
  1765.             IF M->c_row > 11
  1766.                 * room to move up on screen
  1767.                 c_row = M->c_row - 2
  1768.  
  1769.             ELSE
  1770.                 * scroll entire window down 2 lines
  1771.                 scroll(11, column[1], 22, M->pos_r - 1, -2)
  1772.  
  1773.                 * fill in the top row
  1774.                 disp_relation(11, M->c_el, color7)
  1775.  
  1776.                 IF M->c_el <= LEN(M->k_relate) - 6
  1777.                     * off-screen element within subscript range
  1778.  
  1779.                     IF .NOT. EMPTY(k_relate[M->c_el + 6])
  1780.                         * off-screen element is active
  1781.                         @ 22, M->pos_r SAY M->more_down
  1782.  
  1783.                     ENDIF
  1784.                 ENDIF
  1785.  
  1786.                 IF M->c_el = 1
  1787.                     * first element brought onto screen..no "more_up"
  1788.                     @ 11,M->pos_r SAY " "
  1789.  
  1790.                 ENDIF
  1791.             ENDIF
  1792.  
  1793.             keystroke = 0
  1794.  
  1795.         CASE M->keystroke = 24 .AND. .NOT.;
  1796.              (EMPTY(k_relate[M->c_el]) .OR. M->c_el = LEN(M->k_relate))
  1797.             * down arrow..move down one element
  1798.             c_el = M->c_el + 1
  1799.  
  1800.             IF c_row < 22 - 2
  1801.                 * room to move down on screen
  1802.                 c_row = M->c_row + 2
  1803.  
  1804.             ELSE
  1805.                 * scroll entire window up 2 lines
  1806.                 scroll(11, column[1], 22, M->pos_r - 1, 2)
  1807.  
  1808.                 * definitely more up
  1809.                 @ 11,M->pos_r SAY M->more_up
  1810.  
  1811.                 IF .NOT. EMPTY(k_relate[M->c_el])
  1812.                     * fill in the bottom row
  1813.                     disp_relation(21, M->c_el, color7)
  1814.  
  1815.                 ENDIF
  1816.  
  1817.                 IF M->c_el < LEN(M->k_relate)
  1818.                     * off-screen element within subscript range
  1819.  
  1820.                     IF EMPTY(k_relate[M->c_el + 1])
  1821.                         * erase "more_down" indicator from screen
  1822.                         @ 22,M->pos_r SAY " "
  1823.  
  1824.                     ENDIF
  1825.  
  1826.                 ELSE
  1827.                     * no off-screen element..erase "more_down" indicator
  1828.                     @ 22,M->pos_r SAY " "
  1829.  
  1830.                 ENDIF
  1831.             ENDIF
  1832.  
  1833.             keystroke = 0
  1834.  
  1835.         CASE M->local_func = 1
  1836.             * "help" selected from pull-down menu
  1837.             DO syshelp
  1838.             keystroke = 0
  1839.  
  1840.         OTHERWISE
  1841.             * get new keystroke
  1842.  
  1843.             IF .NOT. key_ready()
  1844.                 * no key pending..hilite the current item
  1845.                 disp_relation(M->c_row, M->c_el, cHilite)
  1846.  
  1847.                 * display a blob of light if element empty
  1848.                 SetColor(M->cHilite)
  1849.                 @ M->c_row,column[1] + 2;
  1850.                 SAY IF(EMPTY(k_relate[M->c_el]), " ", "")
  1851.                 SetColor(M->cNorm)
  1852.  
  1853.                 * wait for keystroke
  1854.                 read_key()
  1855.  
  1856.                 * re-write the current item as normal
  1857.                 disp_relation(M->c_row, M->c_el, cNorm)
  1858.  
  1859.                 @ M->c_row, column[1] + 2 SAY ""
  1860.  
  1861.             ENDIF
  1862.     ENDCASE
  1863. ENDDO
  1864.  
  1865. * restore the window
  1866. RESTSCREEN(8, column[1] - 1, 23, M->pos_r + 1, M->rel_buff)
  1867.  
  1868. * restore the help code
  1869. help_code = M->old_help
  1870.  
  1871. * restore access to menu options
  1872. box_open = .F.
  1873.  
  1874. * avoid confusion
  1875. keystroke = 0
  1876. SetColor(saveColor)
  1877. RETURN 0
  1878.  
  1879.  
  1880. ******
  1881. *    draw_relat()
  1882. *
  1883. *    fill the relations window
  1884. ******
  1885. FUNCTION draw_relat
  1886.  
  1887. PARAMETERS start_el
  1888. PRIVATE i
  1889.  
  1890. * clear the window
  1891. scroll(11, column[1], 22, M->pos_r, 0)
  1892.  
  1893. i = 0
  1894.  
  1895. DO WHILE M->i < 6 .AND. M->start_el + M->i <= LEN(M->k_relate)
  1896.  
  1897.     IF EMPTY(k_relate[M->start_el + M->i])
  1898.         * end of active list
  1899.         EXIT
  1900.  
  1901.     ENDIF
  1902.  
  1903.     * display one relation
  1904.     disp_relation(11 + (2 * M->i), M->start_el + M->i, color7)
  1905.  
  1906.     * next
  1907.     i = M->i + 1
  1908.  
  1909. ENDDO
  1910.  
  1911. IF M->start_el > 1
  1912.     * indicate active elements above window
  1913.     @ 11, M->pos_r SAY M->more_up
  1914.  
  1915. ENDIF
  1916.  
  1917. IF M->start_el + M->i <= LEN(M->k_relate)
  1918.     * off-screen element within subscript range
  1919.  
  1920.     IF .NOT. EMPTY(k_relate[M->start_el + M->i])
  1921.         * indicate active elements below window
  1922.         @ 22, M->pos_r SAY M->more_down
  1923.  
  1924.     ENDIF
  1925. ENDIF
  1926.  
  1927. RETURN 0
  1928.  
  1929.  
  1930. ******
  1931. *    get_relation()
  1932. *
  1933. *    accept entry of one relationship
  1934. *
  1935. *    note: a character key may be used to select a file whose
  1936. *          name begins with that letter
  1937. ******
  1938. FUNCTION get_relation
  1939.  
  1940. PARAMETERS row_n, element
  1941.  
  1942. PRIVATE stroke, k_input, k_trim, s_alias, t_alias, i, j, q, pos_c,;
  1943.         ntx_expr, k_type, ok
  1944.  
  1945. IF isdata(M->keystroke)
  1946.     * character key..look for matching filename
  1947.     i = c_search(UPPER(CHR(M->keystroke)), M->dbf, 0, afull(M->dbf))
  1948.  
  1949.     IF SUBSTR(dbf[M->i],1,1) = UPPER(CHR(M->keystroke))
  1950.         * found..make the selection as the source file
  1951.         KEYBOARD CHR(13)
  1952.  
  1953.     ENDIF
  1954.  
  1955. ELSE
  1956.  
  1957.     IF EMPTY(k_relate[M->element])
  1958.         * brand new..start at the beginning
  1959.         i = 1
  1960.  
  1961.     ELSE
  1962.         * relation exists..begin with source file
  1963.         i = ASC(s_relate[M->element]) - ASC("A") + 1
  1964.  
  1965.     ENDIF
  1966. ENDIF
  1967.  
  1968. j = 0
  1969. stroke = 0
  1970.  
  1971. DO WHILE .NOT. (M->j > 0 .AND. M->stroke = 13)
  1972.     * till both source and target files are selected
  1973.  
  1974.     DO CASE
  1975.  
  1976.         CASE M->stroke = 13
  1977.             * enter key..select source
  1978.  
  1979.             IF M->i < 6
  1980.                 * can only select if another file is open to the right
  1981.  
  1982.                 IF .NOT. EMPTY(dbf[M->i + 1])
  1983.  
  1984.                     IF .NOT. EMPTY(k_relate[M->element])
  1985.                         * assume same target for existing relation
  1986.                         j = ASC(t_relate[M->element]) - ASC("A") + 1
  1987.  
  1988.                     ENDIF
  1989.  
  1990.                     IF M->j <= M->i
  1991.                         * target must be to the right of the source
  1992.                         j = M->i + 1
  1993.  
  1994.                     ENDIF
  1995.                 ENDIF
  1996.             ENDIF
  1997.  
  1998.             stroke = 0
  1999.  
  2000.         CASE M->stroke = 4
  2001.             * right arrow
  2002.  
  2003.             IF M->j = 0 .AND. M->i < 6
  2004.                 * source not selected..change source
  2005.  
  2006.                 IF .NOT. EMPTY(dbf[M->i + 1])
  2007.                     * only open files are selectable
  2008.                     i = M->i + 1
  2009.  
  2010.                 ENDIF
  2011.  
  2012.             ELSE
  2013.  
  2014.                 IF M->j > 0 .AND. M->j < 6
  2015.                     * source selected..change target
  2016.  
  2017.                     IF .NOT. EMPTY(dbf[M->j + 1])
  2018.                         * only open files are selectable
  2019.                         j = M->j + 1
  2020.  
  2021.                     ENDIF
  2022.                 ENDIF
  2023.             ENDIF
  2024.  
  2025.             stroke = 0
  2026.  
  2027.         CASE M->stroke = 19
  2028.             * left arrow
  2029.  
  2030.             IF M->j = 0 .AND. M->i > 1
  2031.                 * source not selected..change source
  2032.                 i = M->i - 1
  2033.  
  2034.             ELSE
  2035.  
  2036.                 IF M->j > 0
  2037.                     * source selected..change target
  2038.                     j = M->j - 1
  2039.  
  2040.                     IF M->j = M->i
  2041.                         * target must be to the right
  2042.                         j = 0    && revert to unselected source
  2043.  
  2044.                     ENDIF
  2045.                 ENDIF
  2046.             ENDIF
  2047.  
  2048.             stroke = 0
  2049.  
  2050.         CASE isdata(M->stroke)
  2051.             * character key..perform character search
  2052.             q = c_search(UPPER(CHR(M->stroke)),M->dbf,M->i,afull(M->dbf))
  2053.  
  2054.             IF SUBSTR(dbf[M->q],1,1) = UPPER(CHR(M->stroke))
  2055.                 * found
  2056.  
  2057.                 IF M->j = 0
  2058.                     * source not selected..make selection
  2059.                     i = M->q
  2060.                     KEYBOARD CHR(13)
  2061.  
  2062.                 ELSE
  2063.  
  2064.                     IF M->q > M->i
  2065.                         * found file is acceptable as target..make selection
  2066.                         j = M->q
  2067.                         KEYBOARD CHR(13)
  2068.  
  2069.                     ELSE
  2070.                         * found file cannot be target
  2071.                         j = 0        && revert to unselected source
  2072.                         i = M->q    && found file is current s_alias
  2073.  
  2074.                     ENDIF
  2075.                 ENDIF
  2076.             ENDIF
  2077.  
  2078.             stroke = 0
  2079.  
  2080.         CASE M->stroke = 27
  2081.             * escape..abort
  2082.             @ M->row_n,column[1] SAY SPACE(M->width)
  2083.             RETURN 0
  2084.  
  2085.         CASE M->stroke = 28
  2086.             * "help" selected from pull-down menu
  2087.             DO syshelp
  2088.             stroke = 0
  2089.  
  2090.         OTHERWISE
  2091.             * update screen and get new stroke
  2092.  
  2093.             IF M->j = 0
  2094.                 * source file not selected..clear the row
  2095.                 @ M->row_n,column[1] SAY SPACE(M->width)
  2096.  
  2097.                 * extract the current source alias
  2098.                 s_alias = name(dbf[M->i])
  2099.  
  2100.                 * display it as intense
  2101.                 SetColor(M->color12)
  2102.                 @ M->row_n,column[M->i] + 2 SAY M->s_alias
  2103.                 SetColor(M->cNorm)
  2104.  
  2105.             ELSE
  2106.                 * source selected (do not disturb)..extract target alias
  2107.                 t_alias = name(dbf[M->j])
  2108.  
  2109.                 * calculate column after s_alias
  2110.                 pos_c = column[M->i] + 2 + LEN(M->s_alias)
  2111.  
  2112.                 * clear to right edge of window
  2113.                 @ M->row_n,M->pos_c SAY SPACE(M->pos_r - M->pos_c)
  2114.  
  2115.                 * draw line and arrow pointing to target alias
  2116.                 @ M->row_n,M->pos_c;
  2117.                 SAY REPLICATE("─", column[M->j] - M->pos_c + 1) + CHR(16)
  2118.  
  2119.                 * display target alias as intense
  2120.                 SetColor(M->color12)
  2121.                 ?? t_alias
  2122.                 SetColor(M->cNorm)
  2123.  
  2124.             ENDIF
  2125.  
  2126.             * get new stroke
  2127.             stroke = raw_key()
  2128.  
  2129.     ENDCASE
  2130. ENDDO
  2131.  
  2132. * hilite source and target in reverse video to indicate both selected
  2133. SetColor(M->cHilite)
  2134. @ M->row_n,column[M->i] + 2 SAY M->s_alias
  2135. @ M->row_n,column[M->j] + 2 SAY M->t_alias
  2136. SetColor(M->cNorm)
  2137.  
  2138. * determine correct type for relation expression
  2139. SELECT (M->j)
  2140. ntx_expr = ctrl_key()        && get the controlling index key
  2141.  
  2142. IF EMPTY(M->ntx_expr)
  2143.     * target not indexed..must be numeric or recno()
  2144.     k_type = "N"
  2145.  
  2146. ELSE
  2147.     * same type as target index key
  2148.     k_type = TYPE(M->ntx_expr)
  2149.  
  2150. ENDIF
  2151.  
  2152. * select source work area to test key expression
  2153. SELECT (M->i)
  2154.  
  2155. * start with previous expression
  2156. k_trim = k_relate[M->element]
  2157. ok = .F.
  2158.  
  2159. DO WHILE .NOT. M->ok
  2160.     * accept input of key expression
  2161.     k_trim = enter_rc(M->k_trim, M->row_n + 1, column[M->i] + 2,;
  2162.                       127, "@KS" + LTRIM(STR(M->pos_r - column[M->i] - 2)),;
  2163.                       M->color1)
  2164.  
  2165.     * empty expression will abort, else must be correct type
  2166.     ok = EMPTY(M->k_trim) .OR. TYPE(M->k_trim) = M->k_type
  2167.  
  2168.     IF .NOT. M->ok
  2169.         error_msg("Invalid Expression")
  2170.  
  2171.     ENDIF
  2172. ENDDO
  2173.  
  2174. * clear the expression row
  2175. @ M->row_n + 1,column[1] SAY SPACE(M->width)
  2176.  
  2177. IF EMPTY(M->k_trim)
  2178.     * abort
  2179.     RETURN 0
  2180.  
  2181. ENDIF
  2182.  
  2183. * will need to set relations
  2184. need_relat = .T.
  2185.  
  2186. * store defined relation in global arrays
  2187. k_relate[M->element] = M->k_trim
  2188. s_relate[M->element] = CHR(M->i + ASC("A") - 1) + M->s_alias
  2189. t_relate[M->element] = CHR(M->j + ASC("A") - 1) + M->t_alias
  2190.  
  2191. RETURN 0
  2192.  
  2193.  
  2194. ******
  2195. *    disp_relation()
  2196. *
  2197. *    display the specified relation on the specified row in the specified color
  2198. ******
  2199. FUNCTION disp_relation
  2200.  
  2201. PARAMETERS disp_row, element, cSpecial
  2202. PRIVATE j, k
  2203.  
  2204. IF EMPTY(k_relate[M->element])
  2205.     * clear lines only
  2206.     @ M->disp_row,column[1] SAY SPACE(M->width)
  2207.     @ M->disp_row + 1,column[1] SAY SPACE(M->width)
  2208.     RETURN 0
  2209.  
  2210. ENDIF
  2211.  
  2212. * calculate the work areas of the related files
  2213. j = ASC(s_relate[M->element]) - ASC("A") + 1    && source
  2214. k = ASC(t_relate[M->element]) - ASC("A") + 1    && target
  2215.  
  2216. * display the source alias in the specified color
  2217. SetColor(M->cSpecial)
  2218. @ M->disp_row, column[M->j] + 2 SAY SUBSTR(s_relate[M->element], 2)
  2219. SetColor(M->cNorm)
  2220.  
  2221. * display an arrow (always normal color)
  2222. ?? REPLICATE("─", column[M->k] - COL() + 1) + CHR(16)
  2223.  
  2224. * display the target alias in the specified color
  2225. SetColor(M->cSpecial)
  2226. ?? SUBSTR(t_relate[M->element], 2)
  2227. SetColor(M->cNorm)
  2228.  
  2229. * display the key on the next line (always normal color)
  2230. @ M->disp_row + 1, column[M->j] + 2;
  2231. SAY pad(k_relate[M->element], M->pos_r - column[M->j] - 2)
  2232.  
  2233. RETURN 0
  2234.  
  2235.  
  2236. ******
  2237. *    c_search()
  2238. *
  2239. *    find the next array element with a matching first character
  2240. ******
  2241. FUNCTION c_search
  2242.  
  2243. PARAMETERS c, array, cur_el, num_d
  2244. PRIVATE chr_el
  2245.  
  2246. * begin with next element
  2247. chr_el = M->cur_el + 1
  2248.  
  2249. DO WHILE M->chr_el <= M->num_d
  2250.     * forward search..exit if found
  2251.  
  2252.     IF UPPER(SUBSTR(array[M->chr_el], 1, 1)) = UPPER(M->c)
  2253.         EXIT
  2254.  
  2255.     ENDIF
  2256.  
  2257.     * next
  2258.     chr_el = M->chr_el + 1
  2259.  
  2260. ENDDO
  2261.  
  2262. IF M->chr_el > M->num_d
  2263.     * not found..search from beginning
  2264.     chr_el = 1
  2265.  
  2266.     DO WHILE M->chr_el < M->cur_el .AND.;
  2267.              UPPER(SUBSTR(array[M->chr_el], 1, 1)) <> UPPER(M->c)
  2268.  
  2269.         * next
  2270.         chr_el = M->chr_el + 1
  2271.  
  2272.     ENDDO
  2273. ENDIF
  2274.  
  2275. RETURN M->chr_el
  2276.  
  2277.  
  2278. ******
  2279. *    ctrl_key()
  2280. *
  2281. *    return controlling index key for the current work area
  2282. ******
  2283. FUNCTION ctrl_key
  2284.  
  2285. PRIVATE key, ntx
  2286.  
  2287. IF M->need_ntx
  2288.     * index may be specified but not set
  2289.     ntx = "ntx" + LTRIM(STR(SELECT()))
  2290.  
  2291.     * read key directly from file
  2292.     key = ntx_key(&ntx[1])
  2293.  
  2294. ELSE
  2295.     * get key from system if index already set
  2296.     key = INDEXKEY(0)
  2297.  
  2298. ENDIF
  2299.  
  2300. RETURN M->key
  2301.  
  2302.  
  2303. ******
  2304. *    get_filter()
  2305. *
  2306. *    accept entry of filter expression for the current work area
  2307. ******
  2308. FUNCTION get_filter
  2309.  
  2310. PRIVATE k_filter,k_trim,old_help
  2311.  
  2312. * save old and set new help codes
  2313. old_help = M->help_code
  2314. help_code = 7
  2315.  
  2316. * get the current contents of the filter expression
  2317. k_filter = "kf" + SUBSTR("123456", M->cur_area, 1)
  2318. k_trim = &k_filter
  2319.  
  2320. * select the current work area for testing of filter expression
  2321. SELECT (M->cur_area)
  2322.  
  2323. * hilite the affected data file
  2324. hi_cur()
  2325.  
  2326. * establish array for mulitbox
  2327. DECLARE boxarray[4]
  2328.  
  2329. boxarray[1] = "fltr_title(sysparam)"
  2330. boxarray[2] = "getfilter(sysparam)"
  2331. boxarray[3] = "ok_button(sysparam)"
  2332. boxarray[4] = "can_button(sysparam)"
  2333.  
  2334. * indicate the function that will complete the process
  2335. okee_dokee = "do_filter()"
  2336.  
  2337. * open the box
  2338. multibox(7, 17, 5, 2, M->boxarray)
  2339.  
  2340. * restore help code
  2341. help_code = M->old_help
  2342.  
  2343. * un-hilite the name of the current data file
  2344. dehi_cur()
  2345.  
  2346. RETURN 0
  2347.  
  2348.  
  2349. ******
  2350. *    fltr_title()
  2351. *
  2352. *    display title for filter entry
  2353. ******
  2354. FUNCTION fltr_title
  2355.  
  2356. PARAMETERS sysparam
  2357.  
  2358. * title includes filename.ext but no path
  2359. RETURN box_title(M->sysparam, "Set filter for " +;
  2360.                               SUBSTR(M->cur_dbf, RAT("\", M->cur_dbf) + 1) +;
  2361.                               " to...")
  2362.  
  2363.  
  2364. ******
  2365. *    getfilter()
  2366. *
  2367. *    accept input of filter expression to the temporary variable "k_trim"
  2368. ******
  2369. FUNCTION getfilter
  2370.  
  2371. PARAMETERS sysparam
  2372.  
  2373. RETURN get_k_trim(M->sysparam, "Condition")
  2374.  
  2375.  
  2376. ******
  2377. *    do_filter()
  2378. *
  2379. *    complete the filter entry
  2380. ******
  2381. FUNCTION do_filter
  2382.  
  2383. PRIVATE done, k_sample
  2384.  
  2385. IF EMPTY(M->k_trim)
  2386.     * a confirmed empty expression means eliminate the current filter
  2387.     done = .T.
  2388.  
  2389.     IF .NOT. EMPTY(&k_filter)
  2390.         * cancel any filter that may be active
  2391.         SET FILTER TO
  2392.  
  2393.         * set global filter expression to nul
  2394.         &k_filter = ""
  2395.  
  2396.     ENDIF
  2397.  
  2398. ELSE
  2399.  
  2400.     IF TYPE(M->k_trim) = "L"
  2401.         * expression evaluates ok
  2402.         done = .T.
  2403.  
  2404.         IF .NOT. (&k_filter == M->k_trim)
  2405.             * change in filter expression..set global variables
  2406.             need_filtr = .T.
  2407.             &k_filter = M->k_trim
  2408.  
  2409.         ENDIF
  2410.  
  2411.     ELSE
  2412.         done = .F.
  2413.         error_msg("Filter must be a Logical expression")
  2414.  
  2415.     ENDIF
  2416. ENDIF
  2417.  
  2418. RETURN M->done
  2419.  
  2420.  
  2421. ******
  2422. *    clear_dbf()
  2423. *
  2424. *    clear specified work area..shift higher work areas if requested
  2425. *
  2426. *    shift values:
  2427. *        0  =  no shift
  2428. *        1  =  shift right (insert)
  2429. *        2  =  shift left (delete)
  2430. ******
  2431. FUNCTION clear_dbf
  2432.  
  2433. PARAMETERS work_area, shift
  2434. PRIVATE s_alias,c_area,temp,xtemp,i,file_name,alias_6,n_active
  2435.  
  2436. * determine number of active work areas
  2437. n_active = afull(M->dbf)
  2438.  
  2439. * extract alias of specified work area
  2440. s_alias = name(dbf[M->work_area])
  2441.  
  2442. * area 6 could be affected if shifting due to insert
  2443. alias_6 = ""
  2444.  
  2445. * access the list of index files for the current area
  2446. temp = "ntx" + SUBSTR("123456", M->work_area, 1)
  2447.  
  2448. DO CASE
  2449.  
  2450.     CASE M->shift = 0
  2451.         * no shift..no problem
  2452.         dbf[M->work_area] = ""
  2453.  
  2454.         * reduce number of open files by no. of index files + 1
  2455.         n_files = M->n_files - afull(&temp) - 1
  2456.  
  2457.     CASE M->shift = 1
  2458.         * shift right..current data file (if any) will remain open
  2459.  
  2460.         IF .NOT. EMPTY(dbf[6])
  2461.             * remember the alias
  2462.             alias_6 = name(dbf[6])
  2463.  
  2464.             * reduce number of open files by no. of index files + 1
  2465.             n_files = M->n_files - afull(M->ntx6) - 1
  2466.  
  2467.         ENDIF
  2468.  
  2469.         * shift may not be needed after all
  2470.         shift = IF(EMPTY(dbf[M->work_area]) .OR. M->work_area = 6, 0, 1)
  2471.  
  2472.         * open an empty element in global array of data files
  2473.         array_ins(M->dbf, M->work_area)
  2474.  
  2475.     CASE M->shift = 2
  2476.         * shift left..current data file will be closed
  2477.         array_del(M->dbf, M->work_area)
  2478.  
  2479.         * shift may not be needed after all
  2480.         shift = IF(EMPTY(dbf[M->work_area]), 0, 2)
  2481.  
  2482.         * reduce number of open files by no. of index files + 1
  2483.         n_files = M->n_files - afull(&temp) - 1
  2484.  
  2485. ENDCASE
  2486.  
  2487. i = 1
  2488.  
  2489. DO WHILE M->i <= M->n_active
  2490.     * select area i
  2491.     c_area = CHR(M->i + ASC("A") - 1)
  2492.     SELECT (M->i)
  2493.  
  2494.     IF M->i = M->work_area .OR. (M->i > M->work_area .AND. M->shift <> 0)
  2495.         * close all work areas to be shifted or closed
  2496.         USE
  2497.  
  2498.     ENDIF
  2499.  
  2500.     * search filters in all active areas for disappearing aliases
  2501.     temp = "kf" + SUBSTR("123456", M->i, 1)
  2502.  
  2503.     IF (((M->s_alias + "->" $ UPPER(&temp)) .OR.;
  2504.        (M->i = M->work_area .AND. .NOT. EMPTY(&temp)));
  2505.        .AND. M->shift <> 1) .OR. (.NOT. EMPTY(M->alias_6) .AND.;
  2506.        M->alias_6 + "->" $ UPPER(&temp) .AND. M->shift = 1)
  2507.         * data file was part of filter expression or none can exist
  2508.  
  2509.         * turn of the filter
  2510.         SET FILTER TO
  2511.  
  2512.         * will need to reset
  2513.         need_filtr = .T.
  2514.  
  2515.         * set global filter expression to nul
  2516.         &temp = ""
  2517.  
  2518.     ENDIF
  2519.  
  2520.     * next
  2521.     i = M->i + 1
  2522.  
  2523. ENDDO
  2524.  
  2525. DO CASE
  2526.  
  2527.     CASE M->shift = 0
  2528.         * clear array of index files
  2529.         temp = "ntx" + SUBSTR("123456", M->work_area, 1)
  2530.         afill(&temp, "")
  2531.  
  2532.         * clear field list
  2533.         temp = "field_n" + SUBSTR("123456", M->work_area, 1)
  2534.         afill(&temp, "")
  2535.  
  2536.         * clear filter
  2537.         temp = "kf" + SUBSTR("123456", M->work_area, 1)
  2538.         &temp = ""
  2539.  
  2540.     CASE M->shift = 1
  2541.         * shift right
  2542.         need_filtr = .T.    && will need to reset
  2543.         need_ntx = .T.        && ditto
  2544.  
  2545.         * count backwards..dbf array may not be contiguous
  2546.         i = 6
  2547.  
  2548.         DO WHILE EMPTY(dbf[M->i])
  2549.             * find highest active area
  2550.             i = M->i - 1
  2551.  
  2552.         ENDDO
  2553.  
  2554.         DO WHILE M->i > M->work_area
  2555.             * shift all higher work areas..list of index files
  2556.             temp = "ntx" + SUBSTR("123456", M->i, 1)
  2557.             xtemp = "ntx" + SUBSTR("123456", M->i - 1, 1)
  2558.             acopy(&xtemp,&temp)
  2559.  
  2560.             * active fields list
  2561.             temp = "field_n" + SUBSTR("123456", M->i, 1)
  2562.             xtemp = "field_n" + SUBSTR("123456", M->i - 1, 1)
  2563.             acopy(&xtemp,&temp)
  2564.  
  2565.             * current rows
  2566.             temp = "cr" + SUBSTR("123456", M->i, 1)
  2567.             xtemp = "cr" + SUBSTR("123456", M->i - 1, 1)
  2568.             acopy(&xtemp,&temp)
  2569.  
  2570.             * current elements
  2571.             temp = "el" + SUBSTR("123456", M->i, 1)
  2572.             xtemp = "el" + SUBSTR("123456", M->i - 1, 1)
  2573.             acopy(&xtemp,&temp)
  2574.  
  2575.             * filter expressions
  2576.             temp = "kf" + SUBSTR("123456", M->i, 1)
  2577.             xtemp = "kf" + SUBSTR("123456", M->i - 1, 1)
  2578.             &temp = &xtemp
  2579.  
  2580.             * next
  2581.             i = M->i - 1
  2582.  
  2583.         ENDDO
  2584.  
  2585.         * clear the specified work area (i = work_area)
  2586.         xtemp = SUBSTR("123456", M->i, 1)    && str(i) for convenience
  2587.  
  2588.         * clear index files list
  2589.         temp = "ntx" + xtemp
  2590.         afill(&temp, "")
  2591.  
  2592.         * clear active fields list
  2593.         temp = "field_n" + xtemp
  2594.         afill(&temp, "")
  2595.  
  2596.         * clear filter expression
  2597.         temp = "kf" + xtemp
  2598.         &temp = ""
  2599.  
  2600.         * reset current rows
  2601.         temp = "cr" + xtemp
  2602.         &temp[2] = row_a[2]
  2603.         &temp[3] = row_a[3]
  2604.  
  2605.         * reset current elements
  2606.         temp = "el" + xtemp
  2607.         afill(&temp, 1)
  2608.  
  2609.     CASE M->shift = 2
  2610.         * shift left
  2611.         need_filtr = .T.    && will need to reset
  2612.         need_ntx = .T.        && ditto
  2613.  
  2614.         i = M->work_area
  2615.  
  2616.         DO WHILE M->i < 6 .AND. .NOT. EMPTY(dbf[M->i])
  2617.             * shift all higher work areas..list of index files
  2618.             temp = "ntx" + SUBSTR("123456", M->i, 1)
  2619.             xtemp = "ntx" + SUBSTR("123456", M->i + 1, 1)
  2620.             acopy(&xtemp,&temp)
  2621.  
  2622.             * active fields list
  2623.             temp = "field_n" + SUBSTR("123456", M->i, 1)
  2624.             xtemp = "field_n" + SUBSTR("123456", M->i + 1, 1)
  2625.             acopy(&xtemp,&temp)
  2626.  
  2627.             * current rows
  2628.             temp = "cr" + SUBSTR("123456", M->i, 1)
  2629.             xtemp = "cr" + SUBSTR("123456", M->i + 1, 1)
  2630.             acopy(&xtemp,&temp)
  2631.  
  2632.             * current elements
  2633.             temp = "el" + SUBSTR("123456", M->i, 1)
  2634.             xtemp = "el" + SUBSTR("123456", M->i + 1, 1)
  2635.             acopy(&xtemp,&temp)
  2636.  
  2637.             * filter expressions
  2638.             temp = "kf" + SUBSTR("123456", M->i, 1)
  2639.             xtemp = "kf" + SUBSTR("123456", M->i + 1, 1)
  2640.             &temp = &xtemp
  2641.  
  2642.             * next
  2643.             i = M->i + 1
  2644.  
  2645.         ENDDO
  2646.  
  2647.         * clear the last (previously active) work area
  2648.         xtemp = SUBSTR("123456", M->i, 1)    && str(i) for convenience
  2649.  
  2650.         * clear index files list
  2651.         temp = "ntx" + M->xtemp
  2652.         afill(&temp, "")
  2653.  
  2654.         * clear active fields list
  2655.         temp = "field_n" + M->xtemp
  2656.         afill(&temp, "")
  2657.  
  2658.         * clear filter expression
  2659.         temp = "kf" + M->xtemp
  2660.         &temp = ""
  2661.  
  2662.         * reset current rows
  2663.         temp = "cr" + M->xtemp
  2664.         &temp[2] = row_a[2]
  2665.         &temp[3] = row_a[3]
  2666.  
  2667.         * reset current elements
  2668.         temp = "el" + M->xtemp
  2669.         afill(&temp, 1)
  2670.  
  2671. ENDCASE
  2672.  
  2673. * will need to reset
  2674. need_field = .T.
  2675.  
  2676. **
  2677. *    note: the source and target of relations are identified
  2678. *          by the letter of the work area + the alias
  2679. **
  2680.  
  2681. * get letter of cleared work area
  2682. c_area = CHR(M->work_area + ASC("A") - 1)
  2683.  
  2684. i = 1
  2685.  
  2686. DO WHILE M->i <= LEN(M->k_relate)
  2687.     * search all active relations
  2688.  
  2689.     IF EMPTY(k_relate[M->i])
  2690.         * no more active relations
  2691.         EXIT
  2692.  
  2693.     ENDIF
  2694.  
  2695.     IF ((SUBSTR(s_relate[M->i], 1, 1) = M->c_area .OR.;
  2696.        SUBSTR(t_relate[M->i], 1, 1) = M->c_area) .AND. M->shift <> 1) .OR.;
  2697.        (M->shift = 1 .AND. SUBSTR(t_relate[M->i], 1, 1) = "F")
  2698.         * relation must be removed from list
  2699.  
  2700.         array_del(M->s_relate, M->i)
  2701.         array_del(M->k_relate, M->i)
  2702.         array_del(M->t_relate, M->i)
  2703.         need_relat = .T.
  2704.  
  2705.     ELSE
  2706.  
  2707.         IF (M->shift = 2 .AND. SUBSTR(s_relate[M->i], 1, 1) > M->c_area) .OR.;
  2708.            (M->shift = 1 .AND. SUBSTR(s_relate[M->i], 1, 1) >= M->c_area)
  2709.             * source work area was shifted..adjust source area
  2710.  
  2711.             s_relate[M->i] = CHR(ASC(SUBSTR(s_relate[M->i], 1, 1)) +;
  2712.                              IF(M->shift = 1, 1, -1)) +;
  2713.                              SUBSTR(s_relate[M->i], 2)
  2714.             need_relat = .T.
  2715.  
  2716.         ENDIF
  2717.  
  2718.         IF (M->shift = 2 .AND. SUBSTR(t_relate[M->i], 1, 1) > M->c_area) .OR.;
  2719.            (M->shift = 1 .AND. SUBSTR(t_relate[M->i], 1, 1) >= M->c_area)
  2720.             * target work area was shifted..adjust target area
  2721.  
  2722.             t_relate[M->i] = CHR(ASC(SUBSTR(t_relate[M->i], 1, 1)) +;
  2723.                              IF(M->shift = 1, 1, -1)) +;
  2724.                              SUBSTR(t_relate[M->i], 2)
  2725.             need_relat = .T.
  2726.  
  2727.         ENDIF
  2728.  
  2729.         * next
  2730.         i = M->i + 1
  2731.  
  2732.     ENDIF
  2733. ENDDO
  2734.  
  2735. IF M->shift <> 0
  2736.     * re-open active data files in new work areas
  2737.     i = 6
  2738.  
  2739.     DO WHILE M->i >= M->work_area
  2740.         * search all shifted work areas
  2741.  
  2742.         IF .NOT. EMPTY(dbf[M->i])
  2743.             * open data file
  2744.             c_area = CHR(M->i + ASC("A") - 1)
  2745.             SELECT (M->i)
  2746.             file_name = dbf[M->i]
  2747.             USE &file_name
  2748.  
  2749.         ENDIF
  2750.  
  2751.         * next
  2752.         i = M->i - 1
  2753.  
  2754.     ENDDO
  2755. ENDIF
  2756.  
  2757. RETURN 0
  2758.  
  2759.  
  2760. ******
  2761. *    save_view()
  2762. *
  2763. *    save the current view in a ".VEW" file
  2764. *
  2765. *    note: - the view file is a data base file with a default extension
  2766. *            of ".VEW" and 2 fields: "item_name" and "contents".
  2767. *          -    the first 2 items are reserved for the global variables
  2768. *            "cur_dir", and "n_files"..then a variable number of
  2769. *            filter expressions..the remaining items are arrays.
  2770. *          -    if the contents of an item will not fit in the contents
  2771. *            field, it will be continued in the next record where
  2772. *            the item_name will be left blank.
  2773. *          -    for arrays, only the identifier is saved..the number of
  2774. *            items is the number of elements to fill
  2775. ******
  2776. FUNCTION save_view
  2777.  
  2778. PRIVATE filename, old_help
  2779.  
  2780. * save old and set new help codes
  2781. old_help = M->help_code
  2782. help_code = 21
  2783.  
  2784. * get user entered file name..will default to primary + ".VEW"
  2785. IF EMPTY(M->view_file) .AND. .NOT. EMPTY(dbf[1])
  2786.     * default to name of primary data file
  2787.     filename = name(dbf[1]) + ".VEW"
  2788.  
  2789. ELSE
  2790.     * whatever the last view was
  2791.     filename = M->view_file
  2792.  
  2793. ENDIF
  2794.  
  2795. * it's better in a box
  2796. filebox(".VEW", "vew_list", "vcrea_titl", "do_creavew", .T., 8)
  2797.  
  2798. * restore help code
  2799. help_code = M->old_help
  2800.  
  2801. RETURN 0
  2802.  
  2803.  
  2804. ******
  2805. *    vcrea_titl()
  2806. *
  2807. *    display title for save view
  2808. ******
  2809. FUNCTION vcrea_titl
  2810.  
  2811. PARAMETERS sysparam
  2812.  
  2813. RETURN box_title(M->sysparam, "Save view as...")
  2814.  
  2815.  
  2816. ******
  2817. *    do_creavew()
  2818. *
  2819. *    save the current view in a .VEW file
  2820. ******
  2821. FUNCTION do_creavew
  2822.  
  2823. PRIVATE i, j, k, m_name, l_name, add_name
  2824.  
  2825. IF EMPTY(M->filename)
  2826.     error_msg("View file not selected")
  2827.     RETURN .F.
  2828.  
  2829. ENDIF
  2830.  
  2831. * select system reserved work area
  2832. SELECT 10
  2833.  
  2834. stat_msg("Generating View File")
  2835.  
  2836. * add new .VEW files to vew_list if created in current directory only
  2837. add_name = .NOT. FILE(name(filename) + ".VEW")
  2838.  
  2839. * create structure extended template
  2840. CREATE ddbbuuuu.ext
  2841.  
  2842. * define 2 fields
  2843. APPEND BLANK
  2844. REPLACE field_name WITH "ITEM_NAME",field_type WITH "C",field_len WITH 10
  2845.  
  2846. APPEND BLANK
  2847. REPLACE field_name WITH "CONTENTS",field_type WITH "C",field_len WITH 10
  2848.  
  2849. * create the view file
  2850. USE
  2851. CREATE &filename FROM ddbbuuuu.ext
  2852.  
  2853. * set global variable
  2854. view_file = M->filename
  2855.  
  2856. * open view file..avoid alias conflict
  2857. USE &view_file ALIAS ddbbuuuu
  2858.  
  2859. * erase template
  2860. ERASE ddbbuuuu.ext
  2861.  
  2862. * 2 global variables always saved
  2863. APPEND BLANK
  2864. REPLACE item_name WITH "cur_dir"
  2865. put_line(cur_dir)
  2866.  
  2867. APPEND BLANK
  2868. REPLACE item_name WITH "n_files"
  2869. put_line(LTRIM(STR(n_files)))
  2870.  
  2871. i = 1
  2872.  
  2873. DO WHILE i <= 6
  2874.     * filters
  2875.  
  2876.     IF EMPTY(dbf[i])
  2877.         * no more data files
  2878.         EXIT
  2879.  
  2880.     ENDIF
  2881.  
  2882.     * get variable name for macro expansion
  2883.     m_name = "kf" + SUBSTR("123456", i, 1)
  2884.  
  2885.     IF .NOT. EMPTY(&m_name)
  2886.         * only save active filters
  2887.         APPEND BLANK
  2888.         REPLACE item_name WITH m_name
  2889.         put_line(&m_name)
  2890.  
  2891.     ENDIF
  2892.  
  2893.     * next
  2894.     i = i + 1
  2895.  
  2896. ENDDO
  2897.  
  2898. * save arrays..avoid saving empty elements
  2899. i = 1
  2900.  
  2901. DO WHILE i <= 6
  2902.     * data file filespecs
  2903.  
  2904.     IF EMPTY(dbf[i])
  2905.         * no more data files
  2906.         EXIT
  2907.  
  2908.     ENDIF
  2909.  
  2910.     * save one filespec
  2911.     APPEND BLANK
  2912.     REPLACE item_name WITH "dbf"
  2913.     put_line(dbf[i])
  2914.  
  2915.     * next
  2916.     i = i + 1
  2917.  
  2918. ENDDO
  2919.  
  2920. * save index lists and fields lists
  2921. l_name = "ntx"
  2922.  
  2923. FOR k = 1 TO 2
  2924.     * first the indexed, then the fields
  2925.     i = 1
  2926.  
  2927.     DO WHILE i <= 6
  2928.         * index or field list for each data file
  2929.  
  2930.         IF EMPTY(dbf[i])
  2931.             * no more data files
  2932.             EXIT
  2933.  
  2934.         ENDIF
  2935.  
  2936.         * get array identifier for macro expansion
  2937.         m_name = l_name + SUBSTR("123456", i, 1)
  2938.  
  2939.         j = 1
  2940.  
  2941.         DO WHILE j <= LEN(&m_name)
  2942.             * index or field list for one data file
  2943.  
  2944.             IF EMPTY(&m_name[j])
  2945.                 * an early exit saves time and disk space
  2946.                 EXIT
  2947.  
  2948.             ENDIF
  2949.  
  2950.             * save one index filespec or one field name
  2951.             APPEND BLANK
  2952.             REPLACE item_name WITH m_name
  2953.             put_line(&m_name[j])
  2954.  
  2955.             * next element
  2956.             j = j + 1
  2957.  
  2958.         ENDDO
  2959.  
  2960.         * next work area
  2961.         i = i + 1
  2962.  
  2963.     ENDDO
  2964.  
  2965.     * switch to field lists
  2966.     l_name = "field_n"
  2967.  
  2968. NEXT
  2969.  
  2970. i = 1
  2971.  
  2972. DO WHILE i <= 3
  2973.     * relations in 3 arrays..s_relate, k_relate, and t_relate
  2974.     m_name = SUBSTR("skt", i, 1) + "_relate"
  2975.     j = 1
  2976.  
  2977.     DO WHILE j <= LEN(&m_name)
  2978.         * one array
  2979.  
  2980.         IF EMPTY(&m_name[j])
  2981.             * an early exit saves time and disk space
  2982.             EXIT
  2983.  
  2984.         ENDIF
  2985.  
  2986.         * one item
  2987.         APPEND BLANK
  2988.         REPLACE item_name WITH m_name
  2989.         put_line(&m_name[j])
  2990.  
  2991.         * next element
  2992.         j = j + 1
  2993.  
  2994.     ENDDO
  2995.  
  2996.     * next array
  2997.     i = i + 1
  2998.  
  2999. ENDDO
  3000.  
  3001. * close view file
  3002. USE
  3003.  
  3004. * add file name to array of view files
  3005. IF AT(".VEW", filename) = LEN(filename) - 3 .AND.;
  3006.    FILE(name(filename) + ".VEW") .AND. add_name
  3007.     * add only new .VEW files in the current directory
  3008.  
  3009.     * determine number of first empty element
  3010.     i = afull(vew_list) + 1
  3011.  
  3012.     IF i <= LEN(vew_list)
  3013.         * room for one more
  3014.         vew_list[i] = filename
  3015.  
  3016.         * must be alphabetical
  3017.         array_sort(vew_list)
  3018.  
  3019.     ENDIF
  3020. ENDIF
  3021.  
  3022. stat_msg("")
  3023.  
  3024. RETURN .T.
  3025.  
  3026.  
  3027. ******
  3028. *    put_line()
  3029. *
  3030. *    store string in contents field(s) of open view file
  3031. ******
  3032. FUNCTION put_line
  3033.  
  3034. PARAMETERS line
  3035. PRIVATE pos
  3036.  
  3037. * assign contents to the current record
  3038. REPLACE contents WITH line
  3039.  
  3040. * position to begin fragmentation
  3041. pos = LEN(contents) + 1
  3042.  
  3043. DO WHILE pos <= LEN(line)
  3044.     * continue contents in next record
  3045.     APPEND BLANK
  3046.     REPLACE contents WITH SUBSTR(line, pos)
  3047.  
  3048.     * next chunk
  3049.     pos = pos + LEN(contents)
  3050.  
  3051. ENDDO
  3052.  
  3053. RETURN 0
  3054.  
  3055.  
  3056. ******
  3057. *    set_from()
  3058. *
  3059. *    restore View from .VEW file
  3060. ******
  3061. FUNCTION set_from
  3062.  
  3063. PARAMETERS from_view
  3064. PRIVATE filename, old_help
  3065.  
  3066. * save old and set new help codes
  3067. old_help = M->help_code
  3068. help_code = 21
  3069.  
  3070. * default to previous View file if any
  3071. filename = M->view_file
  3072.  
  3073. IF M->from_view
  3074.     * called from set_view
  3075.  
  3076.     IF filebox(".VEW", "vew_list", "vopen_titl", "do_openvew", .F., 8) <> 0
  3077.         * indicate new View has been set
  3078.         keystroke = 13
  3079.  
  3080.     ENDIF
  3081.  
  3082. ELSE
  3083.     * just do it
  3084.     do_openvew()
  3085.  
  3086. ENDIF
  3087.  
  3088. * restore help code
  3089. help_code = M->old_help
  3090.  
  3091. RETURN 0
  3092.  
  3093.  
  3094. ******
  3095. *    vopen_titl()
  3096. *
  3097. *    display title for restore view
  3098. ******
  3099. FUNCTION vopen_titl
  3100.  
  3101. PARAMETERS sysparam
  3102.  
  3103. RETURN box_title(M->sysparam, "Restore view from...")
  3104.  
  3105.  
  3106. ******
  3107. *    do_openvew()
  3108. *
  3109. *    restore view from .VEW file
  3110. *
  3111. *    note: this function is called when the enter key is
  3112. *          pressed while the cursor is on the Ok button
  3113. ******
  3114. FUNCTION do_openvew
  3115.  
  3116. PRIVATE m_name, i, done
  3117.  
  3118. DO CASE
  3119.  
  3120.     CASE EMPTY(M->filename)
  3121.         error_msg("View file not selected")
  3122.         done = .F.
  3123.  
  3124.     CASE .NOT. FILE(M->filename)
  3125.         error_msg("Can't open " + M->filename)
  3126.         done = .F.
  3127.  
  3128.     OTHERWISE
  3129.         * select system reserved work area
  3130.         SELECT 10
  3131.  
  3132.         * open .VEW file..avoid alias conflict
  3133.         USE &filename ALIAS ddbbuuuu
  3134.  
  3135.         IF .NOT. (TYPE("item_name") = "C" .AND. TYPE("contents") = "C")
  3136.             USE
  3137.             error_msg("Invalid view file")
  3138.             RETURN .F.
  3139.  
  3140.         ENDIF
  3141.  
  3142.         * ok to restore View..set global variable
  3143.         view_file = M->filename
  3144.  
  3145.         * entire View will need setup
  3146.         STORE .T. TO need_field,need_ntx,need_relat,need_filtr
  3147.         stat_msg("Restoring view")
  3148.  
  3149.         * clear the current view if any
  3150.         i = 6
  3151.  
  3152.         DO WHILE M->i > 0
  3153.  
  3154.             IF .NOT. EMPTY(dbf[M->i])
  3155.                 * clear one work area
  3156.                 clear_dbf(M->i, 0)
  3157.  
  3158.             ENDIF
  3159.  
  3160.             * next
  3161.             i = M->i - 1
  3162.  
  3163.         ENDDO
  3164.  
  3165.         * select system reserved work area
  3166.         SELECT 10
  3167.  
  3168.         * "cur_dir" and "n_files" always saved first
  3169.         cur_dir = get_line()
  3170.         n_files = VAL(get_line())
  3171.  
  3172.         IF TRIM(item_name) == "k_filter"
  3173.             * continued support for old format
  3174.             REPLACE item_name WITH "kf1"
  3175.             kf1 = get_line()
  3176.  
  3177.         ELSE
  3178.  
  3179.             DO WHILE SUBSTR(item_name, 1, 2) == "kf"
  3180.                 * get one filter expression
  3181.                 m_name = TRIM(item_name)
  3182.  
  3183.                 * assign the expression
  3184.                 &m_name = get_line()
  3185.  
  3186.             ENDDO
  3187.         ENDIF
  3188.  
  3189.         * all remaining information to be stored in global arrays
  3190.         DO WHILE .NOT. EOF()
  3191.             * get next array identifier and initialize subscript
  3192.             m_name = TRIM(item_name)
  3193.             i = 1
  3194.  
  3195.             * fill one array
  3196.             DO WHILE TRIM(item_name) == m_name
  3197.                 * fill one element of array
  3198.                 &m_name[i] = get_line()
  3199.  
  3200.                 * next element
  3201.                 i = i + 1
  3202.  
  3203.             ENDDO
  3204.         ENDDO
  3205.  
  3206.         * close the view file
  3207.         USE
  3208.  
  3209.         * open all data files in their select areas
  3210.         i = 1
  3211.  
  3212.         DO WHILE M->i <= 6
  3213.  
  3214.             IF EMPTY(dbf[M->i])
  3215.                 * no more data files to open
  3216.                 EXIT
  3217.  
  3218.             ENDIF
  3219.  
  3220.             * select the corresponding work area
  3221.             SELECT (M->i)
  3222.  
  3223.             * open the data file
  3224.             filename = dbf[M->i]
  3225.             USE &filename
  3226.  
  3227.             * next work area
  3228.             i = M->i + 1
  3229.  
  3230.         ENDDO
  3231.  
  3232.         stat_msg("")
  3233.         done = .T.
  3234.  
  3235. ENDCASE
  3236.  
  3237. RETURN M->done
  3238.  
  3239.  
  3240. ******
  3241. *    get_line()
  3242. *
  3243. *    assemble contents of variable from .VEW file
  3244. ******
  3245. FUNCTION get_line
  3246.  
  3247. PRIVATE line
  3248.  
  3249. * assign contents from first record
  3250. line = TRIM(contents)
  3251. SKIP
  3252.  
  3253. DO WHILE LEN(TRIM(item_name)) = 0 .AND. .NOT. EOF()
  3254.     * blank name field means contents are continued in next record
  3255.     line = line + TRIM(contents)
  3256.     SKIP
  3257.  
  3258. ENDDO
  3259.  
  3260. RETURN line
  3261.  
  3262.  
  3263. * EOF DBUVIEW.PRG
  3264.