home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / devtools / dataflex / datalist.pkg < prev    next >
Encoding:
Text File  |  1993-08-10  |  67.6 KB  |  2,117 lines

  1. //************************************************************************
  2. //
  3. // Copyright 1987-1992 Data Access Corporation, Miami FL, USA
  4. // All Rights reserved
  5. // DataFlex is a registered trademark of Data Access Corporation.
  6. //
  7. //
  8. //     $Source: /u3/source.30/product/pkg/RCS/datalist.pkg,v $
  9. //     $Revision: 1.1 $
  10. //     $State: Exp $
  11. //     $Author: james $
  12. //     $Date: 1992/09/08 14:43:03 $
  13. //     $Locker:  $
  14. //
  15. //     $Log: datalist.pkg,v $
  16. //Revision 1.1  1992/09/08  14:43:03  james
  17. //Initial revision
  18. //
  19. //Revision 1.27  92/07/02  18:17:23  lee
  20. //added guard in beginning/end_of_data for no items to prevent invalid item
  21. //refrerence.
  22. //
  23. //Revision 1.26  92/07/01  04:30:08  lee
  24. //if virtual_scroll fails, perform find_record to find and display current
  25. //record. (was just moving to row w/o find or refresh to deos.)
  26. //
  27. //Revision 1.25  92/06/28  16:11:42  lee
  28. //fixed deletion bottom row so you can navigate to the records after the deleted
  29. //record.
  30. //
  31. //Revision 1.24  92/06/27  10:13:35  lee
  32. //fixed initialize list to deal with pad and top row as blank.
  33. //
  34. //Revision 1.23  92/06/27  09:29:46  lee
  35. //changed up_row and scroll (upward) to goto end of data if it was on blank
  36. //row and still is after virtual scroll. This assumes this occurred because
  37. //you were on the top row with only a blank record showing.
  38. //end_of_data now correctly moves to last row in partially filled lists.
  39. //blank and padding row are added to list when displaying as empty (activatin
  40. //and clear_data).
  41. //
  42. //Revision 1.22  92/06/22  13:46:27  lee
  43. //changed default setting of auto_regenerate_state to true (OOPS!).
  44. //
  45. //Revision 1.21  92/06/17  23:55:00  lee
  46. //fixed various bugs in table: only validates on same row and during save
  47. //childwrapping moves to last enterable item when moving backward
  48. //request_delete disables validation during removal of row.
  49. //beginning/end_of panel moves to top/biottom row, same column
  50. //
  51. //Revision 1.20  92/06/10  06:09:45  lee
  52. //various fixes for bugs introduced during "overhaul"
  53. //
  54. //Revision 1.19  92/06/06  11:55:44  lee
  55. //put guard in fill_page to not search for more records if there is only one row.
  56. //(it was previously going to one after/before the first/last item on beg/end of
  57. //data).
  58. //
  59. //Revision 1.18  92/06/06  08:12:46  lee
  60. //added add-mode stuff (lots of it!). moved some things from table into
  61. //data_list for row_changing.
  62. //
  63. //Revision 1.17  92/05/14  16:11:25  SWM
  64. //Updated Copyright slug.
  65. //
  66. //Revision 1.16  92/04/28  14:31:12  lee
  67. //Initialize_list now passes TRUE to beginning of data to prevent save on
  68. //initialization.
  69. //
  70. //Revision 1.15  92/04/03  16:37:16  lee
  71. //fixed syntax usage for item_matching forward to be correct. batch data_lists
  72. //will now perform item_matching (and incremental-search) properly.
  73. //
  74. //Revision 1.14  92/04/01  11:13:53  lee
  75. //fixed references to bind_list_main_file/index to bind_datalist_...
  76. //
  77. //Revision 1.13  92/04/01  00:30:04  lee
  78. //removed navstart and liststart (unused), renamed bind_main_file and bind_index
  79. //in datalist to bind_list_main_file and bind_list_index to avoid conflict with
  80. //commands used by data_set, moved bind_static from sellist to datalist as it
  81. //only sets properties defined in datalist (not sellist).
  82. //
  83. //Revision 1.12  92/03/29  18:44:37  lee
  84. //added MSG_END_CONSTRUCT_OBJECT, moved ENDMAC macro stuff into END_CONSTRUCT-
  85. //OBJECT procedures (in .pkgs). moved Flag_ITems to list.pkg after generalizing
  86. //it based on PROTOTYPE_OBJECT instead of Whether or not it is a table-oriented
  87. //object. Moved define_access_keys mechanism completely into actionbr.pkg.
  88. //fixed two typos: import_class_protocol used !# instead of !3, and register-
  89. //procedure used !1 instead of !2.
  90. //
  91. //Revision 1.11  92/03/27  16:21:05  steve-l
  92. //DISPLAY_ROW altered to set line_Display_state and send refresh instead of
  93. //forwarding refresh directly
  94. //
  95. //Revision 1.10  92/03/18  12:40:09  steve-l
  96. //altered all calls to vfind to perform a relate if successful
  97. //
  98. //Revision 1.9  92/03/18  02:18:16  steve-l
  99. //added SEND UPDATE_DEPENDENT_ITEMS to end of Beginning_of_data and End_of_data
  100. //and added function PROTOTYPE_OBJECT to return row-prototype object-id.
  101. //
  102. //Revision 1.8  92/03/10  17:06:47  steve-l
  103. //REFRESH altered to support "remote" delete (e.g. delete from zoom)
  104. //
  105. //Revision 1.7  92/03/09  19:00:53  james
  106. //Added #CHKSUB directive to insure source
  107. //only compiled with correct revision of 
  108. //compiler.
  109. //
  110. //Revision 1.6  92/02/28  10:19:45  steve-l
  111. //VIRTUAL_SCROLL altered to correct slight batch-mode scrolling problems, i.e.
  112. //bad distance parameter and bogus return values corrected
  113. //
  114. //Revision 1.5  92/01/13  14:47:59  steve-l
  115. //Added MSG_REFRESH procedure and altered display_row procedure
  116. //
  117. //Revision 1.4  92/01/12  15:27:29  steve-l
  118. //*** empty log message ***
  119. //
  120. //Revision 1.3  91/11/19  09:37:27  steve-l
  121. //Checking in for Steve-L
  122. //
  123. //Revision 1.2  91/11/08  09:14:10  steve-l
  124. //the function VIRTUAL_SCROLL was altered to re-read the correct record
  125. //[DAR 2000]; CLEAR and CLEAR_ALL altered to respect cleared bit-array
  126. //[DAR 2193]
  127. //
  128. //************************************************************************/
  129.  
  130. //************************************************************************
  131. //     File Name: DataList.Pkg
  132. // Creation Date: January 1, 1991
  133. // Modified Date: March 17, 1992
  134. //     Author(s): Steven A. Lowe
  135. //
  136. // This module contains the Data_List class definition.
  137. //************************************************************************/
  138.  
  139. #CHKSUB 1 1 // Verify the UI subsystem.
  140.  
  141. use protoent   //row-prototype class
  142. use WideList   //multi-column list class
  143. use Server     //data_set connection class
  144.  
  145. //
  146. // constants for REFRESH message parameter values
  147. //
  148. #IFSUB 'MODE_CLEAR'
  149. #ELSE
  150.     #REPLACE MODE_CLEAR             1  //notification from origin of clear
  151.     #REPLACE MODE_FIND_OR_CLEAR_SET 2  //notification from find or clear
  152.     #REPLACE MODE_CLEAR_ALL         3  //notification from clear-all
  153.     #REPLACE MODE_DELETE            4  //notification after successful delete
  154.     #REPLACE MODE_SAVE              5  //notification after successful save
  155. #ENDIF
  156.  
  157.  
  158. Register_Function Current_Record returns integer
  159.  
  160. class Data_List is a Wide_List STARTMAC dlStart ENDMAC dlEnd
  161.  
  162.   //
  163.   // forward-reference of row-prototype, Element
  164.   //
  165.   Register_Object Element
  166.  
  167.   //
  168.   // forward-reference of data-set find functions
  169.   //
  170.   procedure construct_object integer img
  171.     forward send construct_object img
  172.     on_key kBegin_of_Panel SEND Goto_Top_Row    PRIVATE
  173.     on_key kEnd_of_Panel   SEND Goto_Bottom_Row PRIVATE
  174.     Property integer Advancing_State        PUBLIC   0
  175.     Property integer Auto_Regenerate_State  PUBLIC   1
  176.     Property integer Batch_State            PUBLIC   0
  177.     Property integer Changing_State         PUBLIC   0
  178.     Property integer Just_Reordered_State   PUBLIC   0
  179.     Property integer Main_File              PRIVATE  0
  180.     Property integer No_Create_State        PUBLIC   1
  181.     Property integer Ordering               PUBLIC  -1
  182.     Property integer Line_Display_State     PUBLIC   0
  183.     Property integer Reordering_State       PUBLIC   0
  184.     Property integer Static_State           PUBLIC   0
  185.     Property integer Unsorted_State         PUBLIC   0
  186.     Property integer Was_New_Row_State      PUBLIC   0
  187.     object Records is an array
  188.     end_object
  189.     send define_server  //invoke Server support constructor
  190.     set Auto_Fill_State to TRUE  //default auto-fill to true
  191.   end_procedure
  192.  
  193.   IMPORT_CLASS_PROTOCOL Server_Mixin
  194.  
  195.   //
  196.   // dummy functions for non-input classes (like selection list)
  197.   //
  198.   function auto_clear_deo_state returns integer
  199.     function_return 0
  200.   end_function
  201.   function auto_save_state returns integer
  202.     function_return 0
  203.   end_function
  204.  
  205.   //
  206.   // created to empty list item data (aug'd by SelList)
  207.   //
  208.   procedure empty_list
  209.     send delete_data
  210.   end_procedure
  211.  
  212.   procedure activating returns integer
  213.     local integer retval srvr# ordr#
  214.     get server to srvr#
  215.     get ordering to ordr#
  216.     if ((srvr# <> 0) AND (main_file(current_object) = main_file(srvr#)) AND ;
  217.         (ordr# >= 0)) set suggested_ordering of srvr# to ordr#
  218.     forward get msg_activating to retval
  219.     if ((retval = 0) AND (static_state(current_object) = 0)) begin
  220.       send empty_list    //delete_data
  221.  
  222.       send add_row
  223.       send entry_display 0 0    //redisplay active (parent) files
  224.       send insert_row 0 // add top padding row
  225.       set top_item to (item_limit(current_object))
  226.       set changed_state to false
  227.       send Enter_Add_Mode FALSE
  228.     end
  229.     procedure_return retval
  230.   end_procedure
  231.  
  232.   procedure Beginning_of_Panel
  233.     set search_mode to (search_mode(current_object))  //reset incr srch index
  234.     forward send Beginning_of_Panel
  235.   end_procedure
  236.  
  237.   procedure End_of_Panel
  238.     set search_mode to (search_mode(current_object))  //reset incr srch index
  239.     forward send End_of_Panel
  240.   end_procedure
  241.  
  242.   procedure down_row
  243.     set search_mode to (search_mode(current_object))  //reset incr srch index
  244.     forward send down_Row
  245.   end_procedure
  246.  
  247.   procedure up_row
  248.     local integer origRec oldErr
  249.     set search_mode to (search_mode(current_object))  //reset incr srch index
  250.     get current_record to origRec
  251.     move (err) to oldErr
  252.     indicate err FALSE
  253.     forward send up_Row
  254.     [err] procedure_return
  255.     indicate err as oldErr NE 0
  256.     //
  257.     // if we were on a blank row, and we're still on a blank row, we must
  258.     // be on the top row at the end of the data: force end of data
  259.     //
  260.     if ((origRec = 0) AND (current_record(current_object) = 0)) ;
  261.         send end_of_data
  262.   end_procedure
  263.  
  264.   procedure set Main_File integer newval
  265.     set Data_List.Main_File to newval
  266.   end_procedure
  267.  
  268.   function Main_File returns INTEGER
  269.     local integer retval obj#
  270.     get Data_List.Main_File to retval
  271.     if retval le 0 begin
  272.       get Server to obj#
  273.       if obj# ne 0 get Main_File of obj# to retval
  274.     end
  275.     function_Return retval
  276.   end_function
  277.  
  278.   procedure set record_number integer row# integer newval
  279.     set array_Value of (Records(current_object)) item row# to newval
  280.   end_procedure
  281.  
  282.   function record_number integer row# returns integer
  283.     local integer retval
  284.     get array_Value of (Records(Current_Object)) item row# to retval
  285.     function_Return retval
  286.   end_function
  287.  
  288.   function Current_Record returns integer
  289.     local integer retval
  290.     get record_number item (current_row(current_object)) to retval
  291.     function_Return retval
  292.   end_function
  293.  
  294.   procedure SET Current_Record integer newVal
  295.     set record_number item (current_row(current_object)) to newVal
  296.   end_procedure
  297.  
  298.   //
  299.   // the following scroll procedure is invoked by RT via scrollbar arrows
  300.   // (w/mouse) or PgUp/PgDn keys
  301.   //
  302.   procedure scroll integer dir integer dist 
  303.     local integer retval destItem lim oldDyn oldCol wasNew oldChg oldObjEntEx
  304.  
  305.     if (Batch_State(current_object)) forward send scroll dir dist
  306.     else begin
  307.       get current_item to destItem
  308.       get item_limit to lim
  309.  
  310.       //
  311.       // exit current item
  312.       //
  313.       get object_item_entry_exit to oldObjEntEx
  314.       if (oldObjEntEx AND (exec_exit(current_object,destItem) <> 0)) ;
  315.           procedure_return
  316.       set object_item_entry_exit to FALSE
  317.  
  318.       move (destItem - base_item(current_object)) to oldCol
  319.  
  320.       move (current_record(current_object) = 0) to wasNew
  321.       if wasNew begin
  322.         get Exit_Add_Mode TRUE FALSE destItem to retval
  323.         //
  324.         // if still on a blank record on scroll up, no more rows on screen,
  325.         // so we must be at the end of data on top row: force end of data
  326.         //
  327.         if ((dir = UPWARD_DIRECTION) AND ;
  328.             (current_record(current_object) = 0)) begin
  329.           send end_of_data
  330.           procedure_return
  331.         end
  332.       end
  333.  
  334.       get dynamic_update_state to oldDyn
  335.       set dynamic_update_state to FALSE
  336.  
  337.                   // if trying to move past end of list, just go to last item
  338.       if ((dir = DOWNWARD_DIRECTION) AND ;
  339.           (row_count(current_object) - 1) <= (bottom_row(current_object))) ;
  340.           move (((row_count(current_object) - 1) * lim) + oldCol) to destItem
  341.       else begin  // else attempt to scroll
  342.         get virtual_scroll dir dist to retval
  343.  
  344.         if retval LT 0 begin // if couldn't scroll whole dist, goto 1st/last
  345.           if dir EQ DOWNWARD_DIRECTION ;
  346.               move (((row_count(current_object) - 2) * lim) + oldCol) ;
  347.               to destItem       // (- 2) to move to row before padding row
  348.           else move (top_item(current_object) + oldCol) to destItem
  349.         end
  350.       end
  351.  
  352.       if (wasNew AND (current_record(current_object) = 0)) ;
  353.           send Enter_Add_Mode FALSE
  354.  
  355.       set current_item to destItem
  356.  
  357.       set dynamic_update_state to oldDyn
  358.  
  359.       set object_item_entry_exit to oldObjEntEx
  360.  
  361.       //
  362.       // enter current item
  363.       //
  364.       if (oldObjEntEx AND (exec_entry(current_object,destItem) <> 0)) ;
  365.           procedure_return
  366.  
  367.       //
  368.       // make sure Server is latched on to new current record
  369.       //
  370.       send find_record (current_record(current_object))
  371.       //
  372.       // reset incremental search index
  373.       //
  374.       set search_mode to (search_mode(current_object))
  375.     end
  376.   end_procedure
  377.  
  378.   //
  379.   // note displayRow changes baseItem without resetting it
  380.   //
  381.   procedure display_row integer row#
  382.     local integer oldlinedisp oldval lim
  383.  
  384.     get item_limit to lim
  385.  
  386.     set base_item to (row# * lim)
  387.     get line_display_State to oldlinedisp
  388.     set line_display_state to true
  389.     get current_item to oldval
  390.     set new_item to (row# * lim)
  391.     send refresh MODE_FIND_OR_CLEAR_SET
  392.     set new_item to oldval
  393.     set line_display_state to oldlinedisp
  394.   end_procedure
  395.  
  396.   //
  397.   // invoked by append_blank_row and insert_blank_row
  398.   //
  399.   procedure clear_row integer row#
  400.     local integer oldval lim ser#
  401.  
  402.     get item_limit to lim
  403.  
  404.     set base_item to (row# * lim)
  405.     get Server to ser#
  406.     if ser# ne 0 send Clear to ser#
  407.     else begin
  408.       get main_file to ser#
  409.       if ser# ne 0 begin
  410.         move ser# to filenumber
  411.         move 0 to fieldindex
  412.         clear Indirect_File
  413.       end
  414.       send clear
  415.     end
  416.     set record_number item row# to 0
  417.   end_procedure
  418.  
  419.   procedure INSERT_ROW integer row#  //insert row before specified row#
  420.     forward send insert_row (Prototype_Object(current_object)) row#
  421.     send insert_item to (Records(Current_Object)) row# 0 //insert 0 before row#
  422.   end_procedure
  423.  
  424.   procedure INSERT_NEW_ROW integer row#  //insert & display row before specified row#
  425.     send insert_row row#
  426.     send display_row row#
  427.   end_procedure
  428.  
  429.   procedure add_row     //add row at end of item list
  430.     forward send add_row (Prototype_Object(current_object))
  431.     set array_value of (Records(Current_Object)) ;
  432.         item (Row_Count(Current_Object) - 1) to 0
  433.   end_procedure
  434.  
  435.   procedure append_new_row     //add row at end of item list & display
  436.     send add_Row
  437.     send display_row (row_count(Current_Object) - 1)
  438.   end_procedure
  439.  
  440.   procedure append_blank_row     //add blank row at end of item list
  441.     send add_row
  442.     send clear_row (row_count(Current_Object) - 1)
  443.   end_procedure
  444.  
  445.   procedure insert_blank_row integer row#
  446.     send insert_row row#
  447.     send clear_row row#
  448.   end_procedure
  449.  
  450.   procedure Destroy_Top integer numRows
  451.     local integer count
  452.     move 0 to count
  453.     while count lt numRows
  454.       send Delete_Row 0
  455.       increment count
  456.     end
  457.   end_procedure
  458.  
  459.   procedure Destroy_Bottom integer numRows
  460.     local integer count maxrows
  461.     move 0 to count
  462.     get row_count to maxrows
  463.     while count lt numRows
  464.       decrement maxrows
  465.       send Delete_Row maxrows
  466.       increment count
  467.     until maxrows le 0
  468.   end_procedure
  469.  
  470.   procedure DELETE_ROW integer row#   //remove given row#
  471.     local integer lim baseItem counter width
  472.     get item_limit to width
  473.     calc (width * row#) to baseItem
  474.     calc (baseItem + width - 1) to lim
  475.     for counter from baseItem to lim
  476.       send delete_item baseItem
  477.     loop
  478.     send delete_item to (Records(Current_Object)) row#
  479.   end_procedure
  480.  
  481.   //
  482.   // invoked by Scroll, Display, and Row_Changing
  483.   //
  484.   procedure find_record integer rec#
  485.     local integer srvr# oldDisp
  486.     get Server to srvr#
  487.     if srvr# ne 0 begin
  488.       get Line_Display_State to oldDisp
  489.       set Line_Display_State to true  //set flag to prevent regen
  490.       if (Deferred_State(current_object)) send Read_By_RecNum to srvr# ;
  491.           (main_file(current_object)) rec#
  492.       else send Find_by_RecNum to srvr# (main_file(current_object)) rec#
  493.       set Line_Display_State to oldDisp //reset no-regen flag
  494.     end
  495.     else send Read_Record rec#
  496.   end_procedure
  497.  
  498.   procedure read_record integer rec#
  499.     local integer oldrec
  500.     get main_file to filenumber
  501.     if filenumber ne 0 begin
  502.       move 0 to fieldindex
  503.       move Indirect_File.RECNUM to oldrec
  504.       clear Indirect_File
  505.       move rec# to Indirect_File.recnum
  506.       find eq Indirect_File.RECNUM
  507.       if [not found] clear Indirect_File
  508.       else relate Indirect_File
  509.     end
  510.     else indicate found false
  511.   end_procedure
  512.  
  513.   //
  514.   // called by VIRTUAL_SCROLL and MSG_FILL_PAGE to trim list to displayable area
  515.   // plus top and bottom 'buffer' rows (should not be used if Batch)
  516.   //
  517.   procedure trim_page integer direction
  518.     local integer count retval oldChg rowCnt
  519.  
  520.     calc (row_count(current_object) - Displayable_rows(Current_Object)) to count
  521.     //
  522.     // trimming could be by count-1 iff count>1, with over/under rows
  523.     // simply cleared afterward, instead of destroying and recreating items
  524.     //
  525.     if count gt 0 begin
  526.       if direction eq UPWARD_DIRECTION send DESTROY_BOTTOM count
  527.       else send DESTROY_TOP count
  528.     end
  529.     send insert_row 0             //pad by one at top
  530.  
  531.     get row_count to rowCnt
  532.  
  533.     //
  534.     // if the last row was not already blank
  535.     //
  536.     if ((record_number(current_object,rowCnt - 1) <> 0) AND ;
  537.         (not(no_create_state(current_object)) OR ;
  538.         ((rowCnt - 1) >= displayable_rows(current_object)))) ;
  539.         send add_row
  540.  
  541.     //
  542.     // set top_item triggers set current_item; setting changing_state to
  543.     // true kills item_change effects, but still sets current_item
  544.     // however, it does not set base_item
  545.     //
  546.     get changing_State to oldChg
  547.     set changing_State to true
  548.     set top_item to (item_limit(Current_Object))
  549.     set changing_State to oldChg
  550.     //
  551.     // manually set base item for current row
  552.     //
  553.     set base_item to (current_row(current_object) * item_limit(current_object))
  554.  
  555.     //
  556.     // manually force entry for new current item
  557.     //
  558.  
  559.     if (select_mode(current_object)) EQ AUTO_SELECT ;
  560.         set select_state item current to TRUE
  561.   end_procedure
  562.  
  563.   //
  564.   // fix up rows at end of page; delete and add rows as necessary.
  565.   // if page is (can be) full, should be blank padding row off screen
  566.   // if page is partially full, if no_create = false, should be blank row
  567.   //
  568.   procedure finish_page
  569.     local integer count retval oldChg rowCnt svr rec# file# ndx
  570.  
  571.     get row_count to rowCnt
  572.  
  573.     calc ((rowCnt - top_row(current_object)) - displayable_rows(current_object)) to count
  574.  
  575.     //
  576.     // if last row is blank, remove it
  577.     //
  578.     if ((count GE 0) AND (record_number(current_object,rowCnt - 1) = 0)) begin
  579.       send delete_row (rowCnt - 1)
  580.       decrement count
  581.     end
  582.  
  583.     //
  584.     // if extra padding rows exist, remove them
  585.     //
  586.     if count GT 0 send DESTROY_BOTTOM count
  587.     //
  588.     // else, if page is not full, try to find records to fill out page
  589.     //
  590.     else if count LT 0 begin
  591.       move (0 - count) to count
  592.  
  593.       get server to svr
  594.       get main_file to file#
  595.       get record_number (row_count(current_object) - 1) to rec#
  596.       if ((svr <> 0) AND (rec# <> 0)) send Read_by_RecNum to svr file# rec#
  597.       else send read_Record rec#
  598.  
  599.       [not found] procedure_return
  600.  
  601.       get main_file to file#
  602.       get ordering to ndx
  603.  
  604.       if svr ne 0 send establish_find_direction to svr (GT) file# ndx
  605.  
  606.       repeat
  607.         if svr send Locate_Next to svr
  608.  
  609.         //
  610.         // if this object has no server, use the VFIND command to locate
  611.         // the next record for the given file, search-index, and find-mode
  612.         //
  613.         else begin
  614.           vfind file# ndx (GT)
  615.           [found] move file# to filenumber
  616.           [found] move 0 to fieldindex
  617.           [found] relate Indirect_File.RECNUM
  618.         end
  619.  
  620.         //
  621.         // if a record was found, display it
  622.         //
  623.         if [found] begin
  624.           send append_new_row
  625.           decrement count
  626.         end
  627.         else move 0 to count
  628.  
  629.       until count EQ 0
  630.  
  631.     end
  632.     //
  633.     // if the last row is not already blank, and no_create=false, add blank row
  634.     //
  635.     get row_count to rowCnt
  636.     if ((rowCnt <= 0) OR ((record_number(current_object,rowCnt - 1) <> 0) AND ;
  637.         (not(no_create_state(current_object)) OR ;
  638.         ((rowCnt - 1) >= displayable_rows(current_object))))) ;
  639.         send add_row
  640.  
  641.   end_procedure
  642.  
  643.   //
  644.   // this scroll function is used by virtual tables; batch tables use the
  645.   // normal scroll procedure
  646.   //
  647.   function virtual_scroll integer direction integer dist returns integer
  648.     local integer count mode oldDyn srvr# row# retval
  649.     local integer distance rowCount file# rec# ndx
  650.  
  651.     //
  652.     // if this is a batch list, use the inherited SCROLL procedure & exit
  653.     //
  654.     if (Batch_State(current_object)) begin
  655.       send scroll direction (dist * item_limit(current_object))
  656.       function_return 0
  657.     end
  658.  
  659.     //
  660.     // this is a virtual list, so see if it has a server or a main-file;
  661.     // if it doesn't, we can't do anything so exit 
  662.     //
  663.     get Server to srvr#
  664.     get main_file to file#
  665.     if ((srvr# = 0) AND (file# = 0)) function_return 1
  666.  
  667.     //
  668.     // if distance argument is zero, a full-page scroll is implied; otherwise,
  669.     // use the given distance value (in rows)
  670.     //
  671.     if dist eq 0 ;
  672.         calc ((display_size(Current_Object) / item_limit(Current_Object)) - 1) ;
  673.         to distance
  674.     else move dist to distance
  675.  
  676.     //
  677.     // if direction argument is upward, start with the top row and
  678.     // set the mode to LT
  679.     //
  680.     if direction eq upward_direction begin
  681.       get top_Row to row#
  682.       move (LT) to mode
  683.     end
  684.  
  685.     //
  686.     // else if direction argument is downward, start with the bottom row and
  687.     // set the mode to GT
  688.     //
  689.     else begin
  690.       get bottom_row to row#
  691.       move (GT) to mode
  692.     end
  693.  
  694.     //
  695.     // get the record number for the starting row and read it into the buffer
  696.     //
  697.     get record_number item row# to rec#
  698.  
  699.     //
  700.     // if the starting row has a valid record and this list has a server,
  701.     // use the server to read the starting record into the buffer
  702.     //
  703.     if ((srvr# <> 0) AND (rec# > 0)) send Read_by_RecNum to srvr# file# rec#
  704.  
  705.     //
  706.     // else if the starting row does not have a valid record or it does not
  707.     // have a valid server, use the list's Read_Record procedure to read
  708.     // the starting record into the buffer (or clear the buffer if rec# = 0)
  709.     //
  710.     else send Read_Record rec#
  711.  
  712.     //
  713.     // if the find failed (by either method), exit - we cannot scroll if we
  714.     // can't find the starting record
  715.     //
  716.     [not found] function_Return 2  //missing record err
  717.  
  718.     //
  719.     // save the old Dynamic_Update_State value and reset it to FALSE
  720.     //
  721.     get dynamic_update_State to oldDyn
  722.     set dynamic_update_state to false
  723.  
  724.     //
  725.     // initialize the (row-scan loop) counter
  726.     //
  727.     move 0 to count
  728.  
  729.     //
  730.     // get the search ordering
  731.     //
  732.     get Ordering to ndx
  733.  
  734.     //
  735.     // if this object has a server, use Establish_Find_Direction to init
  736.     // for scan (using Locate_Next)
  737.     //
  738.     if srvr# ne 0 send establish_find_direction to srvr# mode file# ndx
  739.  
  740.     //
  741.     // else if this object has no server, make sure the ordering is not
  742.     // BEST_INDEX (because the non-constrained find commands don't
  743.     // understand it); if the ordering is BEST_INDEX, reset to RECNUM
  744.     //
  745.     else if ndx lt 0 move 0 to ndx
  746.  
  747.     //
  748.     // we've already got the first record (the starting record), so make
  749.     // sure the FOUND indicator is set to TRUE (in case it changed since
  750.     // the starting record was found)
  751.     //
  752.     indicate found true
  753.  
  754.     //
  755.     // as long as we have a record and have not 'gone the distance',
  756.     // the following loop continues to scan and display records
  757.     //
  758.     While ((count < distance) AND found)
  759.  
  760.       //
  761.       // if this object has a server, use Locate_Next to find the next
  762.       // record (using the ordering, file, and mode set by the
  763.       // Establish_Find_Direction message sent previously)
  764.       //
  765.       if srvr# send Locate_Next to srvr#
  766.  
  767.       //
  768.       // if this object has no server, use the VFIND command to locate
  769.       // the next record for the given file, search-index, and find-mode
  770.       //
  771.       else begin
  772.         vfind file# ndx mode
  773.         [found] move file# to filenumber
  774.         [found] move 0 to fieldindex
  775.         [found] relate Indirect_File.RECNUM
  776.       end
  777.  
  778.       //
  779.       // if a record was found, display it
  780.       //
  781.       if [found] begin
  782.  
  783.         //
  784.         // if this is the first record found, remove the blank padding rows
  785.         // from this list's items (at the top and bottom); note that if no
  786.         // records are found by the scanning loop, no 'trimming' of the
  787.         // display-page occurs
  788.         //
  789.         if count eq 0 begin
  790.  
  791.           //
  792.           // remove top blank padding rows (usually only 1)
  793.           //
  794.           while (top_row(Current_Object)) GT 0
  795.             send delete_row 0
  796.           end
  797.  
  798.           //
  799.           // find out how many rows remain in the list
  800.           //
  801.           get row_count to rowCount
  802.  
  803.           //
  804.           // remove bottom blank padding rows (usually only 1)
  805.           //
  806.           while rowCount GT (displayable_rows(Current_Object))
  807.             send delete_row (rowCount - 1)
  808.             get row_count to rowCount
  809.           end
  810.         end
  811.  
  812.         //
  813.         // if we're scrolling upward, insert a new row at the top of the
  814.         // list for the record we just found. note that this includes
  815.         // displaying the values from the fields in the record buffer to
  816.         // their respective items in the new row
  817.         //
  818.         if direction eq upward_direction send insert_new_row 0
  819.  
  820.         //
  821.         // else if we're scrolling downward, append a new row at the bottom
  822.         // of the list for the record we just found. note that this includes
  823.         // displaying the values from the fields in the record buffer to
  824.         // their respective items in the new row
  825.         //
  826.         else send append_new_row
  827.  
  828.         //
  829.         // increment the (row-scan loop) counter
  830.         //
  831.         increment count
  832.       end
  833.     end
  834.  
  835.     // if we actually found at least one new record, we must re-trim the
  836.     // page to put back the blank padding rows at the top and bottom of
  837.     // the list (these rows are for navigation and cosmetic purposes)
  838.     //
  839.     if count gt 0 send trim_page direction
  840.  
  841.     //
  842.     // make sure the current record is correct by comparing its RECNUM to
  843.     // current_record (the record number for the current row)
  844.     //
  845.     move 0 to fieldindex
  846.     move file# to filenumber
  847.     move Indirect_File.RECNUM to rec#
  848.     get current_record to ndx
  849.  
  850.     //
  851.     // if the buffer's RECNUM field does not match current_record, or we
  852.     // couldn't scroll, read the current_record into the buffer, so that the
  853.     // record buffer matches the data on the screen, i.e. so the current row's
  854.     // record is in the buffer
  855.     //
  856.     if ((ndx <> rec#) OR (count = 0)) begin
  857.       clear Indirect_File                 //clear the main file
  858.       move ndx to Indirect_File.RECNUM    //set RECNUM to current_record
  859.       find eq Indirect_File.RECNUM        //find by recnum in the main file
  860.       if [not found] clear Indirect_File  //if find fails, clear buffer
  861.       else relate Indirect_File           //else if find succeeds, relate
  862.     end
  863.  
  864.     //
  865.     // restore Dynamic_Update_State to its prior value
  866.     //
  867.     set dynamic_update_state to oldDyn
  868.  
  869.     //
  870.     // return the difference between the number of rows actually scrolled
  871.     // and the requested number of rows to scroll; if we were able to scroll
  872.     // the full requested number of rows, the return value will be 0.  If we
  873.     // were unable to scroll the full requested number of rows, the return
  874.     // value will be negative.  A positive return value indicates an error
  875.     // or some kind that prevented the starting row from being found.
  876.     //
  877.     function_Return (count - distance)
  878.  
  879.   end_function
  880.  
  881.   procedure delete_Data
  882.     local integer obj#
  883.     forward send delete_Data
  884.     move (Records(current_object)) to obj#
  885.     if obj# ne 0 begin
  886.       send delete_Data to obj#
  887.       set base_item to 0
  888.     end
  889.   end_procedure
  890.  
  891.     //
  892.     // if allow new row, last row is not current row, is visible ;
  893.     // or the bottom row is clear and is blank, delete it
  894.     //
  895.   procedure trim_last_row
  896.     local integer rowCnt
  897.     get row_count to rowCnt
  898.     if (not(no_create_state(current_object)) AND ;
  899.         (current_row(current_object) <> (rowCnt - 1))) begin
  900.       if ((rowCnt > 0) AND ((((rowCnt - top_row(current_object)) <= ;
  901.           displayable_rows(current_object)) OR ;
  902.           (record_number(current_object,bottom_row(current_object)) = 0)) AND ;
  903.           (record_number(current_object,rowCnt - 1) = 0))) ;
  904.         send delete_row (rowCnt - 1)
  905.     end
  906.   end_procedure
  907.  
  908.   procedure insert_clear_row
  909.     local integer oldDynUpdt base oldChg rowCnt
  910.  
  911.     get Dynamic_Update_State to oldDynUpdt
  912.     set Dynamic_Update_State to false
  913.     get base_item to base  //send insert blank row changed base_item...
  914.     send insert_blank_row (current_row(current_object))
  915.     get Changing_State to oldChg
  916.     set Changing_State to true
  917.     if (current_Row(current_object)) EQ (top_row(current_object)) ;
  918.         set top_item to base
  919.     else set current_item to base
  920.     set item 1 // 1 = direction:forward, finds first enterable item.
  921.     set base_item to base
  922.     send entry_display 0 0    //redisplay active (parent) files
  923.     send trim_last_row
  924.     if (current_row(current_object)) EQ (row_count(current_object) - 1) ;
  925.         send finish_page
  926.     set Changing_State to oldChg
  927.     set Dynamic_Update_State to oldDynUpdt
  928.   end_procedure
  929.  
  930.   //
  931.   // created for Server support
  932.   //
  933.   procedure clear  //notification of clear-record
  934.     if (not(Line_Display_State(current_object)) AND ;
  935.         Current_Record(Current_Object) <> 0) ;
  936.         send enter_add_mode TRUE
  937.  
  938.     send entry_clear 1          //clear current row
  939.     send entry_display 0 0      //redisplay parent-files
  940.  
  941.     set current_record to 0     //curRec := 0
  942.   end_procedure
  943.  
  944.   procedure clear_data integer all_flag
  945.     local integer oldDynUpdt retval
  946.  
  947.     if (current_record(current_object) = 0) ;
  948.         get Exit_Add_Mode FALSE FALSE ;
  949.         (current_item(current_object)) to retval
  950.  
  951.     is_file_included (main_file(current_object)) 0  //check cleared bit-array
  952.     if [found] begin
  953.       if (Line_Display_State(current_object)) send entry_clear_all 1
  954.       else begin
  955.         get Dynamic_Update_State to oldDynUpdt
  956.         set Dynamic_Update_State to false
  957.         send empty_list    //delete_data
  958.         send add_row
  959.         send entry_display 0 0    //redisplay active (parent) files
  960.         send insert_row 0 // insert top padding row
  961.         set top_item to (item_limit(current_object))
  962.         set Dynamic_Update_State to oldDynUpdt
  963.         set changed_state to false
  964.       end
  965.     end
  966.     else if all_flag send entry_clear_all 1
  967.     else send entry_clear 1
  968.  
  969.     send Enter_Add_Mode FALSE
  970.   end_procedure
  971.  
  972.   //
  973.   // created for Server support
  974.   //
  975.   procedure clear_all  //notification of clear-set
  976.     send clear_data TRUE
  977.   end_procedure
  978.  
  979.   //
  980.   // created for Server support
  981.   //
  982.   procedure clear_Set  //notification of derived clear
  983.     send clear_data FALSE
  984.   end_procedure
  985.  
  986.   //
  987.   //use of lineDisplayState is required because the list sends its Server
  988.   //msgs Clear and Find when it only wants to affect the current row
  989.   //
  990.   procedure display
  991.     if (Line_Display_State(current_object)) send entry_display 0 0
  992.     else begin
  993.       is_file_included (main_file(current_object)) 1  //check done bit-array
  994.       if [found] send Refresh_Page downward_Direction
  995.       else send entry_display 0 0
  996.     end
  997.   end_procedure
  998.  
  999.   procedure Refresh_Page integer direction
  1000.     local integer dynUpdt oldChg retval newitem
  1001.  
  1002.     set changed_state to false
  1003.     if (active_State(current_object)) begin
  1004.       get dynamic_update_state to dynUpdt
  1005.       set dynamic_update_state to false
  1006.       get Changing_State to oldChg
  1007.       set Changing_State to TRUE
  1008.       send delete_Data
  1009.       send fill_page direction
  1010.       //
  1011.       // recalc row attributes
  1012.       //
  1013.       if direction eq downward_direction ;
  1014.         move (top_item(current_object)) to newitem
  1015.       else begin
  1016.         move (top_item(current_object) + display_size(current_object) - 1) ;
  1017.             to newitem
  1018.         //
  1019.         // if partially filled, move to last row on screen
  1020.         //
  1021.         if (item_count(current_object) - top_item(current_object)) LE ;
  1022.             (display_size(current_object)) begin
  1023.           move ((row_count(current_object) - 1) * item_limit(current_object)) ;
  1024.               to newItem
  1025.           //
  1026.           // if not on top row, and last row is blank, goto next to last row
  1027.           //
  1028.           if ((row(current_object,newItem) <> top_row(current_object)) AND ;
  1029.               (record_number(current_object,row(current_object,newItem))) = 0) ;
  1030.               move (newItem - item_limit(current_object)) to newItem
  1031.         end
  1032.       end
  1033.       set new_item to newitem
  1034.       if (select_mode(current_object)) EQ AUTO_SELECT ;
  1035.           send select_toggling newitem TRUE
  1036.       set base_item to ;
  1037.           (current_row(current_object) * item_limit(current_object))
  1038.       set Changing_State to oldChg
  1039.       set dynamic_update_state to dynUpdt
  1040.     end
  1041.     else send empty_list  //(delete_data) inactive list, so empty it
  1042.   end_procedure
  1043.  
  1044.   //
  1045.   // this procedure clears the destination row (and enter add-mode)
  1046.   //
  1047.   //
  1048.   // if added to end of table, enter_add_mode, otherwise clear_row,
  1049.   // (which also causes enter_add_mode)
  1050.   //
  1051.   procedure start_new_row integer item#
  1052.     local integer oldItem row# oldDyn oldLineDisp
  1053.     get current_item to oldItem
  1054.     set new_item to item#  //temporarily change current item/row for add-mode
  1055.     get row item# to row#
  1056.     if row# GE (row_count(current_object) - 1) begin
  1057.       get dynamic_update_state to oldDyn
  1058.       set dynamic_update_state to FALSE
  1059.       get line_display_State to oldLineDisp
  1060.       set line_display_state to true
  1061.       send clear_row row#
  1062.       set line_display_State to oldLineDisp
  1063.       send Enter_Add_Mode FALSE
  1064.       set dynamic_update_state to oldDyn
  1065.     end
  1066.     else send clear_row row#
  1067.     set new_item to oldItem  //restore original current item/row
  1068.   end_procedure
  1069.  
  1070.   function enterable_item integer item# returns integer
  1071.     local integer oldItem newItem
  1072.  
  1073.     get current_item to oldItem
  1074.     set new_item to (item# - 1)
  1075.  
  1076.     get next_entry_ok to newItem
  1077.     if newItem LT 0 move item# to newItem
  1078.  
  1079.     set new_item to oldItem
  1080.  
  1081.     function_return newItem
  1082.   end_function
  1083.  
  1084.   //
  1085.   // this function is invoked by ITEM_CHANGE when changing rows; it returns
  1086.   // the item# that ITEM_CHANGE is to go to, which may or may not be the
  1087.   // original destination
  1088.   //
  1089.   function row_changing integer from# integer to# returns integer
  1090.     local integer diff lim toRow fromRow topRow oldbase wasNew
  1091.     local integer botRow rec# scrollRet oldDyn
  1092.  
  1093.     get row item from# to fromRow
  1094.     move (record_number(current_object,fromRow) = 0) to wasNew
  1095.  
  1096.     //
  1097.     // if the origin row is blank, close the hole
  1098.     //
  1099.     if (wasNew AND not(batch_State(current_object))) ;
  1100.       get Exit_Add_Mode TRUE TRUE to# to to#  //returns adjusted dest item
  1101.  
  1102.     //
  1103.     // reset wasNew to TRUE if the origin row was blank
  1104.     // (before we forwarded to this routine from table)
  1105.     //
  1106.     move (wasNew OR was_new_row_state(current_object)) to wasNew
  1107.  
  1108.     get row item from# to fromRow
  1109.     get row item to# to toRow
  1110.     get item_limit to lim
  1111.     get top_row to topRow
  1112.     get bottom_row to botRow
  1113.  
  1114.     //
  1115.     // if movement is backward, and destination row is prior to the top
  1116.     // row, scroll the list
  1117.     //
  1118.     if toRow LT topRow begin      //should only be on up-arrow on top row
  1119.  
  1120.       //
  1121.       // the number of rows to scroll is the difference between the
  1122.       // top row and the destination row
  1123.       //
  1124.       calc (topRow - toRow) to diff
  1125.  
  1126.       //
  1127.       // scroll the designated number of rows
  1128.       //
  1129.       get virtual_scroll UPWARD_DIRECTION diff to scrollRet
  1130.  
  1131.       //
  1132.       // if virtual_scroll returns a positive number, an error occurred,
  1133.       // most likely the inability to read the current row in preparation
  1134.       // for scanning; in this case, return the top_item as the destination
  1135.       //
  1136.       if scrollRet gt 0 function_return (top_item(Current_Object))
  1137.  
  1138.       //
  1139.       // if virtual_scroll returns the negation of the requested number
  1140.       // of rows to scroll, no scrolling occurred
  1141.       //
  1142.       if (diff + scrollRet) EQ 0 begin
  1143.         send find_record (current_record(current_object))
  1144.         function_return from#
  1145.       end
  1146.  
  1147.       //
  1148.       // if virtual_scroll was successful and this is not a batch list,
  1149.       // adjust the destination item by the number of rows inserted
  1150.       //
  1151.       else if (not(Batch_State(current_object))) ; 
  1152.           calc (to# + (diff * lim)) to to#
  1153.  
  1154.     end
  1155.  
  1156.     //
  1157.     // if movement is forward, and the destination row is after the bottom
  1158.     // row, scroll the list
  1159.     //
  1160.     else if toRow GT botRow begin  //should only be on down-arrow on botton row
  1161.  
  1162.       //
  1163.       // the number of rows to scroll is the difference between the
  1164.       // destination row and the bottom row
  1165.       //
  1166.       calc (toRow - botRow) to diff
  1167.  
  1168.       //
  1169.       // if we're advancing one row and the original row was a
  1170.       // blank row and no_create_state is false, insert a blank row
  1171.       // by entering (continuing) add-mode
  1172.       //
  1173.       if ((diff = 1) AND wasNew AND advancing_state(current_object) AND ;
  1174.           not(no_create_state(current_object)) AND ;
  1175.           auto_clear_deo_state(current_object)) begin
  1176.  
  1177.         //
  1178.         // clear the destination row
  1179.         //
  1180.         send start_new_row to#
  1181.  
  1182.         //
  1183.         // delete to topmost (padding) row
  1184.         //
  1185.         send delete_row 0
  1186.  
  1187.         //
  1188.         // return the destination row's first column, adjusted for the
  1189.         // row-deletion above
  1190.         //
  1191.         get enterable_item (toRow * lim - lim) to to#
  1192.         function_return to#
  1193.       end
  1194.  
  1195.       //
  1196.       // attempt to scroll the designated number of rows
  1197.       //
  1198.       get virtual_scroll DOWNWARD_DIRECTION diff to scrollRet
  1199.  
  1200.       //
  1201.       // if virtual_scroll returns a value greater than zero, an error
  1202.       // occurred; typically, the current record could not be read
  1203.       //
  1204.       if scrollRet GT 0 ;
  1205.           function_return ((row_count(current_object) - 1) * lim)
  1206.  
  1207.       //
  1208.       // if virtual_scroll returns the negation of the number of rows
  1209.       // requested, no scrolling occurred. if no create, stay on last row;
  1210.       // if create, put the cursor on the last row and make it blank
  1211.       //
  1212.       if ((diff + scrollRet) = 0) begin
  1213.         //
  1214.         // if no create, just goto desired row (adjusted for padding row)
  1215.         //
  1216.         if (No_Create_State(current_object)) ;
  1217.             function_return (to# - lim)
  1218.         else begin // if (advancing_state(current_object)) begin
  1219.           //
  1220.           // clear the destination row
  1221.           //
  1222.           send start_new_row to#
  1223.  
  1224.           //
  1225.           // delete to topmost (padding) row
  1226.           //
  1227.           send delete_row 0
  1228.  
  1229.           //
  1230.           // return the destination row's first column, adjusted for the
  1231.           // row-deletion above
  1232.           //
  1233.           get enterable_item (toRow * lim - lim) to to#
  1234.           function_return to#
  1235.         end
  1236.       end
  1237.  
  1238.       //
  1239.       // if virtual_scroll was successful and this is not a batch list,
  1240.       // adjust the destination item by the number of rows inserted
  1241.       //
  1242.       if (not(Batch_State(current_object))) ;
  1243.           calc (to# - ((diff + scrollRet) * lim)) to to# 
  1244.  
  1245.     end
  1246.     //
  1247.     // if the destination row has no valid record_number, clear it and
  1248.     // force the destination item to be its first column
  1249.     //
  1250.     // also, see if add-mode should continue
  1251.     //
  1252.     else if ((No_Create_State(current_object) = 0) AND ;
  1253.         ((record_number(Current_Object,toRow) = 0) OR ;
  1254.         (wasNew AND advancing_state(current_object) AND ;
  1255.         auto_clear_deo_state(current_object)))) begin
  1256.  
  1257.       send start_new_row to#
  1258.  
  1259.       //
  1260.       // return the first column of the (blank) destination row
  1261.       //
  1262.       get enterable_item (toRow * lim) to to#
  1263.       function_return to#
  1264.     end
  1265.  
  1266.     //
  1267.     // if it was a new record that was just created, and we are on the last row
  1268.     // we need to replace the padding row we just overwrote
  1269.     //
  1270.     else if (wasNew AND (current_record(current_object) <> 0) AND ;
  1271.         (current_row(current_object) eq (row_count(current_object) - 1))) ;
  1272.         send add_row
  1273.  
  1274.     //
  1275.     // get the row for the destination item
  1276.     //
  1277.     get row item to# to toRow
  1278.  
  1279.     //
  1280.     // if this list is not batch, ensure that the record buffer contains
  1281.     // the record corresponding to the destination row
  1282.     //
  1283.     if (not(Batch_State(current_object))) begin
  1284.  
  1285.       //
  1286.       // if scrolling down was required, adjust destination to end of list
  1287.       //
  1288.       if toRow gt botRow move botRow to toRow
  1289.  
  1290.       //
  1291.       // if scrolling up was required, adjust destination to start of list
  1292.       //
  1293.       else if toRow lt topRow move topRow to toRow
  1294.  
  1295.       //
  1296.       // get the record_number of the destination row
  1297.       //
  1298.       get record_number item toRow to rec#
  1299.  
  1300.       //
  1301.       // save the base_item value and reset to the first column of the
  1302.       // destination row
  1303.       //
  1304.       get base_item to oldbase
  1305.       set base_item to (toRow * lim)
  1306.       set new_item to to#       //temporarily change current row for add-mode
  1307.  
  1308.       //
  1309.       // if this list is auto-select, make sure the destination row is
  1310.       // selected
  1311.       //
  1312.       if (select_mode(current_object)) EQ AUTO_SELECT ;
  1313.           send select_toggling (toRow * lim) TRUE
  1314.  
  1315.       //
  1316.       // find the record for the destination row
  1317.       //
  1318.       send Find_Record rec#
  1319.  
  1320.       //
  1321.       // reset base_item to it's original value
  1322.       //
  1323.       set base_item to oldbase
  1324.       set new_item to from#     //restore current row
  1325.  
  1326.     end
  1327.  
  1328.     function_return to#
  1329.   end_function
  1330.  
  1331.   procedure item_change integer from# integer to# returns integer
  1332.     local integer retval toRow lim newCol newItem curItem suspendValidate
  1333.     //
  1334.     // if Changing_State is TRUE, we have an item_change invocation already
  1335.     // in progress, so just give rubber-stamp approval to the destination
  1336.     // item and exit
  1337.     //
  1338.     if (Changing_State(Current_Object)) begin
  1339.       set Advancing_State to FALSE
  1340.       procedure_Return to#
  1341.     end
  1342.  
  1343.     //
  1344.     // set Changing_State to TRUE to prevent infinite recursion
  1345.     //
  1346.     set Changing_State to true
  1347.  
  1348.     //
  1349.     // remember item_limit
  1350.     //
  1351.     get item_limit to lim
  1352.  
  1353.     //
  1354.     // if we are changing columns, set Reordering_State to TRUE; this will
  1355.     // permit the AUTO_REORDER_LIST message to function, if used as the
  1356.     // iENTRY message of a destination item
  1357.     //
  1358.     if (MOD(from#,lim)) NE (MOD(to#,lim)) set reordering_state to true
  1359.  
  1360.     //
  1361.     // else if we are not changing columns, set Reordering_State to FALSE;
  1362.     // this will prevent the AUTO_REORDER_LIST message from functioning,
  1363.     // if used as the iENTRY message of a destination item
  1364.     //
  1365.     else set reordering_state to false
  1366.  
  1367.     //
  1368.     // init Just_Reordered_State to FALSE
  1369.     //
  1370.     set just_reordered_state to false
  1371.  
  1372.     //
  1373.     // forward the ITEM_CHANGE message to perform the inherited behavior
  1374.     //
  1375.     forward get msg_item_change from# to# retval
  1376.  
  1377.     //
  1378.     // set Changing_State back to FALSE, now that the danger of infinite
  1379.     // recursion is past (it could only happen via forwarding)
  1380.     //
  1381.     set Changing_State to false
  1382.  
  1383.     //
  1384.     // set Reordering_State to FALSE, now that the iENTRY message of the
  1385.     // destination has already been executed
  1386.     //
  1387.     set reordering_state to false
  1388.  
  1389.     //
  1390.     // if Just_Reordered_State is TRUE, the destination item did indeed use
  1391.     // the AUTO_REORDER_LIST message as its iENTRY message and it was
  1392.     // successfully invoked.  In this case, we must make sure that we are
  1393.     // in the intended destination column
  1394.     //
  1395.     if (just_reordered_state(current_object)) begin
  1396.  
  1397.       //
  1398.       // set Just_Reordered_State back to FALSE
  1399.       //
  1400.       set just_reordered_state to false
  1401.  
  1402.       //
  1403.       // calculate the column of the destination item
  1404.       //
  1405.       move (MOD(to#,lim)) to newCol
  1406.  
  1407.       //
  1408.       // list-reordering always leaves the cursor on the top row, so we
  1409.       // must alter the return-value (the destination item) to insure that
  1410.       // the cursor goes to the intended column (not always the first column)
  1411.       //
  1412.       move (top_item(current_object) + newCol) to retval
  1413.  
  1414.     end
  1415.  
  1416.     //
  1417.     // figure out the destination-item's row number
  1418.     //
  1419.     get row retval to toRow
  1420.  
  1421.     //
  1422.     // set BASE_ITEM to the appropriate value for the destination row
  1423.     //
  1424.     set base_item to (toRow * lim)
  1425.  
  1426.     set Advancing_State to FALSE
  1427.  
  1428.     //
  1429.     // return the destination item number
  1430.     //
  1431.     procedure_Return retval
  1432.  
  1433.   end_procedure
  1434.  
  1435.   procedure fill_page integer direction 
  1436.     local integer rowCount count mode IsBatch srvr#
  1437.     local integer file# ndx curRow rec# retval
  1438.     get Server to srvr#
  1439.     get main_file to file#
  1440.     if ((srvr# = 0) AND (file# = 0)) procedure_return  //no server & no mainfile
  1441.     get displayable_rows to rowCount
  1442.     if (item_count(Current_Object)) LT 1 send add_Row
  1443.     if direction eq UPWARD_DIRECTION send display_row 0
  1444.     else send display_row (Row_Count(Current_Object) - 1)
  1445.     if direction eq UPWARD_DIRECTION move 0 to mode  //LT
  1446.     else move 4 to mode  //GT
  1447.     get Batch_State to IsBatch
  1448.     get Ordering to ndx
  1449.     if srvr# ne 0 send establish_find_direction to srvr# mode file# ndx
  1450.     else if ndx lt 0 move 0 to ndx   //default to RECNUM if no data-set/order
  1451.     move 1 to count
  1452.     if rowCount GT 1 begin
  1453.       Repeat
  1454.         if srvr# send Locate_Next to srvr#
  1455.         else begin
  1456.           vfind file# ndx mode
  1457.           [found] move file# to filenumber
  1458.           [found] move 0 to fieldindex
  1459.           [found] relate Indirect_File.RECNUM
  1460.         end
  1461.         [found] begin
  1462.           if direction eq UPWARD_DIRECTION send INSERT_NEW_ROW 0
  1463.           else send append_new_row
  1464.           increment count
  1465.         end
  1466.       until (FINDERR OR (not(IsBatch) AND (count >= rowCount)))
  1467.     end
  1468.     if (not(IsBatch)) begin
  1469.       send trim_page direction
  1470.  
  1471.       get current_Row to curRow
  1472.       get record_number item curRow to rec#
  1473.       if rec# gt 0 begin
  1474.         if srvr# ne 0 begin
  1475.           set base_item to (curRow * item_limit(current_object))
  1476.           send Read_by_RecNum to srvr# file# rec#
  1477.         end
  1478.         else send Read_Record rec#
  1479.       end
  1480.     end
  1481.     set Unsorted_State to FALSE
  1482.   end_procedure
  1483.  
  1484.   procedure Beginning_of_Data integer noSave
  1485.     local integer obj# fnum ordr# rowCount oldCol
  1486.     set search_mode to (search_mode(current_object))   //reset incr srch index
  1487.     get row_count to rowCount
  1488.     if rowCount LE 0 move 0 to oldCol
  1489.     else begin
  1490.       move (current_item(current_object) - base_item(current_object)) to oldCol
  1491.       if (Batch_State(current_object) AND ;              //if list empty, treat
  1492.           ((rowCount > 1) OR ;                           //as if it were virtual
  1493.           (record_number(current_object,0) <> 0))) begin //list already filled
  1494.         set top_item to oldCol
  1495.         procedure_Return
  1496.       end
  1497.     end
  1498.     get Server to obj#
  1499.     get Ordering to ordr#
  1500.     get main_file to fnum
  1501.     if fnum eq 0 procedure_return  // no main file, no data display
  1502.     if obj# ne 0 begin
  1503.       if (Deferred_State(current_object)) begin
  1504.         send Request_Read to obj# FIRST_RECORD fnum ordr#
  1505.         if [found] begin
  1506.           send Refresh_Page downward_Direction
  1507.           set current_item to (base_item(current_object) + oldCol)
  1508.         end
  1509.         else send Clear_All
  1510.       end
  1511.       else begin
  1512.         send Request_Find to obj# FIRST_RECORD fnum ordr#
  1513.         if [not found] begin
  1514.           send Clear to obj#
  1515.           send clear_all
  1516.         end
  1517.         else set current_item to (base_item(current_object) + oldCol)
  1518.       end
  1519.     end
  1520.     else begin
  1521.       if ordr# lt 0 move 0 to ordr#
  1522.       move 0 to fieldindex
  1523.       move fnum to filenumber
  1524.       clear Indirect_File
  1525.       vfind fnum ordr# 3  //GE
  1526.       if [found] begin
  1527.         move fnum to filenumber
  1528.         move 0 to fieldindex
  1529.         relate Indirect_File.RECNUM
  1530.         send Refresh_Page Downward_Direction
  1531.         set current_item to (base_item(current_object) + oldCol)
  1532.       end
  1533.       else send Clear_All
  1534.     end
  1535.     send update_dependent_items
  1536.   end_procedure
  1537.  
  1538.   procedure End_of_Data
  1539.     local integer obj# fnum ordr# rec# olddisp oldCol lim wasNew retVal
  1540.     local integer rowCount
  1541.     set search_mode to (search_mode(current_object))  //reset incr srch index
  1542.     get item_limit to lim
  1543.     get row_count to rowCount
  1544.     if rowCount LE 0 move 0 to oldCol
  1545.     else begin
  1546.       move (MOD(current_item(current_object),lim)) to oldCol
  1547.       if (Batch_State(current_object)) begin
  1548.         set top_item to (integer((item_count(current_object) - 1) / lim) ;
  1549.           * lim + oldCol)
  1550.         procedure_Return
  1551.       end
  1552.     end
  1553.     get Server to obj#
  1554.     get Ordering to ordr#
  1555.     get Main_File to fnum
  1556.     if fnum eq 0 procedure_return  //no main file, no data display
  1557.     if obj# ne 0 begin
  1558.       move (current_record(current_object) = 0) to wasNew
  1559.       send Request_Read to obj# LAST_RECORD fnum ordr#
  1560.       if [found] begin
  1561.           if wasNew get Exit_Add_Mode FALSE FALSE ;
  1562.               (current_item(current_object)) to retVal
  1563.         send Refresh_Page upward_Direction
  1564.         if not (Deferred_State(current_object)) begin
  1565.           get line_display_state to olddisp
  1566.           set line_display_state to true
  1567.           get current_record to rec#
  1568.           send Find_By_RecNum to obj# fnum rec#
  1569.           set line_display_state to olddisp
  1570.         end
  1571.         set current_item to (base_item(current_object) + oldCol)
  1572.       end
  1573.       else if (Deferred_State(current_object)) send Clear_All
  1574.       else begin
  1575.         send Clear to obj#
  1576.         send clear_all
  1577.       end
  1578.     end
  1579.     else begin
  1580.       if ordr# lt 0 move 0 to ordr#
  1581.       move 0 to fieldindex
  1582.       move fnum to filenumber
  1583.       clear Indirect_File
  1584.       vfind fnum ordr# 0  //LT
  1585.       if [found] begin
  1586.         move fnum to filenumber
  1587.         move 0 to fieldindex
  1588.         relate Indirect_File.RECNUM
  1589.         send Refresh_Page upward_Direction
  1590.         set current_item to (base_item(current_object) + oldCol)
  1591.       end
  1592.       else send Clear_All
  1593.     end
  1594.     send update_dependent_items
  1595.   end_procedure
  1596.  
  1597.   procedure Goto_Top_Row
  1598.     local integer retval oldCol
  1599.  
  1600.     move (current_item(current_object) - base_item(current_object)) to oldCol
  1601.     if (focus(desktop) <> current_object) send activate
  1602.     set current_item to (top_item(current_object) + OldCol)
  1603.   end_procedure
  1604.  
  1605.   procedure Goto_Bottom_Row
  1606.     local integer retval oldCol lastRow botRow
  1607.  
  1608.     move (current_item(current_object) - base_item(current_object)) to oldCol
  1609.  
  1610.     if (focus(desktop) <> current_object) send activate
  1611.  
  1612.     move (row_count(current_object) - 1) to lastRow
  1613.     get bottom_row to botRow
  1614.     if botRow LT lastRow move botRow to lastRow
  1615.  
  1616.     set current_item to ((lastRow * item_limit(current_object)) + OldCol)
  1617.   end_procedure
  1618.  
  1619.   procedure Initialize_List
  1620.     local integer rowCount retval topRow
  1621.     forward send initialize_list
  1622.     if (Unsorted_State(current_object) AND ;
  1623.         (current_record(current_object) <> 0)) ;
  1624.         get Regenerate (current_item(current_object)) TRUE to retval
  1625.     else begin
  1626.       get Row_Count to rowCount
  1627.       get top_row to topRow
  1628.       if ((rowCount < 1) OR ;
  1629.           (((rowCount - topRow) = 1) AND ;
  1630.           (record_number(current_object,topRow) = 0) AND ;
  1631.           not(changed_state(current_object)))) begin
  1632.         if (server(current_object)) EQ 0 begin
  1633.           get main_file to filenumber
  1634.           move 0 to fieldnumber
  1635.           if status Indirect_File send refresh_page downward_direction
  1636.           else send beginning_of_Data TRUE // TRUE arg = nosave
  1637.         end
  1638.         else send Beginning_of_Data TRUE   // TRUE arg = nosave
  1639.       end
  1640.     end
  1641.   end_procedure
  1642.  
  1643.   function item_matching string searchStr integer item# returns integer
  1644.     local integer slen ser# file# retval rec# ordr# oldCol mainfile
  1645.     local string lookStr
  1646.     if (Batch_State(current_object)) begin
  1647.         forward get item_matching searchStr to item#
  1648.         move item# to retval
  1649.     end
  1650.     else begin
  1651.       move -1 to retval
  1652.       length searchStr to slen
  1653.       if slen gt 1 left searchStr to lookStr (slen - 1)
  1654.       else move "" to lookStr
  1655.       get data_file to file#
  1656.       if file# le 0 function_return -1 //can't find if no valid main file
  1657.       get Server to ser#
  1658.       get main_file to mainfile
  1659.       move (current_item(current_object) - base_item(current_object)) ;
  1660.           to oldCol
  1661.       move file# to filenumber
  1662.       move 0 to fieldindex
  1663.       move Indirect_File.RECNUM to rec#
  1664.       move 0 to Indirect_File.RECNUM      //hold recbuf
  1665.       move rec# to Indirect_File.RECNUM   //replace rec#
  1666.       get data_field to fieldindex
  1667.       move lookStr to Indirect_File.RECNUM
  1668.       if mainfile ne file# begin  //find in parent-file
  1669.         if ser# ne 0 begin   //has a server
  1670.           send Request_Superfind to ser# GE file# ;
  1671.               (data_field(current_object,CURRENT))
  1672.           [found] move (oldCol+top_item(current_object)) to retval  //current item
  1673.         end
  1674.         else begin  //no server
  1675.           send entry_superfind GE mainfile
  1676.           if [found] begin
  1677.             send display
  1678.             move (oldCol+top_item(current_object)) to retval  //current item
  1679.             indicate found true
  1680.           end
  1681.           else begin
  1682.             move file# to filenumber
  1683.             move 0 to fieldindex
  1684.             clear Indirect_File
  1685.             move rec# to Indirect_File.RECNUM
  1686.             find eq Indirect_File.RECNUM
  1687.           end
  1688.         end
  1689.       end
  1690.       else begin  //find in main-file
  1691.         get Ordering to ordr#
  1692.         if ser# ne 0 begin
  1693.           if (Deferred_State(current_object)) begin
  1694.             send Request_Read to ser# GE file# ordr#
  1695.             if [found] begin
  1696.               send display
  1697.               move (oldCol+top_item(current_object)) to retval  //current item
  1698.               indicate found true
  1699.             end
  1700.           end
  1701.           else begin
  1702.             send Request_Find to ser# GE file# ordr#
  1703.             [found] move (oldCol+top_item(current_object)) to retval  //current item
  1704.           end
  1705.         end
  1706.         else begin
  1707.           if ordr# lt 0 move 0 to ordr#
  1708.           vfind file# ordr# GE
  1709.           if [found] begin
  1710.             move file# to filenumber
  1711.             move 0 to fieldindex
  1712.             relate Indirect_File.RECNUM
  1713.             send display
  1714.             move (oldCol+top_item(current_object)) to retval  //current item
  1715.             indicate found true
  1716.           end
  1717.         end
  1718.         [not found] begin
  1719.           move file# to filenumber
  1720.           move 0 to fieldindex
  1721.           clear Indirect_File
  1722.           move rec# to Indirect_File.RECNUM
  1723.           find eq Indirect_File.RECNUM
  1724.         end
  1725.       end
  1726.     end
  1727.     function_return retval
  1728.   end_function
  1729.  
  1730.   procedure Scan_Servers
  1731.     send find_servers_to_watch TRUE
  1732.   end_procedure
  1733.  
  1734.   procedure auto_reorder_list integer item#
  1735.     if (reordering_state(current_object)) send reorder_list item#
  1736.   end_procedure
  1737.  
  1738.   procedure reorder_list integer theItem#
  1739.     local integer ordr file field dataType fldNdx item#
  1740.     local integer reoState mainfile mainNdx
  1741.     if NUM_ARGUMENTS lt 1 get current_item to item#
  1742.     else move theItem# to item#
  1743.     get reordering_state to reoState
  1744.     set reordering_state to false
  1745.     get data_field item item# to field
  1746.     get data_file item item# to file
  1747.     if ((file > 0) AND (field >= 0)) begin
  1748.       FIELD_DEF file field to dataType fldNdx
  1749.       if ((fldNdx > 0) OR (field = 0)) begin  //field for item# has a main index
  1750.         get main_file to mainfile
  1751.         get ordering to ordr
  1752.         if file eq mainfile begin  //reorder using main-file
  1753.           if ordr ne fldNdx begin  //dont' reset unless req.
  1754.             set ordering to fldNdx                             //reset ordering
  1755.             send read_Record (current_record(current_object))  //read row's rec
  1756.             send display  //redisplay page starting with current row
  1757.  
  1758.             if reoState set just_reordered_state to true  //set for item_change
  1759.             else set current_item to (MOD(item#,item_limit(current_object)) + ;
  1760.                   base_item(current_object))  //reset in case called via key
  1761.  
  1762.           end
  1763.         end
  1764.         else begin  //reorder using parent-file
  1765.           get superfind_field mainfile item# to mainNdx  //get field for superfind
  1766.           FIELD_DEF mainfile mainNdx to dataType mainNdx //get main index for field
  1767.           if ((mainNdx <> ordr) AND (mainNdx >= 0)) begin
  1768.             set ordering to mainNdx
  1769.             send read_record (current_record(current_object))
  1770.             send display
  1771.  
  1772.             if reoState set just_reordered_state to true  //set for item_change
  1773.             else set current_item to (MOD(item#,item_limit(current_object)) + ;
  1774.                   base_item(current_object))  //reset in case called via key
  1775.  
  1776.           end
  1777.         end
  1778.       end
  1779.     end
  1780.   end_procedure
  1781.  
  1782.   procedure assign_current_record
  1783.       get main_file to filenumber
  1784.       move 0 to fieldindex
  1785.       set record_number to (row(current_object,base_item(current_object))) ;
  1786.           Indirect_File.RECNUM
  1787.   end_procedure
  1788.  
  1789.   procedure refresh integer notifyMode
  1790.     local integer oldRec retval mainfile lineDisp
  1791.  
  1792.     get main_file to mainfile
  1793.  
  1794.     if ((notifyMode = MODE_DELETE) AND ;
  1795.         (mainfile = main_file(server(current_object)))) begin
  1796.       forward send refresh notifyMode
  1797.       send assign_current_record
  1798.       send Enter_Add_Mode FALSE
  1799.     end
  1800.     //
  1801.     // if line-oriented or we are not deleting the table's main-file or
  1802.     // this is a save or delete-parent-file notification, just redisplay
  1803.     // current row
  1804.     //
  1805.     else if ((notifyMode > MODE_CLEAR_ALL) OR ;
  1806.         Line_Display_State(current_object)) begin
  1807.  
  1808.       get current_record to oldRec
  1809.       forward send refresh notifyMode   
  1810.       send assign_current_record
  1811.  
  1812.       if ((oldRec = 0) AND (current_record(current_object) <> 0)) begin
  1813.  
  1814.         get line_display_state to lineDisp
  1815.  
  1816.         if notifyMode EQ MODE_SAVE begin
  1817.           set Unsorted_State to TRUE
  1818.           if (lineDisp OR advancing_state(current_object) OR ;
  1819.               not(auto_clear_deo_state(current_object)) OR ;
  1820.               not(was_new_row_state(current_object))) ;
  1821.               get Exit_Add_Mode FALSE FALSE ;
  1822.               (current_item(current_object)) to retval
  1823.         end
  1824.         else if not lineDisp get Exit_Add_Mode FALSE FALSE ;
  1825.             (current_item(current_object)) to retval
  1826.  
  1827.       end
  1828.     end
  1829.  
  1830.     else begin               //notifyMode = find/clearSet or Clear
  1831.       is_file_included mainfile 1            //look in done
  1832.  
  1833.       if [found] begin
  1834.           if (current_record(current_object) = 0) ;
  1835.             get Exit_Add_Mode FALSE FALSE ;
  1836.               (current_item(current_object)) to retval
  1837.           send Refresh_Page downward_Direction
  1838.       end
  1839.       else begin
  1840.         is_file_included mainfile 0                  //look in cleared
  1841.  
  1842.         if [found] begin  //empty list or insert blank row
  1843.           if ((notifyMode = MODE_CLEAR_ALL) OR ;
  1844.               (notifyMode = MODE_FIND_OR_CLEAR_SET)) send clear_all
  1845.           else send clear
  1846.         end
  1847.         else begin
  1848.           forward send refresh notifyMode
  1849.           send assign_current_record
  1850.         end
  1851.       end
  1852.     end
  1853.   end_procedure
  1854.  
  1855.   function find_top_record integer item# returns integer  //find rec and return rec#
  1856.     local integer ser# file# rec# ordr# destRow
  1857.  
  1858.     get server to ser#
  1859.     get main_file to file#
  1860.     get row item item# to destRow
  1861.     get record_number item destRow to rec#
  1862.  
  1863.     if ((rec# = 0) AND (destRow > 1)) ;
  1864.         get record_number item (destRow - 1) to rec#
  1865.  
  1866.     //
  1867.     // if this list has a server, use the server's Read_By_RecNum
  1868.     // to find the (new) current row's record
  1869.     //
  1870.     if ser# ne 0 send Read_by_RecNum to ser# file# rec#
  1871.  
  1872.     //
  1873.     // if this list has no server but has a valid main_file, use
  1874.     // Read_Record to find the (new) current row's record
  1875.     //
  1876.     else if file# ne 0 send read_Record rec#
  1877.  
  1878.     //
  1879.     // if this list has no server or main_file, the find automatically
  1880.     // fails (nothing to find on/with/by!)
  1881.     //
  1882.     else indicate found false
  1883.  
  1884.     [not found] begin
  1885.       get ordering to ordr#
  1886.       move file# to filenumber
  1887.       move 0 to fieldindex
  1888.       clear Indirect_File
  1889.       if ser# ne 0 send Request_Read to ser# FIRST_RECORD file# ordr#
  1890.       else if file# ne 0 begin
  1891.         if ordr# lt 0 move 0 to ordr#
  1892.         vfind file# ordr# GE
  1893.         [found] begin
  1894.           move file# to filenumber
  1895.           move 0 to fieldindex
  1896.           relate Indirect_File.RECNUM
  1897.         end
  1898.       end
  1899.     end
  1900.  
  1901.     [not found] move 0 to rec#
  1902.  
  1903.     function_return rec#
  1904.   end_function
  1905.  
  1906.   //
  1907.   // passed destination item#
  1908.   // returns adjusted item#
  1909.   //
  1910.   function Remove_Hole integer item# returns integer
  1911.     local integer dynUpdt rowCount curRow lim retval svr rec# mainfile rowBot
  1912.  
  1913.     get current_row to curRow
  1914.     move item# to retval
  1915.     get item_limit to lim
  1916.  
  1917.     //
  1918.     // save the value of Dynamic_Update_State and reset to FALSE
  1919.     //
  1920.     get dynamic_update_State to dynUpdt
  1921.     set dynamic_update_State to false
  1922.  
  1923.     get row_count to rowCount
  1924.  
  1925.     //
  1926.     // if the list has more than one row, delete the current row
  1927.     // if it is not the last blank row
  1928.     //
  1929.     if rowCount GT 1 begin
  1930.       if ((curRow <> (rowCount - 1)) AND ;
  1931.         (record_number(current_object,curRow) = 0)) begin
  1932.         //
  1933.         // delete the current row
  1934.         //
  1935.         send delete_row curRow
  1936.  
  1937.         if item# GE ((curRow + 1) * lim) calc (retval - lim) to retval
  1938.       end
  1939.  
  1940.       //
  1941.       // add/delete rows at end, if necessary
  1942.       //
  1943.       if ((current_record(current_object) <> 0) OR ;
  1944.           (current_row(current_object) = bottom_row(current_object)))
  1945.         send finish_page
  1946.  
  1947.       //
  1948.       // reset base_item to the new current row's first column
  1949.       //
  1950.       set base_item to (curRow * item_limit(current_object))
  1951.  
  1952.     end
  1953.     else begin // if list has only one row which is empty, clear it
  1954.       send entry_clear 1      //make sure main-file items cleared
  1955.       send entry_display 0 1  //make sure parent-files redisplayed
  1956.     end
  1957.  
  1958.     set dynamic_update_State to dynUpdt // restore dynamic_update_state
  1959.     function_return retval
  1960.   end_function
  1961.  
  1962.   function regenerate integer item# integer forceFlag returns integer
  1963.     local integer rec#
  1964.  
  1965.     if (forceFlag OR Auto_Regenerate_State(current_object)) begin
  1966.  
  1967.       //
  1968.       // get the record_number of the (new) current row of the list
  1969.       //
  1970.       get find_top_record item item# to rec#  //finds and returns rec#
  1971.  
  1972.       if rec# eq 0 send clear_all       //rec# = 0 if find failed
  1973.  
  1974.       //
  1975.       // if the find on the current row's record was successful, regenerate
  1976.       // the list page using the current row as the new top row
  1977.       //
  1978.       else send Refresh_Page DOWNWARD_DIRECTION
  1979.  
  1980.       function_Return (top_item(current_object))
  1981.  
  1982.     end
  1983.  
  1984.     function_return item#
  1985.  
  1986.   end_function
  1987.  
  1988.   procedure Enter_Add_Mode integer makeHoleFlag
  1989.     if makeHoleFlag send insert_clear_row
  1990.     else if (current_row(current_object)) NE (bottom_row(current_object)) ;
  1991.         send trim_last_row
  1992.   end_procedure
  1993.  
  1994.   function Exit_Add_Mode integer closeHoleFlag integer regenPageFlag ;
  1995.         integer item# returns integer
  1996.     local integer dynUpdt rowCount curRow rec# retval
  1997.  
  1998.  
  1999.     get current_item to retval
  2000.     get current_row to curRow
  2001.  
  2002.     if closeHoleFlag get Remove_Hole item item# to retval
  2003.  
  2004.     if (regenPageFlag AND unsorted_state(current_object)) ;
  2005.         get Regenerate retval FALSE to retval
  2006.  
  2007.     function_return retval
  2008.  
  2009.   end_function
  2010.  
  2011.   //
  2012.   //  added for dependent-items support
  2013.   //
  2014.   function prototype_object returns integer
  2015.     function_return (element(current_object))
  2016.   end_function
  2017.  
  2018.   function next_entry_ok returns integer
  2019.     local integer retval
  2020.  
  2021.     set Advancing_State to TRUE  //set on now, turned off after item_change
  2022.  
  2023.     forward get next_entry_ok to retval
  2024.  
  2025.     function_return retval
  2026.   end_function
  2027.  
  2028.   procedure exiting integer toObject returns integer
  2029.     local integer retval
  2030.     forward get msg_exiting toObject to retval
  2031.     set advancing_state to FALSE
  2032.     procedure_return retval
  2033.   end_procedure
  2034.  
  2035. end_class
  2036.  
  2037. //
  2038. // Support Commands
  2039. //
  2040.  
  2041. //
  2042. // dlStart <class> <image> { ACTION_BAR <actionbar#> } { POP_UP | POPUP}
  2043. //     { RING } { VIRTUAL | BATCH } { USING <ServerID> } { MAIN_FILE 
  2044. //     <FileName> } { BY <Index> }
  2045. //
  2046. // handles optional syntax for Table construction statement
  2047. //
  2048. #COMMAND dlStart R R 
  2049.   FORWARD_BEGIN_CONSTRUCT !1 !2 !3 !4 !5 !6 !7 !8 !9
  2050.   bind_using !3 !4 !5 !6 !7 !8 !9
  2051.   bind_datalist_main_file !3 !4 !5 !6 !7 !8 !9
  2052.   bind_datalist_index !3 !4 !5 !6 !7 !8 !9
  2053.   bind_batch !3 !4 !5 !6 !7 !8 !9
  2054. #ENDCOMMAND
  2055.  
  2056. #COMMAND Bind_Batch
  2057.   #IF (!0>0)
  2058.     #IFSAME !1 BATCH VIRTUAL
  2059.       #IFSAME !1 BATCH
  2060.         set Batch_State to true
  2061.       #ELSE
  2062.         set Batch_State to false
  2063.       #ENDIF
  2064.     #ELSE
  2065.       Bind_Batch !2 !3 !4 !5 !6 !7 !8 !9
  2066.     #ENDIF
  2067.   #ENDIF
  2068. #ENDCOMMAND
  2069.  
  2070. #COMMAND Bind_Static
  2071.   #IF (!0>0)
  2072.     #IFSAME !1 STATIC
  2073.       set Batch_State to true
  2074.       set Static_State to true
  2075.     #ELSE
  2076.       Bind_Static !2 !3 !4 !5 !6 !7 !8 !9
  2077.     #ENDIF
  2078.   #ENDIF
  2079. #ENDCOMMAND
  2080.  
  2081. #COMMAND bind_datalist_main_file
  2082.   #IF (!0>1)
  2083.     #IFSAME !1 MAIN_FILE
  2084.       #PUSH !u
  2085.       #SET U$ !2.RECNUM
  2086.       set main_file to |CI!u
  2087.       #POP U$
  2088.     #ELSE
  2089.       bind_datalist_main_file !2 !3 !4 !5 !6 !7 !8 !9
  2090.     #ENDIF
  2091.   #ENDIF
  2092. #ENDCOMMAND
  2093.  
  2094. #COMMAND bind_datalist_index
  2095.   #IF (!0>1)
  2096.     #IFSAME !1 BY
  2097.       set ordering to !2
  2098.     #ELSE
  2099.       bind_datalist_index !2 !3 !4 !5 !6 !7 !8 !9
  2100.     #ENDIF
  2101.   #ENDIF
  2102. #ENDCOMMAND
  2103.  
  2104. //
  2105. // dlEnd <className>
  2106. //
  2107. // This macro ends the declaration of an instance, and checks for the
  2108. // existance of the ELEMENT component (defined by Begin_Row...End_Row)
  2109. //
  2110. #COMMAND dlEnd R
  2111.   #IFDEF OBJ$!Zj$ROWDEF
  2112.   #ELSE
  2113.     #ERROR 777 Object is missing BEGIN_ROW...END_ROW commands
  2114.   #ENDIF
  2115.   FORWARD_END_CONSTRUCT !1 !2 !3 !4 !5 !6 !7 !8 !9 //end instance normally
  2116. #ENDCOMMAND
  2117.