source: tspsg/src/mainwindow.cpp @ 94cd045fad

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

+ Started adding a toolbar customization with the ude of QtToolbarDialog? (http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Widgets/qttoolbardialog/).

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