source: tspsg-svn/trunk/src/mainwindow.cpp @ 123

Last change on this file since 123 was 123, checked in by laleppa, 14 years ago

+ Added flags from Flag Icons collection by IconDrawer? (see ReadMe?.rtf or http://www.icondrawer.com/).

  • Corrected russism in ukrainian translation.
  • Deleted generated documentation as it is redundant. Use doxygen to regenerate it yourself.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id URL
File size: 50.3 KB
Line 
1/*
2 *  TSPSG: TSP Solver and Generator
3 *  Copyright (C) 2007-2010 Lёppa <contacts[at]oleksii[dot]name>
4 *
5 *  $Id: mainwindow.cpp 123 2010-07-03 02:12:40Z laleppa $
6 *  $URL: https://tspsg.svn.sourceforge.net/svnroot/tspsg/trunk/src/mainwindow.cpp $
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 _T_T_L_
27#include "_.h"
28_C_ _R_ _Y_ _P_ _T_
29#endif
30
31/*!
32 * \brief Class constructor.
33 * \param parent Main Window parent widget.
34 *
35 *  Initializes Main Window and creates its layout based on target OS.
36 *  Loads TSPSG settings and opens a task file if it was specified as a commandline parameter.
37 */
38MainWindow::MainWindow(QWidget *parent)
39        : QMainWindow(parent)
40{
41        settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TSPSG", "tspsg", this);
42
43        if (settings->contains("Style")) {
44QStyle *s = QStyleFactory::create(settings->value("Style").toString());
45                if (s != NULL)
46                        QApplication::setStyle(s);
47                else
48                        settings->remove("Style");
49        }
50
51        loadLanguage();
52        setupUi();
53        setAcceptDrops(true);
54
55        initDocStyleSheet();
56
57#ifndef QT_NO_PRINTER
58        printer = new QPrinter(QPrinter::HighResolution);
59#endif // QT_NO_PRINTER
60
61#ifdef Q_OS_WINCE_WM
62        currentGeometry = QApplication::desktop()->availableGeometry(0);
63        // We need to react to SIP show/hide and resize the window appropriately
64        connect(QApplication::desktop(), SIGNAL(workAreaResized(int)), SLOT(desktopResized(int)));
65#endif // Q_OS_WINCE_WM
66        connect(actionFileNew, SIGNAL(triggered()), SLOT(actionFileNewTriggered()));
67        connect(actionFileOpen, SIGNAL(triggered()), SLOT(actionFileOpenTriggered()));
68        connect(actionFileSave, SIGNAL(triggered()), SLOT(actionFileSaveTriggered()));
69        connect(actionFileSaveAsTask, SIGNAL(triggered()), SLOT(actionFileSaveAsTaskTriggered()));
70        connect(actionFileSaveAsSolution, SIGNAL(triggered()), SLOT(actionFileSaveAsSolutionTriggered()));
71#ifndef QT_NO_PRINTER
72        connect(actionFilePrintPreview, SIGNAL(triggered()), SLOT(actionFilePrintPreviewTriggered()));
73        connect(actionFilePrint, SIGNAL(triggered()), SLOT(actionFilePrintTriggered()));
74#endif // QT_NO_PRINTER
75#ifndef HANDHELD
76        connect(actionSettingsToolbarsConfigure, SIGNAL(triggered()), SLOT(actionSettingsToolbarsConfigureTriggered()));
77#endif // HANDHELD
78        connect(actionSettingsPreferences, SIGNAL(triggered()), SLOT(actionSettingsPreferencesTriggered()));
79#ifdef Q_OS_WIN32
80        connect(actionHelpCheck4Updates, SIGNAL(triggered()), SLOT(actionHelpCheck4UpdatesTriggered()));
81#endif // Q_OS_WIN32
82        connect(actionSettingsLanguageAutodetect, SIGNAL(triggered(bool)), SLOT(actionSettingsLanguageAutodetectTriggered(bool)));
83        connect(groupSettingsLanguageList, SIGNAL(triggered(QAction *)), SLOT(groupSettingsLanguageListTriggered(QAction *)));
84        connect(actionSettingsStyleSystem, SIGNAL(triggered(bool)), SLOT(actionSettingsStyleSystemTriggered(bool)));
85        connect(groupSettingsStyleList, SIGNAL(triggered(QAction*)), SLOT(groupSettingsStyleListTriggered(QAction*)));
86        connect(actionHelpAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
87        connect(actionHelpAbout, SIGNAL(triggered()), SLOT(actionHelpAboutTriggered()));
88
89        connect(buttonSolve, SIGNAL(clicked()), SLOT(buttonSolveClicked()));
90        connect(buttonRandom, SIGNAL(clicked()), SLOT(buttonRandomClicked()));
91        connect(buttonBackToTask, SIGNAL(clicked()), SLOT(buttonBackToTaskClicked()));
92        connect(spinCities, SIGNAL(valueChanged(int)), SLOT(spinCitiesValueChanged(int)));
93
94#ifndef HANDHELD
95        // Centering main window
96QRect rect = geometry();
97        rect.moveCenter(QApplication::desktop()->availableGeometry(this).center());
98        setGeometry(rect);
99        if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
100                // Loading of saved window state
101                settings->beginGroup("MainWindow");
102                restoreGeometry(settings->value("Geometry").toByteArray());
103                restoreState(settings->value("State").toByteArray());
104                settings->endGroup();
105        }
106#endif // HANDHELD
107
108        tspmodel = new CTSPModel(this);
109        taskView->setModel(tspmodel);
110        connect(tspmodel, SIGNAL(numCitiesChanged(int)), SLOT(numCitiesChanged(int)));
111        connect(tspmodel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(dataChanged(const QModelIndex &, const QModelIndex &)));
112        connect(tspmodel, SIGNAL(layoutChanged()), SLOT(dataChanged()));
113        if ((QCoreApplication::arguments().count() > 1) && (tspmodel->loadTask(QCoreApplication::arguments().at(1))))
114                setFileName(QCoreApplication::arguments().at(1));
115        else {
116                setFileName();
117                spinCities->setValue(settings->value("NumCities",DEF_NUM_CITIES).toInt());
118                spinCitiesValueChanged(spinCities->value());
119        }
120        setWindowModified(false);
121}
122
123MainWindow::~MainWindow()
124{
125#ifndef QT_NO_PRINTER
126        delete printer;
127#endif
128}
129
130/* Privates **********************************************************/
131
132void MainWindow::actionFileNewTriggered()
133{
134        if (!maybeSave())
135                return;
136        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
137        tspmodel->clear();
138        setFileName();
139        setWindowModified(false);
140        tabWidget->setCurrentIndex(0);
141        solutionText->clear();
142        toggleSolutionActions(false);
143        QApplication::restoreOverrideCursor();
144}
145
146void MainWindow::actionFileOpenTriggered()
147{
148        if (!maybeSave())
149                return;
150
151QStringList filters(tr("All Supported Formats") + " (*.tspt *.zkt)");
152        filters.append(tr("%1 Task Files").arg("TSPSG") + " (*.tspt)");
153        filters.append(tr("%1 Task Files").arg("ZKomModRd") + " (*.zkt)");
154        filters.append(tr("All Files") + " (*)");
155
156QString file = QFileInfo(fileName).canonicalPath();
157QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
158        file = QFileDialog::getOpenFileName(this, tr("Task Load"), file, filters.join(";;"), NULL, opts);
159        if (file.isEmpty() || !QFileInfo(file).isFile())
160                return;
161        if (!tspmodel->loadTask(file))
162                return;
163        setFileName(file);
164        tabWidget->setCurrentIndex(0);
165        setWindowModified(false);
166        solutionText->clear();
167        toggleSolutionActions(false);
168}
169
170bool MainWindow::actionFileSaveTriggered()
171{
172        if ((fileName == tr("Untitled") + ".tspt") || (!fileName.endsWith(".tspt", Qt::CaseInsensitive)))
173                return saveTask();
174        else
175                if (tspmodel->saveTask(fileName)) {
176                        setWindowModified(false);
177                        return true;
178                } else
179                        return false;
180}
181
182void MainWindow::actionFileSaveAsTaskTriggered()
183{
184        saveTask();
185}
186
187void MainWindow::actionFileSaveAsSolutionTriggered()
188{
189static QString selectedFile;
190        if (selectedFile.isEmpty())
191                selectedFile = QFileInfo(fileName).canonicalPath();
192        else
193                selectedFile = QFileInfo(selectedFile).canonicalPath();
194        if (!selectedFile.isEmpty())
195                selectedFile += "/";
196        if (fileName == tr("Untitled") + ".tspt") {
197#ifndef QT_NO_PRINTER
198                selectedFile += "solution.pdf";
199#else
200                selectedFile += "solution.html";
201#endif // QT_NO_PRINTER
202        } else {
203#ifndef QT_NO_PRINTER
204                selectedFile += QFileInfo(fileName).completeBaseName() + ".pdf";
205#else
206                selectedFile += QFileInfo(fileName).completeBaseName() + ".html";
207#endif // QT_NO_PRINTER
208        }
209
210QStringList filters;
211#ifndef QT_NO_PRINTER
212        filters.append(tr("PDF Files") + " (*.pdf)");
213#endif
214        filters.append(tr("HTML Files") + " (*.html *.htm)");
215#if QT_VERSION >= 0x040500
216        filters.append(tr("OpenDocument Files") + " (*.odt)");
217#endif // QT_VERSION >= 0x040500
218        filters.append(tr("All Files") + " (*)");
219
220QFileDialog::Options opts(settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog);
221QString file = QFileDialog::getSaveFileName(this, QString(), selectedFile, filters.join(";;"), NULL, opts);
222        if (file.isEmpty())
223                return;
224        selectedFile = file;
225        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
226#ifndef QT_NO_PRINTER
227        if (selectedFile.endsWith(".pdf",Qt::CaseInsensitive)) {
228QPrinter printer(QPrinter::HighResolution);
229                printer.setOutputFormat(QPrinter::PdfFormat);
230                printer.setOutputFileName(selectedFile);
231                solutionText->document()->print(&printer);
232                QApplication::restoreOverrideCursor();
233                return;
234        }
235#endif
236        if (selectedFile.endsWith(".htm", Qt::CaseInsensitive) || selectedFile.endsWith(".html", Qt::CaseInsensitive)) {
237QFile file(selectedFile);
238                if (!file.open(QFile::WriteOnly)) {
239                        QApplication::restoreOverrideCursor();
240                        QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(file.errorString()));
241                        return;
242                }
243QFileInfo fi(selectedFile);
244QString format = settings->value("Output/GraphImageFormat", DEF_GRAPH_IMAGE_FORMAT).toString();
245#if !defined(NOSVG) && (QT_VERSION >= 0x040500)
246        if (!QImageWriter::supportedImageFormats().contains(format.toAscii()) && (format != "svg")) {
247#else // NOSVG && QT_VERSION >= 0x040500
248        if (!QImageWriter::supportedImageFormats().contains(format.toAscii())) {
249#endif // NOSVG && QT_VERSION >= 0x040500
250                format = DEF_GRAPH_IMAGE_FORMAT;
251                settings->remove("Output/GraphImageFormat");
252        }
253QString html = solutionText->document()->toHtml("UTF-8"),
254                img =  fi.completeBaseName() + "." + format;
255                html.replace(QRegExp("<img\\s+src=\"tspsg://graph.pic\""), QString("<img src=\"%1\" width=\"%2\" height=\"%3\" alt=\"%4\"").arg(img).arg(graph.width() + 2).arg(graph.height() + 2).arg(tr("Solution Graph")));
256
257                // Saving solution text as HTML
258QTextStream ts(&file);
259                ts.setCodec(QTextCodec::codecForName("UTF-8"));
260                ts << html;
261                file.close();
262
263                // Saving solution graph as SVG or PNG (depending on settings and SVG support)
264#if !defined(NOSVG) && (QT_VERSION >= 0x040500)
265                if (format == "svg") {
266QSvgGenerator svg;
267                        svg.setSize(QSize(graph.width(), graph.height()));
268                        svg.setResolution(graph.logicalDpiX());
269                        svg.setFileName(fi.path() + "/" + img);
270                        svg.setTitle(tr("Solution Graph"));
271                        svg.setDescription(tr("Generated with %1").arg(QApplication::applicationName()));
272QPainter p;
273                        p.begin(&svg);
274                        p.drawPicture(1, 1, graph);
275                        p.end();
276                } else {
277#endif // NOSVG && QT_VERSION >= 0x040500
278QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32);
279                        i.fill(0x00FFFFFF);
280QPainter p;
281                        p.begin(&i);
282                        p.drawPicture(1, 1, graph);
283                        p.end();
284QImageWriter pic(fi.path() + "/" + img);
285                        if (pic.supportsOption(QImageIOHandler::Description)) {
286                                pic.setText("Title", "Solution Graph");
287                                pic.setText("Software", QApplication::applicationName());
288                        }
289                        if (format == "png")
290                                pic.setQuality(5);
291                        else if (format == "jpeg")
292                                pic.setQuality(80);
293                        if (!pic.write(i)) {
294                                QApplication::restoreOverrideCursor();
295                                QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution graph.\nError: %1").arg(pic.errorString()));
296                                return;
297                        }
298#if !defined(NOSVG) && (QT_VERSION >= 0x040500)
299                }
300#endif // NOSVG && QT_VERSION >= 0x040500
301
302// Qt < 4.5 has no QTextDocumentWriter class
303#if QT_VERSION >= 0x040500
304        } else {
305QTextDocumentWriter dw(selectedFile);
306                if (!selectedFile.endsWith(".odt",Qt::CaseInsensitive))
307                        dw.setFormat("plaintext");
308                if (!dw.write(solutionText->document()))
309                        QMessageBox::critical(this, tr("Solution Save"), tr("Unable to save the solution.\nError: %1").arg(dw.device()->errorString()));
310#endif // QT_VERSION >= 0x040500
311        }
312        QApplication::restoreOverrideCursor();
313}
314
315#ifndef QT_NO_PRINTER
316void MainWindow::actionFilePrintPreviewTriggered()
317{
318QPrintPreviewDialog ppd(printer, this);
319        connect(&ppd,SIGNAL(paintRequested(QPrinter *)),SLOT(printPreview(QPrinter *)));
320        ppd.exec();
321}
322
323void MainWindow::actionFilePrintTriggered()
324{
325QPrintDialog pd(printer,this);
326        if (pd.exec() != QDialog::Accepted)
327                return;
328        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
329        solutionText->print(printer);
330        QApplication::restoreOverrideCursor();
331}
332#endif // QT_NO_PRINTER
333
334void MainWindow::actionSettingsPreferencesTriggered()
335{
336SettingsDialog sd(this);
337        if (sd.exec() != QDialog::Accepted)
338                return;
339        if (sd.colorChanged() || sd.fontChanged()) {
340                if (!solutionText->document()->isEmpty() && sd.colorChanged())
341                        QMessageBox::information(this, tr("Settings Changed"), tr("You have changed color settings.\nThey will be applied to the next solution output."));
342                initDocStyleSheet();
343        }
344        if (sd.translucencyChanged() != 0)
345                toggleTranclucency(sd.translucencyChanged() == 1);
346}
347
348void MainWindow::actionSettingsLanguageAutodetectTriggered(bool checked)
349{
350        if (checked) {
351                settings->remove("Language");
352                QMessageBox::information(this, tr("Language change"), tr("Language will be autodetected on the next %1 start.").arg(QApplication::applicationName()));
353        } else
354                settings->setValue("Language", groupSettingsLanguageList->checkedAction()->data().toString());
355}
356
357void MainWindow::groupSettingsLanguageListTriggered(QAction *action)
358{
359        if (actionSettingsLanguageAutodetect->isChecked()) {
360                // We have language autodetection. It needs to be disabled to change language.
361                if (QMessageBox::question(this, tr("Language change"), tr("You have language autodetection turned on.\nIt needs to be off.\nDo you wish to turn it off?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
362                        actionSettingsLanguageAutodetect->trigger();
363                } else
364                        return;
365        }
366bool untitled = (fileName == tr("Untitled") + ".tspt");
367        if (loadLanguage(action->data().toString())) {
368                QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
369                settings->setValue("Language",action->data().toString());
370                retranslateUi();
371                if (untitled)
372                        setFileName();
373#ifdef Q_OS_WIN32
374                if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
375                        toggleStyle(labelVariant, true);
376                        toggleStyle(labelCities, true);
377                }
378#endif
379                QApplication::restoreOverrideCursor();
380                if (!solutionText->document()->isEmpty())
381                        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."));
382        }
383}
384
385void MainWindow::actionSettingsStyleSystemTriggered(bool checked)
386{
387        if (checked) {
388                settings->remove("Style");
389                QMessageBox::information(this, tr("Style Change"), tr("To apply the default style you need to restart %1.").arg(QApplication::applicationName()));
390        } else {
391                settings->setValue("Style", groupSettingsStyleList->checkedAction()->text());
392        }
393}
394
395void MainWindow::groupSettingsStyleListTriggered(QAction *action)
396{
397QStyle *s = QStyleFactory::create(action->text());
398        if (s != NULL) {
399                QApplication::setStyle(s);
400                settings->setValue("Style", action->text());
401                actionSettingsStyleSystem->setChecked(false);
402        }
403}
404
405#ifndef HANDHELD
406void MainWindow::actionSettingsToolbarsConfigureTriggered()
407{
408QtToolBarDialog dlg(this);
409        dlg.setToolBarManager(toolBarManager);
410        dlg.exec();
411QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
412        if (tb != NULL) {
413                tb->setMenu(menuFileSaveAs);
414                tb->setPopupMode(QToolButton::MenuButtonPopup);
415                tb->resize(tb->sizeHint());
416        }
417
418        loadToolbarList();
419}
420#endif // HANDHELD
421
422#ifdef Q_OS_WIN32
423void MainWindow::actionHelpCheck4UpdatesTriggered()
424{
425        if (!hasUpdater()) {
426                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."));
427                return;
428        }
429
430        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
431        QProcess::execute("updater/Update.exe -name=\"TSPSG: TSP Solver and Generator\" -check=\"freeupdate\"");
432        QApplication::restoreOverrideCursor();
433}
434#endif // Q_OS_WIN32
435
436void MainWindow::actionHelpAboutTriggered()
437{
438QString title;
439#ifdef HANDHELD
440        title += QString("<b>TSPSG<br>TSP Solver and Generator</b><br>");
441#else
442        title += QString("<b>%1</b><br>").arg(QApplication::applicationName());
443#endif // HANDHELD
444        title += QString("%1: <b>%2</b><br>").arg(tr("Version"), QApplication::applicationVersion());
445#ifndef HANDHELD
446        title += QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b><br>").arg(QDate::currentDate().toString("yyyy"), QApplication::organizationDomain(), QApplication::organizationName());
447        title += QString("<b><a href=\"http://tspsg.sourceforge.net/\">http://tspsg.sourceforge.net/</a></b>");
448#else
449        title += QString("<b><a href=\"http://tspsg.sourceforge.net/\">http://tspsg.sf.net/</a></b>");
450#endif // HANDHELD
451
452QString about;
453        about += QString("%1: <b>%2</b><br>").arg(tr("Target OS (ARCH)"), OS);
454#ifndef STATIC_BUILD
455        about += QString("%1 (%2):<br>").arg(tr("Qt library"), tr("shared"));
456        about += QString("&nbsp;&nbsp;&nbsp;&nbsp;%1: <b>%2</b><br>").arg(tr("Build time"), QT_VERSION_STR);
457        about += QString("&nbsp;&nbsp;&nbsp;&nbsp;%1: <b>%2</b><br>").arg(tr("Runtime"), qVersion());
458#else
459        about += QString("%1: <b>%2</b> (%3)<br>").arg(tr("Qt library"), QT_VERSION_STR, tr("static"));
460#endif // STATIC_BUILD
461        about += tr("Buid <b>%1</b>, built on <b>%2</b> at <b>%3</b>").arg(BUILD_NUMBER).arg(__DATE__).arg(__TIME__) + "<br>";
462        about += QString("%1: <b>%2</b><br>").arg(tr("Algorithm"), CTSPSolver::getVersionId());
463        about += "<br>";
464        about += tr("TSPSG is free software: you can redistribute it and/or modify it<br>"
465                "under the terms of the GNU General Public License as published<br>"
466                "by the Free Software Foundation, either version 3 of the License,<br>"
467                "or (at your option) any later version.<br>"
468                "<br>"
469                "TSPSG is distributed in the hope that it will be useful, but<br>"
470                "WITHOUT ANY WARRANTY; without even the implied warranty of<br>"
471                "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>"
472                "GNU General Public License for more details.<br>"
473                "<br>"
474                "You should have received a copy of the GNU General Public License<br>"
475                "along with TSPSG.  If not, see <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses/</a>.");
476
477QDialog *dlg = new QDialog(this);
478QLabel *lblIcon = new QLabel(dlg),
479        *lblTitle = new QLabel(dlg),
480        *lblTranslated = new QLabel(dlg);
481#ifdef HANDHELD
482QLabel *lblSubTitle = new QLabel(QString("<b>&copy; 2007-%1 <a href=\"http://%2/\">%3</a></b>").arg(QDate::currentDate().toString("yyyy"), QApplication::organizationDomain(), QApplication::organizationName()), dlg);
483#endif // HANDHELD
484QTextBrowser *txtAbout = new QTextBrowser(dlg);
485QVBoxLayout *vb = new QVBoxLayout();
486QHBoxLayout *hb1 = new QHBoxLayout(),
487        *hb2 = new QHBoxLayout();
488QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, dlg);
489
490        lblTitle->setOpenExternalLinks(true);
491        lblTitle->setText(title);
492        lblTitle->setAlignment(Qt::AlignTop);
493        lblTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
494#ifndef HANDHELD
495        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()));
496#endif // HANDHELD
497
498        lblIcon->setPixmap(QPixmap(":/images/tspsg.png").scaledToHeight(lblTitle->sizeHint().height(), Qt::SmoothTransformation));
499        lblIcon->setAlignment(Qt::AlignVCenter);
500#ifndef HANDHELD
501        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()));
502#endif // HANDHELD
503
504        hb1->addWidget(lblIcon);
505        hb1->addWidget(lblTitle);
506
507        txtAbout->setWordWrapMode(QTextOption::NoWrap);
508        txtAbout->setOpenExternalLinks(true);
509        txtAbout->setHtml(about);
510        txtAbout->moveCursor(QTextCursor::Start);
511#ifndef HANDHELD
512        txtAbout->setStyleSheet(QString("QTextBrowser {background-color: %1; border-color: %2; border-width: 1px; border-style: solid; border-radius: 4px; padding: 1px;}").arg(palette().base().color().name(), palette().shadow().color().name()));
513#endif // HANDHELD
514
515        bb->button(QDialogButtonBox::Ok)->setCursor(QCursor(Qt::PointingHandCursor));
516
517        lblTranslated->setText(QApplication::translate("--------", "AUTHORS", "Please, provide translator credits here."));
518        if (lblTranslated->text() == "AUTHORS")
519                lblTranslated->hide();
520        else {
521                lblTranslated->setOpenExternalLinks(true);
522#ifndef HANDHELD
523                lblTranslated->setStyleSheet(QString("QLabel {background-color: %1; border-color: %2; border-width: 1px; border-style: solid; border-radius: 3px; padding: 1px;}").arg(palette().alternateBase().color().name(), palette().shadow().color().name()));
524#endif // HANDHELD
525                hb2->addWidget(lblTranslated);
526        }
527
528        // This one isn't displayed anywhere, yet. Provided as a placeholder for future use.
529        QApplication::translate("--------", "VERSION", "Please, provide your translation version here.");
530
531        hb2->addWidget(bb);
532
533#ifdef Q_OS_WINCE_WM
534        vb->setMargin(3);
535#endif // Q_OS_WINCE_WM
536        vb->addLayout(hb1);
537#ifdef HANDHELD
538        vb->addWidget(lblSubTitle);
539#endif // HANDHELD
540        vb->addWidget(txtAbout);
541        vb->addLayout(hb2);
542
543        dlg->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
544        dlg->setWindowTitle(tr("About %1").arg(QApplication::applicationName()));
545        dlg->setWindowIcon(QIcon::fromTheme("help-about", QIcon(":/images/icons/help-about.png")));
546        dlg->setLayout(vb);
547
548        connect(bb, SIGNAL(accepted()), dlg, SLOT(accept()));
549
550#ifdef Q_OS_WIN32
551        // Adding some eyecandy in Vista and 7 :-)
552        if (QtWin::isCompositionEnabled())  {
553                QtWin::enableBlurBehindWindow(dlg, true);
554        }
555#endif // Q_OS_WIN32
556
557        dlg->resize(450, 350);
558
559        dlg->exec();
560
561        delete dlg;
562}
563
564void MainWindow::buttonBackToTaskClicked()
565{
566        tabWidget->setCurrentIndex(0);
567}
568
569void MainWindow::buttonRandomClicked()
570{
571        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
572        tspmodel->randomize();
573        QApplication::restoreOverrideCursor();
574}
575
576void MainWindow::buttonSolveClicked()
577{
578TMatrix matrix;
579QList<double> row;
580int n = spinCities->value();
581bool ok;
582        for (int r = 0; r < n; r++) {
583                row.clear();
584                for (int c = 0; c < n; c++) {
585                        row.append(tspmodel->index(r,c).data(Qt::UserRole).toDouble(&ok));
586                        if (!ok) {
587                                QMessageBox::critical(this, tr("Data error"), tr("Error in cell [Row %1; Column %2]: Invalid data format.").arg(r + 1).arg(c + 1));
588                                return;
589                        }
590                }
591                matrix.append(row);
592        }
593
594QProgressDialog pd(this);
595QProgressBar *pb = new QProgressBar(&pd);
596        pb->setAlignment(Qt::AlignCenter);
597        pb->setFormat(tr("%v of %1 parts found").arg(n));
598        pd.setBar(pb);
599        pd.setMaximum(n);
600        pd.setAutoReset(false);
601        pd.setLabelText(tr("Calculating optimal route..."));
602        pd.setWindowTitle(tr("Solution Progress"));
603        pd.setWindowModality(Qt::ApplicationModal);
604        pd.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
605        pd.show();
606
607CTSPSolver solver;
608        connect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
609        connect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
610SStep *root = solver.solve(n, matrix);
611        disconnect(&solver, SIGNAL(routePartFound(int)), &pd, SLOT(setValue(int)));
612        disconnect(&pd, SIGNAL(canceled()), &solver, SLOT(cancel()));
613        if (!root) {
614                pd.reset();
615                if (!solver.wasCanceled())
616                        QMessageBox::warning(this, tr("Solution Result"), tr("Unable to find a solution.\nMaybe, this task has no solution."));
617                return;
618        }
619        pb->setFormat(tr("Generating header"));
620        pd.setLabelText(tr("Generating solution output..."));
621        pd.setMaximum(solver.getTotalSteps() + 1);
622        pd.setValue(0);
623
624        solutionText->clear();
625        solutionText->setDocumentTitle(tr("Solution of Variant #%1 Task").arg(spinVariant->value()));
626
627QPainter pic;
628        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
629                pic.begin(&graph);
630                pic.setRenderHint(QPainter::Antialiasing);
631                pic.setFont(settings->value("Output/Font", QFont(getDefaultFont(), 9)).value<QFont>());
632                pic.setBrush(QBrush(QColor(Qt::white)));
633                pic.setBackgroundMode(Qt::OpaqueMode);
634        }
635
636QTextDocument *doc = solutionText->document();
637QTextCursor cur(doc);
638
639        cur.beginEditBlock();
640        cur.setBlockFormat(fmt_paragraph);
641        cur.insertText(tr("Variant #%1 Task").arg(spinVariant->value()), fmt_default);
642        cur.insertBlock(fmt_paragraph);
643        cur.insertText(tr("Task:"));
644        outputMatrix(cur, matrix);
645        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
646#ifdef _T_T_L_
647                _b_ _i_ _z_ _a_ _r_ _r_ _e_
648#endif
649                drawNode(pic, 0);
650        }
651        cur.insertHtml("<hr>");
652        cur.insertBlock(fmt_paragraph);
653int imgpos = cur.position();
654        cur.insertText(tr("Variant #%1 Solution").arg(spinVariant->value()), fmt_default);
655        cur.endEditBlock();
656
657SStep *step = root;
658int c = n = 1;
659        pb->setFormat(tr("Generating step %v"));
660        while ((step->next != SStep::NoNextStep) && (c < spinCities->value())) {
661                if (pd.wasCanceled()) {
662                        pd.setLabelText(tr("Cleaning up..."));
663                        pd.setMaximum(0);
664                        pd.setCancelButton(NULL);
665                        pd.show();
666                        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
667                        solver.cleanup(true);
668                        solutionText->clear();
669                        toggleSolutionActions(false);
670                        return;
671                }
672                pd.setValue(n);
673
674                cur.beginEditBlock();
675                cur.insertBlock(fmt_paragraph);
676                cur.insertText(tr("Step #%1").arg(n));
677                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())))) {
678                        outputMatrix(cur, *step);
679                }
680                cur.insertBlock(fmt_paragraph);
681                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);
682                if (!step->alts.empty()) {
683                        SStep::SCandidate cand;
684                        QString alts;
685                        foreach(cand, step->alts) {
686                                if (!alts.isEmpty())
687                                        alts += ", ";
688                                alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1);
689                        }
690                        cur.insertBlock(fmt_paragraph);
691                        cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist);
692                }
693                cur.insertBlock(fmt_paragraph);
694                cur.insertText(" ", fmt_default);
695                cur.endEditBlock();
696
697                if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
698                        if (step->prNode != NULL)
699                                drawNode(pic, n, false, step->prNode);
700                        if (step->plNode != NULL)
701                                drawNode(pic, n, true, step->plNode);
702                }
703                n++;
704
705                if (step->next == SStep::RightBranch) {
706                        c++;
707                        step = step->prNode;
708                } else if (step->next == SStep::LeftBranch) {
709                        step = step->plNode;
710                } else
711                        break;
712        }
713        pb->setFormat(tr("Generating footer"));
714        pd.setValue(n);
715
716        cur.beginEditBlock();
717        cur.insertBlock(fmt_paragraph);
718        if (solver.isOptimal())
719                cur.insertText(tr("Optimal path:"));
720        else
721                cur.insertText(tr("Resulting path:"));
722
723        cur.insertBlock(fmt_paragraph);
724        cur.insertText("  " + solver.getSortedPath(tr("City %1")));
725
726        cur.insertBlock(fmt_paragraph);
727        if (isInteger(step->price))
728                cur.insertHtml("<p>" + tr("The price is <b>%n</b> unit(s).", "", qRound(step->price)) + "</p>");
729        else
730                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>");
731        if (!solver.isOptimal()) {
732                cur.insertBlock(fmt_paragraph);
733                cur.insertText(" ");
734                cur.insertBlock(fmt_paragraph);
735                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>");
736        }
737        cur.endEditBlock();
738
739        if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) {
740                pic.end();
741
742QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32);
743                i.fill(0);
744                pic.begin(&i);
745                pic.drawPicture(1, 1, graph);
746                pic.end();
747                doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i);
748
749QTextImageFormat img;
750                img.setName("tspsg://graph.pic");
751
752                cur.setPosition(imgpos);
753                cur.insertImage(img, QTextFrameFormat::FloatRight);
754        }
755
756        if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) {
757                // Scrolling to the end of the text.
758                solutionText->moveCursor(QTextCursor::End);
759        } else
760                solutionText->moveCursor(QTextCursor::Start);
761
762        pd.setLabelText(tr("Cleaning up..."));
763        pd.setMaximum(0);
764        pd.setCancelButton(NULL);
765        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
766        solver.cleanup(true);
767        toggleSolutionActions();
768        tabWidget->setCurrentIndex(1);
769}
770
771void MainWindow::dataChanged()
772{
773        setWindowModified(true);
774}
775
776void MainWindow::dataChanged(const QModelIndex &tl, const QModelIndex &br)
777{
778        setWindowModified(true);
779        if (settings->value("Autosize", DEF_AUTOSIZE).toBool()) {
780                for (int k = tl.row(); k <= br.row(); k++)
781                        taskView->resizeRowToContents(k);
782                for (int k = tl.column(); k <= br.column(); k++)
783                        taskView->resizeColumnToContents(k);
784        }
785}
786
787#ifdef Q_OS_WINCE_WM
788void MainWindow::changeEvent(QEvent *ev)
789{
790        if ((ev->type() == QEvent::ActivationChange) && isActiveWindow())
791                desktopResized(0);
792
793        QWidget::changeEvent(ev);
794}
795
796void MainWindow::desktopResized(int screen)
797{
798        if ((screen != 0) || !isActiveWindow())
799                return;
800
801QRect availableGeometry = QApplication::desktop()->availableGeometry(0);
802        if (currentGeometry != availableGeometry) {
803                QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
804                /*!
805                 * \hack HACK: This hack checks whether \link QDesktopWidget::availableGeometry() availableGeometry()\endlink's \c top + \c hegiht = \link QDesktopWidget::screenGeometry() screenGeometry()\endlink's \c height.
806                 *  If \c true, the window gets maximized. If we used \c setGeometry() in this case, the bottom of the
807                 *  window would end up being behind the soft buttons. Is this a bug in Qt or Windows Mobile?
808                 */
809                if ((availableGeometry.top() + availableGeometry.height()) == QApplication::desktop()->screenGeometry().height()) {
810                        setWindowState(windowState() | Qt::WindowMaximized);
811                } else {
812                        if (windowState() & Qt::WindowMaximized)
813                                setWindowState(windowState() ^ Qt::WindowMaximized);
814                        setGeometry(availableGeometry);
815                }
816                currentGeometry = availableGeometry;
817                QApplication::restoreOverrideCursor();
818        }
819}
820#endif // Q_OS_WINCE_WM
821
822void MainWindow::numCitiesChanged(int nCities)
823{
824        blockSignals(true);
825        spinCities->setValue(nCities);
826        blockSignals(false);
827}
828
829#ifndef QT_NO_PRINTER
830void MainWindow::printPreview(QPrinter *printer)
831{
832        solutionText->print(printer);
833}
834#endif // QT_NO_PRINTER
835
836void MainWindow::spinCitiesValueChanged(int n)
837{
838        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
839int count = tspmodel->numCities();
840        tspmodel->setNumCities(n);
841        if ((n > count) && settings->value("Autosize", DEF_AUTOSIZE).toBool())
842                for (int k = count; k < n; k++) {
843                        taskView->resizeColumnToContents(k);
844                        taskView->resizeRowToContents(k);
845                }
846        QApplication::restoreOverrideCursor();
847}
848
849void MainWindow::closeEvent(QCloseEvent *ev)
850{
851        if (!maybeSave()) {
852                ev->ignore();
853                return;
854        }
855        if (!settings->value("SettingsReset", false).toBool()) {
856                settings->setValue("NumCities", spinCities->value());
857
858                // Saving Main Window state
859#ifndef HANDHELD
860                if (settings->value("SavePos", DEF_SAVEPOS).toBool()) {
861                        settings->beginGroup("MainWindow");
862                        settings->setValue("Geometry", saveGeometry());
863                        settings->setValue("State", saveState());
864                        settings->setValue("Toolbars", toolBarManager->saveState());
865                        settings->endGroup();
866                }
867#endif // HANDHELD
868        } else {
869                settings->remove("SettingsReset");
870        }
871
872        QMainWindow::closeEvent(ev);
873}
874
875void MainWindow::dragEnterEvent(QDragEnterEvent *ev)
876{
877        if (ev->mimeData()->hasUrls() && (ev->mimeData()->urls().count() == 1)) {
878QFileInfo fi(ev->mimeData()->urls().first().toLocalFile());
879                if ((fi.suffix() == "tspt") || (fi.suffix() == "zkt"))
880                        ev->acceptProposedAction();
881        }
882}
883
884void MainWindow::drawNode(QPainter &pic, int nstep, bool left, SStep *step)
885{
886const int r = 35;
887qreal x, y;
888        if (step != NULL)
889                x = left ? r : r * 3.5;
890        else
891                x = r * 2.25;
892        y = r * (3 * nstep + 1);
893
894#ifdef _T_T_L_
895        if (nstep == -481124) {
896                _t_t_l_(pic, r, x);
897                return;
898        }
899#endif
900
901        pic.drawEllipse(QPointF(x, y), r, r);
902
903        if (step != NULL) {
904QFont font;
905                if (left) {
906                        font = pic.font();
907                        font.setStrikeOut(true);
908                        pic.setFont(font);
909                }
910                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");
911                if (left) {
912                        font.setStrikeOut(false);
913                        pic.setFont(font);
914                }
915                if (step->price != INFINITY) {
916                        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()));
917                } else {
918                        pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, "\n"INFSTR);
919                }
920        } else {
921                pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, tr("Root"));
922        }
923
924        if (nstep == 1) {
925                pic.drawLine(QPointF(x, y - r), QPointF(r * 2.25, y - 2 * r));
926        } else if (nstep > 1) {
927                pic.drawLine(QPointF(x, y - r), QPointF((step->pNode->pNode->next == SStep::RightBranch) ? r * 3.5 : r, y - 2 * r));
928        }
929
930}
931
932void MainWindow::dropEvent(QDropEvent *ev)
933{
934        if (maybeSave() && tspmodel->loadTask(ev->mimeData()->urls().first().toLocalFile())) {
935                setFileName(ev->mimeData()->urls().first().toLocalFile());
936                tabWidget->setCurrentIndex(0);
937                setWindowModified(false);
938                solutionText->clear();
939                toggleSolutionActions(false);
940
941                ev->setDropAction(Qt::CopyAction);
942                ev->accept();
943        }
944}
945
946bool MainWindow::hasUpdater() const
947{
948#ifdef Q_OS_WIN32
949        return QFile::exists("updater/Update.exe");
950#else // Q_OS_WIN32
951        return false;
952#endif // Q_OS_WIN32
953}
954
955void MainWindow::initDocStyleSheet()
956{
957        solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(getDefaultFont(), DEF_FONT_SIZE)).value<QFont>());
958
959        fmt_paragraph.setTopMargin(0);
960        fmt_paragraph.setRightMargin(10);
961        fmt_paragraph.setBottomMargin(0);
962        fmt_paragraph.setLeftMargin(10);
963
964        fmt_table.setTopMargin(5);
965        fmt_table.setRightMargin(10);
966        fmt_table.setBottomMargin(5);
967        fmt_table.setLeftMargin(10);
968        fmt_table.setBorder(0);
969        fmt_table.setBorderStyle(QTextFrameFormat::BorderStyle_None);
970        fmt_table.setCellSpacing(5);
971
972        fmt_cell.setAlignment(Qt::AlignHCenter);
973
974        settings->beginGroup("Output/Colors");
975
976QColor color = settings->value("Text", DEF_TEXT_COLOR).value<QColor>();
977QColor hilight;
978        if (color.value() < 192)
979                hilight.setHsv(color.hue(), color.saturation(), 127 + qRound(color.value() / 2));
980        else
981                hilight.setHsv(color.hue(), color.saturation(), color.value() / 2);
982
983        solutionText->document()->setDefaultStyleSheet(QString("* {color: %1;}").arg(color.name()));
984        fmt_default.setForeground(QBrush(color));
985
986        fmt_selected.setForeground(QBrush(settings->value("Selected", DEF_SELECTED_COLOR).value<QColor>()));
987        fmt_selected.setFontWeight(QFont::Bold);
988
989        fmt_alternate.setForeground(QBrush(settings->value("Alternate", DEF_ALTERNATE_COLOR).value<QColor>()));
990        fmt_alternate.setFontWeight(QFont::Bold);
991        fmt_altlist.setForeground(QBrush(hilight));
992
993        settings->endGroup();
994
995        solutionText->setTextColor(color);
996}
997
998void MainWindow::loadLangList()
999{
1000QMap<QString, QStringList> langlist;
1001QFileInfoList langs;
1002QFileInfo lang;
1003QString name;
1004QStringList language, dirs;
1005QTranslator t;
1006QDir dir;
1007        dir.setFilter(QDir::Files);
1008        dir.setNameFilters(QStringList("tspsg_*.qm"));
1009        dir.setSorting(QDir::NoSort);
1010
1011        dirs << PATH_L10N << ":/l10n";
1012        foreach (QString dirname, dirs) {
1013                dir.setPath(dirname);
1014                if (dir.exists()) {
1015                        langs = dir.entryInfoList();
1016                        for (int k = 0; k < langs.size(); k++) {
1017                                lang = langs.at(k);
1018                                if (lang.completeBaseName().compare("tspsg_en", Qt::CaseInsensitive) && !langlist.contains(lang.completeBaseName().mid(6)) && t.load(lang.completeBaseName(), dirname)) {
1019
1020                                        language.clear();
1021                                        language.append(lang.completeBaseName().mid(6));
1022                                        language.append(t.translate("--------", "COUNTRY", "Please, provide an ISO 3166-1 alpha-2 country code for this translation language here (eg., UA).").toLower());
1023                                        language.append(t.translate("--------", "LANGNAME", "Please, provide a native name of your translation language here."));
1024                                        language.append(t.translate("MainWindow", "Set application language to %1", "").arg(name));
1025
1026                                        langlist.insert(language.at(0), language);
1027                                }
1028                        }
1029                }
1030        }
1031
1032QAction *a;
1033        foreach (language, langlist) {
1034                a = menuSettingsLanguage->addAction(language.at(2));
1035                a->setStatusTip(language.at(3));
1036                a->setIcon(QIcon::fromTheme(QString("flag-%1").arg(language.at(1)), QIcon(QString(":/images/icons/l10n/flag-%1.png").arg(language.at(1)))));
1037                a->setData(language.at(0));
1038                a->setCheckable(true);
1039                a->setActionGroup(groupSettingsLanguageList);
1040                if (settings->value("Language", QLocale::system().name()).toString().startsWith(language.at(0)))
1041                        a->setChecked(true);
1042        }
1043}
1044
1045bool MainWindow::loadLanguage(const QString &lang)
1046{
1047// i18n
1048bool ad = false;
1049QString lng = lang;
1050        if (lng.isEmpty()) {
1051                ad = settings->value("Language", "").toString().isEmpty();
1052                lng = settings->value("Language", QLocale::system().name()).toString();
1053        }
1054static QTranslator *qtTranslator; // Qt library translator
1055        if (qtTranslator) {
1056                qApp->removeTranslator(qtTranslator);
1057                delete qtTranslator;
1058                qtTranslator = NULL;
1059        }
1060static QTranslator *translator; // Application translator
1061        if (translator) {
1062                qApp->removeTranslator(translator);
1063                delete translator;
1064                translator = NULL;
1065        }
1066
1067        if (lng == "en")
1068                return true;
1069
1070        // Trying to load system Qt library translation...
1071        qtTranslator = new QTranslator(this);
1072        if (qtTranslator->load("qt_" + lng, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
1073                qApp->installTranslator(qtTranslator);
1074        else {
1075                // No luck. Let's try to load a bundled one.
1076                if (qtTranslator->load("qt_" + lng, PATH_L10N)) {
1077                        // We have a translation in the localization direcotry.
1078                        qApp->installTranslator(qtTranslator);
1079                } else if (qtTranslator->load("qt_" + lng, ":/l10n")) {
1080                        // We have a translation "built-in" into application resources.
1081                        qApp->installTranslator(qtTranslator);
1082                } else {
1083                        // Qt library translation unavailable for this language.
1084                        delete qtTranslator;
1085                        qtTranslator = NULL;
1086                }
1087        }
1088
1089        // Now let's load application translation.
1090        translator = new QTranslator(this);
1091        if (translator->load("tspsg_" + lng, PATH_L10N)) {
1092                // We have a translation in the localization directory.
1093                qApp->installTranslator(translator);
1094        } else if (translator->load("tspsg_" + lng, ":/l10n")) {
1095                // We have a translation "built-in" into application resources.
1096                qApp->installTranslator(translator);
1097        } else {
1098                delete translator;
1099                translator = NULL;
1100                if (!ad) {
1101                        settings->remove("Language");
1102                        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
1103                        QMessageBox::warning(isVisible() ? this : NULL, tr("Language Change"), tr("Unable to load the translation language.\nFalling back to autodetection."));
1104                        QApplication::restoreOverrideCursor();
1105                }
1106                return false;
1107        }
1108        return true;
1109}
1110
1111void MainWindow::loadStyleList()
1112{
1113        menuSettingsStyle->clear();
1114QStringList styles = QStyleFactory::keys();
1115        menuSettingsStyle->insertAction(NULL, actionSettingsStyleSystem);
1116        actionSettingsStyleSystem->setChecked(!settings->contains("Style"));
1117        menuSettingsStyle->addSeparator();
1118QAction *a;
1119        foreach (QString style, styles) {
1120                a = menuSettingsStyle->addAction(style);
1121                a->setData(false);
1122                a->setStatusTip(tr("Set application style to %1").arg(style));
1123                a->setCheckable(true);
1124                a->setActionGroup(groupSettingsStyleList);
1125                if ((style == settings->value("Style").toString())
1126                        || QString(QApplication::style()->metaObject()->className()).contains(QRegExp(QString("^Q?%1(Style)?$").arg(QRegExp::escape(style)), Qt::CaseInsensitive))) {
1127                        a->setChecked(true);
1128                }
1129        }
1130}
1131
1132void MainWindow::loadToolbarList()
1133{
1134        menuSettingsToolbars->clear();
1135#ifndef HANDHELD
1136        menuSettingsToolbars->insertAction(NULL, actionSettingsToolbarsConfigure);
1137        menuSettingsToolbars->addSeparator();
1138QList<QToolBar *> list = toolBarManager->toolBars();
1139        foreach (QToolBar *t, list) {
1140                menuSettingsToolbars->insertAction(NULL, t->toggleViewAction());
1141        }
1142#else // HANDHELD
1143        menuSettingsToolbars->insertAction(NULL, toolBarMain->toggleViewAction());
1144#endif // HANDHELD
1145}
1146
1147bool MainWindow::maybeSave()
1148{
1149        if (!isWindowModified())
1150                return true;
1151int res = QMessageBox::warning(this, tr("Unsaved Changes"), tr("Would you like to save changes in the current task?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
1152        if (res == QMessageBox::Save)
1153                return actionFileSaveTriggered();
1154        else if (res == QMessageBox::Cancel)
1155                return false;
1156        else
1157                return true;
1158}
1159
1160void MainWindow::outputMatrix(QTextCursor &cur, const TMatrix &matrix)
1161{
1162int n = spinCities->value();
1163QTextTable *table = cur.insertTable(n, n, fmt_table);
1164
1165        for (int r = 0; r < n; r++) {
1166                for (int c = 0; c < n; c++) {
1167                        cur = table->cellAt(r, c).firstCursorPosition();
1168                        cur.setBlockFormat(fmt_cell);
1169                        cur.setBlockCharFormat(fmt_default);
1170                        if (matrix.at(r).at(c) == INFINITY)
1171                                cur.insertText(INFSTR);
1172                        else
1173                                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()));
1174                }
1175                QApplication::processEvents();
1176        }
1177        cur.movePosition(QTextCursor::End);
1178}
1179
1180void MainWindow::outputMatrix(QTextCursor &cur, const SStep &step)
1181{
1182int n = spinCities->value();
1183QTextTable *table = cur.insertTable(n, n, fmt_table);
1184
1185        for (int r = 0; r < n; r++) {
1186                for (int c = 0; c < n; c++) {
1187                        cur = table->cellAt(r, c).firstCursorPosition();
1188                        cur.setBlockFormat(fmt_cell);
1189                        if (step.matrix.at(r).at(c) == INFINITY)
1190                                cur.insertText(INFSTR, fmt_default);
1191                        else if ((r == step.candidate.nRow) && (c == step.candidate.nCol))
1192                                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);
1193                        else {
1194SStep::SCandidate cand;
1195                                cand.nRow = r;
1196                                cand.nCol = c;
1197                                if (step.alts.contains(cand))
1198                                        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);
1199                                else
1200                                        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);
1201                        }
1202                }
1203                QApplication::processEvents();
1204        }
1205
1206        cur.movePosition(QTextCursor::End);
1207}
1208
1209void MainWindow::retranslateUi(bool all)
1210{
1211        if (all)
1212                Ui::MainWindow::retranslateUi(this);
1213
1214        loadStyleList();
1215        loadToolbarList();
1216
1217#ifndef QT_NO_PRINTER
1218        actionFilePrintPreview->setText(tr("P&rint Preview..."));
1219#ifndef QT_NO_TOOLTIP
1220        actionFilePrintPreview->setToolTip(tr("Preview solution results"));
1221#endif // QT_NO_TOOLTIP
1222#ifndef QT_NO_STATUSTIP
1223        actionFilePrintPreview->setStatusTip(tr("Preview current solution results before printing"));
1224#endif // QT_NO_STATUSTIP
1225
1226        actionFilePrint->setText(tr("&Print..."));
1227#ifndef QT_NO_TOOLTIP
1228        actionFilePrint->setToolTip(tr("Print solution"));
1229#endif // QT_NO_TOOLTIP
1230#ifndef QT_NO_STATUSTIP
1231        actionFilePrint->setStatusTip(tr("Print current solution results"));
1232#endif // QT_NO_STATUSTIP
1233        actionFilePrint->setShortcut(tr("Ctrl+P"));
1234#endif // QT_NO_PRINTER
1235
1236#ifndef HANDHELD
1237        actionSettingsToolbarsConfigure->setText(tr("Configure..."));
1238#ifndef QT_NO_STATUSTIP
1239        actionSettingsToolbarsConfigure->setStatusTip(tr("Customize toolbars"));
1240#endif // QT_NO_STATUSTIP
1241#endif // HANDHELD
1242
1243#ifdef Q_OS_WIN32
1244        actionHelpCheck4Updates->setText(tr("Check for &Updates..."));
1245#ifndef QT_NO_STATUSTIP
1246        actionHelpCheck4Updates->setStatusTip(tr("Check for %1 updates").arg(QApplication::applicationName()));
1247#endif // QT_NO_STATUSTIP
1248#endif // Q_OS_WIN32
1249}
1250
1251bool MainWindow::saveTask() {
1252QStringList filters(tr("%1 Task File").arg("TSPSG") + " (*.tspt)");
1253        filters.append(tr("All Files") + " (*)");
1254QString file;
1255        if (fileName.endsWith(".tspt", Qt::CaseInsensitive))
1256                file = fileName;
1257        else
1258                file = QFileInfo(fileName).canonicalPath() + "/" + QFileInfo(fileName).completeBaseName() + ".tspt";
1259
1260QFileDialog::Options opts = settings->value("UseNativeDialogs", DEF_USE_NATIVE_DIALOGS).toBool() ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog;
1261        file = QFileDialog::getSaveFileName(this, tr("Task Save"), file, filters.join(";;"), NULL, opts);
1262
1263        if (file.isEmpty())
1264                return false;
1265        if (tspmodel->saveTask(file)) {
1266                setFileName(file);
1267                setWindowModified(false);
1268                return true;
1269        }
1270        return false;
1271}
1272
1273void MainWindow::setFileName(const QString &fileName)
1274{
1275        this->fileName = fileName;
1276        setWindowTitle(QString("%1[*] - %2").arg(QFileInfo(fileName).completeBaseName()).arg(QApplication::applicationName()));
1277}
1278
1279void MainWindow::setupUi()
1280{
1281        Ui::MainWindow::setupUi(this);
1282
1283        // File Menu
1284        actionFileNew->setIcon(QIcon::fromTheme("document-new", QIcon(":/images/icons/document-new.png")));
1285        actionFileOpen->setIcon(QIcon::fromTheme("document-open", QIcon(":/images/icons/document-open.png")));
1286        actionFileSave->setIcon(QIcon::fromTheme("document-save", QIcon(":/images/icons/document-save.png")));
1287        menuFileSaveAs->setIcon(QIcon::fromTheme("document-save-as", QIcon(":/images/icons/document-save-as.png")));
1288        actionFileExit->setIcon(QIcon::fromTheme("application-exit", QIcon(":/images/icons/application-exit.png")));
1289        // Settings Menu
1290        menuSettingsLanguage->setIcon(QIcon::fromTheme("preferences-desktop-locale", QIcon(":/images/icons/preferences-desktop-locale.png")));
1291        actionSettingsLanguageEnglish->setIcon(QIcon::fromTheme("flag-gb", QIcon(":/images/icons/l10n/flag-gb.png")));
1292        menuSettingsStyle->setIcon(QIcon::fromTheme("preferences-desktop-theme", QIcon(":/images/icons/preferences-desktop-theme.png")));
1293        actionSettingsPreferences->setIcon(QIcon::fromTheme("preferences-system", QIcon(":/images/icons/preferences-system.png")));
1294        // Help Menu
1295        actionHelpContents->setIcon(QIcon::fromTheme("help-contents", QIcon(":/images/icons/help-contents.png")));
1296        actionHelpContextual->setIcon(QIcon::fromTheme("help-contextual", QIcon(":/images/icons/help-contextual.png")));
1297        actionHelpAbout->setIcon(QIcon::fromTheme("help-about", QIcon(":/images/icons/help-about.png")));
1298        // Buttons
1299        buttonRandom->setIcon(QIcon::fromTheme("roll", QIcon(":/images/icons/roll.png")));
1300        buttonSolve->setIcon(QIcon::fromTheme("dialog-ok", QIcon(":/images/icons/dialog-ok.png")));
1301        buttonSaveSolution->setIcon(QIcon::fromTheme("document-save-as", QIcon(":/images/icons/document-save-as.png")));
1302        buttonBackToTask->setIcon(QIcon::fromTheme("go-previous", QIcon(":/images/icons/go-previous.png")));
1303
1304//      action->setIcon(QIcon::fromTheme("", QIcon(":/images/icons/.png")));
1305
1306#if QT_VERSION >= 0x040600
1307        setToolButtonStyle(Qt::ToolButtonFollowStyle);
1308#endif
1309
1310#ifndef HANDHELD
1311QStatusBar *statusbar = new QStatusBar(this);
1312        statusbar->setObjectName("statusbar");
1313        setStatusBar(statusbar);
1314#endif // HANDHELD
1315
1316#ifdef Q_OS_WINCE_WM
1317        menuBar()->setDefaultAction(menuFile->menuAction());
1318
1319QScrollArea *scrollArea = new QScrollArea(this);
1320        scrollArea->setFrameShape(QFrame::NoFrame);
1321        scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1322        scrollArea->setWidgetResizable(true);
1323        scrollArea->setWidget(tabWidget);
1324        setCentralWidget(scrollArea);
1325#else
1326        setCentralWidget(tabWidget);
1327#endif // Q_OS_WINCE_WM
1328
1329        //! \hack HACK: A little hack for toolbar icons to have a sane size.
1330#ifdef HANDHELD
1331        toolBarMain->setIconSize(QSize(logicalDpiX() / 4, logicalDpiY() / 4));
1332#endif // HANDHELD
1333QToolButton *tb = static_cast<QToolButton *>(toolBarMain->widgetForAction(actionFileSave));
1334        if (tb != NULL)  {
1335                tb->setMenu(menuFileSaveAs);
1336                tb->setPopupMode(QToolButton::MenuButtonPopup);
1337        }
1338
1339//      solutionText->document()->setDefaultFont(settings->value("Output/Font", QFont(DEF_FONT_FAMILY, DEF_FONT_SIZE)).value<QFont>());
1340        solutionText->setWordWrapMode(QTextOption::WordWrap);
1341
1342#ifndef QT_NO_PRINTER
1343        actionFilePrintPreview = new QAction(this);
1344        actionFilePrintPreview->setObjectName("actionFilePrintPreview");
1345        actionFilePrintPreview->setEnabled(false);
1346        actionFilePrintPreview->setIcon(QIcon::fromTheme("document-print-preview", QIcon(":/images/icons/document-print-preview.png")));
1347
1348        actionFilePrint = new QAction(this);
1349        actionFilePrint->setObjectName("actionFilePrint");
1350        actionFilePrint->setEnabled(false);
1351        actionFilePrint->setIcon(QIcon::fromTheme("document-print", QIcon(":/images/icons/document-print.png")));
1352
1353        menuFile->insertAction(actionFileExit,actionFilePrintPreview);
1354        menuFile->insertAction(actionFileExit,actionFilePrint);
1355        menuFile->insertSeparator(actionFileExit);
1356
1357        toolBarMain->insertAction(actionSettingsPreferences, actionFilePrint);
1358#endif // QT_NO_PRINTER
1359
1360        groupSettingsLanguageList = new QActionGroup(this);
1361        actionSettingsLanguageEnglish->setData("en");
1362        actionSettingsLanguageEnglish->setActionGroup(groupSettingsLanguageList);
1363        loadLangList();
1364        actionSettingsLanguageAutodetect->setChecked(settings->value("Language", "").toString().isEmpty());
1365
1366        actionSettingsStyleSystem->setData(true);
1367        groupSettingsStyleList = new QActionGroup(this);
1368
1369#ifndef HANDHELD
1370        actionSettingsToolbarsConfigure = new QAction(this);
1371        actionSettingsToolbarsConfigure->setIcon(QIcon::fromTheme("configure-toolbars", QIcon(":/images/icons/configure-toolbars.png")));
1372#endif // HANDHELD
1373
1374#ifdef Q_OS_WIN32
1375        actionHelpCheck4Updates = new QAction(this);
1376        actionHelpCheck4Updates->setIcon(QIcon::fromTheme("system-software-update", QIcon(":/images/icons/system-software-update.png")));
1377        actionHelpCheck4Updates->setEnabled(hasUpdater());
1378        menuHelp->insertAction(actionHelpAboutQt, actionHelpCheck4Updates);
1379        menuHelp->insertSeparator(actionHelpAboutQt);
1380#endif // Q_OS_WIN32
1381
1382        spinCities->setMaximum(MAX_NUM_CITIES);
1383
1384#ifndef HANDHELD
1385        toolBarManager = new QtToolBarManager;
1386        toolBarManager->setMainWindow(this);
1387QString cat = toolBarMain->windowTitle();
1388        toolBarManager->addToolBar(toolBarMain, cat);
1389#ifndef QT_NO_PRINTER
1390        toolBarManager->addAction(actionFilePrintPreview, cat);
1391#endif // QT_NO_PRINTER
1392        toolBarManager->addAction(actionHelpContents, cat);
1393        toolBarManager->addAction(actionHelpContextual, cat);
1394//      toolBarManager->addAction(action, cat);
1395        toolBarManager->restoreState(settings->value("MainWindow/Toolbars").toByteArray());
1396#endif // HANDHELD
1397
1398        retranslateUi(false);
1399
1400#ifdef Q_OS_WIN32
1401        // Adding some eyecandy in Vista and 7 :-)
1402        if (QtWin::isCompositionEnabled() && settings->value("UseTranslucency", DEF_USE_TRANSLUCENCY).toBool())  {
1403                toggleTranclucency(true);
1404        }
1405#endif // Q_OS_WIN32
1406}
1407
1408void MainWindow::toggleSolutionActions(bool enable)
1409{
1410        buttonSaveSolution->setEnabled(enable);
1411        actionFileSaveAsSolution->setEnabled(enable);
1412        solutionText->setEnabled(enable);
1413#ifndef QT_NO_PRINTER
1414        actionFilePrint->setEnabled(enable);
1415        actionFilePrintPreview->setEnabled(enable);
1416#endif // QT_NO_PRINTER
1417}
1418
1419void MainWindow::toggleTranclucency(bool enable)
1420{
1421#ifdef Q_OS_WIN32
1422        toggleStyle(labelVariant, enable);
1423        toggleStyle(labelCities, enable);
1424        toggleStyle(statusBar(), enable);
1425        tabWidget->setDocumentMode(enable);
1426        QtWin::enableBlurBehindWindow(this, enable);
1427#else
1428        Q_UNUSED(enable);
1429#endif // Q_OS_WIN32
1430}
Note: See TracBrowser for help on using the repository browser.