Salome HOME
6feef6fbd1aa5522b5462f036b4842d1040039e8
[modules/yacs.git] / src / genericgui / ItemEdition.cxx
1 // Copyright (C) 2006-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
20 #include "ItemEdition.hxx"
21 #include "EditionProc.hxx"
22 #include "EditionBloc.hxx"
23 #include "EditionComponent.hxx"
24 #include "EditionContainer.hxx"
25 #include "EditionControlLink.hxx"
26 #include "EditionDataLink.hxx"
27 #include "EditionDataType.hxx"
28 #include "EditionElementaryNode.hxx"
29 #include "EditionForEachLoop.hxx"
30 #include "EditionOptimizerLoop.hxx"
31 #include "EditionInputPort.hxx"
32 #include "EditionLoop.hxx"
33 #include "EditionWhile.hxx"
34 #include "EditionOutNode.hxx"
35 #include "EditionOutputPort.hxx"
36 #include "EditionPresetNode.hxx"
37 #include "EditionPyFunc.hxx"
38 #include "EditionSalomeNode.hxx"
39 #include "EditionScript.hxx"
40 #include "EditionStudyInNode.hxx"
41 #include "EditionStudyOutNode.hxx"
42 #include "EditionSwitch.hxx"
43
44 #include "QtGuiContext.hxx"
45 #include "TypeCode.hxx"
46 #include "commandsProc.hxx"
47
48 #include <QLineEdit>
49 #include <QLabel>
50 #include <QPushButton>
51 #include <QLayout>
52
53
54 //#define _DEVDEBUG_
55 #include "YacsTrace.hxx"
56
57 #include <string>
58 #include <cassert>
59
60 using namespace std;
61
62 using namespace YACS;
63 using namespace YACS::HMI;
64
65
66 /*! get name and strings for type of item and category
67  */
68 ItemEditionBase::ItemEditionBase(Subject* subject)
69   : GuiObserver(), _subject(subject)
70 {
71   _subject->attach(this);
72   _stackId = -1;
73   _name = _subject->getName();
74   _type = "Unknown";
75   _category = "Unknown";
76   ProcInvoc* invoc = QtGuiContext::getQtCurrent()->getInvoc();
77   if (SubjectNode * sub = dynamic_cast<SubjectNode*>(_subject))
78     {
79       _category = "Node";
80       _type = invoc->getTypeName(invoc->getTypeOfNode(sub->getNode()));
81     }
82   else if (SubjectDataPort * sub = dynamic_cast<SubjectDataPort*>(_subject))
83     {
84       _category = "Port";
85       _type = invoc->getTypeName(invoc->getTypeOfPort(sub->getPort()));
86     }
87   else if (SubjectLink * sub = dynamic_cast<SubjectLink*>(_subject))
88     {
89       _category = "Link";
90       _type = "Link";
91     }
92   else if (SubjectControlLink * sub = dynamic_cast<SubjectControlLink*>(_subject))
93     {
94       _category = "ControlLink";
95       _type = "Control Link";
96     }
97   else if (SubjectDataType * sub = dynamic_cast<SubjectDataType*>(_subject))
98     {
99       _category = "Data";
100       switch (sub->getTypeCode()->kind())
101         {
102         case YACS::ENGINE::Double:   _type = "Double"; break;
103         case YACS::ENGINE::Int:      _type = "Int"; break;
104         case YACS::ENGINE::String:   _type = "String"; break;
105         case YACS::ENGINE::Bool:     _type = "Bool"; break;
106         case YACS::ENGINE::Objref:   _type = "Objref"; break;
107         case YACS::ENGINE::Sequence: _type = "Sequence"; break;
108         case YACS::ENGINE::Array:    _type = "Array"; break;
109         case YACS::ENGINE::Struct:   _type = "Struct"; break;
110         default: _type = "None or Unknown";
111         }
112     }
113   else if (SubjectComponent * sub = dynamic_cast<SubjectComponent*>(_subject))
114     {
115       _category = "Component";
116       _type = "Salome Component";
117     }
118   else if (SubjectContainerBase * sub = dynamic_cast<SubjectContainerBase*>(_subject))
119     {
120       _category = "Container";
121       _type = sub->getLabelForHuman();
122     }
123 }
124
125 ItemEditionBase::~ItemEditionBase()
126 {
127 }
128
129 void ItemEditionBase::select(bool isSelected)
130 {
131   DEBTRACE("ItemEditionBase::select " << isSelected);
132 }
133
134 void ItemEditionBase::synchronize()
135 {
136 }
137
138 void ItemEditionBase::update(GuiEvent event, int type, Subject* son)
139 {
140 }
141
142 Subject* ItemEditionBase::getSubject()
143 {
144   return _subject;
145 }
146
147 /*! generic item edition based on a FormEditItem widget to be completed 
148  *  in derived classes. Apply - cancel edition buttons are not always
149  *  relevants.
150  */
151 ItemEdition::ItemEdition(Subject* subject,
152                          QWidget* parent,
153                          const char* name)
154   : FormEditItem(parent), ItemEditionBase(subject)
155 {
156   DEBTRACE("ItemEdition::ItemEdition " << name);
157
158   _haveScript = false;
159   _isEdited = false;
160   setEdited(false);
161
162   connect(_wid->pb_apply, SIGNAL(clicked()), this, SLOT(onApply()));
163   connect(_wid->pb_cancel, SIGNAL(clicked()), this, SLOT(onCancel()));
164
165   // --- type of item and name
166
167   _wid->la_type->setText(_type.c_str());
168   _wid->le_name->setText(_name.c_str());
169   connect(_wid->le_name, SIGNAL(textChanged(const QString&)),
170           this, SLOT(onModifyName(const QString&)));
171   _wid->le_name->setReadOnly(true); // to be changed on derived classes depending on context
172
173   _stackId = QtGuiContext::getQtCurrent()->getStackedWidget()->addWidget(this);
174   DEBTRACE("_stackId " << _stackId);
175   YASSERT(!QtGuiContext::getQtCurrent()->_mapOfEditionItem.count(_subject));
176   QtGuiContext::getQtCurrent()->_mapOfEditionItem[_subject] = this;
177   //QtGuiContext::getQtCurrent()->getStackedWidget()->raiseWidget(_stackId);
178 }
179
180 ItemEdition::~ItemEdition()
181 {
182   DEBTRACE("ItemEdition::~ItemEdition " << _name);
183   if(QtGuiContext::getQtCurrent())
184     {
185       DEBTRACE("---");
186       QtGuiContext::getQtCurrent()->getStackedWidget()->removeWidget(this);
187       QtGuiContext::getQtCurrent()->_mapOfEditionItem.erase(_subject);
188       DEBTRACE("---");
189     }
190 }
191
192 /*! used in derived nodes for synchronisation with schema model.
193  */
194 void ItemEdition::synchronize()
195 {
196 }
197
198 void ItemEdition::select(bool isSelected)
199 {
200   DEBTRACE("ItemEdition::select " << isSelected);
201   if (isSelected)
202     {
203       synchronize();
204       QtGuiContext::getQtCurrent()->getStackedWidget()->setCurrentWidget(this);
205     }
206 }
207
208 void ItemEdition::setName(std::string name)
209 {
210   _name = name;
211   setEdited(false);
212 }
213
214 void ItemEdition::onApply()
215 {
216   DEBTRACE("onApply");
217   string name = _wid->le_name->text().toStdString();
218   name = filterName(name);
219   bool nameEdited = false;
220   if (name != _name)
221     {
222       nameEdited = true;
223       bool ret = _subject->setName(name);
224       if (ret)
225         {
226           nameEdited = false;
227           _name = name;
228         }
229     }
230   DEBTRACE(_isEdited << " " << nameEdited);
231   _isEdited = nameEdited;
232   setEdited(_isEdited);
233 }
234
235 void ItemEdition::onCancel()
236 {
237   DEBTRACE("onCancel");
238   _wid->le_name->setText(_name.c_str());
239   setEdited(false);
240 }
241
242 std::string ItemEdition::filterName(const std::string& name)
243 {
244   string nameFiltered;
245   nameFiltered = "";
246   for (int i= 0; i< name.size(); i++)
247     {
248       unsigned char a = (unsigned char)(name[i]);
249       if (   ((a >= '0') && (a <= '9'))
250           || ((a >= 'A') && (a <= 'Z'))
251           || ((a >= 'a') && (a <= 'z'))
252           || ( a == '_'))
253         nameFiltered += a;
254     }
255   DEBTRACE(name << " " << nameFiltered);
256   return nameFiltered;
257 }
258
259 void ItemEdition::onModifyName(const QString &text)
260 {
261   if (_name != text.toStdString()) setEdited(true);
262 }
263
264 void ItemEdition::setEdited(bool isEdited)
265 {
266   DEBTRACE("ItemEdition::setEdited " << isEdited);
267   if (isEdited)
268     {
269       QtGuiContext::getQtCurrent()->_setOfModifiedSubjects.insert(_subject);
270       _subject->update(EDIT, 1, _subject);
271       if (QtGuiContext::getQtCurrent()->getSubjectProc())
272         QtGuiContext::getQtCurrent()->getSubjectProc()->update(EDIT, 1, _subject);
273     }
274   else
275     {
276       QtGuiContext::getQtCurrent()->_setOfModifiedSubjects.erase(_subject);
277       _subject->update(EDIT, 0, _subject);
278       if (QtGuiContext::getQtCurrent()->_setOfModifiedSubjects.empty() && QtGuiContext::getQtCurrent()->getSubjectProc())
279         QtGuiContext::getQtCurrent()->getSubjectProc()->update(EDIT, 0, _subject);
280     }
281
282   SchemaModel *model = QtGuiContext::getQtCurrent()->getSchemaModel();
283   SchemaItem* schemaItem = QtGuiContext::getQtCurrent()->_mapOfSchemaItem[_subject];
284   if (schemaItem)
285     {
286       QModelIndex index = schemaItem->modelIndex();
287       model->setData(index, QVariant()); // just to emit dataChanged signal
288     }
289   
290   _wid->pb_apply->setEnabled(isEdited);
291   _wid->pb_cancel->setEnabled(isEdited);
292 }
293
294 /*! when loading a schema, creation of all edition widgets is time and memory consuming,
295  *  so, widget edition creation is differed until user select an item in tree
296  *  or 2D vue.
297  */ 
298 void ItemEdition::update(GuiEvent event, int type, Subject* son)
299 {
300   DEBTRACE("ItemEdition::update " <<eventName(event) << " " << type);
301   if (QtGuiContext::getQtCurrent()->isLoading())
302     {
303       // --- create only EditionProc while loading to store status
304       if (event == NEWROOT)
305         ItemEdition *item =  new EditionProc(son,
306                                              QtGuiContext::getQtCurrent()->getStackedWidget(),
307                                              son->getName().c_str());
308       return;
309     }
310
311   ItemEdition *item = 0;
312   switch (event)
313     {
314     case NEWROOT:
315       item =  new EditionProc(son,
316                               QtGuiContext::getQtCurrent()->getStackedWidget(),
317                               son->getName().c_str());
318       break;
319     case ADD:
320       switch (type)
321         {
322         case YACS::HMI::SALOMEPROC:
323           item =  new EditionProc(son,
324                                   QtGuiContext::getQtCurrent()->getStackedWidget(),
325                                   son->getName().c_str());
326           break;
327         case YACS::HMI::BLOC:
328           item =  new EditionBloc(son,
329                                   QtGuiContext::getQtCurrent()->getStackedWidget(),
330                                   son->getName().c_str());
331           break;
332         case YACS::HMI::FOREACHLOOP:
333           item =  new EditionForEachLoop(son,
334                                          QtGuiContext::getQtCurrent()->getStackedWidget(),
335                                          son->getName().c_str());
336           break;
337         case YACS::HMI::OPTIMIZERLOOP:
338           item =  new EditionOptimizerLoop(son, QtGuiContext::getQtCurrent()->getStackedWidget(),
339                                            son->getName().c_str());
340           break;
341         case YACS::HMI::FORLOOP:
342           item =  new EditionLoop(son,
343                                   QtGuiContext::getQtCurrent()->getStackedWidget(),
344                                   son->getName().c_str());
345           break;
346         case YACS::HMI::WHILELOOP:
347           item =  new EditionWhile(son,
348                                    QtGuiContext::getQtCurrent()->getStackedWidget(),
349                                    son->getName().c_str());
350           break;
351         case YACS::HMI::SWITCH:
352           item =  new EditionSwitch(son,
353                                     QtGuiContext::getQtCurrent()->getStackedWidget(),
354                                     son->getName().c_str());
355           break;
356         case YACS::HMI::PYTHONNODE:
357           item =  new EditionScript(son,
358                                     QtGuiContext::getQtCurrent()->getStackedWidget(),
359                                     son->getName().c_str());
360           break;
361         case YACS::HMI::PYFUNCNODE:
362           item =  new EditionPyFunc(son,
363                                     QtGuiContext::getQtCurrent()->getStackedWidget(),
364                                     son->getName().c_str());
365           break;
366         case YACS::HMI::CORBANODE:
367         case YACS::HMI::SALOMENODE:
368           item =  new EditionSalomeNode(son,
369                                         QtGuiContext::getQtCurrent()->getStackedWidget(),
370                                         son->getName().c_str());
371           break;
372         case YACS::HMI::PRESETNODE:
373           item =  new EditionPresetNode(son,
374                                         QtGuiContext::getQtCurrent()->getStackedWidget(),
375                                         son->getName().c_str());
376           break;
377         case YACS::HMI::OUTNODE:
378           item =  new EditionOutNode(son,
379                                      QtGuiContext::getQtCurrent()->getStackedWidget(),
380                                      son->getName().c_str());
381           break;
382         case YACS::HMI::STUDYINNODE:
383           item =  new EditionStudyInNode(son,
384                                          QtGuiContext::getQtCurrent()->getStackedWidget(),
385                                          son->getName().c_str());
386           break;
387         case YACS::HMI::STUDYOUTNODE:
388           item =  new EditionStudyOutNode(son,
389                                           QtGuiContext::getQtCurrent()->getStackedWidget(),
390                                           son->getName().c_str());
391           break;
392         case YACS::HMI::INPUTPORT:
393         case YACS::HMI::INPUTDATASTREAMPORT:
394           item =  new EditionInputPort(son,
395                                        QtGuiContext::getQtCurrent()->getStackedWidget(),
396                                        son->getName().c_str());
397           break;
398         case YACS::HMI::OUTPUTPORT:
399         case YACS::HMI::OUTPUTDATASTREAMPORT:
400           item =  new EditionOutputPort(son,
401                                         QtGuiContext::getQtCurrent()->getStackedWidget(),
402                                         son->getName().c_str());
403           break;
404         case YACS::HMI::CONTAINER:
405           item =  new EditionContainer(son,QtGuiContext::getQtCurrent()->getStackedWidget(),son->getName().c_str());
406           break;
407         case YACS::HMI::COMPONENT:
408           item =  new EditionComponent(son,
409                                        QtGuiContext::getQtCurrent()->getStackedWidget(),
410                                        son->getName().c_str());
411
412           break;
413         case YACS::HMI::DATATYPE:
414           item =  new EditionDataType(son,
415                                       QtGuiContext::getQtCurrent()->getStackedWidget(),
416                                       son->getName().c_str());
417           break;
418         case YACS::HMI::REFERENCE:
419         case YACS::HMI::CPPNODE:
420         case YACS::HMI::SALOMEPYTHONNODE:
421         case YACS::HMI::XMLNODE:
422         case YACS::HMI::SPLITTERNODE:
423         case YACS::HMI::DFTODSFORLOOPNODE:
424         case YACS::HMI::DSTODFFORLOOPNODE:
425           item =  new ItemEdition(son,
426                                   QtGuiContext::getQtCurrent()->getStackedWidget(),
427                                   son->getName().c_str());
428           break;
429         default:
430           DEBTRACE("ItemEdition::update() ADD, type not handled:" << type);
431         }
432       break;
433     case ADDLINK:
434       switch (type)
435         {
436         case YACS::HMI::DATALINK:
437           item =  new EditionDataLink(son,
438                                       QtGuiContext::getQtCurrent()->getStackedWidget(),
439                                       son->getName().c_str());
440           break;
441         default:
442           DEBTRACE("ItemEdition::update() ADDLINK, type not handled:" << type);
443         }
444       break;
445     case ADDCONTROLLINK:
446       switch (type)
447         {
448         case YACS::HMI::CONTROLLINK:
449           item =  new EditionControlLink(son,
450                                          QtGuiContext::getQtCurrent()->getStackedWidget(),
451                                          son->getName().c_str());
452           break;
453         default:
454           DEBTRACE("ItemEdition::update() ADDCONTROLLINK, type not handled:" << type);
455         }
456       break;
457     case RENAME:
458       _name = _subject->getName();
459       _wid->le_name->setText(_name.c_str());
460       break;
461     case SYNCHRO:
462       synchronize();
463       break;
464 //     default:
465 //       DEBTRACE("ItemEdition::update(), event not handled: " << eventName(event));
466     }
467 }
468
469 ItemEditionRoot::ItemEditionRoot(Subject* subject,
470                                  QWidget* parent,
471                                  const char* name)
472   : ItemEdition(subject, parent, name)
473 {
474   DEBTRACE("ItemEditionRoot::ItemEditionRoot")
475 }
476
477 ItemEditionRoot::~ItemEditionRoot()
478 {
479   _subjectSet.clear(); // --- avoid destruction loop on delete context
480 }