Module Dftable.pkg

     1//************************************************************************
     2//
     3// Confidential Trade Secret.
     4// Copyright 1987-1997 Data Access Corporation, Miami FL, USA
     5// All Rights reserved
     6// DataFlex is a registered trademark of Data Access Corporation.
     7//
     8//************************************************************************
     9//
    10// $File name  : DFTable.pkg
    11// $File title : Table (dbGrid) support for VDF
    12// Notice      :
    13// $Author(s)  : John Tuohy
    14//
    15// $Rev History
    16//
    17// 11/6/98  JJT - Fixed but in Assign_DD_Label
    18//  8/13/97 JJT - Set up support for Prompt_button_State
    19// 07/30/97 JJT - Added set current_item check for batch_state
    20// 6/24/97  JJT - Added Auto-label DD support: Auto_label_State. Assign_DD_Label
    21// 01/31/97 JJT - default highlight_row_state to T
    22// 07/23/96 JJT - New Class names
    23// 06/05/96 JJT - Fixed new_item and current_item to check if current_item
    24//                really exists before calling update_focus_field
    25// 06/03/96 JJT - Fixed new_item and current_item to check for extended dso
    26//                before proceeding.
    27// 05/28/96 JJT - Added code list exported description support.
    28// 04/26/96 JJT - Augmented Set Current_item/Item to refresh DD Buffer
    29//                (we need a better way).
    30// 05/01/95 JJT - Modified to support Cell and row highlighting
    31// 03/28/95 JJT - Removed 0 Layer class
    32//                Changed name to dftable.pkg
    33// 08/19/94 JJT - Blended Classes from CB and DAF
    34//************************************************************************
    35
    36
    37// not defined in windows, the aspect for a multi row FORM
    38#REPLACE BASPECT_MULTIFORM |CI135
    39
    40Use Windows.pkg
    41Use Table_ds.pkg
    42Use DFData.pkg
    43Use dfConfrm.pkg
    44Use PrmpBtMx.pkg // need the defines for prompt button modes
    45Use DfDeoFt.pkg
    46
    47{ ClassType=Abstract }
    48{ HelpTopic=dbGrid_ }
    49// batch_state should never be used in dbGrids, only dbLists.
    50{ OverrideProperty=Batch_State DesignTime=False Visibility=Private }
    51Class dbGrid_ is a DataList
    52    Import_Class_Protocol Table_ds_mixin
    53End_Class
    54
    55//
    56//  dfGrid
    57//
    58{ ClassType=Abstract }
    59{ HelpTopic=dbGridDS }
    60{ OverrideProperty=Floating_Menu_Object InitialValue=Default_dbFloating_Menu_ID }
    61{ OverrideProperty=Highlight_Row_State InitialValue=True }
    62Class dbGridDS is a dbGrid_
    63
    64  Procedure Construct_Object
    65     Forward Send Construct_Object No_Image
    66
    67     Set Floating_Menu_Object to Default_dbFloating_Menu_ID
    68
    69     // set default verify messages for table. The most sensible is to
    70     // use no save verify, a line delete verify and parent's data-loss
    71     // Note: these messsages are defined in dfconfrm.pkg
    72     Set Verify_Delete_msg to (RefFunc(Line_Delete_Confirmation))
    73     Set Verify_Save_msg   to (RefFunc(No_Confirmation))
    74
    75     on_key key_F11 send add_or_remove_row      PRIVATE  // same as F5
    76
    77     { Category=Appearance }
    78     Property String Prompt_Button_Value      '>>'
    79     { Category=Appearance }
    80     { EnumList="PB_PromptAuto, PB_PromptOn, PB_PromptOff" }
    81     Property Integer Prompt_Button_Mode      PB_PromptAuto
    82     Set HighLight_Row_State to True
    83  End_Procedure // Construct_Object
    84
    85  // These two messages are maintained for backwards compatibility. Avoid
    86  // using these. Use Prompt_Button_Mode instead
    87  { MethodType=Property Visibility=Private Obsolete=True }
    88  Procedure Set Auto_Create_Prompt_Button integer bState
    89        Set Prompt_Button_Mode to (if(bstate,PB_PromptAuto,PB_PromptOff))
    90  End_Procedure
    91
    92  { MethodType=Property Visibility=Private Obsolete=True }
    93  Function Auto_Create_Prompt_Button Returns integer
    94        Function_Return (Prompt_Button_Mode(self)=PB_PromptAuto)
    95  End_Function
    96
    97  // If any items are checkboxes we also need to set their aspect.
    98  // We can't set these for the protoobject
    99  // because they won't get copied in to the real rows. However, setting
   100  // aspect for the actual table items (even if there are none) works.
   101  // Also, you must set this for every item because setting zero sets all other items.
   102  //
   103  Procedure End_Construct_Object
   104     integer ele i ic
   105     Forward Send END_CONSTRUCT_OBJECT // as you were.
   106     Get prototype_object to ele // get prototype row object
   107     get item_count of ele to ic // number of items in this object
   108     decrement ic                //
   109     For i from 0 to ic
   110         if (checkbox_item_state(ele,i)) Begin  // if item is check
   111             Set Button_aspect item i TO BASPECT_CHECKLIST   // set check look
   112             Set Form_Datatype item i to ASCII_WINDOW
   113         end
   114         else Set Button_aspect item i TO BASPECT_MULTIFORM // set form look
   115     Loop
   116     Send Create_Prompt_Button (Prompt_Button_Mode(self)) // add prompt symbol to headers is needed
   117     //Send Set_up_rows
   118  End_Procedure // END_CONSTRUCT_OBJECT
   119
   120  { MethodType=Event }
   121  Procedure Header_Mouse_Click Integer Item#
   122     Integer iRVal
   123     Boolean bUsePrompt
   124     // if prompt not used, do normal header stuff which supports reversing indexes.
   125     If (prompt_button_mode(self)=PB_PromptOff) ;
   126         Forward Send Header_mouse_Click Item#
   127     else Begin
   128        Get Msg_Activate_Column item# to iRval
   129        // with VDF8 if prompt_button_mode (for headers) is OFF we will not send prompt.
   130        If (not(iRval)) Send Prompt
   131     end
   132  End_Procedure
   133
   134  { MethodType=Property  NoDoc=True }
   135  Procedure Set Current_Item integer item#
   136    Integer i 
   137    Integer iOldItem iNewItem
   138    If (item# eq Current_item(Self) or batch_state(Self)) ;
   139       Forward Set Current_Item to item#
   140    Else Begin
   141       get dynamic_update_State to i
   142       Set dynamic_update_State to 0
   143       
   144       Get Current_Item to iOldItem
   145       Forward Set Current_Item to item#
   146       Get Current_Item to iNewItem
   147       If (iOldItem<>iNewItem) Begin
   148            // Bug fix that makes sure we did not land in a skipfound field
   149            Send SkipFoundAdjust // see comments in SkipFoundAdjust about this fix
   150       End
   151       
   152       If i eq 1 ;
   153          set dynamic_update_State to 2
   154       Else ;
   155          if i eq 0 Set dynamic_update_State to 0
   156    End
   157  end_procedure
   158
   159  // find the prompt object for the passed prototype obj and item
   160  // this augmented in DD to be a bit more fancy
   161  { Visibility=Private }
   162  Function Ele_Prompt_Object integer ele integer item# returns integer
   163     Function_Return (Prompt_Object(ele,item#))
   164  End_Function
   165
   166  // Create a prompt Buttons. This was created so the process of creating
   167  // a prompt button object can be augmented.
   168  // Although a param is passed, it is ignored here (used in forms). This
   169  // checks all labels if auto-prompt is true, is a trailer prompt marker
   170  // exists (...) and if the column a prompt. If so, it sets the trailer
   171  // prompt marker (if it is not already there).
   172  // To disable this entire process set Prompt_Button_Mode to PB_PromptOff
   173  Procedure Create_Prompt_Button Integer CreateMode // 0=auto, 1=make, 2=remove
   174     integer ele i ic
   175     String sPrVal sLbl
   176     integer PrValLen
   177     Get Prompt_Button_Value to sPrVal
   178//     If (Auto_Create_Prompt_Button(self)=0 OR sPrVal='') ;
   179//        Procedure_Return
   180     If (CreateMode=PB_PromptOff OR sPrVal='') ;
   181         Procedure_Return
   182     Length sPrVal to PrValLen
   183     Get prototype_object to ele // get prototype row object
   184     get item_count of ele to ic // number of items in this object
   185     decrement ic
   186     For i from 0 to ic
   187         If (CreateMode=PB_PromptOn OR ;
   188              (Ele_Prompt_Object(self,ele,i) AND ;
   189               Shadow_State(ele,i)=0 ) ) Begin
   190            Get Header_Label Item i to sLbl
   191            If (sLbl<>'' AND right(sLbl,PrValLen)<>sPrVal) ;
   192               Set Header_Label item i to (sLbl * sPrVal)
   193         End
   194     Loop
   195  End_Procedure // Create_Prompt_Button
   196
   197    // used to create automatic embedded prompt buttons. Called by end_construct_object
   198    { Visibility=Private }
   199    Procedure CreateEmbeddedPrompts
   200        handle  hEle
   201        integer i ic
   202        Get prototype_object to hEle // get prototype row object
   203        get item_count of hEle to ic // number of items in this object
   204        decrement ic
   205        For i from 0 to ic
   206            // only create automatic buttons if there is no button predefined already and the
   207            // column has a prompt object associated with it.
   208            If ( (Form_Button(self,i)=FORM_BUTTON_NONE) AND Ele_Prompt_Object(self,hEle,i) ) Begin
   209                Set Form_Button_Value i To (psEmbeddedButtonValue(self))
   210                Set Form_Button i To FORM_BUTTON_PROMPT
   211            End
   212        Loop
   213    End_Procedure
   214
   215    // changes to improve autofind logic.
   216    { Visibility=Private }
   217    procedure DoAutoFind
   218        Integer bChanged bOn iCur
   219        Get Current_item to iCur
   220        // both changed_state and item_changed_state must be set for an autofind. If a default
   221        // value is set item_changed_state will be true and changed_state will be false. We want to
   222        // ignore these conditions
   223        get item_changed_State item iCur to bChanged
   224        if (bChanged and changed_state(self)) begin
   225            get item_option item iCur AUTOFIND_BIT to bOn
   226            if bOn begin
   227                get item_option item iCur AUTOFIND_GE_BIT to bOn
   228                Send entry_autofind (if(bOn,GE,EQ)) iCur
   229            end
   230        end
   231    end_procedure
   232
   233     // changes to improve autofind logic. Before save do an autofind check for all items in row
   234     { Visibility=Private }
   235     function Row_save  returns integer
   236        Integer iFrom iTo iCrnt iOld iErr
   237        Integer iOldDyn
   238        Boolean bInRowSave
   239
   240        Get pbInRowSave to bInRowSave
   241        If bInRowSave Begin
   242            Function_Return 1
   243        End
   244
   245        Get Current_item to iOld
   246        Get base_item    to iFrom
   247        Get Item_limit   to iTo
   248        Move (iFrom+iTo-1) to iTo
   249        Get Dynamic_Update_state to iOldDyn
   250        Set Dynamic_Update_state to 0 // let's not show item changing
   251        For iCrnt from iFrom to iTo
   252            Set New_Item to iCrnt
   253            Send DoAutoFind
   254        loop
   255        Set New_item to iOld
   256        If iOldDyn ;
   257            Set Dynamic_Update_state to 2 // 2=only paint what's dirty
   258        forward get row_save to iErr
   259        Function_Return iErr
   260    end_function
   261
   262    // changes to improve autofind logic. Do autofind before changing
   263    { MethodType=Event NoDoc=True }
   264    Procedure Item_Change Integer iFromItem Integer iToItem returns integer
   265        integer iNewTo
   266        integer iOldCur iNewCur
   267        if (Changing_State(self)) procedure_Return iToItem
   268        // it is possible though unlikely that autofind will change the current item. If this
   269        // happens we might need to recalculate where we should change from and to. This will
   270        // only happen if autofind is on the main file which represents a pretty odd way to use
   271        // tables.
   272        Get Current_item to iOldCur
   273        send DoAutoFind // if autofind is on main file, the entire table can be refreshed and current_item changed!
   274        Get Current_item to iNewCur
   275        If (iOldCur<>iNewCur) Begin // current_item changed. We will adjust iToItem and iFromItem to make the best of this
   276             // if iFromItem was not the old current_item this is a very strange event - Just return
   277             If (iOldCur<>iFromItem) procedure_return iNewCur
   278             Move iNewCur to iFromItem // adjust iFromItem to be the newly changed current_item
   279             // Adjust iToItem  relative to change the in iFromItem. If the new iToItem is out of bounds, do nothing
   280             Move (iToItem - iOldCur + iNewCur) to iToItem
   281             If (iToItem<0 or iToItem>=item_count(self)) procedure_return iNewCur
   282        end
   283        forward get msg_item_change iFromItem iToItem to iNewTo
   284        procedure_return iNewTo
   285    end_Procedure
   286
   287
   288    { Visibility=Private }
   289    // this was added as a bug fix in 12.1. It is possible to navigate into a skipfound item if you
   290    // are navigating from a blank grid row to an existing row. This happens because the runtime skipfound
   291    // logic checks the file buffer's status and this happens before the row navigation. Changing this in runtime
   292    // would be a deep change which could create side-effects. The safer fix here does a check after the item
   293    // change has occurred. It checks to see if the item has landed in an improper skipfound field. If it has it
   294    // tried to get out the field. This should workaround this issue with a minimum of side effects. You will only
   295    // see a change with skipfound fields. 
   296    Procedure SkipFoundAdjust 
   297        Boolean bSkipFound
   298        Integer iNewItem iFile iStat
   299        Get Current_Item to iNewItem
   300        Get item_option iNewItem SkipFound to bSkipFound
   301        If bSkipFound Begin
   302             Get data_file iNewItem to iFile
   303             If (iFile) Begin
   304                Get_Attribute DF_FILE_STATUS of iFile to iStat
   305                If (iStat<>DF_FILE_INACTIVE) Begin
   306                    // if we landed on an active skipfound field, we need to move somewhere else
   307                    Send next // move to valid forward next item 
   308                    If (Current_Item(Self)=iNewItem) Begin
   309                        // in rare case that forward navigate failed, go backwards
   310                        Send Previous
   311                    End
   312                End
   313             End
   314        End
   315    End_Procedure
   316
   317
   318End_Class // DfTable
   319
   320
   321Use DD_Deomx.pkg // mixin support for dd classes
   322use DD_CdDeo.pkg // mixin support for exported descriptions
   323
   324{ ClassType=Abstract }
   325{ HelpTopic=dbGridDD }
   326Class dbGridDD is a dbGridDS
   327  Import_Class_Protocol Extended_DEO_Mixin
   328  Import_Class_Protocol Extended_DEO_Status_Help_Mixin
   329  Import_Class_Protocol Code_Description_Mixin
   330  // we are implementing Scan_servers directly in this class to get the embedded buttonF
   331  //Import_Class_Protocol Extended_DEO_Prompt_Mixin
   332
   333  Procedure Construct_Object
   334     Forward Send Construct_Object
   335     Send Define_Code_Description_Mixin
   336  End_Procedure // Construct_Object
   337
   338  { MethodType=Property  NoDoc=True }
   339  Procedure Set Current_Item Integer Itm
   340     // we must if there are no items. In which case do nothing
   341     If ( Focus(Desktop)=self AND ;
   342          (Current_Item(self)<Item_Count(self)) AND ;
   343          Item_Count(self) AND ;
   344          Extended_deo_State(self) ) ;
   345             Send Update_Focus_Field
   346     Forward Set Current_Item to Itm
   347  End_Procedure // Set Current_Item
   348
   349  { Visibility=Private }
   350  Procedure Set New_Item Integer Itm
   351     // we must if there are no items. In which case do nothing
   352     If ( Focus(Desktop)=self AND ;
   353          Item_Count(self) AND ;
   354          Extended_deo_State(self) ) ;
   355             Send Update_Focus_Field
   356     Forward Set New_Item to Itm
   357  End_Procedure // Set Current_Item
   358
   359    { Visibility=Private }
   360    Function Ele_Prompt_Object integer ele integer item# returns integer
   361        Integer iObj
   362        Integer iDSO
   363        Integer iFile
   364        Integer iField
   365        Forward Get Ele_Prompt_Object ele Item# to iObj
   366        If (iObj=0 AND Extended_DEO_State(self)) Begin
   367            // only check if not combo column (combos don't use prompt lists)
   368            If not (Column_Combo_state(self,Item#) ) begin
   369                Get Server to iDSO
   370                If iDSO Begin
   371                    Get Data_File of ele item Item# to iFile
   372                    If iFile Begin
   373                        Get Data_Field of ele item Item# to iField
   374                        Get File_Field_Prompt_Object of iDSO iFile iField to iObj
   375                        // if checkbox don't show prompts for simple validation tables
   376                        If (iObj=DD_Global_Validation_Prompt_Object and checkbox_item_state(self,Item#)) ;
   377                            move 0 to iObj
   378                    End
   379                End
   380            End
   381        End
   382        Function_Return iObj
   383    End_Function
   384
   385
   386
   387  //************************************************************************//
   388  // Assign_DD_Label                                                        //
   389  // This assigns the DEO's from the DD. This uses short labels and         //
   390  // sets column headers.                                                   //
   391  //************************************************************************//
   392  { Visibility=Private }
   393  Procedure Assign_DD_Label Integer iDSO Integer iFile Integer iField ;
   394       Integer iDEO Integer iItem
   395    String sName
   396    Get File_Field_Label of iDSO iFile iField DD_LABEL_SHORT to sName
   397    Set Header_Label item iItem to sName
   398  End_Procedure
   399
   400  // this fixes grid bug where insert_row loses the current changed value.
   401  // this only happens when you've changed an item in the top row and you press
   402  // the up arrow.
   403  { NoDoc=True }
   404  procedure Up_Row
   405    Integer iCur
   406    get current_item to iCur
   407    // if row 0 and the current item is changed..just set the value to
   408    // itself. Local value bypasses all the DD stuff (which will happen later)
   409    if (current_row(self)=0 AND item_changed_state(self,iCur)) ;
   410        set local_value item iCur to (value(self,iCur))
   411    forward send up_row
   412  End_Procedure
   413
   414  // Hook to set prompt buttons for header and embedded
   415  { Visibility=Private }
   416  Procedure Scan_Servers
   417    Integer iMode
   418    Forward Send Scan_Servers
   419
   420    If Not (Extended_DEO_State(self)) ;
   421       Procedure_Return
   422
   423    Get Prompt_Button_Mode to iMode
   424    If iMode eq PB_PromptAuto ;
   425       Send Create_Prompt_Button iMode
   426    If (pbEmbeddedPrompts(self)) send CreateEmbeddedPrompts
   427  End_Procedure
   428
   429    // notification that an item option has been changed by the DD. This
   430    // change already made to prototype object and must now be made items
   431    // for that column. Note that only the options that matter trigger this
   432    // notification
   433    { Visibility=Private }
   434    Procedure Item_Options_Changed integer iItem
   435        integer i iRows iCols
   436        integer iCur iOptions
   437        get Row_Count  to iRows
   438        Get Item_Limit to iCols
   439        Get Item_Options of (ProtoType_object(self)) iItem to iOptions
   440        For i from 0 to (iRows-1)
   441            Move (i * iCols + iItem) to iCur
   442            Set Item_Options iCur to iOptions
   443            Set Form_Options iCur to iOptions
   444        Loop
   445    end_procedure
   446
   447    // notification that an item mask value has been changed by the DD. This
   448    // change already made to the first form must be made to all other items
   449    // in the same column
   450    { Visibility=Private }
   451    Procedure Item_Mask_Changed integer iItem
   452        integer i iRows iCols
   453        string sMask
   454        get Row_Count  to iRows
   455        Get Item_Limit to iCols
   456        Get Form_Mask iItem to sMask
   457        For i from 1 to (iRows-1)
   458            Set Form_Mask (i * iCols + iItem) to sMask
   459        Loop
   460        set dynamic_update_state to 1 // required to paint changes
   461    end_procedure
   462End_Class
   463
   464Struct tGridComboHelper
   465    boolean   bDataOnly        // internal. Data only no description
   466    integer   eCodeDisplay     // can be accessed via get/set Column_Combo_Code_Display_Mode
   467    string[]  sDataValues      // internal. array of data values
   468End_Struct
   469
   470
   471
   472{ HelpTopic=dbGrid }
   473Class dbGrid Is A dbGridDD
   474
   475    Procedure Construct_Object
   476        forward send Construct_object
   477
   478        { Visibility=Private }
   479        property integer piActiveColumn 0 // use by comboFillItem callback to figure out column
   480
   481        // Array of of helpers. One is set for each active combo column
   482        { Visibility=Private }
   483        Property tGridComboHelper[] pGridComboHelpers
   484
   485    end_procedure
   486
   487    { MethodType=Property Visibility=Private }
   488    Function pGridComboHelper integer iColumn returns tGridComboHelper
   489        tGridComboHelper GridComboHelper
   490        tGridComboHelper[] GridComboHelpers
   491        Get pGridComboHelpers to GridComboHelpers
   492        // If this is accessed before the column helper is created, create it,
   493        If (SizeOfArray(GridComboHelpers)<=iColumn) Begin
   494            // if turning on a column combo, intialize the helper struct
   495            Move CB_CODE_DISPLAY_DESCRIPTION to GridComboHelper.eCodeDisplay // default value
   496            Set pGridComboHelper iColumn to GridComboHelper // initializes the struct
   497        End
   498        Else Begin
   499            Move GridComboHelpers[iColumn] to GridComboHelper
   500        End
   501        Function_Return GridComboHelper
   502    end_function
   503
   504    { MethodType=Property Visibility=Private }
   505    Procedure Set pGridComboHelper integer iColumn tGridComboHelper GridComboHelper
   506        tGridComboHelper[] GridComboHelpers
   507        Get pGridComboHelpers to GridComboHelpers
   508        Move GridComboHelper  to GridComboHelpers[iColumn]
   509        Set pGridComboHelpers to GridComboHelpers
   510    End_Procedure
   511
   512    // aumgent to clear the datavalues in the helper object
   513    { NoDoc=True }
   514    Procedure Column_Combo_Delete_Data integer iColumn
   515        tGridComboHelper GridComboHelper
   516        forward send Column_Combo_delete_Data iColumn
   517        Get pGridComboHelper iColumn to GridComboHelper
   518        Move (ResizeArray(GridComboHelper.sDataValues,0)) to GridComboHelper.sDataValues
   519        Set pGridComboHelper iColumn to GridComboHelper
   520    End_Procedure
   521
   522// 12.1: helper is added as needed in pGridComboHelper, not here.
   523//    // augment to create and remove a helper object as needed.
   524//    { MethodType=Property  NoDoc=True }
   525//    Procedure Set Column_Combo_State integer iColumn boolean bState
   526//        boolean bOldState
   527//        tGridComboHelper GridComboHelper
   528//        Get Column_Combo_State iColumn to bOldState
   529//        If ( not(bOldState) and bState) begin
   530//            // if turning on a column combo, intialize the helper struct
   531//            Move CB_CODE_DISPLAY_DESCRIPTION to GridComboHelper.eCodeDisplay // default value
   532//            set pGridComboHelper iColumn to GridComboHelper // initializes the struct
   533//        end
   534//        Forward Set Column_Combo_state iColumn to bState
   535//    End_Procedure
   536
   537    { MethodType=Property }
   538    Function Column_Combo_Code_Display_Mode integer iColumn Returns integer
   539        tGridComboHelper GridComboHelper
   540        Get pGridComboHelper iColumn to GridComboHelper
   541        Function_return GridComboHelper.eCodeDisplay
   542    End_Function
   543
   544    { MethodType=Property }
   545    { ColumnBased=True }
   546    { Category=Appearance }
   547    { EnumList="CB_Code_Display_Description, CB_Code_Display_Code, CB_Code_Display_Both" }
   548    { InitialValue=CB_Code_Display_Description }
   549    Procedure Set Column_Combo_Code_Display_Mode integer iColumn integer eVal
   550        tGridComboHelper GridComboHelper
   551        Get pGridComboHelper iColumn to GridComboHelper
   552        Move eVal to GridComboHelper.eCodeDisplay
   553        Set pGridComboHelper iColumn to GridComboHelper
   554    End_Function
   555
   556    // For a column, pass data and return the description
   557    { Visibility=Private }
   558    Function Column_Combo_Data_To_Description integer iColumn String sValue returns String
   559        tGridComboHelper GridComboHelper
   560        integer i iItems
   561
   562        Get pGridComboHelper iColumn to GridComboHelper
   563
   564        If (GridComboHelper.bDataOnly or GridComboHelper.eCodeDisplay=CB_CODE_DISPLAY_CODE) begin
   565            Function_Return sValue
   566        end
   567
   568        // search for the data in our list of data values for this column
   569        Move (SizeOfArray(GridComboHelper.sDataValues)) to iItems
   570        For i From 0 to (iItems-1)
   571            If (GridComboHelper.sDataValues[i]=sValue) Begin
   572                Get Column_Combo_Value iColumn I to sValue
   573                Function_Return sValue
   574            end
   575        end
   576
   577        // else if no match we will use the data as the description
   578        Function_Return sValue
   579    End_function
   580
   581    // for a column, pass description and find the data
   582    { Visibility=Private }
   583    Function Column_Combo_Description_to_Data integer iColumn String sValue returns String
   584        integer iItem
   585        tGridComboHelper GridComboHelper
   586
   587        Get pGridComboHelper iColumn to GridComboHelper
   588
   589        // if data only, just return the data
   590        If (GridComboHelper.bDataOnly or GridComboHelper.eCodeDisplay=CB_CODE_DISPLAY_CODE) begin
   591            Function_Return sValue
   592        end
   593
   594        // some kind of translation is needed. See if we have a match in our combo-list and then find the data value
   595        Get Column_Combo_Find iColumn 0 sValue to iItem
   596        If (iItem >= 0) begin // if value is found
   597            Move GridComboHelper.sDataValues[iItem] to sValue
   598        end
   599        // else if not found, Just return the data (validation can be handled by the dd).
   600
   601        Function_Return sValue
   602    End_Function
   603
   604    // Public augmentation point. Pass current datavalue and all info
   605    // in record buffer. Should return what you want to see on the screen.
   606    // Augment to support various description/data Display formats.
   607    //
   608    { MethodType=Event }
   609    Function Column_Combo_Description_Value integer iColumn integer eMode String sDescVal String sDataVal returns string
   610        If (eMode=CB_CODE_DISPLAY_CODE) begin
   611            Move sDataVal to sDescVal
   612        end
   613        Else If (eMode=CB_CODE_DISPLAY_BOTH) begin
   614            Move (sDataVal * "-" * sDescVal) to sDescVal
   615        end
   616        // else if deisplay description, juyst return the description as is
   617        Function_Return sDescVal
   618    End_Function // Column_Combo_Description_Value
   619
   620
   621
   622    // Message to add Items to a list. Similar to Add_Item except
   623    // it handles an optional second parameter. If no 2nd param the first
   624    // is used in its place. This will normally be used inside of Fill_List.
   625    //
   626    // Send Column_Combo_Add_Item iColumn Descr_Value {Data_Value}
   627    //
   628    Procedure Column_Combo_Add_Item integer iColumn String sDescription String sDat
   629        String  sData
   630        Integer iItem
   631        tGridComboHelper GridComboHelper
   632
   633        // If sDat not passed, use sDescription for both display and database values
   634        Move (If(num_arguments<3, sDescription, sDat)) to sData
   635
   636        Get Column_Combo_item_count iColumn to iItem   // get this before we add the item.
   637
   638        Get pGridComboHelper iColumn to GridComboHelper
   639
   640        // If no items we have a new list. We want to know if it is data only
   641        // or data descr. By default, assume that it is data-only
   642        If (iItem=0) begin
   643            Move True to GridComboHelper.bDataOnly
   644        end
   645
   646        // this lets us convert the description. By default it returns the
   647        // value passed. This allows you to pass a data param that gets
   648        // changed for display purposes.
   649        Get Column_Combo_Description_Value iColumn GridComboHelper.eCodeDisplay sDescription sData to sDescription
   650
   651        Forward send Column_Combo_Add_Item iColumn sDescription            // used by the display list
   652
   653        Move sData to GridComboHelper.sDataValues[iItem]                 // the actual data value
   654
   655        // If description does not match the data we set this flag false
   656        If (sDescription<>sData AND GridComboHelper.bDataOnly ) begin
   657            Move false to GridComboHelper.bDataOnly
   658        end
   659        set pGridComboHelper iColumn to GridComboHelper
   660    End_Procedure
   661
   662
   663    // this is the one the callback calls. We must figure out the column and pass it on
   664    { Visibility=Private }
   665    Procedure ComboFillItem integer iItem string sData string sDescription ;
   666                            integer iFile RowId riId
   667        integer iCol
   668        Get piActiveColumn to iCol
   669        Send ColumnComboFillItem iCol iItem sData sDescription iFile riId
   670    End_Procedure
   671
   672    { Visibility=Private }
   673    Procedure ColumnComboFillItem integer iCol integer iItem string sData string sDescription ;
   674                            integer iFile RowId riId
   675        If (sDescription='') Move sData to sDescription
   676        Send Column_Combo_Add_Item iCol sDescription sData
   677    End_Procedure
   678
   679    { Visibility=Private }
   680    Procedure Column_Combo_Add_Blank_Item integer iCol String Blank_Desc
   681        integer iItems
   682        Get Column_combo_Item_count iCol to iItems
   683        Send ColumnComboFillItem iCol iItems '' Blank_Desc 0 (NullRowId())
   684    End_Procedure
   685
   686    // Fills the list by loading the entire defined data-file
   687    //
   688    { MethodType=Event }
   689    Procedure Column_Combo_Fill_List integer iCol
   690        integer iFile iField eDisplayMode
   691        handle  hoSrvr hoEle hoTable
   692
   693        Send Column_Combo_Delete_Data iCol
   694        Set piActiveColumn to iCol
   695        Get Server to hoSrvr
   696        Get Prototype_object to hoEle
   697        Get Data_File  of hoEle iCol to iFile
   698        Get Data_Field of hoEle iCol to iField
   699        If (hoSrvr AND iFile) Begin
   700            Get Item_Field_Property GET_File_Field_Table_Object iCol to hoTable
   701            // this does a callback of ComboFillItem for each item in the list
   702            Send File_Field_Fill_List of hoSrvr iFile iField Self msg_ComboFillItem
   703            If (hoTable AND not(Column_Combo_Entry_State(self,iCol)) AND Allow_Blank_State(hoTable)) begin
   704                 //Column_Combo_Allow_Undefined_state(Self,iCol)) begin
   705                    Send Column_Combo_Add_Blank_Item iCol DD_BLANK_CODE_DESCRIPTION
   706            end
   707        End
   708    End_Procedure
   709
   710    // augment to update the DD each time this changes
   711    { MethodType=Event  Nodoc=True }
   712    Procedure Combo_Item_Changed integer iItem
   713        Forward Send combo_item_Changed iItem
   714        Set Item_Field_Current_Value iItem to (Value(Self,iItem)) // this updates the DD
   715    end_Procedure
   716
   717    // If a combo column, convert from description to data and forward
   718    { MethodType=Property Visibility=Private }
   719    Procedure Set Item_Field_Current_Value Integer iItem String sValue
   720        integer iCol
   721        Boolean bCombo
   722        Get Column iItem to iCol
   723        Get Column_Combo_State iCol to bCombo
   724        If bCombo begin
   725            Get Column_Combo_Description_to_data iCol sValue to sValue
   726        end
   727        Forward Set Item_Field_Current_Value iItem to sValue
   728    End_Procedure // Set Item_Field_Current_Value
   729
   730    // If a combo column, convert from data to description and forward
   731    { Visibility=Private }
   732    Procedure Item_Value_Changed Integer iItem String sValue
   733        Boolean bCombo
   734        integer iCol
   735        Get Column iItem to iCol
   736        Get Column_Combo_State iCol to bCombo
   737        If bCombo begin
   738            Get Column_Combo_Data_to_Description iCol sValue to sValue
   739        end
   740        Forward Send Item_Value_Changed iItem sValue
   741    End_Procedure
   742
   743
   744    // augment to refresh all dynamic code tables
   745    { Nodoc=True }
   746    Procedure Activate returns integer
   747        integer iRVal iCol iColumns
   748        Handle hoTable
   749        String  sValue
   750        boolean bCol
   751
   752        Forward Get MSG_Activate to iRVal
   753
   754        if not iRVal Begin
   755            Get Item_limit to iColumns
   756            For iCol From 0 to (iColumns-1)
   757                Get Column_Combo_State iCol to bCol
   758                If bCol begin
   759                    Get Item_Field_Property GET_File_Field_Table_Object iCol to hoTable
   760                    If (hoTable AND (Static_State(hoTable)=0 OR Table_Loaded_State(hoTable)=0)) Begin
   761                        Send Column_Combo_Fill_List iCol
   762                    End
   763                End
   764            Loop
   765        End
   766        Procedure_Return iRVal
   767    End_Procedure // Activate
   768
   769    // augment to refill a combo validation table if needed (if the val table is not static)
   770    Function Item_Entry Integer iMsg Integer iItem Returns Integer
   771        Integer iResult iCol
   772        Boolean bCol
   773        Handle hoTable
   774        Forward Get Item_Entry iMsg iItem to iResult
   775        If (iResult=0) Begin
   776            Get Column iItem to iCol
   777            Get Column_Combo_State iCol to bCol
   778            If bCol Begin
   779                Get Item_Field_Property GET_File_Field_Table_Object iCol to hoTable
   780                If (hoTable and (not(Static_State(hoTable)) or not(Table_Loaded_State(hoTable))) ) Begin
   781                    // if a combo column that has a DD validation table that is not statuc or not loaded, fill it now
   782                    Send Column_Combo_Fill_List iCol
   783                End
   784            End
   785        End
   786        Function_Return iResult
   787    End_Function
   788
   789
   790    // This Replaces DD message with one that understands
   791    // description and data difference.    //
   792    { MethodType=Property Visibility=Private }
   793    Function Data_Value integer iItem Returns String
   794        string sValue
   795        integer iCol
   796        Boolean bCombo
   797
   798        Get Column iItem to iCol
   799        Get Column_Combo_State iCol to bCombo
   800        If bCombo begin
   801            Get Value iItem to sValue
   802            Get Column_Combo_Description_to_Data iCol sValue to sValue
   803        end
   804        else begin
   805            Forward Get Data_Value iItem to sValue
   806        end
   807        Function_Return sValue
   808    End_Function
   809
   810    // Augmented to handle entry_state=F combos. These type of combos must
   811    // have a default value (since something always appears in the form). So
   812    // we must check for cases where we have a value in the combo that is
   813    // not reflected in the DD buffer. In such a case, update the buffer with
   814    // a default value. Called by entry_defaults
   815    //
   816    { MethodType=Event Visibility=Private }
   817    Procedure ColumnComboEntryDefaults integer iItem handle hoDSO integer iFile integer iField
   818        integer iCol
   819        boolean bColCombo bEntry
   820
   821        Get Column iItem to iCol
   822        Get Column_combo_state iCol to bColCombo
   823        If bColCombo begin
   824            get Column_Combo_Entry_State iCol to bEntry
   825            If not bEntry begin
   826                // set default value in DD to the data value of current combo
   827                Set File_Field_Default_Value of hoDSO iFile iField to (Data_Value(Self,iItem))
   828            end
   829        end
   830    End_Procedure
   831
   832
   833    // change so that list is initialized first. Also, set extended_deo_state before
   834    // attempting to fill list (it needs that information).
   835    { Visibility=Private }
   836    Procedure Attach_Deo_To_Server
   837        Handle hoSrvr hoEle
   838        integer iCols iCol iItems
   839        boolean bColCombo bExtended
   840
   841        Get Server to hoSrvr
   842        If hoSrvr begin
   843            Get Extended_DSO_State of hoSrvr to bExtended
   844            Set Extended_DEO_State to bExtended
   845        end
   846        Get ProtoType_object to hoEle
   847        Get Item_Count of hoEle to iCols
   848        For iCol From 0 to (iCols-1)
   849            Get Column_Combo_state iCol to bColCombo
   850            If bColCombo begin
   851                If not bExtended begin
   852                    Error DFERR_PROGRAM "Column Combos in DEO Grids must be attached to a DDO"
   853                    Move iCols to iCol // force exit from for loop
   854                end
   855                Else Begin
   856                    // if the list is empty fill it. This way static lists are only loaded one time
   857                    Get Column_Combo_Item_count iCol to iItems
   858                    If (iItems=0) Send Column_Combo_fill_list iCol
   859                end
   860            end
   861        Loop
   862        Forward Send Attach_deo_to_Server
   863    End_Procedure
   864
   865    // augment to unset capslock if the display mode is not Code. If not code display the data that is displayed is
   866    // not the data being sent to the DD and it should not be capslocked by the DD. Also set a bigger form_margin.
   867    // You'd only need a big form_margin if entry_state is true which would be unlikely with a description combo (but it is supported).
   868    { Visibility=Private }
   869    Procedure Copy_Item_Options Integer iDSO Integer iFile Integer iField Integer iDEO Integer iItem
   870        Integer eDisplayMode
   871        Boolean bCombo bDataOnly
   872        tGridComboHelper GridComboHelper
   873        Forward Send Copy_Item_Options iDSO iFile iField iDEO iItem
   874        If Not (Extended_deo_State(self)) Procedure_Return
   875        Get Column_combo_state iItem to bCombo
   876        If bCombo begin
   877            Get pGridComboHelper iItem to GridComboHelper
   878            Get Column_Combo_Code_Display_mode iItem to eDisplayMode
   879            If (eDisplayMode<>CB_CODE_DISPLAY_CODE and not(GridComboHelper.bDataOnly)) Begin
   880                Set Column_Capslock_State iItem to False // this might be been set true by the forward send of this message
   881                set Form_Margin   iItem to 255 // allow 255 characters which should be enough for any combo
   882                set Form_DataType iItem to ASCII_WINDOW // If display description-- make it a string
   883            end
   884        end
   885    End_Procedure
   886
   887
   888    { Visibility=Private }
   889    Procedure Set Local_Value integer iItem string sVal
   890        integer iCol
   891        Boolean bCombo
   892        Get Column iItem to iCol
   893        Get Column_Combo_State iCol to bCombo
   894        If bCombo begin
   895            get Column_Combo_Data_To_Description iCol sVal to sVal
   896        end
   897        Forward Set Local_Value iItem to sVal
   898    End_Procedure // Set Local_Value
   899
   900    { NoDoc=True }
   901    procedure Prompt
   902        integer iCol
   903        get Current_Col to iCol
   904        If not (Column_Combo_State(self,iCol)) Begin
   905            Forward send Prompt
   906        end
   907    end_procedure
   908
   909     { NoDoc=True }
   910     // 12.1 Fix: We must augment Entry_update to handle column combos where the description is different than the
   911     // data. In such a case, we do not want the internal entry_update ot move data from the column. Instead,
   912     // we will do this manually. If the item should not be updated, we will stop it by setting its state temporarily
   913     // to NoPut/NoEnter. This change is purposefully made to be as targeted as possible. It only
   914     // changes entry_update for the one column. If you don't use combos, this has no impact at all.
   915     // It might have made more sense to completely rewrite the entry_update but it seems safer to just make as
   916     // small a change as spossible.
   917     Procedure Entry_Update Integer iFile Integer iDoAll
   918           Integer iBase iLimit iItem iDataFile iDataField iCols iNoPut iNoEnter
   919           String sVal
   920           Integer[] iDescCol iDescNoEnter iDescNoPut
   921
   922           // only do this with normal Finds and autofinds.. DD saves never calls this method. Finds always pass
   923           // iDoAll as 1 (saves are 3). This check is done to keep the change as limited as possible
   924           If (iDoAll=1) Begin
   925               Get Item_Limit to iLimit  // number of cols in row
   926               Get Base_Item to iBase    // first item in row
   927               For iItem from 0 to (iLimit-1)
   928                   // We only care about column_combo_state=T, Column_Combo_display_modes that use descriptions
   929                   // and columns that are bound to the DD and columns that are not displayonly
   930                   If (Column_Combo_State(Self,iItem) and ;
   931                       Column_Combo_Code_Display_Mode(Self,iItem)<>CB_Code_Display_Code and ;
   932                       Data_File(Self,iItem)>0) Begin
   933
   934                       Get Column_Option iItem noPut to iNoPut
   935                       Get Column_Option iItem noEnter to iNoEnter
   936                       // if it is noput and noenter it is displayonly and there is nothing to do
   937                       // Entry_update will update items unless both noput and noenter are set. You'd think
   938                       // that NoPut would stop it, but for finds it does not.
   939                       If not (iNoPut and iNoEnter) Begin
   940                           Move (iBase+iItem) to iDescCol[iCols]   // keep track of the item to change
   941                           Move iNoEnter to iDescNoEnter[iCols]    // the item's NoEnter
   942                           Move iNoPut   to iDescNoPut[iCols]      // the item's NoPut
   943                           // Changing this will stop the runtime from moving data from the item to the buffer
   944                           Set Item_Option iDescCol[iCols] noPut to True
   945                           Set Item_Option iDescCol[iCols] noEnter to True
   946                           Increment iCols
   947
   948                       End
   949                   End
   950               Loop
   951           End
   952
   953           // the normal entry_update
   954           Forward Send Entry_Update iFile iDoAll
   955
   956           // For any items we changed, we must manually do the Entry_update and restore the item state
   957           For iItem from 0 to (iCols-1)
   958               Get Data_Field iDescCol[iItem] to iDataField
   959               Get Data_File  iDescCol[iItem] to iDataFile
   960               Get Data_Value iDescCol[iItem] to sVal // converts from description to data
   961               Set_Field_Value iDataFile iDataField to sVal // upadate the buffer
   962               // restore items
   963               Set Item_Option iDescCol[iItem] noPut   to iDescNoput[iItem]
   964               Set Item_Option iDescCol[iItem] noEnter to iDescNoEnter[iItem]
   965           Loop
   966
   967     End_Procedure
   968
   969
   970End_Class
   971
   972