Salome HOME
Copyrights update 2015.
[modules/yacs.git] / src / genericgui / EditionScript.cxx
1 // Copyright (C) 2006-2015  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 "EditionScript.hxx"
21 #include "QtGuiContext.hxx"
22 #include "Resource.hxx"
23 #include "Container.hxx"
24 #include "InlineNode.hxx"
25 #include "FormContainer.hxx"
26 #include "Message.hxx"
27
28 #if HAS_QSCI4>0
29 #include <qsciscintilla.h>
30 #include <qscilexerpython.h>
31 #endif
32
33 #include <QToolButton>
34 #include <QSplitter>
35 #include <QTemporaryFile>
36 #include <QTextStream>
37 #include <QProcess>
38
39 #include <cassert>
40
41 //#define _DEVDEBUG_
42 #include "YacsTrace.hxx"
43
44 using namespace std;
45
46 using namespace YACS;
47 using namespace YACS::HMI;
48
49 #if HAS_QSCI4>0
50 class myQsciScintilla: public QsciScintilla
51 {
52 public:
53   myQsciScintilla(QWidget *parent=0)
54     : QsciScintilla(parent) {};
55   ~myQsciScintilla(){};
56   virtual QSize sizeHint() const { return QSize(350, 150); };
57 protected:
58   virtual bool event(QEvent *e);
59 };
60
61 bool myQsciScintilla::event(QEvent *e)
62 {
63   if (e->type() == QEvent::ShortcutOverride)
64     {
65       e->accept();
66       return true;
67     }
68   return QsciScintilla::event(e);
69 }
70
71 #endif
72
73
74 EditionScript::EditionScript(Subject* subject,
75                          QWidget* parent,
76                          const char* name)
77   : EditionElementaryNode(subject, parent, name)
78 {
79   _subInlineNode = 0;
80   _sci = 0;
81
82   _subInlineNode = dynamic_cast<SubjectInlineNode*>(_subject);
83   YASSERT(_subInlineNode);
84
85   QSplitter *splitter = new QSplitter(this);
86   splitter->setOrientation(Qt::Vertical);
87   _wid->gridLayout1->addWidget(splitter);
88
89   QWidget* widg=new QWidget;
90   _portslayout = new QVBoxLayout;
91   widg->setLayout(_portslayout);
92   _portslayout->setMargin(1);
93   splitter->addWidget(widg);
94
95   QWidget* window=new QWidget;
96   _glayout=new QVBoxLayout;
97   window->setLayout(_glayout);
98   _glayout->setMargin(1);
99   splitter->addWidget(window);
100
101   //add an options section in ports layout for execution mode (local or remote)
102   QHBoxLayout* hboxLayout = new QHBoxLayout();
103   hboxLayout->setMargin(0);
104   QToolButton* tb_options = new QToolButton();
105   tb_options->setCheckable(true);
106   QIcon icon;
107   icon.addFile("icons:icon_down.png");
108   icon.addFile("icons:icon_up.png", QSize(), QIcon::Normal, QIcon::On);
109   tb_options->setIcon(icon);
110   hboxLayout->addWidget(tb_options);
111
112   QLabel* label = new QLabel("Execution Mode");
113   QFont font;
114   font.setBold(true);
115   font.setWeight(75);
116   label->setFont(font);
117   hboxLayout->addWidget(label);
118
119   _portslayout->addLayout(hboxLayout);
120
121   fr_options = new QFrame();
122   QHBoxLayout* hboxLayout1 = new QHBoxLayout(fr_options);
123   hboxLayout1->setMargin(0);
124   radiolocal= new QRadioButton("YACS");
125   radioremote= new QRadioButton("Container");
126   radiolocal->setChecked(true);
127   hboxLayout1->addWidget(radiolocal);
128   hboxLayout1->addWidget(radioremote);
129   hboxLayout->addWidget(fr_options);
130
131   fr_container = new QFrame();
132   QHBoxLayout* hboxLayout2 = new QHBoxLayout(fr_container);
133   hboxLayout2->setMargin(0);
134   QLabel* laContainer = new QLabel("Container:");
135   hboxLayout2->addWidget(laContainer);
136   cb_container = new ComboBox();
137   hboxLayout2->addWidget(cb_container);
138   _portslayout->addWidget(fr_container);
139
140   //
141   YACS::ENGINE::InlineNode *pyNode(dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode()));
142   YACS::ENGINE::Container *cont(pyNode->getContainer());
143   formcontainer = new FormContainerDecorator(cont,this);
144   _portslayout->addWidget(formcontainer);
145   //_portslayout->addWidget(formcontainer->getWidget());
146   //end of insertion of execution mode
147
148   createTablePorts(_portslayout);
149   setEditablePorts(true);
150
151   _haveScript = true;
152 #if HAS_QSCI4>0
153   _sci = new myQsciScintilla(this);
154 #else
155   _sci = new QTextEdit(this);
156 #endif
157   _wid->gridLayout->removeItem(_wid->spacerItem);
158
159   _editor = new QPushButton("External Editor", this);
160   connect(_editor, SIGNAL(clicked()), this, SLOT(onEdit()));
161   if(!Resource::pythonExternalEditor.isEmpty())
162     {
163       _glayout->addWidget( _editor );
164     }
165   _glayout->addWidget( _sci );
166
167 #if HAS_QSCI4>0
168   _sci->setUtf8(1);
169   QsciLexerPython *lex = new QsciLexerPython(_sci);
170   lex->setFont(Resource::pythonfont);
171   _sci->setLexer(lex);
172   _sci->setBraceMatching(QsciScintilla::SloppyBraceMatch);
173   _sci->setAutoIndent(1);
174   _sci->setIndentationWidth(4);
175   _sci->setIndentationGuides(1);
176   _sci->setIndentationsUseTabs(0);
177   _sci->setAutoCompletionThreshold(2);
178   //_sci->setMarginLineNumbers(1,true);
179   _sci->setMarginWidth(1,0);
180   _sci->setFolding(QsciScintilla::PlainFoldStyle);
181 #endif
182
183   if (!QtGuiContext::getQtCurrent()->isEdition())
184     _sci->setReadOnly(true);
185
186   if (YACS::ENGINE::InlineNode* pyNode =
187       dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode()))
188     {
189       _sci->append(pyNode->getScript().c_str());
190     }
191   connect(_sci, SIGNAL(textChanged()), this, SLOT(onScriptModified()));
192
193   connect(tb_options, SIGNAL(toggled(bool)), this, SLOT(on_tb_options_toggled(bool)));
194   connect(radioremote, SIGNAL(toggled(bool)), this, SLOT(on_remote_toggled(bool)));
195   connect(cb_container, SIGNAL(mousePressed()), this, SLOT(fillContainerPanel()));
196   connect(cb_container, SIGNAL(activated(int)), this, SLOT(changeContainer(int)));
197
198   update(UPDATE,0,0);
199   on_tb_options_toggled(false);
200 }
201
202 EditionScript::~EditionScript()
203 {
204 }
205
206 void EditionScript::synchronize()
207 {
208   DEBTRACE("EditionScript::synchronize " << this->_isEdited);
209   EditionElementaryNode::synchronize();
210   YACS::ENGINE::InlineNode* pyNode = dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode());
211   YASSERT(pyNode);
212   disconnect(_sci, SIGNAL(textChanged()), this, SLOT(onScriptModified()));
213   if (!_isEdited)
214   {
215     _sci->clear();
216     _sci->append(pyNode->getScript().c_str());
217   }
218   connect(_sci, SIGNAL(textChanged()), this, SLOT(onScriptModified()));
219 }
220
221 void EditionScript::onApply()
222 {
223   DEBTRACE("EditionScript::onApply");
224   bool scriptEdited = false;
225 #if HAS_QSCI4>0
226   _sci->lexer()->setFont(Resource::pythonfont);
227 #endif
228
229   if(Resource::pythonExternalEditor.isEmpty())
230     {
231       _editor->hide();
232       _glayout->removeWidget(_editor);
233     }
234   else
235     {
236       _editor->show();
237       if(_glayout->itemAt(0)->widget() != _editor)
238         _glayout->insertWidget ( 0, _editor );
239     }
240
241   if (_haveScript)
242     {
243 #if HAS_QSCI4>0
244       if (_sci->isModified())
245         {
246           scriptEdited = true;
247           std::string text=_sci->text().toStdString();
248           if(text[text.length()-1] != '\n')
249             text=text+'\n';
250           bool ret = _subInlineNode->setScript(text);
251           if (ret) scriptEdited = false;
252         }
253 #else
254       if (_sci->document()->isModified())
255         {
256           scriptEdited = true;
257           std::string text=_sci->document()->toPlainText().toStdString();
258           if(text[text.length()-1] != '\n')
259             text=text+'\n';
260           bool ret = _subInlineNode->setScript(text);
261           if (ret) scriptEdited = false;
262         }
263 #endif
264     }
265
266   bool containerEdited = true;
267   if (formcontainer->onApply()) {
268     fillContainerPanel();
269     containerEdited = false;
270   } else {
271     Message mess(GuiContext::getCurrent()->_lastErrorMessage);
272     return;
273   }
274
275   _isEdited = _isEdited || scriptEdited || containerEdited;
276
277   EditionElementaryNode::onApply();
278 }
279
280 void EditionScript::onCancel()
281 {
282   if (_haveScript)
283     _sci->setText(_subInlineNode->getScript().c_str());
284   formcontainer->onCancel();
285   EditionElementaryNode::onCancel();
286 }
287
288 void EditionScript::onScriptModified()
289 {
290   DEBTRACE("EditionScript::onScriptModified");
291   _isEdited = true;
292   setEdited(true);
293 }
294
295 void EditionScript::onEdit()
296 {
297   DEBTRACE("EditionScript::onEdit");
298   QTemporaryFile outFile;
299   if (!outFile.open())
300     return;
301   QString fileName = outFile.fileName();
302   QTextStream out(&outFile);
303 #if HAS_QSCI4>0
304   out << _sci->text();
305 #else
306   out << _sci->toPlainText();
307 #endif
308   outFile.close();
309
310   QStringList options=Resource::pythonExternalEditor.split(" ");
311   QString prog=options.takeAt(0);
312   QProcess::execute(prog, QStringList() << options << fileName);
313
314   QFile inFile(fileName);
315   if (!inFile.open(QIODevice::ReadOnly))
316     return;
317   QTextStream in(&inFile);
318 #if HAS_QSCI4>0
319   _sci->setText(in.readAll());
320 #else
321   _sci->setPlainText(in.readAll());
322 #endif
323   onApply();
324 }
325
326 void EditionScript::on_tb_options_toggled(bool checked)
327 {
328   DEBTRACE("EditionScript::on_tb_options_toggled " << checked);
329   _checked = checked;
330   if(_checked)
331     {
332       fr_options->show();
333       if(_remote)
334         {
335           fr_container->show();
336           formcontainer->show();
337         }
338     }
339   else
340     {
341       fr_options->hide();
342       fr_container->hide();
343       formcontainer->hide();
344     }
345 }
346
347 void EditionScript::on_remote_toggled(bool checked)
348 {
349   DEBTRACE("EditionScript::on_remote_toggled " << checked);
350   _remote=checked;
351   YACS::ENGINE::InlineNode *pyNode = dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode());
352   std::string mode = pyNode->getExecutionMode();
353   DEBTRACE(mode);
354
355   if(checked)
356     {
357       //remote radio button is checked
358       if(mode != "remote")
359         _subInlineNode->setExecutionMode("remote");
360       fr_container->show();
361       formcontainer->show();
362       fillContainerPanel();
363     }
364   else
365     {
366       //remote radio button is unchecked
367       if(mode != "local")
368         _subInlineNode->setExecutionMode("local");
369       fr_container->hide();
370       formcontainer->hide();
371     }
372 }
373
374 void EditionScript::fillContainerPanel()
375 {
376   DEBTRACE("EditionScript::fillContainerPanel ");
377   YACS::ENGINE::Proc* proc = GuiContext::getCurrent()->getProc();
378
379   cb_container->clear();
380   std::map<string,YACS::ENGINE::Container*>::const_iterator it = proc->containerMap.begin();
381   for(; it != proc->containerMap.end(); ++it)
382     cb_container->addItem( QString((*it).first.c_str()));
383
384   YACS::ENGINE::InlineNode *pyNode = dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode());
385
386   YACS::ENGINE::Container * cont = pyNode->getContainer();
387   if (cont)
388     {
389       int index = cb_container->findText(cont->getName().c_str());
390       cb_container->setCurrentIndex(index);
391       formcontainer->FillPanel(cont);
392     } 
393   else if (cb_container->count()) {
394     changeContainer(0);
395   }
396 }
397
398 void EditionScript::changeContainer(int index)
399 {
400   DEBTRACE("EditionScript::changeContainer ");
401   string contName = cb_container->itemText(index).toStdString();
402   DEBTRACE(contName);
403   YACS::ENGINE::InlineNode *pyNode = dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode());
404   YACS::ENGINE::Container *oldContainer = pyNode->getContainer();
405
406   YACS::ENGINE::Container *newContainer = 0;
407   YACS::ENGINE::Proc* proc = GuiContext::getCurrent()->getProc();
408   if (proc->containerMap.count(contName))
409     newContainer = proc->containerMap[contName];
410   if (!newContainer)
411     {
412       DEBTRACE("-------------> not found : " << contName);
413       return;
414     }
415   YASSERT(GuiContext::getCurrent()->_mapOfSubjectContainer.count(newContainer));
416   SubjectContainerBase *scnt(GuiContext::getCurrent()->_mapOfSubjectContainer[newContainer]);
417
418   _subInlineNode->setContainer(scnt);
419   
420   // show the selected container parameters
421   formcontainer->FillPanel(newContainer);
422 }
423
424 void EditionScript::update(GuiEvent event, int type, Subject* son)
425 {
426   DEBTRACE("EditionScript::update " << eventName(event) <<" "<<type<<" "<<son);
427   EditionElementaryNode::update(event, type, son);
428   if(event == ASSOCIATE)
429     {
430       fillContainerPanel();
431       SubjectContainer *scont = dynamic_cast<SubjectContainer*>(son);
432       YASSERT(scont);
433       formcontainer->FillPanel(scont->getContainer());
434     }
435   else if(event == UPDATE)
436     {
437       YACS::ENGINE::InlineNode *pyNode = dynamic_cast<YACS::ENGINE::InlineNode*>(_subInlineNode->getNode());
438       std::string mode = pyNode->getExecutionMode();
439       if(mode == "remote")
440         {
441           _remote=true;
442           radioremote->setChecked(true);
443         }
444       else if(mode == "local")
445         {
446           _remote=false;
447           radiolocal->setChecked(true);
448         }
449
450       fillContainerPanel();
451     }
452 }
453