StatechartViewerController.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
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
26
27#include <queue>
28
29#include <QMenu>
30#include <QToolBar>
31
32#include <IceUtil/UUID.h>
33
36#include <ArmarXCore/interface/statechart/RemoteStateOffererIce.h> //RemoteStateOffererInterfacePrx
40
43#include <ArmarXGui/gui-plugins/StatechartViewerPlugin/ui_StatechartViewer.h>
46
47#include "model/State.h"
50#include "view/StatechartView.h"
51
52namespace armarx
53{
54
56 {
57 setlocale(LC_ALL, "C");
58
59 ui = new Ui::StatechartViewer();
60 connect(this, SIGNAL(componentConnected()), this, SLOT(connectToIce()));
61
62 qRegisterMetaType<LockableGraphPtr>("LockableGraphPtr");
63 qRegisterMetaType<MediatorPtr>("MediatorPtr");
64 qRegisterMetaType<size_t>("size_t");
65 qRegisterMetaType<IceStateConverterPtr>("IceStateConverterPtr");
66 qRegisterMetaType<StateIceBasePtr>("StateIceBasePtr");
67
68 ui->setupUi(getWidget());
70 ui->gridLayout_2->addWidget(proxyFinder, 0, 0, 2, 1);
71 proxyFinder->setSearchMask("*RemoteStateOfferer");
72 follower = new ActiveStateFollower(nullptr, getWidget());
73 connect(ui->btnRefreshStateInstances, SIGNAL(clicked()), this, SLOT(updateStateComboBox()));
74 connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateStateFollower()));
75 connect(ui->tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(removeTab(int)));
76 connect(ui->btnAddViewer, SIGNAL(clicked()), this, SLOT(addNewStateView()));
77 connect(proxyFinder->getProxyNameComboBox(),
78 SIGNAL(currentIndexChanged(QString)),
79 this,
80 SLOT(updateStateComboBox()),
81 Qt::UniqueConnection);
82 }
83
85 {
86 shutdown = true;
87 std::unique_lock lock(mutex); // wait for network functions to finish
88 }
89
90 void
92 {
94 this,
96 1000,
97 false,
98 "StatechartViewerRefetch");
99 }
100
101 void
103 {
104 qRegisterMetaType<statechartmodel::TransitionCPtr>("statechartmodel::TransitionCPtr");
105 qRegisterMetaType<statechartmodel::SignalType>("statechartmodel::SignalType");
106 watcher = new StateWatcher;
107 getArmarXManager()->addObject(watcher, false, "StateWatcher" + IceUtil::generateUUID());
108 updateTask->start();
109 emit componentConnected();
110 proxyFinder->setIceManager(getIceManager());
111 }
112
113 void
115 {
116
117 updateTask->stop();
118 getArmarXManager()->removeObjectNonBlocking(watcher->getName());
119 }
120
121 void
125
126 void
128 {
129 int size = settings->beginReadArray("StatechartViewers");
130 for (int i = 0; i < size; ++i)
131 {
132 settings->setArrayIndex(i);
133 QString proxyName = settings->value("proxyName").toString();
134 QString globalStateName = settings->value("globalStateName").toString();
135 delayedConverterAdding.push_back(qMakePair(proxyName, globalStateName));
136 }
137 settings->endArray();
138 }
139
140 void
142 {
143 settings->beginWriteArray("StatechartViewers");
144 int i = 0;
145 for (RemoteStateData& data : converters)
146 {
147 settings->setArrayIndex(i);
148 settings->setValue("globalStateName", data.globalStateName);
149 settings->setValue("proxyName", data.proxyName);
150 i++;
151 }
152 settings->endArray();
153 }
154
155 void
156 StatechartViewerController::connectToIce()
157 {
158 for (QPair<QString, QString>& pair : delayedConverterAdding)
159 {
160 addNewStateView(pair.first, pair.second);
161 }
162 if (!ui->tabWidget->currentStateview())
163 {
164 addNewStateView("RobotControlStateOfferer", "RobotStatechart->RobotControl");
165 }
166
167 ui->tabWidget->currentStateview()->viewAll();
168 }
169
170 void
171 StatechartViewerController::updateStatechartView(StateIceBasePtr stateptr,
172 IceStateConverterPtr converter)
173 {
174 std::unique_lock lock(mutex);
175 auto start = IceUtil::Time::now();
176 converter->convert(stateptr);
177 ARMARX_DEBUG << deactivateSpam(3) << "converting instance took : "
178 << (IceUtil::Time::now() - start).toMilliSecondsDouble() << " ms";
179 }
180
181 void
183 {
184 if (shutdown)
185 {
186 return;
187 }
188 QMap<QPointer<StatechartView>, RemoteStateData> tempConverters;
189 {
190 std::unique_lock lock(mutex);
191 tempConverters = converters;
192 }
193 for (RemoteStateData& stateData : tempConverters)
194 {
195 RemoteStateOffererInterfacePrx statechartHandler;
196 try
197 {
199 stateData.proxyName.toStdString(), false, "", false);
200 if (!statechartHandler)
201 {
202 continue;
203 }
204 auto start = IceUtil::Time::now();
205
206
207 start = IceUtil::Time::now();
208
209 auto asyncResult = statechartHandler->begin_getStatechartInstanceByGlobalIdStr(
210 stateData.globalStateName.toStdString());
211 while (!asyncResult->isCompleted())
212 {
213 if (shutdown)
214 {
215 return;
216 }
217 usleep(100);
218 // qApp->processEvents();
219 }
220 armarx::StateIceBasePtr stateptr =
221 statechartHandler->end_getStatechartInstanceByGlobalIdStr(asyncResult);
222 if (!stateptr)
223 {
224 ARMARX_WARNING_S << "Could not find state with name "
225 << stateData.globalStateName.toStdString();
226 continue;
227 }
228 // armarx::StateIceBasePtr stateptr = m_statechartHandler->getStatechartInstance(stateMap.begin()->first);
230 << " took : " << (IceUtil::Time::now() - start).toMilliSecondsDouble()
231 << " ms";
232 QMetaObject::invokeMethod(this,
233 "updateStatechartView",
234 Q_ARG(StateIceBasePtr, stateptr),
235 Q_ARG(IceStateConverterPtr, stateData.converter));
236 // stateData.converter.convert(stateptr);
237 }
238 catch (Ice::NotRegisteredException&)
239 {
240 getIceManager()->removeProxyFromCache(statechartHandler);
242 << "No ice ID 'RobotControlStateOfferer' registered";
243 }
244 catch (...)
245 {
247 }
248 }
249 }
250
251 void
252 StatechartViewerController::displayParameters(
253 statechartmodel::StateInstancePtr selectedStateInstance)
254 {
255 try
256 {
257 QList<QTreeWidgetItem*> items;
258 if (selectedStateInstance && watcher)
259 {
260 auto paramContainerTypes = {
261 "inputParameters", "localParameters", "outputParameters"};
262 ui->paramView->clear();
263
264
265 for (auto& type : paramContainerTypes)
266 {
267 QTreeWidgetItem* item = new QTreeWidgetItem();
268 item->setText(0, type);
269 StateParameterMap map;
270 try
271 {
272 map = watcher->getStateParameterMap(selectedStateInstance->getStateClass(),
273 type);
274 }
275 catch (...)
276 {
278 continue;
279 }
280
281
282 for (auto& elem : map)
283 {
284 QTreeWidgetItem* subItem = new QTreeWidgetItem();
285 StateParameterIceBasePtr param = elem.second;
286 subItem->setText(0, elem.first.c_str());
287 subItem->setText(1, param->value->output().c_str());
288 item->addChild(subItem);
289 }
290 items.push_back(item);
291 // inputParamsJson->setVariant(type, var);
292 }
293 ui->paramView->addTopLevelItems(items);
294 for (auto& item : items)
295 {
296 ui->paramView->expandItem(item);
297 }
298 }
299 else
300 {
301 ARMARX_INFO << "no state instance!";
302 }
303 if (items.size() == 0)
304 {
305 QTreeWidgetItem* item = new QTreeWidgetItem();
306 item->setText(0, "No data available yet");
307 ui->paramView->addTopLevelItem(item);
308 }
309 }
310 catch (...)
311 {
312 QTreeWidgetItem* item = new QTreeWidgetItem();
313 item->setText(0, "No data available yet");
314 ui->paramView->addTopLevelItem(item);
316 }
317 }
318
319 void
320 StatechartViewerController::addNewStateView(QString proxyName, QString stateName)
321 {
322 auto view = ui->tabWidget->addEmptyStateTab();
323 if (!view)
324 {
325 return;
326 }
327 connect(view,
328 SIGNAL(selectedStateChanged(statechartmodel::StateInstancePtr)),
329 this,
330 SLOT(displayParameters(statechartmodel::StateInstancePtr)));
331 converters[view].converter.reset(new IceStateConverter());
332 converters[view].converter->setStateWatcher(watcher);
333 view->setState(converters[view].converter->getTopState()->getStateClass());
334 converters[view].proxyName = proxyName;
335 converters[view].globalStateName = stateName;
336 QString instanceName;
337 if (stateName.lastIndexOf("->") >= 0)
338 {
339 instanceName = stateName.right(stateName.size() - stateName.lastIndexOf("->") - 2);
340 }
341 else
342 {
343 instanceName = stateName;
344 }
345 ui->tabWidget->setTabText(ui->tabWidget->currentIndex(), instanceName);
346
347 view->getLayoutController().enableLayouting();
349 connectToStateTab(ui->tabWidget->currentIndex());
350 }
351
352 void
353 StatechartViewerController::addNewStateView()
354 {
355 addNewStateView(proxyFinder->getSelectedProxyName(),
356 ui->comboBoxStateInstances->currentText());
357 }
358
359 void
360 StatechartViewerController::followActiveState()
361 {
362 auto view = ui->tabWidget->currentStateview();
363 if (!view)
364 {
365 return;
366 }
367 follower->setStatechartView(view);
368 }
369
370 void
371 StatechartViewerController::updateStateComboBox()
372 {
373 if (proxyFinder->getSelectedProxyName().isEmpty())
374 {
375 return;
376 }
377 if (getState() < eManagedIceObjectStarting)
378 {
379 return;
380 }
382 proxyFinder->getSelectedProxyName().toStdString(), false, "", false);
383
384 ui->comboBoxStateInstances->clear();
385 if (proxy)
386 {
387 QStringList stateInstances;
388 for (auto& elem : proxy->getAvailableStateInstances())
389 {
390 stateInstances << (elem.second.c_str());
391 }
392 stateInstances.removeDuplicates();
393 ui->comboBoxStateInstances->addItems(stateInstances);
394 }
395 ui->btnAddViewer->setEnabled(ui->comboBoxStateInstances->count() > 0);
396 }
397
398 void
399 StatechartViewerController::updateStateFollower()
400 {
401 auto view = ui->tabWidget->currentStateview();
402 if (!view)
403 {
404 return;
405 }
406 follower->setStatechartView(view);
407 }
408
409 void
410 StatechartViewerController::removeTab(int index)
411 {
412 QPointer<StatechartView> view = qobject_cast<StatechartView*>(ui->tabWidget->widget(index));
413 if (view)
414 {
415 converters.remove(view);
416 }
417 else
418 {
419 ARMARX_INFO_S << "View already NULL";
420 }
421 }
422
423 QPointer<QWidget>
425 {
426 if (customToolbar)
427 {
428 if (parent != customToolbar->parent())
429 {
430 customToolbar->setParent(parent);
431 }
432
433 return qobject_cast<QToolBar*>(customToolbar);
434 }
435
436 customToolbar = new QToolBar(parent);
437 customToolbar->setIconSize(QSize(16, 16));
438 autoFollowAction = customToolbar->addAction(QIcon(":/icons/magic-wand-icon.png"),
439 "Auto follow active state");
440 autoFollowAction->setCheckable(true);
441 autoFollowAction->setChecked(true);
442 follower->startFollowing();
443 connect(autoFollowAction, SIGNAL(toggled(bool)), follower, SLOT(toggle(bool)));
444
445 centerActiveStateAction = customToolbar->addAction(QIcon(":/icons/zoom-original-2.png"),
446 "Center on active state");
447 connect(centerActiveStateAction,
448 SIGNAL(triggered(bool)),
449 follower,
450 SLOT(centerOnCurrentState(bool)));
451 return qobject_cast<QToolBar*>(customToolbar);
452 }
453
454 void
456 {
457 ARMARX_INFO << "Trying to connect to " << index;
458 if (index != -1 && ui->tabWidget->currentStateview() &&
459 ui->tabWidget->currentStateview()->getScene())
460 {
461 connect(
462 ui->tabWidget->currentStateview()->getScene(),
463 SIGNAL(transitionContextMenuRequested(
465 this,
468 Qt::UniqueConnection);
469 }
470 }
471
472 void
476 QPoint mouseScreenPos,
477 QPointF mouseItemPos)
478 {
479 ARMARX_DEBUG_S << "pos: " << mouseItemPos;
480 QMenu menu;
481 QAction* triggerTransition = menu.addAction("Trigger Transition " + transition->eventName);
482 if (transition->sourceState != state->getActiveSubstate())
483 {
484 triggerTransition->setEnabled(false);
485 }
486
487
488 QAction* result = menu.exec(mouseScreenPos);
489
490
491 if (result == triggerTransition)
492 {
493 std::unique_lock lock(mutex);
494
495 for (RemoteStateData& data : converters)
496 {
497 std::set<std::string> proxyNames;
498 std::string globalId;
499 auto states = data.converter->getCompleteStateMap();
500 for (auto& statepair : states)
501 {
502 proxyNames.insert(data.proxyName.toStdString());
503 if (state == statepair.second.first->getStateClass())
504 {
505 globalId = statepair.first;
506 ARMARX_DEBUG << "Found state " << statepair.first;
507 }
508 StateIceBasePtr iceState = statepair.second.second;
509 RemoteStateIceBasePtr remoteState =
510 RemoteStateIceBasePtr::dynamicCast(iceState);
511 if (remoteState)
512 {
513 proxyNames.insert(remoteState->proxyName);
514 }
515 }
516 if (!globalId.empty())
517 {
518 RemoteStateOffererInterfacePrx correctOffererproxy;
520 << VAROUT(Ice::StringSeq(proxyNames.begin(), proxyNames.end()));
521 std::map<RemoteStateOffererInterfacePrx, Ice::AsyncResultPtr> proxyResultPtrs;
522 for (auto proxyName : proxyNames)
523 {
524 RemoteStateOffererInterfacePrx proxy;
525 try
526 {
528 proxyName, false, "", false);
529 if (proxy)
530 {
531 proxyResultPtrs[proxy] =
532 proxy->begin_isHostOfStateByGlobalIdStr(globalId);
533 }
534 }
535 catch (...)
536 {
537 getArmarXManager()->getIceManager()->removeProxyFromCache(proxy);
538 }
539 }
540 for (auto& proxyPair : proxyResultPtrs)
541 {
542 RemoteStateOffererInterfacePrx proxy;
543 try
544 {
545 proxy = proxyPair.first;
546 if (proxy->end_isHostOfStateByGlobalIdStr(proxyPair.second))
547 {
548 correctOffererproxy = proxy;
549 break;
550 }
551 }
552 catch (...)
553 {
554 getArmarXManager()->getIceManager()->removeProxyFromCache(proxy);
555 }
556 }
557
558 if (correctOffererproxy)
559 {
560 ARMARX_INFO << "Sending event " << transition->eventName << " to "
561 << transition->sourceState->getInstanceName();
562 correctOffererproxy->begin_issueEventWithGlobalIdStr(
563 globalId,
564 new Event(transition->sourceState->getInstanceName().toStdString(),
565 transition->eventName.toStdString()));
566 }
567 }
568 }
569 }
570 }
571
572} // namespace armarx
uint8_t index
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define VAROUT(x)
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
An Event is used to communicate between e.g.
Definition Event.h:51
Widget to conveniently retrieve a proxy instance name of a specific interface type (the template para...
IceManagerPtr getIceManager() const
Returns the IceManager.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
int getState() const
Retrieve current state of the ManagedIceObject.
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
The periodic task executes one thread method repeatedly using the time period specified in the constr...
void onInitComponent() override
Pure virtual hook for the subclass.
void showTransitionContextMenu(statechartmodel::TransitionCPtr transition, statechartmodel::StatePtr state, QPoint mouseScreenPos, QPointF mouseItemPos)
QPointer< QWidget > getCustomTitlebarWidget(QWidget *parent) override
getTitleToolbar returns a pointer to the a toolbar widget of this controller.
void onDisconnectComponent() override
Hook for subclass.
void loadSettings(QSettings *settings) override
Implement to load the settings that are part of the GUI configuration.
void saveSettings(QSettings *settings) override
Implement to save the settings as part of the GUI configuration.
void onConnectComponent() override
Pure virtual hook for the subclass.
void onExitComponent() override
Hook for subclass.
#define ARMARX_DEBUG_S
The logging level for output that is only interesting while debugging.
Definition Logging.h:205
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
std::shared_ptr< State > StatePtr
Definition State.h:48
std::shared_ptr< StateInstance > StateInstancePtr
std::shared_ptr< const Transition > TransitionCPtr
Definition Transition.h:91
This file offers overloads of toIce() and fromIce() functions for STL container types.
void handleExceptions()
std::shared_ptr< IceStateConverter > IceStateConverterPtr