return theGroupID;
}
+// Check theFeature is a first or last feature in folder and return this folder
+static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr)
+{
+ const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+ for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+ if ((*anIt)->id() != theFolderAttr)
+ continue;
+
+ ObjectPtr anOwner = (*anIt)->owner();
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(anOwner);
+ if (aFolder.get())
+ return aFolder;
+ }
+ return FolderPtr();
+}
+
static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
myDoc = theDoc;
// update all fields and recreate features and result objects if needed
TDF_LabelList aNoUpdated;
- synchronizeFeatures(aNoUpdated, true, true, true, true);
+ synchronizeFeatures(aNoUpdated, true, false, true, true);
myHistory.clear();
}
// store feature in the features array: before "initData" because in macro features
// in initData it creates new features, appeared later than this
TDF_Label aPrevFeateureLab;
+ FolderPtr aParentFolder;
if (theAfterThis.get()) { // searching for the previous feature label
std::shared_ptr<Model_Data> aPrevData =
std::dynamic_pointer_cast<Model_Data>(theAfterThis->data());
if (aPrevData.get()) {
aPrevFeateureLab = aPrevData->label().Father();
}
+ // Check if the previous feature is the last feature in a folder,
+ // then the folder should be updated to contain additional feature.
+ // Macro features are not stored in folder.
+ if (!theFeature->isMacro()) {
+ // If the last feature is a sub-feature of composite, use parent feature
+ // to check belonging to a folder.
+ FeaturePtr afterThis = ModelAPI_Tools::compositeOwner(theAfterThis);
+ if (!afterThis)
+ afterThis = theAfterThis;
+ aParentFolder = inFolder(afterThis, ModelAPI_Folder::LAST_FEATURE_ID());
+ }
}
AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab);
// must be after binding to the map because of "Box" macro feature that
// creates other features in "initData"
initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
+ // put feature to the end of folder if it is added while
+ // the history line is set to the last feature from the folder
+ if (aParentFolder) {
+ aParentFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(theFeature);
+ updateHistory(ModelAPI_Folder::group());
+ }
// event: feature is added, mist be before "initData" to update OB correctly on Duplicate:
// first new part, then the content
static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
aComposite->removeFeature(theFeature);
}
}
+ // remove feature from folder
+ removeFromFolder(std::list<FeaturePtr>(1, theFeature));
// this must be before erase since theFeature erasing removes all information about
// the feature results and groups of results
// To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated
} else {
// it may be a folder
- ObjectPtr aFolder = folder(aRefs->Value(a));
+ const ObjectPtr& aFolder = folder(aRefs->Value(a));
if (aFolder.get()) {
// store folder information for the Features group only
if (isFeature || isFolder) {
}
}
-ObjectPtr Model_Objects::folder(TDF_Label theLabel) const
+const ObjectPtr& Model_Objects::folder(TDF_Label theLabel) const
{
if (myFolders.IsBound(theLabel))
return myFolders.Find(theLabel);
- return ObjectPtr();
+ static ObjectPtr anEmptyResult;
+ return anEmptyResult;
}
FeaturePtr Model_Objects::feature(TDF_Label theLabel) const
return ObjectPtr();
createHistory(theGroupID);
const std::string& aGroupID = groupNameFoldering(theGroupID, theAllowFolder);
+ const std::vector<ObjectPtr>& aVec = myHistory[theGroupID];
+ //if (aVec.size() <= theIndex)
+ // return aVec[aVec.size() - 1]; // too high index requested (to avoid crash in #2360)
return aGroupID.empty() ? myHistory[theGroupID][theIndex] : myHistory[aGroupID][theIndex];
}
TDF_Label& aFeatureLab = anUpdatedIter.Value();
while(aFeatureLab.Depth() > 3)
aFeatureLab = aFeatureLab.Father();
- if (myFeatures.IsBound(aFeatureLab))
+ if (myFeatures.IsBound(aFeatureLab) || myFolders.IsBound(aFeatureLab))
anUpdatedMap.Add(aFeatureLab);
}
// create a feature
ObjectPtr aFeature = isFolder ? ObjectPtr(new ModelAPI_Folder)
- : aSession->createFeature(aFeatureID, anOwner);
+ : ObjectPtr(aSession->createFeature(aFeatureID, anOwner));
if (!aFeature.get()) {
// somethig is wrong, most probably, the opened document has invalid structure
Events_InfoMessage("Model_Objects", "Invalid type of object in the document").send();
// unbind after the "erase" call: on abort sketch
// is removes sub-objects that corrupts aFIter
myFolders.UnBind(aFldIt.Key());
+ // reinitialize iterator because unbind may corrupt the previous order in the map
+ aFldIt.Initialize(myFolders);
}
}
myHistory.clear();
}
- if (theExecuteFeatures)
- anOwner->executeFeatures() = false;
+ if (!theExecuteFeatures)
+ anOwner->setExecuteFeatures(false);
aLoop->activateFlushes(isActive);
if (theFlush) {
aLoop->flush(aRedispEvent);
aLoop->flush(aToHideEvent);
}
- if (theExecuteFeatures)
- anOwner->executeFeatures() = true;
+ if (!theExecuteFeatures)
+ anOwner->setExecuteFeatures(true);
}
/// synchronises back references for the given object basing on the collected data
for(; aNewIter != theNewRefs.end(); aNewIter++) {
if (aData->refsToMe().find(*aNewIter) == aData->refsToMe().end()) {
FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aNewIter)->owner());
- aData->addBackReference(aRefFeat, (*aNewIter)->id());
+ if (aRefFeat)
+ aData->addBackReference(aRefFeat, (*aNewIter)->id());
+ else // add back reference to a folder
+ aData->addBackReference((*aNewIter)->owner(), (*aNewIter)->id());
}
}
if (theNewRefs.size() != aData->refsToMe().size()) { // some back ref must be removed
} else aCurrentIter++;
}
}
+ // for the last feature in the folder, check if it is a sub-feature,
+ // then refer the folder to a top-level parent composite feature
+ const std::set<AttributePtr>& aRefs = aData->refsToMe();
+ std::set<AttributePtr>::iterator anIt = aRefs.begin();
+ for (; anIt != aRefs.end(); ++anIt)
+ if ((*anIt)->id() == ModelAPI_Folder::LAST_FEATURE_ID())
+ break;
+ if (anIt != aRefs.end()) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+ if (aFeature) {
+ CompositeFeaturePtr aParent;
+ CompositeFeaturePtr aGrandParent = ModelAPI_Tools::compositeOwner(aFeature);
+ do {
+ aParent = aGrandParent;
+ if (aGrandParent)
+ aGrandParent = ModelAPI_Tools::compositeOwner(aParent);
+ } while (aGrandParent.get());
+ if (aParent) {
+ ObjectPtr aFolder = (*anIt)->owner();
+ // remove reference from the current feature
+ aData->removeBackReference(aFolder, ModelAPI_Folder::LAST_FEATURE_ID());
+ // set reference to a top-level parent
+ aFolder->data()->reference(ModelAPI_Folder::LAST_FEATURE_ID())->setValue(aParent);
+ std::shared_ptr<Model_Data> aParentData =
+ std::dynamic_pointer_cast<Model_Data>(aParent->data());
+ aParentData->addBackReference(aFolder, ModelAPI_Folder::LAST_FEATURE_ID());
+ }
+ }
+ }
aData->updateConcealmentFlag();
}
return false;
}
- theParentName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex);
- return true;
+ std::pair<std::string, bool> aName = ModelAPI_Tools::getDefaultName(theResult, theResultIndex);
+ if (aName.second)
+ theParentName = aName.first;
+ return aName.second;
}
void Model_Objects::storeResult(std::shared_ptr<ModelAPI_Data> theFeatureData,
if (theResult->data()->name().empty()) {
// if was not initialized, generate event and set a name
std::string aNewName = theFeatureData->name();
- if (!hasCustomName(theFeatureData, theResult, theResultIndex, aNewName)) {
+ if (hasCustomName(theFeatureData, theResult, theResultIndex, aNewName)) {
+ // if the name of result is user-defined, then, at first time, assign name of the result
+ // by empty string to be sure that corresponding flag in the data model is set
+ theResult->data()->setName("");
+ } else {
std::stringstream aName;
aName << aNewName;
// if there are several results (issue #899: any number of result),
updateHistory(ModelAPI_Feature::group());
}
+// Returns one of the limiting features of the list
static FeaturePtr limitingFeature(std::list<FeaturePtr>& theFeatures, const bool isLast)
{
FeaturePtr aFeature;
return aFeature;
}
+// Verify the feature is sub-element in composite feature or it is not used in the history
+static bool isSkippedFeature(FeaturePtr theFeature)
+{
+ bool isSub = ModelAPI_Tools::compositeOwner(theFeature).get() != NULL;
+ return isSub || (theFeature && !theFeature->isInHistory());
+}
+
std::shared_ptr<ModelAPI_Folder> Model_Objects::findFolder(
const std::list<std::shared_ptr<ModelAPI_Feature> >& theFeatures,
const bool theBelow)
if (theBelow)
continue;
+ // if feature is in sub-component, skip it
+ FeaturePtr aCurFeature = feature(aCurLabel);
+ if (isSkippedFeature(aCurFeature))
+ continue;
+
if (!aLastFeatureInFolder.IsNull()) {
if (IsEqual(aCurLabel, aLastFeatureInFolder))
aLastFeatureInFolder.Nullify(); // the last feature in the folder is achived
continue;
}
- aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
- if (aFoundFolder) {
+ const ObjectPtr& aFolderObj = folder(aCurLabel);
+ if (aFolderObj.get()) {
+ aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aFolderObj);
AttributeReferencePtr aLastFeatAttr =
aFoundFolder->reference(ModelAPI_Folder::LAST_FEATURE_ID());
if (aLastFeatAttr) {
}
if (theBelow && aRefIndex < aRefs->Upper()) {
+ TDF_Label aLabel;
+ // skip following features which are sub-components or not in history
+ for (int anIndex = aRefIndex + 1; anIndex <= aRefs->Upper(); ++anIndex) {
+ aLabel = aRefs->Value(anIndex);
+ FeaturePtr aCurFeature = feature(aLabel);
+ if (!isSkippedFeature(aCurFeature))
+ break;
+ }
// check the next object is a folder
- TDF_Label aLabel = aRefs->Value(aRefIndex + 1);
aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aLabel));
}
!aFeatures.empty() && aRefIndex >= aRefs->Lower() && aRefIndex <= aRefs->Upper();
aRefIndex += aStep) {
TDF_Label aCurLabel = aRefs->Value(aRefIndex);
- TDF_Label aFeatureLabel;
+ // if feature is in sub-component, skip it
+ FeaturePtr aCurFeature = feature(aCurLabel);
+ if (isSkippedFeature(aCurFeature))
+ continue;
aLimitingFeature = limitingFeature(aFeatures, theBelow);
- aData = std::static_pointer_cast<Model_Data>(aLimitingFeature->data());
- if (aData && aData->isValid())
- aFeatureLabel = aData->label().Father();
-
- if (!IsEqual(aCurLabel, aFeatureLabel))
+ if (!aCurFeature->data()->isEqual(aLimitingFeature->data()))
return FolderPtr(); // not a sequential list
}
return true;
}
-static FolderPtr inFolder(const FeaturePtr& theFeature, const std::string& theFolderAttr)
-{
- const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
- for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
- if ((*anIt)->id() != theFolderAttr)
- continue;
-
- ObjectPtr anOwner = (*anIt)->owner();
- FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(anOwner);
- if (aFolder.get())
- return aFolder;
- }
- return FolderPtr();
-}
-
static FolderPtr isExtractionCorrect(const FolderPtr& theFirstFeatureFolder,
const FolderPtr& theLastFeatureFolder,
bool& isExtractBefore)
TDF_Label aFolderLabel = aData->label().Father();
TDF_Label aPrevFeatureLabel = aRefs->Value(aRefIndex);
// update start reference of the folder
- if (aFolderStartFeature.get())
- aFolderStartFeature = feature(aRefs->Value(aRefIndex + 1));
+ if (aFolderStartFeature.get()) {
+ FeaturePtr aNewStartFeature;
+ do { // skip all features placed in the composite features
+ aPrevFeatureLabel = aRefs->Value(aRefIndex++);
+ aNewStartFeature =
+ aRefIndex <= aRefs->Upper() ? feature(aRefs->Value(aRefIndex)) : FeaturePtr();
+ } while (aNewStartFeature && isSkippedFeature(aNewStartFeature));
+ aFolderStartFeature = aNewStartFeature;
+ }
// move the folder in the list of references after the last feature from the list
RemoveFromRefArray(aFeaturesLab, aFolderLabel);
AddToRefArray(aFeaturesLab, aFolderLabel, aPrevFeatureLabel);
} else {
// update end reference of the folder
- if (aFolderEndFeature.get())
- aFolderEndFeature = feature(aRefs->Value(aRefIndex - 1));
+ if (aFolderEndFeature.get()) {
+ FeaturePtr aNewEndFeature;
+ do { // skip all features placed in the composite features
+ --aRefIndex;
+ aNewEndFeature =
+ aRefIndex >= aRefs->Lower() ? feature(aRefs->Value(aRefIndex)) : FeaturePtr();
+ } while (aNewEndFeature && isSkippedFeature(aNewEndFeature));
+ aFolderEndFeature = aNewEndFeature;
+ }
}
// update folder references
TDF_Label aLastFeatureLabel;
for (int aRefIndex = aRefs->Lower(); aRefIndex <= aRefs->Upper(); ++aRefIndex) {
+ TDF_Label aCurLabel = aRefs->Value(aRefIndex);
+
if (aFoundFolder)
++theIndexInFolder;
- TDF_Label aCurLabel = aRefs->Value(aRefIndex);
- if (aCurLabel == aLabelToFind) // the feature is reached
+ if (aCurLabel == aLabelToFind) { // the feature is reached
+ if (aFoundFolder) {
+ if (isSkippedFeature(theFeature)) {
+ theIndexInFolder = -1;
+ return FolderPtr();
+ }
+ // decrease the index of the feature in the folder by the number of skipped features
+ for (int anIndex = theIndexInFolder - 1; anIndex > 0; anIndex--) {
+ aCurLabel = aRefs->Value(aRefIndex - anIndex);
+ if (isSkippedFeature(feature(aCurLabel)))
+ theIndexInFolder--;
+ }
+ }
return aFoundFolder;
+ }
if (!aFoundFolder) {
// if the current label refers to a folder, feel all necessary data
- aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(folder(aCurLabel));
- if (aFoundFolder) {
+ const ObjectPtr& aFolderObj = folder(aCurLabel);
+ if (aFolderObj.get()) {
+ aFoundFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(aFolderObj);
theIndexInFolder = -1;
AttributeReferencePtr aLastRef =
std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
if (aData.get() && aData->isValid()) {
TDF_Label aFeatureLabel = aData->label().Father();
- TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse);
- if (!aNextLabel.IsNull())
- return feature(aNextLabel);
+ do {
+ TDF_Label aNextLabel = nextLabel(aFeatureLabel, theReverse);
+ if (aNextLabel.IsNull())
+ break; // last or something is wrong
+ FeaturePtr aFound = feature(aNextLabel);
+ if (aFound)
+ return aFound; // the feature is found
+ // if the next label is a folder, skip it
+ aFeatureLabel = folder(aNextLabel).get() ? aNextLabel : TDF_Label();
+ } while (!aFeatureLabel.IsNull());
}
return FeaturePtr(); // not found, last, or something is wrong
}
{
Handle(TDataStd_ReferenceArray) aRefs;
if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
+ FeaturePtr aLast = feature(aRefs->Value(aRefs->Upper()));
+ if (!aLast.get() && aRefs->Length() != 0) { // erase the invalid feature from the array
+ RemoveFromRefArray(featuresLabel(), aRefs->Value(aRefs->Upper()));
+ return lastFeature(); // try once again, after the last was removed
+ }
return feature(aRefs->Value(aRefs->Upper()));
}
return FeaturePtr(); // no features at all