source: tspsg/src/mainwindow.cpp @ c90b437dd8

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

More copyright headers updates.

Some strings wheren't found by generic search and replace :-)
Also, there were some really outdated since 2010.

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