| 1 #include <QApplication> |
1 #include <QApplication> |
| 2 #include <QFileDialog> |
2 #include <QFileDialog> |
| 3 #include <QMessageBox> |
3 #include <QMessageBox> |
| 4 #include <QMdiSubWindow> |
4 #include <QMdiSubWindow> |
| 5 #include <QStackedWidget> |
5 #include <QStackedWidget> |
| |
6 #include <QCloseEvent> |
| 6 #include "mainwindow.h" |
7 #include "mainwindow.h" |
| 7 #include "ui_mainwindow.h" |
8 #include "ui_mainwindow.h" |
| 8 #include "version.h" |
9 #include "version.h" |
| |
10 #include "ui/canvas.h" |
| 9 #include "document.h" |
11 #include "document.h" |
| 10 #include "settingseditor/settingseditor.h" |
12 #include "settingseditor/settingseditor.h" |
| 11 #include "widgets/colorselectdialog.h" |
13 #include "widgets/colorselectdialog.h" |
| 12 |
14 |
| 13 static const QDir LOCALE_DIR {":/locale"}; |
15 static const QDir LOCALE_DIR {":/locale"}; |
| |
16 |
| |
17 class ModelSubWindow : public QMdiSubWindow |
| |
18 { |
| |
19 Q_OBJECT |
| |
20 public: |
| |
21 const ModelId modelId; |
| |
22 ModelSubWindow(ModelId modelId, QWidget* widget) : |
| |
23 QMdiSubWindow{widget}, |
| |
24 modelId{modelId} |
| |
25 { |
| |
26 } |
| |
27 protected: |
| |
28 void closeEvent(QCloseEvent* event) override |
| |
29 { |
| |
30 event->ignore(); |
| |
31 } |
| |
32 }; |
| 14 |
33 |
| 15 static void doQtRegistrations() |
34 static void doQtRegistrations() |
| 16 { |
35 { |
| 17 QCoreApplication::setApplicationName(::appName); |
36 QCoreApplication::setApplicationName(::appName); |
| 18 QCoreApplication::setOrganizationName("hecknology.net"); |
37 QCoreApplication::setOrganizationName("hecknology.net"); |
| 29 constexpr MemberType memberInstance(BaseType* instance) const |
48 constexpr MemberType memberInstance(BaseType* instance) const |
| 30 { |
49 { |
| 31 return *reinterpret_cast<MemberType*>(reinterpret_cast<char*>(instance) + this->member); |
50 return *reinterpret_cast<MemberType*>(reinterpret_cast<char*>(instance) + this->member); |
| 32 } |
51 } |
| 33 }; |
52 }; |
| |
53 |
| |
54 class ModelData : public QObject |
| |
55 { |
| |
56 Q_OBJECT |
| |
57 public: |
| |
58 ModelData(QObject* parent) : QObject {parent} {} |
| |
59 std::unique_ptr<Canvas> canvas; |
| |
60 std::unique_ptr<QItemSelectionModel> itemSelectionModel; |
| |
61 std::unique_ptr<EditTools> tools; |
| |
62 Model* model; |
| |
63 }; |
| |
64 #include "main.moc" |
| 34 |
65 |
| 35 static constexpr MemberData<Ui_MainWindow, QAction*, gl::RenderStyle> renderStyleButtons[] = { |
66 static constexpr MemberData<Ui_MainWindow, QAction*, gl::RenderStyle> renderStyleButtons[] = { |
| 36 { offsetof(Ui_MainWindow, actionRenderStyleNormal), gl::RenderStyle::Normal }, |
67 { offsetof(Ui_MainWindow, actionRenderStyleNormal), gl::RenderStyle::Normal }, |
| 37 { offsetof(Ui_MainWindow, actionRenderStyleBfc), gl::RenderStyle::BfcRedGreen }, |
68 { offsetof(Ui_MainWindow, actionRenderStyleBfc), gl::RenderStyle::BfcRedGreen }, |
| 38 { offsetof(Ui_MainWindow, actionRenderStyleRandom), gl::RenderStyle::RandomColors }, |
69 { offsetof(Ui_MainWindow, actionRenderStyleRandom), gl::RenderStyle::RandomColors }, |
| 105 qApp->installTranslator(translator); |
136 qApp->installTranslator(translator); |
| 106 } |
137 } |
| 107 } |
138 } |
| 108 } |
139 } |
| 109 |
140 |
| 110 /* |
141 ModelData* findModelData(DocumentManager* documents, ModelId modelId) |
| 111 void MainWindow::handleDocumentSplitterChange() |
142 { |
| 112 { |
143 return documents->findPayload<ModelData>(modelId); |
| 113 EditorTabWidget* currentDocument = this->currentDocument(); |
144 } |
| 114 if (currentDocument != nullptr) |
145 |
| 115 { |
146 static ModelSubWindow* currentModelSubWindow(Ui_MainWindow* ui) |
| 116 this->documentSplitterState = currentDocument->saveSplitterState(); |
147 { |
| 117 for (int i = 0; i < this->ui->tabs->count(); i += 1) |
148 return qobject_cast<ModelSubWindow*>(ui->mdiArea->activeSubWindow()); |
| 118 { |
149 } |
| 119 EditorTabWidget* document = qobject_cast<EditorTabWidget*>(this->ui->tabs->widget(i)); |
150 |
| 120 if (document != nullptr and document != currentDocument) |
151 static ModelData* currentModelData(Ui_MainWindow* ui, DocumentManager* documents) |
| 121 { |
152 { |
| 122 document->restoreSplitterState(this->documentSplitterState); |
153 if (auto* const activeSubWindow = currentModelSubWindow(ui)) { |
| 123 } |
154 return findModelData(documents, activeSubWindow->modelId); |
| 124 } |
155 } |
| 125 this->settings.setMainSplitterState(this->documentSplitterState); |
156 else { |
| 126 } |
|
| 127 } |
|
| 128 */ |
|
| 129 |
|
| 130 static EditorTabWidget* currentTabWidget(Ui_MainWindow* ui) |
|
| 131 { |
|
| 132 QMdiSubWindow* activeSubWindow = ui->mdiArea->activeSubWindow(); |
|
| 133 if (activeSubWindow == nullptr) { |
|
| 134 return nullptr; |
157 return nullptr; |
| 135 } |
158 } |
| |
159 } |
| |
160 |
| |
161 static Model* currentModelBody(Ui_MainWindow* ui, DocumentManager* documents) |
| |
162 { |
| |
163 if (auto* const activeSubWindow = currentModelSubWindow(ui)) { |
| |
164 return documents->getModelById(activeSubWindow->modelId); |
| |
165 } |
| 136 else { |
166 else { |
| 137 return qobject_cast<EditorTabWidget*>(activeSubWindow->widget()); |
167 return nullptr; |
| 138 } |
168 } |
| 139 }; |
169 } |
| 140 |
170 |
| 141 |
171 static std::optional<ModelId> findCurrentModelId(Ui_MainWindow* ui) |
| 142 static void closeDocument(DocumentManager* documents, EditorTabWidget *document) |
172 { |
| 143 { |
173 ModelSubWindow* activeSubWindow = qobject_cast<ModelSubWindow*>(ui->mdiArea->activeSubWindow()); |
| 144 std::optional<ModelId> modelId = documents->findIdForModel(document->model); |
174 if (activeSubWindow != nullptr) { |
| 145 if (modelId.has_value()) { |
175 return activeSubWindow->modelId; |
| 146 documents->closeDocument(modelId.value()); |
|
| 147 delete document; |
|
| 148 } |
|
| 149 } |
|
| 150 |
|
| 151 static std::optional<ModelId> findCurrentModelId(Ui_MainWindow* ui, DocumentManager* documents) |
|
| 152 { |
|
| 153 const EditorTabWidget* tab = currentTabWidget(ui); |
|
| 154 if (tab != nullptr) { |
|
| 155 return documents->findIdForModel(tab->model); |
|
| 156 } |
176 } |
| 157 else { |
177 else { |
| 158 return {}; |
178 return {}; |
| 159 } |
179 } |
| 160 } |
180 } |
| 194 action->setData(path); |
214 action->setData(path); |
| 195 menu->addAction(action); |
215 menu->addAction(action); |
| 196 } |
216 } |
| 197 } |
217 } |
| 198 |
218 |
| |
219 template<typename Fn> |
| |
220 static void forModel(const DocumentManager* documents, Fn&& fn) |
| |
221 { |
| |
222 forValueInMap(*documents, [&fn](const DocumentManager::ModelInfo& info) |
| |
223 { |
| |
224 ModelData* modelSpecificData = qobject_cast<ModelData*>(info.payload); |
| |
225 if (modelSpecificData != nullptr) { |
| |
226 fn(&info, modelSpecificData); |
| |
227 } |
| |
228 }); |
| |
229 } |
| |
230 |
| 199 static void updateRenderPreferences( |
231 static void updateRenderPreferences( |
| 200 Ui_MainWindow* ui, |
232 Ui_MainWindow* ui, |
| 201 const gl::RenderPreferences* renderPreferences) |
233 const gl::RenderPreferences* renderPreferences, |
| 202 { |
234 const DocumentManager* documents) |
| 203 for (QMdiSubWindow* subWindow : ui->mdiArea->subWindowList()) { |
235 { |
| 204 EditorTabWidget* tab = qobject_cast<EditorTabWidget*>(subWindow->widget()); |
236 forModel(documents, [&renderPreferences](const void*, const ModelData* data){ |
| 205 if (tab != nullptr) { |
237 if (data->canvas != nullptr) { |
| 206 tab->canvas->setRenderPreferences(*renderPreferences); |
238 data->canvas->setRenderPreferences(*renderPreferences); |
| 207 } |
239 } |
| 208 } |
240 }); |
| 209 for (auto data : ::renderStyleButtons) { |
241 for (auto data : ::renderStyleButtons) { |
| 210 QAction* action = data.memberInstance(ui); |
242 QAction* action = data.memberInstance(ui); |
| 211 action->setChecked(renderPreferences->style == data.payload); |
243 action->setChecked(renderPreferences->style == data.payload); |
| 212 } |
244 } |
| 213 ui->actionDrawAxes->setChecked(renderPreferences->drawAxes); |
245 ui->actionDrawAxes->setChecked(renderPreferences->drawAxes); |
| 338 renderPreferences = loadRenderPreferences(&settings); |
369 renderPreferences = loadRenderPreferences(&settings); |
| 339 changeLanguage(settings.locale(), &translator); |
370 changeLanguage(settings.locale(), &translator); |
| 340 libraries.restoreFromSettings(&settings); |
371 libraries.restoreFromSettings(&settings); |
| 341 updateRecentlyOpenedDocumentsMenu(); |
372 updateRecentlyOpenedDocumentsMenu(); |
| 342 colorTable = loadColors(&libraries); |
373 colorTable = loadColors(&libraries); |
| 343 updateRenderPreferences(&ui, &renderPreferences); |
374 updateRenderPreferences(&ui, &renderPreferences, &documents); |
| 344 ui.mdiArea->setViewMode(static_cast<QMdiArea::ViewMode>(settings.viewMode())); |
375 ui.mdiArea->setViewMode(static_cast<QMdiArea::ViewMode>(settings.viewMode())); |
| 345 ui.retranslateUi(&mainWindow); |
376 ui.retranslateUi(&mainWindow); |
| 346 }; |
377 }; |
| 347 const auto addRecentlyOpenedFile = [&](const QString& path){ |
378 const auto addRecentlyOpenedFile = [&](const QString& path){ |
| 348 constexpr int maxRecentlyOpenedFiles = 10; |
379 constexpr int maxRecentlyOpenedFiles = 10; |
| 355 saveSettings(); |
386 saveSettings(); |
| 356 updateRecentlyOpenedDocumentsMenu(); |
387 updateRecentlyOpenedDocumentsMenu(); |
| 357 }; |
388 }; |
| 358 const auto openModelForEditing = [&](const ModelId modelId){ |
389 const auto openModelForEditing = [&](const ModelId modelId){ |
| 359 Model* model = documents.getModelById(modelId); |
390 Model* model = documents.getModelById(modelId); |
| 360 EditorTabWidget* document = new EditorTabWidget{model, &documents, colorTable}; |
391 if (model != nullptr) { |
| 361 QObject::connect( |
392 ModelData* data = new ModelData(&documents); |
| 362 document, |
393 data->tools = std::make_unique<EditTools>(model, colorTable); |
| 363 &EditorTabWidget::modelAction, |
394 data->canvas = std::make_unique<Canvas>(model, data->tools.get(), &documents, colorTable); |
| 364 std::bind(executeAction, model, std::placeholders::_1)); |
395 data->itemSelectionModel = std::make_unique<QItemSelectionModel>(model); |
| 365 QItemSelectionModel* selectionModel = new QItemSelectionModel{model}; |
396 data->model = model; |
| 366 itemSelectionModels[model] = selectionModel; |
397 QObject::connect( |
| 367 QObject::connect(selectionModel, &QItemSelectionModel::selectionChanged, |
398 data->tools.get(), |
| 368 [model, document](const QItemSelection& selected, const QItemSelection& deselected) |
399 &EditTools::modelAction, |
| 369 { |
400 std::bind(executeAction, model, std::placeholders::_1)); |
| 370 auto resolveIndex = [&model](const QModelIndex& index){ |
401 QObject::connect(data->itemSelectionModel.get(), &QItemSelectionModel::selectionChanged, |
| 371 return model->idAt(index.row()); |
402 [modelId, &documents]( |
| 372 }; |
403 const QItemSelection& selected, |
| 373 auto resolve = [&resolveIndex](const QItemSelection& selection) |
404 const QItemSelection& deselected) |
| 374 { |
405 { |
| 375 return fn::map<QSet<ModelId>>(selection.indexes(), resolveIndex); |
406 ModelData* data = findModelData(&documents, modelId); |
| 376 }; |
407 if (data != nullptr) { |
| 377 document->canvas->handleSelectionChange(resolve(selected), resolve(deselected)); |
408 auto resolveIndex = [&data](const QModelIndex& index){ |
| 378 }); |
409 return data->model->idAt(index.row()); |
| 379 document->canvas->setRenderPreferences(renderPreferences); |
410 }; |
| 380 QObject::connect( |
411 auto resolve = [&resolveIndex](const QItemSelection& selection) |
| 381 document, |
412 { |
| 382 &EditorTabWidget::newStatusText, |
413 return fn::map<QSet<ModelId>>(selection.indexes(), resolveIndex); |
| 383 [&](const QString& newStatusText) { |
414 }; |
| 384 mainWindow.statusBar()->showMessage(newStatusText); |
415 data->canvas->handleSelectionChange(resolve(selected), resolve(deselected)); |
| |
416 } |
| 385 }); |
417 }); |
| 386 const QFileInfo fileInfo{*documents.modelPath(modelId)}; |
418 data->canvas->setRenderPreferences(renderPreferences); |
| 387 QMdiSubWindow* subWindow = ui.mdiArea->addSubWindow(document); |
419 QObject::connect( |
| 388 subWindow->setWindowTitle(tabName(fileInfo)); |
420 data->tools.get(), |
| 389 subWindow->show(); |
421 &EditTools::newStatusText, |
| |
422 [&](const QString& newStatusText) { |
| |
423 mainWindow.statusBar()->showMessage(newStatusText); |
| |
424 }); |
| |
425 const QFileInfo fileInfo{*documents.modelPath(modelId)}; |
| |
426 QMdiSubWindow* subWindow = ui.mdiArea->addSubWindow(data->canvas.get()); |
| |
427 subWindow->setWindowTitle(tabName(fileInfo)); |
| |
428 subWindow->show(); |
| |
429 } |
| 390 }; |
430 }; |
| 391 QObject::connect(ui.actionNew, &QAction::triggered, [&]{ |
431 QObject::connect(ui.actionNew, &QAction::triggered, [&]{ |
| 392 openModelForEditing(documents.newModel()); |
432 openModelForEditing(documents.newModel()); |
| 393 }); |
433 }); |
| 394 QObject::connect(ui.actionOpen, &QAction::triggered, [&]{ |
434 QObject::connect(ui.actionOpen, &QAction::triggered, [&]{ |
| 409 { |
449 { |
| 410 restoreSettings(); |
450 restoreSettings(); |
| 411 } |
451 } |
| 412 }); |
452 }); |
| 413 QObject::connect(ui.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); |
453 QObject::connect(ui.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); |
| 414 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&ui]{ |
454 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{ |
| 415 EditorTabWidget* tab = currentTabWidget(&ui); |
455 if (ModelData* data = currentModelData(&ui, &documents)) { |
| 416 if (tab != nullptr) |
456 adjustGridToView(data->canvas.get()); |
| 417 { |
|
| 418 adjustGridToView(tab->canvas); |
|
| 419 } |
457 } |
| 420 }); |
458 }); |
| 421 QObject::connect(ui.actionClose, &QAction::triggered, [&ui, &documents]{ |
459 QObject::connect(ui.actionClose, &QAction::triggered, [&ui, &documents]{ |
| 422 EditorTabWidget* tab = currentTabWidget(&ui); |
460 if (ModelData* data = currentModelData(&ui, &documents)) { |
| 423 if (tab != nullptr) |
461 // TODO |
| 424 { |
|
| 425 closeDocument(&documents, tab); |
|
| 426 } |
462 } |
| 427 }); |
463 }); |
| 428 const auto save = [&](ModelId modelId){ |
464 const auto save = [&](ModelId modelId){ |
| 429 QString error; |
465 QString error; |
| 430 QTextStream errorStream{&error}; |
466 QTextStream errorStream{&error}; |
| 465 } |
501 } |
| 466 } |
502 } |
| 467 }; |
503 }; |
| 468 QObject::connect(ui.actionSaveAs, &QAction::triggered, actionSaveAs); |
504 QObject::connect(ui.actionSaveAs, &QAction::triggered, actionSaveAs); |
| 469 QObject::connect(ui.actionSave, &QAction::triggered, [&]{ |
505 QObject::connect(ui.actionSave, &QAction::triggered, [&]{ |
| 470 if (currentTabWidget(&ui) != nullptr) { |
506 const std::optional<ModelId> modelId = findCurrentModelId(&ui); |
| 471 const std::optional<ModelId> modelId = findCurrentModelId(&ui, &documents); |
507 if (modelId.has_value()) { |
| 472 if (modelId.has_value()) { |
508 const QString* path = documents.modelPath(*modelId); |
| 473 const QString* path = documents.modelPath(*modelId); |
509 if (path == nullptr or path->isEmpty()) { |
| 474 if (path == nullptr or path->isEmpty()) { |
510 actionSaveAs(); |
| 475 actionSaveAs(); |
511 } |
| 476 } |
512 else { |
| 477 else { |
513 save(*modelId); |
| 478 save(*modelId); |
|
| 479 } |
|
| 480 } |
514 } |
| 481 } |
515 } |
| 482 }); |
516 }); |
| 483 QObject::connect(ui.actionDelete, &QAction::triggered, [&]{ |
517 QObject::connect(ui.actionDelete, &QAction::triggered, [&]{ |
| 484 EditorTabWidget* tab = currentTabWidget(&ui); |
518 if (Model* model = currentModelBody(&ui, &documents)) { |
| 485 if (tab != nullptr) { |
|
| 486 std::vector<int> selectedRows = rows(ui.modelListView->selectionModel()->selectedRows()); |
519 std::vector<int> selectedRows = rows(ui.modelListView->selectionModel()->selectedRows()); |
| 487 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<int>{}); |
520 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<int>{}); |
| 488 for (int row : selectedRows) { |
521 for (int row : selectedRows) { |
| 489 executeAction(tab->model, DeleteFromModel{.position = row}); |
522 executeAction(model, DeleteFromModel{.position = row}); |
| 490 } |
523 } |
| 491 } |
524 } |
| 492 }); |
525 }); |
| 493 QObject::connect(ui.actionDrawAxes, &QAction::triggered, [&](bool drawAxes){ |
526 QObject::connect(ui.actionDrawAxes, &QAction::triggered, [&](bool drawAxes){ |
| 494 renderPreferences.drawAxes = drawAxes; |
527 renderPreferences.drawAxes = drawAxes; |
| 495 saveSettings(); |
528 saveSettings(); |
| 496 updateRenderPreferences(&ui, &renderPreferences); |
529 updateRenderPreferences(&ui, &renderPreferences, &documents); |
| 497 }); |
530 }); |
| 498 for (auto data : ::renderStyleButtons) { |
531 for (auto data : ::renderStyleButtons) { |
| 499 QAction* action = data.memberInstance(&ui); |
532 QAction* action = data.memberInstance(&ui); |
| 500 QObject::connect(action, &QAction::triggered, [&, data]{ |
533 QObject::connect(action, &QAction::triggered, [&, data]{ |
| 501 renderPreferences.style = data.payload; |
534 renderPreferences.style = data.payload; |
| 502 saveSettings(); |
535 saveSettings(); |
| 503 updateRenderPreferences(&ui, &renderPreferences); |
536 updateRenderPreferences(&ui, &renderPreferences, &documents); |
| 504 }); |
537 }); |
| 505 } |
538 } |
| 506 const auto checkEditingModeAction = [&ui](EditingMode mode) { |
539 const auto checkEditingModeAction = [&ui](EditingMode mode) { |
| 507 for (QAction* action : ui.editingModesToolBar->actions()) { |
540 for (QAction* action : ui.editingModesToolBar->actions()) { |
| 508 action->setChecked(action->data().value<EditingMode>() == mode); |
541 action->setChecked(action->data().value<EditingMode>() == mode); |
| 509 } |
542 } |
| 510 }; |
543 }; |
| 511 initializeTools(&ui, &mainWindow); |
544 initializeTools(&ui, &mainWindow); |
| 512 for (QAction* action : ui.editingModesToolBar->actions()) { |
545 for (QAction* action : ui.editingModesToolBar->actions()) { |
| 513 QObject::connect(action, &QAction::triggered, [&, action]{ |
546 QObject::connect(action, &QAction::triggered, [&, action]{ |
| 514 EditorTabWidget* tab = currentTabWidget(&ui); |
547 if (ModelData* data = currentModelData(&ui, &documents)) { |
| 515 if (tab != nullptr) { |
|
| 516 const EditingMode mode = action->data().value<EditingMode>(); |
548 const EditingMode mode = action->data().value<EditingMode>(); |
| 517 tab->setEditMode(mode); |
549 data->tools->setEditMode(mode); |
| 518 checkEditingModeAction(mode); |
550 checkEditingModeAction(mode); |
| 519 } |
551 } |
| 520 }); |
552 }); |
| 521 } |
553 } |
| 522 QObject::connect(ui.mdiArea, &QMdiArea::subWindowActivated, |
554 QObject::connect(ui.mdiArea, &QMdiArea::subWindowActivated, |
| 523 [&](QMdiSubWindow* subWindow) { |
555 [&](QMdiSubWindow* subWindow) { |
| 524 if (subWindow != nullptr) { |
556 ModelSubWindow* modelSubWindow = qobject_cast<ModelSubWindow*>(subWindow); |
| 525 EditorTabWidget* tab = qobject_cast<EditorTabWidget*>(subWindow->widget()); |
557 if (modelSubWindow != nullptr) { |
| 526 if (tab != nullptr) { |
558 if (ModelData* data = documents.findPayload<ModelData>(modelSubWindow->modelId)) { |
| 527 checkEditingModeAction(tab->currentEditingMode()); |
559 checkEditingModeAction(data->tools->currentEditingMode()); |
| 528 QItemSelectionModel* selectionModel = itemSelectionModels.value(tab->model); |
560 if (data->itemSelectionModel != nullptr) { |
| 529 if (selectionModel != nullptr) { |
561 ui.modelListView->setModel(data->model); |
| 530 ui.modelListView->setModel(tab->model); |
562 ui.modelListView->setSelectionModel(data->itemSelectionModel.get()); |
| 531 ui.modelListView->setSelectionModel(selectionModel); |
|
| 532 } |
563 } |
| 533 } |
564 } |
| 534 } |
565 } |
| 535 }); |
566 }); |
| 536 mainWindow.setWindowTitle(title()); |
567 mainWindow.setWindowTitle(title()); |
| 537 mainWindow.restoreGeometry(settings.mainWindowGeometry()); |
568 mainWindow.restoreGeometry(settings.mainWindowGeometry()); |
| 538 restoreSettings(); |
569 restoreSettings(); |
| 539 updateRenderPreferences(&ui, &renderPreferences); |
570 updateRenderPreferences(&ui, &renderPreferences, &documents); |
| 540 mainWindow.show(); |
571 mainWindow.show(); |
| 541 const int result = app.exec(); |
572 const int result = app.exec(); |
| 542 saveSettings(); |
573 saveSettings(); |
| 543 return result; |
574 return result; |
| 544 } |
575 } |