- Timestamp:
- Mar 22, 2010, 9:45:16 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:ignore
-
old new 1 1 *.idb 2 *.ini3 2 *.ncb 4 3 *.pdb
-
- Property svn:ignore
-
trunk/src/main.cpp
r98 r99 45 45 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf8")); 46 46 QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8")); 47 app.setOrganizationName(" ..::Lёppsville::.. Homes");48 app.setOrganizationDomain(" l-homes.org");47 app.setOrganizationName("Oleksii \"Lёppa\" Serdiuk"); 48 app.setOrganizationDomain("oleksii.name"); 49 49 app.setApplicationName("TSPSG"); 50 50 app.setApplicationVersion(BUILD_VERSION); -
trunk/src/mainwindow.cpp
r98 r99 60 60 #endif // QT_NO_PRINTER 61 61 connect(actionSettingsPreferences,SIGNAL(triggered()),this,SLOT(actionSettingsPreferencesTriggered())); 62 #ifdef Q_OS_WIN32 63 connect(actionHelpCheck4Updates, SIGNAL(triggered()), SLOT(actionHelpCheck4UpdatesTriggered())); 64 #endif // Q_OS_WIN32 62 65 connect(actionSettingsLanguageAutodetect,SIGNAL(triggered(bool)),this,SLOT(actionSettingsLanguageAutodetectTriggered(bool))); 63 66 connect(groupSettingsLanguageList,SIGNAL(triggered(QAction *)),this,SLOT(groupSettingsLanguageListTriggered(QAction *))); … … 134 137 filters.append(tr("All Files") + " (*)"); 135 138 139 QString file = QFileInfo(fileName).canonicalPath(); 136 140 QFileDialog::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); 138 142 if (file.isEmpty() || !QFileInfo(file).isFile()) 139 143 return; … … 147 151 } 148 152 149 void MainWindow::actionFileSaveTriggered() 150 { 151 qDebug() << tr("Untitled"); 153 bool MainWindow::actionFileSaveTriggered() 154 { 152 155 if ((fileName == tr("Untitled") + ".tspt") || (!fileName.endsWith(".tspt", Qt::CaseInsensitive))) 153 saveTask();156 return saveTask(); 154 157 else 155 if (tspmodel->saveTask(fileName)) 158 if (tspmodel->saveTask(fileName)) { 156 159 setWindowModified(false); 160 return true; 161 } else 162 return false; 157 163 } 158 164 … … 165 171 { 166 172 static 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"; 171 182 #else 172 selectedFile= "solution.html";183 selectedFile += "solution.html"; 173 184 #endif // QT_NO_PRINTER 174 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"; 177 188 #else 178 selectedFile = QFileInfo(fileName).canonicalPath() + "/" +QFileInfo(fileName).completeBaseName() + ".html";189 selectedFile += QFileInfo(fileName).completeBaseName() + ".html"; 179 190 #endif // QT_NO_PRINTER 180 }181 191 } 182 192 … … 191 201 filters.append(tr("All Files") + " (*)"); 192 202 193 QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;203 QFileDialog::Options opts(settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog); 194 204 QString file = QFileDialog::getSaveFileName(this, QString(), selectedFile, filters.join(";;"), NULL, opts); 195 205 if (file.isEmpty()) … … 211 221 if (!(selectedFile.endsWith(".htm",Qt::CaseInsensitive) || selectedFile.endsWith(".html",Qt::CaseInsensitive) || selectedFile.endsWith(".odt",Qt::CaseInsensitive) || selectedFile.endsWith(".txt",Qt::CaseInsensitive))) 212 222 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 215 226 // Qt < 4.5 has no QTextDocumentWriter class 216 227 QFile file(selectedFile); 217 228 if (!file.open(QFile::WriteOnly)) { 218 229 QApplication::restoreOverrideCursor(); 230 QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(file->errorString())); 219 231 return; 220 232 } … … 258 270 if (sd.colorChanged() || sd.fontChanged()) { 259 271 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) 268 276 toggleTranclucency(sd.translucencyChanged() == 1); 269 }270 277 } 271 278 … … 283 290 if (actionSettingsLanguageAutodetect->isChecked()) { 284 291 // 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) { 286 293 actionSettingsLanguageAutodetect->trigger(); 287 294 } else … … 302 309 #endif 303 310 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 316 void 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 306 328 307 329 void MainWindow::actionHelpAboutTriggered() 308 330 { 309 //! \todo TODO: Normal about window :-)310 331 QString title; 311 332 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) … … 314 335 title += QString("<b>TSPSG: TSP Solver and Generator</b><br>"); 315 336 #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()); 317 338 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) 318 title += QString("<b>© 2007-%1 Oleksii \"Lёppa\" Serdiuk</b><br>").arg(QDate::currentDate().toString("yyyy"));339 title += QString("<b>© 2007-%1 <a href=\"http://%2/\">%3</a></b><br>").arg(QDate::currentDate().toString("yyyy"), QApplication::organizationDomain(), QApplication::organizationName()); 319 340 title += QString("<b><a href=\"http://tspsg.sourceforge.net/\">http://tspsg.sourceforge.net/</a></b>"); 320 341 #else … … 410 431 vb->addLayout(hb2); 411 432 412 dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint);433 dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); 413 434 dlg->setWindowTitle(tr("About TSPSG")); 414 435 dlg->setLayout(vb); … … 453 474 row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok)); 454 475 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)); 456 477 return; 457 478 } … … 459 480 matrix.append(row); 460 481 } 482 483 QProgressDialog pd(this); 484 QProgressBar *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 461 496 CTSPSolver 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())); 499 SStep *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>"); 473 520 SStep *step = root; 474 521 n = 1; 475 522 while (n <= spinCities->value()) { 523 if (pd.wasCanceled()) { 524 solutionText->clear(); 525 return; 526 } 527 pd.setValue(spinCities->value() + 2 + n); 528 476 529 if (step->prNode->prNode != NULL || ((step->prNode->prNode == NULL) && (step->plNode->prNode == NULL))) { 477 530 if (n != spinCities->value()) { 478 output.append("<p>" + tr("Step #%1").arg(n++) + "</p>");531 solutionText->append("<p>" + tr("Step #%1").arg(n++) + "</p>"); 479 532 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)); 481 534 } 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>"); 483 536 if (!step->alts.empty()) { 484 537 SCandidate cand; … … 489 542 alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1); 490 543 } 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>"); 492 545 } 493 output.append("<p> </p>");546 solutionText->append("<p> </p>"); 494 547 } 495 548 } … … 501 554 break; 502 555 } 556 pd.setValue(spinCities->value() + 2 + n); 557 503 558 if (solver.isOptimal()) 504 output.append("<p>" + tr("Optimal path:") + "</p>");559 solutionText->append("<p>" + tr("Optimal path:") + "</p>"); 505 560 else 506 output.append("<p>" + tr("Resulting path:") + "</p>");507 output.append("<p> " + solver.getSortedPath() + "</p>");561 solutionText->append("<p>" + tr("Resulting path:") + "</p>"); 562 solutionText->append("<p> " + solver.getSortedPath() + "</p>"); 508 563 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>"); 510 565 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>"); 512 567 if (!solver.isOptimal()) { 513 output.append("<p> </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> </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 } 520 571 521 572 if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) { 522 573 // Scrolling to the end of text. 523 574 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); 526 584 toggleSolutionActions(); 527 585 tabWidget->setCurrentIndex(1); 528 QApplication::restoreOverrideCursor();529 586 } 530 587 … … 632 689 } 633 690 691 bool 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 634 700 void MainWindow::initDocStyleSheet() 635 701 { … … 719 785 if (!ad) { 720 786 settings->remove("Language"); 721 if (QApplication::overrideCursor() != 0) 722 QApplication::restoreOverrideCursor(); 787 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 723 788 if (isVisible()) 724 789 QMessageBox::warning(this, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection.")); 725 790 else 726 791 QMessageBox::warning(NULL, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection.")); 792 QApplication::restoreOverrideCursor(); 727 793 } 728 794 return false; … … 735 801 if (!isWindowModified()) 736 802 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();803 int res = QMessageBox::warning(this, tr("Unsaved Changes"), tr("Would you like to save changes in the current task?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); 738 804 if (res == QMessageBox::Save) 739 return saveTask();805 return actionFileSaveTriggered(); 740 806 else if (res == QMessageBox::Cancel) 741 807 return false; … … 744 810 } 745 811 746 void MainWindow::outputMatrix(const TMatrix &matrix, QStringList &output) 812 QString MainWindow::outputMatrix(const TMatrix &matrix) const 747 813 { 748 814 int n = spinCities->value(); 749 QString line="";815 QString output(""), line; 750 816 output.append("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"); 751 817 for (int r = 0; r < n; r++) { … … 761 827 } 762 828 output.append("</table>"); 763 } 764 765 void MainWindow::outputMatrix(const SStep &step, QStringList &output) 829 return output; 830 } 831 832 QString MainWindow::outputMatrix(const SStep &step) const 766 833 { 767 834 int n = spinCities->value(); 768 QString line="";835 QString output(""), line; 769 836 output.append("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"); 770 837 for (int r = 0; r < n; r++) { … … 789 856 } 790 857 output.append("</table>"); 858 return output; 791 859 } 792 860 … … 816 884 actionFilePrint->setShortcut(QApplication::translate("MainWindow", "Ctrl+P", 0, QApplication::UnicodeUTF8)); 817 885 #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 818 895 } 819 896 … … 901 978 toolBar->insertAction(actionSettingsPreferences,actionFilePrint); 902 979 #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 903 986 904 987 groupSettingsLanguageList = new QActionGroup(this); … … 925 1008 actionFileSaveAsSolution->setEnabled(enable); 926 1009 solutionText->setEnabled(enable); 927 if (!enable)928 output.clear();929 1010 #ifndef QT_NO_PRINTER 930 1011 actionFilePrint->setEnabled(enable); -
trunk/src/mainwindow.h
r95 r99 53 53 void actionFileNewTriggered(); 54 54 void actionFileOpenTriggered(); 55 voidactionFileSaveTriggered();55 bool actionFileSaveTriggered(); 56 56 void actionFileSaveAsTaskTriggered(); 57 57 void actionFileSaveAsSolutionTriggered(); … … 63 63 void actionSettingsLanguageAutodetectTriggered(bool checked); 64 64 void groupSettingsLanguageListTriggered(QAction *action); 65 #ifdef Q_OS_WIN32 66 void actionHelpCheck4UpdatesTriggered(); 67 #endif // Q_OS_WIN32 65 68 void actionHelpAboutTriggered(); 66 69 // Buttons … … 84 87 QString fileName; 85 88 QActionGroup *groupSettingsLanguageList; 86 QStringList output;87 89 #ifndef QT_NO_PRINTER 88 90 QPrinter *printer; … … 90 92 QAction *actionFilePrint; 91 93 #endif // QT_NO_PRINTER 94 #ifdef Q_OS_WIN32 95 QAction *actionHelpCheck4Updates; 96 #endif // Q_OS_WIN32 92 97 QSettings *settings; 93 98 CTSPModel *tspmodel; … … 97 102 98 103 void closeEvent(QCloseEvent *ev); 104 bool hasUpdater() const; 99 105 void initDocStyleSheet(); 100 106 void loadLangList(); 101 107 bool loadLanguage(const QString &lang = QString()); 102 108 bool maybeSave(); 103 void outputMatrix(const TMatrix &matrix, QStringList &output);104 void outputMatrix(const SStep &step, QStringList &output);109 QString outputMatrix(const TMatrix &matrix) const; 110 QString outputMatrix(const SStep &step) const; 105 111 void retranslateUi(bool all = true); 106 112 bool saveTask(); -
trunk/src/os.h
r97 r99 149 149 #define OS "Windows"ARCH 150 150 #define OSID quint8(28) 151 #elif defined Q_OS_WINCE_WM 152 #define OS "Windows Mobile"ARCH 153 #define OSID quint8(29) 151 154 #elif defined Q_OS_WINCE 152 155 #define OS "Windows CE"ARCH 153 #define OSID quint8( 29)156 #define OSID quint8(30) 154 157 #else 155 158 #define OS "Unknown"ARCH -
trunk/src/settingsdialog.cpp
r98 r99 189 189 cbCitiesLimit->setEnabled(cbShowMatrix->isChecked()); 190 190 cbCitiesLimit->setChecked(settings->value("UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT && cbShowMatrix->isChecked()).toBool()); 191 spinCitiesLimit->setEnabled(cbShowMatrix->isChecked() );191 spinCitiesLimit->setEnabled(cbShowMatrix->isChecked() && cbCitiesLimit->isChecked()); 192 192 spinCitiesLimit->setValue(settings->value("ShowMatrixLimit", DEF_SHOW_MATRIX_LIMIT).toInt()); 193 193 spinCitiesLimit->setMaximum(MAX_NUM_CITIES); -
trunk/src/tspmodel.cpp
r95 r99 81 81 } else if (role == Qt::DisplayRole || role == Qt::EditRole) { 82 82 if (index.row() < nCities && index.column() < nCities) 83 if (table [index.row()][index.column()]== INFINITY)83 if (table.at(index.row()).at(index.column()) == INFINITY) 84 84 return tr(INFSTR); 85 85 else 86 86 //! \hack HACK: Converting to string to prevent spinbox in edit mode 87 return QVariant(table [index.row()][index.column()]).toString();87 return QVariant(table.at(index.row()).at(index.column())).toString(); 88 88 else 89 89 return QVariant(); … … 139 139 if (!f.open(QIODevice::ReadOnly)) { 140 140 QApplication::restoreOverrideCursor(); 141 QMessageBox(QMessageBox::Critical,tr("Task Load"),QString(tr("Unable to open task file.\nError: %1")).arg(f.errorString()),QMessageBox::Ok).exec(); 141 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 142 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), QString(tr("Unable to open task file.\nError: %1")).arg(f.errorString())); 143 QApplication::restoreOverrideCursor(); 142 144 return false; 143 145 } … … 163 165 f.close(); 164 166 QApplication::restoreOverrideCursor(); 165 QMessageBox(QMessageBox::Critical,tr("Task Load"),tr("Unable to load task:") + "\n" + tr("Unknown file format or file is corrupted."),QMessageBox::Ok).exec(); 167 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 168 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), tr("Unable to load task:") + "\n" + tr("Unknown file format or file is corrupted.")); 169 QApplication::restoreOverrideCursor(); 166 170 return false; 167 171 } … … 232 236 if (!f.open(QIODevice::WriteOnly)) { 233 237 QApplication::restoreOverrideCursor(); 234 QMessageBox(QMessageBox::Critical,tr("Task Save"),QString(tr("Unable to create task file.\nError: %1\nMaybe, file is read-only?")).arg(f.errorString()),QMessageBox::Ok).exec(); 238 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), QString(tr("Unable to create task file.\nError: %1\nMaybe, file is read-only?")).arg(f.errorString())); 239 f.remove(); 235 240 return false; 236 241 } … … 238 243 ds.setVersion(QDataStream::Qt_4_4); 239 244 if (f.error() != QFile::NoError) { 240 f.close(); 241 QApplication::restoreOverrideCursor(); 242 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 245 QApplication::restoreOverrideCursor(); 246 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 247 f.close(); 248 f.remove(); 243 249 return false; 244 250 } … … 246 252 ds << TSPT; 247 253 if (f.error() != QFile::NoError) { 248 f.close(); 249 QApplication::restoreOverrideCursor(); 250 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 254 QApplication::restoreOverrideCursor(); 255 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 256 f.close(); 257 f.remove(); 251 258 return false; 252 259 } … … 254 261 ds << TSPT_VERSION; 255 262 if (f.error() != QFile::NoError) { 256 f.close(); 257 QApplication::restoreOverrideCursor(); 258 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 263 QApplication::restoreOverrideCursor(); 264 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 265 f.close(); 266 f.remove(); 259 267 return false; 260 268 } … … 262 270 ds << TSPT_META_VERSION; 263 271 if (f.error() != QFile::NoError) { 264 f.close(); 265 QApplication::restoreOverrideCursor(); 266 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 272 QApplication::restoreOverrideCursor(); 273 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 274 f.close(); 275 f.remove(); 267 276 return false; 268 277 } … … 270 279 ds << OSID; 271 280 if (f.error() != QFile::NoError) { 272 f.close(); 273 QApplication::restoreOverrideCursor(); 274 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 281 QApplication::restoreOverrideCursor(); 282 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 283 f.close(); 284 f.remove(); 275 285 return false; 276 286 } … … 278 288 ds << nCities; 279 289 if (f.error() != QFile::NoError) { 280 f.close(); 281 QApplication::restoreOverrideCursor(); 282 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 290 QApplication::restoreOverrideCursor(); 291 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 292 f.close(); 293 f.remove(); 283 294 return false; 284 295 } … … 289 300 ds << static_cast<double>(table[r][c]); // We cast to double because double may be float on some platforms and we store double values in file 290 301 if (f.error() != QFile::NoError) { 302 QApplication::restoreOverrideCursor(); 303 QMessageBox::critical(QApplication::activeWindow(), tr("Task Save"), tr("Unable to save task.\nError: %1").arg(f.errorString())); 291 304 f.close(); 292 QApplication::restoreOverrideCursor(); 293 QMessageBox(QMessageBox::Critical,tr("Task Save"),tr("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec(); 305 f.remove(); 294 306 return false; 295 307 } … … 369 381 err = tr("Unknown error."); 370 382 QApplication::restoreOverrideCursor(); 371 QMessageBox(QMessageBox::Critical,tr("Task Load"),tr("Unable to load task:") + "\n" + err,QMessageBox::Ok).exec(); 383 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 384 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), tr("Unable to load task:") + "\n" + err); 385 QApplication::restoreOverrideCursor(); 372 386 return true; 373 387 } … … 386 400 if (version > TSPT_VERSION) { 387 401 QApplication::restoreOverrideCursor(); 388 QMessageBox(QMessageBox::Critical,tr("Task Load"),tr("Unable to load task:") + "\n" + tr("File version is newer than application supports.\nPlease, try to update application."),QMessageBox::Ok).exec(); 402 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 403 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), tr("Unable to load task:") + "\n" + tr("File version is newer than application supports.\nPlease, try to update application.")); 404 QApplication::restoreOverrideCursor(); 389 405 return false; 390 406 } … … 400 416 if ((size < 3) || (size > MAX_NUM_CITIES)) { 401 417 QApplication::restoreOverrideCursor(); 402 QMessageBox(QMessageBox::Critical,tr("Task Load"),tr("Unable to load task:") + "\n" + tr("Unexpected data read.\nFile is possibly corrupted."),QMessageBox::Ok).exec(); 418 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 419 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), tr("Unable to load task:") + "\n" + tr("Unexpected data read.\nFile is possibly corrupted.")); 420 QApplication::restoreOverrideCursor(); 403 421 return false; 404 422 } … … 438 456 if (version > ZKT_VERSION) { 439 457 QApplication::restoreOverrideCursor(); 440 QMessageBox(QMessageBox::Critical,tr("Task Load"),tr("Unable to load task:") + "\n" + tr("File version is newer than application supports.\nPlease, try to update application."),QMessageBox::Ok).exec(); 458 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 459 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), tr("Unable to load task:") + "\n" + tr("File version is newer than application supports.\nPlease, try to update application.")); 460 QApplication::restoreOverrideCursor(); 441 461 return false; 442 462 } … … 448 468 if ((size < 3) || (size > 5)) { 449 469 QApplication::restoreOverrideCursor(); 450 QMessageBox(QMessageBox::Critical,tr("Task Load"),tr("Unable to load task:") + "\n" + tr("Unexpected data read.\nFile is possibly corrupted."),QMessageBox::Ok).exec(); 470 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 471 QMessageBox::critical(QApplication::activeWindow(), tr("Task Load"), tr("Unable to load task:") + "\n" + tr("Unexpected data read.\nFile is possibly corrupted.")); 472 QApplication::restoreOverrideCursor(); 451 473 return false; 452 474 } -
trunk/src/tspsolver.cpp
r98 r99 24 24 #include "tspsolver.h" 25 25 26 //! Class constructor 27 CTSPSolver::CTSPSolver() 28 : nCities(0), root(NULL) 29 { 26 //! \internal \brief A short for maximum double, used internally in the solution algorithm. 27 #define MAX_DOUBLE std::numeric_limits<double>::max() 28 29 /*! 30 * \brief Returns CTSPSolver's version ID. 31 * \return A string: <b>\$Id$</b>. 32 */ 33 QString CTSPSolver::getVersionId() 34 { 35 return QString("$Id$"); 36 } 37 38 /*! 39 * \brief Constructs CTSPSolver object. 40 * \param parent A parent object. 41 */ 42 CTSPSolver::CTSPSolver(QObject *parent) 43 : QObject(parent), nCities(0), root(NULL) {} 44 45 /*! 46 * \brief Cleans up the object and frees up memory used by the solution tree. 47 * \param processEvents If set to \c true then \link QCoreApplication::processEvents() QApplication::processEvents(QEventLoop::ExcludeUserInputEvents)\endlink will be called from time to time while cleaning up. 48 * \warning After call to this function a solution tree returned by the solve() function is no longer valid. 49 * \note It is not required to call this function manually. This function is always called by solve() at the beginning of the solution process. 50 * 51 * \sa solve() 52 */ 53 void CTSPSolver::cleanup(bool processEvents) 54 { 55 if (!processEvents) 56 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 57 route.clear(); 58 mayNotBeOptimal = false; 59 if (root != NULL) 60 deleteTree(root, processEvents); 61 if (!processEvents) 62 QApplication::restoreOverrideCursor(); 30 63 } 31 64 … … 51 84 52 85 /*! 53 * \brief Returns CTSPSolver's version ID. 54 * \return A string: <b>\$Id$</b>. 55 */ 56 QString CTSPSolver::getVersionId() 57 { 58 return QString("$Id$"); 59 } 60 61 /*! 62 * \brief Returns whether or not the solution is definitely optimal. 63 * \return \c true if solution is definitely optimal, otherwise \c false. 64 * 65 * The solution may need some further interations to determine whether it is optimal. 86 * \brief Indicates whether or not the solution is definitely optimal. 87 * \return \c true if the solution is definitely optimal, otherwise \c false. 88 * 89 * The solution may need some further iterations to determine whether or not it is optimal. 66 90 * In such cases this function returns \c false. 67 91 */ … … 75 99 * \param numCities Number of cities in the task. 76 100 * \param task The matrix of city-to-city travel costs. 77 * \param parent The parent widget for displaying messages and dialogs.78 101 * \return Pointer to the root of the solution tree. 79 102 * 80 103 * \todo TODO: Comment the algorithm. 81 104 */ 82 SStep *CTSPSolver::solve(int numCities, TMatrix task, QWidget *parent)105 SStep *CTSPSolver::solve(int numCities, const TMatrix &task) 83 106 { 84 107 if (numCities <= 1) 85 108 return NULL; 109 110 QMutexLocker locker(&mutex); 86 111 cleanup(); 112 canceled = false; 113 locker.unlock(); 114 87 115 nCities = numCities; 88 QProgressDialog pd(parent);89 QProgressBar *pb = new QProgressBar(&pd);90 pb->setAlignment(Qt::AlignCenter);91 pb->setFormat(tr("%v of %m parts found"));92 pd.setBar(pb);93 pd.setMaximum(nCities);94 pd.setMinimumDuration(1000);95 pd.setLabelText(tr("Calculating optimal route..."));96 pd.setWindowTitle(tr("Solution Progress"));97 pd.setWindowModality(Qt::ApplicationModal);98 pd.setValue(0);99 116 100 117 SStep *step = new SStep(); 101 118 step->matrix = task; 119 // We need to distinguish the values forbidden by the user 120 // from the values forbidden by the algorithm. 121 // So we replace user's infinities by the maximum available double value. 122 normalize(step->matrix); 123 #ifdef DEBUG 124 qDebug() << step->matrix; 125 #endif // DEBUG 102 126 step->price = align(step->matrix); 103 127 root = step; … … 108 132 double check = INFINITY; 109 133 while (this->route.size() < nCities) { 110 // forbidden.clear();111 134 step->alts = findCandidate(step->matrix,nRow,nCol); 135 112 136 while (hasSubCycles(nRow,nCol)) { 113 // forbidden[nRow] = nCol; 137 #ifdef DEBUG 138 qDebug() << "Forbidden: (" << nRow << ";" << nCol << ")"; 139 #endif // DEBUG 114 140 step->matrix[nRow][nCol] = INFINITY; 115 141 step->price += align(step->matrix); 116 142 step->alts = findCandidate(step->matrix,nRow,nCol); 117 143 } 118 if ((nRow == -1) || (nCol == -1) || pd.wasCanceled()) { 144 145 #ifdef DEBUG 146 qDebug() /*<< step->matrix*/ << "Selected: (" << nRow << ";" << nCol << ")"; 147 qDebug() << "Alternate:" << step->alts; 148 qDebug() << "Step price:" << step->price << endl; 149 #endif // DEBUG 150 151 locker.relock(); 152 if ((nRow == -1) || (nCol == -1) || canceled) { 119 153 cleanup(); 120 break; 121 } 154 return NULL; 155 } 156 locker.unlock(); 122 157 123 158 // Route with (nRow,nCol) path … … 132 167 } 133 168 right->price = step->price + align(right->matrix); 134 // Forbid selected route to exclude its reuse in next steps.169 // Forbid the selected route to exclude its reuse in next steps. 135 170 right->matrix[nCol][nRow] = INFINITY; 136 171 right->matrix[nRow][nCol] = INFINITY; … … 148 183 step->prNode = right; 149 184 185 // This matrix is not used anymore. Restoring infinities back. 186 denormalize(step->matrix); 187 150 188 if (right->price <= left->price) { 151 189 // Route with (nRow,nCol) path is cheaper 152 190 step = right; 153 191 this->route[nRow] = nCol; 154 pd.setValue(this->route.size());192 emit routePartFound(this->route.size()); 155 193 if (firstStep) { 156 194 check = left->price; … … 168 206 } 169 207 170 if (!root && !pd.wasCanceled()) { 171 pd.reset(); 172 QMessageBox(QMessageBox::Warning,tr("Solution Result"),tr("Unable to find solution.\nMaybe, this task has no solutions."),QMessageBox::Ok,parent).exec(); 173 } 174 175 qApp->processEvents(); 176 177 if (root) { 178 route = this->route; 179 mayNotBeOptimal = (check < step->price); 180 } 208 route = this->route; 209 mayNotBeOptimal = (check < step->price); 210 181 211 return root; 212 } 213 214 /*! 215 * \brief Indicates whether or not the solution process was canceled. 216 * \return \c true if the solution process was canceled, otherwise \c false. 217 */ 218 bool CTSPSolver::wasCanceled() const 219 { 220 QMutexLocker locker(&mutex); 221 return canceled; 222 } 223 224 /*! 225 * \brief Cancels the solution process. 226 */ 227 void CTSPSolver::cancel() 228 { 229 QMutexLocker locker(&mutex); 230 canceled = true; 182 231 } 183 232 … … 198 247 if (min > 0) { 199 248 r += min; 200 subRow(matrix,k,min); 249 if (min < MAX_DOUBLE) 250 subRow(matrix,k,min); 201 251 } 202 252 } … … 205 255 if (min > 0) { 206 256 r += min; 207 subCol(matrix,k,min); 257 if (min < MAX_DOUBLE) 258 subCol(matrix,k,min); 208 259 } 209 260 } … … 211 262 } 212 263 213 void CTSPSolver::cleanup() 214 { 215 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 216 route.clear(); 217 mayNotBeOptimal = false; 218 if (root != NULL) 219 deleteTree(root); 220 QApplication::restoreOverrideCursor(); 221 } 222 223 void CTSPSolver::deleteTree(SStep *&root) 264 void CTSPSolver::deleteTree(SStep *&root, bool processEvents) 224 265 { 225 266 if (root == NULL) … … 228 269 SStep *parent; 229 270 forever { 271 if (processEvents) 272 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); 230 273 if (step->plNode != NULL) { 231 274 // We have left child node - going inside it … … 252 295 } 253 296 } 297 } 298 299 void CTSPSolver::denormalize(TMatrix &matrix) const 300 { 301 for (int r = 0; r < nCities; r++) 302 for (int c = 0; c < nCities; c++) 303 if ((r != c) && (matrix.at(r).at(c) == MAX_DOUBLE)) 304 matrix[r][c] = INFINITY; 254 305 } 255 306 … … 287 338 if ((k != exr) && (min > matrix.at(k).at(nCol))) 288 339 min = matrix.at(k).at(nCol); 289 return min == INFINITY? 0 : min;340 return (min == INFINITY) ? 0 : min; 290 341 } 291 342 … … 293 344 { 294 345 double min = INFINITY; 295 for (int k = 0; k < nCities; k++) 346 for (int k = 0; k < nCities; k++) { 296 347 if (((k != exc)) && (min > matrix.at(nRow).at(k))) 297 348 min = matrix.at(nRow).at(k); 298 return min == INFINITY ? 0 : min; 349 } 350 return (min == INFINITY) ? 0 : min; 299 351 } 300 352 … … 313 365 } 314 366 367 void CTSPSolver::normalize(TMatrix &matrix) const 368 { 369 for (int r = 0; r < nCities; r++) 370 for (int c = 0; c < nCities; c++) 371 if ((r != c) && (matrix.at(r).at(c) == INFINITY)) 372 matrix[r][c] = MAX_DOUBLE; 373 } 374 315 375 void CTSPSolver::subCol(TMatrix &matrix, int nCol, double val) 316 376 { … … 327 387 } 328 388 389 #ifdef DEBUG 329 390 QDebug operator<<(QDebug dbg, const TMatrix &matrix) 330 391 { 331 392 for (int r = 0; r < matrix.count(); r++) { 332 393 for (int c = 0; c < matrix.at(r).count(); c++) 333 dbg.space() << matrix.at(r).at(c);394 dbg.space() << QString::number(matrix.at(r).at(c)).leftJustified(5); 334 395 dbg << endl; 335 396 } 336 397 return dbg; 337 398 } 399 400 QDebug operator<<(QDebug dbg, const SCandidate &cand) 401 { 402 dbg.nospace() << "(" << cand.nRow << ";" << cand.nCol << ")"; 403 return dbg; 404 } 405 #endif // DEBUG -
trunk/src/tspsolver.h
r98 r99 78 78 * \author Copyright © 2007-2010 Lёppa <contacts[at]oleksii[dot]name> 79 79 */ 80 class CTSPSolver 80 class CTSPSolver: public QObject 81 81 { 82 Q_ DECLARE_TR_FUNCTIONS(CTSPSolver)82 Q_OBJECT 83 83 84 84 public: 85 CTSPSolver(); 85 static QString getVersionId(); 86 87 CTSPSolver(QObject *parent = NULL); 88 void cleanup(bool processEvents = false); 86 89 QString getSortedPath() const; 87 static QString getVersionId();88 90 bool isOptimal() const; 89 SStep *solve(int numCities, TMatrix task, QWidget *parent = 0); 91 SStep *solve(int numCities, const TMatrix &task); 92 bool wasCanceled() const; 90 93 ~CTSPSolver(); 91 94 95 public slots: 96 void cancel(); 97 98 signals: 99 /*! 100 * \brief This signal is emitted once every time a part of the route is found. 101 * \param n Indicates the number of the route parts found. 102 */ 103 void routePartFound(int n); 104 92 105 private: 93 bool mayNotBeOptimal ;106 bool mayNotBeOptimal, canceled; 94 107 int nCities; 95 108 SStep *root; 96 109 QHash<int,int> route; 97 // QHash<int,int> forbidden;110 mutable QMutex mutex; 98 111 99 112 double align(TMatrix &matrix); 100 void cleanup();101 void de leteTree(SStep *&root);113 void deleteTree(SStep *&root, bool processEvents = false); 114 void denormalize(TMatrix &matrix) const; 102 115 QList<SCandidate> findCandidate(const TMatrix &matrix, int &nRow, int &nCol) const; 103 116 double findMinInCol(int nCol, const TMatrix &matrix, int exr = -1) const; 104 117 double findMinInRow(int nRow, const TMatrix &matrix, int exc = -1) const; 105 118 bool hasSubCycles(int nRow, int nCol) const; 119 void normalize(TMatrix &matrix) const; 106 120 void subCol(TMatrix &matrix, int nCol, double val); 107 121 void subRow(TMatrix &matrix, int nRow, double val); … … 110 124 #ifdef DEBUG 111 125 QDebug operator<<(QDebug dbg, const TMatrix &matrix); 112 #endif 126 QDebug operator<<(QDebug dbg, const SCandidate &candidate); 127 #endif // DEBUG 113 128 114 129 #endif // TSPSOLVER_H
Note: See TracChangeset
for help on using the changeset viewer.