FOSSredder 0.5.0
Loading...
Searching...
No Matches
ExportViewModel.cpp
Go to the documentation of this file.
1
5
7
8#include <algorithm>
9#include <cstddef>
10
11#include <QLocale>
12
16#include "ui/shell/AppActions.h"
17#include "ui/shell/Settings.h"
22
23namespace ui {
24namespace exportKeys = ui::payload::keys::exportSelection;
25
26namespace {
27
28inline constexpr auto kPlot = "plot";
29inline constexpr auto kTab = "tab";
30inline constexpr auto kCsv = "CSV";
31inline constexpr auto kXlsx = "XLSX";
32inline constexpr auto kPng = "PNG";
33inline constexpr auto kJpg = "JPG";
34inline constexpr int kCreateMode = 0;
35inline constexpr int kProgressMode = 1;
36
37QString qstr(const char* value) {
38 return QString::fromLatin1(value);
39}
40
41int indexOfId(const QVariantList& rows, const QString& id,
42 const QString& idKey = QStringLiteral("id")) {
43 if (id.isEmpty()) {
44 return -1;
45 }
46 for (int i = 0; i < rows.size(); ++i) {
47 if (rows.at(i).toMap().value(idKey).toString() == id) {
48 return i;
49 }
50 }
51 return -1;
52}
53
54QVariantMap rowById(const QVariantList& rows, const QString& id,
55 const QString& idKey = QStringLiteral("id")) {
56 const int index = indexOfId(rows, id.trimmed(), idKey);
57 return index >= 0 ? rows.at(index).toMap() : QVariantMap{};
58}
59
60QString nonEmptyString(const QVariantMap& map, const QString& key,
61 const QString& defaultValue = {}) {
62 const QString value = map.value(key).toString();
63 return value.isEmpty() ? defaultValue : value;
64}
65} // namespace
66
67ExportViewModel::ExportViewModel(QObject* parent) : QObject(parent) {}
68
70 WorkspaceCommands* commands,
71 WorkspaceSelectors* selectors) {
72 if (store_ == store && commands_ == commands && selectors_ == selectors) {
73 return;
74 }
75 bindWorkspaceRoles(store, commands, selectors);
76 configureExportLogSink();
78}
79
81 if (exportWorkflow_ == value) {
82 return;
83 }
84 bindWorkflow(value);
85 configureExportLogSink();
86 emitChanged();
87}
88
90 if (actions_ == value) {
91 return;
92 }
93 bindActions(value);
94 emitChanged();
95}
96
98 if (fileSystemBrowser_ == value) {
99 return;
100 }
101 fileSystemBrowser_ = value;
102 if (targetDirectory_.isEmpty()) {
103 targetDirectory_ = defaultTargetDirectory();
104 appliedDefaultTargetDirectory_ = targetDirectory_;
105 }
106 emitChanged();
107}
108
110 if (settings_ == value) {
111 return;
112 }
113 bindSettings(value);
114 if (targetDirectory_.isEmpty() ||
115 targetDirectory_ == appliedDefaultTargetDirectory_) {
116 targetDirectory_ = defaultTargetDirectory();
117 appliedDefaultTargetDirectory_ = targetDirectory_;
118 }
119 packageFormatIndex_ = settings_ ? settings_->exportArchiveFormat() : 0;
120 emitChanged();
121}
122
123void ExportViewModel::bindWorkspaceRoles(WorkspaceStore* store,
124 WorkspaceCommands* commands,
125 WorkspaceSelectors* selectors) {
126 if (store_) {
127 disconnect(store_, nullptr, this, nullptr);
128 }
129 store_ = store;
130 commands_ = commands;
131 selectors_ = selectors;
132 if (store_) {
133 connect(store_, &WorkspaceStore::dataRevisionChanged, this,
135 }
136}
137
138void ExportViewModel::bindActions(Actions* value) {
139 if (actions_) {
140 disconnect(actions_, nullptr, this, nullptr);
141 }
142 actions_ = value;
143 if (actions_) {
144 connect(actions_, &Actions::exportDirectorySelected, this,
146 }
147}
148
149void ExportViewModel::bindSettings(Settings* value) {
150 if (settings_) {
151 disconnect(settings_, nullptr, this, nullptr);
152 }
153 settings_ = value;
154 if (!settings_) {
155 return;
156 }
157 connect(settings_, &Settings::exportDefaultDirectoryChanged, this, [this]() {
158 if (targetDirectory_.isEmpty() ||
159 targetDirectory_ == appliedDefaultTargetDirectory_) {
160 targetDirectory_ = defaultTargetDirectory();
161 appliedDefaultTargetDirectory_ = targetDirectory_;
162 emitChanged();
163 }
164 });
165 connect(settings_, &Settings::exportArchiveFormatChanged, this, [this]() {
166 packageFormatIndex_ = settings_ ? settings_->exportArchiveFormat() : 0;
167 emitChanged();
168 });
169 connect(settings_, &Settings::exportIncludeFormulasChanged, this,
170 &ExportViewModel::emitChanged);
171}
172
173void ExportViewModel::bindWorkflow(ExportWorkflow* value) {
174 if (exportWorkflow_) {
175 disconnect(exportWorkflow_, nullptr, this, nullptr);
176 }
177 exportWorkflow_ = value;
178 if (exportWorkflow_) {
179 connect(exportWorkflow_, &ExportWorkflow::stateChanged, this,
180 &ExportViewModel::emitChanged);
181 }
182}
183
184void ExportViewModel::configureExportLogSink() {
185 if (!exportWorkflow_) {
186 return;
187 }
188 if (!commands_) {
189 exportWorkflow_->setExportLogSink({});
190 return;
191 }
192 exportWorkflow_->setExportLogSink([this](const auto& log) {
193 if (commands_) {
194 commands_->saveExportLog(log);
195 }
196 });
197}
198
199bool ExportViewModel::isAnnualMode() const {
200 return addMode_ == exportKeys::kAnnual;
201}
202
203QVariantList ExportViewModel::annualRows() const {
204 return selectors_ ? selectors_->annualRows() : QVariantList();
205}
206
207QVariantList ExportViewModel::analysisRows() const {
208 return selectors_ ? selectors_->analysisRows() : QVariantList();
209}
210
211QVariantMap ExportViewModel::annualRowById(const QString& id) const {
212 return rowById(annualRows(), id);
213}
214
215QVariantMap ExportViewModel::analysisRowById(const QString& id) const {
216 return rowById(analysisRows(), id);
217}
218
219QString ExportViewModel::selectedAddObjectId() const {
220 return isAnnualMode() ? selectedAddAnnualId_ : selectedAddAnalysisId_;
221}
222
223void ExportViewModel::ensureAddSelection() {
224 const QVariantList rows = addRows();
225 if (rows.isEmpty()) {
226 if (isAnnualMode()) {
227 selectedAddAnnualId_.clear();
228 } else {
229 selectedAddAnalysisId_.clear();
230 }
231 return;
232 }
233 if (indexOfId(rows, selectedAddObjectId()) >= 0) {
234 return;
235 }
236 const QString firstId =
237 rows.first().toMap().value(QStringLiteral("id")).toString();
238 if (isAnnualMode()) {
239 selectedAddAnnualId_ = firstId;
240 } else {
241 selectedAddAnalysisId_ = firstId;
242 }
243}
244
245void ExportViewModel::setTargetDirectory(const QString& value) {
246 if (targetDirectory_ == value) {
247 return;
248 }
249 targetDirectory_ = value;
250 emitChanged();
251}
252
254 const int next = std::clamp(value, 0, 1);
255 if (packageFormatIndex_ == next) {
256 return;
257 }
258 packageFormatIndex_ = next;
259 emitChanged();
260}
261
262void ExportViewModel::setAddMode(const QString& value) {
263 const QString normalized = value.trimmed().toLower() == exportKeys::kAnalysis
264 ? exportKeys::kAnalysis
265 : exportKeys::kAnnual;
266 if (addMode_ == normalized) {
267 return;
268 }
269 addMode_ = normalized;
270 ensureAddSelection();
271 emitChanged();
272}
273
274QVariantList ExportViewModel::addRows() const {
275 return isAnnualMode() ? annualRows() : analysisRows();
276}
277
279 return isAnnualMode() ? QStringLiteral("display") : QStringLiteral("name");
280}
281
283 return indexOfId(addRows(), selectedAddObjectId());
284}
285
287 return !selectedAddObjectId().isEmpty();
288}
289
291 if (targetDirectory_.isEmpty()) {
292 targetDirectory_ = defaultTargetDirectory();
293 appliedDefaultTargetDirectory_ = targetDirectory_;
294 }
295 if (settings_) {
296 packageFormatIndex_ = settings_->exportArchiveFormat();
297 }
298 ensureAddSelection();
299 refreshEntriesFromWorkspace();
300 emitChanged();
301}
302
304 targetDirectory_ = defaultTargetDirectory();
305 appliedDefaultTargetDirectory_ = targetDirectory_;
306 packageFormatIndex_ = settings_ ? settings_->exportArchiveFormat() : 0;
307 exportEntries_.clear();
308 ensureAddSelection();
309 if (exportWorkflow_) {
310 exportWorkflow_->clearActiveExportLog();
311 }
312 emitChanged();
313}
314
315QString ExportViewModel::defaultTargetDirectory() const {
316 if (settings_ && !settings_->exportDefaultDirectory().isEmpty()) {
317 return settings_->exportDefaultDirectory();
318 }
319 if (fileSystemBrowser_) {
320 return fileSystemBrowser_->appDir();
321 }
322 return {};
323}
324
325void ExportViewModel::refreshEntriesFromWorkspace() {
326 QVariantList refreshed;
327 refreshed.reserve(exportEntries_.size());
328 for (const QVariant& value : exportEntries_) {
329 QVariantMap entry = value.toMap();
330 if (entry.value(QStringLiteral("kind")).toString() == exportKeys::kAnnual) {
331 const QString id = entry.value(QStringLiteral("objectId")).toString();
332 const QVariantMap annual = annualRowById(id);
333 entry.insert(
334 QStringLiteral("objectName"),
335 nonEmptyString(annual, QStringLiteral("name"),
336 entry.value(QStringLiteral("objectName")).toString()));
337 entry.insert(QStringLiteral("analyses"),
338 analysesForAnnual(
339 id, entry.value(QStringLiteral("analyses")).toList()));
340 refreshed.push_back(entry);
341 continue;
342 }
343 const QString id = entry.value(QStringLiteral("objectId")).toString();
344 const QVariantMap analysis = analysisRowById(id);
345 refreshed.push_back(createAnalysisEntry(
346 id,
347 nonEmptyString(analysis, QStringLiteral("name"),
348 entry.value(QStringLiteral("objectName")).toString()),
349 nonEmptyString(analysis, QStringLiteral("type"),
350 entry.value(QStringLiteral("analysisType")).toString()),
351 entry.value(QStringLiteral("exportType")).toString()));
352 }
353 exportEntries_ = refreshed;
354}
355
356QVariantMap
357ExportViewModel::createAnnualEntry(const QString& id, const QString& name,
358 const QVariantList& analyses) const {
359 return {{QStringLiteral("kind"), exportKeys::kAnnual},
360 {QStringLiteral("isAnnual"), true},
361 {QStringLiteral("objectId"), id},
362 {QStringLiteral("objectName"), name},
363 {QStringLiteral("annualIndex"), indexOfId(annualRows(), id)},
364 {QStringLiteral("collapsed"), false},
365 {QStringLiteral("analyses"), analyses}};
366}
367
368QVariantMap
369ExportViewModel::createAnalysisEntry(const QString& id, const QString& name,
370 const QString& type,
371 const QString& exportType) const {
372 const QString normalizedType = type.trimmed().isEmpty()
373 ? analysisTypeById(id)
374 : type.trimmed().toLower();
375 const QVariantList options = exportOptionsForAnalysisType(normalizedType);
376 const QString selectedExportType =
377 normalizedExportType(exportType, normalizedType);
378 return {
379 {QStringLiteral("kind"), exportKeys::kAnalysis},
380 {QStringLiteral("isAnnual"), false},
381 {QStringLiteral("objectId"), id},
382 {QStringLiteral("objectName"), name},
383 {QStringLiteral("analysisIndex"), indexOfId(analysisRows(), id)},
384 {QStringLiteral("analysisType"), normalizedType},
385 {QStringLiteral("exportType"), selectedExportType},
386 {QStringLiteral("exportTypeOptions"), options},
387 {QStringLiteral("exportTypeIndex"), options.indexOf(selectedExportType)}};
388}
389
390QVariantList
391ExportViewModel::analysesForAnnual(const QString& annualId,
392 const QVariantList& currentAnalyses) const {
393 const QVariantMap annual = annualRowById(annualId);
394 const QVariantList ids =
395 annual.value(QStringLiteral("analysisIds")).toList().isEmpty()
396 ? annual.value(QStringLiteral("assignedAnalysisIds")).toList()
397 : annual.value(QStringLiteral("analysisIds")).toList();
398 QVariantMap currentTypeById;
399 for (const QVariant& value : currentAnalyses) {
400 const QVariantMap row = value.toMap();
401 const QString id = row.value(QStringLiteral("objectId")).toString();
402 if (!id.isEmpty()) {
403 currentTypeById.insert(id, row.value(QStringLiteral("exportType")));
404 }
405 }
406 QVariantList out;
407 for (const QVariant& idValue : ids) {
408 const QString analysisId = idValue.toString();
409 const QVariantMap row = analysisRowById(analysisId);
410 out.push_back(createAnalysisEntry(
411 analysisId, nonEmptyString(row, QStringLiteral("name")),
412 nonEmptyString(row, QStringLiteral("type"),
413 analysisTypeById(analysisId)),
414 currentTypeById.value(analysisId).toString()));
415 }
416 return out;
417}
418
419QVariantList
420ExportViewModel::exportOptionsForAnalysisType(const QString& type) const {
421 return type.trimmed().toLower() == qstr(kPlot)
422 ? QVariantList{qstr(kPng), qstr(kJpg)}
423 : QVariantList{qstr(kCsv), qstr(kXlsx)};
424}
425
426QString ExportViewModel::normalizedExportType(const QString& exportType,
427 const QString& type) const {
428 const QString upper = exportType.trimmed().toUpper();
429 const QVariantList options = exportOptionsForAnalysisType(type);
430 for (const QVariant& option : options) {
431 if (option.toString() == upper) {
432 return upper;
433 }
434 }
435 return defaultExportType(type);
436}
437
438QString ExportViewModel::defaultExportType(const QString& type) const {
439 return exportOptionsForAnalysisType(type).value(0).toString();
440}
441
442QString ExportViewModel::analysisTypeById(const QString& id) const {
443 const QVariantMap row = analysisRowById(id);
444 return nonEmptyString(row, QStringLiteral("type"), qstr(kTab)).toLower();
445}
446
448 const QVariantList rows = addRows();
449 const QVariantMap row = index >= 0 && index < rows.size()
450 ? rows.at(index).toMap()
451 : QVariantMap();
452 const QString id = row.value(QStringLiteral("id")).toString();
453 if (isAnnualMode()) {
454 selectedAddAnnualId_ = id;
455 } else {
456 selectedAddAnalysisId_ = id;
457 }
458 emitChanged();
459}
460
462 const QString objectId = selectedAddObjectId();
463 if (objectId.isEmpty()) {
464 return;
465 }
466 if (isAnnualMode()) {
467 const QVariantMap annual = annualRowById(objectId);
468 exportEntries_.push_back(createAnnualEntry(
469 objectId, nonEmptyString(annual, QStringLiteral("name")),
470 analysesForAnnual(objectId, {})));
471 } else {
472 const QVariantMap analysis = analysisRowById(objectId);
473 const QString type = nonEmptyString(analysis, QStringLiteral("type"),
474 analysisTypeById(objectId));
475 exportEntries_.push_back(createAnalysisEntry(
476 objectId, nonEmptyString(analysis, QStringLiteral("name")), type,
477 nonEmptyString(analysis, QStringLiteral("exportFormat"))));
478 }
479 emitChanged();
480}
481
483 if (index < 0 || index >= exportEntries_.size()) {
484 return;
485 }
486 exportEntries_.removeAt(index);
487 emitChanged();
488}
489
491 int annualIndex) {
492 if (entryIndex < 0 || entryIndex >= exportEntries_.size()) {
493 return;
494 }
495 const QVariantList rows = annualRows();
496 if (annualIndex < 0 || annualIndex >= rows.size()) {
497 return;
498 }
499 QVariantMap entry = exportEntries_.at(entryIndex).toMap();
500 const QVariantList existingAnalyses =
501 entry.value(QStringLiteral("analyses")).toList();
502 const QVariantMap annual = rows.at(annualIndex).toMap();
503 const QString id = annual.value(QStringLiteral("id")).toString();
504 entry.insert(QStringLiteral("objectId"), id);
505 entry.insert(QStringLiteral("objectName"),
506 nonEmptyString(annual, QStringLiteral("name")));
507 entry.insert(QStringLiteral("annualIndex"), annualIndex);
508 entry.insert(QStringLiteral("analyses"),
509 analysesForAnnual(id, existingAnalyses));
510 exportEntries_[entryIndex] = entry;
511 emitChanged();
512}
513
514void ExportViewModel::updateAnnualCollapsed(int entryIndex, bool collapsed) {
515 if (entryIndex < 0 || entryIndex >= exportEntries_.size()) {
516 return;
517 }
518 QVariantMap entry = exportEntries_.at(entryIndex).toMap();
519 entry.insert(QStringLiteral("collapsed"), collapsed);
520 exportEntries_[entryIndex] = entry;
521 emitChanged();
522}
523
525 int analysisIndex) {
526 if (entryIndex < 0 || entryIndex >= exportEntries_.size()) {
527 return;
528 }
529 const QVariantList rows = analysisRows();
530 if (analysisIndex < 0 || analysisIndex >= rows.size()) {
531 return;
532 }
533 const QVariantMap row = rows.at(analysisIndex).toMap();
534 const QString id = row.value(QStringLiteral("id")).toString();
535 const QString type =
536 nonEmptyString(row, QStringLiteral("type"), qstr(kTab)).toLower();
537 exportEntries_[entryIndex] = createAnalysisEntry(
538 id, nonEmptyString(row, QStringLiteral("name")), type, {});
539 emitChanged();
540}
541
543 int entryIndex, const QString& exportType) {
544 if (entryIndex < 0 || entryIndex >= exportEntries_.size()) {
545 return;
546 }
547 const QVariantMap current = exportEntries_.at(entryIndex).toMap();
548 exportEntries_[entryIndex] = createAnalysisEntry(
549 current.value(QStringLiteral("objectId")).toString(),
550 current.value(QStringLiteral("objectName")).toString(),
551 current.value(QStringLiteral("analysisType")).toString(), exportType);
552 emitChanged();
553}
554
556 int entryIndex, int analysisIndex, const QString& exportType) {
557 if (entryIndex < 0 || entryIndex >= exportEntries_.size()) {
558 return;
559 }
560 QVariantMap entry = exportEntries_.at(entryIndex).toMap();
561 QVariantList analyses = entry.value(QStringLiteral("analyses")).toList();
562 if (analysisIndex < 0 || analysisIndex >= analyses.size()) {
563 return;
564 }
565 const QVariantMap analysis = analyses.at(analysisIndex).toMap();
566 analyses[analysisIndex] = createAnalysisEntry(
567 analysis.value(QStringLiteral("objectId")).toString(),
568 analysis.value(QStringLiteral("objectName")).toString(),
569 analysis.value(QStringLiteral("analysisType")).toString(), exportType);
570 entry.insert(QStringLiteral("analyses"), analyses);
571 exportEntries_[entryIndex] = entry;
572 emitChanged();
573}
574
575QVariantList ExportViewModel::exportItems() const {
576 QVariantList out;
577 for (const QVariant& value : exportEntries_) {
578 const QVariantMap entry = value.toMap();
579 const QString kind = entry.value(QStringLiteral("kind")).toString();
580 if (kind == exportKeys::kAnnual) {
581 const QString annualId =
582 entry.value(QStringLiteral("objectId")).toString();
583 out.push_back(
584 QVariantMap{{exportKeys::kObjectType, exportKeys::kAnnual},
585 {exportKeys::kObjectId, annualId},
586 {exportKeys::kObjectName,
587 entry.value(QStringLiteral("objectName")).toString()},
588 {exportKeys::kExportType, QString()}});
589 for (const QVariant& analysisValue :
590 entry.value(QStringLiteral("analyses")).toList()) {
591 const QVariantMap analysis = analysisValue.toMap();
592 out.push_back(QVariantMap{
593 {exportKeys::kObjectType, exportKeys::kAnalysis},
594 {exportKeys::kAnnualId, annualId},
595 {exportKeys::kObjectId,
596 analysis.value(QStringLiteral("objectId")).toString()},
597 {exportKeys::kObjectName,
598 analysis.value(QStringLiteral("objectName")).toString()},
599 {exportKeys::kExportType,
600 analysis.value(QStringLiteral("exportType")).toString()}});
601 }
602 continue;
603 }
604 out.push_back(
605 QVariantMap{{exportKeys::kObjectType, exportKeys::kAnalysis},
606 {exportKeys::kAnnualId, QString()},
607 {exportKeys::kObjectId,
608 entry.value(QStringLiteral("objectId")).toString()},
609 {exportKeys::kObjectName,
610 entry.value(QStringLiteral("objectName")).toString()},
611 {exportKeys::kExportType,
612 entry.value(QStringLiteral("exportType")).toString()}});
613 }
614 return out;
615}
616
618 return exportWorkflow_ && workflowMode() == kCreateMode &&
619 !targetDirectory_.isEmpty() && !exportItems().isEmpty();
620}
621
623 return exportWorkflow_ && workflowMode() == kCreateMode;
624}
625
627 return exportWorkflow_ && workflowMode() == kProgressMode;
628}
629
631 return showCancel();
632}
633
635 return exportWorkflow_ && exportWorkflow_->isPaused();
636}
637
639 return isPaused() ? tr("Resume") : tr("Pause");
640}
641
643 return exportWorkflow_ && workflowMode() != kCreateMode
644 ? exportWorkflow_->progress()
645 : 0.0;
646}
647
649 if (!exportWorkflow_) {
650 return tr("Ready");
651 }
652 if (!exportWorkflow_->error().isEmpty()) {
653 return exportWorkflow_->error();
654 }
655 if (!exportWorkflow_->phase().isEmpty()) {
656 return exportWorkflow_->phase();
657 }
658 return tr("Ready");
659}
660
662 return exportWorkflow_ && !exportWorkflow_->error().isEmpty();
663}
664
665QVariantList ExportViewModel::exportLogs() const {
666 return selectors_ ? selectors_->exportLogRows() : QVariantList{};
667}
668
670 if (actions_) {
671 actions_->browseExportDirectory();
672 }
673}
674
676 if (!canStart()) {
677 return;
678 }
680 "ExportViewModel::startExport", "Export start submitted",
681 {{observability::context::kPath, targetDirectory_.toStdString()},
683 std::to_string(std::max(1, static_cast<int>(exportItems().size())))}});
684 const bool includeFormulas =
685 settings_ ? settings_->exportIncludeFormulas() : true;
686 const int itemCount = static_cast<int>(exportItems().size());
687 exportWorkflow_->exportDataWithPayload(0, targetDirectory_, includeFormulas,
688 defaultLocale(), payload(),
689 std::max(1, itemCount));
690}
691
693 if (exportWorkflow_) {
694 observability::traceViewModel("ExportViewModel::cancelExport",
695 "Export cancel submitted");
696 exportWorkflow_->cancelExport();
697 }
698}
699
701 if (exportWorkflow_) {
702 exportWorkflow_->pauseExport();
703 }
704}
705
707 if (exportWorkflow_) {
708 exportWorkflow_->resumeExport();
709 }
710}
711
712void ExportViewModel::openExportLogLocation(const QString& logId) {
713 if (!selectors_ || !fileSystemBrowser_) {
714 return;
715 }
716
717 const QString targetPath = selectors_->exportLogTargetPath(logId);
718 fileSystemBrowser_->openLocation(targetPath);
719}
720
721void ExportViewModel::deleteExportLog(const QString& logId) {
722 if (!commands_) {
723 return;
724 }
726 "ExportViewModel::deleteExportLog", "Export log delete submitted",
727 {{observability::context::kId, logId.toStdString()}});
728 const QString trimmed = logId.trimmed();
729 if (!trimmed.isEmpty()) {
730 commands_->deleteExportLog(trimmed);
731 }
732}
733
734QVariantMap ExportViewModel::payload() const {
735 return {{exportKeys::kTargetDirectory, targetDirectory_},
736 {exportKeys::kPackageFormatIndex, packageFormatIndex_},
737 {exportKeys::kItems, exportItems()}};
738}
739
740QString ExportViewModel::defaultLocale() const {
741 return QLocale::system().name().replace(QLatin1Char('_'), QLatin1Char('-'));
742}
743
744int ExportViewModel::workflowMode() const {
745 return exportWorkflow_ ? exportWorkflow_->currentMode() : kCreateMode;
746}
747
748void ExportViewModel::emitChanged() {
749 emit changed();
750}
751
752} // namespace ui
Declares QAction wrappers exposed to the UI layer and QML.
Declares the QML API for the Export view.
Declares the asynchronous export workflow used by ExportViewModel.
Declares the UI helper that exposes a minimal filesystem view to QML.
Declarations for the UI PayloadKeys component.
Declares the centralized UI settings view model exposed to QML.
Declarations for the UI Trace component.
Declares read-only workspace selectors for QML payloads.
Declares the UI workspace snapshot store.
Owns the main window actions and exposes them to QML.
Definition AppActions.h:18
void exportDirectorySelected(const QString &path)
Emitted after an export directory was chosen by the user.
Q_INVOKABLE void clearForm()
Clears the export form back to defaults.
QVariantList analysisRows
Q_INVOKABLE void browseDirectory()
Opens the export directory picker through shell actions.
Q_INVOKABLE void cancelExport()
Cancels the active export workflow.
void changed()
Emitted when export view model state changed.
void setActions(Actions *value)
Binds shell actions such as the export directory picker.
Q_INVOKABLE void updateStandaloneAnalysisAtIndex(int entryIndex, int analysisIndex)
Replaces a standalone analysis package entry.
Q_INVOKABLE void refreshFromWorkspace()
Refreshes export form rows from the current workspace state.
Q_INVOKABLE void deleteExportLog(const QString &logId)
Deletes an export log from the workspace.
void setPackageFormatIndex(int value)
Updates the selected package format index.
Q_INVOKABLE void updateAnnualAnalysisExportType(int entryIndex, int analysisIndex, const QString &exportType)
Updates export type for an analysis inside an annual entry.
Q_INVOKABLE void openExportLogLocation(const QString &logId)
Opens the target folder for an export log.
Q_INVOKABLE void pauseExport()
Pauses the active export workflow.
Q_INVOKABLE void updateStandaloneAnalysisExportType(int entryIndex, const QString &exportType)
Updates export type for a standalone analysis entry.
void setWorkspaceRoles(WorkspaceStore *store, WorkspaceCommands *commands, WorkspaceSelectors *selectors)
Binds workspace roles used for catalog rows and export logs.
void setTargetDirectory(const QString &value)
Updates the selected export target directory.
Q_INVOKABLE void removeEntry(int index)
Removes an export package entry.
Q_INVOKABLE void addSelectedEntry()
Adds the selected annual or analysis to the export package.
void setSettings(Settings *value)
Binds export settings used by defaults and package options.
Q_INVOKABLE void updateAnnualCollapsed(int entryIndex, bool collapsed)
Updates collapsed state for an annual package entry.
void setFileSystemBrowser(FileSystemBrowser *value)
Binds filesystem defaults used by the export form.
QVariantList exportLogs
void setExportWorkflow(ExportWorkflow *value)
Binds the workflow used to execute exports.
Q_INVOKABLE void updateAnnualEntryAtIndex(int entryIndex, int annualIndex)
Replaces an annual package entry with another annual row.
Q_INVOKABLE void resumeExport()
Resumes the active export workflow.
ExportViewModel(QObject *parent=nullptr)
Creates the export view model.
Q_INVOKABLE void startExport()
Starts the export workflow with the current package configuration.
Q_INVOKABLE void selectAddRow(int index)
Selects a row in the current add combobox.
QVariantList annualRows
void setAddMode(const QString &value)
Switches the add combobox between annual and analysis mode.
Coordinates asynchronous exports from a read-only state snapshot.
void stateChanged()
Emitted when export workflow state changed.
Exposes directory listing and application-directory lookup to QML.
Q_INVOKABLE QString appDir() const
Return the current application directory path.
Stores and exposes globally persisted UI settings for settings-related views.
Definition Settings.h:19
QString exportDefaultDirectory
Definition Settings.h:44
void exportDefaultDirectoryChanged()
void exportArchiveFormatChanged()
void exportIncludeFormulasChanged()
Maps UI intent to core workspace writer commands.
Projects workspace store data into QML-facing read models.
Owns the current UI-side workspace snapshot and revision lifecycle.
void dataRevisionChanged()
constexpr auto kPath
Definition Trace.h:35
constexpr auto kId
Definition Trace.h:30
constexpr auto kCount
Definition Trace.h:23
void traceViewModel(const char *origin, std::string message, core::errors::ErrorContext context={})
Emits a view model trace event.
Definition Trace.h:97
QVariantList options(const QString &neutral, const QString &unverified, const QString &verified, const QString &completed)
Builds transaction status options.
Declares UI-side workspace command submission.