source: tspsg/src/mainwindow.cpp @ ca3d2a30fa

0.1.3.145-beta1-symbian0.1.4.170-beta2-bb10appveyorimgbotreadme
Last change on this file since ca3d2a30fa was ca3d2a30fa, checked in by Oleksii Serdiuk, 14 years ago

+ Implemented saving the solution graph when saving solution as HTML (in SVG format).

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