1 #include "weightdata.h"
5 #include <QtAlgorithms>
11 WeightDataModel::WeightDataModel(QString &datafilename, QObject *parent) :
12 QAbstractTableModel(parent), datafile(datafilename)
18 Qt::ItemFlags WeightDataModel::flags(const QModelIndex &index) const
21 return Qt::ItemIsEnabled;
22 switch(index.column()) {
23 case 0: return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
24 case 1: return Qt::ItemIsEnabled | Qt::ItemIsEditable;
25 default: return Qt::NoItemFlags;
29 QVariant WeightDataModel::headerData(int section, Qt::Orientation orientation, int role) const
31 if (role != Qt::DisplayRole)
33 if (orientation == Qt::Horizontal) {
34 return section == 0 ? tr("Date") : tr("Weight");
37 return QString("%1").arg(section);
41 bool WeightDataModel::dateExists(const QDate &date) const
43 return rowOfDate(date) != -1;
46 int WeightDataModel::rowOfDate(const QDate &date) const
48 // TODO: binary search
49 for(int i=0; i<weights.size(); i++)
50 if (weights[i].date == date)
55 QModelIndex WeightDataModel::indexOfDate(const QDate &date) const
57 return index(rowOfDate(date), 0);
60 QVariant WeightDataModel::data(const QModelIndex &index, int role) const
62 if (!index.isValid() || index.row() >= rowCount()
63 || index.column() >= columnCount())
66 if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::SizeHintRole)
69 if (role == Qt::SizeHintRole) {
70 if (index.column() == 0)
76 if (index.column() == 0) {
77 return weights.at(index.row()).date.toString(Qt::ISODate);
80 if (role == Qt::DisplayRole)
81 return QString("%1 %2").arg(weights.at(index.row()).weight,5,'f',1)
82 .arg(Settings::weightUnit());
84 return weights.at(index.row()).weight;
90 double WeightDataModel::minWeight() const {
91 // TODO: cache minimum and maximum weight on initial read and modifications?
92 double min = std::numeric_limits<double>::max();
93 foreach(const DW& dw, weights) {
100 double WeightDataModel::maxWeight() const {
101 double max = std::numeric_limits<double>::min();
102 foreach(const DW& dw, weights) {
109 bool WeightDataModel::setData(const QModelIndex &index, const QVariant &value, int role)
111 if (!index.isValid() || role != Qt::EditRole)
113 switch (index.column()) {
115 QDate date = value.toDate();
118 weights[index.row()].date = date;
123 double weight = value.toDouble(&ok);
126 weights[index.row()].weight = weight;
129 default: return false;
132 emit(dataChanged(index, index));
138 bool WeightDataModel::setDataForRow(int row, const DateWeight &dw)
140 if (row < 0 || row >= weights.size())
144 QModelIndex a = index(row, 0);
145 QModelIndex b = index(row, 1);
147 emit(dataChanged(a, b));
151 // Sets data for a date. Adds a new row for the date if it doesn't exist.
152 void WeightDataModel::setWeightForDate(const QDate &date, double weight)
154 int row = rowOfDate(date);
156 row = rowForNewDate(date);
159 DateWeight dw = {date, weight};
160 setDataForRow(row, dw);
162 int WeightDataModel::rowForNewDate(const QDate &date) const
164 if (weights.size() == 0)
166 if (date < weights.first().date)
168 // TODO: binary search
169 for(int i=1; i<weights.size(); i++) {
170 if (weights.at(i-1).date < date && weights.at(i).date > date)
173 if (date > weights.last().date)
174 return weights.size();
175 assert(0 && "UNREACHABLE");
179 void WeightDataModel::setWeightForDate(const WeightDataModel::DateWeight &dw)
181 setWeightForDate(dw.date, dw.weight);
184 // Insert count "empty" rows starting from row.
185 // DOESN'T WRITE DATA BACK TO DISK to allow inserter
186 // to modify the row, then write it.
187 bool WeightDataModel::insertRows(int row, int count, const QModelIndex &/*parent*/)
189 beginInsertRows(QModelIndex(), row, row+count-1);
192 weights.insert(row, empty);
197 bool WeightDataModel::removeRows(int row, int count, const QModelIndex &/*parent*/)
199 beginRemoveRows(QModelIndex(), row, row+count-1);
201 weights.removeAt(row);
207 void WeightDataModel::clear()
212 void WeightDataModel::writeToDisk()
214 if (QFile::exists(datafile.fileName())) {
215 QString backupfile = datafile.fileName()+".bak";
216 if (QFile::exists(backupfile))
217 QFile::remove(backupfile);
218 QFile::copy(datafile.fileName(), backupfile);
220 if (datafile.open(QIODevice::WriteOnly | QIODevice::Text)) {
221 QTextStream stream(&datafile);
222 foreach(DateWeight w, weights)
223 stream << w.date.toString(Qt::ISODate) << ';' << w.weight << "\n";
228 void WeightDataModel::readFromDisk()
230 if (!datafile.exists()) {
234 if (datafile.open(QIODevice::ReadOnly | QIODevice::Text)) {
236 QTextStream stream(&datafile);
237 QString line = stream.readLine();
238 while (!line.isNull()) {
239 QStringList parts = line.split(';');
240 if (parts.size() != 2) {
241 throw(QString("Invalid line in file: '%1'").arg(line));
244 w.date = QDate::fromString(parts[0], Qt::ISODate);
245 if (!w.date.isValid()) {
246 throw(QString("Invalid date in file: '%1'").arg(parts[0]));
249 w.weight = parts[1].toDouble(&ok);
251 throw(QString("Invalid weight in file: '%1'").arg(parts[1]));
253 weights.push_back(w);
254 line = stream.readLine();
261 throw(QString("Could not read file '%1'").arg(datafile.fileName()));