Changeset 394216e468 in tspsg for src/mainwindow.cpp


Ignore:
Timestamp:
Mar 22, 2010, 9:45:16 PM (14 years ago)
Author:
Oleksii Serdiuk
Branches:
0.1.3.145-beta1-symbian, 0.1.4.170-beta2-bb10, appveyor, imgbot, master, readme
Children:
1babbd6ba3
Parents:
e2abfd326f
Message:
  • Fixed a bug when a solution couldn't be found for some tasks while the task had at least one solution (mostly, tasks with a lot of restrictions).
  • Fixed a bug when Save As dialog always appeared (even for non-Untitled files) when selecting Save in Unsaved Changes dialog.
  • Improved the solution algorithm.
  • Moved progress dialog from CTSPSolver to MainWindow?. CTSPSolver doesn't contain any GUI related code now.

+ Added routePartFound() signal to CTSPSolver which is emitted once every time a part of the route is found.
+ Added cancel() slot and wasCanceled() public function to CTSPSolver to be able to cancel a solution process and to know whether it was canceled.
+ Progress is now shown when generating a solution output.
+ Check for updates functionality (only in Windows version at this moment).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/mainwindow.cpp

    re2abfd326f r394216e468  
    6060#endif // QT_NO_PRINTER
    6161        connect(actionSettingsPreferences,SIGNAL(triggered()),this,SLOT(actionSettingsPreferencesTriggered()));
     62#ifdef Q_OS_WIN32
     63        connect(actionHelpCheck4Updates, SIGNAL(triggered()), SLOT(actionHelpCheck4UpdatesTriggered()));
     64#endif // Q_OS_WIN32
    6265        connect(actionSettingsLanguageAutodetect,SIGNAL(triggered(bool)),this,SLOT(actionSettingsLanguageAutodetectTriggered(bool)));
    6366        connect(groupSettingsLanguageList,SIGNAL(triggered(QAction *)),this,SLOT(groupSettingsLanguageListTriggered(QAction *)));
     
    134137        filters.append(tr("All Files") + " (*)");
    135138
     139QString file = QFileInfo(fileName).canonicalPath();
    136140QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
    137 QString file = QFileDialog::getOpenFileName(this, tr("Task Load"), QString(), filters.join(";;"), NULL, opts);
     141        file = QFileDialog::getOpenFileName(this, tr("Task Load"), file, filters.join(";;"), NULL, opts);
    138142        if (file.isEmpty() || !QFileInfo(file).isFile())
    139143                return;
     
    147151}
    148152
    149 void MainWindow::actionFileSaveTriggered()
    150 {
    151         qDebug() << tr("Untitled");
     153bool MainWindow::actionFileSaveTriggered()
     154{
    152155        if ((fileName == tr("Untitled") + ".tspt") || (!fileName.endsWith(".tspt", Qt::CaseInsensitive)))
    153                 saveTask();
     156                return saveTask();
    154157        else
    155                 if (tspmodel->saveTask(fileName))
     158                if (tspmodel->saveTask(fileName)) {
    156159                        setWindowModified(false);
     160                        return true;
     161                } else
     162                        return false;
    157163}
    158164
     
    165171{
    166172static QString selectedFile;
    167         if (selectedFile.isEmpty()) {
    168                 if (fileName == tr("Untitled") + ".tspt") {
    169 #ifndef QT_NO_PRINTER
    170                         selectedFile = "solution.pdf";
     173        if (selectedFile.isEmpty())
     174                selectedFile = QFileInfo(fileName).canonicalPath();
     175        else
     176                selectedFile = QFileInfo(selectedFile).canonicalPath();
     177        if (!selectedFile.isEmpty())
     178                selectedFile += "/";
     179        if (fileName == tr("Untitled") + ".tspt") {
     180#ifndef QT_NO_PRINTER
     181                selectedFile += "solution.pdf";
    171182#else
    172                         selectedFile = "solution.html";
     183                selectedFile += "solution.html";
    173184#endif // QT_NO_PRINTER
    174                 } else {
    175 #ifndef QT_NO_PRINTER
    176                         selectedFile = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".pdf";
     185        } else {
     186#ifndef QT_NO_PRINTER
     187                selectedFile += QFileInfo(fileName).completeBaseName() + ".pdf";
    177188#else
    178                         selectedFile = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".html";
     189                selectedFile += QFileInfo(fileName).completeBaseName() + ".html";
    179190#endif // QT_NO_PRINTER
    180                 }
    181191        }
    182192
     
    191201        filters.append(tr("All Files") + " (*)");
    192202
    193 QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
     203QFileDialog::Options opts(settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog);
    194204QString file = QFileDialog::getSaveFileName(this, QString(), selectedFile, filters.join(";;"), NULL, opts);
    195205        if (file.isEmpty())
     
    211221        if (!(selectedFile.endsWith(".htm",Qt::CaseInsensitive) || selectedFile.endsWith(".html",Qt::CaseInsensitive) || selectedFile.endsWith(".odt",Qt::CaseInsensitive) || selectedFile.endsWith(".txt",Qt::CaseInsensitive)))
    212222                dw.setFormat("plaintext");
    213         dw.write(solutionText->document());
    214 #else
     223        if (!dw.write(solutionText->document()))
     224                QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(dw.device()->errorString()));
     225#else // QT_VERSION >= 0x040500
    215226        // Qt < 4.5 has no QTextDocumentWriter class
    216227QFile file(selectedFile);
    217228        if (!file.open(QFile::WriteOnly)) {
    218229                QApplication::restoreOverrideCursor();
     230                QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(file->errorString()));
    219231                return;
    220232        }
     
    258270        if (sd.colorChanged() || sd.fontChanged()) {
    259271                initDocStyleSheet();
    260                 if (!output.isEmpty() && sd.colorChanged() && (QMessageBox(QMessageBox::Question,tr("Settings Changed"),tr("You have changed color settings.\nDo you wish to apply them to current solution text?"),QMessageBox::Yes | QMessageBox::No,this).exec() == QMessageBox::Yes)) {
    261                         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    262                         solutionText->clear();
    263                         solutionText->setHtml(output.join(""));
    264                         QApplication::restoreOverrideCursor();
    265                 }
    266         }
    267         if (sd.translucencyChanged() != 0) {
     272                if (!solutionText->document()->isEmpty() && sd.colorChanged())
     273                        QMessageBox::information(this, tr("Settings Changed"), tr("You have changed color settings.\nThey will be applied to the next solution output."));
     274        }
     275        if (sd.translucencyChanged() != 0)
    268276                toggleTranclucency(sd.translucencyChanged() == 1);
    269         }
    270277}
    271278
     
    283290        if (actionSettingsLanguageAutodetect->isChecked()) {
    284291                // We have language autodetection. It needs to be disabled to change language.
    285                 if (QMessageBox(QMessageBox::Question,tr("Language change"),tr("You have language autodetection turned on.\nIt needs to be off.\nDo you wish to turn it off?"),QMessageBox::Yes | QMessageBox::No,this).exec() == QMessageBox::Yes) {
     292                if (QMessageBox::question(this, tr("Language change"), tr("You have language autodetection turned on.\nIt needs to be off.\nDo you wish to turn it off?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
    286293                        actionSettingsLanguageAutodetect->trigger();
    287294                } else
     
    302309#endif
    303310                QApplication::restoreOverrideCursor();
    304         }
    305 }
     311                QMessageBox::information(this, tr("Settings Changed"), tr("You have changed the application language.\nTo get current solution output in the new language\nyou need to re-run the solution process."));
     312        }
     313}
     314
     315#ifdef Q_OS_WIN32
     316void MainWindow::actionHelpCheck4UpdatesTriggered()
     317{
     318        if (!hasUpdater()) {
     319                QMessageBox::warning(this, tr("Unsupported Feature"), tr("Sorry, but this feature is not supported on your platform\nor support for this feature was not installed."));
     320                return;
     321        }
     322
     323        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
     324        QProcess::execute("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\"");
     325        QApplication::restoreOverrideCursor();
     326}
     327#endif // Q_OS_WIN32
    306328
    307329void MainWindow::actionHelpAboutTriggered()
    308330{
    309 //! \todo TODO: Normal about window :-)
    310331QString title;
    311332#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
     
    314335        title += QString("<b>TSPSG: TSP Solver and Generator</b><br>");
    315336#endif // Q_OS_WINCE || Q_OS_SYMBIAN
    316         title += QString("%1: <b>%2</b><br>").arg(tr("Version"), BUILD_VERSION);
     337        title += QString("%1: <b>%2</b><br>").arg(tr("Version"), QApplication::applicationVersion());
    317338#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
    318         title += QString("<b>&copy; 2007-%1 Oleksii \"Lёppa\" Serdiuk</b><br>").arg(QDate::currentDate().toString("yyyy"));
     339        title += QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b><br>").arg(QDate::currentDate().toString("yyyy"), QApplication::organizationDomain(), QApplication::organizationName());
    319340        title += QString("<b><a href=\"http://tspsg.sourceforge.net/\">http://tspsg.sourceforge.net/</a></b>");
    320341#else
     
    410431        vb->addLayout(hb2);
    411432
    412         dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint);
     433        dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
    413434        dlg->setWindowTitle(tr("About TSPSG"));
    414435        dlg->setLayout(vb);
     
    453474                        row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok));
    454475                        if (!ok) {
    455                                 QMessageBox(QMessageBox::Critical,tr("Data error"),tr("Error in cell [Row %1; Column %2]: Invalid data format.").arg(r + 1).arg(c + 1),QMessageBox::Ok,this).exec();
     476                                QMessageBox::critical(this, tr("Data error"), tr("Error in cell [Row %1; Column %2]: Invalid data format.").arg(r + 1).arg(c + 1));
    456477                                return;
    457478                        }
     
    459480                matrix.append(row);
    460481        }
     482
     483QProgressDialog pd(this);
     484QProgressBar *pb = new QProgressBar(&pd);
     485        pb->setAlignment(Qt::AlignCenter);
     486        pb->setFormat(tr("%v of %1 parts found").arg(n));
     487        pd.setBar(pb);
     488        pd.setMaximum(n * 2 + 3);
     489        pd.setMinimumDuration(1000);
     490        pd.setLabelText(tr("Calculating optimal route..."));
     491        pd.setWindowTitle(tr("Solution Progress"));
     492        pd.setWindowModality(Qt::ApplicationModal);
     493        pd.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
     494        pd.setValue(0);
     495
    461496CTSPSolver solver;
    462 SStep *root = solver.solve(n,matrix,this);
    463         if (!root)
    464                 return;
    465         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    466 QColor color = settings->value("Output/Color",DEF_FONT_COLOR).value<QColor>();
    467         output.clear();
    468         output.append("<p>" + tr("Variant #%1").arg(spinVariant->value()) + "</p>");
    469         output.append("<p>" + tr("Task:") + "</p>");
    470         outputMatrix(matrix, output);
    471         output.append("<hr>");
    472         output.append("<p>" + tr("Solution of Variant #%1 task").arg(spinVariant->value()) + "</p>");
     497        connect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
     498        connect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
     499SStep *root = solver.solve(n, matrix);
     500        disconnect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
     501        disconnect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
     502        if (!root) {
     503                pd.reset();
     504                if (!solver.wasCanceled())
     505                        QMessageBox::warning(this, tr("Solution Result"), tr("Unable to find a solution.\nMaybe, this task has no solution."));
     506                return;
     507        }
     508        pb->setFormat("%p%");
     509        pd.setLabelText(tr("Generating solution output..."));
     510        pd.setValue(n + 1);
     511
     512        solutionText->clear();
     513        pd.setValue(n + 2);
     514
     515        solutionText->setDocumentTitle(tr("Solution of Variant #%1 task").arg(spinVariant->value()));
     516        solutionText->append("<p>" + tr("Variant #%1").arg(spinVariant->value()) + "</p>");
     517        solutionText->append("<p>" + tr("Task:") + "</p>");
     518        solutionText->append(outputMatrix(matrix));
     519        solutionText->append("<hr><p>" + tr("Solution of Variant #%1 task").arg(spinVariant->value()) + "</p>");
    473520SStep *step = root;
    474521        n = 1;
    475522        while (n <= spinCities->value()) {
     523                if (pd.wasCanceled()) {
     524                        solutionText->clear();
     525                        return;
     526                }
     527                pd.setValue(spinCities->value() + 2 + n);
     528
    476529                if (step->prNode->prNode != NULL || ((step->prNode->prNode == NULL) && (step->plNode->prNode == NULL))) {
    477530                        if (n != spinCities->value()) {
    478                                 output.append("<p>" + tr("Step #%1").arg(n++) + "</p>");
     531                                solutionText->append("<p>" + tr("Step #%1").arg(n++) + "</p>");
    479532                                if (settings->value("Output/ShowMatrix", DEF_SHOW_MATRIX).toBool() && (!settings->value("Output/UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT).toBool() || (settings->value("Output/UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT).toBool() && (spinCities->value() <= settings->value("Output/ShowMatrixLimit", DEF_SHOW_MATRIX_LIMIT).toInt())))) {
    480                                         outputMatrix(*step, output);
     533                                        solutionText->append(outputMatrix(*step));
    481534                                }
    482                                 output.append("<p>" + tr("Selected candidate for branching: %1.").arg(tr("(%1;%2)").arg(step->candidate.nRow + 1).arg(step->candidate.nCol + 1)) + "</p>");
     535                                solutionText->append("<p>" + tr("Selected candidate for branching: %1.").arg(tr("(%1;%2)").arg(step->candidate.nRow + 1).arg(step->candidate.nCol + 1)) + "</p>");
    483536                                if (!step->alts.empty()) {
    484537SCandidate cand;
     
    489542                                                alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1);
    490543                                        }
    491                                         output.append("<p class=\"hasalts\">" + tr("%n alternate candidate(s) for branching: %1.","",step->alts.count()).arg(alts) + "</p>");
     544                                        solutionText->append("<p class=\"hasalts\">" + tr("%n alternate candidate(s) for branching: %1.","",step->alts.count()).arg(alts) + "</p>");
    492545                                }
    493                                 output.append("<p>&nbsp;</p>");
     546                                solutionText->append("<p>&nbsp;</p>");
    494547                        }
    495548                }
     
    501554                        break;
    502555        }
     556        pd.setValue(spinCities->value() + 2 + n);
     557
    503558        if (solver.isOptimal())
    504                 output.append("<p>" + tr("Optimal path:") + "</p>");
     559                solutionText->append("<p>" + tr("Optimal path:") + "</p>");
    505560        else
    506                 output.append("<p>" + tr("Resulting path:") + "</p>");
    507         output.append("<p>&nbsp;&nbsp;" + solver.getSortedPath() + "</p>");
     561                solutionText->append("<p>" + tr("Resulting path:") + "</p>");
     562        solutionText->append("<p>&nbsp;&nbsp;" + solver.getSortedPath() + "</p>");
    508563        if (isInteger(step->price))
    509                 output.append("<p>" + tr("The price is <b>%n</b> unit(s).", "", qRound(step->price)) + "</p>");
     564                solutionText->append("<p>" + tr("The price is <b>%n</b> unit(s).", "", qRound(step->price)) + "</p>");
    510565        else
    511                 output.append("<p>" + tr("The price is <b>%1</b> units.").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()) + "</p>");
     566                solutionText->append("<p>" + tr("The price is <b>%1</b> units.").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()) + "</p>");
    512567        if (!solver.isOptimal()) {
    513                 output.append("<p>&nbsp;</p>");
    514                 output.append("<p>" + tr("<b>WARNING!!!</b><br>This result is a record, but it may not be optimal.<br>Iterations need to be continued to check whether this result is optimal or get an optimal one.") + "</p>");
    515         }
    516         output.append("<p></p>");
    517 
    518         solutionText->setHtml(output.join(""));
    519         solutionText->setDocumentTitle(tr("Solution of Variant #%1 task").arg(spinVariant->value()));
     568                solutionText->append("<p>&nbsp;</p>");
     569                solutionText->append("<p>" + tr("<b>WARNING!!!</b><br>This result is a record, but it may not be optimal.<br>Iterations need to be continued to check whether this result is optimal or get an optimal one.") + "</p>");
     570        }
    520571
    521572        if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) {
    522573                // Scrolling to the end of text.
    523574                solutionText->moveCursor(QTextCursor::End);
    524         }
    525 
     575        } else
     576                solutionText->moveCursor(QTextCursor::Start);
     577
     578        pd.setLabelText(tr("Cleaning up..."));
     579        pd.setMaximum(0);
     580        pd.setCancelButton(NULL);
     581        pd.adjustSize();
     582        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
     583        solver.cleanup(true);
    526584        toggleSolutionActions();
    527585        tabWidget->setCurrentIndex(1);
    528         QApplication::restoreOverrideCursor();
    529586}
    530587
     
    632689}
    633690
     691bool MainWindow::hasUpdater() const
     692{
     693#ifdef Q_OS_WIN32
     694        return QFile::exists("updater/Update.exe");
     695#else // Q_OS_WIN32
     696        return false;
     697#endif // Q_OS_WIN32
     698}
     699
    634700void MainWindow::initDocStyleSheet()
    635701{
     
    719785                if (!ad) {
    720786                        settings->remove("Language");
    721                         if (QApplication::overrideCursor() != 0)
    722                                 QApplication::restoreOverrideCursor();
     787                        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
    723788                        if (isVisible())
    724789                                QMessageBox::warning(this, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
    725790                        else
    726791                                QMessageBox::warning(NULL, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
     792                        QApplication::restoreOverrideCursor();
    727793                }
    728794                return false;
     
    735801        if (!isWindowModified())
    736802                return true;
    737 int res = QMessageBox(QMessageBox::Warning,tr("Unsaved Changes"),tr("Would you like to save changes in current task?"),QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,this).exec();
     803int res = QMessageBox::warning(this, tr("Unsaved Changes"), tr("Would you like to save changes in the current task?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
    738804        if (res == QMessageBox::Save)
    739                 return saveTask();
     805                return actionFileSaveTriggered();
    740806        else if (res == QMessageBox::Cancel)
    741807                return false;
     
    744810}
    745811
    746 void MainWindow::outputMatrix(const TMatrix &matrix, QStringList &output)
     812QString MainWindow::outputMatrix(const TMatrix &matrix) const
    747813{
    748814int n = spinCities->value();
    749 QString line="";
     815QString output(""), line;
    750816        output.append("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
    751817        for (int r = 0; r < n; r++) {
     
    761827        }
    762828        output.append("</table>");
    763 }
    764 
    765 void MainWindow::outputMatrix(const SStep &step, QStringList &output)
     829        return output;
     830}
     831
     832QString MainWindow::outputMatrix(const SStep &step) const
    766833{
    767834int n = spinCities->value();
    768 QString line="";
     835QString output(""), line;
    769836        output.append("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
    770837        for (int r = 0; r < n; r++) {
     
    789856        }
    790857        output.append("</table>");
     858        return output;
    791859}
    792860
     
    816884        actionFilePrint->setShortcut(QApplication::translate("MainWindow", "Ctrl+P", 0, QApplication::UnicodeUTF8));
    817885#endif // QT_NO_PRINTER
     886#ifdef Q_OS_WIN32
     887        actionHelpCheck4Updates->setText(tr("Check for &Updates..."));
     888#ifndef QT_NO_TOOLTIP
     889        actionHelpCheck4Updates->setToolTip(tr("Check for %1 updates").arg(QApplication::applicationName()));
     890#endif // QT_NO_TOOLTIP
     891#ifndef QT_NO_STATUSTIP
     892        actionHelpCheck4Updates->setStatusTip(tr("Check for %1 updates").arg(QApplication::applicationName()));
     893#endif // QT_NO_STATUSTIP
     894#endif // Q_OS_WIN32
    818895}
    819896
     
    901978        toolBar->insertAction(actionSettingsPreferences,actionFilePrint);
    902979#endif // QT_NO_PRINTER
     980#ifdef Q_OS_WIN32
     981        actionHelpCheck4Updates = new QAction(this);
     982        actionHelpCheck4Updates->setEnabled(hasUpdater());
     983        menuHelp->insertAction(actionHelpAboutQt, actionHelpCheck4Updates);
     984        menuHelp->insertSeparator(actionHelpAboutQt);
     985#endif // Q_OS_WIN32
    903986
    904987        groupSettingsLanguageList = new QActionGroup(this);
     
    9251008        actionFileSaveAsSolution->setEnabled(enable);
    9261009        solutionText->setEnabled(enable);
    927         if (!enable)
    928                 output.clear();
    9291010#ifndef QT_NO_PRINTER
    9301011        actionFilePrint->setEnabled(enable);
Note: See TracChangeset for help on using the changeset viewer.