Salome HOME
Copyright update 2022
[modules/yacs.git] / src / ydfx_gui / YDFXGUIPushButtons.cxx
1 // Copyright (C) 2016-2022  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "YDFXGUIPyThreadSaver.hxx"
22 #include "YDFXGUIPushButtons.hxx"
23
24 #include "YDFXGUIWrap.hxx"
25 #include "YDFXGUISeqInit.hxx"
26 #include "YDFXGUIHostParametrizer.hxx"
27
28 #include "YACSEvalSession.hxx"
29 #include "YACSEvalObserver.hxx"
30 #include "YACSEvalResource.hxx"
31 #include "YACSEvalExecParams.hxx"
32
33 #include "Exception.hxx"
34
35 #include <QPainter>
36 #include <QVBoxLayout>
37 #include <QApplication>
38 #include <QStackedLayout>
39 #include <QDialogButtonBox>
40
41 /////////////
42
43 YDFXGUIPushButton1::YDFXGUIPushButton1(QWidget *parent, YACSEvalYFXWrap *efx, YDFXGUIAllPorts *ports):QPushButton(parent),_efx(efx),_ports(ports)
44 {
45   setEnabled(false);
46 }
47
48 /////////////
49
50 YDFXGUIResourcePushButton::YDFXGUIResourcePushButton(QWidget *parent, YACSEvalYFXWrap *efx, YDFXGUIAllPorts *ports):YDFXGUIPushButton1(parent,efx,ports)
51 {
52   setText("Assign Resources");
53   connect(this,SIGNAL(clicked(bool)),this,SLOT(resourceAssignmentRequested()));
54   connect(efx,SIGNAL(runSignal(bool)),this,SLOT(setHidden(bool)));
55 }
56
57 void YDFXGUIResourcePushButton::resourceAssignmentRequested()
58 {
59   QDialog dial(this);
60   QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
61   sizePolicy.setHorizontalStretch(0);
62   sizePolicy.setVerticalStretch(0);
63   sizePolicy.setHeightForWidth(dial.sizePolicy().hasHeightForWidth());
64   dial.setSizePolicy(sizePolicy);
65   QVBoxLayout *vbox(new QVBoxLayout(&dial));
66   YDFXGUIHostParametrizer *param(new YDFXGUIHostParametrizer(&dial,_efx));
67   QObject::connect(param->getDialogButtonBox(),SIGNAL(accepted()),&dial,SLOT(accept()));
68   QObject::connect(param->getDialogButtonBox(),SIGNAL(rejected()),&dial,SLOT(reject()));
69   vbox->addWidget(param);
70   param->loadFromSettings(_settings);
71   if(dial.exec())
72     {
73       param->applyToEFX();
74       param->learnSettings(_settings);
75     }
76 }
77
78 /////////////
79
80 YDFXGUISeqInitButton::YDFXGUISeqInitButton(QWidget *parent, YACSEvalYFXWrap *efx, YDFXGUIAllPorts *ports):YDFXGUIPushButton1(parent,efx,ports)
81 {
82   setText("Init sequences");
83   connect(this,SIGNAL(clicked(bool)),this,SLOT(sequenceInitRequested()));
84   connect(efx,SIGNAL(runSignal(bool)),this,SLOT(setHidden(bool)));
85 }
86
87 void YDFXGUISeqInitButton::sequenceInitRequested()
88 {
89   QDialog dial(this);
90   YDFXGUISeqInit *zeWidget(new YDFXGUISeqInit(&dial,_efx));
91   zeWidget->loadState(_state);
92   QVBoxLayout *mainLayout(new QVBoxLayout(&dial));
93   mainLayout->addWidget(zeWidget);
94   QObject::connect(zeWidget,SIGNAL(assignButtonClicked()),&dial,SLOT(accept()));
95   if(dial.exec())
96     {
97       _state=zeWidget->saveState();
98       Q_EMIT sequenceWellDefined(true);
99     }
100 }
101
102 /////////////
103
104 YDFXGUIRunInfo::YDFXGUIRunInfo(QObject *parent, int nbOfItems):QObject(parent),_computationInProgress(false),_items(nbOfItems,0)
105 {
106 }
107
108 void YDFXGUIRunInfo::startComputation()
109 {
110   _mut.lock();
111   std::fill(_items.begin(),_items.end(),0);
112   _computationInProgress=true;
113   _mut.unlock();
114   Q_EMIT somethingChanged();
115 }
116
117 void YDFXGUIRunInfo::endComputation()
118 {
119   _mut.lock();
120   _computationInProgress=false;
121   _mut.unlock();
122   Q_EMIT somethingChanged();
123 }
124
125 void YDFXGUIRunInfo::sampleOK(int pos)
126 {
127   _mut.lock();
128   _items[pos]=1;
129   _mut.unlock();
130   Q_EMIT somethingChanged();
131 }
132
133 void YDFXGUIRunInfo::sampleKO(int pos)
134 {
135   _mut.lock();
136   _items[pos]=2;
137   _mut.unlock();
138   Q_EMIT somethingChanged();
139 }
140
141 std::vector<char> YDFXGUIRunInfo::getItems() const
142 {
143   std::vector<char> ret;
144   _mut.lock();
145   ret=_items;
146   _mut.unlock();
147   return ret;
148 }
149
150 int YDFXGUIRunInfo::getNbOfItems() const
151 {
152   _mut.lock();
153   int ret(_items.size());
154   _mut.unlock();
155   return ret;
156 }
157
158 void YDFXGUIRunInfo::setNbOfItems(int nbOfItems)
159 {
160   _items.resize(nbOfItems);
161   std::fill(_items.begin(),_items.end(),0);
162 }
163
164 bool YDFXGUIRunInfo::getComputationStatus() const
165 {
166   _mut.lock();
167   bool ret(_computationInProgress);
168   _mut.unlock();
169   return ret;
170 }
171
172 /////////////
173
174 class MyObserver : public YACSEvalObserver
175 {
176 public:
177   MyObserver(YDFXGUIRunInfo *info):_info(info) { }
178   void startComputation(YACSEvalYFX *sender)
179   {
180     //std::cerr << " Start ! " << _info->getNbOfItems() << std::endl;
181   }
182   void notifySampleOK(YACSEvalYFX *sender, int sampleId)
183   {
184     _info->sampleOK(sampleId);
185     //std::cerr << "sample OK = " << sampleId << std::endl;
186   }
187   void notifySampleKO(YACSEvalYFX *sender, int sampleId)
188   {
189     _info->sampleKO(sampleId);
190     //std::cerr << "sample KO = " << sampleId << std::endl;
191   }
192 private:
193   YDFXGUIRunInfo *_info;
194 };
195
196 /////////////
197
198 YDFXGUIRunThread::YDFXGUIRunThread(QObject *parent, YACSEvalYFXWrap *efx, YACSEvalSession *session, YDFXGUIRunInfo *info):QThread(parent),_efx(efx),_session(session),_info(info),_ret0(false),_ret1(-1)
199 {
200   _session->setForcedPyThreadSavedStatus(true);
201 }
202
203 void YDFXGUIRunThread::run()
204 {
205   YDFXGUIPyThreadSaver::SaveContext(this);
206   _efx->getParams()->setStopASAPAfterErrorStatus(false);
207   MyObserver *obs(new MyObserver(_info));
208   _efx->registerObserver(obs);
209   obs->decrRef();
210   _ret0=_efx->run(_session,_ret1);
211 }
212
213 YDFXGUIRunThread::~YDFXGUIRunThread()
214 {
215 }
216
217 bool YDFXGUIRunThread::getReturns(int& ret1) const
218 {
219   ret1=_ret1;
220   return _ret0;
221 }
222
223 /////////////
224
225 YDFXGUIRunningButton::YDFXGUIRunningButton(QWidget *parent):QPushButton(parent)
226 {
227   setText("Run !");
228   int dummy;
229   YACSEvalYFXWrap *efx(getEFX());
230   setEnabled(ComputeStateRes(efx,dummy) && ComputeStateSeq(efx));
231   connect(this,SIGNAL(clicked()),this,SLOT(runWizardSlot()));
232 }
233
234 YACSEvalYFXWrap *YDFXGUIRunningButton::getEFX()
235 {
236   YDFXGUIRunButton *parentc(qobject_cast<YDFXGUIRunButton *>(parent()));
237   if(!parentc)
238     return 0;
239   return parentc->getEFX();
240 }
241
242 YDFXGUIRunInfo *YDFXGUIRunningButton::getInfo()
243 {
244   YDFXGUIRunButton *parentc(qobject_cast<YDFXGUIRunButton *>(parent()));
245   if(!parentc)
246     return 0;
247   return parentc->getInfo();
248 }
249
250 YACSEvalSession *YDFXGUIRunningButton::getSess()
251 {
252   YDFXGUIRunButton *parentc(qobject_cast<YDFXGUIRunButton *>(parent()));
253   if(!parentc)
254     return 0;
255   return parentc->getSess();
256 }
257
258 YDFXGUIRunThread *YDFXGUIRunningButton::getThread()
259 {
260   YDFXGUIRunButton *parentc(qobject_cast<YDFXGUIRunButton *>(parent()));
261   if(!parentc)
262     return 0;
263   return parentc->getThread();
264 }
265
266 /////////////
267
268 YDFXGUIMachineDialog::YDFXGUIMachineDialog(QWidget *parent):QDialog(parent)
269 {
270 }
271
272 void YDFXGUIMachineDialog::interactivityStatusChanged(bool)
273 {
274   QSize sz1(_wid->minimumSizeHint()),sz2(_wid->sizeHint());
275   QMargins marg(layout()->contentsMargins());
276   int delta(marg.top()+marg.bottom());
277   setMinimumHeight(sz1.height()+delta);
278   setMaximumHeight(sz2.height()+delta);
279 }
280
281 /////////////
282
283 void YDFXGUIRunningButton::runWizardSlot()
284 {
285   YDFXGUIMachineDialog dial(this);
286   QGridLayout *mainLayout(new QGridLayout(&dial));
287   YDFXGUIHostParametrizer *zeWidget(new YDFXGUIHostParametrizer(&dial,getEFX()));
288   dial.setWidget(zeWidget);
289   dial.interactivityStatusChanged(true);
290   connect(zeWidget,SIGNAL(interactivityChanged(bool)),&dial,SLOT(interactivityStatusChanged(bool)));
291   mainLayout->addWidget(zeWidget);
292   connect(zeWidget->getDialogButtonBox(),SIGNAL(accepted()),&dial,SLOT(accept()));
293   connect(zeWidget->getDialogButtonBox(),SIGNAL(rejected()),&dial,SLOT(reject()));
294   if(dial.exec())
295     {
296       getEFX()->lockPortsForEvaluation();
297       zeWidget->applyToEFX();
298       getInfo()->setNbOfItems(getEFX()->getNbOfItems());
299       runEvaluation();
300     }
301 }
302
303 void YDFXGUIRunningButton::runEvaluation()
304 {
305   if(!getSess()->isLaunched())
306     getSess()->launch();
307 #if PY_VERSION_HEX < 0x03070000
308   if(!PyEval_ThreadsInitialized())
309     PyEval_InitThreads();
310 #endif
311   connect(getThread(),SIGNAL(finished()),this,SLOT(evaluationFinished()));
312   setEnabled(false);
313   getThread()->start();
314 }
315
316 void YDFXGUIRunningButton::evaluationFinished()
317 {
318   YACSEvalYFXWrap *efx(getEFX());
319   int dummy;
320   setEnabled(ComputeStateRes(efx,dummy) && ComputeStateSeq(efx));
321 }
322
323 bool YDFXGUIRunningButton::ComputeStateRes(YACSEvalYFXWrap *efx, int& nbOfSamples)
324 {
325   return efx->computeSequencesStatus(nbOfSamples);
326 }
327
328 bool YDFXGUIRunningButton::ComputeStateSeq(YACSEvalYFXWrap *efx)
329 {
330   bool isOKForDef(true);
331   try
332     {
333       efx->giveResources()->checkOKForRun();
334     }
335   catch(YACS::Exception& e)
336     {
337       isOKForDef=false;
338     }
339   return isOKForDef;
340 }
341
342 /////////////////////
343
344 YDFXGUIRunningPB::YDFXGUIRunningPB(QWidget *parent, YDFXGUIRunInfo *info):QWidget(parent),_info(info)
345 {
346 }
347
348 void YDFXGUIRunningPB::paintEvent(QPaintEvent *event)
349 {
350   const int SZ_OF_PEN_RECT=2;
351   QPainter painter(this);
352   QRect refRect(rect());
353   QRect refRect2(refRect);//event->rect());
354   painter.setPen(QPen(Qt::black,SZ_OF_PEN_RECT,Qt::SolidLine));//,Qt::RoundCap));
355   refRect2.translate(SZ_OF_PEN_RECT,SZ_OF_PEN_RECT);
356   refRect2.setWidth(refRect2.width()-2*SZ_OF_PEN_RECT);;
357   refRect2.setHeight(refRect2.height()-2*SZ_OF_PEN_RECT);
358   painter.drawRect(refRect2);
359   //
360   std::vector<char> items(_info->getItems());
361   int nbOfItems(items.size());
362   //
363   float xFact(float(refRect.width()-3.5*SZ_OF_PEN_RECT)/float(nbOfItems));
364   //
365   QPalette pal(QApplication::palette("QPushButton"));
366   QColor color(pal.color(QPalette::Window)),color2;
367   painter.setPen(QPen(color,0));
368   for(int ii=0;ii<nbOfItems;)
369     {
370       for(;ii<nbOfItems && items[ii]==0;ii++);
371       if(ii==nbOfItems)
372         continue;
373       int ref(items[ii]),start(ii);
374       for(;ii<nbOfItems && items[ii]==ref;ii++);
375       int endd(ii);
376       if(ref==1)
377         color2=Qt::green;
378       else
379         color2=Qt::red;
380       QBrush brush(color2);
381       painter.setBrush(brush);
382       painter.setPen(QPen(color2,0));
383       float xs(float(start)*xFact+1.5f*SZ_OF_PEN_RECT);
384       float xe(float(endd)*xFact+1.5f*SZ_OF_PEN_RECT);
385       painter.drawRect(QRectF(xs,1.5f*SZ_OF_PEN_RECT,xe-xs,refRect.height()-3.5f*SZ_OF_PEN_RECT));
386     }
387   int nbOfEltsDone(nbOfItems-std::count(items.begin(),items.end(),0));
388   QString txt(QString("%1/%2 (%3%)").arg(nbOfEltsDone).arg(nbOfItems).arg(float(nbOfEltsDone)/float(nbOfItems)*100.f,0,'f',0));
389   QFont ft(font());
390   ft.setBold(true);
391   QFontMetrics fm(ft);
392   QSize refRect3(fm.boundingRect(txt).size());
393   painter.setFont(ft);
394   painter.setPen(QPen(Qt::black));
395   painter.drawText(QPoint((refRect.width()-refRect3.width())/2,refRect.height()/2+refRect3.height()/2-fm.descent()),txt);
396 }
397
398 QSize YDFXGUIRunningPB::sizeHint() const
399 {
400   int width(3*_info->getNbOfItems());
401   width=std::max(width,50);
402   width=std::min(width,150);
403   return QSize(width,15);
404 }
405
406 QSize YDFXGUIRunningPB::minimumSizeHint() const
407 {
408   int width(3*_info->getNbOfItems());
409   width=std::max(width,50);
410   width=std::min(width,120);
411   return sizeHint();
412 }
413
414 /////////////
415
416 YDFXGUIRunButton::YDFXGUIRunButton(QWidget *parent, YACSEvalSession *session, YACSEvalYFXWrap *efx):QWidget(parent),_info(new YDFXGUIRunInfo(this,0)),_th(new YDFXGUIRunThread(this,efx,session,_info)),_push(new YDFXGUIRunningButton(this)),_pb(new YDFXGUIRunningPB(this,_info))
417 {
418   QVBoxLayout *mainLayout(new QVBoxLayout(this));
419   mainLayout->addWidget(_pb);
420   mainLayout->addWidget(_push);
421   _pb->hide();
422   _push->setEnabled(false);
423   //
424   connect(getThread(),SIGNAL(started()),_info,SLOT(startComputation()));
425   connect(getThread(),SIGNAL(finished()),_info,SLOT(endComputation()));
426   //
427   connect(_info,SIGNAL(somethingChanged()),this,SLOT(update()));
428   connect(_info,SIGNAL(somethingChanged()),_pb,SLOT(update()));
429 }
430
431 QSize YDFXGUIRunButton::sizeHint() const
432 {
433   QSize sz,sz2(QWidget::sizeHint());
434   if(_info->getComputationStatus())
435     sz=_pb->sizeHint();
436   else
437     sz=_push->sizeHint();
438   sz.rwidth()+=sz2.rwidth();
439   sz.rheight()+=sz2.rheight();
440   return sz;
441 }
442
443 QSize YDFXGUIRunButton::minimumSizeHint() const
444 {
445   QSize sz,sz2(QWidget::minimumSizeHint());
446   if(_info->getComputationStatus())
447     sz=_pb->minimumSizeHint();
448   else
449     sz=_push->minimumSizeHint();
450   sz.rwidth()+=sz2.rwidth();
451   sz.rheight()+=sz2.rheight();
452   return sz;
453 }
454
455 void YDFXGUIRunButton::update()
456 {
457   bool stat(_info->getComputationStatus());
458   _pb->setVisible(stat);
459   _push->setHidden(stat);
460   QWidget::update();
461 }
462
463 void YDFXGUIRunButton::setEnabled(bool status)
464 {
465   _push->setEnabled(status);
466   QWidget::setEnabled(status);
467 }
468
469 void YDFXGUIRunButton::setDisabled(bool status)
470 {
471   _push->setDisabled(status);
472   QWidget::setEnabled(status);
473 }