Moved StationListModel to AbstractListModel base
[quandoparte] / application / stationlistmodel.cpp
1 /*
2
3 Copyright (C) 2011 Luciano Montanaro <mikelima@cirulla.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING.  If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19
20 */
21
22 #include "stationlistmodel.h"
23 #include "settings.h"
24
25 #include <QFile>
26 #include <QFileInfo>
27 #include <QDebug>
28 #include <QStandardItem>
29 #include <QGeoCoordinate>
30
31 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
32 QTM_USE_NAMESPACE
33 Q_DECLARE_METATYPE(QGeoCoordinate)
34 #endif
35
36 StationListModel::StationListModel(QObject *parent) :
37     QAbstractListModel(parent)
38 {
39 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
40     setRoleNames(roleNames());
41 #endif
42     Settings *settings = Settings::instance();
43     m_favorites = settings->favoriteStations().toSet();
44     qDebug() << "favorites:" << m_favorites;
45 }
46
47 bool StationListModel::load(const QString &filename)
48 {
49     QFile file(filename);
50     QFileInfo fi(file);
51
52     qDebug() << "loading file:" << fi.absoluteFilePath();
53
54     emit layoutAboutToBeChanged();
55     beginResetModel();
56     if (!file.open(QFile::ReadOnly | QFile::Text)) {
57         qDebug() << "cannot open file:" << filename;
58         return false;
59     }
60     m_reader.setDevice(&file);
61     m_reader.readNext();
62     while (!m_reader.atEnd()) {
63         if (m_reader.isStartElement()) {
64             if(m_reader.name() == "stations") {
65                 readStationsElement();
66             } else {
67                 m_reader.raiseError(tr("Not a qpl file"));
68             }
69         } else {
70             m_reader.readNext();
71         }
72     }
73     file.close();
74     qDebug() << rowCount() << "stations loaded";
75     if (m_reader.hasError()) {
76         qDebug() << "parser error for:" << filename;
77         return false;
78     } else if (file.error() != QFile::NoError) {
79         qDebug() << "file error for:" << filename;
80         return false;
81     }
82     endResetModel();
83     emit layoutChanged();
84     return true;
85 }
86
87 QHash<int, QByteArray> StationListModel::roleNames() const
88 {
89     QHash<int, QByteArray> roles;
90     roles[Qt::DisplayRole] = "name";
91     roles[StationListModel::PositionRole] = "position";
92     roles[StationListModel::RecentIndicatorRole] = "recent";
93     roles[StationListModel::FavoriteIndicatorRole] = "favorite";
94     roles[StationListModel::StationCodeRole] = "code";
95     roles[StationListModel::LongitudeRole] = "longitude";
96     roles[StationListModel::LatitudeRole] = "latitude";
97     roles[StationListModel::SectionRole] = "section";
98     return roles;
99 }
100
101 int StationListModel::rowCount(const QModelIndex &) const
102 {
103     return m_stations.count();
104 }
105
106 QVariant StationListModel::data(const QModelIndex &index, int role) const
107 {
108     if (!index.isValid()) return QVariant();
109     if (index.row() < 0 || index.row() >= m_stations.count()) {
110         return QVariant();
111     }
112     StationItem item = m_stations[index.row()];
113     Settings *settings = Settings::instance();
114     switch (role) {
115     case Qt::DisplayRole:
116         return QVariant::fromValue(item.name());
117     case PositionRole:
118         return QVariant::fromValue(item.position());
119     case RecentIndicatorRole:
120         return QVariant(settings->recentStations().contains(item.name()));
121     case FavoriteIndicatorRole:
122         return QVariant(m_favorites.contains(item.name()));
123     case StationCodeRole:
124         return QVariant::fromValue(item.code());
125     case LatitudeRole:
126         return QVariant::fromValue(item.position().latitude());
127     case LongitudeRole:
128         return QVariant::fromValue(item.position().longitude());
129     case SectionRole:
130         if (m_favorites.contains(item.name()))
131             return QVariant::fromValue(tr("Favorites"));
132         else
133             return QVariant(item.name()[0]);
134     default:
135         return QVariant::fromValue(QString("Unknown role requested"));
136     }
137 }
138
139 bool StationListModel::setData(const QModelIndex &index, QVariant &value, int role)
140 {
141     if (!index.isValid())
142         return false;
143     if (role == FavoriteIndicatorRole) {
144         bool favorite = value.toBool();
145         if (data(index, FavoriteIndicatorRole) != favorite) {
146             QString name =  m_stations[index.row()].name();
147             if (favorite) {
148                 qDebug() << "adding" << name << "to favorites";
149                 m_favorites.insert(name);
150             } else {
151                 qDebug() << "removing" << name << "from favorites";
152                 m_favorites.remove(name);
153             }
154             Settings *settings = Settings::instance();
155             settings->setFavoriteStations(QStringList::fromSet(m_favorites));
156             QVector<int> changedRoles;
157             changedRoles << FavoriteIndicatorRole;
158             //emit dataChanged(index, index, changedRoles);
159             emit dataChanged(index, index);
160         }
161         return true;
162     }
163    return false;
164 }
165
166 Qt::ItemFlags StationListModel::flags(const QModelIndex &index) const
167 {
168     if (!index.isValid())
169         return 0;
170     return Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
171 }
172
173 void StationListModel::readStationsElement()
174 {
175     m_reader.readNext();
176     while (!m_reader.atEnd()) {
177         if (m_reader.isEndElement()) {
178             m_reader.readNext();
179             break;
180         } else if (m_reader.isStartElement()) {
181             if (m_reader.name() == "station") {
182                 readStationElement();
183             } else {
184                 skipUnknownElement(m_reader.name().toString());
185             }
186         } else {
187             m_reader.readNext();
188         }
189     }
190 }
191
192 void StationListModel::readStationElement()
193 {
194     StationItem item;
195     m_reader.readNext();
196     while (!m_reader.atEnd()) {
197         if (m_reader.isEndElement()) {
198             m_stations.append(item);
199             m_reader.readNext();
200             break;
201         } else if (m_reader.isStartElement()) {
202             if (m_reader.name() == "pos") {
203                 readPosElement(item);
204             } else  if (m_reader.name() == "name") {
205                 readNameElement(item);
206             } else  if (m_reader.name() == "code") {
207                 readCodeElement(item);
208             } else {
209                 skipUnknownElement(m_reader.name().toString());
210             }
211         } else {
212             m_reader.readNext();
213         }
214     }
215 }
216
217 void StationListModel::readPosElement(StationItem &item)
218 {
219     QStringList coordinates = m_reader.readElementText().split(",");
220     QGeoCoordinate pos = QGeoCoordinate(coordinates[0].toDouble(), coordinates[1].toDouble());
221     item.setPosition(pos);
222     m_reader.readElementText();
223     if (m_reader.isEndElement()) {
224         m_reader.readNext();
225     }
226 }
227
228 void StationListModel::readNameElement(StationItem &item)
229 {
230     item.setName(m_reader.readElementText());
231     if (m_reader.isEndElement()) {
232         m_reader.readNext();
233     }
234 }
235
236 void StationListModel::readCodeElement(StationItem &item)
237 {
238     const QString code = m_reader.readElementText();
239     qDebug() << "reading code element" << code;
240
241     item.setCode(code);
242     if (m_reader.isEndElement()) {
243         m_reader.readNext();
244     }
245 }
246
247 void StationListModel::skipUnknownElement(const QString &name)
248 {
249     qDebug() << "skipping unknown element" << name << "at line" << m_reader.lineNumber();
250
251     m_reader.readNext();
252     while (!m_reader.atEnd()) {
253         if (m_reader.isEndElement()) {
254             m_reader.readNext();
255             break;
256         } else if (!m_reader.isStartElement()) {
257             skipUnknownElement(m_reader.name().toString());
258         } else {
259             m_reader.readNext();
260         }
261     }
262 }