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
RevLine 
[1babbd6ba3]1/*
2 *  TSPSG: TSP Solver and Generator
[b4b4f8d479]3 *  Copyright (C) 2007-2014 Oleksii Serdiuk <contacts[at]oleksii[dot]name>
[1babbd6ba3]4 *
[7ba743d983]5 *  $Id: $Format:%h %ai %an$ $
6 *  $URL: http://tspsg.info/ $
[1babbd6ba3]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
[2940c14782]12 *  the Free Software Foundation, either version 2 of the License, or
[1babbd6ba3]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"
[07e43cf61a]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
[1241232377]65#include <QtConcurrentRun>
[07e43cf61a]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
[1babbd6ba3]79
[89e5214692]80#ifdef Q_OS_WIN32
[b8a2a118c4]81#   include "shobjidl.h"
[43c29c04ba]82#endif
83
[2a5e50e0a9]84#ifdef Q_OS_BLACKBERRY
85#   include <bb/ApplicationSupport>
86#   include <bb/cascades/pickers/FilePicker>
87using namespace bb::cascades::pickers;
88#endif
89
[3cadf24d00]90#ifdef _T_T_L_
91#include "_.h"
[e9db3e216b]92_C_ _R_ _Y_ _P_ _T_
[3cadf24d00]93#endif
94
[07e43cf61a]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;
[1241232377]104#ifdef Q_OS_BLACKBERRY
105    return (std::modf(x, &i) == 0.0);
106#else
[07e43cf61a]107    return (modf(x, &i) == 0.0);
[1241232377]108#endif
[07e43cf61a]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
[1babbd6ba3]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)
[9eb63a1598]136    : QMainWindow(parent)
[1babbd6ba3]137{
[31694c8b58]138    settings = initSettings(this);
[1babbd6ba3]139
[47c811cc09]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
[9eb63a1598]145    if (settings->contains("Style")) {
[e3533af1cf]146QStyle *s = QStyleFactory::create(settings->value("Style").toString());
[9eb63a1598]147        if (s != NULL)
148            QApplication::setStyle(s);
149        else
150            settings->remove("Style");
151    }
[e3533af1cf]152
[9eb63a1598]153    loadLanguage();
154    setupUi();
155    setAcceptDrops(true);
[1babbd6ba3]156
[7ed8b57eea]157#ifdef Q_OS_BLACKBERRY
158    taskView->setEditTriggers(QAbstractItemView::AllEditTriggers);
159#endif
160
[9eb63a1598]161    initDocStyleSheet();
[1babbd6ba3]162
163#ifndef QT_NO_PRINTER
[9eb63a1598]164    printer = new QPrinter(QPrinter::HighResolution);
[a885c3d9d2]165    settings->beginGroup("Printer");
[20e8115cee]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
[a885c3d9d2]174    printer->setOrientation(qvariant_cast<QPrinter::Orientation>(settings->value("PageOrientation", DEF_PAGE_ORIENTATION)));
175    printer->setPageMargins(
[20e8115cee]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(),
[a885c3d9d2]180        QPrinter::Millimeter);
181    settings->endGroup();
[1babbd6ba3]182#endif // QT_NO_PRINTER
183
[89e5214692]184#ifdef Q_OS_WINCE_WM
[9eb63a1598]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)));
[89e5214692]188#endif // Q_OS_WINCE_WM
[9eb63a1598]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()));
[7ed8b57eea]194#ifndef QT_NO_PRINTDIALOG
[9eb63a1598]195    connect(actionFilePrintPreview, SIGNAL(triggered()), SLOT(actionFilePrintPreviewTriggered()));
[20e8115cee]196    connect(actionFilePageSetup, SIGNAL(triggered()), SLOT(actionFilePageSetupTriggered()));
[9eb63a1598]197    connect(actionFilePrint, SIGNAL(triggered()), SLOT(actionFilePrintTriggered()));
[1babbd6ba3]198#endif // QT_NO_PRINTER
[7bb19df196]199#ifndef HANDHELD
[9eb63a1598]200    connect(actionSettingsToolbarsConfigure, SIGNAL(triggered()), SLOT(actionSettingsToolbarsConfigureTriggered()));
[7bb19df196]201#endif // HANDHELD
[9eb63a1598]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)));
[1babbd6ba3]218
219#ifndef HANDHELD
[9eb63a1598]220    // Centering main window
[1babbd6ba3]221QRect rect = geometry();
[9eb63a1598]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    }
[1babbd6ba3]231#endif // HANDHELD
232
[9eb63a1598]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    }
[1babbd6ba3]263}
264
265MainWindow::~MainWindow()
266{
267#ifndef QT_NO_PRINTER
[9eb63a1598]268    delete printer;
[1babbd6ba3]269#endif
270}
271
[2a5e50e0a9]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
[1babbd6ba3]284/* Privates **********************************************************/
285
286void MainWindow::actionFileNewTriggered()
287{
[9eb63a1598]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();
[8f2427aaf0]296    graph = QPicture();
[9eb63a1598]297    toggleSolutionActions(false);
298    QApplication::restoreOverrideCursor();
[1babbd6ba3]299}
300
301void MainWindow::actionFileOpenTriggered()
302{
[9eb63a1598]303    if (!maybeSave())
304        return;
[1babbd6ba3]305
[2a5e50e0a9]306    QStringList filters;
307#ifdef Q_OS_BLACKBERRY
308    filters << "*.tspt" << "*.zkt";
309#else
310    filters.append(tr("All Supported Formats") + " (*.tspt *.zkt)");
[9eb63a1598]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") + " (*)");
[2a5e50e0a9]314#endif
[1babbd6ba3]315
[ac76a6a753]316QString file;
[9eb63a1598]317    if ((fileName == tr("Untitled") + ".tspt") && settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
[2a5e50e0a9]318#ifdef Q_OS_BLACKBERRY
319        file = settings->value(OS"/LastUsed/TaskLoadPath", "/accounts/1000/shared/documents").toString();
320#else
[9eb63a1598]321        file = settings->value(OS"/LastUsed/TaskLoadPath").toString();
[2a5e50e0a9]322#endif
[9eb63a1598]323    else
324        file = QFileInfo(fileName).path();
[2a5e50e0a9]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;
[9eb63a1598]345    file = QFileDialog::getOpenFileName(this, tr("Task Load"), file, filters.join(";;"), NULL, opts);
346    if (file.isEmpty() || !QFileInfo(file).isFile())
347        return;
[2a5e50e0a9]348#endif
[9eb63a1598]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);
[1babbd6ba3]359}
360
361bool MainWindow::actionFileSaveTriggered()
362{
[9eb63a1598]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;
[1babbd6ba3]371}
372
373void MainWindow::actionFileSaveAsTaskTriggered()
374{
[9eb63a1598]375    saveTask();
[1babbd6ba3]376}
377
378void MainWindow::actionFileSaveAsSolutionTriggered()
379{
380static QString selectedFile;
[9eb63a1598]381    if (selectedFile.isEmpty()) {
382        if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool()) {
[2a5e50e0a9]383#ifdef Q_OS_BLACKBERRY
384            selectedFile = settings->value(OS"/LastUsed/SolutionSavePath", "/accounts/1000/shared/documents").toString();
385#else
[9eb63a1598]386            selectedFile = settings->value(OS"/LastUsed/SolutionSavePath").toString();
[2a5e50e0a9]387#endif
[9eb63a1598]388        }
389    } else
390        selectedFile = QFileInfo(selectedFile).path();
391    if (!selectedFile.isEmpty())
392        selectedFile.append("/");
393    if (fileName == tr("Untitled") + ".tspt") {
[1babbd6ba3]394#ifndef QT_NO_PRINTER
[9eb63a1598]395        selectedFile += "solution.pdf";
[1babbd6ba3]396#else
[9eb63a1598]397        selectedFile += "solution.html";
[1babbd6ba3]398#endif // QT_NO_PRINTER
[9eb63a1598]399    } else {
[1babbd6ba3]400#ifndef QT_NO_PRINTER
[9eb63a1598]401        selectedFile += QFileInfo(fileName).completeBaseName() + ".pdf";
[1babbd6ba3]402#else
[9eb63a1598]403        selectedFile += QFileInfo(fileName).completeBaseName() + ".html";
[1babbd6ba3]404#endif // QT_NO_PRINTER
[9eb63a1598]405    }
[1babbd6ba3]406
407QStringList filters;
[2a5e50e0a9]408#ifdef Q_OS_BLACKBERRY
409    filters << "*.pdf" << "*.html" << "*.htm" << "*.odf";
410#else
[1babbd6ba3]411#ifndef QT_NO_PRINTER
[9eb63a1598]412    filters.append(tr("PDF Files") + " (*.pdf)");
[1babbd6ba3]413#endif
[9eb63a1598]414    filters.append(tr("HTML Files") + " (*.html *.htm)");
[f48433245d]415    filters.append(tr("Web Archive Files") + " (*.mht *.mhtml)");
[9eb63a1598]416    filters.append(tr("OpenDocument Files") + " (*.odt)");
417    filters.append(tr("All Files") + " (*)");
[2a5e50e0a9]418#endif
[1babbd6ba3]419
[2a5e50e0a9]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);
[9eb63a1598]442    if (file.isEmpty())
443        return;
444    selectedFile = file;
[2a5e50e0a9]445#endif
[9eb63a1598]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));
[1babbd6ba3]449#ifndef QT_NO_PRINTER
[8f2427aaf0]450    if (selectedFile.endsWith(".pdf", Qt::CaseInsensitive)) {
451        printer->setOutputFileName(selectedFile);
452        solutionText->document()->print(printer);
453        printer->setOutputFileName(QString());
[9eb63a1598]454        QApplication::restoreOverrideCursor();
455        return;
456    }
[1babbd6ba3]457#endif
[b26dc16dcf]458    QByteArray imgdata;
[f48433245d]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))) {
[b26dc16dcf]462        QFile file(selectedFile);
463        if (!file.open(QFile::WriteOnly | QFile::Text)) {
[9eb63a1598]464            QApplication::restoreOverrideCursor();
465            QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(file.errorString()));
466            return;
467        }
[b26dc16dcf]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();
[2a436ea693]480#if !defined(NOSVG)
[7a39458d16]481        if (!QImageWriter::supportedImageFormats().contains(format.toLatin1()) && (format != "svg")) {
[2a436ea693]482#else // NOSVG
[7a39458d16]483        if (!QImageWriter::supportedImageFormats().contains(format.toLatin1())) {
[2a436ea693]484#endif // NOSVG
[8f2427aaf0]485            format = DEF_GRAPH_IMAGE_FORMAT;
486            settings->remove("Output/GraphImageFormat");
487        }
[20015b41e7]488
[8f2427aaf0]489        if (!graph.isNull()) {
[b26dc16dcf]490            imgdata = generateImage(format);
491            if (imgdata.isEmpty()) {
[b96b44b6b7]492                QApplication::restoreOverrideCursor();
[b26dc16dcf]493                return;
[9eb63a1598]494            }
[8f2427aaf0]495            if (embed) {
[b26dc16dcf]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")));
[9eb63a1598]506            }
507        }
[b26dc16dcf]508
[8f2427aaf0]509        // Saving solution text as HTML
510QTextStream ts(&file);
511        ts.setCodec(QTextCodec::codecForName("UTF-8"));
[f48433245d]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        }
[b26dc16dcf]527        ts << html << endl;
[f48433245d]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        }
[8f2427aaf0]541        file.close();
[f48433245d]542        if (!embed && !mhtml) {
[b26dc16dcf]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        }
[9eb63a1598]555    } else {
[ca3d2a30fa]556QTextDocumentWriter dw(selectedFile);
[9eb63a1598]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();
[1babbd6ba3]563}
564
[7ed8b57eea]565#ifndef QT_NO_PRINTDIALOG
[1babbd6ba3]566void MainWindow::actionFilePrintPreviewTriggered()
567{
568QPrintPreviewDialog ppd(printer, this);
[9eb63a1598]569    connect(&ppd,SIGNAL(paintRequested(QPrinter *)),SLOT(printPreview(QPrinter *)));
570    ppd.exec();
[144fbe6b96]571
572qreal l, t, r, b;
573    printer->getPageMargins(&l, &t, &r, &b, QPrinter::Millimeter);
574
[a885c3d9d2]575    settings->beginGroup("Printer");
[144fbe6b96]576    settings->setValue("PaperSize", printer->paperSize());
[20e8115cee]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    }
[a885c3d9d2]606    settings->setValue("PageOrientation", printer->orientation());
[144fbe6b96]607    settings->setValue("MarginLeft", l);
608    settings->setValue("MarginTop", t);
609    settings->setValue("MarginRight", r);
610    settings->setValue("MarginBottom", b);
[a885c3d9d2]611    settings->endGroup();
[1babbd6ba3]612}
613
614void MainWindow::actionFilePrintTriggered()
615{
616QPrintDialog pd(printer,this);
[9eb63a1598]617    if (pd.exec() != QDialog::Accepted)
618        return;
619    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
620    solutionText->print(printer);
621    QApplication::restoreOverrideCursor();
[1babbd6ba3]622}
[7ed8b57eea]623#endif // QT_NO_PRINTDIALOG
[1babbd6ba3]624
625void MainWindow::actionSettingsPreferencesTriggered()
626{
627SettingsDialog sd(this);
[89e5214692]628#ifdef Q_OS_SYMBIAN
[1b40fef578]629    sd.setWindowState(Qt::WindowMaximized);
630#endif
[9eb63a1598]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);
[1babbd6ba3]640}
641
642void MainWindow::actionSettingsLanguageAutodetectTriggered(bool checked)
643{
[9eb63a1598]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());
[1babbd6ba3]649}
650
651void MainWindow::groupSettingsLanguageListTriggered(QAction *action)
652{
[97e90f9be6]653#ifndef Q_WS_MAEMO_5
[9eb63a1598]654    if (actionSettingsLanguageAutodetect->isChecked())
655        actionSettingsLanguageAutodetect->trigger();
[97e90f9be6]656#endif
[1babbd6ba3]657bool untitled = (fileName == tr("Untitled") + ".tspt");
[9eb63a1598]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();
[b8a2a118c4]664#ifndef HANDHELD
[9eb63a1598]665        if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
666            toggleStyle(labelVariant, true);
667            toggleStyle(labelCities, true);
668        }
[1babbd6ba3]669#endif
[9eb63a1598]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    }
[1babbd6ba3]674}
675
[e3533af1cf]676void MainWindow::actionSettingsStyleSystemTriggered(bool checked)
677{
[9eb63a1598]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    }
[e3533af1cf]684}
685
686void MainWindow::groupSettingsStyleListTriggered(QAction *action)
687{
688QStyle *s = QStyleFactory::create(action->text());
[9eb63a1598]689    if (s != NULL) {
690        QApplication::setStyle(s);
691        settings->setValue("Style", action->text());
692        actionSettingsStyleSystem->setChecked(false);
693    }
[e3533af1cf]694}
695
[7bb19df196]696#ifndef HANDHELD
697void MainWindow::actionSettingsToolbarsConfigureTriggered()
698{
699QtToolBarDialog dlg(this);
[9eb63a1598]700    dlg.setToolBarManager(toolBarManager);
701    dlg.exec();
[7bb19df196]702QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
[9eb63a1598]703    if (tb != NULL) {
704        tb->setMenu(menuFileSaveAs);
705        tb->setPopupMode(QToolButton::MenuButtonPopup);
706        tb->resize(tb->sizeHint());
707    }
[7bb19df196]708
[9eb63a1598]709    loadToolbarList();
[7bb19df196]710}
711#endif // HANDHELD
712
[1babbd6ba3]713void MainWindow::actionHelpCheck4UpdatesTriggered()
714{
[9eb63a1598]715    if (!hasUpdater()) {
[019894f5ef]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."));
[9eb63a1598]717        return;
718    }
[1babbd6ba3]719
[9eb63a1598]720    check4Updates();
[1babbd6ba3]721}
722
723void MainWindow::actionHelpAboutTriggered()
724{
[9eb63a1598]725    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[43c29c04ba]726
[1babbd6ba3]727QString title;
[9eb63a1598]728    title += QString("<b>%1</b><br>").arg(QCoreApplication::applicationName());
729    title += QString("%1: <b>%2</b><br>").arg(tr("Version"), QCoreApplication::applicationVersion());
[1babbd6ba3]730#ifndef HANDHELD
[9eb63a1598]731    title += QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b><br>").arg(QDate::currentDate().toString("yyyy"), QCoreApplication::organizationDomain(), QCoreApplication::organizationName());
[7bb19df196]732#endif // HANDHELD
[9eb63a1598]733    title += QString("<b><a href=\"http://tspsg.info/\">http://tspsg.info/</a></b>");
[1babbd6ba3]734
735QString about;
[9eb63a1598]736    about += QString("%1: <b>%2</b><br>").arg(tr("Target OS (ARCH)"), PLATFROM);
[fddcfa4b55]737    about += QString("%1:<br>").arg(tr("Qt library"));
[9eb63a1598]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());
[03df0acb95]740    about.append(QString("%1: <b>%2x%3</b><br>").arg(tr("Logical screen DPI")).arg(logicalDpiX()).arg(logicalDpiY()));
[1299ea5b49]741QString tag;
742#ifdef REVISION_STR
[87b8a22768]743    tag = tr(" from git commit <b>%1</b>").arg(QString(REVISION_STR).left(10));
[1299ea5b49]744#endif
[87b8a22768]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>";
[07e43cf61a]746    about += QString("%1: <b>%2</b><br>").arg(tr("Algorithm"), TSPSolver::CTSPSolver::getVersionId());
[9eb63a1598]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"
[2940c14782]750        "the Free Software Foundation, either version 2 of the License, or<br>\n"
[9eb63a1598]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>.");
[43c29c04ba]760
761QString credits;
[fecf053b50]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"
[9eb63a1598]765        "<br>\n"
766        "Most icons used in %1 are part of <b>Oxygen&nbsp;Icons</b> project "
[fecf053b50]767        "licensed according to the <i>GNU Lesser General Public License</i>,<br>\n"
[9eb63a1598]768        "see <a href=\"http://www.oxygen-icons.org/\">www.oxygen-icons.org</a><br>\n"
769        "<br>\n"
[30eb4f72f9]770        "Country flag icons used in %1 are part of <b>Flag Icons</b> by "
[fecf053b50]771        "<b>GoSquared</b> licensed under the terms of <i>MIT License</i>,<br>\n"
[30eb4f72f9]772        "see <a href=\"https://www.gosquared.com/\">www.gosquared.com</a><br>\n"
[9eb63a1598]773        "<br>\n"
774        "%1 comes with the default \"embedded\" font <b>DejaVu&nbsp;LGC&nbsp;Sans&nbsp;"
[fecf053b50]775        "Mono</b> from the <b>DejaVu fonts</b> licensed under <i>Free license</i></a>,<br>\n"
[9eb63a1598]776        "see <a href=\"http://dejavu-fonts.org/\">dejavu-fonts.org</a>")
777            .arg("TSPSG");
[43c29c04ba]778
779QFile f(":/files/COPYING");
[9eb63a1598]780    f.open(QIODevice::ReadOnly);
[43c29c04ba]781
[88a59e4d65]782QString translation = QCoreApplication::translate("--------", "AUTHORS %1", "Please, provide translator credits here. %1 will be replaced with VERSION");
[9eb63a1598]783    if ((translation != "AUTHORS %1") && (translation.contains("%1"))) {
[88a59e4d65]784QString about = QCoreApplication::translate("--------", "VERSION", "Please, provide your translation version here.");
[9eb63a1598]785        if (about != "VERSION")
786            translation = translation.arg(about);
787    }
[1babbd6ba3]788
789QDialog *dlg = new QDialog(this);
790QLabel *lblIcon = new QLabel(dlg),
[9eb63a1598]791    *lblTitle = new QLabel(dlg);
[1babbd6ba3]792#ifdef HANDHELD
[88a59e4d65]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);
[1babbd6ba3]794#endif // HANDHELD
[43c29c04ba]795QTabWidget *tabs = new QTabWidget(dlg);
[1babbd6ba3]796QTextBrowser *txtAbout = new QTextBrowser(dlg);
[43c29c04ba]797QTextBrowser *txtLicense = new QTextBrowser(dlg);
798QTextBrowser *txtCredits = new QTextBrowser(dlg);
[1babbd6ba3]799QVBoxLayout *vb = new QVBoxLayout();
800QHBoxLayout *hb1 = new QHBoxLayout(),
[9eb63a1598]801    *hb2 = new QHBoxLayout();
[1babbd6ba3]802QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, dlg);
803
[9eb63a1598]804    lblTitle->setOpenExternalLinks(true);
805    lblTitle->setText(title);
806    lblTitle->setAlignment(Qt::AlignTop);
807    lblTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
[1babbd6ba3]808#ifndef HANDHELD
[9eb63a1598]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()));
[1babbd6ba3]810#endif // HANDHELD
811
[9eb63a1598]812    lblIcon->setPixmap(QPixmap(":/images/tspsg.png").scaledToHeight(lblTitle->sizeHint().height(), Qt::SmoothTransformation));
813    lblIcon->setAlignment(Qt::AlignVCenter);
[1babbd6ba3]814#ifndef HANDHELD
[9eb63a1598]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()));
[1babbd6ba3]816#endif // HANDHELD
817
[9eb63a1598]818    hb1->addWidget(lblIcon);
819    hb1->addWidget(lblTitle);
[1babbd6ba3]820
[9eb63a1598]821    txtAbout->setWordWrapMode(QTextOption::NoWrap);
822    txtAbout->setOpenExternalLinks(true);
823    txtAbout->setHtml(about);
824    txtAbout->moveCursor(QTextCursor::Start);
825    txtAbout->setFrameShape(QFrame::NoFrame);
[7ed8b57eea]826#ifdef Q_OS_BLACKBERRY
827    txtAbout->setAttribute(Qt::WA_InputMethodEnabled, false);
828#endif
[1babbd6ba3]829
[43c29c04ba]830//      txtCredits->setWordWrapMode(QTextOption::NoWrap);
[9eb63a1598]831    txtCredits->setOpenExternalLinks(true);
832    txtCredits->setHtml(credits);
833    txtCredits->moveCursor(QTextCursor::Start);
834    txtCredits->setFrameShape(QFrame::NoFrame);
[7ed8b57eea]835#ifdef Q_OS_BLACKBERRY
836    txtCredits->setAttribute(Qt::WA_InputMethodEnabled, false);
837#endif
[1babbd6ba3]838
[9eb63a1598]839    txtLicense->setWordWrapMode(QTextOption::NoWrap);
840    txtLicense->setOpenExternalLinks(true);
841    txtLicense->setText(f.readAll());
842    txtLicense->moveCursor(QTextCursor::Start);
843    txtLicense->setFrameShape(QFrame::NoFrame);
[7ed8b57eea]844#ifdef Q_OS_BLACKBERRY
845    txtLicense->setAttribute(Qt::WA_InputMethodEnabled, false);
846#endif
[1babbd6ba3]847
[9eb63a1598]848    bb->button(QDialogButtonBox::Ok)->setCursor(QCursor(Qt::PointingHandCursor));
849    bb->button(QDialogButtonBox::Ok)->setIcon(GET_ICON("dialog-ok"));
[3cadf24d00]850
[9eb63a1598]851    hb2->addWidget(bb);
[1babbd6ba3]852
[89e5214692]853#ifdef Q_OS_WINCE_WM
[9eb63a1598]854    vb->setMargin(3);
[89e5214692]855#endif // Q_OS_WINCE_WM
[9eb63a1598]856    vb->addLayout(hb1);
[1babbd6ba3]857#ifdef HANDHELD
[9eb63a1598]858    vb->addWidget(lblSubTitle);
[1babbd6ba3]859#endif // HANDHELD
[43c29c04ba]860
[9eb63a1598]861    tabs->addTab(txtAbout, tr("About"));
862    tabs->addTab(txtLicense, tr("License"));
863    tabs->addTab(txtCredits, tr("Credits"));
864    if (translation != "AUTHORS %1") {
[43c29c04ba]865QTextBrowser *txtTranslation = new QTextBrowser(dlg);
866//              txtTranslation->setWordWrapMode(QTextOption::NoWrap);
[9eb63a1598]867        txtTranslation->setOpenExternalLinks(true);
868        txtTranslation->setText(translation);
869        txtTranslation->moveCursor(QTextCursor::Start);
870        txtTranslation->setFrameShape(QFrame::NoFrame);
[43c29c04ba]871
[9eb63a1598]872        tabs->addTab(txtTranslation, tr("Translation"));
873    }
[43c29c04ba]874#ifndef HANDHELD
[9eb63a1598]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()));
[43c29c04ba]876#endif // HANDHELD
877
[9eb63a1598]878    vb->addWidget(tabs);
879    vb->addLayout(hb2);
[1babbd6ba3]880
[9eb63a1598]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"));
[d97db6d321]884
[9eb63a1598]885    dlg->setLayout(vb);
[1babbd6ba3]886
[9eb63a1598]887    connect(bb, SIGNAL(accepted()), dlg, SLOT(accept()));
[1babbd6ba3]888
[b8a2a118c4]889#ifndef HANDHELD
890    // Adding some eyecandy
[9eb63a1598]891    if (QtWin::isCompositionEnabled())  {
892        QtWin::enableBlurBehindWindow(dlg, true);
893    }
[b8a2a118c4]894#endif // HANDHELD
[1babbd6ba3]895
[5cbcd091ed]896#ifndef HANDHELD
[9eb63a1598]897    dlg->resize(450, 350);
[7ed8b57eea]898#elif defined(Q_OS_SYMBIAN) || defined(Q_OS_BLACKBERRY)
[1b40fef578]899    dlg->setWindowState(Qt::WindowMaximized);
[5cbcd091ed]900#endif
[9eb63a1598]901    QApplication::restoreOverrideCursor();
[1babbd6ba3]902
[9eb63a1598]903    dlg->exec();
[1babbd6ba3]904
[9eb63a1598]905    delete dlg;
[1babbd6ba3]906}
907
908void MainWindow::buttonBackToTaskClicked()
909{
[9eb63a1598]910    tabWidget->setCurrentIndex(0);
[1babbd6ba3]911}
912
913void MainWindow::buttonRandomClicked()
914{
[9eb63a1598]915    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
916    tspmodel->randomize();
917    QApplication::restoreOverrideCursor();
[1babbd6ba3]918}
919
920void MainWindow::buttonSolveClicked()
921{
[07e43cf61a]922    TSPSolver::TMatrix matrix;
923    QList<double> row;
924    int n = spinCities->value();
925    bool ok;
[9eb63a1598]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    }
[1babbd6ba3]937
938QProgressDialog pd(this);
939QProgressBar *pb = new QProgressBar(&pd);
[9eb63a1598]940    pb->setAlignment(Qt::AlignCenter);
941    pb->setFormat(tr("%v of %1 parts found").arg(n));
942    pd.setBar(pb);
[43c29c04ba]943QPushButton *cancel = new QPushButton(&pd);
[9eb63a1598]944    cancel->setIcon(GET_ICON("dialog-cancel"));
[019894f5ef]945    cancel->setText(QCoreApplication::translate("QDialogButtonBox", "Cancel", "No need to translate this. The translation will be taken from Qt translation files."));
[9eb63a1598]946    pd.setCancelButton(cancel);
947    pd.setMaximum(n);
[7ed8b57eea]948    pd.setAutoClose(false);
[9eb63a1598]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();
[1babbd6ba3]955
[89e5214692]956#ifdef Q_OS_WIN32
[43c29c04ba]957HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID*)&tl);
[9eb63a1598]958    if (SUCCEEDED(hr)) {
959        hr = tl->HrInit();
960        if (FAILED(hr)) {
961            tl->Release();
962            tl = NULL;
963        } else {
[b0dfe0844e]964            tl->SetProgressValue(HWND(winId()), 0, n * 2);
[9eb63a1598]965        }
966    }
[43c29c04ba]967#endif
968
[07e43cf61a]969    TSPSolver::CTSPSolver solver;
[9eb63a1598]970    solver.setCleanupOnCancel(false);
971    connect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
972    connect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
[89e5214692]973#ifdef Q_OS_WIN32
[9eb63a1598]974    if (tl != NULL)
975        connect(&solver, SIGNAL(routePartFound(int)), SLOT(solverRoutePartFound(int)));
[43c29c04ba]976#endif
[07e43cf61a]977    TSPSolver::SStep *root = solver.solve(n, matrix);
[89e5214692]978#ifdef Q_OS_WIN32
[9eb63a1598]979    if (tl != NULL)
980        disconnect(&solver, SIGNAL(routePartFound(int)), this, SLOT(solverRoutePartFound(int)));
[43c29c04ba]981#endif
[9eb63a1598]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()) {
[89e5214692]987#ifdef Q_OS_WIN32
[9eb63a1598]988            if (tl != NULL) {
[b0dfe0844e]989                tl->SetProgressState(HWND(winId()), TBPF_ERROR);
[9eb63a1598]990            }
[43c29c04ba]991#endif
[9eb63a1598]992            QApplication::alert(this);
993            QMessageBox::warning(this, tr("Solution Result"), tr("Unable to find a solution.\nMaybe, this task has no solution."));
994        }
[d97db6d321]995        pd.setLabelText(tr("Memory cleanup..."));
[9eb63a1598]996        pd.setMaximum(0);
997        pd.setCancelButton(NULL);
998        pd.show();
[89e5214692]999#ifdef Q_OS_WIN32
[9eb63a1598]1000        if (tl != NULL)
[b0dfe0844e]1001            tl->SetProgressState(HWND(winId()), TBPF_INDETERMINATE);
[43c29c04ba]1002#endif
[9eb63a1598]1003        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
[43c29c04ba]1004
[a713b103e8]1005#ifndef QT_NO_CONCURRENT
[07e43cf61a]1006        QFuture<void> f = QtConcurrent::run(&solver, &TSPSolver::CTSPSolver::cleanup, false);
[9eb63a1598]1007        while (!f.isFinished()) {
1008            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1009        }
[a713b103e8]1010#else
[9eb63a1598]1011        solver.cleanup(true);
[a713b103e8]1012#endif
[9eb63a1598]1013        pd.reset();
[89e5214692]1014#ifdef Q_OS_WIN32
[9eb63a1598]1015        if (tl != NULL) {
[b0dfe0844e]1016            tl->SetProgressState(HWND(winId()), TBPF_NOPROGRESS);
[9eb63a1598]1017            tl->Release();
1018            tl = NULL;
1019        }
[43c29c04ba]1020#endif
[9eb63a1598]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);
[1babbd6ba3]1027
[89e5214692]1028#ifdef Q_OS_WIN32
[9eb63a1598]1029    if (tl != NULL)
[b0dfe0844e]1030        tl->SetProgressValue(HWND(winId()), spinCities->value(), spinCities->value() + solver.getTotalSteps() + 1);
[43c29c04ba]1031#endif
1032
[9eb63a1598]1033    solutionText->clear();
1034    solutionText->setDocumentTitle(tr("Solution of Variant #%1 Task").arg(spinVariant->value()));
[317ba0432e]1035
[345e7b6132]1036QPainter pic;
[8f2427aaf0]1037bool dograph = settings->value("Output/GenerateGraph", DEF_GENERATE_GRAPH).toBool();
1038    if (dograph) {
[9eb63a1598]1039        pic.begin(&graph);
1040        pic.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
[20e8115cee]1041QFont font = qvariant_cast<QFont>(settings->value("Output/Font", QFont(DEF_FONT_FACE)));
[fddcfa4b55]1042        font.setStyleHint(QFont::TypeWriter);
[8f2427aaf0]1043        // Font size in pixels = graph node radius / 2.75.
1044        // See MainWindow::drawNode() for graph node radius calcualtion description.
[89e5214692]1045#ifndef Q_OS_SYMBIAN
[8f2427aaf0]1046        font.setPixelSize(logicalDpiX() * (settings->value("Output/GraphWidth", DEF_GRAPH_WIDTH).toReal() / CM_IN_INCH) / 4.5 / 2.75);
[fddcfa4b55]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
[9eb63a1598]1051        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
1052            font.setWeight(QFont::DemiBold);
[8f2427aaf0]1053            font.setPixelSize(font.pixelSize() * HQ_FACTOR);
[9eb63a1598]1054        }
1055        pic.setFont(font);
1056        pic.setBrush(QBrush(QColor(Qt::white)));
1057        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
[7aaa0b0ec7]1058QPen pen = pic.pen();
[8f2427aaf0]1059            pen.setWidth(HQ_FACTOR);
[9eb63a1598]1060            pic.setPen(pen);
1061        }
1062        pic.setBackgroundMode(Qt::OpaqueMode);
[8f2427aaf0]1063    } else {
1064        graph = QPicture();
[9eb63a1598]1065    }
[345e7b6132]1066
[317ba0432e]1067QTextDocument *doc = solutionText->document();
1068QTextCursor cur(doc);
1069
[9eb63a1598]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);
[a885c3d9d2]1074    cur.insertText(tr("Task:"), fmt_default);
[9eb63a1598]1075    outputMatrix(cur, matrix);
[8f2427aaf0]1076    if (dograph) {
[3cadf24d00]1077#ifdef _T_T_L_
[9eb63a1598]1078        _b_ _i_ _z_ _a_ _r_ _r_ _e_
[3cadf24d00]1079#endif
[9eb63a1598]1080        drawNode(pic, 0);
1081    }
1082    cur.insertHtml("<hr>");
1083    cur.insertBlock(fmt_paragraph);
[07e43cf61a]1084    int imgpos = cur.position();
[9eb63a1598]1085    cur.insertText(tr("Variant #%1 Solution").arg(spinVariant->value()), fmt_default);
1086    cur.endEditBlock();
[317ba0432e]1087
[07e43cf61a]1088    TSPSolver::SStep *step = root;
1089    int c = n = 1;
[9eb63a1598]1090    pb->setFormat(tr("Generating step %v"));
[07e43cf61a]1091    while ((step->next != TSPSolver::SStep::NoNextStep) && (c < spinCities->value())) {
[9eb63a1598]1092        if (pd.wasCanceled()) {
[d97db6d321]1093            pd.setLabelText(tr("Memory cleanup..."));
[9eb63a1598]1094            pd.setMaximum(0);
1095            pd.setCancelButton(NULL);
1096            pd.show();
1097            QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
[89e5214692]1098#ifdef Q_OS_WIN32
[9eb63a1598]1099            if (tl != NULL)
[b0dfe0844e]1100                tl->SetProgressState(HWND(winId()), TBPF_INDETERMINATE);
[43c29c04ba]1101#endif
[a713b103e8]1102#ifndef QT_NO_CONCURRENT
[07e43cf61a]1103            QFuture<void> f = QtConcurrent::run(&solver, &TSPSolver::CTSPSolver::cleanup, false);
[9eb63a1598]1104            while (!f.isFinished()) {
1105                QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1106            }
[a713b103e8]1107#else
[9eb63a1598]1108            solver.cleanup(true);
[a713b103e8]1109#endif
[9eb63a1598]1110            solutionText->clear();
1111            toggleSolutionActions(false);
[89e5214692]1112#ifdef Q_OS_WIN32
[9eb63a1598]1113            if (tl != NULL) {
[b0dfe0844e]1114                tl->SetProgressState(HWND(winId()), TBPF_NOPROGRESS);
[9eb63a1598]1115                tl->Release();
1116                tl = NULL;
1117            }
[43c29c04ba]1118#endif
[9eb63a1598]1119            return;
1120        }
1121        pd.setValue(n);
[89e5214692]1122#ifdef Q_OS_WIN32
[9eb63a1598]1123        if (tl != NULL)
[b0dfe0844e]1124            tl->SetProgressValue(HWND(winId()), spinCities->value() + n, spinCities->value() + solver.getTotalSteps() + 1);
[43c29c04ba]1125#endif
[1babbd6ba3]1126
[9eb63a1598]1127        cur.beginEditBlock();
1128        cur.insertBlock(fmt_paragraph);
[a885c3d9d2]1129        cur.insertText(tr("Step #%1").arg(n), fmt_default);
[9eb63a1598]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        }
[8f2427aaf0]1133        if (step->alts.empty())
1134            cur.insertBlock(fmt_lastparagraph);
1135        else
1136            cur.insertBlock(fmt_paragraph);
[07e43cf61a]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);
[9eb63a1598]1138        if (!step->alts.empty()) {
[07e43cf61a]1139            TSPSolver::SStep::SCandidate cand;
[9eb63a1598]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            }
[8f2427aaf0]1146            cur.insertBlock(fmt_lastparagraph);
[9eb63a1598]1147            cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist);
1148        }
1149        cur.endEditBlock();
1150
[8f2427aaf0]1151        if (dograph) {
[9eb63a1598]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
[07e43cf61a]1159        if (step->next == TSPSolver::SStep::RightBranch) {
[9eb63a1598]1160            c++;
1161            step = step->prNode;
[07e43cf61a]1162        } else if (step->next == TSPSolver::SStep::LeftBranch) {
[9eb63a1598]1163            step = step->plNode;
1164        } else
1165            break;
1166    }
1167    pb->setFormat(tr("Generating footer"));
1168    pd.setValue(n);
[89e5214692]1169#ifdef Q_OS_WIN32
[9eb63a1598]1170    if (tl != NULL)
[b0dfe0844e]1171        tl->SetProgressValue(HWND(winId()), spinCities->value() + n, spinCities->value() + solver.getTotalSteps() + 1);
[43c29c04ba]1172#endif
[1babbd6ba3]1173
[9eb63a1598]1174    cur.beginEditBlock();
1175    cur.insertBlock(fmt_paragraph);
1176    if (solver.isOptimal())
[8f2427aaf0]1177        cur.insertText(tr("Optimal path:"), fmt_default);
[9eb63a1598]1178    else
[8f2427aaf0]1179        cur.insertText(tr("Resulting path:"), fmt_default);
[9eb63a1598]1180
1181    cur.insertBlock(fmt_paragraph);
1182    cur.insertText("  " + solver.getSortedPath(tr("City %1")));
1183
[8f2427aaf0]1184    if (solver.isOptimal())
1185        cur.insertBlock(fmt_paragraph);
1186    else
1187        cur.insertBlock(fmt_lastparagraph);
[9eb63a1598]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
[8f2427aaf0]1198    if (dograph) {
[9eb63a1598]1199        pic.end();
[345e7b6132]1200
[c8ed26ddf1]1201        QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32);
[79f83a3845]1202        i.fill(QColor(255, 255, 255, 0).rgba());
[9eb63a1598]1203        pic.begin(&i);
1204        pic.drawPicture(1, 1, graph);
1205        pic.end();
1206        doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i);
[345e7b6132]1207
1208QTextImageFormat img;
[9eb63a1598]1209        img.setName("tspsg://graph.pic");
1210        if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool()) {
[8f2427aaf0]1211            img.setWidth(i.width() / HQ_FACTOR);
1212            img.setHeight(i.height() / HQ_FACTOR);
[9eb63a1598]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
[d97db6d321]1228    pd.setLabelText(tr("Memory cleanup..."));
[9eb63a1598]1229    pd.setMaximum(0);
1230    pd.setCancelButton(NULL);
1231    QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
[89e5214692]1232#ifdef Q_OS_WIN32
[9eb63a1598]1233    if (tl != NULL)
[b0dfe0844e]1234        tl->SetProgressState(HWND(winId()), TBPF_INDETERMINATE);
[43c29c04ba]1235#endif
[a713b103e8]1236#ifndef QT_NO_CONCURRENT
[07e43cf61a]1237    QFuture<void> f = QtConcurrent::run(&solver, &TSPSolver::CTSPSolver::cleanup, false);
[9eb63a1598]1238    while (!f.isFinished()) {
1239        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1240    }
[a713b103e8]1241#else
[9eb63a1598]1242    solver.cleanup(true);
[a713b103e8]1243#endif
[9eb63a1598]1244    toggleSolutionActions();
1245    tabWidget->setCurrentIndex(1);
[89e5214692]1246#ifdef Q_OS_WIN32
[9eb63a1598]1247    if (tl != NULL) {
[b0dfe0844e]1248        tl->SetProgressState(HWND(winId()), TBPF_NOPROGRESS);
[9eb63a1598]1249        tl->Release();
1250        tl = NULL;
1251    }
[43c29c04ba]1252#endif
1253
[9eb63a1598]1254    pd.reset();
1255    QApplication::alert(this, 3000);
[1babbd6ba3]1256}
1257
1258void MainWindow::dataChanged()
1259{
[9eb63a1598]1260    setWindowModified(true);
[1babbd6ba3]1261}
1262
1263void MainWindow::dataChanged(const QModelIndex &tl, const QModelIndex &br)
1264{
[9eb63a1598]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    }
[1babbd6ba3]1272}
1273
[89e5214692]1274#ifdef Q_OS_WINCE_WM
[1babbd6ba3]1275void MainWindow::changeEvent(QEvent *ev)
1276{
[9eb63a1598]1277    if ((ev->type() == QEvent::ActivationChange) && isActiveWindow())
1278        desktopResized(0);
[1babbd6ba3]1279
[9eb63a1598]1280    QWidget::changeEvent(ev);
[1babbd6ba3]1281}
1282
1283void MainWindow::desktopResized(int screen)
1284{
[9eb63a1598]1285    if ((screen != 0) || !isActiveWindow())
1286        return;
[1babbd6ba3]1287
1288QRect availableGeometry = QApplication::desktop()->availableGeometry(0);
[9eb63a1598]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    }
[1babbd6ba3]1306}
[89e5214692]1307#endif // Q_OS_WINCE_WM
[1babbd6ba3]1308
1309void MainWindow::numCitiesChanged(int nCities)
1310{
[9eb63a1598]1311    blockSignals(true);
1312    spinCities->setValue(nCities);
1313    blockSignals(false);
[1babbd6ba3]1314}
1315
1316#ifndef QT_NO_PRINTER
1317void MainWindow::printPreview(QPrinter *printer)
1318{
[9eb63a1598]1319    solutionText->print(printer);
[1babbd6ba3]1320}
1321#endif // QT_NO_PRINTER
1322
[89e5214692]1323#ifdef Q_OS_WIN32
[43c29c04ba]1324void MainWindow::solverRoutePartFound(int n)
1325{
[b0dfe0844e]1326    tl->SetProgressValue(HWND(winId()), n, spinCities->value() * 2);
[43c29c04ba]1327}
[89e5214692]1328#endif // Q_OS_WIN32
[43c29c04ba]1329
[1babbd6ba3]1330void MainWindow::spinCitiesValueChanged(int n)
1331{
[9eb63a1598]1332    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[1babbd6ba3]1333int count = tspmodel->numCities();
[9eb63a1598]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();
[1babbd6ba3]1341}
1342
[f5c945d7ac]1343void MainWindow::check4Updates(bool silent)
1344{
[89e5214692]1345#ifdef Q_OS_WIN32
[9eb63a1598]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    }
[0007f69c46]1353#else
[9eb63a1598]1354    Q_UNUSED(silent)
[f5c945d7ac]1355#endif
[9eb63a1598]1356    settings->setValue("Check4Updates/LastAttempt", QDate::currentDate().toString(Qt::ISODate));
[f5c945d7ac]1357}
1358
[1babbd6ba3]1359void MainWindow::closeEvent(QCloseEvent *ev)
1360{
[9eb63a1598]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
[7bb19df196]1369#ifndef HANDHELD
[9eb63a1598]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        }
[a713b103e8]1377#else
[9eb63a1598]1378        settings->setValue("MainWindow/ToolbarVisible", toolBarMain->isVisible());
[7bb19df196]1379#endif // HANDHELD
[9eb63a1598]1380    } else {
1381        settings->remove("SettingsReset");
1382    }
[1babbd6ba3]1383
[9eb63a1598]1384    QMainWindow::closeEvent(ev);
[1babbd6ba3]1385}
1386
[b574c383b7]1387void MainWindow::dragEnterEvent(QDragEnterEvent *ev)
1388{
[9eb63a1598]1389    if (ev->mimeData()->hasUrls() && (ev->mimeData()->urls().count() == 1)) {
[b574c383b7]1390QFileInfo fi(ev->mimeData()->urls().first().toLocalFile());
[9eb63a1598]1391        if ((fi.suffix() == "tspt") || (fi.suffix() == "zkt"))
1392            ev->acceptProposedAction();
1393    }
[b574c383b7]1394}
1395
[07e43cf61a]1396void MainWindow::drawNode(QPainter &pic, int nstep, bool left, TSPSolver::SStep *step)
[345e7b6132]1397{
[8f2427aaf0]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;
[9eb63a1598]1404    if (settings->value("Output/HQGraph", DEF_HQ_GRAPH).toBool())
[8f2427aaf0]1405        r *= HQ_FACTOR;
[89e5214692]1406#ifdef Q_OS_SYMBIAN
[144fbe6b96]1407    /*! \hack HACK: Solution graph on Symbian is visually larger than on
[23ad8db4a5]1408     *   Windows Mobile. This coefficient makes it about the same size.
1409     */
1410    r /= 1.3;
1411#endif
1412
[345e7b6132]1413qreal x, y;
[9eb63a1598]1414    if (step != NULL)
1415        x = left ? r : r * 3.5;
1416    else
1417        x = r * 2.25;
1418    y = r * (3 * nstep + 1);
[345e7b6132]1419
[3cadf24d00]1420#ifdef _T_T_L_
[9eb63a1598]1421    if (nstep == -481124) {
1422        _t_t_l_(pic, r, x);
1423        return;
1424    }
[3cadf24d00]1425#endif
1426
[9eb63a1598]1427    pic.drawEllipse(QPointF(x, y), r, r);
[345e7b6132]1428
[9eb63a1598]1429    if (step != NULL) {
[345e7b6132]1430QFont font;
[9eb63a1598]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) {
[5cbcd091ed]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()));
[9eb63a1598]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) {
[07e43cf61a]1453        pic.drawLine(QPointF(x, y - r), QPointF((step->pNode->pNode->next == TSPSolver::SStep::RightBranch) ? r * 3.5 : r, y - 2 * r));
[9eb63a1598]1454    }
[345e7b6132]1455
1456}
1457
[b574c383b7]1458void MainWindow::dropEvent(QDropEvent *ev)
1459{
[9eb63a1598]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    }
[b574c383b7]1470}
1471
[b26dc16dcf]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);
[7a39458d16]1502        pic.setFormat(format.toLatin1());
[b26dc16dcf]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)) {
[b96b44b6b7]1512            QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
[b26dc16dcf]1513            QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution graph.\nError: %1").arg(pic.errorString()));
[b96b44b6b7]1514            QApplication::restoreOverrideCursor();
[b26dc16dcf]1515            return QByteArray();
1516        }
1517#if !defined(NOSVG)
1518    }
1519#endif // NOSVG
1520    return data;
1521}
1522
[1babbd6ba3]1523void MainWindow::initDocStyleSheet()
1524{
[9eb63a1598]1525    solutionText->document()->setDefaultFont(qvariant_cast<QFont>(settings->value("Output/Font", QFont(DEF_FONT_FACE, DEF_FONT_SIZE))));
[317ba0432e]1526
[a885c3d9d2]1527    fmt_paragraph.setTopMargin(5);
[9eb63a1598]1528    fmt_paragraph.setRightMargin(10);
1529    fmt_paragraph.setBottomMargin(0);
1530    fmt_paragraph.setLeftMargin(10);
[8f2427aaf0]1531
1532    fmt_lastparagraph.setTopMargin(5);
1533    fmt_lastparagraph.setRightMargin(10);
1534    fmt_lastparagraph.setBottomMargin(15);
1535    fmt_lastparagraph.setLeftMargin(10);
[317ba0432e]1536
[0a4e16b182]1537    settings->beginGroup("Output/Colors");
1538
[9eb63a1598]1539    fmt_table.setTopMargin(5);
1540    fmt_table.setRightMargin(10);
[a885c3d9d2]1541    fmt_table.setBottomMargin(0);
[9eb63a1598]1542    fmt_table.setLeftMargin(10);
[0a4e16b182]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);
[317ba0432e]1548
[9eb63a1598]1549    fmt_cell.setAlignment(Qt::AlignHCenter);
[317ba0432e]1550
[0a4e16b182]1551QColor color = QColor(settings->value("Text", DEF_TEXT_COLOR).toString());
[1babbd6ba3]1552QColor hilight;
[9eb63a1598]1553    if (color.value() < 192)
[356169a3d3]1554        hilight.setHsv(color.hue(), color.saturation(), 127 + (color.value() / 2));
[9eb63a1598]1555    else
1556        hilight.setHsv(color.hue(), color.saturation(), color.value() / 2);
[317ba0432e]1557
[89e5214692]1558#ifdef Q_OS_SYMBIAN
[5f49b20d9d]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
[9eb63a1598]1565    solutionText->document()->setDefaultStyleSheet(QString("* {color: %1;}").arg(color.name()));
1566    fmt_default.setForeground(QBrush(color));
[89e5214692]1567#ifdef Q_OS_SYMBIAN
[5f49b20d9d]1568    }
1569#endif
[317ba0432e]1570
[0a4e16b182]1571    fmt_selected.setForeground(QBrush(QColor(settings->value("Selected", DEF_SELECTED_COLOR).toString())));
[9eb63a1598]1572    fmt_selected.setFontWeight(QFont::Bold);
[317ba0432e]1573
[0a4e16b182]1574    fmt_alternate.setForeground(QBrush(QColor(settings->value("Alternate", DEF_ALTERNATE_COLOR).toString())));
[9eb63a1598]1575    fmt_alternate.setFontWeight(QFont::Bold);
1576    fmt_altlist.setForeground(QBrush(hilight));
[317ba0432e]1577
[9eb63a1598]1578    settings->endGroup();
[1babbd6ba3]1579}
1580
1581void MainWindow::loadLangList()
1582{
[3cadf24d00]1583QMap<QString, QStringList> langlist;
1584QFileInfoList langs;
1585QFileInfo lang;
1586QStringList language, dirs;
1587QTranslator t;
1588QDir dir;
[9eb63a1598]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    }
[3cadf24d00]1613
1614QAction *a;
[9eb63a1598]1615    foreach (language, langlist) {
1616        a = menuSettingsLanguage->addAction(language.at(2));
[9adbc413c7]1617#ifndef QT_NO_STATUSTIP
[9eb63a1598]1618        a->setStatusTip(language.at(3));
[9adbc413c7]1619#endif
[356169a3d3]1620#if QT_VERSION >= QT_VERSION_CHECK(4,6,0)
[9eb63a1598]1621        a->setIcon(QIcon::fromTheme(QString("flag-%1").arg(language.at(1)), QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1)))));
[2a436ea693]1622#else
[9eb63a1598]1623        a->setIcon(QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1))));
[2a436ea693]1624#endif
[9eb63a1598]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    }
[1babbd6ba3]1631}
1632
1633bool MainWindow::loadLanguage(const QString &lang)
1634{
1635// i18n
1636bool ad = false;
1637QString lng = lang;
[9eb63a1598]1638    if (lng.isEmpty()) {
1639        ad = settings->value("Language").toString().isEmpty();
1640        lng = settings->value("Language", QLocale::system().name()).toString();
1641    }
[1babbd6ba3]1642static QTranslator *qtTranslator; // Qt library translator
[9eb63a1598]1643    if (qtTranslator) {
1644        qApp->removeTranslator(qtTranslator);
1645        delete qtTranslator;
1646        qtTranslator = NULL;
1647    }
[1babbd6ba3]1648static QTranslator *translator; // Application translator
[9eb63a1598]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);
[b26801b000]1660    if (qtTranslator->load("qt_" + lng, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
[4cc94b19ad]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
[9eb63a1598]1665        qApp->installTranslator(qtTranslator);
[b26801b000]1666    } else {
1667        // Qt library translation unavailable for this language.
1668        delete qtTranslator;
1669        qtTranslator = NULL;
[9eb63a1598]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;
[1babbd6ba3]1692}
1693
[e3533af1cf]1694void MainWindow::loadStyleList()
1695{
[9eb63a1598]1696    menuSettingsStyle->clear();
[e3533af1cf]1697QStringList styles = QStyleFactory::keys();
[9eb63a1598]1698    menuSettingsStyle->insertAction(NULL, actionSettingsStyleSystem);
1699    actionSettingsStyleSystem->setChecked(!settings->contains("Style"));
1700    menuSettingsStyle->addSeparator();
[e3533af1cf]1701QAction *a;
[9eb63a1598]1702    foreach (QString style, styles) {
1703        a = menuSettingsStyle->addAction(style);
1704        a->setData(false);
[9adbc413c7]1705#ifndef QT_NO_STATUSTIP
[9eb63a1598]1706        a->setStatusTip(tr("Set application style to %1").arg(style));
[9adbc413c7]1707#endif
[9eb63a1598]1708        a->setCheckable(true);
1709        a->setActionGroup(groupSettingsStyleList);
[5f8c8ea92c]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)
[97e90f9be6]1712#ifndef Q_WS_MAEMO_5
[5f8c8ea92c]1713            || QString(QApplication::style()->metaObject()->className()).contains(rx)
[97e90f9be6]1714#endif
[9eb63a1598]1715        ) {
1716            a->setChecked(true);
1717        }
1718    }
[e3533af1cf]1719}
1720
[7bb19df196]1721void MainWindow::loadToolbarList()
1722{
[9eb63a1598]1723    menuSettingsToolbars->clear();
[7bb19df196]1724#ifndef HANDHELD
[9eb63a1598]1725    menuSettingsToolbars->insertAction(NULL, actionSettingsToolbarsConfigure);
1726    menuSettingsToolbars->addSeparator();
[7bb19df196]1727QList<QToolBar *> list = toolBarManager->toolBars();
[9eb63a1598]1728    foreach (QToolBar *t, list) {
1729        menuSettingsToolbars->insertAction(NULL, t->toggleViewAction());
1730    }
[7bb19df196]1731#else // HANDHELD
[9eb63a1598]1732    menuSettingsToolbars->insertAction(NULL, toolBarMain->toggleViewAction());
[7bb19df196]1733#endif // HANDHELD
1734}
1735
[1babbd6ba3]1736bool MainWindow::maybeSave()
1737{
[9eb63a1598]1738    if (!isWindowModified())
1739        return true;
[89e5214692]1740#ifdef Q_OS_SYMBIAN
[fddcfa4b55]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
[9eb63a1598]1745    if (res == QMessageBox::Save)
1746        return actionFileSaveTriggered();
1747    else if (res == QMessageBox::Cancel)
1748        return false;
1749    else
1750        return true;
[1babbd6ba3]1751}
1752
[07e43cf61a]1753void MainWindow::outputMatrix(QTextCursor &cur, const TSPSolver::TMatrix &matrix)
[1babbd6ba3]1754{
1755int n = spinCities->value();
[317ba0432e]1756QTextTable *table = cur.insertTable(n, n, fmt_table);
1757
[9eb63a1598]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);
[1babbd6ba3]1771}
1772
[07e43cf61a]1773void MainWindow::outputMatrix(QTextCursor &cur, const TSPSolver::SStep &step)
[1babbd6ba3]1774{
1775int n = spinCities->value();
[317ba0432e]1776QTextTable *table = cur.insertTable(n, n, fmt_table);
1777
[9eb63a1598]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 {
[07e43cf61a]1787    TSPSolver::SStep::SCandidate cand;
[9eb63a1598]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);
[1babbd6ba3]1800}
1801
[89e5214692]1802#ifdef Q_OS_SYMBIAN
[1b40fef578]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}
[89e5214692]1822#endif // Q_OS_SYMBIAN
[1b40fef578]1823
[1babbd6ba3]1824void MainWindow::retranslateUi(bool all)
1825{
[9eb63a1598]1826    if (all)
1827        Ui_MainWindow::retranslateUi(this);
[1babbd6ba3]1828
[7ed8b57eea]1829#ifdef Q_OS_BLACKBERRY
1830    menuSettings->removeAction(menuSettingsStyle->menuAction());
1831#else
[9eb63a1598]1832    loadStyleList();
[7ed8b57eea]1833#endif
[9eb63a1598]1834    loadToolbarList();
[e3533af1cf]1835
[7ed8b57eea]1836#ifndef QT_NO_PRINTDIALOG
[9eb63a1598]1837    actionFilePrintPreview->setText(tr("P&rint Preview..."));
[1babbd6ba3]1838#ifndef QT_NO_TOOLTIP
[9eb63a1598]1839    actionFilePrintPreview->setToolTip(tr("Preview solution results"));
[1babbd6ba3]1840#endif // QT_NO_TOOLTIP
1841#ifndef QT_NO_STATUSTIP
[9eb63a1598]1842    actionFilePrintPreview->setStatusTip(tr("Preview current solution results before printing"));
[20e8115cee]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"));
[88a59e4d65]1851#endif // QT_NO_STATUSTIP
[1babbd6ba3]1852
[9eb63a1598]1853    actionFilePrint->setText(tr("&Print..."));
[1babbd6ba3]1854#ifndef QT_NO_TOOLTIP
[9eb63a1598]1855    actionFilePrint->setToolTip(tr("Print solution"));
[1babbd6ba3]1856#endif // QT_NO_TOOLTIP
1857#ifndef QT_NO_STATUSTIP
[9eb63a1598]1858    actionFilePrint->setStatusTip(tr("Print current solution results"));
[1babbd6ba3]1859#endif // QT_NO_STATUSTIP
[7ed8b57eea]1860#ifndef QT_NO_SHORTCUT
[9eb63a1598]1861    actionFilePrint->setShortcut(tr("Ctrl+P"));
[7ed8b57eea]1862#endif // QT_NO_SHORTCUT
1863#endif // QT_NO_PRINTDIALOG
[8b0661d1ee]1864
[20e8115cee]1865#ifndef QT_NO_STATUSTIP
1866    actionFileExit->setStatusTip(tr("Exit %1").arg(QCoreApplication::applicationName()));
1867#endif // QT_NO_STATUSTIP
1868
[8b0661d1ee]1869#ifndef HANDHELD
[9eb63a1598]1870    actionSettingsToolbarsConfigure->setText(tr("Configure..."));
[8b0661d1ee]1871#ifndef QT_NO_STATUSTIP
[9eb63a1598]1872    actionSettingsToolbarsConfigure->setStatusTip(tr("Customize toolbars"));
[8b0661d1ee]1873#endif // QT_NO_STATUSTIP
1874#endif // HANDHELD
1875
[88a59e4d65]1876#ifndef QT_NO_STATUSTIP
[9eb63a1598]1877    actionHelpReportBug->setStatusTip(tr("Report about a bug in %1").arg(QCoreApplication::applicationName()));
[88a59e4d65]1878#endif // QT_NO_STATUSTIP
[9eb63a1598]1879    if (actionHelpCheck4Updates != NULL) {
1880        actionHelpCheck4Updates->setText(tr("Check for &Updates..."));
[1babbd6ba3]1881#ifndef QT_NO_STATUSTIP
[9eb63a1598]1882        actionHelpCheck4Updates->setStatusTip(tr("Check for %1 updates").arg(QCoreApplication::applicationName()));
[1babbd6ba3]1883#endif // QT_NO_STATUSTIP
[9eb63a1598]1884    }
[88a59e4d65]1885#ifndef QT_NO_STATUSTIP
[9eb63a1598]1886    actionHelpAbout->setStatusTip(tr("About %1").arg(QCoreApplication::applicationName()));
[88a59e4d65]1887#endif // QT_NO_STATUSTIP
[23ad8db4a5]1888
[89e5214692]1889#ifdef Q_OS_SYMBIAN
[23ad8db4a5]1890    actionRightSoftKey->setText(tr("E&xit"));
1891#endif
[1babbd6ba3]1892}
1893
[2a5e50e0a9]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)");
[9eb63a1598]1901    filters.append(tr("All Files") + " (*)");
[2a5e50e0a9]1902#endif
[1babbd6ba3]1903QString file;
[9eb63a1598]1904    if ((fileName == tr("Untitled") + ".tspt") && settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool()) {
[2a5e50e0a9]1905#ifdef Q_OS_BLACKBERRY
1906        file = settings->value(OS"/LastUsed/TaskSavePath", "/accounts/1000/shared/documents").toString();
1907#else
[9eb63a1598]1908        file = settings->value(OS"/LastUsed/TaskSavePath").toString();
[2a5e50e0a9]1909#endif
[9eb63a1598]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";
[1babbd6ba3]1917
[2a5e50e0a9]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;
[9eb63a1598]1939    file = QFileDialog::getSaveFileName(this, tr("Task Save"), file, filters.join(";;"), NULL, opts);
1940    if (file.isEmpty())
1941        return false;
[2a5e50e0a9]1942#endif
1943    if (settings->value("SaveLastUsed", DEF_SAVE_LAST_USED).toBool())
[9eb63a1598]1944        settings->setValue(OS"/LastUsed/TaskSavePath", QFileInfo(file).path());
[144fbe6b96]1945    if (QFileInfo(file).suffix().isEmpty()) {
1946        file.append(".tspt");
1947    }
[9eb63a1598]1948
1949    if (tspmodel->saveTask(file)) {
1950        setFileName(file);
1951        setWindowModified(false);
1952        return true;
1953    }
1954    return false;
[1babbd6ba3]1955}
1956
1957void MainWindow::setFileName(const QString &fileName)
1958{
[9eb63a1598]1959    this->fileName = fileName;
1960    setWindowTitle(QString("%1[*] - %2").arg(QFileInfo(fileName).completeBaseName()).arg(QCoreApplication::applicationName()));
[1babbd6ba3]1961}
1962
1963void MainWindow::setupUi()
1964{
[9eb63a1598]1965    Ui_MainWindow::setupUi(this);
[1babbd6ba3]1966
[89e5214692]1967#ifdef Q_OS_SYMBIAN
[1b40fef578]1968    setWindowFlags(windowFlags() | Qt::WindowSoftkeysVisibleHint);
[89e5214692]1969#endif // Q_OS_SYMBIAN
[1b40fef578]1970
[9eb63a1598]1971    // File Menu
1972    actionFileNew->setIcon(GET_ICON("document-new"));
1973    actionFileOpen->setIcon(GET_ICON("document-open"));
1974    actionFileSave->setIcon(GET_ICON("document-save"));
[7ed8b57eea]1975#if !defined(HANDHELD) || defined(Q_OS_BLACKBERRY)
[9eb63a1598]1976    menuFileSaveAs->setIcon(GET_ICON("document-save-as"));
[a713b103e8]1977#endif
[9eb63a1598]1978    actionFileExit->setIcon(GET_ICON("application-exit"));
1979    // Settings Menu
[7ed8b57eea]1980#if !defined(HANDHELD) || defined(Q_OS_BLACKBERRY)
[9eb63a1598]1981    menuSettingsLanguage->setIcon(GET_ICON("preferences-desktop-locale"));
[356169a3d3]1982#if QT_VERSION >= QT_VERSION_CHECK(4,6,0)
[9eb63a1598]1983    actionSettingsLanguageEnglish->setIcon(QIcon::fromTheme("flag-gb", QIcon(":/images/icons/l10n/flag-gb.png")));
[356169a3d3]1984#else
[9eb63a1598]1985    actionSettingsLanguageEnglish->setIcon(QIcon(":/images/icons/l10n/flag-gb.png"));
[356169a3d3]1986#endif // QT_VERSION >= QT_VERSION_CHECK(4,6,0)
[9eb63a1598]1987    menuSettingsStyle->setIcon(GET_ICON("preferences-desktop-theme"));
[a713b103e8]1988#endif // HANDHELD
[9eb63a1598]1989    actionSettingsPreferences->setIcon(GET_ICON("preferences-system"));
1990    // Help Menu
[7ed8b57eea]1991#if !defined(HANDHELD) || defined(Q_OS_BLACKBERRY)
[9eb63a1598]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"));
[7ed8b57eea]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
[356169a3d3]2002#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
[fddcfa4b55]2003    actionHelpAboutQt->setIcon(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"));
[7ed8b57eea]2004#else // QT_VERSION < QT_VERSION_CHECK(5,0,0)
[356169a3d3]2005    actionHelpAboutQt->setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
2006#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0)
[7ed8b57eea]2007#endif // Q_OS_BLACKBERRY
[356169a3d3]2008#endif // HANDHELD
[9eb63a1598]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"));
[3cadf24d00]2014
[2a436ea693]2015//      action->setIcon(GET_ICON(""));
[3cadf24d00]2016
[356169a3d3]2017#if QT_VERSION >= QT_VERSION_CHECK(4,6,0)
[9eb63a1598]2018    setToolButtonStyle(Qt::ToolButtonFollowStyle);
[1babbd6ba3]2019#endif
2020
2021#ifndef HANDHELD
2022QStatusBar *statusbar = new QStatusBar(this);
[9eb63a1598]2023    statusbar->setObjectName("statusbar");
2024    setStatusBar(statusbar);
[1babbd6ba3]2025#endif // HANDHELD
2026
[89e5214692]2027#ifdef Q_OS_WINCE_WM
[9eb63a1598]2028    menuBar()->setDefaultAction(menuFile->menuAction());
[1babbd6ba3]2029
2030QScrollArea *scrollArea = new QScrollArea(this);
[9eb63a1598]2031    scrollArea->setFrameShape(QFrame::NoFrame);
2032    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2033    scrollArea->setWidgetResizable(true);
2034    scrollArea->setWidget(tabWidget);
2035    setCentralWidget(scrollArea);
[1babbd6ba3]2036#else
[9eb63a1598]2037    setCentralWidget(tabWidget);
[89e5214692]2038#endif // Q_OS_WINCE_WM
[1babbd6ba3]2039
[9eb63a1598]2040    //! \hack HACK: A little hack for toolbar icons to have a sane size.
[97e90f9be6]2041#if defined(HANDHELD) && !defined(Q_WS_MAEMO_5)
[89e5214692]2042#ifdef Q_OS_SYMBIAN
[23ad8db4a5]2043    toolBarMain->setIconSize(QSize(logicalDpiX() / 5.2, logicalDpiY() / 5.2));
[5cbcd091ed]2044#else
[9eb63a1598]2045    toolBarMain->setIconSize(QSize(logicalDpiX() / 4, logicalDpiY() / 4));
[89e5214692]2046#endif // Q_OS_SYMBIAN
[5cbcd091ed]2047#endif // HANDHELD && !Q_WS_MAEMO_5
[7bb19df196]2048QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
[5cbcd091ed]2049    if (tb != NULL) {
[9eb63a1598]2050        tb->setMenu(menuFileSaveAs);
2051        tb->setPopupMode(QToolButton::MenuButtonPopup);
2052    }
[1babbd6ba3]2053
[8b0661d1ee]2054//      solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, DEF_FONT_SIZE)).value<QFont>());
[9eb63a1598]2055    solutionText->setWordWrapMode(QTextOption::WordWrap);
[1babbd6ba3]2056
[7ed8b57eea]2057#ifndef QT_NO_PRINTDIALOG
[9eb63a1598]2058    actionFilePrintPreview = new QAction(this);
2059    actionFilePrintPreview->setObjectName("actionFilePrintPreview");
2060    actionFilePrintPreview->setEnabled(false);
2061    actionFilePrintPreview->setIcon(GET_ICON("document-print-preview"));
[1babbd6ba3]2062
[20e8115cee]2063    actionFilePageSetup = new QAction(this);
2064    actionFilePageSetup->setObjectName("actionFilePrintSetup");
2065//    actionFilePageSetup->setEnabled(false);
[356169a3d3]2066#if QT_VERSION >= QT_VERSION_CHECK(4,6,0)
[20e8115cee]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
[9eb63a1598]2072    actionFilePrint = new QAction(this);
2073    actionFilePrint->setObjectName("actionFilePrint");
2074    actionFilePrint->setEnabled(false);
2075    actionFilePrint->setIcon(GET_ICON("document-print"));
[1babbd6ba3]2076
[20e8115cee]2077    menuFile->insertAction(actionFileExit, actionFilePrintPreview);
2078    menuFile->insertAction(actionFileExit, actionFilePageSetup);
2079    menuFile->insertAction(actionFileExit, actionFilePrint);
[9eb63a1598]2080    menuFile->insertSeparator(actionFileExit);
[1babbd6ba3]2081
[9eb63a1598]2082    toolBarMain->insertAction(actionSettingsPreferences, actionFilePrint);
[7ed8b57eea]2083#endif // QT_NO_PRINTDIALOG
[e51c78af27]2084
[9eb63a1598]2085    groupSettingsLanguageList = new QActionGroup(this);
[97e90f9be6]2086#ifdef Q_WS_MAEMO_5
[9eb63a1598]2087    groupSettingsLanguageList->addAction(actionSettingsLanguageAutodetect);
[97e90f9be6]2088#endif
[9eb63a1598]2089    actionSettingsLanguageEnglish->setData("en");
2090    actionSettingsLanguageEnglish->setActionGroup(groupSettingsLanguageList);
2091    loadLangList();
2092    actionSettingsLanguageAutodetect->setChecked(settings->value("Language", "").toString().isEmpty());
[e3533af1cf]2093
[9eb63a1598]2094    actionSettingsStyleSystem->setData(true);
2095    groupSettingsStyleList = new QActionGroup(this);
[97e90f9be6]2096#ifdef Q_WS_MAEMO_5
[9eb63a1598]2097    groupSettingsStyleList->addAction(actionSettingsStyleSystem);
[97e90f9be6]2098#endif
[e3533af1cf]2099
[7bb19df196]2100#ifndef HANDHELD
[9eb63a1598]2101    actionSettingsToolbarsConfigure = new QAction(this);
2102    actionSettingsToolbarsConfigure->setIcon(GET_ICON("configure-toolbars"));
[7bb19df196]2103#endif // HANDHELD
2104
[9eb63a1598]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;
[1babbd6ba3]2113
[47c811cc09]2114    spinCities->setMaximum(settings->value("Tweaks/MaxNumCities", MAX_NUM_CITIES).toInt());
[1babbd6ba3]2115
[94cd045fad]2116#ifndef HANDHELD
[20e8115cee]2117    toolBarManager = new QtToolBarManager(this);
[9eb63a1598]2118    toolBarManager->setMainWindow(this);
[7bb19df196]2119QString cat = toolBarMain->windowTitle();
[9eb63a1598]2120    toolBarManager->addToolBar(toolBarMain, cat);
[94cd045fad]2121#ifndef QT_NO_PRINTER
[9eb63a1598]2122    toolBarManager->addAction(actionFilePrintPreview, cat);
[20e8115cee]2123    toolBarManager->addAction(actionFilePageSetup, cat);
[94cd045fad]2124#endif // QT_NO_PRINTER
[9eb63a1598]2125    toolBarManager->addAction(actionHelpContents, cat);
2126    toolBarManager->addAction(actionHelpContextual, cat);
2127    toolBarManager->restoreState(settings->value("MainWindow/Toolbars").toByteArray());
[a713b103e8]2128#else
[9eb63a1598]2129    toolBarMain->setVisible(settings->value("MainWindow/ToolbarVisible", true).toBool());
[94cd045fad]2130#endif // HANDHELD
[7bb19df196]2131
[89e5214692]2132#ifdef Q_OS_SYMBIAN
[23ad8db4a5]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
[9eb63a1598]2141    retranslateUi(false);
[7bb19df196]2142
[b8a2a118c4]2143#ifndef HANDHELD
2144    // Adding some eyecandy
[9eb63a1598]2145    if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
2146        toggleTranclucency(true);
2147    }
[b8a2a118c4]2148#endif // HANDHELD
[1babbd6ba3]2149}
2150
2151void MainWindow::toggleSolutionActions(bool enable)
2152{
[9eb63a1598]2153    buttonSaveSolution->setEnabled(enable);
2154    actionFileSaveAsSolution->setEnabled(enable);
2155    solutionText->setEnabled(enable);
[7ed8b57eea]2156#ifndef QT_NO_PRINTDIALOG
[9eb63a1598]2157    actionFilePrint->setEnabled(enable);
2158    actionFilePrintPreview->setEnabled(enable);
[7ed8b57eea]2159#endif // QT_NO_PRINTDIALOG
[1babbd6ba3]2160}
2161
2162void MainWindow::toggleTranclucency(bool enable)
2163{
[b8a2a118c4]2164#ifndef HANDHELD
[9eb63a1598]2165    toggleStyle(labelVariant, enable);
2166    toggleStyle(labelCities, enable);
2167    toggleStyle(statusBar(), enable);
2168    tabWidget->setDocumentMode(enable);
2169    QtWin::enableBlurBehindWindow(this, enable);
[1babbd6ba3]2170#else
[9eb63a1598]2171    Q_UNUSED(enable);
[b8a2a118c4]2172#endif // HANDHELD
[1babbd6ba3]2173}
[88a59e4d65]2174
2175void MainWindow::actionHelpOnlineSupportTriggered()
2176{
[9eb63a1598]2177    QDesktopServices::openUrl(QUrl("http://tspsg.info/goto/support"));
[88a59e4d65]2178}
2179
2180void MainWindow::actionHelpReportBugTriggered()
2181{
[9eb63a1598]2182    QDesktopServices::openUrl(QUrl("http://tspsg.info/goto/bugtracker"));
[88a59e4d65]2183}
[fddcfa4b55]2184
[89e5214692]2185#ifdef Q_OS_SYMBIAN
[fddcfa4b55]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);
[019894f5ef]2195    m->addAction(QApplication::translate("QDialogButtonBox", "Discard", "No need to translate this. The translation will be taken from Qt translation files."),
[fddcfa4b55]2196                 this, SLOT(discard()));
[019894f5ef]2197    m->addAction(QApplication::translate("QDialogButtonBox", "Cancel", "No need to translate this. The translation will be taken from Qt translation files."),
[fddcfa4b55]2198                 this, SLOT(cancel()));
2199
[019894f5ef]2200    QAction *o = new QAction(QApplication::translate("QtToolBarDialog", "Actions"), this);
[fddcfa4b55]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}
[89e5214692]2213#endif // Q_OS_SYMBIAN
Note: See TracBrowser for help on using the repository browser.