ScenarioListController.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package ArmarXCore::core
19 * @author Cedric Seehausen (usdnr at kit dot edu)
20 * @date 2016
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25
27
28#include <sstream>
29#include <thread>
30
31#include <QApplication>
32#include <QMessageBox>
33#include <QSettings>
34#include <QTimer>
35
36#include <SimoxUtility/algorithm/string/string_tools.h>
37
49
51#include "../gui/scenarioitem.h"
52
53using namespace ScenarioManager;
54using namespace Controller;
55using namespace Data_Structure;
56using namespace Parser;
57using namespace Exec;
58
59#define UPDATE_TIMER 500 //ms
60
62 ExecutorPtr executor,
63 QObject* parent) :
64 QObject(parent),
65 treemodel(),
67 packages(packages),
68 executor(executor)
69{
70 qRegisterMetaType<ApplicationInstanceStatusMap>("ApplicationInstanceStatusMap");
71 qRegisterMetaType<FilterableTreeModelSortFilterProxyModelPtr>(
72 "FilterableTreeModelSortFilterProxyModelPtr");
73
74 QTimer* timer = new QTimer(this);
75 QObject::connect(timer, SIGNAL(timeout()), this, SLOT(updateStati()));
76 timer->start(UPDATE_TIMER);
77
78 updateTask = new armarx::SimplePeriodicTask<>(
79 [&] { fetchStati(); }, 100, false, "ScenarioManagerUpdateStatusTask");
80 updateTask->start();
81
82 model->setDynamicSortFilter(true);
83 model->setSourceModel(&treemodel);
84
85 QObject::connect(&createScenarioView,
86 SIGNAL(created(std::string, std::string)),
87 this,
88 SLOT(createdScenario(std::string, std::string)));
89
90 QObject::connect(&treemodel,
91 SIGNAL(applicationsDrop(
92 QList<QPair<QString, ScenarioManager::Data_Structure::Application*>>,
93 int,
94 QModelIndex)),
95 this,
97 QList<QPair<QString, ScenarioManager::Data_Structure::Application*>>,
98 int,
99 QModelIndex)));
100 QObject::connect(this,
102 this,
104}
105
107{
108 updateTask->stop();
109}
110
113{
114 return model;
115}
116
117void
118ScenarioListController::stop(int row, int column, QModelIndex parent)
119{
120 ScenarioItem* item =
121 model->data(model->index(row, column, parent), SCENARIOITEMSOURCE).value<ScenarioItem*>();
122 if (item == nullptr)
123 {
124 return;
125 }
126 if (parent.isValid())
127 {
128 if (parent.parent().isValid()) //stop application
129 {
130 if (!item->isEnabled())
131 {
132 return;
133 }
135 executor->stopApplication(instance);
136 }
137 else //stop packageSubpackage
138 {
139 if (!item->isEnabled())
140 {
141 return;
142 }
143 for (const auto& app : *item->getApplicationInstances())
144 {
145 executor->stopApplication(app);
146 }
147 }
148 }
149 else //stop scenario
150 {
151 ScenarioPtr scenario = item->getScenario();
152 executor->stopScenario(scenario);
153 }
154
155 refreshNow();
156}
157
158void
160{
161 updateTask->stop();
162}
163
164void
165ScenarioListController::start(int row, int column, QModelIndex parent)
166{
167 ScenarioItem* item =
168 model->data(model->index(row, column, parent), SCENARIOITEMSOURCE).value<ScenarioItem*>();
169 if (!item)
170 {
171 return;
172 }
173 if (parent.isValid())
174 {
175 if (parent.parent().isValid()) //start application
176 {
177 if (!item->isEnabled())
178 {
179 return;
180 }
182 instance->updateFound();
183 if (!instance->getFound())
184 {
185 ShowWarningDialog(
186 "The binary `" + QString::fromStdString(instance->getExecutableAbsPath()) +
187 "` for the application " + QString::fromStdString(instance->getName()) +
188 " could not be found");
189 treemodel.update();
190 return;
191 }
192 auto scenario = instance->getScenario();
193 executor->startApplication(instance);
194 }
195 else // start packagesubtree
196 {
197 if (!item->isEnabled())
198 {
199 return;
200 }
202 for (const auto& app : *item->getApplicationInstances())
203 {
204 app->updateFound();
205 if (!app->getFound())
206 {
207 ShowWarningDialog("The Binary for the Application " +
208 QString::fromStdString(app->getName()) +
209 " could not be found");
210 treemodel.update();
211 return;
212 }
213
214 executor->startApplication(app);
215 }
216 }
217 }
218 else //start scenario
219 {
220 startScenario(item);
221 }
222
223 refreshNow();
224}
225
226void
227ScenarioListController::startScenario(ScenarioItem* scenarioItem)
228{
229 ScenarioPtr scenario = scenarioItem->getScenario();
230 StartScenario(scenario, executor, iceAdmin);
231}
232
233void
234ScenarioListController::restart(int row, int column, QModelIndex parent)
235{
236 //hole entsprechende application aus dem package und uebergebe sie dem executor zum restarten & update model entsprechend
237 ScenarioItem* item =
238 model->data(model->index(row, column, parent), SCENARIOITEMSOURCE).value<ScenarioItem*>();
239 if (item == nullptr || !item->isEnabled())
240 {
241 return;
242 }
243 if (parent.isValid())
244 {
245 if (parent.parent().isValid())
246 {
247 //start/stop application
248 executor->restartApplication(item->getApplicationInstance());
249 }
250 else
251 {
252 //start/stop packageSubtree
253 for (const auto& app : *item->getApplicationInstances())
254 {
255 executor->restartApplication(app);
256 }
257 }
258 }
259 else //start/stop scenario
260 {
261 try
262 {
263 executor->restartScenario(item->getScenario());
264 }
265 catch (IceGrid::ServerStartException& ex)
266 {
267 ShowWarningDialog("Ice had an launching error. Please make sure your remote launch "
268 "settings are correct");
269 }
270 }
271
272 refreshNow();
273}
274
275void
277 QList<QPair<QString, ScenarioManager::Data_Structure::Application*>> applications,
278 int row,
279 const QModelIndex& parent)
280{
281 ScenarioItem* item; //reinterpret_cast<ScenarioItem*>(model->data(parent, SCENARIOITEM).data());
282 QModelIndex scenarioIndex;
283
284 if (parent.parent().isValid() && parent.parent().parent().isValid())
285 {
286 item = model->data(parent.parent().parent(), SCENARIOITEMPROXY).value<ScenarioItem*>();
287 scenarioIndex = parent.parent().parent();
288 }
289 else if (parent.parent().isValid())
290 {
291 item = model->data(parent.parent(), SCENARIOITEMPROXY).value<ScenarioItem*>();
292 scenarioIndex = parent.parent();
293 }
294 else
295 {
296 item = model->data(parent, SCENARIOITEMPROXY).value<ScenarioItem*>();
297 scenarioIndex = parent;
298 }
299
300 if (item == nullptr)
301 {
302 return;
303 }
304
305 ScenarioPtr scenario = item->getScenario();
306 if (!scenario->isScenarioFileWriteable())
307 {
308 QMessageBox::critical(
309 0,
310 "Adding application failed!",
311 "The scenario '" + QString::fromStdString(scenario->getName()) +
312 "' is read only. You cannot add an application to this scenario!");
313 return;
314 }
316 std::vector<std::string> acceptedApps =
317 generator.getDependencieTree(scenario->getPackage()->getName());
318
319
320 for (const auto& pair : applications)
321 {
323 PackagePtr appPackage;
324 for (const auto& package : *packages)
325 {
326 for (const auto& pApp : *package->getApplications())
327 {
328 if (pApp->getName().compare(app->getName()) == 0)
329 {
330 appPackage = package;
331 }
332 }
333 }
334
335 if (appPackage.get() == nullptr)
336 {
337 return;
338 }
339
340 if (std::find(acceptedApps.begin(), acceptedApps.end(), appPackage->getName()) ==
341 acceptedApps.end())
342 {
343 const std::string dependenciesStr = simox::alg::join(acceptedApps, ", ");
344
345 QMessageBox box;
346 QString message("You cannot drop an app from ");
347 message.append(QString::fromStdString(appPackage->getName()));
348 message.append(" into a scenario from ");
349 message.append(QString::fromStdString(scenario->getPackage()->getName()));
350 message.append(QString::fromStdString(". Package `" +
351 scenario->getPackage()->getName() +
352 "` depends on " + dependenciesStr));
353 box.setText(message);
354 box.exec();
355 return;
356 }
357
358
359 const std::string appName = app->getName();
360
361 int instanceCounter = 0;
362 std::string instanceName = pair.first.toStdString();
363 if (instanceName.empty())
364 {
365 for (const ApplicationInstancePtr& instances : *scenario->getApplications())
366 {
367 if (instances->getName().compare(appName) == 0)
368 {
369 instanceCounter++;
370 }
371 }
372 if (instanceCounter == 0)
373 {
374 instanceName = "";
375 }
376 else
377 {
378 instanceName = "instance" + std::to_string(instanceCounter);
379 }
380 }
381 else
382 {
383 for (const ApplicationInstancePtr& instances : *scenario->getApplications())
384 {
385 if (instances->getInstanceName().compare(instanceName) == 0)
386 {
387 instanceCounter++;
388 }
389 }
390 if (instanceCounter > 0)
391 {
392 instanceName += std::to_string(instanceCounter);
393 }
394 }
395
396
397 std::string configPath = scenario->getPath();
398 configPath = configPath.substr(0, configPath.find_last_of('/'));
399 configPath.append("/config/");
400
401
402 configPath.append(app->getName());
403 if (!instanceName.empty())
404 {
405 configPath.append(".");
406 configPath.append(instanceName);
407 }
408 configPath.append(".cfg");
409
410 std::ofstream out(configPath);
411 out.close();
412
414 app->getPathToExecutable(),
415 instanceName,
416 configPath,
417 appPackage->getName(),
418 scenario,
419 "",
420 true));
421
422 std::string cacheDir = Parser::IceParser::getCacheDir();
423
424 executor->loadAndSetCachedProperties(appInstance, cacheDir, true);
425 appInstance->load(true);
426
427 for (const auto& elem : app->getProperties()->getProperties()->getPropertiesForPrefix(""))
428 {
429 appInstance->modifyProperty(elem.first, elem.second);
430 appInstance->setDefaultPropertyEnabled(elem.first, true);
431 }
432
433 appInstance->save();
434
435 scenario->addApplication(appInstance);
436
437 QModelIndex subScenarioIndex =
438 findSubScenarioModelIndexByScenarioIndex(scenarioIndex, appPackage->getName());
439 ;
440
441 //if this is unvalid than the user dropped an app out of an package that is not currently used inside the scenario
442 //so create subscenario item
443 //this behaviour was kind of buggy be careful while optimising
444 if (!subScenarioIndex.isValid())
445 {
446 std::vector<ApplicationInstancePtr> list;
447
448 ScenarioItem* subScenarioItem = new ScenarioItem(appPackage->getName(), list);
449
450 treemodel.insertRow(0, subScenarioItem, scenarioIndex);
451
452 subScenarioIndex =
453 findSubScenarioModelIndexByScenarioIndex(scenarioIndex, appPackage->getName());
454
455 treemodel.insertRow(0, new ScenarioItem(appInstance), subScenarioIndex);
456 }
457 else
458 {
459 treemodel.insertRow(0, new ScenarioItem(appInstance), subScenarioIndex);
460 }
461 }
462 scenario->save();
463}
464
465void
467{
468 ScenarioItem* scenItem;
469 if (item.parent().isValid() && item.parent().parent().isValid())
470 {
471 scenItem = model->data(item.parent().parent(), SCENARIOITEMSOURCE).value<ScenarioItem*>();
472
473 if (scenItem == nullptr)
474 {
475 return;
476 }
477
478 ScenarioItem* appItem = model->data(item, SCENARIOITEMSOURCE).value<ScenarioItem*>();
479
480 ScenarioPtr scenario = scenItem->getScenario();
481 scenario->removeApplication(appItem->getApplicationInstance());
482
483 scenario->save();
484 treemodel.removeRow(model->mapToSource(item).row(), model->mapToSource(item.parent()));
485 }
486 else if (item.parent().isValid())
487 {
488 scenItem = model->data(item.parent(), SCENARIOITEMSOURCE).value<ScenarioItem*>();
489
490 if (scenItem == nullptr)
491 {
492 return;
493 }
494
495 ScenarioItem* packageItem = model->data(item, SCENARIOITEMSOURCE).value<ScenarioItem*>();
496
497 ScenarioPtr scenario = scenItem->getScenario();
498
499 for (const auto& app : *packageItem->getApplicationInstances())
500 {
501 scenario->removeApplication(app);
502 }
503 scenario->save();
504 treemodel.removeRow(model->mapToSource(item).row(), model->mapToSource(item.parent()));
505 }
506 else
507 {
508 scenItem = model->data(item, SCENARIOITEMSOURCE).value<ScenarioItem*>();
509
510 if (scenItem == nullptr)
511 {
512 return;
513 }
514
515 ScenarioPtr scen = scenItem->getScenario();
516
517 const std::string file =
518 armarx::ArmarXDataPath::GetDefaultUserConfigPath() + "/ScenarioManager.conf";
519 QSettings settings(QString(file.c_str()), QSettings::NativeFormat);
520 QStringList scenarios = settings.value("scenarios").toStringList();
521 scenarios.removeDuplicates();
522 QString toFind(QString::fromStdString(scen->getName()));
523 toFind.append("::Package::");
524 toFind.append(QString::fromStdString(scen->getPackage()->getName()));
525 scenarios.removeAt(scenarios.indexOf(toFind));
526 settings.setValue("scenarios", scenarios);
527
528 for (const auto& package : *packages)
529 {
530 for (auto it = package->getScenarios()->begin(); it != package->getScenarios()->end();
531 ++it)
532 {
533 if (scen.get() == it->get())
534 {
535 package->getScenarios()->erase(it);
536 break;
537 }
538 }
539 }
540 treemodel.removeRow(model->mapToSource(item).row(), model->mapToSource(item.parent()));
541 emit updated();
542 }
543}
544
545void
547{
549
550 if (packages->size() != 0)
551 {
552 QVector<QPair<QString, bool>> packageNames;
553 for (const auto& package : *packages)
554 {
555 packageNames << qMakePair(QString::fromStdString(package->getName()),
556 package->isScenarioPathWritable());
557 }
558 createScenarioView.setPackages(packageNames);
559 createScenarioView.exec();
560 }
561 else
562 {
563 QMessageBox messageBox;
564 messageBox.setText("You have to have at least one Package open to create an Scenario");
565 messageBox.exec();
566 }
567
569}
570
571void
572ScenarioListController::createdScenario(std::string name, std::string packageStr)
573{
574 XMLScenarioParser parser;
575
576 PackagePtr package;
577 for (unsigned int i = 0; i < packages->size(); i++)
578 {
579 if (packages->at(i)->getName().compare(packageStr) == 0)
580 {
581 package = packages->at(i);
582 break;
583 }
584 }
585 if (package.get() == nullptr)
586 {
587 return;
588 }
589
590 if (parser.isScenarioexistent(name, package))
591 {
592 QMessageBox box;
593 QString message("The Scenario " + QString::fromStdString(name) +
594 " already exists in Package " + QString::fromStdString(packageStr));
595 box.setText(message);
596 box.exec();
597 return;
598 }
599
600 ScenarioPtr ptr = parser.createNewScenario(name, package);
601 if (ptr.get() == nullptr)
602 {
603 return;
604 }
605
606 for (const auto& p : *packages)
607 {
608 if (p->getName().compare(packageStr) == 0)
609 {
610 p->addScenario(ptr);
611 treemodel.insertRow(0, new ScenarioItem(ptr));
612 break;
613 }
614 }
615
616 const std::string file =
617 armarx::ArmarXDataPath::GetDefaultUserConfigPath() + "/ScenarioManager.conf";
618 QSettings settings(QString(file.c_str()), QSettings::NativeFormat);
619 QStringList scenarios = settings.value("scenarios").toStringList();
620 scenarios.removeDuplicates();
621 QString toAdd;
622 toAdd.append(QString::fromStdString(ptr->getName()));
623 toAdd.append("::Package::");
624 toAdd.append(QString::fromStdString(package->getName()));
625 scenarios.append(toAdd);
626 settings.setValue("scenarios", scenarios);
627 emit updated();
628}
629
630void
632{
633
634 ScenarioItem* item = model->data(index, SCENARIOITEMSOURCE).value<ScenarioItem*>();
635 if (index.column() > 0 || item == nullptr)
636 {
637 return;
638 }
639
640 if (index.parent().isValid())
641 {
642 if (index.parent().parent().isValid())
643 {
645 appInstance->updateFound();
646 if (!appInstance->getFound())
647 {
648 QMessageBox message;
649 message.setText("Could not find Application " + item->data(0).toString() + " at " +
650 QString::fromStdString(appInstance->getPathToExecutable()) + ".");
651 message.exec();
652 if (!appInstance->getFound())
653 {
654 updateModel();
655 emit updated();
656 }
657 return;
658 }
659
660 emit applicationInstanceClicked(appInstance, item);
661 }
662 else
663 {
664 return;
665 }
666 }
667 else
668 {
669 emit scenarioClicked(item->getScenario());
670 }
671}
672
673void
675 updateModel() //Scenarios don't have a setStatus-method, therefore UI should calculate Scenario status based on other
676{
677 ScenarioItem* rootItem = treemodel.getRootItem();
678
679 for (const auto& package : *packages)
680 {
681 auto scenarios = package->getScenarios();
682 for (const auto& scenario : *scenarios)
683 {
684 std::map<std::string, std::vector<ApplicationInstancePtr>> packageSubtrees;
685 for (const auto& app : *scenario->getApplications())
686 {
687 std::string packageName = app->getPackageName();
688
689 if (packageSubtrees.count(packageName) == 0)
690 {
691 packageSubtrees[packageName] = std::vector<ApplicationInstancePtr>();
692 }
693 packageSubtrees[packageName].push_back(app);
694 }
695
696 ScenarioItem* scenarioItem;
697 int index =
698 findScenario(rootItem, scenario->getName(), scenario->getPackage()->getName());
699 if (index == -1)
700 {
701 scenarioItem = new ScenarioItem(scenario);
702
703 for (const auto& it : packageSubtrees)
704 {
705 ScenarioItem* currentItem = new ScenarioItem(it.first, it.second);
706 scenarioItem->appendChild(currentItem);
707 }
708 treemodel.insertRow(0, scenarioItem);
709 }
710 else
711 {
712 scenarioItem = static_cast<ScenarioItem*>(rootItem->child(index));
713
714 for (int i = 0; i < scenarioItem->childCount(); i++)
715 {
716 ScenarioItem* subPackageItem =
717 static_cast<ScenarioItem*>(scenarioItem->child(i));
718 std::string name = subPackageItem->data(0).toString().toStdString();
719
720 std::vector<ApplicationInstancePtr> currentBuildSubtree = packageSubtrees[name];
721 ApplicationInstanceVectorPtr currentTreeSubtree =
722 subPackageItem->getApplicationInstances();
723 for (size_t k = 0; k < currentTreeSubtree->size(); k++)
724 {
725 bool found = false;
726 for (size_t j = 0; j < currentBuildSubtree.size(); j++)
727 {
728 if (currentTreeSubtree->at(k)->getName() ==
729 currentBuildSubtree[j]->getName() &&
730 currentTreeSubtree->at(k)->getInstanceName() ==
731 currentBuildSubtree[j]->getInstanceName())
732 {
733 found = true;
734 break;
735 }
736 }
737 if (!found)
738 {
739 treemodel.insertRow(
740 0,
741 new ScenarioItem(currentTreeSubtree->at(k)),
742 findSubScenarioModelIndex(scenario->getName(), name));
743 }
744 }
745 }
746 }
747 }
748 }
749}
750
751QModelIndex
752ScenarioListController::findApplicationModelIndex(
754{
755 QModelIndex subScenarioModelIndex = findSubScenarioModelIndex(
756 application->getScenario()->getName(), application->getPackageName());
757 if (!subScenarioModelIndex.isValid())
758 {
759 return QModelIndex();
760 }
761 int count = 0;
762 QModelIndex appIndex = subScenarioModelIndex.model()->index(0, 0);
763 while (true)
764 {
765 appIndex = appIndex.sibling(count, 0);
766 if (!appIndex.isValid())
767 {
768 return QModelIndex();
769 }
770 if (application->getInstanceName().empty())
771 {
772 if (application->getName() == appIndex.data().toString().toStdString())
773 {
774 return appIndex;
775 }
776 }
777 else
778 {
779 if (application->getInstanceName() + "." + application->getName() ==
780 appIndex.data().toString().toStdString())
781 {
782 return appIndex;
783 }
784 }
785
786 count++;
787 }
788}
789
790QModelIndex
791ScenarioListController::findSubScenarioModelIndex(std::string scenarioName, std::string packageName)
792{
793 QModelIndex scenarioIndex = treemodel.index(0, 0);
794
795 bool scenarioFound = false;
796 int count = 0;
797 while (!scenarioFound)
798 {
799 scenarioIndex = scenarioIndex.sibling(count, 0);
800
801 if (!scenarioIndex.isValid())
802 {
803 return QModelIndex();
804 }
805 if (scenarioName == scenarioIndex.data().toString().toStdString())
806 {
807 scenarioFound = true;
808 break;
809 }
810
811 count++;
812 }
813
814 count = 0;
815 while (true)
816 {
817 QModelIndex currentSubPackageIndex = scenarioIndex.model()->index(count, 0);
818 if (!currentSubPackageIndex.isValid())
819 {
820 return QModelIndex();
821 }
822 if (packageName == currentSubPackageIndex.data().toString().toStdString())
823 {
824 return currentSubPackageIndex;
825 }
826 count++;
827 }
828
829 return QModelIndex();
830}
831
832QModelIndex
833ScenarioListController::findSubScenarioModelIndexByScenarioIndex(QModelIndex scenarioIndex,
834 std::string packageName)
835{
836 int count = 0;
837 while (true)
838 {
839 QModelIndex currentSubPackageIndex = scenarioIndex.model()->index(count, 0, scenarioIndex);
840 if (packageName == currentSubPackageIndex.data().toString().toStdString())
841 {
842 return currentSubPackageIndex;
843 }
844 if (!currentSubPackageIndex.isValid())
845 {
846 return QModelIndex();
847 }
848 count++;
849 }
850
851 return QModelIndex();
852}
853
854//looks if the current scenario is already added
855int
856ScenarioListController::findScenario(ScenarioItem* rootItem,
857 std::string name,
858 std::string packageName)
859{
860 for (int i = 0; i < rootItem->childCount(); i++)
861 {
862 if (static_cast<ScenarioItem*>(rootItem->child(i))->getScenario()->getName() == name &&
863 static_cast<ScenarioItem*>(rootItem->child(i))
864 ->getScenario()
865 ->getPackage()
866 ->getName() == packageName)
867 {
868 return i;
869 }
870 }
871
872 return -1;
873}
874
875void
877{
878 std::vector<ApplicationInstancePtr> apps;
879 {
880 std::unique_lock lock(applicationInstanceMutex);
881 apps.swap(applicationInstances);
882 }
883 if (apps.empty())
884 {
885 return;
886 }
887 // Checking whether the binaries exist is a stat() per application. It used to happen on the
888 // GUI thread for every application on every refresh; do it here instead, and only every few
889 // seconds - binaries do not appear and disappear at the rate of the status poll.
890 const auto now = std::chrono::steady_clock::now();
891 const bool refreshFound = now - lastFoundUpdate >= FoundUpdateInterval;
892 if (refreshFound)
893 {
894 lastFoundUpdate = now;
895 }
896
898 IceUtil::Time start = IceUtil::Time ::now();
899 //update all app instances and scenarios
900 for (const ApplicationInstancePtr& appInst : apps)
901 {
902 if (refreshFound)
903 {
904 appInst->updateFound();
905 }
906 // One application must not be able to take the poll thread down with it: an exception
907 // escaping here used to kill the periodic task outright, freezing every status in the
908 // view at whatever it happened to be at the time.
909 try
910 {
911 stati[appInst] = executor->getApplicationStatus(appInst);
912 }
913 catch (...)
914 {
915 ARMARX_WARNING << deactivateSpam(5) << "Failed to determine the status of "
916 << appInst->getName() << ": " << armarx::GetHandledExceptionString()
917 << ". Leaving it unchanged.";
918 }
919 }
920 ARMARX_DEBUG << deactivateSpam(5) << "Fetching scenario stati took "
921 << (IceUtil::Time::now() - start).toMilliSecondsDouble() << " ms";
922 emit statusFetched(stati);
923}
924
925bool
927 ExecutorPtr executor,
928 IceGrid::AdminPrx iceAdmin)
929{
930 const ApplicationInstanceVectorPtr applications = scenario->getApplications();
931 ARMARX_CHECK_NOT_NULL(applications);
932
933 executor->setStarter(StarterFactory::getFactory()->getStarter(), scenario);
934 executor->setStopStrategy(executor->getDefaultStopStrategy(), scenario);
935
936 // Cheap: the "binary exists" flags are cached and refreshed by the status polling thread.
937 if (!scenario->allApplicationsFound())
938 {
939 ShowWarningDialog("Not all binaries in the Scenario " +
940 QString::fromStdString(scenario->getName()) + " could be found",
941 true,
942 QString::fromStdString(scenario->getName() + "BinariesMissing"));
943 // return false;
944 }
945
946 // Just a request per application. Preparing the property definitions - which can take seconds
947 // per application when the cache is cold or a binary was rebuilt - happens inside the start
948 // operation on the application's own worker thread, so nothing blocks the GUI here.
949 executor->startScenario(scenario);
950 return true;
951}
952
953void
955{
956 // A request publishes its intent synchronously, so rebuilding the model right after issuing one
957 // greys out the button on this event loop turn instead of up to a poll period later.
958 treemodel.update();
959}
960
961void
963{
964 //update all app instances and scenarios
965 // but this needs to be done async -> first get list of applications,
966 // then send these to other thread
967 std::vector<ApplicationInstancePtr> apps;
968 for (ScenarioManager::Data_Structure::PackagePtr& package : *packages)
969 {
970 ScenarioVectorPtr scenarios = package->getScenarios();
971 for (const ScenarioPtr& scenario : *scenarios)
972 {
973 ApplicationInstanceVectorPtr appInsts = scenario->getApplications();
974 for (const ApplicationInstancePtr& appInst : *appInsts)
975 {
976 apps.push_back(appInst);
977 }
978 }
979 }
980
981 {
982 std::unique_lock lock(applicationInstanceMutex);
983 apps.swap(applicationInstances);
984 }
985}
986
987void
989{
990 for (auto& pair : stati)
991 {
992 pair.first->setStatus(pair.second);
993 }
994
995 // Rebuild unconditionally. This used to be skipped unless some status *string* had changed,
996 // which went stale as soon as a row cached anything else - the pending intent that greys out a
997 // button, for one. A restart that finished between two polls never showed up as a status
998 // change (Running before, Running after), so the model was never rebuilt and the restart
999 // button stayed greyed out until some unrelated application happened to change status.
1000 //
1001 // Rebuilding is cheap: ScenarioItem::update() reports what actually changed and only those
1002 // rows get a dataChanged(), so the costly part - refiltering and relayouting the view - still
1003 // only happens when something really moved.
1004 auto start = IceUtil::Time ::now();
1005 treemodel.update();
1006 ARMARX_DEBUG << deactivateSpam(5) << "Updating scenario Model took "
1007 << (IceUtil::Time::now() - start).toMilliSecondsDouble() << " ms";
1008
1009 emit statusUpdated();
1010}
1011
1012void
1015{
1016 for (const auto& package : *packages)
1017 {
1018 for (const auto& scenario : *package->getScenarios())
1019 {
1020 if (application->getScenario()->getName() == scenario->getName())
1021 {
1022 std::string cacheDir = Parser::IceParser::getCacheDir();
1023 executor->loadAndSetCachedProperties(application, cacheDir, false, false);
1024 qApp->processEvents();
1025
1026 // only save the scenario itself, don't make each application save it's own config
1027 scenario->save(false);
1028 return;
1029 }
1030 }
1031 }
1032}
1033
1034void
1036{
1037 iceAdmin = admin;
1038}
1039
1040void
1041ScenarioListController::ShowWarningDialog(QString message, bool showOnce, QString messageId)
1042{
1043 static std::set<QString> dialogIds;
1044 if (showOnce)
1045 {
1046 ARMARX_CHECK_EXPRESSION(!messageId.isEmpty());
1047 if (dialogIds.count(messageId))
1048 {
1049 return;
1050 }
1051 dialogIds.insert(messageId);
1052 }
1053 QMessageBox box;
1054 box.setText(message);
1055 box.exec();
1056}
uint8_t index
#define UPDATE_TIMER
TreeItem representing data contained in a Scenario or an Application.
ScenarioManager::Data_Structure::ScenarioPtr getScenario()
If this item represents a Scenario, it is returned.
ScenarioManager::Data_Structure::ApplicationInstancePtr getApplicationInstance()
If this item represents an Application, it is returned.
ScenarioManager::Data_Structure::ApplicationInstanceVectorPtr getApplicationInstances()
void saveScenario(ScenarioManager::Data_Structure::ApplicationInstancePtr application)
void restart(int row, int column, QModelIndex parent)
Restarts the object in the specified location.
static bool StartScenario(ScenarioManager::Data_Structure::ScenarioPtr scenario, Exec::ExecutorPtr executor, IceGrid::AdminPrx iceAdmin)
void updated()
Gets emitted after changes have been made to the data structure.
void applicationInstanceClicked(Data_Structure::ApplicationInstancePtr appInstance, ScenarioItem *item)
Gets emitted after an ApplicationInstance has been clicked.
void start(int row, int column, QModelIndex parent)
Starts or stops the object in the specified location.
void stop(int row, int column, QModelIndex parent)
void setIceAdmin(IceGrid::AdminPrx iceAdmin)
Set an IceAdmin for the controller.
void updateModel()
Updates the model by reloading all scenarios and applications.
void createScenario()
Shows a view that allows the user to create a new Scenario.
void scenarioClicked(Data_Structure::ScenarioPtr scenario)
Gets emitted after a Scenario has been clicked.
void addApplicationsToScenario(QList< QPair< QString, ScenarioManager::Data_Structure::Application * > > applications, int row, const QModelIndex &parent)
Adds applications to a scenario.
void fetchStati()
fetches application stati over their designated strategy.
void createdScenario(std::string name, std::string package)
Creates a new scenario in the package.
FilterableTreeModelSortFilterProxyModelPtr getTreeModel()
Returns the model used by the ScenarioListView and managed by this controller.
ScenarioListController(Data_Structure::PackageVectorPtr packages, Exec::ExecutorPtr executor, QObject *parent=0)
Constructor which sets the data structure, the executor and optionally the parent object.
void removeItem(QModelIndex item)
Removes an item from the model.
void refreshNow()
Rebuilds the tree straight away instead of waiting for the next status poll, so that the button of a ...
void updateStati()
Updates the statuses of all Applications and Scenarios.
void statusFetched(ApplicationInstanceStatusMap stati)
void statusUpdated()
Gets emitted after changes have been made to the States of the Applications.
void showApplication(const QModelIndex &index)
Calculates the object at the given index and signals to show it.
Class containing data about the instance of an application.
Class containing data about an application Provides methods to get and set the date contained in the ...
Definition Application.h:49
armarx::PropertyDefinitionsPtr getProperties()
static std::shared_ptr< StarterFactory > getFactory()
Returns the right StarterFactory for this operatin system.
static DependencyTree getDependencieTree(std::string packageName)
static std::string getCacheDir()
This class provides different methods to parse and save scenario data in XML-Files.
int childCount() const
Definition treeitem.cpp:57
void appendChild(TreeItem *child)
Definition treeitem.cpp:44
virtual QVariant data(int column) const
Definition treeitem.cpp:69
bool isEnabled()
Definition treeitem.cpp:98
TreeItem * parent()
Definition treeitem.cpp:75
TreeItem * child(int row)
Definition treeitem.cpp:51
static std::string GetDefaultUserConfigPath()
The user config directory of ArmarX.
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
std::shared_ptr< FilterableTreeModelSortFilterProxyModel > FilterableTreeModelSortFilterProxyModelPtr
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:182
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
std::map< ApplicationInstancePtr, std::string > ApplicationInstanceStatusMap
std::shared_ptr< Scenario > ScenarioPtr
Definition Scenario.h:35
std::shared_ptr< std::vector< ScenarioPtr > > ScenarioVectorPtr
Definition Scenario.h:37
std::shared_ptr< std::vector< ScenarioManager::Data_Structure::PackagePtr > > PackageVectorPtr
Definition Package.h:123
std::shared_ptr< Package > PackagePtr
Definition Package.h:122
std::shared_ptr< ApplicationInstance > ApplicationInstancePtr
std::shared_ptr< std::vector< ApplicationInstancePtr > > ApplicationInstanceVectorPtr
std::shared_ptr< Executor > ExecutorPtr
Definition Executor.h:210
std::string GetHandledExceptionString()
SimplePeriodicTask(Ts...) -> SimplePeriodicTask< std::function< void(void)> >
#define ARMARX_TRACE
Definition trace.h:75
@ SCENARIOITEMSOURCE
Definition treeitem.h:37
@ SCENARIOITEMPROXY
Definition treeitem.h:38