source: tspsg/src/mainwindow.cpp @ fecf053b50

appveyorimgbot
Last change on this file since fecf053b50 was fecf053b50, checked in by Oleksii Serdiuk, 10 years ago

Updated link to Qt Project

Also made some small, mostly stylistic, changes to the Credits text.

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