1 /***************************************************************************
2 hopmodel.cpp
3 -------------------
4 Hop model
5 -------------------
6 Copyright 2006-2008, David Johnson
7 Please see the header file for copyright and license information
8 ***************************************************************************/
9
10 #include <QApplication>
11 #include <QMessageBox>
12 #include <QPair>
13
14 #include "data.h"
15 #include "hopmodel.h"
16
17 using namespace Resource;
18
19 //////////////////////////////////////////////////////////////////////////////
20 // HopModel()
21 // ------------
22 // Constructor
23
HopModel(QObject * parent,HopList * list)24 HopModel::HopModel(QObject *parent, HopList *list)
25 : QAbstractTableModel(parent), list_(list)
26 {}
27
~HopModel()28 HopModel::~HopModel() {}
29
30 //////////////////////////////////////////////////////////////////////////////
31 // flush()
32 // -------
33 // Reset the model
34
flush()35 void HopModel::flush()
36 {
37 beginResetModel();
38 endResetModel();
39 }
40
41 //////////////////////////////////////////////////////////////////////////////
42 // data()
43 // ------
44 // Return data at index
45
data(const QModelIndex & index,int role) const46 QVariant HopModel::data(const QModelIndex &index, int role) const
47 {
48 if (!index.isValid()) return QVariant();
49 if (index.row() >= list_->count()) return QVariant();
50
51 // row is the entry in the QList
52 const Hop &hop = list_->at(index.row());
53
54 // column is the hop "field"
55 if (role == Qt::DisplayRole) {
56 switch (index.column()) {
57 case NAME:
58 return hop.name();
59 case WEIGHT:
60 return hop.weight().toString(3);
61 case ALPHA:
62 return QString::number(hop.alpha(), 'f', 1) + '%';
63 case TIME:
64 return QString::number(hop.time()) + tr(" min", "minutes");
65 case TYPE:
66 return hop.type();
67 default:
68 return QVariant();
69 }
70 } else if (role == Qt::EditRole) {
71 switch (index.column()) {
72 case NAME:
73 return hop.name();
74 case WEIGHT: {
75 // return converted quantity
76 Weight weight = hop.weight();
77 weight.convert(Data::instance()->defaultHopUnit());
78 return weight.amount();
79 }
80 case ALPHA:
81 return hop.alpha();
82 case TIME:
83 return hop.time();
84 case TYPE:
85 return hop.type();
86 default:
87 return QVariant();
88 }
89 } else if (role == Qt::TextAlignmentRole) {
90 switch (index.column()) {
91 case NAME:
92 case TYPE:
93 return Qt::AlignLeft;
94 case WEIGHT:
95 case ALPHA:
96 case TIME:
97 default:
98 return Qt::AlignRight;
99 }
100 } else {
101 return QVariant();
102 }
103 }
104
105 //////////////////////////////////////////////////////////////////////////////
106 // setData()
107 // ---------
108 // Set data at index
109
setData(const QModelIndex & index,const QVariant & value,int role)110 bool HopModel::setData(const QModelIndex &index,
111 const QVariant &value, int role)
112 {
113 static bool deleting = false;
114
115 Hop hop;
116 QString name;
117 int row = index.row();
118 int column = index.column();
119
120 if (!index.isValid()) return false;
121 if (role != Qt::EditRole) return false;
122 if (row >= list_->count()) return false;
123
124 // grab existing hop
125 if (row < list_->count()) hop = list_->value(row);
126
127 switch (column) {
128 case NAME:
129 // editing name as several special cases
130 name = value.toString();
131
132 // deleting name deletes hop
133 if (name.isEmpty()) {
134 if (row >= list_->count()) return false; // already blank
135
136 // TODO: for some reason this gets entered recursively...
137 if (deleting) return false;
138 deleting = true;
139
140 int status = QMessageBox::question(QApplication::activeWindow(),
141 TITLE + tr(" - Delete?"),
142 tr("Do you wish to remove this entry?"),
143 QMessageBox::Yes | QMessageBox::Cancel);
144 if (status == QMessageBox::Yes) {
145 // remove hop
146 beginRemoveRows(index.parent(), row, row);
147
148 list_->removeAt(row);
149 emit modified();
150 endRemoveRows();
151
152 deleting = false;
153 return true;
154 } else {
155 // ignore
156 deleting = false;
157 return false;
158 }
159 }
160
161 // no change, nothing to do
162 if (name == list_->at(row).name()) {
163 return false;
164 }
165
166 // changed name
167 hop.setName(name);
168 if (Data::instance()->hasHop(name)) {
169 Hop newhop = Data::instance()->hop(name);
170 // we don't override weight or time
171 hop.setType(newhop.type());
172 hop.setAlpha(newhop.alpha());
173 }
174 break;
175
176 case WEIGHT:
177 hop.setWeight(Weight(value.toDouble(),
178 Data::instance()->defaultHopUnit()));
179 break;
180
181 case ALPHA:
182 hop.setAlpha(value.toDouble());
183 break;
184
185 case TIME:
186 hop.setTime(value.toUInt());
187 break;
188
189 case TYPE:
190 hop.setType(value.toString());
191 break;
192
193 default:
194 return false;
195 }
196
197 list_->replace(row, hop);
198 emit modified();
199
200 // whole row may have changed
201 emit dataChanged(index.sibling(row, NAME),
202 index.sibling(row, TIME));
203
204 return true;
205 }
206
207 //////////////////////////////////////////////////////////////////////////////
208 // insertRows()
209 // ------------
210 // Insert rows into table
211
insertRows(int row,int count,const QModelIndex &)212 bool HopModel::insertRows(int row, int count, const QModelIndex&)
213 {
214 if (count != 1) return false; // only insert one row at a time
215 if ((row < 0) || (row >= list_->count())) row = list_->count();
216
217 Hop hop = Data::instance()->hop(tr("Generic"));
218
219 beginInsertRows(QModelIndex(), row, row);
220 list_->insert(row, hop);
221 emit modified();
222 endInsertRows();
223 return true;
224 }
225
226 //////////////////////////////////////////////////////////////////////////////
227 // removeRows()
228 // ------------
229 // Remove rows from table
230
removeRows(int row,int count,const QModelIndex &)231 bool HopModel::removeRows(int row, int count, const QModelIndex&)
232 {
233 if (count != 1) return false; // only remove one row at a time
234 if ((row < 0) || (row >= list_->count())) return false;
235
236 int status = QMessageBox::question(QApplication::activeWindow(),
237 TITLE + tr(" - Delete?"),
238 tr("Do you wish to remove this entry?"),
239 QMessageBox::Yes | QMessageBox::Cancel);
240 if (status == QMessageBox::Cancel) {
241 return false;
242 }
243
244 beginRemoveRows(QModelIndex(), row, row);
245 list_->removeAt(row);
246 emit modified();
247 endRemoveRows();
248 return true;
249 }
250
251 //////////////////////////////////////////////////////////////////////////////
252 // headerData()
253 // ------------
254 // Return header information
255
headerData(int section,Qt::Orientation orientation,int role) const256 QVariant HopModel::headerData(int section, Qt::Orientation orientation,
257 int role) const
258 {
259 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
260 switch (section) {
261 case NAME:
262 return tr("Hop");
263 case WEIGHT:
264 return tr("Weight");
265 case ALPHA:
266 return tr("Alpha");
267 case TIME:
268 return tr("Time");
269 case TYPE:
270 return tr("Type");
271 default:
272 return QVariant();
273 }
274 }
275
276 return QVariant();
277 }
278
279 //////////////////////////////////////////////////////////////////////////////
280 // flags()
281 // ------
282 // Return flags at index
283
flags(const QModelIndex & index) const284 Qt::ItemFlags HopModel::flags(const QModelIndex &index) const
285 {
286 if (!index.isValid()) return Qt::ItemIsEnabled;
287
288 return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
289 }
290
291 //////////////////////////////////////////////////////////////////////////////
292 // rowCount()
293 // ----------
294 // Return number of rows of data
295
rowCount(const QModelIndex &) const296 int HopModel::rowCount(const QModelIndex &) const
297 {
298 return list_->count();
299 }
300
301 //////////////////////////////////////////////////////////////////////////////
302 // columnCount()
303 // -------------
304 // Return number of columns of data
305
columnCount(const QModelIndex &) const306 int HopModel::columnCount(const QModelIndex &) const
307 {
308 return COUNT;
309 }
310
311 //////////////////////////////////////////////////////////////////////////////
312 // sort()
313 // ------
314 // Sort by column
315
sort(int column,Qt::SortOrder order)316 void HopModel::sort(int column, Qt::SortOrder order)
317 {
318 QList<QPair<QString,Hop> > sortlist;
319
320 foreach(Hop hop, *list_) {
321 QString field;
322 switch (column) {
323 case NAME:
324 field = hop.name();
325 break;
326 case WEIGHT:
327 field = QString::number(hop.weight().amount()).rightJustified(8,'0');
328 break;
329 case ALPHA:
330 field = QString::number(hop.alpha(),'f',1).rightJustified(8,'0');
331 break;
332 case TYPE:
333 field = hop.type();
334 break;
335 case TIME:
336 default:
337 field = QString::number(hop.time()).rightJustified(8,'0');
338 break;
339 }
340 sortlist.append(QPair<QString,Hop>(field, hop));
341 }
342
343 // sort list
344 qSort(sortlist.begin(), sortlist.end());
345
346 emit layoutAboutToBeChanged();
347
348 // create new list
349 list_->clear();
350 QPair<QString,Hop> pair;
351 foreach(pair, sortlist) {
352 if (order == Qt::AscendingOrder)
353 list_->append(pair.second);
354 else
355 list_->prepend(pair.second);
356 }
357
358 emit layoutChanged();
359 }
360