source: tspsg/src/tspmodel.cpp @ 9aa0e521ed

0.1.3.145-beta1-symbian0.1.4.170-beta2-bb10appveyorimgbotreadme
Last change on this file since 9aa0e521ed was 430bd7f7e9, checked in by Oleksii Serdiuk, 15 years ago

+ Finished solving algorithm (needs thorough testing).
+ Solution can be saved to HTML or OpenDocument? format.
+ Added VERSIONINFO resource for windows builds.

  • Updated translations to have unified terminology everywhere.

NB: This will be the first public alpha build.

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[2f915f19f2]1/*
[430bd7f7e9]2 *  TSPSG: TSP Solver and Generator
[5354a01311]3 *  Copyright (C) 2007-2009 Lёppa <contacts[at]oleksii[dot]name>
[2f915f19f2]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
[bcfd415fe2]24#include "tspmodel.h"
[2f915f19f2]25
26CTSPModel::CTSPModel(QObject *parent)
[aecdf994f9]27        : QAbstractTableModel(parent), nCities(0)
[2f915f19f2]28{
[665d32434f]29        settings = new QSettings(QSettings::IniFormat,QSettings::UserScope,"TSPSG","tspsg");
[2f915f19f2]30}
31
[9b7064d770]32inline int CTSPModel::rand(int min, int max) const
[2f915f19f2]33{
34        return min + (int)(((float)qrand() / RAND_MAX) * max);
35}
36
[4c96f94558]37int CTSPModel::rowCount(const QModelIndex &) const
[2f915f19f2]38{
39        return nCities;
40}
41
[4c96f94558]42int CTSPModel::columnCount(const QModelIndex &) const
[2f915f19f2]43{
44        return nCities;
45}
46
[5354a01311]47QVariant CTSPModel::headerData(int section, Qt::Orientation orientation, int role) const
[2f915f19f2]48{
[c02b4903bd]49        if (role == Qt::DisplayRole) {
[5354a01311]50                if (orientation == Qt::Vertical)
[5587b87fac]51                        return trUtf8("City %1").arg(section + 1);
[5354a01311]52                else
53                        return trUtf8("%1").arg(section + 1);
[c02b4903bd]54        }
[2f915f19f2]55        return QVariant();
56}
57
58QVariant CTSPModel::data(const QModelIndex &index, int role) const
59{
60        if (!index.isValid())
61                return QVariant();
62        if (role == Qt::TextAlignmentRole)
63                return int(Qt::AlignCenter);
[2bc8e278b7]64        else if (role == Qt::FontRole) {
65QFont font;
66                font.setBold(true);
67                return font;
68        } else if (role == Qt::DisplayRole || role == Qt::EditRole) {
[2f915f19f2]69                if (index.row() < nCities && index.column() < nCities)
[2bc8e278b7]70                        if (table[index.row()][index.column()] == INFINITY)
71                                return trUtf8(INFSTR);
72                        else
73                                // HACK: Converting to string to prevent spinbox in edit mode
74                                return QVariant(table[index.row()][index.column()]).toString();
[2f915f19f2]75                else
76                        return QVariant();
[2bc8e278b7]77        } else if (role == Qt::UserRole)
78                return table[index.row()][index.column()];
[2f915f19f2]79        return QVariant();
80}
81
82bool CTSPModel::setData(const QModelIndex &index, const QVariant &value, int role)
83{
[2bc8e278b7]84        if (!index.isValid())
85                return false;
86        if (role == Qt::EditRole && index.row() != index.column()) {
87                if (value.toString().compare(INFSTR) == 0)
88                        table[index.row()][index.column()] = INFINITY;
89                else {
90bool ok;
91double tmp = value.toDouble(&ok);
92                        if (!ok || tmp < 0)
93                                return false;
94                        else
95                                table[index.row()][index.column()] = tmp;
96                }
97                emit dataChanged(index,index);
98                return true;
99        }
100        return false;
[2f915f19f2]101}
102
103Qt::ItemFlags CTSPModel::flags(const QModelIndex &index) const
104{
105Qt::ItemFlags flags = QAbstractItemModel::flags(index);
[2bc8e278b7]106        if (index.row() != index.column())
[2f915f19f2]107                flags |= Qt::ItemIsEditable;
108        return flags;
109}
110
[993d5af6f6]111quint16 CTSPModel::numCities() const
[2f915f19f2]112{
113        return nCities;
114}
115
116void CTSPModel::setNumCities(int n)
117{
[2bc8e278b7]118        if (n == nCities)
119                return;
120        emit layoutAboutToBeChanged();
[430bd7f7e9]121        table.resize(n);
122        for (int k = 0; k < n; k++) {
123                table[k].resize(n);
[2f915f19f2]124        }
[430bd7f7e9]125        if (n > nCities)
126                for (int k = nCities; k < n; k++)
127                        table[k][k] = INFINITY;
[2f915f19f2]128        nCities = n;
[2bc8e278b7]129        emit layoutChanged();
130}
131
[899d1b8e15]132void CTSPModel::clear()
133{
134        for (int r = 0; r < nCities; r++)
135                for (int c = 0; c < nCities; c++)
136                        if (r != c)
137                                table[r][c] = 0;
138        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
139}
140
[430bd7f7e9]141inline bool CTSPModel::loadError(QDataStream::Status status)
[9b7064d770]142{
143QString err;
144        if (status == QDataStream::Ok)
145                return false;
146        else if (status == QDataStream::ReadPastEnd)
147                err = trUtf8("Unexpected end of file.");
148        else if (status == QDataStream::ReadCorruptData)
149                err = trUtf8("Corrupt data read. File possibly corrupted.");
150        else
151                err = trUtf8("Unknown error.");
152        QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + err,QMessageBox::Ok).exec();
153        return true;
154}
155
[993d5af6f6]156void CTSPModel::loadTask(QString fname)
157{
158QFile f(fname);
[9b7064d770]159        if (!f.open(QIODevice::ReadOnly)) {
160                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),QString(trUtf8("Unable to open task file.\nError: %1")).arg(f.errorString()),QMessageBox::Ok).exec();
161                return;
162        }
[993d5af6f6]163QDataStream ds(&f);
164        ds.setVersion(QDataStream::Qt_4_4);
165quint32 sig;
166        ds >> sig;
[9b7064d770]167        if (loadError(ds.status()))
168                return;
[993d5af6f6]169        ds.device()->reset();
170        if (sig == TSPT)
171                loadTSPT(&ds);
172        else if ((sig >> 16) == ZKT)
173                loadZKT(&ds);
174        else
[9b7064d770]175                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("Unknown file format or file is corrupted."),QMessageBox::Ok).exec();
[993d5af6f6]176        f.close();
177}
178
179void CTSPModel::loadTSPT(QDataStream *ds)
180{
181        // Skipping signature
182        ds->skipRawData(sizeof(TSPT));
[9b7064d770]183        if (loadError(ds->status()))
184                return;
[993d5af6f6]185        // File version
186quint8 version;
187        *ds >> version;
[9b7064d770]188        if (loadError(ds->status()))
189                return;
[993d5af6f6]190        if (version > TSPT_VERSION) {
[9b7064d770]191                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("File version is newer than application supports.\nPlease, try to update application."),QMessageBox::Ok).exec();
[993d5af6f6]192                return;
193        }
194        // Skipping metadata
195        ds->skipRawData(TSPT_META_SIZE);
[9b7064d770]196        if (loadError(ds->status()))
197                return;
[993d5af6f6]198        // Cities number
199quint16 size;
200        *ds >> size;
[9b7064d770]201        if (loadError(ds->status()))
202                return;
203        if (size < 3) {
204                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("Unexpected data read.\nFile is possibly corrupted."),QMessageBox::Ok).exec();
205                return;
206        }
[993d5af6f6]207        if (nCities != size)
208                emit numCitiesChanged(size);
209        // Costs
210        for (int r = 0; r < size; r++)
211                for (int c = 0; c < size; c++)
[9b7064d770]212                        if (r != c) {
[993d5af6f6]213                                *ds >> table[r][c];
[9b7064d770]214                                if (loadError(ds->status())) {
215                                        clear();
216                                        return;
217                                }
218                        }
[993d5af6f6]219        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
220}
221
222void CTSPModel::loadZKT(QDataStream *ds)
223{
224        // Skipping signature
225        ds->skipRawData(sizeof(ZKT));
[9b7064d770]226        if (loadError(ds->status()))
227                return;
[993d5af6f6]228        // File version
229quint16 version;
230        ds->readRawData(reinterpret_cast<char *>(&version),2);
[9b7064d770]231        if (loadError(ds->status()))
232                return;
[993d5af6f6]233        if (version > ZKT_VERSION) {
[9b7064d770]234                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("File version is newer than application supports.\nPlease, try to update application."),QMessageBox::Ok).exec();
[993d5af6f6]235                return;
236        }
237        // Cities number
238quint8 size;
239        ds->readRawData(reinterpret_cast<char *>(&size),1);
[9b7064d770]240        if (loadError(ds->status()))
241                return;
242        if ((size < 3) || (size > 5)) {
243                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("Unexpected data read.\nFile is possibly corrupted."),QMessageBox::Ok).exec();
244                return;
245        }
[993d5af6f6]246        if (nCities != size)
247                emit numCitiesChanged(size);
248        // Costs
249double val;
[430bd7f7e9]250        for (int r = 0; r < 5; r++)
251                for (int c = 0; c < 5; c++)
252                        if ((r != c) && (r < size)) {
[993d5af6f6]253                                ds->readRawData(reinterpret_cast<char *>(&val),8);
[9b7064d770]254                                if (loadError(ds->status())) {
255                                        clear();
256                                        return;
257                                }
[993d5af6f6]258                                table[r][c] = val;
[9b7064d770]259                        } else {
[993d5af6f6]260                                ds->skipRawData(8);
[9b7064d770]261                                if (loadError(ds->status())) {
262                                        clear();
263                                        return;
264                                }
265                        }
[993d5af6f6]266        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
267}
268
[690f6939a7]269bool CTSPModel::saveTask(QString fname)
[993d5af6f6]270{
271QFile f(fname);
[9b7064d770]272        if (!f.open(QIODevice::WriteOnly)) {
273                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),QString(trUtf8("Unable to create task file.\nError: %1\nMaybe, file is read-only?")).arg(f.errorString()),QMessageBox::Ok).exec();
[690f6939a7]274                return false;
[9b7064d770]275        }
[993d5af6f6]276QDataStream ds(&f);
277        ds.setVersion(QDataStream::Qt_4_4);
[9b7064d770]278        if (f.error() != QFile::NoError) {
279                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
280                f.close();
[690f6939a7]281                return false;
[9b7064d770]282        }
[993d5af6f6]283        // File signature
284        ds << TSPT;
[9b7064d770]285        if (f.error() != QFile::NoError) {
286                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
287                f.close();
[690f6939a7]288                return false;
[9b7064d770]289        }
[993d5af6f6]290        // File version
291        ds << TSPT_VERSION;
[9b7064d770]292        if (f.error() != QFile::NoError) {
293                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
294                f.close();
[690f6939a7]295                return false;
[9b7064d770]296        }
[993d5af6f6]297        // File metadata version
298        ds << TSPT_META_VERSION;
[9b7064d770]299        if (f.error() != QFile::NoError) {
300                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
301                f.close();
[690f6939a7]302                return false;
[9b7064d770]303        }
[993d5af6f6]304        // Metadata
305        ds << OSID;
[9b7064d770]306        if (f.error() != QFile::NoError) {
307                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
308                f.close();
[690f6939a7]309                return false;
[9b7064d770]310        }
[993d5af6f6]311        // Number of cities
312        ds << nCities;
[9b7064d770]313        if (f.error() != QFile::NoError) {
314                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
315                f.close();
[690f6939a7]316                return false;
[9b7064d770]317        }
[993d5af6f6]318        // Costs
319        for (int r = 0; r < nCities; r++)
320                for (int c = 0; c < nCities; c++)
[9b7064d770]321                        if (r != c) {
[993d5af6f6]322                                ds << table[r][c];
[9b7064d770]323                                if (f.error() != QFile::NoError) {
324                                        QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
325                                        f.close();
[690f6939a7]326                                        return false;
[9b7064d770]327                                }
328                        }
[993d5af6f6]329        f.close();
[690f6939a7]330        return true;
[993d5af6f6]331}
332
[2bc8e278b7]333void CTSPModel::randomize()
334{
[aecdf994f9]335int randMin = settings->value("MinCost",DEF_RAND_MIN).toInt();
336int randMax = settings->value("MaxCost",DEF_RAND_MAX).toInt();
[2bc8e278b7]337        for (int r = 0; r < nCities; r++)
338                for (int c = 0; c < nCities; c++)
339                        if (r != c)
340                                table[r][c] = rand(randMin,randMax);
341        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
[2f915f19f2]342}
Note: See TracBrowser for help on using the repository browser.