open-insight/LSL2/STPROC/SET_RECORD.txt
Infineon\StieberD 7762b129af pre cutover push
2024-09-04 20:33:41 -07:00

1023 lines
56 KiB
Plaintext

Function Set_Record(Data, DictColPos, VirtualOnly, SkipSymbolics, Window)
/***********************************************************************************************************************
This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
permission from SRP Computer Solutions, Inc.
Name : Set_Record
Description : Updates an OpenInsight window's controls with the data being passed in.
Notes : The primary purpose of this routine is to make it easier to update the contents of an OpenInsight
window without having to name the controls. This allows the developer to simulate the AREV method
which would automatically update the window's fields whenever @RECORD was update. OpenInsight
makes this more cumbersome by requiring each control to be updated individually using a property
setting.
Set_Record provides a level of automation that simulate AREV's @RECORD support. The developer can
pass in a specific field position and the data that needs to be updated in that field or the
developer can pass in the entire record array. Set_Record will automatically query the window's
controls and update them as needed. Even symbolic fields will be updated accordingly.
(NOTE: OpenInsight 7.2 introduced a new property - ATRECORD. This works the same as the RECORD
property when used in the Get_Property function. However, unlike the RECORD property it will update
the window's databound controls, including symbolic fields, when used in the Set_Property function.
This also simulates AREV's @RECORD support. However, it cannot be used to update specific fields at
a time or to update non-databound controls that need to be associated with database columns such as
OLE controls.)
Simulating @RECORD = RecordVar
==============================
In AREV, the entire data record could be updated at once by setting @RECORD to the new value. As
an example, if the developer needed to restore the content of the AREV window to the value of
record as it was read from the disk, the following line of code could be called:
@RECORD = WC_OREC% ; * Restore the contents of the original record.
To do the equivelent using Set_Record:
Set_Record(OrigRecord) ; // Restore the contents of the original record.
Simulating @RECORD<FieldVal> = FieldData
========================================
Individual database columns (aka fields) could also be updated by specifing the column number. In
AREV the code might look like this:
@RECORD<5> = 1000 ; * Put the customer number in place.
To do the equivelent using Set_Record:
Set_Record(1000, 5) ; // Put the customer number in place.
Value, subvalue, text, and subtext positions can also be updated by separating each delimiter
position with a comma. In AREV the code might look like this:
@RECORD<10, 2> = "8005552222" ; * Put the contact phone number in the
* 2nd value position of field 10.
To do the equivalent with this routine:
Set_Record("8005552222", "10,2") ; // Put the contact phone number in the
// 2nd value position of field 10.
Virtual Databound Controls
==========================
Sometimes controls that need to display live data are not truly databound to the database column.
A good example of this is if an ActiveX control is used to display and manage data. The internal
method OpenInsight uses to populate the window has no knowledge that these controls are connected
to the database in any way so they just get ignored.
Set_Record provides support for this through the use of the user-defined property @POS. This will
virtually bind the control to a database column (or columns, see below). Use the CREATE event of
the window to set @POS. For single field controls you would do something like:
Set_Property(@Window:".COMBO_1", "@POS", 5)
For multi-field controls (e.g. AMV fields) like the SRP OLE EditTable, just separate each database
column number with @VM. For instance:
Set_Property(@Window:".OLE_EDITTABLE1", "@POS", 2:@VM:5:@VM:6:@VM:"":@VM:7)
Set_Property(@Window:".OLE_EDITTABLE2", "@POS", 2:@VM:"DESCRIPTION":@VM:6)
In the first example, the first command has a null embedded between database columns 6 and 7. This
is to illusrate how one would handle an EditTable column that is not associated with a database
column. In the case of the SRP OLE EditTable, this could be a column of buttons or hyperlinks which
are there for functionality and not data storage.
The second example has a word embedded between database columns 2 and 6. This is to illustrate how
one would handle an EditTable column that is virtually bound to a symbolic (calculated) column. Just
enter then name of the symbolic column and this routine will recalculate the value and put the data
into the the appropriate EditTable column.
Handling Symbolic (aka Calculated) Columns
==========================================
As noted above in the Virtual Databound Controls section, non-databound controls can be virtually
bound to a symbolic column by using the @POS user-defined property. Set_Record will compute it using
the latest content from the data record.
By default, controls that are truly databound to symbolic columns will be recalculated after all the
data fields have been updated. However, sometimes this is not necessary or desirable. Once instance
would be during the window's WRITE event. Since OpenInsight windows clear all controls during a
successful database write, there is no need to go through the additional effort to recalculate
symbolic columns. In these situations set the SkipSymbolic parameter to 1:
Set_Record(RecordVar, "", Yes$)
Another option for handling symbolics using Set_Record is to update them while leaving all data
fields alone. This is useful when changes have been made to a virtually databound control and there
is a need to update the dependent symbolic controls. This is done by passing "SYM" into the
DictColPos parameter:
Set_Record("", "SYM")
A Word About Data Conversions
=============================
Native OpenInsight controls have validation and conversion settings which respond to the INVALUE
property. OLE controls, however, do not have validation and conversion settings that can be
configured in the Form Designer. Therefore, OLE controls must provide their own way of reporting
what validation and/or conversion patterns needed to be used. For the SRP OLE EditTable this is done
through the CellConv property. If a CellConv property has been set, the raw data will be converted
to this format first before the EditTable is visually updated. Otherwise, only internal data will be
displayed in the OLE control.
Parameters :
Data [in] -- The data that needs to updated into the controls. If DictColPos is not populated then
this should be an entire data record. Otherwise, it should only be the field data for
the indicated data column position.
DictColPos [in] -- The database column position being updated. If unassigned or null then Data is assumed
to be the entire data record. Value, subvalue, text, and subtext positions can also be
updated using commas to separate each delimiter position. See Notes for details.
VirtualOnly [in] -- Flag to determine if only virtually data databound controls should be updated. This
would be ideal during a READ event since has already updated the true databound
controls.
SkipSymbolics [in] -- Flag to determine if symbolic (calculated) columns should be updated. If unassigned or
null it will be Yes. This should be set to no if data is being updated during the WRITE
event. This will speed up the execution of this routine.
Window [in] -- The window being updated. If unassigned or null it will be @Window.
Record [out] -- The data record with updated values.
History : (Date, Initials, Notes)
01/27/06 dmb Original programmer
02/02/06 dmb Add new parameter, VirtualOnly, to indicate that only virtually databound controls (e.g. OLE
controls) should be updated. Modified the logic so that virtually databound controls will be
updated even if there are no true databound controls bound to the same data column.
02/03/06 dmb Add support for value, subvalue, text, and subtext updates to a single field. Fix problem
where symbolic columns weren't being updated if only a specific field is being updated.
Improved support for virtually bound controls so virtually bound symbolic columns will be
updated even if there are no controls that are actually bound to the symbolic column.
03/24/06 dmb Change EQ to _EQC when checking for SRP OLE EditTable ProgIDs.
03/24/06 dmb If the entire record is being set then clear SRP OLE EditTables to remove accidental data
from a previous record.
02/14/08 dmb New feature: Rows As Columns. This checks the @ROWSASCOLUMNS UDP which populates SRP
EditTable rows with database column data. Thus, the format is inverted.
02/15/08 dmb New feature: Cells as Fields. This checks the @CELLSASFIELDS UDP which populates SRP
EditTable cells with specific single-valued database columns.
02/17/08 dmb New feature: If DictColPos is set to "SYM" then only symbolic columns will be recalculated
and displayed.
02/17/08 dmb Remove Utility("CURSOR") calls. This was causing to many visual distractions.
03/04/08 dmb Don't use Clear method on SRP EditTables if they are also the control with focus.
03/18/08 rch Use @CLEARFILL setting if provided to Clear SRP EditTables.
12/09/10 rch Move 'While Flag' statements after Remove statements to just before Repeat statements so
the last value in each array gets processed by loop's logic.
12/01/12 krf Implement SRP FastArray processes to improve performance. Also built reliance upon the
@EDITTABLES UDP for the current window to store all SRP EditTable controls. Thus, this needs
to be populated from within the form's CREATE event or from the promoted CREATE event.
02/26/13 dmb UDPCtrl was not being populated using the SRP_FastArray_Extract so it was getting the
handle to UDPCtrls rather than the value stored in the hash table. - [SRPFW-8]
02/28/13 dmb UDP column positions and names were not being properly extracted since the Remove statement
is unable to handle the two-dimensional array that tracks these. - [SRPFW-10]
03/02/13 dmb Fix a reference to CellConv by extracting array <2> rather than the whole value. This was
left out during the last major enhancement conversion. - [SRPFW-10]
04/01/13 dmb Fix a VNAV issue in Get_Column_Positions gosub. Original code created a For/Next loop setting
the variable i. This For/Next loop was replaced with a Remove loop, but the variable i was
not being set. - [SRPFW-10]
***********************************************************************************************************************/
$insert Logical
$insert OIWin_Equates
If Assigned(Window) else Window = @Window
If Window EQ "" then Window = @Window
WinId = Window
$insert OIWin_Comm_Init
Declare function Get_property, Utility, OIWin_Compile_Impacts, Calculate, GetTickCount, SRP_FastArray_Create, SRP_FastArray_Extract, SRP_FastArray_GetVariable
Declare subroutine Set_Property, Utility, Send_Message, Send_Event, SRP_FastArray_Release, SRP_FastArray_Insert
Benchmark = ''
Total = ''
ProcessCnt = 0
ProcessDone = No$
Loop
ProcessCnt += 1
Until ProcessCnt GT 7 OR ProcessDone = Yes$
StartTime = GetTickCount()
On ProcessCnt GoSub Initialize_Vars, Set_At_Variables, Get_Column_Positions, Update_Window, Update_Record, Update_Symbolics, Clean_Up
EndTime = GetTickCount()
Benchmark := "Process ":ProcessCnt:": ":(EndTime - StartTime):"ms|"
Total += (EndTime - StartTime)
Repeat
Benchmark := "|Total ":Total:"ms"
* Call Msg(@Window, Benchmark)
GoSub Restore_At_Variables
Return Record
Initialize_Vars:
If Assigned(Data) else Data = ""
If Assigned(DictColPos) else DictColPos = ""
Convert " " to "" in DictColPos
Begin Case
Case DictColPos EQ ""
// DictColPos is null so the whole data record is being updated.
WholeRecord = Yes$
Case DictColPos _EQC "SYM"
// DictColPos is set to update only symbolics. To do this the WholeRecord flag needs to be set.
WholeRecord = Yes$
Case Num(DictColPos[1, 1])
// DictColPos is numerical so only a specific column is being updated.
WholeRecord = No$
Case Otherwise$
// An unrecognized value was sent in. Just assume the whole data record is being updated.
WholeRecord = Yes$
End Case
If Assigned(VirtualOnly) else VirtualOnly = No$
If VirtualOnly EQ "" then VirtualOnly = No$
If Assigned(SkipSymbolics) else SkipSymbolics = No$
If SkipSymbolics EQ "" then SkipSymbolics = No$
Controls = "" ; // List of OpenInsight controls that will be updated.
Properties = "" ; // List of OpenInsight properties that will be set. For native OI controls this will be INVALUE. OLE controls will use appropriate properties.
Values = "" ; // List of values that will be updated to the controls.
EdtCols = "" ; // EditTable column positions. AMV data is mapped to specific column positions within the EditTable control.
RowMaps = RowMaps@ ; // @VM/@SVM common array from OIWin_Comm_Init containing a list of all dictionary column names, their column numbers, and formatting information.
If RowMaps[-1, 1] = @VM then RowMaps[-1, 1] = ""
RMCount = Count(RowMaps, @VM) + (RowMaps NE "")
// @FM/@VM Common array of control, control type, and other relevant information. Subvalue 4 in each RowMaps entry has an index to this array.
MasterRowMap = SRP_FastArray_Create(MasterRowMap@)
MRCount = Count(MasterRowMap@, @FM) + (MasterRowMap@ NE "")
FocusControl = Get_Property(Window, "FOCUS") ; // Get the name of the control with focus will need this later.
UpdatedOLEEditTables = "" ; // Store the list of OLE EditTables already updated. Refer to this before executing a Clear method.
return
Set_At_Variables:
If Window NE @Window then
// Preserve the original values of @ variables in case a different window other than @Window is being updated.
Transfer @ID to OrigID
Transfer @RECORD to OrigRecord
Transfer @DICT to OrigDict
end
TableName = JoinMap@<1, 1>
If TableName NE "" then
// Set up @ variables so that symbolic (calculated) columns can be computed after the data record has been
// updated.
Dictionary = "DICT.":TableName
Open Dictionary to @DICT then
NumKeyCtrls = Count(KeyMap@, @FM) + (KeyMap@ NE "")
@ID = ""
For i = 1 to NumKeyCtrls
@ID := Get_Property(KeyMap@<i, 1>, "INVALUE"):"*"
Next i
@ID[-1, 1] = ""
Begin Case
Case WholeRecord EQ Yes$ AND DictColPos _NEC "SYM"
DelimDepth = 1
@RECORD = Data
Case WholeRecord EQ No$
GoSub ParseDictColPos
If DelimDepth GT 1 then GoSub Update_Data_Array
@RECORD = Get_Property(Window, "RECORD")
@RECORD<DictColPos> = Data
Case Otherwise$
// Most likely only updating symbolic columns. Make sure @RECORD is current.
@RECORD = Get_Property(Window, "RECORD")
End Case
end
end else
@RECORD = ""
end
return
Get_Column_Positions:
// Get the actual data column positions and the virtual (@POS) data column positions of the current window
// to set up in look up arrays
// Start with the actual data column positions. OpenInsight EditTable controls store data column positions
// as an @SVM delimited array. This code will flatten this out so each each EditTable column will have its
// own lookup reference.
OICtrls = SRP_FastArray_Create()
OICtrlColPos = SRP_FastArray_Create()
OICtrlEdtCol = SRP_FastArray_Create()
OICtrlTypes = SRP_FastArray_Create()
// These variables will track symbolic (calculated) column information so that the CALCULATE event or CALCULATE
// function can be executed as needed.
NumSymCtrls = 0
OISymCtrls = SRP_FastArray_Create()
OISymDepColPos = SRP_FastArray_Create()
OISymCtrlEdtCol = SRP_FastArray_Create()
OISymCtrlRowsAsColumns = SRP_FastArray_Create()
OISymCtrlCellsAsFields = SRP_FastArray_Create()
OISymCtrlSelPos = SRP_FastArray_Create()
OISymCtrlTypes = SRP_FastArray_Create()
OISymCtrlOrigText = SRP_FastArray_Create()
OISymCtrlColName = SRP_FastArray_Create()
OICtrlPos = 1
ControlSemanticPos = 1
ControlListItemPos = 1
Flag = ""
Unused = ""
Loop
Remove OICtrl from ControlMap@ at OICtrlPos Setting Flag
ControlSemantic = ControlSemantics@[ControlSemanticPos, @FM] ; ControlSemanticPos = Col2() + 1
ControlListItem = ControlList@[ControlListItemPos, @FM] ; ControlListItemPos = Col2() + 1
Unused = ControlSemantic[1, @VM]
ColName = ControlSemantic[Col2() + 1, @VM]
ColPos = ControlSemantic[Col2() + 1, @VM]
OICtrlType = ControlListItem<1, 3>
NumEdtCols = Count(ColPos, @SVM) + 1 ; // There is always one even if it is null
EdtColPos = 0 ; // Start the column counter at 0. Increase as each column is retrieved.
ColPosFlag = ""
ColPosPos = 1
Loop
Remove CurrColPos from ColPos at ColPosPos setting ColPosFlag
EdtColPos += 1
Begin Case
Case CurrColPos GT 0
// Regular databound control.
SRP_FastArray_Insert(OICtrlColPos, -1, 0, 0, CurrColPos)
SRP_FastArray_Insert(OICtrls, -1, 0, 0, OICtrl)
SRP_FastArray_Insert(OICtrlEdtCol, -1, 0, 0, EdtColPos)
SRP_FastArray_Insert(OICtrlTypes, -1, 0, 0, OICtrlType)
Case ColName<0, 0, EdtColPos> NE "" AND CurrColPos EQ "" AND OICtrlType NE "WINDOW"
// Must be a symbolic (calculated) control. If symbolics are not being skipped then collect
// necessary information for them to be updated later on.
If Not(SkipSymbolics) then
DepColPos = ""
ColNames = ColName<0, 0, EdtColPos>
ColNameFlag = ""
ColNamePos = 1
Loop
Remove ColName from ColNames at ColNamePos setting ColNameFlag
If Len(ColName) then
DepCols = OIWin_Compile_Impacts(TableName, ColName)
DepColsFlag = ""
DepColsPos = 1
Loop
Remove DepCol from DepCols at DepColsPos Setting DepColsFlag
DepCol = Field(DepCol, "*", 2)
If Num(DepCol) then
// This is a database column position. If it hasn't already been identified then
// append the tracking variables.
Locate DepCol in DepColPos using @FM setting fPos else
DepColPos<-1> = DepCol ; // Track columns already found to avoid duplication
// Information is being inserted rather than appended so the most independent
// columns appear first in the list. This way the CALCULATE event is sent to
// those controls and more dependent columsn will have the most current
// information available.
NumSymCtrls += 1
SRP_FastArray_Insert(OISymCtrls, 1, 0, 0, OICtrl)
SRP_FastArray_Insert(OISymDepColPos, 1, 0, 0, DepCol)
SRP_FastArray_Insert(OISymCtrlEdtCol, 1, 0, 0, EdtColPos)
SRP_FastArray_Insert(OISymCtrlRowsAsColumns, 1, 0, 0, "") ; // Not needed here, but need to keep values synched for the UDP controls.
SRP_FastArray_Insert(OISymCtrlCellsAsFields, 1, 0, 0, "") ; // Not needed here, but need to keep values synched for the UDP controls.
SRP_FastArray_Insert(OISymCtrlSelPos, 1, 0, 0, "") ; // Not needed here, but need to keep values synched for the UDP controls.
SRP_FastArray_Insert(OISymCtrlTypes, 1, 0, 0, OICtrlType)
SRP_FastArray_Insert(OISymCtrlOrigText, 1, 0, 0, "") ; // Not needed here, but need to keep values synched for the UDP controls.
SRP_FastArray_Insert(OISymCtrlColName, 1, 0, 0, "") ; // Not needed here, but need to keep values synched for the UDP controls.
end
end else
// This is another symbolic column. Add it to the list so all dependent database
// columns are collected.
ColNames<-1> = DepCol
end
While DepColsFlag
Repeat
end
While ColNameFlag
Repeat
end
End Case
While ColPosFlag
Repeat
While Flag
Repeat
// Now get the virtual (@POS) data column positions. SRP OLE EditTable controls store data column positions
// as an @VM delimited array. This code will flatten this out so each each SRP OLE EditTable column will have its
// own lookup reference.
ControlMap = Get_Property(Window, "@EDITTABLES")
Convert @FM to @RM in ControlMap
UDPColPos = Get_Property(ControlMap, "@POS")
UDPRowsAsColumns = Get_Property(ControlMap, "@ROWSASCOLUMNS")
UDPCellsAsFields = Get_Property(ControlMap, "@CELLSASFIELDS")
UDPTypes = Get_Property(ControlMap, "TYPE")
UDPOrigTexts = Get_Property(ControlMap, "ORIG_TEXT")
UDPCtrls = SRP_FastArray_Create()
UDPCtrlColPos = SRP_FastArray_Create()
UDPCtrlRowsAsColumnsList = SRP_FastArray_Create()
UDPCtrlCellsAsFieldsList = SRP_FastArray_Create()
UDPCtrlSelPosList = SRP_FastArray_Create()
* UDPCtrlTypes = SRP_FastArray_Create()
UDPCtrlEdtCol = SRP_FastArray_Create()
UDPCtrlOrigText = SRP_FastArray_Create()
ControlMapPos = 1
UDPColPosPos = 1
UDPRowsAsColumnsPos = 1
UDPCellsAsFieldsPos = 1
UDPTypesPos = 1
UDPOrigTextsPos = 1
Flag = ""
Unused = ""
Loop
ColPos = UDPColPos[UDPColPosPos, @RM]
UDPColPosPos = Col2() + 1
Remove UDPCtrl from ControlMap at ControlMapPos Setting Flag
Remove UDPCtrlRowsAsColumns from UDPRowsAsColumns at UDPRowsAsColumnsPos Setting Unused
Remove UDPCtrlCellsAsFields from UDPCellsAsFields at UDPCellsAsFieldsPos Setting Unused
Remove UDPCtrlType from UDPTypes at UDPTypesPos Setting Unused
Remove UDPOrigText from UDPOrigTexts at UDPOrigTextsPos Setting Unused
If ColPos NE "" then
If UDPCtrlRowsAsColumns EQ "" then UDPCtrlRowsAsColumns = No$ ; // Make sure something is in place so the <-1> append logic will work.
If UDPCtrlCellsAsFields EQ "" then UDPCtrlCellsAsFields = No$ ; // Make sure something is in place so the <-1> append logic will work.
If UDPOrigText EQ "" then UDPOrigText = UDPCtrlType ; // Make sure something is in place so the <-1> append logic will work.
NumEdtCols = Count(ColPos, @VM) + (ColPos NE "")
If UDPCtrlCellsAsFields EQ Yes$ then
NumEdtRows = Count(ColPos<0, 1>, @SVM) + (ColPos<0, 1> NE "")
If NumEdtRows GT 1 then NumEdtCols = NumEdtCols * NumEdtRows
end else
NumEdtRows = 1
end
ColNameFlag = ""
ColNamePos = 1
For i = 1 to NumEdtCols
For j = 1 to NumEdtRows
ColName = ColPos<0, i, j>
If ColName NE "" then
UDPCtrlSelPos = i:";":j
SRP_FastArray_Insert(UDPCtrlColPos, -1, 0, 0, ColName)
SRP_FastArray_Insert(UDPCtrls, -1, 0, 0, UDPCtrl)
SRP_FastArray_Insert(UDPCtrlEdtCol, -1, 0, 0, i)
SRP_FastArray_Insert(UDPCtrlRowsAsColumnsList, -1, 0, 0, UDPCtrlRowsAsColumns)
SRP_FastArray_Insert(UDPCtrlCellsAsFieldsList, -1, 0, 0, UDPCtrlCellsAsFields)
SRP_FastArray_Insert(UDPCtrlSelPosList, -1, 0, 0, UDPCtrlSelPos)
* SRP_FastArray_Insert(UDPCtrlTypes, -1, 0, 0, UDPCtrlType)
SRP_FastArray_Insert(UDPCtrlOrigText, -1, 0, 0, UDPOrigText)
// In case there are no true databound controls on the form, the data column positions that are
// virtually bound will be added to the RowMaps variable. This way the logic that updates the
// entire window will catch these virtually bound column positions and update accordingly.
If Num(ColName) then
// This is a data column so put the column position in the dictionary column name and number
// areas.
MRIndex = MRCount + 1
RowMaps := @VM:ColName:@SVM:ColName:@SVM:@SVM:MRIndex
RMCount += 1
SRP_FastArray_Insert(MasterRowMap, -1, 0, 0, UDPCtrl:@VM:i:@VM:UDPCtrlType)
MRCount += 1
end else
// This is a symbolic column so only put the column name in the dictionary column name area.
RowMaps := @VM:ColName:@SVM
RMCount += 1
DepColPos = ""
DepCols = OIWin_Compile_Impacts(TableName, ColName)
DepColsFlag = ""
DepColsPos = 1
Loop
Remove DepCol from DepCols at DepColsPos Setting DepColsFlag
DepCol = Field(DepCol, "*", 2)
If Num(DepCol) then
// This is a database column position. If it hasn't already been identified then
// append the tracking variables.
Locate DepCol in DepColPos using @FM setting fPos else
DepColPos<-1> = DepCol ; // Track columns already found to avoid duplication
// Information is being inserted rather than appended so the most independent
// columns appear first in the list. This way the CALCULATE event is sent to
// those controls and more dependent columsn will have the most current
// information available.
SRP_FastArray_Insert(OISymCtrls, 1, 0, 0, UDPCtrl) ; NumSymCtrls += 1
SRP_FastArray_Insert(OISymDepColPos, 1, 0, 0, DepCol)
SRP_FastArray_Insert(OISymCtrlEdtCol, 1, 0, 0, i)
SRP_FastArray_Insert(OISymCtrlRowsAsColumns, 1, 0, 0, UDPCtrlRowsAsColumns)
SRP_FastArray_Insert(OISymCtrlCellsAsFields, 1, 0, 0, UDPCtrlCellsAsFields)
SRP_FastArray_Insert(OISymCtrlSelPos, 1, 0, 0, UDPCtrlSelPos)
SRP_FastArray_Insert(OISymCtrlTypes, 1, 0, 0, UDPCtrlType)
SRP_FastArray_Insert(OISymCtrlOrigText, 1, 0, 0, UDPOrigText)
SRP_FastArray_Insert(OISymCtrlColName, 1, 0, 0, ColName) ; // The name of the symbolic column so it can be calculated later on.
end
end
While DepColsFlag
Repeat
end
end
Next j
Next i
end
While Flag
Repeat
// Check the DictColPos for the special keyword "SYM". This means only the symbolic columns should be updated.
// Reset the ProcessCnt counter accordingly.
If DictColPos _EQC "SYM" then ProcessCnt += 2
return
Update_Window:
// Update the control(s) on the window with the data.
If WholeRecord EQ No$ then
// Only one database column is being updated. Add all the controls that are bound to this database column and
// update them.
FieldData = Data
// Add all the controls that are actually data bound to this database column.
If Not(VirtualOnly) then GoSub Add_OI_Control_Information
// Add all the controls that are virtually data bound to this database column.
GoSub Add_UDP_Control_Information
end else
// The entire data record is being updated. Use the common variables already set up in the OIWin_Comm_Init
// insert to loop through each control, get the database column bound to it, then update it with the data record
// column.
Loop
RowMap = RowMaps[1, @VM]
RowMaps[1, Col2()] = ""
While RowMap GT ""
DictColName = RowMap<1, 1, 1>
DictColPos = RowMap<1, 1, 2>
Begin Case
Case DictColPos GT 0
// This is a data column.
FieldData = Data<DictColPos>
// Add the control indexed to this RowMap.
If Not(VirtualOnly) then GoSub Add_Native_Control_Information
// Add all the controls that are virtually data bound to this database column.
GoSub Add_UDP_Control_Information
Case DictColPos EQ ""
// This is a symbolic (calculated) column but a non-databound control might be virtually bound to
// it. The symbolic will need to be calculated and the value put into FieldData. However, in order
// to avoid unnecessary symbolic calculations check first to see if any controls are virtually bound
Transfer DictColName to DictColPos
GoSub Add_UDP_Control_Information
End Case
Repeat
end
// Strip off the preceding @RM
Controls[1, 1] = ""
Properties[1, 1] = ""
Values[1, 1] = ""
EdtCols[1, 1] = ""
Set_Property(Controls, Properties, Values, EdtCols)
ProgID = Get_Property(FocusControl, "OLE.ProgID") ; // Get the ProgID of the focus control
If ProgID _EQC "SRP.EditTable.1" then ; // Is the focus control an SRP EditTable?
Send_Message(FocusControl, "OLE.AbortCellEdit") ; // Because the SRP EditTable can already be in edit mode before the data
Send_Message(FocusControl, "OLE.EditCell", "") ; // is updated, reset the edit mode so the data is visible in the cell
end
return
Update_Record:
If TableName NE "" then
// Clear out and then update the RECORD property of the window. This will make sure that all related components
// to the data changes are in synch so symbolic (calculated) columns and the database write work correctly.
Set_Property(Window, "RECORD", "")
Set_Property(Window, "RECORD", @RECORD)
end
return
Update_Symbolics:
// Symbolics are updated last (and not with the data controls in the Update_Window gosub) because they need to be
// recalculated after the data controls have been populated.
If Not(SkipSymbolics) then
If WholeRecord EQ Yes$ then
// Send a CALCULATE event to all controls bound to a symbolic column.
For fPos = 1 to NumSymCtrls
GoSub Calculate_And_Display
Next fPos
// No longer need OISymDepColPos array since all controls are being recalculated.
SRP_FastArray_Release(OISymDepColPos)
end else
// Convert from Fast Array back to normal array
Handle = OISymDepColPos
OISymDepColPos = SRP_FastArray_GetVariable(Handle)
SRP_FastArray_Release(Handle)
// Send a CALCULATE event to those controls which are dependent upon the changed database column.
Match = Yes$
Loop
Locate DictColPos in OISymDepColPos using @FM setting fPos then
OISymDepColPos<fPos> = "" ; // Clear field position so it won't be found again.
GoSub Calculate_And_Display
end else
Match = No$
end
Until Not(Match)
Repeat
end
end
return
Clean_Up:
SRP_FastArray_Release(MasterRowMap)
SRP_FastArray_Release(OICtrls)
SRP_FastArray_Release(OICtrlColPos)
SRP_FastArray_Release(OICtrlEdtCol)
SRP_FastArray_Release(OICtrlTypes)
SRP_FastArray_Release(OISymCtrls)
SRP_FastArray_Release(OISymCtrlEdtCol)
SRP_FastArray_Release(OISymCtrlRowsAsColumns)
SRP_FastArray_Release(OISymCtrlCellsAsFields)
SRP_FastArray_Release(OISymCtrlSelPos)
SRP_FastArray_Release(OISymCtrlTypes)
SRP_FastArray_Release(OISymCtrlOrigText)
SRP_FastArray_Release(OISymCtrlColName)
SRP_FastArray_Release(UDPCtrls)
SRP_FastArray_Release(UDPCtrlColPos)
SRP_FastArray_Release(UDPCtrlRowsAsColumnsList)
SRP_FastArray_Release(UDPCtrlCellsAsFieldsList)
SRP_FastArray_Release(UDPCtrlSelPosList)
* SRP_FastArray_Release(UDPCtrlTypes)
SRP_FastArray_Release(UDPCtrlEdtCol)
SRP_FastArray_Release(UDPCtrlOrigText)
return
Calculate_And_Display:
SymCtrl = SRP_FastArray_Extract(OISymCtrls, fPos, 0, 0)
SymCtrlEdtCol = SRP_FastArray_Extract(OISymCtrlEdtCol, fPos, 0, 0)
SymCtrlRowsAsColumns = SRP_FastArray_Extract(OISymCtrlRowsAsColumns, fPos, 0, 0)
SymCtrlCellsAsFields = SRP_FastArray_Extract(OISymCtrlCellsAsFields, fPos, 0, 0)
SymCtrlSelPos = SRP_FastArray_Extract(OISymCtrlSelPos, fPos, 0, 0)
SymCtrlOrigText = SRP_FastArray_Extract(OISymCtrlOrigText, fPos, 0, 0)
SymCtrlColName = SRP_FastArray_Extract(OISymCtrlColName, fPos, 0, 0)
If SymCtrlColName EQ "" then
// This control is bound to an actual symbolic (calculated) column. Use the CALCULATE event to update it.
Send_Event(SymCtrl, "CALCULATE", SymCtrlEdtCol)
end else
// This control is virtually bound to a symboic (calculated) column. Use the CALCULATE function to compute its
// value and update the control's display directly.
SymResult = Calculate(SymCtrlColName)
If SymCtrlOrigText _EQC "SRP.EditTable.1" then
// OLE EditTable controls need to have enough empty rows to display the data being added. Compute the
// number of additional rows and use the Dimension property to create them.
If WholeRecord EQ Yes$ then
Locate SymCtrl in UpdatedOLEEditTables using @FM setting Dummy else
// This OLE EditTable might have information from a previous record. Therefore, clear the OLE
// EditTable just in case but track the control so it won't get cleared if other columns are updated
If DictColPos _NEC "SYM" then
// If the control with focus is the control being updated then don't call the Clear method.
// First, the changes that are being made in this control will be cleared. Second, if the
// current cell is a Combobox type this will crash OpenInsight.
If SymCtrlRowsAsColumns OR SymCtrlCellsAsFields then
// Clear data but maintain the original rows
Send_Message(SymCtrl, "OLE.Clear", 2)
end else
// Clear data and rows
Send_Message(SymCtrl, "OLE.Clear", 0)
end
end
UpdatedOLEEditTables<-1> = SymCtrl ; // Track this OLE EditTable so the Clear method won't be executed again.
end
end
Dimension = Get_Property(SymCtrl, "OLE.Dimension")
CurrNumColumns = Dimension[1, @FM]
CurrNumRows = Dimension[Col2() + 1, @FM]
Begin Case
Case SymCtrlRowsAsColumns EQ Yes$
// Data in the SRP EditTable is being stored in a LIST format where rows are associated with field
// data.
NeededColumns = Count(SymResult, @VM) + (SymResult NE "")
If NeededColumns GT CurrNumColumns then
CurrNumColumns = NeededColumns
Set_Property(SymCtrl, "OLE.Dimension", CurrNumColumns)
end
Conv = Get_Property(SymCtrl, "OLE.CellConv[1;":SymCtrlEdtCol:"]")<2>
If Conv NE "" then SymResult = Oconv(SymResult, Conv)
Set_Property(SymCtrl, "OLE.RecordData[":SymCtrlEdtCol:"]", SymResult)
Case SymCtrlCellsAsFields EQ Yes$
// Each cell within he SRP EditTable is associated with a specific field data.
NeededColumns = Trim(SymCtrlSelPos[1, ";"])
NeededRows = Trim(SymCtrlSelPos[Col2() + 1, ";"])
If (NeededColumns GT CurrNumColumns) OR (NeededRows GT CurrNumRows) then
If NeededColumns GT CurrNumColumns then CurrNumColumns = NeededColumns
If NeededRows GT CurrNumRows then CurrNumRows = NeededRows
Set_Property(SymCtrl, "OLE.Dimension", CurrNumColumns:@FM:CurrNumRows)
end
Conv = Get_Property(SymCtrl, "OLE.CellConv[":SymCtrlSelPos:"]")<2>
If Conv NE "" then SymResult = Oconv(SymResult, Conv)
Set_Property(SymCtrl, "OLE.CellText[":SymCtrlSelPos:"]", SymResult)
Case Otherwise$
// Data in the SRP EditTable is being stored in the traditional ARRAY format where columns are
// associated with field data.
NeededRows = Count(SymResult, @VM) + (SymResult NE "")
If NeededRows GT CurrNumRows then
DCurrNumRows = NeededRows
Set_Property(SymCtrl, "OLE.Dimension", @FM:CurrNumRows)
end
Conv = Get_Property(SymCtrl, "OLE.CellConv[":SymCtrlEdtCol:";1]")<2>
If Conv NE "" then SymResult = Oconv(SymResult, Conv)
Set_Property(SymCtrl, "OLE.ColumnData[":SymCtrlEdtCol:"]", SymResult)
End Case
end else
// Data is being updated in a standard OpenInsight control. Use the INVALUE property to make sure the data
// is being converted correctly.
Set_Property(SymCtrl, "INVALUE", SymResult, SymCtrlEdtCol)
end
end
return
Add_Native_Control_Information:
MRIndex = RowMap<1, 1, 4>
Control = SRP_FastArray_Extract(MasterRowMap, MRIndex, 1, 0)
EdtCol = SRP_FastArray_Extract(MasterRowMap, MRIndex, 2, 0)
CtrlType = SRP_FastArray_Extract(MasterRowMap, MRIndex, 3, 0)
If CtrlType NE "OLECONTROL" then
// Only native OpenInsight controls apply here.
If CtrlType EQ "EDITTABLE" then
// EditTable controls need to have enough empty rows to display the data being added. Compute the number of
// additional rows and use the INSERT method to create them.
Invalue = Get_Property(Control, "INVALUE")
CurrNumRows = Count(Invalue<1>, @VM) + (Invalue<1> NE "")
NeededRows = Count(FieldData, @VM) + (FieldData NE "")
For i = CurrNumRows to NeededRows
Send_Message(Control, "INSERT", -1, "")
Next i
end
Controls := @RM : Control
Properties := @RM : "INVALUE"
Values := @RM : FieldData
EdtCols := @RM : EdtCol
end
return
Add_OI_Control_Information:
TempOICtrlColPos = SRP_FastArray_GetVariable(OICtrlColPos)
Match = Yes$
Loop
Locate DictColPos in TempOICtrlColPos using @FM setting fPos then
Control = SRP_FastArray_Extract(OICtrls, fPos, 0, 0)
CtrlType = SRP_FastArray_Extract(OICtrlTypes, fPos, 0, 0)
If CtrlType EQ "EDITTABLE" then
// EditTable controls need to have enough empty rows to display the data being added. Compute the number
// of additional rows and use the INSERT method to create them.
Invalue = Get_Property(Control, "INVALUE")
CurrNumRows = Count(Invalue<1>, @VM) + (Invalue<1> NE "")
NeededRows = Count(FieldData, @VM) + (FieldData NE "")
For i = CurrNumRows to NeededRows
Send_Message(Control, "INSERT", -1, "")
Next i
end
Controls := @RM : Control
Properties := @RM : "INVALUE"
Values := @RM : FieldData
EdtCol = SRP_FastArray_Extract(OICtrlEdtCol, fPos, 0, 0)
EdtCols := @RM : EdtCol
TempOICtrlColPos<fPos> = ""
end else
Match = No$
end
Until Not(Match)
Repeat
return
Add_UDP_Control_Information:
TempUDPCtrlColPos = SRP_FastArray_GetVariable(UDPCtrlColPos)
Match = Yes$
Loop
Locate DictColPos in TempUDPCtrlColPos using @FM setting fPos then
Control = SRP_FastArray_Extract(UDPCtrls, fPos, 0, 0)
RowsAsColumns = SRP_FastArray_Extract(UDPCtrlRowsAsColumnsList, fPos, 0, 0)
CellsAsFields = SRP_FastArray_Extract(UDPCtrlCellsAsFieldsList, fPos, 0, 0)
SelPos = SRP_FastArray_Extract(UDPCtrlSelPosList, fPos, 0, 0)
OrigText = SRP_FastArray_Extract(UDPCtrlOrigText, fPos, 0, 0)
// If DictColPos is not a number then this is a symbolic that needs to be calculated
If Not(Num(DictColPos)) then FieldData = Calculate(DictColPos)
Controls := @RM : Control
Begin Case
Case OrigText _EQC "SRP.EditTable.1"
// OLE EditTable controls need to have enough empty rows to display the data being added. Compute
// the number of additional rows and use the Dimension property to create them.
If WholeRecord EQ Yes$ then
Locate Control in UpdatedOLEEditTables using @FM setting Dummy else
// This OLE EditTable might have information from a previous record. Therefore, clear the
// OLE EditTable just in case but track the control so it won't get cleared if other columns
// are updated.
If Control NE FocusControl then
// If the control with focus is the control being updated then don't call the Clear
// method. First, the changes that are being made in this control will be cleared.
// Second, if the current cell is a Combobox type this will crash OpenInsight.
ClearFill = Get_Property(Control, "@CLEARFILL")
*If RowsAsColumns OR CellsAsFields then
Begin Case
Case ClearFill
// Clear using fill value defined for EditTable
Send_Message(Control, "OLE.Clear", ClearFill)
Case RowsAsColumns OR CellsAsFields
// Clear data but maintain the original rows
Send_Message(Control, "OLE.Clear", 2)
Case Otherwise$
// Clear data and rows
Send_Message(Control, "OLE.Clear", 0)
End Case
end
UpdatedOLEEditTables<-1> = Control ; // Track this OLE EditTable so the Clear method won't be executed again.
end
end
Dimension = Get_Property(Control, "OLE.Dimension")
CurrNumColumns = Dimension<1>
CurrNumRows = Dimension<2>
Begin Case
Case RowsAsColumns EQ Yes$
// Data in the SRP EditTable is being stored in a LIST format where rows are associated with
// field data.
NeededColumns = Count(FieldData, @VM) + (FieldData NE "")
If NeededColumns GT CurrNumColumns then
Dimension<1> = NeededColumns
Set_Property(Control, "OLE.Dimension", Dimension)
end
EdtCol = SRP_FastArray_Extract(UDPCtrlEdtCol, fPos, 0, 0)
Properties := @RM : "OLE.RecordData[":EdtCol:"]"
CellConv = Get_Property(Control, "OLE.CellConv[1;":EdtCol:"]")
Case CellsAsFields EQ Yes$
// Each cell within he SRP EditTable is associated with a specific field data.
NeededColumns = Trim(Field(SelPos, ";", 1))
NeededRows = Trim(Field(SelPos, ";", 2))
If (NeededColumns GT CurrNumColumns) OR (NeededRows GT CurrNumRows) then
If NeededColumns GT CurrNumColumns then Dimension<1> = NeededColumns
If NeededRows GT CurrNumRows then Dimension<2> = NeededRows
Set_Property(Control, "OLE.Dimension", Dimension)
end
Properties := @RM : "OLE.CellText[":SelPos:"]"
CellConv = Get_Property(Control, "OLE.CellConv[":SelPos:"]")
Case Otherwise$
// Data in the SRP EditTable is being stored in the traditional ARRAY format where columns
// are associated with field data.
NeededRows = Count(FieldData, @VM) + (FieldData NE "")
If NeededRows GT CurrNumRows then
Dimension<2> = NeededRows
Set_Property(Control, "OLE.Dimension", Dimension)
end
EdtCol = SRP_FastArray_Extract(UDPCtrlEdtCol, fPos, 0, 0)
Properties := @RM : "OLE.ColumnData[":EdtCol:"]"
CellConv = Get_Property(Control, "OLE.CellConv[":EdtCol:";1]")
End Case
Conv = CellConv<2>
If Conv NE "" then FieldData = Oconv(FieldData, Conv)
Values := @RM : FieldData
EdtCols := @RM : ""
Case Otherwise$
Properties := @RM : "INVALUE"
Values := @RM : FieldData
EdtCols := @RM : ""
End Case
TempUDPCtrlColPos<fPos> = ""
end else
Match = No$
end
Until Not(Match)
Repeat
return
Restore_At_Variables:
Record = @RECORD ; // Copy @RECORD before it gets restored (if necessary) so it can be returned.
If Window NE @Window then
// Restore the original values of @ variables in case a different window other than @Window is being updated.
Transfer OrigID to @ID
Transfer OrigRecord to @RECORD
Transfer OrigDict to @DICT
end
return
ParseDictColPos:
// Determine if the data needs to update a value, subvalue, text, or subtext part of a field.
DelimDepth = 0
Loop
DelimDepth += 1
Pos = Field(DictColPos, ",", DelimDepth)
Until Not(Num(Pos)) OR Pos EQ "" OR DelimDepth EQ 6
Begin Case
Case DelimDepth EQ 1 ; Transfer Pos to FieldPos
Case DelimDepth EQ 2 ; Transfer Pos to ValPos
Case DelimDepth EQ 3 ; Transfer Pos to SubValPos
Case DelimDepth EQ 4 ; Transfer Pos to TextPos
Case DelimDepth EQ 5 ; Transfer Pos to SubTextPos
End Case
Repeat
DictColPos = FieldPos
DelimDepth -= 1
return
Update_Data_Array:
// Drill into the data field as much as necessary and update with the data being passed in. The entire data field
// will then be put into each control that is bound to this database column.
DataArray = ""
DataArray<1> = @RECORD<FieldPos>
DataArray<2> = Field(DataArray<1>, @VM, ValPos)
If DelimDepth GT 2 then
DataArray<3> = Field(DataArray<2>, @SVM, SubValPos)
If DelimDepth GT 3 then
DataArray<4> = Field(DataArray<3>, @TM, TextPos)
If DelimDepth GT 4 then
Data = FieldStore(DataArray<4>, @STM, SubTextPos, 1, Data)
end
Data = FieldStore(DataArray<3>, @TM, TextPos, 1, Data)
end
Data = FieldStore(DataArray<2>, @SVM, SubValPos, 1, Data)
end
Data = FieldStore(DataArray<1>, @VM, ValPos, 1, Data)
return