source: tspsg/src/mainwindow.cpp @ b8a2a118c4

0.1.4.170-beta2-bb10appveyorimgbotreadme
Last change on this file since b8a2a118c4 was b8a2a118c4, checked in by Oleksii Serdiuk, 13 years ago
  • Translucency effect is now available on all desktop platforms. No check for its support by window system is made at this moment. Blur is only available in Windows Vista or higher.
  • Property mode set to 100644
File size: 63.8 KB
RevLine 
[1babbd6ba3]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
[97e90f9be6]26#ifdef Q_WS_WIN32
[b8a2a118c4]27#   include "shobjidl.h"
[43c29c04ba]28#endif
29
[3cadf24d00]30#ifdef _T_T_L_
31#include "_.h"
[e9db3e216b]32_C_ _R_ _Y_ _P_ _T_
[3cadf24d00]33#endif
34
[1babbd6ba3]35/*!
36 * \brief Class constructor.
37 * \param parent Main Window parent widget.
38 *
39 *  Initializes Main Window and creates its layout based on target OS.
40 *  Loads TSPSG settings and opens a task file if it was specified as a commandline parameter.
41 */
42MainWindow::MainWindow(QWidget *parent)
[9eb63a1598]43    : QMainWindow(parent)
[1babbd6ba3]44{
[9eb63a1598]45    settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TSPSG", "tspsg", this);
[1babbd6ba3]46
[9eb63a1598]47    if (settings->contains("Style")) {
[e3533af1cf]48QStyle *s = QStyleFactory::create(settings->value("Style").toString());
[9eb63a1598]49        if (s != NULL)
50            QApplication::setStyle(s);
51        else
52            settings->remove("Style");
53    }
[e3533af1cf]54
[9eb63a1598]55    loadLanguage();
56    setupUi();
57    setAcceptDrops(true);
[1babbd6ba3]58
[9eb63a1598]59    initDocStyleSheet();
[1babbd6ba3]60
61#ifndef QT_NO_PRINTER
[9eb63a1598]62    printer = new QPrinter(QPrinter::HighResolution);
[1babbd6ba3]63#endif // QT_NO_PRINTER
64
[97e90f9be6]65#ifdef Q_WS_WINCE_WM
[9eb63a1598]66    currentGeometry = QApplication::desktop()->availableGeometry(0);
67    // We need to react to SIP show/hide and resize the window appropriately
68    connect(QApplication::desktop(), SIGNAL(workAreaResized(int)), SLOT(desktopResized(int)));
[97e90f9be6]69#endif // Q_WS_WINCE_WM
[9eb63a1598]70    connect(actionFileNew, SIGNAL(triggered()), SLOT(actionFileNewTriggered()));
71    connect(actionFileOpen, SIGNAL(triggered()), SLOT(actionFileOpenTriggered()));
72    connect(actionFileSave, SIGNAL(triggered()), SLOT(actionFileSaveTriggered()));
73    connect(actionFileSaveAsTask, SIGNAL(triggered()), SLOT(actionFileSaveAsTaskTriggered()));
74    connect(actionFileSaveAsSolution, SIGNAL(triggered()), SLOT(actionFileSaveAsSolutionTriggered()));
[1babbd6ba3]75#ifndef QT_NO_PRINTER
[9eb63a1598]76    connect(actionFilePrintPreview, SIGNAL(triggered()), SLOT(actionFilePrintPreviewTriggered()));
77    connect(actionFilePrint, SIGNAL(triggered()), SLOT(actionFilePrintTriggered()));
[1babbd6ba3]78#endif // QT_NO_PRINTER
[7bb19df196]79#ifndef HANDHELD
[9eb63a1598]80    connect(actionSettingsToolbarsConfigure, SIGNAL(triggered()), SLOT(actionSettingsToolbarsConfigureTriggered()));
[7bb19df196]81#endif // HANDHELD
[9eb63a1598]82    connect(actionSettingsPreferences, SIGNAL(triggered()), SLOT(actionSettingsPreferencesTriggered()));
83    if (actionHelpCheck4Updates != NULL)
84        connect(actionHelpCheck4Updates, SIGNAL(triggered()), SLOT(actionHelpCheck4UpdatesTriggered()));
85    connect(actionSettingsLanguageAutodetect, SIGNAL(triggered(bool)), SLOT(actionSettingsLanguageAutodetectTriggered(bool)));
86    connect(groupSettingsLanguageList, SIGNAL(triggered(QAction *)), SLOT(groupSettingsLanguageListTriggered(QAction *)));
87    connect(actionSettingsStyleSystem, SIGNAL(triggered(bool)), SLOT(actionSettingsStyleSystemTriggered(bool)));
88    connect(groupSettingsStyleList, SIGNAL(triggered(QAction*)), SLOT(groupSettingsStyleListTriggered(QAction*)));
89    connect(actionHelpOnlineSupport, SIGNAL(triggered()), SLOT(actionHelpOnlineSupportTriggered()));
90    connect(actionHelpReportBug, SIGNAL(triggered()), SLOT(actionHelpReportBugTriggered()));
91    connect(actionHelpAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
92    connect(actionHelpAbout, SIGNAL(triggered()), SLOT(actionHelpAboutTriggered()));
93
94    connect(buttonSolve, SIGNAL(clicked()), SLOT(buttonSolveClicked()));
95    connect(buttonRandom, SIGNAL(clicked()), SLOT(buttonRandomClicked()));
96    connect(buttonBackToTask, SIGNAL(clicked()), SLOT(buttonBackToTaskClicked()));
97    connect(spinCities, SIGNAL(valueChanged(int)), SLOT(spinCitiesValueChanged(int)));
[1babbd6ba3]98
99#ifndef HANDHELD
[9eb63a1598]100    // Centering main window
[1babbd6ba3]101QRect rect = geometry();
[9eb63a1598]102    rect.moveCenter(QApplication::desktop()->availableGeometry(this).center());
103    setGeometry(rect);
104    if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
105        // Loading of saved window state
106        settings->beginGroup("MainWindow");
107        restoreGeometry(settings->value("Geometry").toByteArray());
108        restoreState(settings->value("State").toByteArray());
109        settings->endGroup();
110    }
[1babbd6ba3]111#endif // HANDHELD
112
[9eb63a1598]113    tspmodel = new CTSPModel(this);
114    taskView->setModel(tspmodel);
115    connect(tspmodel, SIGNAL(numCitiesChanged(int)), SLOT(numCitiesChanged(int)));
116    connect(tspmodel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(dataChanged(const QModelIndex &, const QModelIndex &)));
117    connect(tspmodel, SIGNAL(layoutChanged()), SLOT(dataChanged()));
118    if ((QCoreApplication::arguments().count() > 1) && (tspmodel->loadTask(QCoreApplication::arguments().at(1))))
119        setFileName(QCoreApplication::arguments().at(1));
120    else {
121        setFileName();
122        spinCities->setValue(settings->value("NumCities",DEF_NUM_CITIES).toInt());
123        spinCitiesValueChanged(spinCities->value());
124    }
125    setWindowModified(false);
126
127    if (actionHelpCheck4Updates != NULL) {
128        if (!settings->contains("Check4Updates/Enabled")) {
129            QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
130            settings->setValue("Check4Updates/Enabled",
131                QMessageBox::question(this, QCoreApplication::applicationName(),
132                    tr("Would you like %1 to automatically check for updates every %n day(s)?", "", settings->value("Check4Updates/Interval", DEF_UPDATE_CHECK_INTERVAL).toInt()).arg(QCoreApplication::applicationName()),
133                    QMessageBox::Yes | QMessageBox::No
134                ) == QMessageBox::Yes
135            );
136            QApplication::restoreOverrideCursor();
137        }
138        if ((settings->value("Check4Updates/Enabled", DEF_CHECK_FOR_UPDATES).toBool())
139            && (QDate(qvariant_cast<QDate>(settings->value("Check4Updates/LastAttempt"))).daysTo(QDate::currentDate()) >= settings->value("Check4Updates/Interval", DEF_UPDATE_CHECK_INTERVAL).toInt())) {
140            check4Updates(true);
141        }
142    }
[1babbd6ba3]143}
144
145MainWindow::~MainWindow()
146{
147#ifndef QT_NO_PRINTER
[9eb63a1598]148    delete printer;
[1babbd6ba3]149#endif
150}
151
152/* Privates **********************************************************/
153
154void MainWindow::actionFileNewTriggered()
155{
[9eb63a1598]156    if (!maybeSave())
157        return;
158    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
159    tspmodel->clear();
160    setFileName();
161    setWindowModified(false);
162    tabWidget->setCurrentIndex(0);
163    solutionText->clear();
164    toggleSolutionActions(false);
165    QApplication::restoreOverrideCursor();
[1babbd6ba3]166}
167
168void MainWindow::actionFileOpenTriggered()
169{
[9eb63a1598]170    if (!maybeSave())
171        return;
[1babbd6ba3]172
173QStringList filters(tr("All Supported Formats") + " (*.tspt *.zkt)");
[9eb63a1598]174    filters.append(tr("%1 Task Files").arg("TSPSG") + " (*.tspt)");
175    filters.append(tr("%1 Task Files").arg("ZKomModRd") + " (*.zkt)");
176    filters.append(tr("All Files") + " (*)");
[1babbd6ba3]177
[ac76a6a753]178QString file;
[9eb63a1598]179    if ((fileName == tr("Untitled") + ".tspt") && settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
180        file = settings->value(OS"/LastUsed/TaskLoadPath").toString();
181    else
182        file = QFileInfo(fileName).path();
[1babbd6ba3]183QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
[9eb63a1598]184    file = QFileDialog::getOpenFileName(this, tr("Task Load"), file, filters.join(";;"), NULL, opts);
185    if (file.isEmpty() || !QFileInfo(file).isFile())
186        return;
187    if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
188        settings->setValue(OS"/LastUsed/TaskLoadPath", QFileInfo(file).path());
189
190    if (!tspmodel->loadTask(file))
191        return;
192    setFileName(file);
193    tabWidget->setCurrentIndex(0);
194    setWindowModified(false);
195    solutionText->clear();
196    toggleSolutionActions(false);
[1babbd6ba3]197}
198
199bool MainWindow::actionFileSaveTriggered()
200{
[9eb63a1598]201    if ((fileName == tr("Untitled") + ".tspt") || !fileName.endsWith(".tspt", Qt::CaseInsensitive))
202        return saveTask();
203    else
204        if (tspmodel->saveTask(fileName)) {
205            setWindowModified(false);
206            return true;
207        } else
208            return false;
[1babbd6ba3]209}
210
211void MainWindow::actionFileSaveAsTaskTriggered()
212{
[9eb63a1598]213    saveTask();
[1babbd6ba3]214}
215
216void MainWindow::actionFileSaveAsSolutionTriggered()
217{
218static QString selectedFile;
[9eb63a1598]219    if (selectedFile.isEmpty()) {
220        if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool()) {
221            selectedFile = settings->value(OS"/LastUsed/SolutionSavePath").toString();
222        }
223    } else
224        selectedFile = QFileInfo(selectedFile).path();
225    if (!selectedFile.isEmpty())
226        selectedFile.append("/");
227    if (fileName == tr("Untitled") + ".tspt") {
[1babbd6ba3]228#ifndef QT_NO_PRINTER
[9eb63a1598]229        selectedFile += "solution.pdf";
[1babbd6ba3]230#else
[9eb63a1598]231        selectedFile += "solution.html";
[1babbd6ba3]232#endif // QT_NO_PRINTER
[9eb63a1598]233    } else {
[1babbd6ba3]234#ifndef QT_NO_PRINTER
[9eb63a1598]235        selectedFile += QFileInfo(fileName).completeBaseName() + ".pdf";
[1babbd6ba3]236#else
[9eb63a1598]237        selectedFile += QFileInfo(fileName).completeBaseName() + ".html";
[1babbd6ba3]238#endif // QT_NO_PRINTER
[9eb63a1598]239    }
[1babbd6ba3]240
241QStringList filters;
242#ifndef QT_NO_PRINTER
[9eb63a1598]243    filters.append(tr("PDF Files") + " (*.pdf)");
[1babbd6ba3]244#endif
[9eb63a1598]245    filters.append(tr("HTML Files") + " (*.html *.htm)");
246    filters.append(tr("OpenDocument Files") + " (*.odt)");
247    filters.append(tr("All Files") + " (*)");
[1babbd6ba3]248
249QFileDialog::Options opts(settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog);
250QString file = QFileDialog::getSaveFileName(this, QString(), selectedFile, filters.join(";;"), NULL, opts);
[9eb63a1598]251    if (file.isEmpty())
252        return;
253    selectedFile = file;
254    if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
255        settings->setValue(OS"/LastUsed/SolutionSavePath", QFileInfo(selectedFile).path());
256    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[1babbd6ba3]257#ifndef QT_NO_PRINTER
[9eb63a1598]258    if (selectedFile.endsWith(".pdf",Qt::CaseInsensitive)) {
[1babbd6ba3]259QPrinter printer(QPrinter::HighResolution);
[9eb63a1598]260        printer.setOutputFormat(QPrinter::PdfFormat);
261        printer.setOutputFileName(selectedFile);
262        solutionText->document()->print(&printer);
263        QApplication::restoreOverrideCursor();
264        return;
265    }
[1babbd6ba3]266#endif
[9eb63a1598]267    if (selectedFile.endsWith(".htm", Qt::CaseInsensitive) || selectedFile.endsWith(".html", Qt::CaseInsensitive)) {
[1babbd6ba3]268QFile file(selectedFile);
[9eb63a1598]269        if (!file.open(QFile::WriteOnly)) {
270            QApplication::restoreOverrideCursor();
271            QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(file.errorString()));
272            return;
273        }
[ca3d2a30fa]274QFileInfo fi(selectedFile);
[20015b41e7]275QString format = settings->value("Output/GraphImageFormat", DEF_GRAPH_IMAGE_FORMAT).toString();
[2a436ea693]276#if !defined(NOSVG)
[9eb63a1598]277    if (!QImageWriter::supportedImageFormats().contains(format.toAscii()) && (format != "svg")) {
[2a436ea693]278#else // NOSVG
[9eb63a1598]279    if (!QImageWriter::supportedImageFormats().contains(format.toAscii())) {
[2a436ea693]280#endif // NOSVG
[9eb63a1598]281        format = DEF_GRAPH_IMAGE_FORMAT;
282        settings->remove("Output/GraphImageFormat");
283    }
[ca3d2a30fa]284QString html = solutionText->document()->toHtml("UTF-8"),
[9eb63a1598]285        img =  fi.completeBaseName() + "." + format;
286        html.replace(QRegExp("font-family:([^;]*);"), "font-family:\\1, 'DejaVu Sans Mono', 'Courier New', Courier, monospace;");
287        html.replace(QRegExp("<img\\s+src=\"tspsg://graph.pic\""), QString("<img src=\"%1\" alt=\"%2\"").arg(img, tr("Solution Graph")));
[20015b41e7]288
[9eb63a1598]289        // Saving solution text as HTML
[1babbd6ba3]290QTextStream ts(&file);
[9eb63a1598]291        ts.setCodec(QTextCodec::codecForName("UTF-8"));
292        ts << html;
293        file.close();
[20015b41e7]294
[9eb63a1598]295        // Saving solution graph as SVG or PNG (depending on settings and SVG support)
[2a436ea693]296#if !defined(NOSVG)
[9eb63a1598]297        if (format == "svg") {
[ca3d2a30fa]298QSvgGenerator svg;
[9eb63a1598]299            svg.setSize(QSize(graph.width() + 2, graph.height() + 2));
300            svg.setResolution(graph.logicalDpiX());
301            svg.setFileName(fi.path() + "/" + img);
302            svg.setTitle(tr("Solution Graph"));
303            svg.setDescription(tr("Generated with %1").arg(QCoreApplication::applicationName()));
[20015b41e7]304QPainter p;
[9eb63a1598]305            p.begin(&svg);
306            p.drawPicture(1, 1, graph);
307            p.end();
308        } else {
[2a436ea693]309#endif // NOSVG
[131c5fc3ba]310QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32);
[9eb63a1598]311            i.fill(0x00FFFFFF);
[ca3d2a30fa]312QPainter p;
[9eb63a1598]313            p.begin(&i);
314            p.drawPicture(1, 1, graph);
315            p.end();
[20015b41e7]316QImageWriter pic(fi.path() + "/" + img);
[9eb63a1598]317            if (pic.supportsOption(QImageIOHandler::Description)) {
318                pic.setText("Title", "Solution Graph");
319                pic.setText("Software", QCoreApplication::applicationName());
320            }
321            if (format == "png")
322                pic.setQuality(5);
323            else if (format == "jpeg")
324                pic.setQuality(80);
325            if (!pic.write(i)) {
326                QApplication::restoreOverrideCursor();
327                QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution graph.\nError: %1").arg(pic.errorString()));
328                return;
329            }
[2a436ea693]330#if !defined(NOSVG)
[9eb63a1598]331        }
[2a436ea693]332#endif // NOSVG
[9eb63a1598]333    } else {
[ca3d2a30fa]334QTextDocumentWriter dw(selectedFile);
[9eb63a1598]335        if (!selectedFile.endsWith(".odt",Qt::CaseInsensitive))
336            dw.setFormat("plaintext");
337        if (!dw.write(solutionText->document()))
338            QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(dw.device()->errorString()));
339    }
340    QApplication::restoreOverrideCursor();
[1babbd6ba3]341}
342
343#ifndef QT_NO_PRINTER
344void MainWindow::actionFilePrintPreviewTriggered()
345{
346QPrintPreviewDialog ppd(printer, this);
[9eb63a1598]347    connect(&ppd,SIGNAL(paintRequested(QPrinter *)),SLOT(printPreview(QPrinter *)));
348    ppd.exec();
[1babbd6ba3]349}
350
351void MainWindow::actionFilePrintTriggered()
352{
353QPrintDialog pd(printer,this);
[9eb63a1598]354    if (pd.exec() != QDialog::Accepted)
355        return;
356    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
357    solutionText->print(printer);
358    QApplication::restoreOverrideCursor();
[1babbd6ba3]359}
360#endif // QT_NO_PRINTER
361
362void MainWindow::actionSettingsPreferencesTriggered()
363{
364SettingsDialog sd(this);
[9eb63a1598]365    if (sd.exec() != QDialog::Accepted)
366        return;
367    if (sd.colorChanged() || sd.fontChanged()) {
368        if (!solutionText->document()->isEmpty() && sd.colorChanged())
369            QMessageBox::information(this, tr("Settings Changed"), tr("You have changed color settings.\nThey will be applied to the next solution output."));
370        initDocStyleSheet();
371    }
372    if (sd.translucencyChanged() != 0)
373        toggleTranclucency(sd.translucencyChanged() == 1);
[1babbd6ba3]374}
375
376void MainWindow::actionSettingsLanguageAutodetectTriggered(bool checked)
377{
[9eb63a1598]378    if (checked) {
379        settings->remove("Language");
380        QMessageBox::information(this, tr("Language change"), tr("Language will be autodetected on the next %1 start.").arg(QCoreApplication::applicationName()));
381    } else
382        settings->setValue("Language", groupSettingsLanguageList->checkedAction()->data().toString());
[1babbd6ba3]383}
384
385void MainWindow::groupSettingsLanguageListTriggered(QAction *action)
386{
[97e90f9be6]387#ifndef Q_WS_MAEMO_5
[9eb63a1598]388    if (actionSettingsLanguageAutodetect->isChecked())
389        actionSettingsLanguageAutodetect->trigger();
[97e90f9be6]390#endif
[1babbd6ba3]391bool untitled = (fileName == tr("Untitled") + ".tspt");
[9eb63a1598]392    if (loadLanguage(action->data().toString())) {
393        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
394        settings->setValue("Language",action->data().toString());
395        retranslateUi();
396        if (untitled)
397            setFileName();
[b8a2a118c4]398#ifndef HANDHELD
[9eb63a1598]399        if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
400            toggleStyle(labelVariant, true);
401            toggleStyle(labelCities, true);
402        }
[1babbd6ba3]403#endif
[9eb63a1598]404        QApplication::restoreOverrideCursor();
405        if (!solutionText->document()->isEmpty())
406            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."));
407    }
[1babbd6ba3]408}
409
[e3533af1cf]410void MainWindow::actionSettingsStyleSystemTriggered(bool checked)
411{
[9eb63a1598]412    if (checked) {
413        settings->remove("Style");
414        QMessageBox::information(this, tr("Style Change"), tr("To apply the default style you need to restart %1.").arg(QCoreApplication::applicationName()));
415    } else {
416        settings->setValue("Style", groupSettingsStyleList->checkedAction()->text());
417    }
[e3533af1cf]418}
419
420void MainWindow::groupSettingsStyleListTriggered(QAction *action)
421{
422QStyle *s = QStyleFactory::create(action->text());
[9eb63a1598]423    if (s != NULL) {
424        QApplication::setStyle(s);
425        settings->setValue("Style", action->text());
426        actionSettingsStyleSystem->setChecked(false);
427    }
[e3533af1cf]428}
429
[7bb19df196]430#ifndef HANDHELD
431void MainWindow::actionSettingsToolbarsConfigureTriggered()
432{
433QtToolBarDialog dlg(this);
[9eb63a1598]434    dlg.setToolBarManager(toolBarManager);
435    dlg.exec();
[7bb19df196]436QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
[9eb63a1598]437    if (tb != NULL) {
438        tb->setMenu(menuFileSaveAs);
439        tb->setPopupMode(QToolButton::MenuButtonPopup);
440        tb->resize(tb->sizeHint());
441    }
[7bb19df196]442
[9eb63a1598]443    loadToolbarList();
[7bb19df196]444}
445#endif // HANDHELD
446
[1babbd6ba3]447void MainWindow::actionHelpCheck4UpdatesTriggered()
448{
[9eb63a1598]449    if (!hasUpdater()) {
450        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."));
451        return;
452    }
[1babbd6ba3]453
[9eb63a1598]454    check4Updates();
[1babbd6ba3]455}
456
457void MainWindow::actionHelpAboutTriggered()
458{
[9eb63a1598]459    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[43c29c04ba]460
[1babbd6ba3]461QString title;
[9eb63a1598]462    title += QString("<b>%1</b><br>").arg(QCoreApplication::applicationName());
463    title += QString("%1: <b>%2</b><br>").arg(tr("Version"), QCoreApplication::applicationVersion());
[1babbd6ba3]464#ifndef HANDHELD
[9eb63a1598]465    title += QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b><br>").arg(QDate::currentDate().toString("yyyy"), QCoreApplication::organizationDomain(), QCoreApplication::organizationName());
[7bb19df196]466#endif // HANDHELD
[9eb63a1598]467    title += QString("<b><a href=\"http://tspsg.info/\">http://tspsg.info/</a></b>");
[1babbd6ba3]468
469QString about;
[9eb63a1598]470    about += QString("%1: <b>%2</b><br>").arg(tr("Target OS (ARCH)"), PLATFROM);
[1babbd6ba3]471#ifndef STATIC_BUILD
[9eb63a1598]472    about += QString("%1 (%2):<br>").arg(tr("Qt library"), tr("shared"));
473    about += QString("&nbsp;&nbsp;&nbsp;&nbsp;%1: <b>%2</b><br>").arg(tr("Build time"), QT_VERSION_STR);
474    about += QString("&nbsp;&nbsp;&nbsp;&nbsp;%1: <b>%2</b><br>").arg(tr("Runtime"), qVersion());
[1babbd6ba3]475#else
[9eb63a1598]476    about += QString("%1: <b>%2</b> (%3)<br>").arg(tr("Qt library"), QT_VERSION_STR, tr("static"));
[1babbd6ba3]477#endif // STATIC_BUILD
[9eb63a1598]478    about += tr("Buid <b>%1</b>, built on <b>%2</b> at <b>%3</b> with <b>%4</b> compiler.").arg(BUILD_NUMBER).arg(__DATE__).arg(__TIME__).arg(COMPILER) + "<br>";
479    about += QString("%1: <b>%2</b><br>").arg(tr("Algorithm"), CTSPSolver::getVersionId());
480    about += "<br>";
481    about += tr("This program is free software: you can redistribute it and/or modify<br>\n"
482        "it under the terms of the GNU General Public License as published by<br>\n"
483        "the Free Software Foundation, either version 3 of the License, or<br>\n"
484        "(at your option) any later version.<br>\n"
485        "<br>\n"
486        "This program is distributed in the hope that it will be useful,<br>\n"
487        "but WITHOUT ANY WARRANTY; without even the implied warranty of<br>\n"
488        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>\n"
489        "GNU General Public License for more details.<br>\n"
490        "<br>\n"
491        "You should have received a copy of the GNU General Public License<br>\n"
492        "along with TSPSG.  If not, see <a href=\"http://www.gnu.org/licenses/\">www.gnu.org/licenses/</a>.");
[43c29c04ba]493
494QString credits;
[9eb63a1598]495    credits += tr("%1 was created using <b>Qt&nbsp;framework</b> licensed "
496        "under the terms of the GNU Lesser General Public License,<br>\n"
497        "see <a href=\"http://qt.nokia.com/\">qt.nokia.com</a><br>\n"
498        "<br>\n"
499        "Most icons used in %1 are part of <b>Oxygen&nbsp;Icons</b> project "
500        "licensed according to the GNU Lesser General Public License,<br>\n"
501        "see <a href=\"http://www.oxygen-icons.org/\">www.oxygen-icons.org</a><br>\n"
502        "<br>\n"
503        "Country flag icons used in %1 are part of the free "
504        "<b>Flag&nbsp;Icons</b> collection created by <b>IconDrawer</b>,<br>\n"
505        "see <a href=\"http://www.icondrawer.com/\">www.icondrawer.com</a><br>\n"
506        "<br>\n"
507        "%1 comes with the default \"embedded\" font <b>DejaVu&nbsp;LGC&nbsp;Sans&nbsp;"
508        "Mono</b> from the <b>DejaVu fonts</b> licensed under a Free license</a>,<br>\n"
509        "see <a href=\"http://dejavu-fonts.org/\">dejavu-fonts.org</a>")
510            .arg("TSPSG");
[43c29c04ba]511
512QFile f(":/files/COPYING");
[9eb63a1598]513    f.open(QIODevice::ReadOnly);
[43c29c04ba]514
[88a59e4d65]515QString translation = QCoreApplication::translate("--------", "AUTHORS %1", "Please, provide translator credits here. %1 will be replaced with VERSION");
[9eb63a1598]516    if ((translation != "AUTHORS %1") && (translation.contains("%1"))) {
[88a59e4d65]517QString about = QCoreApplication::translate("--------", "VERSION", "Please, provide your translation version here.");
[9eb63a1598]518        if (about != "VERSION")
519            translation = translation.arg(about);
520    }
[1babbd6ba3]521
522QDialog *dlg = new QDialog(this);
523QLabel *lblIcon = new QLabel(dlg),
[9eb63a1598]524    *lblTitle = new QLabel(dlg);
[1babbd6ba3]525#ifdef HANDHELD
[88a59e4d65]526QLabel *lblSubTitle = new QLabel(QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b>").arg(QDate::currentDate().toString("yyyy"), QCoreApplication::organizationDomain(), QCoreApplication::organizationName()), dlg);
[1babbd6ba3]527#endif // HANDHELD
[43c29c04ba]528QTabWidget *tabs = new QTabWidget(dlg);
[1babbd6ba3]529QTextBrowser *txtAbout = new QTextBrowser(dlg);
[43c29c04ba]530QTextBrowser *txtLicense = new QTextBrowser(dlg);
531QTextBrowser *txtCredits = new QTextBrowser(dlg);
[1babbd6ba3]532QVBoxLayout *vb = new QVBoxLayout();
533QHBoxLayout *hb1 = new QHBoxLayout(),
[9eb63a1598]534    *hb2 = new QHBoxLayout();
[1babbd6ba3]535QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, dlg);
536
[9eb63a1598]537    lblTitle->setOpenExternalLinks(true);
538    lblTitle->setText(title);
539    lblTitle->setAlignment(Qt::AlignTop);
540    lblTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
[1babbd6ba3]541#ifndef HANDHELD
[9eb63a1598]542    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()));
[1babbd6ba3]543#endif // HANDHELD
544
[9eb63a1598]545    lblIcon->setPixmap(QPixmap(":/images/tspsg.png").scaledToHeight(lblTitle->sizeHint().height(), Qt::SmoothTransformation));
546    lblIcon->setAlignment(Qt::AlignVCenter);
[1babbd6ba3]547#ifndef HANDHELD
[9eb63a1598]548    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()));
[1babbd6ba3]549#endif // HANDHELD
550
[9eb63a1598]551    hb1->addWidget(lblIcon);
552    hb1->addWidget(lblTitle);
[1babbd6ba3]553
[9eb63a1598]554    txtAbout->setWordWrapMode(QTextOption::NoWrap);
555    txtAbout->setOpenExternalLinks(true);
556    txtAbout->setHtml(about);
557    txtAbout->moveCursor(QTextCursor::Start);
558    txtAbout->setFrameShape(QFrame::NoFrame);
[1babbd6ba3]559
[43c29c04ba]560//      txtCredits->setWordWrapMode(QTextOption::NoWrap);
[9eb63a1598]561    txtCredits->setOpenExternalLinks(true);
562    txtCredits->setHtml(credits);
563    txtCredits->moveCursor(QTextCursor::Start);
564    txtCredits->setFrameShape(QFrame::NoFrame);
[1babbd6ba3]565
[9eb63a1598]566    txtLicense->setWordWrapMode(QTextOption::NoWrap);
567    txtLicense->setOpenExternalLinks(true);
568    txtLicense->setText(f.readAll());
569    txtLicense->moveCursor(QTextCursor::Start);
570    txtLicense->setFrameShape(QFrame::NoFrame);
[1babbd6ba3]571
[9eb63a1598]572    bb->button(QDialogButtonBox::Ok)->setCursor(QCursor(Qt::PointingHandCursor));
573    bb->button(QDialogButtonBox::Ok)->setIcon(GET_ICON("dialog-ok"));
[3cadf24d00]574
[9eb63a1598]575    hb2->addWidget(bb);
[1babbd6ba3]576
[97e90f9be6]577#ifdef Q_WS_WINCE_WM
[9eb63a1598]578    vb->setMargin(3);
[97e90f9be6]579#endif // Q_WS_WINCE_WM
[9eb63a1598]580    vb->addLayout(hb1);
[1babbd6ba3]581#ifdef HANDHELD
[9eb63a1598]582    vb->addWidget(lblSubTitle);
[1babbd6ba3]583#endif // HANDHELD
[43c29c04ba]584
[9eb63a1598]585    tabs->addTab(txtAbout, tr("About"));
586    tabs->addTab(txtLicense, tr("License"));
587    tabs->addTab(txtCredits, tr("Credits"));
588    if (translation != "AUTHORS %1") {
[43c29c04ba]589QTextBrowser *txtTranslation = new QTextBrowser(dlg);
590//              txtTranslation->setWordWrapMode(QTextOption::NoWrap);
[9eb63a1598]591        txtTranslation->setOpenExternalLinks(true);
592        txtTranslation->setText(translation);
593        txtTranslation->moveCursor(QTextCursor::Start);
594        txtTranslation->setFrameShape(QFrame::NoFrame);
[43c29c04ba]595
[9eb63a1598]596        tabs->addTab(txtTranslation, tr("Translation"));
597    }
[43c29c04ba]598#ifndef HANDHELD
[9eb63a1598]599    tabs->setStyleSheet(QString("QTabWidget::pane {background-color: %1; border-color: %3; border-width: 1px; border-style: solid; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; padding: 1px;} QTabBar::tab {background-color: %2; border-color: %3; border-width: 1px; border-style: solid; border-bottom: none; border-top-left-radius: 4px; border-top-right-radius: 4px; padding: 2px 6px;} QTabBar::tab:selected {background-color: %4;} QTabBar::tab:!selected {margin-top: 1px;}").arg(palette().base().color().name(), palette().button().color().name(), palette().shadow().color().name(), palette().light().color().name()));
[43c29c04ba]600#endif // HANDHELD
601
[9eb63a1598]602    vb->addWidget(tabs);
603    vb->addLayout(hb2);
[1babbd6ba3]604
[9eb63a1598]605    dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
606    dlg->setWindowTitle(tr("About %1").arg(QCoreApplication::applicationName()));
607    dlg->setWindowIcon(GET_ICON("help-about"));
608    dlg->setLayout(vb);
[1babbd6ba3]609
[9eb63a1598]610    connect(bb, SIGNAL(accepted()), dlg, SLOT(accept()));
[1babbd6ba3]611
[b8a2a118c4]612#ifndef HANDHELD
613    // Adding some eyecandy
[9eb63a1598]614    if (QtWin::isCompositionEnabled())  {
615        QtWin::enableBlurBehindWindow(dlg, true);
616    }
[b8a2a118c4]617#endif // HANDHELD
[1babbd6ba3]618
[9eb63a1598]619    dlg->resize(450, 350);
620    QApplication::restoreOverrideCursor();
[1babbd6ba3]621
[9eb63a1598]622    dlg->exec();
[1babbd6ba3]623
[9eb63a1598]624    delete dlg;
[1babbd6ba3]625}
626
627void MainWindow::buttonBackToTaskClicked()
628{
[9eb63a1598]629    tabWidget->setCurrentIndex(0);
[1babbd6ba3]630}
631
632void MainWindow::buttonRandomClicked()
633{
[9eb63a1598]634    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
635    tspmodel->randomize();
636    QApplication::restoreOverrideCursor();
[1babbd6ba3]637}
638
639void MainWindow::buttonSolveClicked()
640{
641TMatrix matrix;
642QList<double> row;
643int n = spinCities->value();
644bool ok;
[9eb63a1598]645    for (int r = 0; r < n; r++) {
646        row.clear();
647        for (int c = 0; c < n; c++) {
648            row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok));
649            if (!ok) {
650                QMessageBox::critical(this, tr("Data error"), tr("Error in cell [Row %1; Column %2]: Invalid data format.").arg(r + 1).arg(c + 1));
651                return;
652            }
653        }
654        matrix.append(row);
655    }
[1babbd6ba3]656
657QProgressDialog pd(this);
658QProgressBar *pb = new QProgressBar(&pd);
[9eb63a1598]659    pb->setAlignment(Qt::AlignCenter);
660    pb->setFormat(tr("%v of %1 parts found").arg(n));
661    pd.setBar(pb);
[43c29c04ba]662QPushButton *cancel = new QPushButton(&pd);
[9eb63a1598]663    cancel->setIcon(GET_ICON("dialog-cancel"));
664    cancel->setText(QCoreApplication::translate("QProgressDialog", "Cancel", "No need to translate this. This translation will be taken from Qt translation files."));
665    pd.setCancelButton(cancel);
666    pd.setMaximum(n);
667    pd.setAutoReset(false);
668    pd.setLabelText(tr("Calculating optimal route..."));
669    pd.setWindowTitle(tr("Solution Progress"));
670    pd.setWindowModality(Qt::ApplicationModal);
671    pd.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
672    pd.show();
[1babbd6ba3]673
[97e90f9be6]674#ifdef Q_WS_WIN32
[43c29c04ba]675HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID*)&tl);
[9eb63a1598]676    if (SUCCEEDED(hr)) {
677        hr = tl->HrInit();
678        if (FAILED(hr)) {
679            tl->Release();
680            tl = NULL;
681        } else {
[43c29c04ba]682//                      tl->SetProgressState(winId(), TBPF_INDETERMINATE);
[9eb63a1598]683            tl->SetProgressValue(winId(), 0, n * 2);
684        }
685    }
[43c29c04ba]686#endif
687
[1babbd6ba3]688CTSPSolver solver;
[9eb63a1598]689    solver.setCleanupOnCancel(false);
690    connect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
691    connect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
[97e90f9be6]692#ifdef Q_WS_WIN32
[9eb63a1598]693    if (tl != NULL)
694        connect(&solver, SIGNAL(routePartFound(int)), SLOT(solverRoutePartFound(int)));
[43c29c04ba]695#endif
[1babbd6ba3]696SStep *root = solver.solve(n, matrix);
[97e90f9be6]697#ifdef Q_WS_WIN32
[9eb63a1598]698    if (tl != NULL)
699        disconnect(&solver, SIGNAL(routePartFound(int)), this, SLOT(solverRoutePartFound(int)));
[43c29c04ba]700#endif
[9eb63a1598]701    disconnect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
702    disconnect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
703    if (!root) {
704        pd.reset();
705        if (!solver.wasCanceled()) {
[97e90f9be6]706#ifdef Q_WS_WIN32
[9eb63a1598]707            if (tl != NULL) {
[43c29c04ba]708//                              tl->SetProgressValue(winId(), n, n * 2);
[9eb63a1598]709                tl->SetProgressState(winId(), TBPF_ERROR);
710            }
[43c29c04ba]711#endif
[9eb63a1598]712            QApplication::alert(this);
713            QMessageBox::warning(this, tr("Solution Result"), tr("Unable to find a solution.\nMaybe, this task has no solution."));
714        }
715        pd.setLabelText(tr("Cleaning up..."));
716        pd.setMaximum(0);
717        pd.setCancelButton(NULL);
718        pd.show();
[97e90f9be6]719#ifdef Q_WS_WIN32
[9eb63a1598]720        if (tl != NULL)
721            tl->SetProgressState(winId(), TBPF_INDETERMINATE);
[43c29c04ba]722#endif
[9eb63a1598]723        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
[43c29c04ba]724
[a713b103e8]725#ifndef QT_NO_CONCURRENT
[43c29c04ba]726QFuture<void> f = QtConcurrent::run(&solver, &CTSPSolver::cleanup, false);
[9eb63a1598]727        while (!f.isFinished()) {
728            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
729        }
[a713b103e8]730#else
[9eb63a1598]731        solver.cleanup(true);
[a713b103e8]732#endif
[9eb63a1598]733        pd.reset();
[97e90f9be6]734#ifdef Q_WS_WIN32
[9eb63a1598]735        if (tl != NULL) {
736            tl->SetProgressState(winId(), TBPF_NOPROGRESS);
737            tl->Release();
738            tl = NULL;
739        }
[43c29c04ba]740#endif
[9eb63a1598]741        return;
742    }
743    pb->setFormat(tr("Generating header"));
744    pd.setLabelText(tr("Generating solution output..."));
745    pd.setMaximum(solver.getTotalSteps() + 1);
746    pd.setValue(0);
[1babbd6ba3]747
[97e90f9be6]748#ifdef Q_WS_WIN32
[9eb63a1598]749    if (tl != NULL)
750        tl->SetProgressValue(winId(), spinCities->value(), spinCities->value() + solver.getTotalSteps() + 1);
[43c29c04ba]751#endif
752
[9eb63a1598]753    solutionText->clear();
754    solutionText->setDocumentTitle(tr("Solution of Variant #%1 Task").arg(spinVariant->value()));
[317ba0432e]755
[345e7b6132]756QPainter pic;
[9eb63a1598]757    if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
758        pic.begin(&graph);
759        pic.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
[a713b103e8]760QFont font = qvariant_cast<QFont>(settings->value("Output/Font", QFont(DEF_FONT_FACE, 9)));
[9eb63a1598]761        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
762            font.setWeight(QFont::DemiBold);
763            font.setPointSizeF(font.pointSizeF() * 2);
764        }
765        pic.setFont(font);
766        pic.setBrush(QBrush(QColor(Qt::white)));
767        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
[7aaa0b0ec7]768QPen pen = pic.pen();
[9eb63a1598]769            pen.setWidth(2);
770            pic.setPen(pen);
771        }
772        pic.setBackgroundMode(Qt::OpaqueMode);
773    }
[345e7b6132]774
[317ba0432e]775QTextDocument *doc = solutionText->document();
776QTextCursor cur(doc);
777
[9eb63a1598]778    cur.beginEditBlock();
779    cur.setBlockFormat(fmt_paragraph);
780    cur.insertText(tr("Variant #%1 Task").arg(spinVariant->value()), fmt_default);
781    cur.insertBlock(fmt_paragraph);
782    cur.insertText(tr("Task:"));
783    outputMatrix(cur, matrix);
784    if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
[3cadf24d00]785#ifdef _T_T_L_
[9eb63a1598]786        _b_ _i_ _z_ _a_ _r_ _r_ _e_
[3cadf24d00]787#endif
[9eb63a1598]788        drawNode(pic, 0);
789    }
790    cur.insertHtml("<hr>");
791    cur.insertBlock(fmt_paragraph);
[345e7b6132]792int imgpos = cur.position();
[9eb63a1598]793    cur.insertText(tr("Variant #%1 Solution").arg(spinVariant->value()), fmt_default);
794    cur.endEditBlock();
[317ba0432e]795
[1babbd6ba3]796SStep *step = root;
[9cda6e0f5d]797int c = n = 1;
[9eb63a1598]798    pb->setFormat(tr("Generating step %v"));
799    while ((step->next != SStep::NoNextStep) && (c < spinCities->value())) {
800        if (pd.wasCanceled()) {
801            pd.setLabelText(tr("Cleaning up..."));
802            pd.setMaximum(0);
803            pd.setCancelButton(NULL);
804            pd.show();
805            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
[97e90f9be6]806#ifdef Q_WS_WIN32
[9eb63a1598]807            if (tl != NULL)
808                tl->SetProgressState(winId(), TBPF_INDETERMINATE);
[43c29c04ba]809#endif
[a713b103e8]810#ifndef QT_NO_CONCURRENT
[43c29c04ba]811QFuture<void> f = QtConcurrent::run(&solver, &CTSPSolver::cleanup, false);
[9eb63a1598]812            while (!f.isFinished()) {
813                QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
814            }
[a713b103e8]815#else
[9eb63a1598]816            solver.cleanup(true);
[a713b103e8]817#endif
[9eb63a1598]818            solutionText->clear();
819            toggleSolutionActions(false);
[97e90f9be6]820#ifdef Q_WS_WIN32
[9eb63a1598]821            if (tl != NULL) {
822                tl->SetProgressState(winId(), TBPF_NOPROGRESS);
823                tl->Release();
824                tl = NULL;
825            }
[43c29c04ba]826#endif
[9eb63a1598]827            return;
828        }
829        pd.setValue(n);
[97e90f9be6]830#ifdef Q_WS_WIN32
[9eb63a1598]831        if (tl != NULL)
832            tl->SetProgressValue(winId(), spinCities->value() + n, spinCities->value() + solver.getTotalSteps() + 1);
[43c29c04ba]833#endif
[1babbd6ba3]834
[9eb63a1598]835        cur.beginEditBlock();
836        cur.insertBlock(fmt_paragraph);
837        cur.insertText(tr("Step #%1").arg(n));
838        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())))) {
839            outputMatrix(cur, *step);
840        }
841        cur.insertBlock(fmt_paragraph);
842        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);
843        if (!step->alts.empty()) {
844            SStep::SCandidate cand;
845            QString alts;
846            foreach(cand, step->alts) {
847                if (!alts.isEmpty())
848                    alts += ", ";
849                alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1);
850            }
851            cur.insertBlock(fmt_paragraph);
852            cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist);
853        }
854        cur.insertBlock(fmt_paragraph);
855        cur.insertText(" ", fmt_default);
856        cur.endEditBlock();
857
858        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
859            if (step->prNode != NULL)
860                drawNode(pic, n, false, step->prNode);
861            if (step->plNode != NULL)
862                drawNode(pic, n, true, step->plNode);
863        }
864        n++;
865
866        if (step->next == SStep::RightBranch) {
867            c++;
868            step = step->prNode;
869        } else if (step->next == SStep::LeftBranch) {
870            step = step->plNode;
871        } else
872            break;
873    }
874    pb->setFormat(tr("Generating footer"));
875    pd.setValue(n);
[97e90f9be6]876#ifdef Q_WS_WIN32
[9eb63a1598]877    if (tl != NULL)
878        tl->SetProgressValue(winId(), spinCities->value() + n, spinCities->value() + solver.getTotalSteps() + 1);
[43c29c04ba]879#endif
[1babbd6ba3]880
[9eb63a1598]881    cur.beginEditBlock();
882    cur.insertBlock(fmt_paragraph);
883    if (solver.isOptimal())
884        cur.insertText(tr("Optimal path:"));
885    else
886        cur.insertText(tr("Resulting path:"));
887
888    cur.insertBlock(fmt_paragraph);
889    cur.insertText("  " + solver.getSortedPath(tr("City %1")));
890
891    cur.insertBlock(fmt_paragraph);
892    if (isInteger(step->price))
893        cur.insertHtml("<p>" + tr("The price is <b>%n</b> unit(s).", "", qRound(step->price)) + "</p>");
894    else
895        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>");
896    if (!solver.isOptimal()) {
897        cur.insertBlock(fmt_paragraph);
898        cur.insertText(" ");
899        cur.insertBlock(fmt_paragraph);
900        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>");
901    }
902    cur.endEditBlock();
903
904    if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
905        pic.end();
[345e7b6132]906
[131c5fc3ba]907QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_RGB32);
[9eb63a1598]908        i.fill(0xFFFFFF);
909        pic.begin(&i);
910        pic.drawPicture(1, 1, graph);
911        pic.end();
912        doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i);
[345e7b6132]913
914QTextImageFormat img;
[9eb63a1598]915        img.setName("tspsg://graph.pic");
916        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
917            img.setWidth(i.width() / 2);
918            img.setHeight(i.height() / 2);
919        } else {
920            img.setWidth(i.width());
921            img.setHeight(i.height());
922        }
923
924        cur.setPosition(imgpos);
925        cur.insertImage(img, QTextFrameFormat::FloatRight);
926    }
927
928    if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) {
929        // Scrolling to the end of the text.
930        solutionText->moveCursor(QTextCursor::End);
931    } else
932        solutionText->moveCursor(QTextCursor::Start);
933
934    pd.setLabelText(tr("Cleaning up..."));
935    pd.setMaximum(0);
936    pd.setCancelButton(NULL);
937    QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
[97e90f9be6]938#ifdef Q_WS_WIN32
[9eb63a1598]939    if (tl != NULL)
940        tl->SetProgressState(winId(), TBPF_INDETERMINATE);
[43c29c04ba]941#endif
[a713b103e8]942#ifndef QT_NO_CONCURRENT
[43c29c04ba]943QFuture<void> f = QtConcurrent::run(&solver, &CTSPSolver::cleanup, false);
[9eb63a1598]944    while (!f.isFinished()) {
945        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
946    }
[a713b103e8]947#else
[9eb63a1598]948    solver.cleanup(true);
[a713b103e8]949#endif
[9eb63a1598]950    toggleSolutionActions();
951    tabWidget->setCurrentIndex(1);
[97e90f9be6]952#ifdef Q_WS_WIN32
[9eb63a1598]953    if (tl != NULL) {
954        tl->SetProgressState(winId(), TBPF_NOPROGRESS);
955        tl->Release();
956        tl = NULL;
957    }
[43c29c04ba]958#endif
959
[9eb63a1598]960    pd.reset();
961    QApplication::alert(this, 3000);
[1babbd6ba3]962}
963
964void MainWindow::dataChanged()
965{
[9eb63a1598]966    setWindowModified(true);
[1babbd6ba3]967}
968
969void MainWindow::dataChanged(const QModelIndex &tl, const QModelIndex &br)
970{
[9eb63a1598]971    setWindowModified(true);
972    if (settings->value("Autosize", DEF_AUTOSIZE).toBool()) {
973        for (int k = tl.row(); k <= br.row(); k++)
974            taskView->resizeRowToContents(k);
975        for (int k = tl.column(); k <= br.column(); k++)
976            taskView->resizeColumnToContents(k);
977    }
[1babbd6ba3]978}
979
[97e90f9be6]980#ifdef Q_WS_WINCE_WM
[1babbd6ba3]981void MainWindow::changeEvent(QEvent *ev)
982{
[9eb63a1598]983    if ((ev->type() == QEvent::ActivationChange) && isActiveWindow())
984        desktopResized(0);
[1babbd6ba3]985
[9eb63a1598]986    QWidget::changeEvent(ev);
[1babbd6ba3]987}
988
989void MainWindow::desktopResized(int screen)
990{
[9eb63a1598]991    if ((screen != 0) || !isActiveWindow())
992        return;
[1babbd6ba3]993
994QRect availableGeometry = QApplication::desktop()->availableGeometry(0);
[9eb63a1598]995    if (currentGeometry != availableGeometry) {
996        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
997        /*!
998         * \hack HACK: This hack checks whether \link QDesktopWidget::availableGeometry() availableGeometry()\endlink's \c top + \c hegiht = \link QDesktopWidget::screenGeometry() screenGeometry()\endlink's \c height.
999         *  If \c true, the window gets maximized. If we used \c setGeometry() in this case, the bottom of the
1000         *  window would end up being behind the soft buttons. Is this a bug in Qt or Windows Mobile?
1001         */
1002        if ((availableGeometry.top() + availableGeometry.height()) == QApplication::desktop()->screenGeometry().height()) {
1003            setWindowState(windowState() | Qt::WindowMaximized);
1004        } else {
1005            if (windowState() & Qt::WindowMaximized)
1006                setWindowState(windowState() ^ Qt::WindowMaximized);
1007            setGeometry(availableGeometry);
1008        }
1009        currentGeometry = availableGeometry;
1010        QApplication::restoreOverrideCursor();
1011    }
[1babbd6ba3]1012}
[97e90f9be6]1013#endif // Q_WS_WINCE_WM
[1babbd6ba3]1014
1015void MainWindow::numCitiesChanged(int nCities)
1016{
[9eb63a1598]1017    blockSignals(true);
1018    spinCities->setValue(nCities);
1019    blockSignals(false);
[1babbd6ba3]1020}
1021
1022#ifndef QT_NO_PRINTER
1023void MainWindow::printPreview(QPrinter *printer)
1024{
[9eb63a1598]1025    solutionText->print(printer);
[1babbd6ba3]1026}
1027#endif // QT_NO_PRINTER
1028
[97e90f9be6]1029#ifdef Q_WS_WIN32
[43c29c04ba]1030void MainWindow::solverRoutePartFound(int n)
1031{
[9eb63a1598]1032    tl->SetProgressValue(winId(), n, spinCities->value() * 2);
[43c29c04ba]1033}
[97e90f9be6]1034#endif // Q_WS_WIN32
[43c29c04ba]1035
[1babbd6ba3]1036void MainWindow::spinCitiesValueChanged(int n)
1037{
[9eb63a1598]1038    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[1babbd6ba3]1039int count = tspmodel->numCities();
[9eb63a1598]1040    tspmodel->setNumCities(n);
1041    if ((n > count) && settings->value("Autosize", DEF_AUTOSIZE).toBool())
1042        for (int k = count; k < n; k++) {
1043            taskView->resizeColumnToContents(k);
1044            taskView->resizeRowToContents(k);
1045        }
1046    QApplication::restoreOverrideCursor();
[1babbd6ba3]1047}
1048
[f5c945d7ac]1049void MainWindow::check4Updates(bool silent)
1050{
[97e90f9be6]1051#ifdef Q_WS_WIN32
[9eb63a1598]1052    if (silent)
1053        QProcess::startDetached("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\" -silentcheck");
1054    else {
1055        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1056        QProcess::execute("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\"");
1057        QApplication::restoreOverrideCursor();
1058    }
[0007f69c46]1059#else
[9eb63a1598]1060    Q_UNUSED(silent)
[f5c945d7ac]1061#endif
[9eb63a1598]1062    settings->setValue("Check4Updates/LastAttempt", QDate::currentDate().toString(Qt::ISODate));
[f5c945d7ac]1063}
1064
[1babbd6ba3]1065void MainWindow::closeEvent(QCloseEvent *ev)
1066{
[9eb63a1598]1067    if (!maybeSave()) {
1068        ev->ignore();
1069        return;
1070    }
1071    if (!settings->value("SettingsReset", false).toBool()) {
1072        settings->setValue("NumCities", spinCities->value());
1073
1074        // Saving Main Window state
[7bb19df196]1075#ifndef HANDHELD
[9eb63a1598]1076        if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
1077            settings->beginGroup("MainWindow");
1078            settings->setValue("Geometry", saveGeometry());
1079            settings->setValue("State", saveState());
1080            settings->setValue("Toolbars", toolBarManager->saveState());
1081            settings->endGroup();
1082        }
[a713b103e8]1083#else
[9eb63a1598]1084        settings->setValue("MainWindow/ToolbarVisible", toolBarMain->isVisible());
[7bb19df196]1085#endif // HANDHELD
[9eb63a1598]1086    } else {
1087        settings->remove("SettingsReset");
1088    }
[1babbd6ba3]1089
[9eb63a1598]1090    QMainWindow::closeEvent(ev);
[1babbd6ba3]1091}
1092
[b574c383b7]1093void MainWindow::dragEnterEvent(QDragEnterEvent *ev)
1094{
[9eb63a1598]1095    if (ev->mimeData()->hasUrls() && (ev->mimeData()->urls().count() == 1)) {
[b574c383b7]1096QFileInfo fi(ev->mimeData()->urls().first().toLocalFile());
[9eb63a1598]1097        if ((fi.suffix() == "tspt") || (fi.suffix() == "zkt"))
1098            ev->acceptProposedAction();
1099    }
[b574c383b7]1100}
1101
[345e7b6132]1102void MainWindow::drawNode(QPainter &pic, int nstep, bool left, SStep *step)
1103{
[e26679937d]1104int r;
[9eb63a1598]1105    if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool())
1106        r = 70;
1107    else
1108        r = 35;
[345e7b6132]1109qreal x, y;
[9eb63a1598]1110    if (step != NULL)
1111        x = left ? r : r * 3.5;
1112    else
1113        x = r * 2.25;
1114    y = r * (3 * nstep + 1);
[345e7b6132]1115
[3cadf24d00]1116#ifdef _T_T_L_
[9eb63a1598]1117    if (nstep == -481124) {
1118        _t_t_l_(pic, r, x);
1119        return;
1120    }
[3cadf24d00]1121#endif
1122
[9eb63a1598]1123    pic.drawEllipse(QPointF(x, y), r, r);
[345e7b6132]1124
[9eb63a1598]1125    if (step != NULL) {
[345e7b6132]1126QFont font;
[9eb63a1598]1127        if (left) {
1128            font = pic.font();
1129            font.setStrikeOut(true);
1130            pic.setFont(font);
1131        }
1132        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");
1133        if (left) {
1134            font.setStrikeOut(false);
1135            pic.setFont(font);
1136        }
1137        if (step->price != INFINITY) {
1138            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()));
1139        } else {
1140            pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, "\n"INFSTR);
1141        }
1142    } else {
1143        pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, tr("Root"));
1144    }
1145
1146    if (nstep == 1) {
1147        pic.drawLine(QPointF(x, y - r), QPointF(r * 2.25, y - 2 * r));
1148    } else if (nstep > 1) {
1149        pic.drawLine(QPointF(x, y - r), QPointF((step->pNode->pNode->next == SStep::RightBranch) ? r * 3.5 : r, y - 2 * r));
1150    }
[345e7b6132]1151
1152}
1153
[b574c383b7]1154void MainWindow::dropEvent(QDropEvent *ev)
1155{
[9eb63a1598]1156    if (maybeSave() && tspmodel->loadTask(ev->mimeData()->urls().first().toLocalFile())) {
1157        setFileName(ev->mimeData()->urls().first().toLocalFile());
1158        tabWidget->setCurrentIndex(0);
1159        setWindowModified(false);
1160        solutionText->clear();
1161        toggleSolutionActions(false);
1162
1163        ev->setDropAction(Qt::CopyAction);
1164        ev->accept();
1165    }
[b574c383b7]1166}
1167
[1babbd6ba3]1168void MainWindow::initDocStyleSheet()
1169{
[9eb63a1598]1170    solutionText->document()->setDefaultFont(qvariant_cast<QFont>(settings->value("Output/Font", QFont(DEF_FONT_FACE, DEF_FONT_SIZE))));
[317ba0432e]1171
[9eb63a1598]1172    fmt_paragraph.setTopMargin(0);
1173    fmt_paragraph.setRightMargin(10);
1174    fmt_paragraph.setBottomMargin(0);
1175    fmt_paragraph.setLeftMargin(10);
[317ba0432e]1176
[9eb63a1598]1177    fmt_table.setTopMargin(5);
1178    fmt_table.setRightMargin(10);
1179    fmt_table.setBottomMargin(5);
1180    fmt_table.setLeftMargin(10);
1181    fmt_table.setBorder(0);
1182    fmt_table.setBorderStyle(QTextFrameFormat::BorderStyle_None);
1183    fmt_table.setCellSpacing(5);
[317ba0432e]1184
[9eb63a1598]1185    fmt_cell.setAlignment(Qt::AlignHCenter);
[317ba0432e]1186
[9eb63a1598]1187    settings->beginGroup("Output/Colors");
[8b0661d1ee]1188
[a713b103e8]1189QColor color = qvariant_cast<QColor>(settings->value("Text", DEF_TEXT_COLOR));
[1babbd6ba3]1190QColor hilight;
[9eb63a1598]1191    if (color.value() < 192)
1192        hilight.setHsv(color.hue(), color.saturation(), 127 + qRound(color.value() / 2));
1193    else
1194        hilight.setHsv(color.hue(), color.saturation(), color.value() / 2);
[317ba0432e]1195
[9eb63a1598]1196    solutionText->document()->setDefaultStyleSheet(QString("* {color: %1;}").arg(color.name()));
1197    fmt_default.setForeground(QBrush(color));
[317ba0432e]1198
[9eb63a1598]1199    fmt_selected.setForeground(QBrush(qvariant_cast<QColor>(settings->value("Selected", DEF_SELECTED_COLOR))));
1200    fmt_selected.setFontWeight(QFont::Bold);
[317ba0432e]1201
[9eb63a1598]1202    fmt_alternate.setForeground(QBrush(qvariant_cast<QColor>(settings->value("Alternate", DEF_ALTERNATE_COLOR))));
1203    fmt_alternate.setFontWeight(QFont::Bold);
1204    fmt_altlist.setForeground(QBrush(hilight));
[317ba0432e]1205
[9eb63a1598]1206    settings->endGroup();
[8b0661d1ee]1207
[9eb63a1598]1208    solutionText->setTextColor(color);
[1babbd6ba3]1209}
1210
1211void MainWindow::loadLangList()
1212{
[3cadf24d00]1213QMap<QString, QStringList> langlist;
1214QFileInfoList langs;
1215QFileInfo lang;
1216QStringList language, dirs;
1217QTranslator t;
1218QDir dir;
[9eb63a1598]1219    dir.setFilter(QDir::Files);
1220    dir.setNameFilters(QStringList("tspsg_*.qm"));
1221    dir.setSorting(QDir::NoSort);
1222
1223    dirs << PATH_L10N << ":/l10n";
1224    foreach (QString dirname, dirs) {
1225        dir.setPath(dirname);
1226        if (dir.exists()) {
1227            langs = dir.entryInfoList();
1228            for (int k = 0; k < langs.size(); k++) {
1229                lang = langs.at(k);
1230                if (lang.completeBaseName().compare("tspsg_en", Qt::CaseInsensitive) && !langlist.contains(lang.completeBaseName().mid(6)) && t.load(lang.completeBaseName(), dirname)) {
1231
1232                    language.clear();
1233                    language.append(lang.completeBaseName().mid(6));
1234                    language.append(t.translate("--------", "COUNTRY", "Please, provide an ISO 3166-1 alpha-2 country code for this translation language here (eg., UA).").toLower());
1235                    language.append(t.translate("--------", "LANGNAME", "Please, provide a native name of your translation language here."));
1236                    language.append(t.translate("MainWindow", "Set application language to %1", "").arg(language.at(2)));
1237
1238                    langlist.insert(language.at(0), language);
1239                }
1240            }
1241        }
1242    }
[3cadf24d00]1243
1244QAction *a;
[9eb63a1598]1245    foreach (language, langlist) {
1246        a = menuSettingsLanguage->addAction(language.at(2));
[9adbc413c7]1247#ifndef QT_NO_STATUSTIP
[9eb63a1598]1248        a->setStatusTip(language.at(3));
[9adbc413c7]1249#endif
[2a436ea693]1250#if QT_VERSION >= 0x040600
[9eb63a1598]1251        a->setIcon(QIcon::fromTheme(QString("flag-%1").arg(language.at(1)), QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1)))));
[2a436ea693]1252#else
[9eb63a1598]1253        a->setIcon(QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1))));
[2a436ea693]1254#endif
[9eb63a1598]1255        a->setData(language.at(0));
1256        a->setCheckable(true);
1257        a->setActionGroup(groupSettingsLanguageList);
1258        if (settings->value("Language", QLocale::system().name()).toString().startsWith(language.at(0)))
1259            a->setChecked(true);
1260    }
[1babbd6ba3]1261}
1262
1263bool MainWindow::loadLanguage(const QString &lang)
1264{
1265// i18n
1266bool ad = false;
1267QString lng = lang;
[9eb63a1598]1268    if (lng.isEmpty()) {
1269        ad = settings->value("Language").toString().isEmpty();
1270        lng = settings->value("Language", QLocale::system().name()).toString();
1271    }
[1babbd6ba3]1272static QTranslator *qtTranslator; // Qt library translator
[9eb63a1598]1273    if (qtTranslator) {
1274        qApp->removeTranslator(qtTranslator);
1275        delete qtTranslator;
1276        qtTranslator = NULL;
1277    }
[1babbd6ba3]1278static QTranslator *translator; // Application translator
[9eb63a1598]1279    if (translator) {
1280        qApp->removeTranslator(translator);
1281        delete translator;
1282        translator = NULL;
1283    }
1284
1285    if (lng == "en")
1286        return true;
1287
1288    // Trying to load system Qt library translation...
1289    qtTranslator = new QTranslator(this);
1290    if (qtTranslator->load("qt_" + lng, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
1291        qApp->installTranslator(qtTranslator);
1292    else {
1293        // No luck. Let's try to load a bundled one.
1294        if (qtTranslator->load("qt_" + lng, PATH_L10N)) {
1295            // We have a translation in the localization direcotry.
1296            qApp->installTranslator(qtTranslator);
1297        } else if (qtTranslator->load("qt_" + lng, ":/l10n")) {
1298            // We have a translation "built-in" into application resources.
1299            qApp->installTranslator(qtTranslator);
1300        } else {
1301            // Qt library translation unavailable for this language.
1302            delete qtTranslator;
1303            qtTranslator = NULL;
1304        }
1305    }
1306
1307    // Now let's load application translation.
1308    translator = new QTranslator(this);
1309    if (translator->load("tspsg_" + lng, PATH_L10N)) {
1310        // We have a translation in the localization directory.
1311        qApp->installTranslator(translator);
1312    } else if (translator->load("tspsg_" + lng, ":/l10n")) {
1313        // We have a translation "built-in" into application resources.
1314        qApp->installTranslator(translator);
1315    } else {
1316        delete translator;
1317        translator = NULL;
1318        if (!ad) {
1319            settings->remove("Language");
1320            QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
1321            QMessageBox::warning(isVisible() ? this : NULL, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
1322            QApplication::restoreOverrideCursor();
1323        }
1324        return false;
1325    }
1326    return true;
[1babbd6ba3]1327}
1328
[e3533af1cf]1329void MainWindow::loadStyleList()
1330{
[9eb63a1598]1331    menuSettingsStyle->clear();
[e3533af1cf]1332QStringList styles = QStyleFactory::keys();
[9eb63a1598]1333    menuSettingsStyle->insertAction(NULL, actionSettingsStyleSystem);
1334    actionSettingsStyleSystem->setChecked(!settings->contains("Style"));
1335    menuSettingsStyle->addSeparator();
[e3533af1cf]1336QAction *a;
[9eb63a1598]1337    foreach (QString style, styles) {
1338        a = menuSettingsStyle->addAction(style);
1339        a->setData(false);
[9adbc413c7]1340#ifndef QT_NO_STATUSTIP
[9eb63a1598]1341        a->setStatusTip(tr("Set application style to %1").arg(style));
[9adbc413c7]1342#endif
[9eb63a1598]1343        a->setCheckable(true);
1344        a->setActionGroup(groupSettingsStyleList);
1345        if ((style == settings->value("Stlye").toString())
[97e90f9be6]1346#ifndef Q_WS_MAEMO_5
[9eb63a1598]1347            || QString(QApplication::style()->metaObject()->className()).contains(QRegExp(QString("^Q?%1(Style)?$").arg(QRegExp::escape(style)), Qt::CaseInsensitive))
[97e90f9be6]1348#endif
[9eb63a1598]1349        ) {
1350            a->setChecked(true);
1351        }
1352    }
[e3533af1cf]1353}
1354
[7bb19df196]1355void MainWindow::loadToolbarList()
1356{
[9eb63a1598]1357    menuSettingsToolbars->clear();
[7bb19df196]1358#ifndef HANDHELD
[9eb63a1598]1359    menuSettingsToolbars->insertAction(NULL, actionSettingsToolbarsConfigure);
1360    menuSettingsToolbars->addSeparator();
[7bb19df196]1361QList<QToolBar *> list = toolBarManager->toolBars();
[9eb63a1598]1362    foreach (QToolBar *t, list) {
1363        menuSettingsToolbars->insertAction(NULL, t->toggleViewAction());
1364    }
[7bb19df196]1365#else // HANDHELD
[9eb63a1598]1366    menuSettingsToolbars->insertAction(NULL, toolBarMain->toggleViewAction());
[7bb19df196]1367#endif // HANDHELD
1368}
1369
[1babbd6ba3]1370bool MainWindow::maybeSave()
1371{
[9eb63a1598]1372    if (!isWindowModified())
1373        return true;
[1babbd6ba3]1374int res = QMessageBox::warning(this, tr("Unsaved Changes"), tr("Would you like to save changes in the current task?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
[9eb63a1598]1375    if (res == QMessageBox::Save)
1376        return actionFileSaveTriggered();
1377    else if (res == QMessageBox::Cancel)
1378        return false;
1379    else
1380        return true;
[1babbd6ba3]1381}
1382
[317ba0432e]1383void MainWindow::outputMatrix(QTextCursor &cur, const TMatrix &matrix)
[1babbd6ba3]1384{
1385int n = spinCities->value();
[317ba0432e]1386QTextTable *table = cur.insertTable(n, n, fmt_table);
1387
[9eb63a1598]1388    for (int r = 0; r < n; r++) {
1389        for (int c = 0; c < n; c++) {
1390            cur = table->cellAt(r, c).firstCursorPosition();
1391            cur.setBlockFormat(fmt_cell);
1392            cur.setBlockCharFormat(fmt_default);
1393            if (matrix.at(r).at(c) == INFINITY)
1394                cur.insertText(INFSTR);
1395            else
1396                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()));
1397        }
1398        QCoreApplication::processEvents();
1399    }
1400    cur.movePosition(QTextCursor::End);
[1babbd6ba3]1401}
1402
[317ba0432e]1403void MainWindow::outputMatrix(QTextCursor &cur, const SStep &step)
[1babbd6ba3]1404{
1405int n = spinCities->value();
[317ba0432e]1406QTextTable *table = cur.insertTable(n, n, fmt_table);
1407
[9eb63a1598]1408    for (int r = 0; r < n; r++) {
1409        for (int c = 0; c < n; c++) {
1410            cur = table->cellAt(r, c).firstCursorPosition();
1411            cur.setBlockFormat(fmt_cell);
1412            if (step.matrix.at(r).at(c) == INFINITY)
1413                cur.insertText(INFSTR, fmt_default);
1414            else if ((r == step.candidate.nRow) && (c == step.candidate.nCol))
1415                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);
1416            else {
[9cda6e0f5d]1417SStep::SCandidate cand;
[9eb63a1598]1418                cand.nRow = r;
1419                cand.nCol = c;
1420                if (step.alts.contains(cand))
1421                    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);
1422                else
1423                    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);
1424            }
1425        }
1426        QCoreApplication::processEvents();
1427    }
1428
1429    cur.movePosition(QTextCursor::End);
[1babbd6ba3]1430}
1431
1432void MainWindow::retranslateUi(bool all)
1433{
[9eb63a1598]1434    if (all)
1435        Ui_MainWindow::retranslateUi(this);
[1babbd6ba3]1436
[9eb63a1598]1437    loadStyleList();
1438    loadToolbarList();
[e3533af1cf]1439
[1babbd6ba3]1440#ifndef QT_NO_PRINTER
[9eb63a1598]1441    actionFilePrintPreview->setText(tr("P&rint Preview..."));
[1babbd6ba3]1442#ifndef QT_NO_TOOLTIP
[9eb63a1598]1443    actionFilePrintPreview->setToolTip(tr("Preview solution results"));
[1babbd6ba3]1444#endif // QT_NO_TOOLTIP
1445#ifndef QT_NO_STATUSTIP
[9eb63a1598]1446    actionFilePrintPreview->setStatusTip(tr("Preview current solution results before printing"));
1447    actionFileExit->setStatusTip(tr("Exit %1").arg(QCoreApplication::applicationName()));
[88a59e4d65]1448#endif // QT_NO_STATUSTIP
[1babbd6ba3]1449
[9eb63a1598]1450    actionFilePrint->setText(tr("&Print..."));
[1babbd6ba3]1451#ifndef QT_NO_TOOLTIP
[9eb63a1598]1452    actionFilePrint->setToolTip(tr("Print solution"));
[1babbd6ba3]1453#endif // QT_NO_TOOLTIP
1454#ifndef QT_NO_STATUSTIP
[9eb63a1598]1455    actionFilePrint->setStatusTip(tr("Print current solution results"));
[1babbd6ba3]1456#endif // QT_NO_STATUSTIP
[9eb63a1598]1457    actionFilePrint->setShortcut(tr("Ctrl+P"));
[1babbd6ba3]1458#endif // QT_NO_PRINTER
[8b0661d1ee]1459
1460#ifndef HANDHELD
[9eb63a1598]1461    actionSettingsToolbarsConfigure->setText(tr("Configure..."));
[8b0661d1ee]1462#ifndef QT_NO_STATUSTIP
[9eb63a1598]1463    actionSettingsToolbarsConfigure->setStatusTip(tr("Customize toolbars"));
[8b0661d1ee]1464#endif // QT_NO_STATUSTIP
1465#endif // HANDHELD
1466
[88a59e4d65]1467#ifndef QT_NO_STATUSTIP
[9eb63a1598]1468    actionHelpReportBug->setStatusTip(tr("Report about a bug in %1").arg(QCoreApplication::applicationName()));
[88a59e4d65]1469#endif // QT_NO_STATUSTIP
[9eb63a1598]1470    if (actionHelpCheck4Updates != NULL) {
1471        actionHelpCheck4Updates->setText(tr("Check for &Updates..."));
[1babbd6ba3]1472#ifndef QT_NO_STATUSTIP
[9eb63a1598]1473        actionHelpCheck4Updates->setStatusTip(tr("Check for %1 updates").arg(QCoreApplication::applicationName()));
[1babbd6ba3]1474#endif // QT_NO_STATUSTIP
[9eb63a1598]1475    }
[88a59e4d65]1476#ifndef QT_NO_STATUSTIP
[9eb63a1598]1477    actionHelpAbout->setStatusTip(tr("About %1").arg(QCoreApplication::applicationName()));
[88a59e4d65]1478#endif // QT_NO_STATUSTIP
[1babbd6ba3]1479}
1480
1481bool MainWindow::saveTask() {
1482QStringList filters(tr("%1 Task File").arg("TSPSG") + " (*.tspt)");
[9eb63a1598]1483    filters.append(tr("All Files") + " (*)");
[1babbd6ba3]1484QString file;
[9eb63a1598]1485    if ((fileName == tr("Untitled") + ".tspt") && settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool()) {
1486        file = settings->value(OS"/LastUsed/TaskSavePath").toString();
1487        if (!file.isEmpty())
1488            file.append("/");
1489        file.append(fileName);
1490    } else if (fileName.endsWith(".tspt", Qt::CaseInsensitive))
1491        file = fileName;
1492    else
1493        file = QFileInfo(fileName).path() + "/" + QFileInfo(fileName).completeBaseName() + ".tspt";
[1babbd6ba3]1494
1495QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
[9eb63a1598]1496    file = QFileDialog::getSaveFileName(this, tr("Task Save"), file, filters.join(";;"), NULL, opts);
1497    if (file.isEmpty())
1498        return false;
1499    else if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
1500        settings->setValue(OS"/LastUsed/TaskSavePath", QFileInfo(file).path());
1501
1502    if (tspmodel->saveTask(file)) {
1503        setFileName(file);
1504        setWindowModified(false);
1505        return true;
1506    }
1507    return false;
[1babbd6ba3]1508}
1509
1510void MainWindow::setFileName(const QString &fileName)
1511{
[9eb63a1598]1512    this->fileName = fileName;
1513    setWindowTitle(QString("%1[*] - %2").arg(QFileInfo(fileName).completeBaseName()).arg(QCoreApplication::applicationName()));
[1babbd6ba3]1514}
1515
1516void MainWindow::setupUi()
1517{
[9eb63a1598]1518    Ui_MainWindow::setupUi(this);
[1babbd6ba3]1519
[9eb63a1598]1520    // File Menu
1521    actionFileNew->setIcon(GET_ICON("document-new"));
1522    actionFileOpen->setIcon(GET_ICON("document-open"));
1523    actionFileSave->setIcon(GET_ICON("document-save"));
[a713b103e8]1524#ifndef HANDHELD
[9eb63a1598]1525    menuFileSaveAs->setIcon(GET_ICON("document-save-as"));
[a713b103e8]1526#endif
[9eb63a1598]1527    actionFileExit->setIcon(GET_ICON("application-exit"));
1528    // Settings Menu
[a713b103e8]1529#ifndef HANDHELD
[9eb63a1598]1530    menuSettingsLanguage->setIcon(GET_ICON("preferences-desktop-locale"));
[a713b103e8]1531#if QT_VERSION >= 0x040600
[9eb63a1598]1532    actionSettingsLanguageEnglish->setIcon(QIcon::fromTheme("flag-gb", QIcon(":/images/icons/l10n/flag-gb.png")));
[a713b103e8]1533#else // QT_VERSION >= 0x040600
[9eb63a1598]1534    actionSettingsLanguageEnglish->setIcon(QIcon(":/images/icons/l10n/flag-gb.png"));
[a713b103e8]1535#endif // QT_VERSION >= 0x040600
[9eb63a1598]1536    menuSettingsStyle->setIcon(GET_ICON("preferences-desktop-theme"));
[a713b103e8]1537#endif // HANDHELD
[9eb63a1598]1538    actionSettingsPreferences->setIcon(GET_ICON("preferences-system"));
1539    // Help Menu
[a713b103e8]1540#ifndef HANDHELD
[9eb63a1598]1541    actionHelpContents->setIcon(GET_ICON("help-contents"));
1542    actionHelpContextual->setIcon(GET_ICON("help-contextual"));
1543    actionHelpOnlineSupport->setIcon(GET_ICON("applications-internet"));
1544    actionHelpReportBug->setIcon(GET_ICON("tools-report-bug"));
1545    actionHelpAbout->setIcon(GET_ICON("help-about"));
1546    actionHelpAboutQt->setIcon(QIcon(":/images/icons/"ICON_SIZE"/qtlogo."ICON_FORMAT));
[a713b103e8]1547#endif
[9eb63a1598]1548    // Buttons
1549    buttonRandom->setIcon(GET_ICON("roll"));
1550    buttonSolve->setIcon(GET_ICON("dialog-ok"));
1551    buttonSaveSolution->setIcon(GET_ICON("document-save-as"));
1552    buttonBackToTask->setIcon(GET_ICON("go-previous"));
[3cadf24d00]1553
[2a436ea693]1554//      action->setIcon(GET_ICON(""));
[3cadf24d00]1555
[1babbd6ba3]1556#if QT_VERSION >= 0x040600
[9eb63a1598]1557    setToolButtonStyle(Qt::ToolButtonFollowStyle);
[1babbd6ba3]1558#endif
1559
1560#ifndef HANDHELD
1561QStatusBar *statusbar = new QStatusBar(this);
[9eb63a1598]1562    statusbar->setObjectName("statusbar");
1563    setStatusBar(statusbar);
[1babbd6ba3]1564#endif // HANDHELD
1565
[97e90f9be6]1566#ifdef Q_WS_WINCE_WM
[9eb63a1598]1567    menuBar()->setDefaultAction(menuFile->menuAction());
[1babbd6ba3]1568
1569QScrollArea *scrollArea = new QScrollArea(this);
[9eb63a1598]1570    scrollArea->setFrameShape(QFrame::NoFrame);
1571    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1572    scrollArea->setWidgetResizable(true);
1573    scrollArea->setWidget(tabWidget);
1574    setCentralWidget(scrollArea);
[1babbd6ba3]1575#else
[9eb63a1598]1576    setCentralWidget(tabWidget);
[97e90f9be6]1577#endif // Q_WS_WINCE_WM
[1babbd6ba3]1578
[9eb63a1598]1579    //! \hack HACK: A little hack for toolbar icons to have a sane size.
[97e90f9be6]1580#if defined(HANDHELD) && !defined(Q_WS_MAEMO_5)
[9eb63a1598]1581    toolBarMain->setIconSize(QSize(logicalDpiX() / 4, logicalDpiY() / 4));
[e51c78af27]1582#endif // HANDHELD
[7bb19df196]1583QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
[9eb63a1598]1584    if (tb != NULL)      {
1585        tb->setMenu(menuFileSaveAs);
1586        tb->setPopupMode(QToolButton::MenuButtonPopup);
1587    }
[1babbd6ba3]1588
[8b0661d1ee]1589//      solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, DEF_FONT_SIZE)).value<QFont>());
[9eb63a1598]1590    solutionText->setWordWrapMode(QTextOption::WordWrap);
[1babbd6ba3]1591
1592#ifndef QT_NO_PRINTER
[9eb63a1598]1593    actionFilePrintPreview = new QAction(this);
1594    actionFilePrintPreview->setObjectName("actionFilePrintPreview");
1595    actionFilePrintPreview->setEnabled(false);
1596    actionFilePrintPreview->setIcon(GET_ICON("document-print-preview"));
[1babbd6ba3]1597
[9eb63a1598]1598    actionFilePrint = new QAction(this);
1599    actionFilePrint->setObjectName("actionFilePrint");
1600    actionFilePrint->setEnabled(false);
1601    actionFilePrint->setIcon(GET_ICON("document-print"));
[1babbd6ba3]1602
[9eb63a1598]1603    menuFile->insertAction(actionFileExit,actionFilePrintPreview);
1604    menuFile->insertAction(actionFileExit,actionFilePrint);
1605    menuFile->insertSeparator(actionFileExit);
[1babbd6ba3]1606
[9eb63a1598]1607    toolBarMain->insertAction(actionSettingsPreferences, actionFilePrint);
[1babbd6ba3]1608#endif // QT_NO_PRINTER
[e51c78af27]1609
[9eb63a1598]1610    groupSettingsLanguageList = new QActionGroup(this);
[97e90f9be6]1611#ifdef Q_WS_MAEMO_5
[9eb63a1598]1612    groupSettingsLanguageList->addAction(actionSettingsLanguageAutodetect);
[97e90f9be6]1613#endif
[9eb63a1598]1614    actionSettingsLanguageEnglish->setData("en");
1615    actionSettingsLanguageEnglish->setActionGroup(groupSettingsLanguageList);
1616    loadLangList();
1617    actionSettingsLanguageAutodetect->setChecked(settings->value("Language", "").toString().isEmpty());
[e3533af1cf]1618
[9eb63a1598]1619    actionSettingsStyleSystem->setData(true);
1620    groupSettingsStyleList = new QActionGroup(this);
[97e90f9be6]1621#ifdef Q_WS_MAEMO_5
[9eb63a1598]1622    groupSettingsStyleList->addAction(actionSettingsStyleSystem);
[97e90f9be6]1623#endif
[e3533af1cf]1624
[7bb19df196]1625#ifndef HANDHELD
[9eb63a1598]1626    actionSettingsToolbarsConfigure = new QAction(this);
1627    actionSettingsToolbarsConfigure->setIcon(GET_ICON("configure-toolbars"));
[7bb19df196]1628#endif // HANDHELD
1629
[9eb63a1598]1630    if (hasUpdater()) {
1631        actionHelpCheck4Updates = new QAction(this);
1632        actionHelpCheck4Updates->setIcon(GET_ICON("system-software-update"));
1633        actionHelpCheck4Updates->setEnabled(hasUpdater());
1634        menuHelp->insertAction(actionHelpAboutQt, actionHelpCheck4Updates);
1635        menuHelp->insertSeparator(actionHelpAboutQt);
1636    } else
1637        actionHelpCheck4Updates = NULL;
[1babbd6ba3]1638
[9eb63a1598]1639    spinCities->setMaximum(MAX_NUM_CITIES);
[1babbd6ba3]1640
[94cd045fad]1641#ifndef HANDHELD
[9eb63a1598]1642    toolBarManager = new QtToolBarManager;
1643    toolBarManager->setMainWindow(this);
[7bb19df196]1644QString cat = toolBarMain->windowTitle();
[9eb63a1598]1645    toolBarManager->addToolBar(toolBarMain, cat);
[94cd045fad]1646#ifndef QT_NO_PRINTER
[9eb63a1598]1647    toolBarManager->addAction(actionFilePrintPreview, cat);
[94cd045fad]1648#endif // QT_NO_PRINTER
[9eb63a1598]1649    toolBarManager->addAction(actionHelpContents, cat);
1650    toolBarManager->addAction(actionHelpContextual, cat);
[94cd045fad]1651//      toolBarManager->addAction(action, cat);
[9eb63a1598]1652    toolBarManager->restoreState(settings->value("MainWindow/Toolbars").toByteArray());
[a713b103e8]1653#else
[9eb63a1598]1654    toolBarMain->setVisible(settings->value("MainWindow/ToolbarVisible", true).toBool());
[94cd045fad]1655#endif // HANDHELD
[7bb19df196]1656
[9eb63a1598]1657    retranslateUi(false);
[7bb19df196]1658
[b8a2a118c4]1659#ifndef HANDHELD
1660    // Adding some eyecandy
[9eb63a1598]1661    if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
1662        toggleTranclucency(true);
1663    }
[b8a2a118c4]1664#endif // HANDHELD
[1babbd6ba3]1665}
1666
1667void MainWindow::toggleSolutionActions(bool enable)
1668{
[9eb63a1598]1669    buttonSaveSolution->setEnabled(enable);
1670    actionFileSaveAsSolution->setEnabled(enable);
1671    solutionText->setEnabled(enable);
[1babbd6ba3]1672#ifndef QT_NO_PRINTER
[9eb63a1598]1673    actionFilePrint->setEnabled(enable);
1674    actionFilePrintPreview->setEnabled(enable);
[1babbd6ba3]1675#endif // QT_NO_PRINTER
1676}
1677
1678void MainWindow::toggleTranclucency(bool enable)
1679{
[b8a2a118c4]1680#ifndef HANDHELD
[9eb63a1598]1681    toggleStyle(labelVariant, enable);
1682    toggleStyle(labelCities, enable);
1683    toggleStyle(statusBar(), enable);
1684    tabWidget->setDocumentMode(enable);
1685    QtWin::enableBlurBehindWindow(this, enable);
[1babbd6ba3]1686#else
[9eb63a1598]1687    Q_UNUSED(enable);
[b8a2a118c4]1688#endif // HANDHELD
[1babbd6ba3]1689}
[88a59e4d65]1690
1691void MainWindow::actionHelpOnlineSupportTriggered()
1692{
[9eb63a1598]1693    QDesktopServices::openUrl(QUrl("http://tspsg.info/goto/support"));
[88a59e4d65]1694}
1695
1696void MainWindow::actionHelpReportBugTriggered()
1697{
[9eb63a1598]1698    QDesktopServices::openUrl(QUrl("http://tspsg.info/goto/bugtracker"));
[88a59e4d65]1699}
Note: See TracBrowser for help on using the repository browser.