2 * This file is part of family-shop-mgr.
\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
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
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
17 * Author: Unai IRIGOYEN
\r
22 #include "ShoppingTreeModel.h"
\r
24 #include "ShoppingTreeItem.h"
\r
28 ShoppingTreeModel::ShoppingTreeModel(const QString &xmlFileName,
\r
30 QAbstractItemModel(parent), m_document("ShoppingList")
\r
36 m_xmlFileName = xmlFileName;
\r
37 QFile file(m_xmlFileName);
\r
38 if(!file.open(QIODevice::ReadOnly))
\r
41 if(!m_document.setContent(&file, true, &error, &errLine, &errColumn))
\r
43 emit xmlParseError(error, errLine, errColumn);
\r
49 QDomElement root = m_document.documentElement();
\r
50 if(root.tagName() != "shoppingList" || !root.hasAttribute("version"))
\r
52 emit invalidDocument();
\r
55 else if(root.attribute("version") == "1.0")
\r
57 // set column titles
\r
58 QVector<QVariant> rootData;
\r
59 rootData << "Category/Item name"
\r
60 << "Quantity" << "Store";
\r
62 rootItem = new ShoppingTreeItem(rootData);
\r
66 // upgrade document version if possible
\r
70 QDomElement child = root.firstChildElement("category");
\r
71 while(!child.isNull())
\r
73 // Parse all categories
\r
74 parseCategoryElement(child);
\r
75 child = child.nextSiblingElement("category");
\r
78 child = root.firstChildElement("item");
\r
79 while(!child.isNull())
\r
81 // parse all items which don't have category
\r
82 rootItem->insertChildren(
\r
83 rootItem->childCount(), 1,
\r
84 rootItem->columnCount());
\r
85 QVector<QVariant> columnData =
\r
86 getColumnsFromItemElement(child);
\r
87 for(int column = 0; column < columnData.size(); column++)
\r
89 rootItem->child(rootItem->childCount() - 1)->setData(column, columnData[column]);
\r
91 m_domElementForItem.insert(rootItem->child(rootItem->childCount() - 1),
\r
96 ShoppingTreeModel::~ShoppingTreeModel()
\r
101 QVariant ShoppingTreeModel::data(const QModelIndex &index, int role) const
\r
103 if(!index.isValid())
\r
106 if(role != Qt::DisplayRole && role != Qt::EditRole)
\r
109 ShoppingTreeItem *item = getItem(index);
\r
110 return item->data(index.column());
\r
113 Qt::ItemFlags ShoppingTreeModel::flags(const QModelIndex &index) const
\r
115 if(!index.isValid())
\r
118 return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
\r
121 ShoppingTreeItem *ShoppingTreeModel::getItem(const QModelIndex &index) const
\r
123 if(index.isValid()){
\r
124 ShoppingTreeItem *item = static_cast<ShoppingTreeItem*>(index.internalPointer());
\r
125 if(item) return item;
\r
131 QVariant ShoppingTreeModel::headerData(int section, Qt::Orientation orientation,
\r
134 if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
\r
135 return rootItem->data(section);
\r
140 QModelIndex ShoppingTreeModel::index(int row, int column, const QModelIndex &parent) const
\r
142 if(parent.isValid() && parent.column() != 0)
\r
143 return QModelIndex();
\r
145 ShoppingTreeItem *parentItem = getItem(parent);
\r
147 ShoppingTreeItem *childItem = parentItem->child(row);
\r
149 return createIndex(row, column, childItem);
\r
151 return QModelIndex();
\r
154 bool ShoppingTreeModel::insertRows(int position, int rows, const QModelIndex &parent)
\r
156 ShoppingTreeItem *parentItem = getItem(parent);
\r
159 beginInsertRows(parent, position, position + rows - 1);
\r
160 success = parentItem->insertChildren(position, rows, rootItem->columnCount());
\r
166 QModelIndex ShoppingTreeModel::parent(const QModelIndex &index) const
\r
168 if(!index.isValid())
\r
169 return QModelIndex();
\r
171 ShoppingTreeItem *childItem = getItem(index);
\r
172 ShoppingTreeItem *parentItem = childItem->parent();
\r
174 if(parentItem == rootItem)
\r
175 return QModelIndex();
\r
177 return createIndex(parentItem->childNumber(), 0, parentItem);
\r
180 bool ShoppingTreeModel::removeRows(int position, int rows, const QModelIndex &parent)
\r
182 ShoppingTreeItem *parentItem = getItem(parent);
\r
185 beginRemoveRows(parent, position, position + rows - 1);
\r
186 success = parentItem->removeChildren(position, rows);
\r
192 int ShoppingTreeModel::rowCount(const QModelIndex &parent) const
\r
194 ShoppingTreeItem *parentItem = getItem(parent);
\r
196 return parentItem->childCount();
\r
199 int ShoppingTreeModel::columnCount(const QModelIndex &parent) const
\r
201 return rootItem->columnCount();
\r
203 bool ShoppingTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
\r
205 if(role != Qt::EditRole)
\r
208 ShoppingTreeItem *item = getItem(index);
\r
210 // only "items" have more than one editable column
\r
211 if(index.column() != 0 && m_domElementForItem.value(item).tagName() != "item")
\r
215 bool result = (item->setData(index.column(),value) &&
\r
216 updateDomElement(item, index.column()));
\r
219 emit dataChanged(index, index);
\r
224 bool ShoppingTreeModel::setHeaderData(int section, Qt::Orientation orientation,
\r
225 const QVariant &value, int role)
\r
227 if(role != Qt::EditRole || orientation != Qt::Horizontal)
\r
230 bool result = rootItem->setData(section, value);
\r
233 emit headerDataChanged(orientation, section, section);
\r
238 void ShoppingTreeModel::parseCategoryElement(const QDomElement &element,
\r
239 ShoppingTreeItem *parentItem)
\r
241 // if parent is null then add category to root
\r
243 parentItem = rootItem;
\r
245 ShoppingTreeItem *item;
\r
246 QString title = element.firstChildElement("title").text();
\r
247 if(!title.isEmpty())
\r
249 parentItem->insertChildren(parentItem->childCount(), 1,
\r
250 rootItem->columnCount());
\r
252 parentItem->child(parentItem->childCount() - 1)->setData(0, title);
\r
253 m_domElementForItem.insert(parentItem->child(parentItem->childCount() - 1),
\r
255 item = parentItem->child(parentItem->childCount() - 1);
\r
259 emit invalidDocument();
\r
263 // add each sub category and item to the tree
\r
264 QDomElement child = element.firstChildElement();
\r
265 while(!child.isNull())
\r
267 if(child.tagName() == "category")
\r
269 parseCategoryElement(child, parentItem);
\r
271 else if(child.tagName() == "item")
\r
273 item->insertChildren(
\r
274 item->childCount(), 1,
\r
275 rootItem->columnCount());
\r
276 QVector<QVariant> columnData =
\r
277 getColumnsFromItemElement(child);
\r
278 for(int column = 0; column < columnData.size(); column++)
\r
280 item->child(item->childCount() - 1)->setData(column, columnData[column]);
\r
282 m_domElementForItem.insert(item->child(item->childCount() - 1),
\r
287 emit invalidDocument();
\r
291 child = child.nextSiblingElement();
\r
295 QVector<QVariant> ShoppingTreeModel::getColumnsFromItemElement(const QDomElement &element)
\r
297 QVector<QVariant> data;
\r
298 QString title = element.firstChildElement("title").text();
\r
299 int quantity = element.firstChildElement("quantity").text().toInt();
\r
300 QString store = element.firstChildElement("store").text();
\r
301 if(title.isEmpty() || quantity < 0)
\r
303 emit invalidDocument();
\r
307 data << title << quantity << store;
\r
311 bool ShoppingTreeModel::updateDomElement(ShoppingTreeItem *item, int column)
\r
313 QDomElement element = m_domElementForItem.value(item);
\r
315 if(element.isNull())
\r
323 QDomElement oldTitleElement = element.firstChildElement("title");
\r
324 QDomElement newTitleElement = m_document.createElement("title");
\r
326 QDomText newTitleText = m_document.createTextNode(item->data(0).toString());
\r
327 newTitleElement.appendChild(newTitleText);
\r
329 element.replaceChild(newTitleElement, oldTitleElement);
\r
335 QDomElement oldQuantityElement = element.firstChildElement("quantity");
\r
336 QDomElement newQuantityElement = m_document.createElement("quantity");
\r
338 QDomText newQuantityText = m_document.createTextNode(item->data(1).toString());
\r
339 newQuantityElement.appendChild(newQuantityText);
\r
341 element.replaceChild(newQuantityElement, oldQuantityElement);
\r
347 QDomElement oldStoreElement = element.firstChildElement("store");
\r
348 QDomElement newStoreElement = m_document.createElement("store");
\r
350 QDomText newStoreText = m_document.createTextNode(item->data(0).toString());
\r
351 newStoreElement.appendChild(newStoreText);
\r
353 element.replaceChild(newStoreElement, oldStoreElement);
\r
366 void ShoppingTreeModel::updateXmlFile() const
\r
368 QFile xmlFile(m_xmlFileName);
\r
370 xmlFile.open(QIODevice::WriteOnly);
\r
371 xmlFile.write(m_document.toByteArray(4));
\r