00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <BRep_Tool.hxx>
00027 # include <TopoDS.hxx>
00028 # include <TopoDS_Edge.hxx>
00029 # include <TopoDS_Shape.hxx>
00030 # include <TopExp.hxx>
00031 # include <TopTools_ListOfShape.hxx>
00032 # include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
00033 # include <TopTools_IndexedMapOfShape.hxx>
00034 # include <QItemDelegate>
00035 # include <QLocale>
00036 # include <QHeaderView>
00037 # include <QMessageBox>
00038 # include <QVBoxLayout>
00039 # include <QItemSelection>
00040 # include <QItemSelectionModel>
00041 # include <boost/signal.hpp>
00042 # include <boost/bind.hpp>
00043 #endif
00044
00045 #include "TaskChamfer.h"
00046 #include "ui_TaskChamfer.h"
00047
00048 #include <Mod/Part/App/PartFeature.h>
00049 #include <App/Application.h>
00050 #include <App/Document.h>
00051 #include <App/DocumentObject.h>
00052 #include <Gui/Application.h>
00053 #include <Gui/BitmapFactory.h>
00054 #include <Gui/Command.h>
00055 #include <Gui/WaitCursor.h>
00056 #include <Gui/Selection.h>
00057 #include <Gui/SelectionFilter.h>
00058
00059 using namespace PartDesignGui;
00060
00061
00062
00063 ChamferDistanceDelegate::ChamferDistanceDelegate(QObject *parent) : QItemDelegate(parent)
00064 {
00065 }
00066
00067 QWidget *ChamferDistanceDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &,
00068 const QModelIndex & index) const
00069 {
00070 if (index.column() < 1)
00071 return 0;
00072
00073 QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
00074 editor->setMinimum(0.0);
00075 editor->setMaximum(100.0);
00076 editor->setSingleStep(0.1);
00077
00078 return editor;
00079 }
00080
00081 void ChamferDistanceDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
00082 {
00083 double value = index.model()->data(index, Qt::EditRole).toDouble();
00084
00085 QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
00086 spinBox->setValue(value);
00087 }
00088
00089 void ChamferDistanceDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
00090 const QModelIndex &index) const
00091 {
00092 QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
00093 spinBox->interpretText();
00094
00095
00096 QString value = QLocale::system().toString(spinBox->value(),'f',2);
00097
00098 model->setData(index, value, Qt::EditRole);
00099 }
00100
00101 void ChamferDistanceDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
00102 const QModelIndex &) const
00103 {
00104 editor->setGeometry(option.rect);
00105 }
00106
00107
00108
00109 ChamferDistanceModel::ChamferDistanceModel(QObject * parent) : QStandardItemModel(parent)
00110 {
00111 }
00112
00113 Qt::ItemFlags ChamferDistanceModel::flags (const QModelIndex & index) const
00114 {
00115 Qt::ItemFlags fl = QStandardItemModel::flags(index);
00116 if (index.column() == 0)
00117 fl = fl | Qt::ItemIsUserCheckable;
00118 return fl;
00119 }
00120
00121 bool ChamferDistanceModel::setData (const QModelIndex & index, const QVariant & value, int role)
00122 {
00123 bool ok = QStandardItemModel::setData(index, value, role);
00124 if (role == Qt::CheckStateRole) {
00125 toggleCheckState(index);
00126 }
00127 return ok;
00128 }
00129
00130
00131
00132 namespace PartDesignGui {
00133 class EdgeSelection : public Gui::SelectionFilterGate
00134 {
00135 App::DocumentObject*& object;
00136 public:
00137 EdgeSelection(App::DocumentObject*& obj)
00138 : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), object(obj)
00139 {
00140 }
00141 bool allow(App::Document*pDoc, App::DocumentObject*pObj, const char*sSubName)
00142 {
00143 if (pObj != this->object)
00144 return false;
00145 if (!sSubName || sSubName[0] == '\0')
00146 return false;
00147 std::string element(sSubName);
00148 return element.substr(0,4) == "Edge";
00149 }
00150 };
00151 class ChamferWidgetP
00152 {
00153 public:
00154 App::DocumentObject* object;
00155 EdgeSelection* selection;
00156 typedef boost::signals::connection Connection;
00157 Connection connectApplicationDeletedObject;
00158 Connection connectApplicationDeletedDocument;
00159 };
00160 };
00161
00162
00163
00164 ChamferWidget::ChamferWidget(QWidget* parent, Qt::WFlags fl)
00165 : QWidget(parent, fl), ui(new Ui_TaskChamfer()), d(new ChamferWidgetP())
00166 {
00167 ui->setupUi(this);
00168
00169 d->object = 0;
00170 d->selection = new EdgeSelection(d->object);
00171 Gui::Selection().addSelectionGate(d->selection);
00172
00173 d->connectApplicationDeletedObject = App::GetApplication().signalDeletedObject
00174 .connect(boost::bind(&ChamferWidget::onDeleteObject, this, _1));
00175 d->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument
00176 .connect(boost::bind(&ChamferWidget::onDeleteDocument, this, _1));
00177
00178 QStandardItemModel* model = new ChamferDistanceModel(this);
00179 connect(model, SIGNAL(toggleCheckState(const QModelIndex&)),
00180 this, SLOT(toggleCheckState(const QModelIndex&)));
00181 model->insertColumns(0,3);
00182 model->setHeaderData(0, Qt::Horizontal, tr("Edges to chamfer"), Qt::DisplayRole);
00183 model->setHeaderData(1, Qt::Horizontal, tr("Start distance"), Qt::DisplayRole);
00184 model->setHeaderData(2, Qt::Horizontal, tr("End distance"), Qt::DisplayRole);
00185 ui->treeView->setRootIsDecorated(false);
00186 ui->treeView->setItemDelegate(new ChamferDistanceDelegate(this));
00187 ui->treeView->setModel(model);
00188
00189 QHeaderView* header = ui->treeView->header();
00190 header->setResizeMode(0, QHeaderView::Stretch);
00191 header->setDefaultAlignment(Qt::AlignLeft);
00192 header->setMovable(false);
00193 on_chamferType_activated(0);
00194 findShapes();
00195 }
00196
00197
00198
00199
00200 ChamferWidget::~ChamferWidget()
00201 {
00202
00203 d->connectApplicationDeletedDocument.disconnect();
00204 d->connectApplicationDeletedObject.disconnect();
00205 Gui::Selection().rmvSelectionGate();
00206 }
00207
00208 void ChamferWidget::onSelectionChanged(const Gui::SelectionChanges& msg)
00209 {
00210
00211 if (!d->object || !msg.pSubName)
00212 return;
00213 if (msg.Type == Gui::SelectionChanges::AddSelection) {
00214
00215
00216 App::Document* doc = d->object->getDocument();
00217 std::string docname = doc->getName();
00218 std::string objname = d->object->getNameInDocument();
00219 if (docname==msg.pDocName && objname==msg.pObjectName) {
00220 QString subelement = QString::fromAscii(msg.pSubName);
00221 QAbstractItemModel* model = ui->treeView->model();
00222 for (int i=0; i<model->rowCount(); ++i) {
00223 int id = model->data(model->index(i,0), Qt::UserRole).toInt();
00224 QString name = QString::fromAscii("Edge%1").arg(id);
00225 if (name == subelement) {
00226
00227 Qt::CheckState checkState = Qt::Checked;
00228 QVariant value(static_cast<int>(checkState));
00229 QModelIndex index = model->index(i,0);
00230 model->setData(index, value, Qt::CheckStateRole);
00231
00232 ui->treeView->selectionModel()->setCurrentIndex(index,QItemSelectionModel::NoUpdate);
00233 QItemSelection selection(index, model->index(i,1));
00234 ui->treeView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
00235 break;
00236 }
00237 }
00238 }
00239 }
00240 }
00241
00242 void ChamferWidget::onDeleteObject(const App::DocumentObject& obj)
00243 {
00244 if (d->object == &obj) {
00245 d->object = 0;
00246 ui->shapeObject->removeItem(ui->shapeObject->currentIndex());
00247 ui->shapeObject->setCurrentIndex(0);
00248 on_shapeObject_activated(0);
00249 }
00250 else {
00251 QString shape = QString::fromAscii(obj.getNameInDocument());
00252
00253 for (int i=1; i<ui->shapeObject->count(); i++) {
00254 if (ui->shapeObject->itemData(i).toString() == shape) {
00255 ui->shapeObject->removeItem(i);
00256 break;
00257 }
00258 }
00259 }
00260 }
00261
00262 void ChamferWidget::onDeleteDocument(const App::Document& doc)
00263 {
00264 if (d->object) {
00265 if (d->object->getDocument() == &doc) {
00266 ui->shapeObject->setCurrentIndex(0);
00267 on_shapeObject_activated(0);
00268 setEnabled(false);
00269 }
00270 }
00271 else if (App::GetApplication().getActiveDocument() == &doc) {
00272 ui->shapeObject->setCurrentIndex(0);
00273 on_shapeObject_activated(0);
00274 setEnabled(false);
00275 }
00276 }
00277
00278 void ChamferWidget::toggleCheckState(const QModelIndex& index)
00279 {
00280 if (!d->object)
00281 return;
00282 QVariant check = index.data(Qt::CheckStateRole);
00283 int id = index.data(Qt::UserRole).toInt();
00284 QString name = QString::fromAscii("Edge%1").arg(id);
00285 Qt::CheckState checkState = static_cast<Qt::CheckState>(check.toInt());
00286
00287 bool block = this->blockConnection(false);
00288
00289
00290 if (checkState & Qt::Checked) {
00291 App::Document* doc = d->object->getDocument();
00292 Gui::Selection().addSelection(doc->getName(),
00293 d->object->getNameInDocument(),
00294 (const char*)name.toAscii());
00295 }
00296 else {
00297 App::Document* doc = d->object->getDocument();
00298 Gui::Selection().rmvSelection(doc->getName(),
00299 d->object->getNameInDocument(),
00300 (const char*)name.toAscii());
00301 }
00302
00303 this->blockConnection(block);
00304 }
00305
00306 void ChamferWidget::findShapes()
00307 {
00308 App::Document* activeDoc = App::GetApplication().getActiveDocument();
00309 if (!activeDoc) return;
00310
00311 std::vector<App::DocumentObject*> objs = activeDoc->getObjectsOfType
00312 (Part::Feature::getClassTypeId());
00313 int index = 1;
00314 int current_index = 0;
00315 for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it!=objs.end(); ++it, ++index) {
00316 ui->shapeObject->addItem(QString::fromUtf8((*it)->Label.getValue()));
00317 ui->shapeObject->setItemData(index, QString::fromAscii((*it)->getNameInDocument()));
00318 if (current_index == 0) {
00319 if (Gui::Selection().isSelected(*it)) {
00320 current_index = index;
00321 }
00322 }
00323 }
00324
00325
00326 if (objs.size() == 1)
00327 current_index = 1;
00328
00329 if (current_index > 0) {
00330 ui->shapeObject->setCurrentIndex(current_index);
00331 on_shapeObject_activated(current_index);
00332 }
00333 }
00334
00335 void ChamferWidget::changeEvent(QEvent *e)
00336 {
00337 if (e->type() == QEvent::LanguageChange) {
00338 int index = ui->shapeObject->currentIndex();
00339
00340 int count = ui->shapeObject->count() - 1;
00341 QStringList text;
00342 QList<QVariant> data;
00343 for (int i=0; i<count; i++) {
00344 text << ui->shapeObject->itemText(i+1);
00345 data << ui->shapeObject->itemData(i+1);
00346 }
00347
00348 ui->retranslateUi(this);
00349 for (int i=0; i<count; i++) {
00350 ui->shapeObject->addItem(text.at(i));
00351 ui->shapeObject->setItemData(i+1, data.at(i));
00352 }
00353
00354 ui->shapeObject->setCurrentIndex(index);
00355 QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
00356 count = model->rowCount();
00357 for (int i=0; i<count; i++) {
00358 int id = model->data(model->index(i, 0), Qt::UserRole).toInt();
00359 model->setData(model->index(i, 0), QVariant(tr("Edge%1").arg(id)));
00360 }
00361 }
00362 else {
00363 QWidget::changeEvent(e);
00364 }
00365 }
00366
00367 void ChamferWidget::on_shapeObject_activated(int index)
00368 {
00369 d->object = 0;
00370 QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
00371 model->removeRows(0, model->rowCount());
00372
00373 QByteArray name = ui->shapeObject->itemData(index).toByteArray();
00374 App::Document* doc = App::GetApplication().getActiveDocument();
00375 if (!doc)
00376 return;
00377 App::DocumentObject* part = doc->getObject((const char*)name);
00378 if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
00379 d->object = part;
00380 TopoDS_Shape myShape = static_cast<Part::Feature*>(part)->Shape.getValue();
00381
00382 TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
00383 TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
00384 TopTools_IndexedMapOfShape mapOfShape;
00385 TopExp::MapShapes(myShape, TopAbs_EDGE, mapOfShape);
00386
00387
00388 std::vector<int> edge_ids;
00389 for (int i=1; i<= edge2Face.Extent(); ++i) {
00390
00391 const TopTools_ListOfShape& los = edge2Face.FindFromIndex(i);
00392 if (los.Extent() == 2) {
00393
00394 const TopoDS_Shape& edge = edge2Face.FindKey(i);
00395 const TopTools_ListOfShape& los = edge2Face.FindFromIndex(i);
00396 if (los.Extent() == 2) {
00397
00398
00399 const TopoDS_Shape& face1 = los.First();
00400 const TopoDS_Shape& face2 = los.Last();
00401 GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge),
00402 TopoDS::Face(face1),
00403 TopoDS::Face(face2));
00404 if (cont == GeomAbs_C0) {
00405 int id = mapOfShape.FindIndex(edge);
00406 edge_ids.push_back(id);
00407 }
00408 }
00409 }
00410 }
00411
00412 model->insertRows(0, edge_ids.size());
00413 int index = 0;
00414 for (std::vector<int>::iterator it = edge_ids.begin(); it != edge_ids.end(); ++it) {
00415 model->setData(model->index(index, 0), QVariant(tr("Edge%1").arg(*it)));
00416 model->setData(model->index(index, 0), QVariant(*it), Qt::UserRole);
00417 model->setData(model->index(index, 0), Qt::Unchecked, Qt::CheckStateRole);
00418 model->setData(model->index(index, 1), QVariant(QLocale::system().toString(1.0,'f',2)));
00419 model->setData(model->index(index, 2), QVariant(QLocale::system().toString(1.0,'f',2)));
00420 index++;
00421 }
00422 }
00423 }
00424
00425 void ChamferWidget::on_selectAllButton_clicked()
00426 {
00427 QAbstractItemModel* model = ui->treeView->model();
00428 for (int i=0; i<model->rowCount(); ++i) {
00429 Qt::CheckState checkState = Qt::Checked;
00430 QVariant value(static_cast<int>(checkState));
00431 model->setData(model->index(i,0), value, Qt::CheckStateRole);
00432 }
00433 }
00434
00435 void ChamferWidget::on_selectNoneButton_clicked()
00436 {
00437 QAbstractItemModel* model = ui->treeView->model();
00438 for (int i=0; i<model->rowCount(); ++i) {
00439 Qt::CheckState checkState = Qt::Unchecked;
00440 QVariant value(static_cast<int>(checkState));
00441 model->setData(model->index(i,0), value, Qt::CheckStateRole);
00442 }
00443 }
00444
00445 void ChamferWidget::on_chamferType_activated(int index)
00446 {
00447 QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
00448 if (index == 0) {
00449 model->setHeaderData(1, Qt::Horizontal, tr("Distance"), Qt::DisplayRole);
00450 ui->treeView->hideColumn(2);
00451 ui->chamferEndDistance->hide();
00452 }
00453 else {
00454 model->setHeaderData(1, Qt::Horizontal, tr("Start distance"), Qt::DisplayRole);
00455 ui->treeView->showColumn(2);
00456 ui->chamferEndDistance->show();
00457 }
00458
00459 ui->treeView->resizeColumnToContents(0);
00460 ui->treeView->resizeColumnToContents(1);
00461 ui->treeView->resizeColumnToContents(2);
00462 }
00463
00464 void ChamferWidget::on_chamferStartDistance_valueChanged(double distance)
00465 {
00466 QAbstractItemModel* model = ui->treeView->model();
00467 QString text = QLocale::system().toString(distance,'f',2);
00468 for (int i=0; i<model->rowCount(); ++i) {
00469 QVariant value = model->index(i,0).data(Qt::CheckStateRole);
00470 Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
00471
00472
00473 if (checkState & Qt::Checked) {
00474 model->setData(model->index(i, 1), QVariant(text));
00475 }
00476 }
00477 }
00478
00479 void ChamferWidget::on_chamferEndDistance_valueChanged(double distance)
00480 {
00481 QAbstractItemModel* model = ui->treeView->model();
00482 QString text = QLocale::system().toString(distance,'f',2);
00483 for (int i=0; i<model->rowCount(); ++i) {
00484 QVariant value = model->index(i,0).data(Qt::CheckStateRole);
00485 Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
00486
00487
00488 if (checkState & Qt::Checked) {
00489 model->setData(model->index(i, 2), QVariant(text));
00490 }
00491 }
00492 }
00493
00494 bool ChamferWidget::accept()
00495 {
00496 if (!d->object) {
00497 QMessageBox::warning(this, tr("No shape selected"),
00498 tr("No valid shape is selected.\n"
00499 "Please select a valid shape in the drop-down box first."));
00500 return false;
00501 }
00502 App::Document* activeDoc = App::GetApplication().getActiveDocument();
00503 QAbstractItemModel* model = ui->treeView->model();
00504 bool end_distance = !ui->treeView->isColumnHidden(2);
00505 bool todo = false;
00506
00507 QString shape, type, name;
00508 int index = ui->shapeObject->currentIndex();
00509 shape = ui->shapeObject->itemData(index).toString();
00510 type = QString::fromAscii("Part::Chamfer");
00511 name = QString::fromAscii(activeDoc->getUniqueObjectName("Chamfer").c_str());
00512
00513 activeDoc->openTransaction("Chamfer");
00514 QString code = QString::fromAscii(
00515 "FreeCAD.ActiveDocument.addObject(\"%1\",\"%2\")\n"
00516 "FreeCAD.ActiveDocument.%2.Base = FreeCAD.ActiveDocument.%3\n"
00517 "__chamfers__ = []\n")
00518 .arg(type).arg(name).arg(shape);
00519 for (int i=0; i<model->rowCount(); ++i) {
00520 QVariant value = model->index(i,0).data(Qt::CheckStateRole);
00521 Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
00522
00523
00524 if (checkState & Qt::Checked) {
00525
00526 int id = model->index(i,0).data(Qt::UserRole).toInt();
00527 double r1 = model->index(i,1).data().toDouble();
00528 double r2 = r1;
00529 if (end_distance)
00530 r2 = model->index(i,2).data().toDouble();
00531 code += QString::fromAscii(
00532 "__chamfers__.append((%1,%2,%3))\n")
00533 .arg(id).arg(r1,0,'f',2).arg(r2,0,'f',2);
00534 todo = true;
00535 }
00536 }
00537
00538 if (!todo) {
00539 QMessageBox::warning(this, tr("No edge selected"),
00540 tr("No edge entity is checked to chamfer.\n"
00541 "Please check one or more edge entities first."));
00542 return false;
00543 }
00544
00545 Gui::WaitCursor wc;
00546 code += QString::fromAscii(
00547 "FreeCAD.ActiveDocument.%1.Edges = __chamfers__\n"
00548 "del __chamfers__\n"
00549 "FreeCADGui.ActiveDocument.%2.Visibility = False\n")
00550 .arg(name).arg(shape);
00551 Gui::Application::Instance->runPythonCode((const char*)code.toAscii());
00552 activeDoc->commitTransaction();
00553 activeDoc->recompute();
00554
00555 QByteArray to = name.toAscii();
00556 QByteArray from = shape.toAscii();
00557 Gui::Command::copyVisual(to, "ShapeColor", from);
00558 Gui::Command::copyVisual(to, "LineColor", from);
00559 Gui::Command::copyVisual(to, "PointColor", from);
00560
00561 return true;
00562 }
00563
00564
00565
00566 TaskChamfer::TaskChamfer()
00567 {
00568 widget = new ChamferWidget();
00569 Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox(
00570 Gui::BitmapFactory().pixmap("Part_Chamfer"),
00571 widget->windowTitle(), true, 0);
00572 taskbox->groupLayout()->addWidget(widget);
00573 Content.push_back(taskbox);
00574 }
00575
00576 TaskChamfer::~TaskChamfer()
00577 {
00578
00579 }
00580
00581 void TaskChamfer::open()
00582 {
00583 }
00584
00585 void TaskChamfer::clicked(int)
00586 {
00587 }
00588
00589 bool TaskChamfer::accept()
00590 {
00591 return widget->accept();
00592 }
00593
00594 bool TaskChamfer::reject()
00595 {
00596 return true;
00597 }
00598
00599
00600
00601 PROPERTY_SOURCE(PartDesignGui::ViewProviderChamfer, PartGui::ViewProviderPart)
00602
00603 ViewProviderChamfer::ViewProviderChamfer()
00604 {
00605 sPixmap = "Part_Chamfer";
00606 }
00607
00608 ViewProviderChamfer::~ViewProviderChamfer()
00609 {
00610 }
00611
00612 #include "moc_TaskChamfer.cpp"