Salome HOME
Merge from V6_main 01/04/2013
[modules/yacs.git] / src / genericgui / GuiEditor.cxx
1 // Copyright (C) 2006-2013  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.
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 #include "GuiEditor.hxx"
22 #include "RuntimeSALOME.hxx"
23 #include "Proc.hxx"
24 #include "Node.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"
32 #include "Scene.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>
41
42 #include <string>
43 #include <sstream>
44 #include <iostream>
45
46 //#define _DEVDEBUG_
47 #include "YacsTrace.hxx"
48
49 using namespace std;
50 using namespace YACS::ENGINE;
51 using namespace YACS::HMI;
52
53 GuiEditor::GuiEditor()
54 {
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);
76 }
77
78 GuiEditor::~GuiEditor()
79 {
80   DEBTRACE("GuiEditor::~GuiEditor");
81 }
82
83 void GuiEditor::CreateNodeFromCatalog(const ItemMimeData* myData, SubjectComposedNode *cnode,bool createNewComponentInstance)
84 {
85   DEBTRACE("GuiEditor::CreateNodeFromCatalog");
86   int nb = myData->getDataSize();
87   DEBTRACE(nb);
88   for (int i=0; i<nb; i++)
89     {
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);
95     }
96 }
97
98 void GuiEditor::CreateNode(std::string typeNode)
99 {
100   DEBTRACE("GuiEditor::CreateNode " << typeNode);
101   YACS::ENGINE::Catalog *catalog = YACS::ENGINE::getSALOMERuntime()->getBuiltinCatalog();
102
103   Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
104   if (!sub)
105     {
106       DEBTRACE("GuiEditor::CreateNode : invalid selection!");
107       return;
108     }
109   DEBTRACE(sub->getName());
110
111   YACS::HMI::SubjectComposedNode *cnode = dynamic_cast< YACS::HMI::SubjectComposedNode*>(sub);
112   if (!cnode)
113     {
114       DEBTRACE("GuiEditor::CreateNode : no ComposedNode selected!");
115       return;
116     }
117
118   _createNode(catalog, cnode, typeNode, "", Resource::COMPONENT_INSTANCE_NEW);
119 }
120
121 void GuiEditor::_createNode(YACS::ENGINE::Catalog* catalog,
122                             SubjectComposedNode *cnode,
123                             std::string service,
124                             std::string compoName,
125                             bool createNewComponentInstance)
126 {
127   // --- find a name not used
128
129   string name = service;
130   if (name == "PresetNode")
131     name = "DataIn";
132   Node *node =cnode->getNode();
133   ComposedNode *father = dynamic_cast<ComposedNode*>(node);
134   YASSERT(father);
135   list<Node*> children = father->edGetDirectDescendants();
136   bool nameInUse = true;
137   std::stringstream tryname;
138   while (nameInUse)
139     {
140       nameInUse = false;
141       long newid = GuiContext::getCurrent()->getNewId();
142       tryname.str("");
143       tryname << name << newid;
144       if (newid > 100000) break; 
145       for (list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
146         {
147           if ((*it)->getName() == tryname.str())
148             nameInUse = true;
149         }
150     }
151   name = tryname.str();
152
153   int swCase = 0;
154   SubjectSwitch *aSwitch = dynamic_cast<SubjectSwitch*>(cnode);
155   if (aSwitch)
156     {
157       map<int, SubjectNode*> bodyMap = aSwitch->getBodyMap();
158       if (bodyMap.empty()) swCase = 1;
159       else
160         {
161           map<int, SubjectNode*>::reverse_iterator rit = bodyMap.rbegin();
162           swCase = (*rit).first + 1;
163         }
164       if (!aSwitch->addNode(catalog, compoName, service, name, createNewComponentInstance, swCase))
165         Message mess;
166     }
167   else if (cnode && (dynamic_cast<SubjectBloc*>(cnode) == 0) && cnode->getChild() != 0)
168     {
169       // loop with a body : can't add a node
170       QMessageBox msgBox;
171       std::string msg;
172       msg="This loop has already a body. It is not possible to add directly another node\n";
173       msg=msg+"Do you want to put the existing node in a bloc and add the new node in this bloc ?\n";
174       msgBox.setText(msg.c_str());
175       msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No );
176       msgBox.setDefaultButton(QMessageBox::No);
177       int ret = msgBox.exec();
178       if(ret == QMessageBox::Yes)
179         {
180           // User wants to put body node in bloc
181           if (cnode->getChild()->putInComposedNode("Bloc1","Bloc"))
182             {
183               //the bloc has been successfully created. Add the new node
184               SubjectBloc* newbloc = dynamic_cast<SubjectBloc*>(cnode->getChild());
185               if (!newbloc->addNode(catalog, compoName, service, name, createNewComponentInstance))
186                 Message mess;
187             }
188           else
189             Message mess;
190         }
191     }
192   else if (cnode)
193     if (!cnode->addNode(catalog, compoName, service, name, createNewComponentInstance))
194       Message mess;
195 }
196
197 void GuiEditor::AddTypeFromCatalog(const ItemMimeData* myData)
198 {
199   DEBTRACE("GuiEditor::AddTypeFromCatalog");
200   SubjectProc* sProc = QtGuiContext::getQtCurrent()->getSubjectProc();
201   int nb = myData->getDataSize();
202   DEBTRACE(nb);
203   for (int i=0; i<nb; i++)
204     {
205       Catalog* catalog = myData->getCatalog(i);
206       DEBTRACE("catalog " << catalog);
207       string aType = myData->getType(i);
208       DEBTRACE(aType);
209       sProc->addDataType(catalog, aType);
210     }
211 }
212
213 void GuiEditor::CreateBloc()
214 {
215   DEBTRACE("GuiEditor::CreateBloc");
216   CreateNode("Bloc");
217 }
218
219 void GuiEditor::CreateForLoop()
220 {
221   DEBTRACE("GuiEditor::CreateForLoop");
222   CreateNode("ForLoop");
223 }
224
225 void GuiEditor::CreateForEachLoop(std::string type)
226 {
227   DEBTRACE("GuiEditor::CreateForEachLoop");
228   // The ForEachLoop node for datatype type must exist in builtin catalog
229   // So  create it in builtin catalog if it does not exist and datatype is loaded in the current Proc
230   YACS::ENGINE::Catalog *catalog = YACS::ENGINE::getSALOMERuntime()->getBuiltinCatalog();
231   Proc* proc = GuiContext::getCurrent()->getProc();
232   std::string typeName="ForEachLoop_"+type;
233   if (!catalog->_composednodeMap.count(typeName))
234     {
235       if(proc->typeMap.count(type))
236         {
237           catalog->_composednodeMap[typeName]=new ForEachLoop(typeName,proc->typeMap[type]);
238         }
239     }
240   CreateNode(typeName);
241 }
242
243 void GuiEditor::CreateWhileLoop()
244 {
245   DEBTRACE("GuiEditor::CreateWhileLoop");
246   CreateNode("WhileLoop");
247 }
248
249 void GuiEditor::CreateSwitch()
250 {
251   DEBTRACE("GuiEditor::CreateSwitch");
252   CreateNode("Switch");
253 }
254
255 void GuiEditor::CreateOptimizerLoop()
256 {
257   DEBTRACE("GuiEditor::CreateOptimizerLoop");
258   CreateNode("OptimizerLoop");
259 }
260
261 void GuiEditor::CreateContainer()
262 {
263   DEBTRACE("GuiEditor::CreateContainer");
264   SubjectProc *sproc = QtGuiContext::getQtCurrent()->getSubjectProc();
265   YASSERT(sproc);
266   SubjectContainer *scont = 0;
267   while (!scont)
268     {
269       std::stringstream name;
270       long newid = GuiContext::getCurrent()->getNewId();
271       if (newid > 100000) break; 
272       name.str("");
273       name << "container" << newid;
274       scont = sproc->addContainer(name.str());
275     }
276 }
277
278 void GuiEditor::CreateComponentInstance()
279 {
280   DEBTRACE("GuiEditor::CreateComponentInstance");
281   SubjectProc *sproc = QtGuiContext::getQtCurrent()->getSubjectProc();
282   YASSERT(sproc);
283   Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
284   SubjectComponent *sco = dynamic_cast<SubjectComponent*>(sub);
285   if (!sco)
286     {
287       DEBTRACE("GuiEditor::CreateComponentInstance: " << "selection is not a component");
288       return;
289     }
290   string compoName = sco->getComponent()->getCompoName();
291   string containerName = sco->getComponent()->getContainer()->getName();
292   sproc->addComponent(compoName, containerName);
293 }
294
295
296 SubjectDataPort* GuiEditor::CreateInputPort(SubjectElementaryNode* seNode, 
297                                             std::string name,
298                                             YACS::ENGINE::Catalog *catalog,
299                                             std::string type,
300                                             SubjectDataPort* before)
301 {
302   DEBTRACE("GuiEditor::CreateInputPort");
303   SubjectDataPort *sdp = 0;
304   if (name.empty())
305     {
306       std::stringstream aName;
307       long newid = 0;
308       while (newid < 100000)
309         {
310           newid = GuiContext::getCurrent()->getNewId();
311           aName.str("");
312           aName << "i" << newid;
313           try
314             {
315               seNode->getNode()->getInputPort(aName.str());
316             }
317           catch(Exception& ex)
318             {
319               break;
320             }
321         }
322       sdp = seNode->addInputPort(catalog,type, aName.str());
323     }
324   else
325     sdp = seNode->addInputPort(catalog,type, name);
326   if (!sdp)
327     Message mess;
328   return sdp;
329 }
330
331 SubjectDataPort*  GuiEditor::CreateOutputPort(SubjectElementaryNode* seNode, 
332                                               std::string name,
333                                               YACS::ENGINE::Catalog *catalog,
334                                               std::string type,
335                                               SubjectDataPort* before)
336 {
337   DEBTRACE("GuiEditor::CreateOutputPort");
338   SubjectDataPort *sdp = 0;
339   if (name.empty())
340     {
341       std::stringstream aName;
342       long newid = 0;
343       while (newid < 100000)
344         {
345           newid = GuiContext::getCurrent()->getNewId();
346           aName.str("");
347           aName << "o" << newid;
348           try
349             {
350               seNode->getNode()->getOutputPort(aName.str());
351             }
352           catch(Exception& ex)
353             {
354               break;
355             }
356         }
357       sdp = seNode->addOutputPort(catalog,type, aName.str());
358     }
359   else
360     sdp = seNode->addOutputPort(catalog,type, name);
361   if (!sdp)
362     Message mess;
363   return sdp;
364 }
365
366 /*!
367  * Subject shrink or expand, command from popup menu: needs a valid selection
368  */
369 void GuiEditor::shrinkExpand() {
370   DEBTRACE("GuiEditor::shrinkExpand");
371
372   Subject* sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
373   if (!sub) {
374     DEBTRACE("GuiEditor::shrinkExpand : invalid selection!");
375     return;
376   };
377
378   if (! QtGuiContext::getQtCurrent()->_mapOfSceneItem.count(sub)) {
379     DEBTRACE("GuiEditor::shrinkExpand: no scene item corresponding to this subject");
380     return;
381   };
382
383   SceneItem* item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sub];
384   SceneNodeItem *sni = dynamic_cast<SceneNodeItem*>(item);
385   if (!sni) {
386     DEBTRACE("GuiEditor::shrinkExpand: no scene node item corresponding to this subject");
387     return;
388   };
389
390   if (sni->isExpanded()) {
391     sni->setExpanded(false);
392   } else {
393     sni->setExpanded(true);
394   };
395   sni->reorganizeShrinkExpand();
396   sni->showOutScopeLinks();
397   sni->updateLinks();
398 }
399
400 /*!
401  * Subject destruction, command from popup menu: needs a valid selection
402  */
403 void GuiEditor::DeleteSubject()
404 {
405   DEBTRACE("GuiEditor::DeleteSubject");
406   if (!QtGuiContext::getQtCurrent()->isEdition()) return;
407   QModelIndexList selList
408     = QtGuiContext::getQtCurrent()->getSelectionModel()->selectedIndexes();
409   if (selList.isEmpty())
410     return;
411
412   QModelIndex selected = selList.front();
413   if (!selected.isValid())
414     return;
415
416   SchemaItem *selItem = static_cast<SchemaItem*>(selected.internalPointer());
417   if (!selItem) return;
418   Subject *subToRemove = selItem->getSubject();
419   Subject *subParent = subToRemove->getParent();
420   DeleteSubject(subParent, subToRemove);
421 }
422
423 /*!
424  * Subject destruction, command from button in port table view or via selection
425  */
426 void GuiEditor::DeleteSubject(Subject* parent,
427                               Subject* toRemove)
428 {
429   DEBTRACE("GuiEditor::DeleteSubject "<<parent->getName()<<" "<<toRemove->getName());
430   if (!QtGuiContext::getQtCurrent()->isEdition()) return;
431   toRemove->askRegisterUndoDestroy();
432   if(!parent->destroy(toRemove))
433     Message mess;
434 }
435
436 void GuiEditor::CutSubject()
437 {
438   DEBTRACE("GuiEditor::CutSubject");
439   if (!QtGuiContext::getQtCurrent()->isEdition()) return;
440   Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
441   if (!sub)
442     {
443       Message mess("GuiEditor::Cut : invalid selection!");
444       return;
445     }
446   DEBTRACE(sub->getName());
447   QtGuiContext::getQtCurrent()->setSubjectToCut(sub);
448 }
449
450 void GuiEditor::CopySubject()
451 {
452   DEBTRACE("GuiEditor::CopySubject");
453   if (!QtGuiContext::getQtCurrent()->isEdition()) return;
454   Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
455   if (!sub)
456     {
457       Message mess("GuiEditor::Copy : invalid selection!");
458       return;
459     }
460   DEBTRACE(sub->getName());
461   QtGuiContext::getQtCurrent()->setSubjectToCopy(sub);
462 }
463
464 void GuiEditor::PasteSubject()
465 {
466   DEBTRACE("GuiEditor::PasteSubject");
467   if (!QtGuiContext::getQtCurrent()->isEdition()) return;
468   Subject *newParent = QtGuiContext::getQtCurrent()->getSelectedSubject();
469   if (!newParent)
470     {
471       Message mess("GuiEditor::Paste : invalid selection!");
472       return;
473     }
474   bool isCut = false;
475   Subject *sub = QtGuiContext::getQtCurrent()->getSubjectToPaste(isCut);
476   if (!sub)
477     {
478       Message mess("Nothing to paste");
479       return;
480     }
481   if (SubjectNode *snode = dynamic_cast<SubjectNode*>(sub))
482     {
483       if (isCut)
484         {
485           DEBTRACE("cut");
486           if (!snode->reparent(newParent))
487             Message mess;
488         }
489       else
490         {
491           DEBTRACE("copy");
492           if (!snode->copy(newParent))
493             Message mess;
494         }
495       return;
496     }
497   Message mess("Paste not possible for this kind of object");
498 }
499
500 void GuiEditor::PutSubjectInBloc()
501 {
502   Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
503   if (!sub)
504     {
505       Message mess("GuiEditor::PutSubjectInBloc : invalid selection!");
506       return;
507     }
508   if (SubjectNode *snode = dynamic_cast<SubjectNode*>(sub))
509     {
510       //Build the set of children node names
511       Node* node=snode->getNode();
512       ComposedNode* father=node->getFather();
513       std::list<Node*> children = father->edGetDirectDescendants();
514       std::set<std::string> names;
515       for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
516         names.insert((*it)->getName());
517
518       std::stringstream tryname;
519       long newid=0;
520       while (newid < 100000)
521         {
522           tryname.str("");
523           tryname << "Bloc" << newid;
524           if(names.find(tryname.str()) == names.end())break;
525           newid++;
526         }
527       
528       if (!snode->putInComposedNode(tryname.str(),"Bloc"))
529         Message mess;
530
531       return;
532     }
533   Message mess("Put in Bloc not possible for this kind of object");
534 }
535
536 void GuiEditor::PutGraphInForeachLoop(std::string typeNode)
537 {
538   // put graph in Bloc node before
539   std::string blocname = PutGraphInBloc();
540
541   Proc* proc = GuiContext::getCurrent()->getProc();
542   Node* bloc = proc->getChildByShortName(blocname);
543   SubjectNode * sbloc = GuiContext::getCurrent()->_mapOfSubjectNode[bloc];
544   //put the built bloc into target node
545   sbloc->putInComposedNode("ForEachLoop_"+typeNode,"ForEachLoop_"+typeNode);
546 }
547
548 void GuiEditor::PutGraphInOptimizerLoop()
549 {
550   // put graph in Bloc node before
551   std::string blocname = PutGraphInBloc();
552
553   Proc* proc = GuiContext::getCurrent()->getProc();
554   Node* bloc = proc->getChildByShortName(blocname);
555   SubjectNode * sbloc = GuiContext::getCurrent()->_mapOfSubjectNode[bloc];
556   //put the built bloc into target node
557   sbloc->putInComposedNode("OptimizerLoop0","OptimizerLoop");
558 }
559
560 std::string GuiEditor::PutGraphInBloc()
561 {
562   Proc* proc = GuiContext::getCurrent()->getProc();
563   std::list<Node *> children = proc->getChildren();
564
565   //get the set of children node names
566   std::set<std::string> names;
567   for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
568     names.insert((*it)->getName());
569
570   //get the next numbered name
571   std::stringstream tryname;
572   long newid=0;
573   while (newid < 100000)
574     {
575       tryname.str("");
576       tryname << "Bloc" << newid;
577       if(names.find(tryname.str()) == names.end())break;
578       newid++;
579     }
580   std::string blocname = tryname.str();
581
582   //put one by one the child nodes of Proc node into a new Bloc node
583   SubjectNode * snode;
584   for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
585     {
586       snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
587       snode->saveLinks();
588       snode->putInComposedNode(blocname,"Bloc", false);
589     }
590   for (std::list<Node*>::iterator it = children.begin(); it != children.end(); ++it)
591     {
592       snode = 0;
593       snode = GuiContext::getCurrent()->_mapOfSubjectNode[(*it)];
594       snode->restoreLinks();
595     }
596   return blocname;
597 }
598
599 void GuiEditor::rebuildLinks()
600 {
601 // --- only global link redraw for now...
602   DEBTRACE("GuiEditor::rebuildLinks");
603   YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
604   SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
605   SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
606   proc->rebuildLinks();
607 }
608
609 void GuiEditor::arrangeNodes(bool isRecursive)
610 {
611   Subject *sub = QtGuiContext::getQtCurrent()->getSelectedSubject();
612   if (!sub)
613     {
614       DEBTRACE("GuiEditor::arrangeNodes : invalid selection!");
615       return;
616     }
617   DEBTRACE(sub->getName());
618
619   if (! QtGuiContext::getQtCurrent()->_mapOfSceneItem.count(sub))
620     {
621       DEBTRACE("no scene item corresponding to this subject");
622       return;
623     }
624   SceneItem* item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[sub];
625   SceneComposedNodeItem *sci = dynamic_cast<SceneComposedNodeItem*>(item);
626   if (! sci)
627     {
628       DEBTRACE("no scene composed node item corresponding to this subject");
629       return;
630     }
631   sci->arrangeNodes(isRecursive);
632 //   if (Scene::_autoComputeLinks && !QtGuiContext::getQtCurrent()->isLoading())
633 //     {
634 //       YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
635 //       SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
636 //       SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
637 //       proc->rebuildLinks();
638 //     }
639 }
640
641 void GuiEditor::arrangeProc()
642 {
643   YACS::HMI::SubjectProc* subproc = QtGuiContext::getQtCurrent()->getSubjectProc();
644   SceneItem *item = QtGuiContext::getQtCurrent()->_mapOfSceneItem[subproc];
645   SceneComposedNodeItem *proc = dynamic_cast<SceneComposedNodeItem*>(item);
646   proc->arrangeNodes(true);
647 }
648
649 void GuiEditor::showUndo(QWidget *parent)
650 {
651   FormUndoRedo *undo = new FormUndoRedo(parent);
652   undo->tabWidget->setCurrentWidget(undo->undoTab);
653   undo->exec();
654 }
655
656 void GuiEditor::showRedo(QWidget *parent)
657 {
658   FormUndoRedo *redo = new FormUndoRedo(parent);
659   redo->tabWidget->setCurrentWidget(redo->redoTab);
660   redo->exec();
661 }
662
663 /*! Replace accentuated characters from latin1 to US ascii equivalent without accent.
664 *   I did not found anything to do that in Qt...
665 */
666 QString GuiEditor::asciiFilter(const QString & name)
667 {
668   DEBTRACE(name.toStdString());
669   string aName = name.toAscii().data();
670   DEBTRACE(aName);
671   for (int i=0; i < aName.size(); i++)
672     {
673       int v = (unsigned char)(aName[i]);
674       DEBTRACE(v << " " << _table[v]);
675       aName[i] = _table[v];
676     }
677   DEBTRACE(aName);
678   return aName.c_str();
679 }