FreeCAD/src/Mod/PartDesign/Gui/Workbench.cpp

820 lines
36 KiB
C++

/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]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 *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <qobject.h>
# include <boost/bind.hpp>
# include <Precision.hxx>
# include <QMessageBox>
# include <gp_Pnt.hxx>
# include <gp_Dir.hxx>
# include <gp_Pln.hxx>
#endif
#include "Workbench.h"
#include <App/Plane.h>
#include <App/Part.h>
#include <App/Placement.h>
#include <App/Application.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/MenuManager.h>
#include <Gui/ToolBarManager.h>
#include <Gui/Control.h>
#include <Gui/DlgCheckableMessageBox.h>
#include <Gui/ViewProviderPart.h>
#include <Gui/ActiveObjectList.h>
#include <Mod/Sketcher/Gui/Workbench.h>
#include <Mod/Part/App/Part2DObject.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/Feature.h>
#include <Mod/PartDesign/App/FeatureSketchBased.h>
#include <Mod/PartDesign/App/FeatureMultiTransform.h>
#include <Mod/Part/App/DatumFeature.h>
#include <Mod/Sketcher/App/SketchObject.h>
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<PartDesign::Body*>(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<App::DocumentObject*> 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(
"<h2>Converting PartDesign features to new Body centric schema</h2>"
"If you are unsure what that mean save the document under a new name.<br>"
"You will not be able to load your work in an older Version of FreeCAD,<br>"
"After the translation took place...<br><br>"
"More information you will find here:<br>"
" <a href=\"http://www.freecadweb.org/wiki/index.php?title=Assembly_project\">http://www.freecadweb.org/wiki/index.php?title=Assembly_project</a> <br>"
"Or the Assembly dedicated portion of our forum:<br>"
" <a href=\"http://forum.freecadweb.org/viewforum.php?f=20&sid=2a1a326251c44576f450739e4a74c37d\">http://forum.freecadweb.org/</a> <br>"
),
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<App::DocumentObject*> features = doc->getObjects();
// Assign all non-PartDesign features to a new group
for (std::vector<App::DocumentObject*>::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<App::DocumentObject*> roots;
for (std::vector<App::DocumentObject*>::iterator f = features.begin(); f != features.end(); f++) {
// Note: The dependency list always contains at least the object itself
std::vector<App::DocumentObject*> 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<PartDesign::Body*>(PDBODYKEY);
assert(activeBody);
// Create one Body for every root and put the appropriate features into it
for (std::vector<App::DocumentObject*>::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<PartDesign::Body*>(PDBODYKEY);
}
std::set<App::DocumentObject*> inList;
inList.insert(*r); // start with the root feature
std::vector<App::DocumentObject*> bodyFeatures;
std::string modelString = "";
do {
for (std::set<App::DocumentObject*>::const_iterator o = inList.begin(); o != inList.end(); o++) {
std::vector<App::DocumentObject*>::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<App::DocumentObject*> newInList;
for (std::set<App::DocumentObject*>::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<App::DocumentObject*> 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<App::DocumentObject*>::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<App::DocumentObject*>::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<App::DocumentObject*>::const_iterator prevf;
for (std::vector<App::DocumentObject*>::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) {
if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) {
Sketcher::SketchObject* sketch = static_cast<Sketcher::SketchObject*>(*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<App::DocumentObject*> 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<PartDesign::Body*>(PDBODYKEY);
assert(activeBody);
} else {
// empty document with no tip, so do migration
_doMigration(doc);
activeBody = Gui::Application::Instance->activeView()->getActiveObject<PartDesign::Body*>(PDBODYKEY);
assert(activeBody);
}
}
else
{
activeBody = Gui::Application::Instance->activeView()->getActiveObject<PartDesign::Body*>(PDBODYKEY);
assert(activeBody);
activePart = Gui::Application::Instance->activeView()->getActiveObject<App::Part*>("Part");
assert(activePart);
// document change not implemented yet
assert(activePart->getDocument() == doc);
//// Find active body
//for (std::vector<App::DocumentObject*>::const_iterator b = bodies.begin(); b != bodies.end(); b++) {
// PartDesign::Body* body = static_cast<PartDesign::Body*>(*b);
// if (body->IsActive.getValue()) {
// activeBody = body;
// break;
// }
//}
//// Do the base planes exist in this document?
//bool found = false;
//std::vector<App::DocumentObject*> planes = doc->getObjectsOfType(App::Plane::getClassTypeId());
//for (std::vector<App::DocumentObject*>::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<PartDesign::Body*>(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<Gui::TaskView::TaskWatcher*> 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;
}