27#include "ui_statepropertyeditor.h"
28#include "ui_transitionpropertyeditor.h"
32#include <QItemSelectionModel>
33#include <QMetaProperty>
39QStringList allStates(
const State *state)
45 if (!state->
label().isEmpty())
46 ret << state->
label();
48 for (
const State *st : childStates)
50 ret.removeDuplicates();
54QStringList childStates(
const State *state)
62 for (
const State *st : childStates) {
63 if (!st->label().isEmpty()) {
68 ret.removeDuplicates();
75struct PropertyEditor::Private
80 [[nodiscard]] T *current()
const
82 return qobject_cast<T *>(m_currentElement);
88 void updateSimpleProperty()
const;
89 void setInitalState(
const QString &label)
const;
90 void setDefaultState(
const QString &label)
const;
91 void setSourceState(
const QString &label)
const;
92 void setTargetState(
const QString &label)
const;
93 void childModeChanged()
const;
94 void currentChanged(
const QModelIndex ¤t,
const QModelIndex &previous);
95 void modelAboutToBeReset();
96 void loadFromCurrentElement()
const;
99 QItemSelectionModel *m_selectionModel;
102 QPointer<KDSME::Element> m_currentElement;
103 Ui::StatePropertyEditor *m_stateWidget;
104 Ui::TransitionPropertyEditor *m_transitionWidget;
105 int m_noWidgetIndex, m_stateWidgetIndex, m_transitionWidgetIndex;
107 QHash<QObject *, QString> m_widgetToPropertyMap;
112 , m_selectionModel(nullptr)
113 , m_commandController(nullptr)
114 , m_stateModel(nullptr)
115 , m_stateWidget(nullptr)
116 , m_transitionWidget(nullptr)
117 , m_noWidgetIndex(-1)
118 , m_stateWidgetIndex(-1)
119 , m_transitionWidgetIndex(-1)
124 : QStackedWidget(parent)
125 , d(new Private(this))
127 d->m_stateWidget =
new Ui::StatePropertyEditor;
128 d->m_transitionWidget =
new Ui::TransitionPropertyEditor;
129 d->m_noWidgetIndex = addWidget(
new QWidget(
this));
131 auto *w =
new QWidget(
this);
132 d->m_stateWidget->setupUi(w);
133 d->m_stateWidgetIndex = addWidget(w);
134 w =
new QWidget(
this);
135 d->m_transitionWidget->setupUi(w);
136 d->m_transitionWidgetIndex = addWidget(w);
138 d->m_widgetToPropertyMap.insert(d->m_stateWidget->labelLineEdit, QStringLiteral(
"label"));
139 d->m_widgetToPropertyMap.insert(d->m_stateWidget->onEntryEditor, QStringLiteral(
"onEntry"));
140 d->m_widgetToPropertyMap.insert(d->m_stateWidget->onExitEditor, QStringLiteral(
"onExit"));
141 d->m_widgetToPropertyMap.insert(d->m_stateWidget->childModeEdit, QStringLiteral(
"childMode"));
142 d->m_widgetToPropertyMap.insert(d->m_stateWidget->historyTypeEdit, QStringLiteral(
"historyType"));
143 d->m_widgetToPropertyMap.insert(d->m_transitionWidget->labelLineEdit, QStringLiteral(
"label"));
144 d->m_widgetToPropertyMap.insert(d->m_transitionWidget->guardEditor, QStringLiteral(
"guard"));
145 d->m_widgetToPropertyMap.insert(d->m_transitionWidget->signalEdit, QStringLiteral(
"signal"));
146 d->m_widgetToPropertyMap.insert(d->m_transitionWidget->timeoutEdit, QStringLiteral(
"timeout"));
148 connect(d->m_stateWidget->labelLineEdit, SIGNAL(editingFinished()),
this, SLOT(updateSimpleProperty()));
149 connect(d->m_stateWidget->initialStateComboBox, &QComboBox::textActivated,
this, [
this](
const QString &text) { d->setInitalState(text); });
150 connect(d->m_stateWidget->defaultStateComboBox, &QComboBox::textActivated,
this, [
this](
const QString &text) { d->setDefaultState(text); });
151 connect(d->m_stateWidget->onEntryEditor, SIGNAL(editingFinished(QString)), SLOT(updateSimpleProperty()));
152 connect(d->m_stateWidget->onExitEditor, SIGNAL(editingFinished(QString)), SLOT(updateSimpleProperty()));
153 connect(d->m_stateWidget->childModeEdit, SIGNAL(currentIndexChanged(
int)), SLOT(updateSimpleProperty()));
154 connect(d->m_stateWidget->childModeEdit, SIGNAL(currentIndexChanged(
int)), SLOT(childModeChanged()));
155 connect(d->m_stateWidget->historyTypeEdit, SIGNAL(currentIndexChanged(
int)), SLOT(updateSimpleProperty()));
157 connect(d->m_transitionWidget->labelLineEdit, SIGNAL(editingFinished()), SLOT(updateSimpleProperty()));
158 connect(d->m_transitionWidget->sourceStateComboBox, &QComboBox::textActivated,
this, [
this](
const QString &text) { d->setSourceState(text); });
159 connect(d->m_transitionWidget->targetStateComboBox, &QComboBox::textActivated,
this, [
this](
const QString &text) { d->setTargetState(text); });
160 connect(d->m_transitionWidget->guardEditor, SIGNAL(editingFinished(QString)), SLOT(updateSimpleProperty()));
161 connect(d->m_transitionWidget->signalEdit, SIGNAL(editingFinished()), SLOT(updateSimpleProperty()));
162 connect(d->m_transitionWidget->timeoutEdit, SIGNAL(valueChanged(
int)), SLOT(updateSimpleProperty()));
164 setCurrentIndex(d->m_noWidgetIndex);
169 delete d->m_stateWidget;
170 delete d->m_transitionWidget;
175 if (d->m_selectionModel) {
177 disconnect(d->m_selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
178 this, SLOT(currentChanged(QModelIndex,QModelIndex)));
179 disconnect(d->m_selectionModel->model(), SIGNAL(modelAboutToBeReset()),
180 this, SLOT(modelAboutToBeReset()));
184 d->m_selectionModel = selectionModel;
186 if (d->m_selectionModel) {
188 connect(d->m_selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
189 this, SLOT(currentChanged(QModelIndex,QModelIndex)));
190 connect(d->m_selectionModel->model(), SIGNAL(modelAboutToBeReset()),
191 this, SLOT(modelAboutToBeReset()));
198 d->m_commandController = cmdController;
203 d->m_stateModel = selectionModel;
206void PropertyEditor::Private::currentChanged(
const QModelIndex ¤t,
const QModelIndex &previous)
210 setCurrentElement(currentElement);
213void PropertyEditor::Private::modelAboutToBeReset()
215 setCurrentElement(
nullptr);
218void PropertyEditor::Private::setCurrentElement(
KDSME::Element *element)
220 if (m_currentElement == element) {
224 if (m_currentElement) {
225 QObject::disconnect(m_currentElement,
nullptr, q, SLOT(loadFromCurrentElement()));
228 m_currentElement = element;
230 if (m_currentElement) {
231 for (
int i = 0; i < m_currentElement->metaObject()->propertyCount(); ++i) {
232 const QMetaProperty prop = m_currentElement->metaObject()->property(i);
233 if (!prop.hasNotifySignal())
235 QObject::connect(m_currentElement, QByteArray {
"2" + prop.notifySignal().methodSignature() }.constData(), q, SLOT(loadFromCurrentElement()));
238 loadFromCurrentElement();
241void PropertyEditor::Private::loadFromCurrentElement() const
243 auto *state = current<State>();
245 m_stateWidget->labelLineEdit->setText(state->
label());
246 m_stateWidget->initialStateComboBox->clear();
247 m_stateWidget->defaultStateComboBox->clear();
249 m_stateWidget->initialStateLabel->setVisible(state->
isComposite());
250 m_stateWidget->initialStateComboBox->setVisible(state->
isComposite());
253 m_stateWidget->childModeLabel->setVisible(state->
isComposite());
254 m_stateWidget->childModeEdit->setVisible(state->
isComposite());
257 m_stateWidget->initialStateComboBox->addItems(childStates(state));
260 m_stateWidget->initialStateComboBox->setCurrentText(initialState->
label());
262 m_stateWidget->initialStateComboBox->setCurrentIndex(0);
264 m_stateWidget->childModeEdit->setCurrentIndex(state->
childMode());
268 m_stateWidget->defaultStateComboBox->addItems(allStates(state->
machine()));
269 State *defaultState = qobject_cast<HistoryState *>(state)->defaultState();
270 m_stateWidget->defaultStateComboBox->setCurrentText(defaultState ? defaultState->
label() : QLatin1String(
""));
273 m_stateWidget->onEntryEditor->setPlainText(state->
onEntry());
274 m_stateWidget->onExitEditor->setPlainText(state->
onExit());
276 auto *historyState = current<HistoryState>();
277 m_stateWidget->historyTypeLabel->setVisible(historyState);
278 m_stateWidget->historyTypeEdit->setVisible(historyState);
280 m_stateWidget->historyTypeEdit->setCurrentIndex(historyState->historyType());
282 q->setCurrentIndex(m_stateWidgetIndex);
284 }
else if (
auto *transition = current<Transition>()) {
285 m_transitionWidget->labelLineEdit->setText(transition->label());
287 m_transitionWidget->sourceStateComboBox->clear();
288 State *sourceState = transition->sourceState();
289 Q_ASSERT(sourceState);
291 m_transitionWidget->sourceStateComboBox->addItems(allStates(sourceState->
machine()));
292 m_transitionWidget->sourceStateComboBox->setCurrentText(sourceState->
label());
294 m_transitionWidget->sourceStateComboBox->setCurrentText(QString());
296 m_transitionWidget->targetStateComboBox->clear();
297 State *targetState = transition->targetState();
299 m_transitionWidget->targetStateComboBox->addItems(allStates(sourceState->
machine()));
301 m_transitionWidget->targetStateComboBox->setCurrentText(QString());
304 m_transitionWidget->targetStateComboBox->setCurrentText(targetState->
label());
306 m_transitionWidget->targetStateComboBox->setCurrentText(QString());
308 m_transitionWidget->guardEditor->setPlainText(transition->guard());
309 q->setCurrentIndex(m_transitionWidgetIndex);
311 auto *signalTransition = current<SignalTransition>();
312 m_transitionWidget->signalLabel->setVisible(signalTransition);
313 m_transitionWidget->signalEdit->setVisible(signalTransition);
314 if (signalTransition)
315 m_transitionWidget->signalEdit->setText(signalTransition->signal());
317 auto *timeoutTransition = current<TimeoutTransition>();
318 m_transitionWidget->timeoutLabel->setVisible(timeoutTransition);
319 m_transitionWidget->timeoutEdit->setVisible(timeoutTransition);
320 if (timeoutTransition)
321 m_transitionWidget->timeoutEdit->setValue(timeoutTransition->timeout());
324 q->setCurrentIndex(m_noWidgetIndex);
328void PropertyEditor::Private::updateSimpleProperty()
const
330 QObject *
object = q->sender();
331 if (!
object || !m_currentElement || !object->metaObject()->userProperty().isValid())
334 const QString propertyName = m_widgetToPropertyMap.value(
object);
335 Q_ASSERT(!propertyName.isEmpty());
337 const QVariant currentValue = m_currentElement->property(propertyName.toUtf8().constData());
340 auto *comboBox = qobject_cast<QComboBox *>(
object);
341#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
342 if (comboBox && currentValue.typeId() != QMetaType::QString) {
344 if (comboBox && currentValue.type() != QVariant::String) {
346 newValue = comboBox->currentIndex();
348 newValue =
object->metaObject()->userProperty().read(
object);
350 if (currentValue == newValue)
353 Q_ASSERT(m_commandController);
354 auto *command =
new ModifyPropertyCommand(m_currentElement, propertyName.toUtf8().constData(), newValue);
355 m_commandController->undoStack()->push(command);
358void PropertyEditor::Private::setInitalState(
const QString &label)
const
360 auto *state = current<State>();
365 if (currentInitialState != initialState) {
367 m_commandController->undoStack()->push(command);
372void PropertyEditor::Private::setDefaultState(
const QString &label)
const
374 auto *state = current<HistoryState>();
378 if (state->defaultState() != defaultState) {
380 m_commandController->undoStack()->push(command);
385void PropertyEditor::Private::setSourceState(
const QString &label)
const
387 auto *transition = current<Transition>();
390 if (transition->sourceState() != sourceState) {
392 command->setSourceState(sourceState);
393 m_commandController->undoStack()->push(command);
398void PropertyEditor::Private::setTargetState(
const QString &label)
const
400 auto *transition = current<Transition>();
403 if (transition->targetState() != targetState) {
405 command->setTargetState(targetState);
406 m_commandController->undoStack()->push(command);
411void PropertyEditor::Private::childModeChanged()
const
415 m_stateWidget->initialStateLabel->setEnabled(!parallelMode);
416 m_stateWidget->initialStateComboBox->setEnabled(!parallelMode);
419#include "moc_propertyeditor.cpp"
Modifies the default state of a KDSME::HistoryState.
Modifies the initial state of a KDSME::State.
Modifies any specific property of a QObject.
Command for modifying properties of a KDSME::Transition.
void setStateModel(StateModel *selectionModel)
void setCommandController(CommandController *cmdController)
PropertyEditor(QWidget *parent=nullptr)
void setSelectionModel(QItemSelectionModel *selectionModel)
@ ElementRole
return Element*
QList< State * > childStates() const
Q_INVOKABLE KDSME::StateMachine * machine() const
Type type() const override
KDSME_CORE_EXPORT State * findInitialState(const State *state)
KDSME_CORE_EXPORT State * findState(State *root, const QString &label)