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

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

+ Added support for switching between available Qt Styles.

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