8780603af66babda7ab35daba7262e5c11c869d2
[occt.git] / src / TDocStd / TDocStd_MultiTransactionManager.cxx
1 // Created on: 2002-11-19
2 // Created by: Vladimir ANIKIN
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
17 #include <Standard_Type.hxx>
18 #include <TCollection_ExtendedString.hxx>
19 #include <TDocStd_ApplicationDelta.hxx>
20 #include <TDocStd_Document.hxx>
21 #include <TDocStd_MultiTransactionManager.hxx>
22
23 IMPLEMENT_STANDARD_RTTIEXT(TDocStd_MultiTransactionManager,Standard_Transient)
24
25 //=======================================================================
26 //function : TDocStd_MultiTransactionManager
27 //purpose  : Constructor
28 //=======================================================================
29 TDocStd_MultiTransactionManager::TDocStd_MultiTransactionManager ()
30 {
31   myUndoLimit = 0;
32   myOpenTransaction = Standard_False;
33   myIsNestedTransactionMode = Standard_False;
34   myOnlyTransactionModification = Standard_False;
35 }
36
37 //=======================================================================
38 //function : SetUndoLimit
39 //purpose  : 
40 //=======================================================================
41
42 void TDocStd_MultiTransactionManager::SetUndoLimit(const Standard_Integer theLimit)
43 {
44   myUndoLimit = theLimit;
45
46   CommitCommand ();
47   
48   Standard_Integer n = myUndos.Length() - myUndoLimit;
49   while (n > 0) {
50     RemoveLastUndo();
51     --n;
52   }
53
54   Standard_Integer i;
55   for(i = myDocuments.Length(); i > 0; i--)
56     myDocuments.Value(i)->SetUndoLimit(myUndoLimit);
57
58 }
59
60 //=======================================================================
61 //function : Undo
62 //purpose  : 
63 //=======================================================================
64
65 void TDocStd_MultiTransactionManager::Undo()
66 {
67   if (myUndos.IsEmpty()) return;
68   const TDocStd_SequenceOfDocument& docs = myUndos.First()->GetDocuments();
69   Standard_Integer i;
70   for (i = docs.Length(); i > 0; i--) {
71     Handle(TDocStd_Document) doc = docs.Value(i);
72     if (doc.IsNull() || doc->GetAvailableUndos() == 0) continue;
73     doc->Undo();
74   }
75   myRedos.Prepend(myUndos.First());
76   myUndos.Remove(1);
77   myOpenTransaction = Standard_False;
78 }
79
80 //=======================================================================
81 //function : Redo
82 //purpose  : 
83 //=======================================================================
84
85 void TDocStd_MultiTransactionManager::Redo() {
86   if (myRedos.IsEmpty()) return;
87   const TDocStd_SequenceOfDocument& docs = myRedos.First()->GetDocuments();
88   Standard_Integer i;
89   for (i = docs.Length(); i > 0; i--) {
90     Handle(TDocStd_Document) doc = docs.Value(i);
91     if (doc.IsNull() || doc->GetAvailableRedos() == 0) continue;
92     doc->Redo();
93   }
94   myUndos.Prepend(myRedos.First());
95   myRedos.Remove(1);
96   myOpenTransaction = Standard_False;
97 }
98
99 //=======================================================================
100 //function : OpenCommand
101 //purpose  : 
102 //=======================================================================
103
104 void TDocStd_MultiTransactionManager::OpenCommand() {
105   if (myOpenTransaction) {
106 #ifdef OCCT_DEBUG
107     std::cout << "TDocStd_MultiTransactionManager::OpenCommand(): "
108             "Can't start new application transaction while a "
109             "previous one is not commited or aborted" << std::endl;
110 #endif
111     throw Standard_Failure("Can't start new application transaction"
112                             "while a previous one is not commited or aborted");
113   }
114   myOpenTransaction = Standard_True;
115   Standard_Integer i;
116   for(i = myDocuments.Length(); i > 0; i--) {
117     while(myDocuments.Value(i)->HasOpenCommand())
118       myDocuments.Value(i)->AbortCommand();
119     myDocuments.Value(i)->OpenCommand();
120   }
121 }
122
123 //=======================================================================
124 //function : AbortCommand
125 //purpose  : 
126 //=======================================================================
127
128 void TDocStd_MultiTransactionManager::AbortCommand() {
129   myOpenTransaction = Standard_False;
130   Standard_Integer i;
131   for(i = myDocuments.Length(); i > 0; i--) {
132     while(myDocuments.Value(i)->HasOpenCommand())
133       myDocuments.Value(i)->AbortCommand();
134   }
135 }
136
137 //=======================================================================
138 //function : CommitCommand
139 //purpose  : 
140 //=======================================================================
141
142 Standard_Boolean TDocStd_MultiTransactionManager::CommitCommand()
143 {
144   Handle(TDocStd_ApplicationDelta) aDelta = new TDocStd_ApplicationDelta;
145   Standard_Boolean isCommited = Standard_False;
146   Standard_Integer i;
147   for(i = myDocuments.Length(); i > 0; i--) {
148     isCommited = Standard_False;
149     while(myDocuments.Value(i)->HasOpenCommand())
150       if (myDocuments.Value(i)->CommitCommand())
151         isCommited = Standard_True;
152     if(isCommited) {
153       aDelta->GetDocuments().Append(myDocuments.Value(i));
154     }
155   }
156   
157   if (aDelta->GetDocuments().Length()) {
158     myUndos.Prepend(aDelta);
159     if (myUndos.Length() > myUndoLimit) {
160       RemoveLastUndo();
161     }
162     myRedos.Clear();
163     isCommited = Standard_True;
164   }
165   myOpenTransaction = Standard_False;
166   return isCommited;
167 }
168
169 //=======================================================================
170 //function : CommitCommand
171 //purpose  : 
172 //=======================================================================
173
174 Standard_Boolean TDocStd_MultiTransactionManager::CommitCommand
175                         (const TCollection_ExtendedString& theName)
176 {
177   Standard_Boolean isCommited = CommitCommand();
178   if (isCommited && myUndos.Length())
179     myUndos.First()->SetName(theName);
180   return isCommited;
181 }
182
183 //=======================================================================
184 //function : DumpTransaction
185 //purpose  : 
186 //=======================================================================
187
188 void TDocStd_MultiTransactionManager::DumpTransaction(Standard_OStream& anOS) const
189 {
190   Standard_Integer i;
191   if(myDocuments.Length() == 0)
192     anOS << "Manager is empty" << std::endl;
193   else {
194     if(myDocuments.Length() == 1)
195       anOS << "There is one document ( ";
196     else
197       anOS << "There are " << myDocuments.Length() << " documents ( ";
198     for(i = 1; i <= myDocuments.Length(); i++) {
199       Handle(Standard_Transient) aDoc (myDocuments.Value(i));
200       anOS << "\"" << aDoc.get();
201       anOS << "\" ";
202     }
203     anOS << ") in the manager "  << std::endl;
204
205     if(myIsNestedTransactionMode)
206       anOS << "Nested transaction mode is on" << std::endl;
207     else
208       anOS << "Nested transaction mode is off" << std::endl;
209
210     anOS << " " << std::endl;
211   }
212
213   for (i = myUndos.Length(); i > 0; i--) {
214     Handle(TDocStd_ApplicationDelta) delta = myUndos.Value(i);
215     anOS<<" Undo: ";
216     delta->Dump(anOS);
217     if (i == 1) {
218       anOS<<"  < Last action"<<std::endl;
219     } else {
220       anOS<<std::endl;
221     }
222   }
223   for (i = 1; i <= myRedos.Length(); i++) {
224     Handle(TDocStd_ApplicationDelta) delta = myRedos.Value(i);
225     anOS<<" Redo: ";
226     delta->Dump(anOS);
227     anOS<<std::endl;
228   }
229 }
230
231 //=======================================================================
232 //function : RemoveLastUndo
233 //purpose  : 
234 //=======================================================================
235
236 void TDocStd_MultiTransactionManager::RemoveLastUndo()
237 {
238   if(myUndos.Length() == 0) return;
239   const TDocStd_SequenceOfDocument& docs = myUndos.Last()->GetDocuments();
240   Standard_Integer i;
241   for (i = 1; i <= docs.Length(); i++) {
242     docs.Value(i)->RemoveFirstUndo();
243   }
244   myUndos.Remove(myUndos.Length());
245 }
246
247 //=======================================================================
248 //function : AddDocument
249 //purpose  : 
250 //=======================================================================
251
252 void TDocStd_MultiTransactionManager::AddDocument
253   (const Handle(TDocStd_Document)& theDoc)
254 {
255   Standard_Integer i;
256   for(i = myDocuments.Length(); i > 0; i--)
257     if(myDocuments.Value(i) == theDoc)
258       return; // the document is already added to the list
259
260   if(theDoc->IsNestedTransactionMode() !=
261      myIsNestedTransactionMode)
262     theDoc->SetNestedTransactionMode(myIsNestedTransactionMode);
263
264   theDoc->SetModificationMode(myOnlyTransactionModification);
265   
266   myDocuments.Append(theDoc);
267   theDoc->SetUndoLimit(myUndoLimit);
268   if(myOpenTransaction) {
269     if(!theDoc->HasOpenCommand())
270       theDoc->OpenCommand();
271   }
272   else {
273     if(theDoc->HasOpenCommand())
274       theDoc->CommitCommand();
275   }
276   theDoc->ClearUndos();
277   theDoc->ClearRedos();
278 }
279
280 //=======================================================================
281 //function : RemoveDocument
282 //purpose  : 
283 //=======================================================================
284
285 void TDocStd_MultiTransactionManager::RemoveDocument
286   (const Handle(TDocStd_Document)& theDoc)
287 {
288   Standard_Integer i;
289   for(i = myDocuments.Length(); i > 0; i--) {
290     if(myDocuments.Value(i) == theDoc)
291       myDocuments.Remove(i);
292   }
293   for (i = myUndos.Length(); i > 0; i--) {
294     Handle(TDocStd_ApplicationDelta) delta = myUndos.Value(i);
295     TDocStd_SequenceOfDocument& docs = delta->GetDocuments();
296     for(Standard_Integer j = docs.Length(); j > 0; j--) {
297       if(docs.Value(j) == theDoc) {
298         docs.Remove(j);
299         if(docs.Length() == 0)
300           myUndos.Remove(i);
301       }
302     }
303   }
304   for (i = myRedos.Length(); i > 0; i--) {
305     Handle(TDocStd_ApplicationDelta) delta = myRedos.Value(i);
306     TDocStd_SequenceOfDocument& docs = delta->GetDocuments();
307     for(Standard_Integer j = docs.Length(); j > 0; j--) {
308       if(docs.Value(j) == theDoc) {
309         docs.Remove(j);
310         if(docs.Length() == 0)
311           myRedos.Remove(i);
312       }
313     }
314   }
315 }
316
317 //=======================================================================
318 //function : SetNestedTransactionMode
319 //purpose  : 
320 //=======================================================================
321
322 void TDocStd_MultiTransactionManager::SetNestedTransactionMode
323   (const Standard_Boolean isAllowed)
324 {
325   myIsNestedTransactionMode = isAllowed;
326   Standard_Integer i;
327   for(i = myDocuments.Length(); i > 0; i--) {
328     if(myDocuments.Value(i)->IsNestedTransactionMode() != myIsNestedTransactionMode)
329       myDocuments.Value(i)->SetNestedTransactionMode(myIsNestedTransactionMode);
330   }
331 }
332
333 //=======================================================================
334 //function : SetModificationMode
335 //purpose  : if theTransactionOnly is True changes is denied outside transactions
336 //=======================================================================
337
338 void TDocStd_MultiTransactionManager::SetModificationMode
339   (const Standard_Boolean theTransactionOnly)
340 {
341   myOnlyTransactionModification = theTransactionOnly;
342
343   Standard_Integer i;
344   for(i = myDocuments.Length(); i > 0; i--) {
345     myDocuments.Value(i)->SetModificationMode(myOnlyTransactionModification);
346   }
347 }
348
349 //=======================================================================
350 //function : ClearUndos
351 //purpose  : 
352 //=======================================================================
353
354 void TDocStd_MultiTransactionManager::ClearUndos()
355 {
356   AbortCommand();
357
358   myUndos.Clear();
359   Standard_Integer i;
360   for(i = myDocuments.Length(); i > 0; i--) {
361     myDocuments.Value(i)->ClearUndos();
362   }
363 }
364
365 //=======================================================================
366 //function : ClearRedos
367 //purpose  : 
368 //=======================================================================
369
370 void TDocStd_MultiTransactionManager::ClearRedos()
371 {
372   AbortCommand();
373
374   myRedos.Clear();
375   Standard_Integer i;
376   for(i = myDocuments.Length(); i > 0; i--) {
377     myDocuments.Value(i)->ClearRedos();
378   }
379 }
380
381
382