git-svn-id: file:///svnroot/family-shop-mgr@9 26eb2498-383b-47a6-be48-5d6f36779e85
[family-shop-mgr] / code / family-shop-mgr / ShoppingTreeModel.cpp
1 /*\r
2  * This file is part of family-shop-mgr.\r
3  *\r
4  * family-shop-mgr is free software: you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation, either version 3 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * family-shop-mgr is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License\r
15  * along with family-shop-mgr.  If not, see <http://www.gnu.org/licenses/>.\r
16  *\r
17  * Author: Unai IRIGOYEN\r
18  * Date: 12/07/2009\r
19  *\r
20  */\r
21 \r
22 #include "ShoppingTreeModel.h"\r
23 \r
24 #include "ShoppingTreeItem.h"\r
25 #include <QFile>\r
26 #include <QtGui>\r
27 \r
28 ShoppingTreeModel::ShoppingTreeModel(const QString &xmlFileName,\r
29                                      QObject *parent) :\r
30 QAbstractItemModel(parent), m_document("ShoppingList")\r
31 {\r
32     QString error;\r
33     int errLine;\r
34     int errColumn;\r
35 \r
36     QFile file(xmlFileName);\r
37     if(!file.open(QIODevice::ReadOnly))\r
38         return;\r
39     // Parse xml file\r
40     if(!m_document.setContent(&file, true, &error, &errLine, &errColumn))\r
41     {\r
42         emit xmlParseError(error, errLine, errColumn);\r
43         file.close();\r
44         return;\r
45     }\r
46     file.close();\r
47 \r
48     QDomElement root = m_document.documentElement();\r
49     if(root.tagName() != "shoppingList" || !root.hasAttribute("version"))\r
50     {\r
51         emit invalidDocument();\r
52         return;\r
53     }\r
54     else if(root.attribute("version") == "1.0")\r
55     {\r
56         // set column titles\r
57         QVector<QVariant> rootData;\r
58         rootData << "Category/Item name"\r
59                 << "Quantity" << "Store";\r
60 \r
61         rootItem = new ShoppingTreeItem(rootData);\r
62     }\r
63     else\r
64     {\r
65         // upgrade document version if possible\r
66         ;\r
67     }\r
68 \r
69     QDomElement child = root.firstChildElement("category");\r
70     while(!child.isNull())\r
71     {\r
72         // Parse all categories\r
73         parseCategoryElement(child);\r
74         child = child.nextSiblingElement("category");\r
75     }\r
76 \r
77     child = root.firstChildElement("item");\r
78     while(!child.isNull())\r
79     {\r
80         // parse all items which don't have category\r
81         rootItem->insertChildren(\r
82                 rootItem->childCount(), 1,\r
83                 rootItem->columnCount());\r
84         QVector<QVariant> columnData =\r
85                 getColumnsFromItemElement(child);\r
86         for(int column = 0; column < columnData.size(); column++)\r
87         {\r
88             rootItem->child(rootItem->childCount() - 1)->setData(column, columnData[column]);\r
89         }\r
90         m_domElementForItem.insert(rootItem->child(rootItem->childCount() - 1),\r
91                                    child);\r
92     }\r
93 }\r
94 \r
95 ShoppingTreeModel::~ShoppingTreeModel()\r
96 {\r
97     delete rootItem;\r
98 }\r
99 \r
100 QVariant ShoppingTreeModel::data(const QModelIndex &index, int role) const\r
101 {\r
102     if(!index.isValid())\r
103         return QVariant();\r
104 \r
105     if(role != Qt::DisplayRole && role != Qt::EditRole)\r
106         return QVariant();\r
107 \r
108     ShoppingTreeItem *item = getItem(index);\r
109     return item->data(index.column());\r
110 }\r
111 \r
112 Qt::ItemFlags ShoppingTreeModel::flags(const QModelIndex &index) const\r
113 {\r
114     if(!index.isValid())\r
115         return 0;\r
116 \r
117     return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;\r
118 }\r
119 \r
120 ShoppingTreeItem *ShoppingTreeModel::getItem(const QModelIndex &index) const\r
121 {\r
122     if(index.isValid()){\r
123         ShoppingTreeItem *item = static_cast<ShoppingTreeItem*>(index.internalPointer());\r
124         if(item) return item;\r
125     }\r
126 \r
127     return rootItem;\r
128 }\r
129 \r
130 QVariant ShoppingTreeModel::headerData(int section, Qt::Orientation orientation,\r
131                                        int role) const\r
132 {\r
133     if(orientation == Qt::Horizontal && role == Qt::DisplayRole)\r
134         return rootItem->data(section);\r
135 \r
136     return QVariant();\r
137 }\r
138 \r
139 QModelIndex ShoppingTreeModel::index(int row, int column, const QModelIndex &parent) const\r
140 {\r
141     if(parent.isValid() && parent.column() != 0)\r
142         return QModelIndex();\r
143 \r
144     ShoppingTreeItem *parentItem = getItem(parent);\r
145 \r
146     ShoppingTreeItem *childItem = parentItem->child(row);\r
147     if(childItem)\r
148         return createIndex(row, column, childItem);\r
149     else\r
150         return QModelIndex();\r
151 }\r
152 \r
153 bool ShoppingTreeModel::insertColumns(int position, int columns, const QModelIndex &parent)\r
154 {\r
155     bool success;\r
156 \r
157     beginInsertColumns(parent, position, position + columns - 1);\r
158     success = rootItem->insertColumns(position, columns);\r
159     endInsertColumns();\r
160 \r
161     return success;\r
162 }\r
163 \r
164 bool ShoppingTreeModel::insertRows(int position, int rows, const QModelIndex &parent)\r
165 {\r
166     ShoppingTreeItem *parentItem = getItem(parent);\r
167     bool success;\r
168 \r
169     beginInsertRows(parent, position, position + rows - 1);\r
170     success = parentItem->insertChildren(position, rows, rootItem->columnCount());\r
171     endInsertRows();\r
172 \r
173     return success;\r
174 }\r
175 \r
176 QModelIndex ShoppingTreeModel::parent(const QModelIndex &index) const\r
177 {\r
178     if(!index.isValid())\r
179         return QModelIndex();\r
180 \r
181     ShoppingTreeItem *childItem = getItem(index);\r
182     ShoppingTreeItem *parentItem = childItem->parent();\r
183 \r
184     if(parentItem == rootItem)\r
185         return QModelIndex();\r
186 \r
187     return createIndex(parentItem->childNumber(), 0, parentItem);\r
188 }\r
189 \r
190 bool ShoppingTreeModel::removeColumns(int position, int columns, const QModelIndex &parent)\r
191 {\r
192     bool success;\r
193 \r
194     beginRemoveColumns(parent, position, position + columns - 1);\r
195     success = rootItem->removeColumns(position, columns);\r
196     endRemoveColumns();\r
197 \r
198     if(rootItem->columnCount() != 0)\r
199         removeRows(0, rowCount());\r
200 \r
201     return success;\r
202 }\r
203 \r
204 bool ShoppingTreeModel::removeRows(int position, int rows, const QModelIndex &parent)\r
205 {\r
206     ShoppingTreeItem *parentItem = getItem(parent);\r
207     bool success;\r
208 \r
209     beginRemoveRows(parent, position, position + rows - 1);\r
210     success = parentItem->removeChildren(position, rows);\r
211     endRemoveRows();\r
212 \r
213     return success;\r
214 }\r
215 \r
216 int ShoppingTreeModel::rowCount(const QModelIndex &parent) const\r
217 {\r
218     ShoppingTreeItem *parentItem = getItem(parent);\r
219 \r
220     return parentItem->childCount();\r
221 }\r
222 \r
223 int ShoppingTreeModel::columnCount(const QModelIndex &parent) const\r
224 {\r
225     return rootItem->columnCount();\r
226 }\r
227 bool ShoppingTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)\r
228 {\r
229     if(role != Qt::EditRole)\r
230         return false;\r
231 \r
232     ShoppingTreeItem *item = getItem(index);\r
233     bool result = item->setData(index.column(),value);\r
234 \r
235     if(result)\r
236         emit dataChanged(index, index);\r
237 \r
238     return result;\r
239 }\r
240 \r
241 bool ShoppingTreeModel::setHeaderData(int section, Qt::Orientation orientation,\r
242                                       const QVariant &value, int role)\r
243 {\r
244     if(role != Qt::EditRole || orientation != Qt::Horizontal)\r
245         return false;\r
246 \r
247     bool result = rootItem->setData(section, value);\r
248 \r
249     if(result)\r
250         emit headerDataChanged(orientation, section, section);\r
251 \r
252     return result;\r
253 }\r
254 \r
255 void ShoppingTreeModel::parseCategoryElement(const QDomElement &element,\r
256                                              ShoppingTreeItem *parentItem)\r
257 {\r
258     // if parent is null then add category to root\r
259     if(!parentItem)\r
260         parentItem = rootItem;\r
261 \r
262     ShoppingTreeItem *item;\r
263     QString title = element.firstChildElement("title").text();\r
264     if(!title.isEmpty())\r
265     {\r
266         parentItem->insertChildren(parentItem->childCount(), 1,\r
267                                    rootItem->columnCount());\r
268 \r
269         parentItem->child(parentItem->childCount() - 1)->setData(0, title);\r
270         m_domElementForItem.insert(parentItem->child(parentItem->childCount() - 1),\r
271                                    element);\r
272         item = parentItem->child(parentItem->childCount() - 1);\r
273     }\r
274     else\r
275     {\r
276         emit invalidDocument();\r
277         return;\r
278     }\r
279 \r
280     // add each sub category and item to the tree\r
281     QDomElement child = element.firstChildElement();\r
282     while(!child.isNull())\r
283     {\r
284         if(child.tagName() == "category")\r
285         {\r
286             parseCategoryElement(child, parentItem);\r
287         }\r
288         else if(child.tagName() == "item")\r
289         {\r
290             item->insertChildren(\r
291                     item->childCount(), 1,\r
292                     rootItem->columnCount());\r
293             QVector<QVariant> columnData =\r
294                     getColumnsFromItemElement(child);\r
295             for(int column = 0; column < columnData.size(); column++)\r
296             {\r
297                 item->child(item->childCount() - 1)->setData(column, columnData[column]);\r
298             }\r
299             m_domElementForItem.insert(item->child(item->childCount() - 1),\r
300                                        child);\r
301         }\r
302         else\r
303         {\r
304             emit invalidDocument();\r
305             return;\r
306         }\r
307 \r
308         child = child.nextSiblingElement();\r
309     }\r
310 }\r
311 \r
312 QVector<QVariant> ShoppingTreeModel::getColumnsFromItemElement(const QDomElement &element)\r
313 {\r
314     QVector<QVariant> data;\r
315     QString title = element.firstChildElement("title").text();\r
316     int quantity = element.firstChildElement("quantity").text().toInt();\r
317     QString store = element.firstChildElement("store").text();\r
318     if(title.isEmpty() || quantity < 0)\r
319     {\r
320         emit invalidDocument();\r
321         return data;\r
322     }\r
323 \r
324     data << title << quantity << store;\r
325     return data;\r
326 }\r