unit ObjectInspector;

interface

Uses
 ExtCtrls,
 StdCtrls,
 buttons,
 Classes,
 engine,
 CM2EditorSupportInterface,
 CM2GenPlugTypes,
 CM2VisPlugtypes,
 SysUtils,
 CM2PlugInTypes,
 filter,
 xmldom, XMLIntf, XMLDoc, msxmldom;

type
 TVisPlugEditorSupport = Record
  Name: String;
  Value: String;
  Description: String;
  Required: Boolean;
  ValueType: byte;
  ValueRange: String;
  CanContainSensor: boolean;
 End;
 TVisPlugEditorSupportList = class(TObject)
 private
  fList: Array of TVisPlugEditorSupport;
  fInterfaceVersion: byte;
  fName: String;
  fVersion: Word;
  function GETCOUNT: Cardinal;
  function GETINFO(Index: Integer): TVisPlugEditorSupport;
 public
  Procedure BuildFromPlugIn(PlugIn: TVisPlugIn);
  Procedure Add(fName, fValue, fDescription: String; fRequired: Boolean; fValueType: Byte; fValueRange: String; fCanContainSensor: Boolean);
  Procedure ChangeValue(aName, NewValue: String);
  Property Name: String read fName;
  Property Version: Word read fVersion;
  Property InterfaceVersion: byte read fInterfaceVersion;
  Property Count: Cardinal read GETCOUNT;
  Property VisPlugEditorInfo[Index: Integer]: TVisPlugEditorSupport read GETINFO; default;
  Function GetVisPlugEditorInfoByName(N: String): TVisPlugEditorSupport;
 end;
 TVisEditorSupportList = Class(Tobject)
 private
  fList: Array of TVisPlugEditorSupportList;
  function GETCOUNT: Cardinal;
  function GETINFOLIST(Index: Integer): TVisPlugEditorSupportList;
 public
  Procedure Add(VP: TVisPlugIn);
  Property Count: Cardinal read GETCOUNT;
  Property VisPlugEditorSupportList[Index: Integer]: TVisPlugEditorSupportList read GETINFOLIST; default;
  Procedure BuildFromPlugInList(VPL: TVisPlugInList);
  Function GetIndexByName(Name: String): Integer;
  Procedure SaveToFile(Filename: String);
  Procedure LoadFromFile(Filename: String);
 end;

 TSensorParamEditorSupport = TVisPlugEditorSupport;
 TSensorParamEditorSupportList = class(TObject)
 private
  fList: array of TSensorParamEditorSupport;
  fSensorName: String;
  fSensorIndex: Integer;
  function GETCOUNT: Cardinal;
  function GETSPES(Index: Integer): TSensorParamEditorSupport;
 public
  Property Count: Cardinal read GETCOUNT;
  Property SensorName: String read fSensorName;
  Property SensorIndex: Integer read fSensorIndex;
  Property SensorParamEditorSupport[Index: Integer]: TSensorParamEditorSupport read GETSPES; default;
  Procedure Build(PlugIn: TGenPlugIn; ExInfoList: TExInfoList; SenName: String; SenIndex: Integer);
  Function GetSensorParamEditorSupportByName(N: String): TSensorParamEditorSupport;
  Procedure ChangeValue(aName, NewValue: String);
 end;
 TGenPlugEditorsupportList = Class(TObject)
 private
  fList: Array of TSensorParamEditorSupportList;
  fName: String;
  fVersion: Word;
  function GETCOUNT: Cardinal;
  function GETSPESL(Index: Integer): TSensorParamEditorSupportList;
 public
  Property Count: Cardinal read GETCOUNT;
  Property Name: String read fName;
  Property Version: Word read fVersion;
  Property SensorParamEditorSupportList[Index: Integer]: TSensorParamEditorSupportList read GETSPESL; default;
  Procedure BuildFromPlugIn(PlugIn: TGenPlugIn);
 end;
 TGenEditorSupportList = Class(Tobject)
 private
  fList: Array of TGenPlugEditorSupportList;
  function GETCOUNT: Cardinal;
  function GETGPlugESL(Index: Integer): TGenPlugEditorSupportList;
 public
  Property Count: Cardinal read GETCOUNT;
  Procedure Add(GP: TGenPlugIn);
  Property GenPlugEditorSupportList[Index: Integer]: TGenPlugEditorSupportList read GETGPlugESL; default;
  Procedure BuildFromPlugInList(GPL: TGENPlugInList);
  Function GetIndexByName(Name: String; Var PlugInIndex, SensorIndex: Integer): Boolean;
  Procedure SaveToFile(Filename: String);
  Procedure LoadFromFile(Filename: String);
 end;
 TOIItem = record
  Name: String;
  Value: String;
  Node: array of TEdRawNode;
  EditorSupport: TVisPlugEditorSupport;
 end;
 TOIItemList = Class(Tobject)
 private
  fList: Array of TOIITem;
  fName: String;
  function GETCOUNT: Cardinal;
  function GETOIITEM(Index: Integer): TOIItem;
  procedure SETOIITEM(Index: Integer; const Value: TOIItem);
 public
  Property Count: Cardinal read GETCOUNT;
  Property OIItem[Index: Integer]: TOIItem read GETOIITEM write SETOIITEM; default;
  Property Name: String read fName;
  Procedure LoadNode(Node: TEdRawNode);
  Procedure LoadNodes(Nodes: TEdRawNodes);
  Procedure LoadVisualNode(Node: TEdVisualNode);
  Procedure LoadFormNode(Node: TEdFormNode);
  Procedure LoadSensorNode(Node: TEdSensorNode);
  Procedure LoadTextNode(Node: TEdTextNode);
  Function Find(Name: String): TOIItem;
  Procedure Clear;
 end;
 TFormEditorSupport = TVisPlugEditorSupport;
 TFormEditorSupportList = class(Tobject)
 private
  fList: Array of TFormEditorSupport;
  function GETCOUNT: Cardinal;
    function GETFES(Index: Integer): TFormEditorSupport;
 public
  Constructor Create;
  Property Count: Cardinal read GETCOUNT;
  Property FormEditorSupport[Index: Integer]: TFormEditorSupport read GETFES; default;
  Function GetFormEditorInfoByName(N: String): TFormEditorSupport;
  Procedure ChangeValue(aName, NewValue: String);
  Procedure SaveToFile(Filename: String);
  Procedure LoadFromFile(Filename: String);
  Function GetValue(Name: String): String;
 end;
 TOIContent = Record
  Node: TEdRawNode;
 end;
 TOIContentList = Class(TObject)
 private
  fList: array of TOIContent;
  function GETCOUNT: Cardinal;
  function GETCONTENT(Index: Integer): TOIContent;
 public
  Property Count: Cardinal read GETCOUNT;
  Property Content[Index: Integer]: TOIContent read GETCONTENT; default;
  Procedure BuildFromTag(Node: TEdRawNode);
  Procedure Clear;
 end;
 TOIEvent = Record
  Trigger: String;
  Mods: String;
  Command: String;
  Node: TEdRawNode;
 end;
 TOIEventList = Class(TObject)
 private
  fList: Array of TOIEvent;
    function GETCOUNT: Integer;
    function GETEVENT(Index: Integer): TOIEvent;
 public
  Property Count: Integer read GETCOUNT;
  Property Event[Index: Integer]: TOIEvent read GETEVENT; default;
  Procedure Clear;
  Procedure BuildFromTag(Node: TEdEventsNode);
 end;

implementation


Uses
 Main, Dialogs, forms;

{ TVisPlugEditorSupportList }

procedure TVisPlugEditorSupportList.Add(fName, fValue,
  fDescription: String; fRequired: Boolean; fValueType: Byte;
  fValueRange: String; fCanContainSensor: Boolean);
begin
 SetLength(fList, Length(fList) + 1);
 fList[Length(fList)-1].Name := fName;
 fList[Length(fList)-1].Value := fValue;
 fList[Length(fList)-1].Description := fDescription;
 fList[Length(fList)-1].Required := fRequired;
 fList[Length(fList)-1].ValueType := fValueType;
 fList[Length(fList)-1].ValueRange := fValueRange;
 fList[Length(fList)-1].CanContainSensor := fCanContainSensor;
end;

procedure TVisPlugEditorSupportList.BuildFromPlugIn(
  PlugIn: TVisPlugIn);
Var
 I: Integer;
 VisEx: TVisExList;
 ESV: TEditorSupportVIS;
 EsVis: TEsVis;
begin
 fInterfaceVersion := Plugin.InterfaceVersion;
 fName := Plugin.Name;
 fVersion := PlugIn.Version;
 Case InterfaceVersion of
  1: VisEx := TVisExList.Create(PlugIn.Plugin);
  2: VisEx := TVisExList.Create(PlugIn.PlugIn2);
  3: VisEx := TVisExList.Create(PlugIn.PlugIn3);
  4: VisEx := TVisExList.Create(PlugIn.PlugIn4);
 end;
 For I := 0 to VisEx.Count - 1 do begin
  SetLength(fList, Length(fList) + 1);
  fList[Length(fList)-1].Name := VisEx[I].Name;
  fList[Length(fList)-1].Value := VisEx[I].Value;
  fList[Length(fList)-1].Description := VisEx[I].Description;
  fList[Length(fList)-1].Required := VisEx[I].EIT = eitRequired;
  fList[Length(fList)-1].CanContainSensor := true;
 end;
 FreeAndNil(VisEx);
 ESV := TEditorsupportVIS.Create;
 ESV.LoadFrom(PlugIn);
 If Not ESV.SupportsEditor then begin
  FreeAndNil(ESV);
  exit;
 end;
 For I := 0 to Count - 1 do begin
  EsVis := ESV.GetByName(fList[I].Name);
  fList[I].ValueType := EsVis.ValueType;
  fList[I].ValueRange := EsVis.ValueRange;
 end;
 FreeAndNil(ESV);
end;

procedure TVisPlugEditorSupportList.ChangeValue(aName, NewValue: String);
Var
 I: Integer;
begin
 For I := 0 to count - 1 do begin
  If uppercase(aName) = uppercase(fList[I].Name) then begin
   fList[I].Value := NewValue;
   exit;
  end;
 end;
end;

function TVisPlugEditorSupportList.GETCOUNT: Cardinal;
begin
 Result := Length(fList);
end;

function TVisPlugEditorSupportList.GETINFO(
  Index: Integer): TVisPlugEditorSupport;
begin
 Result := fList[Index];
end;

function TVisPlugEditorSupportList.GetVisPlugEditorInfoByName(
  N: String): TVisPlugEditorSupport;
Var
 I: Integer;
begin
 Result.Required := false;
 Result.ValueType := vtUnknown;
 Result.Description := '';
 Result.CanContainSensor := true;
 Result.Value := '';
 For I := 0 to count - 1 do begin
  If fList[I].Name = N then begin
   Result := fList[I];
   exit;
  end;
 end;
end;

{ TVisEditorSupportList }

procedure TVisEditorSupportList.Add(VP: TVisPlugIn);
begin
 SetLength(fList, Length(fList) + 1);
 fList[Length(fList)-1] := TVisPlugEditorSupportList.Create;
 fList[Length(fList)-1].BuildFromPlugIn(VP);
end;

procedure TVisEditorSupportList.BuildFromPlugInList(
  VPL: TVisPlugInList);
Var
 I: Integer;
begin
 For I := 0 to VPL.Count - 1 do begin
  Add(VPL[I]);
 end;
end;

function TVisEditorSupportList.GETCOUNT: Cardinal;
begin
 Result := Length(fList);
end;

function TVisEditorSupportList.GetIndexByName(Name: String): Integer;
Var
 I: Integer;
begin
 Result := -1;
 For I := 0 to count - 1 do begin
  If fList[I].Name = Name then begin
   Result := I;
   break;
  end;
 end;
end;

function TVisEditorSupportList.GETINFOLIST(
  Index: Integer): TVisPlugEditorSupportList;
begin
 Result := fList[Index];
end;

{ TGenSensorParamEditorSupportList }

procedure TSensorParamEditorSupportList.Build(PlugIn: TGenPlugIn; ExInfoList: TExInfoList;
  SenName: String; SenIndex: Integer);
Var
 I: Integer;
 ESG: TEditorSupportGEN;
 EsGen: TEsGen;
begin
 fSensorName := SenName;
 fSensorIndex := SenIndex;
 For I := 0 to ExInfoList.Count - 1 do begin
  SetLength(fList, Length(fList) + 1);
  fList[Length(fList)-1].Name := ExInfoList[I].Name;
  fList[Length(fList)-1].Value := ExInfoList[I].Value;
  fList[Length(fList)-1].Description := ExInfoList[I].Description;
  fList[Length(fList)-1].Required := ExInfoList[I].EIT = eitRequired;
  fList[Length(fList)-1].CanContainSensor := true;
 end;
 ESG := TEditorsupportGen.Create;
 ESG.LoadFrom(PlugIn, SenIndex);
 If Not ESG.SupportsEditor then begin
  FreeAndNil(ESG);
  exit;
 end;
 For I := 0 to Count - 1 do begin
  EsGen := ESG.GetByName(fList[I].Name);
  fList[I].ValueType := EsGen.ValueType;
  fList[I].ValueRange := EsGen.ValueRange;
 end;
 FreeAndNil(ESG);
end;

procedure TSensorParamEditorSupportList.ChangeValue(aName,
  NewValue: String);
Var
 I: Integer;
begin
 For I := 0 to Count - 1 do begin
  If uppercase(SensorParamEditorSupport[I].Name) = uppercase(aName) then begin
   fList[I].Value := NewValue;
   exit;
  end;
 end;
end;

function TSensorParamEditorSupportList.GETCOUNT: Cardinal;
begin
 Result := length(fList);
end;

function TSensorParamEditorSupportList.GetSensorParamEditorSupportByName(
  N: String): TSensorParamEditorSupport;
Var
 I: Integer;
begin
 Result.Required := false;
 Result.ValueType := vtUnknown;
 Result.Description := '';
 Result.Value := '';
 Result.CanContainSensor := true;
 For I := 0 to count - 1 do begin
  If uppercase(fList[I].Name) = uppercase(N) then begin
   Result := fList[I];
   break;
  end;
 end;
end;

function TSensorParamEditorSupportList.GETSPES(
  Index: Integer): TSensorParamEditorSupport;
begin
 Result := fList[Index];
end;

procedure TVisEditorSupportList.LoadFromFile(Filename: String);
Var
 XML: TXMLDocument;
 DummyForm: TForm;
 Root: IXMLNode;
 Plugin: IXMLNode;
 Sel, I, II: Integer;
 N, V: String;
begin
 If not fileexists(filename) then exit;
 DummyForm := Tform.Create(nil);
 DummyForm.Visible := false;
 XML := TXMLDocument.Create(Dummyform);
 XML.LoadFromFile(filename);
 XML.Active := true;

 Root := XML.ChildNodes.FindNode('DVVisual');
 If Root <> nil then begin
  For I := 0 to root.ChildNodes.Count - 1 do begin
   If uppercase(root.ChildNodes[I].NodeName) = 'PLUGIN' then begin
    Plugin := root.ChildNodes[I];
    Sel := GetIndexByName(PlugIn.Attributes['name']);
    If Sel > -1 then begin
     For II := 0 to plugin.ChildNodes.Count - 1 do begin
      If uppercase(Plugin.Childnodes[II].NodeName) = 'PARAMETER' then begin
       N := PlugIn.ChildNodes[II].Attributes['name'];
       V := PlugIn.ChildNodes[II].Attributes['value'];
       fList[Sel].ChangeValue(N, V);
      end;
     end;
    end;
   end;
  end;
 end;
 FreeAndNil(XML);
 FreeAndNil(DummyForm);
end;

procedure TVisEditorSupportList.SaveToFile(Filename: String);
Var
 I, II: Integer;
 List: TStringList;
begin
 List := TStringList.Create;
 List.Add('<DVVisual>');
 For I := 0 to Length(fList) - 1 do begin
  List.Add(' <plugin name="' + fList[I].Name + '">');
  For II := 0 to length(fList[I].fList) - 1 do begin
   If fList[I][II].Value <> '' then begin
    List.Add('  <parameter name="' + fList[I].fList[II].Name + '" value="' + fList[I].fList[II].Value + '"/>');
   end;
  end;
  If List[List.count-1] =  ' <plugin name="' + fList[I].Name + '">' then begin
   List.Delete(List.count-1);
  end
   else
  begin
   List.Add(' </plugin>');
  end;
 end;
 List.Add('</DVVisual>');
 List.SaveToFile(filename);
 FreeAndNil(List);
end;

{ TGenPlugEditorsupportList }

procedure TGenPlugEditorsupportList.BuildFromPlugIn(PlugIn: TGenPlugIn);
Var
 I: Integer;
 GenEx: TGenExList;
 SName: String;
begin
 fName := PlugIn.Name;
 fVersion := PlugIn.Version;
 GenEx := TGenExList.Create(Plugin.PlugIn);
 For I := 0 to GenEx.Count - 1 do begin
  SetLength(fList, length(fList) + 1);
  fList[Length(fList)-1] := TSensorParamEditorsupportList.Create;
  SName := PlugIn.SensorList[I].Name;
  fList[Length(fList)-1].Build(Plugin, GenEx[I], SName, I);
 end;
 FreeAndNil(GenEx);
end;

function TGenPlugEditorsupportList.GETCOUNT: Cardinal;
begin
 Result := length(fList);
end;

function TGenPlugEditorsupportList.GETSPESL(
  Index: Integer): TSensorParamEditorSupportList;
begin
 Result := fList[Index];
end;

{ TGenEditorSupportList }

procedure TGenEditorSupportList.Add(GP: TGenPlugIn);
begin
 SetLength(fList, Length(fList) + 1);
 fList[Length(fList)-1] := TGenPlugEditorSupportList.Create;
 fList[Length(fList)-1].BuildFromPlugIn(GP);
end;

procedure TGenEditorSupportList.BuildFromPlugInList(GPL: TGENPlugInList);
Var
 I: Integer;
begin
 For I := 0 to GPL.Count - 1 do begin
  Add(GPL[I]);
 end;
end;

function TGenEditorSupportList.GETCOUNT: Cardinal;
begin
 Result := length(fList);
end;

function TGenEditorSupportList.GETGPlugESL(
  Index: Integer): TGenPlugEditorSupportList;
begin
 Result := fList[Index];
end;

{ TObjectInspectorItemList }

procedure TOIItemList.Clear;
begin
 SetLength(fList, 0);
end;

function TOIItemList.Find(Name: String): TOIItem;
Var
 I: Integer;
begin
 Result.Name := '';
 Result.Value := '';
 Result.Node := nil;
 Result.EditorSupport.Name := '';
 Result.EditorSupport.Value := '';
 Result.EditorSupport.Description := '';
 Result.EditorSupport.Required := false;
 Result.EditorSupport.ValueType := vtUnknown;
 Result.EditorSupport.ValueRange := '';
 Result.EditorSupport.CanContainSensor := false;
 For I := 0 to count - 1 do begin
  If uppercase(fList[I].Name) = uppercase(Name) then begin
   Result := fList[I];
   exit;
  end;
 end;
end;

function TOIItemList.GETCOUNT: Cardinal;
begin
 Result := Length(fList);
end;

function TOIItemList.GETOIITEM(Index: Integer): TOIItem;
begin
 Result := fList[Index];
end;

procedure TOIItemList.LoadFormNode(Node: TEdFormNode);
Var
 I: Integer;
 ParamBlockNode: TEdParameterBlockNode;
 PNode: TEdParameterNode;
begin
 fName := Node.Name;
 ParamBlockNode := Node.GetParameterBlockNode;
 // Start by adding "NAME" to the list, it's not a parameter, but an attribute and therefore needs to be
 // treated differently in order to work correctly
 SetLength(fList, Length(fList) + 1);
 SetLength(fList[Length(fList)-1].Node, 1);
 fList[Length(fList)-1].Name := 'Name';
 fList[Length(fList)-1].Value := Node.FormName;
 fList[Length(fList)-1].Node[0] := Node;
 fList[Length(fList)-1].EditorSupport := oeMain.FESL.GetFormEditorInfoByName('Name');
 fList[Length(fList)-1].EditorSupport.CanContainSensor := false;
 For I := 0 to ParamBlockNode.Count - 1 do begin
  If ParamBlockNode.Node[I].NodeType = ntParameter then begin
   SetLength(fList, Length(fList) + 1);
   SetLength(fList[Length(fList)-1].Node, 1);
   PNode := (ParamBlockNode.Node[I] as TEdParameterNode);
   fList[Length(fList)-1].Name := PNode.Name;
   If PNode.Count = 0 then begin
    fList[Length(fList)-1].Value := PNode.Value;
    fList[Length(fList)-1].Node[0] := PNode;
    fList[Length(fList)-1].EditorSupport := oeMain.FESL.GetFormEditorInfoByName(PNode.Name);
   end
    else
   begin
    fList[Length(fList)-1].Node[0] := PNode.Node[0];
    fList[Length(fList)-1].Value := '[sensor]';
    fList[Length(fList)-1].EditorSupport.CanContainSensor := true;
   end;
  end;
 end;
end;

procedure TOIItemList.LoadNode(Node: TEdRawNode);
begin
 fName := '';
 Clear;
 If Node = nil then Exit;
 Case Node.NodeType of
  ntVisual: LoadVisualNode(Node as TEdVisualNode);
  ntForm: LoadFormNode(Node as TEdFormNode);
  ntSensor: LoadSensorNode(Node as TEdSensorNode);
  Engine.ntText: LoadTextNode(Node as TEdTextNode);
 end;
end;

procedure TOIItemList.LoadNodes(Nodes: TEdRawNodes);
Var
 Sel, At, I, II: Integer;
 S, PS: String;
 List: TStringList;
 ParamBlockNode: TEdParameterBlockNode;
 ParamNode: TEdParameterNode;
// PNodes: Array of TEdParameterNode;
Begin
 If length(Nodes) = 0 then exit;
 // Get list of parameters for the first selected node
 Case Nodes[0].NodeType of
  ntForm: Begin
           PS := (Nodes[0] as TEdFormNode).GetParameterBlockNode.ResolveParameters;
          end;
  ntVisual: begin
             PS := (Nodes[0] as TEdVisualNode).GetParameterBlockNode.ResolveParameters;
            end;
 end;
 // Convert from string to a list
 List := TStringList.Create;
 For I := 1 to CountFilt(PS, '|') do begin
  S := GetFilt(PS, I, '|');
  S := GetFilt(S, 1, '=');
  List.Add(S);
 end;
 // Scan all selected nodes for repeat parameters
 At := 0;
 while At < List.count do begin
  PS := List[At];
  // we don't need to check against itself therefore we run from 1 instead of 0
  For I := 1 to length(Nodes) - 1 do begin
   Case Nodes[I].NodeType of
    ntForm: begin
             If (Nodes[I] as TEdFormNode).GetParameterBlockNode.GetParameterNode(PS) = nil then begin
              List.Delete(At);
              Dec(at);
              Break;
             end
            end;
    ntVisual: begin
               If (Nodes[I] as TEdVisualNode).GetParameterBlockNode.GetParameterNode(PS) = nil then begin
                List.Delete(At);
                Dec(at);
                break;
               end;
              end;
     else
              begin
               MessageDlg('Location: TOIItemList.LoadNodes'+#13+#10+'Unknown Node has been selected for multiple selection.', mtError, [mbOK], 0);
               exit;
              end;
   end;
  end;
  Inc(At);
 end;
 SetLength(fList, List.Count);
 Case Nodes[0].NodeType of
  ntForm: begin
           ParamBlockNode := (Nodes[0] as TEdFormNode).GetParameterBlockNode;
           For I := 0 to List.Count - 1 do begin
             SetLength(fList[I].Node, Length(Nodes));
             ParamNode := ParamBlockNode.GetParameterNode(list[I]);
             If ParamNode.NodeType = ntParameter then begin
               If ParamNode.Count = 0 then begin
                 fList[I].Name := ParamNode.Name;
                 fList[I].Value := ParamNode.Value;
                 fList[I].Node[0] := ParamNode;
                 fList[I].EditorSupport := oeMain.FESL.GetFormEditorInfoByName(ParamNode.Name);
               end
             end;
           end;
          end;
  ntVisual: Begin
             Sel := oeMain.VESL.GetIndexByName((Nodes[0] as TEdVisualNode).VisualName);
             ParamBlockNode := (Nodes[0] as TEdVisualNode).GetParameterBlockNode;
             For I := 0 to List.count - 1 do begin
              SetLength(fList[I].Node, Length(Nodes));
              ParamNode := ParamBlockNode.GetParameterNode(List[I]);
              If ParamNode.NodeType = ntParameter then begin
               If ParamNode.Count = 0 then begin
                fList[I].Name := ParamNode.Name;
                fList[I].Value := ParamNode.Value;
                fList[I].Node[0] := ParamNode;
                fList[I].EditorSupport := oeMain.VESL[Sel].GetVisPlugEditorInfoByName(ParamNode.Name)
               end;
              end;
             end;
            end;
 end;
 For II := 0 to list.count - 1 do begin
  fList[II].EditorSupport.CanContainSensor := false;
  For I := 1 to length(Nodes) - 1 do begin
   ParamNode := nil;
   Case Nodes[I].NodeType of
    ntForm: begin
             ParamNode := (Nodes[I] as TEdFormNode).GetParameterBlockNode.GetParameterNode(List[II]);
            end;
    ntVisual: Begin
               ParamNode := (Nodes[I] as TEdVisualNode).GetParameterBlockNode.GetParameterNode(List[II]);
              end;
   end;
   fList[II].Node[I] := ParamNode;
  end;
 end;
 fName := 'Multiple Objects Selected';
End;

procedure TOIItemList.LoadSensorNode(Node: TEdSensorNode);
Var
 I: Integer;
 ParamBlockNode: TEdParameterBlockNode;
 PNode: TEdParameterNode;
 PlugIndex, SensIndex: Integer;
 S: String;
begin
 Self.fName := Node.PlugInName + '.' + Node.SensorName;
 If not oeMain.GESL.GetIndexByName(fName, PlugIndex, SensIndex) then begin
  MessageDlg('Unable to locate plugin name in the Editor Support list'+#13+#10+'Location: TOIItemList.LoadSensorNode', mtError, [mbOK], 0);
  exit;
 end;
 SetLength(fList, Length(fList) + 1);
 SetLength(fList[Length(fList)-1].Node, 1);
 fList[Length(fList)-1].Name := 'Update';
 fList[Length(fList)-1].Value := Node.UpdateStr;
 fList[Length(fList)-1].Node[0] := Node;
 fList[Length(fList)-1].EditorSupport.Name := 'Update';
 fList[Length(fList)-1].EditorSupport.Value := '1';
 fList[Length(fList)-1].EditorSupport.Description := 'Allows you to set the polling value for the sensor.';
 fList[Length(fList)-1].EditorSupport.Required := True;
 fList[Length(fList)-1].EditorSupport.ValueType := vtUnknown;
 fList[Length(fList)-1].EditorSupport.ValueRange := '';
 fList[Length(fList)-1].EditorSupport.CanContainSensor := false;
 SetLength(fList, Length(fList) + 1);
 SetLength(fList[Length(fList)-1].Node, 1);
 fList[Length(fList)-1].Name := 'Dedicated';
 If Node.IsDedicated then S := 'Yes'
  else S := 'No';
 fList[Length(fList)-1].Value := S;
 fList[Length(fList)-1].Node[0] := Node;
 fList[Length(fList)-1].EditorSupport.Name := 'Dedicated';
 fList[Length(fList)-1].EditorSupport.Value := 'No';
 fList[Length(fList)-1].EditorSupport.Description := 'Will run the sensor on a dedicated thread, doesn''t work with advanced update strings.';
 fList[Length(fList)-1].EditorSupport.Required := True;
 fList[Length(fList)-1].EditorSupport.ValueType := vtFixed;
 fList[Length(fList)-1].EditorSupport.ValueRange := 'No|Yes';
 fList[Length(fList)-1].EditorSupport.CanContainSensor := false;
 SetLength(fList, Length(fList) + 1);
 SetLength(fList[Length(fList)-1].Node, 1);
 fList[Length(fList)-1].Name := 'ID';
 fList[Length(fList)-1].Value := Node.IDName;
 fList[Length(fList)-1].Node[0] := Node;
 fList[Length(fList)-1].EditorSupport.Name := 'ID';
 fList[Length(fList)-1].EditorSupport.Value := '';
 fList[Length(fList)-1].EditorSupport.Description := 'Allows you to assign an ID to the sensor for linked creation later.';
 fList[Length(fList)-1].EditorSupport.Required := False;
 fList[Length(fList)-1].EditorSupport.ValueType := vtUnknown;
 fList[Length(fList)-1].EditorSupport.ValueRange := '';
 fList[Length(fList)-1].EditorSupport.CanContainSensor := false;
 ParamBlockNode := Node.GetParameterBlockNode;
 If ParamBlockNode = nil then exit;
 For I := 0 to ParamBlockNode.Count - 1 do begin
  If ParamBlockNode.Node[I].NodeType = ntParameter then begin
   SetLength(fList, Length(fList) + 1);
   SetLength(fList[Length(fList)-1].Node, 1);
   PNode := (ParamBlockNode.Node[I] as TEdParameterNode);
   fList[Length(fList)-1].Name := PNode.Name;
   If PNode.Count = 0 then begin
    fList[Length(fList)-1].Value := PNode.Value;
    fList[Length(fList)-1].Node[0] := PNode;
    fList[Length(fList)-1].EditorSupport := oeMain.GESL[PlugIndex].SensorParamEditorSupportList[SensIndex].GetSensorParamEditorSupportByName(PNode.Name);
   end
    else
   begin
    fList[Length(fList)-1].Value := '[sensor]';
    fList[Length(fList)-1].Node[0] := PNode.Node[0];
    fList[Length(fList)-1].EditorSupport := oeMain.GESL[PlugIndex].SensorParamEditorSupportList[SensIndex].GetSensorParamEditorSupportByName(PNode.Name);
    fList[Length(fList)-1].EditorSupport.CanContainSensor := true;
   end;
  end;
 end;
end;

procedure TOIItemList.LoadTextNode(Node: TEdTextNode);
begin
 SetLength(fList, 1);
 SetLength(fList[Length(fList)-1].Node, 1);
 fList[Length(fList)-1].Name := 'Text';
 fList[Length(fList)-1].Value := Node.TextValue;
 fList[Length(fList)-1].Node[0] := Node;
 fList[Length(fList)-1].EditorSupport.Name := 'Text';
 fList[Length(fList)-1].EditorSupport.Value := '';
 fList[Length(fList)-1].EditorSupport.Description := 'Choose the output text to appear on screen';
 fList[Length(fList)-1].EditorSupport.Required := True;
 fList[Length(fList)-1].EditorSupport.ValueType := vtUnknown;
 fList[Length(fList)-1].EditorSupport.ValueRange := '';
 fList[Length(fList)-1].EditorSupport.CanContainSensor := false;
end;

procedure TOIItemList.LoadVisualNode(Node: TEdVisualNode);
Var
 Sel, I: Integer;
 ParamBlockNode: TEdParameterBlockNode;
 PNode: TEdParameterNode;
begin
 Self.fName := Node.VisualName;
 Sel := oeMain.VESL.GetIndexByName(Node.VisualName);
 If Sel = -1 then begin
  MessageDlg('Unable to locate plugin name in the Editor Support list'+#13+#10+'Location: TOIItemList.LoadVisualNode', mtError, [mbOK], 0);
  exit;
 end;
 ParamBlockNode := Node.GetParameterBlockNode;
 For I := 0 to ParamBlockNode.Count - 1 do begin
  If ParamBlockNode.Node[I].NodeType = ntParameter then begin
   SetLength(fList, Length(fList) + 1);
   SetLength(fList[Length(fList)-1].Node, 1);
   PNode := (ParamBlockNode.Node[I] as TEdParameterNode);
   fList[Length(fList)-1].Name := PNode.Name;
   If PNode.Count = 0 then begin
    fList[Length(fList)-1].Value := PNode.Value;
    fList[Length(fList)-1].Node[0] := PNode;
    fList[Length(fList)-1].EditorSupport := oeMain.VESL[Sel].GetVisPlugEditorInfoByName(PNode.Name);
   end
    else
   begin
    fList[Length(fList)-1].Node[0] := PNode.Node[0];
    fList[Length(fList)-1].Value := '[sensor]';
    fList[Length(fList)-1].EditorSupport.CanContainSensor := true;
   end;
  end;
 end;
end;

function TGenEditorSupportList.GetIndexByName(Name: String;
  var PlugInIndex, SensorIndex: Integer): Boolean;
Var
 I: Integer;
begin
 Result := False;
 PlugInIndex := -1; SensorIndex := -1;
 For I := 0 to Count - 1 do begin
  If uppercase(GetFilt(Name, 1, '.')) = uppercase(fList[I].Name) then begin
   PlugInIndex := I;
   Break;
  end;
 end;
 If PlugInIndex = -1 then exit;
 For I := 0 to GenPlugEditorSupportList[PlugInIndex].Count - 1 do begin
  If uppercase(GetFilt(Name, 2, '.')) = uppercase(GenPlugEditorSupportList[PlugInIndex].SensorParamEditorSupportList[I].SensorName) then begin
   SensorIndex := I;
   Result := true;
   exit;
  end;
 end;
 Result := False;
end;

procedure TGenEditorSupportList.LoadFromFile(Filename: String);
Var
 XML: TXMLDocument;
 DummyForm: TForm;
 Root: IXMLNode;
 Plugin: IXMLNode;
 Sensor: IXMLNode;
 PI, SI, I, II, III: Integer;
 PN, SN, N, V: String;
begin
 If not fileexists(filename) then exit;
 DummyForm := Tform.Create(nil);
 DummyForm.Visible := false;
 XML := TXMLDocument.Create(Dummyform);
 XML.LoadFromFile(filename);
 XML.Active := true;

 Root := XML.ChildNodes.FindNode('DVGeneral');
 If Root <> nil then begin
  For I := 0 to root.ChildNodes.Count - 1 do begin
   If uppercase(root.ChildNodes[I].NodeName) = 'PLUGIN' then begin
    Plugin := root.ChildNodes[I];
    PN := PlugIn.Attributes['name'];
    For II := 0 to Plugin.ChildNodes.Count - 1 do begin
     If uppercase(Plugin.ChildNodes[II].NodeName) = 'SENSOR' then begin
      Sensor := Plugin.ChildNodes[II];
      SN := Sensor.Attributes['name'];
      GetIndexByName(PN + '.' + SN, PI, SI);
      If (PI > -1) and (SI > -1) then begin
       For III := 0 to Sensor.ChildNodes.Count - 1 do begin
        If uppercase(Sensor.ChildNodes[III].NodeName) = 'PARAMETER' then begin
         N := Sensor.ChildNodes[III].Attributes['name'];
         V := Sensor.ChildNodes[III].Attributes['value'];
         fList[PI][SI].ChangeValue(N, V);
        end;
       end;
      end;
     end;
    end;
   end;
  end;
 end;
 FreeAndNil(XML);
 FreeAndNil(DummyForm);
end;

procedure TGenEditorSupportList.SaveToFile(Filename: String);
Var
 I, II, III: Integer;
 List: TStringList;
begin
 List := TStringList.Create;
 List.Add('<DVGeneral>');
 For I := 0 to Length(fList) - 1 do begin
  List.Add(' <plugin name="' + fList[I].Name + '">');
  For II := 0 to length(fList[I].fList) - 1 do begin
   If fList[I][II].Count > 0 then begin
    List.Add('  <sensor name="' + fList[I][II].SensorName + '">');
    For III := 0 to length(fList[I][II].fList) - 1 do begin
     If fList[I][II][III].Value <> '' then begin
      List.Add('  <parameter name="' + fList[I][II][III].Name + '" value="' + fList[I][II][III].Value + '"/>');
     end;
    end;
    If List[List.count-1] = '   <sensor name="' + fList[I][II].SensorName + '">' then begin
     List.Delete(List.Count -1);
    end
     else
    begin
     List.Add('  </sensor>');
    end;
   end;
  end;
  If List[List.Count-1] = ' <plugin name="' + fList[I].Name + '">' then begin
   List.Delete(List.Count -1);
  end
   else
  begin
   List.Add(' </plugin>');
  end;
 end;
 List.Add('</DVGeneral>');
 List.SaveToFile(filename);
 FreeAndNil(List);
end;

{ TFormEditorSupportList }

procedure TFormEditorSupportList.ChangeValue(aName, NewValue: String);
Var
 I: Integer;
begin
 For I := 0 to Count - 1 do begin
  If uppercase(aName) = uppercase(fList[I].Name) then begin
   fList[I].Value := NewValue;
   exit;
  end;
 end;
end;

constructor TFormEditorSupportList.Create;
begin
 SetLength(fList, 0);
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'Name';
 fList[Length(fList) - 1].Value := 'MyForm';
 fList[Length(fList) - 1].Required := true;
 fList[Length(fList) - 1].Description := 'Give the form a descriptive name for easy reference';
 fList[Length(fList) - 1].ValueType := vtUnknown;
 fList[Length(fList) - 1].ValueRange := '';
 fList[Length(fList) - 1].CanContainSensor := false;
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'Alpha';
 fList[Length(fList) - 1].Value := '255';
 fList[Length(fList) - 1].Required := false;
 fList[Length(fList) - 1].Description := 'Allows you to set the alphablend value of the form';
 fList[Length(fList) - 1].ValueType := vtRange;
 fList[Length(fList) - 1].ValueRange := '20|255';
 fList[Length(fList) - 1].CanContainSensor := true;
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'Color';
 fList[Length(fList) - 1].Value := 'clBtnFace';
 fList[Length(fList) - 1].Required := True;
 fList[Length(fList) - 1].Description := 'The background color of the form';
 fList[Length(fList) - 1].ValueType := vtColor;
 fList[Length(fList) - 1].ValueRange := '';
 fList[Length(fList) - 1].CanContainSensor := true;
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'WindowMode';
 fList[Length(fList) - 1].Value := 'Normal';
 fList[Length(fList) - 1].Required := True;
 fList[Length(fList) - 1].Description := 'Allows you to select how to form will appear on screen';
 fList[Length(fList) - 1].ValueType := vtFixed;
 fList[Length(fList) - 1].CanContainSensor := true;
 fList[Length(fList) - 1].ValueRange := 'Normal|PinToDesktop|AlwaysOnTop';
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'Show';
 fList[Length(fList) - 1].Value := 'Yes';
 fList[Length(fList) - 1].Required := True;
 fList[Length(fList) - 1].Description := 'Choose whether or not the form is visible';
 fList[Length(fList) - 1].ValueType := vtFixed;
 fList[Length(fList) - 1].ValueRange := 'Yes|No';
 fList[Length(fList) - 1].CanContainSensor := true;
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'Transparent';
 fList[Length(fList) - 1].Value := 'No';
 fList[Length(fList) - 1].Required := false;
 fList[Length(fList) - 1].Description := 'Should the form be transparent';
 fList[Length(fList) - 1].ValueType := vtFixed;
 fList[Length(fList) - 1].ValueRange := 'No|Yes';
 fList[Length(fList) - 1].CanContainSensor := true;
 SetLength(fList, length(fList) + 1);
 fList[Length(fList) - 1].Name := 'TransparentColor';
 fList[Length(fList) - 1].Value := 'clnone';
 fList[Length(fList) - 1].Required := false;
 fList[Length(fList) - 1].Description := 'If the form is transparent this is the color that will be converted into transparent';
 fList[Length(fList) - 1].ValueType := vtColor;
 fList[Length(fList) - 1].ValueRange := 'clNone';
 fList[Length(fList) - 1].CanContainSensor := true;
end;

function TFormEditorSupportList.GETCOUNT: Cardinal;
begin
 Result := Length(fList);
end;

function TFormEditorSupportList.GETFES(Index: Integer): TFormEditorSupport;
begin
 Result := fList[Index];
end;

function TFormEditorSupportList.GetFormEditorInfoByName(
  N: String): TFormEditorSupport;
Var
 I: Integer;
begin
 Result.ValueType := vtUnknown;
 Result.Required := false;
 Result.Description := '';
 Result.Value := '';
 Result.CanContainSensor := true;
 For I := 0 to count - 1 do begin
  If uppercase(fList[I].Name) = uppercase(N) then begin
   Result := fList[I];
   Break;
  end;
 end;
end;

function TFormEditorSupportList.GetValue(Name: String): String;
Var
 I: Integer;
begin
 Result := '';
 For I := 0 to Count - 1 do begin
  if uppercase(flist[I].Name) = uppercase(name) then begin
   Result := fList[I].Value;
   Exit;
  end;
 end;
end;

procedure TFormEditorSupportList.LoadFromFile(Filename: String);
Var
 XML: TXMLDocument;
 DummyForm: TForm;
 Root: IXMLNode;
 I: Integer;
 N, V: String;
begin
 If not fileexists(filename) then exit;
 DummyForm := Tform.Create(nil);
 DummyForm.Visible := false;
 XML := TXMLDocument.Create(Dummyform);
 XML.LoadFromFile(filename);
 XML.Active := true;
 Root := XML.ChildNodes.FindNode('DVForm');
 If Root <> nil then begin
  For I := 0 to root.ChildNodes.Count - 1 do begin
   If uppercase(root.Childnodes[I].NodeName) = 'PARAMETER' then begin
    N := root.ChildNodes[I].Attributes['name'];
    V := root.ChildNodes[I].Attributes['value'];
    ChangeValue(N, V);
   end;
  end;
 end;
 FreeAndNil(XML);
 FreeAndNil(DummyForm);
end;

procedure TFormEditorSupportList.SaveToFile(Filename: String);
Var
 I: Integer;
 List: TStringList;
begin
 List := TStringList.Create;
 List.Add('<DVForm>');
 For I := 0 to Length(fList) - 1 do begin
  If fList[I].Value <> '' then begin
   List.Add(' <parameter name="' + fList[I].Name + '" value="' + fList[I].Value + '"/>');
  end;
 end;
 List.Add('</DVForm>');
 List.SaveToFile(filename);
 FreeAndNil(List);
end;

{ TOIContentList }

procedure TOIContentList.BuildFromTag(Node: TEdRawNode);
Var
 I: Integer;
 Cont: TEdContentNode;
begin
 Clear;
 If Node = nil then exit;
 Cont := nil;
 Case Node.NodeType of
  ntForm: Cont := (Node as TEdFormNode).GetContentNode;
  ntVisual: Cont := (Node as TEdVisualNode).GetContentNode;
 end;
 If Cont = nil then exit;
 For I := 0 to Cont.Count - 1 do begin
  SetLength(fList, Length(fList)+1);
  fList[Length(fList)-1].Node := Cont[I];
 end;
end;

procedure TOIContentList.Clear;
begin
 SetLength(fList, 0);
end;

function TOIContentList.GETCONTENT(Index: Integer): TOIContent;
begin
 result := fList[Index];
end;

function TOIContentList.GETCOUNT: Cardinal;
begin
 result := length(fList);
end;

procedure TOIItemList.SETOIITEM(Index: Integer; const Value: TOIItem);
begin
 fList[Index] := Value;
end;

{ TOIEventList }

procedure TOIEventList.BuildFromTag(Node: TEdEventsNode);
begin
 Clear;
 If Node = nil then exit;
end;

procedure TOIEventList.Clear;
begin
 Setlength(fList, 0);
end;

function TOIEventList.GETCOUNT: Integer;
begin
 Result := length(fList);
end;

function TOIEventList.GETEVENT(Index: Integer): TOIEvent;
begin
 Result := fList[Index];
end;

end.
