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

Last change on this file since 65 was 59, checked in by laleppa, 15 years ago
  • Restore normal application cursor before displaying error message when loading/saving task. Not restoring the cursor caused it overlapping the error message text.
  • Property svn:keywords set to Id URL
File size: 11.2 KB
RevLine 
[14]1/*
[42]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 59 2009-08-30 21:02:07Z 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();
[42]121        table.resize(n);
122        for (int k = 0; k < n; k++) {
123                table[k].resize(n);
[14]124        }
[42]125        if (n > nCities)
126                for (int k = nCities; k < n; k++)
127                        table[k][k] = INFINITY;
[14]128        nCities = n;
[15]129        emit layoutChanged();
[14]130}
131
[29]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
[42]141inline bool CTSPModel::loadError(QDataStream::Status status)
[35]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.");
[59]152        QApplication::restoreOverrideCursor();
[35]153        QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + err,QMessageBox::Ok).exec();
154        return true;
155}
156
[47]157bool CTSPModel::loadTask(QString fname)
[31]158{
[59]159        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[31]160QFile f(fname);
[35]161        if (!f.open(QIODevice::ReadOnly)) {
[59]162                QApplication::restoreOverrideCursor();
[35]163                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),QString(trUtf8("Unable to open task file.\nError: %1")).arg(f.errorString()),QMessageBox::Ok).exec();
[47]164                return false;
[35]165        }
[31]166QDataStream ds(&f);
167        ds.setVersion(QDataStream::Qt_4_4);
168quint32 sig;
169        ds >> sig;
[59]170        if (loadError(ds.status())) {
[47]171                return false;
[59]172        }
[31]173        ds.device()->reset();
[49]174        if (sig == TSPT) {
[47]175                if (!loadTSPT(&ds)) {
176                        f.close();
177                        return false;
178                }
[49]179        } else if ((sig >> 16) == ZKT) {
[47]180                if (!loadZKT(&ds)) {
181                        f.close();
182                        return false;
183                }
[49]184        } else {
[59]185                f.close();
186                QApplication::restoreOverrideCursor();
[35]187                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("Unknown file format or file is corrupted."),QMessageBox::Ok).exec();
[47]188                return false;
189        }
[31]190        f.close();
[59]191        QApplication::restoreOverrideCursor();
[47]192        return true;
[31]193}
194
[47]195bool CTSPModel::loadTSPT(QDataStream *ds)
[31]196{
197        // Skipping signature
198        ds->skipRawData(sizeof(TSPT));
[35]199        if (loadError(ds->status()))
[47]200                return false;
[31]201        // File version
202quint8 version;
203        *ds >> version;
[35]204        if (loadError(ds->status()))
[47]205                return false;
[31]206        if (version > TSPT_VERSION) {
[59]207                QApplication::restoreOverrideCursor();
[35]208                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();
[47]209                return false;
[31]210        }
211        // Skipping metadata
212        ds->skipRawData(TSPT_META_SIZE);
[35]213        if (loadError(ds->status()))
[47]214                return false;
[50]215        // Number of cities
[31]216quint16 size;
217        *ds >> size;
[35]218        if (loadError(ds->status()))
[47]219                return false;
[50]220        if ((size < 3) || (size > MAX_NUM_CITIES)) {
[59]221                QApplication::restoreOverrideCursor();
[35]222                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("Unexpected data read.\nFile is possibly corrupted."),QMessageBox::Ok).exec();
[47]223                return false;
[35]224        }
[50]225        if (nCities != size) {
226                setNumCities(size);
[31]227                emit numCitiesChanged(size);
[50]228        }
229        // Travel costs
[31]230        for (int r = 0; r < size; r++)
231                for (int c = 0; c < size; c++)
[35]232                        if (r != c) {
[31]233                                *ds >> table[r][c];
[35]234                                if (loadError(ds->status())) {
235                                        clear();
[47]236                                        return false;
[35]237                                }
238                        }
[31]239        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
[59]240        QApplication::restoreOverrideCursor();
[47]241        return true;
[31]242}
243
[47]244bool CTSPModel::loadZKT(QDataStream *ds)
[31]245{
246        // Skipping signature
247        ds->skipRawData(sizeof(ZKT));
[35]248        if (loadError(ds->status()))
[47]249                return false;
[31]250        // File version
251quint16 version;
252        ds->readRawData(reinterpret_cast<char *>(&version),2);
[35]253        if (loadError(ds->status()))
[47]254                return false;
[31]255        if (version > ZKT_VERSION) {
[59]256                QApplication::restoreOverrideCursor();
[35]257                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();
[47]258                return false;
[31]259        }
[50]260        // Number of cities
[31]261quint8 size;
262        ds->readRawData(reinterpret_cast<char *>(&size),1);
[35]263        if (loadError(ds->status()))
[47]264                return false;
[35]265        if ((size < 3) || (size > 5)) {
[59]266                QApplication::restoreOverrideCursor();
[35]267                QMessageBox(QMessageBox::Critical,trUtf8("Task Load"),trUtf8("Unable to load task:") + "\n" + trUtf8("Unexpected data read.\nFile is possibly corrupted."),QMessageBox::Ok).exec();
[47]268                return false;
[35]269        }
[50]270        if (nCities != size) {
271                setNumCities(size);
[31]272                emit numCitiesChanged(size);
[50]273        }
274        // Travel costs
[31]275double val;
[42]276        for (int r = 0; r < 5; r++)
277                for (int c = 0; c < 5; c++)
278                        if ((r != c) && (r < size)) {
[31]279                                ds->readRawData(reinterpret_cast<char *>(&val),8);
[35]280                                if (loadError(ds->status())) {
281                                        clear();
[47]282                                        return false;
[35]283                                }
[31]284                                table[r][c] = val;
[35]285                        } else {
[31]286                                ds->skipRawData(8);
[35]287                                if (loadError(ds->status())) {
288                                        clear();
[47]289                                        return false;
[35]290                                }
291                        }
[31]292        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
[59]293        QApplication::restoreOverrideCursor();
[47]294        return true;
[31]295}
296
[37]297bool CTSPModel::saveTask(QString fname)
[31]298{
[59]299        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
[31]300QFile f(fname);
[35]301        if (!f.open(QIODevice::WriteOnly)) {
[59]302                QApplication::restoreOverrideCursor();
[35]303                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]304                return false;
[35]305        }
[31]306QDataStream ds(&f);
307        ds.setVersion(QDataStream::Qt_4_4);
[35]308        if (f.error() != QFile::NoError) {
[59]309                f.close();
310                QApplication::restoreOverrideCursor();
[35]311                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]312                return false;
[35]313        }
[31]314        // File signature
315        ds << TSPT;
[35]316        if (f.error() != QFile::NoError) {
[59]317                f.close();
318                QApplication::restoreOverrideCursor();
[35]319                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]320                return false;
[35]321        }
[31]322        // File version
323        ds << TSPT_VERSION;
[35]324        if (f.error() != QFile::NoError) {
[59]325                f.close();
326                QApplication::restoreOverrideCursor();
[35]327                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]328                return false;
[35]329        }
[31]330        // File metadata version
331        ds << TSPT_META_VERSION;
[35]332        if (f.error() != QFile::NoError) {
[59]333                f.close();
334                QApplication::restoreOverrideCursor();
[35]335                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]336                return false;
[35]337        }
[31]338        // Metadata
339        ds << OSID;
[35]340        if (f.error() != QFile::NoError) {
[59]341                f.close();
342                QApplication::restoreOverrideCursor();
[35]343                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]344                return false;
[35]345        }
[31]346        // Number of cities
347        ds << nCities;
[35]348        if (f.error() != QFile::NoError) {
[59]349                f.close();
350                QApplication::restoreOverrideCursor();
[35]351                QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]352                return false;
[35]353        }
[31]354        // Costs
355        for (int r = 0; r < nCities; r++)
356                for (int c = 0; c < nCities; c++)
[35]357                        if (r != c) {
[31]358                                ds << table[r][c];
[35]359                                if (f.error() != QFile::NoError) {
[59]360                                        f.close();
361                                        QApplication::restoreOverrideCursor();
[35]362                                        QMessageBox(QMessageBox::Critical,trUtf8("Task Save"),trUtf8("Unable to save task.\nError: %1").arg(f.errorString()),QMessageBox::Ok).exec();
[37]363                                        return false;
[35]364                                }
365                        }
[31]366        f.close();
[59]367        QApplication::restoreOverrideCursor();
[37]368        return true;
[31]369}
370
[15]371void CTSPModel::randomize()
372{
[21]373int randMin = settings->value("MinCost",DEF_RAND_MIN).toInt();
374int randMax = settings->value("MaxCost",DEF_RAND_MAX).toInt();
[15]375        for (int r = 0; r < nCities; r++)
376                for (int c = 0; c < nCities; c++)
377                        if (r != c)
378                                table[r][c] = rand(randMin,randMax);
379        emit dataChanged(index(0,0),index(nCities - 1,nCities - 1));
380}
Note: See TracBrowser for help on using the repository browser.