void CmdPartDesignDuplicateSelection::activated(int iMsg) { Q_UNUSED(iMsg); 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; std::sort(beforeFeatures.begin(), beforeFeatures.end()); std::sort(afterFeatures.begin(), afterFeatures.end()); std::set_difference(afterFeatures.begin(), afterFeatures.end(), beforeFeatures.begin(), beforeFeatures.end(), std::back_inserter(newFeatures)); for (auto feature : newFeatures) { if (PartDesign::Body::isAllowed(feature)) { doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), feature->getNameInDocument()); doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", feature->getNameInDocument()); } } // Adjust visibility of features doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument()); } updateActive(); }
void CmdPartDesignMoveFeatureInTree::activated(int iMsg) { Q_UNUSED(iMsg); 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->hasObject ( 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 const std::vector<App::DocumentObject*> & model = body->Group.getValues(); // Ask user to select the target feature bool ok; QStringList items; 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("PartDesign_MoveFeatureInTree", "Select feature"), qApp->translate("PartDesign_MoveFeatureInTree", "Select a feature from the list"), items, 0, false, &ok); if (!ok) return; int index = items.indexOf(text); // first object is the beginning of the body App::DocumentObject* target = index != 0 ? model[index-1] : nullptr; openCommand("Move an object inside tree"); for ( auto feat: features ) { if ( feat == target ) continue; std::string targetStr; if (target) { targetStr.append("App.activeDocument().").append(target->getNameInDocument()); } else { targetStr = "None"; } // 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.removeObject(App.activeDocument().%s)", body->getNameInDocument(), feat->getNameInDocument() ); doCommand ( Doc, "App.activeDocument().%s.insertObject(App.activeDocument().%s, %s, True)", body->getNameInDocument(), feat->getNameInDocument(), targetStr.c_str () ); } updateActive(); }
void CmdPartDesignMoveFeature::activated(int iMsg) { Q_UNUSED(iMsg); std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); if (features.empty()) return; // Check if all features are valid to move if (std::any_of(std::begin(features), std::end(features), [](App::DocumentObject* obj){return !PartDesignGui::isFeatureMovable(obj); })) { //show messagebox and cancel QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Features cannot be moved"), QObject::tr("Some of the selected features have dependencies in the source body")); return; } // Collect dependenies of the selected features std::vector<App::DocumentObject*> dependencies = PartDesignGui::collectMovableDependencies(features); if (!dependencies.empty()) features.insert(std::end(features), std::begin(dependencies), std::end(dependencies)); // Create a list of all bodies in this part std::vector<App::DocumentObject*> bodies = getDocument()->getObjectsOfType(Part::BodyBase::getClassTypeId()); std::set<App::DocumentObject*> source_bodies; for (auto feat : features) { PartDesign::Body* source = PartDesign::Body::findBodyOf(feat); source_bodies.insert(static_cast<App::DocumentObject*>(source)); } std::vector<App::DocumentObject*> target_bodies; for (auto body : bodies) { if (!source_bodies.count(body)) target_bodies.push_back(body); } if (target_bodies.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Features cannot be moved"), QObject::tr("There are no other bodies to move to")); return; } // Ask user to select the target body (remove source bodies from list) bool ok; QStringList items; for (auto body : target_bodies) { items.push_back(QString::fromUtf8(body->Label.getValue())); } QString text = QInputDialog::getItem(Gui::getMainWindow(), qApp->translate("PartDesign_MoveFeature", "Select body"), qApp->translate("PartDesign_MoveFeature", "Select a body from the list"), items, 0, false, &ok); if (!ok) return; int index = items.indexOf(text); if (index < 0) return; PartDesign::Body* target = static_cast<PartDesign::Body*>(target_bodies[index]); openCommand("Move an object"); for (auto feat: features) { // Find body of this feature 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() == feat); doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)", source->getNameInDocument(), (feat)->getNameInDocument()); } App::DocumentObject* targetOldTip = target->Tip.getValue(); // Add to target body (always at the Tip) doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)", target->getNameInDocument(), (feat)->getNameInDocument()); // Recompute to update the shape doCommand(Gui,"App.activeDocument().recompute()"); // Adjust visibility of features // TODO: May be something can be done in view provider (2015-08-05, Fat-Zer) // If we removed the tip of the source body, make the new tip visible if ( featureWasTip ) { App::DocumentObject * sourceNewTip = source->Tip.getValue(); if (sourceNewTip) doCommand(Gui,"Gui.activeDocument().show(\"%s\")", sourceNewTip->getNameInDocument()); } // Hide old tip and show new tip (the moved feature) of the target body App::DocumentObject* targetNewTip = target->Tip.getValue(); if ( targetOldTip != targetNewTip ) { if ( targetOldTip ) { doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", targetOldTip->getNameInDocument()); } if (targetNewTip) { doCommand(Gui,"Gui.activeDocument().show(\"%s\")", targetNewTip->getNameInDocument()); } } // Fix sketch support if (feat->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { Sketcher::SketchObject *sketch = static_cast<Sketcher::SketchObject*>(feat); try { PartDesignGui::fixSketchSupport(sketch); } catch (Base::Exception &) { QMessageBox::warning( Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), QObject::tr("Please edit '%1' and redefine it to use a Base or Datum plane as the sketch plane."). arg( QString::fromLatin1( sketch->Label.getValue () ) ) ); } } //relink origin for sketches and datums (coordinates) PartDesignGui::relinkToOrigin(feat, target); } updateActive(); }