#include <Model_ResultBody.h>
#include <Model_ResultGroup.h>
#include <ModelAPI_Validator.h>
+#include <ModelAPI_CompositeFeature.h>
#include <Events_Loop.h>
#include <Events_Error.h>
if (!isError) {
myDoc->SetUndoLimit(UNDO_LIMIT);
// to avoid the problem that feature is created in the current, not this, document
- Model_Session::get()->setActiveDocument(anApp->getDocument(myID), false);
+ std::shared_ptr<Model_Session> aSession =
+ std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
+ aSession->setActiveDocument(anApp->getDocument(myID), false);
+ aSession->setCheckTransactions(false);
synchronizeFeatures(false, true);
- Model_Session::get()->setActiveDocument(Model_Session::get()->moduleDocument(), false);
- Model_Session::get()->setActiveDocument(anApp->getDocument(myID), true);
+ aSession->setCheckTransactions(true);
+ aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false);
+ aSession->setActiveDocument(anApp->getDocument(myID), true);
}
return !isError;
}
std::shared_ptr<ModelAPI_Session> aPM = Model_Session::get();
if (this != aPM->moduleDocument().get() && this == aPM->activeDocument().get()) {
aPM->setActiveDocument(aPM->moduleDocument());
+ } else if (this == aPM->moduleDocument().get()) {
+ // erase the active document if root is closed
+ aPM->setActiveDocument(DocumentPtr());
}
// close all subs
const std::set<std::string> aSubs = subDocuments(true);
}
}
-void Model_Document::finishOperation()
+bool Model_Document::finishOperation()
{
bool isNestedClosed = !myDoc->HasOpenCommand() && !myNestedNum.empty();
static std::shared_ptr<Model_Session> aSession =
std::static_pointer_cast<Model_Session>(Model_Session::get());
- // just to be sure that everybody knows that changes were performed
- if (isNestedClosed) {
- aSession->setCheckTransactions(false); // for nested transaction commit
- }
synchronizeBackRefs();
Events_Loop* aLoop = Events_Loop::loop();
aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
// to avoid "updated" message appearance by updater
//aLoop->clear(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
- if (isNestedClosed) {
- aSession->setCheckTransactions(true); // for nested transaction commit
- }
-
// finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside
+ bool aResult = false;
const std::set<std::string> aSubs = subDocuments(true);
std::set<std::string>::iterator aSubIter = aSubs.begin();
for (; aSubIter != aSubs.end(); aSubIter++)
- subDoc(*aSubIter)->finishOperation();
+ if (subDoc(*aSubIter)->finishOperation())
+ aResult = true;
- if (myDoc->CommitCommand()) { // if commit is successfull, just increment counters
+ // transaction may be empty if this document was created during this transaction (create part)
+ if (!myTransactions.empty() && myDoc->CommitCommand()) { // if commit is successfull, just increment counters
(*myTransactions.rbegin())++;
+ aResult = true;
}
if (isNestedClosed) {
compactNested();
}
+ if (!aResult && !myTransactions.empty() /* it can be for just created part document */)
+ aResult = *(myTransactions.rbegin()) != 0;
+
+ if (!aResult && Model_Session::get()->moduleDocument().get() == this) {
+ // nothing inside in all documents, so remove this transaction from the transactions list
+ undoInternal(true, false);
+ myDoc->ClearRedos();
+ myRedos.clear();
+ }
+ return aResult;
}
void Model_Document::abortOperation()
{
if (!myNestedNum.empty() && !myDoc->HasOpenCommand()) { // abort all what was done in nested
compactNested();
- undo();
+ undoInternal(false, false);
myDoc->ClearRedos();
myRedos.clear();
} else { // abort the current
return false;
}
-void Model_Document::undo()
+void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchronize)
{
int aNumTransactions = *myTransactions.rbegin();
myTransactions.pop_back();
for(int a = 0; a < aNumTransactions; a++)
myDoc->Undo();
- synchronizeFeatures(true, true);
- // undo for all subs
- const std::set<std::string> aSubs = subDocuments(true);
- std::set<std::string>::iterator aSubIter = aSubs.begin();
- for (; aSubIter != aSubs.end(); aSubIter++)
- subDoc(*aSubIter)->undo();
+ if (theSynchronize)
+ synchronizeFeatures(true, true);
+ if (theWithSubs) {
+ // undo for all subs
+ const std::set<std::string> aSubs = subDocuments(true);
+ std::set<std::string>::iterator aSubIter = aSubs.begin();
+ for (; aSubIter != aSubs.end(); aSubIter++)
+ subDoc(*aSubIter)->undoInternal(theWithSubs, theSynchronize);
+ }
+}
+
+void Model_Document::undo()
+{
+ undoInternal(true, true);
}
bool Model_Document::canRedo()
std::shared_ptr<ModelAPI_Document> aThis =
Model_Application::getApplication()->getDocument(myID);
// after all updates, sends a message that groups of features were created or updated
- std::static_pointer_cast<Model_Session>(Model_Session::get())
- ->setCheckTransactions(false);
Events_Loop* aLoop = Events_Loop::loop();
aLoop->activateFlushes(false);
}
}
// update results of thefeatures (after features created because they may be connected, like sketch and sub elements)
+ std::list<FeaturePtr> aComposites; // composites must be updated after their subs (issue 360)
TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
for (; aLabIter2.More(); aLabIter2.Next()) {
TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
if (myObjs.IsBound(aFeatureLabel)) { // a new feature is inserted
FeaturePtr aFeature = myObjs.Find(aFeatureLabel);
+ if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature).get())
+ aComposites.push_back(aFeature);
updateResults(aFeature);
}
}
+ std::list<FeaturePtr>::iterator aComposite = aComposites.begin();
+ for(; aComposite != aComposites.end(); aComposite++) {
+ updateResults(*aComposite);
+ }
// check all features are checked: if not => it was removed
NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myObjs);
ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
aFeature->erase();
// unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
- TDF_Label aLab = aFIter.Key();
- aFIter.Next();
- myObjs.UnBind(aLab);
+ myObjs.UnBind(aFIter.Key());
+ // reinitialize iterator because unbind may corrupt the previous order in the map
+ aFIter.Initialize(myObjs);
} else
aFIter.Next();
}
aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TOHIDE));
- std::static_pointer_cast<Model_Session>(Model_Session::get())
- ->setCheckTransactions(true);
myExecuteFeatures = true;
}