-
Notifications
You must be signed in to change notification settings - Fork 10
/
msItemsHolder.mixin.pas
232 lines (199 loc) · 5.41 KB
/
msItemsHolder.mixin.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
{$IfNDef TmsItemsHolder_uses_intf}
// Объект содержащий список других объектов
// interface
{$Define TmsItemsHolder_uses_intf}
// uses
Generics.Collections,
Data.DBXJSONReflect,
System.Rtti
{$Else TmsItemsHolder_uses_intf}
{$IfNDef TmsItemsHolder_intf}
// http://programmingmindstream.blogspot.ru/2014/12/generic-2.html
{$Define TmsItemsHolder_intf}
TmsRttiFieldLambda = reference to procedure (aField: TRttiField);
TmsItemsList = TList<TmsItem>;
TmsItemsListEnumerator = TEnumerator<TmsItem>;
TmsItemsHolder = class abstract(TmsItemsHolderParent)
private
[JSONMarshalled(True)]
f_Items : TmsItemsList;
function pm_GetItems: TmsItemsList;
procedure pm_SetItems(aValue: TmsItemsList);
class procedure RegisterItemsLike(aLambda: TmsRttiFieldLambda);
protected
function ItemsCount: Integer;
private
property _Items: TmsItemsList read pm_GetItems write pm_SetItems;
protected
procedure ItemAdded(const anItem: TmsItem); virtual;
function FirstItem: TmsItem;
public
constructor Create;
procedure Cleanup; override;
procedure Assign(anOther : TmsItemsHolder);
class procedure RegisterInMarshal(aMarshal: TJSONMarshal);
class procedure RegisterInUnMarshal(aMarshal: TJSONUnMarshal);
function GetEnumerator: TmsItemsListEnumerator;
function IndexOf(const anItem: TmsItem): Integer;
procedure Add(const anItem: TmsItem);
end;//TmsItemsHolder
{$Else TmsItemsHolder_intf}
// implementation
{$IfNDef TmsItemsHolder_uses_impl}
// uses
System.TypInfo,
msGarbageCollector
{$Define TmsItemsHolder_uses_impl}
{$Else TmsItemsHolder_uses_impl}
// TmsItemsHolder
constructor TmsItemsHolder.Create;
begin
inherited;
Assert(f_Items = nil);
f_Items := TmsItemsList.Create;
end;
procedure TmsItemsHolder.Cleanup;
begin
FreeAndNil(f_Items);
inherited;
end;
function TmsItemsHolder.pm_GetItems: TmsItemsList;
begin
if (f_Items = nil) then
f_Items := TmsItemsList.Create;
Result := f_Items;
end;
procedure TmsItemsHolder.pm_SetItems(aValue: TmsItemsList);
var
l_Item : TmsItem;
begin
if (f_Items <> nil) then
f_Items.Clear;
if (aValue <> nil) then
for l_Item in aValue do
begin
if (f_Items = nil) then
f_Items := TmsItemsList.Create;
Self.Add(l_Item);
end;//for l_Shape in aValue
end;
procedure TmsItemsHolder.Assign(anOther : TmsItemsHolder);
begin
Self._Items := anOther._Items;
end;
class procedure TmsItemsHolder.RegisterItemsLike(aLambda: TmsRttiFieldLambda);
var
l_Field : TRttiField;
begin
for l_Field in TRttiContext.Create.GetType(Self).GetFields do
if (l_Field.Visibility = mvPrivate) then
if (l_Field.Name = 'f_Items') then
begin
aLambda(l_Field);
Exit;
end;//l_Field.Name = 'f_Items'
Assert(false, 'Не найдено поля для Items');
end;
class procedure TmsItemsHolder.RegisterInMarshal(aMarshal: TJSONMarshal);
begin
RegisterItemsLike(
procedure (aField: TRttiField)
var
l_FieldName : String;
begin
l_FieldName := aField.Name;
aMarshal.RegisterConverter(Self, l_FieldName,
function (Data: TObject; Field: String): TListOfObjects
var
l_Item: TmsItem;
l_Index: Integer;
begin
Assert(Field = l_FieldName);
if ((Data As TmsItemsHolder).ItemsCount <= 0) then
begin
Result := nil;
Exit;
end;//Data As TmsItemsHolder).ItemsCount <= 0
SetLength(Result, (Data As TmsItemsHolder).ItemsCount);
l_Index := 0;
for l_Item in (Data As TmsItemsHolder) do
begin
Result[l_Index] := l_Item.toObject;
Inc(l_Index);
end;//for l_Item
end
);//aMarshal.RegisterConverter
end
);//RegisterItemsLike
aMarshal.RegisterJSONMarshalled(Self, 'FRefCount', false);
end;
class procedure TmsItemsHolder.RegisterInUnMarshal(aMarshal: TJSONUnMarshal);
begin
RegisterItemsLike(
procedure (aField: TRttiField)
var
l_FieldName : String;
begin
l_FieldName := aField.Name;
aMarshal.RegisterReverter(Self, l_FieldName,
procedure (Data: TObject; Field: String; Args: TListOfObjects)
var
l_Object: TObject;
l_Holder : TmsItemsHolder;
l_ItemI : TmsItem;
l_C : Integer;
begin
Assert(Field = l_FieldName);
l_Holder := Data As TmsItemsHolder;
Assert(l_Holder <> nil);
l_C := l_Holder._AddRef;
Assert(l_C > 0);
try
for l_Object in Args do
begin
if Supports(l_Object, TmsItem, l_ItemI) then
try
l_Holder.Add(l_ItemI);
finally
l_ItemI := nil;
end
else
raise Exception.Create(l_Object.ClassName + ' не поддерживает нужный интерфейс');
end//for l_Object
finally
if (l_C = 1) then
TmsGarbageCollector.Instance.Add(l_Holder);
l_Holder._Release;
end;//try..finally
end
);//aMarshal.RegisterReverter
end
);//RegisterItemsLike
end;
function TmsItemsHolder.GetEnumerator: TmsItemsListEnumerator;
begin
Result := f_Items.GetEnumerator;
end;
function TmsItemsHolder.IndexOf(const anItem: TmsItem): Integer;
begin
Result := _Items.IndexOf(anItem);
end;
function TmsItemsHolder.ItemsCount: Integer;
begin
Result := _Items.Count;
end;
procedure TmsItemsHolder.ItemAdded(const anItem: TmsItem);
begin
end;
procedure TmsItemsHolder.Add(const anItem: TmsItem);
begin
_Items.Add(anItem);
ItemAdded(anItem);
end;
function TmsItemsHolder.FirstItem: TmsItem;
begin
Result := _Items.First;
end;
{$EndIf TmsItemsHolder_uses_impl}
{$EndIf TmsItemsHolder_intf}
{$EndIf TmsItemsHolder_uses_intf}