X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=fdfaa6f6970b47511770cd250fac59957c812b3d;hb=93d261c062c12388f4420043776e8ee19ddceaa0;hp=21823b4e05b73ba391dff15922d5fd5f5c77caab;hpb=ba8ee992b99097165d62ac9a93e842a47787216a;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 21823b4e0..fdfaa6f69 100755 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -15,9 +15,9 @@ #include #include #include - +#include #include -#include +#include #include #include @@ -32,12 +32,21 @@ #include #include #include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include #include #ifndef WIN32 @@ -113,61 +122,61 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum aStatus = anApp->Open(aPath, aLoaded); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); - Events_Error::send( - std::string("Exception in opening of document: ") + aFail->GetMessageString()); + Events_InfoMessage("Model_Document", + "Exception in opening of document: %1").arg(aFail->GetMessageString()).send(); return false; } bool isError = aStatus != PCDM_RS_OK; if (isError) { switch (aStatus) { case PCDM_RS_UnknownDocument: - Events_Error::send(std::string("Can not open document")); + Events_InfoMessage("Model_Document", "Can not open document").send(); break; case PCDM_RS_AlreadyRetrieved: - Events_Error::send(std::string("Can not open document: already opened")); + Events_InfoMessage("Model_Document", "Can not open document: already opened").send(); break; case PCDM_RS_AlreadyRetrievedAndModified: - Events_Error::send( - std::string("Can not open document: already opened and modified")); + Events_InfoMessage("Model_Document", + "Can not open document: already opened and modified").send(); break; case PCDM_RS_NoDriver: - Events_Error::send(std::string("Can not open document: driver library is not found")); + Events_InfoMessage("Model_Document", "Can not open document: driver library is not found").send(); break; case PCDM_RS_UnknownFileDriver: - Events_Error::send(std::string("Can not open document: unknown driver for opening")); + Events_InfoMessage("Model_Document", "Can not open document: unknown driver for opening").send(); break; case PCDM_RS_OpenError: - Events_Error::send(std::string("Can not open document: file open error")); + Events_InfoMessage("Model_Document", "Can not open document: file open error").send(); break; case PCDM_RS_NoVersion: - Events_Error::send(std::string("Can not open document: invalid version")); + Events_InfoMessage("Model_Document", "Can not open document: invalid version").send(); break; case PCDM_RS_NoModel: - Events_Error::send(std::string("Can not open document: no data model")); + Events_InfoMessage("Model_Document", "Can not open document: no data model").send(); break; case PCDM_RS_NoDocument: - Events_Error::send(std::string("Can not open document: no document inside")); + Events_InfoMessage("Model_Document", "Can not open document: no document inside").send(); break; case PCDM_RS_FormatFailure: - Events_Error::send(std::string("Can not open document: format failure")); + Events_InfoMessage("Model_Document", "Can not open document: format failure").send(); break; case PCDM_RS_TypeNotFoundInSchema: - Events_Error::send(std::string("Can not open document: invalid object")); + Events_InfoMessage("Model_Document", "Can not open document: invalid object").send(); break; case PCDM_RS_UnrecognizedFileFormat: - Events_Error::send(std::string("Can not open document: unrecognized file format")); + Events_InfoMessage("Model_Document", "Can not open document: unrecognized file format").send(); break; case PCDM_RS_MakeFailure: - Events_Error::send(std::string("Can not open document: make failure")); + Events_InfoMessage("Model_Document", "Can not open document: make failure").send(); break; case PCDM_RS_PermissionDenied: - Events_Error::send(std::string("Can not open document: permission denied")); + Events_InfoMessage("Model_Document", "Can not open document: permission denied").send(); break; case PCDM_RS_DriverFailure: - Events_Error::send(std::string("Can not open document: driver failure")); + Events_InfoMessage("Model_Document", "Can not open document: driver failure").send(); break; default: - Events_Error::send(std::string("Can not open document: unknown error")); + Events_InfoMessage("Model_Document", "Can not open document: unknown error").send(); break; } } @@ -225,22 +234,22 @@ bool Model_Document::save( aStatus = anApp->SaveAs(myDoc, aPath); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); - Events_Error::send( - std::string("Exception in saving of document: ") + aFail->GetMessageString()); + Events_InfoMessage("Model_Document", + "Exception in saving of document: %1").arg(aFail->GetMessageString()).send(); return false; } bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj; if (!isDone) { switch (aStatus) { case PCDM_SS_DriverFailure: - Events_Error::send(std::string("Can not save document: save driver-library failure")); + Events_InfoMessage("Model_Document", "Can not save document: save driver-library failure").send(); break; case PCDM_SS_WriteFailure: - Events_Error::send(std::string("Can not save document: file writing failure")); + Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send(); break; case PCDM_SS_Failure: default: - Events_Error::send(std::string("Can not save document")); + Events_InfoMessage("Model_Document", "Can not save document").send(); break; } } @@ -267,8 +276,8 @@ bool Model_Document::save( aFile.Copy(aDestination); theResults.push_back(aDestinationDir.ToCString()); } else { - Events_Error::send( - std::string("Can not open file ") + aSubPath.ToCString() + " for saving"); + Events_InfoMessage("Model_Document", + "Can not open file %1 for saving").arg(aSubPath.ToCString()).send(); } } } else { // simply save opened document @@ -359,7 +368,7 @@ void Model_Document::compactNested() } } -/// Compares the content ofthe given attributes, returns true if equal. +/// Compares the content of the given attributes, returns true if equal. /// This method is used to avoid empty transactions when only "current" is changed /// to some value and then comes back in this transaction, so, it compares only /// references and Boolean and Integer Arrays for the current moment. @@ -481,6 +490,11 @@ bool Model_Document::finishOperation() bool isNestedClosed = !myDoc->HasOpenCommand() && !myNestedNum.empty(); static std::shared_ptr aSession = std::static_pointer_cast(Model_Session::get()); + + // open transaction if nested is closed to fit inside all synchronizeBackRefs and flushed consequences + if (isNestedClosed) { + myDoc->OpenCommand(); + } // do it before flashes to enable and recompute nesting features correctly if (myNestedNum.empty() || (isNestedClosed && myNestedNum.size() == 1)) { // if all nested operations are closed, make current the higher level objects (to perform @@ -500,6 +514,12 @@ bool Model_Document::finishOperation() aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + + if (isNestedClosed) { + if (myDoc->CommitCommand()) + myTransactions.rbegin()->myOCAFNum++; + } + // this must be here just after everything is finished but before real transaction stop // to avoid messages about modifications outside of the transaction // and to rebuild everything after all updates and creates @@ -568,8 +588,28 @@ static void modifiedLabels(const Handle(TDocStd_Document)& theDoc, TDF_LabelList } // add also label of the modified attributes const TDF_AttributeDeltaList& anAttrs = aDelta->AttributeDeltas(); + TDF_LabelMap anExcludedInt; /// named shape evolution also modifies integer on this label: exclude it for (TDF_ListIteratorOfAttributeDeltaList anAttr(anAttrs); anAttr.More(); anAttr.Next()) { - theDelta.Append(anAttr.Value()->Label()); + if (anAttr.Value()->Attribute()->ID() == TDataStd_BooleanArray::GetID()) { + continue; // Boolean array is used for feature auxiliary attributes only, feature args are not modified + } + if (anAttr.Value()->Attribute()->ID() == TNaming_NamedShape::GetID()) { + anExcludedInt.Add(anAttr.Value()->Label()); + continue; // named shape evolution is changed in history update => skip them, they are not the features arguents + } + if (anAttr.Value()->Attribute()->ID() == TDataStd_Integer::GetID()) { + if (anExcludedInt.Contains(anAttr.Value()->Label())) + continue; + } + theDelta.Append(anAttr.Value()->Label()); + } + TDF_ListIteratorOfLabelList aDeltaIter(theDelta); + for(; aDeltaIter.More(); aDeltaIter.Next()) { + if (anExcludedInt.Contains(aDeltaIter.Value())) { + theDelta.Remove(aDeltaIter); + if (!aDeltaIter.More()) + break; + } } } @@ -615,7 +655,7 @@ void Model_Document::abortOperation() for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->abortOperation(); // references may be changed because they are set in attributes on the fly - myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot()); + myObjs->synchronizeFeatures(aDeltaLabels, true, false, isRoot()); } bool Model_Document::isOperation() const @@ -681,7 +721,7 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron } // after undo of all sub-documents to avoid updates on not-modified data (issue 370) if (theSynchronize) { - myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot()); + myObjs->synchronizeFeatures(aDeltaLabels, true, false, isRoot()); // update the current features status setCurrentFeature(currentFeature(false), false); } @@ -728,7 +768,7 @@ void Model_Document::redo() subDoc(*aSubIter)->redo(); // after redo of all sub-documents to avoid updates on not-modified data (issue 370) - myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot()); + myObjs->synchronizeFeatures(aDeltaLabels, true, false, isRoot()); // update the current features status setCurrentFeature(currentFeature(false), false); } @@ -824,11 +864,45 @@ void Model_Document::removeFeature(FeaturePtr theFeature) myObjs->removeFeature(theFeature); } +// recursive function to check if theSub is a child of theMain composite feature +// through all the hierarchy of parents +static bool isSub(const CompositeFeaturePtr theMain, const FeaturePtr theSub) { + CompositeFeaturePtr aParent = ModelAPI_Tools::compositeOwner(theSub); + if (!aParent.get()) + return false; + if (aParent == theMain) + return true; + return isSub(theMain, aParent); +} + + void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis) { + bool aCurrentUp = theMoved == currentFeature(false); + if (aCurrentUp) { + setCurrentFeatureUp(); + } + // if user adds after high-level feature with nested, add it after all nested (otherwise the nested will be disabled) + CompositeFeaturePtr aCompositeAfter = std::dynamic_pointer_cast(theAfterThis); + if (aCompositeAfter.get()) { + FeaturePtr aSub = aCompositeAfter; + do { + FeaturePtr aNext = myObjs->nextFeature(aSub); + if (!isSub(aCompositeAfter, aNext)) { + theAfterThis = aSub; + break; + } + aSub = aNext; + } while (aSub.get()); + } + myObjs->moveFeature(theMoved, theAfterThis); - if (theAfterThis == currentFeature(true)) + if (aCurrentUp) { // make the moved feature enabled or disabled due to the real status + setCurrentFeature(currentFeature(false), false); + } else if (theAfterThis == currentFeature(false)) { + // must be after move to make enabled all features which are before theMoved setCurrentFeature(theMoved, true); + } } void Model_Document::updateHistory(const std::shared_ptr theObject) @@ -905,17 +979,6 @@ std::shared_ptr Model_Document::currentFeature(const bool theV return std::shared_ptr(); // null feature means the higher than first } -// recursive function to check if theSub is a child of theMain composite feature -// through all the hierarchy of parents -static bool isSub(const CompositeFeaturePtr theMain, const FeaturePtr theSub) { - CompositeFeaturePtr aParent = ModelAPI_Tools::compositeOwner(theSub); - if (!aParent.get()) - return false; - if (aParent == theMain) - return true; - return isSub(theMain, aParent); -} - void Model_Document::setCurrentFeature( std::shared_ptr theCurrent, const bool theVisible) { @@ -939,7 +1002,7 @@ void Model_Document::setCurrentFeature( } } - if (theVisible) { // make features below which are not in history also enabled: sketch subs + if (theVisible && !theCurrent.get()) { // needed to avoid disabling of PartSet initial constructions FeaturePtr aNext = theCurrent.get() ? myObjs->nextFeature(theCurrent) : myObjs->firstFeature(); for (; aNext.get(); aNext = myObjs->nextFeature(theCurrent)) { @@ -969,12 +1032,11 @@ void Model_Document::setCurrentFeature( } // make all features after this feature disabled in reversed order (to remove results without deps) static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); - static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); - static Events_ID aDeleteEvent = aLoop->eventByName(EVENT_OBJECT_DELETED); bool aPassed = false; // flag that the current object is already passed in cycle FeaturePtr anIter = myObjs->lastFeature(); bool aWasChanged = false; + bool isCurrentParameter = theCurrent.get() && theCurrent->getKind() == "Parameter"; for(; anIter.get(); anIter = myObjs->nextFeature(anIter, true)) { // check this before passed become enabled: the current feature is enabled! if (anIter == theCurrent) aPassed = true; @@ -988,13 +1050,19 @@ void Model_Document::setCurrentFeature( } if (anIter->getKind() == "Parameter") {// parameters are always out of the history of features, but not parameters - if (theCurrent.get() && theCurrent->getKind() != "Parameter") + // due to the issue 1491 all parameters are kept enabled any time + //if (!isCurrentParameter) aDisabledFlag = false; + } else if (isCurrentParameter) { // if paramater is active, all other features become enabled (issue 1307) + aDisabledFlag = false; } + if (anIter->setDisabled(aDisabledFlag)) { - // state of feature is changed => so feature become updated static Events_ID anUpdateEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED); - ModelAPI_EventCreator::get()->sendUpdated(anIter, anUpdateEvent); + // state of feature is changed => so inform that it must be updated if it has such state + if (!aDisabledFlag && + (anIter->data()->execState() == ModelAPI_StateMustBeUpdated || anIter->data()->execState() == ModelAPI_StateInvalidArgument)) + ModelAPI_EventCreator::get()->sendUpdated(anIter, anUpdateEvent); // flush is in the end of this method ModelAPI_EventCreator::get()->sendUpdated(anIter, aRedispEvent /*, false*/); aWasChanged = true; @@ -1026,6 +1094,13 @@ void Model_Document::setCurrentFeatureUp() FeaturePtr aCurrent = currentFeature(false); if (aCurrent.get()) { // if not, do nothing because null is the upper FeaturePtr aPrev = myObjs->nextFeature(aCurrent, true); + // make the higher level composite as current (sketch becomes disabled if line is enabled) + if (aPrev.get()) { + FeaturePtr aComp = ModelAPI_Tools::compositeOwner(aPrev); + // without cycle (issue 1555): otherwise extrusion fuse will be enabled and displayed whaen inside sketch + if (aComp.get()) + aPrev = aComp; + } // do not flush: it is called only on remove, it will be flushed in the end of transaction setCurrentFeature(aPrev, false); } @@ -1094,12 +1169,38 @@ void Model_Document::addNamingName(const TDF_Label theLabel, std::string theName myNamingNames[theName] = theLabel; } +void Model_Document::changeNamingName(const std::string theOldName, const std::string theNewName) +{ + std::map::iterator aFind = myNamingNames.find(theOldName); + if (aFind != myNamingNames.end()) { + myNamingNames[theNewName] = aFind->second; + myNamingNames.erase(theOldName); + } +} + TDF_Label Model_Document::findNamingName(std::string theName) { std::map::iterator aFind = myNamingNames.find(theName); - if (aFind == myNamingNames.end()) - return TDF_Label(); // not found - return aFind->second; + if (aFind != myNamingNames.end()) { + return aFind->second; + } + // not found exact name, try to find by sub-components + std::string::size_type aSlash = theName.rfind('/'); + if (aSlash != std::string::npos) { + std::string anObjName = theName.substr(0, aSlash); + aFind = myNamingNames.find(anObjName); + if (aFind != myNamingNames.end()) { + TCollection_ExtendedString aSubName(theName.substr(aSlash + 1).c_str()); + // searching sub-labels with this name + TDF_ChildIDIterator aNamesIter(aFind->second, TDataStd_Name::GetID(), Standard_True); + for(; aNamesIter.More(); aNamesIter.Next()) { + Handle(TDataStd_Name) aName = Handle(TDataStd_Name)::DownCast(aNamesIter.Value()); + if (aName->Get() == aSubName) + return aName->Label(); + } + } + } + return TDF_Label(); // not found } ResultPtr Model_Document::findByName(const std::string theName) @@ -1262,3 +1363,139 @@ FeaturePtr Model_Document::lastFeature() return myObjs->lastFeature(); return FeaturePtr(); } + +static Handle(TNaming_NamedShape) searchForOriginalShape(TopoDS_Shape theShape, TDF_Label aMain) { + Handle(TNaming_NamedShape) aResult; + while(!theShape.IsNull()) { // searching for the very initial shape that produces this one + TopoDS_Shape aShape = theShape; + theShape.Nullify(); + if (!TNaming_Tool::HasLabel(aMain, aShape)) // to avoid crash of TNaming_SameShapeIterator if pure shape does not exists + break; + for(TNaming_SameShapeIterator anIter(aShape, aMain); anIter.More(); anIter.Next()) { + TDF_Label aNSLab = anIter.Label(); + Handle(TNaming_NamedShape) aNS; + if (aNSLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) { + if (aShapesIter.Evolution() == TNaming_SELECTED || aShapesIter.Evolution() == TNaming_DELETE) + continue; // don't use the selection evolution + if (aShapesIter.NewShape().IsSame(aShape)) { // found the original shape + aResult = aNS; + if (aResult->Evolution() == TNaming_MODIFY) + theShape = aShapesIter.OldShape(); + if (!theShape.IsNull()) // otherwise may me searching for another item of this shape with longer history + break; + } + } + } + } + } + return aResult; +} + +std::shared_ptr Model_Document::producedByFeature( + std::shared_ptr theResult, + const std::shared_ptr& theShape) +{ + ResultBodyPtr aBody = std::dynamic_pointer_cast(theResult); + if (!aBody.get()) { + return feature(theResult); // for not-body just returns the feature that produced this result + } + // otherwise get the shape and search the very initial label for it + TopoDS_Shape aShape = theShape->impl(); + if (aShape.IsNull()) + return FeaturePtr(); + + // for comsolids and compounds all the naming is located in the main object, so, try to use + // it first + ResultCompSolidPtr aMain = ModelAPI_Tools::compSolidOwner(theResult); + if (aMain.get()) { + FeaturePtr aMainRes = producedByFeature(aMain, theShape); + if (aMainRes) + return aMainRes; + } + + std::shared_ptr aBodyData = std::dynamic_pointer_cast(theResult->data()); + if (!aBodyData.get() || !aBodyData->isValid()) + return FeaturePtr(); + + TopoDS_Shape anOldShape; // old shape in the pair oldshape->theShape in the named shape + TopoDS_Shape aShapeContainer; // old shape of the shape that contains aShape as sub-element + Handle(TNaming_NamedShape) aCandidatInThis, aCandidatContainer; + TDF_Label aBodyLab = aBodyData->label(); + // use childs and this label (the lowest priority) + TDF_ChildIDIterator aNSIter(aBodyLab, TNaming_NamedShape::GetID(), Standard_True); + bool aUseThis = !aNSIter.More(); + while(anOldShape.IsNull() && (aNSIter.More() || aUseThis)) { + Handle(TNaming_NamedShape) aNS; + if (aUseThis) { + if (!aBodyLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + break; + } else { + aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); + } + for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) { + if (aShapesIter.Evolution() == TNaming_SELECTED || aShapesIter.Evolution() == TNaming_DELETE) + continue; // don't use the selection evolution + if (aShapesIter.NewShape().IsSame(aShape)) { // found the original shape + aCandidatInThis = aNS; + if (aCandidatInThis->Evolution() == TNaming_MODIFY) + anOldShape = aShapesIter.OldShape(); + if (!anOldShape.IsNull()) // otherwise may me searching for another item of this shape with longer history + break; + } + // check that the shape contains aShape as sub-shape to fill container + if (aShapesIter.NewShape().ShapeType() < aShape.ShapeType() && aCandidatContainer.IsNull()) { + TopExp_Explorer anExp(aShapesIter.NewShape(), aShape.ShapeType()); + for(; anExp.More(); anExp.Next()) { + if (aShape.IsSame(anExp.Current())) { + aCandidatContainer = aNS; + aShapeContainer = aShapesIter.NewShape(); + } + } + } + } + // iterate to the next label or to the body label in the end + if (!aUseThis) + aNSIter.Next(); + if (!aNSIter.More()) { + if (aUseThis) + break; + aUseThis = true; + } + } + if (aCandidatInThis.IsNull()) { + // to fix 1512: searching for original shape of this shape if modification of it is not in this result + aCandidatInThis = searchForOriginalShape(aShape, myDoc->Main()); + if (aCandidatInThis.IsNull()) { + if (aCandidatContainer.IsNull()) + return FeaturePtr(); + // with the lower priority use the higher level shape that contains aShape + aCandidatInThis = aCandidatContainer; + anOldShape = aShapeContainer; + } else { + // to stop the searching by the following searchForOriginalShape + anOldShape.Nullify(); + } + } + + Handle(TNaming_NamedShape) aNS = searchForOriginalShape(anOldShape, myDoc->Main()); + if (!aNS.IsNull()) + aCandidatInThis = aNS; + + FeaturePtr aResult; + TDF_Label aResultLab = aCandidatInThis->Label(); + while(aResultLab.Depth() > 3) + aResultLab = aResultLab.Father(); + FeaturePtr aFeature = myObjs->feature(aResultLab); + if (aFeature.get()) { + if (!aResult.get() || myObjs->isLater(aResult, aFeature)) { + aResult = aFeature; + } + } + return aResult; +} + +bool Model_Document::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const +{ + return myObjs->isLater(theLater, theCurrent); +}