|
From: <fas...@us...> - 2006-11-28 10:51:42
|
Revision: 723
http://svn.sourceforge.net/instantobjects/revision/?rev=723&view=rev
Author: fastbike2
Date: 2006-11-28 02:51:28 -0800 (Tue, 28 Nov 2006)
Log Message:
-----------
Fix for [ 1467622 ] Duplicate Attribute Names
Modified Paths:
--------------
trunk/Source/Design/InstantAttributeEditor.pas
trunk/Source/ObjectFoundry/OFExpert.pas
Modified: trunk/Source/Design/InstantAttributeEditor.pas
===================================================================
--- trunk/Source/Design/InstantAttributeEditor.pas 2006-11-28 07:20:59 UTC (rev 722)
+++ trunk/Source/Design/InstantAttributeEditor.pas 2006-11-28 10:51:28 UTC (rev 723)
@@ -57,6 +57,18 @@
TInstantBooleanEvent = procedure (Sender: TObject; const AClassName: String;
var IsPersistent: Boolean) of object;
+ TInstantAttributeValidator = class
+ private
+ FAttribute: TInstantCodeAttribute;
+ FInterface: IInterface;
+ protected
+ property Attribute: TInstantCodeAttribute read FAttribute;
+ property MMInterface: IInterface read FInterface;
+ public
+ constructor Create(AnAttribute: TInstantCodeAttribute; const AInterface: IInterface);
+ procedure Validate; virtual;
+ end;
+
TInstantAttributeEditorForm = class(TInstantEditForm)
AccessSheet: TTabSheet;
DefinitionSheet: TTabSheet;
@@ -123,10 +135,12 @@
FModel: TInstantCodeModel;
FOnIsClassPersistent: TInstantBooleanEvent;
FOnLoadClasses: TInstantStringsEvent;
+ FValidator: TInstantAttributeValidator;
function GetSubject: TInstantCodeAttribute;
procedure SetSubject(const Value: TInstantCodeAttribute);
procedure SetLimited(Value: Boolean);
procedure SetModel(const Value: TInstantCodeModel);
+ procedure SetValidator(const Value: TInstantAttributeValidator);
protected
procedure LoadClasses;
procedure LoadData; override;
@@ -151,6 +165,7 @@
property OnLoadClasses: TInstantStringsEvent read FOnLoadClasses
write FOnLoadClasses;
property Subject: TInstantCodeAttribute read GetSubject write SetSubject;
+ property Validator: TInstantAttributeValidator read FValidator write SetValidator;
end;
implementation
@@ -172,6 +187,7 @@
begin
PageControl.ActivePage := DefinitionSheet;
ActiveControl := NameEdit;
+ FValidator := TInstantAttributeValidator.Create(Subject, nil);
end;
function TInstantAttributeEditorForm.GetSubject: TInstantCodeAttribute;
@@ -385,25 +401,19 @@
end;
procedure TInstantAttributeEditorForm.OkButtonClick(Sender: TObject);
-var
- Attribute: TInstantCodeAttribute;
- I: Integer;
begin
if OKButton.CanFocus then
OKButton.SetFocus;
- if Assigned(Subject.Owner) then
- for I := 0 to Pred(Subject.Owner.AttributeCount) do
- begin
- Attribute := Subject.Owner.Attributes[I];
- if (Attribute <> Subject) and SameText(Attribute.Name, Subject.Name) then
- begin
- ModalResult := mrNone;
- PageControl.ActivePage := DefinitionSheet;
- NameEdit.SetFocus;
- raise Exception.Create('Attribute Name already used');
- end;
- end;
+ try
+ FValidator.Validate;
+ except
+ ModalResult := mrNone;
+ PageControl.ActivePage := DefinitionSheet;
+ NameEdit.SetFocus;
+ raise;
+ end;
+
if (Subject.AttributeType = atString) and (Subject.Metadata.Size = 0) then
if not Confirm(SConfirmZeroSizeStringAttribute) then
begin
@@ -502,10 +512,11 @@
end;
end;
-procedure TInstantAttributeEditorForm.SetSubject(
- const Value: TInstantCodeAttribute);
+procedure TInstantAttributeEditorForm.SetSubject(const Value: TInstantCodeAttribute);
begin
inherited Subject := Value;
+ if FValidator <> nil then
+ FValidator.FAttribute := Value;
end;
procedure TInstantAttributeEditorForm.SubjectChanged;
@@ -740,10 +751,87 @@
procedure TInstantAttributeEditorForm.StorageNameEditChange(Sender: TObject);
begin
inherited;
- if Assigned(StorageNameEdit.DataSource) then
+ if Assigned(StorageNameEdit.DataSource) then
SubjectExposer.AssignFieldValue(StorageNameEdit.Field, StorageNameEdit.Text);
UpdateControls;
end;
+procedure TInstantAttributeEditorForm.SetValidator(const Value: TInstantAttributeValidator);
+begin
+ if FValidator <> Value then begin
+ if FValidator <> nil then
+ FreeAndNil(FValidator);
+ FValidator := Value;
+ end;
+end;
+
+{ TInstantAttributeValidator }
+
+constructor TInstantAttributeValidator.Create(
+ AnAttribute: TInstantCodeAttribute; const AInterface: IInterface);
+begin
+ inherited Create;
+ FAttribute := AnAttribute;
+ FInterface := AInterface;
+end;
+
+procedure TInstantAttributeValidator.Validate;
+var
+ TempAttribute: TInstantCodeAttribute;
+ CodeClass: TInstantCodeClass;
+ I: Integer;
+
+ procedure CheckChildClass(CurrentClass: TInstantCodeClass);
+ var
+ J,K: Integer;
+ begin
+ if CurrentClass = nil then
+ Exit;
+ for J := 0 to Pred(CurrentClass.SubClassCount) do
+ begin
+ for K := 0 to Pred(CurrentClass.SubClasses[J].PropertyCount) do
+ if SameText(CurrentClass.SubClasses[J].Properties[K].Name, FAttribute.Name) then
+ raise Exception.CreateFmt('Attribute "%s" exists in descendant class "%s"',
+ [FAttribute.Name, CurrentClass.SubClasses[J].Name]);
+ for K := 0 to Pred(CurrentClass.SubClasses[J].MethodCount) do
+ if SameText(CurrentClass.SubClasses[J].Methods[K].Name, FAttribute.Name) then
+ raise Exception.CreateFmt('Attribute "%s" exists as a method in descendant class "%s"',
+ [FAttribute.Name, CurrentClass.SubClasses[J].Name]);
+ CheckChildClass(CurrentClass.SubClasses[J]);
+ end;
+ end;
+
+begin
+ if not Assigned(FAttribute) and not Assigned(FAttribute.Owner)
+ and not Assigned(FAttribute.Owner.Owner) then
+ raise Exception.Create('Cannot validate attribute');
+
+ // check that the same attribute name is not used in an ancestor class
+ CodeClass := FAttribute.Owner.Owner.BaseClass;
+ while (CodeClass <> nil) do
+ begin
+ for I := 0 to Pred(CodeClass.PropertyCount) do
+ if SameText(CodeClass.Properties[I].Name, FAttribute.Name) then
+ raise Exception.CreateFmt('Attribute "%s" exists in ancestor class "%s"',
+ [FAttribute.Name, CodeClass.Name]);
+ for I := 0 to Pred(CodeClass.MethodCount) do
+ if SameText(CodeClass.Methods[I].Name, FAttribute.Name) then
+ raise Exception.CreateFmt('Attribute "%s" exists as a method in ancestor class "%s"',
+ [FAttribute.Name, CodeClass.Name]);
+ CodeClass := CodeClass.BaseClass;
+ end;
+ // check that the same attribute name is not used in any child class
+ CheckChildClass(FAttribute.Owner.Owner);
+
+ if Assigned(FAttribute.Owner) then
+ for I := 0 to Pred(FAttribute.Owner.AttributeCount) do
+ begin
+ TempAttribute := FAttribute.Owner.Attributes[I];
+ if (TempAttribute <> FAttribute) and SameText(TempAttribute.Name, FAttribute.Name) then
+ raise Exception.Create('Attribute Name already used');
+ end;
+end;
+
+
end.
Modified: trunk/Source/ObjectFoundry/OFExpert.pas
===================================================================
--- trunk/Source/ObjectFoundry/OFExpert.pas 2006-11-28 07:20:59 UTC (rev 722)
+++ trunk/Source/ObjectFoundry/OFExpert.pas 2006-11-28 10:51:28 UTC (rev 723)
@@ -24,7 +24,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
- * Steven Mitchell
+ * Steven Mitchell, David Moorhouse
*
* ***** END LICENSE BLOCK ***** *)
@@ -35,7 +35,7 @@
uses
Classes,
{$IFDEF VER130}
- Windows, // Need in D5 for definition of THandle
+ Windows, // Need in D5 for definition of THandle
{$ENDIF}
MMIOAPI, OFOptions, SysUtils, MMToolsAPI, OFDefs;
@@ -98,6 +98,13 @@
const
SObjectFoundry = 'ObjectFoundry';
+type
+ TMMAttributeValidator = class(TInstantAttributeValidator)
+ public
+ procedure Validate; override;
+ end;
+
+
// Function externalised from AttributeEditorLoadClasses function.
function TObjectFoundryExpert.IsInstantObjectClass(AClass: IMMClassBase):
Boolean;
@@ -184,6 +191,7 @@
var
Attribute: TMMCodeAttribute;
lClass: IMMClassifier;
+ AttributeValidator: TMMAttributeValidator;
function GetBaseClassStorageName: String;
begin
@@ -201,6 +209,7 @@
begin
lClass := P.ClassBase;
Attribute := TMMCodeAttribute.Create(P);
+ AttributeValidator := TMMAttributeValidator.Create(Attribute, P);
try
with TInstantAttributeEditorForm.Create(nil) do
try
@@ -208,6 +217,7 @@
OnLoadClasses := AttributeEditorLoadClasses;
OnIsClassPersistent := ClassIsPersistent;
Subject := Attribute;
+ Validator := AttributeValidator;
Result := ShowModal = mrOK;
if Result then
Attribute.ApplyChanges;
@@ -215,6 +225,7 @@
Free;
end;
finally
+ AttributeValidator.Free;
Attribute.Free;
end;
end else
@@ -577,4 +588,48 @@
end;
end;
+{ TMMAttributeValidator }
+
+procedure TMMAttributeValidator.Validate;
+var
+ MMProperty: IMMProperty;
+ CodeClass: IMMClassifier;
+ I: Integer;
+
+ procedure CheckChildClass(CurrentClass: IMMClassifier);
+ var
+ J: Integer;
+ begin
+ if CurrentClass = nil then
+ Exit;
+ for J := 0 to Pred(CurrentClass.DescendantCount) do
+ begin
+ if CurrentClass.Descendants[J].FindMember(Attribute.Name, I) then
+ raise Exception.CreateFmt('Attribute "%s" exists in descendant class "%s"',
+ [Attribute.Name, CurrentClass.Descendants[J].Name]);
+ CheckChildClass(CurrentClass.Descendants[J]);
+ end;
+ end;
+
+begin
+ if MMInterface = nil then
+ Exit;
+ MMProperty := MMInterface as IMMProperty;
+
+ if MMProperty.ClassBase.FindMember(Attribute.Name, I) then
+ raise Exception.Create('Attribute Name already used');
+
+ // check that the same attribute name is not used in an ancestor class
+ CodeClass := MMProperty.ClassBase;
+ while (CodeClass <> nil) do
+ begin
+ if CodeClass.FindMember(Attribute.Name, I) then
+ raise Exception.CreateFmt('Attribute "%s" exists in ancestor class "%s"',
+ [Attribute.Name, CodeClass.Name]);
+ CodeClass := CodeClass.Ancestor;
+ end;
+ // check that the same attribute name is not used in any child class
+ CheckChildClass(MMProperty.ClassBase);
+end;
+
end.
|