diff --git a/kmymoney/plugins/views/reports/core/listtable.h b/kmymoney/plugins/views/reports/core/listtable.h --- a/kmymoney/plugins/views/reports/core/listtable.h +++ b/kmymoney/plugins/views/reports/core/listtable.h @@ -61,6 +61,9 @@ QString renderCSV() const final override; void drawChart(KReportChartView&) const final override {} void dump(const QString& file, const QString& context = QString()) const final override; + bool saveToXml(const QString &file); + bool loadFromXml(const QString &file); + QString toXml(); void init(); public: diff --git a/kmymoney/plugins/views/reports/core/listtable.cpp b/kmymoney/plugins/views/reports/core/listtable.cpp --- a/kmymoney/plugins/views/reports/core/listtable.cpp +++ b/kmymoney/plugins/views/reports/core/listtable.cpp @@ -22,6 +22,9 @@ // ---------------------------------------------------------------------------- // QT Includes +#include +#include +#include #include #include #include @@ -467,6 +470,144 @@ g.close(); } +bool ListTable::saveToXml(const QString &file) +{ + QFile out(file); + if (!out.open(QIODevice::WriteOnly)) + return false; + QTextStream stream(&out); + stream << toXml(); + return true; +} + +bool ListTable::loadFromXml(const QString &file) +{ + QFile in(file); + if (!in.open(QIODevice::ReadOnly)) + return false; + + QDomDocument doc; + doc.setContent(in.readAll()); + QDomElement docElem = doc.documentElement(); + QDomNode n = docElem.firstChild(); + m_rows.clear(); + int line = 0; + while(!n.isNull()) { + QDomElement e = n.toElement(); // try to convert the node to an element. + if(!e.isNull()) { + line++; + ListTable::TableRow row; + QDomNamedNodeMap attributes = e.attributes(); + for (int i = 0; i < attributes.count(); ++i) { + const QDomAttr& attr = attributes.item(i).toAttr(); + //qDebug() << line << attr.name() << attr.value(); + row[attr.name()] = attr.value(); + } + m_rows.append(row); + } + n = n.nextSibling(); + } + return true; +} + +/** + * The class KDomElement is a replacement for QDomElement + * with the possibility to store attributes sorted. + * + * Sorted attributes are important for a textual comparison. + * + * @author Ralf Habacker + */ +class KDomElement { +public: + KDomElement(const QString &name = QString()) : m_tag(name) {} + void setAttribute(const QString &name, const QString &value) + { + m_attributes.append(QString("%1=\"%2\"").arg(name, value)); + } + + virtual ~KDomElement() + { + } + + void appendChild(KDomElement &element) + { + m_childs.append(element); + } + + virtual QString toString() const + { + if (m_childs.size() > 0) { + QString s = !m_tag.isEmpty() ? QString("<%1 %2>\n").arg(m_tag, m_attributes.join(" ")) : ""; + foreach(const KDomElement &child, m_childs) { + s += child.toString(); + } + s += !m_tag.isEmpty() ? QString("\n").arg(m_tag) : ""; + return s; + } else + return !m_tag.isEmpty() ? QString("<%1 %2 />\n").arg(m_tag, m_attributes.join(" ")) : ""; + } + +protected: + QString m_tag; + QStringList m_attributes; + QList m_childs; +}; + +/** + * The class KDomDocument is a simple replacement for QDomDocument. + * + * @author Ralf Habacker + */ +class KDomDocument : public KDomElement { +public: + KDomDocument(const QString &name=QString()) + : KDomElement(""), + m_type(name) + { + } + + virtual ~KDomDocument() + { + } + + KDomElement createElement(const QString &name) + { + return KDomElement(name); + } + + QString toString() const + { + QString s = "\n"; + if (!m_type.isEmpty()) + s.append(QString("\n").arg(m_type)); + s.append(KDomElement::toString()); + return s; + } + + QString m_type; +}; + +QString ListTable::toXml() +{ + KDomDocument doc; + KDomElement el = doc.createElement("ListTable"); + QString name = m_config.name(); + el.setAttribute("name", name); + + foreach(ListTable::TableRow row, m_rows) { + KDomElement r = doc.createElement("TableRow"); + QStringList keys = row.keys(); + keys.sort(); + foreach(const QString &key, keys) { + r.setAttribute(key, row[key]); + } + el.appendChild(r); + } + doc.appendChild(el); + return doc.toString(); +} + void ListTable::includeInvestmentSubAccounts() { // if we're not in expert mode, we need to make sure diff --git a/kmymoney/plugins/views/reports/core/pivotgrid.h b/kmymoney/plugins/views/reports/core/pivotgrid.h --- a/kmymoney/plugins/views/reports/core/pivotgrid.h +++ b/kmymoney/plugins/views/reports/core/pivotgrid.h @@ -34,6 +34,9 @@ #include "reportaccount.h" #include "mymoneymoney.h" +class QDomDocument; +class QDomElement; + namespace reports { @@ -94,19 +97,22 @@ for (uint i = 0; i < _numcolumns; i++) append(PivotCell()); } + bool saveToXml(QDomDocument &doc, QDomElement &parent); MyMoneyMoney m_total; }; class PivotGridRowSet: public QMap { public: explicit PivotGridRowSet(unsigned _numcolumns = 0); + bool saveToXml(QDomDocument &doc, QDomElement &el); }; class PivotInnerGroup: public QMap { public: explicit PivotInnerGroup(unsigned _numcolumns = 0): m_total(_numcolumns) {} + bool saveToXml(QDomDocument &doc, QDomElement &parent); PivotGridRowSet m_total; }; @@ -147,6 +153,8 @@ PivotGridRowSet rowSet(QString id); PivotGridRowSet m_total; + bool saveToXml(QDomDocument &doc, QDomElement &parent); + bool loadFromXml(QDomDocument &doc, QDomElement &parent); }; } diff --git a/kmymoney/plugins/views/reports/core/pivotgrid.cpp b/kmymoney/plugins/views/reports/core/pivotgrid.cpp --- a/kmymoney/plugins/views/reports/core/pivotgrid.cpp +++ b/kmymoney/plugins/views/reports/core/pivotgrid.cpp @@ -20,6 +20,10 @@ // ---------------------------------------------------------------------------- // QT Includes +#include +#include +#include +#include // ---------------------------------------------------------------------------- // KDE Includes @@ -110,6 +114,14 @@ insert(ePrice, PivotGridRow(_numcolumns)); } +bool PivotGridRowSet::saveToXml(QDomDocument &doc, QDomElement &el) +{ + foreach(ERowType type, keys()) { + (*this)[type].saveToXml(doc, el); + } + return true; +} + PivotGridRowSet PivotGrid::rowSet(QString id) { @@ -132,4 +144,49 @@ return PivotGridRowSet(); } +bool PivotGrid::saveToXml(QDomDocument &doc, QDomElement &parent) +{ + QDomElement el = doc.createElement("PivotGrid"); + for(PivotGrid::iterator it_outergroup = begin(); it_outergroup != end(); it_outergroup++) { + QDomElement pog = doc.createElement("PivotOuterGroup"); + for(PivotOuterGroup::iterator it_innergroup = (*it_outergroup).begin(); it_innergroup != (*it_outergroup).end(); it_innergroup++) { + QDomElement pig = doc.createElement("PivotInnerGroup"); + for(PivotInnerGroup::iterator it_row = (*it_innergroup).begin(); it_row != (*it_innergroup).end(); it_row++) { + pig.setAttribute("account", it_row.key().id()); + it_row.value().saveToXml(doc, pig); + } + pog.appendChild(pig); + } + el.appendChild(pog); + } + parent.appendChild(el); + + return true; +} + +bool PivotGrid::loadFromXml(QDomDocument &doc, QDomElement &parent) +{ + Q_UNUSED(doc); + Q_UNUSED(parent); + return false; +} + +bool PivotInnerGroup::saveToXml(QDomDocument &doc, QDomElement &parent) +{ + Q_UNUSED(doc); + Q_UNUSED(parent); + return true; +} + +bool PivotGridRow::saveToXml(QDomDocument &doc, QDomElement &parent) +{ + for(int i=0; i < size(); i++) { + const PivotCell &cell = at(i); + QDomElement el = doc.createElement("PivotCell"); + el.setAttribute("value", cell.toDouble()); + parent.appendChild(el); + } + return true; +} + } // namespace diff --git a/kmymoney/plugins/views/reports/core/pivottable.h b/kmymoney/plugins/views/reports/core/pivottable.h --- a/kmymoney/plugins/views/reports/core/pivottable.h +++ b/kmymoney/plugins/views/reports/core/pivottable.h @@ -109,6 +109,10 @@ */ void dump(const QString& file, const QString& context = QString()) const final override; + bool loadFromXml(const QString &file); + bool saveToXml(const QString &file); + QString toXml(); + /** * Returns the grid generated by the report * diff --git a/kmymoney/plugins/views/reports/core/pivottable.cpp b/kmymoney/plugins/views/reports/core/pivottable.cpp --- a/kmymoney/plugins/views/reports/core/pivottable.cpp +++ b/kmymoney/plugins/views/reports/core/pivottable.cpp @@ -21,6 +21,8 @@ // ---------------------------------------------------------------------------- // QT Includes +#include +#include #include #include #include @@ -2380,4 +2382,30 @@ return column; } +bool PivotTable::loadFromXml(const QString &file) +{ + Q_UNUSED(file); + return false; +} + +bool PivotTable::saveToXml(const QString &file) +{ + QFile out(file); + if (!out.open(QIODevice::WriteOnly)) + return false; + QTextStream stream(&out); + stream << toXml(); + return true; +} + +QString PivotTable::toXml() +{ + QDomDocument doc; + QDomElement el = doc.createElement("PivotTable"); + QString name = m_config_f.name(); + el.setAttribute("name", name); + m_grid.saveToXml(doc, el); + doc.appendChild(el); + return doc.toString(); +} } // namespace diff --git a/kmymoney/plugins/views/reports/core/reporttable.h b/kmymoney/plugins/views/reports/core/reporttable.h --- a/kmymoney/plugins/views/reports/core/reporttable.h +++ b/kmymoney/plugins/views/reports/core/reporttable.h @@ -131,6 +131,10 @@ virtual void drawChart(KReportChartView& view) const = 0; virtual void dump(const QString& file, const QString& context = QString()) const = 0; + virtual bool loadFromXml(const QString &file) = 0; + virtual bool saveToXml(const QString &file) = 0; + virtual QString toXml() = 0; + /** * Creates the complete html document. * diff --git a/kmymoney/plugins/views/reports/kreportsview.cpp b/kmymoney/plugins/views/reports/kreportsview.cpp --- a/kmymoney/plugins/views/reports/kreportsview.cpp +++ b/kmymoney/plugins/views/reports/kreportsview.cpp @@ -259,7 +259,9 @@ { Q_D(KReportsView); if (auto tab = dynamic_cast(d->m_reportTabWidget->currentWidget())) { - QString filterList = i18nc("CSV (Filefilter)", "CSV files") + QLatin1String(" (*.csv);;") + i18nc("HTML (Filefilter)", "HTML files") + QLatin1String(" (*.html)"); + QString filterList = i18nc("CSV (Filefilter)", "CSV files") + QLatin1String(" (*.csv);;") + + i18nc("HTML (Filefilter)", "HTML files") + QLatin1String(" (*.html)") + i18nc("XML (Filefilter)", "XML files") + QLatin1String(" (*.xml)"); QUrl newURL = QFileDialog::getSaveFileUrl(this, i18n("Export as"), QUrl::fromLocalFile(KRecentDirs::dir(":kmymoney-export")), filterList, &d->m_selectedExportFilter); if (!newURL.isEmpty()) { KRecentDirs::add(":kmymoney-export", newURL.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); diff --git a/kmymoney/plugins/views/reports/kreportsview_p.h b/kmymoney/plugins/views/reports/kreportsview_p.h --- a/kmymoney/plugins/views/reports/kreportsview_p.h +++ b/kmymoney/plugins/views/reports/kreportsview_p.h @@ -342,13 +342,16 @@ QFile file(filename); if (file.open(QIODevice::WriteOnly)) { - if (QFileInfo(filename).suffix().toLower() == QLatin1String("csv")) { + QString suffix = QFileInfo(filename).suffix().toLower(); + if (suffix == QLatin1String("csv")) { QTextStream(&file) << m_table->renderReport(QLatin1String("csv"), m_encoding, QString()); - } else { + } else if (suffix == "html") { QString table = m_table->renderReport(QLatin1String("html"), m_encoding, m_report.name(), includeCSS); QTextStream stream(&file); stream << table; + } else { + QTextStream(&file) << m_table->toXml(); } file.close(); }