PartDesign: update body management commands according to the changes in body paradigms

This commit is contained in:
Alexander Golubev 2015-08-07 15:33:15 +03:00 committed by Stefan Tröger
parent 8b62680fe7
commit a5fcd5775e
3 changed files with 169 additions and 90 deletions

View File

@ -111,8 +111,9 @@ void Body::onChanged(const App::Property *prop)
short Body::mustExecute() const short Body::mustExecute() const
{ {
if ( Tip.isTouched() || if ( Tip.isTouched() ||
BaseFeature.isTouched() ) BaseFeature.isTouched() ) {
return 1; return 1;
}
return Part::BodyBase::mustExecute(); return Part::BodyBase::mustExecute();
} }

View File

@ -104,9 +104,17 @@ void CmdPartDesignBody::activated(int iMsg)
if (!features.empty()) { if (!features.empty()) {
if (features.size() == 1) { if (features.size() == 1) {
baseFeature = features[0]; baseFeature = features[0];
// TODO Check if the feature belongs to another body and may be some other sanity checks (2015-08-04, Fat-Zer) if ( baseFeature->isDerivedFrom ( PartDesign::Feature::getClassTypeId() ) &&
PartDesign::Body::findBodyOf ( baseFeature ) ) {
// Prevent creatung bodies based on features already belonging to other bodies
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"),
QObject::tr("Body can't be based on a PartDesign feature."));
return;
}
} else { } else {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"),
QObject::tr("Body may be based no more than on one feature.")); QObject::tr("Body may be based no more than on one feature."));
return; return;
} }
@ -182,20 +190,30 @@ void CmdPartDesignMoveTip::activated(int iMsg)
} else { } else {
selFeature = nullptr; selFeature = nullptr;
} }
// TODO Refuse to set tip to nonsolid features (2015-08-05, Fat-Zer)
if (!selFeature || !body ) { if (!selFeature) {
QMessageBox::warning (0, QObject::tr( "Selection error" ), QMessageBox::warning (0, QObject::tr( "Selection error" ),
QObject::tr( "Select exactly one PartDesign feature or a body." ) ); QObject::tr( "Select exactly one PartDesign feature or a body." ) );
return; return;
} else if (!body) { } else if (!body) {
QMessageBox::warning (0, QObject::tr( "Selection error" ), QMessageBox::warning (0, QObject::tr( "Selection error" ),
QObject::tr( "Couldn't determin a body for selected feature." ) ); QObject::tr( "Couldn't determin a body for the selected feature '%s'.", selFeature->Label.getValue() ) );
return;
} else if ( !selFeature->isDerivedFrom(PartDesign::Feature::getClassTypeId () ) &&
!selFeature->getTypeId().isDerivedFrom ( PartDesign::Body::getClassTypeId() ) &&
body->BaseFeature.getValue() != selFeature ) {
QMessageBox::warning (0, QObject::tr( "Selection error" ),
QObject::tr( "Only a solid feature can be the tip of a body." ) );
return; return;
} }
openCommand("Move insert point to selected feature");
App::DocumentObject* oldTip = body->Tip.getValue(); App::DocumentObject* oldTip = body->Tip.getValue();
if (oldTip == selFeature) { // it's not generally an error, so print only a console message
Base::Console().Message ("%s is already the tip of the body", selFeature->getNameInDocument () );
return;
}
openCommand("Move tip to selected feature");
if (oldTip) { if (oldTip) {
doCommand(Gui, "Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument() ); doCommand(Gui, "Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument() );
} }
@ -212,6 +230,7 @@ void CmdPartDesignMoveTip::activated(int iMsg)
// TOOD: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see // TOOD: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see
// others, so we would have to remember their state somehow // others, so we would have to remember their state somehow
updateActive();
} }
bool CmdPartDesignMoveTip::isActive(void) bool CmdPartDesignMoveTip::isActive(void)
@ -234,34 +253,17 @@ CmdPartDesignDuplicateSelection::CmdPartDesignDuplicateSelection()
sToolTipText = QT_TR_NOOP("Duplicates the selected object and adds it to the active body"); sToolTipText = QT_TR_NOOP("Duplicates the selected object and adds it to the active body");
sWhatsThis = sToolTipText; sWhatsThis = sToolTipText;
sStatusTip = sToolTipText; sStatusTip = sToolTipText;
sPixmap = "";
} }
void CmdPartDesignDuplicateSelection::activated(int iMsg) { void CmdPartDesignDuplicateSelection::activated(int iMsg) {
// TODO Review the function (2015-08-05, Fat-Zer) PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */false);
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true);
if(!pcActiveBody) return;
std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId());
if (features.empty()) return;
App::DocumentObject* selFeature = features.front();
if (!pcActiveBody->hasFeature(selFeature)) {
// NOTE: We assume all selected features will be in the same document
// Switch to other body
pcActiveBody = static_cast<PartDesign::Body*>(Part::BodyBase::findBodyOf(selFeature));
if (pcActiveBody != NULL)
Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)",
PDBODYKEY, pcActiveBody->getNameInDocument());
else
return;
}
std::vector<App::DocumentObject*> beforeFeatures = getDocument()->getObjects(); std::vector<App::DocumentObject*> beforeFeatures = getDocument()->getObjects();
openCommand("Duplicate a PartDesign object"); openCommand("Duplicate a PartDesign object");
doCommand(Doc,"FreeCADGui.runCommand('Std_DuplicateSelection')"); doCommand(Doc,"FreeCADGui.runCommand('Std_DuplicateSelection')");
if (pcActiveBody) {
// Find the features that were added // Find the features that were added
std::vector<App::DocumentObject*> afterFeatures = getDocument()->getObjects(); std::vector<App::DocumentObject*> afterFeatures = getDocument()->getObjects();
std::vector<App::DocumentObject*> newFeatures; std::vector<App::DocumentObject*> newFeatures;
@ -270,11 +272,11 @@ void CmdPartDesignDuplicateSelection::activated(int iMsg) {
std::set_difference(afterFeatures.begin(), afterFeatures.end(), beforeFeatures.begin(), beforeFeatures.end(), std::set_difference(afterFeatures.begin(), afterFeatures.end(), beforeFeatures.begin(), beforeFeatures.end(),
std::back_inserter(newFeatures)); std::back_inserter(newFeatures));
for (std::vector<App::DocumentObject*>::const_iterator f = newFeatures.begin(); f != newFeatures.end(); f++) { for (auto feature : newFeatures) {
if (PartDesign::Body::isAllowed(*f)) { if (PartDesign::Body::isAllowed(feature)) {
doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)",
pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); pcActiveBody->getNameInDocument(), feature->getNameInDocument());
doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", feature->getNameInDocument());
} }
} }
@ -282,6 +284,9 @@ void CmdPartDesignDuplicateSelection::activated(int iMsg) {
doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument()); doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument());
} }
updateActive();
}
bool CmdPartDesignDuplicateSelection::isActive(void) bool CmdPartDesignDuplicateSelection::isActive(void)
{ {
if (getActiveGuiDocument()) if (getActiveGuiDocument())
@ -310,9 +315,6 @@ CmdPartDesignMoveFeature::CmdPartDesignMoveFeature()
void CmdPartDesignMoveFeature::activated(int iMsg) void CmdPartDesignMoveFeature::activated(int iMsg)
{ {
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true);
if(!pcActiveBody) return;
std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId());
if (features.empty()) return; if (features.empty()) return;
@ -335,25 +337,25 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
openCommand("Move an object"); openCommand("Move an object");
for (std::vector<App::DocumentObject*>::const_iterator f = features.begin(); f != features.end(); f++) { for (auto feat: features) {
// Find body of this feature // Find body of this feature
Part::BodyBase* source = PartDesign::Body::findBodyOf(*f); Part::BodyBase* source = PartDesign::Body::findBodyOf(feat);
bool featureWasTip = false; bool featureWasTip = false;
if (source == target) continue; if (source == target) continue;
// Remove from the source body if the feature belonged to a body // Remove from the source body if the feature belonged to a body
if (source) { if (source) {
featureWasTip = (source->Tip.getValue() == *f); featureWasTip = (source->Tip.getValue() == feat);
doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)",
source->getNameInDocument(), (*f)->getNameInDocument()); source->getNameInDocument(), (feat)->getNameInDocument());
} }
App::DocumentObject* targetOldTip = target->Tip.getValue(); App::DocumentObject* targetOldTip = target->Tip.getValue();
// Add to target body (always at the Tip) // Add to target body (always at the Tip)
doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)",
target->getNameInDocument(), (*f)->getNameInDocument()); target->getNameInDocument(), (feat)->getNameInDocument());
// Recompute to update the shape // Recompute to update the shape
doCommand(Gui,"App.activeDocument().recompute()"); doCommand(Gui,"App.activeDocument().recompute()");
@ -377,8 +379,8 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
} }
// Fix sketch support // Fix sketch support
if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { if (feat->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) {
Sketcher::SketchObject *sketch = static_cast<Sketcher::SketchObject*>(*f); Sketcher::SketchObject *sketch = static_cast<Sketcher::SketchObject*>(feat);
try { try {
PartDesignGui::Workbench::fixSketchSupport(sketch); PartDesignGui::Workbench::fixSketchSupport(sketch);
} catch (Base::Exception &) { } catch (Base::Exception &) {
@ -388,6 +390,8 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
} }
} }
} }
updateActive();
} }
bool CmdPartDesignMoveFeature::isActive(void) bool CmdPartDesignMoveFeature::isActive(void)
@ -411,53 +415,85 @@ CmdPartDesignMoveFeatureInTree::CmdPartDesignMoveFeatureInTree()
void CmdPartDesignMoveFeatureInTree::activated(int iMsg) void CmdPartDesignMoveFeatureInTree::activated(int iMsg)
{ {
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true);
if(!pcActiveBody) return;
std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId());
if (features.empty()) return; if (features.empty()) return;
PartDesign::Body *body = PartDesignGui::getBodyFor ( features.front(), false );
App::DocumentObject * bodyBase = nullptr;
// sanity check
bool allFeaturesFromSameBody = true;
if ( body ) {
bodyBase= body->BaseFeature.getValue();
for ( auto feat: features ) {
if ( !body->hasFeature ( feat ) ) {
allFeaturesFromSameBody = false;
break;
}
if ( bodyBase== feat) {
QMessageBox::warning (0, QObject::tr( "Selection error" ),
QObject::tr( "Impossible to move the base feature of a body." ) );
return;
}
}
}
if (!body || ! allFeaturesFromSameBody) {
QMessageBox::warning (0, QObject::tr( "Selection error" ),
QObject::tr( "Select one or more features from the same body." ) );
return;
}
// Create a list of all features in this body // Create a list of all features in this body
std::vector<App::DocumentObject*> model = pcActiveBody->Model.getValues(); const std::vector<App::DocumentObject*> & model = body->Model.getValues();
// Ask user to select the target feature // Ask user to select the target feature
bool ok; bool ok;
QStringList items; QStringList items;
for (std::vector<App::DocumentObject*>::iterator it = model.begin(); it != model.end(); ++it) if ( bodyBase ) {
items.push_back(QString::fromUtf8((*it)->Label.getValue())); items.push_back( QString::fromUtf8 ( bodyBase->Label.getValue () ) );
} else {
items.push_back( QObject::tr( "Beginning of the body" ) );
}
for ( auto feat: model ) {
items.push_back( QString::fromUtf8 ( feat->Label.getValue() ) );
}
QString text = QInputDialog::getItem(Gui::getMainWindow(), QString text = QInputDialog::getItem(Gui::getMainWindow(),
qApp->translate(className(), "Select feature"), qApp->translate(className(), "Select feature"),
qApp->translate(className(), "Select a feature from the list"), qApp->translate(className(), "Select a feature from the list"),
items, 0, false, &ok); items, 0, false, &ok);
if (!ok) return; if (!ok) return;
int index = items.indexOf(text); int index = items.indexOf(text);
PartDesign::Feature* target = static_cast<PartDesign::Feature*>(model[index]); // first object is the beginning of the body
App::DocumentObject* target = index != 0 ? model[index-1] : nullptr;
openCommand("Move an object inside tree"); openCommand("Move an object inside tree");
for (std::vector<App::DocumentObject*>::const_iterator f = features.begin(); f != features.end(); f++) { for ( auto feat: features ) {
if (*f == target) continue; if ( feat == target ) continue;
// Remove and re-insert the feature from the Body std::string targetStr;
// Note: If the tip was moved then the new tip will be at the moved position, that is, at the same if (target) {
// feature as before! targetStr.append("App.activeDocument().").append(target->getNameInDocument());
doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", } else {
pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); targetStr = "None";
doCommand(Doc,
"App.activeDocument().%s.insertFeature(App.activeDocument().%s, App.activeDocument().%s, True)",
pcActiveBody->getNameInDocument(), (*f)->getNameInDocument(), target->getNameInDocument());
} }
// Recompute to update the shape // Remove and re-insert the feature to/from the Body
doCommand(Gui,"App.activeDocument().recompute()"); // TODO if tip was moved the new position of tip is quite undetermined (2015-08-07, Fat-Zer)
// TODO warn the user if we are moving an object to some place before the object's link (2015-08-07, Fat-Zer)
doCommand ( Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)",
body->getNameInDocument(), feat->getNameInDocument() );
doCommand ( Doc, "App.activeDocument().%s.insertFeature(App.activeDocument().%s, %s, True)",
body->getNameInDocument(), feat->getNameInDocument(), targetStr.c_str () );
}
updateActive();
} }
bool CmdPartDesignMoveFeatureInTree::isActive(void) bool CmdPartDesignMoveFeatureInTree::isActive(void)
{ {
if (getActiveGuiDocument()) return hasActiveDocument ();
return true;
else
return false;
} }

View File

@ -505,23 +505,65 @@ void Workbench::slotNewObject(const App::DocumentObject& obj)
void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const
{ {
if (strcmp(recipient,"Tree") == 0) auto selection = Gui::Selection().getSelection();
{ // Add move Tip Command
if (Gui::Selection().countObjectsOfType(PartDesign::Body::getClassTypeId()) + if ( selection.size () >= 1 ) {
Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + App::DocumentObject *feature = selection.front().pObject;
Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + PartDesign::Body *body = PartDesignGui::getBodyFor ( feature, false );
Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) // lote of assertion so feature sould be marked as a tip
if ( selection.size () == 1 && feature && (
feature->isDerivedFrom ( PartDesign::Body::getClassTypeId () ) ||
( feature->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) && body ) ||
( feature->isDerivedFrom ( Part::Feature::getClassTypeId () ) && body &&
body->BaseFeature.getValue() == feature )
) ) {
*item << "PartDesign_MoveTip"; *item << "PartDesign_MoveTip";
if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + }
Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) +
Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) if (strcmp(recipient, "Tree") == 0) {
*item << "PartDesign_MoveFeature"
<< "PartDesign_MoveFeatureInTree"; Gui::MDIView *activeView = Gui::Application::Instance->activeView();
if ( selection.size () > 0 && activeView ) {
bool docHaveBodies = activeView->getAppDocument()->countObjectsOfType (
PartDesign::Body::getClassTypeId () ) > 0;
if ( docHaveBodies ) {
bool addMoveFeature = true;
bool addMoveFeatureInTree = (body != nullptr);
for (auto sel: selection) {
// if at least one selected feature cannot be moved to a body
// disable the entry
if ( addMoveFeature && !PartDesign::Body::isAllowed ( sel.pObject ) ) {
addMoveFeature = false;
}
// if all at lest one selected feature doesn't belongs to the same body
// disable the menu entry
if ( addMoveFeatureInTree && !body->hasFeature ( sel.pObject ) ) {
addMoveFeatureInTree = false;
}
if ( !addMoveFeatureInTree && !addMoveFeature ) {
break;
}
}
if (addMoveFeature) {
*item << "PartDesign_MoveFeature";
}
if (addMoveFeatureInTree) {
*item << "PartDesign_MoveFeatureInTree";
}
}
}
if (Gui::Selection().countObjectsOfType(PartDesign::Transformed::getClassTypeId()) - if (Gui::Selection().countObjectsOfType(PartDesign::Transformed::getClassTypeId()) -
Gui::Selection().countObjectsOfType(PartDesign::MultiTransform::getClassTypeId()) == 1 ) Gui::Selection().countObjectsOfType(PartDesign::MultiTransform::getClassTypeId()) == 1 )
*item << "PartDesign_MultiTransform"; *item << "PartDesign_MultiTransform";
} }
} }
}
void Workbench::activated() void Workbench::activated()
{ {