Salome HOME
e20a21709eabfc023ce1e76c689a3e3264da2a73
[modules/jobmanager.git] / src / genericgui / BL_GenericGui.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_GenericGui.hxx"
21
22 #ifdef WNT
23 #undef ERROR
24 #endif
25
26 BL::GenericGui::GenericGui(BL::MainWindows_Wrap * wrapper) : QObject(wrapper->getDockParent())
27 {
28   DEBTRACE("Creating BL::GenericGui");
29   BL_ASSERT(wrapper);
30   _wrapper = wrapper;
31   _job_name_selected = "";
32
33   _dock_parent = _wrapper->getDockParent();
34
35   // _salome_services is a servant
36   // POA wil destroy it at the end of the application
37   _salome_services = new BL::SALOMEServices();
38 }
39
40 BL::GenericGui::~GenericGui()
41 {
42   DEBTRACE("Destroying BL::GenericGui");
43   _salome_services->end();
44 }
45
46 void 
47 BL::GenericGui::createDockWidgets()
48 {
49   DEBTRACE("createDockWidgets BL::GenericGui");
50   _jobs_manager = new BL::JobsManager_QT(_dock_parent, this, _salome_services);
51   _model_manager = new BL::QModelManager(this, _jobs_manager);
52   _model = _model_manager->getModel();
53
54   /* Summary */
55   _dw_summary = new QDockWidget(_dock_parent);
56   _dw_summary->setWindowTitle("Summary");
57   _summary = new BL::Summary(_dw_summary, _jobs_manager);
58   _summary->setModel(_model);
59   QScrollArea * scroll_widget_summary = new QScrollArea(_dw_summary);
60   scroll_widget_summary->setWidget(_summary);
61   scroll_widget_summary->setWidgetResizable(true);
62   _dw_summary->setWidget(scroll_widget_summary);
63
64   /* ResourceCatalog */
65   _dw_resource_catalog = new QDockWidget(_dock_parent);
66   _dw_resource_catalog->setWindowTitle("Resource Catalog");
67   _resource_catalog = new JM::ResourceCatalog(_dw_resource_catalog, _salome_services, false);
68   QScrollArea * scroll_widget_resource = new QScrollArea(_dw_resource_catalog);
69   scroll_widget_resource->setWidget(_resource_catalog);
70   scroll_widget_resource->setWidgetResizable(true);
71   _dw_resource_catalog->setWidget(scroll_widget_resource);
72
73   /* Main Dock Window */
74   _dock_parent->addDockWidget(Qt::RightDockWidgetArea, _jobs_manager);
75   _dock_parent->addDockWidget(Qt::RightDockWidgetArea, _dw_summary);
76   _dock_parent->addDockWidget(Qt::RightDockWidgetArea, _dw_resource_catalog);
77   _dock_parent->splitDockWidget(_jobs_manager, _dw_summary, Qt::Vertical);
78   _dock_parent->tabifyDockWidget(_dw_summary, _dw_resource_catalog);
79
80   /* Signals and Slots */
81   // JobsManager -> Model
82   connect(_jobs_manager, SIGNAL(new_job_added(QString)), _model_manager, SLOT(new_job_added(QString)));
83   connect(_jobs_manager, SIGNAL(job_state_changed(QString)), _model_manager, SLOT(job_state_changed(QString)));
84   connect(_jobs_manager, SIGNAL(job_state_changed(QString)), this, SLOT(job_state_changed(QString)));
85   // Model -> summary
86   connect(_model, SIGNAL(rowsInserted(QModelIndex, int, int)), _summary, SLOT(rowsInserted(QModelIndex, int, int)));
87   connect(_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), _summary, SLOT(rowsRemoved(QModelIndex, int, int)));
88   connect(_model, SIGNAL(itemChanged(QStandardItem*)), _summary, SLOT(itemChanged(QStandardItem*)));
89
90   // Init at the end to be able to get jobs already in Launcher
91   if (_salome_services->initNS() == false)
92     DEBMSG("WARNING !!!!! SALOME IS NOT REACHABLE !!!!");
93   // refresh at the beacause we need that _salome_services be
94   // initialized
95   _resource_catalog->refresh_resource_list();
96 }
97
98 void 
99 BL::GenericGui::createCentralWidget()
100 {
101   DEBTRACE("createCentralWidget BL::GenericGui");
102
103   _tab_parent  = _wrapper->getTabParent();
104   /* Tab Central Widget */
105   /* Buttons */
106   _buttons = new BL::Buttons(_tab_parent);
107   _buttons->setCreateButtonSlot(this, SLOT(create_job()));
108   _buttons->setEditCloneButtonSlot(this, SLOT(edit_clone_job()));
109   _buttons->setStartButtonSlot(this, SLOT(start_job()));
110   _buttons->setReStartButtonSlot(this, SLOT(restart_job()));
111   _buttons->setDeleteButtonSlot(this, SLOT(delete_job()));
112   _buttons->setStopButtonSlot(this, SLOT(stop_job()));
113   _buttons->setRefreshButtonSlot(this, SLOT(refresh_job()));
114   _buttons->setGetResultsButtonSlot(this, SLOT(get_results_job()));
115
116   /* Jobs Table */
117   _jobs_table = new BL::JobsTable(_tab_parent);
118   _jobs_table->setModel(_model);
119   _jobs_table->set_main_gui(this);
120
121   /* Job Tab */
122   _job_tab = new BL::JobTab(_tab_parent, _jobs_manager);
123   _job_tab->setModel(_model);
124
125   // Central Widget
126   QWidget * central_widget = new QWidget(_tab_parent);
127   QSplitter * tab_central_widget = new QSplitter(Qt::Vertical, _tab_parent);
128   tab_central_widget->addWidget(_jobs_table);
129   tab_central_widget->addWidget(_job_tab);
130   tab_central_widget->setChildrenCollapsible(false);
131   QVBoxLayout * central_layout = new QVBoxLayout;
132   central_layout->addWidget(_buttons);
133   central_layout->addWidget(tab_central_widget);
134   central_widget->setLayout(central_layout);
135
136   // Adding a scroll area for low resolution
137   QScrollArea * scroll_central_widget = new QScrollArea(_tab_parent);
138   scroll_central_widget->setWidget(central_widget);
139   scroll_central_widget->setWidgetResizable(true);
140   _tab_parent->setCentralWidget(scroll_central_widget);
141
142   /* Signals and Slots */
143   // Model -> JobTab
144   connect(_model, SIGNAL(itemChanged(QStandardItem*)), _job_tab, SLOT(itemChanged(QStandardItem*)));
145
146   // TableView -> X
147   connect(_jobs_table, SIGNAL(clicked(QModelIndex)), this, SLOT(job_selected(QModelIndex)));
148   connect(_jobs_table, SIGNAL(activated(QModelIndex)), this, SLOT(job_activated(QModelIndex)));
149 }
150
151 void
152 BL::GenericGui::deleteDockWidget()
153 {
154   // Specific for SALOME...
155   _dock_parent->removeDockWidget(_dw_summary);
156   delete _dw_summary;
157   _dock_parent->removeDockWidget(_dw_resource_catalog);
158   delete _dw_resource_catalog;
159   _dock_parent->removeDockWidget(_jobs_manager);
160   delete _jobs_manager;
161 }
162
163 void 
164 BL::GenericGui::showDockWidgets(bool isVisible)
165 {
166   DEBTRACE("BL::GenericGui::showDockWidgets " << isVisible);
167   if (_jobs_manager) {
168     _jobs_manager->setVisible(isVisible);
169     _jobs_manager->toggleViewAction()->setVisible(isVisible);
170   }
171   if (_dw_summary) {
172     _dw_summary->setVisible(isVisible);
173     _dw_summary->toggleViewAction()->setVisible(isVisible);
174   }
175   if (_dw_resource_catalog) {
176     _dw_resource_catalog->setVisible(isVisible);
177     _dw_resource_catalog->toggleViewAction()->setVisible(isVisible);
178   }
179 }
180
181 void
182 BL::GenericGui::createActions()
183 {
184   DEBTRACE("CreateActions BL::GenericGui");
185   _create_job_action = _wrapper->createAction("Create a Job", QIcon(), "Create a Job", "Create a Job", 0, _dock_parent, false, this, SLOT(create_job()));
186   _edit_clone_job_action = _wrapper->createAction("Edit/Clone a Job", QIcon(), "Edit/Clone a Job", "Edit/Clone a Job", 0, _dock_parent, false, this, SLOT(edit_clone_job()));
187   _start_job_action = _wrapper->createAction("Start a Job", QIcon(), "Start a Job", "Start a Job", 0, _dock_parent, false, this, SLOT(start_job()));
188   _restart_job_action = _wrapper->createAction("Restart a Job", QIcon(), "Restart a Job", "Restart a Job", 0, _dock_parent, false, this, SLOT(restart_job()));
189   _delete_job_action = _wrapper->createAction("Delete a Job", QIcon(), "Delete a Job", "Delete a Job", Qt::Key_Delete, _dock_parent, false, this, SLOT(delete_job()));
190   _refresh_job_action = _wrapper->createAction("Refresh Jobs", QIcon(), "Refresh Jobs", "Refresh Jobs", 0, _dock_parent, false, this, SLOT(refresh_job()));
191   _get_results_job_action = _wrapper->createAction("Get Job Results", QIcon(), "Get Job Results", "Get Job Results", 0, _dock_parent, false, this, SLOT(refresh_job()));
192   _stop_job_action = _wrapper->createAction("Stop a Job", QIcon(), "Stop a Job", "Stop a Job", 0, _dock_parent, false, this, SLOT(stop_job()));
193 }
194
195 void
196 BL::GenericGui::createMenus()
197 {
198   DEBTRACE("CreateMenus BL::GenericGui");
199   int menu_id = _wrapper->createTopMenu("JobManager");
200   _wrapper->addActionToMenu(_create_job_action, menu_id);
201   _wrapper->addActionToMenu(_edit_clone_job_action, menu_id);
202   _wrapper->addActionToMenu(_start_job_action, menu_id);
203   _wrapper->addActionToMenu(_restart_job_action, menu_id);
204   _wrapper->addActionToMenu(_stop_job_action, menu_id);
205   _wrapper->addActionToMenu(_delete_job_action, menu_id);
206   _wrapper->addActionToMenu(_get_results_job_action, menu_id);
207   _wrapper->addActionToMenu(_refresh_job_action, menu_id);
208 }
209
210 void
211 BL::GenericGui::create_job()
212 {
213   DEBTRACE("Create Job Slot BL::GenericGui");
214   _jobs_manager->create_job();
215 }
216
217 void
218 BL::GenericGui::edit_clone_job()
219 {
220   DEBTRACE("Edit/Clone Job Slot BL::GenericGui");
221   _jobs_manager->edit_clone_job(_job_name_selected.toStdString());
222 }
223
224 void
225 BL::GenericGui::start_job()
226 {
227   DEBTRACE("Start Job Slot BL::GenericGui");
228   _jobs_manager->start_job(_job_name_selected.toStdString());
229   updateButtonsStates();
230 }
231
232 void
233 BL::GenericGui::restart_job()
234 {
235   DEBTRACE("Restart Job Slot BL::GenericGui");
236   _jobs_manager->restart_job(_job_name_selected.toStdString());
237   updateButtonsStates();
238 }
239
240 void
241 BL::GenericGui::refresh_job()
242 {
243   DEBTRACE("Refresh Job Slot BL::GenericGui");
244   _jobs_manager->refresh_jobs();
245 }
246
247 void
248 BL::GenericGui::get_results_job()
249 {
250   DEBTRACE("Get Results Job Slot BL::GenericGui");
251   if (!_jobs_table->isMultipleSelected())
252   {
253     _jobs_manager->get_results_job(_job_name_selected.toStdString());
254   }
255   else
256   {
257     QModelIndexList selected_rows = _jobs_table->selectionModel()->selectedRows();
258     for (int i = 0; i < selected_rows.length(); ++i)
259     {
260       QString job_name = _model->itemFromIndex(selected_rows[i])->text();
261     _jobs_manager->get_results_job(job_name.toStdString());
262     }
263   }
264 }
265
266 void
267 BL::GenericGui::stop_job()
268 {
269   DEBTRACE("Stop Job Slot BL::GenericGui");
270   if (!_jobs_table->isMultipleSelected())
271   {
272     _jobs_manager->stop_job(_job_name_selected.toStdString());
273   }
274   else
275   {
276     QModelIndexList selected_rows = _jobs_table->selectionModel()->selectedRows();
277     for (int i = 0; i < selected_rows.length(); ++i)
278     {
279       QString job_name = _model->itemFromIndex(selected_rows[i])->text();
280       _jobs_manager->stop_job(job_name.toStdString());
281     }
282   }
283 }
284
285
286 void
287 BL::GenericGui::delete_job()
288 {
289   DEBTRACE("Delete Job Slot BL::GenericGui");
290   int ret = QMessageBox::Cancel;
291
292   if (!_jobs_table->isMultipleSelected())
293   {
294     ret = QMessageBox::warning(NULL, "Delete a job", "Do you really want to delete job " + _job_name_selected + " ? ",
295                                QMessageBox::Ok|QMessageBox::Cancel,
296                                QMessageBox::Ok);
297   }
298   else
299   {
300    ret = QMessageBox::warning(NULL, "Delete jobs", "Do you really want to delete these jobs ?",
301                               QMessageBox::Ok|QMessageBox::Cancel,
302                               QMessageBox::Ok);
303   }
304   if (ret == QMessageBox::Ok)
305   {
306     delete_job_internal();
307   }
308 }
309
310 void
311 BL::GenericGui::delete_job_external(const QString & name)
312 {
313   DEBTRACE("Delete Job External");
314   _jobs_manager->delete_job(name);
315   if (!_jobs_table->selectCurrent())
316   {
317     _job_name_selected = "";
318     updateButtonsStates();
319   }
320 }
321
322 void
323 BL::GenericGui::delete_job_internal()
324 {
325   if (!_jobs_table->isMultipleSelected())
326   {
327     QModelIndexList selected_list = _jobs_table->getSelectedIndexes();
328     QString job_name_to_delete    = _model->itemFromIndex(selected_list[0])->text();
329     DEBTRACE("Single Deleting job: " << job_name_to_delete.toStdString());
330     _jobs_manager->delete_job(job_name_to_delete);
331     if (!_jobs_table->selectCurrent())
332     {
333       _job_name_selected = "";
334       updateButtonsStates();
335     }
336   }
337   else
338   {
339     QModelIndexList selected_list = _jobs_table->getSelectedIndexes();
340     QString job_name = _model->itemFromIndex(selected_list[0])->text();
341     DEBTRACE("Multiple Deleting job: " << job_name.toStdString());
342     _jobs_manager->delete_job(job_name);
343     delete_job_internal(); // Recursive delete
344   }
345 }
346
347 void
348 BL::GenericGui::reset_job_selection()
349 {
350   _job_name_selected = "";
351   _job_tab->reset("");
352   updateButtonsStates();
353 }
354
355 void
356 BL::GenericGui::job_selected(const QModelIndex & index)
357 {
358   DEBTRACE("BL::GenericGui::job_selected");
359
360   //Find if a job is selected (ignore index)
361   //If Multiple job are selected, take first job
362   QItemSelectionModel * selection_model = _jobs_table->selectionModel();
363   QModelIndexList selected_rows = selection_model->selectedRows();
364   if (selected_rows.length() >= 1)
365   {
366     QModelIndex idx = selected_rows[0];
367     QStandardItem * item = _model->itemFromIndex(idx);
368     QStandardItem * item_name = _model->item(item->row());
369     _job_name_selected = item_name->text();
370     _job_tab->job_selected(idx);
371     DEBTRACE("BL::GenericGui::job_selected name is " << _job_name_selected.toStdString());
372   }
373   else
374   {
375     _job_name_selected = "";
376     _job_tab->reset("");
377     DEBTRACE("BL::GenericGui::job_selected - no jobs are selected");
378   }
379   updateButtonsStates();
380 }
381
382 void
383 BL::GenericGui::job_activated(const QModelIndex & index)
384 {
385   DEBTRACE("BL::GenericGui::job_activated slot");
386   job_selected(index);
387 }
388
389 void
390 BL::GenericGui::job_state_changed(const QString & name)
391 {
392   if (name == _job_name_selected)
393     updateButtonsStates();
394 }
395
396 void
397 BL::GenericGui::updateButtonsStates()
398 {
399   if (!_jobs_table->isMultipleSelected())
400   {
401     updateButtonsStatesSingleSelection();
402   }
403   else
404   {
405     _start_job_action->setEnabled(false);
406     _edit_clone_job_action->setEnabled(false);
407     _restart_job_action->setEnabled(false);
408     _buttons->disable_start_button();
409     _buttons->disable_edit_clone_button();
410     _buttons->disable_restart_button();
411
412     // You can always delete jobs
413     _delete_job_action->setEnabled(true);
414     _buttons->enable_delete_button();
415
416     // Enable stop ?
417     bool enable_stop = true;
418     QModelIndexList selected_rows = _jobs_table->selectionModel()->selectedRows();
419     for (int i = 0; i < selected_rows.length(); ++i)
420     {
421       QString job_name = _model->itemFromIndex(selected_rows[i])->text();
422       BL::Job * job = _jobs_manager->getJob(job_name.toStdString());
423       BL::Job::State job_state = job->getState();
424       if (job_state != BL::Job::QUEUED  &&
425           job_state != BL::Job::RUNNING &&
426           job_state != BL::Job::PAUSED)
427         enable_stop = false;
428     }
429     if (enable_stop)
430     {
431       _stop_job_action->setEnabled(true);
432       _buttons->enable_stop_button();
433     }
434     else
435     {
436       _stop_job_action->setEnabled(false);
437       _buttons->disable_stop_button();
438     }
439
440     // Enable get_results ?
441     bool enable_results = true;
442     for (int i = 0; i < selected_rows.length(); ++i)
443     {
444       QString job_name = _model->itemFromIndex(selected_rows[i])->text();
445       BL::Job * job = _jobs_manager->getJob(job_name.toStdString());
446       BL::Job::State job_state = job->getState();
447       if (job_state != BL::Job::FINISHED &&
448           job_state != BL::Job::FAILED)
449         enable_results= false;
450     }
451     if (enable_results)
452     {
453       _get_results_job_action->setEnabled(true);
454       _buttons->enable_get_results_button();
455     }
456     else
457     {
458       _get_results_job_action->setEnabled(false);
459       _buttons->disable_get_results_button();
460     }
461   }
462 }
463
464 void
465 BL::GenericGui::updateButtonsStatesSingleSelection()
466 {
467   DEBTRACE("BL::GenericGui::updateButtonsStatesSingleSelection slot");
468
469   // First case: no job selected
470   if (_job_name_selected == "")
471   {
472     _start_job_action->setEnabled(false);
473     _delete_job_action->setEnabled(false);
474     _get_results_job_action->setEnabled(false);
475     _buttons->disable_start_button();
476     _buttons->disable_delete_button();
477     _buttons->disable_get_results_button();
478     _edit_clone_job_action->setEnabled(false);
479     _buttons->disable_edit_clone_button();
480     _restart_job_action->setEnabled(false);
481     _buttons->disable_restart_button();
482     _stop_job_action->setEnabled(false);
483     _buttons->disable_stop_button();
484   }
485   else if (_job_name_selected != "")
486   {
487     BL::Job * job = _jobs_manager->getJob(_job_name_selected.toStdString());
488     BL::Job::State job_state = job->getState();
489
490     _edit_clone_job_action->setEnabled(true);
491     _buttons->enable_edit_clone_button();
492     switch (job_state)
493     {
494       case BL::Job::CREATED:
495         _start_job_action->setEnabled(true);
496         _delete_job_action->setEnabled(true);
497         _get_results_job_action->setEnabled(false);
498         _buttons->enable_start_button();
499         _buttons->enable_delete_button();
500         _buttons->disable_get_results_button();
501         _restart_job_action->setEnabled(false);
502         _buttons->disable_restart_button();
503         _stop_job_action->setEnabled(false);
504         _buttons->disable_stop_button();
505         break;
506
507       case BL::Job::IN_PROCESS:
508         _start_job_action->setEnabled(false);
509         _buttons->disable_start_button();
510         _delete_job_action->setEnabled(false);
511         _buttons->disable_delete_button();
512         _get_results_job_action->setEnabled(false);
513         _buttons->disable_get_results_button();
514         _restart_job_action->setEnabled(false);
515         _buttons->disable_restart_button();
516         _stop_job_action->setEnabled(false);
517         _buttons->disable_stop_button();
518         break;
519
520       case BL::Job::QUEUED:
521         _start_job_action->setEnabled(false);
522         _buttons->disable_start_button();
523         _delete_job_action->setEnabled(true);
524         _buttons->enable_delete_button();
525         _get_results_job_action->setEnabled(false);
526         _buttons->disable_get_results_button();
527         _restart_job_action->setEnabled(false);
528         _buttons->disable_restart_button();
529         _stop_job_action->setEnabled(true);
530         _buttons->enable_stop_button();
531         break;
532
533       case BL::Job::RUNNING:
534         _start_job_action->setEnabled(false);
535         _buttons->disable_start_button();
536         _delete_job_action->setEnabled(true);
537         _buttons->enable_delete_button();
538         _get_results_job_action->setEnabled(false);
539         _buttons->disable_get_results_button();
540         _restart_job_action->setEnabled(false);
541         _buttons->disable_restart_button();
542         _stop_job_action->setEnabled(true);
543         _buttons->enable_stop_button();
544         break;
545
546       case BL::Job::PAUSED:
547         _start_job_action->setEnabled(false);
548         _buttons->disable_start_button();
549         _delete_job_action->setEnabled(true);
550         _buttons->enable_delete_button();
551         _get_results_job_action->setEnabled(false);
552         _buttons->disable_get_results_button();
553         _restart_job_action->setEnabled(false);
554         _buttons->disable_restart_button();
555         _stop_job_action->setEnabled(true);
556         _buttons->enable_stop_button();
557         break;
558
559       case BL::Job::ERROR:
560         _start_job_action->setEnabled(false);
561         _buttons->disable_start_button();
562         _delete_job_action->setEnabled(true);
563         _buttons->enable_delete_button();
564         _get_results_job_action->setEnabled(false);
565         _buttons->disable_get_results_button();
566         _restart_job_action->setEnabled(true);
567         _buttons->enable_restart_button();
568         _stop_job_action->setEnabled(false);
569         _buttons->disable_stop_button();
570         break;
571
572       case BL::Job::FINISHED:
573         _start_job_action->setEnabled(false);
574         _buttons->disable_start_button();
575         _delete_job_action->setEnabled(true);
576         _buttons->enable_delete_button();
577         _get_results_job_action->setEnabled(true);
578         _buttons->enable_get_results_button();
579         _restart_job_action->setEnabled(true);
580         _buttons->enable_restart_button();
581         _stop_job_action->setEnabled(false);
582         _buttons->disable_stop_button();
583         break;
584
585       case BL::Job::FAILED:
586         _start_job_action->setEnabled(false);
587         _buttons->disable_start_button();
588         _delete_job_action->setEnabled(true);
589         _buttons->enable_delete_button();
590         _get_results_job_action->setEnabled(true);
591         _buttons->enable_get_results_button();
592         _restart_job_action->setEnabled(true);
593         _buttons->enable_restart_button();
594         _stop_job_action->setEnabled(false);
595         _buttons->disable_stop_button();
596         break;
597
598       case BL::Job::NOT_CREATED:
599         _start_job_action->setEnabled(false);
600         _buttons->disable_start_button();
601         _delete_job_action->setEnabled(true);
602         _buttons->enable_delete_button();
603         _get_results_job_action->setEnabled(false);
604         _buttons->disable_get_results_button();
605         _restart_job_action->setEnabled(true);
606         _buttons->enable_restart_button();
607         _stop_job_action->setEnabled(false);
608         _buttons->disable_stop_button();
609         break;
610     }
611   }
612   else
613   {
614     DEBTRACE("ERROR in updateButtonsStates !!!!!!");
615   }
616 }