1 // Copyright (c) 2006-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include <TDocStd_Document.ixx>
16 #include <TDocStd.hxx>
18 #include <TDocStd_XLink.hxx>
19 #include <TDocStd_XLinkIterator.hxx>
20 #include <TDocStd_Application.hxx>
22 #include <TDocStd_Context.hxx>
23 #include <TCollection_ExtendedString.hxx>
24 #include <TCollection_AsciiString.hxx>
25 #include <TDF_AttributeIterator.hxx>
26 #include <TDF_ListIteratorOfDeltaList.hxx>
27 #include <TDF_AttributeList.hxx>
28 #include <TDF_ListIteratorOfAttributeList.hxx>
29 #include <TDF_AttributeDelta.hxx>
30 #include <TDF_AttributeDeltaList.hxx>
31 #include <TDF_ListIteratorOfAttributeDeltaList.hxx>
32 #include <TDF_Label.hxx>
33 #include <TDF_Delta.hxx>
34 #include <TDocStd_CompoundDelta.hxx>
35 #include <TDocStd_Owner.hxx>
36 #include <TDocStd_Modified.hxx>
38 #include <TDF_IDMap.hxx>
39 #include <TDocStd_LabelIDMapDataMap.hxx>
41 #include <CDM_MetaData.hxx>
43 // List should have a RemoveLast...
44 #define TDocStd_List_RemoveLast(theList) \
45 TDF_ListIteratorOfDeltaList it(theList); \
46 Standard_Integer i,n = theList.Extent(); \
47 for (i = 1; i < n; i++) it.Next(); \
56 #define SRN_DELTA_COMPACT
58 //=======================================================================
61 //=======================================================================
63 Handle(TDocStd_Document) TDocStd_Document::Get (const TDF_Label& acces)
65 return TDocStd_Owner::GetDocument(acces.Data());
68 //=======================================================================
69 //function : TDocStd_Document
71 //=======================================================================
74 TDocStd_Document::TDocStd_Document(const TCollection_ExtendedString& aStorageFormat) :
75 myStorageFormat(aStorageFormat),
76 myData (new TDF_Data()),
79 myIsNestedTransactionMode(0)
81 TDF_Transaction* pTr = new TDF_Transaction (myData,"UNDO");
82 myUndoTransaction = *pTr; delete pTr;
83 TDocStd_Owner::SetDocument(myData,this);
85 #ifdef SRN_DELTA_COMPACT
92 //=======================================================================
95 //=======================================================================
97 Standard_Boolean TDocStd_Document::IsSaved() const
99 return CDM_Document::IsStored();
103 //=======================================================================
106 //=======================================================================
108 TCollection_ExtendedString TDocStd_Document::GetName () const
110 return CDM_Document::MetaData()->Name();
113 //=======================================================================
116 //=======================================================================
118 TCollection_ExtendedString TDocStd_Document::GetPath () const
120 return CDM_Document::MetaData()->Path();
124 //=======================================================================
127 //=======================================================================
129 void TDocStd_Document::SetData (const Handle(TDF_Data)& D)
132 TDF_Transaction* pTr = new TDF_Transaction(myData,"UNDO");
133 myUndoTransaction = *pTr; delete pTr;
136 //=======================================================================
139 //=======================================================================
141 Handle(TDF_Data) TDocStd_Document::GetData () const
146 //=======================================================================
149 //=======================================================================
151 TDF_Label TDocStd_Document::Main () const
153 return myData->Root().FindChild(1,Standard_True);
156 //=======================================================================
159 //=======================================================================
161 Standard_Boolean TDocStd_Document::IsEmpty() const
163 TDF_AttributeIterator It (Main());
167 //=======================================================================
170 //=======================================================================
172 Standard_Boolean TDocStd_Document::IsValid() const
174 return TDocStd_Modified::IsEmpty(Main());
177 //=======================================================================
178 //function : SetModified
180 //=======================================================================
182 void TDocStd_Document::SetModified (const TDF_Label& L)
184 TDocStd_Modified::Add(L);
187 //=======================================================================
188 //function : IsModified
190 //=======================================================================
191 //Standard_Boolean TDocStd_Document::IsModified (const TDF_Label& L) const
193 // return TDocStd_Modified::Contains(L);
196 //=======================================================================
197 //function : PurgeModified
199 //=======================================================================
201 void TDocStd_Document::PurgeModified()
203 TDocStd_Modified::Clear(Main());
206 //=======================================================================
207 //function : GetModified
209 //=======================================================================
211 const TDF_LabelMap& TDocStd_Document::GetModified() const
213 return TDocStd_Modified::Get(Main());
218 //=======================================================================
221 //=======================================================================
223 void TDocStd_Document::Update(const Handle(CDM_Document)& /*aToDocument*/,
224 const Standard_Integer aReferenceIdentifier,
225 const Standard_Address aModifContext)
227 const TDocStd_Context CC = *((TDocStd_Context *)&aModifContext);
228 if (CC.ModifiedReferences() || !IsUpToDate(aReferenceIdentifier)) {
229 TCollection_AsciiString aDocEntry(aReferenceIdentifier);
230 UpdateReferences(aDocEntry);
231 SetIsUpToDate(aReferenceIdentifier);
235 //=======================================================================
236 //function : NewCommand
238 //=======================================================================
240 void TDocStd_Document::NewCommand()
243 if (myUndoTransaction.IsOpen() && myData->Transaction() > 1) {
244 Standard_DomainError::Raise ("NewCommand : many open transactions");
252 cout<<"End NewCommand"<<endl;
257 //=======================================================================
258 //function : HasOpenCommand
260 //=======================================================================
261 Standard_Boolean TDocStd_Document::HasOpenCommand() const
263 return myUndoTransaction.IsOpen();
266 //=======================================================================
267 //function : OpenCommand
269 //=======================================================================
271 void TDocStd_Document::OpenCommand ()
273 if (!myIsNestedTransactionMode && myUndoTransaction.IsOpen()) {
274 Standard_DomainError::Raise("TDocStd_Document::OpenCommand : already open");
277 // if (myUndoLimit != 0) myUndoTransaction.Open();
280 //=======================================================================
281 //function : CommitCommand
283 //=======================================================================
285 Standard_Boolean TDocStd_Document::CommitCommand ()
287 return CommitTransaction();
291 //=======================================================================
292 //function : AbortCommand
294 //=======================================================================
296 void TDocStd_Document::AbortCommand ()
302 //=======================================================================
303 //function : CommitTransaction
304 //purpose : Private method.
305 //=======================================================================
307 Standard_Boolean TDocStd_Document::CommitTransaction()
309 myData->AllowModification(Standard_True);
311 Standard_Boolean isDone = Standard_False;
312 // nested transaction mode
313 if (myIsNestedTransactionMode && myUndoTransaction.IsOpen()) {
315 Handle(TDF_Delta) D = myUndoTransaction.Commit(Standard_True);
316 Handle(TDocStd_CompoundDelta) aCompDelta =
317 Handle(TDocStd_CompoundDelta)::DownCast(myUndoFILO.First());
318 AppendDeltaToTheFirst(aCompDelta, D);
320 myUndoFILO.RemoveFirst();
321 if(myUndoFILO.Extent()) {
322 aCompDelta = Handle(TDocStd_CompoundDelta)::DownCast(myUndoFILO.First());
323 AppendDeltaToTheFirst(aCompDelta, D);
324 myUndoTransaction.Open();
329 myRedos.Clear(); // if we push an Undo we clear the redos
330 isDone = Standard_True;
334 // deny modifications if the transaction is not opened
335 if(myOnlyTransactionModification) {
336 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
337 ? Standard_True :Standard_False);
343 if (myUndoLimit != 0 && myUndoTransaction.IsOpen()) {
345 Handle(TDF_Delta) D = myUndoTransaction.Commit(Standard_True);
346 if (!(D.IsNull() || D->IsEmpty())) {
347 isDone = Standard_True;
349 myRedos.Clear(); // if we push an Undo we clear the redos
350 myUndos.Append(D); // New undos are at the end of the list
351 // Check the limit to remove the oldest one
352 if (myUndos.Extent() > myUndoLimit) {
353 #ifdef SRN_DELTA_COMPACT
354 Handle(TDF_Delta) aDelta = myUndos.First();
356 myUndos.RemoveFirst();
357 #ifdef SRN_DELTA_COMPACT
358 if(myFromUndo == aDelta) {
359 //The oldest Undo delta coincides with `from` delta
360 if(myUndos.Extent() == 1) { //There is the only Undo
361 myFromUndo.Nullify();
362 myFromRedo.Nullify();
365 myFromUndo = myUndos.First();
373 // deny or allow modifications acording to transaction state
374 if(myOnlyTransactionModification) {
375 myData->AllowModification (myUndoTransaction.IsOpen() && myUndoLimit
376 ? Standard_True :Standard_False);
379 // Notify CDM_Application of the successful commit
380 if (isDone && IsOpened()) {
381 const Handle(TDocStd_Application) anAppli =
382 Handle(TDocStd_Application)::DownCast(Application());
383 if (!anAppli.IsNull())
384 anAppli -> OnCommitTransaction (this);
390 //=======================================================================
391 //function : AbortTransaction
392 //purpose : Private method.
393 //=======================================================================
395 void TDocStd_Document::AbortTransaction()
397 myData->AllowModification(Standard_True);
399 if (myUndoTransaction.IsOpen())
400 if (myUndoLimit != 0)
401 myUndoTransaction.Abort();
403 if (myIsNestedTransactionMode && myUndoFILO.Extent()) {
404 if (!myUndoFILO.First()->IsEmpty())
405 myData->Undo(myUndoFILO.First(),Standard_True);
406 myUndoFILO.RemoveFirst();
407 if (myUndoFILO.Extent())
408 myUndoTransaction.Open();
410 // deny or allow modifications acording to transaction state
411 if (myOnlyTransactionModification) {
412 myData->AllowModification (myUndoTransaction.IsOpen() && myUndoLimit
413 ? Standard_True :Standard_False);
415 // Notify CDM_Application of the event
417 const Handle(TDocStd_Application) anAppli =
418 Handle(TDocStd_Application)::DownCast(Application());
419 if (!anAppli.IsNull())
420 anAppli -> OnAbortTransaction (this);
425 //=======================================================================
426 //function :OpenTransaction
427 //purpose : Private method.
428 //=======================================================================
430 void TDocStd_Document::OpenTransaction()
432 myData->AllowModification(Standard_True);
434 // nested transaction mode
435 if (myIsNestedTransactionMode) {
437 if (myUndoTransaction.IsOpen()) {
438 Handle(TDF_Delta) D = myUndoTransaction.Commit(Standard_True);
439 Handle(TDocStd_CompoundDelta) aCompDelta =
440 Handle(TDocStd_CompoundDelta)::DownCast(myUndoFILO.First());
441 AppendDeltaToTheFirst(aCompDelta, D);
443 Standard_Integer aLastTime = myData->Time();
444 if (myUndoFILO.Extent())
445 aLastTime = myUndoFILO.First()->EndTime();
446 Handle(TDocStd_CompoundDelta) aCompoundDelta =
447 new TDocStd_CompoundDelta;
448 aCompoundDelta->Validity(aLastTime, aLastTime);
449 myUndoFILO.Prepend(aCompoundDelta);
452 if (myUndoLimit != 0) myUndoTransaction.Open();
454 // deny or allow modifications acording to transaction state
455 if (myOnlyTransactionModification) {
456 myData->AllowModification (myUndoTransaction.IsOpen() && myUndoLimit
457 ? Standard_True :Standard_False);
459 // Notify CDM_Application of the event
461 const Handle(TDocStd_Application) anAppli =
462 Handle(TDocStd_Application)::DownCast(Application());
463 if (!anAppli.IsNull())
464 anAppli -> OnOpenTransaction (this);
468 //=======================================================================
469 //function : SetUndoLimit
471 //=======================================================================
473 void TDocStd_Document::SetUndoLimit(const Standard_Integer L)
475 #ifdef SRN_DELTA_COMPACT
476 myFromUndo.Nullify(); //Compaction has to aborted
477 myFromRedo.Nullify();
480 CommitTransaction ();
481 myUndoLimit = (L > 0) ? L : 0;
482 Standard_Integer n = myUndos.Extent() - myUndoLimit;
484 myUndos.RemoveFirst();
487 // deny or allow modifications acording to transaction state
488 if(myOnlyTransactionModification) {
489 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
490 ? Standard_True :Standard_False);
492 //OpenTransaction(); dp 15/10/99
495 //=======================================================================
496 //function : GetUndoLimit
498 //=======================================================================
500 Standard_Integer TDocStd_Document::GetUndoLimit() const
505 //=======================================================================
508 //=======================================================================
510 Standard_Integer TDocStd_Document::GetAvailableUndos() const
512 return myUndos.Extent();
515 //=======================================================================
516 //function : ClearUndos
518 //=======================================================================
520 void TDocStd_Document::ClearUndos()
524 #ifdef SRN_DELTA_COMPACT
525 myFromRedo.Nullify();
526 myFromUndo.Nullify();
530 //=======================================================================
531 //function : ClearRedos
533 //=======================================================================
535 void TDocStd_Document::ClearRedos()
538 #ifdef SRN_DELTA_COMPACT
539 myFromRedo.Nullify();
543 //=======================================================================
546 // Some importante notice:
547 // 1) The most recent undo delta is at the end of the list.
548 // 2) Removing the LAST item of a list is tedious, but it is done only on
549 // Undo. Remove first is done at each command if the limit is reached!
550 // 3) To make fun, the redos are not like the undos: the most recent delta
551 // is at the beginning! Like this, it is easier to remove it after use.
552 //=======================================================================
553 Standard_Boolean TDocStd_Document::Undo()
555 // Don't call NewCommand(), because it may commit Interactive Attributes
556 // and generate a undesirable Delta!
558 Standard_Boolean isOpened = myUndoTransaction.IsOpen();
559 Standard_Boolean undoDone = Standard_False;
560 //TDF_Label currentObjectLabel = CurrentLabel (); //Sauve pour usage ulterieur.
562 if (!myUndos.IsEmpty()) {
563 // Reset the transaction
566 // only for nested transaction mode
567 while(myIsNestedTransactionMode && myUndoFILO.Extent())
570 // allow modifications
571 myData->AllowModification(Standard_True);
574 // should test the applicability before.
576 cout<<"DF before Undo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
578 Handle(TDF_Delta) D = myData->Undo(myUndos.Last(),Standard_True);
580 D->SetName(myUndos.Last()->Name());
583 cout<<"DF after Undo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
587 // Remove the last Undo
588 TDocStd_List_RemoveLast(myUndos);
589 undoDone = Standard_True;
592 if (isOpened && undoDone) OpenTransaction();
594 // deny or allow modifications acording to transaction state
595 if(myOnlyTransactionModification) {
596 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
597 ? Standard_True :Standard_False);
603 //=======================================================================
604 //function : GetAvailableRedos
606 //=======================================================================
608 Standard_Integer TDocStd_Document:: GetAvailableRedos() const
610 // should test the applicability before.
611 return myRedos.Extent();
614 //=======================================================================
617 //=======================================================================
618 Standard_Boolean TDocStd_Document::Redo()
620 Standard_Boolean isOpened = myUndoTransaction.IsOpen();
621 Standard_Boolean undoDone = Standard_False;
622 // TDF_Label currentObjectLabel = CurrentLabel();//Sauve pour usage ulterieur.
623 if (!myRedos.IsEmpty()) {
624 // should test the applicability before.
625 // Reset the transaction
628 // only for nested transaction mode
629 while(myIsNestedTransactionMode && myUndoFILO.Extent())
632 // allow modifications
633 myData->AllowModification(Standard_True);
637 cout<<"DF before Redo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
639 Handle(TDF_Delta) D = myData->Undo(myRedos.First(),Standard_True);
641 D->SetName(myRedos.First()->Name());
644 cout<<"DF after Redo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
646 // Push the redo of the redo as an undo (got it !)
648 // remove the Redo from the head
649 myRedos.RemoveFirst();
650 undoDone = Standard_True;
653 if (isOpened && undoDone) OpenTransaction();
655 // deny or allow modifications acording to transaction state
656 if(myOnlyTransactionModification) {
657 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
658 ? Standard_True :Standard_False);
664 //=======================================================================
665 //function : UpdateReferences
667 //=======================================================================
669 void TDocStd_Document::UpdateReferences(const TCollection_AsciiString& aDocEntry)
672 TDF_AttributeList aRefList;
673 TDocStd_XLink* xRefPtr;
674 for (TDocStd_XLinkIterator xItr (this); xItr.More(); xItr.Next()) {
675 xRefPtr = xItr.Value();
676 if (xRefPtr->DocumentEntry() == aDocEntry) {
677 aRefList.Append(xRefPtr->Update());
680 TDF_ListIteratorOfAttributeList It(aRefList);
681 for (;It.More();It.Next()) {
682 // // mise a jour import
683 SetModified(It.Value()->Label());
688 //=======================================================================
689 //function : GetUndos
691 //=======================================================================
693 const TDF_DeltaList& TDocStd_Document::GetUndos() const
699 //=======================================================================
700 //function : GetRedos
702 //=======================================================================
704 const TDF_DeltaList& TDocStd_Document::GetRedos() const
709 //=======================================================================
710 //function : InitDeltaCompaction
712 //=======================================================================
714 Standard_Boolean TDocStd_Document::InitDeltaCompaction()
716 #ifdef SRN_DELTA_COMPACT
717 if (myUndoLimit == 0 || myUndos.Extent() == 0) {
718 myFromRedo.Nullify();
719 myFromUndo.Nullify();
720 return Standard_False; //No Undos to compact
723 myFromRedo.Nullify();
725 myFromUndo = myUndos.Last();
726 if(myRedos.Extent() > 0) myFromRedo = myRedos.First();
728 return Standard_True;
731 //=======================================================================
732 //function : PerformDeltaCompaction
734 //=======================================================================
736 Standard_Boolean TDocStd_Document::PerformDeltaCompaction()
738 #ifdef SRN_DELTA_COMPACT
739 if(myFromUndo.IsNull()) return Standard_False; //Redo can be Null for this operation
742 Handle(TDocStd_CompoundDelta) aCompoundDelta = new TDocStd_CompoundDelta;
743 TDF_ListIteratorOfDeltaList anIterator(myUndos);
744 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator;
745 TDocStd_LabelIDMapDataMap aMap;
746 Standard_Boolean isFound = Standard_False, isTimeSet = Standard_False;
750 for(; anIterator.More(); anIterator.Next()) {
752 if(myFromUndo == anIterator.Value()) isFound = Standard_True;
753 aList.Append(anIterator.Value()); //Fill the list of deltas that precede compound delta
757 if(!isTimeSet) { //Set begin and end time when the compound delta is valid
758 aCompoundDelta->Validity(anIterator.Value()->BeginTime(), myUndos.Last()->EndTime());
759 isTimeSet = Standard_True;
762 aDeltasIterator.Initialize(anIterator.Value()->AttributeDeltas());
763 for(; aDeltasIterator.More(); aDeltasIterator.Next()) {
764 if(!aMap.IsBound(aDeltasIterator.Value()->Label())) {
765 TDF_IDMap* pIDMap = new TDF_IDMap();
766 aMap.Bind(aDeltasIterator.Value()->Label(), *pIDMap);
769 if(aMap(aDeltasIterator.Value()->Label()).Add(aDeltasIterator.Value()->ID())) //The attribute is not
770 aCompoundDelta->AddAttributeDelta(aDeltasIterator.Value()); //already in the delta
775 myUndos.Assign(aList);
776 myUndos.Append(aCompoundDelta);
780 if(myFromRedo.IsNull()) {
782 return Standard_True;
787 for(anIterator.Initialize(myRedos); anIterator.More(); anIterator.Next()) {
788 aList.Append(anIterator.Value());
789 if(anIterator.Value() == myFromRedo) break;
793 myRedos.Assign(aList);
795 return Standard_True;
799 //=======================================================================
800 //function : StorageFormat
802 //=======================================================================
804 TCollection_ExtendedString TDocStd_Document::StorageFormat() const
806 return myStorageFormat;
810 //=======================================================================
811 //function : ChangeStorageFormat
813 //=======================================================================
815 void TDocStd_Document::ChangeStorageFormat (const TCollection_ExtendedString& newStorageFormat)
817 if (newStorageFormat != myStorageFormat) {
818 myStorageFormat = newStorageFormat;
819 myResourcesAreLoaded = Standard_False;
820 CDM_Document::LoadResources ();
827 //=======================================================================
828 //function : Recompute
830 //=======================================================================
832 void TDocStd_Document::Recompute ()
834 if (IsValid()) return;
835 // find the top function and execute it
836 // Handle(TDesign_Function) F;
837 // if (Main().FindAttribute(TDesign_Function::GetID(),F)) {
838 // TFunction_Solver slv;
839 // slv.SetTouched(GetModified());
840 // slv.ExecuteFrom(F);
844 //=======================================================================
845 //function : AppendDeltaToTheFirst
846 //purpose : Appends delta to the first delta in the myUndoFILO
847 //=======================================================================
849 void TDocStd_Document::AppendDeltaToTheFirst
850 (const Handle(TDocStd_CompoundDelta)& theDelta1,
851 const Handle(TDF_Delta)& theDelta2)
853 if(theDelta2->IsEmpty()) return;
854 TDocStd_LabelIDMapDataMap aMap;
856 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator1
857 (theDelta1->AttributeDeltas());
858 for(; aDeltasIterator1.More(); aDeltasIterator1.Next()) {
859 TDF_Label aLabel = aDeltasIterator1.Value()->Label();
860 if(!aMap.IsBound(aLabel)) {
862 aMap.Bind(aLabel, aTmpIDMap);
864 Standard_GUID anID = aDeltasIterator1.Value()->ID();
865 TDF_IDMap& anIDMap = aMap.ChangeFind(aLabel);
869 theDelta1->Validity(theDelta1->BeginTime(), theDelta2->EndTime());
870 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator2
871 (theDelta2->AttributeDeltas());
872 for(; aDeltasIterator2.More(); aDeltasIterator2.Next()) {
873 TDF_Label aLabel = aDeltasIterator2.Value()->Label();
874 Standard_GUID anID = aDeltasIterator2.Value()->ID();
875 if(aMap.IsBound(aLabel)) {
876 const TDF_IDMap& anIDMap = aMap.Find(aLabel);
877 if(anIDMap.Contains(anID)) continue;
879 theDelta1->AddAttributeDelta(aDeltasIterator2.Value());
883 //=======================================================================
884 //function : RemoveFirstUndo
886 //=======================================================================
887 void TDocStd_Document::RemoveFirstUndo() {
888 if (myUndos.IsEmpty()) return;
889 myUndos.RemoveFirst();
892 //=======================================================================
893 //function : BeforeClose
895 //=======================================================================
896 void TDocStd_Document::BeforeClose()
898 SetModificationMode(Standard_False);
900 if(myIsNestedTransactionMode)