source: tspsg-svn/trunk/src/tspmodel.cpp @ 40

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

+ Task save prompt before creating or opening task and closing application if current task was modified.

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