/*************************************************************************** * Copyright (c) 2002 Jürgen Riegel * * Copyright (c) 2014 Luke Parry * * * * 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 * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DrawGuiUtil.h" #include "MDIViewPage.h" #include "QGIViewPart.h" #include "QGSPage.h" #include "QGVPage.h" #include "Rez.h" #include "TaskActiveView.h" #include "TaskComplexSection.h" #include "TaskDetail.h" #include "TaskProjGroup.h" #include "TaskProjection.h" #include "TaskSectionView.h" #include "ViewProviderPage.h" #include "ViewProviderDrawingView.h" #include "CommandHelpers.h" void execSimpleSection(Gui::Command* cmd); void execComplexSection(Gui::Command* cmd); void getSelectedShapes(Gui::Command* cmd, std::vector& shapes, std::vector& xShapes, App::DocumentObject* faceObj, std::string& faceName); std::pair faceFromSelection(); std::pair viewDirection(); class Vertex; using namespace TechDrawGui; using namespace TechDraw; using DU = DrawUtil; //=========================================================================== // TechDraw_PageDefault //=========================================================================== DEF_STD_CMD_A(CmdTechDrawPageDefault) CmdTechDrawPageDefault::CmdTechDrawPageDefault() : Command("TechDraw_PageDefault") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("New Page"); sToolTipText = QT_TR_NOOP("Creates a new page with the default template"); sWhatsThis = "TechDraw_PageDefault"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_PageDefault"; } void CmdTechDrawPageDefault::activated(int iMsg) { Q_UNUSED(iMsg); QString templateFileName = Preferences::defaultTemplate(); QFileInfo tfi(templateFileName); if (tfi.isReadable()) { Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Drawing create page")); auto page = getDocument()->addObject("Page"); if (!page) { throw Base::TypeError("CmdTechDrawPageDefault - page not created"); } page->translateLabel("DrawPage", "Page", page->getNameInDocument()); auto svgTemplate = getDocument()->addObject("Template"); if (!svgTemplate) { throw Base::TypeError("CmdTechDrawPageDefault - template not created"); } svgTemplate->translateLabel("DrawSVGTemplate", "Template", svgTemplate->getNameInDocument()); page->Template.setValue(svgTemplate); auto filespec = DU::cleanFilespecBackslash(templateFileName.toStdString()); svgTemplate->Template.setValue(filespec); updateActive(); commitCommand(); TechDrawGui::ViewProviderPage *dvp = dynamic_cast (Gui::Application::Instance->getViewProvider(page)); if (dvp) { dvp->show(); } } else { QMessageBox::critical(Gui::getMainWindow(), QLatin1String("No template"), QLatin1String("No default template found")); } } bool CmdTechDrawPageDefault::isActive() { return hasActiveDocument(); } //=========================================================================== // TechDraw_PageTemplate //=========================================================================== DEF_STD_CMD_A(CmdTechDrawPageTemplate) CmdTechDrawPageTemplate::CmdTechDrawPageTemplate() : Command("TechDraw_PageTemplate") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("New Page From Template"); sToolTipText = QT_TR_NOOP("Creates a new page from a custom template"); sWhatsThis = "TechDraw_PageTemplate"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_PageTemplate"; } void CmdTechDrawPageTemplate::activated(int iMsg) { Q_UNUSED(iMsg); QString work_dir = Gui::FileDialog::getWorkingDirectory(); QString templateDir = Preferences::defaultTemplateDir(); QString templateFileName = Gui::FileDialog::getOpenFileName( Gui::getMainWindow(), QString::fromUtf8(QT_TR_NOOP("Select a template file")), templateDir, QString::fromUtf8(QT_TR_NOOP("Template (*.svg)"))); Gui::FileDialog::setWorkingDirectory(work_dir);// Don't overwrite WD with templateDir if (templateFileName.isEmpty()) { return; } QFileInfo tfi(templateFileName); if (tfi.isReadable()) { Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Drawing create page")); auto page = getDocument()->addObject("Page"); if (!page) { throw Base::TypeError("CmdTechDrawPageTemplate - page not created"); } page->translateLabel("DrawPage", "Page", page->getNameInDocument()); auto svgTemplate = getDocument()->addObject("Template"); if (!svgTemplate) { throw Base::TypeError("CmdTechDrawPageTemplate - template not created"); } svgTemplate->translateLabel("DrawSVGTemplate", "Template", svgTemplate->getNameInDocument()); page->Template.setValue(svgTemplate); auto filespec = DU::cleanFilespecBackslash(templateFileName.toStdString()); svgTemplate->Template.setValue(filespec); updateActive(); commitCommand(); TechDrawGui::ViewProviderPage *dvp = dynamic_cast (Gui::Application::Instance->getViewProvider(page)); if (dvp) { dvp->show(); } } else { QMessageBox::critical(Gui::getMainWindow(), QLatin1String("No template"), QLatin1String("Template file is invalid")); } } bool CmdTechDrawPageTemplate::isActive() { return hasActiveDocument(); } //=========================================================================== // TechDraw_RedrawPage //=========================================================================== DEF_STD_CMD_A(CmdTechDrawRedrawPage) CmdTechDrawRedrawPage::CmdTechDrawRedrawPage() : Command("TechDraw_RedrawPage") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Redraw Page"); sToolTipText = QT_TR_NOOP("Redraws the current page"); sWhatsThis = "TechDraw_RedrawPage"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_RedrawPage"; } void CmdTechDrawRedrawPage::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } Gui::WaitCursor wc; page->redrawCommand(); } bool CmdTechDrawRedrawPage::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this, false); return (havePage && haveView); } //=========================================================================== // TechDraw_PrintAll //=========================================================================== DEF_STD_CMD_A(CmdTechDrawPrintAll) CmdTechDrawPrintAll::CmdTechDrawPrintAll() : Command("TechDraw_PrintAll") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Print All Pages"); sToolTipText = QT_TR_NOOP("Prints all pages with the print dialog"); sWhatsThis = "TechDraw_PrintAll"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_PrintAll"; } void CmdTechDrawPrintAll::activated(int iMsg) { Q_UNUSED(iMsg); MDIViewPage::printAllPages(); } bool CmdTechDrawPrintAll::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_View //=========================================================================== DEF_STD_CMD_A(CmdTechDrawView) CmdTechDrawView::CmdTechDrawView() : Command("TechDraw_View") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("New View"); sToolTipText = QT_TR_NOOP( "Inserts a new view into the current page based on the selected object in the tree view " "or 3D view.\n" "If no object is selected, a file browser opens to select an SVG or image file."); sWhatsThis = "TechDraw_View"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_View"; } void CmdTechDrawView::activated(int iMsg) { Q_UNUSED(iMsg); bool viewCreated = false; TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); // switch to the page if it's not current active window auto* vpp = freecad_cast (Gui::Application::Instance->getViewProvider(page)); if (vpp) { vpp->show(); } //set projection direction from selected Face //use first object with a face selected std::vector shapes, xShapes; App::DocumentObject* partObj = nullptr; std::string faceName; auto selection = getSelection().getSelectionEx(nullptr, App::DocumentObject::getClassTypeId()); for (auto& sel : selection) { bool is_linked = false; auto obj = sel.getObject(); if (obj->isDerivedFrom() || obj->isDerivedFrom()) { continue; } if (obj->isDerivedFrom()) { std::string SpreadName = obj->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Create spreadsheet view")); std::string FeatName = getUniqueObjectName("Sheet"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewSpreadsheet', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewSpreadsheet', 'Sheet', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Source = App.activeDocument().%s", FeatName.c_str(), SpreadName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); viewCreated = true; continue; } else if (DrawGuiUtil::isArchSection(obj)) { std::string FeatName = getUniqueObjectName("BIM view"); std::string SourceName = obj->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Create BIM view")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewArch', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewArch', 'BIM view', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Source = App.activeDocument().%s", FeatName.c_str(), SourceName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); viewCreated = true; continue; } if (obj->isDerivedFrom() || obj->isDerivedFrom() || obj->isDerivedFrom()) { is_linked = true; } // If parent of the obj is a link to another document, we possibly need to treat non-link obj as linked, too // 1st, is obj in another document? if (obj->getDocument() != this->getDocument()) { std::set parents = obj->getInListEx(true); for (auto& parent : parents) { // Only consider parents in the current document, i.e. possible links in this View's document if (parent->getDocument() != this->getDocument()) { continue; } // 2nd, do we really have a link to obj? if (parent->isDerivedFrom() || parent->isDerivedFrom() || parent->isDerivedFrom()) { // We have a link chain from this document to obj, and obj is in another document -> it is an XLink target is_linked = true; } } } if (is_linked) { xShapes.push_back(obj); continue; } //not a Link and not null. assume to be drawable. Undrawables will be // skipped later. shapes.push_back(obj); if (partObj) { continue; } //don't know if this works for an XLink for (auto& sub : sel.getSubNames()) { if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { faceName = sub; // partObj = obj; break; } } } ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/TechDraw"); if (shapes.empty() && xShapes.empty()) { if (!viewCreated) { // If nothing was selected, then we offer to insert SVG or Images files. bool dontShowAgain = hGrp->GetBool("DontShowInsertFileMessage", false); if (!dontShowAgain) { auto msgText = QObject::tr("To insert a view from existing objects, " "select them before invoking this tool. Without a selection, a " "file browser will open to insert an SVG or image file."); QMessageBox msgBox(Gui::getMainWindow()); msgBox.setText(msgText); auto dontShowMsg = QObject::tr("Do not show this message again"); QCheckBox dontShowCheckBox(dontShowMsg, &msgBox); msgBox.setCheckBox(&dontShowCheckBox); QPushButton* okButton = msgBox.addButton(QMessageBox::Ok); msgBox.exec(); if (msgBox.clickedButton() == okButton && dontShowCheckBox.isChecked()) { // Save the preference to not show the message again hGrp->SetBool("DontShowInsertFileMessage", true); } } QString filename = Gui::FileDialog::getOpenFileName(Gui::getMainWindow(), QObject::tr("Select a SVG or Image file to open"), Preferences::defaultSymbolDir(), QStringLiteral("%1 (*.svg *.svgz *.jpg *.jpeg *.png *.bmp);;%2 (*.*)") .arg(QObject::tr("SVG or Image files"), QObject::tr("All Files"))); if (!filename.isEmpty()) { if (filename.endsWith(QStringLiteral(".svg"), Qt::CaseInsensitive) || filename.endsWith(QStringLiteral(".svgz"), Qt::CaseInsensitive)) { std::string FeatName = getUniqueObjectName("Symbol"); filename = Base::Tools::escapeEncodeFilename(filename); auto filespec = DU::cleanFilespecBackslash(filename.toStdString()); openCommand(QT_TRANSLATE_NOOP("Command", "Create Symbol")); doCommand(Doc, "import codecs"); doCommand(Doc, "f = codecs.open(\"%s\", 'r', encoding=\"utf-8\")", filespec.c_str()); doCommand(Doc, "svg = f.read()"); doCommand(Doc, "f.close()"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewSymbol', '%s')", FeatName.c_str()); doCommand( Doc, "App.activeDocument().%s.translateLabel('DrawViewSymbol', 'Symbol', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Symbol = svg", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); } else { std::string FeatName = getUniqueObjectName("Image"); filename = Base::Tools::escapeEncodeFilename(filename); auto filespec = DU::cleanFilespecBackslash(filename.toStdString()); openCommand(QT_TRANSLATE_NOOP("Command", "Create image")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewImage', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewImage', 'Image', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.ImageFile = '%s'", FeatName.c_str(), filespec.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); } updateActive(); commitCommand(); } } return; } Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Create view")); std::string FeatName = getUniqueObjectName("View"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawProjGroupItem', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawProjGroupItem', 'View', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); App::DocumentObject* docObj = getDocument()->getObject(FeatName.c_str()); auto* dvp = dynamic_cast(docObj); if (!dvp) { throw Base::TypeError("CmdTechDrawView DVP not found\n"); } dvp->Source.setValues(shapes); dvp->XSource.setValues(xShapes); getDocument()->setStatus(App::Document::Status::SkipRecompute, true); auto dirs = viewDirection(); doCommand(Doc, "App.activeDocument().%s.Direction = FreeCAD.Vector(%.12f, %.12f, %.12f)", FeatName.c_str(), dirs.first.x, dirs.first.y, dirs.first.z); doCommand(Doc, "App.activeDocument().%s.RotationVector = FreeCAD.Vector(%.12f, %.12f, %.12f)", FeatName.c_str(), dirs.second.x, dirs.second.y, dirs.second.z); doCommand(Doc, "App.activeDocument().%s.XDirection = FreeCAD.Vector(%.12f, %.12f, %.12f)", FeatName.c_str(), dirs.second.x, dirs.second.y, dirs.second.z); getDocument()->setStatus(App::Document::Status::SkipRecompute, false); doCommand(Doc, "App.activeDocument().%s.recompute()", FeatName.c_str()); commitCommand(); // create the rest of the desired views Gui::Control().showDialog(new TaskDlgProjGroup(dvp, true)); } bool CmdTechDrawView::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_BrokenView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawBrokenView) CmdTechDrawBrokenView::CmdTechDrawBrokenView() : Command("TechDraw_BrokenView") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Broken View"); sToolTipText = QT_TR_NOOP("Inserts a new broken view for the selected objects or base view and break definition objects"); sWhatsThis = "TechDraw_BrokenView"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_BrokenView"; } void CmdTechDrawBrokenView::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); // get shape objects from a base view std::vector shapesFromBase; std::vector xShapesFromBase; std::vector baseViews = getSelection().getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); TechDraw::DrawViewPart* dvp{nullptr}; if (!baseViews.empty()) { dvp = static_cast(*baseViews.begin()); shapesFromBase = dvp->Source.getValues(); xShapesFromBase = dvp->XSource.getValues(); } auto doc = getDocument(); if (dvp) { doc = dvp->getDocument(); } // get the shape objects from the selection std::vector shapes; std::vector xShapes; App::DocumentObject* faceObj = nullptr; std::string faceName; getSelectedShapes(this, shapes, xShapes, faceObj, faceName); // we need either a base view (dvp) or some shape objects in the selection if (!dvp && (shapes.empty() && xShapes.empty())) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Empty selection"), QObject::tr("Select objects to break or a base view and break definition objects")); return; } shapes.insert(shapes.end(), shapesFromBase.begin(), shapesFromBase.end()); shapes.insert(xShapes.end(), xShapesFromBase.begin(), xShapesFromBase.end()); // pick the Break objects out of the selected pile std::vector selection = getSelection().getSelectionEx( nullptr, App::DocumentObject::getClassTypeId(), Gui::ResolveMode::NoResolve); std::vector breakObjects; for (auto& selObj : selection) { auto temp = selObj.getObject(); // a sketch outside a body is returned as an independent object in the selection if (selObj.getSubNames().empty()) { if (DrawBrokenView::isBreakObject(*temp)) { breakObjects.push_back(selObj.getObject()); } continue; } // a sketch inside a body is returned as body + subelement, so we have to search through // subnames to find it. This may(?) apply to App::Part and Group also? auto subname = selObj.getSubNames().front(); if (subname.back() == '.') { subname = subname.substr(0, subname.length() - 1); auto objects = doc->getObjects(); for (auto& obj : objects) { std::string objname{obj->getNameInDocument()}; if (subname == objname && DrawBrokenView::isBreakObject(*obj)) { breakObjects.push_back(obj); } } } } if (breakObjects.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No break objects found in this selection")); return; } // remove Break objects from shape pile shapes = DrawBrokenView::removeBreakObjects(breakObjects, shapes); xShapes = DrawBrokenView::removeBreakObjects(breakObjects, xShapes); if (shapes.empty() && xShapes.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No shapes, groups, or links in this selection")); return; } Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Create broken view")); getDocument()->setStatus(App::Document::Status::SkipRecompute, true); std::string FeatName = getUniqueObjectName("BrokenView"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawBrokenView','%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); App::DocumentObject* docObj = getDocument()->getObject(FeatName.c_str()); TechDraw::DrawBrokenView* dbv = dynamic_cast(docObj); if (!dbv) { throw Base::TypeError("CmdTechDrawBrokenView DBV not found\n"); } dbv->Source.setValues(shapes); dbv->XSource.setValues(xShapes); dbv->Breaks.setValues(breakObjects); //set projection direction from selected Face std::pair dirs; if (faceName.size()) { dirs = DrawGuiUtil::getProjDirFromFace(faceObj, faceName); } else { dirs = DrawGuiUtil::get3DDirAndRot(); } Base::Vector3d projDir = dirs.first; doCommand(Doc, "App.activeDocument().%s.Direction = FreeCAD.Vector(%.6f,%.6f,%.6f)", FeatName.c_str(), projDir.x, projDir.y, projDir.z); doCommand(Doc, "App.activeDocument().%s.XDirection = FreeCAD.Vector(%.6f,%.6f,%.6f)", FeatName.c_str(), dirs.second.x, dirs.second.y, dirs.second.z); getDocument()->setStatus(App::Document::Status::SkipRecompute, true); commitCommand(); dbv->recomputeFeature(); } bool CmdTechDrawBrokenView::isActive(void) { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_ActiveView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawActiveView) CmdTechDrawActiveView::CmdTechDrawActiveView() : Command("TechDraw_ActiveView") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Active View"); sToolTipText = "Inserts an image of the open 3D view in the current page.\n" "If multiple 3D views are open, a selection dialog will be shown."; sWhatsThis = "TechDraw_ActiveView"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ActiveView"; } void CmdTechDrawActiveView::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this, true); if (!page) { return; } std::string PageName = page->getNameInDocument(); Gui::Control().showDialog(new TaskDlgActiveView(page)); } bool CmdTechDrawActiveView::isActive() { return DrawGuiUtil::needPage(this, true); } //=========================================================================== // TechDraw_SectionGroup //=========================================================================== DEF_STD_CMD_ACL(CmdTechDrawSectionGroup) CmdTechDrawSectionGroup::CmdTechDrawSectionGroup() : Command("TechDraw_SectionGroup") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Section View (Simple or Complex)"); sToolTipText = QT_TR_NOOP("Inserts a simple or complex section view in the current page"); sWhatsThis = "TechDraw_SectionGroup"; sStatusTip = sToolTipText; } void CmdTechDrawSectionGroup::activated(int iMsg) { // Base::Console().message("CMD::SectionGrp - activated(%d)\n", iMsg); Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); if (dlg) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Task in progress"), QObject::tr("Close active task dialog and try again")); return; } Gui::ActionGroup* pcAction = qobject_cast(_pcAction); pcAction->setIcon(pcAction->actions().at(iMsg)->icon()); switch (iMsg) { case 0: execSimpleSection(this); break; case 1: execComplexSection(this); break; default: Base::Console().message("CMD::SectionGrp - invalid iMsg: %d\n", iMsg); }; } Gui::Action* CmdTechDrawSectionGroup::createAction() { Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); QAction* p1 = pcAction->addAction(QString()); p1->setIcon(Gui::BitmapFactory().iconFromTheme("actions/TechDraw_SectionView")); p1->setObjectName(QStringLiteral("TechDraw_SectionView")); p1->setWhatsThis(QStringLiteral("TechDraw_SectionView")); QAction* p2 = pcAction->addAction(QString()); p2->setIcon(Gui::BitmapFactory().iconFromTheme("actions/TechDraw_ComplexSection")); p2->setObjectName(QStringLiteral("TechDraw_ComplexSection")); p2->setWhatsThis(QStringLiteral("TechDraw_ComplexSection")); _pcAction = pcAction; languageChange(); pcAction->setIcon(p1->icon()); int defaultId = 0; pcAction->setProperty("defaultAction", QVariant(defaultId)); return pcAction; } void CmdTechDrawSectionGroup::languageChange() { Command::languageChange(); if (!_pcAction) return; Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); QAction* arc1 = a[0]; arc1->setText(QApplication::translate("CmdTechDrawSectionGroup", "Section View")); arc1->setToolTip(QApplication::translate("TechDraw_SectionView", "Inserts a simple section view")); arc1->setStatusTip(arc1->toolTip()); QAction* arc2 = a[1]; arc2->setText(QApplication::translate("CmdTechDrawSectionGroup", "Complex Section View")); arc2->setToolTip( QApplication::translate("TechDraw_ComplexSection", "Inserts a complex section view")); arc2->setStatusTip(arc2->toolTip()); } bool CmdTechDrawSectionGroup::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this, false); return (havePage && haveView); } //=========================================================================== // TechDraw_SectionView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawSectionView) CmdTechDrawSectionView::CmdTechDrawSectionView() : Command("TechDraw_SectionView") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Section View"); sToolTipText = QT_TR_NOOP("Inserts a new section view based on the selected view in the current page"); sWhatsThis = "TechDraw_SectionView"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_SectionView"; } void CmdTechDrawSectionView::activated(int iMsg) { Q_UNUSED(iMsg); Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); if (dlg) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Task in progress"), QObject::tr("Close active task dialog and try again")); return; } execSimpleSection(this); } bool CmdTechDrawSectionView::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); bool taskInProgress = false; if (havePage) { taskInProgress = Gui::Control().activeDialog(); } return (havePage && haveView && !taskInProgress); } void execSimpleSection(Gui::Command* cmd) { std::vector baseObj = cmd->getSelection().getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); if (baseObj.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least 1 DrawViewPart object as base")); return; } TechDraw::DrawPage* page = DrawGuiUtil::findPage(cmd); if (!page) { return; } TechDraw::DrawViewPart* dvp = static_cast(*baseObj.begin()); Gui::Control().showDialog(new TaskDlgSectionView(dvp)); cmd->updateActive();//ok here since dialog doesn't call doc.recompute() cmd->commitCommand(); } //=========================================================================== // TechDraw_ComplexSection //=========================================================================== DEF_STD_CMD_A(CmdTechDrawComplexSection) CmdTechDrawComplexSection::CmdTechDrawComplexSection() : Command("TechDraw_ComplexSection") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Complex Section View"); sToolTipText = QT_TR_NOOP("Inserts a complex section view based on the selected view in the current page"); sWhatsThis = "TechDraw_ComplexSection"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ComplexSection"; } void CmdTechDrawComplexSection::activated(int iMsg) { Q_UNUSED(iMsg); Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); if (dlg) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Task in progress"), QObject::tr("Close active task dialog and try again")); return; } execComplexSection(this); } bool CmdTechDrawComplexSection::isActive() { return DrawGuiUtil::needPage(this); } //Complex Sections can be created without a baseView, so the gathering of input //for the dialog is more involved that simple section void execComplexSection(Gui::Command* cmd) { TechDraw::DrawViewPart* baseView(nullptr); std::vector shapes; std::vector xShapes; App::DocumentObject* profileObject(nullptr); std::vector profileSubs; Gui::ResolveMode resolve = Gui::ResolveMode::OldStyleElement; bool single = false; auto selection = cmd->getSelection().getSelectionEx( nullptr, App::DocumentObject::getClassTypeId(), resolve, single); for (auto& sel : selection) { bool is_linked = false; auto obj = sel.getObject(); if (obj->isDerivedFrom()) { continue; } if (obj->isDerivedFrom()) { //use the dvp's Sources as sources for this ComplexSection & //check the subelement(s) to see if they can be used as a profile baseView = static_cast(obj); if (!sel.getSubNames().empty()) { //need to add profile subs as parameter profileObject = baseView; profileSubs = sel.getSubNames(); } continue; } if (obj->isDerivedFrom() || obj->isDerivedFrom() || obj->isDerivedFrom()) { is_linked = true; } // If parent of the obj is a link to another document, we possibly need to treat non-link obj as linked, too // 1st, is obj in another document? if (obj->getDocument() != cmd->getDocument()) { std::set parents = obj->getInListEx(true); for (auto& parent : parents) { // Only consider parents in the current document, i.e. possible links in this View's document if (parent->getDocument() != cmd->getDocument()) { continue; } // 2nd, do we really have a link to obj? if (parent->isDerivedFrom() || parent->isDerivedFrom() || parent->isDerivedFrom()) { // We have a link chain from this document to obj, and obj is in another document -> it is an XLink target is_linked = true; } } } if (is_linked) { xShapes.push_back(obj); continue; } //not a Link and not null. assume to be drawable. Undrawables will be // skipped later. if (TechDraw::DrawComplexSection::isProfileObject(obj)) { profileObject = obj; } else { shapes.push_back(obj); } } if (!baseView) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No base view selected")); return; } if (shapes.empty() && xShapes.empty() && !baseView) { QMessageBox::warning( Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No base view, shapes, groups, or links in this selection")); return; } if (!profileObject) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No profile object found in selection")); return; } TechDraw::DrawPage* page = DrawGuiUtil::findPage(cmd); if (!page) { return; } Gui::Control().showDialog( new TaskDlgComplexSection(page, baseView, shapes, xShapes, profileObject, profileSubs)); } //=========================================================================== // TechDraw_DetailView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawDetailView) CmdTechDrawDetailView::CmdTechDrawDetailView() : Command("TechDraw_DetailView") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Detail View"); sToolTipText = QT_TR_NOOP("Inserts a new detail view based on the selected view in the current page"); sWhatsThis = "TechDraw_DetailView"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_DetailView"; } void CmdTechDrawDetailView::activated(int iMsg) { Q_UNUSED(iMsg); std::vector baseObj = getSelection().getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); if (baseObj.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least 1 DrawViewPart object as base")); return; } TechDraw::DrawViewPart* dvp = static_cast(*(baseObj.begin())); Gui::Control().showDialog(new TaskDlgDetail(dvp)); } bool CmdTechDrawDetailView::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); bool taskInProgress = false; if (havePage) { taskInProgress = Gui::Control().activeDialog(); } return (havePage && haveView && !taskInProgress); } //=========================================================================== // TechDraw_ProjectionGroup //=========================================================================== DEF_STD_CMD_A(CmdTechDrawProjectionGroup) CmdTechDrawProjectionGroup::CmdTechDrawProjectionGroup() : Command("TechDraw_ProjectionGroup") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Projection Group"); sToolTipText = QT_TR_NOOP("Inserts multiple new linked views of the selected objects in the current page"); sWhatsThis = "TechDraw_ProjectionGroup"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ProjectionGroup"; } void CmdTechDrawProjectionGroup::activated(int iMsg) { Q_UNUSED(iMsg); //set projection direction from selected Face //use first object with a face selected std::vector shapes; std::vector xShapes; App::DocumentObject* partObj = nullptr; std::string faceName; Gui::ResolveMode resolve = Gui::ResolveMode::OldStyleElement; bool single = false; auto selection = getSelection().getSelectionEx(nullptr, App::DocumentObject::getClassTypeId(), resolve, single); for (auto& sel : selection) { bool is_linked = false; auto obj = sel.getObject(); if (obj->isDerivedFrom()) { continue; } if (obj->isDerivedFrom() || obj->isDerivedFrom() || obj->isDerivedFrom()) { is_linked = true; } // If parent of the obj is a link to another document, we possibly need to treat non-link obj as linked, too // 1st, is obj in another document? if (obj->getDocument() != this->getDocument()) { std::set parents = obj->getInListEx(true); for (auto& parent : parents) { // Only consider parents in the current document, i.e. possible links in this View's document if (parent->getDocument() != this->getDocument()) { continue; } // 2nd, do we really have a link to obj? if (parent->isDerivedFrom() || parent->isDerivedFrom() || parent->isDerivedFrom()) { // We have a link chain from this document to obj, and obj is in another document -> it is an XLink target is_linked = true; } } } if (is_linked) { xShapes.push_back(obj); continue; } //not a Link and not null. assume to be drawable. Undrawables will be // skipped later. shapes.push_back(obj); if (partObj) { continue; } for (auto& sub : sel.getSubNames()) { if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { faceName = sub; partObj = obj; break; } } } if (shapes.empty() && xShapes.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No shapes, groups, or links in this selection")); return; } TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); Base::Vector3d projDir; Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Create projection group")); std::string multiViewName = getUniqueObjectName("ProjGroup"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawProjGroup', '%s')", multiViewName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), multiViewName.c_str()); App::DocumentObject* docObj = getDocument()->getObject(multiViewName.c_str()); auto multiView(static_cast(docObj)); multiView->Source.setValues(shapes); multiView->XSource.setValues(xShapes); doCommand(Doc, "App.activeDocument().%s.addProjection('Front')", multiViewName.c_str()); std::pair dirs = !faceName.empty() ? DrawGuiUtil::getProjDirFromFace(partObj, faceName) : DrawGuiUtil::get3DDirAndRot(); getDocument()->setStatus(App::Document::Status::SkipRecompute, true); doCommand(Doc, "App.activeDocument().%s.Anchor.Direction = FreeCAD.Vector(%.12f, %.12f, %.12f)", multiViewName.c_str(), dirs.first.x, dirs.first.y, dirs.first.z); doCommand(Doc, "App.activeDocument().%s.Anchor.RotationVector = FreeCAD.Vector(%.12f, %.12f, %.12f)", multiViewName.c_str(), dirs.second.x, dirs.second.y, dirs.second.z); doCommand(Doc, "App.activeDocument().%s.Anchor.XDirection = FreeCAD.Vector(%.12f, %.12f, %.12f)", multiViewName.c_str(), dirs.second.x, dirs.second.y, dirs.second.z); getDocument()->setStatus(App::Document::Status::SkipRecompute, false); doCommand(Doc, "App.activeDocument().%s.Anchor.recompute()", multiViewName.c_str()); commitCommand(); updateActive(); // create the rest of the desired views Gui::Control().showDialog(new TaskDlgProjGroup(multiView, true)); } bool CmdTechDrawProjectionGroup::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool taskInProgress = false; if (havePage) { taskInProgress = Gui::Control().activeDialog(); } return (havePage && !taskInProgress); } //! common checks of Selection for Dimension commands //non-empty selection, no more than maxObjs selected and at least 1 DrawingPage exists bool _checkSelectionBalloon(Gui::Command* cmd, unsigned maxObjs) { std::vector selection = cmd->getSelection().getSelectionEx(); if (selection.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), QObject::tr("Select an object first")); return false; } const std::vector SubNames = selection[0].getSubNames(); if (SubNames.size() > maxObjs) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), QObject::tr("Too many objects selected")); return false; } std::vector pages = cmd->getDocument()->getObjectsOfType(TechDraw::DrawPage::getClassTypeId()); if (pages.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), QObject::tr("Create a page first")); return false; } return true; } bool _checkDrawViewPartBalloon(Gui::Command* cmd) { std::vector selection = cmd->getSelection().getSelectionEx(); auto objFeat(dynamic_cast(selection[0].getObject())); if (!objFeat) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), QObject::tr("No view of a part in selection")); return false; } return true; } bool _checkDirectPlacement(const QGIView* view, const std::vector& subNames, QPointF& placement) { // Let's see, if we can help speed up the placement of the balloon: // As of now we support: // Single selected vertex: place the balloon tip end here // Single selected edge: place the balloon tip at its midpoint (suggested placement for e.g. chamfer dimensions) // // Single selected faces are currently not supported, but maybe we could in this case use the center of mass? if (subNames.size() != 1) { // If nothing or more than one subjects are selected, let the user decide, where to place the balloon return false; } const QGIViewPart* viewPart = dynamic_cast(view); if (!viewPart) { //not a view of a part, so no geometry to attach to return false; } std::string geoType = TechDraw::DrawUtil::getGeomTypeFromName(subNames[0]); if (geoType == "Vertex") { int index = TechDraw::DrawUtil::getIndexFromName(subNames[0]); TechDraw::VertexPtr vertex = static_cast(viewPart->getViewObject())->getProjVertexByIndex(index); if (vertex) { placement = viewPart->mapToScene(Rez::guiX(vertex->x()), Rez::guiX(vertex->y())); return true; } } else if (geoType == "Edge") { int index = TechDraw::DrawUtil::getIndexFromName(subNames[0]); TechDraw::BaseGeomPtr geo = static_cast(viewPart->getViewObject())->getGeomByIndex(index); if (geo) { Base::Vector3d midPoint(Rez::guiX(geo->getMidPoint())); placement = viewPart->mapToScene(midPoint.x, midPoint.y); return true; } } return false; } DEF_STD_CMD_A(CmdTechDrawBalloon) CmdTechDrawBalloon::CmdTechDrawBalloon() : Command("TechDraw_Balloon") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Balloon Annotation"); sToolTipText = QT_TR_NOOP("Inserts a new balloon annotation in the selected view"); sWhatsThis = "TechDraw_Balloon"; sStatusTip = sToolTipText; sPixmap = "TechDraw_Balloon"; } void CmdTechDrawBalloon::activated(int iMsg) { Q_UNUSED(iMsg); bool result = _checkSelectionBalloon(this, 1); if (!result) { return; } std::vector selection = getSelection().getSelectionEx(); auto objFeat(dynamic_cast(selection[0].getObject())); if (!objFeat) { return; } TechDraw::DrawPage* page = objFeat->findParentPage(); std::string PageName = page->getNameInDocument(); Gui::Document* guiDoc = Gui::Application::Instance->getDocument(page->getDocument()); ViewProviderPage* pageVP = freecad_cast(guiDoc->getViewProvider(page)); ViewProviderDrawingView* viewVP = freecad_cast(guiDoc->getViewProvider(objFeat)); if (pageVP && viewVP) { QGVPage* viewPage = pageVP->getQGVPage(); QGSPage* scenePage = pageVP->getQGSPage(); if (viewPage) { auto* view = dynamic_cast(viewVP->getQView()); QPointF placement; if (view && _checkDirectPlacement(view, selection[0].getSubNames(), placement)) { //this creates the balloon if something is already selected scenePage->createBalloon(placement, objFeat); return; } viewPage->startBalloonPlacing(objFeat); } } } bool CmdTechDrawBalloon::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this, false); bool taskInProgress = Gui::Control().activeDialog(); return (havePage && haveView && !taskInProgress); } //=========================================================================== // TechDraw_ClipGroup //=========================================================================== DEF_STD_CMD_A(CmdTechDrawClipGroup) CmdTechDrawClipGroup::CmdTechDrawClipGroup() : Command("TechDraw_ClipGroup") { // setting the sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Clip Group"); sToolTipText = QT_TR_NOOP("Inserts a new clip group for the selected view"); sWhatsThis = "TechDraw_ClipGroup"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ClipGroup"; } void CmdTechDrawClipGroup::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); std::string FeatName = getUniqueObjectName("Clip"); openCommand(QT_TRANSLATE_NOOP("Command", "Create clip")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewClip', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); } bool CmdTechDrawClipGroup::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_ClipGroupAdd //=========================================================================== DEF_STD_CMD_A(CmdTechDrawClipGroupAdd) CmdTechDrawClipGroupAdd::CmdTechDrawClipGroupAdd() : Command("TechDraw_ClipGroupAdd") { sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Add View To Clip Group"); sToolTipText = QT_TR_NOOP("Adds the selected view to a clip group"); sWhatsThis = "TechDraw_ClipGroupAdd"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ClipGroupAdd"; } void CmdTechDrawClipGroupAdd::activated(int iMsg) { Q_UNUSED(iMsg); std::vector selection = getSelection().getSelectionEx(); if (selection.size() != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select one clip group and one view")); return; } TechDraw::DrawViewClip* clip = nullptr; TechDraw::DrawView* view = nullptr; std::vector::iterator itSel = selection.begin(); for (; itSel != selection.end(); itSel++) { if ((*itSel).getObject()->isDerivedFrom()) { clip = static_cast((*itSel).getObject()); } else if ((*itSel).getObject()->isDerivedFrom()) { view = static_cast((*itSel).getObject()); } } if (!view) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly one view to add to clip group")); return; } if (!clip) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly one clip group")); return; } TechDraw::DrawPage* pageClip = clip->findParentPage(); TechDraw::DrawPage* pageView = view->findParentPage(); if (pageClip != pageView) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Clip and view must be from same page")); return; } std::string PageName = pageClip->getNameInDocument(); std::string ClipName = clip->getNameInDocument(); std::string ViewName = view->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Add clip group")); doCommand(Doc, "App.activeDocument().%s.ViewObject.Visibility = False", ViewName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", ClipName.c_str(), ViewName.c_str()); doCommand(Doc, "App.activeDocument().%s.ViewObject.Visibility = True", ViewName.c_str()); updateActive(); commitCommand(); } bool CmdTechDrawClipGroupAdd::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveClip = false; if (havePage) { auto drawClipType(TechDraw::DrawViewClip::getClassTypeId()); auto selClips = getDocument()->getObjectsOfType(drawClipType); if (!selClips.empty()) { haveClip = true; } } return (havePage && haveClip); } //=========================================================================== // TechDraw_ClipGroupRemove //=========================================================================== DEF_STD_CMD_A(CmdTechDrawClipGroupRemove) CmdTechDrawClipGroupRemove::CmdTechDrawClipGroupRemove() : Command("TechDraw_ClipGroupRemove") { sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Remove From Clip Group"); sToolTipText = QT_TR_NOOP("Removes a view based on the selected clip group"); sWhatsThis = "TechDraw_ClipGroupRemove"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ClipGroupRemove"; } void CmdTechDrawClipGroupRemove::activated(int iMsg) { Q_UNUSED(iMsg); auto dObj(getSelection().getObjectsOfType(TechDraw::DrawView::getClassTypeId())); if (dObj.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly one view to remove from clip group")); return; } auto view(static_cast(dObj.front())); TechDraw::DrawPage* page = view->findParentPage(); const std::vector pViews = page->getViews(); TechDraw::DrawViewClip* clip(nullptr); for (auto& v : pViews) { clip = dynamic_cast(v); if (clip && clip->isViewInClip(view)) { break; } clip = nullptr; } if (!clip) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("View does not belong to a clip")); return; } std::string ClipName = clip->getNameInDocument(); std::string ViewName = view->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Remove clip group")); doCommand(Doc, "App.activeDocument().%s.ViewObject.Visibility = False", ViewName.c_str()); doCommand(Doc, "App.activeDocument().%s.removeView(App.activeDocument().%s)", ClipName.c_str(), ViewName.c_str()); doCommand(Doc, "App.activeDocument().%s.ViewObject.Visibility = True", ViewName.c_str()); updateActive(); commitCommand(); } bool CmdTechDrawClipGroupRemove::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveClip = false; if (havePage) { auto drawClipType(TechDraw::DrawViewClip::getClassTypeId()); auto selClips = getDocument()->getObjectsOfType(drawClipType); if (!selClips.empty()) { haveClip = true; } } return (havePage && haveClip); } //=========================================================================== // TechDraw_Symbol //=========================================================================== DEF_STD_CMD_A(CmdTechDrawSymbol) CmdTechDrawSymbol::CmdTechDrawSymbol() : Command("TechDraw_Symbol") { // setting the Gui eye-candy sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Insert SVG"); sToolTipText = QT_TR_NOOP("Inserts a symbol from an SVG file"); sWhatsThis = "TechDraw_Symbol"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_Symbol"; } void CmdTechDrawSymbol::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); // Reading an image QString filename = Gui::FileDialog::getOpenFileName( Gui::getMainWindow(), QObject::tr("Choose an SVG file to open"), Preferences::defaultSymbolDir(), QStringLiteral("%1 (*.svg *.svgz);;%2 (*.*)") .arg(QObject::tr("Scalable vector graphic"), QObject::tr("All files"))); if (!filename.isEmpty()) { std::string FeatName = getUniqueObjectName("Symbol"); filename = Base::Tools::escapeEncodeFilename(filename); auto filespec = DU::cleanFilespecBackslash(filename.toStdString()); openCommand(QT_TRANSLATE_NOOP("Command", "Create Symbol")); doCommand(Doc, "import codecs"); doCommand(Doc, "f = codecs.open(\"%s\", 'r', encoding=\"utf-8\")", filespec.c_str()); doCommand(Doc, "svg = f.read()"); doCommand(Doc, "f.close()"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewSymbol', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewSymbol', 'Symbol', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Symbol = svg", FeatName.c_str()); auto baseView = CommandHelpers::firstViewInSelection(this); if (baseView) { auto baseName = baseView->getNameInDocument(); doCommand(Doc, "App.activeDocument().%s.Owner = App.activeDocument().%s", FeatName.c_str(), baseName); } doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); } } bool CmdTechDrawSymbol::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_DraftView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawDraftView) CmdTechDrawDraftView::CmdTechDrawDraftView() : Command("TechDraw_DraftView") { // setting the Gui eye-candy sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Draft View"); //: "Draft" is a workbench and should not be translated sToolTipText = QT_TR_NOOP("Inserts a view of a Draft object"); sWhatsThis = "TechDraw_NewDraft"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_DraftView"; } void CmdTechDrawDraftView::activated(int iMsg) { Q_UNUSED(iMsg); std::vector objects = getSelection().getObjectsOfType(App::DocumentObject::getClassTypeId()); if (objects.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least one object")); return; } TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); std::pair dirs = DrawGuiUtil::get3DDirAndRot(); for (auto* obj : objects) { if (obj->isDerivedFrom() || obj->isDerivedFrom()) { // skip over TechDraw objects as they are not valid subjects for a DraftView continue; } std::string FeatName = getUniqueObjectName("DraftView"); std::string SourceName = obj->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Create DraftView")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewDraft', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewDraft', 'DraftView', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Source = App.activeDocument().%s", FeatName.c_str(), SourceName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Direction = FreeCAD.Vector(%.12f, %.12f, %.12f)", FeatName.c_str(), dirs.first.x, dirs.first.y, dirs.first.z); updateActive(); commitCommand(); } } bool CmdTechDrawDraftView::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_ArchView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawArchView) CmdTechDrawArchView::CmdTechDrawArchView() : Command("TechDraw_ArchView") { // setting the Gui eye-candy sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("BIM View"); sToolTipText = QT_TR_NOOP("Inserts a view of a BIM section plane"); sWhatsThis = "TechDraw_NewArch"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ArchView"; } void CmdTechDrawArchView::activated(int iMsg) { Q_UNUSED(iMsg); const std::vector objects = getSelection().getObjectsOfType(App::DocumentObject::getClassTypeId()); App::DocumentObject* archObject = nullptr; int archCount = 0; for (auto& obj : objects) { if (obj->isDerivedFrom() || obj->isDerivedFrom()) { // skip over TechDraw objects as they are not valid subjects for a ArchView continue; } if (DrawGuiUtil::isArchSection(obj)) { archCount++; archObject = obj; } } if (archCount > 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select only 1 BIM section plane")); return; } if (!archObject) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No BIM section plane in selection")); return; } TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); std::string FeatName = getUniqueObjectName("BIM view"); std::string SourceName = archObject->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Create BIM view")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewArch', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewArch', 'BIM view', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Source = App.activeDocument().%s", FeatName.c_str(), SourceName.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); doCommand(Doc, "if App.activeDocument().%s.Scale: App.activeDocument().%s.Scale = App.activeDocument().%s.Scale", PageName.c_str(), FeatName.c_str(), PageName.c_str()); updateActive(); commitCommand(); } bool CmdTechDrawArchView::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_SpreadsheetView //=========================================================================== DEF_STD_CMD_A(CmdTechDrawSpreadsheetView) CmdTechDrawSpreadsheetView::CmdTechDrawSpreadsheetView() : Command("TechDraw_SpreadsheetView") { // setting the sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Spreadsheet View"); sToolTipText = QT_TR_NOOP("Inserts a view of a spreadsheet in the current page"); sWhatsThis = "TechDraw_SpreadsheetView"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_SpreadsheetView"; } void CmdTechDrawSpreadsheetView::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); const std::vector spreads = getSelection().getObjectsOfType(Spreadsheet::Sheet::getClassTypeId()); if (spreads.size() != 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select exactly one spreadsheet object")); return; } std::string SpreadName = spreads.front()->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Create spreadsheet view")); std::string FeatName = getUniqueObjectName("Sheet"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewSpreadsheet', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewSpreadsheet', 'Sheet', '%s')", FeatName.c_str(), FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.Source = App.activeDocument().%s", FeatName.c_str(), SpreadName.c_str()); // look for an owner view in the selection auto baseView = CommandHelpers::firstViewInSelection(this); if (baseView) { auto baseName = baseView->getNameInDocument(); doCommand(Doc, "App.activeDocument().%s.Owner = App.activeDocument().%s", FeatName.c_str(), baseName); } doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); } bool CmdTechDrawSpreadsheetView::isActive() { //need a Page and a SpreadSheet::Sheet bool havePage = DrawGuiUtil::needPage(this); bool haveSheet = false; if (havePage) { auto spreadSheetType(Spreadsheet::Sheet::getClassTypeId()); auto selSheets = getDocument()->getObjectsOfType(spreadSheetType); if (!selSheets.empty()) { haveSheet = true; } } return (havePage && haveSheet); } //=========================================================================== // TechDraw_ExportPageSVG //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExportPageSVG) CmdTechDrawExportPageSVG::CmdTechDrawExportPageSVG() : Command("TechDraw_ExportPageSVG") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Export Page as SVG"); sToolTipText = QT_TR_NOOP("Exports the current page as an SVG"); sWhatsThis = "TechDraw_ExportPageSVG"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ExportPageSVG"; } void CmdTechDrawExportPageSVG::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::string PageName = page->getNameInDocument(); Gui::Document* activeGui = Gui::Application::Instance->getDocument(page->getDocument()); Gui::ViewProvider* vp = activeGui->getViewProvider(page); ViewProviderPage* vpPage = freecad_cast(vp); if (vpPage) { vpPage->show(); // make sure a mdi will be available vpPage->getMDIViewPage()->saveSVG(); } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No drawing page"), QObject::tr("FreeCAD could not find a page to export")); return; } } bool CmdTechDrawExportPageSVG::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_ExportPageDXF //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExportPageDXF) CmdTechDrawExportPageDXF::CmdTechDrawExportPageDXF() : Command("TechDraw_ExportPageDXF") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Export Page as DXF"); sToolTipText = QT_TR_NOOP("Exports the current page as a DXF"); sWhatsThis = "TechDraw_ExportPageDXF"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ExportPageDXF"; } void CmdTechDrawExportPageDXF::activated(int iMsg) { Q_UNUSED(iMsg); TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); if (!page) { return; } std::vector views = page->getViews(); for (auto& v : views) { if (v->isDerivedFrom()) { QMessageBox::StandardButton rc = QMessageBox::question( Gui::getMainWindow(), QObject::tr("Cannot export selection"), QObject::tr("Page contains a BIM view which will not be exported. Continue?"), QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No)); if (rc == QMessageBox::No) { return; } else { break; } } } //WF? allow more than one TD Page per Dxf file?? 1 TD page = 1 DXF file = 1 drawing? QString defaultDir; QString fileName = Gui::FileDialog::getSaveFileName( Gui::getMainWindow(), QString::fromUtf8(QT_TR_NOOP("Save DXF file")), defaultDir, QStringLiteral("DXF (*.dxf)")); if (fileName.isEmpty()) { return; } std::string PageName = page->getNameInDocument(); openCommand(QT_TRANSLATE_NOOP("Command", "Save page to DXF")); doCommand(Doc, "import TechDraw"); fileName = Base::Tools::escapeEncodeFilename(fileName); auto filespec = DU::cleanFilespecBackslash(fileName.toStdString()); doCommand(Doc, "TechDraw.writeDXFPage(App.activeDocument().%s, u\"%s\")", PageName.c_str(), filespec.c_str()); commitCommand(); } bool CmdTechDrawExportPageDXF::isActive() { return DrawGuiUtil::needPage(this); } //=========================================================================== // TechDraw_ProjectShape //=========================================================================== DEF_STD_CMD_A(CmdTechDrawProjectShape) CmdTechDrawProjectShape::CmdTechDrawProjectShape() : Command("TechDraw_ProjectShape") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Project Shape"); sToolTipText = QT_TR_NOOP("Creates a projected geometry of the selected object in the 3D view from the current camera angle"); sWhatsThis = "TechDraw_ProjectShape"; sStatusTip = sToolTipText; sPixmap = "actions/TechDraw_ProjectShape"; } void CmdTechDrawProjectShape::activated(int iMsg) { Q_UNUSED(iMsg); Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); if (!dlg) { Gui::Control().showDialog(new TaskDlgProjection()); } } bool CmdTechDrawProjectShape::isActive() { return true; } void CreateTechDrawCommands() { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdTechDrawPageDefault()); rcCmdMgr.addCommand(new CmdTechDrawPageTemplate()); rcCmdMgr.addCommand(new CmdTechDrawRedrawPage()); rcCmdMgr.addCommand(new CmdTechDrawPrintAll()); rcCmdMgr.addCommand(new CmdTechDrawView()); rcCmdMgr.addCommand(new CmdTechDrawActiveView()); rcCmdMgr.addCommand(new CmdTechDrawSectionGroup()); rcCmdMgr.addCommand(new CmdTechDrawSectionView()); rcCmdMgr.addCommand(new CmdTechDrawComplexSection()); rcCmdMgr.addCommand(new CmdTechDrawDetailView()); rcCmdMgr.addCommand(new CmdTechDrawProjectionGroup()); rcCmdMgr.addCommand(new CmdTechDrawClipGroup()); rcCmdMgr.addCommand(new CmdTechDrawClipGroupAdd()); rcCmdMgr.addCommand(new CmdTechDrawClipGroupRemove()); rcCmdMgr.addCommand(new CmdTechDrawSymbol()); rcCmdMgr.addCommand(new CmdTechDrawExportPageSVG()); rcCmdMgr.addCommand(new CmdTechDrawExportPageDXF()); rcCmdMgr.addCommand(new CmdTechDrawDraftView()); rcCmdMgr.addCommand(new CmdTechDrawArchView()); rcCmdMgr.addCommand(new CmdTechDrawSpreadsheetView()); rcCmdMgr.addCommand(new CmdTechDrawBalloon()); rcCmdMgr.addCommand(new CmdTechDrawProjectShape()); rcCmdMgr.addCommand(new CmdTechDrawBrokenView()); } //**************************************** //! extract the selected shapes and xShapes and determine if a face has been //! selected to define the projection direction void getSelectedShapes(Gui::Command* cmd, std::vector& shapes, std::vector& xShapes, App::DocumentObject* faceObj, std::string& faceName) { Gui::ResolveMode resolve = Gui::ResolveMode::OldStyleElement; bool single = false; auto selection = cmd->getSelection().getSelectionEx(nullptr, App::DocumentObject::getClassTypeId(), resolve, single); for (auto& sel : selection) { bool is_linked = false; auto obj = sel.getObject(); if (obj->isDerivedFrom()) { continue; } if (obj->isDerivedFrom() || obj->isDerivedFrom() || obj->isDerivedFrom()) { is_linked = true; } // If parent of the obj is a link to another document, we possibly need to treat non-link obj as linked, too // 1st, is obj in another document? if (obj->getDocument() != cmd->getDocument()) { std::set parents = obj->getInListEx(true); for (auto& parent : parents) { // Only consider parents in the current document, i.e. possible links in this View's document if (parent->getDocument() != cmd->getDocument()) { continue; } // 2nd, do we really have a link to obj? if (parent->isDerivedFrom() || parent->isDerivedFrom() || parent->isDerivedFrom()) { // We have a link chain from this document to obj, and obj is in another document -> it is an XLink target is_linked = true; } } } if (is_linked) { xShapes.push_back(obj); continue; } //not a Link and not null. assume to be drawable. Undrawables will be // skipped later. shapes.push_back(obj); if (faceObj) { continue; } //don't know if this works for an XLink for (auto& sub : sel.getSubNames()) { if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { faceName = sub; // faceObj = obj; break; } } } } std::pair viewDirection() { if (!Preferences::useCameraDirection()) { return { Base::Vector3d(0, -1, 0), Base::Vector3d(1, 0, 0) }; } auto faceInfo = faceFromSelection(); if (faceInfo.first) { return DrawGuiUtil::getProjDirFromFace(faceInfo.first, faceInfo.second); } return DrawGuiUtil::get3DDirAndRot(); } std::pair faceFromSelection() { auto selection = Gui::Selection().getSelectionEx( nullptr, App::DocumentObject::getClassTypeId(), Gui::ResolveMode::NoResolve); if (selection.empty()) { return { nullptr, "" }; } for (auto& sel : selection) { for (auto& sub : sel.getSubNames()) { if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { return { sel.getObject(), sub }; } } } return { nullptr, "" }; }