source: tspsg/src/mainwindow.cpp @ c8ed26ddf1

appveyorimgbotreadme
Last change on this file since c8ed26ddf1 was c8ed26ddf1, checked in by Oleksii Serdiuk, 12 years ago

Implemented color selection from Settings Dialog.

Changing background color appeared to be much harder than expected, so
this feature was removed for now. It is possible to change background
color of the solution output area. However, this background change
doesn't affect printing and export - there background color always stays
white. Will investigate possible workarounds later...

Closes ticket:13 - All colors should be configurable through Settings Dialog

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