Salome HOME
Merge from V6_main 01/04/2013
[modules/jobmanager.git] / src / genericgui / BL_JobsManager_QT.cxx
1 // Copyright (C) 2009-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 "BL_JobsManager_QT.hxx"
21 #include "BL_GenericGui.hxx"
22
23 BL::JobManagerEvent::JobManagerEvent(const std::string & action_i, 
24                                      const std::string & event_name_i, 
25                                      const std::string & job_name_i, 
26                                      const std::string & data_i) : QEvent(QEvent::User)
27 {
28   action = action_i;
29   event_name = event_name_i;
30   job_name = job_name_i;
31   data = data_i;
32 }
33
34 BL::JobManagerEvent::~JobManagerEvent() {}  
35
36 BL::JobsManager_QT::JobsManager_QT(QWidget * parent, BL::GenericGui * main_gui, BL::SALOMEServices * salome_services) : 
37   QDockWidget(parent), BL::JobsManager(salome_services)
38 {
39   DEBTRACE("Creating BL::JobsManager_QT");
40   _main_gui = main_gui;
41   setObserver(this);
42   _model_manager = NULL;
43
44   // Widget Part
45
46   QWidget * main_widget = new QWidget(this);
47
48   _load_jobs = new QPushButton("Load Jobs");
49   _save_jobs = new QPushButton("Save Jobs");
50   connect(_load_jobs, SIGNAL(clicked()), this, SLOT(load_jobs_button()));
51   connect(_save_jobs, SIGNAL(clicked()), this, SLOT(save_jobs_button()));
52
53   _auto_refresh_jobs = new QPushButton("Auto Refresh: no");
54   _timer = new QTimer(this);
55   _timer->stop();
56   connect(_timer, SIGNAL(timeout()), this, SLOT(RefreshJobs()));
57
58   // Menu for auto refresh
59   QMenu * refresh_menu = new QMenu(this);
60   refresh_menu->addAction("No", this, SLOT(no_auto_refresh()));
61   refresh_menu->addAction("10 seconds", this, SLOT(ten_seconds_refresh()));
62   refresh_menu->addAction("30 seconds", this, SLOT(thirty_seconds_refresh()));
63   refresh_menu->addAction("1 minute", this, SLOT(one_minute_refresh()));
64   refresh_menu->addAction("5 minutes", this, SLOT(five_minutes_refresh()));
65   refresh_menu->addAction("30 minutes", this, SLOT(thirty_minutes_refresh()));
66   refresh_menu->addAction("1 hour", this, SLOT(one_hour_refresh()));
67   _auto_refresh_jobs->setMenu(refresh_menu);
68
69   QHBoxLayout * button_layout = new QHBoxLayout();
70   button_layout->addWidget(_load_jobs);
71   button_layout->addWidget(_save_jobs);
72   button_layout->addWidget(_auto_refresh_jobs);
73
74   QGroupBox * message_box = new QGroupBox("Messages");
75   _log = new QTextEdit(this);
76   _log->setReadOnly(true);
77   QVBoxLayout * message_box_layout = new QVBoxLayout(message_box);
78   message_box_layout->addWidget(_log);
79   message_box->setLayout(message_box_layout);
80
81   QVBoxLayout * mainLayout = new QVBoxLayout();
82   mainLayout->addLayout(button_layout);
83   mainLayout->addWidget(message_box);
84   main_widget->setLayout(mainLayout);
85
86   QScrollArea * scroll_widget = new QScrollArea(this);
87   scroll_widget->setWidget(main_widget);
88   scroll_widget->setWidgetResizable(true);
89   setWidget(scroll_widget);
90   setWindowTitle("Job Manager");
91 }
92
93 BL::JobsManager_QT::~JobsManager_QT()
94 {
95   DEBTRACE("Destroying BL::JobsManager_QT");
96 }
97
98 void
99 BL::JobsManager_QT::set_model_manager(BL::QModelManager * model_manager)
100 {
101   _model_manager = model_manager;
102 }
103
104 void
105 BL::JobsManager_QT::load_jobs_button()
106 {
107   DEBTRACE("load_jobs");
108   QString jobs_file = QFileDialog::getOpenFileName(this,
109                                                    tr("Choose an xml jobs file"), "",
110                                                    tr("xml (*.xml);;All Files (*)"));
111   if (jobs_file == "")
112   {
113     write_normal_text("Load jobs action cancelled\n");
114   }
115   else
116     load_jobs(jobs_file.toStdString());
117 }
118
119 void
120 BL::JobsManager_QT::save_jobs_button()
121 {
122   DEBTRACE("save_jobs");
123   QFileDialog dialog(this, "Save jobs file");
124   QStringList filters;
125   filters << "XML files (*.xml)"
126           << "Any files (*)";
127   dialog.setFileMode(QFileDialog::AnyFile);
128   dialog.setFilters(filters);
129   dialog.selectFilter("(*.xml)");
130   dialog.setDefaultSuffix("xml");
131   dialog.setConfirmOverwrite(true);
132   dialog.setAcceptMode(QFileDialog::AcceptSave);
133   QString jobs_file("");
134   QStringList fileNames;
135   fileNames.clear();
136   if (bool ret = dialog.exec())
137   {
138     DEBTRACE(ret << " " << dialog.confirmOverwrite());
139     fileNames = dialog.selectedFiles();
140     if (!fileNames.isEmpty())
141       jobs_file= fileNames.first();
142   }
143   if (jobs_file == "")
144   {
145     write_normal_text("Save jobs action cancelled\n");
146   }
147   else
148     save_jobs(jobs_file.toStdString());
149 }
150
151 void
152 BL::JobsManager_QT::RefreshJobs()
153 {
154   refresh_jobs(); 
155 }
156
157 void
158 BL::JobsManager_QT::no_auto_refresh()
159 {
160   _auto_refresh_jobs->setText("Auto Refresh: no");
161   _timer->stop();
162 }
163
164 void
165 BL::JobsManager_QT::ten_seconds_refresh()
166 {
167   _auto_refresh_jobs->setText("Auto Refresh: 10s");
168   _timer->stop();
169   _timer->start(10 * 1000);
170 }
171
172 void 
173 BL::JobsManager_QT::thirty_seconds_refresh()
174 {
175   _auto_refresh_jobs->setText("Auto Refresh: 30s");
176   _timer->stop();
177   _timer->start(30 * 1000);
178 }
179
180 void 
181 BL::JobsManager_QT::one_minute_refresh()
182 {
183   _auto_refresh_jobs->setText("Auto Refresh: 1min");
184   _timer->stop();
185   _timer->start(1 * 60 * 1000);
186 }
187
188 void 
189 BL::JobsManager_QT::five_minutes_refresh()
190 {
191   _auto_refresh_jobs->setText("Auto Refresh: 5min");
192   _timer->stop();
193   _timer->start(5 * 60 * 1000);
194 }
195
196 void 
197 BL::JobsManager_QT::thirty_minutes_refresh()
198 {
199   _auto_refresh_jobs->setText("Auto Refresh: 30min");
200   _timer->stop();
201   _timer->start(30 * 60 * 1000);
202 }
203
204 void 
205 BL::JobsManager_QT::one_hour_refresh()
206 {
207   _auto_refresh_jobs->setText("Auto Refresh: 1hour");
208   _timer->stop();
209   _timer->start(1 * 60 * 60 * 1000);
210 }
211
212 void 
213 BL::JobsManager_QT::restart_job(const std::string & name)
214 {
215   DEBTRACE("Restart job with name: " << name);
216   BL::CreateJobWizard wizard(this, _salome_services);
217   wizard.clone(name);
218   wizard.end(1);
219   wizard.job_name = name;
220   wizard.start_job = true;
221   _main_gui->delete_job_internal();
222   create_job_with_wizard(wizard);
223 }
224
225 void 
226 BL::JobsManager_QT::edit_clone_job(const std::string & name)
227 {
228   BL::CreateJobWizard wizard(this, _salome_services);
229   wizard.clone(name);
230   wizard.exec();
231
232   // Check if the job has the same name
233   if (name == wizard.job_name)
234   {
235     DEBTRACE("Job " << name << " has been edited");
236     _main_gui->delete_job_internal();
237   }
238
239   if (wizard.job_name != "")
240   {
241     create_job_with_wizard(wizard);
242   }
243   else
244   {
245     DEBTRACE("User cancel Create Job Wizard");
246   }
247 }
248
249 void
250 BL::JobsManager_QT::create_job()
251 {
252     BL::CreateJobWizard wizard(this, _salome_services);
253     wizard.exec();
254     if (wizard.job_name != "")
255     {
256       create_job_with_wizard(wizard);
257     }
258     else
259     {
260        DEBTRACE("User cancel Create Job Wizard");
261     }
262 }
263
264 void 
265 BL::JobsManager_QT::create_job_with_wizard(BL::CreateJobWizard & wizard)
266 {
267   BL::Job * new_job = createJob(wizard.job_name);
268   if (wizard.yacs_file != "")
269   {
270     // YACS schema job
271     new_job->setType(BL::Job::YACS_SCHEMA);
272     new_job->setJobFile(wizard.yacs_file);
273     new_job->setDumpYACSState(wizard.dump_yacs_state);
274   }
275   else if (wizard.command != "")
276   {
277     // Command Job
278     new_job->setType(BL::Job::COMMAND);
279     new_job->setJobFile(wizard.command);
280   }
281   else if (wizard.python_salome_file != "")
282   {
283     // Command Job
284     new_job->setType(BL::Job::PYTHON_SALOME);
285     new_job->setJobFile(wizard.python_salome_file);
286   }
287
288   // For all jobs
289   new_job->setEnvFile(wizard.env_file);
290   BL::Job::BatchParam param;
291   param.batch_directory = wizard.batch_directory;
292   param.maximum_duration = wizard.maximum_duration;
293   param.expected_memory = wizard.expected_memory;
294   param.nb_proc = wizard.nb_proc;
295   new_job->setBatchParameters(param);
296   BL::Job::FilesParam files_params;
297   files_params.result_directory = wizard.result_directory;
298   files_params.input_files_list = wizard.input_files_list;
299   files_params.output_files_list = wizard.output_files_list;
300   new_job->setFilesParameters(files_params);
301   new_job->setResource(wizard.resource_choosed);
302   new_job->setBatchQueue(wizard.batch_queue);
303   new_job->setLoadLevelerJobType(wizard.ll_jobtype);
304
305   // End
306   addJobToLauncher(wizard.job_name);
307   emit new_job_added(QString::fromStdString(wizard.job_name));
308   QStandardItemModel * model = _model_manager->getModel();
309   QList<QStandardItem *> item_list = model->findItems(QString::fromStdString(wizard.job_name));
310   QStandardItem * job_state_item = model->item(item_list.at(0)->row(), 2);
311   _main_gui->_jobs_table->selectRow(item_list.at(0)->row());
312   if (wizard.start_job)
313     start_job(wizard.job_name);
314 }
315
316 void
317 BL::JobsManager_QT::delete_job(QString job_name)
318 {
319   BL::JobsManager::removeJob(job_name.toStdString());
320   _model_manager->delete_job(job_name);
321   _main_gui->_job_tab->reset(job_name);
322 }
323
324 void 
325 BL::JobsManager_QT::sendEvent(const std::string & action, 
326                               const std::string & event_name, 
327                               const std::string & job_name, 
328                               const std::string & data)
329 {
330   DEBTRACE("sendEvent BL::JobsManager_QT");
331
332   // Sending a QEvent to go back to main thread
333   BL::JobManagerEvent * event = new JobManagerEvent(action, event_name, job_name, data);
334   QApplication::postEvent(this, event);
335 }
336
337 bool 
338 BL::JobsManager_QT::event(QEvent * e)
339 {
340   QDockWidget::event(e);
341   JobManagerEvent * event = dynamic_cast<JobManagerEvent*>(e);
342   if (!event) return false;
343
344   DEBTRACE("BL::JobsManager_QT Receiving event : " 
345            << event->action << " " 
346            << event->event_name << " "
347            << event->job_name << " "
348            << event->data);
349
350   if (event->action == "create_job")
351   {
352     if (event->event_name == "Ok")
353     {
354       QString str((event->job_name).c_str());
355       write_normal_text("Job " + str + " created\n");
356     }
357     else
358     {
359       QString str((event->job_name).c_str());
360       write_error_text("Error in creating job: " + str + "\n");
361       write_error_text("*** ");
362       write_error_text((event->data).c_str());
363       write_error_text(" ***\n");
364     }
365   }
366   else if (event->action == "start_job")
367   {
368     if (event->event_name == "Ok")
369     {
370       QString str((event->job_name).c_str());
371       write_normal_text("Job " + str + " queued\n");
372     }
373     else
374     {
375       QString str((event->job_name).c_str());
376       write_error_text("Error in starting job: " + str + "\n");
377       write_error_text("*** ");
378       write_error_text((event->data).c_str());
379       write_error_text(" ***\n");
380     }
381     emit job_state_changed(QString((event->job_name).c_str()));
382   }
383   else if (event->action == "refresh_job")
384   {
385     if (event->event_name == "Ok")
386     {
387       QString name((event->job_name).c_str());
388       QString state((event->data).c_str());
389       state = state.toLower();
390       write_normal_text("Job " + name + " new state is " + state + "\n");
391       emit job_state_changed(QString((event->job_name).c_str()));
392     }
393     else
394     {
395       QString str((event->job_name).c_str());
396       write_error_text("Error in refreshing job: " + str + "\n");
397       write_error_text("*** ");
398       write_error_text((event->data).c_str());
399       write_error_text(" ***\n");
400     }
401   }
402   else if (event->action == "delete_job")
403   {
404     if (event->event_name == "Ok")
405     {
406       QString str((event->job_name).c_str());
407       write_normal_text("Job " + str + " deleted\n");
408     }
409     else
410     {
411       QString str((event->job_name).c_str());
412       write_error_text("Warning delete job: " + str + " maybe not complete, exception catch in SALOME Launcher service\n");
413       write_error_text("*** ");
414       write_error_text((event->data).c_str());
415       write_error_text(" ***\n");
416     }
417   }
418   else if (event->action == "get_results_job")
419   {
420     if (event->event_name == "Ok")
421     {
422       QString str((event->job_name).c_str());
423       write_normal_text("Results of Job " + str + " are get\n");
424     }
425     else
426     {
427       QString str((event->job_name).c_str());
428       write_error_text("Warning for results of job: " + str + " maybe not complete, exception catch in SALOME Launcher service\n");
429       write_error_text("*** ");
430       write_error_text((event->data).c_str());
431       write_error_text(" ***\n");
432     }
433   }
434   else if (event->action == "stop_job")
435   {
436     if (event->event_name == "Ok")
437     {
438       QString str((event->job_name).c_str());
439       write_normal_text("Job " + str + " is stopped\n");
440     }
441     else
442     {
443       QString str((event->job_name).c_str());
444       write_error_text("Error when trying to stop job: " + str + "\n");
445       write_error_text("*** ");
446       write_error_text((event->data).c_str());
447       write_error_text(" ***\n");
448     }
449   }
450   else if (event->action == "save_jobs")
451   {
452     if (event->event_name == "Error")
453     {
454       write_error_text("Error in saving jobs: \n");
455       write_error_text("*** ");
456       write_error_text((event->data).c_str());
457       write_error_text(" ***\n");
458     }
459     else
460     {
461       QString str((event->data).c_str());
462       write_normal_text("Jobs saved in file " + str + "\n");
463     }
464   }
465   else if (event->action == "load_jobs")
466   {
467     if (event->event_name == "Error")
468     {
469       write_error_text("Error in loading jobs: \n");
470       write_error_text("*** ");
471       write_error_text((event->data).c_str());
472       write_error_text(" ***\n");
473     }
474     else
475     {
476       QString str((event->data).c_str());
477       write_normal_text("Jobs loaded from file " + str + "\n");
478     }
479   }
480   else if (event->action == "add_job")
481   {
482     if (event->event_name == "Ok")
483     {
484       QString str((event->job_name).c_str());
485       write_normal_text("New job added " + str + "\n");
486       emit new_job_added(str);
487     }
488   }
489   else if (event->action == "to_remove_job")
490   {
491     if (event->event_name == "Ok")
492       _main_gui->delete_job_external((event->job_name).c_str());
493   }
494   else
495   {
496     QString str((event->action).c_str());
497     write_error_text("Unknown type of event received:" + str + "\n");
498   }
499   return true;
500 }
501
502 void 
503 BL::JobsManager_QT::write_normal_text(const QString & text)
504 {
505   _log->setReadOnly(false);
506   QTextCursor cursor = _log->textCursor();
507   QTextCharFormat text_format;
508   text_format.setForeground(Qt::darkBlue);
509   cursor.insertText(text, text_format);
510   _log->setTextCursor(cursor);
511   _log->setReadOnly(true);
512 }
513
514 void 
515 BL::JobsManager_QT::write_error_text(const QString & text)
516 {
517   _log->setReadOnly(false);
518   QTextCursor cursor = _log->textCursor();
519   QTextCharFormat text_format;
520   text_format.setForeground(Qt::red);
521   cursor.insertText(text, text_format);
522   _log->setTextCursor(cursor);
523   _log->setReadOnly(true);
524 }