diff --git a/kmymoney/mymoney/mymoneyreport.cpp b/kmymoney/mymoney/mymoneyreport.cpp
index 31f3eba38..b9a7b1af7 100644
--- a/kmymoney/mymoney/mymoneyreport.cpp
+++ b/kmymoney/mymoney/mymoneyreport.cpp
@@ -1,1003 +1,1016 @@
/*
* Copyright 2004-2006 Ace Jones
* Copyright 2006 Darren Gould
* Copyright 2007-2010 Alvaro Soliverez
* Copyright 2017-2018 Łukasz Wojniłowicz
+ * Copyright 2018 Michael Kiefer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "mymoneyreport_p.h"
// ----------------------------------------------------------------------------
// QT Includes
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
#include "mymoneymoney.h"
#include "mymoneyfile.h"
#include "mymoneyaccount.h"
#include "mymoneytransaction.h"
#include "mymoneytransactionfilter.h"
#include "mymoneyexception.h"
MyMoneyReport::MyMoneyReport() :
MyMoneyObject(*new MyMoneyReportPrivate)
{
}
MyMoneyReport::MyMoneyReport(const QString &id) :
MyMoneyObject(*new MyMoneyReportPrivate, id)
{
}
MyMoneyReport::MyMoneyReport(eMyMoney::Report::RowType rt,
unsigned ct,
eMyMoney::TransactionFilter::Date dl,
eMyMoney::Report::DetailLevel ss,
const QString& name,
const QString& comment) :
MyMoneyObject(*new MyMoneyReportPrivate)
{
Q_D(MyMoneyReport);
d->m_name = name;
d->m_comment = comment;
d->m_detailLevel = ss;
d->m_investmentSum = ct & eMyMoney::Report::QueryColumn::CapitalGain ? eMyMoney::Report::InvestmentSum::Sold : eMyMoney::Report::InvestmentSum::Period;
d->m_reportType = d->rowTypeToReportType(rt);
d->m_rowType = rt;
d->m_dateLock = dl;
//set report type
if (d->m_reportType == eMyMoney::Report::ReportType::PivotTable)
d->m_columnType = static_cast(ct);
if (d->m_reportType == eMyMoney::Report::ReportType::QueryTable)
d->m_queryColumns = static_cast(ct);
setDateFilter(dl);
//throw exception if the type is inconsistent
if (d->rowTypeToReportType(rt) == eMyMoney::Report::ReportType::Invalid ||
d->m_reportType == eMyMoney::Report::ReportType::NoReport)
throw MYMONEYEXCEPTION_CSTRING("Invalid report type");
//add the corresponding account groups
if (rt == eMyMoney::Report::RowType::AssetLiability) {
addAccountGroup(eMyMoney::Account::Type::Asset);
addAccountGroup(eMyMoney::Account::Type::Liability);
d->m_showRowTotals = true;
}
if (rt == eMyMoney::Report::RowType::Account) {
addAccountGroup(eMyMoney::Account::Type::Asset);
addAccountGroup(eMyMoney::Account::Type::AssetLoan);
addAccountGroup(eMyMoney::Account::Type::Cash);
addAccountGroup(eMyMoney::Account::Type::Checkings);
addAccountGroup(eMyMoney::Account::Type::CreditCard);
if (m_expertMode)
addAccountGroup(eMyMoney::Account::Type::Equity);
addAccountGroup(eMyMoney::Account::Type::Expense);
addAccountGroup(eMyMoney::Account::Type::Income);
addAccountGroup(eMyMoney::Account::Type::Liability);
addAccountGroup(eMyMoney::Account::Type::Loan);
addAccountGroup(eMyMoney::Account::Type::Savings);
addAccountGroup(eMyMoney::Account::Type::Stock);
d->m_showRowTotals = true;
}
if (rt == eMyMoney::Report::RowType::ExpenseIncome) {
addAccountGroup(eMyMoney::Account::Type::Expense);
addAccountGroup(eMyMoney::Account::Type::Income);
d->m_showRowTotals = true;
}
//FIXME take this out once we have sorted out all issues regarding budget of assets and liabilities -- asoliverez@gmail.com
if (rt == eMyMoney::Report::RowType::Budget || rt == eMyMoney::Report::RowType::BudgetActual) {
addAccountGroup(eMyMoney::Account::Type::Expense);
addAccountGroup(eMyMoney::Account::Type::Income);
}
if (rt == eMyMoney::Report::RowType::AccountInfo) {
addAccountGroup(eMyMoney::Account::Type::Asset);
addAccountGroup(eMyMoney::Account::Type::Liability);
}
//cash flow reports show splits for all account groups
if (rt == eMyMoney::Report::RowType::CashFlow) {
addAccountGroup(eMyMoney::Account::Type::Expense);
addAccountGroup(eMyMoney::Account::Type::Income);
addAccountGroup(eMyMoney::Account::Type::Asset);
addAccountGroup(eMyMoney::Account::Type::Liability);
}
#ifdef DEBUG_REPORTS
QDebug out = qDebug();
out << _name << toString(_rt) << toString(m_reportType);
foreach(const eMyMoney::Account::Type accountType, m_accountGroups)
out << MyMoneyeMyMoney::Account::accountTypeToString(accountType);
if (m_accounts.size() > 0)
out << m_accounts;
#endif
}
MyMoneyReport::MyMoneyReport(const MyMoneyReport& other) :
MyMoneyObject(*new MyMoneyReportPrivate(*other.d_func()), other.id()),
MyMoneyTransactionFilter(other)
{
}
MyMoneyReport::MyMoneyReport(const QString& id, const MyMoneyReport& other) :
MyMoneyObject(*new MyMoneyReportPrivate(*other.d_func()), id),
MyMoneyTransactionFilter(other)
{
Q_D(MyMoneyReport);
d->m_movingAverageDays = 0;
d->m_currentDateColumn = 0;
}
MyMoneyReport::~MyMoneyReport()
{
}
eMyMoney::Report::ReportType MyMoneyReport::reportType() const
{
Q_D(const MyMoneyReport);
return d->m_reportType;
}
void MyMoneyReport::setReportType(eMyMoney::Report::ReportType rt)
{
Q_D(MyMoneyReport);
d->m_reportType = rt;
}
QString MyMoneyReport::name() const
{
Q_D(const MyMoneyReport);
return d->m_name;
}
void MyMoneyReport::setName(const QString& s)
{
Q_D(MyMoneyReport);
d->m_name = s;
}
bool MyMoneyReport::isShowingRowTotals() const
{
Q_D(const MyMoneyReport);
return (d->m_showRowTotals);
}
void MyMoneyReport::setShowingRowTotals(bool f)
{
Q_D(MyMoneyReport);
d->m_showRowTotals = f;
}
bool MyMoneyReport::isShowingColumnTotals() const
{
Q_D(const MyMoneyReport);
return d->m_showColumnTotals;
}
void MyMoneyReport::setShowingColumnTotals(bool f)
{
Q_D(MyMoneyReport);
d->m_showColumnTotals = f;
}
eMyMoney::Report::RowType MyMoneyReport::rowType() const
{
Q_D(const MyMoneyReport);
return d->m_rowType;
}
void MyMoneyReport::setRowType(eMyMoney::Report::RowType rt)
{
Q_D(MyMoneyReport);
d->m_rowType = rt;
d->m_reportType = d->rowTypeToReportType(rt);
d->m_accountGroupFilter = false;
d->m_accountGroups.clear();
if (rt == eMyMoney::Report::RowType::AssetLiability) {
addAccountGroup(eMyMoney::Account::Type::Asset);
addAccountGroup(eMyMoney::Account::Type::Liability);
}
if (rt == eMyMoney::Report::RowType::ExpenseIncome) {
addAccountGroup(eMyMoney::Account::Type::Expense);
addAccountGroup(eMyMoney::Account::Type::Income);
}
}
bool MyMoneyReport::isRunningSum() const
{
Q_D(const MyMoneyReport);
return (d->m_rowType == eMyMoney::Report::RowType::AssetLiability);
}
eMyMoney::Report::ColumnType MyMoneyReport::columnType() const
{
Q_D(const MyMoneyReport);
return d->m_columnType;
}
void MyMoneyReport::setColumnType(eMyMoney::Report::ColumnType ct)
{
Q_D(MyMoneyReport);
d->m_columnType = ct;
}
bool MyMoneyReport::isConvertCurrency() const
{
Q_D(const MyMoneyReport);
return d->m_convertCurrency;
}
void MyMoneyReport::setConvertCurrency(bool f)
{
Q_D(MyMoneyReport);
d->m_convertCurrency = f;
}
uint MyMoneyReport::columnPitch() const
{
Q_D(const MyMoneyReport);
return static_cast(d->m_columnType);
}
QString MyMoneyReport::comment() const
{
Q_D(const MyMoneyReport);
return d->m_comment;
}
void MyMoneyReport::setComment(const QString& comment)
{
Q_D(MyMoneyReport);
d->m_comment = comment;
}
eMyMoney::Report::QueryColumn MyMoneyReport::queryColumns() const
{
Q_D(const MyMoneyReport);
return d->m_queryColumns;
}
void MyMoneyReport::setQueryColumns(eMyMoney::Report::QueryColumn qc)
{
Q_D(MyMoneyReport);
d->m_queryColumns = qc;
}
QString MyMoneyReport::group() const
{
Q_D(const MyMoneyReport);
return d->m_group;
}
void MyMoneyReport::setGroup(const QString& group)
{
Q_D(MyMoneyReport);
d->m_group = group;
}
bool MyMoneyReport::isFavorite() const
{
Q_D(const MyMoneyReport);
return d->m_favorite;
}
void MyMoneyReport::setFavorite(bool f)
{
Q_D(MyMoneyReport);
d->m_favorite = f;
}
bool MyMoneyReport::isTax() const
{
Q_D(const MyMoneyReport);
return d->m_tax;
}
void MyMoneyReport::setTax(bool f)
{
Q_D(MyMoneyReport);
d->m_tax = f;
}
bool MyMoneyReport::isInvestmentsOnly() const
{
Q_D(const MyMoneyReport);
return d->m_investments;
}
void MyMoneyReport::setInvestmentsOnly(bool f)
{
Q_D(MyMoneyReport);
d->m_investments = f; if (f) d->m_loans = false;
}
bool MyMoneyReport::isLoansOnly() const
{
Q_D(const MyMoneyReport);
return d->m_loans;
}
void MyMoneyReport::setLoansOnly(bool f)
{
Q_D(MyMoneyReport);
d->m_loans = f; if (f) d->m_investments = false;
}
eMyMoney::Report::DetailLevel MyMoneyReport::detailLevel() const
{
Q_D(const MyMoneyReport);
return d->m_detailLevel;
}
void MyMoneyReport::setDetailLevel(eMyMoney::Report::DetailLevel detail)
{
Q_D(MyMoneyReport);
d->m_detailLevel = detail;
}
eMyMoney::Report::InvestmentSum MyMoneyReport::investmentSum() const
{
Q_D(const MyMoneyReport);
return d->m_investmentSum;
}
void MyMoneyReport::setInvestmentSum(eMyMoney::Report::InvestmentSum sum)
{
Q_D(MyMoneyReport);
d->m_investmentSum = sum;
}
bool MyMoneyReport::isHideTransactions() const
{
Q_D(const MyMoneyReport);
return d->m_hideTransactions;
}
void MyMoneyReport::setHideTransactions(bool f)
{
Q_D(MyMoneyReport);
d->m_hideTransactions = f;
}
eMyMoney::Report::ChartType MyMoneyReport::chartType() const
{
Q_D(const MyMoneyReport);
return d->m_chartType;
}
void MyMoneyReport::setChartType(eMyMoney::Report::ChartType type)
{
Q_D(MyMoneyReport);
d->m_chartType = type;
}
bool MyMoneyReport::isChartDataLabels() const
{
Q_D(const MyMoneyReport);
return d->m_chartDataLabels;
}
void MyMoneyReport::setChartDataLabels(bool f)
{
Q_D(MyMoneyReport);
d->m_chartDataLabels = f;
}
bool MyMoneyReport::isChartCHGridLines() const
{
Q_D(const MyMoneyReport);
return d->m_chartCHGridLines;
}
void MyMoneyReport::setChartCHGridLines(bool f)
{
Q_D(MyMoneyReport);
d->m_chartCHGridLines = f;
}
bool MyMoneyReport::isChartSVGridLines() const
{
Q_D(const MyMoneyReport);
return d->m_chartSVGridLines;
}
void MyMoneyReport::setChartSVGridLines(bool f)
{
Q_D(MyMoneyReport);
d->m_chartSVGridLines = f;
}
bool MyMoneyReport::isChartByDefault() const
{
Q_D(const MyMoneyReport);
return d->m_chartByDefault;
}
void MyMoneyReport::setChartByDefault(bool f)
{
Q_D(MyMoneyReport);
d->m_chartByDefault = f;
}
uint MyMoneyReport::chartLineWidth() const
{
Q_D(const MyMoneyReport);
return d->m_chartLineWidth;
}
void MyMoneyReport::setChartLineWidth(uint f)
{
Q_D(MyMoneyReport);
d->m_chartLineWidth = f;
}
bool MyMoneyReport::isLogYAxis() const
{
Q_D(const MyMoneyReport);
return d->m_logYaxis;
}
void MyMoneyReport::setLogYAxis(bool f)
{
Q_D(MyMoneyReport);
d->m_logYaxis = f;
}
+bool MyMoneyReport::isNegExpenses() const
+{
+ Q_D(const MyMoneyReport);
+ return d->m_negExpenses;
+}
+
+void MyMoneyReport::setNegExpenses(bool f)
+{
+ Q_D(MyMoneyReport);
+ d->m_negExpenses = f;
+}
+
QString MyMoneyReport::dataRangeStart() const
{
Q_D(const MyMoneyReport);
return d->m_dataRangeStart;
}
void MyMoneyReport::setDataRangeStart(const QString& f)
{
Q_D(MyMoneyReport);
d->m_dataRangeStart = f;
}
QString MyMoneyReport::dataRangeEnd() const
{
Q_D(const MyMoneyReport);
return d->m_dataRangeEnd;
}
void MyMoneyReport::setDataRangeEnd(const QString& f)
{
Q_D(MyMoneyReport);
d->m_dataRangeEnd = f;
}
QString MyMoneyReport::dataMajorTick() const
{
Q_D(const MyMoneyReport);
return d->m_dataMajorTick;
}
void MyMoneyReport::setDataMajorTick(const QString& f)
{
Q_D(MyMoneyReport);
d->m_dataMajorTick = f;
}
QString MyMoneyReport::dataMinorTick() const
{
Q_D(const MyMoneyReport);
return d->m_dataMinorTick;
}
void MyMoneyReport::setDataMinorTick(const QString& f)
{
Q_D(MyMoneyReport);
d->m_dataMinorTick = f;
}
uint MyMoneyReport::yLabelsPrecision() const
{
Q_D(const MyMoneyReport);
return d->m_yLabelsPrecision;
}
void MyMoneyReport::setYLabelsPrecision(int f)
{
Q_D(MyMoneyReport);
d->m_yLabelsPrecision = f;
}
bool MyMoneyReport::isIncludingSchedules() const
{
Q_D(const MyMoneyReport);
return d->m_includeSchedules;
}
void MyMoneyReport::setIncludingSchedules(bool f)
{
Q_D(MyMoneyReport);
d->m_includeSchedules = f;
}
bool MyMoneyReport::isColumnsAreDays() const
{
Q_D(const MyMoneyReport);
return d->m_columnsAreDays;
}
void MyMoneyReport::setColumnsAreDays(bool f)
{
Q_D(MyMoneyReport);
d->m_columnsAreDays = f;
}
bool MyMoneyReport::isIncludingTransfers() const
{
Q_D(const MyMoneyReport);
return d->m_includeTransfers;
}
void MyMoneyReport::setIncludingTransfers(bool f)
{
Q_D(MyMoneyReport);
d->m_includeTransfers = f;
}
bool MyMoneyReport::isIncludingUnusedAccounts() const
{
Q_D(const MyMoneyReport);
return d->m_includeUnusedAccounts;
}
void MyMoneyReport::setIncludingUnusedAccounts(bool f)
{
Q_D(MyMoneyReport);
d->m_includeUnusedAccounts = f;
}
bool MyMoneyReport::hasBudget() const
{
Q_D(const MyMoneyReport);
return !d->m_budgetId.isEmpty();
}
QString MyMoneyReport::budget() const
{
Q_D(const MyMoneyReport);
return d->m_budgetId;
}
/**
* Sets the budget used for this report
*
* @param budget The ID of the budget to use, or an empty string
* to indicate a budget is NOT included
* @param fa Whether to display actual data alongside the budget.
* Setting to false means the report displays ONLY the budget itself.
* @warning For now, the budget ID is ignored. The budget id is
* simply checked for any non-empty string, and if so, hasBudget()
* will return true.
*/
void MyMoneyReport::setBudget(const QString& budget, bool fa)
{
Q_D(MyMoneyReport);
d->m_budgetId = budget; d->m_includeBudgetActuals = fa;
}
bool MyMoneyReport::isIncludingBudgetActuals() const
{
Q_D(const MyMoneyReport);
return d->m_includeBudgetActuals;
}
void MyMoneyReport::setIncludingBudgetActuals(bool f)
{
Q_D(MyMoneyReport);
d->m_includeBudgetActuals = f;
}
bool MyMoneyReport::isIncludingForecast() const
{
Q_D(const MyMoneyReport);
return d->m_includeForecast;
}
void MyMoneyReport::setIncludingForecast(bool f)
{
Q_D(MyMoneyReport);
d->m_includeForecast = f;
}
bool MyMoneyReport::isIncludingMovingAverage() const
{
Q_D(const MyMoneyReport);
return d->m_includeMovingAverage;
}
void MyMoneyReport::setIncludingMovingAverage(bool f)
{
Q_D(MyMoneyReport);
d->m_includeMovingAverage = f;
}
int MyMoneyReport::movingAverageDays() const
{
Q_D(const MyMoneyReport);
return d->m_movingAverageDays;
}
void MyMoneyReport::setMovingAverageDays(int days)
{
Q_D(MyMoneyReport);
d->m_movingAverageDays = days;
}
bool MyMoneyReport::isIncludingPrice() const
{
Q_D(const MyMoneyReport);
return d->m_includePrice;
}
void MyMoneyReport::setIncludingPrice(bool f)
{
Q_D(MyMoneyReport);
d->m_includePrice = f;
}
bool MyMoneyReport::isIncludingAveragePrice() const
{
Q_D(const MyMoneyReport);
return d->m_includeAveragePrice;
}
void MyMoneyReport::setIncludingAveragePrice(bool f)
{
Q_D(MyMoneyReport);
d->m_includeAveragePrice = f;
}
eMyMoney::Report::DataLock MyMoneyReport::dataFilter() const
{
Q_D(const MyMoneyReport);
return d->m_dataLock;
}
bool MyMoneyReport::isDataUserDefined() const
{
Q_D(const MyMoneyReport);
return d->m_dataLock == eMyMoney::Report::DataLock::UserDefined;
}
void MyMoneyReport::setDataFilter(eMyMoney::Report::DataLock u)
{
Q_D(MyMoneyReport);
d->m_dataLock = u;
}
eMyMoney::TransactionFilter::Date MyMoneyReport::dateRange() const
{
Q_D(const MyMoneyReport);
return d->m_dateLock;
}
bool MyMoneyReport::isDateUserDefined() const
{
Q_D(const MyMoneyReport);
return d->m_dateLock == eMyMoney::TransactionFilter::Date::UserDefined;
}
/**
* Set the underlying date filter and LOCK that filter to the specified
* range. For example, if @p _u is "CurrentMonth", this report should always
* be updated to the current month no matter when the report is run.
*
* This updating is not entirely automatic, you should update it yourself by
* calling updateDateFilter.
*
* @param _u The date range constant (MyMoneyTransactionFilter::dateRangeE)
* which this report should be locked to.
*/
void MyMoneyReport::setDateFilter(eMyMoney::TransactionFilter::Date u)
{
Q_D(MyMoneyReport);
d->m_dateLock = u;
if (u != eMyMoney::TransactionFilter::Date::UserDefined)
MyMoneyTransactionFilter::setDateFilter(u);
}
void MyMoneyReport::setDateFilter(const QDate& db, const QDate& de)
{
MyMoneyTransactionFilter::setDateFilter(db, de);
}
void MyMoneyReport::updateDateFilter()
{
Q_D(MyMoneyReport);
if (d->m_dateLock != eMyMoney::TransactionFilter::Date::UserDefined) MyMoneyTransactionFilter::setDateFilter(d->m_dateLock);
}
bool MyMoneyReport::isMixedTime() const
{
Q_D(const MyMoneyReport);
return d->m_mixedTime;
}
void MyMoneyReport::setMixedTime(bool f)
{
Q_D(MyMoneyReport);
d->m_mixedTime = f;
}
int MyMoneyReport::currentDateColumn() const
{
Q_D(const MyMoneyReport);
return d->m_currentDateColumn;
}
void MyMoneyReport::setCurrentDateColumn(int f)
{
Q_D(MyMoneyReport);
d->m_currentDateColumn = f;
}
uint MyMoneyReport::settlementPeriod() const
{
Q_D(const MyMoneyReport);
return d->m_settlementPeriod;
}
void MyMoneyReport::setSettlementPeriod(uint days)
{
Q_D(MyMoneyReport);
d->m_settlementPeriod = days;
}
bool MyMoneyReport::isShowingSTLTCapitalGains() const
{
Q_D(const MyMoneyReport);
return d->m_showSTLTCapitalGains;
}
void MyMoneyReport::setShowSTLTCapitalGains(bool f)
{
Q_D(MyMoneyReport);
d->m_showSTLTCapitalGains = f;
}
QDate MyMoneyReport::termSeparator() const
{
Q_D(const MyMoneyReport);
return d->m_tseparator;
}
void MyMoneyReport::setTermSeparator(const QDate& date)
{
Q_D(MyMoneyReport);
d->m_tseparator = date;
}
bool MyMoneyReport::isSkippingZero() const
{
Q_D(const MyMoneyReport);
return d->m_skipZero;
}
void MyMoneyReport::setSkipZero(int f)
{
Q_D(MyMoneyReport);
d->m_skipZero = f;
}
void MyMoneyReport::clearTransactionFilter()
{
Q_D(MyMoneyReport);
d->m_accountGroupFilter = false;
d->m_accountGroups.clear();
MyMoneyTransactionFilter::clear();
}
void MyMoneyReport::assignFilter(const MyMoneyTransactionFilter& filter)
{
MyMoneyTransactionFilter::operator=(filter);
}
void MyMoneyReport::validDateRange(QDate& db, QDate& de)
{
db = fromDate();
de = toDate();
// if either begin or end date are invalid we have one of the following
// possible date filters:
//
// a) begin date not set - first transaction until given end date
// b) end date not set - from given date until last transaction
// c) both not set - first transaction until last transaction
//
// If there is no transaction in the engine at all, we use the current
// year as the filter criteria.
if (!db.isValid() || !de.isValid()) {
QList list = MyMoneyFile::instance()->transactionList(*this);
QDate tmpBegin, tmpEnd;
if (!list.isEmpty()) {
qSort(list);
// try to use the post dates
tmpBegin = list.front().postDate();
tmpEnd = list.back().postDate();
// if the post dates are not valid try the entry dates
if (!tmpBegin.isValid())
tmpBegin = list.front().entryDate();
if (!tmpEnd.isValid())
tmpEnd = list.back().entryDate();
}
// make sure that we leave this function with valid dates no mather what
if (!tmpBegin.isValid() || !tmpEnd.isValid() || tmpBegin > tmpEnd) {
tmpBegin = QDate(QDate::currentDate().year(), 1, 1); // the first date in the file
tmpEnd = QDate(QDate::currentDate().year(), 12, 31); // the last date in the file
}
if (!db.isValid())
db = tmpBegin;
if (!de.isValid())
de = tmpEnd;
}
if (db > de)
db = de;
}
bool MyMoneyReport::accountGroups(QList& list) const
{
Q_D(const MyMoneyReport);
bool result = d->m_accountGroupFilter;
if (result) {
QList::const_iterator it_group = d->m_accountGroups.begin();
while (it_group != d->m_accountGroups.end()) {
list += (*it_group);
++it_group;
}
}
return result;
}
void MyMoneyReport::addAccountGroup(eMyMoney::Account::Type type)
{
Q_D(MyMoneyReport);
if (!d->m_accountGroups.isEmpty() && type != eMyMoney::Account::Type::Unknown) {
if (d->m_accountGroups.contains(type))
return;
}
d->m_accountGroupFilter = true;
if (type != eMyMoney::Account::Type::Unknown)
d->m_accountGroups.push_back(type);
}
bool MyMoneyReport::includesAccountGroup(eMyMoney::Account::Type type) const
{
Q_D(const MyMoneyReport);
bool result = (! d->m_accountGroupFilter)
|| (isIncludingTransfers() && d->m_rowType == eMyMoney::Report::RowType::ExpenseIncome)
|| d->m_accountGroups.contains(type);
return result;
}
bool MyMoneyReport::includes(const MyMoneyAccount& acc) const
{
Q_D(const MyMoneyReport);
auto result = false;
if (includesAccountGroup(acc.accountGroup())) {
switch (acc.accountGroup()) {
case eMyMoney::Account::Type::Income:
case eMyMoney::Account::Type::Expense:
if (isTax())
result = (acc.value("Tax") == "Yes") && includesCategory(acc.id());
else
result = includesCategory(acc.id());
break;
case eMyMoney::Account::Type::Asset:
case eMyMoney::Account::Type::Liability:
if (isLoansOnly())
result = acc.isLoan() && includesAccount(acc.id());
else if (isInvestmentsOnly())
result = acc.isInvest() && includesAccount(acc.id());
else if (isIncludingTransfers() && d->m_rowType == eMyMoney::Report::RowType::ExpenseIncome)
// If transfers are included, ONLY include this account if it is NOT
// included in the report itself!!
result = ! includesAccount(acc.id());
else
result = includesAccount(acc.id());
break;
case eMyMoney::Account::Type::Equity:
if (isInvestmentsOnly())
result = (isIncludingPrice() || isIncludingAveragePrice()) && acc.isInvest() && includesAccount(acc.id());
break;
default:
result = includesAccount(acc.id());
}
}
return result;
}
bool MyMoneyReport::hasReferenceTo(const QString& id) const
{
QStringList list;
// collect all ids
accounts(list);
categories(list);
payees(list);
tags(list);
return list.contains(id);
}
int MyMoneyReport::m_lineWidth = 2;
bool MyMoneyReport::m_expertMode = false;
void MyMoneyReport::setLineWidth(int width)
{
m_lineWidth = width;
}
void MyMoneyReport::setExpertMode(bool expertMode)
{
m_expertMode = expertMode;
}
QString MyMoneyReport::toString(eMyMoney::Report::RowType type)
{
switch(type) {
case eMyMoney::Report::RowType::NoRows : return "eMyMoney::Report::RowType::NoRows";
case eMyMoney::Report::RowType::AssetLiability : return "eMyMoney::Report::RowType::AssetLiability";
case eMyMoney::Report::RowType::ExpenseIncome : return "eMyMoney::Report::RowType::ExpenseIncome";
case eMyMoney::Report::RowType::Category : return "eMyMoney::Report::RowType::Category";
case eMyMoney::Report::RowType::TopCategory : return "eTopCategory";
case eMyMoney::Report::RowType::Account : return "eAccount";
case eMyMoney::Report::RowType::Tag : return "eTag";
case eMyMoney::Report::RowType::Payee : return "ePayee";
case eMyMoney::Report::RowType::Month : return "eMonth";
case eMyMoney::Report::RowType::Week : return "eWeek";
case eMyMoney::Report::RowType::TopAccount : return "eTopAccount";
case eMyMoney::Report::RowType::AccountByTopAccount: return "eAccountByTopAccount";
case eMyMoney::Report::RowType::EquityType : return "eEquityType";
case eMyMoney::Report::RowType::AccountType : return "eAccountType";
case eMyMoney::Report::RowType::Institution : return "eInstitution";
case eMyMoney::Report::RowType::Budget : return "eBudget";
case eMyMoney::Report::RowType::BudgetActual : return "eBudgetActual";
case eMyMoney::Report::RowType::Schedule : return "eSchedule";
case eMyMoney::Report::RowType::AccountInfo : return "eAccountInfo";
case eMyMoney::Report::RowType::AccountLoanInfo : return "eAccountLoanInfo";
case eMyMoney::Report::RowType::AccountReconcile : return "eAccountReconcile";
case eMyMoney::Report::RowType::CashFlow : return "eCashFlow";
default : return "undefined";
}
}
QString MyMoneyReport::toString(eMyMoney::Report::ReportType type)
{
switch(type) {
case eMyMoney::Report::ReportType::NoReport: return "eNoReport";
case eMyMoney::Report::ReportType::PivotTable: return "ePivotTable";
case eMyMoney::Report::ReportType::QueryTable: return "eQueryTable";
case eMyMoney::Report::ReportType::InfoTable: return "eInfoTable";
default: return "undefined";
}
}
diff --git a/kmymoney/mymoney/mymoneyreport.h b/kmymoney/mymoney/mymoneyreport.h
index 2ebe94e0a..81f302e5a 100644
--- a/kmymoney/mymoney/mymoneyreport.h
+++ b/kmymoney/mymoney/mymoneyreport.h
@@ -1,437 +1,441 @@
/*
* Copyright 2004-2006 Ace Jones
* Copyright 2006 Darren Gould
* Copyright 2007-2010 Alvaro Soliverez
* Copyright 2017-2018 Łukasz Wojniłowicz
+ * Copyright 2018 Michael Kiefer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MYMONEYREPORT_H
#define MYMONEYREPORT_H
// ----------------------------------------------------------------------------
// QT Includes
// ----------------------------------------------------------------------------
// Project Includes
#include "mymoneyobject.h"
#include "mymoneytransactionfilter.h"
#include "kmm_mymoney_export.h"
#include "mymoneyunittestable.h"
class QString;
class MyMoneyAccount;
template class QList;
namespace eMyMoney { namespace Account { enum class Type; }
namespace TransactionFilter { enum class Date; } }
namespace eMyMoney { namespace Report { enum class RowType; } }
namespace eMyMoney { namespace Report { enum class ReportType; } }
namespace eMyMoney { namespace Report { enum class ColumnType; } }
namespace eMyMoney { namespace Report { enum QueryColumn : int; } }
namespace eMyMoney { namespace Report { enum class DetailLevel; } }
namespace eMyMoney { namespace Report { enum class InvestmentSum; } }
namespace eMyMoney { namespace Report { enum class ChartType; } }
namespace eMyMoney { namespace Report { enum class DataLock; } }
/**
* This class defines a report within the MyMoneyEngine. The report class
* contains all the configuration parameters needed to run a report, plus
* XML serialization.
*
* A report is a transactionfilter, so any report can specify which
* transactions it's interested down to the most minute level of detail.
* It extends the transactionfilter by providing identification (name,
* comments, group type, etc) as well as layout information (what kind
* of layout should be used, how the rows & columns should be presented,
* currency converted, etc.)
*
* As noted above, this class only provides a report DEFINITION. The
* generation and presentation of the report itself are left to higher
* level classes.
*
* @author Ace Jones
*/
class MyMoneyReportPrivate;
class KMM_MYMONEY_EXPORT MyMoneyReport: public MyMoneyObject, public MyMoneyTransactionFilter
{
Q_DECLARE_PRIVATE_D(MyMoneyObject::d_ptr, MyMoneyReport)
KMM_MYMONEY_UNIT_TESTABLE
public:
MyMoneyReport();
explicit MyMoneyReport(const QString &id);
explicit MyMoneyReport(eMyMoney::Report::RowType rt,
unsigned ct,
eMyMoney::TransactionFilter::Date dl,
eMyMoney::Report::DetailLevel ss,
const QString& name,
const QString& comment);
MyMoneyReport(const QString& id,
const MyMoneyReport& other);
MyMoneyReport(const MyMoneyReport & other);
MyMoneyReport(MyMoneyReport && other);
MyMoneyReport & operator=(MyMoneyReport other);
friend void swap(MyMoneyReport& first, MyMoneyReport& second);
~MyMoneyReport();
eMyMoney::Report::ReportType reportType() const;
void setReportType(eMyMoney::Report::ReportType rt);
QString name() const;
void setName(const QString& s);
bool isShowingRowTotals() const;
void setShowingRowTotals(bool f);
bool isShowingColumnTotals() const;
void setShowingColumnTotals(bool f);
eMyMoney::Report::RowType rowType() const;
void setRowType(eMyMoney::Report::RowType rt);
bool isRunningSum() const;
eMyMoney::Report::ColumnType columnType() const;
void setColumnType(eMyMoney::Report::ColumnType ct);
bool isConvertCurrency() const;
void setConvertCurrency(bool f);
uint columnPitch() const;
QString comment() const;
void setComment(const QString& comment);
eMyMoney::Report::QueryColumn queryColumns() const;
void setQueryColumns(eMyMoney::Report::QueryColumn qc);
QString group() const;
void setGroup(const QString& group);
bool isFavorite() const;
void setFavorite(bool f);
bool isTax() const;
void setTax(bool f);
bool isInvestmentsOnly() const;
void setInvestmentsOnly(bool f);
bool isLoansOnly() const;
void setLoansOnly(bool f);
eMyMoney::Report::DetailLevel detailLevel() const;
void setDetailLevel(eMyMoney::Report::DetailLevel detail);
eMyMoney::Report::InvestmentSum investmentSum() const;
void setInvestmentSum(eMyMoney::Report::InvestmentSum sum);
bool isHideTransactions() const;
void setHideTransactions(bool f);
eMyMoney::Report::ChartType chartType() const;
void setChartType(eMyMoney::Report::ChartType type);
bool isChartDataLabels() const;
void setChartDataLabels(bool f);
bool isChartCHGridLines() const;
void setChartCHGridLines(bool f);
bool isChartSVGridLines() const;
void setChartSVGridLines(bool f);
bool isChartByDefault() const;
void setChartByDefault(bool f);
uint chartLineWidth() const;
void setChartLineWidth(uint f);
bool isLogYAxis() const;
void setLogYAxis(bool f);
+ bool isNegExpenses() const;
+ void setNegExpenses(bool f);
+
QString dataRangeStart() const;
void setDataRangeStart(const QString& f);
QString dataRangeEnd() const;
void setDataRangeEnd(const QString& f);
QString dataMajorTick() const;
void setDataMajorTick(const QString& f);
QString dataMinorTick() const;
void setDataMinorTick(const QString& f);
uint yLabelsPrecision() const;
void setYLabelsPrecision(int f);
bool isIncludingSchedules() const;
void setIncludingSchedules(bool f);
bool isColumnsAreDays() const;
void setColumnsAreDays(bool f);
bool isIncludingTransfers() const;
void setIncludingTransfers(bool f);
bool isIncludingUnusedAccounts() const;
void setIncludingUnusedAccounts(bool f);
bool hasBudget() const;
QString budget() const;
/**
* Sets the budget used for this report
*
* @param budget The ID of the budget to use, or an empty string
* to indicate a budget is NOT included
* @param fa Whether to display actual data alongside the budget.
* Setting to false means the report displays ONLY the budget itself.
* @warning For now, the budget ID is ignored. The budget id is
* simply checked for any non-empty string, and if so, hasBudget()
* will return true.
*/
void setBudget(const QString& budget, bool fa = true);
bool isIncludingBudgetActuals() const;
void setIncludingBudgetActuals(bool f);
bool isIncludingForecast() const;
void setIncludingForecast(bool f);
bool isIncludingMovingAverage() const;
void setIncludingMovingAverage(bool f);
int movingAverageDays() const;
void setMovingAverageDays(int days);
bool isIncludingPrice() const;
void setIncludingPrice(bool f);
bool isIncludingAveragePrice() const;
void setIncludingAveragePrice(bool f);
eMyMoney::Report::DataLock dataFilter() const;
bool isDataUserDefined() const;
void setDataFilter(eMyMoney::Report::DataLock u);
eMyMoney::TransactionFilter::Date dateRange() const;
bool isDateUserDefined() const;
/**
* Set the underlying date filter and LOCK that filter to the specified
* range. For example, if @p _u is "CurrentMonth", this report should always
* be updated to the current month no matter when the report is run.
*
* This updating is not entirely automatic, you should update it yourself by
* calling updateDateFilter.
*
* @param _u The date range constant (MyMoneyTransactionFilter::dateRangeE)
* which this report should be locked to.
*/
void setDateFilter(eMyMoney::TransactionFilter::Date u);
/**
* Set the underlying date filter using the start and end dates provided.
* Note that this does not LOCK to any range like setDateFilter(unsigned)
* above. It is just a reimplementation of the MyMoneyTransactionFilter
* version.
*
* @param _db The inclusive begin date of the date range
* @param _de The inclusive end date of the date range
*/
void setDateFilter(const QDate& db, const QDate& de);
/**
* Set the underlying date filter using the 'date lock' property.
*
* Always call this function before executing the report to be sure that
* the date filters properly match the plain-language 'date lock'.
*
* For example, if the report is date-locked to "Current Month", and the
* last time you loaded or ran the report was in August, but it's now
* September, this function will update the date range to be September,
* as is proper.
*/
void updateDateFilter();
bool isMixedTime() const;
void setMixedTime(bool f);
int currentDateColumn() const;
void setCurrentDateColumn(int f);
uint settlementPeriod() const;
void setSettlementPeriod(uint days);
bool isShowingSTLTCapitalGains() const;
void setShowSTLTCapitalGains(bool f);
QDate termSeparator() const;
void setTermSeparator(const QDate& date);
bool isSkippingZero() const;
void setSkipZero(int f);
/**
* This method allows you to clear the underlying transaction filter
*/
void clearTransactionFilter();
/**
* This method allows you to set the underlying transaction filter
*
* @param _filter The filter which should replace the existing transaction
* filter.
*/
void assignFilter(const MyMoneyTransactionFilter& filter);
/**
* Retrieves a VALID beginning & ending date for this report.
*
* The underlying date filter can return en empty QDate() for either the
* begin or end date or both. This is typically unacceptable for reports,
* which need the REAL begin and end date.
*
* This function gets the underlying date filter range, and if either is
* an empty QDate(), it determines the missing date from looking at all
* the transactions which match the underlying filter, and returning the
* date of the first or last transaction (as appropriate).
*
* @param _db The inclusive begin date of the date range
* @param _de The inclusive end date of the date range
*/
void validDateRange(QDate &db, QDate &de);
/**
* This method turns on the account group filter and adds the
* @p type to the list of allowed groups.
*
* Note that account group filtering is handled differently
* than all the filters of the underlying class. This filter
* is meant to be applied to individual splits of matched
* transactions AFTER the underlying filter is used to find
* the matching transactions.
*
* @param type the account group to add to the allowed groups list
*/
void addAccountGroup(eMyMoney::Account::Type type);
/**
* This method returns whether an account group filter has been set,
* and if so, it returns all the account groups set in the filter.
*
* @param list list to append account groups into
* @return return true if an account group filter has been set
*/
bool accountGroups(QList& list) const;
/**
* This method returns whether the specified account group
* is allowed by the account groups filter.
*
* @param type group to append account groups into
* @return return true if an account group filter has been set
*/
bool includesAccountGroup(eMyMoney::Account::Type type) const;
/**
* This method is used to test whether a specific account
* passes the accountGroup test and either the Account or
* Category test, depending on which sort of Account it is.
*
* The m_tax and m_investments properties are also considered.
*
* @param acc the account in question
* @return true if account is in filter set, false otherwise
*/
bool includes(const MyMoneyAccount& acc) const;
/**
* This method checks if a reference to the given object exists. It returns,
* a @p true if the object is referencing the one requested by the
* parameter @p id. If it does not, this method returns @p false.
*
* @param id id of the object to be checked for references
* @retval true This object references object with id @p id.
* @retval false This object does not reference the object with id @p id.
*/
bool hasReferenceTo(const QString& id) const override;
/**
* This method allows to modify the default lineWidth for graphs.
* The default is 2.
*/
static void setLineWidth(int width);
/**
* This member keeps the current setting for line graphs lineWidth.
* @sa setLineWidth()
*/
static int m_lineWidth;
static void setExpertMode(bool expertMode);
static bool m_expertMode;
/**
* Return row type as string.
*
* @param type type to get string for
* @return row type converted to string
*/
static QString toString(eMyMoney::Report::RowType type);
/**
* Return report type as string.
*
* @param type report type to get string for
* @return report type converted to string
*/
static QString toString(eMyMoney::Report::ReportType type);
};
inline void swap(MyMoneyReport& first, MyMoneyReport& second) // krazy:exclude=inline
{
using std::swap;
swap(first.MyMoneyObject::d_ptr, second.MyMoneyObject::d_ptr);
swap(first.MyMoneyTransactionFilter::d_ptr, second.MyMoneyTransactionFilter::d_ptr);
}
inline MyMoneyReport::MyMoneyReport(MyMoneyReport && other) : MyMoneyReport() // krazy:exclude=inline
{
swap(*this, other);
}
inline MyMoneyReport & MyMoneyReport::operator=(MyMoneyReport other) // krazy:exclude=inline
{
swap(*this, other);
return *this;
}
/**
* Make it possible to hold @ref MyMoneyReport objects inside @ref QVariant objects.
*/
Q_DECLARE_METATYPE(MyMoneyReport)
#endif // MYMONEYREPORT_H
diff --git a/kmymoney/mymoney/mymoneyreport_p.h b/kmymoney/mymoney/mymoneyreport_p.h
index 38a033b2c..de23ed9e6 100644
--- a/kmymoney/mymoney/mymoneyreport_p.h
+++ b/kmymoney/mymoney/mymoneyreport_p.h
@@ -1,370 +1,377 @@
/*
* Copyright 2004-2006 Ace Jones
* Copyright 2006 Darren Gould
* Copyright 2007-2010 Alvaro Soliverez
* Copyright 2017-2018 Łukasz Wojniłowicz
+ * Copyright 2018 Michael Kiefer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MYMONEYREPORT_P_H
#define MYMONEYREPORT_P_H
#include "mymoneyreport.h"
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
#include "mymoneyobject_p.h"
#include "mymoneyenums.h"
class MyMoneyReportPrivate : public MyMoneyObjectPrivate
{
public:
MyMoneyReportPrivate() :
m_name(QStringLiteral("Unconfigured Pivot Table Report")),
m_detailLevel(eMyMoney::Report::DetailLevel::None),
m_investmentSum(eMyMoney::Report::InvestmentSum::Sold),
m_hideTransactions(false),
m_convertCurrency(true),
m_favorite(false),
m_tax(false),
m_investments(false),
m_loans(false),
m_reportType(rowTypeToReportType(eMyMoney::Report::RowType::ExpenseIncome)),
m_rowType(eMyMoney::Report::RowType::ExpenseIncome),
m_columnType(eMyMoney::Report::ColumnType::Months),
m_columnsAreDays(false),
m_queryColumns(eMyMoney::Report::QueryColumn::None),
m_dateLock(eMyMoney::TransactionFilter::Date::UserDefined),
m_accountGroupFilter(false),
m_chartType(eMyMoney::Report::ChartType::Line),
m_chartDataLabels(true),
m_chartCHGridLines(true),
m_chartSVGridLines(true),
m_chartByDefault(false),
m_chartLineWidth(MyMoneyReport::m_lineWidth),
m_logYaxis(false),
+ m_negExpenses(false),
m_dataRangeStart('0'),
m_dataRangeEnd('0'),
m_dataMajorTick('0'),
m_dataMinorTick('0'),
m_yLabelsPrecision(2),
m_dataLock(eMyMoney::Report::DataLock::Automatic),
m_includeSchedules(false),
m_includeTransfers(false),
m_includeBudgetActuals(false),
m_includeUnusedAccounts(false),
m_showRowTotals(false),
m_showColumnTotals(true),
m_includeForecast(false),
m_includeMovingAverage(false),
m_movingAverageDays(0),
m_includePrice(false),
m_includeAveragePrice(false),
m_mixedTime(false),
m_currentDateColumn(0),
m_settlementPeriod(3),
m_showSTLTCapitalGains(false),
m_tseparator(QDate::currentDate().addYears(-1)),
m_skipZero(false)
{
}
static eMyMoney::Report::ReportType rowTypeToReportType(eMyMoney::Report::RowType rowType)
{
static const QHash reportTypes {
{eMyMoney::Report::RowType::NoRows, eMyMoney::Report::ReportType::NoReport},
{eMyMoney::Report::RowType::AssetLiability, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::ExpenseIncome, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::Category, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::TopCategory, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Account, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Tag, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Payee, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Month, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Week, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::TopAccount, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::AccountByTopAccount, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::EquityType, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::AccountType, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Institution, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Budget, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::BudgetActual, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::Schedule, eMyMoney::Report::ReportType::InfoTable},
{eMyMoney::Report::RowType::AccountInfo, eMyMoney::Report::ReportType::InfoTable},
{eMyMoney::Report::RowType::AccountLoanInfo, eMyMoney::Report::ReportType::InfoTable},
{eMyMoney::Report::RowType::AccountReconcile, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::CashFlow, eMyMoney::Report::ReportType::QueryTable},
};
return reportTypes.value(rowType, eMyMoney::Report::ReportType::Invalid);
}
/**
* The user-assigned name of the report
*/
QString m_name;
/**
* The user-assigned comment for the report, in case they want to make
* additional notes for themselves about the report.
*/
QString m_comment;
/**
* Where to group this report amongst the others in the UI view. This
* should be assigned by the UI system.
*/
QString m_group;
/**
* How much detail to show in the accounts
*/
eMyMoney::Report::DetailLevel m_detailLevel;
/**
* Whether to sum: all, sold, bought or owned value
*/
eMyMoney::Report::InvestmentSum m_investmentSum;
/**
* Whether to show transactions or just totals.
*/
bool m_hideTransactions;
/**
* Whether to convert all currencies to the base currency of the file (true).
* If this is false, it's up to the report generator to decide how to handle
* the currency.
*/
bool m_convertCurrency;
/**
* Whether this is one of the users' favorite reports
*/
bool m_favorite;
/**
* Whether this report should only include categories marked as "Tax"="Yes"
*/
bool m_tax;
/**
* Whether this report should only include investment accounts
*/
bool m_investments;
/**
* Whether this report should only include loan accounts
* Applies only to querytable reports. Mutually exclusive with
* m_investments.
*/
bool m_loans;
/**
* What sort of algorithm should be used to run the report
*/
eMyMoney::Report::ReportType m_reportType;
/**
* What sort of values should show up on the ROWS of this report
*/
eMyMoney::Report::RowType m_rowType;
/**
* What sort of values should show up on the COLUMNS of this report,
* in the case of a 'PivotTable' report. Really this is used more as a
* QUANTITY of months or days. Whether it's months or days is determined
* by m_columnsAreDays.
*/
eMyMoney::Report::ColumnType m_columnType;
/**
* Whether the base unit of columns of this report is days. Only applies to
* 'PivotTable' reports. If false, then columns are months or multiples thereof.
*/
bool m_columnsAreDays;
/**
* What sort of values should show up on the COLUMNS of this report,
* in the case of a 'QueryTable' report
*/
eMyMoney::Report::QueryColumn m_queryColumns;
/**
* The plain-language description of what the date range should be locked
* to. 'userDefined' means NO locking, in any other case, the report
* will be adjusted to match the date lock. So if the date lock is
* 'currentMonth', the start and end dates of the underlying filter will
* be updated to whatever the current month is. This updating happens
* automatically when the report is loaded, and should also be done
* manually by calling updateDateFilter() before generating the report
*/
eMyMoney::TransactionFilter::Date m_dateLock;
/**
* Which account groups should be included in the report. This filter
* is applied to the individual splits AFTER a transaction has been
* matched using the underlying filter.
*/
QList m_accountGroups;
/**
* Whether an account group filter has been set (see m_accountGroups)
*/
bool m_accountGroupFilter;
/**
* What format should be used to draw this report as a chart
*/
eMyMoney::Report::ChartType m_chartType;
/**
* Whether the value of individual data points should be drawn on the chart
*/
bool m_chartDataLabels;
/**
* Whether grid lines should be drawn on the chart
*/
bool m_chartCHGridLines;
bool m_chartSVGridLines;
/**
* Whether this report should be shown as a chart by default (otherwise it
* should be shown as a textual report)
*/
bool m_chartByDefault;
/**
* Width of the chart lines
*/
uint m_chartLineWidth;
/**
* Whether Y axis is logarithmic or linear
*/
bool m_logYaxis;
+ /**
+ * Whether expenses should be plotted downwards
+ */
+ bool m_negExpenses;
+
/**
* Y data range
*/
QString m_dataRangeStart;
QString m_dataRangeEnd;
/**
* Y data range division
*/
QString m_dataMajorTick;
QString m_dataMinorTick;
/**
* Y labels precision
*/
uint m_yLabelsPrecision;
/**
* Whether data range should be calculated automatically or is user defined
*/
eMyMoney::Report::DataLock m_dataLock;
/**
* Whether to include scheduled transactions
*/
bool m_includeSchedules;
/**
* Whether to include transfers. Only applies to Income/Expense reports
*/
bool m_includeTransfers;
/**
* The id of the budget associated with this report.
*/
QString m_budgetId;
/**
* Whether this report should print the actual data to go along with
* the budget. This is only valid if the report has a budget.
*/
bool m_includeBudgetActuals;
/**
* Whether this report should include all accounts and not only
* accounts with transactions.
*/
bool m_includeUnusedAccounts;
/**
* Whether this report should include columns for row totals
*/
bool m_showRowTotals;
/**
* Whether this report should include rows for column totals
*/
bool m_showColumnTotals;
/**
* Whether this report should include forecast balance
*/
bool m_includeForecast;
/**
* Whether this report should include moving average
*/
bool m_includeMovingAverage;
/**
* The amount of days that spans each moving average
*/
int m_movingAverageDays;
/**
* Whether this report should include prices
*/
bool m_includePrice;
/**
* Whether this report should include moving average prices
*/
bool m_includeAveragePrice;
/**
* Make the actual and forecast lines display as one
*/
bool m_mixedTime;
/**
* This stores the column for the current date
* This value is calculated dynamically and thus it is not saved in the file
*/
int m_currentDateColumn;
/**
* Time in days between the settlement date and the transaction date.
*/
uint m_settlementPeriod;
/**
* Controls showing short-term and long-term capital gains.
*/
bool m_showSTLTCapitalGains;
/**
* Date separating shot-term from long-term gains.
*/
QDate m_tseparator;
/**
* This option is for investments reports only which
* show prices instead of balances as all other reports do.
*
* Select this option to include prices for the given period (week, month,
* quarter, ...) only.
*
*
* If this option is off the last existing price is shown for a period, if
* it is on, in a table the value is '0' shown and in a chart a linear
* interpolation for the missing values will be performed.
*
Example:
*
There are prices for January and March, but there is no price for
* February.
*
* - OFF: shows the price for February as the last price of
* January
*
- ON: in a table the value is '0', in a chart a linear
* interpolation for the February-price will be performed
* (so it makes a kind of average-value using the January- and the
* March-price in the chart)
*
*
*/
bool m_skipZero;
};
#endif
diff --git a/kmymoney/plugins/views/reports/core/kreportchartview.cpp b/kmymoney/plugins/views/reports/core/kreportchartview.cpp
index 8548768bf..c6ed85461 100644
--- a/kmymoney/plugins/views/reports/core/kreportchartview.cpp
+++ b/kmymoney/plugins/views/reports/core/kreportchartview.cpp
@@ -1,758 +1,766 @@
/*
* Copyright 2005 Ace Jones
* Copyright 2005-2018 Thomas Baumgart
* Copyright 2017-2018 Łukasz Wojniłowicz
+ * Copyright 2018 Michael Kiefer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "kreportchartview.h"
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include
#include
// ----------------------------------------------------------------------------
// Project Includes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kmymoneysettings.h"
#include "mymoneyfile.h"
#include "mymoneysecurity.h"
#include "mymoneyenums.h"
using namespace reports;
KReportChartView::KReportChartView(QWidget* parent) :
KChart::Chart(parent),
m_accountSeries(0),
m_seriesTotals(0),
m_numColumns(0),
m_skipZero(0),
m_backgroundBrush(KColorScheme(QPalette::Current).background()),
m_foregroundBrush(KColorScheme(QPalette::Current).foreground()),
m_precision(2)
{
// ********************************************************************
// Set KMyMoney's Chart Parameter Defaults
// ********************************************************************
//Set the background obtained from the color scheme
BackgroundAttributes backAttr(backgroundAttributes());
backAttr.setBrush(m_backgroundBrush);
backAttr.setVisible(true);
setBackgroundAttributes(backAttr);
}
void KReportChartView::drawPivotChart(const PivotGrid &grid, const MyMoneyReport &config, int numberColumns, const QStringList& columnHeadings, const QList& rowTypeList, const QStringList& columnTypeHeaderList)
{
if (numberColumns == 0)
return;
//set the number of columns
setNumColumns(numberColumns);
//set skipZero
m_skipZero = config.isSkippingZero();
//remove existing headers
const HeaderFooterList hfList = headerFooters();
foreach (const auto hf, hfList)
delete hf;
//remove existing legends
const LegendList lgList = legends();
foreach (const auto lg, lgList)
delete lg;
//make sure the model is clear
m_model.clear();
const bool blocked = m_model.blockSignals(true); // don't emit dataChanged() signal during each drawPivotRowSet
//set the new header
HeaderFooter* header = new HeaderFooter;
header->setText(config.name());
header->setType(HeaderFooter::Header);
header->setPosition(Position::North);
TextAttributes headerTextAttr(header->textAttributes());
headerTextAttr.setPen(m_foregroundBrush.color());
header->setTextAttributes(headerTextAttr);
addHeaderFooter(header);
// whether to limit the chart to use series totals only. Used for reports which only
// show one dimension (pie).
setSeriesTotals(false);
// whether series (rows) are accounts (true) or months (false). This causes a lot
// of complexity in the charts. The problem is that circular reports work best with
// an account in a COLUMN, while line/bar prefer it in a ROW.
setAccountSeries(true);
switch (config.chartType()) {
case eMyMoney::Report::ChartType::Line:
case eMyMoney::Report::ChartType::Bar:
case eMyMoney::Report::ChartType::StackedBar: {
CartesianCoordinatePlane* cartesianPlane = new CartesianCoordinatePlane(this);
cartesianPlane->setAutoAdjustVerticalRangeToData(2);
cartesianPlane->setRubberBandZoomingEnabled(true);
replaceCoordinatePlane(cartesianPlane);
// set-up axis type
if (config.isLogYAxis())
cartesianPlane->setAxesCalcModeY(KChart::AbstractCoordinatePlane::Logarithmic);
else
cartesianPlane->setAxesCalcModeY(KChart::AbstractCoordinatePlane::Linear);
QLocale loc = locale();
// set-up grid
GridAttributes ga = cartesianPlane->gridAttributes(Qt::Vertical);
ga.setGridVisible(config.isChartCHGridLines());
ga.setGridStepWidth(config.isDataUserDefined() ? loc.toDouble(config.dataMajorTick()) : 0.0);
ga.setGridSubStepWidth(config.isDataUserDefined() ? loc.toDouble(config.dataMinorTick()) : 0.0);
cartesianPlane->setGridAttributes(Qt::Vertical, ga);
ga = cartesianPlane->gridAttributes(Qt::Horizontal);
ga.setGridVisible(config.isChartSVGridLines());
cartesianPlane->setGridAttributes(Qt::Horizontal, ga);
// set-up data range
cartesianPlane->setVerticalRange(qMakePair(config.isDataUserDefined() ? loc.toDouble(config.dataRangeStart()) : 0.0,
config.isDataUserDefined() ? loc.toDouble(config.dataRangeEnd()) : 0.0));
//set-up x axis
CartesianAxis *xAxis = new CartesianAxis();
xAxis->setPosition(CartesianAxis::Bottom);
xAxis->setTitleText(i18n("Time"));
TextAttributes xAxisTitleTextAttr(xAxis->titleTextAttributes());
xAxisTitleTextAttr.setMinimalFontSize(QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize());
xAxisTitleTextAttr.setPen(m_foregroundBrush.color());
xAxis->setTitleTextAttributes(xAxisTitleTextAttr);
TextAttributes xAxisTextAttr(xAxis->textAttributes());
xAxisTextAttr.setPen(m_foregroundBrush.color());
xAxis->setTextAttributes(xAxisTextAttr);
RulerAttributes xAxisRulerAttr(xAxis->rulerAttributes());
xAxisRulerAttr.setTickMarkPen(m_foregroundBrush.color());
xAxisRulerAttr.setShowRulerLine(true);
xAxis->setRulerAttributes(xAxisRulerAttr);
//set-up y axis
KChart::CartesianAxis *yAxis = new KChart::CartesianAxis;
yAxis->setPosition(CartesianAxis::Left);
if (config.isIncludingPrice())
yAxis->setTitleText(i18n("Price"));
else
yAxis->setTitleText(i18n("Balance"));
TextAttributes yAxisTitleTextAttr(yAxis->titleTextAttributes());
yAxisTitleTextAttr.setMinimalFontSize(QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize());
yAxisTitleTextAttr.setPen(m_foregroundBrush.color());
yAxis->setTitleTextAttributes(yAxisTitleTextAttr);
TextAttributes yAxisTextAttr(yAxis->textAttributes());
yAxisTextAttr.setPen(m_foregroundBrush.color());
yAxis->setTextAttributes(yAxisTextAttr);
RulerAttributes yAxisRulerAttr(yAxis->rulerAttributes());
yAxisRulerAttr.setTickMarkPen(m_foregroundBrush.color());
yAxisRulerAttr.setShowRulerLine(true);
yAxis->setRulerAttributes(yAxisRulerAttr);
switch (config.chartType()) {
case eMyMoney::Report::ChartType::End:
case eMyMoney::Report::ChartType::Line: {
KChart::LineDiagram* diagram = new KChart::LineDiagram(this, cartesianPlane);
if (config.isSkippingZero()) {
LineAttributes attributes = diagram->lineAttributes();
attributes.setMissingValuesPolicy(LineAttributes::MissingValuesAreBridged);
diagram->setLineAttributes(attributes);
}
cartesianPlane->replaceDiagram(diagram);
diagram->addAxis(xAxis);
diagram->addAxis(yAxis);
break;
}
case eMyMoney::Report::ChartType::Bar: {
KChart::BarDiagram* diagram = new KChart::BarDiagram(this, cartesianPlane);
cartesianPlane->replaceDiagram(diagram);
diagram->addAxis(xAxis);
diagram->addAxis(yAxis);
break;
}
case eMyMoney::Report::ChartType::StackedBar: {
KChart::BarDiagram* diagram = new KChart::BarDiagram(this, cartesianPlane);
diagram->setType(BarDiagram::Stacked);
cartesianPlane->replaceDiagram(diagram);
diagram->addAxis(xAxis);
diagram->addAxis(yAxis);
break;
}
default:
break;
}
break;
}
case eMyMoney::Report::ChartType::Pie:
case eMyMoney::Report::ChartType::Ring:{
PolarCoordinatePlane* polarPlane = new PolarCoordinatePlane(this);
replaceCoordinatePlane(polarPlane);
// set-up grid
GridAttributes ga = polarPlane->gridAttributes(true);
ga.setGridVisible(config.isChartCHGridLines());
polarPlane->setGridAttributes(true, ga);
ga = polarPlane->gridAttributes(false);
ga.setGridVisible(config.isChartSVGridLines());
polarPlane->setGridAttributes(false, ga);
setAccountSeries(false);
switch (config.chartType()) {
case eMyMoney::Report::ChartType::Pie: {
KChart::PieDiagram* diagram = new KChart::PieDiagram(this, polarPlane);
polarPlane->replaceDiagram(diagram);
setSeriesTotals(true);
break;
}
case eMyMoney::Report::ChartType::Ring: {
KChart::RingDiagram* diagram = new KChart::RingDiagram(this, polarPlane);
polarPlane->replaceDiagram(diagram);
break;
}
default:
break;
}
break;
}
default: // no valid chart types
return;
}
//get the coordinate plane and the diagram for later use
AbstractCoordinatePlane* cPlane = coordinatePlane();
AbstractDiagram* planeDiagram = cPlane->diagram();
planeDiagram->setAntiAliasing(true);
//the palette - we set it here because it is a property of the diagram
switch (KMyMoneySettings::chartsPalette()) {
case 0:
planeDiagram->useDefaultColors();
break;
case 1:
planeDiagram->useRainbowColors();
break;
case 2:
default:
planeDiagram->useSubduedColors();
break;
}
int eBudgetDiffIdx = rowTypeList.indexOf(eBudgetDiff);
QList myRowTypeList = rowTypeList;
myRowTypeList.removeAt(eBudgetDiffIdx);
QStringList myColumnTypeHeaderList = columnTypeHeaderList;
myColumnTypeHeaderList.removeAt(eBudgetDiffIdx);
int myRowTypeListSize = myRowTypeList.size();
MyMoneyFile* file = MyMoneyFile::instance();
int precision = MyMoneyMoney::denomToPrec(file->baseCurrency().smallestAccountFraction());
int rowNum = 0;
QStringList legendNames;
QMap legendTotal;
switch (config.detailLevel()) {
case eMyMoney::Report::DetailLevel::None:
case eMyMoney::Report::DetailLevel::All: {
// iterate over outer groups
PivotGrid::const_iterator it_outergroup = grid.begin();
while (it_outergroup != grid.end()) {
+ //determine whether expenses should be displayed as negative
+ const bool invertValue = (config.isNegExpenses() && (*it_outergroup).m_inverted);
// iterate over inner groups
PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
while (it_innergroup != (*it_outergroup).end()) {
// iterate over accounts
PivotInnerGroup::const_iterator it_row = (*it_innergroup).begin();
while (it_row != (*it_innergroup).end()) {
//Do not include investments accounts in the chart because they are merely container of stock and other accounts
if (it_row.key().accountType() != eMyMoney::Account::Type::Investment) {
// get displayed precision
int currencyPrecision = precision;
int securityPrecision = precision;
if (!it_row.key().id().isEmpty()) {
const MyMoneyAccount acc = file->account(it_row.key().id());
if (acc.isInvest()) {
securityPrecision = file->currency(acc.currencyId()).pricePrecision();
// stock account isn't evaluated in currency, so take investment account instead
currencyPrecision = MyMoneyMoney::denomToPrec(file->account(acc.parentAccountId()).fraction());
} else
currencyPrecision = MyMoneyMoney::denomToPrec(acc.fraction());
}
// iterate row types
for (int i = 0 ; i < myRowTypeListSize; ++i) {
QString legendText;
//only show the column type in the header if there is more than one type
if (myRowTypeListSize > 1)
legendText = QString(myColumnTypeHeaderList.at(i) + QLatin1Literal(" - ") + it_row.key().name());
else
legendText = it_row.key().name();
//set the legend text
legendNames.append(legendText);
legendTotal.insertMulti(it_row.value().value(myRowTypeList.at(i)).m_total.abs(), rowNum);
precision = myRowTypeList.at(i) == ePrice ? securityPrecision : currencyPrecision;
//set the cell value and tooltip
rowNum = drawPivotGridRow(rowNum, it_row.value().value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, numberColumns, precision);
+ 0, numberColumns, precision, invertValue);
}
}
++it_row;
}
++it_innergroup;
}
++it_outergroup;
}
}
break;
case eMyMoney::Report::DetailLevel::Top: {
// iterate over outer groups
PivotGrid::const_iterator it_outergroup = grid.begin();
while (it_outergroup != grid.end()) {
-
+ //determine whether expenses should be displayed as negative
+ const bool invertValue = (config.isNegExpenses() && (*it_outergroup).m_inverted);
// iterate over inner groups
PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
while (it_innergroup != (*it_outergroup).end()) {
// iterate row types
for (int i = 0 ; i < myRowTypeListSize; ++i) {
QString legendText;
//only show the column type in the header if there is more than one type
if (myRowTypeListSize > 1)
legendText = QString(myColumnTypeHeaderList.at(i) + QLatin1Literal(" - ") + it_innergroup.key());
else
legendText = it_innergroup.key();
//set the legend text
legendNames.append(legendText);
legendTotal.insertMulti((*it_innergroup).m_total.value(myRowTypeList.at(i)).m_total.abs(), rowNum);
//set the cell value and tooltip
rowNum = drawPivotGridRow(rowNum, (*it_innergroup).m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, numberColumns, precision);
+ 0, numberColumns, precision, invertValue);
}
++it_innergroup;
}
++it_outergroup;
}
}
break;
case eMyMoney::Report::DetailLevel::Group: {
// iterate over outer groups
PivotGrid::const_iterator it_outergroup = grid.begin();
while (it_outergroup != grid.end()) {
+ //determine whether expenses should be displayed as negative
+ const bool invertValue = (config.isNegExpenses() && (*it_outergroup).m_inverted);
// iterate row types
for (int i = 0 ; i < myRowTypeListSize; ++i) {
QString legendText;
//only show the column type in the header if there is more than one type
if (myRowTypeListSize > 1)
legendText = QString(myColumnTypeHeaderList.at(i) + QLatin1Literal(" - ") + it_outergroup.key());
else
legendText = it_outergroup.key();
//set the legend text
legendNames.append(legendText);
legendTotal.insertMulti((*it_outergroup).m_total.value(myRowTypeList.at(i)).m_total.abs(), rowNum);
//set the cell value and tooltip
rowNum = drawPivotGridRow(rowNum, (*it_outergroup).m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, numberColumns, precision);
+ 0, numberColumns, precision, invertValue);
}
++it_outergroup;
}
//if selected, show totals too
if (config.isShowingRowTotals()) {
// iterate row types
for (int i = 0 ; i < myRowTypeListSize; ++i) {
QString legendText;
//only show the column type in the header if there is more than one type
if (myRowTypeListSize > 1)
legendText = QString(myColumnTypeHeaderList.at(i) + QLatin1Literal(" - ") + i18nc("Total balance", "Total"));
else
legendText = QString(i18nc("Total balance", "Total"));
//set the legend text
legendNames.append(legendText);
legendTotal.insertMulti(grid.m_total.value(myRowTypeList.at(i)).m_total.abs(), rowNum);
//set the cell value and tooltip
rowNum = drawPivotGridRow(rowNum, grid.m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, numberColumns, precision);
+ 0, numberColumns, precision, false);
}
}
}
break;
case eMyMoney::Report::DetailLevel::Total: {
// iterate row types
for (int i = 0 ; i < myRowTypeListSize; ++i) {
QString legendText;
//only show the column type in the header if there is more than one type
if (myRowTypeListSize > 1)
legendText = QString(myColumnTypeHeaderList.at(i) + QLatin1Literal(" - ") + i18nc("Total balance", "Total"));
else
legendText = QString(i18nc("Total balance", "Total"));
//set the legend text
legendNames.append(legendText);
legendTotal.insertMulti(grid.m_total.value(myRowTypeList.at(i)).m_total.abs(), rowNum);
//set the cell value and tooltip
if (config.isMixedTime()) {
if (myRowTypeList.at(i) == eActual)
rowNum = drawPivotGridRow(rowNum, grid.m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, config.currentDateColumn(), precision);
+ 0, config.currentDateColumn(), precision, false);
else if (myRowTypeList.at(i)== eForecast) {
rowNum = drawPivotGridRow(rowNum, grid.m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- config.currentDateColumn(), numberColumns - config.currentDateColumn(), precision);
+ config.currentDateColumn(), numberColumns - config.currentDateColumn(), precision, false);
} else
rowNum = drawPivotGridRow(rowNum, grid.m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, numberColumns, precision);
+ 0, numberColumns, precision, false);
} else
rowNum = drawPivotGridRow(rowNum, grid.m_total.value(myRowTypeList.at(i)),
config.isChartDataLabels() ? legendText : QString(),
- 0, numberColumns, precision);
+ 0, numberColumns, precision, false);
}
}
break;
default:
case eMyMoney::Report::DetailLevel::End:
return;
}
auto legendRows = legendTotal.values(); // list of legend rows sorted ascending by total value
for (auto i = 0; i < legendRows.count(); ++i) {
const auto ixRow = legendRows.count() - 1 - i; // take row with the highest total value i.e. form the bottom
const auto row = legendRows.at(ixRow);
if ( row != i) { // if legend isn't sorted by total value, then rearrange model
if ((accountSeries() && !seriesTotals()) ||
(seriesTotals() && !accountSeries()))
m_model.insertColumn(i, m_model.takeColumn(row));
else
m_model.insertRow(i, m_model.takeRow(row));
for (auto j = i; j < ixRow; ++j) { // fix invalid indexes after above move operation
if (legendRows.at(j) < row)
++legendRows[j];
}
legendRows[ixRow] = i;
legendNames.move(row, i);
}
}
// Set up X axis labels (ie "abscissa" to use the technical term)
if (accountSeries()) { // if not, we will set these up while putting in the chart values.
QStringList xLabels;
foreach (const auto colHeading, columnHeadings)
xLabels.append(QString(colHeading).replace(QLatin1String(" "), QLatin1String(" ")));
m_model.setVerticalHeaderLabels(xLabels);
}
m_model.setHorizontalHeaderLabels(legendNames);
// set line width for line chart
if (config.chartType() == eMyMoney::Report::ChartType::Line) {
AttributesModel* diagramAttributes = planeDiagram->attributesModel();
int penWidth = config.chartLineWidth();
for (int i = 0 ; i < rowNum ; ++i) {
QPen pen = diagramAttributes->headerData(i, Qt::Horizontal, DatasetPenRole).value< QPen >();
pen.setWidth(penWidth);
m_model.setHeaderData(i, Qt::Horizontal, qVariantFromValue(pen), DatasetPenRole);
}
}
// set the text attributes after calling replaceLegend() otherwise fon sizes will get overwritten
qreal generalFontSize = QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSizeF();
if (generalFontSize == -1)
generalFontSize = 8; // this is a fallback if the fontsize was specified in pixels
// the legend is needed only if at least two data sets are rendered
if (qMin(static_cast(KMyMoneySettings::maximumLegendItems()), rowNum) > 1) {
//the legend will be used later
Legend* legend = new Legend(planeDiagram, this);
legend->setTitleText(i18nc("Chart legend title", "Legend"));
//set the legend basic attributes
//this is done after adding the legend because the values are overridden when adding the legend to the chart
const auto maxLegendItems = KMyMoneySettings::maximumLegendItems();
auto legendItems = legendNames.count();
auto i = 0;
while (legendItems > maxLegendItems) {
legend->setDatasetHidden(legendRows.at(i++), true);
--legendItems;
}
legend->setUseAutomaticMarkerSize(false);
FrameAttributes legendFrameAttr(legend->frameAttributes());
legendFrameAttr.setPen(m_foregroundBrush.color());
// leave some space between the content and the frame
legendFrameAttr.setPadding(2);
legend->setFrameAttributes(legendFrameAttr);
legend->setPosition(Position::East);
legend->setTextAlignment(Qt::AlignLeft);
if (config.isChartDataLabels())
legend->setLegendStyle(KChart::Legend::MarkersAndLines);
else
legend->setLegendStyle(KChart::Legend::LinesOnly);
replaceLegend(legend);
TextAttributes legendTextAttr(legend->textAttributes());
legendTextAttr.setPen(m_foregroundBrush.color());
legendTextAttr.setFontSize(KChart::Measure(generalFontSize, KChartEnums::MeasureCalculationModeAbsolute));
legend->setTextAttributes(legendTextAttr);
TextAttributes legendTitleTextAttr(legend->titleTextAttributes());
legendTitleTextAttr.setPen(m_foregroundBrush.color());
legendTitleTextAttr.setFontSize(KChart::Measure(generalFontSize + 4, KChartEnums::MeasureCalculationModeAbsolute));
legend->setTitleTextAttributes(legendTitleTextAttr);
}
//set data value attributes
//make sure to show only the required number of fractional digits on the labels of the graph
DataValueAttributes dataValueAttr(planeDiagram->dataValueAttributes());
MarkerAttributes markerAttr(dataValueAttr.markerAttributes());
markerAttr.setVisible(true);
markerAttr.setMarkerStyle(MarkerAttributes::MarkerCircle);
dataValueAttr.setMarkerAttributes(markerAttr);
TextAttributes dataValueTextAttr(dataValueAttr.textAttributes());
dataValueTextAttr.setPen(m_foregroundBrush.color());
dataValueTextAttr.setFontSize(KChart::Measure(generalFontSize, KChartEnums::MeasureCalculationModeAbsolute));
dataValueAttr.setTextAttributes(dataValueTextAttr);
m_precision = config.yLabelsPrecision();
dataValueAttr.setDecimalDigits(config.yLabelsPrecision());
dataValueAttr.setVisible(config.isChartDataLabels());
planeDiagram->setDataValueAttributes(dataValueAttr);
planeDiagram->setAllowOverlappingDataValueTexts(true);
m_model.blockSignals(blocked); // reenable dataChanged() signal
//assign model to the diagram
planeDiagram->setModel(&m_model);
// connect needLayoutPlanes, so dimension of chart can be known, so custom Y labels can be generated
connect(cPlane, &KChart::AbstractCoordinatePlane::needLayoutPlanes, this, &KReportChartView::slotNeedUpdate, Qt::QueuedConnection);
}
void KReportChartView::slotNeedUpdate()
{
disconnect(coordinatePlane(), &KChart::AbstractCoordinatePlane::needLayoutPlanes, this, &KReportChartView::slotNeedUpdate); // this won't cause hang-up in KReportsView::slotConfigure
QList grids = coordinatePlane()->gridDimensionsList();
if (grids.isEmpty()) // ring and pie charts have no dimensions
return;
if (grids.at(1).stepWidth == 0) // no labels?
return;
QLocale loc = locale();
QChar separator = loc.groupSeparator();
QChar decimalPoint = loc.decimalPoint();
QStringList labels;
if (m_precision > 10 || m_precision <= 0) // assure that conversion through QLocale::toString() will always work
m_precision = 1;
CartesianCoordinatePlane* cartesianplane = qobject_cast(coordinatePlane());
if (cartesianplane) {
if (cartesianplane->axesCalcModeY() == KChart::AbstractCoordinatePlane::Logarithmic) {
qreal labelValue = qFloor(log10(grids.at(1).start)); // first label is 10 to power of labelValue
/// @todo this might also need some vertical adjustment in case of a horizontal line
/// see below how this has been solved for linear graphs
int labelCount = qFloor(log10(grids.at(1).end)) - qFloor(log10(grids.at(1).start)) + 1;
for (auto i = 0; i < labelCount; ++i) {
labels.append(loc.toString(qPow(10.0, labelValue), 'f', m_precision).remove(separator).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + decimalPoint + "$")));
++labelValue; // next label is 10 to power of previous exponent + 1
}
} else {
qreal labelValue = grids.at(1).start; // first label is start value
qreal step = grids.at(1).stepWidth;
// in case we have a horizontal line, we extend the vertical range around it
if (cartesianplane->verticalRange().first == cartesianplane->verticalRange().second) {
cartesianplane->setVerticalRange(qMakePair(cartesianplane->verticalRange().first - 2,
cartesianplane->verticalRange().first + 2));
grids[1].start -= 2*step;
grids[1].end += 2*step;
labelValue -= 2*step;
}
int labelCount = qFloor((grids.at(1).end - grids.at(1).start) / grids.at(1).stepWidth) + 1;
for (auto i = 0; i < labelCount; ++i) {
labels.append(loc.toString(labelValue, 'f', m_precision).remove(separator).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + decimalPoint + "$")));
labelValue += step; // next label is previous value + step value
}
}
} else
return; // nothing but cartesian plane is handled
KChart::LineDiagram* lineDiagram = qobject_cast(coordinatePlane()->diagram());
if (lineDiagram)
lineDiagram->axes().at(1)->setLabels(labels);
KChart::BarDiagram* barDiagram = qobject_cast(coordinatePlane()->diagram());
if (barDiagram)
barDiagram->axes().at(1)->setLabels(labels);
}
-int KReportChartView::drawPivotGridRow(int rowNum, const PivotGridRow& gridRow, const QString& legendText, const int startColumn, const int columnsToDraw, const int precision)
+int reports::KReportChartView::drawPivotGridRow ( int rowNum, const reports::PivotGridRow& gridRow, const QString& legendText, const int startColumn, const int columnsToDraw, const int precision, const bool invertValue )
{
// Columns
const QString toolTip = QStringLiteral("%1
%2
");
const bool isToolTip = !legendText.isEmpty();
if (seriesTotals()) {
QStandardItem* item = new QStandardItem();
double value = gridRow.m_total.toDouble();
item->setData(QVariant(value), Qt::DisplayRole);
if (isToolTip)
item->setToolTip(toolTip.arg(legendText).arg(value, 0, 'f', precision));
//set the cell value
if (accountSeries()) {
m_model.insertRows(rowNum, 1);
m_model.setItem(rowNum, 0, item);
} else {
m_model.insertColumns(rowNum, 1);
m_model.setItem(0, rowNum, item);
}
} else {
QList itemList;
for (int i = 0; i < startColumn-1; ++i) {
itemList.append(new QStandardItem);
}
for (int i = startColumn; i < startColumn + columnsToDraw; ++i) {
QStandardItem* item = new QStandardItem();
if (!m_skipZero || !gridRow.at(i).isZero()) {
double value = gridRow.at(i).toDouble();
+ if (invertValue)
+ value = -value;
item->setData(QVariant(value), Qt::DisplayRole);
if (isToolTip)
item->setToolTip(toolTip.arg(legendText).arg(value, 0, 'f', precision));
}
itemList.append(item);
}
if (accountSeries())
m_model.appendColumn(itemList);
else
m_model.appendRow(itemList);
}
return ++rowNum;
}
void KReportChartView::setDataCell(int row, int column, const double value, QString tip)
{
QMap cellMap;
cellMap.insert(Qt::DisplayRole, QVariant(value));
if (!tip.isEmpty())
cellMap.insert(Qt::ToolTipRole, QVariant(tip));
const QModelIndex index = m_model.index(row, column);
m_model.setItemData(index, cellMap);
}
/**
* Justifies the model, so that the given rows and columns fit into it.
*/
void KReportChartView::justifyModelSize(int rows, int columns)
{
const int currentRows = m_model.rowCount();
const int currentCols = m_model.columnCount();
if (currentCols < columns)
if (! m_model.insertColumns(currentCols, columns - currentCols))
qDebug() << "justifyModelSize: could not increase model size.";
if (currentRows < rows)
if (! m_model.insertRows(currentRows, rows - currentRows))
qDebug() << "justifyModelSize: could not increase model size.";
Q_ASSERT(m_model.rowCount() >= rows);
Q_ASSERT(m_model.columnCount() >= columns);
}
void KReportChartView::setLineWidth(const int lineWidth)
{
LineDiagram* lineDiagram = qobject_cast(coordinatePlane()->diagram());
if (lineDiagram) {
QList pens;
pens = lineDiagram->datasetPens();
for (int i = 0; i < pens.count(); ++i) {
pens[i].setWidth(lineWidth);
lineDiagram->setPen(i, pens.at(i));
}
}
}
void KReportChartView::drawLimitLine(const double limit)
{
if (coordinatePlane()->diagram()->datasetDimension() != 1)
return;
// temporarily disconnect the view from the model to aovid update of view on
// emission of the dataChanged() signal for each call of setDataCell().
// This speeds up the runtime of drawLimitLine() by a factor of
// approx. 60 on my box (1831ms vs. 31ms).
AbstractDiagram* planeDiagram = coordinatePlane()->diagram();
planeDiagram->setModel(0);
//we get the current number of rows and we add one after that
int row = m_model.rowCount();
justifyModelSize(m_numColumns, row + 1);
for (int col = 0; col < m_numColumns; ++col) {
setDataCell(col, row, limit);
}
planeDiagram->setModel(&m_model);
//TODO: add format to the line
}
void KReportChartView::removeLegend()
{
Legend* chartLegend = Chart::legend();
delete chartLegend;
}
diff --git a/kmymoney/plugins/views/reports/core/kreportchartview.h b/kmymoney/plugins/views/reports/core/kreportchartview.h
index 257e6bd46..2e327357a 100644
--- a/kmymoney/plugins/views/reports/core/kreportchartview.h
+++ b/kmymoney/plugins/views/reports/core/kreportchartview.h
@@ -1,198 +1,199 @@
/*
* Copyright 2005 Ace Jones
* Copyright 2005-2018 Thomas Baumgart
* Copyright 2017-2018 Łukasz Wojniłowicz
+ * Copyright 2018 Michael Kiefer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef KREPORTCHARTVIEW_H
#define KREPORTCHARTVIEW_H
// ----------------------------------------------------------------------------
// QT Includes
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include
// ----------------------------------------------------------------------------
// Project Includes
#include "pivotgrid.h"
#include "mymoneyreport.h"
using namespace KChart;
namespace reports
{
class KReportChartView: public Chart
{
Q_OBJECT
public Q_SLOTS:
void slotNeedUpdate();
public:
explicit KReportChartView(QWidget* parent);
~KReportChartView() {}
/**
* Returns the labels for the X axis
* @see m_abscissaNames
*/
QStringList& abscissaNames() {
return m_abscissaNames;
}
/**
* Draw the chart for a pivot table report
*/
void drawPivotChart(const PivotGrid &grid, const MyMoneyReport &config, int numberColumns, const QStringList& columnHeadings, const QList& rowTypeList, const QStringList& columnTypeHeaderList);
/**
* Draw a limit chart
* @param limit is either a maximum credit or minimum balance for an account
*/
void drawLimitLine(const double limit);
/**
* Remove the chart legend
*/
void removeLegend();
private:
/**
* Draw a PivotGridRow in a chart
*/
- int drawPivotGridRow(int rowNum, const PivotGridRow& gridRow, const QString& legendText, const int startColumn = 0, const int columnsToDraw = 0, const int precision = 2);
+ int drawPivotGridRow(int rowNum, const PivotGridRow& gridRow, const QString& legendText, const int startColumn = 0, const int columnsToDraw = 0, const int precision = 2, const bool invertValue = false);
/**
* Set cell data
*/
void setDataCell(int row, int column, const double value, QString tip = QString());
/**
* Make sure the model has the right size
*/
void justifyModelSize(int rows, int columns);
/**
* Adjust line width of all datasets
*/
void setLineWidth(const int lineWidth);
/**
* Set the accountSeries
* @see m_accountSeries
*/
void setAccountSeries(bool accountSeries) {
m_accountSeries = accountSeries;
}
/**
* Returns accountSeries
* @see m_accountSeries
*/
bool accountSeries() {
return m_accountSeries;
}
/**
* Set the seriesTotals
* @see m_seriesTotals
*/
void setSeriesTotals(bool seriesTotals) {
m_seriesTotals = seriesTotals;
}
/**
* Returns accountSeries
* @see m_seriesTotals
*/
bool seriesTotals() {
return m_seriesTotals;
}
/**
* Set the number of columns
* @see m_numColumns
*/
void setNumColumns(int numColumns) {
m_numColumns = numColumns;
}
/**
* Returns number of columns
* @see m_numColumns
*/
int numColumns() {
return m_numColumns;
}
/**
* The labels of the X axis
*/
QStringList m_abscissaNames;
/**
* whether series (rows) are accounts (true) or months (false). This causes a lot
* of complexity in the charts. The problem is that circular reports work best with
* an account in a COLUMN, while line/bar prefer it in a ROW.
*/
bool m_accountSeries;
/**
* whether to limit the chart to use series totals only. Used for reports which only
* show one dimension (pie)
*/
bool m_seriesTotals;
/**
* Number of columns on the report
*/
int m_numColumns;
/**
* Model to store chart data
*/
QStandardItemModel m_model;
/**
* whether to skip values if zero
*/
bool m_skipZero;
/**
* The cached background brush obtained from the style.
*/
QBrush m_backgroundBrush;
/**
* The cached foreground brush obtained from the style.
*/
QBrush m_foregroundBrush;
/**
* The cached precision obtained from report's data
*/
int m_precision;
};
} // end namespace reports
#endif // KREPORTCHARTVIEW_H
diff --git a/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.cpp b/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.cpp
index 9389e41aa..7553c6681 100644
--- a/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.cpp
+++ b/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.cpp
@@ -1,663 +1,673 @@
/***************************************************************************
kreportconfigurationdlg.cpp - description
-------------------
begin : Mon Jun 21 2004
copyright : (C) 2000-2004 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales
Felix Rodriguez
John C
Thomas Baumgart
Kevin Tambascio
Ace Jones
(C) 2017, 2018 by Łukasz Wojniłowicz
+ 2018 by Michael Kiefer
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "kreportconfigurationfilterdlg.h"
// ----------------------------------------------------------------------------
// QT Includes
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include
#include
// ----------------------------------------------------------------------------
// Project Includes
#include "ktransactionfilter.h"
#include "kmymoneyaccountselector.h"
#include "mymoneyfile.h"
#include "mymoneyexception.h"
#include "mymoneybudget.h"
#include "mymoneyreport.h"
#include "daterangedlg.h"
#include "reporttabimpl.h"
#include "mymoneyenums.h"
#include
#include
#include
#include
#include
#include
#include
#include
class KReportConfigurationFilterDlgPrivate
{
Q_DISABLE_COPY(KReportConfigurationFilterDlgPrivate)
public:
KReportConfigurationFilterDlgPrivate(KReportConfigurationFilterDlg *qq) :
q_ptr(qq),
ui(new Ui::KReportConfigurationFilterDlg),
m_tabRowColPivot(nullptr),
m_tabRowColQuery(nullptr),
m_tabChart(nullptr),
m_tabRange(nullptr),
m_dateRange(nullptr)
{
}
~KReportConfigurationFilterDlgPrivate()
{
delete ui;
}
KReportConfigurationFilterDlg *q_ptr;
Ui::KReportConfigurationFilterDlg *ui;
QPointer m_tabGeneral;
QPointer m_tabRowColPivot;
QPointer m_tabRowColQuery;
QPointer m_tabChart;
QPointer m_tabRange;
QPointer m_tabCapitalGain;
QPointer m_tabPerformance;
QPointer m_tabFilters;
MyMoneyReport m_initialState;
MyMoneyReport m_currentState;
QVector m_budgets;
DateRangeDlg *m_dateRange;
};
KReportConfigurationFilterDlg::KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent) :
QDialog(parent),
d_ptr(new KReportConfigurationFilterDlgPrivate(this))
{
Q_D(KReportConfigurationFilterDlg);
d->ui->setupUi(this);
d->m_initialState = report;
d->m_currentState = report;
//
// Rework labeling
//
setWindowTitle(i18n("Report Configuration"));
//
// Rework the buttons
//
// the Apply button is always enabled
d->ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
d->ui->buttonBox->button(QDialogButtonBox::Apply)->setToolTip(i18nc("@info:tooltip for report configuration apply button", "Apply the configuration changes to the report"));
connect(d->ui->buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &KReportConfigurationFilterDlg::slotSearch);
connect(d->ui->buttonBox->button(QDialogButtonBox::Close), &QAbstractButton::clicked, this, &QDialog::close);
connect(d->ui->buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked, this, &KReportConfigurationFilterDlg::slotReset);
connect(d->ui->buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, this, &KReportConfigurationFilterDlg::slotShowHelp);
//
// Add new tabs
//
if (d->m_initialState.reportType() == eMyMoney::Report::ReportType::PivotTable) {
// we will use date range together with data range
d->m_tabFilters = new KTransactionFilter(this, (report.rowType() == eMyMoney::Report::RowType::Account), false);
} else {
d->m_tabFilters = new KTransactionFilter(this, (report.rowType() == eMyMoney::Report::RowType::Account));
d->m_dateRange = d->m_tabFilters->dateRange();
}
d->ui->m_tabWidget->addTab(d->m_tabFilters, i18nc("Filters tab", "Filters"));
d->m_tabGeneral = new ReportTabGeneral(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(0, d->m_tabGeneral, i18nc("General tab", "General"));
if (d->m_initialState.reportType() == eMyMoney::Report::ReportType::PivotTable) {
int tabNr = 1;
if (!(d->m_initialState.isIncludingPrice() || d->m_initialState.isIncludingAveragePrice())) {
d->m_tabRowColPivot = new ReportTabRowColPivot(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(tabNr++, d->m_tabRowColPivot, i18n("Rows/Columns"));
connect(d->m_tabRowColPivot->ui->m_comboRows, static_cast(&QComboBox::activated), this, static_cast(&KReportConfigurationFilterDlg::slotRowTypeChanged));
connect(d->m_tabRowColPivot->ui->m_comboRows, static_cast(&QComboBox::activated), this, static_cast(&KReportConfigurationFilterDlg::slotUpdateColumnsCombo));
//control the state of the includeTransfer check
connect(d->m_tabFilters->categoriesView(), &KMyMoneySelector::stateChanged, this, &KReportConfigurationFilterDlg::slotUpdateCheckTransfers);
}
d->m_tabChart = new ReportTabChart(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(tabNr++, d->m_tabChart, i18n("Chart"));
d->m_tabRange = new ReportTabRange(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(tabNr++, d->m_tabRange, i18n("Range"));
d->m_dateRange = d->m_tabRange->m_dateRange;
if (!(d->m_initialState.isIncludingPrice() || d->m_initialState.isIncludingAveragePrice())) {
connect(d->m_tabRange->ui->m_comboColumns, static_cast(&QComboBox::activated), this, &KReportConfigurationFilterDlg::slotColumnTypeChanged);
connect(d->m_tabRange->ui->m_comboColumns, static_cast(&QComboBox::activated), this, static_cast(&KReportConfigurationFilterDlg::slotUpdateColumnsCombo));
}
connect(d->m_tabChart->ui->m_logYaxis, &QCheckBox::stateChanged, this, &KReportConfigurationFilterDlg::slotLogAxisChanged);
+ connect(d->m_tabChart->ui->m_negExpenses, &QCheckBox::stateChanged, this, &KReportConfigurationFilterDlg::slotNegExpensesChanged);
} else if (d->m_initialState.reportType() == eMyMoney::Report::ReportType::QueryTable) {
// eInvestmentHoldings is a special-case report, and you cannot configure the
// rows & columns of that report.
if (d->m_initialState.rowType() < eMyMoney::Report::RowType::AccountByTopAccount) {
d->m_tabRowColQuery = new ReportTabRowColQuery(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(1, d->m_tabRowColQuery, i18n("Rows/Columns"));
}
if (d->m_initialState.queryColumns() & eMyMoney::Report::QueryColumn::CapitalGain) {
d->m_tabCapitalGain = new ReportTabCapitalGain(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(1, d->m_tabCapitalGain, i18n("Report"));
}
if (d->m_initialState.queryColumns() & eMyMoney::Report::QueryColumn::Performance) {
d->m_tabPerformance = new ReportTabPerformance(d->ui->m_criteriaTab);
d->ui->m_criteriaTab->insertTab(1, d->m_tabPerformance, i18n("Report"));
}
}
d->ui->m_criteriaTab->setCurrentIndex(d->ui->m_criteriaTab->indexOf(d->m_tabGeneral));
d->ui->m_criteriaTab->setMinimumSize(500, 200);
QList list = MyMoneyFile::instance()->budgetList();
QList::const_iterator it_b;
for (it_b = list.constBegin(); it_b != list.constEnd(); ++it_b) {
d->m_budgets.push_back(*it_b);
}
//
// Now set up the widgets with proper values
//
slotReset();
}
KReportConfigurationFilterDlg::~KReportConfigurationFilterDlg()
{
}
MyMoneyReport KReportConfigurationFilterDlg::getConfig() const
{
Q_D(const KReportConfigurationFilterDlg);
return d->m_currentState;
}
void KReportConfigurationFilterDlg::slotSearch()
{
Q_D(KReportConfigurationFilterDlg);
// setup the filter from the dialog widgets
auto filter = d->m_tabFilters->setupFilter();
// Copy the m_filter over to the filter part of m_currentConfig.
d->m_currentState.assignFilter(filter);
// Then extract the report properties
d->m_currentState.setName(d->m_tabGeneral->ui->m_editName->text());
d->m_currentState.setComment(d->m_tabGeneral->ui->m_editComment->text());
d->m_currentState.setConvertCurrency(d->m_tabGeneral->ui->m_checkCurrency->isChecked());
d->m_currentState.setFavorite(d->m_tabGeneral->ui->m_checkFavorite->isChecked());
d->m_currentState.setSkipZero(d->m_tabGeneral->ui->m_skipZero->isChecked());
if (d->m_tabRowColPivot) {
eMyMoney::Report::DetailLevel dl[4] = { eMyMoney::Report::DetailLevel::All, eMyMoney::Report::DetailLevel::Top, eMyMoney::Report::DetailLevel::Group, eMyMoney::Report::DetailLevel::Total };
d->m_currentState.setDetailLevel(dl[d->m_tabRowColPivot->ui->m_comboDetail->currentIndex()]);
// modify the rowtype only if the widget is enabled
if (d->m_tabRowColPivot->ui->m_comboRows->isEnabled()) {
eMyMoney::Report::RowType rt[2] = { eMyMoney::Report::RowType::ExpenseIncome, eMyMoney::Report::RowType::AssetLiability };
d->m_currentState.setRowType(rt[d->m_tabRowColPivot->ui->m_comboRows->currentIndex()]);
}
d->m_currentState.setShowingRowTotals(false);
if (d->m_tabRowColPivot->ui->m_comboRows->currentIndex() == 0)
d->m_currentState.setShowingRowTotals(d->m_tabRowColPivot->ui->m_checkTotalColumn->isChecked());
d->m_currentState.setShowingColumnTotals(d->m_tabRowColPivot->ui->m_checkTotalRow->isChecked());
d->m_currentState.setIncludingSchedules(d->m_tabRowColPivot->ui->m_checkScheduled->isChecked());
d->m_currentState.setIncludingTransfers(d->m_tabRowColPivot->ui->m_checkTransfers->isChecked());
d->m_currentState.setIncludingUnusedAccounts(d->m_tabRowColPivot->ui->m_checkUnused->isChecked());
if (d->m_tabRowColPivot->ui->m_comboBudget->isEnabled()) {
d->m_currentState.setBudget(d->m_budgets[d->m_tabRowColPivot->ui->m_comboBudget->currentItem()].id(), d->m_initialState.rowType() == eMyMoney::Report::RowType::BudgetActual);
} else {
d->m_currentState.setBudget(QString(), false);
}
//set moving average days
if (d->m_tabRowColPivot->ui->m_movingAverageDays->isEnabled()) {
d->m_currentState.setMovingAverageDays(d->m_tabRowColPivot->ui->m_movingAverageDays->value());
}
} else if (d->m_tabRowColQuery) {
eMyMoney::Report::RowType rtq[8] = { eMyMoney::Report::RowType::Category, eMyMoney::Report::RowType::TopCategory, eMyMoney::Report::RowType::Tag, eMyMoney::Report::RowType::Payee, eMyMoney::Report::RowType::Account, eMyMoney::Report::RowType::TopAccount, eMyMoney::Report::RowType::Month, eMyMoney::Report::RowType::Week };
d->m_currentState.setRowType(rtq[d->m_tabRowColQuery->ui->m_comboOrganizeBy->currentIndex()]);
unsigned qc = eMyMoney::Report::QueryColumn::None;
if (d->m_currentState.queryColumns() & eMyMoney::Report::QueryColumn::Loan)
// once a loan report, always a loan report
qc = eMyMoney::Report::QueryColumn::Loan;
if (d->m_tabRowColQuery->ui->m_checkNumber->isChecked())
qc |= eMyMoney::Report::QueryColumn::Number;
if (d->m_tabRowColQuery->ui->m_checkPayee->isChecked())
qc |= eMyMoney::Report::QueryColumn::Payee;
if (d->m_tabRowColQuery->ui->m_checkTag->isChecked())
qc |= eMyMoney::Report::QueryColumn::Tag;
if (d->m_tabRowColQuery->ui->m_checkCategory->isChecked())
qc |= eMyMoney::Report::QueryColumn::Category;
if (d->m_tabRowColQuery->ui->m_checkMemo->isChecked())
qc |= eMyMoney::Report::QueryColumn::Memo;
if (d->m_tabRowColQuery->ui->m_checkAccount->isChecked())
qc |= eMyMoney::Report::QueryColumn::Account;
if (d->m_tabRowColQuery->ui->m_checkReconciled->isChecked())
qc |= eMyMoney::Report::QueryColumn::Reconciled;
if (d->m_tabRowColQuery->ui->m_checkAction->isChecked())
qc |= eMyMoney::Report::QueryColumn::Action;
if (d->m_tabRowColQuery->ui->m_checkShares->isChecked())
qc |= eMyMoney::Report::QueryColumn::Shares;
if (d->m_tabRowColQuery->ui->m_checkPrice->isChecked())
qc |= eMyMoney::Report::QueryColumn::Price;
if (d->m_tabRowColQuery->ui->m_checkBalance->isChecked())
qc |= eMyMoney::Report::QueryColumn::Balance;
d->m_currentState.setQueryColumns(static_cast(qc));
d->m_currentState.setTax(d->m_tabRowColQuery->ui->m_checkTax->isChecked());
d->m_currentState.setInvestmentsOnly(d->m_tabRowColQuery->ui->m_checkInvestments->isChecked());
d->m_currentState.setLoansOnly(d->m_tabRowColQuery->ui->m_checkLoans->isChecked());
d->m_currentState.setDetailLevel(d->m_tabRowColQuery->ui->m_checkHideSplitDetails->isChecked() ?
eMyMoney::Report::DetailLevel::None : eMyMoney::Report::DetailLevel::All);
d->m_currentState.setHideTransactions(d->m_tabRowColQuery->ui->m_checkHideTransactions->isChecked());
d->m_currentState.setShowingColumnTotals(!d->m_tabRowColQuery->ui->m_checkHideTotals->isChecked());
}
if (d->m_tabChart) {
eMyMoney::Report::ChartType ct[5] = { eMyMoney::Report::ChartType::Line, eMyMoney::Report::ChartType::Bar, eMyMoney::Report::ChartType::StackedBar, eMyMoney::Report::ChartType::Pie, eMyMoney::Report::ChartType::Ring };
d->m_currentState.setChartType(ct[d->m_tabChart->ui->m_comboType->currentIndex()]);
d->m_currentState.setChartCHGridLines(d->m_tabChart->ui->m_checkCHGridLines->isChecked());
d->m_currentState.setChartSVGridLines(d->m_tabChart->ui->m_checkSVGridLines->isChecked());
d->m_currentState.setChartDataLabels(d->m_tabChart->ui->m_checkValues->isChecked());
d->m_currentState.setChartByDefault(d->m_tabChart->ui->m_checkShowChart->isChecked());
d->m_currentState.setChartLineWidth(d->m_tabChart->ui->m_lineWidth->value());
d->m_currentState.setLogYAxis(d->m_tabChart->ui->m_logYaxis->isChecked());
+ d->m_currentState.setNegExpenses(d->m_tabChart->ui->m_negExpenses->isChecked());
}
if (d->m_tabRange) {
d->m_currentState.setDataRangeStart(d->m_tabRange->ui->m_dataRangeStart->text());
d->m_currentState.setDataRangeEnd(d->m_tabRange->ui->m_dataRangeEnd->text());
d->m_currentState.setDataMajorTick(d->m_tabRange->ui->m_dataMajorTick->text());
d->m_currentState.setDataMinorTick(d->m_tabRange->ui->m_dataMinorTick->text());
d->m_currentState.setYLabelsPrecision(d->m_tabRange->ui->m_yLabelsPrecision->value());
d->m_currentState.setDataFilter((eMyMoney::Report::DataLock)d->m_tabRange->ui->m_dataLock->currentIndex());
eMyMoney::Report::ColumnType ct[6] = { eMyMoney::Report::ColumnType::Days, eMyMoney::Report::ColumnType::Weeks, eMyMoney::Report::ColumnType::Months, eMyMoney::Report::ColumnType::BiMonths, eMyMoney::Report::ColumnType::Quarters, eMyMoney::Report::ColumnType::Years };
bool dy[6] = { true, true, false, false, false, false };
d->m_currentState.setColumnType(ct[d->m_tabRange->ui->m_comboColumns->currentIndex()]);
//TODO (Ace) This should be implicit in the call above. MMReport needs fixin'
d->m_currentState.setColumnsAreDays(dy[d->m_tabRange->ui->m_comboColumns->currentIndex()]);
d->m_currentState.setDateFilter(d->m_dateRange->fromDate(), d->m_dateRange->toDate());
}
// setup the date lock
eMyMoney::TransactionFilter::Date range = d->m_dateRange->dateRange();
d->m_currentState.setDateFilter(range);
if (d->m_tabCapitalGain) {
d->m_currentState.setTermSeparator(d->m_tabCapitalGain->ui->m_termSeparator->date());
d->m_currentState.setShowSTLTCapitalGains(d->m_tabCapitalGain->ui->m_showSTLTCapitalGains->isChecked());
d->m_currentState.setSettlementPeriod(d->m_tabCapitalGain->ui->m_settlementPeriod->value());
d->m_currentState.setShowingColumnTotals(!d->m_tabCapitalGain->ui->m_checkHideTotals->isChecked());
d->m_currentState.setInvestmentSum(static_cast(d->m_tabCapitalGain->ui->m_investmentSum->currentData().toInt()));
}
if (d->m_tabPerformance) {
d->m_currentState.setShowingColumnTotals(!d->m_tabPerformance->ui->m_checkHideTotals->isChecked());
d->m_currentState.setInvestmentSum(static_cast(d->m_tabPerformance->ui->m_investmentSum->currentData().toInt()));
}
done(true);
}
void KReportConfigurationFilterDlg::slotRowTypeChanged(int row)
{
Q_D(KReportConfigurationFilterDlg);
d->m_tabRowColPivot->ui->m_checkTotalColumn->setEnabled(row == 0);
}
void KReportConfigurationFilterDlg::slotColumnTypeChanged(int row)
{
Q_D(KReportConfigurationFilterDlg);
if ((d->m_tabRowColPivot->ui->m_comboBudget->isEnabled() && row < 2)) {
d->m_tabRange->ui->m_comboColumns->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false);
}
}
void KReportConfigurationFilterDlg::slotUpdateColumnsCombo()
{
Q_D(KReportConfigurationFilterDlg);
const int monthlyIndex = 2;
const int incomeExpenseIndex = 0;
const bool isIncomeExpenseForecast = d->m_currentState.isIncludingForecast() && d->m_tabRowColPivot->ui->m_comboRows->currentIndex() == incomeExpenseIndex;
if (isIncomeExpenseForecast && d->m_tabRange->ui->m_comboColumns->currentIndex() != monthlyIndex) {
d->m_tabRange->ui->m_comboColumns->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false);
}
}
void KReportConfigurationFilterDlg::slotUpdateColumnsCombo(int)
{
slotUpdateColumnsCombo();
}
void KReportConfigurationFilterDlg::slotLogAxisChanged(int state)
{
Q_D(KReportConfigurationFilterDlg);
if (state == Qt::Checked)
d->m_tabRange->setRangeLogarythmic(true);
else
d->m_tabRange->setRangeLogarythmic(false);
}
+void KReportConfigurationFilterDlg::slotNegExpensesChanged(int state)
+{
+ Q_D(KReportConfigurationFilterDlg);
+ d->m_tabChart->setNegExpenses(state == Qt::Checked);
+}
+
void KReportConfigurationFilterDlg::slotReset()
{
Q_D(KReportConfigurationFilterDlg);
//
// Set up the widget from the initial filter
//
d->m_currentState = d->m_initialState;
//
// Report Properties
//
d->m_tabGeneral->ui->m_editName->setText(d->m_initialState.name());
d->m_tabGeneral->ui->m_editComment->setText(d->m_initialState.comment());
d->m_tabGeneral->ui->m_checkCurrency->setChecked(d->m_initialState.isConvertCurrency());
d->m_tabGeneral->ui->m_checkFavorite->setChecked(d->m_initialState.isFavorite());
if (d->m_initialState.isIncludingPrice() || d->m_initialState.isSkippingZero()) {
d->m_tabGeneral->ui->m_skipZero->setChecked(d->m_initialState.isSkippingZero());
} else {
d->m_tabGeneral->ui->m_skipZero->setEnabled(false);
}
if (d->m_tabRowColPivot) {
KComboBox *combo = d->m_tabRowColPivot->ui->m_comboDetail;
switch (d->m_initialState.detailLevel()) {
case eMyMoney::Report::DetailLevel::None:
case eMyMoney::Report::DetailLevel::End:
case eMyMoney::Report::DetailLevel::All:
combo->setCurrentItem(i18nc("All accounts", "All"), false);
break;
case eMyMoney::Report::DetailLevel::Top:
combo->setCurrentItem(i18n("Top-Level"), false);
break;
case eMyMoney::Report::DetailLevel::Group:
combo->setCurrentItem(i18n("Groups"), false);
break;
case eMyMoney::Report::DetailLevel::Total:
combo->setCurrentItem(i18n("Totals"), false);
break;
}
combo = d->m_tabRowColPivot->ui->m_comboRows;
switch (d->m_initialState.rowType()) {
case eMyMoney::Report::RowType::ExpenseIncome:
case eMyMoney::Report::RowType::Budget:
case eMyMoney::Report::RowType::BudgetActual:
combo->setCurrentItem(i18n("Income & Expenses"), false); // income / expense
break;
default:
combo->setCurrentItem(i18n("Assets & Liabilities"), false); // asset / liability
break;
}
d->m_tabRowColPivot->ui->m_checkTotalColumn->setChecked(d->m_initialState.isShowingRowTotals());
d->m_tabRowColPivot->ui->m_checkTotalRow->setChecked(d->m_initialState.isShowingColumnTotals());
slotRowTypeChanged(combo->currentIndex());
//load budgets combo
if (d->m_initialState.rowType() == eMyMoney::Report::RowType::Budget
|| d->m_initialState.rowType() == eMyMoney::Report::RowType::BudgetActual) {
d->m_tabRowColPivot->ui->m_comboRows->setEnabled(false);
d->m_tabRowColPivot->ui->m_rowsLabel->setEnabled(false);
d->m_tabRowColPivot->ui->m_budgetFrame->setEnabled(!d->m_budgets.empty());
auto i = 0;
for (QVector::const_iterator it_b = d->m_budgets.constBegin(); it_b != d->m_budgets.constEnd(); ++it_b) {
d->m_tabRowColPivot->ui->m_comboBudget->insertItem((*it_b).name(), i);
//set the current selected item
if ((d->m_initialState.budget() == "Any" && (*it_b).budgetStart().year() == QDate::currentDate().year())
|| d->m_initialState.budget() == (*it_b).id())
d->m_tabRowColPivot->ui->m_comboBudget->setCurrentItem(i);
i++;
}
}
//set moving average days spinbox
QSpinBox *spinbox = d->m_tabRowColPivot->ui->m_movingAverageDays;
spinbox->setEnabled(d->m_initialState.isIncludingMovingAverage());
d->m_tabRowColPivot->ui->m_movingAverageLabel->setEnabled(d->m_initialState.isIncludingMovingAverage());
if (d->m_initialState.isIncludingMovingAverage()) {
spinbox->setValue(d->m_initialState.movingAverageDays());
}
d->m_tabRowColPivot->ui->m_checkScheduled->setChecked(d->m_initialState.isIncludingSchedules());
d->m_tabRowColPivot->ui->m_checkTransfers->setChecked(d->m_initialState.isIncludingTransfers());
d->m_tabRowColPivot->ui->m_checkUnused->setChecked(d->m_initialState.isIncludingUnusedAccounts());
} else if (d->m_tabRowColQuery) {
KComboBox *combo = d->m_tabRowColQuery->ui->m_comboOrganizeBy;
switch (d->m_initialState.rowType()) {
case eMyMoney::Report::RowType::NoRows:
case eMyMoney::Report::RowType::Category:
combo->setCurrentItem(i18n("Categories"), false);
break;
case eMyMoney::Report::RowType::TopCategory:
combo->setCurrentItem(i18n("Top Categories"), false);
break;
case eMyMoney::Report::RowType::Tag:
combo->setCurrentItem(i18n("Tags"), false);
break;
case eMyMoney::Report::RowType::Payee:
combo->setCurrentItem(i18n("Payees"), false);
break;
case eMyMoney::Report::RowType::Account:
combo->setCurrentItem(i18n("Accounts"), false);
break;
case eMyMoney::Report::RowType::TopAccount:
combo->setCurrentItem(i18n("Top Accounts"), false);
break;
case eMyMoney::Report::RowType::Month:
combo->setCurrentItem(i18n("Month"), false);
break;
case eMyMoney::Report::RowType::Week:
combo->setCurrentItem(i18n("Week"), false);
break;
default:
throw MYMONEYEXCEPTION_CSTRING("KReportConfigurationFilterDlg::slotReset(): QueryTable report has invalid rowtype");
}
unsigned qc = d->m_initialState.queryColumns();
d->m_tabRowColQuery->ui->m_checkNumber->setChecked(qc & eMyMoney::Report::QueryColumn::Number);
d->m_tabRowColQuery->ui->m_checkPayee->setChecked(qc & eMyMoney::Report::QueryColumn::Payee);
d->m_tabRowColQuery->ui->m_checkTag->setChecked(qc & eMyMoney::Report::QueryColumn::Tag);
d->m_tabRowColQuery->ui->m_checkCategory->setChecked(qc & eMyMoney::Report::QueryColumn::Category);
d->m_tabRowColQuery->ui->m_checkMemo->setChecked(qc & eMyMoney::Report::QueryColumn::Memo);
d->m_tabRowColQuery->ui->m_checkAccount->setChecked(qc & eMyMoney::Report::QueryColumn::Account);
d->m_tabRowColQuery->ui->m_checkReconciled->setChecked(qc & eMyMoney::Report::QueryColumn::Reconciled);
d->m_tabRowColQuery->ui->m_checkAction->setChecked(qc & eMyMoney::Report::QueryColumn::Action);
d->m_tabRowColQuery->ui->m_checkShares->setChecked(qc & eMyMoney::Report::QueryColumn::Shares);
d->m_tabRowColQuery->ui->m_checkPrice->setChecked(qc & eMyMoney::Report::QueryColumn::Price);
d->m_tabRowColQuery->ui->m_checkBalance->setChecked(qc & eMyMoney::Report::QueryColumn::Balance);
d->m_tabRowColQuery->ui->m_checkTax->setChecked(d->m_initialState.isTax());
d->m_tabRowColQuery->ui->m_checkInvestments->setChecked(d->m_initialState.isInvestmentsOnly());
d->m_tabRowColQuery->ui->m_checkLoans->setChecked(d->m_initialState.isLoansOnly());
d->m_tabRowColQuery->ui->m_checkHideTransactions->setChecked(d->m_initialState.isHideTransactions());
d->m_tabRowColQuery->ui->m_checkHideTotals->setChecked(!d->m_initialState.isShowingColumnTotals());
d->m_tabRowColQuery->ui->m_checkHideSplitDetails->setEnabled(!d->m_initialState.isHideTransactions());
d->m_tabRowColQuery->ui->m_checkHideSplitDetails->setChecked
(d->m_initialState.detailLevel() == eMyMoney::Report::DetailLevel::None || d->m_initialState.isHideTransactions());
}
if (d->m_tabChart) {
KMyMoneyGeneralCombo* combo = d->m_tabChart->ui->m_comboType;
switch (d->m_initialState.chartType()) {
case eMyMoney::Report::ChartType::None:
combo->setCurrentItem(static_cast(eMyMoney::Report::ChartType::Line));
break;
case eMyMoney::Report::ChartType::Line:
case eMyMoney::Report::ChartType::Bar:
case eMyMoney::Report::ChartType::StackedBar:
case eMyMoney::Report::ChartType::Pie:
case eMyMoney::Report::ChartType::Ring:
combo->setCurrentItem(static_cast(d->m_initialState.chartType()));
break;
default:
throw MYMONEYEXCEPTION_CSTRING("KReportConfigurationFilterDlg::slotReset(): Report has invalid charttype");
}
d->m_tabChart->ui->m_checkCHGridLines->setChecked(d->m_initialState.isChartCHGridLines());
d->m_tabChart->ui->m_checkSVGridLines->setChecked(d->m_initialState.isChartSVGridLines());
d->m_tabChart->ui->m_checkValues->setChecked(d->m_initialState.isChartDataLabels());
d->m_tabChart->ui->m_checkShowChart->setChecked(d->m_initialState.isChartByDefault());
d->m_tabChart->ui->m_lineWidth->setValue(d->m_initialState.chartLineWidth());
d->m_tabChart->ui->m_logYaxis->setChecked(d->m_initialState.isLogYAxis());
+ d->m_tabChart->ui->m_negExpenses->setChecked(d->m_initialState.isNegExpenses());
}
if (d->m_tabRange) {
d->m_tabRange->ui->m_dataRangeStart->setText(d->m_initialState.dataRangeStart());
d->m_tabRange->ui->m_dataRangeEnd->setText(d->m_initialState.dataRangeEnd());
d->m_tabRange->ui->m_dataMajorTick->setText(d->m_initialState.dataMajorTick());
d->m_tabRange->ui->m_dataMinorTick->setText(d->m_initialState.dataMinorTick());
d->m_tabRange->ui->m_yLabelsPrecision->setValue(d->m_initialState.yLabelsPrecision());
d->m_tabRange->ui->m_dataLock->setCurrentIndex((int)d->m_initialState.dataFilter());
KComboBox *combo = d->m_tabRange->ui->m_comboColumns;
if (d->m_initialState.isColumnsAreDays()) {
switch (d->m_initialState.columnType()) {
case eMyMoney::Report::ColumnType::NoColumns:
case eMyMoney::Report::ColumnType::Days:
combo->setCurrentItem(i18nc("@item the columns will display daily data", "Daily"), false);
break;
case eMyMoney::Report::ColumnType::Weeks:
combo->setCurrentItem(i18nc("@item the columns will display weekly data", "Weekly"), false);
break;
default:
break;
}
} else {
switch (d->m_initialState.columnType()) {
case eMyMoney::Report::ColumnType::NoColumns:
case eMyMoney::Report::ColumnType::Months:
combo->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false);
break;
case eMyMoney::Report::ColumnType::BiMonths:
combo->setCurrentItem(i18nc("@item the columns will display bi-monthly data", "Bi-Monthly"), false);
break;
case eMyMoney::Report::ColumnType::Quarters:
combo->setCurrentItem(i18nc("@item the columns will display quarterly data", "Quarterly"), false);
break;
case eMyMoney::Report::ColumnType::Years:
combo->setCurrentItem(i18nc("@item the columns will display yearly data", "Yearly"), false);
break;
default:
break;
}
}
}
if (d->m_tabCapitalGain) {
d->m_tabCapitalGain->ui->m_termSeparator->setDate(d->m_initialState.termSeparator());
d->m_tabCapitalGain->ui->m_showSTLTCapitalGains->setChecked(d->m_initialState.isShowingSTLTCapitalGains());
d->m_tabCapitalGain->ui->m_settlementPeriod->setValue(d->m_initialState.settlementPeriod());
d->m_tabCapitalGain->ui->m_checkHideTotals->setChecked(!d->m_initialState.isShowingColumnTotals());
d->m_tabCapitalGain->ui->m_investmentSum->blockSignals(true);
d->m_tabCapitalGain->ui->m_investmentSum->clear();
d->m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only owned"), static_cast(eMyMoney::Report::InvestmentSum::Owned));
d->m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only sold"), static_cast(eMyMoney::Report::InvestmentSum::Sold));
d->m_tabCapitalGain->ui->m_investmentSum->blockSignals(false);
d->m_tabCapitalGain->ui->m_investmentSum->setCurrentIndex(d->m_tabCapitalGain->ui->m_investmentSum->findData(static_cast(d->m_initialState.investmentSum())));
}
if (d->m_tabPerformance) {
d->m_tabPerformance->ui->m_checkHideTotals->setChecked(!d->m_initialState.isShowingColumnTotals());
d->m_tabPerformance->ui->m_investmentSum->blockSignals(true);
d->m_tabPerformance->ui->m_investmentSum->clear();
d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("From period"), static_cast(eMyMoney::Report::InvestmentSum::Period));
d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("Owned and sold"), static_cast(eMyMoney::Report::InvestmentSum::OwnedAndSold));
d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only owned"), static_cast(eMyMoney::Report::InvestmentSum::Owned));
d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only sold"), static_cast(eMyMoney::Report::InvestmentSum::Sold));
d->m_tabPerformance->ui->m_investmentSum->blockSignals(false);
d->m_tabPerformance->ui->m_investmentSum->setCurrentIndex(d->m_tabPerformance->ui->m_investmentSum->findData(static_cast(d->m_initialState.investmentSum())));
}
d->m_tabFilters->resetFilter(d->m_initialState);
if (d->m_dateRange) {
d->m_initialState.updateDateFilter();
QDate dateFrom, dateTo;
if (d->m_initialState.dateFilter(dateFrom, dateTo)) {
if (d->m_initialState.isDateUserDefined()) {
d->m_dateRange->setDateRange(dateFrom, dateTo);
} else {
d->m_dateRange->setDateRange(d->m_initialState.dateRange());
}
} else {
d->m_dateRange->setDateRange(eMyMoney::TransactionFilter::Date::All);
}
}
}
void KReportConfigurationFilterDlg::slotShowHelp()
{
Q_D(KReportConfigurationFilterDlg);
if (d->ui->m_tabWidget->currentIndex() == 1)
d->m_tabFilters->slotShowHelp();
else
KHelpClient::invokeHelp("details.reports.config");
}
//TODO Fix the reports and engine to include transfers even if categories are filtered - bug #1523508
void KReportConfigurationFilterDlg::slotUpdateCheckTransfers()
{
Q_D(KReportConfigurationFilterDlg);
auto cb = d->m_tabRowColPivot->ui->m_checkTransfers;
if (!d->m_tabFilters->categoriesView()->allItemsSelected()) {
cb->setChecked(false);
cb->setDisabled(true);
} else {
cb->setEnabled(true);
}
}
diff --git a/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.h b/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.h
index a9d1cf94c..a39637b59 100644
--- a/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.h
+++ b/kmymoney/plugins/views/reports/kreportconfigurationfilterdlg.h
@@ -1,74 +1,76 @@
/***************************************************************************
kreportconfigurationdlg.h - description
-------------------
begin : Mon Jun 21 2004
copyright : (C) 2000-2004 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales
Felix Rodriguez
John C
Thomas Baumgart
Kevin Tambascio
Ace Jones
(C) 2017, 2018 by Łukasz Wojniłowicz
+ 2018 by Michael Kiefer
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef KREPORTCONFIGURATIONFILTERDLG_H
#define KREPORTCONFIGURATIONFILTERDLG_H
// ----------------------------------------------------------------------------
// QT Includes
#include
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
//#include "kfindtransactiondlg.h"
class MyMoneyReport;
/**
* @author Ace Jones
* @author Łukasz Wojniłowicz
*/
class KReportConfigurationFilterDlgPrivate;
class KReportConfigurationFilterDlg : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(KReportConfigurationFilterDlg)
public:
explicit KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent = nullptr);
~KReportConfigurationFilterDlg();
MyMoneyReport getConfig() const;
protected Q_SLOTS:
void slotRowTypeChanged(int);
void slotColumnTypeChanged(int);
void slotReset();
void slotSearch();
void slotShowHelp();
void slotUpdateCheckTransfers();
void slotUpdateColumnsCombo();
void slotUpdateColumnsCombo(int idx);
void slotLogAxisChanged(int state);
+ void slotNegExpensesChanged(int state);
private:
Q_DECLARE_PRIVATE(KReportConfigurationFilterDlg)
KReportConfigurationFilterDlgPrivate * const d_ptr;
};
#endif
diff --git a/kmymoney/plugins/views/reports/kreportsview_p.h b/kmymoney/plugins/views/reports/kreportsview_p.h
index be8297475..e8282eaae 100644
--- a/kmymoney/plugins/views/reports/kreportsview_p.h
+++ b/kmymoney/plugins/views/reports/kreportsview_p.h
@@ -1,1451 +1,1465 @@
/***************************************************************************
kreportsview_p.h - description
-------------------
begin : Sat Mar 27 2004
copyright : (C) 2000-2004 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales
Felix Rodriguez
John C
Thomas Baumgart
Kevin Tambascio
Ace Jones
(C) 2017 Łukasz Wojniłowicz
+ 2018 Michael Kiefer
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef KREPORTSVIEW_P_H
#define KREPORTSVIEW_P_H
#include "kreportsview.h"
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef ENABLE_WEBENGINE
#include
#else
#include
#endif
// ----------------------------------------------------------------------------
// KDE Includes
#include
#include
#include
// ----------------------------------------------------------------------------
// Project Includes
#include "ui_reportcontrol.h"
#include "kmymoneyviewbase_p.h"
#include "kreportconfigurationfilterdlg.h"
#include "mymoneyfile.h"
#include "mymoneyreport.h"
#include "mymoneyexception.h"
#include "kmymoneysettings.h"
#include "querytable.h"
#include "objectinfotable.h"
#include "icons/icons.h"
#include
#include "tocitem.h"
#include "tocitemgroup.h"
#include "tocitemreport.h"
#include "kreportchartview.h"
#include "pivottable.h"
#include "reporttable.h"
#include "reportcontrolimpl.h"
#include "mymoneyenums.h"
using namespace reports;
using namespace eMyMoney;
using namespace Icons;
#define VIEW_LEDGER "ledger"
#define VIEW_SCHEDULE "schedule"
#define VIEW_WELCOME "welcome"
#define VIEW_HOME "home"
#define VIEW_REPORTS "reports"
/**
* Helper class for KReportView.
*
* This is the widget which displays a single report in the TabWidget that comprises this view.
*
* @author Ace Jones
*/
class KReportTab: public QWidget
{
private:
#ifdef ENABLE_WEBENGINE
QWebEngineView *m_tableView;
#else
KWebView *m_tableView;
#endif
reports::KReportChartView *m_chartView;
ReportControl *m_control;
QVBoxLayout *m_layout;
QPrinter *m_currentPrinter;
MyMoneyReport m_report;
bool m_deleteMe;
bool m_chartEnabled;
bool m_showingChart;
bool m_needReload;
bool m_isChartViewValid;
bool m_isTableViewValid;
QPointer m_table;
/**
* Users character set encoding.
*/
QByteArray m_encoding;
public:
KReportTab(QTabWidget* parent, const MyMoneyReport& report, const KReportsView *eventHandler);
~KReportTab();
const MyMoneyReport& report() const {
return m_report;
}
void print();
void toggleChart();
/**
* Updates information about plotted chart in report's data
*/
void updateDataRange();
void copyToClipboard();
void saveAs(const QString& filename, bool includeCSS = false);
void updateReport();
QString createTable(const QString& links = QString());
const ReportControl* control() const {
return m_control;
}
bool isReadyToDelete() const {
return m_deleteMe;
}
void setReadyToDelete(bool f) {
m_deleteMe = f;
}
void modifyReport(const MyMoneyReport& report) {
m_report = report;
}
void showEvent(QShowEvent * event) final override;
void loadTab();
};
/**
* Helper class for KReportView.
*
* This is a named list of reports, which will be one section
* in the list of default reports
*
* @author Ace Jones
*/
class ReportGroup: public QList
{
private:
QString m_name; ///< the title of the group in non-translated form
QString m_title; ///< the title of the group in i18n-ed form
public:
ReportGroup() {}
ReportGroup(const QString& name, const QString& title): m_name(name), m_title(title) {}
const QString& name() const {
return m_name;
}
const QString& title() const {
return m_title;
}
};
/**
* KReportTab Implementation
*/
KReportTab::KReportTab(QTabWidget* parent, const MyMoneyReport& report, const KReportsView* eventHandler):
QWidget(parent),
#ifdef ENABLE_WEBENGINE
m_tableView(new QWebEngineView(this)),
#else
m_tableView(new KWebView(this)),
#endif
m_chartView(new KReportChartView(this)),
m_control(new ReportControl(this)),
m_layout(new QVBoxLayout(this)),
m_currentPrinter(nullptr),
m_report(report),
m_deleteMe(false),
m_chartEnabled(false),
m_showingChart(report.isChartByDefault()),
m_needReload(true),
m_isChartViewValid(false),
m_isTableViewValid(false),
m_table(0)
{
m_layout->setSpacing(6);
m_tableView->setPage(new MyQWebEnginePage(m_tableView));
m_tableView->setZoomFactor(KMyMoneySettings::zoomFactor());
//set button icons
m_control->ui->buttonChart->setIcon(Icons::get(Icon::OfficeChartLine));
m_control->ui->buttonClose->setIcon(Icons::get(Icon::DocumentClose));
m_control->ui->buttonConfigure->setIcon(Icons::get(Icon::Configure));
m_control->ui->buttonCopy->setIcon(Icons::get(Icon::EditCopy));
m_control->ui->buttonDelete->setIcon(Icons::get(Icon::EditDelete));
m_control->ui->buttonExport->setIcon(Icons::get(Icon::DocumentExport));
m_control->ui->buttonNew->setIcon(Icons::get(Icon::DocumentNew));
m_chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_chartView->hide();
m_tableView->hide();
m_layout->addWidget(m_control);
m_layout->addWidget(m_tableView);
m_layout->addWidget(m_chartView);
m_layout->setStretch(1, 10);
m_layout->setStretch(2, 10);
connect(m_control->ui->buttonChart, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotToggleChart);
connect(m_control->ui->buttonConfigure, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotConfigure);
connect(m_control->ui->buttonNew, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotDuplicate);
connect(m_control->ui->buttonCopy, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotCopyView);
connect(m_control->ui->buttonExport, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotSaveView);
connect(m_control->ui->buttonDelete, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotDelete);
connect(m_control->ui->buttonClose, &QAbstractButton::clicked,
eventHandler, &KReportsView::slotCloseCurrent);
#ifdef ENABLE_WEBENGINE
connect(m_tableView->page(), &QWebEnginePage::urlChanged,
eventHandler, &KReportsView::slotOpenUrl);
#else
m_tableView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
connect(m_tableView->page(), &KWebPage::linkClicked,
eventHandler, &KReportsView::slotOpenUrl);
#endif
// if this is a default report, then you can't delete it!
if (report.id().isEmpty())
m_control->ui->buttonDelete->setEnabled(false);
int tabNr = parent->addTab(this,
Icons::get(Icon::Spreadsheet),
report.name());
parent->setTabEnabled(tabNr, true);
parent->setCurrentIndex(tabNr);
// get users character set encoding
m_encoding = QTextCodec::codecForLocale()->name();
}
KReportTab::~KReportTab()
{
delete m_table;
}
void KReportTab::print()
{
if (m_tableView) {
m_currentPrinter = new QPrinter();
QPointer dialog = new QPrintDialog(m_currentPrinter, this);
dialog->setWindowTitle(QString());
if (dialog->exec() != QDialog::Accepted) {
delete m_currentPrinter;
m_currentPrinter = nullptr;
return;
}
#ifdef ENABLE_WEBENGINE
m_tableView->page()->print(m_currentPrinter, [=] (bool) {delete m_currentPrinter; m_currentPrinter = nullptr;});
#else
m_tableView->print(m_currentPrinter);
#endif
}
}
void KReportTab::copyToClipboard()
{
QMimeData* pMimeData = new QMimeData();
pMimeData->setHtml(m_table->renderReport(QLatin1String("html"), m_encoding, m_report.name(), true));
QApplication::clipboard()->setMimeData(pMimeData);
}
void KReportTab::saveAs(const QString& filename, bool includeCSS)
{
QFile file(filename);
if (file.open(QIODevice::WriteOnly)) {
if (QFileInfo(filename).suffix().toLower() == QLatin1String("csv")) {
QTextStream(&file) << m_table->renderReport(QLatin1String("csv"), m_encoding, QString());
} else {
QString table =
m_table->renderReport(QLatin1String("html"), m_encoding, m_report.name(), includeCSS);
QTextStream stream(&file);
stream << table;
}
file.close();
}
}
void KReportTab::loadTab()
{
m_needReload = true;
if (isVisible()) {
m_needReload = false;
updateReport();
}
}
void KReportTab::showEvent(QShowEvent * event)
{
if (m_needReload) {
m_needReload = false;
updateReport();
}
QWidget::showEvent(event);
}
void KReportTab::updateReport()
{
m_isChartViewValid = false;
m_isTableViewValid = false;
// reload the report from the engine. It might have
// been changed by the user
try {
// Don't try to reload default reports from the engine
if (!m_report.id().isEmpty())
m_report = MyMoneyFile::instance()->report(m_report.id());
} catch (const MyMoneyException &) {
}
delete m_table;
m_table = 0;
if (m_report.reportType() == eMyMoney::Report::ReportType::PivotTable) {
m_table = new PivotTable(m_report);
m_chartEnabled = true;
} else if (m_report.reportType() == eMyMoney::Report::ReportType::QueryTable) {
m_table = new QueryTable(m_report);
m_chartEnabled = false;
} else if (m_report.reportType() == eMyMoney::Report::ReportType::InfoTable) {
m_table = new ObjectInfoTable(m_report);
m_chartEnabled = false;
}
m_control->ui->buttonChart->setEnabled(m_chartEnabled);
m_showingChart = !m_showingChart;
toggleChart();
}
void KReportTab::toggleChart()
{
// for now it will just SHOW the chart. In the future it actually has to toggle it.
if (m_showingChart) {
if (!m_isTableViewValid) {
m_tableView->setHtml(m_table->renderReport(QLatin1String("html"), m_encoding, m_report.name()),
QUrl("file://")); // workaround for access permission to css file
}
m_isTableViewValid = true;
m_tableView->show();
m_chartView->hide();
m_control->ui->buttonChart->setText(i18n("Chart"));
m_control->ui->buttonChart->setToolTip(i18n("Show the chart version of this report"));
m_control->ui->buttonChart->setIcon(Icons::get(Icon::OfficeChartLine));
} else {
if (!m_isChartViewValid)
m_table->drawChart(*m_chartView);
m_isChartViewValid = true;
m_tableView->hide();
m_chartView->show();
m_control->ui->buttonChart->setText(i18n("Report"));
m_control->ui->buttonChart->setToolTip(i18n("Show the report version of this chart"));
m_control->ui->buttonChart->setIcon(Icons::get(Icon::ViewFinancialList));
}
m_showingChart = ! m_showingChart;
}
void KReportTab::updateDataRange()
{
QList grids = m_chartView->coordinatePlane()->gridDimensionsList(); // get dimensions of plotted graph
if (grids.isEmpty())
return;
QChar separator = locale().groupSeparator();
QChar decimalPoint = locale().decimalPoint();
int precision = m_report.yLabelsPrecision();
QList> dims; // create list of dimension values in string and qreal
// get qreal values
dims.append(qMakePair(QString(), grids.at(1).start));
dims.append(qMakePair(QString(), grids.at(1).end));
dims.append(qMakePair(QString(), grids.at(1).stepWidth));
dims.append(qMakePair(QString(), grids.at(1).subStepWidth));
// convert qreal values to string variables
for (int i = 0; i < 4; ++i) {
if (i > 2)
++precision;
if (precision == 0)
dims[i].first = locale().toString(qRound(dims.at(i).second));
else
dims[i].first = locale().toString(dims.at(i).second, 'f', precision).remove(separator).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + decimalPoint + "$"));
}
// save string variables in report's data
m_report.setDataRangeStart(dims.at(0).first);
m_report.setDataRangeEnd(dims.at(1).first);
m_report.setDataMajorTick(dims.at(2).first);
m_report.setDataMinorTick(dims.at(3).first);
}
class KReportsViewPrivate : public KMyMoneyViewBasePrivate
{
Q_DECLARE_PUBLIC(KReportsView)
public:
explicit KReportsViewPrivate(KReportsView *qq):
q_ptr(qq),
m_needLoad(true),
m_reportListView(nullptr),
m_reportTabWidget(nullptr),
m_listTab(nullptr),
m_listTabLayout(nullptr),
m_tocTreeWidget(nullptr),
m_columnsAlreadyAdjusted(false)
{
}
~KReportsViewPrivate()
{
}
void init()
{
Q_Q(KReportsView);
m_needLoad = false;
auto vbox = new QVBoxLayout(q);
q->setLayout(vbox);
vbox->setSpacing(6);
vbox->setMargin(0);
// build reports toc
setColumnsAlreadyAdjusted(false);
m_reportTabWidget = new QTabWidget(q);
vbox->addWidget(m_reportTabWidget);
m_reportTabWidget->setTabsClosable(true);
m_listTab = new QWidget(m_reportTabWidget);
m_listTabLayout = new QVBoxLayout(m_listTab);
m_listTabLayout->setSpacing(6);
m_tocTreeWidget = new QTreeWidget(m_listTab);
// report-group items have only 1 column (name of group),
// report items have 2 columns (report name and comment)
m_tocTreeWidget->setColumnCount(2);
// headers
QStringList headers;
headers << i18n("Reports") << i18n("Comment");
m_tocTreeWidget->setHeaderLabels(headers);
m_tocTreeWidget->setAlternatingRowColors(true);
m_tocTreeWidget->setSortingEnabled(true);
m_tocTreeWidget->sortByColumn(0, Qt::AscendingOrder);
// for report group items:
// doubleclick toggles the expand-state,
m_tocTreeWidget->setExpandsOnDoubleClick(false);
m_tocTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
m_tocTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_listTabLayout->addWidget(m_tocTreeWidget);
m_reportTabWidget->addTab(m_listTab, i18n("Reports"));
q->connect(m_reportTabWidget, &QTabWidget::tabCloseRequested,
q, &KReportsView::slotClose);
q->connect(m_tocTreeWidget, &QTreeWidget::itemDoubleClicked,
q, &KReportsView::slotItemDoubleClicked);
q->connect(m_tocTreeWidget, &QWidget::customContextMenuRequested,
q, &KReportsView::slotListContextMenu);
q->connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, q, &KReportsView::refresh);
}
void restoreTocExpandState(QMap& expandStates)
{
for (auto i = 0; i < m_tocTreeWidget->topLevelItemCount(); ++i) {
QTreeWidgetItem* item = m_tocTreeWidget->topLevelItem(i);
if (item) {
QString itemLabel = item->text(0);
if (expandStates.contains(itemLabel)) {
item->setExpanded(expandStates[itemLabel]);
} else {
item->setExpanded(false);
}
}
}
}
/**
* Display a dialog to confirm report deletion
*/
int deleteReportDialog(const QString &reportName)
{
Q_Q(KReportsView);
return KMessageBox::warningContinueCancel(q,
i18n("Are you sure you want to delete report %1? There is no way to recover it.",
reportName), i18n("Delete Report?"));
}
void addReportTab(const MyMoneyReport& report)
{
Q_Q(KReportsView);
new KReportTab(m_reportTabWidget, report, q);
}
void loadView()
{
// remember the id of the current selected item
QTreeWidgetItem* item = m_tocTreeWidget->currentItem();
QString selectedItem = (item) ? item->text(0) : QString();
// save expand states of all top-level items
QMap expandStates;
for (int i = 0; i < m_tocTreeWidget->topLevelItemCount(); ++i) {
item = m_tocTreeWidget->topLevelItem(i);
if (item) {
QString itemLabel = item->text(0);
if (item->isExpanded()) {
expandStates.insert(itemLabel, true);
} else {
expandStates.insert(itemLabel, false);
}
}
}
// find the item visible on top
QTreeWidgetItem* visibleTopItem = m_tocTreeWidget->itemAt(0, 0);
// text of column 0 identifies the item visible on top
QString visibleTopItemText;
bool visibleTopItemFound = true;
if (visibleTopItem == NULL) {
visibleTopItemFound = false;
} else {
// this assumes, that all item-texts in column 0 are unique,
// no matter, whether the item is a report- or a group-item
visibleTopItemText = visibleTopItem->text(0);
}
// turn off updates to avoid flickering during reload
//m_reportListView->setUpdatesEnabled(false);
//
// Rebuild the list page
//
m_tocTreeWidget->clear();
// Default Reports
QList defaultreports;
defaultReports(defaultreports);
QList::const_iterator it_group = defaultreports.constBegin();
// the item to be set as current item
QTreeWidgetItem* currentItem = 0L;
// group number, this will be used as sort key for reportgroup items
// we have:
// 1st some default groups
// 2nd a chart group
// 3rd maybe a favorite group
// 4th maybe an orphan group (for old reports)
int defaultGroupNo = 1;
int chartGroupNo = defaultreports.size() + 1;
// group for diagrams
QString groupName = I18N_NOOP("Charts");
TocItemGroup* chartTocItemGroup =
new TocItemGroup(m_tocTreeWidget, chartGroupNo,
i18n(groupName.toLatin1().data()));
m_allTocItemGroups.insert(groupName, chartTocItemGroup);
while (it_group != defaultreports.constEnd()) {
groupName = (*it_group).name();
TocItemGroup* defaultTocItemGroup =
new TocItemGroup(m_tocTreeWidget, defaultGroupNo++,
i18n(groupName.toLatin1().data()));
m_allTocItemGroups.insert(groupName, defaultTocItemGroup);
if (groupName == selectedItem) {
currentItem = defaultTocItemGroup;
}
QList::const_iterator it_report = (*it_group).begin();
while (it_report != (*it_group).end()) {
MyMoneyReport report = *it_report;
report.setGroup(groupName);
TocItemReport* reportTocItemReport =
new TocItemReport(defaultTocItemGroup, report);
if (report.name() == selectedItem) {
currentItem = reportTocItemReport;
}
// ALSO place it into the Charts list if it's displayed as a chart by default
if (report.isChartByDefault()) {
new TocItemReport(chartTocItemGroup, report);
}
++it_report;
}
++it_group;
}
// group for custom (favorite) reports
int favoriteGroupNo = chartGroupNo + 1;
groupName = I18N_NOOP("Favorite Reports");
TocItemGroup* favoriteTocItemGroup =
new TocItemGroup(m_tocTreeWidget, favoriteGroupNo,
i18n(groupName.toLatin1().data()));
m_allTocItemGroups.insert(groupName, favoriteTocItemGroup);
TocItemGroup* orphanTocItemGroup = 0;
QList customreports = MyMoneyFile::instance()->reportList();
QList::const_iterator it_report = customreports.constBegin();
while (it_report != customreports.constEnd()) {
MyMoneyReport report = *it_report;
groupName = (*it_report).group();
// If this report is in a known group, place it there
// KReportGroupListItem* groupnode = groupitems[(*it_report).group()];
TocItemGroup* groupNode = m_allTocItemGroups[groupName];
if (groupNode) {
new TocItemReport(groupNode, report);
} else {
// otherwise, place it in the orphanage
if (!orphanTocItemGroup) {
// group for orphaned reports
int orphanGroupNo = favoriteGroupNo + 1;
groupName = I18N_NOOP("Old Customized Reports");
orphanTocItemGroup =
new TocItemGroup(m_tocTreeWidget, orphanGroupNo,
i18n(groupName.toLatin1().data()));
m_allTocItemGroups.insert(groupName, orphanTocItemGroup);
}
new TocItemReport(orphanTocItemGroup, report);
}
// ALSO place it into the Favorites list if it's a favorite
if ((*it_report).isFavorite()) {
new TocItemReport(favoriteTocItemGroup, report);
}
// ALSO place it into the Charts list if it's displayed as a chart by default
if ((*it_report).isChartByDefault()) {
new TocItemReport(chartTocItemGroup, report);
}
++it_report;
}
//
// Go through the tabs to set their update flag or delete them if needed
//
int index = 1;
while (index < m_reportTabWidget->count()) {
// TODO: Find some way of detecting the file is closed and kill these tabs!!
if (auto tab = dynamic_cast(m_reportTabWidget->widget(index))) {
if (tab->isReadyToDelete() /* || ! reports.count() */) {
delete tab;
--index;
} else {
tab->loadTab();
}
}
++index;
}
if (visibleTopItemFound) {
// try to find the visibleTopItem that we had at the start of this method
// intentionally not using 'Qt::MatchCaseSensitive' here
// to avoid 'item not found' if someone corrected a typo only
QList visibleTopItemList =
m_tocTreeWidget->findItems(visibleTopItemText,
Qt::MatchFixedString |
Qt::MatchRecursive);
if (visibleTopItemList.isEmpty()) {
// the item could not be found, it was deleted or renamed
visibleTopItemFound = false;
} else {
visibleTopItem = visibleTopItemList.at(0);
if (visibleTopItem == NULL) {
visibleTopItemFound = false;
}
}
}
// adjust column widths,
// but only the first time when the view is loaded,
// maybe the user sets other column widths later,
// so don't disturb him
if (columnsAlreadyAdjusted()) {
// restore expand states of all top-level items
restoreTocExpandState(expandStates);
// restore current item
m_tocTreeWidget->setCurrentItem(currentItem);
// try to scroll to the item visible on top
// when this method started
if (visibleTopItemFound) {
m_tocTreeWidget->scrollToItem(visibleTopItem);
} else {
m_tocTreeWidget->scrollToTop();
}
return;
}
// avoid flickering
m_tocTreeWidget->setUpdatesEnabled(false);
// expand all top-level items
m_tocTreeWidget->expandAll();
// resize columns
m_tocTreeWidget->resizeColumnToContents(0);
m_tocTreeWidget->resizeColumnToContents(1);
// restore expand states of all top-level items
restoreTocExpandState(expandStates);
// restore current item
m_tocTreeWidget->setCurrentItem(currentItem);
// try to scroll to the item visible on top
// when this method started
if (visibleTopItemFound) {
m_tocTreeWidget->scrollToItem(visibleTopItem);
} else {
m_tocTreeWidget->scrollToTop();
}
setColumnsAlreadyAdjusted(true);
m_tocTreeWidget->setUpdatesEnabled(true);
}
void defaultReports(QList& groups)
{
{
ReportGroup list("Income and Expenses", i18n("Income and Expenses"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::ExpenseIncome,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentMonth,
eMyMoney::Report::DetailLevel::All,
i18n("Income and Expenses This Month"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::ExpenseIncome,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Income and Expenses This Year"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::ExpenseIncome,
static_cast(eMyMoney::Report::ColumnType::Years),
TransactionFilter::Date::All,
eMyMoney::Report::DetailLevel::All,
i18n("Income and Expenses By Year"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::ExpenseIncome,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last12Months,
eMyMoney::Report::DetailLevel::Top,
i18n("Income and Expenses Graph"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.back().setChartDataLabels(false);
+ list.push_back(MyMoneyReport(
+ eMyMoney::Report::RowType::ExpenseIncome,
+ static_cast(eMyMoney::Report::ColumnType::Months),
+ TransactionFilter::Date::Last12Months,
+ eMyMoney::Report::DetailLevel::Top,
+ i18n("Income and Expenses Bar Graph"),
+ i18n("Default Report")
+ ));
+ list.back().setChartByDefault(true);
+ list.back().setChartType(eMyMoney::Report::ChartType::StackedBar);
+ list.back().setChartDataLabels(false);
+ list.back().setNegExpenses(true);
+
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::ExpenseIncome,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::Group,
i18n("Income and Expenses Pie Chart"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartType(eMyMoney::Report::ChartType::Pie);
list.back().setShowingRowTotals(false);
groups.push_back(list);
}
{
ReportGroup list("Net Worth", i18n("Net Worth"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::Top,
i18n("Net Worth By Month"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Today,
eMyMoney::Report::DetailLevel::Top,
i18n("Net Worth Today"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Years),
TransactionFilter::Date::All,
eMyMoney::Report::DetailLevel::Top,
i18n("Net Worth By Year"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Next7Days,
eMyMoney::Report::DetailLevel::Top,
i18n("7-day Cash Flow Forecast"),
i18n("Default Report")
));
list.back().setIncludingSchedules(true);
list.back().setColumnsAreDays(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last12Months,
eMyMoney::Report::DetailLevel::Total,
i18n("Net Worth Graph"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Institution,
eMyMoney::Report::QueryColumn::None,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::Top,
i18n("Account Balances by Institution"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountType,
eMyMoney::Report::QueryColumn::None,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::Top,
i18n("Account Balances by Type"),
i18n("Default Report")
));
groups.push_back(list);
}
{
ReportGroup list("Transactions", i18n("Transactions"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Account,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Tag | eMyMoney::Report::QueryColumn::Balance,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Account"),
i18n("Default Report")
));
//list.back().setConvertCurrency(false);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Category,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Account | eMyMoney::Report::QueryColumn::Tag,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Category"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Payee,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Tag,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Payee"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Tag,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Category,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Tag"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Month,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Tag,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Month"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Week,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Tag,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Week"),
i18n("Default Report")
));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Account,
eMyMoney::Report::QueryColumn::Loan,
TransactionFilter::Date::All,
eMyMoney::Report::DetailLevel::All,
i18n("Loan Transactions"),
i18n("Default Report")
));
list.back().setLoansOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountReconcile,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Balance,
TransactionFilter::Date::Last3Months,
eMyMoney::Report::DetailLevel::All,
i18n("Transactions by Reconciliation Status"),
i18n("Default Report")
));
groups.push_back(list);
}
{
ReportGroup list("CashFlow", i18n("Cash Flow"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::CashFlow,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Account,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Cash Flow Transactions This Month"),
i18n("Default Report")
));
groups.push_back(list);
}
{
ReportGroup list("Investments", i18n("Investments"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::TopAccount,
eMyMoney::Report::QueryColumn::Action | eMyMoney::Report::QueryColumn::Shares | eMyMoney::Report::QueryColumn::Price,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Transactions"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountByTopAccount,
eMyMoney::Report::QueryColumn::Shares | eMyMoney::Report::QueryColumn::Price,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Holdings by Account"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::EquityType,
eMyMoney::Report::QueryColumn::Shares | eMyMoney::Report::QueryColumn::Price,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Holdings by Type"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountByTopAccount,
eMyMoney::Report::QueryColumn::Performance,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Performance by Account"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::EquityType,
eMyMoney::Report::QueryColumn::Performance,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Performance by Type"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountByTopAccount,
eMyMoney::Report::QueryColumn::CapitalGain,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Capital Gains by Account"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::EquityType,
eMyMoney::Report::QueryColumn::CapitalGain,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Capital Gains by Type"),
i18n("Default Report")
));
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Today,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Holdings Pie"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Pie);
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last12Months,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Worth Graph"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.back().setColumnsAreDays(true);
list.back().setInvestmentsOnly(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last12Months,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Price Graph"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.back().setColumnsAreDays(true);
list.back().setInvestmentsOnly(true);
list.back().setIncludingBudgetActuals(false);
list.back().setIncludingPrice(true);
list.back().setConvertCurrency(true);
list.back().setChartDataLabels(false);
list.back().setSkipZero(true);
list.back().setShowingColumnTotals(false);
list.back().setShowingRowTotals(false);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last12Months,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Moving Average Price Graph"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.back().setColumnsAreDays(true);
list.back().setInvestmentsOnly(true);
list.back().setIncludingBudgetActuals(false);
list.back().setIncludingAveragePrice(true);
list.back().setMovingAverageDays(10);
list.back().setConvertCurrency(true);
list.back().setChartDataLabels(false);
list.back().setShowingColumnTotals(false);
list.back().setShowingRowTotals(false);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last30Days,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Moving Average"),
i18n("Default Report")
));
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.back().setColumnsAreDays(true);
list.back().setInvestmentsOnly(true);
list.back().setIncludingBudgetActuals(false);
list.back().setIncludingMovingAverage(true);
list.back().setMovingAverageDays(10);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Last30Days,
eMyMoney::Report::DetailLevel::All,
i18n("Investment Moving Average vs Actual"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
list.back().setColumnsAreDays(true);
list.back().setInvestmentsOnly(true);
list.back().setIncludingBudgetActuals(true);
list.back().setIncludingMovingAverage(true);
list.back().setMovingAverageDays(10);
groups.push_back(list);
}
{
ReportGroup list("Taxes", i18n("Taxes"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Category,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Account,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Tax Transactions by Category"),
i18n("Default Report")
));
list.back().setTax(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Payee,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Account,
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Tax Transactions by Payee"),
i18n("Default Report")
));
list.back().setTax(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Category,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Account,
TransactionFilter::Date::LastFiscalYear,
eMyMoney::Report::DetailLevel::All,
i18n("Tax Transactions by Category Last Fiscal Year"),
i18n("Default Report")
));
list.back().setTax(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Payee,
eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Category | eMyMoney::Report::QueryColumn::Account,
TransactionFilter::Date::LastFiscalYear,
eMyMoney::Report::DetailLevel::All,
i18n("Tax Transactions by Payee Last Fiscal Year"),
i18n("Default Report")
));
list.back().setTax(true);
groups.push_back(list);
}
{
ReportGroup list("Budgeting", i18n("Budgeting"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::BudgetActual,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::YearToDate,
eMyMoney::Report::DetailLevel::All,
i18n("Budgeted vs. Actual This Year"),
i18n("Default Report")
));
list.back().setShowingRowTotals(true);
list.back().setBudget("Any", true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::BudgetActual,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::YearToMonth,
eMyMoney::Report::DetailLevel::All,
i18n("Budgeted vs. Actual This Year (YTM)"),
i18n("Default Report")
));
list.back().setShowingRowTotals(true);
list.back().setBudget("Any", true);
// in case we're in January, we show the last year
if (QDate::currentDate().month() == 1) {
list.back().setDateFilter(TransactionFilter::Date::LastYear);
}
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::BudgetActual,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentMonth,
eMyMoney::Report::DetailLevel::All,
i18n("Monthly Budgeted vs. Actual"),
i18n("Default Report")
));
list.back().setBudget("Any", true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::BudgetActual,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentYear,
eMyMoney::Report::DetailLevel::All,
i18n("Yearly Budgeted vs. Actual"),
i18n("Default Report")
));
list.back().setBudget("Any", true);
list.back().setShowingRowTotals(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Budget,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentMonth,
eMyMoney::Report::DetailLevel::All,
i18n("Monthly Budget"),
i18n("Default Report")
));
list.back().setBudget("Any", false);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Budget,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentYear,
eMyMoney::Report::DetailLevel::All,
i18n("Yearly Budget"),
i18n("Default Report")
));
list.back().setBudget("Any", false);
list.back().setShowingRowTotals(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::BudgetActual,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentYear,
eMyMoney::Report::DetailLevel::Group,
i18n("Yearly Budgeted vs Actual Graph"),
i18n("Default Report")
));
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setBudget("Any", true);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
groups.push_back(list);
}
{
ReportGroup list("Forecast", i18n("Forecast"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Next12Months,
eMyMoney::Report::DetailLevel::Top,
i18n("Forecast By Month"),
i18n("Default Report")
));
list.back().setIncludingForecast(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::NextQuarter,
eMyMoney::Report::DetailLevel::Top,
i18n("Forecast Next Quarter"),
i18n("Default Report")
));
list.back().setColumnsAreDays(true);
list.back().setIncludingForecast(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::ExpenseIncome,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::CurrentYear,
eMyMoney::Report::DetailLevel::Top,
i18n("Income and Expenses Forecast This Year"),
i18n("Default Report")
));
list.back().setIncludingForecast(true);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AssetLiability,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Next3Months,
eMyMoney::Report::DetailLevel::Total,
i18n("Net Worth Forecast Graph"),
i18n("Default Report")
));
list.back().setColumnsAreDays(true);
list.back().setIncludingForecast(true);
list.back().setChartByDefault(true);
list.back().setChartCHGridLines(false);
list.back().setChartSVGridLines(false);
list.back().setChartType(eMyMoney::Report::ChartType::Line);
groups.push_back(list);
}
{
ReportGroup list("Information", i18n("General Information"));
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Schedule,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Next12Months,
eMyMoney::Report::DetailLevel::All,
i18n("Schedule Information"),
i18n("Default Report")
));
list.back().setDetailLevel(eMyMoney::Report::DetailLevel::All);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::Schedule,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Next12Months,
eMyMoney::Report::DetailLevel::All,
i18n("Schedule Summary Information"),
i18n("Default Report")
));
list.back().setDetailLevel(eMyMoney::Report::DetailLevel::Top);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountInfo,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Today,
eMyMoney::Report::DetailLevel::All,
i18n("Account Information"),
i18n("Default Report")
));
list.back().setConvertCurrency(false);
list.push_back(MyMoneyReport(
eMyMoney::Report::RowType::AccountLoanInfo,
static_cast(eMyMoney::Report::ColumnType::Months),
TransactionFilter::Date::Today,
eMyMoney::Report::DetailLevel::All,
i18n("Loan Information"),
i18n("Default Report")
));
list.back().setConvertCurrency(false);
groups.push_back(list);
}
}
bool columnsAlreadyAdjusted() const
{
return m_columnsAlreadyAdjusted;
}
void setColumnsAlreadyAdjusted(bool adjusted)
{
m_columnsAlreadyAdjusted = adjusted;
}
KReportsView *q_ptr;
/**
* This member holds the load state of page
*/
bool m_needLoad;
QListWidget* m_reportListView;
QTabWidget* m_reportTabWidget;
QWidget* m_listTab;
QVBoxLayout* m_listTabLayout;
QTreeWidget* m_tocTreeWidget;
QMap m_allTocItemGroups;
QString m_selectedExportFilter;
bool m_columnsAlreadyAdjusted;
MyMoneyAccount m_currentAccount;
};
#endif
diff --git a/kmymoney/plugins/views/reports/reporttabchart.ui b/kmymoney/plugins/views/reports/reporttabchart.ui
index 77c4392ab..59b0ff278 100644
--- a/kmymoney/plugins/views/reports/reporttabchart.ui
+++ b/kmymoney/plugins/views/reports/reporttabchart.ui
@@ -1,199 +1,207 @@
ReportTabChart
0
0
600
234
Chart Tab
<p>On this tab, you configure the chart drawn for this report.</p>
-
-
0
0
<p>Select what form you would like the chart to be drawn as.</p>
Chart Type
false
-
-
Qt::Horizontal
QSizePolicy::Expanding
121
20
-
-
<p>Select this option to draw the numeric values for data points next to their plot location.</p>
Draw values on chart
-
<p>Select this option to cause the report to be shown as a chart when you first open the report. Otherwise, it will come up as a text report.</p>
Show as chart by default
-
SV grid lines
-
<p>Select this option to show horizontal and vertical grid lines on the chart.</p>
CH grid lines
-
Logarithmic vertical axis
+ -
+
+
+ Plot expenses downwards
+
+
+
-
-
0
0
<p>Select what width should be used to draw the line on the chart</p>
Line width
false
-
1
10
-
Qt::Horizontal
QSizePolicy::Expanding
121
20
-
Qt::Vertical
QSizePolicy::Expanding
20
20
KMyMoneyGeneralCombo
QWidget
1
m_checkCHGridLines
m_checkSVGridLines
m_checkValues
m_checkShowChart
m_logYaxis
+ m_negExpenses
m_lineWidth
diff --git a/kmymoney/plugins/views/reports/reporttabimpl.cpp b/kmymoney/plugins/views/reports/reporttabimpl.cpp
index e252f39b4..6b8158b2a 100644
--- a/kmymoney/plugins/views/reports/reporttabimpl.cpp
+++ b/kmymoney/plugins/views/reports/reporttabimpl.cpp
@@ -1,331 +1,346 @@
/* This file is part of the KDE project
Copyright (C) 2009 Laurent Montel
(C) 2017 by Łukasz Wojniłowicz
+ Copyright 2018 Michael Kiefer
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "reporttabimpl.h"
#include
#include "daterangedlg.h"
#include "ui_reporttabgeneral.h"
#include "ui_reporttabrowcolpivot.h"
#include "ui_reporttabrowcolquery.h"
#include "ui_reporttabchart.h"
#include "ui_reporttabrange.h"
#include "ui_reporttabcapitalgain.h"
#include "ui_reporttabperformance.h"
#include "mymoney/mymoneyreport.h"
#include "mymoneyenums.h"
ReportTabGeneral::ReportTabGeneral(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::ReportTabGeneral;
ui->setupUi(this);
}
ReportTabGeneral::~ReportTabGeneral()
{
delete ui;
}
ReportTabRowColPivot::ReportTabRowColPivot(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::ReportTabRowColPivot;
ui->setupUi(this);
}
ReportTabRowColPivot::~ReportTabRowColPivot()
{
delete ui;
}
ReportTabRowColQuery::ReportTabRowColQuery(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::ReportTabRowColQuery;
ui->setupUi(this);
ui->buttonGroup1->setExclusive(false);
ui->buttonGroup1->setId(ui->m_checkMemo, 0);
ui->buttonGroup1->setId(ui->m_checkShares, 1);
ui->buttonGroup1->setId(ui->m_checkPrice, 2);
ui->buttonGroup1->setId(ui->m_checkReconciled, 3);
ui->buttonGroup1->setId(ui->m_checkAccount, 4);
ui->buttonGroup1->setId(ui->m_checkNumber, 5);
ui->buttonGroup1->setId(ui->m_checkPayee, 6);
ui->buttonGroup1->setId(ui->m_checkCategory, 7);
ui->buttonGroup1->setId(ui->m_checkAction, 8);
ui->buttonGroup1->setId(ui->m_checkBalance, 9);
connect(ui->m_checkHideTransactions, &QAbstractButton::toggled, this, &ReportTabRowColQuery::slotHideTransactionsChanged);
}
void ReportTabRowColQuery::slotHideTransactionsChanged(bool checked)
{
if (checked) // toggle m_checkHideSplitDetails only if it's mandatory
ui->m_checkHideSplitDetails->setChecked(checked);
ui->m_checkHideSplitDetails->setEnabled(!checked); // hiding transactions without hiding splits isn't allowed
}
ReportTabRowColQuery::~ReportTabRowColQuery()
{
delete ui;
}
ReportTabChart::ReportTabChart(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::ReportTabChart;
ui->setupUi(this);
ui->m_comboType->addItem(i18nc("type of graphic chart", "Line"), static_cast(eMyMoney::Report::ChartType::Line));
ui->m_comboType->addItem(i18nc("type of graphic chart", "Bar"), static_cast(eMyMoney::Report::ChartType::Bar));
ui->m_comboType->addItem(i18nc("type of graphic chart", "Stacked Bar"), static_cast(eMyMoney::Report::ChartType::StackedBar));
ui->m_comboType->addItem(i18nc("type of graphic chart", "Pie"), static_cast(eMyMoney::Report::ChartType::Pie));
ui->m_comboType->addItem(i18nc("type of graphic chart", "Ring"), static_cast(eMyMoney::Report::ChartType::Ring));
connect(ui->m_comboType, static_cast(&QComboBox::currentIndexChanged), this, &ReportTabChart::slotChartTypeChanged);
emit ui->m_comboType->currentIndexChanged(ui->m_comboType->currentIndex());
}
ReportTabChart::~ReportTabChart()
{
delete ui;
}
void ReportTabChart::slotChartTypeChanged(int index)
{
if (index == static_cast(eMyMoney::Report::ChartType::Pie) ||
index == static_cast(eMyMoney::Report::ChartType::Ring)) {
ui->m_checkCHGridLines->setText(i18n("Show circular grid lines"));
ui->m_checkSVGridLines->setText(i18n("Show sagittal grid lines"));
ui->m_logYaxis->setChecked(false);
ui->m_logYaxis->setEnabled(false);
+ ui->m_negExpenses->setChecked(false);
+ ui->m_negExpenses->setEnabled(false);
} else {
ui->m_checkCHGridLines->setText(i18n("Show horizontal grid lines"));
ui->m_checkSVGridLines->setText(i18n("Show vertical grid lines"));
ui->m_logYaxis->setEnabled(true);
+ ui->m_negExpenses->setEnabled(true);
+ }
+}
+
+void ReportTabChart::setNegExpenses(bool set)
+{
+ // logarithm on negative numbers does not make sense, so disable it
+ if (set) {
+ ui->m_logYaxis->setChecked(false);
+ ui->m_logYaxis->setEnabled(false);
+ } else {
+ ui->m_logYaxis->setEnabled(true);
}
}
ReportTabRange::ReportTabRange(QWidget *parent)
: QWidget(parent),
ui(new Ui::ReportTabRange)
{
ui->setupUi(this);
m_dateRange = new DateRangeDlg;
ui->dateRangeGrid->addWidget(m_dateRange, 0, 0, 1, 2);
connect(ui->m_yLabelsPrecision, static_cast(&QSpinBox::valueChanged), this, &ReportTabRange::slotYLabelsPrecisionChanged);
emit ui->m_yLabelsPrecision->valueChanged(ui->m_yLabelsPrecision->value());
connect(ui->m_dataRangeStart, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedStart);
connect(ui->m_dataRangeEnd, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedEnd);
connect(ui->m_dataMajorTick, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedMajor);
connect(ui->m_dataMinorTick, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedMinor);
connect(ui->m_dataLock, static_cast(&QComboBox::currentIndexChanged), this, &ReportTabRange::slotDataLockChanged);
emit ui->m_dataLock->currentIndexChanged(ui->m_dataLock->currentIndex());
}
ReportTabRange::~ReportTabRange()
{
delete ui;
}
void ReportTabRange::setRangeLogarythmic(bool set)
{
// major and minor tick have no influence if axis is logarithmic so hide them
if (set) {
ui->lblDataMajorTick->hide();
ui->lblDataMinorTick->hide();
ui->m_dataMajorTick->hide();
ui->m_dataMinorTick->hide();
} else {
ui->lblDataMajorTick->show();
ui->lblDataMinorTick->show();
ui->m_dataMajorTick->show();
ui->m_dataMinorTick->show();
}
}
void ReportTabRange::slotEditingFinished(EDimension dim)
{
qreal dataRangeStart = locale().toDouble(ui->m_dataRangeStart->text());
qreal dataRangeEnd = locale().toDouble(ui->m_dataRangeEnd->text());
qreal dataMajorTick = locale().toDouble(ui->m_dataMajorTick->text());
qreal dataMinorTick = locale().toDouble(ui->m_dataMinorTick->text());
if (dataRangeEnd < dataRangeStart) { // end must be higher than start
if (dim == eRangeEnd) {
ui->m_dataRangeStart->setText(ui->m_dataRangeEnd->text());
dataRangeStart = dataRangeEnd;
} else {
ui->m_dataRangeEnd->setText(ui->m_dataRangeStart->text());
dataRangeEnd = dataRangeStart;
}
}
if ((dataRangeStart != 0 || dataRangeEnd != 0)) { // if data range isn't going to be reset
if ((dataRangeEnd - dataRangeStart) < dataMajorTick) // major tick cannot be greater than data range
dataMajorTick = dataRangeEnd - dataRangeStart;
if (dataMajorTick != 0 && // if major tick isn't going to be reset
dataMajorTick < (dataRangeEnd - dataRangeStart) * 0.01) // constraint major tick to be greater or equal to 1% of data range
dataMajorTick = (dataRangeEnd - dataRangeStart) * 0.01; // that should produce more than 256 Y labels in KReportChartView::slotNeedUpdate
//set precision of major tick to be greater by 1
ui->m_dataMajorTick->setText(locale().toString(dataMajorTick, 'f', ui->m_yLabelsPrecision->value() + 1).remove(locale().groupSeparator()).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + locale().decimalPoint() + "$")));
}
if (dataMajorTick < dataMinorTick) { // major tick must be higher than minor
if (dim == eMinorTick) {
ui->m_dataMajorTick->setText(ui->m_dataMinorTick->text());
dataMajorTick = dataMinorTick;
} else {
ui->m_dataMinorTick->setText(ui->m_dataMajorTick->text());
dataMinorTick = dataMajorTick;
}
}
if (dataMinorTick < dataMajorTick * 0.1) { // constraint minor tick to be greater or equal to 10% of major tick, and set precision to be greater by 1
dataMinorTick = dataMajorTick * 0.1;
ui->m_dataMinorTick->setText(locale().toString(dataMinorTick, 'f', ui->m_yLabelsPrecision->value() + 1).remove(locale().groupSeparator()).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + locale().decimalPoint() + "$")));
}
}
void ReportTabRange::slotEditingFinishedStart()
{
slotEditingFinished(eRangeStart);
}
void ReportTabRange::slotEditingFinishedEnd()
{
slotEditingFinished(eRangeEnd);
}
void ReportTabRange::slotEditingFinishedMajor()
{
slotEditingFinished(eMajorTick);
}
void ReportTabRange::slotEditingFinishedMinor()
{
slotEditingFinished(eMinorTick);
}
void ReportTabRange::slotYLabelsPrecisionChanged(const int& value)
{
ui->m_dataRangeStart->setValidator(0);
ui->m_dataRangeEnd->setValidator(0);
ui->m_dataMajorTick->setValidator(0);
ui->m_dataMinorTick->setValidator(0);
MyDoubleValidator *dblVal = new MyDoubleValidator(value);
ui->m_dataRangeStart->setValidator(dblVal);
ui->m_dataRangeEnd->setValidator(dblVal);
MyDoubleValidator *dblVal2 = new MyDoubleValidator(value + 1);
ui->m_dataMajorTick->setValidator(dblVal2);
ui->m_dataMinorTick->setValidator(dblVal2);
}
void ReportTabRange::slotDataLockChanged(int index) {
if (index == static_cast(eMyMoney::Report::DataLock::Automatic)) {
ui->m_dataRangeStart->setText(QStringLiteral("0"));
ui->m_dataRangeEnd->setText(QStringLiteral("0"));
ui->m_dataMajorTick->setText(QStringLiteral("0"));
ui->m_dataMinorTick->setText(QStringLiteral("0"));
ui->m_dataRangeStart->setEnabled(false);
ui->m_dataRangeEnd->setEnabled(false);
ui->m_dataMajorTick->setEnabled(false);
ui->m_dataMinorTick->setEnabled(false);
} else {
ui->m_dataRangeStart->setEnabled(true);
ui->m_dataRangeEnd->setEnabled(true);
ui->m_dataMajorTick->setEnabled(true);
ui->m_dataMinorTick->setEnabled(true);
}
}
ReportTabCapitalGain::ReportTabCapitalGain(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::ReportTabCapitalGain;
ui->setupUi(this);
connect(ui->m_investmentSum, static_cast(&QComboBox::currentIndexChanged), this, &ReportTabCapitalGain::slotInvestmentSumChanged);
}
ReportTabCapitalGain::~ReportTabCapitalGain()
{
delete ui;
}
void ReportTabCapitalGain::slotInvestmentSumChanged(int index) {
Q_UNUSED(index);
if (ui->m_investmentSum->currentData() == static_cast(eMyMoney::Report::InvestmentSum::Owned)) {
ui->m_settlementPeriod->setValue(0);
ui->m_settlementPeriod->setEnabled(false);
ui->m_showSTLTCapitalGains->setChecked(false);
ui->m_showSTLTCapitalGains->setEnabled(false);
ui->m_termSeparator->setEnabled(false);
} else {
ui->m_settlementPeriod->setEnabled(true);
ui->m_showSTLTCapitalGains->setEnabled(true);
ui->m_termSeparator->setEnabled(true);
}
}
ReportTabPerformance::ReportTabPerformance(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::ReportTabPerformance;
ui->setupUi(this);
}
ReportTabPerformance::~ReportTabPerformance()
{
delete ui;
}
MyDoubleValidator::MyDoubleValidator(int decimals, QObject * parent) :
QDoubleValidator(0, 0, decimals, parent)
{
}
QValidator::State MyDoubleValidator::validate(QString &s, int &i) const
{
Q_UNUSED(i);
if (s.isEmpty() || s == "-") {
return QValidator::Intermediate;
}
QChar decimalPoint = locale().decimalPoint();
if(s.indexOf(decimalPoint) != -1) {
int charsAfterPoint = s.length() - s.indexOf(decimalPoint) - 1;
if (charsAfterPoint > decimals()) {
return QValidator::Invalid;
}
}
bool ok;
locale().toDouble(s, &ok);
if (ok) {
return QValidator::Acceptable;
} else {
return QValidator::Invalid;
}
}
diff --git a/kmymoney/plugins/views/reports/reporttabimpl.h b/kmymoney/plugins/views/reports/reporttabimpl.h
index 67e5bcd11..1dc9613a8 100644
--- a/kmymoney/plugins/views/reports/reporttabimpl.h
+++ b/kmymoney/plugins/views/reports/reporttabimpl.h
@@ -1,147 +1,149 @@
/* This file is part of the KDE project
Copyright (C) 2009 Laurent Montel
(C) 2017 by Łukasz Wojniłowicz
+ 2018 by Michael Kiefer
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef REPORTTABIMPL_H
#define REPORTTABIMPL_H
#include
#include
class DateRangeDlg;
namespace Ui
{
class ReportTabGeneral;
class ReportTabRowColPivot;
class ReportTabRowColQuery;
class ReportTabChart;
class ReportTabRange;
class ReportTabCapitalGain;
class ReportTabPerformance;
}
class ReportTabGeneral : public QWidget
{
Q_DISABLE_COPY(ReportTabGeneral)
public:
explicit ReportTabGeneral(QWidget *parent);
~ReportTabGeneral();
Ui::ReportTabGeneral* ui;
};
class ReportTabRowColPivot : public QWidget
{
Q_DISABLE_COPY(ReportTabRowColPivot)
public:
explicit ReportTabRowColPivot(QWidget *parent);
~ReportTabRowColPivot();
Ui::ReportTabRowColPivot* ui;
};
class ReportTabRowColQuery : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(ReportTabRowColQuery)
public:
explicit ReportTabRowColQuery(QWidget *parent);
~ReportTabRowColQuery();
Ui::ReportTabRowColQuery* ui;
private Q_SLOTS:
void slotHideTransactionsChanged(bool checked);
};
class ReportTabChart : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(ReportTabChart)
public:
explicit ReportTabChart(QWidget *parent);
~ReportTabChart();
Ui::ReportTabChart* ui;
+ void setNegExpenses(bool set);
private Q_SLOTS:
void slotChartTypeChanged(int index);
};
class ReportTabRange : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(ReportTabRange)
public:
explicit ReportTabRange(QWidget *parent);
~ReportTabRange();
Ui::ReportTabRange* ui;
DateRangeDlg *m_dateRange;
void setRangeLogarythmic(bool set);
private:
enum EDimension { eRangeStart = 0, eRangeEnd, eMajorTick, eMinorTick};
private Q_SLOTS:
void slotEditingFinished(EDimension dim);
void slotEditingFinishedStart();
void slotEditingFinishedEnd();
void slotEditingFinishedMajor();
void slotEditingFinishedMinor();
void slotYLabelsPrecisionChanged(const int &value);
void slotDataLockChanged(int index);
};
class ReportTabCapitalGain : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(ReportTabCapitalGain)
public:
explicit ReportTabCapitalGain(QWidget *parent);
~ReportTabCapitalGain();
Ui::ReportTabCapitalGain* ui;
private Q_SLOTS:
void slotInvestmentSumChanged(int index);
};
class ReportTabPerformance : public QWidget
{
public:
explicit ReportTabPerformance(QWidget *parent);
~ReportTabPerformance();
Ui::ReportTabPerformance* ui;
};
class MyDoubleValidator : public QDoubleValidator
{
public:
explicit MyDoubleValidator(int decimals, QObject * parent = 0);
QValidator::State validate(QString &s, int &i) const final override;
};
#endif /* REPORTTABIMPL_H */
diff --git a/kmymoney/plugins/xmlhelper/xmlstoragehelper.cpp b/kmymoney/plugins/xmlhelper/xmlstoragehelper.cpp
index eee4cb6f1..f51ac1451 100644
--- a/kmymoney/plugins/xmlhelper/xmlstoragehelper.cpp
+++ b/kmymoney/plugins/xmlhelper/xmlstoragehelper.cpp
@@ -1,1204 +1,1209 @@
/*
* Copyright 2004-2006 Ace Jones
* Copyright 2006 Darren Gould
* Copyright 2007-2010 Alvaro Soliverez
* Copyright 2017-2018 Łukasz Wojniłowicz
+ * Copyright 2018 Michael Kiefer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "xmlstoragehelper.h"
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
#include "mymoneymoney.h"
#include "mymoneybudget.h"
#include "mymoneyreport.h"
#include "mymoneytransactionfilter.h"
#include "mymoneyenums.h"
#include "mymoneyexception.h"
namespace Element {
enum class Report {
Payee,
Tag,
Account,
Text,
Type,
State,
Number,
Amount,
Dates,
Category,
AccountGroup
};
enum class Budget {
Budget = 0,
Account,
Period
};
}
namespace Attribute {
enum class Report {
ID = 0, Group, Type, Name, Comment, ConvertCurrency, Favorite,
SkipZero, DateLock, DataLock, MovingAverageDays,
IncludesActuals, IncludesForecast, IncludesPrice,
IncludesAveragePrice, IncludesMovingAverage,
IncludesSchedules, IncludesTransfers, IncludesUnused,
MixedTime, Investments, Budget,
ShowRowTotals, ShowColumnTotals, Detail,
ColumnsAreDays, ChartType,
ChartCHGridLines, ChartSVGridLines,
ChartDataLabels, ChartByDefault,
LogYAxis, ChartLineWidth, ColumnType, RowType,
DataRangeStart, DataRangeEnd,
DataMajorTick, DataMinorTick,
YLabelsPrecision, QueryColumns,
Tax, Loans, HideTransactions, InvestmentSum,
SettlementPeriod, ShowSTLTCapitalGains, TermsSeparator,
Pattern, CaseSensitive, RegEx, InvertText, State,
From, To,
+ NegExpenses,
// insert new entries above this line
LastAttribute
};
enum class Budget {
ID = 0,
Name,
Start,
Version,
BudgetLevel,
BudgetSubAccounts,
Amount,
// insert new entries above this line
LastAttribute
};
}
namespace MyMoneyXmlContentHandler2 {
enum class Node {
Report,
Budget
};
QString nodeName(Node nodeID)
{
static const QHash nodeNames {
{Node::Report, QStringLiteral("REPORT")},
{Node::Budget, QStringLiteral("BUDGET")}
};
return nodeNames.value(nodeID);
}
uint qHash(const Node key, uint seed) { return ::qHash(static_cast(key), seed); }
QString elementName(Element::Report elementID)
{
static const QMap elementNames {
{Element::Report::Payee, QStringLiteral("PAYEE")},
{Element::Report::Tag, QStringLiteral("TAG")},
{Element::Report::Account, QStringLiteral("ACCOUNT")},
{Element::Report::Text, QStringLiteral("TEXT")},
{Element::Report::Type, QStringLiteral("TYPE")},
{Element::Report::State, QStringLiteral("STATE")},
{Element::Report::Number, QStringLiteral("NUMBER")},
{Element::Report::Amount, QStringLiteral("AMOUNT")},
{Element::Report::Dates, QStringLiteral("DATES")},
{Element::Report::Category, QStringLiteral("CATEGORY")},
{Element::Report::AccountGroup, QStringLiteral("ACCOUNTGROUP")}
};
return elementNames.value(elementID);
}
QString attributeName(Attribute::Report attributeID)
{
static const QMap attributeNames {
{Attribute::Report::ID, QStringLiteral("id")},
{Attribute::Report::Group, QStringLiteral("group")},
{Attribute::Report::Type, QStringLiteral("type")},
{Attribute::Report::Name, QStringLiteral("name")},
{Attribute::Report::Comment, QStringLiteral("comment")},
{Attribute::Report::ConvertCurrency, QStringLiteral("convertcurrency")},
{Attribute::Report::Favorite, QStringLiteral("favorite")},
{Attribute::Report::SkipZero, QStringLiteral("skipZero")},
{Attribute::Report::DateLock, QStringLiteral("datelock")},
{Attribute::Report::DataLock, QStringLiteral("datalock")},
{Attribute::Report::MovingAverageDays, QStringLiteral("movingaveragedays")},
{Attribute::Report::IncludesActuals, QStringLiteral("includesactuals")},
{Attribute::Report::IncludesForecast, QStringLiteral("includesforecast")},
{Attribute::Report::IncludesPrice, QStringLiteral("includesprice")},
{Attribute::Report::IncludesAveragePrice, QStringLiteral("includesaverageprice")},
{Attribute::Report::IncludesMovingAverage, QStringLiteral("includesmovingaverage")},
{Attribute::Report::IncludesSchedules, QStringLiteral("includeschedules")},
{Attribute::Report::IncludesTransfers, QStringLiteral("includestransfers")},
{Attribute::Report::IncludesUnused, QStringLiteral("includeunused")},
{Attribute::Report::MixedTime, QStringLiteral("mixedtime")},
{Attribute::Report::Investments, QStringLiteral("investments")},
{Attribute::Report::Budget, QStringLiteral("budget")},
{Attribute::Report::ShowRowTotals, QStringLiteral("showrowtotals")},
{Attribute::Report::ShowColumnTotals, QStringLiteral("showcolumntotals")},
{Attribute::Report::Detail, QStringLiteral("detail")},
{Attribute::Report::ColumnsAreDays, QStringLiteral("columnsaredays")},
{Attribute::Report::ChartType, QStringLiteral("charttype")},
{Attribute::Report::ChartCHGridLines, QStringLiteral("chartchgridlines")},
{Attribute::Report::ChartSVGridLines, QStringLiteral("chartsvgridlines")},
{Attribute::Report::ChartDataLabels, QStringLiteral("chartdatalabels")},
{Attribute::Report::ChartByDefault, QStringLiteral("chartbydefault")},
{Attribute::Report::LogYAxis, QStringLiteral("logYaxis")},
{Attribute::Report::ChartLineWidth, QStringLiteral("chartlinewidth")},
{Attribute::Report::ColumnType, QStringLiteral("columntype")},
{Attribute::Report::RowType, QStringLiteral("rowtype")},
{Attribute::Report::DataRangeStart, QStringLiteral("dataRangeStart")},
{Attribute::Report::DataRangeEnd, QStringLiteral("dataRangeEnd")},
{Attribute::Report::DataMajorTick, QStringLiteral("dataMajorTick")},
{Attribute::Report::DataMinorTick, QStringLiteral("dataMinorTick")},
{Attribute::Report::YLabelsPrecision, QStringLiteral("yLabelsPrecision")},
{Attribute::Report::QueryColumns, QStringLiteral("querycolumns")},
{Attribute::Report::Tax, QStringLiteral("tax")},
{Attribute::Report::Loans, QStringLiteral("loans")},
{Attribute::Report::HideTransactions, QStringLiteral("hidetransactions")},
{Attribute::Report::InvestmentSum, QStringLiteral("investmentsum")},
{Attribute::Report::SettlementPeriod, QStringLiteral("settlementperiod")},
{Attribute::Report::ShowSTLTCapitalGains, QStringLiteral("showSTLTCapitalGains")},
{Attribute::Report::TermsSeparator, QStringLiteral("tseparator")},
{Attribute::Report::Pattern, QStringLiteral("pattern")},
{Attribute::Report::CaseSensitive, QStringLiteral("casesensitive")},
{Attribute::Report::RegEx, QStringLiteral("regex")},
{Attribute::Report::InvertText, QStringLiteral("inverttext")},
{Attribute::Report::State, QStringLiteral("state")},
{Attribute::Report::From, QStringLiteral("from")},
- {Attribute::Report::To, QStringLiteral("to")}
+ {Attribute::Report::To, QStringLiteral("to")},
+ {Attribute::Report::NegExpenses, QStringLiteral("negexpenses")}
};
return attributeNames.value(attributeID);
}
QString elementName(Element::Budget elementID)
{
static const QMap elementNames {
{Element::Budget::Budget, QStringLiteral("BUDGET")},
{Element::Budget::Account, QStringLiteral("ACCOUNT")},
{Element::Budget::Period, QStringLiteral("PERIOD")}
};
return elementNames.value(elementID);
}
QString attributeName(Attribute::Budget attributeID)
{
static const QMap attributeNames {
{Attribute::Budget::ID, QStringLiteral("id")},
{Attribute::Budget::Name, QStringLiteral("name")},
{Attribute::Budget::Start, QStringLiteral("start")},
{Attribute::Budget::Version, QStringLiteral("version")},
{Attribute::Budget::BudgetLevel, QStringLiteral("budgetlevel")},
{Attribute::Budget::BudgetSubAccounts, QStringLiteral("budgetsubaccounts")},
{Attribute::Budget::Amount, QStringLiteral("amount")}
};
return attributeNames.value(attributeID);
}
QHash rowTypesLUT()
{
static const QHash lut {
{eMyMoney::Report::RowType::NoRows, QStringLiteral("none")},
{eMyMoney::Report::RowType::AssetLiability, QStringLiteral("assetliability")},
{eMyMoney::Report::RowType::ExpenseIncome, QStringLiteral("expenseincome")},
{eMyMoney::Report::RowType::Category, QStringLiteral("category")},
{eMyMoney::Report::RowType::TopCategory, QStringLiteral("topcategory")},
{eMyMoney::Report::RowType::Account, QStringLiteral("account")},
{eMyMoney::Report::RowType::Tag, QStringLiteral("tag")},
{eMyMoney::Report::RowType::Payee, QStringLiteral("payee")},
{eMyMoney::Report::RowType::Month, QStringLiteral("month")},
{eMyMoney::Report::RowType::Week, QStringLiteral("week")},
{eMyMoney::Report::RowType::TopAccount, QStringLiteral("topaccount")},
{eMyMoney::Report::RowType::AccountByTopAccount, QStringLiteral("topaccount-account")},
{eMyMoney::Report::RowType::EquityType, QStringLiteral("equitytype")},
{eMyMoney::Report::RowType::AccountType, QStringLiteral("accounttype")},
{eMyMoney::Report::RowType::Institution, QStringLiteral("institution")},
{eMyMoney::Report::RowType::Budget, QStringLiteral("budget")},
{eMyMoney::Report::RowType::BudgetActual, QStringLiteral("budgetactual")},
{eMyMoney::Report::RowType::Schedule, QStringLiteral("schedule")},
{eMyMoney::Report::RowType::AccountInfo, QStringLiteral("accountinfo")},
{eMyMoney::Report::RowType::AccountLoanInfo, QStringLiteral("accountloaninfo")},
{eMyMoney::Report::RowType::AccountReconcile, QStringLiteral("accountreconcile")},
{eMyMoney::Report::RowType::CashFlow, QStringLiteral("cashflow")},
};
return lut;
}
QString reportNames(eMyMoney::Report::RowType textID)
{
return rowTypesLUT().value(textID);
}
eMyMoney::Report::RowType stringToRowType(const QString &text)
{
return rowTypesLUT().key(text, eMyMoney::Report::RowType::Invalid);
}
QHash columTypesLUT()
{
static const QHash lut {
{eMyMoney::Report::ColumnType::NoColumns, QStringLiteral("none")},
{eMyMoney::Report::ColumnType::Months, QStringLiteral("months")},
{eMyMoney::Report::ColumnType::BiMonths, QStringLiteral("bimonths")},
{eMyMoney::Report::ColumnType::Quarters, QStringLiteral("quarters")},
// {eMyMoney::Report::ColumnType::, QStringLiteral("4")}
// {eMyMoney::Report::ColumnType::, QStringLiteral("5")}
// {eMyMoney::Report::ColumnType::, QStringLiteral("6")}
{eMyMoney::Report::ColumnType::Weeks, QStringLiteral("weeks")},
// {eMyMoney::Report::ColumnType::, QStringLiteral("8")}
// {eMyMoney::Report::ColumnType::, QStringLiteral("9")}
// {eMyMoney::Report::ColumnType::, QStringLiteral("10")}
// {eMyMoney::Report::ColumnType::, QStringLiteral("11")}
{eMyMoney::Report::ColumnType::Years, QStringLiteral("years")}
};
return lut;
}
QString reportNames(eMyMoney::Report::ColumnType textID)
{
return columTypesLUT().value(textID);
}
eMyMoney::Report::ColumnType stringToColumnType(const QString &text)
{
return columTypesLUT().key(text, eMyMoney::Report::ColumnType::Invalid);
}
QHash queryColumnsLUT()
{
static const QHash lut {
{eMyMoney::Report::QueryColumn::None, QStringLiteral("none")},
{eMyMoney::Report::QueryColumn::Number, QStringLiteral("number")},
{eMyMoney::Report::QueryColumn::Payee, QStringLiteral("payee")},
{eMyMoney::Report::QueryColumn::Category, QStringLiteral("category")},
{eMyMoney::Report::QueryColumn::Tag, QStringLiteral("tag")},
{eMyMoney::Report::QueryColumn::Memo, QStringLiteral("memo")},
{eMyMoney::Report::QueryColumn::Account, QStringLiteral("account")},
{eMyMoney::Report::QueryColumn::Reconciled, QStringLiteral("reconcileflag")},
{eMyMoney::Report::QueryColumn::Action, QStringLiteral("action")},
{eMyMoney::Report::QueryColumn::Shares, QStringLiteral("shares")},
{eMyMoney::Report::QueryColumn::Price, QStringLiteral("price")},
{eMyMoney::Report::QueryColumn::Performance, QStringLiteral("performance")},
{eMyMoney::Report::QueryColumn::Loan, QStringLiteral("loan")},
{eMyMoney::Report::QueryColumn::Balance, QStringLiteral("balance")},
{eMyMoney::Report::QueryColumn::CapitalGain, QStringLiteral("capitalgain")}
};
return lut;
}
QString reportNamesForQC(eMyMoney::Report::QueryColumn textID)
{
return queryColumnsLUT().value(textID);
}
eMyMoney::Report::QueryColumn stringToQueryColumn(const QString &text)
{
return queryColumnsLUT().key(text, eMyMoney::Report::QueryColumn::End);
}
QHash detailLevelLUT()
{
static const QHash lut {
{eMyMoney::Report::DetailLevel::None, QStringLiteral("none")},
{eMyMoney::Report::DetailLevel::All, QStringLiteral("all")},
{eMyMoney::Report::DetailLevel::Top, QStringLiteral("top")},
{eMyMoney::Report::DetailLevel::Group, QStringLiteral("group")},
{eMyMoney::Report::DetailLevel::Total, QStringLiteral("total")},
{eMyMoney::Report::DetailLevel::End, QStringLiteral("invalid")}
};
return lut;
}
QString reportNames(eMyMoney::Report::DetailLevel textID)
{
return detailLevelLUT().value(textID);
}
eMyMoney::Report::DetailLevel stringToDetailLevel(const QString &text)
{
return detailLevelLUT().key(text, eMyMoney::Report::DetailLevel::End);
}
QHash chartTypeLUT()
{
static const QHash lut {
{eMyMoney::Report::ChartType::None, QStringLiteral("none")},
{eMyMoney::Report::ChartType::Line, QStringLiteral("line")},
{eMyMoney::Report::ChartType::Bar, QStringLiteral("bar")},
{eMyMoney::Report::ChartType::Pie, QStringLiteral("pie")},
{eMyMoney::Report::ChartType::Ring, QStringLiteral("ring")},
{eMyMoney::Report::ChartType::StackedBar, QStringLiteral("stackedbar")}
};
return lut;
}
QString reportNames(eMyMoney::Report::ChartType textID)
{
return chartTypeLUT().value(textID);
}
eMyMoney::Report::ChartType stringToChartType(const QString &text)
{
return chartTypeLUT().key(text, eMyMoney::Report::ChartType::End);
}
QHash typeAttributeLUT()
{
static const QHash lut {
{0, QStringLiteral("all")},
{1, QStringLiteral("payments")},
{2, QStringLiteral("deposits")},
{3, QStringLiteral("transfers")},
{4, QStringLiteral("none")},
};
return lut;
}
QString typeAttributeToString(int textID)
{
return typeAttributeLUT().value(textID);
}
int stringToTypeAttribute(const QString &text)
{
return typeAttributeLUT().key(text, 4);
}
QHash stateAttributeLUT()
{
static const QHash lut {
{0, QStringLiteral("all")},
{1, QStringLiteral("notreconciled")},
{2, QStringLiteral("cleared")},
{3, QStringLiteral("reconciled")},
{4, QStringLiteral("frozen")},
{5, QStringLiteral("none")}
};
return lut;
}
QString stateAttributeToString(int textID)
{
return stateAttributeLUT().value(textID);
}
int stringToStateAttribute(const QString &text)
{
return stateAttributeLUT().key(text, 5);
}
QHash dateLockLUT()
{
static const QHash lut {
{0, QStringLiteral("alldates")},
{1, QStringLiteral("untiltoday")},
{2, QStringLiteral("currentmonth")},
{3, QStringLiteral("currentyear")},
{4, QStringLiteral("monthtodate")},
{5, QStringLiteral("yeartodate")},
{6, QStringLiteral("yeartomonth")},
{7, QStringLiteral("lastmonth")},
{8, QStringLiteral("lastyear")},
{9, QStringLiteral("last7days")},
{10, QStringLiteral("last30days")},
{11, QStringLiteral("last3months")},
{12, QStringLiteral("last6months")},
{13, QStringLiteral("last12months")},
{14, QStringLiteral("next7days")},
{15, QStringLiteral("next30days")},
{16, QStringLiteral("next3months")},
{17, QStringLiteral("next6months")},
{18, QStringLiteral("next12months")},
{19, QStringLiteral("userdefined")},
{20, QStringLiteral("last3tonext3months")},
{21, QStringLiteral("last11Months")},
{22, QStringLiteral("currentQuarter")},
{23, QStringLiteral("lastQuarter")},
{24, QStringLiteral("nextQuarter")},
{25, QStringLiteral("currentFiscalYear")},
{26, QStringLiteral("lastFiscalYear")},
{27, QStringLiteral("today")},
{28, QStringLiteral("next18months")}
};
return lut;
}
QString dateLockAttributeToString(int textID)
{
return dateLockLUT().value(textID);
}
int stringToDateLockAttribute(const QString &text)
{
return dateLockLUT().key(text, 0);
}
QHash dataLockLUT()
{
static const QHash lut {
{eMyMoney::Report::DataLock::Automatic, QStringLiteral("automatic")},
{eMyMoney::Report::DataLock::UserDefined, QStringLiteral("userdefined")}
};
return lut;
}
QString reportNames(eMyMoney::Report::DataLock textID)
{
return dataLockLUT().value(textID);
}
eMyMoney::Report::DataLock stringToDataLockAttribute(const QString &text)
{
return dataLockLUT().key(text, eMyMoney::Report::DataLock::DataOptionCount);
}
QHash accountTypeAttributeLUT()
{
static const QHash lut {
{0, QStringLiteral("unknown")},
{1, QStringLiteral("checkings")},
{2, QStringLiteral("savings")},
{3, QStringLiteral("cash")},
{4, QStringLiteral("creditcard")},
{5, QStringLiteral("loan")},
{6, QStringLiteral("certificatedep")},
{7, QStringLiteral("investment")},
{8, QStringLiteral("moneymarket")},
{10, QStringLiteral("asset")},
{11, QStringLiteral("liability")},
{12, QStringLiteral("currency")},
{13, QStringLiteral("income")},
{14, QStringLiteral("expense")},
{15, QStringLiteral("assetloan")},
{16, QStringLiteral("stock")},
{17, QStringLiteral("equity")},
{18, QStringLiteral("invalid")}
};
return lut;
}
QString accountTypeAttributeToString(int textID)
{
return accountTypeAttributeLUT().value(textID);
}
int stringToAccountTypeAttribute(const QString &text)
{
return accountTypeAttributeLUT().key(text, 0);
}
eMyMoney::Report::ReportType rowTypeToReportType(eMyMoney::Report::RowType rowType)
{
static const QHash reportTypes {
{eMyMoney::Report::RowType::NoRows, eMyMoney::Report::ReportType::NoReport},
{eMyMoney::Report::RowType::AssetLiability, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::ExpenseIncome, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::Category, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::TopCategory, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Account, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Tag, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Payee, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Month, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Week, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::TopAccount, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::AccountByTopAccount, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::EquityType, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::AccountType, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Institution, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::Budget, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::BudgetActual, eMyMoney::Report::ReportType::PivotTable},
{eMyMoney::Report::RowType::Schedule, eMyMoney::Report::ReportType::InfoTable},
{eMyMoney::Report::RowType::AccountInfo, eMyMoney::Report::ReportType::InfoTable},
{eMyMoney::Report::RowType::AccountLoanInfo, eMyMoney::Report::ReportType::InfoTable},
{eMyMoney::Report::RowType::AccountReconcile, eMyMoney::Report::ReportType::QueryTable},
{eMyMoney::Report::RowType::CashFlow, eMyMoney::Report::ReportType::QueryTable},
};
return reportTypes.value(rowType, eMyMoney::Report::ReportType::Invalid);
}
QHash budgetLevelLUT()
{
static const QHash lut {
{eMyMoney::Budget::Level::None, QStringLiteral("none")},
{eMyMoney::Budget::Level::Monthly, QStringLiteral("monthly")},
{eMyMoney::Budget::Level::MonthByMonth, QStringLiteral("monthbymonth")},
{eMyMoney::Budget::Level::Yearly, QStringLiteral("yearly")},
{eMyMoney::Budget::Level::Max, QStringLiteral("invalid")},
};
return lut;
}
QString budgetNames(eMyMoney::Budget::Level textID)
{
return budgetLevelLUT().value(textID);
}
eMyMoney::Budget::Level stringToBudgetLevel(const QString &text)
{
return budgetLevelLUT().key(text, eMyMoney::Budget::Level::Max);
}
QHash budgetLevelsLUT()
{
static const QHash lut {
{eMyMoney::Budget::Level::None, QStringLiteral("none")},
{eMyMoney::Budget::Level::Monthly, QStringLiteral("monthly")},
{eMyMoney::Budget::Level::MonthByMonth, QStringLiteral("monthbymonth")},
{eMyMoney::Budget::Level::Yearly, QStringLiteral("yearly")},
{eMyMoney::Budget::Level::Max, QStringLiteral("invalid")},
};
return lut;
}
QString budgetLevels(eMyMoney::Budget::Level textID)
{
return budgetLevelsLUT().value(textID);
}
void writeBaseXML(const QString &id, QDomDocument &document, QDomElement &el)
{
Q_UNUSED(document);
el.setAttribute(QStringLiteral("id"), id);
}
MyMoneyReport readReport(const QDomElement &node)
{
if (nodeName(Node::Report) != node.tagName())
throw MYMONEYEXCEPTION_CSTRING("Node was not REPORT");
MyMoneyReport report(node.attribute(attributeName(Attribute::Report::ID)));
// The goal of this reading method is 100% backward AND 100% forward
// compatibility. Any report ever created with any version of KMyMoney
// should be able to be loaded by this method (as long as it's one of the
// report types supported in this version, of course)
// read report's internals
QString type = node.attribute(attributeName(Attribute::Report::Type));
if (type.startsWith(QLatin1String("pivottable")))
report.setReportType(eMyMoney::Report::ReportType::PivotTable);
else if (type.startsWith(QLatin1String("querytable")))
report.setReportType(eMyMoney::Report::ReportType::QueryTable);
else if (type.startsWith(QLatin1String("infotable")))
report.setReportType(eMyMoney::Report::ReportType::InfoTable);
else
throw MYMONEYEXCEPTION_CSTRING("Unknown report type");
report.setGroup(node.attribute(attributeName(Attribute::Report::Group)));
report.clearTransactionFilter();
// read date tab
QString datelockstr = node.attribute(attributeName(Attribute::Report::DateLock), "userdefined");
// Handle the pivot 1.2/query 1.1 case where the values were saved as
// numbers
bool ok = false;
int i = datelockstr.toUInt(&ok);
if (!ok) {
i = stringToDateLockAttribute(datelockstr);
if (i == -1)
i = (int)eMyMoney::TransactionFilter::Date::UserDefined;
}
report.setDateFilter(static_cast(i));
// read general tab
report.setName(node.attribute(attributeName(Attribute::Report::Name)));
report.setComment(node.attribute(attributeName(Attribute::Report::Comment), "Extremely old report"));
report.setConvertCurrency(node.attribute(attributeName(Attribute::Report::ConvertCurrency), "1").toUInt());
report.setFavorite(node.attribute(attributeName(Attribute::Report::Favorite), "0").toUInt());
report.setSkipZero(node.attribute(attributeName(Attribute::Report::SkipZero), "0").toUInt());
if (report.reportType() == eMyMoney::Report::ReportType::PivotTable) {
// read report's internals
report.setIncludingBudgetActuals(node.attribute(attributeName(Attribute::Report::IncludesActuals), "0").toUInt());
report.setIncludingForecast(node.attribute(attributeName(Attribute::Report::IncludesForecast), "0").toUInt());
report.setIncludingPrice(node.attribute(attributeName(Attribute::Report::IncludesPrice), "0").toUInt());
report.setIncludingAveragePrice(node.attribute(attributeName(Attribute::Report::IncludesAveragePrice), "0").toUInt());
report.setMixedTime(node.attribute(attributeName(Attribute::Report::MixedTime), "0").toUInt());
report.setInvestmentsOnly(node.attribute(attributeName(Attribute::Report::Investments), "0").toUInt());
// read rows/columns tab
if (node.hasAttribute(attributeName(Attribute::Report::Budget)))
report.setBudget(node.attribute(attributeName(Attribute::Report::Budget)));
const auto rowTypeFromXML = stringToRowType(node.attribute(attributeName(Attribute::Report::RowType)));
if (rowTypeFromXML != eMyMoney::Report::RowType::Invalid)
report.setRowType(rowTypeFromXML);
else
report.setRowType(eMyMoney::Report::RowType::ExpenseIncome);
if (node.hasAttribute(attributeName(Attribute::Report::ShowRowTotals)))
report.setShowingRowTotals(node.attribute(attributeName(Attribute::Report::ShowRowTotals)).toUInt());
else if (report.rowType() == eMyMoney::Report::RowType::ExpenseIncome) // for backward compatibility
report.setShowingRowTotals(true);
report.setShowingColumnTotals(node.attribute(attributeName(Attribute::Report::ShowColumnTotals), "1").toUInt());
//check for reports with older settings which didn't have the detail attribute
const auto detailLevelFromXML = stringToDetailLevel(node.attribute(attributeName(Attribute::Report::Detail)));
if (detailLevelFromXML != eMyMoney::Report::DetailLevel::End)
report.setDetailLevel(detailLevelFromXML);
else
report.setDetailLevel(eMyMoney::Report::DetailLevel::All);
report.setIncludingMovingAverage(node.attribute(attributeName(Attribute::Report::IncludesMovingAverage), "0").toUInt());
if (report.isIncludingMovingAverage())
report.setMovingAverageDays(node.attribute(attributeName(Attribute::Report::MovingAverageDays), "1").toUInt());
report.setIncludingSchedules(node.attribute(attributeName(Attribute::Report::IncludesSchedules), "0").toUInt());
report.setIncludingTransfers(node.attribute(attributeName(Attribute::Report::IncludesTransfers), "0").toUInt());
report.setIncludingUnusedAccounts(node.attribute(attributeName(Attribute::Report::IncludesUnused), "0").toUInt());
report.setColumnsAreDays(node.attribute(attributeName(Attribute::Report::ColumnsAreDays), "0").toUInt());
// read chart tab
const auto chartTypeFromXML = stringToChartType(node.attribute(attributeName(Attribute::Report::ChartType)));
if (chartTypeFromXML != eMyMoney::Report::ChartType::End)
report.setChartType(chartTypeFromXML);
else
report.setChartType(eMyMoney::Report::ChartType::None);
report.setChartCHGridLines(node.attribute(attributeName(Attribute::Report::ChartCHGridLines), "1").toUInt());
report.setChartSVGridLines(node.attribute(attributeName(Attribute::Report::ChartSVGridLines), "1").toUInt());
report.setChartDataLabels(node.attribute(attributeName(Attribute::Report::ChartDataLabels), "1").toUInt());
report.setChartByDefault(node.attribute(attributeName(Attribute::Report::ChartByDefault), "0").toUInt());
report.setLogYAxis(node.attribute(attributeName(Attribute::Report::LogYAxis), "0").toUInt());
+ report.setNegExpenses(node.attribute(attributeName(Attribute::Report::NegExpenses), "0").toUInt());
report.setChartLineWidth(node.attribute(attributeName(Attribute::Report::ChartLineWidth), QString(MyMoneyReport::m_lineWidth)).toUInt());
// read range tab
const auto columnTypeFromXML = stringToColumnType(node.attribute(attributeName(Attribute::Report::ColumnType)));
if (columnTypeFromXML != eMyMoney::Report::ColumnType::Invalid)
report.setColumnType(columnTypeFromXML);
else
report.setColumnType(eMyMoney::Report::ColumnType::Months);
const auto dataLockFromXML = stringToDataLockAttribute(node.attribute(attributeName(Attribute::Report::DataLock)));
if (dataLockFromXML != eMyMoney::Report::DataLock::DataOptionCount)
report.setDataFilter(dataLockFromXML);
else
report.setDataFilter(eMyMoney::Report::DataLock::Automatic);
report.setDataRangeStart(node.attribute(attributeName(Attribute::Report::DataRangeStart), "0"));
report.setDataRangeEnd(node.attribute(attributeName(Attribute::Report::DataRangeEnd), "0"));
report.setDataMajorTick(node.attribute(attributeName(Attribute::Report::DataMajorTick), "0"));
report.setDataMinorTick(node.attribute(attributeName(Attribute::Report::DataMinorTick), "0"));
report.setYLabelsPrecision(node.attribute(attributeName(Attribute::Report::YLabelsPrecision), "2").toUInt());
} else if (report.reportType() == eMyMoney::Report::ReportType::QueryTable) {
// read rows/columns tab
const auto rowTypeFromXML = stringToRowType(node.attribute(attributeName(Attribute::Report::RowType)));
if (rowTypeFromXML != eMyMoney::Report::RowType::Invalid)
report.setRowType(rowTypeFromXML);
else
report.setRowType(eMyMoney::Report::RowType::Account);
unsigned qc = 0;
QStringList columns = node.attribute(attributeName(Attribute::Report::QueryColumns), "none").split(',');
foreach (const auto column, columns) {
const int queryColumnFromXML = stringToQueryColumn(column);
i = stringToQueryColumn(column);
if (queryColumnFromXML != eMyMoney::Report::QueryColumn::End)
qc |= queryColumnFromXML;
}
report.setQueryColumns(static_cast(qc));
report.setTax(node.attribute(attributeName(Attribute::Report::Tax), "0").toUInt());
report.setInvestmentsOnly(node.attribute(attributeName(Attribute::Report::Investments), "0").toUInt());
report.setLoansOnly(node.attribute(attributeName(Attribute::Report::Loans), "0").toUInt());
report.setHideTransactions(node.attribute(attributeName(Attribute::Report::HideTransactions), "0").toUInt());
report.setShowingColumnTotals(node.attribute(attributeName(Attribute::Report::ShowColumnTotals), "1").toUInt());
const auto detailLevelFromXML = stringToDetailLevel(node.attribute(attributeName(Attribute::Report::Detail), "none"));
if (detailLevelFromXML == eMyMoney::Report::DetailLevel::All)
report.setDetailLevel(detailLevelFromXML);
else
report.setDetailLevel(eMyMoney::Report::DetailLevel::None);
// read performance or capital gains tab
if (report.queryColumns() & eMyMoney::Report::QueryColumn::Performance)
report.setInvestmentSum(static_cast(node.attribute(attributeName(Attribute::Report::InvestmentSum), QString::number(static_cast(eMyMoney::Report::InvestmentSum::Period))).toInt()));
// read capital gains tab
if (report.queryColumns() & eMyMoney::Report::QueryColumn::CapitalGain) {
report.setInvestmentSum(static_cast(node.attribute(attributeName(Attribute::Report::InvestmentSum), QString::number(static_cast(eMyMoney::Report::InvestmentSum::Sold))).toInt()));
if (report.investmentSum() == eMyMoney::Report::InvestmentSum::Sold) {
report.setShowSTLTCapitalGains(node.attribute(attributeName(Attribute::Report::ShowSTLTCapitalGains), "0").toUInt());
report.setSettlementPeriod(node.attribute(attributeName(Attribute::Report::SettlementPeriod), "3").toUInt());
report.setTermSeparator(QDate::fromString(node.attribute(attributeName(Attribute::Report::TermsSeparator), QDate::currentDate().addYears(-1).toString(Qt::ISODate)),Qt::ISODate));
}
}
} else if (report.reportType() == eMyMoney::Report::ReportType::InfoTable) {
if (node.hasAttribute(attributeName(Attribute::Report::ShowRowTotals)))
report.setShowingRowTotals(node.attribute(attributeName(Attribute::Report::ShowRowTotals)).toUInt());
else
report.setShowingRowTotals(true);
}
QDomNode child = node.firstChild();
while (!child.isNull() && child.isElement()) {
QDomElement c = child.toElement();
if (elementName(Element::Report::Text) == c.tagName() && c.hasAttribute(attributeName(Attribute::Report::Pattern))) {
report.setTextFilter(QRegExp(c.attribute(attributeName(Attribute::Report::Pattern)),
c.attribute(attributeName(Attribute::Report::CaseSensitive), "1").toUInt()
? Qt::CaseSensitive : Qt::CaseInsensitive,
c.attribute(attributeName(Attribute::Report::RegEx), "1").toUInt()
? QRegExp::Wildcard : QRegExp::RegExp),
c.attribute(attributeName(Attribute::Report::InvertText), "0").toUInt());
}
if (elementName(Element::Report::Type) == c.tagName() && c.hasAttribute(attributeName(Attribute::Report::Type))) {
i = stringToTypeAttribute(c.attribute(attributeName(Attribute::Report::Type)));
if (i != -1)
report.addType(i);
}
if (elementName(Element::Report::State) == c.tagName() && c.hasAttribute(attributeName(Attribute::Report::State))) {
i = stringToStateAttribute(c.attribute(attributeName(Attribute::Report::State)));
if (i != -1)
report.addState(i);
}
if (elementName(Element::Report::Number) == c.tagName())
report.setNumberFilter(c.attribute(attributeName(Attribute::Report::From)), c.attribute(attributeName(Attribute::Report::To)));
if (elementName(Element::Report::Amount) == c.tagName())
report.setAmountFilter(MyMoneyMoney(c.attribute(attributeName(Attribute::Report::From), "0/100")), MyMoneyMoney(c.attribute(attributeName(Attribute::Report::To), "0/100")));
if (elementName(Element::Report::Dates) == c.tagName()) {
QDate from, to;
if (c.hasAttribute(attributeName(Attribute::Report::From)))
from = QDate::fromString(c.attribute(attributeName(Attribute::Report::From)), Qt::ISODate);
if (c.hasAttribute(attributeName(Attribute::Report::To)))
to = QDate::fromString(c.attribute(attributeName(Attribute::Report::To)), Qt::ISODate);
report.setDateFilter(from, to);
}
if (elementName(Element::Report::Payee) == c.tagName())
report.addPayee(c.attribute(attributeName(Attribute::Report::ID)));
if (elementName(Element::Report::Tag) == c.tagName())
report.addTag(c.attribute(attributeName(Attribute::Report::ID)));
if (elementName(Element::Report::Category) == c.tagName() && c.hasAttribute(attributeName(Attribute::Report::ID)))
report.addCategory(c.attribute(attributeName(Attribute::Report::ID)));
if (elementName(Element::Report::Account) == c.tagName() && c.hasAttribute(attributeName(Attribute::Report::ID)))
report.addAccount(c.attribute(attributeName(Attribute::Report::ID)));
if (elementName(Element::Report::AccountGroup) == c.tagName() && c.hasAttribute(attributeName(Attribute::Report::Group))) {
i = stringToAccountTypeAttribute(c.attribute(attributeName(Attribute::Report::Group)));
if (i != -1)
report.addAccountGroup(static_cast(i));
}
child = child.nextSibling();
}
return report;
}
void writeReport(const MyMoneyReport &report, QDomDocument &document, QDomElement &parent)
{
auto el = document.createElement(nodeName(Node::Report));
// No matter what changes, be sure to have a 'type' attribute. Only change
// the major type if it becomes impossible to maintain compatibility with
// older versions of the program as new features are added to the reports.
// Feel free to change the minor type every time a change is made here.
// write report's internals
if (report.reportType() == eMyMoney::Report::ReportType::PivotTable)
el.setAttribute(attributeName(Attribute::Report::Type), "pivottable 1.15");
else if (report.reportType() == eMyMoney::Report::ReportType::QueryTable)
el.setAttribute(attributeName(Attribute::Report::Type), "querytable 1.14");
else if (report.reportType() == eMyMoney::Report::ReportType::InfoTable)
el.setAttribute(attributeName(Attribute::Report::Type), "infotable 1.0");
el.setAttribute(attributeName(Attribute::Report::Group), report.group());
el.setAttribute(attributeName(Attribute::Report::ID), report.id());
// write general tab
auto anonymous = false;
if (anonymous) {
el.setAttribute(attributeName(Attribute::Report::Name), report.id());
el.setAttribute(attributeName(Attribute::Report::Comment), QString(report.comment()).fill('x'));
} else {
el.setAttribute(attributeName(Attribute::Report::Name), report.name());
el.setAttribute(attributeName(Attribute::Report::Comment), report.comment());
}
el.setAttribute(attributeName(Attribute::Report::ConvertCurrency), report.isConvertCurrency());
el.setAttribute(attributeName(Attribute::Report::Favorite), report.isFavorite());
el.setAttribute(attributeName(Attribute::Report::SkipZero), report.isSkippingZero());
el.setAttribute(attributeName(Attribute::Report::DateLock), dateLockAttributeToString(static_cast(report.dateRange())));
if (report.reportType() == eMyMoney::Report::ReportType::PivotTable) {
// write report's internals
el.setAttribute(attributeName(Attribute::Report::IncludesActuals), report.isIncludingBudgetActuals());
el.setAttribute(attributeName(Attribute::Report::IncludesForecast), report.isIncludingForecast());
el.setAttribute(attributeName(Attribute::Report::IncludesPrice), report.isIncludingPrice());
el.setAttribute(attributeName(Attribute::Report::IncludesAveragePrice), report.isIncludingAveragePrice());
el.setAttribute(attributeName(Attribute::Report::MixedTime), report.isMixedTime());
el.setAttribute(attributeName(Attribute::Report::Investments), report.isInvestmentsOnly()); // it's setable in rows/columns tab of querytable, but here it is internal setting
// write rows/columns tab
if (!report.budget().isEmpty())
el.setAttribute(attributeName(Attribute::Report::Budget), report.budget());
el.setAttribute(attributeName(Attribute::Report::RowType), reportNames(report.rowType()));
el.setAttribute(attributeName(Attribute::Report::ShowRowTotals), report.isShowingRowTotals());
el.setAttribute(attributeName(Attribute::Report::ShowColumnTotals), report.isShowingColumnTotals());
el.setAttribute(attributeName(Attribute::Report::Detail), reportNames(report.detailLevel()));
el.setAttribute(attributeName(Attribute::Report::IncludesMovingAverage), report.isIncludingMovingAverage());
if (report.isIncludingMovingAverage())
el.setAttribute(attributeName(Attribute::Report::MovingAverageDays), report.movingAverageDays());
el.setAttribute(attributeName(Attribute::Report::IncludesSchedules), report.isIncludingSchedules());
el.setAttribute(attributeName(Attribute::Report::IncludesTransfers), report.isIncludingTransfers());
el.setAttribute(attributeName(Attribute::Report::IncludesUnused), report.isIncludingUnusedAccounts());
el.setAttribute(attributeName(Attribute::Report::ColumnsAreDays), report.isColumnsAreDays());
el.setAttribute(attributeName(Attribute::Report::ChartType), reportNames(report.chartType()));
el.setAttribute(attributeName(Attribute::Report::ChartCHGridLines), report.isChartCHGridLines());
el.setAttribute(attributeName(Attribute::Report::ChartSVGridLines), report.isChartSVGridLines());
el.setAttribute(attributeName(Attribute::Report::ChartDataLabels), report.isChartDataLabels());
el.setAttribute(attributeName(Attribute::Report::ChartByDefault), report.isChartByDefault());
el.setAttribute(attributeName(Attribute::Report::LogYAxis), report.isLogYAxis());
+ el.setAttribute(attributeName(Attribute::Report::NegExpenses), report.isNegExpenses());
el.setAttribute(attributeName(Attribute::Report::ChartLineWidth), report.chartLineWidth());
el.setAttribute(attributeName(Attribute::Report::ColumnType), reportNames(report.columnType()));
el.setAttribute(attributeName(Attribute::Report::DataLock), reportNames(report.dataFilter()));
el.setAttribute(attributeName(Attribute::Report::DataRangeStart), report.dataRangeStart());
el.setAttribute(attributeName(Attribute::Report::DataRangeEnd), report.dataRangeEnd());
el.setAttribute(attributeName(Attribute::Report::DataMajorTick), report.dataMajorTick());
el.setAttribute(attributeName(Attribute::Report::DataMinorTick), report.dataMinorTick());
el.setAttribute(attributeName(Attribute::Report::YLabelsPrecision), report.yLabelsPrecision());
} else if (report.reportType() == eMyMoney::Report::ReportType::QueryTable) {
// write rows/columns tab
el.setAttribute(attributeName(Attribute::Report::RowType), reportNames(report.rowType()));
QStringList columns;
unsigned qc = report.queryColumns();
unsigned it_qc = eMyMoney::Report::QueryColumn::Begin;
unsigned index = 1;
while (it_qc != eMyMoney::Report::QueryColumn::End) {
if (qc & it_qc)
columns += reportNamesForQC(static_cast(it_qc));
it_qc *= 2;
index++;
}
el.setAttribute(attributeName(Attribute::Report::QueryColumns), columns.join(","));
el.setAttribute(attributeName(Attribute::Report::Tax), report.isTax());
el.setAttribute(attributeName(Attribute::Report::Investments), report.isInvestmentsOnly());
el.setAttribute(attributeName(Attribute::Report::Loans), report.isLoansOnly());
el.setAttribute(attributeName(Attribute::Report::HideTransactions), report.isHideTransactions());
el.setAttribute(attributeName(Attribute::Report::ShowColumnTotals), report.isShowingColumnTotals());
el.setAttribute(attributeName(Attribute::Report::Detail), reportNames(report.detailLevel()));
// write performance tab
if (report.queryColumns() & eMyMoney::Report::QueryColumn::Performance || report.queryColumns() & eMyMoney::Report::QueryColumn::CapitalGain)
el.setAttribute(attributeName(Attribute::Report::InvestmentSum), static_cast(report.investmentSum()));
// write capital gains tab
if (report.queryColumns() & eMyMoney::Report::QueryColumn::CapitalGain) {
if (report.investmentSum() == eMyMoney::Report::InvestmentSum::Sold) {
el.setAttribute(attributeName(Attribute::Report::SettlementPeriod), report.settlementPeriod());
el.setAttribute(attributeName(Attribute::Report::ShowSTLTCapitalGains), report.isShowingSTLTCapitalGains());
el.setAttribute(attributeName(Attribute::Report::TermsSeparator), report.termSeparator().toString(Qt::ISODate));
}
}
} else if (report.reportType() == eMyMoney::Report::ReportType::InfoTable)
el.setAttribute(attributeName(Attribute::Report::ShowRowTotals), report.isShowingRowTotals());
//
// Text Filter
//
QRegExp textfilter;
if (report.textFilter(textfilter)) {
QDomElement f = document.createElement(elementName(Element::Report::Text));
f.setAttribute(attributeName(Attribute::Report::Pattern), textfilter.pattern());
f.setAttribute(attributeName(Attribute::Report::CaseSensitive), (textfilter.caseSensitivity() == Qt::CaseSensitive) ? 1 : 0);
f.setAttribute(attributeName(Attribute::Report::RegEx), (textfilter.patternSyntax() == QRegExp::Wildcard) ? 1 : 0);
f.setAttribute(attributeName(Attribute::Report::InvertText), report.MyMoneyTransactionFilter::isInvertingText());
el.appendChild(f);
}
//
// Type & State Filters
//
QList typelist;
if (report.types(typelist) && ! typelist.empty()) {
// iterate over payees, and add each one
QList