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