1 // Copyright (C) 2016 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
22 #include "YDFXGUISeqInit.hxx"
29 #include <QPushButton>
30 #include <QScrollArea>
31 #include <QHBoxLayout>
32 #include <QFileDialog>
33 #include <QApplication>
36 #include "AutoGIL.hxx"
38 #include "YDFXGUIWrap.hxx"
39 #include "YDFXGUIPyThreadSaver.hxx"
41 #include "YACSEvalPort.hxx"
42 #include "YACSEvalSeqAny.hxx"
47 const char YDFXGUIStatus::OK_STR[]="OK !";
52 AutoPyRef(PyObject *pyobj=0):_pyobj(pyobj) { }
53 ~AutoPyRef() { release(); }
54 AutoPyRef(const AutoPyRef& other):_pyobj(other._pyobj) { if(_pyobj) Py_XINCREF(_pyobj); }
55 AutoPyRef& operator=(const AutoPyRef& other) { if(_pyobj==other._pyobj) return *this; release(); _pyobj=other._pyobj; Py_XINCREF(_pyobj); return *this; }
56 operator PyObject *() { return _pyobj; }
57 void set(PyObject *pyobj) { if(pyobj==_pyobj) return ; release(); _pyobj=pyobj; }
58 PyObject *get() { return _pyobj; }
59 bool isNull() const { return _pyobj==0; }
60 PyObject *retn() { if(_pyobj) Py_XINCREF(_pyobj); return _pyobj; }
62 void release() { if(_pyobj) Py_XDECREF(_pyobj); _pyobj=0; }
67 ////////////////////////////
69 void YDFXGUIDoubleVectHolder::applyOnInput(YACSEvalInputPort *inp) const
71 YACSEvalSeqAny *val(new YACSEvalSeqAnyDouble(_vect));
72 inp->setSequenceOfValuesToEval(val);
76 ////////////////////////////
78 YDFXGUISeqSetterP::YDFXGUISeqSetterP(QWidget *parent):QPushButton(parent),_isIn(false)
81 connect(this,SIGNAL(clicked()),this,SLOT(selectAFile()));
84 void YDFXGUISeqSetterP::loadState(const QString& state)
87 setToolTip(_fileName);
90 QString YDFXGUISeqSetterP::saveState() const
95 bool YDFXGUISeqSetterP::executeScript(int& sz)
97 QObject *zeBoss(parent()->parent());
98 YDFXGUISeqLine *zeBossc(qobject_cast<YDFXGUISeqLine *>(zeBoss));
102 if(_fileName.isEmpty())
104 Q_EMIT problemDetected(QString("For \"%1\" : no file defined !").arg(zeBossc->getName()));
107 QFile file(_fileName);
108 if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
114 QByteArray line(file.readLine());
115 QString line2(line.data());
117 double v(line2.toDouble(&isOK));
120 Q_EMIT problemDetected(QString("For \"%1\" : At line %2 it is not a float !").arg(zeBossc->getName()).arg(i));
130 void YDFXGUISeqSetterP::enterEvent(QEvent *event)
136 void YDFXGUISeqSetterP::leaveEvent(QEvent *event)
142 void YDFXGUISeqSetterP::paintEvent(QPaintEvent *event)
144 if(_isIn || _fileName.isEmpty())
146 QPushButton::paintEvent(event);
149 QFileInfo fi(_fileName);
150 QString txt(fi.fileName());
151 QRect refRect(rect());
154 QSize refRect2(fm.boundingRect(txt).size());
156 QPainter painter(this);
157 painter.drawText(QPoint((refRect.width()-refRect2.width())/2,
158 refRect.height()/2+refRect2.height()/2-fm.descent()),txt);
161 void YDFXGUISeqSetterP::selectAFile()
163 QFileDialog fd(this,QString("Select a file containing list of floats."));
164 fd.setFileMode(QFileDialog::ExistingFile);
167 QStringList files(fd.selectedFiles());
172 setToolTip(_fileName);
177 ////////////////////////////
179 void YDFXGUISeqSetterT::loadState(const QString& state)
184 QString YDFXGUISeqSetterT::saveState() const
186 return toPlainText();
189 bool YDFXGUISeqSetterT::executeScript(int& sz)
191 QObject *zeBoss(parent()->parent());
192 YDFXGUISeqLine *zeBossc(qobject_cast<YDFXGUISeqLine *>(zeBoss));
196 std::string name(zeBossc->getName().toStdString());
198 static const char TMP_FILENAME[]="/tmp/TMP";
199 std::string txt(toPlainText().toStdString());
200 YDFXGUIPyThreadSaver::SaveContext(QApplication::instance()->thread());
202 YACS::ENGINE::AutoGIL gal;
203 AutoPyRef code(Py_CompileString(txt.c_str(),TMP_FILENAME, Py_file_input));
204 if(code.get() == NULL)
206 Q_EMIT problemDetected(QString("For \"%1\" : python code is invalid !").arg(zeBossc->getName()));
209 AutoPyRef context(PyDict_New());
210 PyDict_SetItemString( context, "__builtins__", PyEval_GetBuiltins() );
211 AutoPyRef res(PyEval_EvalCode(code.get(), context, context));
212 PyObject *item(PyDict_GetItemString(context,name.c_str()));
216 Q_EMIT problemDetected(QString("For \"%1\" : Py var %1 is not defined !").arg(zeBossc->getName()));
219 if(!PyList_Check(item))
221 Q_EMIT problemDetected(QString("For \"%1\" : Py var %1 must be a list !").arg(zeBossc->getName()));
224 sz=PyList_Size(item);
225 _vect.clear() ; _vect.resize(sz);
226 for(int i=0;i<sz;i++)
228 PyObject *val(PyList_GetItem(item,i));
229 if(!PyFloat_Check(val))
231 Q_EMIT problemDetected(QString("For \"%1\" : At pos %2 of python list, it is not a float !").arg(zeBossc->getName()).arg(i));
234 _vect[i]=PyFloat_AS_DOUBLE(val);
240 ////////////////////////////
242 YDFXGUICombo::YDFXGUICombo(QWidget *parent):QComboBox(parent),_isIn(false)
244 setFocusPolicy(Qt::TabFocus);
247 QString YDFXGUICombo::getName()
250 YDFXGUISeqLine *parentc(qobject_cast<YDFXGUISeqLine *>(parent()));
252 ret=parentc->getName();
256 void YDFXGUICombo::enterEvent(QEvent *event)
262 void YDFXGUICombo::leaveEvent(QEvent *event)
268 void YDFXGUICombo::paintEvent(QPaintEvent *event)
272 QComboBox::paintEvent(event);
275 QRect refRect(rect());
279 QSize refRect2(fm.boundingRect(getName()).size());
280 QPainter painter(this);
282 QPen pen(painter.pen());
283 pen.setColor(Qt::red);
285 painter.drawText(QPoint((refRect.width()-refRect2.width())/2,refRect.height()/2+refRect2.height()/2-fm.descent()),getName());
288 ////////////////////////////
290 YDFXGUISeqSetter::YDFXGUISeqSetter(QWidget *parent, const QString& name):QWidget(parent),_textEdit(0),_push(0),_curType(0)
292 QVBoxLayout *verticalLayout(new QVBoxLayout(this));
293 _textEdit=new YDFXGUISeqSetterT(this); verticalLayout->addWidget(_textEdit);
294 _push=new YDFXGUISeqSetterP(this); verticalLayout->addWidget(_push);
295 _textEdit->setText(QString("import math\n%1=[math.sqrt(float(elt)+0.) for elt in range(4)]").arg(name));
300 int YDFXGUISeqSetter::loadState(const QString& state)
302 if(state.isEmpty() || state.size()<3)
304 QString sw(state.mid(0,3));
307 _push->loadState(state.mid(3));
313 _textEdit->loadState(state.mid(3));
319 QString YDFXGUISeqSetter::saveState() const
321 YDFXGUISeqLine *parentc(qobject_cast<YDFXGUISeqLine *>(parent()));
324 int pos(parentc->getPositionOfCombo());
328 ret+=_push->saveState();
334 ret+=_textEdit->saveState();
340 QSize YDFXGUISeqSetter::sizeHint() const
342 QSize sz,sz2(QWidget::sizeHint());
344 sz=_push->sizeHint();
346 sz=_textEdit->sizeHint();
347 sz.rwidth()+=sz2.rwidth();
348 sz.rheight()+=sz2.rheight();
352 QSize YDFXGUISeqSetter::minimumSizeHint() const
354 QSize sz,sz2(QWidget::minimumSizeHint());
356 sz=_push->minimumSizeHint();
358 sz=_textEdit->minimumSizeHint();
359 sz.rwidth()+=sz2.rwidth();
360 sz.rheight()+=sz2.rheight();
364 bool YDFXGUISeqSetter::checkOK(int& sz)
367 return _push->executeScript(sz);
369 return _textEdit->executeScript(sz);
372 void YDFXGUISeqSetter::applyOnInput(YACSEvalInputPort *inp)
375 _push->applyOnInput(inp);
377 _textEdit->applyOnInput(inp);
380 void YDFXGUISeqSetter::typeOfAssignmentChanged(int newType)
387 disconnect(_textEdit,SIGNAL(problemDetected(const QString&)),this,SIGNAL(problemDetected(const QString&)));
388 connect(_push,SIGNAL(problemDetected(const QString&)),this,SIGNAL(problemDetected(const QString&)));
394 disconnect(_push,SIGNAL(problemDetected(const QString&)),this,SIGNAL(problemDetected(const QString&)));
395 connect(_textEdit,SIGNAL(problemDetected(const QString&)),this,SIGNAL(problemDetected(const QString&)));
399 ////////////////////////////
401 YDFXGUISeqLine::YDFXGUISeqLine(QWidget *parent, YACSEvalInputPort *inp):_combo(0),_setter(0),_inp(inp)
403 QHBoxLayout *horizontalLayout(new QHBoxLayout(this));
404 _combo=new YDFXGUICombo(this);
405 _combo->insertItem(0,QString("%1 from file").arg(getName()));
406 _combo->insertItem(1,QString("%1 from PyScript").arg(getName()));
407 horizontalLayout->addWidget(_combo);
408 _setter=new YDFXGUISeqSetter(this,getName());
409 connect(_combo,SIGNAL(currentIndexChanged(int)),this,SLOT(typeOfAssignmentChanged(int)));
410 horizontalLayout->addWidget(_setter);
411 _combo->setCurrentIndex(0);
412 Q_EMIT _combo->currentIndexChanged(0);//to be sure to sync widgets
415 void YDFXGUISeqLine::loadState(const QMap<QString,QString>& state)
417 QString name(getName());
418 QMap<QString,QString>::const_iterator it(state.find(name));
421 int pos(_setter->loadState(it.value()));
422 _combo->setCurrentIndex(pos);
425 void YDFXGUISeqLine::saveState(QMap<QString,QString>& state) const
427 state[getName()]=_setter->saveState();
430 QString YDFXGUISeqLine::getName() const
432 return QString(_inp->getName().c_str());
435 int YDFXGUISeqLine::getPositionOfCombo() const
437 return _combo->currentIndex();
440 bool YDFXGUISeqLine::checkOK(int& sz)
442 return _setter->checkOK(sz);
445 void YDFXGUISeqLine::connectToStatus(YDFXGUIStatus *status)
447 connect(_setter,SIGNAL(problemDetected(const QString&)),status,SLOT(displayInfo(const QString&)));
450 void YDFXGUISeqLine::applyOnInput()
452 _setter->applyOnInput(_inp);
455 void YDFXGUISeqLine::typeOfAssignmentChanged(int newType)
457 _setter->typeOfAssignmentChanged(newType);
458 _setter->updateGeometry();
462 ////////////////////////////
464 YDFXGUIStatus::YDFXGUIStatus(QWidget *parent):QWidget(parent)
468 void YDFXGUIStatus::paintEvent(QPaintEvent *event)
470 QRect refRect(rect());
473 QSize refRect2(fm.boundingRect(_text).size());
475 QPainter painter(this);
476 QPen pen(painter.pen());
477 pen.setColor(_text==OK_STR?Qt::green:Qt::red);
479 painter.drawText(QPoint((refRect.width()-refRect2.width())/2,
480 refRect.height()/2+refRect2.height()/2-fm.descent()),_text);
483 QSize YDFXGUIStatus::sizeHint() const
487 QSize ret(fm.boundingRect(_text).size());
491 QSize YDFXGUIStatus::minimumSizeHint() const
496 void YDFXGUIStatus::declareOK(bool isOK)
505 void YDFXGUIStatus::displayInfo(const QString& txt)
512 ////////////////////////////
514 YDFXGUISeqInitEff::YDFXGUISeqInitEff(QWidget *parent, YACSEvalYFXWrap *efx):QWidget(parent)
516 QVBoxLayout *verticalLayout(new QVBoxLayout(this));
517 std::vector< YACSEvalInputPort * > inputs(efx->getFreeInputPorts());
518 foreach(YACSEvalInputPort *input,inputs)
520 if(!input->isRandomVar())
522 YDFXGUISeqLine *line(new YDFXGUISeqLine(this,input));
523 verticalLayout->addWidget(line);
524 _lines.push_back(line);
528 void YDFXGUISeqInitEff::loadState(const QMap<QString,QString>& state)
530 foreach(YDFXGUISeqLine *line,_lines)
531 line->loadState(state);
534 QMap<QString,QString> YDFXGUISeqInitEff::saveState() const
536 QMap<QString,QString> ret;
537 foreach(YDFXGUISeqLine *line,_lines)
538 line->saveState(ret);
542 void YDFXGUISeqInitEff::connectToStatus(YDFXGUIStatus *status)
544 foreach(YDFXGUISeqLine *line,_lines)
546 line->connectToStatus(status);
550 void YDFXGUISeqInitEff::assignButtonClicked()
553 bool verdict(checkConsistency(sz));
554 Q_EMIT configurationIsOK(verdict);
557 void YDFXGUISeqInitEff::applyOnEFX()
559 foreach(YDFXGUISeqLine *line,_lines)
560 line->applyOnInput();
563 bool YDFXGUISeqInitEff::checkConsistency(int& sz)
565 int refSz(std::numeric_limits<int>::max());
566 foreach(YDFXGUISeqLine *line,_lines)
569 if(!line->checkOK(locSz))
571 if(refSz==std::numeric_limits<int>::max())
575 Q_EMIT line->setter()->problemDetected(QString("Var %1 does not have the same number of elts than others !").arg(line->getName()));
583 ////////////////////////////
585 YDFXGUISeqInit::YDFXGUISeqInit(QWidget *parent, YACSEvalYFXWrap *efx):QWidget(parent),_zeWidget(0)
587 QVBoxLayout *verticalLayout(new QVBoxLayout(this));
588 QFrame *frame(new QFrame(this));
589 frame->setFrameStyle(QFrame::Panel | QFrame::Sunken);
590 verticalLayout->addWidget(frame);
591 QHBoxLayout *horizontalLayout2(new QHBoxLayout(frame));
592 QScrollArea *sa(new QScrollArea(frame));
593 horizontalLayout2->addWidget(sa);
594 _zeWidget=new YDFXGUISeqInitEff(sa,efx);
595 sa->setWidgetResizable(true);
596 sa->setWidget(_zeWidget);
598 QHBoxLayout *horizontalLayout(new QHBoxLayout);
599 QSpacerItem *si(new QSpacerItem(40,20,QSizePolicy::Expanding,QSizePolicy::Minimum));
600 YDFXGUIStatus *statusInfo(new YDFXGUIStatus(this));
601 _zeWidget->connectToStatus(statusInfo);
602 connect(_zeWidget,SIGNAL(configurationIsOK(bool)),statusInfo,SLOT(declareOK(bool)));
603 QPushButton *button(new QPushButton(this));
604 button->setText("Check");
605 QPushButton *button2(new QPushButton(this));
606 button2->setText("Assign !");
607 connect(_zeWidget,SIGNAL(configurationIsOK(bool)),button2,SLOT(setEnabled(bool)));
608 connect(button2,SIGNAL(clicked(bool)),_zeWidget,SLOT(applyOnEFX()));
609 connect(button2,SIGNAL(clicked(bool)),this,SIGNAL(assignButtonClicked()));
610 horizontalLayout->addWidget(statusInfo);
611 horizontalLayout->addItem(si);
612 horizontalLayout->addWidget(button);
613 horizontalLayout->addWidget(button2);
614 connect(button,SIGNAL(pressed()),_zeWidget,SLOT(assignButtonClicked()));
615 button2->setEnabled(false);
617 verticalLayout->addLayout(horizontalLayout);
620 void YDFXGUISeqInit::loadState(const QMap<QString,QString>& state)
622 _zeWidget->loadState(state);
625 QMap<QString,QString> YDFXGUISeqInit::saveState() const
627 return _zeWidget->saveState();