#include "datamodel.h" #include #include #include #include /* Model : The model keep the data in a list. Each tree widget node has an index wich allow to retrieve data from the model. The model also open and save file, and is in charge of modified flags. It is also responsible to switch the editor state to enabled/disabled. */ Model::Model(QTreeWidget *treeWidget, QTextEdit *editor, QString fileName, QString dateFormat) { m_treeWidget = treeWidget; m_editor = editor; m_stFileName = fileName; m_stDateFormat = dateFormat; m_treeWidget->clear(); m_editor->clear(); m_editor->setEnabled(false); m_boFileModified = true; m_folderIcon.addPixmap(treeWidget->style()->standardPixmap(QStyle::SP_DirClosedIcon), QIcon::Normal, QIcon::Off); m_folderIcon.addPixmap(treeWidget->style()->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On); m_bookmarkIcon.addPixmap(treeWidget->style()->standardPixmap(QStyle::SP_FileIcon)); list = new QList(); } Model::~Model() { ModelItem *item; foreach (item, *list) delete item; delete list; } void Model::clear() { list->clear(); } /* Add a new item in the model. */ int Model::addItem(QString name, QString type, QString data, QDateTime creationDate) { int index; index = list->size(); ModelItem *item = new ModelItem(name, type, data, creationDate); list->insert(index, item); m_boFileModified = true; return index; } /* return an item name based on its index. */ QString Model::getName(int index) { ModelItem *item = list->at(index); return item->itemName; } /* return an item type based on its index. */ QString Model::getType(int index) { ModelItem *item = list->at(index); return item->itemType; } /* return an item data based on its index. */ QString Model::getData(int index) { ModelItem *item = list->at(index); return item->itemData; } QDateTime Model::getCreationDate(int index) { ModelItem *item = list->at(index); return item->itemCreationDate; } /* Update data on a given item, by its index. */ void Model::updateData(int index, QString data) { ModelItem *item = list->at(index); item->itemData = data; } void Model::changeName(int index, QString newName) { ModelItem *item = list->at(index); item->itemName = newName; m_boFileModified = true; } /* Save date into current filename. */ void Model::save() { // Save the current page in the model, before saving. updateModelWithCurrent(); writeFile(); m_boFileModified = false; } /* Save data into a new filename. */ void Model::saveAs(QString fileName) { m_stFileName = fileName; save(); } /* Open the specified file. */ bool Model::open() { // Clear model and tree widget. m_treeWidget->clear(); clear(); // Read the file. bool result = readFile(); m_currentItem = NULL; m_boFileModified = false; m_editor->document()->clear(); m_editor->setEnabled(false); return result; } /* Update the model with new data from editor. */ void Model::updateModelWithCurrent() { if ((m_currentItem != NULL) && (m_editor->document()->isModified())) { int index = m_currentItem->data(0, Qt::UserRole).toUInt(); updateData(index, m_editor->document()->toHtml()); // The main document is modified... m_boFileModified = true; // ... but the current page is not, as the model has been updated. m_editor->document()->setModified(false); } } /* Check if the current document is modified. */ bool Model::checkFileModified() { if (m_currentItem == NULL) return m_boFileModified; else return m_boFileModified || m_editor->document()->isModified(); } /* Check if the current document is modified, propose to save it, and save it if asked. */ bool Model::askForSaveAndSave(QWidget *parent) { if (checkFileModified()) { QMessageBox::StandardButton ret; ret = QMessageBox::warning(parent, tr("Warning"), tr("The document has been modified.\n" "Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); if (ret == QMessageBox::Save) { if (m_stFileName != "") { save(); return true; } else { // Ask for name. QString fileName = QFileDialog::getSaveFileName(parent, tr("Save a file"), QDir::currentPath(), tr("XML Files (*.xml);;All files (*.*)")); if (fileName.isEmpty()) return false; else { saveAs(fileName); return true; } } } else if (ret == QMessageBox::Cancel) return false; else return true; } else return true; } /* Return a QString containing html reprsentation of a category summary. Some ugly stuff in it, mainly because QTextEdit html is limited. */ QString Model::getCategoryHtml(QTreeWidgetItem *item) { QString result; QString name; QString type; QString categoryData; QString pageData; int childIndex; QTreeWidgetItem *child; int index = item->data(0, Qt::UserRole).toUInt(); QString categoryName = getName(index); int tableWidth = m_editor->size().width() - 50; QString stTableWidth; stTableWidth.setNum(tableWidth); result = "

 

"; result = result + " 

" + tr("Category : ") + categoryName + ".

"; result = result + "

" + tr("Created on ") + getCreationDate(index).toString(m_stDateFormat) + ".

"; for(int i = 0; i < item->childCount(); i++) { child = item->child(i); childIndex = child->data(0, Qt::UserRole).toUInt(); type = getType(childIndex); if (type == "CATEGORY") categoryData = categoryData + "
  • " + getName(childIndex) + ", " + tr("created on ") + getCreationDate(childIndex).toString(m_stDateFormat) + ".
  • "; else if (type == "PAGE") pageData = pageData + "
  • " + getName(childIndex) + ", " + tr("created on ") + getCreationDate(childIndex).toString(m_stDateFormat) + ".
  • "; } result = result + "

    • " + tr("Sub-categories:") + "
      • " + categoryData + "

    "; result = result + "

    • " + tr("Pages:") + "
      • " + pageData + "

    "; return "" + result + " 
    "; } /* Update editor with data from a new tree item. */ void Model::updateDisplay(QTreeWidgetItem *newItem) { int index = newItem->data(0, Qt::UserRole).toUInt(); QString type = getType(index); if (type == "PAGE") { // Save current page, before loading the new one. updateModelWithCurrent(); QString data = getData(index); m_editor->document()->setHtml(data); m_editor->document()->setModified(false); m_editor->setEnabled(true); m_currentItem = newItem; } else if (type == "CATEGORY") { // Save current page. updateModelWithCurrent(); m_editor->document()->setHtml(getCategoryHtml(newItem)); m_editor->document()->setModified(false); m_editor->setEnabled(false); m_currentItem = newItem; } } /* Accessors */ void Model::setDateFormat(QString value) { m_stDateFormat = value; } QString Model::getFileName() { return m_stFileName; } QTreeWidgetItem * Model::getCurrentItem() { return m_currentItem; } void Model::setCurrentItem(QTreeWidgetItem *value) { m_currentItem = value; } void Model::setFileModified(bool value) { m_boFileModified = value; } /* Read/write methods */ void Model::ParseElement(const QDomElement &element, QTreeWidgetItem *parentItem, QTreeWidget *treeWidget) { QString type; QString name; QString data; QString title; QString creationDate; QString expanded; QTreeWidgetItem *childItem; QDomElement child = element.firstChildElement(); while (!child.isNull()) { name = child.tagName(); if (name == "element") { type = child.attribute("type"); if (type == "CATEGORY") { // Get the name title = child.firstChildElement("name").text(); expanded = child.attribute("expanded"); creationDate = child.attribute("date"); if (creationDate.isEmpty()) creationDate = m_fileCreationDate.toString("MM.dd.yyyy hh:mm:ss"); // Create the tree item with appropriate parent. if (parentItem) { childItem = new QTreeWidgetItem(parentItem); childItem->setFlags(parentItem->flags()); } else { childItem = new QTreeWidgetItem(treeWidget); } if (expanded == "true") childItem->setExpanded(true); else childItem->setExpanded(false); // Setup icons and model. childItem->setIcon(0, this->m_folderIcon); childItem->setText(0, title); int index = this->addItem(title, "CATEGORY", "", QDateTime::fromString(creationDate, "MM.dd.yyyy hh:mm:ss")); childItem->setData(0, Qt::UserRole, index); // Category can have childs element, process them. ParseElement(child, childItem, treeWidget); } else if (type == "PAGE") { // Get name and data. title = child.firstChildElement("name").text(); data = child.firstChildElement("data").text(); creationDate = child.attribute("date"); if (creationDate.isEmpty()) creationDate = m_fileCreationDate.toString("MM.dd.yyyy hh:mm:ss"); // Create the tree item with appropriate parent. if (parentItem) { childItem = new QTreeWidgetItem(parentItem); childItem->setFlags(parentItem->flags()); } else { childItem = new QTreeWidgetItem(treeWidget); } // Setup icons and model. childItem->setIcon(0, this->m_bookmarkIcon); childItem->setText(0, title); int index = this->addItem(title, "PAGE", data, QDateTime::fromString(creationDate, "MM.dd.yyyy hh:mm:ss")); childItem->setData(0, Qt::UserRole, index); } } child = child.nextSiblingElement(); } } /* Load the current file in the model. */ bool Model::readFile() { QDomDocument m_doc; QFile file(m_stFileName); if (!file.open(QIODevice::ReadOnly)) return false; if (!m_doc.setContent(&file)) { file.close(); return false; } // File informations QFileInfo fileInfo(file); m_fileCreationDate = fileInfo.created(); file.close(); QString type; QDomElement elem; QDomElement root = m_doc.documentElement(); QDomElement node = root.toElement(); // Loop on the nodes. while (!node.isNull()) { ParseElement(node, NULL, m_treeWidget); node = node.nextSiblingElement(); } return true; } /* Write the model using the tree structure. */ void Model::writeFile() { QTextStream out; QDomDocument m_doc; QFile file; // Create the base element "document". QDomElement root = m_doc.createElement("document"); m_doc.appendChild(root); // Setup the file file.setFileName(m_stFileName); if (!file.open(QIODevice::WriteOnly)) return; out.setDevice(&file); // Process the nodes. for (int i = 0; i < m_treeWidget->topLevelItemCount(); i++) processSaveItem(&m_doc, &root, m_treeWidget->topLevelItem(i)); // Insert at the begining of the document. QDomNode node = m_doc.createProcessingInstruction("xml","version=\"1.0\""); m_doc.insertBefore(node, m_doc.firstChild()); // write the file. m_doc.save(out, 2); file.close(); } /* Save Process nodes. */ void Model::processSaveItem(QDomDocument *doc, QDomElement *parent, QTreeWidgetItem *item) { QString type; QString name; QString data; QDateTime creationDate; // Get index of data in the model, from the tree item. int index = item->data(0, Qt::UserRole).toUInt(); // Get information from the model. type = this->getType(index); name = this->getName(index); data = this->getData(index); creationDate = this->getCreationDate(index); if (type == "CATEGORY") { // Add an element node with its attibutes. QDomElement element = doc->createElement("element"); parent->appendChild(element); element.setAttribute("type", "CATEGORY"); if (item->isExpanded()) element.setAttribute("expanded", "true"); else element.setAttribute("expanded", "false"); element.setAttribute("date", creationDate.toString("MM.dd.yyyy hh:mm:ss")); // Add the name node. QDomElement nameNode = doc->createElement("name"); element.appendChild(nameNode); QDomText nameText = doc->createTextNode(name); nameNode.appendChild(nameText); // A category can have sub-nodes : process them. for (int i = 0; i < item->childCount(); i++) processSaveItem(doc, &element, item->child(i)); } else if (type == "PAGE") { // Add an element node with its attibutes. QDomElement element = doc->createElement("element"); parent->appendChild(element); element.setAttribute("type", "PAGE"); element.setAttribute("date", creationDate.toString("MM.dd.yyyy hh:mm:ss")); // Add the name node. QDomElement nameNode = doc->createElement("name"); element.appendChild(nameNode); QDomText nameText = doc->createTextNode(name); nameNode.appendChild(nameText); // Add the data node. QDomElement dataNode = doc->createElement("data"); element.appendChild(dataNode); QDomCDATASection dataText = doc->createCDATASection(data); dataNode.appendChild(dataText); } } /* ModelItem : internal class to store items. */ ModelItem::ModelItem(QString name, QString type, QString data, QDateTime creationDate) { itemName = name; itemType = type; itemData = data; itemCreationDate = creationDate; }