1 {
2 *****************************************************************************
3 *                                                                           *
4 *  This file is part of the ZCAD                                            *
5 *                                                                           *
6 *  See the file COPYING.modifiedLGPL.txt, included in this distribution,    *
7 *  for details about the copyright.                                         *
8 *                                                                           *
9 *  This program is distributed in the hope that it will be useful,          *
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
12 *                                                                           *
13 *****************************************************************************
14 }
15 {
16 @author(Andrey Zubarev <zamtmn@yandex.ru>)
17 }
18 {$MODE OBJFPC}
19 {$H+}
20 unit zeundostack;
21 {$INCLUDE def.inc}
22 interface
23 uses gzctnrvectortypes,zebaseundocommands,varmandef,uzbtypesbase,
24      gzctnrvectorpobjects,sysutils,uzbtypes,uzbmemman;
25 const BeginUndo:GDBString='BeginUndo';
26       EndUndo:GDBString='EndUndo';
27 type
28 TUndoRedoResult=(URROk,
29                  URRNoCommandsToUndoInOverlayMode,
30                  URRNoCommandsToUndo,
31                  URRNoCommandsToRedo);
32 TOnUndoRedoProc=procedure of object;
33 PTZctnrVectorUndoCommands=^TZctnrVectorUndoCommands;
34 TZctnrVectorUndoCommands=object(specialize GZVectorPObects{-}<PTElementaryCommand,TElementaryCommand>{//})
35                                  public
36                                  CurrentCommand:TArrayIndex;
37                                  currentcommandstartmarker:TArrayIndex;
38                                  startmarkercount:GDBInteger;
39                                  onUndoRedo:TOnUndoRedoProc;
40                                  procedure PushStartMarker(CommandName:GDBString);
41                                  procedure PushEndMarker;
42                                  procedure PushStone;
43                                  procedure PushChangeCommand(_obj:GDBPointer;_fieldsize:PtrInt);overload;
undonull44                                  function undo(out msg:string;prevheap:TArrayIndex;overlay:GDBBoolean):TUndoRedoResult;
45                                  procedure KillLastCommand;
redonull46                                  function redo(out msg:string):TUndoRedoResult;
47                                  constructor init;
48                                  procedure doOnUndoRedo;
PushBackDatanull49                                  function PushBackData(const data:GDBPointer):TArrayIndex;virtual;
50                                  Procedure ClearFrom(cc:TArrayIndex);
51 
CreateTTypedChangeCommandnull52                                  function CreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
PushCreateTTypedChangeCommandnull53                                  function PushCreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
54 
55                            end;
56 implementation
57 
58 procedure TZctnrVectorUndoCommands.doOnUndoRedo;
59 begin
60   if assigned(onUndoRedo)then
61                              onUndoRedo;
62 end;
63 
64 procedure TZctnrVectorUndoCommands.PushStartMarker(CommandName:GDBString);
65 var
66    pmarker:PTMarkerCommand;
67 begin
68      inc(startmarkercount);
69      if startmarkercount=1 then
70      begin
71      GDBGetMem({$IFDEF DEBUGBUILD}'{30D8D2A8-1130-40FB-81BC-10C7D9A1FF38}',{$ENDIF}pointer(pmarker),sizeof(TMarkerCommand));
72      pmarker^.init(CommandName,-1);
73      currentcommandstartmarker:=self.PushBackData(pmarker);
74      inc(CurrentCommand);
75      end;
76 end;
77 procedure TZctnrVectorUndoCommands.PushStone;
78 var
79    pmarker:PTMarkerCommand;
80 begin
81      //inc(startmarkercount);
82      //if startmarkercount=1 then
83      begin
84      GDBGetMem({$IFDEF DEBUGBUILD}'{30D8D2A8-1130-40FB-81BC-10C7D9A1FF38}',{$ENDIF}pointer(pmarker),sizeof(TMarkerCommand));
85      pmarker^.init('StoneMarker',-2);
86      currentcommandstartmarker:=self.PushBackData(pmarker);
87      inc(CurrentCommand);
88      end;
89 end;
90 procedure TZctnrVectorUndoCommands.PushEndMarker;
91 var
92    pmarker:PTMarkerCommand;
93 begin
94      dec(startmarkercount);
95      if startmarkercount=0 then
96      begin
97      GDBGetMem({$IFDEF DEBUGBUILD}'{F5F5F128-96B3-4AB9-81A1-2B86E0C95EF4}',{$ENDIF}pointer(pmarker),sizeof(TMarkerCommand));
98      pmarker^.init('EndMarker',currentcommandstartmarker);
99      currentcommandstartmarker:=-1;
100      self.PushBackData(pmarker);
101      inc(CurrentCommand);
102      startmarkercount:=0;
103      end;
104 end;
105 //procedure TZctnrVectorUndoCommands.PushTypedChangeCommand(_obj:GDBPointer;_PTypeManager:PUserTypeDescriptor);overload;
106 procedure TZctnrVectorUndoCommands.PushChangeCommand(_obj:GDBPointer;_fieldsize:PtrInt);
107 var
108    pcc:PTChangeCommand;
109 begin
110      if CurrentCommand>0 then
111      begin
112           pcc:=pointer(self.getDataMutable(CurrentCommand-1));
113           if pcc^.GetCommandType=TTC_ChangeCommand then
114           if (pcc^.Addr=_obj)
115           and(pcc^.datasize=_fieldsize) then
116                                              exit;
117      end;
118      GDBGetMem({$IFDEF DEBUGBUILD}'{3A3AAA8F-40EB-415B-BDC2-798712E9F402}',{$ENDIF}pointer(pcc),sizeof(TChangeCommand));
119      pcc^.init(_obj,_fieldsize);
120      inc(CurrentCommand);
121      PushBackData(pcc);
122 end;
123 procedure TZctnrVectorUndoCommands.KillLastCommand;
124 var
125    pcc:PTElementaryCommand;
126    mcounter:integer;
127 begin
128      begin
129           mcounter:=0;
130           repeat
131           pcc:=self.getDataMutable(CurrentCommand-1);
132 
133           if pcc^.GetCommandType=TTC_MEnd then
134                                               begin
135                                               inc(mcounter);
136                                               pcc^.Done;
137                                               end
138      else if pcc^.GetCommandType=TTC_MBegin then
139                                                 begin
140                                                      dec(mcounter);
141                                                      pcc^.Done;
142                                                 end
143      else
144           pcc^.Done;
145           dec(CurrentCommand);
146           until mcounter=0;
147      end;
148      count:=self.CurrentCommand;
149 end;
undonull150 function TZctnrVectorUndoCommands.undo(out msg:string;prevheap:TArrayIndex;overlay:GDBBoolean):TUndoRedoResult;
151 var
152    pcc:PTElementaryCommand;
153    mcounter:integer;
154 begin
155      msg:='';
156      result:=URROk;
157      if CurrentCommand>prevheap then
158      begin
159           mcounter:=0;
160           repeat
161           pcc:=self.getDataMutable(CurrentCommand-1);
162 
163           if pcc^.GetCommandType=TTC_MEnd then
164                                               begin
165                                               inc(mcounter);
166                                               //pcc^.undo;
167                                               end
168      else if pcc^.GetCommandType=TTC_MBegin then
169                                                 begin
170                                                      dec(mcounter);
171                                                      if mcounter=0 then
172                                                      {HistoryOutStr}msg:=msg+('Undo "'+PTMarkerCommand(pcc)^.Name+'"');
173                                                      //pcc^.undo;
174                                                 end
175      else if pcc^.GetCommandType=TTC_MNotUndableIfOverlay then
176                                                 begin
177                                                      if overlay then
178                                                           result:=URRNoCommandsToUndo;
179                                                 end
180      else
181           pcc^.undo;
182 
183           if (pcc^.GetCommandType<>TTC_MNotUndableIfOverlay)then
184                                                               dec(CurrentCommand)
185                                                             else
186                                                                 if not overlay then
187                                                                 dec(CurrentCommand);
188           until mcounter=0;
189      end
190      else
191          begin
192          if overlay then
193                         result:=URRNoCommandsToUndo
194                     else
195                         result:=URRNoCommandsToUndoInOverlayMode;
196          end;
197      {DC:=gdb.GetCurrentDWG^.CreateDrawingRC;
198      gdb.GetCurrentROOT^.FormatAfterEdit(gdb.GetCurrentDWG^,dc);}
199      doOnUndoRedo;
200 end;
redonull201 function TZctnrVectorUndoCommands.redo(out msg:string):TUndoRedoResult;
202 var
203    pcc:PTElementaryCommand;
204    mcounter:integer;
205 begin
206      if CurrentCommand<count then
207      begin
208           {pcc:=pointer(self.getDataMutable(CurrentCommand));
209           pcc^.Comit;
210           inc(CurrentCommand);}
211           mcounter:=0;
212           repeat
213           pcc:=self.getDataMutable(CurrentCommand);
214 
215           if pcc^.GetCommandType=TTC_MEnd then
216                                               begin
217                                               inc(mcounter);
218                                               pcc^.undo;
219                                               end
220      else if pcc^.GetCommandType=TTC_MBegin then
221                                                 begin
222                                                      if mcounter=0 then
223                                                      {HistoryOutStr}msg:=msg+('Redo "'+PTMarkerCommand(pcc)^.Name+'"');
224                                                      dec(mcounter);
225                                                      pcc^.undo;
226                                                 end
227      else pcc^.comit;
228           inc(CurrentCommand);
229           until mcounter=0;
230           result:=URROk;
231      end
232      else
233          result:=URRNoCommandsToRedo;
234      {dc:=gdb.GetCurrentDWG^.CreateDrawingRC;
235      gdb.GetCurrentROOT^.FormatAfterEdit(gdb.GetCurrentDWG^,dc);}
236      doOnUndoRedo;
237 end;
238 
239 constructor TZctnrVectorUndoCommands.init;
240 begin
241      inherited init({$IFDEF DEBUGBUILD}'{EF79AD53-2ECF-4848-8EDA-C498803A4188}',{$ENDIF}1);
242      CurrentCommand:=0;
243      onUndoRedo:=nil;;
244 end;
245 procedure TZctnrVectorUndoCommands.ClearFrom(cc:TArrayIndex);
246 begin
247      cleareraseobjfrom2(cc);
248      CurrentCommand:=Count;
249 end;
250 
TZctnrVectorUndoCommands.PushBackDatanull251 function TZctnrVectorUndoCommands.PushBackData(const data:GDBPointer):TArrayIndex;
252 begin
253      if self.CurrentCommand<count then
254                                        self.cleareraseobjfrom2(self.CurrentCommand);
255      result:=inherited PushBackData(data);
256 end;
CreateTTypedChangeCommandnull257 function TZctnrVectorUndoCommands.CreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
258 begin
259      gdbgetmem({$IFDEF DEBUGBUILD}'{6D631C2E-57FF-4553-991B-332464B7495E}',{$ENDIF}result,sizeof(TTypedChangeCommand));
260      result^.Assign(PDataInstance,PType);
261 end;
PushCreateTTypedChangeCommandnull262 function TZctnrVectorUndoCommands.PushCreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
263 begin
264   if CurrentCommand>0 then
265   begin
266        result:=pointer(self.getDataMutable(CurrentCommand-1));
267        if result^.GetCommandType=TTC_ChangeCommand then
268        if (result^.Addr=PDataInstance)
269        and(result^.PTypeManager=PType)
270                                                 then
271                                                     exit;
272   end;
273   result:=CreateTTypedChangeCommand(PDataInstance,PType);
274   {if CurrentCommand<>count then
275                                self.cleareraseobjfrom2(CurrentCommand);}
276 
277   PushBackData(result);
278   inc(CurrentCommand);
279 end;
280 
281 begin
282 end.
283 
284