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