Download src/Mod/PartDesign/Gui/TaskFeaturePick.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 23.2 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp
-
curl -L -o TaskFeaturePick.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp
23.2 kB
| /****************************************************************************** | |
| * Copyright (c) 2012 Jan Rheinländer * | |
| * <jrheinlaender@users.sourceforge.net> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ******************************************************************************/ | |
| using namespace PartDesignGui; | |
| using namespace Attacher; | |
| // TODO Do ve should snap here to App:Part or GeoFeatureGroup/DocumentObjectGroup ? (2015-09-04, | |
| // Fat-Zer) | |
| const QString TaskFeaturePick::getFeatureStatusString(const featureStatus st) | |
| { | |
| switch (st) { | |
| case validFeature: | |
| return tr("Valid"); | |
| case invalidShape: | |
| return tr("Invalid shape"); | |
| case noWire: | |
| return tr("No wire in sketch"); | |
| case isUsed: | |
| return tr("Sketch already used by other feature"); | |
| case otherBody: | |
| return tr("Belongs to another body"); | |
| case otherPart: | |
| return tr("Belongs to another part"); | |
| case notInBody: | |
| return tr("Doesn't belong to any body"); | |
| case basePlane: | |
| return tr("Base plane"); | |
| case afterTip: | |
| return tr("Feature is located after the tip of the body"); | |
| } | |
| return QString(); | |
| } | |
| TaskFeaturePick::TaskFeaturePick( | |
| std::vector<App::DocumentObject*>& objects, | |
| const std::vector<featureStatus>& status, | |
| bool singleFeatureSelect, | |
| QWidget* parent | |
| ) | |
| : TaskBox(Gui::BitmapFactory().pixmap("edit-select-all"), tr("Select Attachment"), true, parent) | |
| , ui(new Ui_TaskFeaturePick) | |
| , doSelection(false) | |
| { | |
| proxy = new QWidget(this); | |
| ui->setupUi(proxy); | |
| // clang-format off | |
| connect(ui->checkUsed, &QCheckBox::toggled, this, &TaskFeaturePick::onUpdate); | |
| connect(ui->checkOtherBody, &QCheckBox::toggled, this, &TaskFeaturePick::onUpdate); | |
| connect(ui->checkOtherPart, &QCheckBox::toggled, this, &TaskFeaturePick::onUpdate); | |
| connect(ui->radioIndependent, &QRadioButton::toggled, this, &TaskFeaturePick::onUpdate); | |
| connect(ui->radioDependent, &QRadioButton::toggled, this, &TaskFeaturePick::onUpdate); | |
| connect(ui->radioXRef, &QRadioButton::toggled, this, &TaskFeaturePick::onUpdate); | |
| connect(ui->listWidget, &QListWidget::itemSelectionChanged, this, &TaskFeaturePick::onItemSelectionChanged); | |
| connect(ui->listWidget, &QListWidget::itemDoubleClicked, this, &TaskFeaturePick::onDoubleClick); | |
| // clang-format on | |
| if (!singleFeatureSelect) { | |
| ui->listWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); | |
| } | |
| // NOTE: generally there shouldn't be more then one origin | |
| std::map<App::Origin*, Gui::DatumElements> originVisStatus; | |
| auto statusIt = status.cbegin(); | |
| auto objIt = objects.begin(); | |
| assert(status.size() == objects.size()); | |
| bool attached = false; | |
| for (; statusIt != status.end(); ++statusIt, ++objIt) { | |
| QListWidgetItem* item = new QListWidgetItem(QStringLiteral("%1 (%2)").arg( | |
| QString::fromUtf8((*objIt)->Label.getValue()), | |
| getFeatureStatusString(*statusIt) | |
| )); | |
| item->setData(Qt::UserRole, QString::fromLatin1((*objIt)->getNameInDocument())); | |
| ui->listWidget->addItem(item); | |
| App::Document* pDoc = (*objIt)->getDocument(); | |
| documentName = pDoc->getName(); | |
| if (!attached) { | |
| attached = true; | |
| attachDocument(Gui::Application::Instance->getDocument(pDoc)); | |
| } | |
| // check if we need to set any origin in temporary visibility mode | |
| auto* datum = dynamic_cast<App::DatumElement*>(*objIt); | |
| if ((*statusIt == validFeature || *statusIt == basePlane) && datum) { | |
| auto* origin = dynamic_cast<App::Origin*>(datum->getLCS()); | |
| if (origin) { | |
| if ((*objIt)->isDerivedFrom<App::Plane>()) { | |
| originVisStatus[origin].setFlag(Gui::DatumElement::Planes, true); | |
| } | |
| else if ((*objIt)->isDerivedFrom<App::Line>()) { | |
| originVisStatus[origin].setFlag(Gui::DatumElement::Axes, true); | |
| } | |
| } | |
| } | |
| } | |
| // Setup the origin's temporary visibility | |
| for (const auto& originPair : originVisStatus) { | |
| const auto& origin = originPair.first; | |
| auto* vpo = static_cast<Gui::ViewProviderCoordinateSystem*>( | |
| Gui::Application::Instance->getViewProvider(origin) | |
| ); | |
| if (vpo) { | |
| vpo->setTemporaryVisibility(originVisStatus[origin]); | |
| vpo->setTemporaryScale(Gui::ViewParams::instance()->getDatumTemporaryScaleFactor()); | |
| vpo->setPlaneLabelVisibility(true); | |
| origins.push_back(vpo); | |
| } | |
| } | |
| // TODO may be update origin API to show only some objects (2015-08-31, Fat-Zer) | |
| groupLayout()->addWidget(proxy); | |
| statuses = status; | |
| updateList(); | |
| } | |
| TaskFeaturePick::~TaskFeaturePick() | |
| { | |
| for (Gui::ViewProviderCoordinateSystem* vpo : origins) { | |
| vpo->resetTemporaryVisibility(); | |
| vpo->resetTemporarySize(); | |
| vpo->setPlaneLabelVisibility(false); | |
| } | |
| } | |
| void TaskFeaturePick::updateList() | |
| { | |
| int index = 0; | |
| for (auto status : statuses) { | |
| QListWidgetItem* item = ui->listWidget->item(index); | |
| switch (status) { | |
| case validFeature: | |
| item->setHidden(false); | |
| break; | |
| case invalidShape: | |
| item->setHidden(true); | |
| break; | |
| case isUsed: | |
| item->setHidden(!ui->checkUsed->isChecked()); | |
| break; | |
| case noWire: | |
| item->setHidden(true); | |
| break; | |
| case otherBody: | |
| item->setHidden(!ui->checkOtherBody->isChecked()); | |
| break; | |
| case otherPart: | |
| item->setHidden(!ui->checkOtherPart->isChecked()); | |
| break; | |
| case notInBody: | |
| item->setHidden(!ui->checkOtherPart->isChecked()); | |
| break; | |
| case basePlane: | |
| item->setHidden(false); | |
| break; | |
| case afterTip: | |
| item->setHidden(true); | |
| break; | |
| } | |
| index++; | |
| } | |
| } | |
| void TaskFeaturePick::onUpdate(bool) | |
| { | |
| bool enable = false; | |
| if (ui->checkOtherBody->isChecked() || ui->checkOtherPart->isChecked()) { | |
| enable = true; | |
| } | |
| ui->radioDependent->setEnabled(enable); | |
| ui->radioIndependent->setEnabled(enable); | |
| ui->radioXRef->setEnabled(enable); | |
| updateList(); | |
| } | |
| std::vector<App::DocumentObject*> TaskFeaturePick::getFeatures() | |
| { | |
| features.clear(); | |
| QListIterator<QListWidgetItem*> i(ui->listWidget->selectedItems()); | |
| while (i.hasNext()) { | |
| auto item = i.next(); | |
| if (item->isHidden()) { | |
| continue; | |
| } | |
| QString t = item->data(Qt::UserRole).toString(); | |
| features.push_back(t); | |
| } | |
| std::vector<App::DocumentObject*> result; | |
| for (const auto& feature : features) { | |
| result.push_back( | |
| App::GetApplication().getDocument(documentName.c_str())->getObject(feature.toLatin1().data()) | |
| ); | |
| } | |
| return result; | |
| } | |
| std::vector<App::DocumentObject*> TaskFeaturePick::buildFeatures() | |
| { | |
| int index = 0; | |
| std::vector<App::DocumentObject*> result; | |
| try { | |
| auto activeBody = PartDesignGui::getBody(false); | |
| if (!activeBody) { | |
| return result; | |
| } | |
| auto activePart = PartDesignGui::getPartFor(activeBody, false); | |
| for (auto status : statuses) { | |
| QListWidgetItem* item = ui->listWidget->item(index); | |
| if (item->isSelected() && !item->isHidden()) { | |
| QString t = item->data(Qt::UserRole).toString(); | |
| auto obj = App::GetApplication() | |
| .getDocument(documentName.c_str()) | |
| ->getObject(t.toLatin1().data()); | |
| // build the dependent copy or reference if wanted by the user | |
| if (status == otherBody || status == otherPart || status == notInBody) { | |
| if (!ui->radioXRef->isChecked()) { | |
| auto copy = makeCopy(obj, "", ui->radioIndependent->isChecked()); | |
| if (status == otherBody) { | |
| activeBody->addObject(copy); | |
| } | |
| else if (status == otherPart) { | |
| auto oBody = PartDesignGui::getBodyFor(obj, false); | |
| if (!oBody) { | |
| activePart->addObject(copy); | |
| } | |
| else { | |
| activeBody->addObject(copy); | |
| } | |
| } | |
| else if (status == notInBody) { | |
| activeBody->addObject(copy); | |
| // doesn't supposed to get here anything but sketch but to be on the | |
| // safe side better to check | |
| if (copy->isDerivedFrom<Sketcher::SketchObject>()) { | |
| Sketcher::SketchObject* sketch | |
| = static_cast<Sketcher::SketchObject*>(copy); | |
| PartDesignGui::fixSketchSupport(sketch); | |
| } | |
| } | |
| result.push_back(copy); | |
| } | |
| else { | |
| result.push_back(obj); | |
| } | |
| } | |
| else { | |
| result.push_back(obj); | |
| } | |
| } | |
| index++; | |
| } | |
| } | |
| catch (const Base::Exception& e) { | |
| e.reportException(); | |
| } | |
| catch (Py::Exception& e) { | |
| // reported by code analyzers | |
| e.clear(); | |
| Base::Console().warning("Unexpected PyCXX exception\n"); | |
| } | |
| catch (const boost::exception&) { | |
| // reported by code analyzers | |
| Base::Console().warning("Unexpected boost exception\n"); | |
| } | |
| return result; | |
| } | |
| App::DocumentObject* TaskFeaturePick::makeCopy(App::DocumentObject* obj, std::string sub, bool independent) | |
| { | |
| App::DocumentObject* copy = nullptr; | |
| // Check for null to avoid segfault | |
| if (!obj) { | |
| return copy; | |
| } | |
| if (independent | |
| && (obj->isDerivedFrom<Sketcher::SketchObject>() | |
| || obj->isDerivedFrom<PartDesign::FeaturePrimitive>())) { | |
| // we do know that the created instance is a document object, as obj is one. But we do not | |
| // know which exact type | |
| auto* doc = App::GetApplication().getActiveDocument(); | |
| const auto name = fmt::format("Copy{}", obj->getNameInDocument()); | |
| copy = doc->addObject(obj->getTypeId().getName(), name.c_str()); | |
| // copy over all properties | |
| std::vector<App::Property*> props; | |
| std::vector<App::Property*> cprops; | |
| obj->getPropertyList(props); | |
| copy->getPropertyList(cprops); | |
| auto it = cprops.begin(); | |
| for (App::Property* prop : props) { | |
| // independent copies don't have links and are not attached | |
| if (independent | |
| && (prop->isDerivedFrom<App::PropertyLink>() | |
| || prop->isDerivedFrom<App::PropertyLinkList>() | |
| || prop->isDerivedFrom<App::PropertyLinkSub>() | |
| || prop->isDerivedFrom<App::PropertyLinkSubList>() | |
| || (prop->getGroup() && strcmp(prop->getGroup(), "Attachment") == 0))) { | |
| ++it; | |
| continue; | |
| } | |
| App::Property* cprop = *it++; | |
| if (prop->getName() && strcmp(prop->getName(), "Label") == 0) { | |
| static_cast<App::PropertyString*>(cprop)->setValue(name.c_str()); | |
| continue; | |
| } | |
| cprop->Paste(*prop); | |
| // we are a independent copy, therefore no external geometry was copied. WE therefore | |
| // can delete all constraints | |
| if (auto* sketchObj = freecad_cast<Sketcher::SketchObject*>(obj)) { | |
| sketchObj->delConstraintsToExternal(); | |
| } | |
| } | |
| } | |
| else { | |
| const std::string name = (!independent ? std::string("Reference") : std::string("Copy")) | |
| + obj->getNameInDocument(); | |
| const std::string entity = sub; | |
| Part::PropertyPartShape* shapeProp = nullptr; | |
| // TODO Replace it with commands (2015-09-11, Fat-Zer) | |
| if (obj->isDerivedFrom<Part::Datum>()) { | |
| auto* doc = App::GetApplication().getActiveDocument(); | |
| copy = doc->addObject<Part::Datum>(name.c_str()); | |
| // we need to reference the individual datums and make again datums. This is important | |
| // as datum adjust their size dependent on the part size, hence simply copying the shape | |
| // is not enough | |
| long int mode = mmDeactivated; | |
| Part::Datum* datumCopy = static_cast<Part::Datum*>(copy); | |
| if (obj->is<PartDesign::Point>()) { | |
| mode = mm0Vertex; | |
| } | |
| else if (obj->is<PartDesign::Line>()) { | |
| mode = mm1TwoPoints; | |
| } | |
| else if (obj->is<PartDesign::Plane>()) { | |
| mode = mmFlatFace; | |
| } | |
| else { | |
| return copy; | |
| } | |
| // TODO Recheck this. This looks strange in case of independent copy (2015-10-31, | |
| // Fat-Zer) | |
| if (!independent) { | |
| datumCopy->AttachmentSupport.setValue(obj, entity.c_str()); | |
| datumCopy->MapMode.setValue(mode); | |
| } | |
| else if (!entity.empty()) { | |
| datumCopy->Shape.setValue( | |
| static_cast<Part::Datum*>(obj)->Shape.getShape().getSubShape(entity.c_str()) | |
| ); | |
| } | |
| else { | |
| datumCopy->Shape.setValue(static_cast<Part::Datum*>(obj)->Shape.getValue()); | |
| } | |
| } | |
| else if (obj->is<PartDesign::ShapeBinder>() || obj->isDerivedFrom<Part::Feature>()) { | |
| auto* doc = App::GetApplication().getActiveDocument(); | |
| auto* shapeBinderObj = doc->addObject<PartDesign::ShapeBinder>(name.c_str()); | |
| if (!independent) { | |
| shapeBinderObj->Support.setValue(obj, entity.c_str()); | |
| } | |
| else { | |
| shapeProp = &shapeBinderObj->Shape; | |
| } | |
| copy = shapeBinderObj; | |
| } | |
| else if (obj->isDerivedFrom<App::Plane>() || obj->isDerivedFrom<App::Line>()) { | |
| auto* doc = App::GetApplication().getActiveDocument(); | |
| auto* shapeBinderObj = doc->addObject<PartDesign::ShapeBinder>(name.c_str()); | |
| if (!independent) { | |
| shapeBinderObj->Support.setValue(obj, entity.c_str()); | |
| } | |
| else { | |
| std::vector<std::string> subvalues; | |
| subvalues.push_back(entity); | |
| Part::TopoShape shape | |
| = PartDesign::ShapeBinder::buildShapeFromReferences(shapeBinderObj, subvalues); | |
| shapeBinderObj->Shape.setValue(shape); | |
| } | |
| copy = shapeBinderObj; | |
| } | |
| if (independent && shapeProp) { | |
| auto* featureObj = static_cast<Part::Feature*>(obj); | |
| shapeProp->setValue( | |
| entity.empty() ? featureObj->Shape.getValue() | |
| : featureObj->Shape.getShape().getSubShape(entity.c_str()) | |
| ); | |
| } | |
| } | |
| return copy; | |
| } | |
| bool TaskFeaturePick::isSingleSelectionEnabled() const | |
| { | |
| ParameterGrp::handle hGrp = App::GetApplication() | |
| .GetUserParameter() | |
| .GetGroup("BaseApp") | |
| ->GetGroup("Preferences") | |
| ->GetGroup("Selection"); | |
| return hGrp->GetBool("singleClickFeatureSelect", true); | |
| } | |
| void TaskFeaturePick::onSelectionChanged(const Gui::SelectionChanges& msg) | |
| { | |
| if (doSelection) { | |
| return; | |
| } | |
| doSelection = true; | |
| ui->listWidget->clearSelection(); | |
| for (Gui::SelectionSingleton::SelObj obj : Gui::Selection().getSelection()) { | |
| for (int row = 0; row < ui->listWidget->count(); row++) { | |
| QListWidgetItem* item = ui->listWidget->item(row); | |
| QString t = item->data(Qt::UserRole).toString(); | |
| if (t.compare(QString::fromLatin1(obj.FeatName)) == 0) { | |
| item->setSelected(true); | |
| if (msg.Type == Gui::SelectionChanges::AddSelection) { | |
| if (isSingleSelectionEnabled()) { | |
| QMetaObject::invokeMethod( | |
| qobject_cast<Gui::ControlSingleton*>(&Gui::Control()), | |
| "accept", | |
| Qt::QueuedConnection | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| doSelection = false; | |
| } | |
| void TaskFeaturePick::onItemSelectionChanged() | |
| { | |
| if (doSelection) { | |
| return; | |
| } | |
| doSelection = true; | |
| ui->listWidget->blockSignals(true); | |
| Gui::Selection().clearSelection(); | |
| for (int row = 0; row < ui->listWidget->count(); row++) { | |
| QListWidgetItem* item = ui->listWidget->item(row); | |
| QString t = item->data(Qt::UserRole).toString(); | |
| if (item->isSelected()) { | |
| Gui::Selection().addSelection(documentName.c_str(), t.toLatin1()); | |
| } | |
| } | |
| ui->listWidget->blockSignals(false); | |
| doSelection = false; | |
| } | |
| void TaskFeaturePick::onDoubleClick(QListWidgetItem* item) | |
| { | |
| if (doSelection) { | |
| return; | |
| } | |
| doSelection = true; | |
| QString t = item->data(Qt::UserRole).toString(); | |
| Gui::Selection().addSelection(documentName.c_str(), t.toLatin1()); | |
| doSelection = false; | |
| QMetaObject::invokeMethod( | |
| qobject_cast<Gui::ControlSingleton*>(&Gui::Control()), | |
| "accept", | |
| Qt::QueuedConnection | |
| ); | |
| } | |
| void TaskFeaturePick::slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj) | |
| { | |
| if (const auto it = std::ranges::find(origins, &Obj); it != origins.end()) { | |
| origins.erase(it); | |
| } | |
| } | |
| void TaskFeaturePick::slotUndoDocument(const Gui::Document&) | |
| { | |
| if (origins.empty()) { | |
| QTimer::singleShot(100, &Gui::Control(), &Gui::ControlSingleton::closeDialog); | |
| } | |
| } | |
| void TaskFeaturePick::slotDeleteDocument(const Gui::Document&) | |
| { | |
| origins.clear(); | |
| QTimer::singleShot(100, &Gui::Control(), &Gui::ControlSingleton::closeDialog); | |
| } | |
| void TaskFeaturePick::showExternal(bool val) | |
| { | |
| ui->checkOtherBody->setChecked(val); | |
| ui->checkOtherPart->setChecked(val); | |
| updateList(); | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // TaskDialog | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| TaskDlgFeaturePick::TaskDlgFeaturePick( | |
| std::vector<App::DocumentObject*>& objects, | |
| const std::vector<TaskFeaturePick::featureStatus>& status, | |
| std::function<bool(std::vector<App::DocumentObject*>)> afunc, | |
| std::function<void(std::vector<App::DocumentObject*>)> wfunc, | |
| bool singleFeatureSelect, | |
| std::function<void(void)> abortfunc /* = NULL */ | |
| ) | |
| : TaskDialog() | |
| , accepted(false) | |
| { | |
| pick = new TaskFeaturePick(objects, status, singleFeatureSelect); | |
| Content.push_back(pick); | |
| acceptFunction = afunc; | |
| workFunction = wfunc; | |
| abortFunction = abortfunc; | |
| } | |
| TaskDlgFeaturePick::~TaskDlgFeaturePick() | |
| { | |
| // do the work now as before in accept() the dialog is still open, hence the work | |
| // function could not open another dialog | |
| if (accepted) { | |
| try { | |
| workFunction(pick->buildFeatures()); | |
| } | |
| catch (...) { | |
| } | |
| } | |
| else if (abortFunction) { | |
| // Get rid of the TaskFeaturePick before the TaskDialog dtor does. The | |
| // TaskFeaturePick holds pointers to things (ie any implicitly created | |
| // Body objects) that might be modified/removed by abortFunction. | |
| for (auto it : Content) { | |
| delete it; | |
| } | |
| Content.clear(); | |
| try { | |
| abortFunction(); | |
| } | |
| catch (...) { | |
| } | |
| } | |
| } | |
| //==== calls from the TaskView =============================================================== | |
| void TaskDlgFeaturePick::open() | |
| {} | |
| void TaskDlgFeaturePick::clicked(int) | |
| {} | |
| bool TaskDlgFeaturePick::accept() | |
| { | |
| accepted = acceptFunction(pick->getFeatures()); | |
| return accepted; | |
| } | |
| bool TaskDlgFeaturePick::reject() | |
| { | |
| accepted = false; | |
| return true; | |
| } | |
| void TaskDlgFeaturePick::showExternal(bool val) | |
| { | |
| pick->showExternal(val); | |
| } | |