File indexing completed on 2024-04-28 03:51:16

0001 /*.
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "mainwindow.h"
0008 
0009 #include "ui_configure_step_general.h"
0010 
0011 #include "clipboard.h"
0012 #include "worldmodel.h"
0013 #include "worldscene.h"
0014 #include "worldbrowser.h"
0015 #include "propertiesbrowser.h"
0016 #include "infobrowser.h"
0017 #include "undobrowser.h"
0018 #include "itempalette.h"
0019 #include "settings.h"
0020 #include "unitscalc.h"
0021 
0022 #include <stepcore/solver.h>
0023 #include <stepcore/collisionsolver.h>
0024 
0025 #include <QAction>
0026 #include <QDir>
0027 #include <QFile>
0028 #include <QFileDialog>
0029 #include <QGraphicsView>
0030 #include <QIcon>
0031 #include <QItemSelectionModel>
0032 #include <QKeySequence>
0033 #include <QMenu>
0034 #include <QStandardPaths>
0035 #include <QStatusBar>
0036 #include <QTemporaryFile>
0037 
0038 #include <kwidgetsaddons_version.h>
0039 #include <KActionCollection>
0040 #include <KConfig>
0041 #include <KConfigDialog>
0042 #include <KIO/CopyJob>
0043 #include <KIO/Job>
0044 #include <KIO/FileCopyJob>
0045 #include <KJobWidgets>
0046 #include <KLocalizedString>
0047 #include <KMessageBox>
0048 #include <KNSWidgets/Action>
0049 #include <KRecentFilesAction>
0050 #include <KStandardAction>
0051 
0052 #include <QActionGroup>
0053 #include <cstdlib>
0054 #include <ctime>
0055 
0056 MainWindow::MainWindow()
0057 {
0058     std::srand(time(nullptr));
0059 
0060     // Load UnitCalc at startup
0061     UnitsCalc::self();
0062 
0063     setObjectName(QStringLiteral("MainWindow"));
0064 
0065     setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
0066     setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
0067     setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
0068     setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
0069 
0070     worldModel = new WorldModel(this);
0071     worldModel->setActions(actionCollection());
0072 
0073     itemPalette = new ItemPalette(worldModel, this);
0074     itemPalette->setObjectName(QStringLiteral("itemPalette"));
0075     addDockWidget(Qt::LeftDockWidgetArea, itemPalette);
0076 
0077     worldBrowser = new WorldBrowser(worldModel, this);
0078     worldBrowser->setObjectName(QStringLiteral("worldBrowser"));
0079     addDockWidget(Qt::RightDockWidgetArea, worldBrowser);
0080 
0081     propertiesBrowser = new PropertiesBrowser(worldModel, this);
0082     propertiesBrowser->setObjectName(QStringLiteral("propertiesBrowser"));
0083     addDockWidget(Qt::RightDockWidgetArea, propertiesBrowser);
0084 
0085     infoBrowser = new InfoBrowser(worldModel, this);
0086     infoBrowser->setObjectName(QStringLiteral("infoBrowser"));
0087     addDockWidget(Qt::RightDockWidgetArea, infoBrowser);
0088 
0089     undoBrowser = new UndoBrowser(worldModel, this);
0090     undoBrowser->setObjectName(QStringLiteral("undoBrowser"));
0091     addDockWidget(Qt::RightDockWidgetArea, undoBrowser);
0092 
0093     worldScene = new WorldScene(worldModel, this);
0094     worldGraphicsView = new WorldGraphicsView(worldScene, this);
0095     setCentralWidget(worldGraphicsView);
0096 
0097     connect(worldModel, &WorldModel::simulationStopped, this, &MainWindow::simulationStopped);
0098     connect(worldModel->selectionModel(), &QItemSelectionModel::selectionChanged,
0099                                  this, &MainWindow::worldSelectionChanged);
0100     connect(itemPalette, &ItemPalette::beginAddItem,
0101         worldScene,  &WorldScene::beginAddItem);
0102     connect(worldScene,  &WorldScene::endAddItem,
0103         itemPalette, &ItemPalette::endAddItem);
0104     connect(worldScene,  SIGNAL(linkActivated(QUrl)),
0105         infoBrowser, SLOT(openUrl(QUrl)));
0106     connect(worldScene,  &WorldScene::endAddItem,
0107             this,        &MainWindow::worldSelectionChanged);
0108     
0109 
0110     setupActions();
0111     setupGUI();
0112     statusBar()->show();
0113 
0114     newFile();
0115 }
0116 
0117 MainWindow::~MainWindow()
0118 {
0119     disconnect(worldModel->undoStack(), &QUndoStack::cleanChanged, this, &MainWindow::updateCaption);
0120 
0121     KConfig* config = new KConfig(QStringLiteral("steprc"));
0122     actionRecentFiles->saveEntries(config->group("RecentFiles"));
0123     delete config;
0124 }
0125 
0126 void MainWindow::setupActions()
0127 {
0128     /* File menu */
0129     KStandardAction::openNew(this, SLOT(newFile()), actionCollection());
0130     KStandardAction::open(this, SLOT(openFile()), actionCollection());
0131     KStandardAction::save(this, SLOT(saveFile()), actionCollection());
0132     KStandardAction::saveAs(this, SLOT(saveFileAs()), actionCollection());
0133     KStandardAction::quit(this, SLOT(close()), actionCollection());
0134     actionRecentFiles = KStandardAction::openRecent(this, SLOT(openFile(QUrl)),
0135                             actionCollection());
0136 
0137     KConfig* config = new KConfig(QStringLiteral("steprc"));
0138     actionRecentFiles->loadEntries(config->group("RecentFiles"));
0139     delete config;
0140 
0141     QAction * actionOpenTutorial = actionCollection()->add<QAction>(
0142                 QStringLiteral("file_tutorial_open"), this, SLOT(openTutorial()));
0143     actionOpenTutorial->setText(i18n("&Open Tutorial..."));
0144     actionOpenTutorial->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
0145 
0146     QAction * actionOpenExample = actionCollection()->add<QAction>(
0147                 QStringLiteral("file_example_open"), this, SLOT(openExample()));
0148     actionOpenExample->setText(i18n("&Open Example..."));
0149     actionOpenExample->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
0150 
0151     QAction * actionOpenLocalExample = actionCollection()->add<QAction>(
0152                 QStringLiteral("file_example_openlocal"), this, SLOT(openLocalExample()));
0153     actionOpenLocalExample->setText(i18n("Open Down&loaded Example..."));
0154     actionOpenLocalExample->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
0155 
0156     QAction * actionUploadExample = actionCollection()->add<QAction>(
0157                 QStringLiteral("file_example_upload"), this, SLOT(uploadExample()));
0158     actionUploadExample->setText(i18n("Share C&urrent Experiment..."));
0159     actionUploadExample->setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")));
0160 
0161     KNSWidgets::Action *actionDownloadExamples = new KNSWidgets::Action(i18n("&Download New Experiments..."), QStringLiteral("step.knsrc"), actionCollection());
0162     actionCollection()->addAction(QStringLiteral("file_example_download"), actionDownloadExamples);
0163 
0164     /* Edit menu */
0165     actionRedo = KStandardAction::redo(worldModel->undoStack(), SLOT(redo()), actionCollection());
0166     actionUndo = KStandardAction::undo(worldModel->undoStack(), SLOT(undo()), actionCollection());
0167     actionRedo->setEnabled(false); actionUndo->setEnabled(false);
0168     actionRedo->setIconText(i18n("Redo")); actionUndo->setIconText(i18n("Undo"));
0169     connect(worldModel->undoStack(), &QUndoStack::canRedoChanged, actionRedo, &QAction::setEnabled);
0170     connect(worldModel->undoStack(), &QUndoStack::canUndoChanged, actionUndo, &QAction::setEnabled);
0171     connect(worldModel->undoStack(), &QUndoStack::cleanChanged, this, &MainWindow::updateCaption);
0172     connect(worldModel->undoStack(), &QUndoStack::undoTextChanged,
0173                                  this, &MainWindow::undoTextChanged);
0174     connect(worldModel->undoStack(), &QUndoStack::redoTextChanged,
0175                                  this, &MainWindow::redoTextChanged);
0176     
0177     actionCut = KStandardAction::cut(worldModel, SLOT(cutSelectedItems()),
0178                                      actionCollection());
0179     actionCopy = KStandardAction::copy(worldModel, SLOT(copySelectedItems()),
0180                                        actionCollection());
0181     actionPaste = KStandardAction::paste(worldModel, SLOT(pasteItems()),
0182                                          actionCollection());
0183     actionCut->setEnabled(false);
0184     actionCopy->setEnabled(false);
0185     actionPaste->setEnabled(worldModel->clipboard()->canPaste());
0186     connect(worldModel->clipboard(), &Clipboard::canPasteChanged,
0187             actionPaste, &QAction::setEnabled);
0188 
0189     actionDelete = actionCollection()->add<QAction>(QStringLiteral("edit_delete"), worldModel, SLOT(deleteSelectedItems()));
0190     actionDelete->setText(i18n("&Delete"));
0191     actionDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0192     actionDelete->setEnabled(false);
0193     actionCollection()->setDefaultShortcut(actionDelete, QKeySequence(Qt::Key_Delete));
0194 
0195     /* Simulation menu */
0196     // The run speed action group
0197     QActionGroup* runSpeedGroup = new QActionGroup(this);
0198 
0199     // The run action collection, this is used in the toolbar to create a dropdown menu on the run button
0200     runSpeedAction = new QAction(QIcon::fromTheme(QStringLiteral("media-playback-start")), i18n("&Run"), this);
0201     connect(runSpeedAction, &QAction::triggered, 
0202             this, &MainWindow::simulationStartStop);
0203     QMenu* runSpeedActionMenu = new QMenu(this);
0204     runSpeedAction->setMenu(runSpeedActionMenu);
0205     actionCollection()->addAction(QStringLiteral("run_speed"), runSpeedAction);
0206     runSpeedActionMenu->setStatusTip(i18n("Execute the program"));
0207     runSpeedActionMenu->setWhatsThis(i18n("Run: Execute the program"));
0208 
0209     fullSpeedAct = new QAction(i18nc("@option:radio", "1x Speed"), this);
0210     actionCollection()->addAction(QStringLiteral("full_speed"), fullSpeedAct );
0211     fullSpeedAct->setCheckable(true);
0212     fullSpeedAct->setChecked(true);
0213     connect(fullSpeedAct, &QAction::triggered, this, &MainWindow::setFullSpeed);
0214     runSpeedGroup->addAction(fullSpeedAct);
0215     runSpeedActionMenu->addAction(fullSpeedAct);
0216     
0217     slowSpeedAct = new QAction(i18nc("@option:radio choose the slow speed", "2x Speed"), this);
0218     actionCollection()->addAction(QStringLiteral("slow_speed"), slowSpeedAct );
0219     slowSpeedAct->setCheckable(true);
0220     connect(slowSpeedAct, &QAction::triggered, this, &MainWindow::setSlowSpeed);
0221     runSpeedGroup->addAction(slowSpeedAct);
0222     runSpeedActionMenu->addAction(slowSpeedAct);
0223 
0224     slowerSpeedAct = new QAction(i18nc("@option:radio", "4x Speed"), this);
0225     actionCollection()->addAction(QStringLiteral("slower_speed"), slowerSpeedAct );
0226     slowerSpeedAct->setCheckable(true);
0227     connect(slowerSpeedAct, &QAction::triggered, this, &MainWindow::setSlowerSpeed);
0228     runSpeedGroup->addAction(slowerSpeedAct);
0229     runSpeedActionMenu->addAction(slowerSpeedAct);
0230 
0231     slowestSpeedAct = new QAction(i18nc("@option:radio", "8x Speed"), this);
0232     actionCollection()->addAction(QStringLiteral("slowest_speed"), slowestSpeedAct );
0233     slowestSpeedAct->setCheckable(true);
0234     connect(slowestSpeedAct, &QAction::triggered, this, &MainWindow::setSlowestSpeed);
0235     runSpeedGroup->addAction(slowestSpeedAct);
0236     runSpeedActionMenu->addAction(slowestSpeedAct);
0237 
0238     stepSpeedAct = new QAction(i18nc("@option:radio", "16x Speed"), this);
0239     actionCollection()->addAction(QStringLiteral("step_speed"), stepSpeedAct );
0240     stepSpeedAct->setCheckable(true);
0241     connect(stepSpeedAct, &QAction::triggered, this, &MainWindow::setStepSpeed);
0242     runSpeedGroup->addAction(stepSpeedAct);
0243     runSpeedActionMenu->addAction(stepSpeedAct);
0244 
0245     simulationStopped(0);
0246 
0247     /* View menu */
0248     KStandardAction::actualSize(worldGraphicsView, SLOT(actualSize()), actionCollection());
0249     KStandardAction::fitToPage(worldGraphicsView, SLOT(fitToPage()), actionCollection());
0250     KStandardAction::zoomIn(worldGraphicsView, SLOT(zoomIn()), actionCollection());
0251     KStandardAction::zoomOut(worldGraphicsView, SLOT(zoomOut()), actionCollection());
0252 
0253     /* Settings menu */
0254     KStandardAction::preferences(this, SLOT(configureStep()), actionCollection());
0255 
0256     /* Dock widgets */
0257     actionCollection()->addAction(QStringLiteral("toggle_palette_dock"), itemPalette->toggleViewAction());
0258     actionCollection()->addAction(QStringLiteral("toggle_world_dock"), worldBrowser->toggleViewAction());
0259     actionCollection()->addAction(QStringLiteral("toggle_properties_dock"), propertiesBrowser->toggleViewAction());
0260     actionCollection()->addAction(QStringLiteral("toggle_info_dock"), infoBrowser->toggleViewAction());
0261     actionCollection()->addAction(QStringLiteral("toggle_undo_dock"), undoBrowser->toggleViewAction());
0262 }
0263 
0264 void MainWindow::updateCaption()
0265 {
0266     QString shownName;
0267     if (currentFileUrl.isEmpty())
0268     shownName = i18nc("filename", "untitled.step"); //Fixme if needed
0269     else
0270     shownName = currentFileUrl.url(QUrl::PreferLocalFile); //QFileInfo(currentFileName).fileName();
0271     setCaption(shownName, !worldModel->undoStack()->isClean());
0272 }
0273 
0274 bool MainWindow::queryClose()
0275 {
0276     if(worldModel->isSimulationActive()) simulationStop();
0277     if(maybeSave()) {
0278         return true;
0279     } else {
0280         return false;
0281     }
0282 }
0283 
0284 bool MainWindow::newFile()
0285 {
0286     if(worldModel->isSimulationActive()) simulationStop();
0287     if(!maybeSave()) return false;
0288 
0289     worldModel->clearWorld();
0290     worldGraphicsView->actualSize();
0291     worldGraphicsView->centerOn(0,0);
0292     currentFileUrl = QUrl();
0293     updateCaption();
0294     undoBrowser->setEmptyLabel(i18n("<new file>"));
0295     undoBrowser->setCurrentFileUrl(currentFileUrl);
0296 
0297     setFullSpeed(); // resetting the speed to the default speed of 1x
0298     return true;
0299 }
0300 
0301 bool MainWindow::openFile(const QUrl& url, const QUrl& startUrl)
0302 {
0303     if(worldModel->isSimulationActive()) simulationStop();
0304     if(!maybeSave()) return false;
0305 
0306     QUrl fileUrl = url;
0307     if(fileUrl.isEmpty()) {
0308         fileUrl = QFileDialog::getOpenFileUrl(this, i18nc("@title:window", "Open Step File"), startUrl, i18n("Step files (*.step)"));
0309         if(fileUrl.isEmpty()) return false;
0310     }
0311 
0312     worldModel->clearWorld();
0313     newFile();
0314 
0315     QFile file(fileUrl.path());
0316 
0317     if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0318         KMessageBox::error(this, i18n("Cannot open file '%1'", file.fileName()));
0319         return false;
0320     }
0321     
0322     if(!worldModel->loadXml(&file)) {
0323         KMessageBox::error(this, i18n("Cannot parse file '%1': %2", fileUrl.url(QUrl::PreferLocalFile),
0324                                                     worldModel->errorString()));
0325         return false;
0326     }
0327 
0328     worldGraphicsView->fitToPage();
0329     currentFileUrl = fileUrl;
0330     updateCaption();
0331     actionRecentFiles->addUrl(fileUrl);
0332     undoBrowser->setEmptyLabel(i18n("<open file: %1>", fileUrl.fileName()));
0333     undoBrowser->setCurrentFileUrl(currentFileUrl);
0334 
0335     return true;
0336 }
0337 
0338 bool MainWindow::saveFileAs(const QUrl& url, const QUrl& startUrl)
0339 {
0340     if(worldModel->isSimulationActive()) simulationStop();
0341     QUrl fileUrl = url;
0342     if(fileUrl.isEmpty()) {
0343         fileUrl = QFileDialog::getSaveFileUrl(this, i18nc("@title:window", "Save Step File"), startUrl.isEmpty() ? currentFileUrl : startUrl, i18n("Step files (*.step)"));
0344         if(fileUrl.isEmpty()) return false;
0345         }
0346 
0347     bool local = fileUrl.isLocalFile();
0348     QFile* file;
0349 
0350     if(!local) {
0351         QTemporaryFile *tempFile = new QTemporaryFile();
0352         tempFile->setAutoRemove(true);
0353     file = tempFile;
0354     } else {
0355         file = new QFile(fileUrl.path());
0356     }
0357 
0358     if(!file->open(QIODevice::WriteOnly | QIODevice::Text)) {
0359         KMessageBox::error(this, i18n("Cannot open file '%1'", file->fileName()));
0360         delete file;
0361         return false;
0362     }
0363     
0364     if(!worldModel->saveXml(file)) {
0365         KMessageBox::error(this, i18n("Cannot save file '%1': %2",
0366                       fileUrl.url(QUrl::PreferLocalFile),
0367                       worldModel->errorString()));
0368         delete file;
0369         return false;
0370     }
0371 
0372     if(!local) {
0373         KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(file->fileName()), fileUrl, -1, KIO::Overwrite);
0374         KJobWidgets::setWindow(job, this);
0375         job->exec();
0376         if (job->error()) {
0377             KMessageBox::error(this, job->errorString());
0378             delete file;
0379             return false;
0380         }
0381     }
0382 
0383     delete file;
0384 
0385     worldModel->undoStack()->setClean();
0386     currentFileUrl = fileUrl;
0387     updateCaption();
0388     undoBrowser->setCurrentFileUrl(currentFileUrl);
0389     return true;
0390 }
0391 
0392 bool MainWindow::saveFile()
0393 {
0394     if(worldModel->isSimulationActive()) simulationStop();
0395     return saveFileAs(currentFileUrl);
0396 }
0397 
0398 bool MainWindow::maybeSave()
0399 {
0400     if(!worldModel->undoStack()->isClean()) {
0401 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0402          int ret = KMessageBox::warningTwoActionsCancel(this,
0403 #else
0404          int ret = KMessageBox::warningYesNoCancel(this, 
0405 #endif
0406               i18n("The experiment has been modified.\nDo you want to save your changes?"),
0407               i18n("Warning - Step"), KStandardGuiItem::save(), KStandardGuiItem::discard());
0408 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0409          if (ret == KMessageBox::PrimaryAction) return saveFile();
0410 #else
0411          if (ret == KMessageBox::Yes) return saveFile();
0412 #endif
0413          else if(ret == KMessageBox::Cancel) return false;
0414     }
0415     return true;
0416 }
0417 
0418 void MainWindow::openTutorial()
0419 {
0420     // XXX: need to be redone
0421     //qDebug() << "inside MainWindow::openTutorial()";
0422     QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppLocalDataLocation, QStringLiteral("tutorials"), QStandardPaths::LocateDirectory);
0423     QString localDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1Char('/');
0424     foreach(const QString &dirName, dirs) {
0425         //qDebug() << "dirName: " << dirName;
0426         if(!dirName.startsWith(localDir)) {
0427         openFile(QUrl(), QUrl::fromLocalFile(dirName));
0428             return;
0429         }
0430     }
0431 }
0432 
0433 void MainWindow::openExample()
0434 {
0435     //qDebug() << "inside MainWindow::openExample()";
0436     // XXX: need to be redone
0437     QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppLocalDataLocation, QStringLiteral("examples"), QStandardPaths::LocateDirectory);
0438     QString localDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1Char('/');
0439     foreach(const QString &dirName, dirs) {
0440         if(!dirName.startsWith(localDir)) {
0441             openFile(QUrl(), QUrl::fromLocalFile(dirName));
0442             return;
0443         }
0444     }
0445 }
0446 
0447 void MainWindow::openLocalExample()
0448 {
0449     // XXX: need to be redone
0450     QString dir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/examples";
0451     if(dir.isEmpty()) return;
0452     QDir::root().mkpath(dir);
0453     openFile(QUrl(), QUrl::fromLocalFile(dir));
0454 }
0455 
0456 void MainWindow::uploadExample()
0457 {
0458     KMessageBox::error(this, i18n("Uploading is still not implemented in kdelibs."),
0459                         i18n("Sorry - Step"));
0460     /*
0461     int ret = KMessageBox::questionYesNo(this,
0462                 i18n("Do you want to upload current experiment to public web server ?"),
0463                 i18n("Question - Step"));
0464     if(ret != KMessageBox::Yes) return;
0465 
0466     if(currentFileUrl.isEmpty() || !worldModel->undoStack()->isClean()) {
0467         ret = KMessageBox::warningContinueCancel(this,
0468                 i18n("The experiment is not saved. You should it before uploading."),
0469                 i18n("Warning - Step"), KStandardGuiItem::save(), KStandardGuiItem::cancel());
0470         if(ret != KMessageBox::Continue) return;
0471         if(!saveFile()) return;
0472     }
0473 
0474     KNS::Engine::upload( currentFileUrl.url() );
0475     */
0476 }
0477 
0478 void MainWindow::simulationStartStop()
0479 {
0480     if(worldModel->isSimulationActive()) simulationStop();
0481     else simulationStart();
0482 }
0483 
0484 void MainWindow::simulationStart()
0485 {
0486     runSpeedAction->setIconText(i18n("&Stop"));
0487     runSpeedAction->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop")));
0488 
0489     undoBrowser->setUndoEnabled(false);
0490     actionUndo->setEnabled(false);
0491     worldModel->simulationStart();
0492 }
0493 
0494 void MainWindow::simulationStopped(int result)
0495 {
0496     runSpeedAction->setIconText(i18n("&Simulate"));
0497     runSpeedAction->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
0498 
0499     undoBrowser->setUndoEnabled(true);
0500     if(result == StepCore::Solver::ToleranceError) {
0501         KMessageBox::error(this, i18n("Cannot finish this step because local error "
0502                "is greater than local tolerance.\n"
0503                "Please check solver settings and try again."));
0504     } else if(result == StepCore::Solver::IntersectionDetected || 
0505               result == StepCore::Solver::CollisionDetected) {
0506         KMessageBox::error(this, i18n("Cannot finish this step because there are collisions "
0507                "which cannot be resolved automatically.\n"
0508                "Please move colliding objects apart and try again."));
0509     } else if(result != StepCore::Solver::OK) {
0510         KMessageBox::error(this, i18n("Cannot finish this step because of an unknown error."));
0511     }
0512 }
0513 
0514 void MainWindow::simulationStop()
0515 {
0516     worldModel->simulationStop();
0517 }
0518 
0519 void MainWindow::setRunSpeed(int speed)
0520 {
0521     switch (speed) {
0522         case 0: fullSpeedAct->setChecked(true);    
0523                 worldModel->world()->setTimeScale( 1.0);
0524                 break;
0525         case 1: slowSpeedAct->setChecked(true);
0526                 worldModel->world()->setTimeScale( 2.0);
0527                 break;
0528         case 2: slowerSpeedAct->setChecked(true);
0529                 worldModel->world()->setTimeScale( 4.0);
0530                 break;
0531         case 3: slowestSpeedAct->setChecked(true);
0532                 worldModel->world()->setTimeScale( 8.0);
0533                 break;
0534         case 4: stepSpeedAct->setChecked(true);
0535                 worldModel->world()->setTimeScale( 16.0);
0536                 break;
0537     }
0538     runSpeed = speed;
0539 }
0540 
0541 void MainWindow::undoTextChanged(const QString& undoText)
0542 {
0543     if(undoText.isEmpty()) actionUndo->setText(i18n("&Undo"));
0544     else actionUndo->setText(i18n("&Undo: %1", undoText));
0545 }
0546 
0547 void MainWindow::redoTextChanged(const QString& redoText)
0548 {
0549     if(redoText.isEmpty()) actionRedo->setText(i18n("Re&do"));
0550     else actionRedo->setText(i18n("Re&do: %1", redoText));
0551 }
0552 
0553 void MainWindow::worldSelectionChanged()
0554 {
0555     if (!worldScene->hasItemCreator()) {
0556         foreach (const QModelIndex &index,
0557                  worldModel->selectionModel()->selection().indexes()) {
0558             if (index != worldModel->worldIndex() && worldModel->item(index)) {
0559                 actionDelete->setEnabled(true);
0560                 actionCut->setEnabled(true);
0561                 actionCopy->setEnabled(true);
0562                 return;
0563             }
0564         }
0565     }
0566     actionDelete->setEnabled(false);
0567     actionCut->setEnabled(false);
0568     actionCopy->setEnabled(false);
0569 }
0570 
0571 void MainWindow::configureStep()
0572 {
0573     if(KConfigDialog::showDialog( QStringLiteral("settings") )) return; 
0574 
0575     KConfigDialog* dialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self());
0576 
0577     Ui::ConfigureStepGeneralWidget generalUi;
0578     QWidget* generalWidget = new QWidget(nullptr);
0579     generalWidget->setObjectName(QStringLiteral("general"));
0580     generalUi.setupUi(generalWidget);
0581     dialog->addPage(generalWidget, i18n("General"), QStringLiteral("step")); //shows the "step" icon, the "general" icon doesn't exist
0582 
0583     connect(dialog, &KConfigDialog::settingsChanged,
0584                 worldGraphicsView, &WorldGraphicsView::settingsChanged); 
0585     connect(dialog, &KConfigDialog::settingsChanged,
0586                 propertiesBrowser, &PropertiesBrowser::settingsChanged); 
0587 
0588     dialog->show();
0589 }
0590 
0591 /*
0592 void MainWindow::on_actionNew_triggered(bool checked)
0593 {
0594     if(maybeSave()) newFile();
0595 }
0596 
0597 void MainWindow::on_actionOpen_triggered(bool checked)
0598 {
0599     if(maybeSave()) openFile(QString());
0600 }
0601 
0602 void MainWindow::on_actionSave_triggered(bool checked)
0603 {
0604     saveFileAs(currentFileName);
0605 }
0606 
0607 void MainWindow::on_actionSaveAs_triggered(bool checked)
0608 {
0609     saveFile();
0610 }
0611 
0612 void MainWindow::on_actionStep_triggered(bool checked)
0613 {
0614     if(!worldModel->doWorldEvolve(0.1))
0615         QMessageBox::warning(this, i18n("Step"), // XXX: retrieve error message from solver !
0616             i18n("Cannot finish this step because local error is bigger than local tolerance.<br />"
0617                "Please check solver settings and try again."));
0618 }
0619 
0620 void MainWindow::on_actionSimulation_triggered(bool checked)
0621 {
0622     if(!simulationTimer->isActive()) {
0623         actionSimulation->setText(i18n("&Stop"));
0624         simulationTimer->start();
0625     } else {
0626         simulationTimer->stop();
0627         actionSimulation->setText(i18n("&Simulation"));
0628     }
0629 }
0630 
0631 void MainWindow::on_simulationTimer_timeout()
0632 {
0633     worldModel->doWorldEvolve(1.0/FPS);
0634 }
0635 
0636 void MainWindow::on_actionAboutStep_triggered(bool checked)
0637 {
0638     QMessageBox::about(this, i18n("About Step"),
0639              i18n("<center>The <b>Step</b> is an interactive physical simulator.<br /><br />"
0640                 "Distributed under terms of the GNU GPL license.<br />"
0641                 "(C) 2006-2007 Kuznetsov Vladimir.</center>"));
0642 }
0643 */
0644 
0645 #include "moc_mainwindow.cpp"