\r
#include "ShoppingTreeItem.h"\r
#include <QFile>\r
+#include <QApplication>\r
+#include <QtGui>\r
\r
ShoppingTreeModel::ShoppingTreeModel(const QString &xmlFileName,\r
QObject *parent) :\r
int errLine;\r
int errColumn;\r
\r
- QFile file(xmlFileName);\r
+ m_xmlFileName = QApplication::applicationDirPath() + "/" + xmlFileName;\r
+ QFile file(m_xmlFileName);\r
if(!file.open(QIODevice::ReadOnly))\r
return;\r
// Parse xml file\r
if(!m_document.setContent(&file, true, &error, &errLine, &errColumn))\r
{\r
emit xmlParseError(error, errLine, errColumn);\r
- file.close(();\r
+ file.close();\r
return;\r
}\r
file.close();\r
return;\r
}\r
else if(root.attribute("version") == "1.0")\r
+ {\r
// set column titles\r
QVector<QVariant> rootData;\r
rootData << "Category/Item name"\r
rootItem->columnCount());\r
QVector<QVariant> columnData =\r
getColumnsFromItemElement(child);\r
+ rootItem->child(rootItem->childCount() - 1)->\r
+ setItemType(ShoppingTreeItem::Item);\r
for(int column = 0; column < columnData.size(); column++)\r
{\r
rootItem->child(rootItem->childCount() - 1)->setData(column, columnData[column]);\r
}\r
+ m_domElementForItem.insert(rootItem->child(rootItem->childCount() - 1),\r
+ child);\r
+ child = child.nextSiblingElement("item");\r
+ }\r
+\r
+ QHashIterator<ShoppingTreeItem*,QDomElement> i(m_domElementForItem);\r
+ while(i.hasNext())\r
+ {\r
+ i.next();\r
+ connect(i.key(), SIGNAL(childInserted(ShoppingTreeItem*)), this,\r
+ SLOT(registerInsertedChild(ShoppingTreeItem*)));\r
+ connect(i.key(), SIGNAL(childRemoved(ShoppingTreeItem*)), this,\r
+ SLOT(deleteRemovedChild(ShoppingTreeItem*)));\r
+ }\r
+}\r
+\r
+ShoppingTreeModel::~ShoppingTreeModel()\r
+{\r
+ delete rootItem;\r
+}\r
+\r
+QVariant ShoppingTreeModel::data(const QModelIndex &index, int role) const\r
+{\r
+ if(!index.isValid())\r
+ return QVariant();\r
+\r
+ if(role != Qt::DisplayRole && role != Qt::EditRole)\r
+ return QVariant();\r
+\r
+ ShoppingTreeItem *item = getItem(index);\r
+ return item->data(index.column());\r
+}\r
+\r
+Qt::ItemFlags ShoppingTreeModel::flags(const QModelIndex &index) const\r
+{\r
+ if(!index.isValid())\r
+ return 0;\r
+\r
+ return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;\r
+}\r
+\r
+ShoppingTreeItem *ShoppingTreeModel::getItem(const QModelIndex &index) const\r
+{\r
+ if(index.isValid()){\r
+ ShoppingTreeItem *item = static_cast<ShoppingTreeItem*>(index.internalPointer());\r
+ if(item) return item;\r
}\r
+\r
+ return rootItem;\r
+}\r
+\r
+QVariant ShoppingTreeModel::headerData(int section, Qt::Orientation orientation,\r
+ int role) const\r
+{\r
+ if(orientation == Qt::Horizontal && role == Qt::DisplayRole)\r
+ return rootItem->data(section);\r
+\r
+ return QVariant();\r
+}\r
+\r
+QModelIndex ShoppingTreeModel::index(int row, int column, const QModelIndex &parent) const\r
+{\r
+ if(parent.isValid() && parent.column() != 0)\r
+ return QModelIndex();\r
+\r
+ ShoppingTreeItem *parentItem = getItem(parent);\r
+\r
+ ShoppingTreeItem *childItem = parentItem->child(row);\r
+ if(childItem)\r
+ return createIndex(row, column, childItem);\r
+ else\r
+ return QModelIndex();\r
+}\r
+\r
+bool ShoppingTreeModel::insertColumns(int position, int columns, const QModelIndex &parent)\r
+{\r
+ bool success;\r
+\r
+ beginInsertColumns(parent, position, position + columns - 1);\r
+ success = rootItem->insertColumns(position, columns);\r
+ endInsertColumns();\r
+\r
+ return success;\r
+}\r
+\r
+bool ShoppingTreeModel::insertRows(int position, int rows, const QModelIndex &parent)\r
+{\r
+ ShoppingTreeItem *parentItem = getItem(parent);\r
+ bool success;\r
+\r
+ beginInsertRows(parent, position, position + rows - 1);\r
+ success = parentItem->insertChildren(position, rows, rootItem->columnCount());\r
+ endInsertRows();\r
+\r
+ return success;\r
+}\r
+\r
+QModelIndex ShoppingTreeModel::parent(const QModelIndex &index) const\r
+{\r
+ if(!index.isValid())\r
+ return QModelIndex();\r
+\r
+ ShoppingTreeItem *childItem = getItem(index);\r
+ ShoppingTreeItem *parentItem = childItem->parent();\r
+\r
+ if(parentItem == rootItem)\r
+ return QModelIndex();\r
+\r
+ return createIndex(parentItem->childNumber(), 0, parentItem);\r
+}\r
+\r
+bool ShoppingTreeModel::removeColumns(int position, int columns, const QModelIndex &parent)\r
+{\r
+ bool success;\r
+\r
+ beginRemoveColumns(parent, position, position + columns - 1);\r
+ success = rootItem->removeColumns(position, columns);\r
+ endRemoveColumns();\r
+\r
+ if (rootItem->columnCount() == 0)\r
+ removeRows(0, rowCount());\r
+\r
+ return success;\r
+}\r
+\r
+bool ShoppingTreeModel::removeRows(int position, int rows, const QModelIndex &parent)\r
+{\r
+ ShoppingTreeItem *parentItem = getItem(parent);\r
+ bool success;\r
+\r
+ beginRemoveRows(parent, position, position + rows - 1);\r
+ success = parentItem->removeChildren(position, rows);\r
+ endRemoveRows();\r
+\r
+ return success;\r
+}\r
+\r
+int ShoppingTreeModel::rowCount(const QModelIndex &parent) const\r
+{\r
+ ShoppingTreeItem *parentItem = getItem(parent);\r
+\r
+ return parentItem->childCount();\r
+}\r
+\r
+int ShoppingTreeModel::columnCount(const QModelIndex &parent) const\r
+{\r
+ return rootItem->columnCount();\r
+}\r
+bool ShoppingTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)\r
+{\r
+ if(role != Qt::EditRole)\r
+ return false;\r
+\r
+ ShoppingTreeItem *item = getItem(index);\r
+\r
+ // only "items" have more than one editable column\r
+ if(index.column() != 0 && m_domElementForItem.value(item).tagName() != "item")\r
+ return false;\r
+\r
+ // edit item\r
+ bool result = (item->setData(index.column(),value) &&\r
+ updateDomElement(item, index.column()));\r
+\r
+ if(result)\r
+ emit dataChanged(index, index);\r
+\r
+ return result;\r
+}\r
+\r
+bool ShoppingTreeModel::setHeaderData(int section, Qt::Orientation orientation,\r
+ const QVariant &value, int role)\r
+{\r
+ if(role != Qt::EditRole || orientation != Qt::Horizontal)\r
+ return false;\r
+\r
+ bool result = rootItem->setData(section, value);\r
+\r
+ if(result)\r
+ emit headerDataChanged(orientation, section, section);\r
+\r
+ return result;\r
+}\r
+\r
+void ShoppingTreeModel::registerInsertedChild(ShoppingTreeItem *item)\r
+{\r
+ // wait until item type is defined\r
+ item->waitItemTypeDefinition();\r
+\r
+ QDomElement parentElement = m_domElementForItem.value(item->parent());\r
+ QDomElement element;\r
+ if(item->getItemType() == ShoppingTreeItem::Category)\r
+ element = m_document.createElement("category");\r
+ else if(item->getItemType() == ShoppingTreeItem::Item)\r
+ element = m_document.createElement("item");\r
+ else\r
+ return;\r
+\r
+ parentElement.appendChild(element);\r
+ updateXmlFile();\r
+ m_domElementForItem.insert(item, element);\r
+ connect(item, SIGNAL(childInserted(ShoppingTreeItem*)), this,\r
+ SLOT(registerInsertedChild(ShoppingTreeItem*)));\r
+ connect(item, SIGNAL(childRemoved(ShoppingTreeItem*)), this,\r
+ SLOT(deleteRemovedChild(ShoppingTreeItem*)));\r
+}\r
+\r
+void ShoppingTreeModel::deleteRemovedChild(ShoppingTreeItem *item)\r
+{\r
+ QDomElement element = m_domElementForItem.value(item);\r
+ QDomNode parentNode = element.parentNode();\r
+ parentNode.removeChild(element);\r
+ updateXmlFile();\r
+ m_domElementForItem.remove(item);\r
}\r
\r
void ShoppingTreeModel::parseCategoryElement(const QDomElement &element,\r
ShoppingTreeItem *parentItem)\r
{\r
+ // if parent is null then add category to root\r
if(!parentItem)\r
parentItem = rootItem;\r
- // TODO\r
\r
+ ShoppingTreeItem *item;\r
+ QString title = element.firstChildElement("title").text();\r
+ if(!title.isEmpty())\r
+ {\r
+ parentItem->insertChildren(parentItem->childCount(), 1,\r
+ rootItem->columnCount());\r
+\r
+ parentItem->child(parentItem->childCount() - 1)->\r
+ setItemType(ShoppingTreeItem::Category);\r
+ parentItem->child(parentItem->childCount() - 1)->setData(0, title);\r
+ m_domElementForItem.insert(parentItem->child(parentItem->childCount() - 1),\r
+ element);\r
+ item = parentItem->child(parentItem->childCount() - 1);\r
+ }\r
+ else\r
+ {\r
+ emit invalidDocument();\r
+ return;\r
+ }\r
+\r
+ // add each sub category and item to the tree\r
+ QDomElement child = element.firstChildElement();\r
+ while(!child.isNull())\r
+ {\r
+ if(child.tagName() == "category")\r
+ {\r
+ parseCategoryElement(child, parentItem);\r
+ }\r
+ else if(child.tagName() == "item")\r
+ {\r
+ item->insertChildren(\r
+ item->childCount(), 1,\r
+ rootItem->columnCount());\r
+ QVector<QVariant> columnData =\r
+ getColumnsFromItemElement(child);\r
+ item->child(item->childCount() - 1)->setItemType(ShoppingTreeItem::Item);\r
+ for(int column = 0; column < columnData.size(); column++)\r
+ {\r
+ item->child(item->childCount() - 1)->setData(column, columnData[column]);\r
+ }\r
+ m_domElementForItem.insert(item->child(item->childCount() - 1),\r
+ child);\r
+ }\r
+ else\r
+ {\r
+ emit invalidDocument();\r
+ return;\r
+ }\r
+\r
+ child = child.nextSiblingElement();\r
+ }\r
}\r
\r
QVector<QVariant> ShoppingTreeModel::getColumnsFromItemElement(const QDomElement &element)\r
{\r
- QString title = child.firstChildElement("title").text();\r
- int quantity = child.firstChildElement("quantity").text().toInt();\r
- QString store = child.firstChildElement("store").text();\r
+ QVector<QVariant> data;\r
+ QString title = element.firstChildElement("title").text();\r
+ int quantity = element.firstChildElement("quantity").text().toInt();\r
+ QString store = element.firstChildElement("store").text();\r
if(title.isEmpty() || quantity < 0)\r
{\r
- emit invalidDocument;\r
- return;\r
+ emit invalidDocument();\r
+ return data;\r
}\r
\r
- QVector<QVariant> data;\r
data << title << quantity << store;\r
return data;\r
}\r
+\r
+bool ShoppingTreeModel::updateDomElement(ShoppingTreeItem *item, int column)\r
+{\r
+ QDomElement element = m_domElementForItem.value(item);\r
+\r
+ if(element.isNull())\r
+ return false;\r
+\r
+ bool success;\r
+ switch(column)\r
+ {\r
+ case 0:\r
+ {\r
+ QDomElement oldTitleElement = element.firstChildElement("title");\r
+ QDomElement newTitleElement = m_document.createElement("title");\r
+\r
+ QDomText newTitleText = m_document.createTextNode(item->data(0).toString());\r
+ newTitleElement.appendChild(newTitleText);\r
+\r
+ element.replaceChild(newTitleElement, oldTitleElement);\r
+ success = true;\r
+ break;\r
+ }\r
+ case 1:\r
+ {\r
+ QDomElement oldQuantityElement = element.firstChildElement("quantity");\r
+ QDomElement newQuantityElement = m_document.createElement("quantity");\r
+\r
+ QDomText newQuantityText = m_document.createTextNode(item->data(1).toString());\r
+ newQuantityElement.appendChild(newQuantityText);\r
+\r
+ element.replaceChild(newQuantityElement, oldQuantityElement);\r
+ success = true;\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ QDomElement oldStoreElement = element.firstChildElement("store");\r
+ QDomElement newStoreElement = m_document.createElement("store");\r
+\r
+ QDomText newStoreText = m_document.createTextNode(item->data(0).toString());\r
+ newStoreElement.appendChild(newStoreText);\r
+\r
+ element.replaceChild(newStoreElement, oldStoreElement);\r
+ success = true;\r
+ break;\r
+ }\r
+ default:\r
+ success = false;\r
+ }\r
+\r
+ updateXmlFile();\r
+\r
+ return success;\r
+}\r
+\r
+void ShoppingTreeModel::updateXmlFile() const\r
+{\r
+ QFile xmlFile(m_xmlFileName);\r
+ xmlFile.remove();\r
+ xmlFile.open(QIODevice::WriteOnly);\r
+ xmlFile.write(m_document.toByteArray(4));\r
+ xmlFile.close();\r
+}\r