source: tspsg-svn/trunk/src/mainwindow.cpp @ 113

Last change on this file since 113 was 110, checked in by laleppa, 15 years ago

+ Added ChangeLog?, Installation Guide and License pages to doxygen generated documentation.

  • Added city and separator parameters to CTSPSolver::getSortedPath() method to make path generation more flexible.
  • Fixed a bug when the solution graph wasn't drwan correctly in some situations.
  • Property svn:keywords set to Id URL
File size: 43.5 KB
Line 
1/*
2 *  TSPSG: TSP Solver and Generator
3 *  Copyright (C) 2007-2010 Lёppa <contacts[at]oleksii[dot]name>
4 *
5 *  $Id: mainwindow.cpp 110 2010-04-27 23:38:10Z laleppa $
6 *  $URL: https://tspsg.svn.sourceforge.net/svnroot/tspsg/trunk/src/mainwindow.cpp $
7 *
8 *  This file is part of TSPSG.
9 *
10 *  TSPSG is free software: you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License as published by
12 *  the Free Software Foundation, either version 3 of the License, or
13 *  (at your option) any later version.
14 *
15 *  TSPSG is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU General Public License for more details.
19 *
20 *  You should have received a copy of the GNU General Public License
21 *  along with TSPSG.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include "mainwindow.h"
25
26/*!
27 * \brief Class constructor.
28 * \param parent Main Window parent widget.
29 *
30 *  Initializes Main Window and creates its layout based on target OS.
31 *  Loads TSPSG settings and opens a task file if it was specified as a commandline parameter.
32 */
33MainWindow::MainWindow(QWidget *parent)
34        : QMainWindow(parent)
35{
36        settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TSPSG", "tspsg", this);
37
38        loadLanguage();
39        setupUi();
40        setAcceptDrops(true);
41
42        initDocStyleSheet();
43
44#ifndef QT_NO_PRINTER
45        printer = new QPrinter(QPrinter::HighResolution);
46#endif // QT_NO_PRINTER
47
48#ifdef Q_OS_WINCE_WM
49        currentGeometry = QApplication::desktop()->availableGeometry(0);
50        // We need to react to SIP show/hide and resize the window appropriately
51        connect(QApplication::desktop(), SIGNAL(workAreaResized(int)), SLOT(desktopResized(int)));
52#endif // Q_OS_WINCE_WM
53        connect(actionFileNew,SIGNAL(triggered()),this,SLOT(actionFileNewTriggered()));
54        connect(actionFileOpen,SIGNAL(triggered()),this,SLOT(actionFileOpenTriggered()));
55        connect(actionFileSave,SIGNAL(triggered()),this,SLOT(actionFileSaveTriggered()));
56        connect(actionFileSaveAsTask,SIGNAL(triggered()),this,SLOT(actionFileSaveAsTaskTriggered()));
57        connect(actionFileSaveAsSolution,SIGNAL(triggered()),this,SLOT(actionFileSaveAsSolutionTriggered()));
58#ifndef QT_NO_PRINTER
59        connect(actionFilePrintPreview,SIGNAL(triggered()),this,SLOT(actionFilePrintPreviewTriggered()));
60        connect(actionFilePrint,SIGNAL(triggered()),this,SLOT(actionFilePrintTriggered()));
61#endif // QT_NO_PRINTER
62        connect(actionSettingsPreferences,SIGNAL(triggered()),this,SLOT(actionSettingsPreferencesTriggered()));
63#ifdef Q_OS_WIN32
64        connect(actionHelpCheck4Updates, SIGNAL(triggered()), SLOT(actionHelpCheck4UpdatesTriggered()));
65#endif // Q_OS_WIN32
66        connect(actionSettingsLanguageAutodetect,SIGNAL(triggered(bool)),this,SLOT(actionSettingsLanguageAutodetectTriggered(bool)));
67        connect(groupSettingsLanguageList,SIGNAL(triggered(QAction *)),this,SLOT(groupSettingsLanguageListTriggered(QAction *)));
68        connect(actionHelpAboutQt,SIGNAL(triggered()),qApp,SLOT(aboutQt()));
69        connect(actionHelpAbout,SIGNAL(triggered()),this,SLOT(actionHelpAboutTriggered()));
70
71        connect(buttonSolve,SIGNAL(clicked()),this,SLOT(buttonSolveClicked()));
72        connect(buttonRandom,SIGNAL(clicked()),this,SLOT(buttonRandomClicked()));
73        connect(buttonBackToTask,SIGNAL(clicked()),this,SLOT(buttonBackToTaskClicked()));
74        connect(spinCities,SIGNAL(valueChanged(int)),this,SLOT(spinCitiesValueChanged(int)));
75
76#ifndef HANDHELD
77        // Centering main window
78QRect rect = geometry();
79        rect.moveCenter(QApplication::desktop()->availableGeometry(this).center());
80        setGeometry(rect);
81        if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
82                // Loading of saved window state
83                settings->beginGroup("MainWindow");
84                restoreGeometry(settings->value("Geometry").toByteArray());
85                restoreState(settings->value("State").toByteArray());
86                settings->endGroup();
87        }
88#else
89        setWindowState(Qt::WindowMaximized);
90#endif // HANDHELD
91
92        tspmodel = new CTSPModel(this);
93        taskView->setModel(tspmodel);
94        connect(tspmodel,SIGNAL(numCitiesChanged(int)),this,SLOT(numCitiesChanged(int)));
95        connect(tspmodel,SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),this,SLOT(dataChanged(const QModelIndex &, const QModelIndex &)));
96        connect(tspmodel,SIGNAL(layoutChanged()),this,SLOT(dataChanged()));
97        if ((QCoreApplication::arguments().count() > 1) && (tspmodel->loadTask(QCoreApplication::arguments().at(1))))
98                setFileName(QCoreApplication::arguments().at(1));
99        else {
100                setFileName();
101                spinCities->setValue(settings->value("NumCities",DEF_NUM_CITIES).toInt());
102                spinCitiesValueChanged(spinCities->value());
103        }
104        setWindowModified(false);
105}
106
107MainWindow::~MainWindow()
108{
109#ifndef QT_NO_PRINTER
110        delete printer;
111#endif
112}
113
114/* Privates **********************************************************/
115
116void MainWindow::actionFileNewTriggered()
117{
118        if (!maybeSave())
119                return;
120        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
121        tspmodel->clear();
122        setFileName();
123        setWindowModified(false);
124        tabWidget->setCurrentIndex(0);
125        solutionText->clear();
126        toggleSolutionActions(false);
127        QApplication::restoreOverrideCursor();
128}
129
130void MainWindow::actionFileOpenTriggered()
131{
132        if (!maybeSave())
133                return;
134
135QStringList filters(tr("All Supported Formats") + " (*.tspt *.zkt)");
136        filters.append(tr("%1 Task Files").arg("TSPSG") + " (*.tspt)");
137        filters.append(tr("%1 Task Files").arg("ZKomModRd") + " (*.zkt)");
138        filters.append(tr("All Files") + " (*)");
139
140QString file = QFileInfo(fileName).canonicalPath();
141QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
142        file = QFileDialog::getOpenFileName(this, tr("Task Load"), file, filters.join(";;"), NULL, opts);
143        if (file.isEmpty() || !QFileInfo(file).isFile())
144                return;
145        if (!tspmodel->loadTask(file))
146                return;
147        setFileName(file);
148        tabWidget->setCurrentIndex(0);
149        setWindowModified(false);
150        solutionText->clear();
151        toggleSolutionActions(false);
152}
153
154bool MainWindow::actionFileSaveTriggered()
155{
156        if ((fileName == tr("Untitled") + ".tspt") || (!fileName.endsWith(".tspt", Qt::CaseInsensitive)))
157                return saveTask();
158        else
159                if (tspmodel->saveTask(fileName)) {
160                        setWindowModified(false);
161                        return true;
162                } else
163                        return false;
164}
165
166void MainWindow::actionFileSaveAsTaskTriggered()
167{
168        saveTask();
169}
170
171void MainWindow::actionFileSaveAsSolutionTriggered()
172{
173static QString selectedFile;
174        if (selectedFile.isEmpty())
175                selectedFile = QFileInfo(fileName).canonicalPath();
176        else
177                selectedFile = QFileInfo(selectedFile).canonicalPath();
178        if (!selectedFile.isEmpty())
179                selectedFile += "/";
180        if (fileName == tr("Untitled") + ".tspt") {
181#ifndef QT_NO_PRINTER
182                selectedFile += "solution.pdf";
183#else
184                selectedFile += "solution.html";
185#endif // QT_NO_PRINTER
186        } else {
187#ifndef QT_NO_PRINTER
188                selectedFile += QFileInfo(fileName).completeBaseName() + ".pdf";
189#else
190                selectedFile += QFileInfo(fileName).completeBaseName() + ".html";
191#endif // QT_NO_PRINTER
192        }
193
194QStringList filters;
195#ifndef QT_NO_PRINTER
196        filters.append(tr("PDF Files") + " (*.pdf)");
197#endif
198        filters.append(tr("HTML Files") + " (*.html *.htm)");
199#if QT_VERSION >= 0x040500
200        filters.append(tr("OpenDocument Files") + " (*.odt)");
201#endif // QT_VERSION >= 0x040500
202        filters.append(tr("All Files") + " (*)");
203
204QFileDialog::Options opts(settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog);
205QString file = QFileDialog::getSaveFileName(this, QString(), selectedFile, filters.join(";;"), NULL, opts);
206        if (file.isEmpty())
207                return;
208        selectedFile = file;
209        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
210#ifndef QT_NO_PRINTER
211        if (selectedFile.endsWith(".pdf",Qt::CaseInsensitive)) {
212QPrinter printer(QPrinter::HighResolution);
213                printer.setOutputFormat(QPrinter::PdfFormat);
214                printer.setOutputFileName(selectedFile);
215                solutionText->document()->print(&printer);
216                QApplication::restoreOverrideCursor();
217                return;
218        }
219#endif
220        if (selectedFile.endsWith(".htm", Qt::CaseInsensitive) || selectedFile.endsWith(".html", Qt::CaseInsensitive)) {
221QFile file(selectedFile);
222                if (!file.open(QFile::WriteOnly)) {
223                        QApplication::restoreOverrideCursor();
224                        QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(file.errorString()));
225                        return;
226                }
227QFileInfo fi(selectedFile);
228QString format = settings->value("Output/GraphImageFormat", DEF_GRAPH_IMAGE_FORMAT).toString();
229#if !defined(NOSVG) && (QT_VERSION >= 0x040500)
230        if (!QImageWriter::supportedImageFormats().contains(format.toAscii()) && (format != "svg")) {
231#else // NOSVG && QT_VERSION >= 0x040500
232        if (!QImageWriter::supportedImageFormats().contains(format.toAscii())) {
233#endif // NOSVG && QT_VERSION >= 0x040500
234                format = DEF_GRAPH_IMAGE_FORMAT;
235                settings->remove("Output/GraphImageFormat");
236        }
237QString html = solutionText->document()->toHtml("UTF-8"),
238                img =  fi.completeBaseName() + "." + format;
239                html.replace(QRegExp("<img\\s+src=\"tspsg://graph.pic\""), QString("<img src=\"%1\" width=\"%2\" height=\"%3\" alt=\"%4\"").arg(img).arg(graph.width() + 2).arg(graph.height() + 2).arg(tr("Solution Graph")));
240
241                // Saving solution text as HTML
242QTextStream ts(&file);
243                ts.setCodec(QTextCodec::codecForName("UTF-8"));
244                ts << html;
245                file.close();
246
247                // Saving solution graph as SVG or PNG (depending on settings and SVG support)
248#if !defined(NOSVG) && (QT_VERSION >= 0x040500)
249                if (format == "svg") {
250QSvgGenerator svg;
251                        svg.setSize(QSize(graph.width(), graph.height()));
252                        svg.setResolution(graph.logicalDpiX());
253                        svg.setFileName(fi.path() + "/" + img);
254                        svg.setTitle(tr("Solution Graph"));
255                        svg.setDescription(tr("Generated with %1").arg(QApplication::applicationName()));
256QPainter p;
257                        p.begin(&svg);
258                        p.drawPicture(1, 1, graph);
259                        p.end();
260                } else {
261#endif // NOSVG && QT_VERSION >= 0x040500
262QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32);
263                        i.fill(0x00FFFFFF);
264QPainter p;
265                        p.begin(&i);
266                        p.drawPicture(1, 1, graph);
267                        p.end();
268QImageWriter pic(fi.path() + "/" + img);
269                        if (pic.supportsOption(QImageIOHandler::Description)) {
270                                pic.setText("Title", "Solution Graph");
271                                pic.setText("Software", QApplication::applicationName());
272                        }
273                        if (format == "png")
274                                pic.setQuality(5);
275                        else if (format == "jpeg")
276                                pic.setQuality(80);
277                        if (!pic.write(i)) {
278                                QApplication::restoreOverrideCursor();
279                                QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution graph.\nError: %1").arg(pic.errorString()));
280                                return;
281                        }
282#if !defined(NOSVG) && (QT_VERSION >= 0x040500)
283                }
284#endif // NOSVG && QT_VERSION >= 0x040500
285
286// Qt < 4.5 has no QTextDocumentWriter class
287#if QT_VERSION >= 0x040500
288        } else {
289QTextDocumentWriter dw(selectedFile);
290                if (!selectedFile.endsWith(".odt",Qt::CaseInsensitive))
291                        dw.setFormat("plaintext");
292                if (!dw.write(solutionText->document()))
293                        QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(dw.device()->errorString()));
294#endif // QT_VERSION >= 0x040500
295        }
296        QApplication::restoreOverrideCursor();
297}
298
299#ifndef QT_NO_PRINTER
300void MainWindow::actionFilePrintPreviewTriggered()
301{
302QPrintPreviewDialog ppd(printer, this);
303        connect(&ppd,SIGNAL(paintRequested(QPrinter *)),SLOT(printPreview(QPrinter *)));
304        ppd.exec();
305}
306
307void MainWindow::actionFilePrintTriggered()
308{
309QPrintDialog pd(printer,this);
310#if QT_VERSION >= 0x040500
311        // No such methods in Qt < 4.5
312        pd.setOption(QAbstractPrintDialog::PrintSelection,false);
313        pd.setOption(QAbstractPrintDialog::PrintPageRange,false);
314#endif
315        if (pd.exec() != QDialog::Accepted)
316                return;
317        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
318        solutionText->document()->print(printer);
319        QApplication::restoreOverrideCursor();
320}
321#endif // QT_NO_PRINTER
322
323void MainWindow::actionSettingsPreferencesTriggered()
324{
325SettingsDialog sd(this);
326        if (sd.exec() != QDialog::Accepted)
327                return;
328        if (sd.colorChanged() || sd.fontChanged()) {
329                if (!solutionText->document()->isEmpty() && sd.colorChanged())
330                        QMessageBox::information(this, tr("Settings Changed"), tr("You have changed color settings.\nThey will be applied to the next solution output."));
331                initDocStyleSheet();
332        }
333        if (sd.translucencyChanged() != 0)
334                toggleTranclucency(sd.translucencyChanged() == 1);
335}
336
337void MainWindow::actionSettingsLanguageAutodetectTriggered(bool checked)
338{
339        if (checked) {
340                settings->remove("Language");
341                QMessageBox::information(this, tr("Language change"), tr("Language will be autodetected on the next application start."));
342        } else
343                settings->setValue("Language", groupSettingsLanguageList->checkedAction()->data().toString());
344}
345
346void MainWindow::groupSettingsLanguageListTriggered(QAction *action)
347{
348        if (actionSettingsLanguageAutodetect->isChecked()) {
349                // We have language autodetection. It needs to be disabled to change language.
350                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) {
351                        actionSettingsLanguageAutodetect->trigger();
352                } else
353                        return;
354        }
355bool untitled = (fileName == tr("Untitled") + ".tspt");
356        if (loadLanguage(action->data().toString())) {
357                QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
358                settings->setValue("Language",action->data().toString());
359                retranslateUi();
360                if (untitled)
361                        setFileName();
362#ifdef Q_OS_WIN32
363                if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
364                        toggleStyle(labelVariant, true);
365                        toggleStyle(labelCities, true);
366                }
367#endif
368                QApplication::restoreOverrideCursor();
369                if (!solutionText->document()->isEmpty())
370                        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."));
371        }
372}
373
374#ifdef Q_OS_WIN32
375void MainWindow::actionHelpCheck4UpdatesTriggered()
376{
377        if (!hasUpdater()) {
378                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."));
379                return;
380        }
381
382        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
383        QProcess::execute("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\"");
384        QApplication::restoreOverrideCursor();
385}
386#endif // Q_OS_WIN32
387
388void MainWindow::actionHelpAboutTriggered()
389{
390QString title;
391#ifdef HANDHELD
392        title += QString("<b>TSPSG<br>TSP Solver and Generator</b><br>");
393#else
394        title += QString("<b>%1</b><br>").arg(QApplication::applicationName());
395#endif // HANDHELD
396        title += QString("%1: <b>%2</b><br>").arg(tr("Version"), QApplication::applicationVersion());
397#ifndef HANDHELD
398        title += QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b><br>").arg(QDate::currentDate().toString("yyyy"), QApplication::organizationDomain(), QApplication::organizationName());
399        title += QString("<b><a href=\"http://tspsg.sourceforge.net/\">http://tspsg.sourceforge.net/</a></b>");
400#else
401        title += QString("<b><a href=\"http://tspsg.sourceforge.net/\">http://tspsg.sf.net/</a></b>");
402#endif // Q_OS_WINCE_WM && Q_OS_SYMBIAN
403
404QString about;
405        about += QString("%1: <b>%2</b><br>").arg(tr("Target OS (ARCH)"), OS);
406#ifndef STATIC_BUILD
407        about += QString("%1 (%2):<br>").arg(tr("Qt library"), tr("shared"));
408        about += QString("&nbsp;&nbsp;&nbsp;&nbsp;%1: <b>%2</b><br>").arg(tr("Build time"), QT_VERSION_STR);
409        about += QString("&nbsp;&nbsp;&nbsp;&nbsp;%1: <b>%2</b><br>").arg(tr("Runtime"), qVersion());
410#else
411        about += QString("%1: <b>%2</b> (%3)<br>").arg(tr("Qt library"), QT_VERSION_STR, tr("static"));
412#endif // STATIC_BUILD
413        about += tr("Buid <b>%1</b>, built on <b>%2</b> at <b>%3</b>").arg(BUILD_NUMBER).arg(__DATE__).arg(__TIME__) + "<br>";
414        about += QString("%1: <b>%2</b><br>").arg(tr("Algorithm"), CTSPSolver::getVersionId());
415        about += "<br>";
416        about += tr("TSPSG is free software: you can redistribute it and/or modify it<br>"
417                "under the terms of the GNU General Public License as published<br>"
418                "by the Free Software Foundation, either version 3 of the License,<br>"
419                "or (at your option) any later version.<br>"
420                "<br>"
421                "TSPSG is distributed in the hope that it will be useful, but<br>"
422                "WITHOUT ANY WARRANTY; without even the implied warranty of<br>"
423                "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>"
424                "GNU General Public License for more details.<br>"
425                "<br>"
426                "You should have received a copy of the GNU General Public License<br>"
427                "along with TSPSG.  If not, see <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses/</a>.");
428
429QDialog *dlg = new QDialog(this);
430QLabel *lblIcon = new QLabel(dlg),
431        *lblTitle = new QLabel(dlg),
432        *lblTranslated = new QLabel(dlg);
433#ifdef HANDHELD
434QLabel *lblSubTitle = new QLabel(QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b>").arg(QDate::currentDate().toString("yyyy"), QApplication::organizationDomain(), QApplication::organizationName()), dlg);
435#endif // HANDHELD
436QTextBrowser *txtAbout = new QTextBrowser(dlg);
437QVBoxLayout *vb = new QVBoxLayout();
438QHBoxLayout *hb1 = new QHBoxLayout(),
439        *hb2 = new QHBoxLayout();
440QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, dlg);
441
442        lblTitle->setOpenExternalLinks(true);
443        lblTitle->setText(title);
444        lblTitle->setAlignment(Qt::AlignTop);
445        lblTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
446#ifndef HANDHELD
447        lblTitle->setStyleSheet(QString("QLabel {background-color: %1; border-color: %2; border-width: 1px; border-style: solid; border-radius: 3px;}").arg(palette().window().color().name(), palette().shadow().color().name()));
448#endif // HANDHELD
449
450        lblIcon->setPixmap(QPixmap(":/images/tspsg.png").scaledToHeight(lblTitle->sizeHint().height(), Qt::SmoothTransformation));
451        lblIcon->setAlignment(Qt::AlignVCenter);
452#ifndef HANDHELD
453        lblIcon->setStyleSheet(QString("QLabel {background-color: %1; border-color: %2; border-width: 1px; border-style: solid; border-radius: 3px;}").arg(palette().window().color().name(), palette().windowText().color().name()));
454#endif // HANDHELD
455
456        hb1->addWidget(lblIcon);
457        hb1->addWidget(lblTitle);
458
459        txtAbout->setWordWrapMode(QTextOption::NoWrap);
460        txtAbout->setOpenExternalLinks(true);
461        txtAbout->setHtml(about);
462        txtAbout->moveCursor(QTextCursor::Start);
463#ifndef HANDHELD
464        txtAbout->setStyleSheet(QString("QTextBrowser {border-color: %1; border-width: 1px; border-style: solid; border-radius: 3px;}").arg(palette().shadow().color().name()));
465#endif // HANDHELD
466
467        bb->button(QDialogButtonBox::Ok)->setCursor(QCursor(Qt::PointingHandCursor));
468
469        lblTranslated->setText(QApplication::translate("--------", "TRANSLATION", "Please, provide translator credits here."));
470        if (lblTranslated->text() == "TRANSLATION")
471                lblTranslated->hide();
472        else {
473                lblTranslated->setOpenExternalLinks(true);
474#ifndef HANDHELD
475                lblTranslated->setStyleSheet(QString("QLabel {background-color: %1; border-color: %2; border-width: 1px; border-style: solid; border-radius: 3px;}").arg(palette().window().color().name(), palette().shadow().color().name()));
476#endif // HANDHELD
477                hb2->addWidget(lblTranslated);
478        }
479
480        hb2->addWidget(bb);
481
482#ifdef Q_OS_WINCE_WM
483        vb->setMargin(3);
484#endif // Q_OS_WINCE_WM
485        vb->addLayout(hb1);
486#ifdef HANDHELD
487        vb->addWidget(lblSubTitle);
488#endif // HANDHELD
489        vb->addWidget(txtAbout);
490        vb->addLayout(hb2);
491
492        dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
493        dlg->setWindowTitle(tr("About TSPSG"));
494        dlg->setLayout(vb);
495
496        connect(bb, SIGNAL(accepted()), dlg, SLOT(accept()));
497
498#ifdef Q_OS_WIN32
499        // Adding some eyecandy in Vista and 7 :-)
500        if (QtWin::isCompositionEnabled())  {
501                QtWin::enableBlurBehindWindow(dlg, true);
502        }
503#endif // Q_OS_WIN32
504
505        dlg->resize(450, 350);
506
507        dlg->exec();
508
509        delete dlg;
510}
511
512void MainWindow::buttonBackToTaskClicked()
513{
514        tabWidget->setCurrentIndex(0);
515}
516
517void MainWindow::buttonRandomClicked()
518{
519        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
520        tspmodel->randomize();
521        QApplication::restoreOverrideCursor();
522}
523
524void MainWindow::buttonSolveClicked()
525{
526TMatrix matrix;
527QList<double> row;
528int n = spinCities->value();
529bool ok;
530        for (int r = 0; r < n; r++) {
531                row.clear();
532                for (int c = 0; c < n; c++) {
533                        row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok));
534                        if (!ok) {
535                                QMessageBox::critical(this, tr("Data error"), tr("Error in cell [Row %1; Column %2]: Invalid data format.").arg(r + 1).arg(c + 1));
536                                return;
537                        }
538                }
539                matrix.append(row);
540        }
541
542QProgressDialog pd(this);
543QProgressBar *pb = new QProgressBar(&pd);
544        pb->setAlignment(Qt::AlignCenter);
545        pb->setFormat(tr("%v of %1 parts found").arg(n));
546        pd.setBar(pb);
547        pd.setMaximum(n);
548        pd.setAutoReset(false);
549        pd.setLabelText(tr("Calculating optimal route..."));
550        pd.setWindowTitle(tr("Solution Progress"));
551        pd.setWindowModality(Qt::ApplicationModal);
552        pd.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
553        pd.show();
554
555CTSPSolver solver;
556        connect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
557        connect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
558SStep *root = solver.solve(n, matrix);
559        disconnect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
560        disconnect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
561        if (!root) {
562                pd.reset();
563                if (!solver.wasCanceled())
564                        QMessageBox::warning(this, tr("Solution Result"), tr("Unable to find a solution.\nMaybe, this task has no solution."));
565                return;
566        }
567        pb->setFormat(tr("Generating header"));
568        pd.setLabelText(tr("Generating solution output..."));
569        pd.setMaximum(solver.getTotalSteps() + 1);
570        pd.setValue(0);
571
572        solutionText->clear();
573        solutionText->setDocumentTitle(tr("Solution of Variant #%1 Task").arg(spinVariant->value()));
574
575QPainter pic;
576        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
577                pic.begin(&graph);
578                pic.setRenderHint(QPainter::Antialiasing);
579                pic.setFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, 9)).value<QFont>());
580                pic.setBrush(QBrush(QColor(Qt::white)));
581                pic.setBackgroundMode(Qt::OpaqueMode);
582        }
583
584QTextDocument *doc = solutionText->document();
585QTextCursor cur(doc);
586
587        cur.beginEditBlock();
588        cur.setBlockFormat(fmt_paragraph);
589        cur.insertText(tr("Variant #%1 Task").arg(spinVariant->value()), fmt_default);
590        cur.insertBlock(fmt_paragraph);
591        cur.insertText(tr("Task:"));
592        outputMatrix(cur, matrix);
593        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool())
594                drawNode(pic, 0);
595        cur.insertHtml("<hr>");
596        cur.insertBlock(fmt_paragraph);
597int imgpos = cur.position();
598        cur.insertText(tr("Variant #%1 Solution").arg(spinVariant->value()), fmt_default);
599        cur.endEditBlock();
600
601SStep *step = root;
602int c = n = 1;
603        pb->setFormat(tr("Generating step %v"));
604        while ((step->next != SStep::NoNextStep) && (c < spinCities->value())) {
605                if (pd.wasCanceled()) {
606                        pd.setLabelText(tr("Cleaning up..."));
607                        pd.setMaximum(0);
608                        pd.setCancelButton(NULL);
609                        pd.show();
610                        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
611                        solver.cleanup(true);
612                        solutionText->clear();
613                        toggleSolutionActions(false);
614                        return;
615                }
616                pd.setValue(n);
617
618                cur.beginEditBlock();
619                cur.insertBlock(fmt_paragraph);
620                cur.insertText(tr("Step #%1").arg(n));
621                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())))) {
622                        outputMatrix(cur, *step);
623                }
624                cur.insertBlock(fmt_paragraph);
625                cur.insertText(tr("Selected route %1 %2 part.").arg((step->next == SStep::RightBranch) ? tr("with") : tr("without")).arg(tr("(%1;%2)").arg(step->candidate.nRow + 1).arg(step->candidate.nCol + 1)), fmt_default);
626                if (!step->alts.empty()) {
627                        SStep::SCandidate cand;
628                        QString alts;
629                        foreach(cand, step->alts) {
630                                if (!alts.isEmpty())
631                                        alts += ", ";
632                                alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1);
633                        }
634                        cur.insertBlock(fmt_paragraph);
635                        cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist);
636                }
637                cur.insertBlock(fmt_paragraph);
638                cur.insertText(" ", fmt_default);
639                cur.endEditBlock();
640
641                if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
642                        if (step->prNode != NULL)
643                                drawNode(pic, n, false, step->prNode);
644                        if (step->plNode != NULL)
645                                drawNode(pic, n, true, step->plNode);
646                }
647                n++;
648
649                if (step->next == SStep::RightBranch) {
650                        c++;
651                        step = step->prNode;
652                } else if (step->next == SStep::LeftBranch) {
653                        step = step->plNode;
654                } else
655                        break;
656        }
657        pb->setFormat(tr("Generating footer"));
658        pd.setValue(n);
659
660        cur.beginEditBlock();
661        cur.insertBlock(fmt_paragraph);
662        if (solver.isOptimal())
663                cur.insertText(tr("Optimal path:"));
664        else
665                cur.insertText(tr("Resulting path:"));
666
667        cur.insertBlock(fmt_paragraph);
668        cur.insertText("  " + solver.getSortedPath(tr("City %1")));
669
670        cur.insertBlock(fmt_paragraph);
671        if (isInteger(step->price))
672                cur.insertHtml("<p>" + tr("The price is <b>%n</b> unit(s).", "", qRound(step->price)) + "</p>");
673        else
674                cur.insertHtml("<p>" + tr("The price is <b>%1</b> units.").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()) + "</p>");
675        if (!solver.isOptimal()) {
676                cur.insertBlock(fmt_paragraph);
677                cur.insertText(" ");
678                cur.insertBlock(fmt_paragraph);
679                cur.insertHtml("<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>");
680        }
681        cur.endEditBlock();
682
683        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
684                pic.end();
685
686QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32);
687                i.fill(0);
688                pic.begin(&i);
689                pic.drawPicture(1, 1, graph);
690                pic.end();
691                doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i);
692
693QTextImageFormat img;
694                img.setName("tspsg://graph.pic");
695
696                cur.setPosition(imgpos);
697                cur.insertImage(img, QTextFrameFormat::FloatRight);
698        }
699
700        if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) {
701                // Scrolling to the end of the text.
702                solutionText->moveCursor(QTextCursor::End);
703        } else
704                solutionText->moveCursor(QTextCursor::Start);
705
706        pd.setLabelText(tr("Cleaning up..."));
707        pd.setMaximum(0);
708        pd.setCancelButton(NULL);
709        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
710        solver.cleanup(true);
711        toggleSolutionActions();
712        tabWidget->setCurrentIndex(1);
713}
714
715void MainWindow::dataChanged()
716{
717        setWindowModified(true);
718}
719
720void MainWindow::dataChanged(const QModelIndex &tl, const QModelIndex &br)
721{
722        setWindowModified(true);
723        if (settings->value("Autosize", DEF_AUTOSIZE).toBool()) {
724                for (int k = tl.row(); k <= br.row(); k++)
725                        taskView->resizeRowToContents(k);
726                for (int k = tl.column(); k <= br.column(); k++)
727                        taskView->resizeColumnToContents(k);
728        }
729}
730
731#ifdef Q_OS_WINCE_WM
732void MainWindow::changeEvent(QEvent *ev)
733{
734        if ((ev->type() == QEvent::ActivationChange) && isActiveWindow())
735                desktopResized(0);
736
737        QWidget::changeEvent(ev);
738}
739
740void MainWindow::desktopResized(int screen)
741{
742        if ((screen != 0) || !isActiveWindow())
743                return;
744
745QRect availableGeometry = QApplication::desktop()->availableGeometry(0);
746        if (currentGeometry != availableGeometry) {
747                QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
748                /*!
749                 * \hack HACK: This hack checks whether \link QDesktopWidget::availableGeometry() availableGeometry()\endlink's \c top + \c hegiht = \link QDesktopWidget::screenGeometry() screenGeometry()\endlink's \c height.
750                 *  If \c true, the window gets maximized. If we used \c setGeometry() in this case, the bottom of the
751                 *  window would end up being behind the soft buttons. Is this a bug in Qt or Windows Mobile?
752                 */
753                if ((availableGeometry.top() + availableGeometry.height()) == QApplication::desktop()->screenGeometry().height()) {
754                        setWindowState(windowState() | Qt::WindowMaximized);
755                } else {
756                        if (windowState() & Qt::WindowMaximized)
757                                setWindowState(windowState() ^ Qt::WindowMaximized);
758                        setGeometry(availableGeometry);
759                }
760                currentGeometry = availableGeometry;
761                QApplication::restoreOverrideCursor();
762        }
763}
764#endif // Q_OS_WINCE_WM
765
766void MainWindow::numCitiesChanged(int nCities)
767{
768        blockSignals(true);
769        spinCities->setValue(nCities);
770        blockSignals(false);
771}
772
773#ifndef QT_NO_PRINTER
774void MainWindow::printPreview(QPrinter *printer)
775{
776        solutionText->print(printer);
777}
778#endif // QT_NO_PRINTER
779
780void MainWindow::spinCitiesValueChanged(int n)
781{
782        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
783int count = tspmodel->numCities();
784        tspmodel->setNumCities(n);
785        if ((n > count) && settings->value("Autosize", DEF_AUTOSIZE).toBool())
786                for (int k = count; k < n; k++) {
787                        taskView->resizeColumnToContents(k);
788                        taskView->resizeRowToContents(k);
789                }
790        QApplication::restoreOverrideCursor();
791}
792
793void MainWindow::closeEvent(QCloseEvent *ev)
794{
795        if (!maybeSave()) {
796                ev->ignore();
797                return;
798        }
799        if (!settings->value("SettingsReset", false).toBool()) {
800                settings->setValue("NumCities", spinCities->value());
801
802                // Saving Main Window state
803                if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
804                        settings->beginGroup("MainWindow");
805#ifndef HANDHELD
806                        settings->setValue("Geometry", saveGeometry());
807#endif // HANDHELD
808                        settings->setValue("State", saveState());
809                        settings->endGroup();
810                }
811        } else {
812                settings->remove("SettingsReset");
813        }
814
815        QMainWindow::closeEvent(ev);
816}
817
818void MainWindow::dragEnterEvent(QDragEnterEvent *ev)
819{
820        if (ev->mimeData()->hasUrls() && (ev->mimeData()->urls().count() == 1)) {
821QFileInfo fi(ev->mimeData()->urls().first().toLocalFile());
822                if ((fi.suffix() == "tspt") || (fi.suffix() == "zkt"))
823                        ev->acceptProposedAction();
824        }
825}
826
827void MainWindow::drawNode(QPainter &pic, int nstep, bool left, SStep *step)
828{
829const int r = 35;
830qreal x, y;
831        if (step != NULL)
832                x = left ? r : r * 3.5;
833        else
834                x = r * 2.25;
835        y = r * (3 * nstep + 1);
836
837        pic.drawEllipse(QPointF(x, y), r, r);
838
839        if (step != NULL) {
840QFont font;
841                if (left) {
842                        font = pic.font();
843                        font.setStrikeOut(true);
844                        pic.setFont(font);
845                }
846                pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, tr("(%1;%2)").arg(step->pNode->candidate.nRow + 1).arg(step->pNode->candidate.nCol + 1) + "\n");
847                if (left) {
848                        font.setStrikeOut(false);
849                        pic.setFont(font);
850                }
851                if (step->price != INFINITY) {
852                        pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, isInteger(step->price) ?  QString("\n%1").arg(step->price) : QString("\n%1").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()));
853                } else {
854                        pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, "\n"INFSTR);
855                }
856        } else {
857                pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, tr("Root"));
858        }
859
860        if (nstep == 1) {
861                pic.drawLine(QPointF(x, y - r), QPointF(r * 2.25, y - 2 * r));
862        } else if (nstep > 1) {
863                pic.drawLine(QPointF(x, y - r), QPointF((step->pNode->pNode->next == SStep::RightBranch) ? r * 3.5 : r, y - 2 * r));
864        }
865
866}
867
868void MainWindow::dropEvent(QDropEvent *ev)
869{
870        if (maybeSave() && tspmodel->loadTask(ev->mimeData()->urls().first().toLocalFile())) {
871                setFileName(ev->mimeData()->urls().first().toLocalFile());
872                tabWidget->setCurrentIndex(0);
873                setWindowModified(false);
874                solutionText->clear();
875                toggleSolutionActions(false);
876
877                ev->setDropAction(Qt::CopyAction);
878                ev->accept();
879        }
880}
881
882bool MainWindow::hasUpdater() const
883{
884#ifdef Q_OS_WIN32
885        return QFile::exists("updater/Update.exe");
886#else // Q_OS_WIN32
887        return false;
888#endif // Q_OS_WIN32
889}
890
891void MainWindow::initDocStyleSheet()
892{
893        solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, DEF_FONT_SIZE)).value<QFont>());
894
895        fmt_paragraph.setTopMargin(0);
896        fmt_paragraph.setRightMargin(10);
897        fmt_paragraph.setBottomMargin(0);
898        fmt_paragraph.setLeftMargin(10);
899
900        fmt_table.setTopMargin(5);
901        fmt_table.setRightMargin(10);
902        fmt_table.setBottomMargin(5);
903        fmt_table.setLeftMargin(10);
904        fmt_table.setBorder(0);
905        fmt_table.setBorderStyle(QTextFrameFormat::BorderStyle_None);
906        fmt_table.setCellSpacing(5);
907
908        fmt_cell.setAlignment(Qt::AlignHCenter);
909
910QColor color = settings->value("Output/Colors/Text", DEF_TEXT_COLOR).value<QColor>();
911QColor hilight;
912        if (color.value() < 192)
913                hilight.setHsv(color.hue(), color.saturation(), 127 + qRound(color.value() / 2));
914        else
915                hilight.setHsv(color.hue(), color.saturation(), color.value() / 2);
916
917        solutionText->document()->setDefaultStyleSheet(QString("* {color: %1;}").arg(color.name()));
918        fmt_default.setForeground(QBrush(color));
919
920        fmt_selected.setForeground(QBrush(settings->value("Output/Colors/Selected", DEF_SELECTED_COLOR).value<QColor>()));
921        fmt_selected.setFontWeight(QFont::Bold);
922
923        fmt_alternate.setForeground(QBrush(settings->value("Output/Colors/Alternate", DEF_ALTERNATE_COLOR).value<QColor>()));
924        fmt_alternate.setFontWeight(QFont::Bold);
925        fmt_altlist.setForeground(QBrush(hilight));
926
927        solutionText->setTextColor(color);
928}
929
930void MainWindow::loadLangList()
931{
932QDir dir(PATH_L10N, "tspsg_*.qm", QDir::Name | QDir::IgnoreCase, QDir::Files);
933        if (!dir.exists())
934                return;
935QFileInfoList langs = dir.entryInfoList();
936        if (langs.size() <= 0)
937                return;
938QAction *a;
939QTranslator t;
940QString name;
941        for (int k = 0; k < langs.size(); k++) {
942                QFileInfo lang = langs.at(k);
943                if (lang.completeBaseName().compare("tspsg_en", Qt::CaseInsensitive) && t.load(lang.completeBaseName(), PATH_L10N)) {
944                        name = t.translate("--------", "LANGNAME", "Please, provide a native name of your translation language here.");
945                        a = menuSettingsLanguage->addAction(name);
946                        a->setStatusTip(QString("Set application language to %1").arg(name));
947                        a->setData(lang.completeBaseName().mid(6));
948                        a->setCheckable(true);
949                        a->setActionGroup(groupSettingsLanguageList);
950                        if (settings->value("Language", QLocale::system().name()).toString().startsWith(lang.completeBaseName().mid(6)))
951                                a->setChecked(true);
952                }
953        }
954}
955
956bool MainWindow::loadLanguage(const QString &lang)
957{
958// i18n
959bool ad = false;
960QString lng = lang;
961        if (lng.isEmpty()) {
962                ad = settings->value("Language", "").toString().isEmpty();
963                lng = settings->value("Language", QLocale::system().name()).toString();
964        }
965static QTranslator *qtTranslator; // Qt library translator
966        if (qtTranslator) {
967                qApp->removeTranslator(qtTranslator);
968                delete qtTranslator;
969                qtTranslator = NULL;
970        }
971static QTranslator *translator; // Application translator
972        if (translator) {
973                qApp->removeTranslator(translator);
974                delete translator;
975                translator = NULL;
976        }
977
978        if (lng == "en")
979                return true;
980
981        // Trying to load system Qt library translation...
982        qtTranslator = new QTranslator(this);
983        if (qtTranslator->load("qt_" + lng, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
984                qApp->installTranslator(qtTranslator);
985        else {
986                // No luck. Let's try to load a bundled one.
987                if (qtTranslator->load("qt_" + lng, PATH_L10N))
988                        qApp->installTranslator(qtTranslator);
989                else {
990                        // Qt library translation unavailable
991                        delete qtTranslator;
992                        qtTranslator = NULL;
993                }
994        }
995
996        // Now let's load application translation.
997        translator = new QTranslator(this);
998        if (translator->load("tspsg_" + lng, PATH_L10N))
999                qApp->installTranslator(translator);
1000        else {
1001                delete translator;
1002                translator = NULL;
1003                if (!ad) {
1004                        settings->remove("Language");
1005                        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
1006                        if (isVisible())
1007                                QMessageBox::warning(this, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
1008                        else
1009                                QMessageBox::warning(NULL, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
1010                        QApplication::restoreOverrideCursor();
1011                }
1012                return false;
1013        }
1014        return true;
1015}
1016
1017bool MainWindow::maybeSave()
1018{
1019        if (!isWindowModified())
1020                return true;
1021int res = QMessageBox::warning(this, tr("Unsaved Changes"), tr("Would you like to save changes in the current task?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
1022        if (res == QMessageBox::Save)
1023                return actionFileSaveTriggered();
1024        else if (res == QMessageBox::Cancel)
1025                return false;
1026        else
1027                return true;
1028}
1029
1030void MainWindow::outputMatrix(QTextCursor &cur, const TMatrix &matrix)
1031{
1032int n = spinCities->value();
1033QTextTable *table = cur.insertTable(n, n, fmt_table);
1034
1035        for (int r = 0; r < n; r++) {
1036                for (int c = 0; c < n; c++) {
1037                        cur = table->cellAt(r, c).firstCursorPosition();
1038                        cur.setBlockFormat(fmt_cell);
1039                        cur.setBlockCharFormat(fmt_default);
1040                        if (matrix.at(r).at(c) == INFINITY)
1041                                cur.insertText(INFSTR);
1042                        else
1043                                cur.insertText(isInteger(matrix.at(r).at(c)) ? QString("%1").arg(matrix.at(r).at(c)) : QString("%1").arg(matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()));
1044                }
1045                QApplication::processEvents();
1046        }
1047        cur.movePosition(QTextCursor::End);
1048}
1049
1050void MainWindow::outputMatrix(QTextCursor &cur, const SStep &step)
1051{
1052int n = spinCities->value();
1053QTextTable *table = cur.insertTable(n, n, fmt_table);
1054
1055        for (int r = 0; r < n; r++) {
1056                for (int c = 0; c < n; c++) {
1057                        cur = table->cellAt(r, c).firstCursorPosition();
1058                        cur.setBlockFormat(fmt_cell);
1059                        if (step.matrix.at(r).at(c) == INFINITY)
1060                                cur.insertText(INFSTR, fmt_default);
1061                        else if ((r == step.candidate.nRow) && (c == step.candidate.nCol))
1062                                cur.insertText(isInteger(step.matrix.at(r).at(c)) ? QString("%1").arg(step.matrix.at(r).at(c)) : QString("%1").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()), fmt_selected);
1063                        else {
1064SStep::SCandidate cand;
1065                                cand.nRow = r;
1066                                cand.nCol = c;
1067                                if (step.alts.contains(cand))
1068                                        cur.insertText(isInteger(step.matrix.at(r).at(c)) ? QString("%1").arg(step.matrix.at(r).at(c)) : QString("%1").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()), fmt_alternate);
1069                                else
1070                                        cur.insertText(isInteger(step.matrix.at(r).at(c)) ? QString("%1").arg(step.matrix.at(r).at(c)) : QString("%1").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()), fmt_default);
1071                        }
1072                }
1073                QApplication::processEvents();
1074        }
1075
1076        cur.movePosition(QTextCursor::End);
1077}
1078
1079void MainWindow::retranslateUi(bool all)
1080{
1081        if (all)
1082                Ui::MainWindow::retranslateUi(this);
1083
1084        actionSettingsLanguageEnglish->setStatusTip(tr("Set application language to %1").arg("English"));
1085
1086#ifndef QT_NO_PRINTER
1087        actionFilePrintPreview->setText(QApplication::translate("MainWindow", "P&rint Preview...", 0, QApplication::UnicodeUTF8));
1088#ifndef QT_NO_TOOLTIP
1089        actionFilePrintPreview->setToolTip(QApplication::translate("MainWindow", "Preview solution results", 0, QApplication::UnicodeUTF8));
1090#endif // QT_NO_TOOLTIP
1091#ifndef QT_NO_STATUSTIP
1092        actionFilePrintPreview->setStatusTip(QApplication::translate("MainWindow", "Preview current solution results before printing", 0, QApplication::UnicodeUTF8));
1093#endif // QT_NO_STATUSTIP
1094
1095        actionFilePrint->setText(QApplication::translate("MainWindow", "&Print...", 0, QApplication::UnicodeUTF8));
1096#ifndef QT_NO_TOOLTIP
1097        actionFilePrint->setToolTip(QApplication::translate("MainWindow", "Print solution", 0, QApplication::UnicodeUTF8));
1098#endif // QT_NO_TOOLTIP
1099#ifndef QT_NO_STATUSTIP
1100        actionFilePrint->setStatusTip(QApplication::translate("MainWindow", "Print current solution results", 0, QApplication::UnicodeUTF8));
1101#endif // QT_NO_STATUSTIP
1102        actionFilePrint->setShortcut(QApplication::translate("MainWindow", "Ctrl+P", 0, QApplication::UnicodeUTF8));
1103#endif // QT_NO_PRINTER
1104#ifdef Q_OS_WIN32
1105        actionHelpCheck4Updates->setText(tr("Check for &Updates..."));
1106#ifndef QT_NO_TOOLTIP
1107        actionHelpCheck4Updates->setToolTip(tr("Check for %1 updates").arg(QApplication::applicationName()));
1108#endif // QT_NO_TOOLTIP
1109#ifndef QT_NO_STATUSTIP
1110        actionHelpCheck4Updates->setStatusTip(tr("Check for %1 updates").arg(QApplication::applicationName()));
1111#endif // QT_NO_STATUSTIP
1112#endif // Q_OS_WIN32
1113}
1114
1115bool MainWindow::saveTask() {
1116QStringList filters(tr("%1 Task File").arg("TSPSG") + " (*.tspt)");
1117        filters.append(tr("All Files") + " (*)");
1118QString file;
1119        if (fileName.endsWith(".tspt", Qt::CaseInsensitive))
1120                file = fileName;
1121        else
1122                file = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".tspt";
1123
1124QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
1125        file = QFileDialog::getSaveFileName(this, tr("Task Save"), file, filters.join(";;"), NULL, opts);
1126
1127        if (file.isEmpty())
1128                return false;
1129        if (tspmodel->saveTask(file)) {
1130                setFileName(file);
1131                setWindowModified(false);
1132                return true;
1133        }
1134        return false;
1135}
1136
1137void MainWindow::setFileName(const QString &fileName)
1138{
1139        this->fileName = fileName;
1140        setWindowTitle(QString("%1[*] - %2").arg(QFileInfo(fileName).completeBaseName()).arg(tr("Travelling Salesman Problem")));
1141}
1142
1143void MainWindow::setupUi()
1144{
1145        Ui::MainWindow::setupUi(this);
1146
1147#if QT_VERSION >= 0x040600
1148        setToolButtonStyle(Qt::ToolButtonFollowStyle);
1149#endif
1150
1151#ifndef HANDHELD
1152QStatusBar *statusbar = new QStatusBar(this);
1153        statusbar->setObjectName("statusbar");
1154        setStatusBar(statusbar);
1155#endif // HANDHELD
1156
1157#ifdef Q_OS_WINCE_WM
1158        menuBar()->setDefaultAction(menuFile->menuAction());
1159
1160QScrollArea *scrollArea = new QScrollArea(this);
1161        scrollArea->setFrameShape(QFrame::NoFrame);
1162        scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1163        scrollArea->setWidgetResizable(true);
1164        scrollArea->setWidget(tabWidget);
1165        setCentralWidget(scrollArea);
1166#else
1167        setCentralWidget(tabWidget);
1168#endif // Q_OS_WINCE_WM
1169
1170        //! \hack HACK: A little hack for toolbar icons to have a sane size.
1171#ifdef Q_OS_WINCE_WM
1172        toolBar->setIconSize(QSize(logicalDpiX() / 4, logicalDpiY() / 4));
1173#elif defined(Q_OS_SYMBIAN)
1174        toolBar->setIconSize(QSize(logicalDpiX() / 5, logicalDpiY() / 5));
1175#endif // Q_OS_WINCE_WM
1176
1177        solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, DEF_FONT_SIZE)).value<QFont>());
1178        solutionText->setWordWrapMode(QTextOption::WordWrap);
1179
1180#ifndef QT_NO_PRINTER
1181        actionFilePrintPreview = new QAction(this);
1182        actionFilePrintPreview->setObjectName("actionFilePrintPreview");
1183        actionFilePrintPreview->setEnabled(false);
1184        actionFilePrintPreview->setIcon(QIcon(":/images/icons/document_preview.png"));
1185
1186        actionFilePrint = new QAction(this);
1187        actionFilePrint->setObjectName("actionFilePrint");
1188        actionFilePrint->setEnabled(false);
1189        actionFilePrint->setIcon(QIcon(":/images/icons/fileprint.png"));
1190
1191        menuFile->insertAction(actionFileExit,actionFilePrintPreview);
1192        menuFile->insertAction(actionFileExit,actionFilePrint);
1193        menuFile->insertSeparator(actionFileExit);
1194
1195        toolBar->insertAction(actionSettingsPreferences,actionFilePrint);
1196#endif // QT_NO_PRINTER
1197#ifdef Q_OS_WIN32
1198        actionHelpCheck4Updates = new QAction(this);
1199        actionHelpCheck4Updates->setEnabled(hasUpdater());
1200        menuHelp->insertAction(actionHelpAboutQt, actionHelpCheck4Updates);
1201        menuHelp->insertSeparator(actionHelpAboutQt);
1202#endif // Q_OS_WIN32
1203
1204        groupSettingsLanguageList = new QActionGroup(this);
1205        actionSettingsLanguageEnglish->setData("en");
1206        actionSettingsLanguageEnglish->setActionGroup(groupSettingsLanguageList);
1207        loadLangList();
1208        actionSettingsLanguageAutodetect->setChecked(settings->value("Language", "").toString().isEmpty());
1209
1210        spinCities->setMaximum(MAX_NUM_CITIES);
1211
1212        retranslateUi(false);
1213
1214#ifdef Q_OS_WIN32
1215        // Adding some eyecandy in Vista and 7 :-)
1216        if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
1217                toggleTranclucency(true);
1218        }
1219#endif // Q_OS_WIN32
1220}
1221
1222void MainWindow::toggleSolutionActions(bool enable)
1223{
1224        buttonSaveSolution->setEnabled(enable);
1225        actionFileSaveAsSolution->setEnabled(enable);
1226        solutionText->setEnabled(enable);
1227#ifndef QT_NO_PRINTER
1228        actionFilePrint->setEnabled(enable);
1229        actionFilePrintPreview->setEnabled(enable);
1230#endif // QT_NO_PRINTER
1231}
1232
1233void MainWindow::toggleTranclucency(bool enable)
1234{
1235#ifdef Q_OS_WIN32
1236        toggleStyle(labelVariant, enable);
1237        toggleStyle(labelCities, enable);
1238        toggleStyle(statusBar(), enable);
1239        tabWidget->setDocumentMode(enable);
1240        QtWin::enableBlurBehindWindow(this, enable);
1241#else
1242        Q_UNUSED(enable);
1243#endif // Q_OS_WIN32
1244}
Note: See TracBrowser for help on using the repository browser.