StateEditorController.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 */
25
26#include <QMenu>
27#include <QMessageBox>
28
33
37#include "StateTreeController.h"
40
41namespace armarx
42{
43
49 QPointer<TipDialog> tipDialog,
50 QObject* parent) :
51 QObject(parent),
58 {
59 if (mainWindow)
60 {
61 connect(mainWindow->getStateTabWidget(),
62 SIGNAL(currentChanged(int)),
63 this,
64 SLOT(connectToStateTab(int)));
65 }
66 else
67 {
68 ARMARX_ERROR_S << "mainwindow ptr must not be NULL";
69 }
70
71 editState = menu.addAction(QIcon(":/icons/accessories-text-editor-6.ico"), "");
72 deleteState = menu.addAction(QIcon(":/icons/delete.ico"), "Delete State");
73 layoutState = menu.addAction(QIcon(":/icons/magic-wand-icon.png"), "Layout State");
74 setstartstate = menu.addAction("Set as initial State");
75
77 menu.addAction(QIcon(":/statechart-editor/new-endstate.svg"), "Insert new Endstate");
78 replaceState = menu.addAction("Replace State");
79 openCode = menu.addAction(QIcon(":/icons/cpp.svg"), "Open C++ Code");
80 findStateInTree = menu.addAction(QIcon(":/icons/search.svg"), "Find State in Tree");
81 for (QAction* a : menu.actions())
82 {
83 a->setIconVisibleInMenu(true);
84 }
85 connect(mainWindow->ui->actionEdit_State_Properties,
86 SIGNAL(triggered(bool)),
87 this,
88 SLOT(editSelectedState()));
89 }
90
91 void
93 const StateDialog& d)
94 {
95 statechartmodel::StatePtr state = stateInstance->getStateClass();
96
97 if (stateInstance->getParent())
98 {
99 stateInstance->getParent()->renameSubstate(stateInstance->getInstanceName(),
101 }
102
103 if (state)
104 {
105 // ARMARX_INFO_S << "setting class params";
106 // state->setStateName(d.getStateName());
107
108 state->setDescription(d.getDescription());
109 state->setOutgoingEvents(d.getOutgoingEvents());
110 state->setInputParameters(d.getInputParams());
111 state->setLocalParameters(d.getLocalParams());
112 state->setOutputParameters(d.getOutputParams());
113 }
114
116 std::dynamic_pointer_cast<statechartmodel::RemoteState>(stateInstance);
117
118 if (remoteState)
119 {
120 remoteState->proxyName = d.getProxyName();
121 }
122
124 std::dynamic_pointer_cast<statechartmodel::EndState>(stateInstance);
125
126 if (endstate)
127 {
128 endstate->setEventName(d.getStateInstanceName());
129 }
130 }
131
132 void
134 QPoint mouseScreenPos,
135 QPointF mouseItemPos)
136 {
137 if (!stateInstance)
138 {
139 return;
140 }
141 bool editable = true;
142 if (stateInstance && stateInstance->getStateClass() &&
143 !stateInstance->getStateClass()->isEditable())
144 {
145 editable = false;
146 }
147
148
149 statechartmodel::StatePtr parentState = stateInstance->getParent();
150 StateTreeNodePtr node = treeController->getNodeByState(stateInstance->getStateClass());
151 editState->setText("Edit State " + stateInstance->getInstanceName());
152 deleteState->setEnabled(!!parentState && parentState->isEditable());
153 setstartstate->setEnabled(!!parentState && parentState->isEditable());
154
155 replaceState->setEnabled(editable);
156
157
158 openCode->setEnabled(!(!stateInstance->getStateClass() || (node && !node->getCppExists())));
159
160
161 newEndstate->setEnabled(!(stateInstance->getType() == eFinalState ||
162 stateInstance->getType() == eDynamicRemoteState) &&
163 stateInstance->getStateClass() &&
164 stateInstance->getStateClass()->isEditable());
165
166
167 layoutState->setEnabled(!(stateInstance->getType() == eFinalState ||
168 stateInstance->getType() == eDynamicRemoteState ||
169 !stateInstance->getStateClass() ||
170 stateInstance->getStateClass()->getSubstates().size() <= 1));
171
172
173 replaceState->setEnabled(false);
174
175 QAction* result = menu.exec(mouseScreenPos);
176
177 if (result == editState)
178 {
179 StateDialog d(stateInstance,
183 lockRemoteStates && stateInstance->getType() == eRemoteState ? true
184 : false,
185 !editable,
186 tipDialog);
187
188 if (d.exec() == QDialog::Accepted)
189 {
190 stateDialogAccepted(stateInstance, d);
191 }
192 }
193 else if (result == deleteState)
194 {
195 if (QMessageBox::question(0,
196 "State deletion",
197 "Do you really want to delete state '" +
198 stateInstance->getInstanceName() + "'?",
199 QMessageBox::Yes,
200 QMessageBox::No) == QMessageBox::Yes)
201 {
202 parentState->removeSubstate(stateInstance);
203 }
204 }
205 else if (result == layoutState)
206 {
207 mainWindow->layoutState();
208 }
209 else if (result == setstartstate)
210 {
211 parentState->setStartState(stateInstance);
212 }
213 else if (result == newEndstate)
214 {
215 ARMARX_INFO_S << "Inserting endstate";
216 statechartmodel::StatePtr state = stateInstance->getStateClass();
217 int i = 2;
218 const QString newStateNameBase = "MyEndState";
219 QString newStateName = newStateNameBase;
220
221 while (!state->addEndSubstate(newStateName, newStateName, mouseItemPos))
222 {
223 newStateName = newStateNameBase + "_" + QString::number(i);
224 i++;
225 }
226 }
227 else if (result == openCode && stateInstance->getStateClass())
228 {
229 StateTreeNodePtr node = treeController->getNodeByState(stateInstance->getStateClass());
230 treeController->openStateCPP(node);
231 }
232 else if (result == findStateInTree && stateInstance->getStateClass())
233 {
234 treeController->selectNodeByState(stateInstance->getStateClass());
235 }
236 }
237
238 void
241 QPoint mouseScreenPos,
242 QPointF mouseItemPos)
243 {
244 ARMARX_DEBUG_S << "pos: " << mouseItemPos;
245 QMenu menu;
246 QAction* editTransition = menu.addAction("Edit Transition " + transition->eventName);
247 QAction* enableTransitionCode =
248 menu.addAction("Enable Transition Hook for " + transition->eventName);
249 enableTransitionCode->setCheckable(true);
250 enableTransitionCode->setChecked(transition->transitionUserCode);
251
252 StateTreeNodePtr node = treeController->getNodeByState(state);
253
254
255 if (!transition->destinationState || !transition->destinationState->getStateClass() ||
256 !node || !node->getCppExists() || !transition->sourceState)
257 {
258 if (!node->getCppExists())
259 {
260 enableTransitionCode->setText(enableTransitionCode->text() + " (no parent cpp)");
261 }
262 else if (!transition->sourceState)
263 {
264 enableTransitionCode->setText("Transition code unavailable for initial transition");
265 }
266 else if (transition->destinationState && !transition->destinationState->getStateClass())
267 {
268 enableTransitionCode->setText(enableTransitionCode->text() +
269 " (final or unloaded destination state)");
270 }
271 enableTransitionCode->setEnabled(false);
272 }
273
274 QAction* detach = menu.addAction("Detach Transition");
275 //QAction* insertPoint = menu.addAction("Insert Support Point");
276 //insertPoint->setEnabled(false);
277
278 if (!transition->sourceState || !transition->destinationState)
279 {
280 detach->setEnabled(false);
281 }
282
283 QAction* setSupportPoint{nullptr};
284 std::map<QAction*, int> bendMap;
285
286 if (transition->sourceState && transition->destinationState)
287 {
288 menu.addSeparator();
289 bendMap.insert(std::make_pair(menu.addAction("Straighten"), 0));
290 QMenu* bend = menu.addMenu("Bend");
291 bendMap.insert(std::make_pair(bend->addAction("Bend Left 10%"), 10));
292 bendMap.insert(std::make_pair(bend->addAction("Bend Left 25%"), 25));
293 bendMap.insert(std::make_pair(bend->addAction("Bend Left 50%"), 50));
294 bendMap.insert(std::make_pair(bend->addAction("Bend Left 100%"), 100));
295 bendMap.insert(std::make_pair(bend->addAction("Bend Right 10%"), -10));
296 bendMap.insert(std::make_pair(bend->addAction("Bend Right 25%"), -25));
297 bendMap.insert(std::make_pair(bend->addAction("Bend Right 50%"), -50));
298 bendMap.insert(std::make_pair(bend->addAction("Bend Right 100%"), -100));
299 setSupportPoint = menu.addAction("Set Support Point");
300 }
301
302 QAction* result = menu.exec(mouseScreenPos);
303
304
305 if (result == editTransition)
306 {
307 if (transition->destinationState &&
308 transition->destinationState->getType() != eFinalState &&
309 !transition->destinationState->getStateClass())
310 {
311 QMessageBox::warning(mainWindow,
312 "Transition Editing Error",
313 "Transition editing not possible because destination state is "
314 "not loaded - load statechart group of destination state.");
315 }
316 else
317 {
318
320 transition, state, getRelevantProfiles(), communicator, variantInfo);
321
322 if (d.exec() == QDialog::Accepted)
323 {
324 state->setTransitionMapping(transition,
328 }
329 }
330 }
331 else if (result == detach)
332 {
333 state->detachTransitionDestination(transition);
334 }
335 // else if(result == insertPoint)
336 // {
337 // state->addSupportPoint(transition, mouseItemPos);
338 // }
339 else if (bendMap.find(result) != bendMap.end())
340 {
341 state->bendTransition(transition, 50, bendMap[result]);
342 }
343 else if (result == setSupportPoint)
344 {
346
347 if (d.exec() == QDialog::Accepted)
348 {
349 state->bendTransition(transition, d.getU(), d.getV());
350 }
351 }
352 else if (result == enableTransitionCode)
353 {
354 state->setTransitionUserCodeEnabled(transition, result->isChecked());
355 if (result->isChecked())
356 {
357 tipDialog->showMessage(
358 "Transition functions enable you to execute user code during a transition. "
359 "This is designated for parameter conversion or minor calculations. Do NOT "
360 "execute long running operations in transition functions.\n"
361 "On next saving of the statecharts a pure virtual function will be generated "
362 "in the state of this transition. You need to implement this function. "
363 "Otherwise a compilation error will occur.",
364 "Transition Function",
365 "TransitionFunction");
366 }
367 }
368 }
369
370 QList<QString>
372 {
373 if (!currentProfile)
374 {
375 return QList<QString>();
376 }
377
378 QList<QString> result{QString::fromUtf8(currentProfile->getName().c_str())};
379 auto profile = currentProfile;
380
381 while ((profile = profile->getParent()))
382 {
383 result.push_back(QString::fromUtf8(profile->getName().c_str()));
384 }
385
386 return result;
387 }
388
389 void
391 {
392 if (mainWindow->getStateTabWidget()->currentStateview() &&
393 mainWindow->getStateTabWidget()->currentStateview()->getScene() &&
394 mainWindow->getStateTabWidget()
395 ->currentStateview()
396 ->getScene()
397 ->selectedItems()
398 .size() > 0)
399 {
400 StateItem* item = dynamic_cast<StateItem*>(*mainWindow->getStateTabWidget()
401 ->currentStateview()
402 ->getScene()
403 ->selectedItems()
404 .begin());
405
406 if (item)
407 {
412 item->getStateInstance()->getType() == eRemoteState ? true : false,
413 !item->isEditable(),
414 tipDialog);
415 if (d.exec() == QDialog::Accepted)
416 {
418 }
419 }
420 else
421 {
422 TransitionItem* transitionItem =
423 dynamic_cast<TransitionItem*>(*mainWindow->getStateTabWidget()
424 ->currentStateview()
425 ->getScene()
426 ->selectedItems()
427 .begin());
428 item = dynamic_cast<StateItem*>(transitionItem->parentItem());
429 if (transitionItem && item)
430 {
431 TransitionDialog d(transitionItem->getTransition(),
432 item->getStateInstance()->getStateClass(),
436 if (d.exec() == QDialog::Accepted)
437 {
438 item->getStateInstance()->getStateClass()->setTransitionMapping(
439 transitionItem->getTransition(),
443 }
444 }
445 }
446 }
447 }
448
449 void
454
455 void
456 StateEditorController::connectToStateTab(int index)
457 {
460 {
462 SIGNAL(stateContextMenuRequested(
463 statechartmodel::StateInstancePtr, QPoint, QPointF)),
464 this,
466 Qt::UniqueConnection);
467 connect(
469 SIGNAL(transitionContextMenuRequested(
471 this,
474 Qt::UniqueConnection);
475 connect(mainWindow->ui->actionShow_Subsubstates,
476 SIGNAL(toggled(bool)),
478 SLOT(showSubSubstates(bool)));
479 }
480 }
481
482} // namespace armarx
uint8_t index
bool isEditable() const
QString getProxyName() const
statechartmodel::StateParameterMap getLocalParams() const
QString getStateInstanceName() const
statechartmodel::StateParameterMap getOutputParams() const
QString getDescription() const
statechartmodel::EventList getOutgoingEvents() const
statechartmodel::StateParameterMap getInputParams() const
void showTransitionContextMenu(statechartmodel::TransitionCPtr transition, statechartmodel::StatePtr state, QPoint mouseScreenPos, QPointF mouseItemPos)
void stateDialogAccepted(statechartmodel::StateInstancePtr stateInstance, const armarx::StateDialog &d)
void showStateContextMenu(statechartmodel::StateInstancePtr stateInstance, QPoint mouseScreenPos, QPointF mouseItemPos)
StateTreeControllerPtr treeController
StatechartEditorMainWindow * mainWindow
StateEditorController(StatechartEditorMainWindow *mainWindow, StateTreeControllerPtr treeController, Ice::CommunicatorPtr communicator, VariantInfoPtr variantInfo, StatechartProfilePtr currentProfile, QPointer< TipDialog > tipDialog, QObject *parent=0)
QList< QString > getRelevantProfiles() const
statechartmodel::StateInstancePtr getStateInstance() const
Definition StateItem.h:66
StatechartView * currentStateview() const
StateScene * getScene() const
statechartmodel::ParameterMappingList getMappingToParentStateLocal() const
statechartmodel::ParameterMappingList getMappingToNextStateInput() const
statechartmodel::ParameterMappingList getMappingToParentStateOutput() const
statechartmodel::TransitionCPtr getTransition() const
#define ARMARX_DEBUG_S
The logging level for output that is only interesting while debugging.
Definition Logging.h:205
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_INFO_S
Definition Logging.h:202
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49
std::shared_ptr< State > StatePtr
Definition State.h:48
std::shared_ptr< StateInstance > StateInstancePtr
std::shared_ptr< const Transition > TransitionCPtr
Definition Transition.h:91
std::shared_ptr< RemoteState > RemoteStatePtr
Definition RemoteState.h:47
std::shared_ptr< EndState > EndStatePtr
Definition EndState.h:45
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< VariantInfo > VariantInfoPtr
Definition VariantInfo.h:39
std::shared_ptr< class StatechartProfile > StatechartProfilePtr
std::shared_ptr< StateTreeNode > StateTreeNodePtr
std::shared_ptr< StateTreeController > StateTreeControllerPtr