Salome HOME
Merge branch 'master' into omu/workloadmanager
[modules/yacs.git] / src / genericgui / SchemaComposedNodeItem.cxx
1 // Copyright (C) 2006-2020  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 <Python.h>
21
22 #include "Resource.hxx"
23 #include "SchemaComposedNodeItem.hxx"
24 #include "SchemaNodeItem.hxx"
25 #include "SchemaInPortItem.hxx"
26 #include "SchemaOutPortItem.hxx"
27 #include "SchemaComponentItem.hxx"
28 #include "SchemaContainerItem.hxx"
29 #include "SchemaDataTypeItem.hxx"
30 #include "SchemaLinkItem.hxx"
31 #include "SchemaDirTypesItem.hxx"
32 #include "SchemaDirContainersItem.hxx"
33 #include "SchemaDirLinksItem.hxx"
34 #include "Menus.hxx"
35 #include "Message.hxx"
36 #include "QtGuiContext.hxx"
37 #include "ItemMimeData.hxx"
38 #include "GuiEditor.hxx"
39 #include "RuntimeSALOME.hxx"
40 #include "Catalog.hxx"
41
42 #include "commandsProc.hxx"
43 #include "ComposedNode.hxx"
44 #include "guiObservers.hxx"
45 #include "Node.hxx"
46 #include "Switch.hxx"
47
48 #include <QIcon>
49 #include <QMimeData>
50
51 #include <cassert>
52
53 //#define _DEVDEBUG_
54 #include "YacsTrace.hxx"
55
56 using namespace std;
57 using namespace YACS::ENGINE;
58 using namespace YACS::HMI;
59
60 SchemaComposedNodeItem::SchemaComposedNodeItem(SchemaItem *parent, QString label, Subject* subject)
61   : SchemaItem(parent, label, subject)
62 {
63   DEBTRACE("SchemaComposedNodeItem::SchemaComposedNodeItem");
64   switch (subject->getType())
65     {
66     case YACS::HMI::BLOC: 
67       _itemDeco.replace(YLabel, QIcon("icons:block_node.png"));
68       break;
69     case YACS::HMI::FORLOOP: 
70     case YACS::HMI::FOREACHLOOP: 
71     case YACS::HMI::WHILELOOP: 
72     case YACS::HMI::OPTIMIZERLOOP: 
73       _itemDeco.replace(YLabel, QIcon("icons:loop_node.png"));
74       break;
75     case YACS::HMI::SWITCH: 
76       _itemDeco.replace(YLabel, QIcon("icons:switch_node.png"));
77       break;
78     default:
79       _itemDeco.replace(YLabel, QIcon("icons:block_node.png"));
80     }
81    _dirTypesItem = 0;
82   _dirContainersItem = 0;
83   _dirLinksItem = 0;
84   Subject *son = 0;
85   int nbsons = childCount();
86   SchemaModel *model = QtGuiContext::getQtCurrent()->getSchemaModel();
87
88   model->beginInsertRows(modelIndex(), nbsons, nbsons);
89   if (SubjectProc* sProc = dynamic_cast<SubjectProc*>(subject))
90     {
91       son = new Subject(getSubject());
92       _dirTypesItem = new SchemaDirTypesItem(this, "Types", son);
93       son = new Subject(getSubject());
94       _dirContainersItem = new SchemaDirContainersItem(this, "Containers", son);
95     }
96   son = new Subject(getSubject());
97   _dirLinksItem = new SchemaDirLinksItem(this, "Links", son);
98   model->endInsertRows();
99
100   if (!model->isEdition())
101     {
102       setExecState(YACS::UNDEFINED);
103     }
104
105   SubjectComposedNode *scn = dynamic_cast<SubjectComposedNode*>(subject);
106   YASSERT(scn);
107   if (scn->hasValue())
108     {
109       _itemData.replace(YType, scn->getValue().c_str());
110       model->setData(modelIndex(YType), 0);
111     }
112  
113   setCaseValue();
114 }
115
116 SchemaComposedNodeItem::~SchemaComposedNodeItem()
117 {
118   DEBTRACE("SchemaComposedNodeItem::~SchemaComposedNodeItem");
119 }
120
121 void SchemaComposedNodeItem::update(GuiEvent event, int type, Subject* son)
122 {
123   DEBTRACE("SchemaComposedNodeItem::update "<<eventName(event)<<" "<<type<<" "<<son);
124   SchemaModel *model = QtGuiContext::getQtCurrent()->getSchemaModel();
125   SchemaItem *item = 0;
126   SubjectNode *snode = 0;
127   SubjectComposedNode *scnode = 0;
128   Node* node = 0;
129   switch (event)
130     {
131     case YACS::HMI::ADD:
132       switch (type)
133         {
134         case YACS::HMI::BLOC:
135         case YACS::HMI::FORLOOP:
136         case YACS::HMI::WHILELOOP:
137         case YACS::HMI::SWITCH:
138         case YACS::HMI::FOREACHLOOP:
139         case YACS::HMI::OPTIMIZERLOOP:
140           {
141             int nbsons = childCount();
142             model->beginInsertRows(modelIndex(), nbsons, nbsons);
143             item =  new SchemaComposedNodeItem(this,
144                                                son->getName().c_str(),
145                                                son);
146             model->endInsertRows();
147           }
148           break;
149         case YACS::HMI::PYTHONNODE:
150         case YACS::HMI::PYFUNCNODE:
151         case YACS::HMI::CORBANODE:
152         case YACS::HMI::CPPNODE:
153         case YACS::HMI::SALOMENODE:
154         case YACS::HMI::SALOMEPYTHONNODE:
155         case YACS::HMI::XMLNODE:
156         case YACS::HMI::PRESETNODE:
157         case YACS::HMI::OUTNODE:
158         case YACS::HMI::STUDYINNODE:
159         case YACS::HMI::STUDYOUTNODE:
160           {
161             int nbsons = childCount();
162             model->beginInsertRows(modelIndex(), nbsons, nbsons);
163             item =  new SchemaNodeItem(this,
164                                        son->getName().c_str(),
165                                        son);
166             model->endInsertRows();
167           }
168           break;
169         case YACS::HMI::INPUTPORT:
170         case YACS::HMI::INPUTDATASTREAMPORT:
171           {
172             int nbsons = childCount();
173             model->beginInsertRows(modelIndex(), nbsons, nbsons);
174             item =  new SchemaInPortItem(this,
175                                          son->getName().c_str(),
176                                          son);
177             model->endInsertRows();
178           }
179           break;
180         case YACS::HMI::OUTPUTPORT:
181         case YACS::HMI::OUTPUTDATASTREAMPORT:
182           {
183             int nbsons = childCount();
184             model->beginInsertRows(modelIndex(), nbsons, nbsons);
185             item =  new SchemaOutPortItem(this,
186                                           son->getName().c_str(),
187                                           son);
188             model->endInsertRows();
189           }
190           break;
191         case YACS::HMI::COMPONENT:
192           {
193             YASSERT(_dirContainersItem);
194             _dirContainersItem->addComponentItem(son);
195           }
196           break;
197         case YACS::HMI::CONTAINER:
198           {
199             YASSERT(_dirContainersItem);
200             _dirContainersItem->addContainerItem(son);
201           }
202           break;
203         case YACS::HMI::DATATYPE:
204           {
205             YASSERT(_dirTypesItem);
206             _dirTypesItem->addTypeItem(son);
207           }
208           break;
209         }
210       break;
211
212     case YACS::HMI::REMOVE:
213       switch (type)
214         {
215         case YACS::HMI::DATATYPE:
216           {
217             YASSERT(_dirTypesItem);
218             _dirTypesItem->removeTypeItem(son);
219           }
220           break;
221         }
222       break;
223
224     case YACS::HMI::UPDATE:
225       snode = dynamic_cast<SubjectNode*>(_subject);
226       YASSERT(snode);
227       node = snode->getNode();
228       YASSERT(node);
229       switch (node->getState())
230         {
231         case YACS::INVALID:
232           _itemForeground.replace(YLabel, QColor("red"));
233           model->setData(modelIndex(YLabel), 0);
234           break;
235         case YACS::READY:
236           _itemForeground.replace(YLabel, QColor("blue"));
237           model->setData(modelIndex(YLabel), 0);
238               break;
239         default:
240           break;
241         }
242       break;
243     case YACS::HMI::ADDLINK:
244     case YACS::HMI::ADDCONTROLLINK:
245           {
246             YASSERT(_dirLinksItem);
247             _dirLinksItem->addLinkItem(son);
248           }
249       break;
250     case YACS::HMI::UPDATEPROGRESS:
251       setExecState(type);
252       model->setData(modelIndex(YState), 0);
253       break;
254     case YACS::HMI::SETVALUE:
255       scnode = dynamic_cast<SubjectComposedNode*>(_subject);
256       if (scnode->hasValue())
257         {
258           _itemData.replace(YType, scnode->getValue().c_str());
259           model->setData(modelIndex(YType), 0);
260         }
261     case YACS::HMI::SETCASE:
262       {
263         SubjectSwitch *sSwitch = dynamic_cast<SubjectSwitch*>(_subject);
264         if (sSwitch)
265           {
266             Switch *aSwitch = dynamic_cast<Switch*>(sSwitch->getNode());
267             Node *node = aSwitch->edGetNode(type);
268             if (node)
269               {
270                 if (GuiContext::getCurrent()->_mapOfSubjectNode.count(node))
271                   {
272                     Subject* sub = GuiContext::getCurrent()->_mapOfSubjectNode[node];
273                     if (QtGuiContext::getQtCurrent()->_mapOfSchemaItem.count(sub))
274                       {
275                         SchemaItem* item = QtGuiContext::getQtCurrent()->_mapOfSchemaItem[sub];
276                         item->setCaseValue();
277                       }
278                   }
279               }
280           }
281       }
282       break;
283     case YACS::HMI::SETSELECT:
284       {
285         SubjectSwitch *sSwitch = dynamic_cast<SubjectSwitch*>(_subject);
286         if (sSwitch && sSwitch->hasValue())
287           {
288             _itemData.replace(YType, sSwitch->getValue().c_str());
289             model->setData(modelIndex(YType), 0);
290           }
291       }
292       break;
293     case YACS::HMI::CUT:
294       {
295         SchemaItem *toMove = QtGuiContext::getQtCurrent()->_mapOfSchemaItem[son];
296         int position = toMove->row();
297         model->beginRemoveRows(modelIndex(), position, position);
298         removeChild(toMove);
299         model->endRemoveRows();
300       }
301       break;
302     case YACS::HMI::PASTE:
303       {
304         SchemaItem *toPaste = QtGuiContext::getQtCurrent()->_mapOfSchemaItem[son];
305         int nbsons = childCount();
306         model->beginInsertRows(modelIndex(), nbsons, nbsons);
307         toPaste->reparent(this);
308         model->endInsertRows();
309       }
310       break;
311     default:
312       //DEBTRACE("SchemaComposedNodeItem::update(), event not handled: "<< eventName(event));
313       SchemaItem::update(event, type, son);
314     }
315 }
316
317 std::list<YACS::ENGINE::Node*> SchemaComposedNodeItem::getDirectDescendants() const
318 {
319   SubjectNode* SNode = dynamic_cast<SubjectNode*>(_subject);
320   YASSERT(SNode);
321   ComposedNode* CNode = dynamic_cast<ComposedNode*>(SNode->getNode());
322   YASSERT(CNode);
323   return CNode->edGetDirectDescendants();
324 }
325
326 void SchemaComposedNodeItem::popupMenu(QWidget *caller, const QPoint &globalPos)
327 {
328   ComposedNodeMenu m;
329   m.popupMenu(caller, globalPos);
330 }
331
332 Qt::ItemFlags SchemaComposedNodeItem::flags(const QModelIndex &index)
333 {
334   //DEBTRACE("SchemaComposedNodeItem::flags");
335   Qt::ItemFlags pflag = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
336   if (!QtGuiContext::getQtCurrent() || !QtGuiContext::getQtCurrent()->isEdition())
337     return pflag;
338
339   Qt::ItemFlags flagEdit = 0;
340   int column = index.column();
341   switch (column)
342     {
343     case YValue:
344       flagEdit = Qt::ItemIsEditable; // --- item value editable in model view (for node case in switch)
345       break;     
346     }
347
348   return pflag | flagEdit;
349
350 }
351
352 /*!
353  *  drop in composed nodes are used for add nodes from catalog, or reparent nodes,
354  *  or control link
355  */
356 bool SchemaComposedNodeItem::dropMimeData(const QMimeData* data, Qt::DropAction action)
357 {
358   DEBTRACE("SchemaComposedNodeItem::dropMimeData");
359   if (!data) return false;
360   const ItemMimeData* myData = dynamic_cast<const ItemMimeData*>(data);
361   if (!myData) return false;
362   bool ret =false;
363   if (myData->hasFormat("yacs/cataService") || myData->hasFormat("yacs/cataNode"))
364     {
365       ret =true;
366       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
367       bool createNewComponentInstance=Resource::COMPONENT_INSTANCE_NEW;
368       // by default getControl gives false. In this case we use the user preference COMPONENT_INSTANCE_NEW
369       // to create the node. If getControl gives true we invert the user preference
370       if(myData->getControl())
371         createNewComponentInstance=!Resource::COMPONENT_INSTANCE_NEW;
372       QtGuiContext::getQtCurrent()->getGMain()->_guiEditor->CreateNodeFromCatalog(myData, cnode,createNewComponentInstance);
373     }
374   else if(myData->hasFormat("yacs/subjectNode"))
375     {
376       ret = true;
377       Subject *sub = myData->getSubject();
378       if (!sub) return false;
379       SubjectNode *node = dynamic_cast<SubjectNode*>(sub);
380       if (!node) return false;
381       SubjectComposedNode *cnode = dynamic_cast<SubjectComposedNode*>(getSubject());
382       if (cnode)
383         if (! node->reparent(cnode))
384           Message mess;
385     }
386   else if(myData->hasFormat("yacs/subjectOutGate"))
387     {
388       Subject *subFrom = myData->getSubject();
389       if (!subFrom) return false;
390       SubjectNode* from = dynamic_cast<SubjectNode*>(subFrom);
391
392       SubjectNode *to = dynamic_cast<SubjectNode*>(getSubject());
393       if (!to) return false;
394
395       bool ret =false;
396       if (from && to)
397         {
398           ret =true;
399           if (!SubjectNode::tryCreateLink(from, to))
400             Message mess;
401         }
402     }
403   return ret;
404 }
405
406 /*!
407  *  drag for  composed nodes in tree are used for control link with Left Mouse Button
408  *  and for reparent with Middle Mouse Button
409  */
410 QString SchemaComposedNodeItem::getMimeFormat()
411 {
412   if (QApplication::mouseButtons() == Qt::MidButton)
413     return "yacs/subjectNode";
414   else
415     return "yacs/subjectOutGate";
416 }
417
418 void SchemaComposedNodeItem::setCaseValue()
419 {
420   DEBTRACE("SchemaComposedNodeItem::setCaseValue");
421   Subject *sub = _parentItem->getSubject();
422   SubjectSwitch *sSwitch = dynamic_cast<SubjectSwitch*>(sub);
423   if (!sSwitch) return;
424
425   SchemaModel *model = QtGuiContext::getQtCurrent()->getSchemaModel();
426   Switch *aSwitch = dynamic_cast<Switch*>(sSwitch->getNode());
427   YASSERT(aSwitch);
428   SubjectNode *sNode = dynamic_cast<SubjectNode*>(_subject);
429   YASSERT(sNode);
430   int rank = aSwitch->getRankOfNode(sNode->getNode());
431   if (rank == Switch::ID_FOR_DEFAULT_NODE)
432     _itemData.replace(YValue, "default");
433   else
434     _itemData.replace(YValue, rank);
435   model->setData(modelIndex(YValue), 0);
436 }
437
438 QVariant SchemaComposedNodeItem::editionWhatsThis(int column) const
439 {
440   return "<p>To edit the node properties, select the node and use the input panel. <a href=\"modification.html#property-page-for-block-node\">More...</a></p>";
441 }