source: tspsg/src/mainwindow.cpp @ 144fbe6b96

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