1 // Copyright (c) 2006-2012 OPEN CASCADE SAS
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
19 #include <TDocStd_Document.ixx>
21 #include <TDocStd.hxx>
23 #include <TDocStd_XLink.hxx>
24 #include <TDocStd_XLinkIterator.hxx>
25 #include <TDocStd_Application.hxx>
27 #include <TDocStd_Context.hxx>
28 #include <TCollection_ExtendedString.hxx>
29 #include <TCollection_AsciiString.hxx>
30 #include <TDF_AttributeIterator.hxx>
31 #include <TDF_ListIteratorOfDeltaList.hxx>
32 #include <TDF_AttributeList.hxx>
33 #include <TDF_ListIteratorOfAttributeList.hxx>
34 #include <TDF_AttributeDelta.hxx>
35 #include <TDF_AttributeDeltaList.hxx>
36 #include <TDF_ListIteratorOfAttributeDeltaList.hxx>
37 #include <TDF_Label.hxx>
38 #include <TDF_Delta.hxx>
39 #include <TDocStd_CompoundDelta.hxx>
40 #include <TDocStd_Owner.hxx>
41 #include <TDocStd_Modified.hxx>
43 #include <TDF_IDMap.hxx>
44 #include <TDocStd_LabelIDMapDataMap.hxx>
46 #include <CDM_MetaData.hxx>
48 // List should have a RemoveLast...
49 #define TDocStd_List_RemoveLast(theList) \
50 TDF_ListIteratorOfDeltaList it(theList); \
51 Standard_Integer i,n = theList.Extent(); \
52 for (i = 1; i < n; i++) it.Next(); \
61 #define SRN_DELTA_COMPACT
63 //=======================================================================
66 //=======================================================================
68 Handle(TDocStd_Document) TDocStd_Document::Get (const TDF_Label& acces)
70 return TDocStd_Owner::GetDocument(acces.Data());
73 //=======================================================================
76 //=======================================================================
77 void TDocStd_Document::Destroy()
79 SetModificationMode(Standard_False);
80 myData->Root().ForgetAllAttributes(Standard_True);
81 myUndoTransaction.Abort();
82 if(!myUndoFILO.IsEmpty())
90 //=======================================================================
91 //function : TDocStd_Document
93 //=======================================================================
96 TDocStd_Document::TDocStd_Document(const TCollection_ExtendedString& aStorageFormat) :
97 myStorageFormat(aStorageFormat),
98 myData (new TDF_Data()),
101 myIsNestedTransactionMode(0)
103 TDF_Transaction* pTr = new TDF_Transaction (myData,"UNDO");
104 myUndoTransaction = *pTr; delete pTr;
105 TDocStd_Owner::SetDocument(myData,this);
107 #ifdef SRN_DELTA_COMPACT
108 myFromUndo.Nullify();
109 myFromRedo.Nullify();
114 //=======================================================================
117 //=======================================================================
119 Standard_Boolean TDocStd_Document::IsSaved() const
121 return CDM_Document::IsStored();
125 //=======================================================================
128 //=======================================================================
130 TCollection_ExtendedString TDocStd_Document::GetName () const
132 return CDM_Document::MetaData()->Name();
135 //=======================================================================
138 //=======================================================================
140 TCollection_ExtendedString TDocStd_Document::GetPath () const
142 return CDM_Document::MetaData()->Path();
146 //=======================================================================
149 //=======================================================================
151 void TDocStd_Document::SetData (const Handle(TDF_Data)& D)
154 TDF_Transaction* pTr = new TDF_Transaction(myData,"UNDO");
155 myUndoTransaction = *pTr; delete pTr;
158 //=======================================================================
161 //=======================================================================
163 Handle(TDF_Data) TDocStd_Document::GetData () const
168 //=======================================================================
171 //=======================================================================
173 TDF_Label TDocStd_Document::Main () const
175 return myData->Root().FindChild(1,Standard_True);
178 //=======================================================================
181 //=======================================================================
183 Standard_Boolean TDocStd_Document::IsEmpty() const
185 TDF_AttributeIterator It (Main());
189 //=======================================================================
192 //=======================================================================
194 Standard_Boolean TDocStd_Document::IsValid() const
196 return TDocStd_Modified::IsEmpty(Main());
199 //=======================================================================
200 //function : SetModified
202 //=======================================================================
204 void TDocStd_Document::SetModified (const TDF_Label& L)
206 TDocStd_Modified::Add(L);
209 //=======================================================================
210 //function : IsModified
212 //=======================================================================
213 //Standard_Boolean TDocStd_Document::IsModified (const TDF_Label& L) const
215 // return TDocStd_Modified::Contains(L);
218 //=======================================================================
219 //function : PurgeModified
221 //=======================================================================
223 void TDocStd_Document::PurgeModified()
225 TDocStd_Modified::Clear(Main());
228 //=======================================================================
229 //function : GetModified
231 //=======================================================================
233 const TDF_LabelMap& TDocStd_Document::GetModified() const
235 return TDocStd_Modified::Get(Main());
240 //=======================================================================
243 //=======================================================================
245 void TDocStd_Document::Update(const Handle(CDM_Document)& /*aToDocument*/,
246 const Standard_Integer aReferenceIdentifier,
247 const Standard_Address aModifContext)
249 const TDocStd_Context CC = *((TDocStd_Context *)&aModifContext);
250 if (CC.ModifiedReferences() || !IsUpToDate(aReferenceIdentifier)) {
251 TCollection_AsciiString aDocEntry(aReferenceIdentifier);
252 UpdateReferences(aDocEntry);
253 SetIsUpToDate(aReferenceIdentifier);
257 //=======================================================================
258 //function : NewCommand
260 //=======================================================================
262 void TDocStd_Document::NewCommand()
265 if (myUndoTransaction.IsOpen() && myData->Transaction() > 1) {
266 Standard_DomainError::Raise ("NewCommand : many open transactions");
274 cout<<"End NewCommand"<<endl;
279 //=======================================================================
280 //function : HasOpenCommand
282 //=======================================================================
283 Standard_Boolean TDocStd_Document::HasOpenCommand() const
285 return myUndoTransaction.IsOpen();
288 //=======================================================================
289 //function : OpenCommand
291 //=======================================================================
293 void TDocStd_Document::OpenCommand ()
295 if (!myIsNestedTransactionMode && myUndoTransaction.IsOpen()) {
296 Standard_DomainError::Raise("TDocStd_Document::OpenCommand : already open");
299 // if (myUndoLimit != 0) myUndoTransaction.Open();
302 //=======================================================================
303 //function : CommitCommand
305 //=======================================================================
307 Standard_Boolean TDocStd_Document::CommitCommand ()
309 return CommitTransaction();
313 //=======================================================================
314 //function : AbortCommand
316 //=======================================================================
318 void TDocStd_Document::AbortCommand ()
324 //=======================================================================
325 //function : CommitTransaction
326 //purpose : Private method.
327 //=======================================================================
329 Standard_Boolean TDocStd_Document::CommitTransaction()
331 myData->AllowModification(Standard_True);
333 Standard_Boolean isDone = Standard_False;
334 // nested transaction mode
335 if (myIsNestedTransactionMode && myUndoTransaction.IsOpen()) {
337 Handle(TDF_Delta) D = myUndoTransaction.Commit(Standard_True);
338 Handle(TDocStd_CompoundDelta) aCompDelta =
339 Handle(TDocStd_CompoundDelta)::DownCast(myUndoFILO.First());
340 AppendDeltaToTheFirst(aCompDelta, D);
342 myUndoFILO.RemoveFirst();
343 if(myUndoFILO.Extent()) {
344 aCompDelta = Handle(TDocStd_CompoundDelta)::DownCast(myUndoFILO.First());
345 AppendDeltaToTheFirst(aCompDelta, D);
346 myUndoTransaction.Open();
351 myRedos.Clear(); // if we push an Undo we clear the redos
352 isDone = Standard_True;
356 // deny modifications if the transaction is not opened
357 if(myOnlyTransactionModification) {
358 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
359 ? Standard_True :Standard_False);
365 if (myUndoLimit != 0 && myUndoTransaction.IsOpen()) {
367 Handle(TDF_Delta) D = myUndoTransaction.Commit(Standard_True);
368 if (!(D.IsNull() || D->IsEmpty())) {
369 isDone = Standard_True;
371 myRedos.Clear(); // if we push an Undo we clear the redos
372 myUndos.Append(D); // New undos are at the end of the list
373 // Check the limit to remove the oldest one
374 if (myUndos.Extent() > myUndoLimit) {
375 #ifdef SRN_DELTA_COMPACT
376 Handle(TDF_Delta) aDelta = myUndos.First();
378 myUndos.RemoveFirst();
379 #ifdef SRN_DELTA_COMPACT
380 if(myFromUndo == aDelta) {
381 //The oldest Undo delta coincides with `from` delta
382 if(myUndos.Extent() == 1) { //There is the only Undo
383 myFromUndo.Nullify();
384 myFromRedo.Nullify();
387 myFromUndo = myUndos.First();
395 // deny or allow modifications acording to transaction state
396 if(myOnlyTransactionModification) {
397 myData->AllowModification (myUndoTransaction.IsOpen() && myUndoLimit
398 ? Standard_True :Standard_False);
401 // Notify CDM_Application of the successful commit
402 if (isDone && IsOpened()) {
403 const Handle(TDocStd_Application) anAppli =
404 Handle(TDocStd_Application)::DownCast(Application());
405 if (!anAppli.IsNull())
406 anAppli -> OnCommitTransaction (this);
412 //=======================================================================
413 //function : AbortTransaction
414 //purpose : Private method.
415 //=======================================================================
417 void TDocStd_Document::AbortTransaction()
419 myData->AllowModification(Standard_True);
421 if (myUndoTransaction.IsOpen())
422 if (myUndoLimit != 0)
423 myUndoTransaction.Abort();
425 if (myIsNestedTransactionMode && myUndoFILO.Extent()) {
426 if (!myUndoFILO.First()->IsEmpty())
427 myData->Undo(myUndoFILO.First(),Standard_True);
428 myUndoFILO.RemoveFirst();
429 if (myUndoFILO.Extent())
430 myUndoTransaction.Open();
432 // deny or allow modifications acording to transaction state
433 if (myOnlyTransactionModification) {
434 myData->AllowModification (myUndoTransaction.IsOpen() && myUndoLimit
435 ? Standard_True :Standard_False);
437 // Notify CDM_Application of the event
439 const Handle(TDocStd_Application) anAppli =
440 Handle(TDocStd_Application)::DownCast(Application());
441 if (!anAppli.IsNull())
442 anAppli -> OnAbortTransaction (this);
447 //=======================================================================
448 //function :OpenTransaction
449 //purpose : Private method.
450 //=======================================================================
452 void TDocStd_Document::OpenTransaction()
454 myData->AllowModification(Standard_True);
456 // nested transaction mode
457 if (myIsNestedTransactionMode) {
459 if (myUndoTransaction.IsOpen()) {
460 Handle(TDF_Delta) D = myUndoTransaction.Commit(Standard_True);
461 Handle(TDocStd_CompoundDelta) aCompDelta =
462 Handle(TDocStd_CompoundDelta)::DownCast(myUndoFILO.First());
463 AppendDeltaToTheFirst(aCompDelta, D);
465 Standard_Integer aLastTime = myData->Time();
466 if (myUndoFILO.Extent())
467 aLastTime = myUndoFILO.First()->EndTime();
468 Handle(TDocStd_CompoundDelta) aCompoundDelta =
469 new TDocStd_CompoundDelta;
470 aCompoundDelta->Validity(aLastTime, aLastTime);
471 myUndoFILO.Prepend(aCompoundDelta);
474 if (myUndoLimit != 0) myUndoTransaction.Open();
476 // deny or allow modifications acording to transaction state
477 if (myOnlyTransactionModification) {
478 myData->AllowModification (myUndoTransaction.IsOpen() && myUndoLimit
479 ? Standard_True :Standard_False);
481 // Notify CDM_Application of the event
483 const Handle(TDocStd_Application) anAppli =
484 Handle(TDocStd_Application)::DownCast(Application());
485 if (!anAppli.IsNull())
486 anAppli -> OnOpenTransaction (this);
490 //=======================================================================
491 //function : SetUndoLimit
493 //=======================================================================
495 void TDocStd_Document::SetUndoLimit(const Standard_Integer L)
497 #ifdef SRN_DELTA_COMPACT
498 myFromUndo.Nullify(); //Compaction has to aborted
499 myFromRedo.Nullify();
502 CommitTransaction ();
503 myUndoLimit = (L > 0) ? L : 0;
504 Standard_Integer n = myUndos.Extent() - myUndoLimit;
506 myUndos.RemoveFirst();
509 // deny or allow modifications acording to transaction state
510 if(myOnlyTransactionModification) {
511 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
512 ? Standard_True :Standard_False);
514 //OpenTransaction(); dp 15/10/99
517 //=======================================================================
518 //function : GetUndoLimit
520 //=======================================================================
522 Standard_Integer TDocStd_Document::GetUndoLimit() const
527 //=======================================================================
530 //=======================================================================
532 Standard_Integer TDocStd_Document::GetAvailableUndos() const
534 return myUndos.Extent();
537 //=======================================================================
538 //function : ClearUndos
540 //=======================================================================
542 void TDocStd_Document::ClearUndos()
546 #ifdef SRN_DELTA_COMPACT
547 myFromRedo.Nullify();
548 myFromUndo.Nullify();
552 //=======================================================================
553 //function : ClearRedos
555 //=======================================================================
557 void TDocStd_Document::ClearRedos()
560 #ifdef SRN_DELTA_COMPACT
561 myFromRedo.Nullify();
565 //=======================================================================
568 // Some importante notice:
569 // 1) The most recent undo delta is at the end of the list.
570 // 2) Removing the LAST item of a list is tedious, but it is done only on
571 // Undo. Remove first is done at each command if the limit is reached!
572 // 3) To make fun, the redos are not like the undos: the most recent delta
573 // is at the beginning! Like this, it is easier to remove it after use.
574 //=======================================================================
575 Standard_Boolean TDocStd_Document::Undo()
577 // Don't call NewCommand(), because it may commit Interactive Attributes
578 // and generate a undesirable Delta!
580 Standard_Boolean isOpened = myUndoTransaction.IsOpen();
581 Standard_Boolean undoDone = Standard_False;
582 //TDF_Label currentObjectLabel = CurrentLabel (); //Sauve pour usage ulterieur.
584 if (!myUndos.IsEmpty()) {
585 // Reset the transaction
588 // only for nested transaction mode
589 while(myIsNestedTransactionMode && myUndoFILO.Extent())
592 // allow modifications
593 myData->AllowModification(Standard_True);
596 // should test the applicability before.
598 cout<<"DF before Undo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
600 Handle(TDF_Delta) D = myData->Undo(myUndos.Last(),Standard_True);
602 D->SetName(myUndos.Last()->Name());
605 cout<<"DF after Undo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
609 // Remove the last Undo
610 TDocStd_List_RemoveLast(myUndos);
611 undoDone = Standard_True;
614 if (isOpened && undoDone) OpenTransaction();
616 // deny or allow modifications acording to transaction state
617 if(myOnlyTransactionModification) {
618 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
619 ? Standard_True :Standard_False);
625 //=======================================================================
626 //function : GetAvailableRedos
628 //=======================================================================
630 Standard_Integer TDocStd_Document:: GetAvailableRedos() const
632 // should test the applicability before.
633 return myRedos.Extent();
636 //=======================================================================
639 //=======================================================================
640 Standard_Boolean TDocStd_Document::Redo()
642 Standard_Boolean isOpened = myUndoTransaction.IsOpen();
643 Standard_Boolean undoDone = Standard_False;
644 // TDF_Label currentObjectLabel = CurrentLabel();//Sauve pour usage ulterieur.
645 if (!myRedos.IsEmpty()) {
646 // should test the applicability before.
647 // Reset the transaction
650 // only for nested transaction mode
651 while(myIsNestedTransactionMode && myUndoFILO.Extent())
654 // allow modifications
655 myData->AllowModification(Standard_True);
659 cout<<"DF before Redo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
661 Handle(TDF_Delta) D = myData->Undo(myRedos.First(),Standard_True);
663 D->SetName(myRedos.First()->Name());
666 cout<<"DF after Redo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
668 // Push the redo of the redo as an undo (got it !)
670 // remove the Redo from the head
671 myRedos.RemoveFirst();
672 undoDone = Standard_True;
675 if (isOpened && undoDone) OpenTransaction();
677 // deny or allow modifications acording to transaction state
678 if(myOnlyTransactionModification) {
679 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
680 ? Standard_True :Standard_False);
686 //=======================================================================
687 //function : UpdateReferences
689 //=======================================================================
691 void TDocStd_Document::UpdateReferences(const TCollection_AsciiString& aDocEntry)
694 TDF_AttributeList aRefList;
695 TDocStd_XLink* xRefPtr;
696 for (TDocStd_XLinkIterator xItr (this); xItr.More(); xItr.Next()) {
697 xRefPtr = xItr.Value();
698 if (xRefPtr->DocumentEntry() == aDocEntry) {
699 aRefList.Append(xRefPtr->Update());
702 TDF_ListIteratorOfAttributeList It(aRefList);
703 for (;It.More();It.Next()) {
704 // // mise a jour import
705 SetModified(It.Value()->Label());
710 //=======================================================================
711 //function : GetUndos
713 //=======================================================================
715 const TDF_DeltaList& TDocStd_Document::GetUndos() const
721 //=======================================================================
722 //function : GetRedos
724 //=======================================================================
726 const TDF_DeltaList& TDocStd_Document::GetRedos() const
731 //=======================================================================
732 //function : InitDeltaCompaction
734 //=======================================================================
736 Standard_Boolean TDocStd_Document::InitDeltaCompaction()
738 #ifdef SRN_DELTA_COMPACT
739 if (myUndoLimit == 0 || myUndos.Extent() == 0) {
740 myFromRedo.Nullify();
741 myFromUndo.Nullify();
742 return Standard_False; //No Undos to compact
745 myFromRedo.Nullify();
747 myFromUndo = myUndos.Last();
748 if(myRedos.Extent() > 0) myFromRedo = myRedos.First();
750 return Standard_True;
753 //=======================================================================
754 //function : PerformDeltaCompaction
756 //=======================================================================
758 Standard_Boolean TDocStd_Document::PerformDeltaCompaction()
760 #ifdef SRN_DELTA_COMPACT
761 if(myFromUndo.IsNull()) return Standard_False; //Redo can be Null for this operation
764 Handle(TDocStd_CompoundDelta) aCompoundDelta = new TDocStd_CompoundDelta;
765 TDF_ListIteratorOfDeltaList anIterator(myUndos);
766 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator;
767 TDocStd_LabelIDMapDataMap aMap;
768 Standard_Boolean isFound = Standard_False, isTimeSet = Standard_False;
772 for(; anIterator.More(); anIterator.Next()) {
774 if(myFromUndo == anIterator.Value()) isFound = Standard_True;
775 aList.Append(anIterator.Value()); //Fill the list of deltas that precede compound delta
779 if(!isTimeSet) { //Set begin and end time when the compound delta is valid
780 aCompoundDelta->Validity(anIterator.Value()->BeginTime(), myUndos.Last()->EndTime());
781 isTimeSet = Standard_True;
784 aDeltasIterator.Initialize(anIterator.Value()->AttributeDeltas());
785 for(; aDeltasIterator.More(); aDeltasIterator.Next()) {
786 if(!aMap.IsBound(aDeltasIterator.Value()->Label())) {
787 TDF_IDMap* pIDMap = new TDF_IDMap();
788 aMap.Bind(aDeltasIterator.Value()->Label(), *pIDMap);
791 if(aMap(aDeltasIterator.Value()->Label()).Add(aDeltasIterator.Value()->ID())) //The attribute is not
792 aCompoundDelta->AddAttributeDelta(aDeltasIterator.Value()); //already in the delta
797 myUndos.Assign(aList);
798 myUndos.Append(aCompoundDelta);
802 if(myFromRedo.IsNull()) {
804 return Standard_True;
809 for(anIterator.Initialize(myRedos); anIterator.More(); anIterator.Next()) {
810 aList.Append(anIterator.Value());
811 if(anIterator.Value() == myFromRedo) break;
815 myRedos.Assign(aList);
817 return Standard_True;
821 //=======================================================================
822 //function : StorageFormat
824 //=======================================================================
826 TCollection_ExtendedString TDocStd_Document::StorageFormat() const
828 return myStorageFormat;
832 //=======================================================================
833 //function : ChangeStorageFormat
835 //=======================================================================
837 void TDocStd_Document::ChangeStorageFormat (const TCollection_ExtendedString& newStorageFormat)
839 if (newStorageFormat != myStorageFormat) {
840 myStorageFormat = newStorageFormat;
841 myResourcesAreLoaded = Standard_False;
842 CDM_Document::LoadResources ();
849 //=======================================================================
850 //function : Recompute
852 //=======================================================================
854 void TDocStd_Document::Recompute ()
856 if (IsValid()) return;
857 // find the top function and execute it
858 // Handle(TDesign_Function) F;
859 // if (Main().FindAttribute(TDesign_Function::GetID(),F)) {
860 // TFunction_Solver slv;
861 // slv.SetTouched(GetModified());
862 // slv.ExecuteFrom(F);
866 //=======================================================================
867 //function : AppendDeltaToTheFirst
868 //purpose : Appends delta to the first delta in the myUndoFILO
869 //=======================================================================
871 void TDocStd_Document::AppendDeltaToTheFirst
872 (const Handle(TDocStd_CompoundDelta)& theDelta1,
873 const Handle(TDF_Delta)& theDelta2)
875 if(theDelta2->IsEmpty()) return;
876 TDocStd_LabelIDMapDataMap aMap;
878 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator1
879 (theDelta1->AttributeDeltas());
880 for(; aDeltasIterator1.More(); aDeltasIterator1.Next()) {
881 TDF_Label aLabel = aDeltasIterator1.Value()->Label();
882 if(!aMap.IsBound(aLabel)) {
884 aMap.Bind(aLabel, aTmpIDMap);
886 Standard_GUID anID = aDeltasIterator1.Value()->ID();
887 TDF_IDMap& anIDMap = aMap.ChangeFind(aLabel);
891 theDelta1->Validity(theDelta1->BeginTime(), theDelta2->EndTime());
892 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator2
893 (theDelta2->AttributeDeltas());
894 for(; aDeltasIterator2.More(); aDeltasIterator2.Next()) {
895 TDF_Label aLabel = aDeltasIterator2.Value()->Label();
896 Standard_GUID anID = aDeltasIterator2.Value()->ID();
897 if(aMap.IsBound(aLabel)) {
898 const TDF_IDMap& anIDMap = aMap.Find(aLabel);
899 if(anIDMap.Contains(anID)) continue;
901 theDelta1->AddAttributeDelta(aDeltasIterator2.Value());
905 //=======================================================================
906 //function : RemoveFirstUndo
908 //=======================================================================
909 void TDocStd_Document::RemoveFirstUndo() {
910 if (myUndos.IsEmpty()) return;
911 myUndos.RemoveFirst();