1 // Copyright (C) 2006-2020 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
21 #include "GuiEditor.hxx"
22 #include "RuntimeSALOME.hxx"
25 #include "ForEachLoop.hxx"
26 #include "Catalog.hxx"
27 #include "Container.hxx"
28 #include "ComponentInstance.hxx"
29 #include "guiObservers.hxx"
30 #include "QtGuiContext.hxx"
31 #include "TypeCode.hxx"
33 #include "SceneComposedNodeItem.hxx"
34 #include "SceneLinkItem.hxx"
35 #include "Catalog.hxx"
36 #include "ItemMimeData.hxx"
37 #include "Message.hxx"
38 #include "Resource.hxx"
39 #include "FormUndoRedo.hxx"
40 #include <QMessageBox>
47 #include "YacsTrace.hxx"
50 using namespace YACS::ENGINE;
51 using namespace YACS::HMI;
53 GuiEditor::GuiEditor()
55 // approximative conversion from latin1 to US ascii (removing accentuation)
56 DEBTRACE("GuiEditor::GuiEditor");
57 _table = "________________" ; // 0 - 15
58 _table += "________________" ; // 16 - 31
59 _table += " !\"#$%&'()*+,-./" ; // 32 - 47
60 _table += "0123456789:;<=>?" ; // 48 - 63
61 _table += "@ABCDEFGHIJKLMNO" ; // 64 - 79
62 _table += "PQRSTUVWXYZ[\\]^_" ; // 80 - 95
63 _table += "`abcdefghijklmno" ; // 96 - 111
64 _table += "pqrstuvwxyz{|}~_" ; // 112 - 127
65 _table += "________________" ; // 128 - 143
66 _table += "________________" ; // 144 - 159
67 _table += "_icLoY|-_ca-__r-" ; // 160 - 175
68 _table += "-_23'u_..10\"___?" ; // 176 - 191
69 _table += "AAAAAAACEEEEIIII" ; // 192 - 207
70 _table += "DNOOOOOx0UUUUYPB" ; // 208 - 223
71 _table += "aaaaaaaceeeeiiii" ; // 224 - 239
72 _table += "onooooo-0uuuuypy" ; // 240 - 255
73 //_table[167] = char(167); // '§'
74 //_table[176] = char(176); // '°'
75 DEBTRACE(_table.size() << " " << _table);
78 GuiEditor::~GuiEditor()
80 DEBTRACE("GuiEditor::~GuiEditor");
83 void GuiEditor::CreateNodeFromCatalog(const ItemMimeData* myData, SubjectComposedNode *cnode,bool createNewComponentInstance)
85 DEBTRACE("GuiEditor::CreateNodeFromCatalog");
86 int nb = myData->getDataSize();
88 for (int i=0; i<nb; i++)
90 Catalog* catalog = myData->getCatalog(i);
91 string compoName = myData->getCompo(i);
92 string service = myData->getType(i);
93 DEBTRACE(compoName << "/" << service);
94 _createNode(catalog, cnode, service, compoName,createNewComponentInstance);
98 SubjectNode* GuiEditor::CreateNode(std::string typeNode)
100 DEBTRACE("GuiEditor::CreateNode " << typeNode);
101 YACS::ENGINE::Catalog *catalog = YACS::ENGINE::getSALOMERuntime()->getBuiltinCatalog();
103 Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
106 DEBTRACE("GuiEditor::CreateNode : invalid selection!");
109 DEBTRACE(sub->getName());
111 YACS::HMI::SubjectComposedNode *cnode = dynamic_cast< YACS::HMI::SubjectComposedNode*>(sub);
114 DEBTRACE("GuiEditor::CreateNode : no ComposedNode selected!");
118 return _createNode(catalog, cnode, typeNode, "", Resource::COMPONENT_INSTANCE_NEW);
121 SubjectNode* GuiEditor::_createNode(YACS::ENGINE::Catalog* catalog,
122 SubjectComposedNode *cnode,
124 std::string compoName,
125 bool createNewComponentInstance)
127 SubjectNode* aNewNode = 0;
129 // --- find a name not used
131 string name = service;
132 if (name == "PresetNode")
134 Node *node =cnode->getNode();
135 ComposedNode *father = dynamic_cast<ComposedNode*>(node);
137 list<Node*> children = father->edGetDirectDescendants();
138 bool nameInUse = true;
139 std::stringstream tryname;
143 long newid = GuiContext::getCurrent()->getNewId();
145 tryname << name << newid;
146 if (newid > 100000) break;
147 for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
149 if ((*it)->getName() == tryname.str())
153 name = tryname.str();
156 SubjectSwitch *aSwitch = dynamic_cast<SubjectSwitch*>(cnode);
159 map<int, SubjectNode*> bodyMap = aSwitch->getBodyMap();
160 if (bodyMap.empty()) swCase = 1;
163 map<int, SubjectNode*>::reverse_iterator rit = bodyMap.rbegin();
164 swCase = (*rit).first + 1;
166 aNewNode = aSwitch->addNode(catalog, compoName, service, name, createNewComponentInstance, swCase);
170 else if (cnode && (dynamic_cast<SubjectBloc*>(cnode) == 0) && cnode->getChild() != 0)
172 // loop with a body : can't add a node
175 msg="This loop has already a body. It is not possible to add directly another node\n";
176 msg=msg+"Do you want to put the existing node in a bloc and add the new node in this bloc ?\n";
177 msgBox.setText(msg.c_str());
178 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No );
179 msgBox.setDefaultButton(QMessageBox::No);
180 int ret = msgBox.exec();
181 if(ret == QMessageBox::Yes)
183 // User wants to put body node in bloc
184 if (cnode->getChild()->putInComposedNode("Bloc1","Bloc"))
186 //the bloc has been successfully created. Add the new node
187 SubjectBloc* newbloc = dynamic_cast<SubjectBloc*>(cnode->getChild());
188 aNewNode = newbloc->addNode(catalog, compoName, service, name, createNewComponentInstance);
197 aNewNode = cnode->addNode(catalog, compoName, service, name, createNewComponentInstance);
203 void GuiEditor::AddTypeFromCatalog(const ItemMimeData* myData)
205 DEBTRACE("GuiEditor::AddTypeFromCatalog");
206 SubjectProc* sProc = QtGuiContext::getQtCurrent()->getSubjectProc();
207 int nb = myData->getDataSize();
209 for (int i=0; i<nb; i++)
211 Catalog* catalog = myData->getCatalog(i);
212 DEBTRACE("catalog " << catalog);
213 string aType = myData->getType(i);
215 sProc->addDataType(catalog, aType);
219 void GuiEditor::CreateBloc()
221 DEBTRACE("GuiEditor::CreateBloc");
225 void GuiEditor::CreateForLoop()
227 DEBTRACE("GuiEditor::CreateForLoop");
228 CreateNode("ForLoop");
231 void GuiEditor::CreateForEachLoop(std::string type)
233 DEBTRACE("GuiEditor::CreateForEachLoop");
234 // The ForEachLoop node for datatype type must exist in builtin catalog
235 // So create it in builtin catalog if it does not exist and datatype is loaded in the current Proc
236 YACS::ENGINE::Catalog *catalog = YACS::ENGINE::getSALOMERuntime()->getBuiltinCatalog();
237 Proc* proc = GuiContext::getCurrent()->getProc();
238 std::string typeName="ForEachLoop_"+type;
239 if (!catalog->_composednodeMap.count(typeName))
241 if(proc->typeMap.count(type))
243 catalog->_composednodeMap[typeName]=new ForEachLoop(typeName,proc->typeMap[type]);
246 CreateNode(typeName);
249 void GuiEditor::CreateWhileLoop()
251 DEBTRACE("GuiEditor::CreateWhileLoop");
252 CreateNode("WhileLoop");
255 void GuiEditor::CreateSwitch()
257 DEBTRACE("GuiEditor::CreateSwitch");
258 CreateNode("Switch");
261 void GuiEditor::CreateOptimizerLoop()
263 DEBTRACE("GuiEditor::CreateOptimizerLoop");
264 CreateNode("OptimizerLoop");
267 void GuiEditor::CreateContainer()
269 DEBTRACE("GuiEditor::CreateContainer");
270 SubjectProc *sproc = QtGuiContext::getQtCurrent()->getSubjectProc();
272 SubjectContainerBase *scont = 0;
275 std::stringstream name;
276 long newid = GuiContext::getCurrent()->getNewId();
277 if (newid > 100000) break;
279 name << "container" << newid;
280 scont = sproc->addContainer(name.str());
284 void GuiEditor::CreateHPContainer()
286 DEBTRACE("GuiEditor::CreateHPContainer");
287 SubjectProc *sproc = QtGuiContext::getQtCurrent()->getSubjectProc();
289 SubjectContainerBase *scont = 0;
292 std::stringstream name;
293 long newid = GuiContext::getCurrent()->getNewId();
294 if (newid > 100000) break;
296 name << "container" << newid;
297 scont = sproc->addHPContainer(name.str());
301 void GuiEditor::CreateComponentInstance()
303 DEBTRACE("GuiEditor::CreateComponentInstance");
304 SubjectProc *sproc = QtGuiContext::getQtCurrent()->getSubjectProc();
306 Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
307 SubjectComponent *sco = dynamic_cast<SubjectComponent*>(sub);
310 DEBTRACE("GuiEditor::CreateComponentInstance: " << "selection is not a component");
313 string compoName = sco->getComponent()->getCompoName();
314 string containerName = sco->getComponent()->getContainer()->getName();
315 sproc->addComponent(compoName, containerName);
319 SubjectDataPort* GuiEditor::CreateInputPort(SubjectElementaryNode* seNode,
321 YACS::ENGINE::Catalog *catalog,
323 SubjectDataPort* before)
325 DEBTRACE("GuiEditor::CreateInputPort");
326 SubjectDataPort *sdp = 0;
329 std::stringstream aName;
331 while (newid < 100000)
333 newid = GuiContext::getCurrent()->getNewId();
335 aName << "i" << newid;
338 seNode->getNode()->getInputPort(aName.str());
345 sdp = seNode->addInputPort(catalog,type, aName.str());
348 sdp = seNode->addInputPort(catalog,type, name);
354 SubjectDataPort* GuiEditor::CreateOutputPort(SubjectElementaryNode* seNode,
356 YACS::ENGINE::Catalog *catalog,
358 SubjectDataPort* before)
360 DEBTRACE("GuiEditor::CreateOutputPort");
361 SubjectDataPort *sdp = 0;
364 std::stringstream aName;
366 while (newid < 100000)
368 newid = GuiContext::getCurrent()->getNewId();
370 aName << "o" << newid;
373 seNode->getNode()->getOutputPort(aName.str());
380 sdp = seNode->addOutputPort(catalog,type, aName.str());
383 sdp = seNode->addOutputPort(catalog,type, name);
390 * Subject shrink or expand, command from popup menu: needs a valid selection
392 void GuiEditor::shrinkExpand(Qt::KeyboardModifiers kbModifiers) {
393 DEBTRACE("GuiEditor::shrinkExpand");
395 Subject* sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
397 DEBTRACE("GuiEditor::shrinkExpand : invalid selection!");
401 if (! QtGuiContext::getQtCurrent()->_mapOfSceneItem.count(sub)) {
402 DEBTRACE("GuiEditor::shrinkExpand: no scene item corresponding to this subject");
406 SceneItem* item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sub];
407 SceneNodeItem *sni = dynamic_cast<SceneNodeItem*>(item);
409 DEBTRACE("GuiEditor::shrinkExpand: no scene node item corresponding to this subject");
413 ShrinkMode aShrinkMode = CurrentNode;
414 if (kbModifiers == Qt::ControlModifier) {
415 aShrinkMode = ElementaryNodes;
416 } else if (kbModifiers == (Qt::ShiftModifier|Qt::ControlModifier)) {
417 aShrinkMode = ChildrenNodes;
420 sni->reorganizeShrinkExpand(aShrinkMode);
421 sni->showOutScopeLinks();
426 * Subject destruction, command from popup menu: needs a valid selection
428 void GuiEditor::DeleteSubject()
430 DEBTRACE("GuiEditor::DeleteSubject");
431 if (!QtGuiContext::getQtCurrent()->isEdition()) return;
432 QModelIndexList selList
433 = QtGuiContext::getQtCurrent()->getSelectionModel()->selectedIndexes();
434 if (selList.isEmpty())
437 QModelIndex selected = selList.front();
438 if (!selected.isValid())
441 SchemaItem *selItem = static_cast<SchemaItem*>(selected.internalPointer());
442 if (!selItem) return;
443 Subject *subToRemove = selItem->getSubject();
444 Subject *subParent = subToRemove->getParent();
445 DeleteSubject(subParent, subToRemove);
449 * Subject destruction, command from button in port table view or via selection
451 void GuiEditor::DeleteSubject(Subject* parent,
454 DEBTRACE("GuiEditor::DeleteSubject "<<parent->getName()<<" "<<toRemove->getName());
455 if (!QtGuiContext::getQtCurrent()->isEdition()) return;
456 toRemove->askRegisterUndoDestroy();
457 if(!parent->destroy(toRemove))
459 // Empty the clipboard in order to avoid the copy of a destroyed object.
460 QtGuiContext::getQtCurrent()->setSubjectToCopy(NULL);
463 void GuiEditor::CutSubject()
465 DEBTRACE("GuiEditor::CutSubject");
466 if (!QtGuiContext::getQtCurrent()->isEdition()) return;
467 Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
470 Message mess("GuiEditor::Cut : invalid selection!");
473 DEBTRACE(sub->getName());
474 QtGuiContext::getQtCurrent()->setSubjectToCut(sub);
477 void GuiEditor::CopySubject()
479 DEBTRACE("GuiEditor::CopySubject");
480 if (!QtGuiContext::getQtCurrent()->isEdition()) return;
481 Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
484 Message mess("GuiEditor::Copy : invalid selection!");
487 DEBTRACE(sub->getName());
488 QtGuiContext::getQtCurrent()->setSubjectToCopy(sub);
491 void GuiEditor::PasteSubject()
493 DEBTRACE("GuiEditor::PasteSubject");
494 if (!QtGuiContext::getQtCurrent()->isEdition()) return;
495 Subject *newParent = QtGuiContext::getQtCurrent()->getSelectedSubject();
498 Message mess("GuiEditor::Paste : invalid selection!");
502 Subject *sub = QtGuiContext::getQtCurrent()->getSubjectToPaste(isCut);
505 Message mess("Nothing to paste");
508 if (SubjectNode *snode = dynamic_cast<SubjectNode*>(sub))
513 if (!snode->reparent(newParent))
519 if (!snode->copy(newParent))
524 Message mess("Paste not possible for this kind of object");
527 void GuiEditor::PutSubjectInBloc()
529 Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
532 Message mess("GuiEditor::PutSubjectInBloc : invalid selection!");
535 if (SubjectNode *snode = dynamic_cast<SubjectNode*>(sub))
537 //Build the set of children node names
538 Node* node=snode->getNode();
539 ComposedNode* father=node->getFather();
540 std::list<Node*> children = father->edGetDirectDescendants();
541 std::set<std::string> names;
542 for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
543 names.insert((*it)->getName());
545 std::stringstream tryname;
547 while (newid < 100000)
550 tryname << "Bloc" << newid;
551 if(names.find(tryname.str()) == names.end())break;
555 if (!snode->putInComposedNode(tryname.str(),"Bloc"))
560 Message mess("Put in Bloc not possible for this kind of object");
563 void GuiEditor::PutGraphInNode(std::string typeNode)
565 // put graph in Bloc node before
566 std::string blocname = PutGraphInBloc();
567 // put the built bloc into target node type
568 Proc* proc = GuiContext::getCurrent()->getProc();
569 Node* bloc = proc->getChildByShortName(blocname);
570 SubjectNode * sbloc = GuiContext::getCurrent()->_mapOfSubjectNode[bloc];
571 // create a target node
572 SubjectNode * snode = CreateNode(typeNode);
573 // put the built bloc into target node
574 sbloc->putInComposedNode(snode->getName(), typeNode);
575 // select a target node
576 YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
577 QtGuiContext::getQtCurrent()->setSelectedSubject(subproc);
581 std::string GuiEditor::PutGraphInBloc()
583 Proc* proc = GuiContext::getCurrent()->getProc();
584 std::list<Node *> children = proc->edGetDirectDescendants();
586 //get the set of children node names
587 std::set<std::string> names;
588 for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
589 names.insert((*it)->getName());
591 //get the next numbered name
592 std::stringstream tryname;
593 long newid = GuiContext::getCurrent()->getNewId();
594 while (newid < 100000)
597 tryname << "Bloc" << newid;
598 if(names.find(tryname.str()) == names.end())break;
601 std::string blocname = tryname.str();
603 //put one by one the child nodes of Proc node into a new Bloc node
604 std::map< std::string, std::pair<QPointF, QPointF> > aMapOfNodePosition;
606 SceneNodeItem *inode = 0;
607 SubjectNode * snode = 0;
608 for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
610 snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
612 item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[snode];
614 inode = dynamic_cast<SceneNodeItem*>(item);
616 // save current node position to restore it after reparenting
617 aMapOfNodePosition[snode->getName()] = std::make_pair(inode->pos(), QPointF(inode->getExpandedX(), inode->getExpandedY()));
619 snode->putInComposedNode(blocname, "Bloc", false);
621 for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
624 snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
625 snode->restoreLinks();
626 item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[snode];
628 inode = dynamic_cast<SceneNodeItem*>(item);
630 // restore node position
631 inode->setPos(aMapOfNodePosition[snode->getName()].first);
632 // update node position for shrink/expand operation
633 inode->setExpandedPos(aMapOfNodePosition[snode->getName()].second);
634 // notify node about position changing
635 inode->checkGeometryChange();
637 Node* bloc = proc->getChildByShortName(blocname);
638 SubjectNode* sbloc = GuiContext::getCurrent()->_mapOfSubjectNode[bloc];
639 item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sbloc];
641 // notify bloc about child position changing
642 item->checkGeometryChange();
643 // select a target bloc
644 YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
645 QtGuiContext::getQtCurrent()->setSelectedSubject(subproc);
649 void GuiEditor::rebuildLinks()
651 // --- only global link redraw for now...
652 DEBTRACE("GuiEditor::rebuildLinks");
653 YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
654 SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
655 SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
656 proc->rebuildLinks();
659 void GuiEditor::arrangeNodes(bool isRecursive)
661 Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
664 DEBTRACE("GuiEditor::arrangeNodes : invalid selection!");
667 DEBTRACE(sub->getName());
669 if (! QtGuiContext::getQtCurrent()->_mapOfSceneItem.count(sub))
671 DEBTRACE("no scene item corresponding to this subject");
674 SceneItem* item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sub];
675 SceneComposedNodeItem *sci = dynamic_cast<SceneComposedNodeItem*>(item);
678 DEBTRACE("no scene composed node item corresponding to this subject");
681 sci->arrangeNodes(isRecursive);
682 // if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading())
684 // YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
685 // SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
686 // SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
687 // proc->rebuildLinks();
691 void GuiEditor::arrangeProc()
693 YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
694 SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
695 SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
696 proc->arrangeNodes(true);
699 void GuiEditor::showUndo(QWidget *parent)
701 FormUndoRedo *undo = new FormUndoRedo(parent);
702 undo->tabWidget->setCurrentWidget(undo->undoTab);
706 void GuiEditor::showRedo(QWidget *parent)
708 FormUndoRedo *redo = new FormUndoRedo(parent);
709 redo->tabWidget->setCurrentWidget(redo->redoTab);
713 /*! Replace accentuated characters from latin1 to US ascii equivalent without accent.
714 * I did not found anything to do that in Qt...
716 QString GuiEditor::asciiFilter(const QString & name)
718 DEBTRACE(name.toStdString());
719 string aName = name.toLatin1().data();
721 for (int i=0; i < aName.size(); i++)
723 int v = (unsigned char)(aName[i]);
724 DEBTRACE(v << " " << _table[v]);
725 aName[i] = _table[v];
728 return aName.c_str();