/* * TSPSG: TSP Solver and Generator * Copyright (C) 2007-2010 Lёppa * * $Id$ * $URL$ * * This file is part of TSPSG. * * TSPSG is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * TSPSG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with TSPSG. If not, see . */ #include "mainwindow.h" /*! * \brief Class constructor. * \param parent Main Window parent widget. * * Initializes Main Window and creates its layout based on target OS. * Loads TSPSG settings and opens a task file if it was specified as a commandline parameter. */ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TSPSG", "tspsg", this); loadLanguage(); setupUi(); initDocStyleSheet(); #ifndef QT_NO_PRINTER printer = new QPrinter(QPrinter::HighResolution); #endif // QT_NO_PRINTER connect(actionFileNew,SIGNAL(triggered()),this,SLOT(actionFileNewTriggered())); connect(actionFileOpen,SIGNAL(triggered()),this,SLOT(actionFileOpenTriggered())); connect(actionFileSave,SIGNAL(triggered()),this,SLOT(actionFileSaveTriggered())); connect(actionFileSaveAsTask,SIGNAL(triggered()),this,SLOT(actionFileSaveAsTaskTriggered())); connect(actionFileSaveAsSolution,SIGNAL(triggered()),this,SLOT(actionFileSaveAsSolutionTriggered())); #ifndef QT_NO_PRINTER connect(actionFilePrintPreview,SIGNAL(triggered()),this,SLOT(actionFilePrintPreviewTriggered())); connect(actionFilePrint,SIGNAL(triggered()),this,SLOT(actionFilePrintTriggered())); #endif // QT_NO_PRINTER connect(actionSettingsPreferences,SIGNAL(triggered()),this,SLOT(actionSettingsPreferencesTriggered())); connect(actionSettingsLanguageAutodetect,SIGNAL(triggered(bool)),this,SLOT(actionSettingsLanguageAutodetectTriggered(bool))); connect(groupSettingsLanguageList,SIGNAL(triggered(QAction *)),this,SLOT(groupSettingsLanguageListTriggered(QAction *))); connect(actionHelpAboutQt,SIGNAL(triggered()),qApp,SLOT(aboutQt())); connect(actionHelpAbout,SIGNAL(triggered()),this,SLOT(actionHelpAboutTriggered())); connect(buttonSolve,SIGNAL(clicked()),this,SLOT(buttonSolveClicked())); connect(buttonRandom,SIGNAL(clicked()),this,SLOT(buttonRandomClicked())); connect(buttonBackToTask,SIGNAL(clicked()),this,SLOT(buttonBackToTaskClicked())); connect(spinCities,SIGNAL(valueChanged(int)),this,SLOT(spinCitiesValueChanged(int))); if (settings->value("SavePos", DEF_SAVEPOS).toBool()) { // Loading of saved window state settings->beginGroup("MainWindow"); #ifndef Q_OS_WINCE restoreGeometry(settings->value("Geometry").toByteArray()); #endif // Q_OS_WINCE restoreState(settings->value("State").toByteArray()); settings->endGroup(); #ifndef Q_OS_WINCE } else { // Centering main window QRect rect = geometry(); rect.moveCenter(QApplication::desktop()->availableGeometry(this).center()); setGeometry(rect); #endif // Q_OS_WINCE } tspmodel = new CTSPModel(this); taskView->setModel(tspmodel); connect(tspmodel,SIGNAL(numCitiesChanged(int)),this,SLOT(numCitiesChanged(int))); connect(tspmodel,SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),this,SLOT(dataChanged(const QModelIndex &, const QModelIndex &))); connect(tspmodel,SIGNAL(layoutChanged()),this,SLOT(dataChanged())); if ((QCoreApplication::arguments().count() > 1) && (tspmodel->loadTask(QCoreApplication::arguments().at(1)))) setFileName(QCoreApplication::arguments().at(1)); else { setFileName(); spinCities->setValue(settings->value("NumCities",DEF_NUM_CITIES).toInt()); spinCitiesValueChanged(spinCities->value()); } setWindowModified(false); } MainWindow::~MainWindow() { #ifndef QT_NO_PRINTER delete printer; #endif } /* Privates **********************************************************/ void MainWindow::actionFileNewTriggered() { if (!maybeSave()) return; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); tspmodel->clear(); setFileName(); setWindowModified(false); tabWidget->setCurrentIndex(0); solutionText->clear(); toggleSolutionActions(false); QApplication::restoreOverrideCursor(); } void MainWindow::actionFileOpenTriggered() { if (!maybeSave()) return; QStringList filters(tr("All Supported Formats") + " (*.tspt *.zkt)"); filters.append(tr("%1 Task Files").arg("TSPSG") + " (*.tspt)"); filters.append(tr("%1 Task Files").arg("ZKomModRd") + " (*.zkt)"); filters.append(tr("All Files") + " (*)"); QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog; QString file = QFileDialog::getOpenFileName(this, tr("Task Load"), QString(), filters.join(";;"), NULL, opts); if (file.isEmpty() || !QFileInfo(file).isFile()) return; if (!tspmodel->loadTask(file)) return; setFileName(file); tabWidget->setCurrentIndex(0); setWindowModified(false); solutionText->clear(); toggleSolutionActions(false); } void MainWindow::actionFileSaveTriggered() { if ((fileName == tr("Untitled") + ".tspt") || (!fileName.endsWith(".tspt",Qt::CaseInsensitive))) saveTask(); else if (tspmodel->saveTask(fileName)) setWindowModified(false); } void MainWindow::actionFileSaveAsTaskTriggered() { saveTask(); } void MainWindow::actionFileSaveAsSolutionTriggered() { static QString selectedFile; if (selectedFile.isEmpty()) { if (fileName == tr("Untitled") + ".tspt") { #ifndef QT_NO_PRINTER selectedFile = "solution.pdf"; #else selectedFile = "solution.html"; #endif // QT_NO_PRINTER } else { #ifndef QT_NO_PRINTER selectedFile = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".pdf"; #else selectedFile = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".html"; #endif // QT_NO_PRINTER } } QStringList filters; #ifndef QT_NO_PRINTER filters.append(tr("PDF Files") + " (*.pdf)"); #endif filters.append(tr("HTML Files") + " (*.html *.htm)"); #if QT_VERSION >= 0x040500 filters.append(tr("OpenDocument Files") + " (*.odt)"); #endif // QT_VERSION >= 0x040500 filters.append(tr("All Files") + " (*)"); QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog; QString file = QFileDialog::getSaveFileName(this, QString(), selectedFile, filters.join(";;"), NULL, opts); if (file.isEmpty()) return; selectedFile = file; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); #ifndef QT_NO_PRINTER if (selectedFile.endsWith(".pdf",Qt::CaseInsensitive)) { QPrinter printer(QPrinter::HighResolution); printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(selectedFile); solutionText->document()->print(&printer); QApplication::restoreOverrideCursor(); return; } #endif #if QT_VERSION >= 0x040500 QTextDocumentWriter dw(selectedFile); if (!(selectedFile.endsWith(".htm",Qt::CaseInsensitive) || selectedFile.endsWith(".html",Qt::CaseInsensitive) || selectedFile.endsWith(".odt",Qt::CaseInsensitive) || selectedFile.endsWith(".txt",Qt::CaseInsensitive))) dw.setFormat("plaintext"); dw.write(solutionText->document()); #else // Qt < 4.5 has no QTextDocumentWriter class QFile file(selectedFile); if (!file.open(QFile::WriteOnly)) { QApplication::restoreOverrideCursor(); return; } QTextStream ts(&file); ts.setCodec(QTextCodec::codecForName("UTF-8")); ts << solutionText->document()->toHtml("UTF-8"); file.close(); #endif // QT_VERSION >= 0x040500 QApplication::restoreOverrideCursor(); } #ifndef QT_NO_PRINTER void MainWindow::actionFilePrintPreviewTriggered() { QPrintPreviewDialog ppd(printer, this); connect(&ppd,SIGNAL(paintRequested(QPrinter *)),SLOT(printPreview(QPrinter *))); ppd.exec(); } void MainWindow::actionFilePrintTriggered() { QPrintDialog pd(printer,this); #if QT_VERSION >= 0x040500 // No such methods in Qt < 4.5 pd.setOption(QAbstractPrintDialog::PrintSelection,false); pd.setOption(QAbstractPrintDialog::PrintPageRange,false); #endif if (pd.exec() != QDialog::Accepted) return; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); solutionText->document()->print(printer); QApplication::restoreOverrideCursor(); } #endif // QT_NO_PRINTER void MainWindow::actionSettingsPreferencesTriggered() { SettingsDialog sd(this); if (sd.exec() != QDialog::Accepted) return; if (sd.colorChanged() || sd.fontChanged()) { initDocStyleSheet(); 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)) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); solutionText->clear(); solutionText->setHtml(output.join("")); QApplication::restoreOverrideCursor(); } } if (sd.translucencyChanged() != 0) { toggleTranclucency(sd.translucencyChanged() == 1); } } void MainWindow::actionSettingsLanguageAutodetectTriggered(bool checked) { if (checked) { settings->remove("Language"); QMessageBox(QMessageBox::Information,tr("Language change"),tr("Language will be autodetected on next application start."),QMessageBox::Ok,this).exec(); } else settings->setValue("Language",groupSettingsLanguageList->checkedAction()->data().toString()); } void MainWindow::groupSettingsLanguageListTriggered(QAction *action) { if (actionSettingsLanguageAutodetect->isChecked()) { // We have language autodetection. It needs to be disabled to change language. 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) { actionSettingsLanguageAutodetect->trigger(); } else return; } bool untitled = (fileName == tr("Untitled") + ".tspt"); if (loadLanguage(action->data().toString())) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); settings->setValue("Language",action->data().toString()); retranslateUi(); if (untitled) setFileName(); QApplication::restoreOverrideCursor(); } } void MainWindow::actionHelpAboutTriggered() { //! \todo TODO: Normal about window :-) QString title; #ifdef Q_OS_WINCE title += QString::fromUtf8("TSPSG
TSP Solver and Generator

"); #else title += QString::fromUtf8("TSPSG: TSP Solver and Generator
"); #endif // Q_OS_WINCE title += QString::fromUtf8("Version: "BUILD_VERSION"
"); title += QString::fromUtf8("© 2007-%1 Lёppa
").arg(QDate::currentDate().toString("yyyy")); title += QString::fromUtf8("http://tspsg.sf.net/
"); QString about; about += QString::fromUtf8("Target OS: %1
").arg(OS); #ifndef STATIC_BUILD about += "Qt library (shared):
"; about += QString::fromUtf8("    Build time: %1
").arg(QT_VERSION_STR); about += QString::fromUtf8("    Runtime: %1
").arg(qVersion()); #else about += QString::fromUtf8("Qt library: %1 (static)
").arg(QT_VERSION_STR); #endif // STATIC_BUILD about += QString::fromUtf8("Built on %1 at %2
").arg(__DATE__).arg(__TIME__); about += "
"; about += QString::fromUtf8("Id: "VERSIONID"
"); about += QString::fromUtf8("Algorithm: %1
").arg(CTSPSolver::getVersionId()); about += "
"; about += "TSPSG is free software: you can redistribute it and/or modify it
" "under the terms of the GNU General Public License as published
" "by the Free Software Foundation, either version 3 of the License,
" "or (at your option) any later version.
" "
" "TSPSG is distributed in the hope that it will be useful, but
" "WITHOUT ANY WARRANTY; without even the implied warranty of
" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
" "GNU General Public License for more details.
" "
" "You should have received a copy of the GNU General Public License
" "along with TSPSG. If not, see http://www.gnu.org/licenses/."; QDialog *dlg = new QDialog(this); QLabel *lblIcon = new QLabel(dlg), *lblTitle = new QLabel(dlg); QTextBrowser *txtAbout = new QTextBrowser(dlg); QVBoxLayout *vb = new QVBoxLayout(); QHBoxLayout *hb = new QHBoxLayout(); QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, dlg); lblIcon->setPixmap(QPixmap(":/images/tspsg.png").scaledToWidth(logicalDpiX() * 2 / 3, Qt::SmoothTransformation)); lblIcon->setAlignment(Qt::AlignTop); lblTitle->setOpenExternalLinks(true); lblTitle->setText(title); hb->addWidget(lblIcon); hb->addWidget(lblTitle); hb->addStretch(); // txtAbout->setTextInteractionFlags(txtAbout->textInteractionFlags() ^ Qt::TextEditable); txtAbout->setWordWrapMode(QTextOption::NoWrap); txtAbout->setOpenExternalLinks(true); txtAbout->setHtml(about); txtAbout->moveCursor(QTextCursor::Start); bb->button(QDialogButtonBox::Ok)->setCursor(QCursor(Qt::PointingHandCursor)); vb->addLayout(hb); vb->addWidget(txtAbout); vb->addWidget(bb); dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); dlg->setWindowTitle(tr("About TSPSG")); dlg->setLayout(vb); connect(bb, SIGNAL(accepted()), dlg, SLOT(accept())); // Adding some eyecandy in Vista and 7 :-) if (QtWin::isCompositionEnabled()) { QtWin::enableBlurBehindWindow(dlg, true); } dlg->resize(410, 300); dlg->exec(); delete dlg; } void MainWindow::buttonBackToTaskClicked() { tabWidget->setCurrentIndex(0); } void MainWindow::buttonRandomClicked() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); tspmodel->randomize(); QApplication::restoreOverrideCursor(); } void MainWindow::buttonSolveClicked() { TMatrix matrix; QList row; int n = spinCities->value(); bool ok; for (int r = 0; r < n; r++) { row.clear(); for (int c = 0; c < n; c++) { row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok)); if (!ok) { 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(); return; } } matrix.append(row); } CTSPSolver solver; SStep *root = solver.solve(n,matrix,this); if (!root) return; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QColor color = settings->value("Output/Color",DEF_FONT_COLOR).value(); output.clear(); output.append("

" + tr("Variant #%1").arg(spinVariant->value()) + "

"); output.append("

" + tr("Task:") + "

"); outputMatrix(matrix, output); output.append("
"); output.append("

" + tr("Solution of Variant #%1 task").arg(spinVariant->value()) + "

"); SStep *step = root; n = 1; while (n <= spinCities->value()) { if (step->prNode->prNode != NULL || ((step->prNode->prNode == NULL) && (step->plNode->prNode == NULL))) { if (n != spinCities->value()) { output.append("

" + tr("Step #%1").arg(n++) + "

"); 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())))) { outputMatrix(*step, output); } output.append("

" + tr("Selected candidate for branching: %1.").arg(tr("(%1;%2)").arg(step->candidate.nRow + 1).arg(step->candidate.nCol + 1)) + "

"); if (!step->alts.empty()) { SCandidate cand; QString alts; foreach(cand, step->alts) { if (!alts.isEmpty()) alts += ", "; alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1); } output.append("

" + tr("%n alternate candidate(s) for branching: %1.","",step->alts.count()).arg(alts) + "

"); } output.append("

 

"); } } if (step->prNode->prNode != NULL) step = step->prNode; else if (step->plNode->prNode != NULL) step = step->plNode; else break; } if (solver.isOptimal()) output.append("

" + tr("Optimal path:") + "

"); else output.append("

" + tr("Resulting path:") + "

"); output.append("

  " + solver.getSortedPath() + "

"); if (isInteger(step->price)) output.append("

" + tr("The price is %n unit(s).", "", step->price) + "

"); else output.append("

" + tr("The price is %1 units.").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()) + "

"); if (!solver.isOptimal()) { output.append("

 

"); output.append("

" + tr("WARNING!!!
This result is a record, but it may not be optimal.
Iterations need to be continued to check whether this result is optimal or get an optimal one.") + "

"); } output.append("

"); solutionText->setHtml(output.join("")); solutionText->setDocumentTitle(tr("Solution of Variant #%1 task").arg(spinVariant->value())); if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) { // Scrolling to the end of text. solutionText->moveCursor(QTextCursor::End); } toggleSolutionActions(); tabWidget->setCurrentIndex(1); QApplication::restoreOverrideCursor(); } void MainWindow::dataChanged() { setWindowModified(true); } void MainWindow::dataChanged(const QModelIndex &tl, const QModelIndex &br) { setWindowModified(true); if (settings->value("Autosize", DEF_AUTOSIZE).toBool()) { for (int k = tl.row(); k <= br.row(); k++) taskView->resizeRowToContents(k); for (int k = tl.column(); k <= br.column(); k++) taskView->resizeColumnToContents(k); } } void MainWindow::numCitiesChanged(int nCities) { blockSignals(true); spinCities->setValue(nCities); blockSignals(false); } #ifndef QT_NO_PRINTER void MainWindow::printPreview(QPrinter *printer) { solutionText->print(printer); } #endif // QT_NO_PRINTER void MainWindow::spinCitiesValueChanged(int n) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); int count = tspmodel->numCities(); tspmodel->setNumCities(n); if ((n > count) && settings->value("Autosize", DEF_AUTOSIZE).toBool()) for (int k = count; k < n; k++) { taskView->resizeColumnToContents(k); taskView->resizeRowToContents(k); } QApplication::restoreOverrideCursor(); } void MainWindow::closeEvent(QCloseEvent *ev) { if (!maybeSave()) { ev->ignore(); return; } settings->setValue("NumCities", spinCities->value()); // Saving Main Window state if (settings->value("SavePos", DEF_SAVEPOS).toBool()) { settings->beginGroup("MainWindow"); #ifndef Q_OS_WINCE settings->setValue("Geometry", saveGeometry()); #endif // Q_OS_WINCE settings->setValue("State", saveState()); settings->endGroup(); } QMainWindow::closeEvent(ev); } void MainWindow::initDocStyleSheet() { QColor color = settings->value("Output/Color",DEF_FONT_COLOR).value(); QColor hilight; if (color.value() < 192) hilight.setHsv(color.hue(),color.saturation(),127 + qRound(color.value() / 2)); else hilight.setHsv(color.hue(),color.saturation(),color.value() / 2); solutionText->document()->setDefaultStyleSheet("* {color: " + color.name() +";} p {margin: 0px 10px;} table {margin: 5px;} td {padding: 1px 5px;} .hasalts {color: " + hilight.name() + ";} .selected {color: #A00000; font-weight: bold;} .alternate {color: #008000; font-weight: bold;}"); solutionText->document()->setDefaultFont(settings->value("Output/Font",QFont(DEF_FONT_FAMILY,DEF_FONT_SIZE)).value()); } void MainWindow::loadLangList() { QSettings langinfo(PATH_I18N"/languages.ini",QSettings::IniFormat); #if QT_VERSION >= 0x040500 // In Qt < 4.5 QSettings doesn't have method setIniCodec. langinfo.setIniCodec("UTF-8"); #endif QDir dir(PATH_I18N,"*.qm",QDir::Name | QDir::IgnoreCase,QDir::Files); if (!dir.exists()) return; QFileInfoList langs = dir.entryInfoList(); if (langs.size() <= 0) return; QAction *a; for (int k = 0; k < langs.size(); k++) { QFileInfo lang = langs.at(k); if (!lang.completeBaseName().startsWith("qt_") && lang.completeBaseName().compare("en")) { #if QT_VERSION >= 0x040500 a = menuSettingsLanguage->addAction(langinfo.value(lang.completeBaseName() + "/NativeName",lang.completeBaseName()).toString()); #else // We use Name if Qt < 4.5 because NativeName is in UTF-8, QSettings // reads .ini file as ASCII and there is no way to set file encoding. a = menuSettingsLanguage->addAction(langinfo.value(lang.completeBaseName() + "/Name",lang.completeBaseName()).toString()); #endif a->setData(lang.completeBaseName()); a->setCheckable(true); a->setActionGroup(groupSettingsLanguageList); if (settings->value("Language",QLocale::system().name()).toString().startsWith(lang.completeBaseName())) a->setChecked(true); } } } bool MainWindow::loadLanguage(const QString &lang) { // i18n bool ad = false; QString lng = lang; if (lng.isEmpty()) { ad = settings->value("Language","").toString().isEmpty(); lng = settings->value("Language",QLocale::system().name()).toString(); } static QTranslator *qtTranslator; // Qt library translator if (qtTranslator) { qApp->removeTranslator(qtTranslator); delete qtTranslator; qtTranslator = NULL; } static QTranslator *translator; // Application translator if (translator) { qApp->removeTranslator(translator); delete translator; translator = NULL; } if (lng == "en") return true; // Trying to load system Qt library translation... qtTranslator = new QTranslator(this); if (qtTranslator->load("qt_" + lng,QLibraryInfo::location(QLibraryInfo::TranslationsPath))) qApp->installTranslator(qtTranslator); else { // No luck. Let's try to load a bundled one. if (qtTranslator->load("qt_" + lng,PATH_I18N)) qApp->installTranslator(qtTranslator); else { // Qt library translation unavailable delete qtTranslator; qtTranslator = NULL; } } // Now let's load application translation. translator = new QTranslator(this); if (translator->load(lng,PATH_I18N)) qApp->installTranslator(translator); else { delete translator; translator = NULL; if (!ad) QMessageBox(QMessageBox::Warning,tr("Language Change"),tr("Unable to load translation language."),QMessageBox::Ok,this).exec(); return false; } return true; } bool MainWindow::maybeSave() { if (!isWindowModified()) return true; 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(); if (res == QMessageBox::Save) return saveTask(); else if (res == QMessageBox::Cancel) return false; else return true; } void MainWindow::outputMatrix(const TMatrix &matrix, QStringList &output) { int n = spinCities->value(); QString line=""; output.append(""); for (int r = 0; r < n; r++) { line = ""; for (int c = 0; c < n; c++) { if (matrix.at(r).at(c) == INFINITY) line += ""; else line += isInteger(matrix.at(r).at(c)) ? QString("").arg(matrix.at(r).at(c)) : QString("").arg(matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()); } line += ""; output.append(line); } output.append("
"INFSTR"%1%1
"); } void MainWindow::outputMatrix(const SStep &step, QStringList &output) { int n = spinCities->value(); QString line=""; output.append(""); for (int r = 0; r < n; r++) { line = ""; for (int c = 0; c < n; c++) { if (step.matrix.at(r).at(c) == INFINITY) line += ""; else if ((r == step.candidate.nRow) && (c == step.candidate.nCol)) line += isInteger(step.matrix.at(r).at(c)) ? QString("").arg(step.matrix.at(r).at(c)) : QString("").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()); else { SCandidate cand; cand.nRow = r; cand.nCol = c; if (step.alts.contains(cand)) line += isInteger(step.matrix.at(r).at(c)) ? QString("").arg(step.matrix.at(r).at(c)) : QString("").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()); else line += isInteger(step.matrix.at(r).at(c)) ? QString("").arg(step.matrix.at(r).at(c)) : QString("").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()); } } line += ""; output.append(line); } output.append("
"INFSTR"%1%1%1%1%1%1
"); } void MainWindow::retranslateUi(bool all) { if (all) Ui::MainWindow::retranslateUi(this); #ifndef QT_NO_PRINTER actionFilePrintPreview->setText(QApplication::translate("MainWindow", "P&rint Preview...", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP actionFilePrintPreview->setToolTip(QApplication::translate("MainWindow", "Preview solution results", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP #ifndef QT_NO_STATUSTIP actionFilePrintPreview->setStatusTip(QApplication::translate("MainWindow", "Preview current solution results before printing", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_STATUSTIP actionFilePrint->setText(QApplication::translate("MainWindow", "&Print...", 0, QApplication::UnicodeUTF8)); #ifndef QT_NO_TOOLTIP actionFilePrint->setToolTip(QApplication::translate("MainWindow", "Print solution", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_TOOLTIP #ifndef QT_NO_STATUSTIP actionFilePrint->setStatusTip(QApplication::translate("MainWindow", "Print current solution results", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_STATUSTIP actionFilePrint->setShortcut(QApplication::translate("MainWindow", "Ctrl+P", 0, QApplication::UnicodeUTF8)); #endif // QT_NO_PRINTER } bool MainWindow::saveTask() { QStringList filters(tr("%1 Task File").arg("TSPSG") + " (*.tspt)"); filters.append(tr("All Files") + " (*)"); QString file; if (fileName.endsWith(".tspt", Qt::CaseInsensitive)) file = fileName; else file = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".tspt"; QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog; file = QFileDialog::getSaveFileName(this, tr("Task Save"), file, filters.join(";;"), NULL, opts); if (file.isEmpty()) return false; if (tspmodel->saveTask(file)) { setFileName(file); setWindowModified(false); return true; } return false; } void MainWindow::setFileName(const QString &fileName) { this->fileName = fileName; setWindowTitle(QString("%1[*] - %2").arg(QFileInfo(fileName).completeBaseName()).arg(tr("Travelling Salesman Problem"))); } void MainWindow::setupUi() { Ui::MainWindow::setupUi(this); #if QT_VERSION >= 0x040600 setToolButtonStyle(Qt::ToolButtonFollowStyle); #endif #ifndef Q_OS_WINCE QStatusBar *statusbar = new QStatusBar(this); statusbar->setObjectName("statusbar"); setStatusBar(statusbar); #endif // Q_OS_WINCE #ifdef Q_OS_WINCE menuBar()->setDefaultAction(menuFile->menuAction()); #endif // Q_OS_WINCE #ifdef Q_OS_WINCE //! \hack HACK: A little hack for toolbar icons to have a sane size. toolBar->setIconSize(QSize(logicalDpiX() / 4, logicalDpiY() / 4)); #endif // Q_OS_WINCE solutionText->document()->setDefaultFont(settings->value("Output/Font",QFont(DEF_FONT_FAMILY,DEF_FONT_SIZE)).value()); solutionText->setTextColor(settings->value("Output/Color",DEF_FONT_COLOR).value()); solutionText->setWordWrapMode(QTextOption::WordWrap); #ifndef QT_NO_PRINTER actionFilePrintPreview = new QAction(this); actionFilePrintPreview->setObjectName("actionFilePrintPreview"); actionFilePrintPreview->setEnabled(false); actionFilePrintPreview->setIcon(QIcon(":/images/icons/document_preview.png")); actionFilePrint = new QAction(this); actionFilePrint->setObjectName("actionFilePrint"); actionFilePrint->setEnabled(false); actionFilePrint->setIcon(QIcon(":/images/icons/fileprint.png")); menuFile->insertAction(actionFileExit,actionFilePrintPreview); menuFile->insertAction(actionFileExit,actionFilePrint); menuFile->insertSeparator(actionFileExit); toolBar->insertAction(actionSettingsPreferences,actionFilePrint); #endif // QT_NO_PRINTER groupSettingsLanguageList = new QActionGroup(this); actionSettingsLanguageEnglish->setData("en"); actionSettingsLanguageEnglish->setActionGroup(groupSettingsLanguageList); loadLangList(); actionSettingsLanguageAutodetect->setChecked(settings->value("Language","").toString().isEmpty()); spinCities->setMaximum(MAX_NUM_CITIES); retranslateUi(false); // Adding some eyecandy in Vista and 7 :-) if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool()) { toggleTranclucency(true); } } void MainWindow::toggleSolutionActions(bool enable) { buttonSaveSolution->setEnabled(enable); actionFileSaveAsSolution->setEnabled(enable); solutionText->setEnabled(enable); if (!enable) output.clear(); #ifndef QT_NO_PRINTER actionFilePrint->setEnabled(enable); actionFilePrintPreview->setEnabled(enable); #endif // QT_NO_PRINTER } void MainWindow::toggleTranclucency(bool enable) { QtWin::enableBlurBehindWindow(this, enable); QtWin::enableBlurBehindWindow(tabWidget, enable); if (QtWin::enableBlurBehindWindow(tabTask, enable)) tabTask->setAutoFillBackground(enable); if (QtWin::enableBlurBehindWindow(tabSolution, enable)) tabSolution->setAutoFillBackground(enable); }