source: tspsg/src/mainwindow.cpp @ 7bb19df196

0.1.3.145-beta1-symbian0.1.4.170-beta2-bb10appveyorimgbotreadme
Last change on this file since 7bb19df196 was 7bb19df196, checked in by Oleksii Serdiuk, 14 years ago

Finished toolbar customization feature.
It is not available on handheld devices (mainly, because the customization dialog is too big for a small screen).

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