23 const QVariantMap map = value.toMap();
25 const QString aliasValue = map.value(QStringLiteral(
"value")).toString();
26 if (!aliasValue.isEmpty()) {
29 const QString aliasSource = map.value(QStringLiteral(
"source")).toString();
30 if (!aliasSource.isEmpty()) {
33 const QString
id = map.value(QStringLiteral(
"id")).toString();
38 return value.toString();
41QVariantList normalizeStringValues(
const QVariantList& values) {
43 out.reserve(values.size());
44 for (
const auto& value : values) {
50QString rowIdAt(
const QVariantList& rows,
int index,
52 if (index < 0 || index >= rows.size()) {
55 return rows.at(index).toMap().value(idKey).toString();
58int rowIndexOfId(
const QVariantList& rows,
const QString&
id,
63 for (
int i = 0; i < rows.size(); ++i) {
64 if (rows.at(i).toMap().value(idKey).toString() ==
id) {
71QVariantMap rowById(
const QVariantList& rows,
const QString&
id,
73 const int index = rowIndexOfId(rows,
id.trimmed(), idKey);
74 return index >= 0 ? rows.at(index).toMap() : QVariantMap{};
78navigatedSelectionId(
const QVariantList& rows,
const QString& currentId,
79 int delta,
int defaultIndex = 0,
81 const int currentIndex = rowIndexOfId(rows, currentId, idKey);
82 if (currentIndex < 0) {
87 return rowIdAt(rows, 0, idKey);
90 return rowIdAt(rows, rows.size() - 1, idKey);
92 return rowIdAt(rows, defaultIndex, idKey);
95 return currentIndex >= rows.size() - 1
97 : rowIdAt(rows, currentIndex + 1, idKey);
100 return currentIndex <= 0 ? QString()
101 : rowIdAt(rows, currentIndex - 1, idKey);
103 return rowIdAt(rows, currentIndex, idKey);
107deleteNextSelectionId(
const QVariantList& rows,
const QString& removedId,
108 int defaultIndex = 0,
110 const int removedIndex = rowIndexOfId(rows, removedId, idKey);
111 if (rows.isEmpty()) {
114 const int nextIndex = removedIndex >= 0 ? removedIndex + 1 : defaultIndex;
115 const int wrapped = nextIndex % rows.size();
116 return rowIdAt(rows, wrapped < 0 ? wrapped + rows.size() : wrapped, idKey);
119bool canAddText(
const QString& value) {
120 return !value.trimmed().isEmpty();
123bool canRemoveAt(
const QVariantList& values,
int index) {
124 return index >= 0 && index < values.size();
127bool containsTrimmed(
const QVariantList& values,
const QString&
id) {
128 const QString nextId =
id.trimmed();
129 if (nextId.isEmpty()) {
132 for (
const auto& value : values) {
140QVariantList addUniqueTrimmed(
const QVariantList& values,
141 const QString& value) {
142 const QString next = value.trimmed();
143 QVariantList out = normalizeStringValues(values);
144 if (next.isEmpty() || containsTrimmed(out, next)) {
151QVariantList removeTrimmed(
const QVariantList& values,
const QString& value) {
152 const QString target = value.trimmed();
153 if (target.isEmpty()) {
157 out.reserve(values.size());
158 for (
const auto& entry : values) {
159 const QString current =
stringValue(entry).trimmed();
160 if (current != target) {
161 out.push_back(current);
167QVariantList removeAt(
const QVariantList& values,
int index) {
168 QVariantList out = normalizeStringValues(values);
169 if (!canRemoveAt(out, index)) {
176int aliasIndexAfterRemoval(
const QVariantList& aliases,
int removedIndex) {
177 if (aliases.isEmpty()) {
180 return removedIndex < aliases.size() ? removedIndex : aliases.size() - 1;
183bool appendAliasValue(QVariantList& aliases, QString& aliasInputText,
184 int& aliasIndex,
const QString& value) {
185 const QVariantList next = addUniqueTrimmed(aliases, value);
186 if (next == aliases) {
190 aliasIndex = aliases.isEmpty() ? -1 : aliases.size() - 1;
191 aliasInputText.clear();
196 const QVariantList next = removeAt(aliases, index);
197 if (next == aliases) {
201 aliasIndex = aliasIndexAfterRemoval(aliases, index);
205bool setSelectedId(QVariantList& selectedIds,
const QString&
id,
207 const QString normalizedId =
id.trimmed();
208 if (normalizedId.isEmpty()) {
211 const QVariantList next = selected
212 ? addUniqueTrimmed(selectedIds, normalizedId)
213 : removeTrimmed(selectedIds, normalizedId);
214 if (next == selectedIds) {
221QStringList normalizedStringList(
const QVariantList& values) {
222 const QVariantList normalized = normalizeStringValues(values);
224 out.reserve(normalized.size());
225 for (
const auto& value : normalized) {
226 out.push_back(value.toString());
232bool formStateChanged(
const QString& savedName,
233 const QVariantList& savedAliases,
234 const QVariantList& savedContractIds,
235 const QString& currentName,
const QVariantList& aliases,
236 const QVariantList& contractIds) {
237 return savedName != currentName ||
238 normalizedStringList(savedAliases) != normalizedStringList(aliases) ||
239 normalizedStringList(savedContractIds) !=
240 normalizedStringList(contractIds);
243QVariantMap actorFormStateFromRow(
const QString& name,
244 const QVariantList& aliases,
245 const QVariantList& selectedIds = {}) {
247 const QVariantList normalizedAliases = normalizeStringValues(aliases);
252 normalizedAliases.isEmpty() ? -1 : 0);
254 normalizeStringValues(selectedIds));
264 : QObject(parent), store_(store), commands_(commands),
265 selection_(selection), selectors_(selectors) {
267 reloadFromSelection(
true);
271 if (name_ == value) {
279 if (aliases_ == value) {
283 if (aliasIndex_ >= aliases_.size()) {
284 aliasIndex_ = aliases_.isEmpty() ? -1 : aliases_.size() - 1;
290 if (aliasInputText_ == value) {
293 aliasInputText_ = value;
298 if (aliasIndex_ == value) {
306 if (selectedContractIds_ == value) {
309 selectedContractIds_ = value;
318 return !name_.trimmed().isEmpty();
325 return formStateChanged(savedName_, savedAliases_, savedSelectedContractIds_,
326 name_, aliases_, selectedContractIds_);
330 return canAddText(value);
333bool ActorViewModel::hasValidAliasSelection()
const {
334 return canRemoveAt(aliases_, aliasIndex_);
338 if (!appendAliasValue(aliases_, aliasInputText_, aliasIndex_, value)) {
345 if (!hasValidAliasSelection() ||
346 !removeAliasValue(aliases_, aliasIndex_, aliasIndex_)) {
354 currentOwnerId_.clear();
361 if (rows.isEmpty()) {
364 setCurrentId(navigatedSelectionId(rows,
isEdit() ?
currentId() : QString(),
365 -1, rows.size() - 1));
370 if (rows.isEmpty()) {
382 "ActorViewModel::submit",
383 isEdit() ?
"Actor update submitted" :
"Actor create submitted",
386 const QString
id = commands_->saveActor(
398 if (!commands_ ||
currentId().isEmpty()) {
402 "ActorViewModel::deleteCurrent",
"Actor delete submitted",
405 commands_->deleteActor(removedId);
407 deleteNextSelectionId(
actorRows(), removedId, 0, QStringLiteral(
"id")));
411 currentOwnerId_.clear();
418 if (!setSelectedId(selectedContractIds_, contractId, selected)) {
425 return selection_ ? selection_->selectedActorId() : QString();
429 return selectors_ ? selectors_->actorRows() : QVariantList{};
433 return selectors_ ? selectors_->contractRows() : QVariantList{};
436void ActorViewModel::setCurrentId(
const QString&
id) {
446void ActorViewModel::bindSignals() {
447 if (!store_ || !selection_) {
453 reloadFromSelection(
true);
457 reloadFromSelection(
false);
461void ActorViewModel::reloadFromSelection(
bool forceReload) {
462 if (!selection_ || !selectors_) {
467 if (selectedId.isEmpty()) {
468 reloadFormState(forceReload, {});
472 const QVariantMap row = rowById(
actorRows(), selectedId);
473 const QVariantMap state =
476 : actorFormStateFromRow(
480 reloadFormState(forceReload, state);
483void ActorViewModel::clearFormState() {
486 aliasInputText_.clear();
488 selectedContractIds_.clear();
492void ActorViewModel::captureSavedState() {
494 savedAliases_ = aliases_;
495 savedSelectedContractIds_ = selectedContractIds_;
499void ActorViewModel::applyFormState(
const QVariantMap& state) {
500 name_ = state.value(QStringLiteral(
"name")).toString();
501 aliases_ = state.value(QStringLiteral(
"aliases")).toList();
502 aliasInputText_ = state.value(QStringLiteral(
"aliasInputText")).toString();
504 state.value(QStringLiteral(
"aliasIndex"), aliases_.isEmpty() ? -1 : 0)
506 selectedContractIds_ = state.value(QStringLiteral(
"selectedIds")).toList();
510void ActorViewModel::reloadFormState(
bool forceReload,
511 const QVariantMap& state) {
513 if (!forceReload && currentOwnerId_ == nextOwnerId) {
517 currentOwnerId_ = nextOwnerId;
518 if (nextOwnerId.isEmpty() || state.isEmpty()) {
524 applyFormState(state);
Declares the QML API for the Actor view.
Declarations for the UI PayloadKeys component.
Declarations for the UI payload mapper helpers.
Declarations for the UI Trace component.
Declares the workspace selection state synchronized with the store.
Declares read-only workspace selectors for QML payloads.
Declares the UI workspace snapshot store.
QVariantList contractRows
Q_INVOKABLE void deleteCurrent()
Deletes the selected actor through workspace commands.
Q_INVOKABLE void next()
Selects the next actor row.
void setAliasInputText(const QString &value)
Updates the current alias input text.
Q_INVOKABLE void setContractSelected(const QString &contractId, bool selected)
Adds or removes a contract id from the actor form selection.
Q_INVOKABLE void clear()
Clears the editable actor form.
Q_INVOKABLE void previous()
Selects the previous actor row.
void changed()
Emitted when actor view model state changed.
Q_INVOKABLE void selectActor(const QString &id)
Selects an actor for editing.
Q_INVOKABLE bool canAddAlias(const QString &value) const
Checks whether an alias value can be added to the form.
Q_INVOKABLE void addAlias(const QString &value)
Adds an alias to the actor form.
ActorViewModel(WorkspaceStore *store, WorkspaceCommands *commands, WorkspaceSelection *selection, WorkspaceSelectors *selectors, QObject *parent=nullptr)
Creates the actor view model bound to workspace roles.
void setAliasIndex(int value)
Updates the selected alias index.
void setName(const QString &value)
Updates the editable actor name.
Q_INVOKABLE void requestRemoveSelectedAlias()
Removes the currently selected alias when possible.
void setAliases(const QVariantList &value)
Replaces editable actor aliases.
Q_INVOKABLE QString submit()
Creates or updates the actor through workspace commands.
Q_INVOKABLE void enterCreateMode()
Clears selection and opens an empty create form.
void setSelectedContractIds(const QVariantList &value)
Replaces selected contract ids in the actor form.
Maps UI intent to core workspace writer commands.
Tracks the currently selected workspace entities.
void selectedActorIdChanged()
Emitted when the selected actor id changed.
void selectActor(const QString &id)
Selects an actor.
Projects workspace store data into QML-facing read models.
Owns the current UI-side workspace snapshot and revision lifecycle.
void dataRevisionChanged()
void removeAliasValue(std::vector< Alias > &aliases, const std::string &value)
Removes aliases with a given value.
void traceViewModel(const char *origin, std::string message, core::errors::ErrorContext context={})
Emits a view model trace event.
const auto kAliasInputText
QString stringValue(const QVariantMap &map, const QString &key)
Reads a string value from a map.
QStringList toQStringList(const std::vector< std::string > &values)
Converts standard strings to a Qt string list.
Declares UI-side workspace command submission.