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
{
if ( Tip.isTouched() ||
BaseFeature.isTouched() )
BaseFeature.isTouched() ) {
return 1;
}
return Part::BodyBase::mustExecute();
}

View File

@ -104,9 +104,17 @@ void CmdPartDesignBody::activated(int iMsg)
if (!features.empty()) {
if (features.size() == 1) {
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 {
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."));
return;
}
@ -182,20 +190,30 @@ void CmdPartDesignMoveTip::activated(int iMsg)
} else {
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" ),
QObject::tr( "Select exactly one PartDesign feature or a body." ) );
return;
} else if (!body) {
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;
}
openCommand("Move insert point to selected feature");
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) {
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
// others, so we would have to remember their state somehow
updateActive();
}
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");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "";
}
void CmdPartDesignDuplicateSelection::activated(int iMsg) {
// TODO Review the function (2015-08-05, Fat-Zer)
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;
}
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */false);
std::vector<App::DocumentObject*> beforeFeatures = getDocument()->getObjects();
openCommand("Duplicate a PartDesign object");
doCommand(Doc,"FreeCADGui.runCommand('Std_DuplicateSelection')");
if (pcActiveBody) {
// Find the features that were added
std::vector<App::DocumentObject*> afterFeatures = getDocument()->getObjects();
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::back_inserter(newFeatures));
for (std::vector<App::DocumentObject*>::const_iterator f = newFeatures.begin(); f != newFeatures.end(); f++) {
if (PartDesign::Body::isAllowed(*f)) {
for (auto feature : newFeatures) {
if (PartDesign::Body::isAllowed(feature)) {
doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)",
pcActiveBody->getNameInDocument(), (*f)->getNameInDocument());
doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument());
pcActiveBody->getNameInDocument(), feature->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());
}
updateActive();
}
bool CmdPartDesignDuplicateSelection::isActive(void)
{
if (getActiveGuiDocument())
@ -310,9 +315,6 @@ CmdPartDesignMoveFeature::CmdPartDesignMoveFeature()
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());
if (features.empty()) return;
@ -335,25 +337,25 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
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
Part::BodyBase* source = PartDesign::Body::findBodyOf(*f);
Part::BodyBase* source = PartDesign::Body::findBodyOf(feat);
bool featureWasTip = false;
if (source == target) continue;
// Remove from the source body if the feature belonged to a body
if (source) {
featureWasTip = (source->Tip.getValue() == *f);
featureWasTip = (source->Tip.getValue() == feat);
doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)",
source->getNameInDocument(), (*f)->getNameInDocument());
source->getNameInDocument(), (feat)->getNameInDocument());
}
App::DocumentObject* targetOldTip = target->Tip.getValue();
// Add to target body (always at the Tip)
doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)",
target->getNameInDocument(), (*f)->getNameInDocument());
target->getNameInDocument(), (feat)->getNameInDocument());
// Recompute to update the shape
doCommand(Gui,"App.activeDocument().recompute()");
@ -377,8 +379,8 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
}
// Fix sketch support
if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) {
Sketcher::SketchObject *sketch = static_cast<Sketcher::SketchObject*>(*f);
if (feat->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) {
Sketcher::SketchObject *sketch = static_cast<Sketcher::SketchObject*>(feat);
try {
PartDesignGui::Workbench::fixSketchSupport(sketch);
} catch (Base::Exception &) {
@ -388,6 +390,8 @@ void CmdPartDesignMoveFeature::activated(int iMsg)
}
}
}
updateActive();
}
bool CmdPartDesignMoveFeature::isActive(void)
@ -411,53 +415,85 @@ CmdPartDesignMoveFeatureInTree::CmdPartDesignMoveFeatureInTree()
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());
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
std::vector<App::DocumentObject*> model = pcActiveBody->Model.getValues();
const std::vector<App::DocumentObject*> & model = body->Model.getValues();
// Ask user to select the target feature
bool ok;
QStringList items;
for (std::vector<App::DocumentObject*>::iterator it = model.begin(); it != model.end(); ++it)
items.push_back(QString::fromUtf8((*it)->Label.getValue()));
if ( bodyBase ) {
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(),
qApp->translate(className(), "Select feature"),
qApp->translate(className(), "Select a feature from the list"),
items, 0, false, &ok);
if (!ok) return;
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");
for (std::vector<App::DocumentObject*>::const_iterator f = features.begin(); f != features.end(); f++) {
if (*f == target) continue;
for ( auto feat: features ) {
if ( feat == target ) continue;
// Remove and re-insert the feature from the Body
// Note: If the tip was moved then the new tip will be at the moved position, that is, at the same
// feature as before!
doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)",
pcActiveBody->getNameInDocument(), (*f)->getNameInDocument());
doCommand(Doc,
"App.activeDocument().%s.insertFeature(App.activeDocument().%s, App.activeDocument().%s, True)",
pcActiveBody->getNameInDocument(), (*f)->getNameInDocument(), target->getNameInDocument());
std::string targetStr;
if (target) {
targetStr.append("App.activeDocument().").append(target->getNameInDocument());
} else {
targetStr = "None";
}
// Recompute to update the shape
doCommand(Gui,"App.activeDocument().recompute()");
// Remove and re-insert the feature to/from the Body
// 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)
{
if (getActiveGuiDocument())
return true;
else
return false;
return hasActiveDocument ();
}

View File

@ -505,23 +505,65 @@ void Workbench::slotNewObject(const App::DocumentObject& obj)
void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const
{
if (strcmp(recipient,"Tree") == 0)
{
if (Gui::Selection().countObjectsOfType(PartDesign::Body::getClassTypeId()) +
Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) +
Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) +
Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 )
auto selection = Gui::Selection().getSelection();
// Add move Tip Command
if ( selection.size () >= 1 ) {
App::DocumentObject *feature = selection.front().pObject;
PartDesign::Body *body = PartDesignGui::getBodyFor ( feature, false );
// 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";
if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) +
Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) +
Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 )
*item << "PartDesign_MoveFeature"
<< "PartDesign_MoveFeatureInTree";
}
if (strcmp(recipient, "Tree") == 0) {
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()) -
Gui::Selection().countObjectsOfType(PartDesign::MultiTransform::getClassTypeId()) == 1 )
*item << "PartDesign_MultiTransform";
}
}
}
void Workbench::activated()
{