source: tspsg/src/mainwindow.cpp @ ccdffe3a5f

0.1.4.170-beta2-bb10
Last change on this file since ccdffe3a5f was ccdffe3a5f, checked in by Oleksii Serdiuk, 11 years ago

Removed printing related items from menu as there's no printer.

Made dialogs to be shown maximized.

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