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.
15 #include <CDM_Document.hxx>
16 #include <CDM_MetaData.hxx>
17 #include <Standard_Type.hxx>
18 #include <TCollection_AsciiString.hxx>
19 #include <TCollection_ExtendedString.hxx>
20 #include <TDF_AttributeDelta.hxx>
21 #include <TDF_AttributeDeltaList.hxx>
22 #include <TDF_AttributeIterator.hxx>
23 #include <TDF_AttributeList.hxx>
24 #include <TDF_Data.hxx>
25 #include <TDF_Delta.hxx>
26 #include <TDF_IDMap.hxx>
27 #include <TDF_Label.hxx>
28 #include <TDF_ListIteratorOfAttributeDeltaList.hxx>
29 #include <TDF_ListIteratorOfAttributeList.hxx>
30 #include <TDF_ListIteratorOfDeltaList.hxx>
31 #include <TDF_Reference.hxx>
32 #include <TDocStd.hxx>
33 #include <TDocStd_Application.hxx>
34 #include <TDocStd_CompoundDelta.hxx>
35 #include <TDocStd_Context.hxx>
36 #include <TDocStd_Document.hxx>
37 #include <TDocStd_LabelIDMapDataMap.hxx>
38 #include <TDocStd_Modified.hxx>
39 #include <TDocStd_Owner.hxx>
40 #include <TDocStd_XLink.hxx>
41 #include <TDocStd_XLinkIterator.hxx>
43 IMPLEMENT_STANDARD_RTTIEXT(TDocStd_Document,CDM_Document)
45 // List should have a RemoveLast...
46 #define TDocStd_List_RemoveLast(theList) \
47 TDF_ListIteratorOfDeltaList it(theList); \
48 Standard_Integer i,n = theList.Extent(); \
49 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 = static_cast<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()
242 #ifdef OCCT_DEBUG_TRANS
243 if (myUndoTransaction.IsOpen() && myData->Transaction() > 1) {
244 throw Standard_DomainError("NewCommand : many open transactions");
251 #ifdef OCCT_DEBUG_TRANS
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 throw Standard_DomainError("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.
575 #ifdef OCCT_DEBUG_DELTA
576 cout<<"DF before Undo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
578 Handle(TDF_Delta) D = myData->Undo(myUndos.Last(),Standard_True);
579 D->SetName(myUndos.Last()->Name());
580 #ifdef OCCT_DEBUG_DELTA
581 cout<<"DF after Undo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
585 // Remove the last Undo
586 TDocStd_List_RemoveLast(myUndos);
587 undoDone = Standard_True;
590 if (isOpened && undoDone) OpenTransaction();
592 // deny or allow modifications acording to transaction state
593 if(myOnlyTransactionModification) {
594 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
595 ? Standard_True :Standard_False);
601 //=======================================================================
602 //function : GetAvailableRedos
604 //=======================================================================
606 Standard_Integer TDocStd_Document:: GetAvailableRedos() const
608 // should test the applicability before.
609 return myRedos.Extent();
612 //=======================================================================
615 //=======================================================================
616 Standard_Boolean TDocStd_Document::Redo()
618 Standard_Boolean isOpened = myUndoTransaction.IsOpen();
619 Standard_Boolean undoDone = Standard_False;
620 // TDF_Label currentObjectLabel = CurrentLabel();//Sauve pour usage ulterieur.
621 if (!myRedos.IsEmpty()) {
622 // should test the applicability before.
623 // Reset the transaction
626 // only for nested transaction mode
627 while(myIsNestedTransactionMode && myUndoFILO.Extent())
630 // allow modifications
631 myData->AllowModification(Standard_True);
634 #ifdef OCCT_DEBUG_DELTA
635 cout<<"DF before Redo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
637 Handle(TDF_Delta) D = myData->Undo(myRedos.First(),Standard_True);
638 D->SetName(myRedos.First()->Name());
639 #ifdef OCCT_DEBUG_DELTA
640 cout<<"DF after Redo =================================="<<endl; TDF_Tool::DeepDump(cout,myData);
642 // Push the redo of the redo as an undo (got it !)
644 // remove the Redo from the head
645 myRedos.RemoveFirst();
646 undoDone = Standard_True;
649 if (isOpened && undoDone) OpenTransaction();
651 // deny or allow modifications acording to transaction state
652 if(myOnlyTransactionModification) {
653 myData->AllowModification(myUndoTransaction.IsOpen() && myUndoLimit
654 ? Standard_True :Standard_False);
660 //=======================================================================
661 //function : UpdateReferences
663 //=======================================================================
665 void TDocStd_Document::UpdateReferences(const TCollection_AsciiString& aDocEntry)
668 TDF_AttributeList aRefList;
669 TDocStd_XLink* xRefPtr;
670 for (TDocStd_XLinkIterator xItr (this); xItr.More(); xItr.Next()) {
671 xRefPtr = xItr.Value();
672 if (xRefPtr->DocumentEntry() == aDocEntry) {
673 aRefList.Append(xRefPtr->Update());
676 TDF_ListIteratorOfAttributeList It(aRefList);
677 for (;It.More();It.Next()) {
678 // // mise a jour import
679 SetModified(It.Value()->Label());
684 //=======================================================================
685 //function : GetUndos
687 //=======================================================================
689 const TDF_DeltaList& TDocStd_Document::GetUndos() const
695 //=======================================================================
696 //function : GetRedos
698 //=======================================================================
700 const TDF_DeltaList& TDocStd_Document::GetRedos() const
705 //=======================================================================
706 //function : InitDeltaCompaction
708 //=======================================================================
710 Standard_Boolean TDocStd_Document::InitDeltaCompaction()
712 #ifdef SRN_DELTA_COMPACT
713 if (myUndoLimit == 0 || myUndos.Extent() == 0) {
714 myFromRedo.Nullify();
715 myFromUndo.Nullify();
716 return Standard_False; //No Undos to compact
719 myFromRedo.Nullify();
721 myFromUndo = myUndos.Last();
722 if(myRedos.Extent() > 0) myFromRedo = myRedos.First();
724 return Standard_True;
727 //=======================================================================
728 //function : PerformDeltaCompaction
730 //=======================================================================
732 Standard_Boolean TDocStd_Document::PerformDeltaCompaction()
734 #ifdef SRN_DELTA_COMPACT
735 if(myFromUndo.IsNull()) return Standard_False; //Redo can be Null for this operation
738 Handle(TDocStd_CompoundDelta) aCompoundDelta = new TDocStd_CompoundDelta;
739 TDF_ListIteratorOfDeltaList anIterator(myUndos);
740 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator;
741 TDocStd_LabelIDMapDataMap aMap;
742 Standard_Boolean isFound = Standard_False, isTimeSet = Standard_False;
746 for(; anIterator.More(); anIterator.Next()) {
748 if(myFromUndo == anIterator.Value()) isFound = Standard_True;
749 aList.Append(anIterator.Value()); //Fill the list of deltas that precede compound delta
753 if(!isTimeSet) { //Set begin and end time when the compound delta is valid
754 aCompoundDelta->Validity(anIterator.Value()->BeginTime(), myUndos.Last()->EndTime());
755 isTimeSet = Standard_True;
758 aDeltasIterator.Initialize(anIterator.Value()->AttributeDeltas());
759 for(; aDeltasIterator.More(); aDeltasIterator.Next()) {
760 if(!aMap.IsBound(aDeltasIterator.Value()->Label())) {
761 TDF_IDMap* pIDMap = new TDF_IDMap();
762 aMap.Bind(aDeltasIterator.Value()->Label(), *pIDMap);
765 if(aMap(aDeltasIterator.Value()->Label()).Add(aDeltasIterator.Value()->ID())) //The attribute is not
766 aCompoundDelta->AddAttributeDelta(aDeltasIterator.Value()); //already in the delta
771 myUndos.Assign(aList);
772 myUndos.Append(aCompoundDelta);
776 if(myFromRedo.IsNull()) {
778 return Standard_True;
783 for(anIterator.Initialize(myRedos); anIterator.More(); anIterator.Next()) {
784 aList.Append(anIterator.Value());
785 if(anIterator.Value() == myFromRedo) break;
789 myRedos.Assign(aList);
791 return Standard_True;
795 //=======================================================================
796 //function : StorageFormat
798 //=======================================================================
800 TCollection_ExtendedString TDocStd_Document::StorageFormat() const
802 return myStorageFormat;
806 //=======================================================================
807 //function : ChangeStorageFormat
809 //=======================================================================
811 void TDocStd_Document::ChangeStorageFormat (const TCollection_ExtendedString& newStorageFormat)
813 if (newStorageFormat != myStorageFormat) {
814 myStorageFormat = newStorageFormat;
815 myResourcesAreLoaded = Standard_False;
816 CDM_Document::LoadResources ();
823 //=======================================================================
824 //function : Recompute
826 //=======================================================================
828 void TDocStd_Document::Recompute ()
830 if (IsValid()) return;
831 // find the top function and execute it
832 // Handle(TDesign_Function) F;
833 // if (Main().FindAttribute(TDesign_Function::GetID(),F)) {
834 // TFunction_Solver slv;
835 // slv.SetTouched(GetModified());
836 // slv.ExecuteFrom(F);
840 //=======================================================================
841 //function : AppendDeltaToTheFirst
842 //purpose : Appends delta to the first delta in the myUndoFILO
843 //=======================================================================
845 void TDocStd_Document::AppendDeltaToTheFirst
846 (const Handle(TDocStd_CompoundDelta)& theDelta1,
847 const Handle(TDF_Delta)& theDelta2)
849 if(theDelta2->IsEmpty()) return;
850 TDocStd_LabelIDMapDataMap aMap;
852 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator1
853 (theDelta1->AttributeDeltas());
854 for(; aDeltasIterator1.More(); aDeltasIterator1.Next()) {
855 TDF_Label aLabel = aDeltasIterator1.Value()->Label();
856 if(!aMap.IsBound(aLabel)) {
858 aMap.Bind(aLabel, aTmpIDMap);
860 Standard_GUID anID = aDeltasIterator1.Value()->ID();
861 TDF_IDMap& anIDMap = aMap.ChangeFind(aLabel);
865 theDelta1->Validity(theDelta1->BeginTime(), theDelta2->EndTime());
866 TDF_ListIteratorOfAttributeDeltaList aDeltasIterator2
867 (theDelta2->AttributeDeltas());
868 for(; aDeltasIterator2.More(); aDeltasIterator2.Next()) {
869 TDF_Label aLabel = aDeltasIterator2.Value()->Label();
870 Standard_GUID anID = aDeltasIterator2.Value()->ID();
871 if(aMap.IsBound(aLabel)) {
872 const TDF_IDMap& anIDMap = aMap.Find(aLabel);
873 if(anIDMap.Contains(anID)) continue;
875 theDelta1->AddAttributeDelta(aDeltasIterator2.Value());
879 //=======================================================================
880 //function : RemoveFirstUndo
882 //=======================================================================
883 void TDocStd_Document::RemoveFirstUndo() {
884 if (myUndos.IsEmpty()) return;
885 myUndos.RemoveFirst();
888 //=======================================================================
889 //function : BeforeClose
891 //=======================================================================
892 void TDocStd_Document::BeforeClose()
894 SetModificationMode(Standard_False);
896 if(myIsNestedTransactionMode)