/*************************************************************************** * Copyright (c) 2008 Werner Mayer * * * * 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 * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include #endif #include "Workbench.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace PartDesignGui; #if 0 // needed for Qt's lupdate utility qApp->translate("Workbench", "Part Design"); qApp->translate("Gui::TaskView::TaskWatcherCommands", "Face tools"); qApp->translate("Gui::TaskView::TaskWatcherCommands", "Sketch tools"); qApp->translate("Gui::TaskView::TaskWatcherCommands", "Create Geometry"); #endif namespace PartDesignGui { //=========================================================================== // Helper for Body //=========================================================================== PartDesign::Body *getBody(void) { PartDesign::Body * activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); if (!activeBody){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), QObject::tr("In order to use PartDesign you need an active Body object in the document. " "Please make one active (double click) or create one. If you have a legacy document " "with PartDesign objects without Body, use the transfer function in " "PartDesign to put them into a Body." )); } return activeBody; } } /// @namespace PartDesignGui @class Workbench TYPESYSTEM_SOURCE(PartDesignGui::Workbench, Gui::StdWorkbench) Workbench::Workbench() { } Workbench::~Workbench() { } static void buildDefaultPartAndBody(const App::Document* doc) { // This adds both the base planes and the body std::string PartName = doc->getUniqueObjectName("Part"); //// create a PartDesign Part for now, can be later any kind of Part or an empty one Gui::Command::addModule(Gui::Command::Doc, "PartDesignGui"); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().Tip = App.activeDocument().addObject('App::Part','%s')", PartName.c_str()); Gui::Command::doCommand(Gui::Command::Doc, "PartDesignGui.setUpPart(App.activeDocument().%s)", PartName.c_str()); Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('Part',App.activeDocument().%s)", PartName.c_str()); } PartDesign::Body *Workbench::setUpPart(const App::Part *part) { // first do the general Part setup Gui::ViewProviderPart::setUpPart(part); // check for Bodies std::vector bodies = part->getObjectsOfType(PartDesign::Body::getClassTypeId()); assert(bodies.size() == 0); std::string PartName = part->getNameInDocument(); std::string BodyName = part->getDocument()->getUniqueObjectName("MainBody"); Gui::Command::addModule(Gui::Command::Doc, "PartDesign"); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject('PartDesign::Body','%s')", BodyName.c_str()); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.addObject(App.activeDocument().ActiveObject)", part->getNameInDocument()); Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, BodyName.c_str()); Gui::Command::updateActive(); return NULL; } void Workbench::_doMigration(const App::Document* doc) { bool groupCreated = false; if(doc->countObjects() != 0) { // show a warning about the convertion Gui::Dialog::DlgCheckableMessageBox::showMessage( QString::fromLatin1("PartDesign conversion warning"), QString::fromLatin1( "

Converting PartDesign features to new Body centric schema

" "If you are unsure what that mean save the document under a new name.
" "You will not be able to load your work in an older Version of FreeCAD,
" "After the translation took place...

" "More information you will find here:
" " http://www.freecadweb.org/wiki/index.php?title=Assembly_project
" "Or the Assembly dedicated portion of our forum:
" " http://forum.freecadweb.org/
" ), false, QString::fromLatin1("Don't tell me again, I know!") ); } Gui::Command::openCommand("Migrate part to Body feature"); // Get the objects now, before adding the Body and the base planes std::vector features = doc->getObjects(); // Assign all non-PartDesign features to a new group for (std::vector::iterator f = features.begin(); f != features.end(); ) { if ((*f)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || (*f)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { ++f; } else { if (!groupCreated) { Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','NonBodyFeatures')"); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("NonBodyFeatures").toStdString().c_str()); groupCreated = true; } Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().NonBodyFeatures.addObject(App.activeDocument().getObject('%s'))", (*f)->getNameInDocument()); f = features.erase(f); } } // TODO: Fold the group (is that possible through the Python interface?) // Try to find the root(s) of the model tree (the features that depend on no other feature) // Note: We assume a linear graph, except for MultiTransform features std::vector roots; for (std::vector::iterator f = features.begin(); f != features.end(); f++) { // Note: The dependency list always contains at least the object itself std::vector ftemp; ftemp.push_back(*f); if (doc->getDependencyList(ftemp).size() == 1) roots.push_back(*f); } // Always create at least the first body, even if the document is empty buildDefaultPartAndBody(doc); PartDesign::Body *activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); assert(activeBody); // Create one Body for every root and put the appropriate features into it for (std::vector::iterator r = roots.begin(); r != roots.end(); r++) { if (r != roots.begin()) { Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); } std::set inList; inList.insert(*r); // start with the root feature std::vector bodyFeatures; std::string modelString = ""; do { for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) { std::vector::iterator feat = std::find(features.begin(), features.end(), *o); if (feat != features.end()) { bodyFeatures.push_back(*o); modelString += std::string(modelString.empty() ? "" : ",") + "App.ActiveDocument." + (*o)->getNameInDocument(); features.erase(feat); } else { QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Non-linear tree"), QObject::tr("Please look at '") + QString::fromAscii((*o)->getNameInDocument()) + QObject::tr("' and make sure that the migration result is what you would expect.")); } } std::set newInList; for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) { // Omit members of a MultiTransform from the inList, to avoid migration errors if (PartDesign::Body::isMemberOfMultiTransform(*o)) continue; std::vector iL = doc->getInList(*o); newInList.insert(iL.begin(), iL.end()); } inList = newInList; // TODO: Memory leak? Unnecessary copying? } while (!inList.empty()); if (!modelString.empty()) { modelString = std::string("[") + modelString + "]"; Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Model = %s", activeBody->getNameInDocument(), modelString.c_str()); // Set the Tip, but not to a member of a MultiTransform! for (std::vector::const_reverse_iterator f = bodyFeatures.rbegin(); f != bodyFeatures.rend(); f++) { if (PartDesign::Body::isMemberOfMultiTransform(*f)) continue; Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", activeBody->getNameInDocument(), (*f)->getNameInDocument()); break; } } // Initialize the BaseFeature property of all PartDesign solid features App::DocumentObject* baseFeature = NULL; for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) { if (PartDesign::Body::isSolidFeature(*f)) { Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = %s", (*f)->getNameInDocument(), baseFeature == NULL ? "None" : (std::string("App.activeDocument().") + baseFeature->getNameInDocument()).c_str()); baseFeature = *f; } } // Re-route all sketches without support to the base planes std::vector::const_iterator prevf; for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) { if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { Sketcher::SketchObject* sketch = static_cast(*f); App::DocumentObject* support = sketch->Support.getValue(); if (support != NULL) continue; // Sketch is on a face of a solid Base::Placement plm = sketch->Placement.getValue(); Base::Vector3d pnt = plm.getPosition(); // Currently we only handle positions that are parallel to the base planes Base::Rotation rot = plm.getRotation(); Base::Vector3d SketchVector(0,0,1); rot.multVec(SketchVector, SketchVector); std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front"; if (side == "back") SketchVector *= -1.0; int index; if (SketchVector == Base::Vector3d(0,0,1)) index = 0; else if (SketchVector == Base::Vector3d(0,1,0)) index = 1; else if (SketchVector == Base::Vector3d(1,0,0)) index = 2; else { QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), QObject::tr("Please edit '") + QString::fromAscii(sketch->getNameInDocument()) + QObject::tr("' and redefine it to use a Base or Datum plane as the sketch plane.")); continue; } // Find the normal distance from origin to the sketch plane gp_Pln pln(gp_Pnt (pnt.x, pnt.y, pnt.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); double offset = pln.Distance(gp_Pnt(0,0,0)); if (fabs(offset) < Precision::Confusion()) { // One of the base planes Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", sketch->getNameInDocument(), App::Part::BaseplaneTypes[index], side.c_str()); } else { // Offset to base plane // Find out which direction we need to offset double a = SketchVector.GetAngle(pnt); if ((a < -M_PI_2) || (a > M_PI_2)) offset *= -1.0; // Insert a new datum plane before the sketch App::DocumentObject* oldTip = activeBody->Tip.getValue(); Gui::Selection().clearSelection(); if (f != bodyFeatures.begin()) Gui::Selection().addSelection(doc->getName(), (*prevf)->getNameInDocument()); Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); std::string Datum = doc->getUniqueObjectName("DatumPlane"); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",Datum.c_str()); QString refStr = QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(App::Part::BaseplaneTypes[index]) + QString::fromAscii(",'')]"); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.References = %s",Datum.c_str(), refStr.toStdString().c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Offset = %f",Datum.c_str(), offset); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", activeBody->getNameInDocument(), Datum.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", sketch->getNameInDocument(), Datum.c_str(), side.c_str()); Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references Gui::Selection().clearSelection(); if (oldTip != NULL) { Gui::Selection().addSelection(doc->getName(), oldTip->getNameInDocument()); Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); Gui::Selection().clearSelection(); } } } prevf = f; } } } void Workbench::_switchToDocument(const App::Document* doc) { bool groupCreated = false; if (doc == NULL) return; PartDesign::Body* activeBody = NULL; App::Part* activePart = NULL; std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); // No tip, so build up structure or migrate if (!doc->Tip.getValue()) { if (doc->countObjects() == 0){ buildDefaultPartAndBody(doc); activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); assert(activeBody); } else { // empty document with no tip, so do migration _doMigration(doc); activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); assert(activeBody); } } else { activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); assert(activeBody); activePart = Gui::Application::Instance->activeView()->getActiveObject("Part"); assert(activePart); // document change not implemented yet assert(activePart->getDocument() == doc); //// Find active body //for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { // PartDesign::Body* body = static_cast(*b); // if (body->IsActive.getValue()) { // activeBody = body; // break; // } //} //// Do the base planes exist in this document? //bool found = false; //std::vector planes = doc->getObjectsOfType(App::Plane::getClassTypeId()); //for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { // for (unsigned i = 0; i < 3; i++) { // if (strcmp(PartDesignGui::BaseplaneNames[i], (*p)->getNameInDocument()) == 0) { // found = true; // break; // } // } // if (found) break; //} //if (!found) { // // Add the planes ... // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[0]); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XY-Plane").toStdString().c_str()); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[1]); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); // // ... and put them in the 'Origin' group // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", QObject::tr("Origin").toStdString().c_str()); // for (unsigned i = 0; i < 3; i++) // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", PartDesignGui::BaseplaneNames[i]); // // TODO: Fold the group (is that possible through the Python interface?) //} } //// If there is only one body, make it active //if ((activeBody == NULL) && (bodies.size() == 1)) // activeBody = static_cast(bodies.front()); //// add the non PartDesign feature group to the Part //if( groupCreated && doc->Tip.getValue() != NULL) // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Tip.addObject(App.activeDocument().NonBodyFeatures)"); if (activeBody == NULL) { QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Could not create body"), QObject::tr("No body was found in this document, and none could be created. Please report this bug." "We recommend you do not use this document with the PartDesign workbench until the bug has been fixed." )); } std::string bodyName = activeBody->getNameInDocument(); } void Workbench::slotActiveDocument(const Gui::Document& Doc) { _switchToDocument(Doc.getDocument()); } void Workbench::slotNewDocument(const App::Document& Doc) { _switchToDocument(&Doc); } void Workbench::slotFinishRestoreDocument(const App::Document& Doc) { _switchToDocument(&Doc); } void Workbench::slotDeleteDocument(const App::Document&) { //ActivePartObject = 0; //ActiveGuiDoc = 0; //ActiveAppDoc = 0; //ActiveVp = 0; } /* This does not work for Std_DuplicateSelection: Tree.cpp gives: "Cannot reparent unknown object", probably because the signalNewObject is emitted before the duplication of the object has been completely finished void Workbench::slotNewObject(const App::DocumentObject& obj) { if ((obj.getDocument() == ActiveAppDoc) && (ActivePartObject != NULL)) { // Add the new object to the active Body // Note: Will this break Undo? But how else can we catch Edit->Duplicate selection? Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", ActivePartObject->getNameInDocument(), obj.getNameInDocument()); } } */ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const { if (strcmp(recipient,"Tree") == 0) { if (Gui::Selection().countObjectsOfType(PartDesign::Body::getClassTypeId()) + Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveTip"; if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveFeature" << "PartDesign_MoveFeatureInTree"; if (Gui::Selection().countObjectsOfType(PartDesign::Transformed::getClassTypeId()) - Gui::Selection().countObjectsOfType(PartDesign::MultiTransform::getClassTypeId()) == 1 ) *item << "PartDesign_MultiTransform"; } } void Workbench::activated() { Gui::Workbench::activated(); std::vector Watcher; const char* Vertex[] = { "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Vertex COUNT 1..", Vertex, "Vertex tools", "Part_Box" )); const char* Edge[] = { "PartDesign_Fillet", "PartDesign_Chamfer", "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Edge COUNT 1..", Edge, "Edge tools", "Part_Box" )); const char* Face[] = { "PartDesign_NewSketch", "PartDesign_Fillet", "PartDesign_Chamfer", "PartDesign_Draft", "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 1", Face, "Face tools", "Part_Box" )); const char* Body[] = { "PartDesign_NewSketch", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::Body COUNT 1", Body, "Start Body", "Part_Box" )); const char* Body2[] = { "PartDesign_Boolean", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::Body COUNT 1..", Body2, "Start Boolean", "Part_Box" )); const char* Plane1[] = { "PartDesign_NewSketch", "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT App::Plane COUNT 1", Plane1, "Start Part", "Part_Box" )); const char* Plane2[] = { "PartDesign_NewSketch", "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::Plane COUNT 1", Plane2, "Start Part", "Part_Box" )); const char* Line[] = { "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::Line COUNT 1", Line, "Start Part", "Part_Box" )); const char* Point[] = { "PartDesign_Plane", "PartDesign_Line", "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::Point COUNT 1", Point, "Start Part", "Part_Box" )); const char* NoSel[] = { "PartDesign_Body", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommandsEmptySelection( NoSel, "Start Part", "Part_Box" )); const char* Faces[] = { "PartDesign_Fillet", "PartDesign_Chamfer", "PartDesign_Draft", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 2..", Faces, "Face tools", "Part_Box" )); const char* Sketch[] = { "PartDesign_NewSketch", "PartDesign_Pad", "PartDesign_Pocket", "PartDesign_Revolution", "PartDesign_Groove", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Sketcher::SketchObject COUNT 1", Sketch, "Sketch tools", "Part_Box" )); const char* Transformed[] = { "PartDesign_Mirrored", "PartDesign_LinearPattern", "PartDesign_PolarPattern", // "PartDesign_Scaled", "PartDesign_MultiTransform", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::SketchBased", Transformed, "Transformation tools", "PartDesign_MultiTransform" )); // make the previously used active Body active again //PartDesignGui::ActivePartObject = NULL; _switchToDocument(App::GetApplication().getActiveDocument()); addTaskWatcher(Watcher); Gui::Control().showTaskView(); // Let us be notified when a document is activated, so that we can update the ActivePartObject Gui::Application::Instance->signalActiveDocument.connect(boost::bind(&Workbench::slotActiveDocument, this, _1)); App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, _1)); App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); App::GetApplication().signalDeleteDocument.connect(boost::bind(&Workbench::slotDeleteDocument, this, _1)); // Watch out for objects being added to the active document, so that we can add them to the body //App::GetApplication().signalNewObject.connect(boost::bind(&Workbench::slotNewObject, this, _1)); } void Workbench::deactivated() { // Let us be notified when a document is activated, so that we can update the ActivePartObject Gui::Application::Instance->signalActiveDocument.disconnect(boost::bind(&Workbench::slotActiveDocument, this, _1)); App::GetApplication().signalNewDocument.disconnect(boost::bind(&Workbench::slotNewDocument, this, _1)); App::GetApplication().signalFinishRestoreDocument.disconnect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); App::GetApplication().signalDeleteDocument.disconnect(boost::bind(&Workbench::slotDeleteDocument, this, _1)); //App::GetApplication().signalNewObject.disconnect(boost::bind(&Workbench::slotNewObject, this, _1)); removeTaskWatcher(); // reset the active Body Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Workbench::deactivated(); } Gui::MenuItem* Workbench::setupMenuBar() const { Gui::MenuItem* root = StdWorkbench::setupMenuBar(); Gui::MenuItem* item = root->findItem("&Windows"); Gui::MenuItem* geom = new Gui::MenuItem(); geom->setCommand("Sketcher geometries"); SketcherGui::addSketcherWorkbenchGeometries( *geom ); Gui::MenuItem* cons = new Gui::MenuItem(); cons->setCommand("Sketcher constraints"); SketcherGui::addSketcherWorkbenchConstraints( *cons ); Gui::MenuItem* consaccel = new Gui::MenuItem(); consaccel->setCommand("Sketcher tools"); SketcherGui::addSketcherWorkbenchTools(*consaccel); Gui::MenuItem* part = new Gui::MenuItem; root->insertItem(item, part); part->setCommand("&Part Design"); SketcherGui::addSketcherWorkbenchSketchActions( *part ); *part << "PartDesign_Body" << "PartDesign_NewSketch" << "Sketcher_LeaveSketch" << "Sketcher_ViewSketch" << "Sketcher_MapSketch" << "Sketcher_ReorientSketch" << geom << cons << consaccel << "Separator" << "PartDesign_Plane" << "PartDesign_Line" << "PartDesign_Point" << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" << "PartDesign_Groove" << "PartDesign_Fillet" << "PartDesign_Chamfer" << "PartDesign_Draft" << "PartDesign_Mirrored" << "PartDesign_LinearPattern" << "PartDesign_PolarPattern" // << "PartDesign_Scaled" << "PartDesign_MultiTransform" << "Separator" << "PartDesign_Boolean" << "Separator" << "PartDesign_Hole"; // For 0.13 a couple of python packages like numpy, matplotlib and others // are not deployed with the installer on Windows. Thus, the WizardShaft is // not deployed either hence the check for the existence of the command. if (Gui::Application::Instance->commandManager().getCommandByName("PartDesign_InvoluteGear")) { *part << "PartDesign_InvoluteGear"; } if (Gui::Application::Instance->commandManager().getCommandByName("PartDesign_WizardShaft")) { *part << "Separator" << "PartDesign_WizardShaft"; } // Replace the "Duplicate selection" menu item with a replacement that is compatible with Body item = root->findItem("&Edit"); Gui::MenuItem* dup = item->findItem("Std_DuplicateSelection"); dup->setCommand("PartDesign_DuplicateSelection"); return root; } Gui::ToolBarItem* Workbench::setupToolBars() const { Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand("Part Design"); // SketcherGui::addSketcherWorkbenchSketchActions( *part ); *part << "PartDesign_Body" << "PartDesign_NewSketch" << "Sketcher_ViewSketch" << "Sketcher_MapSketch" << "Sketcher_LeaveSketch" << "Separator" << "PartDesign_Plane" << "PartDesign_Line" << "PartDesign_Point" << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" << "PartDesign_Groove" << "PartDesign_Fillet" << "PartDesign_Chamfer" << "PartDesign_Draft" << "PartDesign_Mirrored" << "PartDesign_LinearPattern" << "PartDesign_PolarPattern" // << "PartDesign_Scaled" << "PartDesign_MultiTransform" << "Separator" << "PartDesign_Boolean"; Gui::ToolBarItem* geom = new Gui::ToolBarItem(root); geom->setCommand("Sketcher geometries"); SketcherGui::addSketcherWorkbenchGeometries( *geom ); Gui::ToolBarItem* cons = new Gui::ToolBarItem(root); cons->setCommand("Sketcher constraints"); SketcherGui::addSketcherWorkbenchConstraints( *cons ); Gui::ToolBarItem* consaccel = new Gui::ToolBarItem(root); consaccel->setCommand("Sketcher tools"); SketcherGui::addSketcherWorkbenchTools( *consaccel ); return root; } Gui::ToolBarItem* Workbench::setupCommandBars() const { // Part tools Gui::ToolBarItem* root = new Gui::ToolBarItem; return root; }