From 790268cca527858df4f4f5ad626ca70be25dbb8b Mon Sep 17 00:00:00 2001 From: Paulo Meira <10246101+PMeira@users.noreply.github.com> Date: Sat, 16 Mar 2024 01:03:04 -0300 Subject: [PATCH] Alt/Obj,Batch: add more checks when creating objects; refactor to remove some redundancy. --- docs/changelog.md | 4 ++++ src/CAPI/CAPI_Obj.pas | 43 ++++++++++++++++++++++------------ src/Common/CktElementClass.pas | 1 + src/Common/DSSClass.pas | 3 +++ src/Executive/ExecHelper.pas | 40 ++++++++++++++----------------- src/General/LineCode.pas | 1 + src/General/LineGeometry.pas | 1 + 7 files changed, 55 insertions(+), 38 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index aaaa9c358..a85f3776f 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -17,6 +17,10 @@ # Versions 0.14.x +## Version 0.14.4 (dev, next release) + +- Alt/Obj,Batch: adjust checks for new elements. Refactored some other internal code to simplify this kind of check. + ## Version 0.14.3 (2024-03-13) - Header/Alt: fix `dss_obj_float64_int32_func_t` (returns `double`, not `int32_t`). diff --git a/src/CAPI/CAPI_Obj.pas b/src/CAPI/CAPI_Obj.pas index f093d0424..69af405d4 100644 --- a/src/CAPI/CAPI_Obj.pas +++ b/src/CAPI/CAPI_Obj.pas @@ -226,6 +226,9 @@ function obj_NewFromClass(DSS: TDSSContext; Cls: TDSSClass; Name: String; Activa Result := NIL; if DSS = NIL then DSS := DSSPrime; Obj := Cls.NewObject(Name, Activate); + if Obj = NIL then + Exit; + if BeginEdit then Cls.BeginEdit(Obj, False); @@ -240,25 +243,26 @@ function obj_NewFromClass(DSS: TDSSContext; Cls: TDSSClass; Name: String; Activa function Obj_New(DSS: TDSSContext; ClsIdx: Integer; Name: PAnsiChar; Activate: TAltAPIBoolean; BeginEdit: TAltAPIBoolean): Pointer; CDECL; var - Obj: TDSSObject; Cls: TDSSClass; + checkDups: Boolean; begin Result := NIL; if DSS = NIL then DSS := DSSPrime; Cls := DSS.DSSClassList.At(ClsIdx); - if Cls = NIL then + if (Cls = NIL) or (Cls.RequiresCircuit and InvalidCircuit(DSS)) then Exit; - Obj := Cls.NewObject(Name, Activate); - if BeginEdit then - Cls.BeginEdit(Obj, False); - - if Cls.DSSClassType = DSS_OBJECT then - DSS.DSSObjs.Add(Obj) - else - DSS.ActiveCircuit.AddCktElement(TDSSCktElement(Obj)); + checkDups := (cls.DSSClassType <> DSS_OBJECT) and (not DSS.ActiveCircuit.DuplicatesAllowed); - Result := Obj; + if checkDups then + begin + if cls.Find(Name, true) <> NIL then + begin + DoSimpleMsg(DSS, 'Warning: Duplicate new element definition: "%s.%s". Element being redefined.', [Cls.Name, Name], 266); + Exit; + end; + end; + Result := obj_NewFromClass(DSS, cls, name, Activate, BeginEdit); end; function Obj_GetHandleByName(DSS: TDSSContext; ClsIdx: Integer; Name: PAnsiChar): Pointer; CDECL; @@ -858,18 +862,21 @@ procedure Batch_CreateFromNew(DSS: TDSSContext; var ResultPtr: TDSSObjectPtr; Re Cls: TDSSClass; outptr: TDSSObjectPtr; i: Integer; - prefix: String; + Name, prefix: String; + checkDups: Boolean; begin if DSS = NIL then DSS := DSSPrime; Cls := DSS.DSSClassList.At(ClsIdx); - if Cls = NIL then + if (Cls = NIL) or (Cls.RequiresCircuit and InvalidCircuit(DSS)) then Exit; + + checkDups := (cls.DSSClassType <> DSS_OBJECT) and (not DSS.ActiveCircuit.DuplicatesAllowed); ensureBatchSize(Count, ResultPtr, ResultCount); outptr := ResultPtr; if Names = NIL then begin - // Use a random batch prefix to avoid collisions + // Use a random batch prefix to avoid collisions; we won't check for existing objects here prefix := Format('%09d_', [Random(1000000000)]); for i := 1 to Count do begin @@ -886,7 +893,13 @@ procedure Batch_CreateFromNew(DSS: TDSSContext; var ResultPtr: TDSSObjectPtr; Re begin for i := 1 to Count do begin - outptr^ := Cls.NewObject(Names^, False); + Name := Names^; + if checkDups and (cls.Find(Name, true) <> NIL) then + begin + DoSimpleMsg(DSS, 'Warning: Duplicate new element definition: "%s.%s". Element being redefined.', [Cls.Name, Name], 266); + Exit; + end; + outptr^ := Cls.NewObject(Name, False); if Cls.DSSClassType = DSS_OBJECT then DSS.DSSObjs.Add(outptr^) else diff --git a/src/Common/CktElementClass.pas b/src/Common/CktElementClass.pas index 99e2da8ab..4b11d7bbb 100644 --- a/src/Common/CktElementClass.pas +++ b/src/Common/CktElementClass.pas @@ -76,6 +76,7 @@ constructor TCktElementClass.Create(dssContext: TDSSContext; DSSClsType: Integer end; inherited Create(dssContext, DSSClsType, DSSClsName); + RequiresCircuit := true; ClassParents.Add('CktElement'); end; diff --git a/src/Common/DSSClass.pas b/src/Common/DSSClass.pas index aa0dc47d3..ae9977a7d 100644 --- a/src/Common/DSSClass.pas +++ b/src/Common/DSSClass.pas @@ -479,6 +479,7 @@ TDSSClass = class(TObject) ElementNamesOutOfSynch: Boolean; // When device gets renamed Saved: Boolean; + RequiresCircuit: Boolean; constructor Create(dssContext: TDSSContext; DSSClsType: Integer; DSSClsName: String); destructor Destroy; override; @@ -1494,6 +1495,8 @@ constructor TDSSClass.Create(dssContext: TDSSContext; DSSClsType: Integer; DSSCl ElementNameList := THashListType.Create(100); ElementNamesOutOfSynch := FALSE; + RequiresCircuit := false; + DefineProperties(); end; diff --git a/src/Executive/ExecHelper.pas b/src/Executive/ExecHelper.pas index 6a85d7c9f..e630ca5ee 100644 --- a/src/Executive/ExecHelper.pas +++ b/src/Executive/ExecHelper.pas @@ -127,7 +127,7 @@ TExecHelper = class helper for TExecutive procedure GetObjClassAndName(var ObjClass, ObjName: String); function AddObject(ObjType: String; const Name: String): Integer; overload; - function AddObject(ObjCls: TDSSClass; const Name: String): Integer; overload; + function AddObject(Cls: TDSSClass; const Name: String): Integer; overload; function EditObject(const ObjType, name: String): Integer; procedure SetActiveCircuit(const cktname: String); @@ -1853,7 +1853,7 @@ function TExecHelper.AddObject(ObjType: String; const Name: String): Integer; Result := AddObject(DSS.ActiveDSSClass, Name); end; -function TExecHelper.AddObject(ObjCls: TDSSClass; const Name: String): Integer; +function TExecHelper.AddObject(Cls: TDSSClass; const Name: String): Integer; var Obj: TDSSObject = NIL; begin @@ -1873,7 +1873,7 @@ function TExecHelper.AddObject(ObjCls: TDSSClass; const Name: String): Integer; // intrinsic and user Defined models // Make a new circuit element - DSS.ActiveDSSClass := ObjCls; + DSS.ActiveDSSClass := Cls; // Name must be supplied if Length(Name) = 0 then @@ -1882,53 +1882,47 @@ function TExecHelper.AddObject(ObjCls: TDSSClass; const Name: String): Integer; Exit; end; - // now let's make a new object or set an existing one active, whatever the case - if DSS.ActiveDSSClass.DSSClassType = DSS_OBJECT then + if Cls.RequiresCircuit and (DSS.ActiveCircuit = NIL) then begin - if (DSS.ActiveCircuit = NIL) and ((DSS.ActiveDSSClass = DSS.LineCodeClass) or (DSS.ActiveDSSClass = DSS.LineGeometryClass)) then - begin - DoSimpleMsg(DSS, _('You Must Create a circuit first: "new circuit.yourcktname"'), 279); - Exit; - end; + DoSimpleMsg(DSS, _('You Must Create a circuit first: "new circuit.yourcktname"'), 265); + Exit; + end; + // now let's make a new object or set an existing one active, whatever the case + if Cls.DSSClassType = DSS_OBJECT then + begin // These can be added WITHout having an active circuit // Duplicates not allowed in general DSS objects; - if not DSS.ActiveDSSClass.SetActive(Name) then + if not Cls.SetActive(Name) then begin - Obj := DSS.ActiveDSSClass.NewObject(Name, TRUE, Result); + Obj := Cls.NewObject(Name, TRUE, Result); DSS.DSSObjs.Add(Obj); // Stick in pointer list to keep track of it end; end else begin // These are circuit elements - if DSS.ActiveCircuit = NIL then - begin - DoSimpleMsg(DSS, _('You Must Create a circuit first: "new circuit.yourcktname"'), 265); - Exit; - end; - // IF Object already exists. Treat as an Edit IF dulicates not allowed if DSS.ActiveCircuit.DuplicatesAllowed then begin - Obj := DSS.ActiveDSSClass.NewObject(Name, TRUE, Result); // Returns index into this class + Obj := Cls.NewObject(Name, TRUE, Result); // Returns index into this class DSS.ActiveCircuit.AddCktElement(TDSSCktElement(Obj)); // Adds active object to active circuit end else begin // Check to see if we can set it active first - if not DSS.ActiveDSSClass.SetActive(Name) then + if not Cls.SetActive(Name) then begin - Obj := DSS.ActiveDSSClass.NewObject(Name, TRUE, Result); // Returns index into this class + Obj := Cls.NewObject(Name, TRUE, Result); // Returns index into this class DSS.ActiveCircuit.AddCktElement(TDSSCktElement(Obj)); // Adds active object to active circuit end else begin - DoSimpleMsg(DSS, 'Warning: Duplicate new element definition: "%s.%s". Element being redefined.', [DSS.ActiveDSSClass.Name, Name], 266); + DoSimpleMsg(DSS, 'Warning: Duplicate new element definition: "%s.%s". Element being redefined.', [Cls.Name, Name], 266); Exit; end; end; end; - DSS.ActiveDSSClass.Edit(DSS.Parser); // Process remaining instructions on the command line + Cls.Edit(DSS.Parser); // Process remaining instructions on the command line end; function TExecHelper.EditObject(const ObjType, Name: String): Integer; diff --git a/src/General/LineCode.pas b/src/General/LineCode.pas index e1730e1ec..094a6d22a 100644 --- a/src/General/LineCode.pas +++ b/src/General/LineCode.pas @@ -181,6 +181,7 @@ constructor TLineCode.Create(dssContext: TDSSContext); end; inherited Create(dssContext, DSS_OBJECT, 'LineCode'); + RequiresCircuit := true; end; destructor TLineCode.Destroy; diff --git a/src/General/LineGeometry.pas b/src/General/LineGeometry.pas index e001878a5..9e88035df 100644 --- a/src/General/LineGeometry.pas +++ b/src/General/LineGeometry.pas @@ -203,6 +203,7 @@ constructor TLineGeometry.Create(dssContext: TDSSContext); end; inherited Create(dssContext, DSS_OBJECT, 'LineGeometry'); + RequiresCircuit := true; end; destructor TLineGeometry.Destroy;