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