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

Last change on this file since 114 was 114, checked in by laleppa, 15 years ago

+ Added a checkbox to the "Settings" menu to be able to show/hide Toolbar.

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