Gui/Placement.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #include <QSignalMapper>
00026 #include <QDockWidget>
00027 
00028 #include "Placement.h"
00029 #include "ui_Placement.h"
00030 #include <Gui/DockWindowManager.h>
00031 #include <Gui/Application.h>
00032 #include <Gui/Document.h>
00033 #include <Gui/Selection.h>
00034 #include <Gui/ViewProvider.h>
00035 #include <App/Document.h>
00036 #include <App/PropertyGeo.h>
00037 #include <Base/Console.h>
00038 
00039 using namespace Gui::Dialog;
00040 
00041 namespace Gui { namespace Dialog {
00042 class find_placement
00043 {
00044 public:
00045     find_placement(const std::string& name) : propertyname(name)
00046     {
00047     }
00048     bool operator () (const std::pair<std::string, App::Property*>& elem) const
00049     {
00050         if (elem.first == propertyname) {
00051             return elem.second->isDerivedFrom
00052                 (Base::Type::fromName("App::PropertyPlacement"));
00053         }
00054 
00055         return false;
00056     }
00057 
00058     std::string propertyname;
00059 };
00060 
00061 }
00062 }
00063 
00064 /* TRANSLATOR Gui::Dialog::Placement */
00065 
00066 Placement::Placement(QWidget* parent, Qt::WFlags fl)
00067   : Gui::LocationDialog(parent, fl)
00068 {
00069     propertyName = "Placement"; // default name
00070     ui = new Ui_PlacementComp(this);
00071     ui->applyPlacementChange->hide();
00072 
00073     ui->angle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00074     ui->yawAngle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00075     ui->pitchAngle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00076     ui->rollAngle->setSuffix(QString::fromUtf8(" \xc2\xb0"));
00077 
00078     // create a signal mapper in order to have one slot to perform the change
00079     signalMapper = new QSignalMapper(this);
00080     connect(this, SIGNAL(directionChanged()), signalMapper, SLOT(map()));
00081     signalMapper->setMapping(this, 0);
00082 
00083     int id = 1;
00084     QList<QDoubleSpinBox*> sb = this->findChildren<QDoubleSpinBox*>();
00085     for (QList<QDoubleSpinBox*>::iterator it = sb.begin(); it != sb.end(); ++it) {
00086         connect(*it, SIGNAL(valueChanged(double)), signalMapper, SLOT(map()));
00087         signalMapper->setMapping(*it, id++);
00088     }
00089 
00090     connect(signalMapper, SIGNAL(mapped(int)),
00091             this, SLOT(onPlacementChanged(int)));
00092 }
00093 
00094 Placement::~Placement()
00095 {
00096     delete ui;
00097 }
00098 
00099 void Placement::showDefaultButtons(bool ok)
00100 {
00101     ui->oKButton->setVisible(ok);
00102     ui->closeButton->setVisible(ok);
00103     ui->applyButton->setVisible(ok);
00104 }
00105 
00106 void Placement::applyPlacement(const Base::Placement& p, bool incremental, bool data)
00107 {
00108     Gui::Document* document = Application::Instance->activeDocument();
00109     if (!document) return;
00110 
00111     std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType
00112         (App::DocumentObject::getClassTypeId(), document->getDocument()->getName());
00113     if (!sel.empty()) {
00114         if (data) {
00115             document->openCommand("Placement");
00116             for (std::vector<App::DocumentObject*>::iterator it=sel.begin();it!=sel.end();++it) {
00117                 std::map<std::string,App::Property*> props;
00118                 (*it)->getPropertyMap(props);
00119                 // search for the placement property
00120                 std::map<std::string,App::Property*>::iterator jt;
00121                 jt = std::find_if(props.begin(), props.end(), find_placement(this->propertyName));
00122                 if (jt != props.end()) {
00123                     Base::Placement cur = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
00124                     if (incremental)
00125                         cur = p * cur;
00126                     else
00127                         cur = p;
00128 
00129                     Base::Vector3d pos = cur.getPosition();
00130                     const Base::Rotation& rt = cur.getRotation();
00131                     QString cmd = QString::fromAscii(
00132                         "App.getDocument(\"%1\").%2.Placement="
00133                         "App.Placement("
00134                         "App.Vector(%3,%4,%5),"
00135                         "App.Rotation(%6,%7,%8,%9))\n")
00136                         .arg(QLatin1String((*it)->getDocument()->getName()))
00137                         .arg(QLatin1String((*it)->getNameInDocument()))
00138                         .arg(pos.x,0,'g',6)
00139                         .arg(pos.y,0,'g',6)
00140                         .arg(pos.z,0,'g',6)
00141                         .arg(rt[0],0,'g',6)
00142                         .arg(rt[1],0,'g',6)
00143                         .arg(rt[2],0,'g',6)
00144                         .arg(rt[3],0,'g',6);
00145                     Application::Instance->runPythonCode((const char*)cmd.toAscii());
00146                 }
00147             }
00148 
00149             document->commitCommand();
00150         }
00151         // apply transformation only on view matrix not on placement property
00152         else {
00153             for (std::vector<App::DocumentObject*>::iterator it=sel.begin();it!=sel.end();++it) {
00154                 std::map<std::string,App::Property*> props;
00155                 (*it)->getPropertyMap(props);
00156                 // search for the placement property
00157                 std::map<std::string,App::Property*>::iterator jt;
00158                 jt = std::find_if(props.begin(), props.end(), find_placement(this->propertyName));
00159                 if (jt != props.end()) {
00160                     Base::Placement cur = static_cast<App::PropertyPlacement*>(jt->second)->getValue();
00161                     if (incremental)
00162                         cur = p * cur;
00163                     else
00164                         cur = p;
00165 
00166                     Gui::ViewProvider* vp = document->getViewProvider(*it);
00167                     if (vp) vp->setTransformation(cur.toMatrix());
00168                 }
00169             }
00170         }
00171     }
00172     else {
00173         Base::Console().Warning("No object selected.\n");
00174     }
00175 }
00176 
00177 void Placement::onPlacementChanged(int)
00178 {
00179     // If there are listeners to the 'placementChanged' signal we rely
00180     // on that the listener updates any placement. If no listeners
00181     // are connected the placement is applied to all selected objects
00182     // automatically.
00183     bool incr = ui->applyIncrementalPlacement->isChecked();
00184     Base::Placement plm = this->getPlacement();
00185     applyPlacement(plm, incr, false);
00186 
00187     QVariant data = QVariant::fromValue<Base::Placement>(plm);
00188     /*emit*/ placementChanged(data, incr, false);
00189 }
00190 
00191 void Placement::on_applyIncrementalPlacement_toggled(bool on)
00192 {
00193     if (on) {
00194         this->ref = getPlacementData();
00195         on_resetButton_clicked();
00196     }
00197     else {
00198         Base::Placement p = getPlacementData();
00199         p = p * this->ref;
00200         setPlacementData(p);
00201         onPlacementChanged(0);
00202     }
00203 }
00204 
00205 void Placement::reject()
00206 {
00207     Base::Placement plm;
00208     applyPlacement(plm, true, false);
00209 
00210     QVariant data = QVariant::fromValue<Base::Placement>(plm);
00211     /*emit*/ placementChanged(data, true, false);
00212 
00213     QDialog::reject();
00214 }
00215 
00216 void Placement::accept()
00217 {
00218     on_applyButton_clicked();
00219     QDialog::accept();
00220 }
00221 
00222 void Placement::on_applyButton_clicked()
00223 {
00224     // If there are listeners to the 'placementChanged' signal we rely
00225     // on that the listener updates any placement. If no listeners
00226     // are connected the placement is applied to all selected objects
00227     // automatically.
00228     bool incr = ui->applyIncrementalPlacement->isChecked();
00229     Base::Placement plm = this->getPlacement();
00230     applyPlacement(plm, incr, true);
00231 
00232     QVariant data = QVariant::fromValue<Base::Placement>(plm);
00233     /*emit*/ placementChanged(data, incr, true);
00234 
00235     if (ui->applyIncrementalPlacement->isChecked()) {
00236         QList<QDoubleSpinBox*> sb = this->findChildren<QDoubleSpinBox*>();
00237         for (QList<QDoubleSpinBox*>::iterator it = sb.begin(); it != sb.end(); ++it) {
00238             (*it)->blockSignals(true);
00239             (*it)->setValue(0.0);
00240             (*it)->blockSignals(false);
00241         }
00242     }
00243 }
00244 
00245 void Placement::on_resetButton_clicked()
00246 {
00247     QList<QDoubleSpinBox*> sb = this->findChildren<QDoubleSpinBox*>();
00248     for (QList<QDoubleSpinBox*>::iterator it = sb.begin(); it != sb.end(); ++it) {
00249         (*it)->blockSignals(true);
00250         (*it)->setValue(0.0);
00251         (*it)->blockSignals(false);
00252     }
00253 
00254     onPlacementChanged(0);
00255 }
00256 
00257 void Placement::directionActivated(int index)
00258 {
00259     if (ui->directionActivated(this, index)) {
00260         /*emit*/ directionChanged();
00261     }
00262 }
00263 
00264 Base::Vector3f Placement::getDirection() const
00265 {
00266     return ui->getDirection();
00267 }
00268 
00269 void Placement::setPlacement(const Base::Placement& p)
00270 {
00271     setPlacementData(p);
00272 }
00273 
00274 void Placement::setPlacementData(const Base::Placement& p)
00275 {
00276     signalMapper->blockSignals(true);
00277     ui->xPos->setValue(p.getPosition().x);
00278     ui->yPos->setValue(p.getPosition().y);
00279     ui->zPos->setValue(p.getPosition().z);
00280 
00281     double Y,P,R;
00282     p.getRotation().getYawPitchRoll(Y,P,R);
00283     ui->yawAngle->setValue(Y);
00284     ui->pitchAngle->setValue(P);
00285     ui->rollAngle->setValue(R);
00286 
00287     // check if the user-defined direction is already there
00288     bool newitem = true;
00289     double angle;
00290     Base::Vector3d axis;
00291     p.getRotation().getValue(axis, angle);
00292     ui->angle->setValue(angle*180.0/D_PI);
00293     Base::Vector3f dir((float)axis.x,(float)axis.y,(float)axis.z);
00294     for (int i=0; i<ui->direction->count()-1; i++) {
00295         QVariant data = ui->direction->itemData (i);
00296         if (data.canConvert<Base::Vector3f>()) {
00297             const Base::Vector3f val = data.value<Base::Vector3f>();
00298             if (val == dir) {
00299                 ui->direction->setCurrentIndex(i);
00300                 newitem = false;
00301                 break;
00302             }
00303         }
00304     }
00305 
00306     if (newitem) {
00307         // add a new item before the very last item
00308         QString display = QString::fromAscii("(%1,%2,%3)")
00309             .arg(dir.x)
00310             .arg(dir.y)
00311             .arg(dir.z);
00312         ui->direction->insertItem(ui->direction->count()-1, display,
00313             QVariant::fromValue<Base::Vector3f>(dir));
00314         ui->direction->setCurrentIndex(ui->direction->count()-2);
00315     }
00316     signalMapper->blockSignals(false);
00317 }
00318 
00319 Base::Placement Placement::getPlacement() const
00320 {
00321     Base::Placement p = getPlacementData();
00322     return p;
00323 }
00324 
00325 Base::Placement Placement::getPlacementData() const
00326 {
00327     int index = ui->rotationInput->currentIndex();
00328     Base::Rotation rot;
00329     Base::Vector3d pos;
00330     Base::Vector3d cnt;
00331 
00332     pos = Base::Vector3d(ui->xPos->value(),ui->yPos->value(),ui->zPos->value());
00333     cnt = Base::Vector3d(ui->xCnt->value(),ui->yCnt->value(),ui->zCnt->value());
00334 
00335     if (index == 0) {
00336         Base::Vector3f dir = getDirection();
00337         rot.setValue(Base::Vector3d(dir.x,dir.y,dir.z),ui->angle->value()*D_PI/180.0);
00338     }
00339     else if (index == 1) {
00340         rot.setYawPitchRoll(
00341             ui->yawAngle->value(),
00342             ui->pitchAngle->value(),
00343             ui->rollAngle->value());
00344     }
00345 
00346     Base::Placement p(pos, rot, cnt);
00347     return p;
00348 }
00349 
00350 void Placement::changeEvent(QEvent *e)
00351 {
00352     if (e->type() == QEvent::LanguageChange) {
00353         ui->retranslate(this);
00354     }
00355     else {
00356         QDialog::changeEvent(e);
00357     }
00358 }
00359 
00360 // ----------------------------------------------
00361 
00362 /* TRANSLATOR Gui::Dialog::DockablePlacement */
00363 
00364 DockablePlacement::DockablePlacement(QWidget* parent, Qt::WFlags fl) : Placement(parent, fl)
00365 {
00366     Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
00367     QDockWidget* dw = pDockMgr->addDockWindow(QT_TR_NOOP("Placement"),
00368         this, Qt::BottomDockWidgetArea);
00369     dw->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable);
00370     dw->show();
00371 }
00372 
00373 DockablePlacement::~DockablePlacement()
00374 {
00375 }
00376 
00377 void DockablePlacement::accept()
00378 {
00379     // closes the dock window
00380     Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
00381     pDockMgr->removeDockWindow(this);
00382     Placement::accept();
00383 }
00384 
00385 void DockablePlacement::reject()
00386 {
00387     // closes the dock window
00388     Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
00389     pDockMgr->removeDockWindow(this);
00390     Placement::reject();
00391 }
00392 
00393 // ----------------------------------------------
00394 
00395 /* TRANSLATOR Gui::Dialog::TaskPlacement */
00396 
00397 TaskPlacement::TaskPlacement()
00398 {
00399     this->setButtonPosition(TaskPlacement::South);
00400     widget = new Placement();
00401     widget->showDefaultButtons(false);
00402     taskbox = new Gui::TaskView::TaskBox(QPixmap(), widget->windowTitle(),true, 0);
00403     taskbox->groupLayout()->addWidget(widget);
00404 
00405     Content.push_back(taskbox);
00406     connect(widget, SIGNAL(placementChanged(const QVariant &, bool, bool)),
00407             this, SLOT(slotPlacementChanged(const QVariant &, bool, bool)));
00408 }
00409 
00410 TaskPlacement::~TaskPlacement()
00411 {
00412     // automatically deleted in the sub-class
00413 }
00414 
00415 void TaskPlacement::setPropertyName(const QString& name)
00416 {
00417     widget->propertyName = (const char*)name.toLatin1();
00418 }
00419 
00420 QDialogButtonBox::StandardButtons TaskPlacement::getStandardButtons() const
00421 { 
00422     return QDialogButtonBox::Ok|
00423            QDialogButtonBox::Cancel|
00424            QDialogButtonBox::Apply;
00425 }
00426 
00427 void TaskPlacement::setPlacement(const Base::Placement& p)
00428 {
00429     widget->setPlacement(p);
00430 }
00431 
00432 void TaskPlacement::slotPlacementChanged(const QVariant & p, bool incr, bool data)
00433 {
00434     /*emit*/ placementChanged(p, incr, data);
00435 }
00436 
00437 bool TaskPlacement::accept()
00438 {
00439     widget->accept();
00440     return (widget->result() == QDialog::Accepted);
00441 }
00442 
00443 bool TaskPlacement::reject()
00444 {
00445     widget->reject();
00446     return (widget->result() == QDialog::Rejected);
00447 }
00448 
00449 void TaskPlacement::clicked(int id)
00450 {
00451     if (id == QDialogButtonBox::Apply) {
00452         widget->on_applyButton_clicked();
00453     }
00454 }
00455 
00456 #include "moc_Placement.cpp"

Generated on Wed Nov 23 19:00:26 2011 for FreeCAD by  doxygen 1.6.1