source: tspsg/src/mainwindow.cpp @ aa64ad4082

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

Added proxy style and stylesheet to fix some UI issues on BlackBerry?.

Also, removed style selection option because most styles have UI issues
and removed About Qt menu item because About Qt dialog is too big.

  • Property mode set to 100644
File size: 71.2 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_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
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_PRINTER
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_PRINTER
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#endif
696    QApplication::restoreOverrideCursor();
697
698    dlg->exec();
699
700    delete dlg;
701}
702
703void MainWindow::buttonBackToTaskClicked()
704{
705    tabWidget->setCurrentIndex(0);
706}
707
708void MainWindow::buttonRandomClicked()
709{
710    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
711    tspmodel->randomize();
712    QApplication::restoreOverrideCursor();
713}
714
715void MainWindow::buttonSolveClicked()
716{
717TMatrix matrix;
718QList<double> row;
719int n = spinCities->value();
720bool ok;
721    for (int r = 0; r < n; r++) {
722        row.clear();
723        for (int c = 0; c < n; c++) {
724            row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok));
725            if (!ok) {
726                QMessageBox::critical(this, tr("Data error"), tr("Error in cell [Row %1; Column %2]: Invalid data format.").arg(r + 1).arg(c + 1));
727                return;
728            }
729        }
730        matrix.append(row);
731    }
732
733QProgressDialog pd(this);
734QProgressBar *pb = new QProgressBar(&pd);
735    pb->setAlignment(Qt::AlignCenter);
736    pb->setFormat(tr("%v of %1 parts found").arg(n));
737    pd.setBar(pb);
738QPushButton *cancel = new QPushButton(&pd);
739    cancel->setIcon(GET_ICON("dialog-cancel"));
740    cancel->setText(QCoreApplication::translate("QDialogButtonBox", "Cancel", "No need to translate this. The translation will be taken from Qt translation files."));
741    pd.setCancelButton(cancel);
742    pd.setMaximum(n);
743    pd.setAutoReset(false);
744    pd.setLabelText(tr("Calculating optimal route..."));
745    pd.setWindowTitle(tr("Solution Progress"));
746    pd.setWindowModality(Qt::ApplicationModal);
747    pd.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
748    pd.show();
749
750#ifdef Q_WS_WIN32
751HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID*)&tl);
752    if (SUCCEEDED(hr)) {
753        hr = tl->HrInit();
754        if (FAILED(hr)) {
755            tl->Release();
756            tl = NULL;
757        } else {
758            tl->SetProgressValue(winId(), 0, n * 2);
759        }
760    }
761#endif
762
763CTSPSolver solver;
764    solver.setCleanupOnCancel(false);
765    connect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
766    connect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
767#ifdef Q_WS_WIN32
768    if (tl != NULL)
769        connect(&solver, SIGNAL(routePartFound(int)), SLOT(solverRoutePartFound(int)));
770#endif
771SStep *root = solver.solve(n, matrix);
772#ifdef Q_WS_WIN32
773    if (tl != NULL)
774        disconnect(&solver, SIGNAL(routePartFound(int)), this, SLOT(solverRoutePartFound(int)));
775#endif
776    disconnect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
777    disconnect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
778    if (!root) {
779        pd.reset();
780        if (!solver.wasCanceled()) {
781#ifdef Q_WS_WIN32
782            if (tl != NULL) {
783                tl->SetProgressState(winId(), TBPF_ERROR);
784            }
785#endif
786            QApplication::alert(this);
787            QMessageBox::warning(this, tr("Solution Result"), tr("Unable to find a solution.\nMaybe, this task has no solution."));
788        }
789        pd.setLabelText(tr("Memory cleanup..."));
790        pd.setMaximum(0);
791        pd.setCancelButton(NULL);
792        pd.show();
793#ifdef Q_WS_WIN32
794        if (tl != NULL)
795            tl->SetProgressState(winId(), TBPF_INDETERMINATE);
796#endif
797        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
798
799#ifndef QT_NO_CONCURRENT
800QFuture<void> f = QtConcurrent::run(&solver, &CTSPSolver::cleanup, false);
801        while (!f.isFinished()) {
802            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
803        }
804#else
805        solver.cleanup(true);
806#endif
807        pd.reset();
808#ifdef Q_WS_WIN32
809        if (tl != NULL) {
810            tl->SetProgressState(winId(), TBPF_NOPROGRESS);
811            tl->Release();
812            tl = NULL;
813        }
814#endif
815        return;
816    }
817    pb->setFormat(tr("Generating header"));
818    pd.setLabelText(tr("Generating solution output..."));
819    pd.setMaximum(solver.getTotalSteps() + 1);
820    pd.setValue(0);
821
822#ifdef Q_WS_WIN32
823    if (tl != NULL)
824        tl->SetProgressValue(winId(), spinCities->value(), spinCities->value() + solver.getTotalSteps() + 1);
825#endif
826
827    solutionText->clear();
828    solutionText->setDocumentTitle(tr("Solution of Variant #%1 Task").arg(spinVariant->value()));
829
830QPainter pic;
831bool dograph = settings->value("Output/GenerateGraph", DEF_GENERATE_GRAPH).toBool();
832    if (dograph) {
833        pic.begin(&graph);
834        pic.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
835QFont font = qvariant_cast<QFont>(settings->value("Output/Font", QFont(DEF_FONT_FACE)));
836        font.setStyleHint(QFont::TypeWriter);
837        // Font size in pixels = graph node radius / 2.75.
838        // See MainWindow::drawNode() for graph node radius calcualtion description.
839#ifndef Q_WS_S60
840        font.setPixelSize(logicalDpiX() * (settings->value("Output/GraphWidth", DEF_GRAPH_WIDTH).toReal() / CM_IN_INCH) / 4.5 / 2.75);
841#else
842        // Also, see again MainWindow::drawNode() for why is additional 1.3 divider added in Symbian.
843        font.setPixelSize(logicalDpiX() * (settings->value("Output/GraphWidth", DEF_GRAPH_WIDTH).toReal() / CM_IN_INCH) / 4.5 / 2.75 / 1.3);
844#endif
845        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
846            font.setWeight(QFont::DemiBold);
847            font.setPixelSize(font.pixelSize() * HQ_FACTOR);
848        }
849        pic.setFont(font);
850        pic.setBrush(QBrush(QColor(Qt::white)));
851        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
852QPen pen = pic.pen();
853            pen.setWidth(HQ_FACTOR);
854            pic.setPen(pen);
855        }
856        pic.setBackgroundMode(Qt::OpaqueMode);
857    } else {
858        graph = QPicture();
859    }
860
861QTextDocument *doc = solutionText->document();
862QTextCursor cur(doc);
863
864    cur.beginEditBlock();
865    cur.setBlockFormat(fmt_paragraph);
866    cur.insertText(tr("Variant #%1 Task").arg(spinVariant->value()), fmt_default);
867    cur.insertBlock(fmt_paragraph);
868    cur.insertText(tr("Task:"), fmt_default);
869    outputMatrix(cur, matrix);
870    if (dograph) {
871#ifdef _T_T_L_
872        _b_ _i_ _z_ _a_ _r_ _r_ _e_
873#endif
874        drawNode(pic, 0);
875    }
876    cur.insertHtml("<hr>");
877    cur.insertBlock(fmt_paragraph);
878int imgpos = cur.position();
879    cur.insertText(tr("Variant #%1 Solution").arg(spinVariant->value()), fmt_default);
880    cur.endEditBlock();
881
882SStep *step = root;
883int c = n = 1;
884    pb->setFormat(tr("Generating step %v"));
885    while ((step->next != SStep::NoNextStep) && (c < spinCities->value())) {
886        if (pd.wasCanceled()) {
887            pd.setLabelText(tr("Memory cleanup..."));
888            pd.setMaximum(0);
889            pd.setCancelButton(NULL);
890            pd.show();
891            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
892#ifdef Q_WS_WIN32
893            if (tl != NULL)
894                tl->SetProgressState(winId(), TBPF_INDETERMINATE);
895#endif
896#ifndef QT_NO_CONCURRENT
897QFuture<void> f = QtConcurrent::run(&solver, &CTSPSolver::cleanup, false);
898            while (!f.isFinished()) {
899                QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
900            }
901#else
902            solver.cleanup(true);
903#endif
904            solutionText->clear();
905            toggleSolutionActions(false);
906#ifdef Q_WS_WIN32
907            if (tl != NULL) {
908                tl->SetProgressState(winId(), TBPF_NOPROGRESS);
909                tl->Release();
910                tl = NULL;
911            }
912#endif
913            return;
914        }
915        pd.setValue(n);
916#ifdef Q_WS_WIN32
917        if (tl != NULL)
918            tl->SetProgressValue(winId(), spinCities->value() + n, spinCities->value() + solver.getTotalSteps() + 1);
919#endif
920
921        cur.beginEditBlock();
922        cur.insertBlock(fmt_paragraph);
923        cur.insertText(tr("Step #%1").arg(n), fmt_default);
924        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())))) {
925            outputMatrix(cur, *step);
926        }
927        if (step->alts.empty())
928            cur.insertBlock(fmt_lastparagraph);
929        else
930            cur.insertBlock(fmt_paragraph);
931        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);
932        if (!step->alts.empty()) {
933            SStep::SCandidate cand;
934            QString alts;
935            foreach(cand, step->alts) {
936                if (!alts.isEmpty())
937                    alts += ", ";
938                alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1);
939            }
940            cur.insertBlock(fmt_lastparagraph);
941            cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist);
942        }
943        cur.endEditBlock();
944
945        if (dograph) {
946            if (step->prNode != NULL)
947                drawNode(pic, n, false, step->prNode);
948            if (step->plNode != NULL)
949                drawNode(pic, n, true, step->plNode);
950        }
951        n++;
952
953        if (step->next == SStep::RightBranch) {
954            c++;
955            step = step->prNode;
956        } else if (step->next == SStep::LeftBranch) {
957            step = step->plNode;
958        } else
959            break;
960    }
961    pb->setFormat(tr("Generating footer"));
962    pd.setValue(n);
963#ifdef Q_WS_WIN32
964    if (tl != NULL)
965        tl->SetProgressValue(winId(), spinCities->value() + n, spinCities->value() + solver.getTotalSteps() + 1);
966#endif
967
968    cur.beginEditBlock();
969    cur.insertBlock(fmt_paragraph);
970    if (solver.isOptimal())
971        cur.insertText(tr("Optimal path:"), fmt_default);
972    else
973        cur.insertText(tr("Resulting path:"), fmt_default);
974
975    cur.insertBlock(fmt_paragraph);
976    cur.insertText("  " + solver.getSortedPath(tr("City %1")));
977
978    if (solver.isOptimal())
979        cur.insertBlock(fmt_paragraph);
980    else
981        cur.insertBlock(fmt_lastparagraph);
982    if (isInteger(step->price))
983        cur.insertHtml("<p>" + tr("The price is <b>%n</b> unit(s).", "", qRound(step->price)) + "</p>");
984    else
985        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>");
986    if (!solver.isOptimal()) {
987        cur.insertBlock(fmt_paragraph);
988        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>");
989    }
990    cur.endEditBlock();
991
992    if (dograph) {
993        pic.end();
994
995QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_RGB32);
996        i.fill(0xFFFFFF);
997        pic.begin(&i);
998        pic.drawPicture(1, 1, graph);
999        pic.end();
1000        doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i);
1001
1002QTextImageFormat img;
1003        img.setName("tspsg://graph.pic");
1004        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
1005            img.setWidth(i.width() / HQ_FACTOR);
1006            img.setHeight(i.height() / HQ_FACTOR);
1007        } else {
1008            img.setWidth(i.width());
1009            img.setHeight(i.height());
1010        }
1011
1012        cur.setPosition(imgpos);
1013        cur.insertImage(img, QTextFrameFormat::FloatRight);
1014    }
1015
1016    if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) {
1017        // Scrolling to the end of the text.
1018        solutionText->moveCursor(QTextCursor::End);
1019    } else
1020        solutionText->moveCursor(QTextCursor::Start);
1021
1022    pd.setLabelText(tr("Memory cleanup..."));
1023    pd.setMaximum(0);
1024    pd.setCancelButton(NULL);
1025    QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1026#ifdef Q_WS_WIN32
1027    if (tl != NULL)
1028        tl->SetProgressState(winId(), TBPF_INDETERMINATE);
1029#endif
1030#ifndef QT_NO_CONCURRENT
1031QFuture<void> f = QtConcurrent::run(&solver, &CTSPSolver::cleanup, false);
1032    while (!f.isFinished()) {
1033        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1034    }
1035#else
1036    solver.cleanup(true);
1037#endif
1038    toggleSolutionActions();
1039    tabWidget->setCurrentIndex(1);
1040#ifdef Q_WS_WIN32
1041    if (tl != NULL) {
1042        tl->SetProgressState(winId(), TBPF_NOPROGRESS);
1043        tl->Release();
1044        tl = NULL;
1045    }
1046#endif
1047
1048    pd.reset();
1049    QApplication::alert(this, 3000);
1050}
1051
1052void MainWindow::dataChanged()
1053{
1054    setWindowModified(true);
1055}
1056
1057void MainWindow::dataChanged(const QModelIndex &tl, const QModelIndex &br)
1058{
1059    setWindowModified(true);
1060    if (settings->value("Autosize", DEF_AUTOSIZE).toBool()) {
1061        for (int k = tl.row(); k <= br.row(); k++)
1062            taskView->resizeRowToContents(k);
1063        for (int k = tl.column(); k <= br.column(); k++)
1064            taskView->resizeColumnToContents(k);
1065    }
1066}
1067
1068#ifdef Q_WS_WINCE_WM
1069void MainWindow::changeEvent(QEvent *ev)
1070{
1071    if ((ev->type() == QEvent::ActivationChange) && isActiveWindow())
1072        desktopResized(0);
1073
1074    QWidget::changeEvent(ev);
1075}
1076
1077void MainWindow::desktopResized(int screen)
1078{
1079    if ((screen != 0) || !isActiveWindow())
1080        return;
1081
1082QRect availableGeometry = QApplication::desktop()->availableGeometry(0);
1083    if (currentGeometry != availableGeometry) {
1084        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1085        /*!
1086         * \hack HACK: This hack checks whether \link QDesktopWidget::availableGeometry() availableGeometry()\endlink's \c top + \c hegiht = \link QDesktopWidget::screenGeometry() screenGeometry()\endlink's \c height.
1087         *  If \c true, the window gets maximized. If we used \c setGeometry() in this case, the bottom of the
1088         *  window would end up being behind the soft buttons. Is this a bug in Qt or Windows Mobile?
1089         */
1090        if ((availableGeometry.top() + availableGeometry.height()) == QApplication::desktop()->screenGeometry().height()) {
1091            setWindowState(windowState() | Qt::WindowMaximized);
1092        } else {
1093            if (windowState() & Qt::WindowMaximized)
1094                setWindowState(windowState() ^ Qt::WindowMaximized);
1095            setGeometry(availableGeometry);
1096        }
1097        currentGeometry = availableGeometry;
1098        QApplication::restoreOverrideCursor();
1099    }
1100}
1101#endif // Q_WS_WINCE_WM
1102
1103void MainWindow::numCitiesChanged(int nCities)
1104{
1105    blockSignals(true);
1106    spinCities->setValue(nCities);
1107    blockSignals(false);
1108}
1109
1110#ifndef QT_NO_PRINTER
1111void MainWindow::printPreview(QPrinter *printer)
1112{
1113    solutionText->print(printer);
1114}
1115#endif // QT_NO_PRINTER
1116
1117#ifdef Q_WS_WIN32
1118void MainWindow::solverRoutePartFound(int n)
1119{
1120    tl->SetProgressValue(winId(), n, spinCities->value() * 2);
1121}
1122#endif // Q_WS_WIN32
1123
1124void MainWindow::spinCitiesValueChanged(int n)
1125{
1126    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1127int count = tspmodel->numCities();
1128    tspmodel->setNumCities(n);
1129    if ((n > count) && settings->value("Autosize", DEF_AUTOSIZE).toBool())
1130        for (int k = count; k < n; k++) {
1131            taskView->resizeColumnToContents(k);
1132            taskView->resizeRowToContents(k);
1133        }
1134    QApplication::restoreOverrideCursor();
1135}
1136
1137void MainWindow::check4Updates(bool silent)
1138{
1139#ifdef Q_WS_WIN32
1140    if (silent)
1141        QProcess::startDetached("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\" -silentcheck");
1142    else {
1143        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1144        QProcess::execute("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\"");
1145        QApplication::restoreOverrideCursor();
1146    }
1147#else
1148    Q_UNUSED(silent)
1149#endif
1150    settings->setValue("Check4Updates/LastAttempt", QDate::currentDate().toString(Qt::ISODate));
1151}
1152
1153void MainWindow::closeEvent(QCloseEvent *ev)
1154{
1155    if (!maybeSave()) {
1156        ev->ignore();
1157        return;
1158    }
1159    if (!settings->value("SettingsReset", false).toBool()) {
1160        settings->setValue("NumCities", spinCities->value());
1161
1162        // Saving Main Window state
1163#ifndef HANDHELD
1164        if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
1165            settings->beginGroup("MainWindow");
1166            settings->setValue("Geometry", saveGeometry());
1167            settings->setValue("State", saveState());
1168            settings->setValue("Toolbars", toolBarManager->saveState());
1169            settings->endGroup();
1170        }
1171#else
1172        settings->setValue("MainWindow/ToolbarVisible", toolBarMain->isVisible());
1173#endif // HANDHELD
1174    } else {
1175        settings->remove("SettingsReset");
1176    }
1177
1178    QMainWindow::closeEvent(ev);
1179}
1180
1181void MainWindow::dragEnterEvent(QDragEnterEvent *ev)
1182{
1183    if (ev->mimeData()->hasUrls() && (ev->mimeData()->urls().count() == 1)) {
1184QFileInfo fi(ev->mimeData()->urls().first().toLocalFile());
1185        if ((fi.suffix() == "tspt") || (fi.suffix() == "zkt"))
1186            ev->acceptProposedAction();
1187    }
1188}
1189
1190void MainWindow::drawNode(QPainter &pic, int nstep, bool left, SStep *step)
1191{
1192qreal r; // Radius of graph node
1193    // We calculate r from the full graph width in centimeters:
1194    //   r = width in pixels / 4.5.
1195    //   width in pixels = DPI * width in inches.
1196    //   width in inches = width in cm / cm in inch.
1197    r = logicalDpiX() * (settings->value("Output/GraphWidth", DEF_GRAPH_WIDTH).toReal() / CM_IN_INCH) / 4.5;
1198    if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool())
1199        r *= HQ_FACTOR;
1200#ifdef Q_WS_S60
1201    /*! \hack HACK: Solution graph on Symbian is visually larger than on
1202     *   Windows Mobile. This coefficient makes it about the same size.
1203     */
1204    r /= 1.3;
1205#endif
1206
1207qreal x, y;
1208    if (step != NULL)
1209        x = left ? r : r * 3.5;
1210    else
1211        x = r * 2.25;
1212    y = r * (3 * nstep + 1);
1213
1214#ifdef _T_T_L_
1215    if (nstep == -481124) {
1216        _t_t_l_(pic, r, x);
1217        return;
1218    }
1219#endif
1220
1221    pic.drawEllipse(QPointF(x, y), r, r);
1222
1223    if (step != NULL) {
1224QFont font;
1225        if (left) {
1226            font = pic.font();
1227            font.setStrikeOut(true);
1228            pic.setFont(font);
1229        }
1230        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");
1231        if (left) {
1232            font.setStrikeOut(false);
1233            pic.setFont(font);
1234        }
1235        if (step->price != INFINITY) {
1236            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()));
1237        } else {
1238            pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, "\n"INFSTR);
1239        }
1240    } else {
1241        pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, tr("Root"));
1242    }
1243
1244    if (nstep == 1) {
1245        pic.drawLine(QPointF(x, y - r), QPointF(r * 2.25, y - 2 * r));
1246    } else if (nstep > 1) {
1247        pic.drawLine(QPointF(x, y - r), QPointF((step->pNode->pNode->next == SStep::RightBranch) ? r * 3.5 : r, y - 2 * r));
1248    }
1249
1250}
1251
1252void MainWindow::dropEvent(QDropEvent *ev)
1253{
1254    if (maybeSave() && tspmodel->loadTask(ev->mimeData()->urls().first().toLocalFile())) {
1255        setFileName(ev->mimeData()->urls().first().toLocalFile());
1256        tabWidget->setCurrentIndex(0);
1257        setWindowModified(false);
1258        solutionText->clear();
1259        toggleSolutionActions(false);
1260
1261        ev->setDropAction(Qt::CopyAction);
1262        ev->accept();
1263    }
1264}
1265
1266void MainWindow::initDocStyleSheet()
1267{
1268    solutionText->document()->setDefaultFont(qvariant_cast<QFont>(settings->value("Output/Font", QFont(DEF_FONT_FACE, DEF_FONT_SIZE))));
1269
1270    fmt_paragraph.setTopMargin(5);
1271    fmt_paragraph.setRightMargin(10);
1272    fmt_paragraph.setBottomMargin(0);
1273    fmt_paragraph.setLeftMargin(10);
1274
1275    fmt_lastparagraph.setTopMargin(5);
1276    fmt_lastparagraph.setRightMargin(10);
1277    fmt_lastparagraph.setBottomMargin(15);
1278    fmt_lastparagraph.setLeftMargin(10);
1279
1280    fmt_table.setTopMargin(5);
1281    fmt_table.setRightMargin(10);
1282    fmt_table.setBottomMargin(0);
1283    fmt_table.setLeftMargin(10);
1284    fmt_table.setBorder(0);
1285    fmt_table.setBorderStyle(QTextFrameFormat::BorderStyle_None);
1286    fmt_table.setCellSpacing(5);
1287
1288    fmt_cell.setAlignment(Qt::AlignHCenter);
1289
1290    settings->beginGroup("Output/Colors");
1291
1292QColor color = qvariant_cast<QColor>(settings->value("Text", DEF_TEXT_COLOR));
1293QColor hilight;
1294    if (color.value() < 192)
1295        hilight.setHsv(color.hue(), color.saturation(), 127 + qRound(color.value() / 2));
1296    else
1297        hilight.setHsv(color.hue(), color.saturation(), color.value() / 2);
1298
1299    solutionText->document()->setDefaultStyleSheet(QString("* {color: %1;}").arg(color.name()));
1300    fmt_default.setForeground(QBrush(color));
1301
1302    fmt_selected.setForeground(QBrush(qvariant_cast<QColor>(settings->value("Selected", DEF_SELECTED_COLOR))));
1303    fmt_selected.setFontWeight(QFont::Bold);
1304
1305    fmt_alternate.setForeground(QBrush(qvariant_cast<QColor>(settings->value("Alternate", DEF_ALTERNATE_COLOR))));
1306    fmt_alternate.setFontWeight(QFont::Bold);
1307    fmt_altlist.setForeground(QBrush(hilight));
1308
1309    settings->endGroup();
1310
1311    solutionText->setTextColor(color);
1312}
1313
1314void MainWindow::loadLangList()
1315{
1316QMap<QString, QStringList> langlist;
1317QFileInfoList langs;
1318QFileInfo lang;
1319QStringList language, dirs;
1320QTranslator t;
1321QDir dir;
1322    dir.setFilter(QDir::Files);
1323    dir.setNameFilters(QStringList("tspsg_*.qm"));
1324    dir.setSorting(QDir::NoSort);
1325
1326    dirs << PATH_L10N << ":/l10n";
1327    foreach (QString dirname, dirs) {
1328        dir.setPath(dirname);
1329        if (dir.exists()) {
1330            langs = dir.entryInfoList();
1331            for (int k = 0; k < langs.size(); k++) {
1332                lang = langs.at(k);
1333                if (lang.completeBaseName().compare("tspsg_en", Qt::CaseInsensitive) && !langlist.contains(lang.completeBaseName().mid(6)) && t.load(lang.completeBaseName(), dirname)) {
1334
1335                    language.clear();
1336                    language.append(lang.completeBaseName().mid(6));
1337                    language.append(t.translate("--------", "COUNTRY", "Please, provide an ISO 3166-1 alpha-2 country code for this translation language here (eg., UA).").toLower());
1338                    language.append(t.translate("--------", "LANGNAME", "Please, provide a native name of your translation language here."));
1339                    language.append(t.translate("MainWindow", "Set application language to %1", "").arg(language.at(2)));
1340
1341                    langlist.insert(language.at(0), language);
1342                }
1343            }
1344        }
1345    }
1346
1347QAction *a;
1348    foreach (language, langlist) {
1349        a = menuSettingsLanguage->addAction(language.at(2));
1350#ifndef QT_NO_STATUSTIP
1351        a->setStatusTip(language.at(3));
1352#endif
1353#if QT_VERSION >= 0x040600
1354        a->setIcon(QIcon::fromTheme(QString("flag-%1").arg(language.at(1)), QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1)))));
1355#else
1356        a->setIcon(QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1))));
1357#endif
1358        a->setData(language.at(0));
1359        a->setCheckable(true);
1360        a->setActionGroup(groupSettingsLanguageList);
1361        if (settings->value("Language", QLocale::system().name()).toString().startsWith(language.at(0)))
1362            a->setChecked(true);
1363    }
1364}
1365
1366bool MainWindow::loadLanguage(const QString &lang)
1367{
1368// i18n
1369bool ad = false;
1370QString lng = lang;
1371    if (lng.isEmpty()) {
1372        ad = settings->value("Language").toString().isEmpty();
1373        lng = settings->value("Language", QLocale::system().name()).toString();
1374    }
1375static QTranslator *qtTranslator; // Qt library translator
1376    if (qtTranslator) {
1377        qApp->removeTranslator(qtTranslator);
1378        delete qtTranslator;
1379        qtTranslator = NULL;
1380    }
1381static QTranslator *translator; // Application translator
1382    if (translator) {
1383        qApp->removeTranslator(translator);
1384        delete translator;
1385        translator = NULL;
1386    }
1387
1388    if (lng == "en")
1389        return true;
1390
1391    // Trying to load system Qt library translation...
1392    qtTranslator = new QTranslator(this);
1393    if (qtTranslator->load("qt_" + lng, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
1394        qApp->installTranslator(qtTranslator);
1395    else {
1396        // No luck. Let's try to load a bundled one.
1397        if (qtTranslator->load("qt_" + lng, PATH_L10N)) {
1398            // We have a translation in the localization direcotry.
1399            qApp->installTranslator(qtTranslator);
1400        } else if (qtTranslator->load("qt_" + lng, ":/l10n")) {
1401            // We have a translation "built-in" into application resources.
1402            qApp->installTranslator(qtTranslator);
1403        } else {
1404            // Qt library translation unavailable for this language.
1405            delete qtTranslator;
1406            qtTranslator = NULL;
1407        }
1408    }
1409
1410    // Now let's load application translation.
1411    translator = new QTranslator(this);
1412    if (translator->load("tspsg_" + lng, PATH_L10N)) {
1413        // We have a translation in the localization directory.
1414        qApp->installTranslator(translator);
1415    } else if (translator->load("tspsg_" + lng, ":/l10n")) {
1416        // We have a translation "built-in" into application resources.
1417        qApp->installTranslator(translator);
1418    } else {
1419        delete translator;
1420        translator = NULL;
1421        if (!ad) {
1422            settings->remove("Language");
1423            QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
1424            QMessageBox::warning(isVisible() ? this : NULL, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
1425            QApplication::restoreOverrideCursor();
1426        }
1427        return false;
1428    }
1429    return true;
1430}
1431
1432void MainWindow::loadStyleList()
1433{
1434    menuSettingsStyle->clear();
1435QStringList styles = QStyleFactory::keys();
1436    menuSettingsStyle->insertAction(NULL, actionSettingsStyleSystem);
1437    actionSettingsStyleSystem->setChecked(!settings->contains("Style"));
1438    menuSettingsStyle->addSeparator();
1439QAction *a;
1440    foreach (QString style, styles) {
1441        a = menuSettingsStyle->addAction(style);
1442        a->setData(false);
1443#ifndef QT_NO_STATUSTIP
1444        a->setStatusTip(tr("Set application style to %1").arg(style));
1445#endif
1446        a->setCheckable(true);
1447        a->setActionGroup(groupSettingsStyleList);
1448        if ((style == settings->value("Stlye").toString())
1449#ifndef Q_WS_MAEMO_5
1450            || QString(QApplication::style()->metaObject()->className()).contains(QRegExp(QString("^Q?%1(Style)?$").arg(QRegExp::escape(style)), Qt::CaseInsensitive))
1451#endif
1452        ) {
1453            a->setChecked(true);
1454        }
1455    }
1456}
1457
1458void MainWindow::loadToolbarList()
1459{
1460    menuSettingsToolbars->clear();
1461#ifndef HANDHELD
1462    menuSettingsToolbars->insertAction(NULL, actionSettingsToolbarsConfigure);
1463    menuSettingsToolbars->addSeparator();
1464QList<QToolBar *> list = toolBarManager->toolBars();
1465    foreach (QToolBar *t, list) {
1466        menuSettingsToolbars->insertAction(NULL, t->toggleViewAction());
1467    }
1468#else // HANDHELD
1469    menuSettingsToolbars->insertAction(NULL, toolBarMain->toggleViewAction());
1470#endif // HANDHELD
1471}
1472
1473bool MainWindow::maybeSave()
1474{
1475    if (!isWindowModified())
1476        return true;
1477#ifdef Q_WS_S60
1478    int res = QSMessageBox(this).exec();
1479#else
1480    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);
1481#endif
1482    if (res == QMessageBox::Save)
1483        return actionFileSaveTriggered();
1484    else if (res == QMessageBox::Cancel)
1485        return false;
1486    else
1487        return true;
1488}
1489
1490void MainWindow::outputMatrix(QTextCursor &cur, const TMatrix &matrix)
1491{
1492int n = spinCities->value();
1493QTextTable *table = cur.insertTable(n, n, fmt_table);
1494
1495    for (int r = 0; r < n; r++) {
1496        for (int c = 0; c < n; c++) {
1497            cur = table->cellAt(r, c).firstCursorPosition();
1498            cur.setBlockFormat(fmt_cell);
1499            cur.setBlockCharFormat(fmt_default);
1500            if (matrix.at(r).at(c) == INFINITY)
1501                cur.insertText(INFSTR);
1502            else
1503                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()));
1504        }
1505        QCoreApplication::processEvents();
1506    }
1507    cur.movePosition(QTextCursor::End);
1508}
1509
1510void MainWindow::outputMatrix(QTextCursor &cur, const SStep &step)
1511{
1512int n = spinCities->value();
1513QTextTable *table = cur.insertTable(n, n, fmt_table);
1514
1515    for (int r = 0; r < n; r++) {
1516        for (int c = 0; c < n; c++) {
1517            cur = table->cellAt(r, c).firstCursorPosition();
1518            cur.setBlockFormat(fmt_cell);
1519            if (step.matrix.at(r).at(c) == INFINITY)
1520                cur.insertText(INFSTR, fmt_default);
1521            else if ((r == step.candidate.nRow) && (c == step.candidate.nCol))
1522                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);
1523            else {
1524SStep::SCandidate cand;
1525                cand.nRow = r;
1526                cand.nCol = c;
1527                if (step.alts.contains(cand))
1528                    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);
1529                else
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_default);
1531            }
1532        }
1533        QCoreApplication::processEvents();
1534    }
1535
1536    cur.movePosition(QTextCursor::End);
1537}
1538
1539void MainWindow::retranslateUi(bool all)
1540{
1541    if (all)
1542        Ui_MainWindow::retranslateUi(this);
1543
1544#ifdef Q_OS_BLACKBERRY
1545    menuSettings->removeAction(menuSettingsStyle->menuAction());
1546#else
1547    loadStyleList();
1548#endif
1549    loadToolbarList();
1550
1551#ifndef QT_NO_PRINTER
1552    actionFilePrintPreview->setText(tr("P&rint Preview..."));
1553#ifndef QT_NO_TOOLTIP
1554    actionFilePrintPreview->setToolTip(tr("Preview solution results"));
1555#endif // QT_NO_TOOLTIP
1556#ifndef QT_NO_STATUSTIP
1557    actionFilePrintPreview->setStatusTip(tr("Preview current solution results before printing"));
1558#endif // QT_NO_STATUSTIP
1559
1560    actionFilePageSetup->setText(tr("Pa&ge Setup..."));
1561#ifndef QT_NO_TOOLTIP
1562    actionFilePageSetup->setToolTip(tr("Setup print options"));
1563#endif // QT_NO_TOOLTIP
1564#ifndef QT_NO_STATUSTIP
1565    actionFilePageSetup->setStatusTip(tr("Setup page-related options for printing"));
1566#endif // QT_NO_STATUSTIP
1567
1568    actionFilePrint->setText(tr("&Print..."));
1569#ifndef QT_NO_TOOLTIP
1570    actionFilePrint->setToolTip(tr("Print solution"));
1571#endif // QT_NO_TOOLTIP
1572#ifndef QT_NO_STATUSTIP
1573    actionFilePrint->setStatusTip(tr("Print current solution results"));
1574#endif // QT_NO_STATUSTIP
1575    actionFilePrint->setShortcut(tr("Ctrl+P"));
1576#endif // QT_NO_PRINTER
1577
1578#ifndef QT_NO_STATUSTIP
1579    actionFileExit->setStatusTip(tr("Exit %1").arg(QCoreApplication::applicationName()));
1580#endif // QT_NO_STATUSTIP
1581
1582#ifndef HANDHELD
1583    actionSettingsToolbarsConfigure->setText(tr("Configure..."));
1584#ifndef QT_NO_STATUSTIP
1585    actionSettingsToolbarsConfigure->setStatusTip(tr("Customize toolbars"));
1586#endif // QT_NO_STATUSTIP
1587#endif // HANDHELD
1588
1589#ifndef QT_NO_STATUSTIP
1590    actionHelpReportBug->setStatusTip(tr("Report about a bug in %1").arg(QCoreApplication::applicationName()));
1591#endif // QT_NO_STATUSTIP
1592    if (actionHelpCheck4Updates != NULL) {
1593        actionHelpCheck4Updates->setText(tr("Check for &Updates..."));
1594#ifndef QT_NO_STATUSTIP
1595        actionHelpCheck4Updates->setStatusTip(tr("Check for %1 updates").arg(QCoreApplication::applicationName()));
1596#endif // QT_NO_STATUSTIP
1597    }
1598#ifndef QT_NO_STATUSTIP
1599    actionHelpAbout->setStatusTip(tr("About %1").arg(QCoreApplication::applicationName()));
1600#endif // QT_NO_STATUSTIP
1601
1602#ifdef Q_WS_S60
1603    actionRightSoftKey->setText(tr("E&xit"));
1604#endif
1605}
1606
1607bool MainWindow::saveTask() {
1608QStringList filters(tr("%1 Task File").arg("TSPSG") + " (*.tspt)");
1609    filters.append(tr("All Files") + " (*)");
1610QString file;
1611    if ((fileName == tr("Untitled") + ".tspt") && settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool()) {
1612        file = settings->value(OS"/LastUsed/TaskSavePath").toString();
1613        if (!file.isEmpty())
1614            file.append("/");
1615        file.append(fileName);
1616    } else if (fileName.endsWith(".tspt", Qt::CaseInsensitive))
1617        file = fileName;
1618    else
1619        file = QFileInfo(fileName).path() + "/" + QFileInfo(fileName).completeBaseName() + ".tspt";
1620
1621QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
1622    file = QFileDialog::getSaveFileName(this, tr("Task Save"), file, filters.join(";;"), NULL, opts);
1623    if (file.isEmpty())
1624        return false;
1625    else if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
1626        settings->setValue(OS"/LastUsed/TaskSavePath", QFileInfo(file).path());
1627    if (QFileInfo(file).suffix().isEmpty()) {
1628        file.append(".tspt");
1629    }
1630
1631    if (tspmodel->saveTask(file)) {
1632        setFileName(file);
1633        setWindowModified(false);
1634        return true;
1635    }
1636    return false;
1637}
1638
1639void MainWindow::setFileName(const QString &fileName)
1640{
1641    this->fileName = fileName;
1642    setWindowTitle(QString("%1[*] - %2").arg(QFileInfo(fileName).completeBaseName()).arg(QCoreApplication::applicationName()));
1643}
1644
1645void MainWindow::setupUi()
1646{
1647    Ui_MainWindow::setupUi(this);
1648
1649    // File Menu
1650    actionFileNew->setIcon(GET_ICON("document-new"));
1651    actionFileOpen->setIcon(GET_ICON("document-open"));
1652    actionFileSave->setIcon(GET_ICON("document-save"));
1653#ifndef HANDHELD
1654    menuFileSaveAs->setIcon(GET_ICON("document-save-as"));
1655#endif
1656    actionFileExit->setIcon(GET_ICON("application-exit"));
1657    // Settings Menu
1658#ifndef HANDHELD
1659    menuSettingsLanguage->setIcon(GET_ICON("preferences-desktop-locale"));
1660#if QT_VERSION >= 0x040600
1661    actionSettingsLanguageEnglish->setIcon(QIcon::fromTheme("flag-gb", QIcon(":/images/icons/l10n/flag-gb.png")));
1662#else // QT_VERSION >= 0x040600
1663    actionSettingsLanguageEnglish->setIcon(QIcon(":/images/icons/l10n/flag-gb.png"));
1664#endif // QT_VERSION >= 0x040600
1665    menuSettingsStyle->setIcon(GET_ICON("preferences-desktop-theme"));
1666#endif // HANDHELD
1667    actionSettingsPreferences->setIcon(GET_ICON("preferences-system"));
1668    // Help Menu
1669#ifndef HANDHELD
1670    actionHelpContents->setIcon(GET_ICON("help-contents"));
1671    actionHelpContextual->setIcon(GET_ICON("help-contextual"));
1672    actionHelpOnlineSupport->setIcon(GET_ICON("applications-internet"));
1673    actionHelpReportBug->setIcon(GET_ICON("tools-report-bug"));
1674    actionHelpAbout->setIcon(GET_ICON("help-about"));
1675#ifdef Q_OS_BLACKBERRY
1676    // Qt about dialog is too big for the screen
1677    // and it's impossible to close it.
1678    menuHelp->removeAction(actionHelpAboutQt);
1679#else
1680    actionHelpAboutQt->setIcon(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"));
1681#endif
1682#endif
1683    // Buttons
1684    buttonRandom->setIcon(GET_ICON("roll"));
1685    buttonSolve->setIcon(GET_ICON("dialog-ok"));
1686    buttonSaveSolution->setIcon(GET_ICON("document-save-as"));
1687    buttonBackToTask->setIcon(GET_ICON("go-previous"));
1688
1689//      action->setIcon(GET_ICON(""));
1690
1691#if QT_VERSION >= 0x040600
1692    setToolButtonStyle(Qt::ToolButtonFollowStyle);
1693#endif
1694
1695#ifndef HANDHELD
1696QStatusBar *statusbar = new QStatusBar(this);
1697    statusbar->setObjectName("statusbar");
1698    setStatusBar(statusbar);
1699#endif // HANDHELD
1700
1701#ifdef Q_WS_WINCE_WM
1702    menuBar()->setDefaultAction(menuFile->menuAction());
1703
1704QScrollArea *scrollArea = new QScrollArea(this);
1705    scrollArea->setFrameShape(QFrame::NoFrame);
1706    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1707    scrollArea->setWidgetResizable(true);
1708    scrollArea->setWidget(tabWidget);
1709    setCentralWidget(scrollArea);
1710#else
1711    setCentralWidget(tabWidget);
1712#endif // Q_WS_WINCE_WM
1713
1714    //! \hack HACK: A little hack for toolbar icons to have a sane size.
1715#if defined(HANDHELD) && !defined(Q_WS_MAEMO_5)
1716#ifdef Q_WS_S60
1717    toolBarMain->setIconSize(QSize(logicalDpiX() / 5.2, logicalDpiY() / 5.2));
1718#else
1719    toolBarMain->setIconSize(QSize(logicalDpiX() / 4, logicalDpiY() / 4));
1720#endif // Q_WS_S60
1721#endif // HANDHELD && !Q_WS_MAEMO_5
1722QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
1723    if (tb != NULL) {
1724        tb->setMenu(menuFileSaveAs);
1725        tb->setPopupMode(QToolButton::MenuButtonPopup);
1726    }
1727
1728//      solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, DEF_FONT_SIZE)).value<QFont>());
1729    solutionText->setWordWrapMode(QTextOption::WordWrap);
1730
1731#ifndef QT_NO_PRINTER
1732    actionFilePrintPreview = new QAction(this);
1733    actionFilePrintPreview->setObjectName("actionFilePrintPreview");
1734    actionFilePrintPreview->setEnabled(false);
1735    actionFilePrintPreview->setIcon(GET_ICON("document-print-preview"));
1736
1737    actionFilePageSetup = new QAction(this);
1738    actionFilePageSetup->setObjectName("actionFilePrintSetup");
1739//    actionFilePageSetup->setEnabled(false);
1740#if QT_VERSION >= 0x040600
1741    actionFilePageSetup->setIcon(QIcon::fromTheme("document-page-setup", QIcon(":/trolltech/dialogs/qprintpreviewdialog/images/page-setup-32.png")));
1742#else
1743    actionFilePageSetup->setIcon(QIcon(":/trolltech/dialogs/qprintpreviewdialog/images/page-setup-32.png"));
1744#endif
1745
1746    actionFilePrint = new QAction(this);
1747    actionFilePrint->setObjectName("actionFilePrint");
1748    actionFilePrint->setEnabled(false);
1749    actionFilePrint->setIcon(GET_ICON("document-print"));
1750
1751    menuFile->insertAction(actionFileExit, actionFilePrintPreview);
1752    menuFile->insertAction(actionFileExit, actionFilePageSetup);
1753    menuFile->insertAction(actionFileExit, actionFilePrint);
1754    menuFile->insertSeparator(actionFileExit);
1755
1756    toolBarMain->insertAction(actionSettingsPreferences, actionFilePrint);
1757#endif // QT_NO_PRINTER
1758
1759    groupSettingsLanguageList = new QActionGroup(this);
1760#ifdef Q_WS_MAEMO_5
1761    groupSettingsLanguageList->addAction(actionSettingsLanguageAutodetect);
1762#endif
1763    actionSettingsLanguageEnglish->setData("en");
1764    actionSettingsLanguageEnglish->setActionGroup(groupSettingsLanguageList);
1765    loadLangList();
1766    actionSettingsLanguageAutodetect->setChecked(settings->value("Language", "").toString().isEmpty());
1767
1768    actionSettingsStyleSystem->setData(true);
1769    groupSettingsStyleList = new QActionGroup(this);
1770#ifdef Q_WS_MAEMO_5
1771    groupSettingsStyleList->addAction(actionSettingsStyleSystem);
1772#endif
1773
1774#ifndef HANDHELD
1775    actionSettingsToolbarsConfigure = new QAction(this);
1776    actionSettingsToolbarsConfigure->setIcon(GET_ICON("configure-toolbars"));
1777#endif // HANDHELD
1778
1779    if (hasUpdater()) {
1780        actionHelpCheck4Updates = new QAction(this);
1781        actionHelpCheck4Updates->setIcon(GET_ICON("system-software-update"));
1782        actionHelpCheck4Updates->setEnabled(hasUpdater());
1783        menuHelp->insertAction(actionHelpAboutQt, actionHelpCheck4Updates);
1784        menuHelp->insertSeparator(actionHelpAboutQt);
1785    } else
1786        actionHelpCheck4Updates = NULL;
1787
1788    spinCities->setMaximum(MAX_NUM_CITIES);
1789
1790#ifndef HANDHELD
1791    toolBarManager = new QtToolBarManager(this);
1792    toolBarManager->setMainWindow(this);
1793QString cat = toolBarMain->windowTitle();
1794    toolBarManager->addToolBar(toolBarMain, cat);
1795#ifndef QT_NO_PRINTER
1796    toolBarManager->addAction(actionFilePrintPreview, cat);
1797    toolBarManager->addAction(actionFilePageSetup, cat);
1798#endif // QT_NO_PRINTER
1799    toolBarManager->addAction(actionHelpContents, cat);
1800    toolBarManager->addAction(actionHelpContextual, cat);
1801    toolBarManager->restoreState(settings->value("MainWindow/Toolbars").toByteArray());
1802#else
1803    toolBarMain->setVisible(settings->value("MainWindow/ToolbarVisible", true).toBool());
1804#endif // HANDHELD
1805
1806#ifdef Q_WS_S60
1807    // Replace Exit on the right soft key with our own exit action.
1808    // This makes it translatable.
1809    actionRightSoftKey = new QAction(this);
1810    actionRightSoftKey->setSoftKeyRole(QAction::NegativeSoftKey);
1811    connect(actionRightSoftKey, SIGNAL(triggered()), SLOT(close()));
1812    addAction(actionRightSoftKey);
1813#endif
1814
1815    retranslateUi(false);
1816
1817#ifndef HANDHELD
1818    // Adding some eyecandy
1819    if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
1820        toggleTranclucency(true);
1821    }
1822#endif // HANDHELD
1823}
1824
1825void MainWindow::toggleSolutionActions(bool enable)
1826{
1827    buttonSaveSolution->setEnabled(enable);
1828    actionFileSaveAsSolution->setEnabled(enable);
1829    solutionText->setEnabled(enable);
1830#ifndef QT_NO_PRINTER
1831    actionFilePrint->setEnabled(enable);
1832    actionFilePrintPreview->setEnabled(enable);
1833#endif // QT_NO_PRINTER
1834}
1835
1836void MainWindow::toggleTranclucency(bool enable)
1837{
1838#ifndef HANDHELD
1839    toggleStyle(labelVariant, enable);
1840    toggleStyle(labelCities, enable);
1841    toggleStyle(statusBar(), enable);
1842    tabWidget->setDocumentMode(enable);
1843    QtWin::enableBlurBehindWindow(this, enable);
1844#else
1845    Q_UNUSED(enable);
1846#endif // HANDHELD
1847}
1848
1849void MainWindow::actionHelpOnlineSupportTriggered()
1850{
1851    QDesktopServices::openUrl(QUrl("http://tspsg.info/goto/support"));
1852}
1853
1854void MainWindow::actionHelpReportBugTriggered()
1855{
1856    QDesktopServices::openUrl(QUrl("http://tspsg.info/goto/bugtracker"));
1857}
1858
1859#ifdef Q_WS_S60
1860QSMessageBox::QSMessageBox(QWidget *parent)
1861    : QMessageBox(parent)
1862{
1863    setIcon(QMessageBox::Warning);
1864    setWindowTitle(QApplication::translate("MainWindow", "Unsaved Changes"));
1865    setText(QApplication::translate("MainWindow", "Would you like to save changes in the current task?"));
1866    setStandardButtons(QMessageBox::Save);
1867
1868    QMenu *m = new QMenu(this);
1869    m->addAction(QApplication::translate("QDialogButtonBox", "Discard", "No need to translate this. The translation will be taken from Qt translation files."),
1870                 this, SLOT(discard()));
1871    m->addAction(QApplication::translate("QDialogButtonBox", "Cancel", "No need to translate this. The translation will be taken from Qt translation files."),
1872                 this, SLOT(cancel()));
1873
1874    QAction *o = new QAction(QApplication::translate("QtToolBarDialog", "Actions"), this);
1875    o->setSoftKeyRole(QAction::NegativeSoftKey);
1876    o->setMenu(m);
1877    addAction(o);
1878}
1879
1880void QSMessageBox::cancel(){
1881    done(QMessageBox::Cancel);
1882}
1883
1884void QSMessageBox::discard() {
1885    done(QMessageBox::Discard);
1886}
1887#endif // Q_WS_S60
Note: See TracBrowser for help on using the repository browser.