diff --git a/kmymoney/mymoney/mymoneyreport.cpp b/kmymoney/mymoney/mymoneyreport.cpp index 504a10615..4889ee7d8 100644 --- a/kmymoney/mymoney/mymoneyreport.cpp +++ b/kmymoney/mymoney/mymoneyreport.cpp @@ -1,1035 +1,1039 @@ /*************************************************************************** mymoneyreport.cpp ------------------- begin : Sun July 4 2004 copyright : (C) 2004-2005 by Ace Jones email : acejones@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * 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 "mymoneyreport.h" #include // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyfile.h" #include "mymoneystoragenames.h" using namespace MyMoneyStorageNodes; // define this to debug reports // #define DEBUG_REPORTS const QStringList MyMoneyReport::kRowTypeText = QString("none,assetliability,expenseincome,category,topcategory,account,tag,payee,month,week,topaccount,topaccount-account,equitytype,accounttype,institution,budget,budgetactual,schedule,accountinfo,accountloaninfo,accountreconcile,cashflow").split(','); const QStringList MyMoneyReport::kColumnTypeText = QString("none,months,bimonths,quarters,4,5,6,weeks,8,9,10,11,years").split(','); // if you add names here, don't forget to update the bitmap for EQueryColumns // and shift the bit for eQCend one position to the left const QStringList MyMoneyReport::kQueryColumnsText = QString("none,number,payee,category,tag,memo,account,reconcileflag,action,shares,price,performance,loan,balance,capitalgain").split(','); const MyMoneyReport::EReportType MyMoneyReport::kTypeArray[] = { eNoReport, ePivotTable, ePivotTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, ePivotTable, ePivotTable, eInfoTable, eInfoTable, eInfoTable, eQueryTable, eQueryTable, eNoReport }; const QStringList MyMoneyReport::kDetailLevelText = QString("none,all,top,group,total,invalid").split(','); const QStringList MyMoneyReport::kChartTypeText = QString("none,line,bar,pie,ring,stackedbar").split(','); // This should live in mymoney/mymoneytransactionfilter.h const QStringList kTypeText = QString("all,payments,deposits,transfers,none").split(','); const QStringList kStateText = QString("all,notreconciled,cleared,reconciled,frozen,none").split(','); const QStringList kDateLockText = QString("alldates,untiltoday,currentmonth,currentyear,monthtodate,yeartodate,yeartomonth,lastmonth,lastyear,last7days,last30days,last3months,last6months,last12months,next7days,next30days,next3months,next6months,next12months,userdefined,last3tonext3months,last11Months,currentQuarter,lastQuarter,nextQuarter,currentFiscalYear,lastFiscalYear,today,next18months").split(','); const QStringList kDataLockText = QString("automatic,userdefined").split(','); const QStringList kAccountTypeText = QString("unknown,checkings,savings,cash,creditcard,loan,certificatedep,investment,moneymarket,asset,liability,currency,income,expense,assetloan,stock,equity,invalid").split(','); MyMoneyReport::MyMoneyReport() : m_name("Unconfigured Pivot Table Report"), m_detailLevel(eDetailNone), m_investmentSum(eSumSold), m_hideTransactions(false), m_convertCurrency(true), m_favorite(false), m_tax(false), m_investments(false), m_loans(false), m_reportType(kTypeArray[eExpenseIncome]), m_rowType(eExpenseIncome), m_columnType(eMonths), m_columnsAreDays(false), m_queryColumns(eQCnone), m_dateLock(MyMoneyTransactionFilter::userDefined), m_accountGroupFilter(false), m_chartType(eChartLine), m_chartDataLabels(true), m_chartCHGridLines(true), m_chartSVGridLines(true), m_chartByDefault(false), m_logYaxis(false), m_dataRangeStart('0'), m_dataRangeEnd('0'), m_dataMajorTick('0'), m_dataMinorTick('0'), m_yLabelsPrecision(2), m_dataLock(MyMoneyReport::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) { m_chartLineWidth = m_lineWidth; } MyMoneyReport::MyMoneyReport(const QString& id, const MyMoneyReport& right) : MyMoneyObject(id), m_movingAverageDays(0), m_currentDateColumn(0) { *this = right; setId(id); } MyMoneyReport::MyMoneyReport(ERowType _rt, unsigned _ct, dateOptionE _dl, EDetailLevel _ss, const QString& _name, const QString& _comment) : m_name(_name), m_comment(_comment), m_detailLevel(_ss), m_investmentSum(_ct & eQCcapitalgain ? eSumSold : eSumPeriod), m_hideTransactions(false), m_convertCurrency(true), m_favorite(false), m_tax(false), m_investments(false), m_loans(false), m_reportType(kTypeArray[_rt]), m_rowType(_rt), m_columnType(eMonths), m_columnsAreDays(false), m_queryColumns(eQCnone), m_dateLock(_dl), m_accountGroupFilter(false), m_chartType(eChartLine), m_chartDataLabels(true), m_chartCHGridLines(true), m_chartSVGridLines(true), m_chartByDefault(false), m_logYaxis(false), m_dataRangeStart('0'), m_dataRangeEnd('0'), m_dataMajorTick('0'), m_dataMinorTick('0'), m_yLabelsPrecision(2), m_dataLock(MyMoneyReport::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) { //set initial values m_chartLineWidth = m_lineWidth; //set report type if (m_reportType == ePivotTable) m_columnType = static_cast(_ct); if (m_reportType == eQueryTable) m_queryColumns = static_cast(_ct); setDateFilter(_dl); //throw exception if the type is inconsistent if ((_rt > static_cast(sizeof(kTypeArray) / sizeof(kTypeArray[0]))) || (m_reportType == eNoReport)) throw MYMONEYEXCEPTION("Invalid report type"); //add the corresponding account groups if (_rt == MyMoneyReport::eAssetLiability) { addAccountGroup(MyMoneyAccount::Asset); addAccountGroup(MyMoneyAccount::Liability); m_showRowTotals = true; } if (_rt == MyMoneyReport::eAccount) { addAccountGroup(MyMoneyAccount::Asset); addAccountGroup(MyMoneyAccount::AssetLoan); addAccountGroup(MyMoneyAccount::Cash); addAccountGroup(MyMoneyAccount::Checkings); addAccountGroup(MyMoneyAccount::CreditCard); if (KMyMoneyGlobalSettings::expertMode()) addAccountGroup(MyMoneyAccount::Equity); addAccountGroup(MyMoneyAccount::Expense); addAccountGroup(MyMoneyAccount::Income); addAccountGroup(MyMoneyAccount::Liability); addAccountGroup(MyMoneyAccount::Loan); addAccountGroup(MyMoneyAccount::Savings); addAccountGroup(MyMoneyAccount::Stock); m_showRowTotals = true; } if (_rt == MyMoneyReport::eExpenseIncome) { addAccountGroup(MyMoneyAccount::Expense); addAccountGroup(MyMoneyAccount::Income); 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 == MyMoneyReport::eBudget || _rt == MyMoneyReport::eBudgetActual) { addAccountGroup(MyMoneyAccount::Expense); addAccountGroup(MyMoneyAccount::Income); } if (_rt == MyMoneyReport::eAccountInfo) { addAccountGroup(MyMoneyAccount::Asset); addAccountGroup(MyMoneyAccount::Liability); } //cash flow reports show splits for all account groups if (_rt == MyMoneyReport::eCashFlow) { addAccountGroup(MyMoneyAccount::Expense); addAccountGroup(MyMoneyAccount::Income); addAccountGroup(MyMoneyAccount::Asset); addAccountGroup(MyMoneyAccount::Liability); } #ifdef DEBUG_REPORTS QDebug out = qDebug(); out << _name << toString(_rt) << toString(m_reportType); foreach(const MyMoneyAccount::accountTypeE accountType, m_accountGroups) out << MyMoneyAccount::accountTypeToString(accountType); if (m_accounts.size() > 0) out << m_accounts; #endif } MyMoneyReport::MyMoneyReport(const QDomElement& node) : MyMoneyObject(node), m_currentDateColumn(0) { // properly initialize the object before reading it *this = MyMoneyReport(); if (!read(node)) clearId(); } void MyMoneyReport::clearTransactionFilter() { m_accountGroupFilter = false; m_accountGroups.clear(); MyMoneyTransactionFilter::clear(); } 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; } void MyMoneyReport::setRowType(ERowType _rt) { m_rowType = _rt; m_reportType = kTypeArray[_rt]; m_accountGroupFilter = false; m_accountGroups.clear(); if (_rt == MyMoneyReport::eAssetLiability) { addAccountGroup(MyMoneyAccount::Asset); addAccountGroup(MyMoneyAccount::Liability); } if (_rt == MyMoneyReport::eExpenseIncome) { addAccountGroup(MyMoneyAccount::Expense); addAccountGroup(MyMoneyAccount::Income); } } bool MyMoneyReport::accountGroups(QList& list) const { bool result = m_accountGroupFilter; if (result) { QList::const_iterator it_group = m_accountGroups.begin(); while (it_group != m_accountGroups.end()) { list += (*it_group); ++it_group; } } return result; } void MyMoneyReport::addAccountGroup(MyMoneyAccount::accountTypeE type) { if (!m_accountGroups.isEmpty() && type != MyMoneyAccount::UnknownAccountType) { if (m_accountGroups.contains(type)) return; } m_accountGroupFilter = true; if (type != MyMoneyAccount::UnknownAccountType) m_accountGroups.push_back(type); } bool MyMoneyReport::includesAccountGroup(MyMoneyAccount::accountTypeE type) const { bool result = (! m_accountGroupFilter) || (isIncludingTransfers() && m_rowType == MyMoneyReport::eExpenseIncome) || m_accountGroups.contains(type); return result; } bool MyMoneyReport::includes(const MyMoneyAccount& acc) const { bool result = false; if (includesAccountGroup(acc.accountGroup())) { switch (acc.accountGroup()) { case MyMoneyAccount::Income: case MyMoneyAccount::Expense: if (isTax()) result = (acc.value("Tax") == "Yes") && includesCategory(acc.id()); else result = includesCategory(acc.id()); break; case MyMoneyAccount::Asset: case MyMoneyAccount::Liability: if (isLoansOnly()) result = acc.isLoan() && includesAccount(acc.id()); else if (isInvestmentsOnly()) result = acc.isInvest() && includesAccount(acc.id()); else if (isIncludingTransfers() && m_rowType == MyMoneyReport::eExpenseIncome) // 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 MyMoneyAccount::Equity: + if (isInvestmentsOnly()) + result = (isIncludingPrice() || isIncludingAveragePrice()) && acc.isInvest() && includesAccount(acc.id()); + break; default: result = includesAccount(acc.id()); } } return result; } void MyMoneyReport::write(QDomElement& e, QDomDocument *doc, bool anonymous) const { // 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 (m_reportType == ePivotTable) e.setAttribute(getAttrName(anType), "pivottable 1.15"); else if (m_reportType == eQueryTable) e.setAttribute(getAttrName(anType), "querytable 1.14"); else if (m_reportType == eInfoTable) e.setAttribute(getAttrName(anType), "infotable 1.0"); e.setAttribute(getAttrName(anGroup), m_group); e.setAttribute(getAttrName(anID), m_id); // write general tab if (anonymous) { e.setAttribute(getAttrName(anName), m_id); e.setAttribute(getAttrName(anComment), QString(m_comment).fill('x')); } else { e.setAttribute(getAttrName(anName), m_name); e.setAttribute(getAttrName(anComment), m_comment); } e.setAttribute(getAttrName(anConvertCurrency), m_convertCurrency); e.setAttribute(getAttrName(anFavorite), m_favorite); e.setAttribute(getAttrName(anSkipZero), m_skipZero); e.setAttribute(getAttrName(anDateLock), kDateLockText[m_dateLock]); if (m_reportType == ePivotTable) { // write report's internals e.setAttribute(getAttrName(anIncludesActuals), m_includeBudgetActuals); e.setAttribute(getAttrName(anIncludesForecast), m_includeForecast); e.setAttribute(getAttrName(anIncludesPrice), m_includePrice); e.setAttribute(getAttrName(anIncludesAveragePrice), m_includeAveragePrice); e.setAttribute(getAttrName(anMixedTime), m_mixedTime); e.setAttribute(getAttrName(anInvestments), m_investments); // it's setable in rows/columns tab of querytable, but here it is internal setting // write rows/columns tab if (!m_budgetId.isEmpty()) e.setAttribute(getAttrName(anBudget), m_budgetId); e.setAttribute(getAttrName(anRowType), kRowTypeText[m_rowType]); e.setAttribute(getAttrName(anShowRowTotals), m_showRowTotals); e.setAttribute(getAttrName(anShowColumnTotals), m_showColumnTotals); e.setAttribute(getAttrName(anDetail), kDetailLevelText[m_detailLevel]); e.setAttribute(getAttrName(anIncludesMovingAverage), m_includeMovingAverage); if (m_includeMovingAverage) e.setAttribute(getAttrName(anMovingAverageDays), m_movingAverageDays); e.setAttribute(getAttrName(anIncludesSchedules), m_includeSchedules); e.setAttribute(getAttrName(anIncludesTransfers), m_includeTransfers); e.setAttribute(getAttrName(anIncludesUnused), m_includeUnusedAccounts); e.setAttribute(getAttrName(anColumnsAreDays), m_columnsAreDays); // write chart tab if (m_chartType < 0 || m_chartType >= kChartTypeText.size()) { qDebug("m_chartType out of bounds with %d on report of type %d. Default to none.", m_chartType, m_reportType); e.setAttribute(getAttrName(anChartType), kChartTypeText[eChartNone]); } else e.setAttribute(getAttrName(anChartType), kChartTypeText[m_chartType]); e.setAttribute(getAttrName(anChartCHGridLines), m_chartCHGridLines); e.setAttribute(getAttrName(anChartSVGridLines), m_chartSVGridLines); e.setAttribute(getAttrName(anChartDataLabels), m_chartDataLabels); e.setAttribute(getAttrName(anChartByDefault), m_chartByDefault); e.setAttribute(getAttrName(anLogYAxis), m_logYaxis); e.setAttribute(getAttrName(anChartLineWidth), m_chartLineWidth); e.setAttribute(getAttrName(anColumnType), kColumnTypeText[m_columnType]); e.setAttribute(getAttrName(anDataLock), kDataLockText[m_dataLock]); e.setAttribute(getAttrName(anDataRangeStart), m_dataRangeStart); e.setAttribute(getAttrName(anDataRangeEnd), m_dataRangeEnd); e.setAttribute(getAttrName(anDataMajorTick), m_dataMajorTick); e.setAttribute(getAttrName(anDataMinorTick), m_dataMinorTick); e.setAttribute(getAttrName(anYLabelsPrecision), m_yLabelsPrecision); } else if (m_reportType == eQueryTable) { // write rows/columns tab e.setAttribute(getAttrName(anRowType), kRowTypeText[m_rowType]); QStringList columns; unsigned qc = m_queryColumns; unsigned it_qc = eQCbegin; unsigned index = 1; while (it_qc != eQCend) { if (qc & it_qc) columns += kQueryColumnsText[index]; it_qc *= 2; index++; } e.setAttribute(getAttrName(anQueryColumns), columns.join(",")); e.setAttribute(getAttrName(anTax), m_tax); e.setAttribute(getAttrName(anInvestments), m_investments); e.setAttribute(getAttrName(anLoans), m_loans); e.setAttribute(getAttrName(anHideTransactions), m_hideTransactions); e.setAttribute(getAttrName(anShowColumnTotals), m_showColumnTotals); e.setAttribute(getAttrName(anDetail), kDetailLevelText[m_detailLevel]); // write performance tab if (m_queryColumns & eQCperformance || m_queryColumns & eQCcapitalgain) e.setAttribute(getAttrName(anInvestmentSum), m_investmentSum); // write capital gains tab if (m_queryColumns & eQCcapitalgain) { if (m_investmentSum == MyMoneyReport::eSumSold) { e.setAttribute(getAttrName(anSettlementPeriod), m_settlementPeriod); e.setAttribute(getAttrName(anShowSTLTCapitalGains), m_showSTLTCapitalGains); e.setAttribute(getAttrName(anTermsSeparator), m_tseparator.toString(Qt::ISODate)); } } } else if (m_reportType == eInfoTable) e.setAttribute(getAttrName(anShowRowTotals), m_showRowTotals); // // Text Filter // QRegExp textfilter; if (textFilter(textfilter)) { QDomElement f = doc->createElement(getElName(enText)); f.setAttribute(getAttrName(anPattern), textfilter.pattern()); f.setAttribute(getAttrName(anCaseSensitive), (textfilter.caseSensitivity() == Qt::CaseSensitive) ? 1 : 0); f.setAttribute(getAttrName(anRegEx), (textfilter.patternSyntax() == QRegExp::Wildcard) ? 1 : 0); f.setAttribute(getAttrName(anInvertText), m_invertText); e.appendChild(f); } // // Type & State Filters // QList typelist; if (types(typelist) && ! typelist.empty()) { // iterate over payees, and add each one QList::const_iterator it_type = typelist.constBegin(); while (it_type != typelist.constEnd()) { QDomElement p = doc->createElement(getElName(enType)); p.setAttribute(getAttrName(anType), kTypeText[*it_type]); e.appendChild(p); ++it_type; } } QList statelist; if (states(statelist) && ! statelist.empty()) { // iterate over payees, and add each one QList::const_iterator it_state = statelist.constBegin(); while (it_state != statelist.constEnd()) { QDomElement p = doc->createElement(getElName(enState)); p.setAttribute(getAttrName(anState), kStateText[*it_state]); e.appendChild(p); ++it_state; } } // // Number Filter // QString nrFrom, nrTo; if (numberFilter(nrFrom, nrTo)) { QDomElement f = doc->createElement(getElName(enNumber)); f.setAttribute(getAttrName(anFrom), nrFrom); f.setAttribute(getAttrName(anTo), nrTo); e.appendChild(f); } // // Amount Filter // MyMoneyMoney from, to; if (amountFilter(from, to)) { // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&); QDomElement f = doc->createElement(getElName(enAmount)); f.setAttribute(getAttrName(anFrom), from.toString()); f.setAttribute(getAttrName(anTo), to.toString()); e.appendChild(f); } // // Payees Filter // QStringList payeelist; if (payees(payeelist)) { if (payeelist.empty()) { QDomElement p = doc->createElement(getElName(enPayee)); e.appendChild(p); } else { // iterate over payees, and add each one QStringList::const_iterator it_payee = payeelist.constBegin(); while (it_payee != payeelist.constEnd()) { QDomElement p = doc->createElement(getElName(enPayee)); p.setAttribute(getAttrName(anID), *it_payee); e.appendChild(p); ++it_payee; } } } // // Tags Filter // QStringList taglist; if (tags(taglist)) { if (taglist.empty()) { QDomElement p = doc->createElement(getElName(enTag)); e.appendChild(p); } else { // iterate over tags, and add each one QStringList::const_iterator it_tag = taglist.constBegin(); while (it_tag != taglist.constEnd()) { QDomElement p = doc->createElement(getElName(enTag)); p.setAttribute(getAttrName(anID), *it_tag); e.appendChild(p); ++it_tag; } } } // // Account Groups Filter // QList accountgrouplist; if (accountGroups(accountgrouplist)) { // iterate over accounts, and add each one QList::const_iterator it_group = accountgrouplist.constBegin(); while (it_group != accountgrouplist.constEnd()) { QDomElement p = doc->createElement(getElName(enAccountGroup)); p.setAttribute(getAttrName(anGroup), kAccountTypeText[*it_group]); e.appendChild(p); ++it_group; } } // // Accounts Filter // QStringList accountlist; if (accounts(accountlist)) { // iterate over accounts, and add each one QStringList::const_iterator it_account = accountlist.constBegin(); while (it_account != accountlist.constEnd()) { QDomElement p = doc->createElement(getElName(enAccount)); p.setAttribute(getAttrName(anID), *it_account); e.appendChild(p); ++it_account; } } // // Categories Filter // accountlist.clear(); if (categories(accountlist)) { // iterate over accounts, and add each one QStringList::const_iterator it_account = accountlist.constBegin(); while (it_account != accountlist.constEnd()) { QDomElement p = doc->createElement(getElName(enCategory)); p.setAttribute(getAttrName(anID), *it_account); e.appendChild(p); ++it_account; } } // // Date Filter // if (m_dateLock == MyMoneyTransactionFilter::userDefined) { QDate dateFrom, dateTo; if (dateFilter(dateFrom, dateTo)) { QDomElement f = doc->createElement(getElName(enDates)); if (dateFrom.isValid()) f.setAttribute(getAttrName(anFrom), dateFrom.toString(Qt::ISODate)); if (dateTo.isValid()) f.setAttribute(getAttrName(anTo), dateTo.toString(Qt::ISODate)); e.appendChild(f); } } } bool MyMoneyReport::read(const QDomElement& e) { // 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) if (e.tagName().compare(nodeNames[nnReport]) != 0) return false; // read report's internals QString type = e.attribute(getAttrName(anType)); if (type.startsWith(QLatin1String("pivottable"))) m_reportType = ePivotTable; else if (type.startsWith(QLatin1String("querytable"))) m_reportType = eQueryTable; else if (type.startsWith(QLatin1String("infotable"))) m_reportType = eInfoTable; else return false; m_group = e.attribute(getAttrName(anGroup)); m_id = e.attribute(getAttrName(anID)); clearTransactionFilter(); // read date tab QString datelockstr = e.attribute(getAttrName(anDateLock), "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 = kDateLockText.indexOf(datelockstr); if (i == -1) i = MyMoneyTransactionFilter::userDefined; } setDateFilter(static_cast(i)); // read general tab m_name = e.attribute(getAttrName(anName)); m_comment = e.attribute(getAttrName(anComment), "Extremely old report"); m_convertCurrency = e.attribute(getAttrName(anConvertCurrency), "1").toUInt(); m_favorite = e.attribute(getAttrName(anFavorite), "0").toUInt(); m_skipZero = e.attribute(getAttrName(anSkipZero), "0").toUInt(); if (m_reportType == ePivotTable) { // read report's internals m_includeBudgetActuals = e.attribute(getAttrName(anIncludesActuals), "0").toUInt(); m_includeForecast = e.attribute(getAttrName(anIncludesForecast), "0").toUInt(); m_includePrice = e.attribute(getAttrName(anIncludesPrice), "0").toUInt(); m_includeAveragePrice = e.attribute(getAttrName(anIncludesAveragePrice), "0").toUInt(); m_mixedTime = e.attribute(getAttrName(anMixedTime), "0").toUInt(); m_investments = e.attribute(getAttrName(anInvestments), "0").toUInt(); // read rows/columns tab if (e.hasAttribute(getAttrName(anBudget))) m_budgetId = e.attribute(getAttrName(anBudget)); i = kRowTypeText.indexOf(e.attribute(getAttrName(anRowType))); if (i != -1) setRowType(static_cast(i)); else setRowType(eExpenseIncome); if (e.hasAttribute(getAttrName(anShowRowTotals))) m_showRowTotals = e.attribute(getAttrName(anShowRowTotals)).toUInt(); else if (rowType() == eExpenseIncome) // for backward compatibility m_showRowTotals = true; m_showColumnTotals = e.attribute(getAttrName(anShowColumnTotals), "1").toUInt(); //check for reports with older settings which didn't have the detail attribute i = kDetailLevelText.indexOf(e.attribute(getAttrName(anDetail))); if (i != -1) m_detailLevel = static_cast(i); else m_detailLevel = eDetailAll; m_includeMovingAverage = e.attribute(getAttrName(anIncludesMovingAverage), "0").toUInt(); if (m_includeMovingAverage) m_movingAverageDays = e.attribute(getAttrName(anMovingAverageDays), "1").toUInt(); m_includeSchedules = e.attribute(getAttrName(anIncludesSchedules), "0").toUInt(); m_includeTransfers = e.attribute(getAttrName(anIncludesTransfers), "0").toUInt(); m_includeUnusedAccounts = e.attribute(getAttrName(anIncludesUnused), "0").toUInt(); m_columnsAreDays = e.attribute(getAttrName(anColumnsAreDays), "0").toUInt(); // read chart tab i = kChartTypeText.indexOf(e.attribute(getAttrName(anChartType))); if (i != -1) m_chartType = static_cast(i); else m_chartType = eChartNone; m_chartCHGridLines = e.attribute(getAttrName(anChartCHGridLines), "1").toUInt(); m_chartSVGridLines = e.attribute(getAttrName(anChartSVGridLines), "1").toUInt(); m_chartDataLabels = e.attribute(getAttrName(anChartDataLabels), "1").toUInt(); m_chartByDefault = e.attribute(getAttrName(anChartByDefault), "0").toUInt(); m_logYaxis = e.attribute(getAttrName(anLogYAxis), "0").toUInt(); m_chartLineWidth = e.attribute(getAttrName(anChartLineWidth), QString(m_lineWidth)).toUInt(); // read range tab i = kColumnTypeText.indexOf(e.attribute(getAttrName(anColumnType))); if (i != -1) setColumnType(static_cast(i)); else setColumnType(eMonths); i = kDataLockText.indexOf(e.attribute(getAttrName(anDataLock))); if (i != -1) setDataFilter(static_cast(i)); else setDataFilter(MyMoneyReport::automatic); m_dataRangeStart = e.attribute(getAttrName(anDataRangeStart), "0"); m_dataRangeEnd = e.attribute(getAttrName(anDataRangeEnd), "0"); m_dataMajorTick = e.attribute(getAttrName(anDataMajorTick), "0"); m_dataMinorTick = e.attribute(getAttrName(anDataMinorTick), "0"); m_yLabelsPrecision = e.attribute(getAttrName(anYLabelsPrecision), "2").toUInt(); } else if (m_reportType == eQueryTable) { // read rows/columns tab i = kRowTypeText.indexOf(e.attribute(getAttrName(anRowType))); if (i != -1) setRowType(static_cast(i)); else setRowType(eAccount); unsigned qc = 0; QStringList columns = e.attribute(getAttrName(anQueryColumns), "none").split(','); foreach (const auto column, columns) { i = kQueryColumnsText.indexOf(column); if (i > 0) qc |= (1 << (i - 1)); } setQueryColumns(static_cast(qc)); m_tax = e.attribute(getAttrName(anTax), "0").toUInt(); m_investments = e.attribute(getAttrName(anInvestments), "0").toUInt(); m_loans = e.attribute(getAttrName(anLoans), "0").toUInt(); m_hideTransactions = e.attribute(getAttrName(anHideTransactions), "0").toUInt(); m_showColumnTotals = e.attribute(getAttrName(anShowColumnTotals), "1").toUInt(); m_detailLevel = kDetailLevelText.indexOf(e.attribute(getAttrName(anDetail), "none")) == eDetailAll ? eDetailAll : eDetailNone; // read performance or capital gains tab if (m_queryColumns & eQCperformance) m_investmentSum = static_cast(e.attribute(getAttrName(anInvestmentSum), QString().setNum(MyMoneyReport::eSumPeriod)).toInt()); // read capital gains tab if (m_queryColumns & eQCcapitalgain) { m_investmentSum = static_cast(e.attribute(getAttrName(anInvestmentSum), QString().setNum(MyMoneyReport::eSumSold)).toInt()); if (m_investmentSum == MyMoneyReport::eSumSold) { m_showSTLTCapitalGains = e.attribute(getAttrName(anShowSTLTCapitalGains), "0").toUInt(); m_settlementPeriod = e.attribute(getAttrName(anSettlementPeriod), "3").toUInt(); m_tseparator = QDate::fromString(e.attribute(getAttrName(anTermsSeparator), QDate::currentDate().addYears(-1).toString(Qt::ISODate)),Qt::ISODate); } } } else if (m_reportType == eInfoTable) { if (e.hasAttribute(getAttrName(anShowRowTotals))) m_showRowTotals = e.attribute(getAttrName(anShowRowTotals)).toUInt(); else m_showRowTotals = true; } QDomNode child = e.firstChild(); while (!child.isNull() && child.isElement()) { QDomElement c = child.toElement(); if (getElName(enText) == c.tagName() && c.hasAttribute(getAttrName(anPattern))) { setTextFilter(QRegExp(c.attribute(getAttrName(anPattern)), c.attribute(getAttrName(anCaseSensitive), "1").toUInt() ? Qt::CaseSensitive : Qt::CaseInsensitive, c.attribute(getAttrName(anRegEx), "1").toUInt() ? QRegExp::Wildcard : QRegExp::RegExp), c.attribute(getAttrName(anInvertText), "0").toUInt()); } if (getElName(enType) == c.tagName() && c.hasAttribute(getAttrName(anType))) { i = kTypeText.indexOf(c.attribute(getAttrName(anType))); if (i != -1) addType(i); } if (getElName(enState) == c.tagName() && c.hasAttribute(getAttrName(anState))) { i = kStateText.indexOf(c.attribute(getAttrName(anState))); if (i != -1) addState(i); } if (getElName(enNumber) == c.tagName()) setNumberFilter(c.attribute(getAttrName(anFrom)), c.attribute(getAttrName(anTo))); if (getElName(enAmount) == c.tagName()) setAmountFilter(MyMoneyMoney(c.attribute(getAttrName(anFrom), "0/100")), MyMoneyMoney(c.attribute(getAttrName(anTo), "0/100"))); if (getElName(enDates) == c.tagName()) { QDate from, to; if (c.hasAttribute(getAttrName(anFrom))) from = QDate::fromString(c.attribute(getAttrName(anFrom)), Qt::ISODate); if (c.hasAttribute(getAttrName(anTo))) to = QDate::fromString(c.attribute(getAttrName(anTo)), Qt::ISODate); MyMoneyTransactionFilter::setDateFilter(from, to); } if (getElName(enPayee) == c.tagName()) addPayee(c.attribute(getAttrName(anID))); if (getElName(enTag) == c.tagName()) addTag(c.attribute(getAttrName(anID))); if (getElName(enCategory) == c.tagName() && c.hasAttribute(getAttrName(anID))) addCategory(c.attribute(getAttrName(anID))); if (getElName(enAccount) == c.tagName() && c.hasAttribute(getAttrName(anID))) addAccount(c.attribute(getAttrName(anID))); if (getElName(enAccountGroup) == c.tagName() && c.hasAttribute(getAttrName(anGroup))) { i = kAccountTypeText.indexOf(c.attribute(getAttrName(anGroup))); if (i != -1) addAccountGroup(static_cast(i)); } child = child.nextSibling(); } return true; } void MyMoneyReport::writeXML(QDomDocument& document, QDomElement& parent) const { QDomElement el = document.createElement(nodeNames[nnReport]); write(el, &document, false); parent.appendChild(el); } bool MyMoneyReport::hasReferenceTo(const QString& id) const { QStringList list; // collect all ids accounts(list); categories(list); payees(list); tags(list); return (list.contains(id) > 0); } int MyMoneyReport::m_lineWidth = 2; void MyMoneyReport::setLineWidth(int width) { m_lineWidth = width; } const QString MyMoneyReport::getElName(const elNameE _el) { static const QHash elNames = { {enPayee, QStringLiteral("PAYEE")}, {enTag, QStringLiteral("TAG")}, {enAccount, QStringLiteral("ACCOUNT")}, {enText, QStringLiteral("TEXT")}, {enType, QStringLiteral("TYPE")}, {enState, QStringLiteral("STATE")}, {enNumber, QStringLiteral("NUMBER")}, {enAmount, QStringLiteral("AMOUNT")}, {enDates, QStringLiteral("DATES")}, {enCategory, QStringLiteral("CATEGORY")}, {enAccountGroup, QStringLiteral("ACCOUNTGROUP")} }; return elNames[_el]; } const QString MyMoneyReport::getAttrName(const attrNameE _attr) { static const QHash attrNames = { {anID, QStringLiteral("id")}, {anGroup, QStringLiteral("group")}, {anType, QStringLiteral("type")}, {anName, QStringLiteral("name")}, {anComment, QStringLiteral("comment")}, {anConvertCurrency, QStringLiteral("convertcurrency")}, {anFavorite, QStringLiteral("favorite")}, {anSkipZero, QStringLiteral("skipZero")}, {anDateLock, QStringLiteral("datelock")}, {anDataLock, QStringLiteral("datalock")}, {anMovingAverageDays, QStringLiteral("movingaveragedays")}, {anIncludesActuals, QStringLiteral("includesactuals")}, {anIncludesForecast, QStringLiteral("includesforecast")}, {anIncludesPrice, QStringLiteral("includesprice")}, {anIncludesAveragePrice, QStringLiteral("includesaverageprice")}, {anIncludesMovingAverage, QStringLiteral("includesmovingaverage")}, {anIncludesSchedules, QStringLiteral("includeschedules")}, {anIncludesTransfers, QStringLiteral("includestransfers")}, {anIncludesUnused, QStringLiteral("includeunused")}, {anMixedTime, QStringLiteral("mixedtime")}, {anInvestments, QStringLiteral("investments")}, {anBudget, QStringLiteral("budget")}, {anShowRowTotals, QStringLiteral("showrowtotals")}, {anShowColumnTotals, QStringLiteral("showcolumntotals")}, {anDetail, QStringLiteral("detail")}, {anColumnsAreDays, QStringLiteral("columnsaredays")}, {anChartType, QStringLiteral("charttype")}, {anChartCHGridLines, QStringLiteral("chartchgridlines")}, {anChartSVGridLines, QStringLiteral("chartsvgridlines")}, {anChartDataLabels, QStringLiteral("chartdatalabels")}, {anChartByDefault, QStringLiteral("chartbydefault")}, {anLogYAxis, QStringLiteral("logYaxis")}, {anChartLineWidth, QStringLiteral("chartlinewidth")}, {anColumnType, QStringLiteral("columntype")}, {anRowType, QStringLiteral("rowtype")}, {anDataRangeStart, QStringLiteral("dataRangeStart")}, {anDataRangeEnd, QStringLiteral("dataRangeEnd")}, {anDataMajorTick, QStringLiteral("dataMajorTick")}, {anDataMinorTick, QStringLiteral("dataMinorTick")}, {anYLabelsPrecision, QStringLiteral("yLabelsPrecision")}, {anQueryColumns, QStringLiteral("querycolumns")}, {anTax, QStringLiteral("tax")}, {anLoans, QStringLiteral("loans")}, {anHideTransactions, QStringLiteral("hidetransactions")}, {anInvestmentSum, QStringLiteral("investmentsum")}, {anSettlementPeriod, QStringLiteral("settlementperiod")}, {anShowSTLTCapitalGains, QStringLiteral("showSTLTCapitalGains")}, {anTermsSeparator, QStringLiteral("tseparator")}, {anPattern, QStringLiteral("pattern")}, {anCaseSensitive, QStringLiteral("casesensitive")}, {anRegEx, QStringLiteral("regex")}, {anInvertText, QStringLiteral("inverttext")}, {anState, QStringLiteral("state")}, {anFrom, QStringLiteral("from")}, {anTo, QStringLiteral("to")} }; return attrNames[_attr]; } QString MyMoneyReport::toString(ERowType type) { switch(type) { case eNoRows : return "eNoRows"; case eAssetLiability : return "eAssetLiability"; case eExpenseIncome : return "eExpenseIncome"; case eCategory : return "eCategory"; case eTopCategory : return "eTopCategory"; case eAccount : return "eAccount"; case eTag : return "eTag"; case ePayee : return "ePayee"; case eMonth : return "eMonth"; case eWeek : return "eWeek"; case eTopAccount : return "eTopAccount"; case eAccountByTopAccount: return "eAccountByTopAccount"; case eEquityType : return "eEquityType"; case eAccountType : return "eAccountType"; case eInstitution : return "eInstitution"; case eBudget : return "eBudget"; case eBudgetActual : return "eBudgetActual"; case eSchedule : return "eSchedule"; case eAccountInfo : return "eAccountInfo"; case eAccountLoanInfo : return "eAccountLoanInfo"; case eAccountReconcile : return "eAccountReconcile"; case eCashFlow : return "eCashFlow"; default : return "undefined"; } } QString MyMoneyReport::toString(MyMoneyReport::EReportType type) { switch(type) { case eNoReport: return "eNoReport"; case ePivotTable: return "ePivotTable"; case eQueryTable: return "eQueryTable"; case eInfoTable: return "eInfoTable"; default: return "undefined"; } } diff --git a/kmymoney/views/kreportsview.cpp b/kmymoney/views/kreportsview.cpp index 4d484fdbe..c5a16afe8 100644 --- a/kmymoney/views/kreportsview.cpp +++ b/kmymoney/views/kreportsview.cpp @@ -1,1798 +1,1800 @@ /*************************************************************************** kreportsview.cpp - 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 ***************************************************************************/ /*************************************************************************** * * * 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 "kreportsview.h" // ---------------------------------------------------------------------------- // QT Includes #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 #include #include #include "querytable.h" #include "objectinfotable.h" #include "kreportconfigurationfilterdlg.h" #include #include using namespace reports; using namespace Icons; #define VIEW_LEDGER "ledger" #define VIEW_SCHEDULE "schedule" #define VIEW_WELCOME "welcome" #define VIEW_HOME "home" #define VIEW_REPORTS "reports" /** * KReportsView::KReportTab Implementation */ KReportsView::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_report(report), m_deleteMe(false), m_chartEnabled(false), m_showingChart(report.isChartByDefault()), m_needReload(true), m_table(0) { m_layout->setSpacing(6); m_tableView->setPage(new MyQWebEnginePage(m_tableView)); m_tableView->setZoomFactor(KMyMoneyGlobalSettings::zoomFactor()); //set button icons m_control->ui->buttonChart->setIcon(QIcon::fromTheme(g_Icons[Icon::OfficeChartLine])); m_control->ui->buttonClose->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentClose])); m_control->ui->buttonConfigure->setIcon(QIcon::fromTheme(g_Icons[Icon::Configure])); m_control->ui->buttonCopy->setIcon(QIcon::fromTheme(g_Icons[Icon::EditCopy])); m_control->ui->buttonDelete->setIcon(QIcon::fromTheme(g_Icons[Icon::EditDelete])); m_control->ui->buttonExport->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentExport])); m_control->ui->buttonNew->setIcon(QIcon::fromTheme(g_Icons[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); connect(m_control->ui->buttonChart, SIGNAL(clicked()), eventHandler, SLOT(slotToggleChart())); connect(m_control->ui->buttonConfigure, SIGNAL(clicked()), eventHandler, SLOT(slotConfigure())); connect(m_control->ui->buttonNew, SIGNAL(clicked()), eventHandler, SLOT(slotDuplicate())); connect(m_control->ui->buttonCopy, SIGNAL(clicked()), eventHandler, SLOT(slotCopyView())); connect(m_control->ui->buttonExport, SIGNAL(clicked()), eventHandler, SLOT(slotSaveView())); connect(m_control->ui->buttonDelete, SIGNAL(clicked()), eventHandler, SLOT(slotDelete())); connect(m_control->ui->buttonClose, SIGNAL(clicked()), eventHandler, SLOT(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, QIcon::fromTheme(g_Icons[Icon::Spreadsheet]), report.name()); parent->setTabEnabled(tabNr, true); parent->setCurrentIndex(tabNr); // get users character set encoding m_encoding = QTextCodec::codecForLocale()->name(); } KReportsView::KReportTab::~KReportTab() { delete m_table; } void KReportsView::KReportTab::print() { if (m_tableView) { m_currentPrinter = new QPrinter(); QPrintDialog *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 KReportsView::KReportTab::copyToClipboard() { QMimeData* pMimeData = new QMimeData(); pMimeData->setHtml(m_table->renderReport(QLatin1String("html"), m_encoding, m_report.name(), true)); QApplication::clipboard()->setMimeData(pMimeData); } void KReportsView::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 KReportsView::KReportTab::loadTab() { m_needReload = true; if (isVisible()) { m_needReload = false; updateReport(); } } void KReportsView::KReportTab::showEvent(QShowEvent * event) { if (m_needReload) { m_needReload = false; updateReport(); } QWidget::showEvent(event); } void KReportsView::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() == MyMoneyReport::ePivotTable) { m_table = new PivotTable(m_report); m_chartEnabled = true; } else if (m_report.reportType() == MyMoneyReport::eQueryTable) { m_table = new QueryTable(m_report); m_chartEnabled = false; } else if (m_report.reportType() == MyMoneyReport::eInfoTable) { m_table = new ObjectInfoTable(m_report); m_chartEnabled = false; } m_control->ui->buttonChart->setEnabled(m_chartEnabled); m_showingChart = !m_showingChart; toggleChart(); } void KReportsView::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(QIcon::fromTheme(g_Icons[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(QIcon::fromTheme(g_Icons[Icon::ViewFinancialList])); } m_showingChart = ! m_showingChart; } void KReportsView::KReportTab::updateDataRange() { QList grids = m_chartView->coordinatePlane()->gridDimensionsList(); // get dimmensions of ploted 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); } /** * KReportsView Implementation */ KReportsView::KReportsView(QWidget *parent, const char *name) : KMyMoneyViewBase(parent, name, i18n("Reports")), m_needReload(false), m_needLoad(true), m_reportListView(0) { } void KReportsView::init() { m_needLoad = false; // build reports toc setColumnsAlreadyAdjusted(false); m_reportTabWidget = new QTabWidget(this); 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, // so avoid any further action in case of doubleclick // (see slotItemDoubleClicked) m_tocTreeWidget->setExpandsOnDoubleClick(false); m_tocTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); m_tocTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_listTabLayout->addWidget(m_tocTreeWidget); m_reportTabWidget->addTab(m_listTab, i18n("Reports")); connect(m_reportTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(slotClose(int))); connect(m_tocTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotItemDoubleClicked(QTreeWidgetItem*,int))); connect(m_tocTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotListContextMenu(QPoint))); connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadView())); } void KReportsView::showEvent(QShowEvent * event) { if (m_needLoad) init(); emit aboutToShow(); if (m_needReload) { loadView(); m_needReload = false; } KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (tab) emit reportSelected(tab->report()); else emit reportSelected(MyMoneyReport()); // don't forget base class implementation KMyMoneyViewBase::showEvent(event); } void KReportsView::slotLoadView() { m_needReload = true; if (isVisible()) { loadView(); m_needReload = false; } } void KReportsView::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++) { QTreeWidgetItem* 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()) { QString 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; QString 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; QString 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!! KReportTab* 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 KReportsView::slotOpenUrl(const QUrl &url) { QString view = url.fileName(); if (view.isEmpty()) return; QString command = QUrlQuery(url).queryItemValue("command"); QString id = QUrlQuery(url).queryItemValue("id"); QString tid = QUrlQuery(url).queryItemValue("tid"); if (view == VIEW_REPORTS) { if (command.isEmpty()) { // slotRefreshView(); } else if (command == QLatin1String("print")) slotPrintView(); else if (command == QLatin1String("copy")) slotCopyView(); else if (command == QLatin1String("save")) slotSaveView(); else if (command == QLatin1String("configure")) slotConfigure(); else if (command == QLatin1String("duplicate")) slotDuplicate(); else if (command == QLatin1String("close")) slotCloseCurrent(); else if (command == QLatin1String("delete")) slotDelete(); else qWarning() << i18n("Unknown command '%1' in KReportsView::slotOpenUrl()", qPrintable(command)); } else if (view == VIEW_LEDGER) { emit ledgerSelected(id, tid); } else { qWarning() << i18n("Unknown view '%1' in KReportsView::slotOpenUrl()", qPrintable(view)); } } void KReportsView::slotPrintView() { KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (tab) tab->print(); } void KReportsView::slotCopyView() { KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (tab) tab->copyToClipboard(); } void KReportsView::slotSaveView() { KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (tab) { QString filterList = i18nc("CSV (Filefilter)", "CSV files") + " (*.csv)" + ";;" + i18nc("HTML (Filefilter)", "HTML files") + " (*.html)"; QUrl newURL = QFileDialog::getSaveFileUrl(this, i18n("Export as"), QUrl::fromLocalFile(KRecentDirs::dir(":kmymoney-export")), filterList, &m_selectedExportFilter); if (!newURL.isEmpty()) { KRecentDirs::add(":kmymoney-export", newURL.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); QString newName = newURL.toDisplayString(QUrl::PreferLocalFile); // TODO BUG:342776 port to KF5 if (newName.indexOf('.') == -1) newName.append(".html"); try { tab->saveAs(newName, true); } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Failed to save: %1", e.what())); } } } } void KReportsView::slotConfigure() { QString cm = "KReportsView::slotConfigure"; KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (!tab) // nothing to do return; int tabNr = m_reportTabWidget->currentIndex(); tab->updateDataRange(); // range will be needed during configuration, but cannot be obtained earlier MyMoneyReport report = tab->report(); if (report.comment() == i18n("Default Report") || report.comment() == i18n("Generated Report")) { report.setComment(i18n("Custom Report")); report.setName(i18n("%1 (Customized)", report.name())); } QPointer dlg = new KReportConfigurationFilterDlg(report); if (dlg->exec()) { MyMoneyReport newreport = dlg->getConfig(); // If this report has an ID, then MODIFY it, otherwise ADD it MyMoneyFileTransaction ft; try { if (! newreport.id().isEmpty()) { MyMoneyFile::instance()->modifyReport(newreport); ft.commit(); tab->modifyReport(newreport); m_reportTabWidget->setTabText(tabNr, newreport.name()); m_reportTabWidget->setCurrentIndex(tabNr) ; } else { MyMoneyFile::instance()->addReport(newreport); ft.commit(); QString reportGroupName = newreport.group(); // find report group TocItemGroup* tocItemGroup = m_allTocItemGroups[reportGroupName]; if (!tocItemGroup) { QString error = i18n("Could not find reportgroup \"%1\" for report \"%2\".\nPlease report this error to the developer's list: kmymoney-devel@kde.org", reportGroupName, newreport.name()); // write to messagehandler qWarning() << cm << error; // also inform user KMessageBox::error(m_reportTabWidget, error, i18n("Critical Error")); // cleanup delete dlg; return; } // do not add TocItemReport to TocItemGroup here, // this is done in loadView addReportTab(newreport); } } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Failed to configure report: %1", e.what())); } } delete dlg; } void KReportsView::slotDuplicate() { QString cm = "KReportsView::slotDuplicate"; KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (!tab) { // nothing to do return; } MyMoneyReport dupe = tab->report(); dupe.setName(i18n("Copy of %1", dupe.name())); if (dupe.comment() == i18n("Default Report")) dupe.setComment(i18n("Custom Report")); dupe.clearId(); QPointer dlg = new KReportConfigurationFilterDlg(dupe); if (dlg->exec()) { MyMoneyReport newReport = dlg->getConfig(); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->addReport(newReport); ft.commit(); QString reportGroupName = newReport.group(); // find report group TocItemGroup* tocItemGroup = m_allTocItemGroups[reportGroupName]; if (!tocItemGroup) { QString error = i18n("Could not find reportgroup \"%1\" for report \"%2\".\nPlease report this error to the developer's list: kmymoney-devel@kde.org", reportGroupName, newReport.name()); // write to messagehandler qWarning() << cm << error; // also inform user KMessageBox::error(m_reportTabWidget, error, i18n("Critical Error")); // cleanup delete dlg; return; } // do not add TocItemReport to TocItemGroup here, // this is done in loadView addReportTab(newReport); } catch (const MyMoneyException &e) { QString error = i18n("Cannot add report, reason: \"%1\"", e.what()); // write to messagehandler qWarning() << cm << error; // also inform user KMessageBox::error(m_reportTabWidget, error, i18n("Critical Error")); } } delete dlg; } void KReportsView::slotDelete() { KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (!tab) { // nothing to do return; } MyMoneyReport report = tab->report(); if (! report.id().isEmpty()) { if (KMessageBox::Continue == deleteReportDialog(report.name())) { // close the tab and then remove the report so that it is not // generated again during the following loadView() call slotClose(m_reportTabWidget->currentIndex()); MyMoneyFileTransaction ft; MyMoneyFile::instance()->removeReport(report); ft.commit(); } } else { KMessageBox::information(this, QString("") + i18n("%1 is a default report, so it cannot be deleted.", report.name()) + QString(""), i18n("Delete Report?")); } } int KReportsView::deleteReportDialog(const QString &reportName) { return KMessageBox::warningContinueCancel(this, QString("") + i18n("Are you sure you want to delete report %1? There is no way to recover it.", reportName) + QString(""), i18n("Delete Report?")); } void KReportsView::slotOpenReport(const QString& id) { if (id.isEmpty()) { // nothing to do return; } KReportTab* page = 0; // Find the tab which contains the report int index = 1; while (index < m_reportTabWidget->count()) { KReportTab* current = dynamic_cast(m_reportTabWidget->widget(index)); if (current->report().id() == id) { page = current; break; } ++index; } // Show the tab, or create a new one, as needed if (page) m_reportTabWidget->setCurrentIndex(index); else addReportTab(MyMoneyFile::instance()->report(id)); } void KReportsView::slotOpenReport(const MyMoneyReport& report) { qDebug() << Q_FUNC_INFO << " " << report.name(); KReportTab* page = 0; // Find the tab which contains the report indicated by this list item int index = 1; while (index < m_reportTabWidget->count()) { KReportTab* current = dynamic_cast(m_reportTabWidget->widget(index)); if (current->report().name() == report.name()) { page = current; break; } ++index; } // Show the tab, or create a new one, as needed if (page) m_reportTabWidget->setCurrentIndex(index); else addReportTab(report); } void KReportsView::slotItemDoubleClicked(QTreeWidgetItem* item, int) { TocItem* tocItem = dynamic_cast(item); if (!tocItem->isReport()) { // toggle the expanded-state for reportgroup-items item->setExpanded(item->isExpanded() ? false : true); // nothing else to do for reportgroup-items return; } TocItemReport* reportTocItem = dynamic_cast(tocItem); MyMoneyReport& report = reportTocItem->getReport(); KReportTab* page = 0; // Find the tab which contains the report indicated by this list item int index = 1; while (index < m_reportTabWidget->count()) { KReportTab* current = dynamic_cast(m_reportTabWidget->widget(index)); // If this report has an ID, we'll use the ID to match if (! report.id().isEmpty()) { if (current->report().id() == report.id()) { page = current; break; } } // Otherwise, use the name to match. THIS ASSUMES that no 2 default reports // have the same name...but that would be pretty a boneheaded thing to do. else { if (current->report().name() == report.name()) { page = current; break; } } ++index; } // Show the tab, or create a new one, as needed if (page) m_reportTabWidget->setCurrentIndex(index); else addReportTab(report); } void KReportsView::slotToggleChart() { KReportTab* tab = dynamic_cast(m_reportTabWidget->currentWidget()); if (tab) tab->toggleChart(); } void KReportsView::slotCloseCurrent() { slotClose(m_reportTabWidget->currentIndex()); } void KReportsView::slotClose(int index) { KReportTab* tab = dynamic_cast(m_reportTabWidget->widget(index)); if (tab) { m_reportTabWidget->removeTab(index); tab->setReadyToDelete(true); } } void KReportsView::slotCloseAll() { if(!m_needLoad) { while (true) { KReportTab* tab = dynamic_cast(m_reportTabWidget->widget(1)); if (tab) { m_reportTabWidget->removeTab(1); tab->setReadyToDelete(true); } else break; } } } void KReportsView::addReportTab(const MyMoneyReport& report) { new KReportTab(m_reportTabWidget, report, this); } void KReportsView::slotListContextMenu(const QPoint & p) { QTreeWidgetItem *item = m_tocTreeWidget->itemAt(p); if (!item) { return; } TocItem* tocItem = dynamic_cast(item); if (!tocItem->isReport()) { // currently there is no context menu for reportgroup items return; } QMenu* contextmenu = new QMenu(this); contextmenu->addAction(i18nc("To open a new report", "&Open"), this, SLOT(slotOpenFromList())); contextmenu->addAction(i18nc("Configure a report", "&Configure"), this, SLOT(slotConfigureFromList())); contextmenu->addAction(i18n("&New report"), this, SLOT(slotNewFromList())); // Only add this option if it's a custom report. Default reports cannot be deleted TocItemReport* reportTocItem = dynamic_cast(tocItem); MyMoneyReport& report = reportTocItem->getReport(); if (! report.id().isEmpty()) { contextmenu->addAction(i18n("&Delete"), this, SLOT(slotDeleteFromList())); } contextmenu->popup(m_tocTreeWidget->mapToGlobal(p)); } void KReportsView::slotOpenFromList() { TocItem* tocItem = dynamic_cast(m_tocTreeWidget->currentItem()); if (tocItem) slotItemDoubleClicked(tocItem, 0); } void KReportsView::slotConfigureFromList() { TocItem* tocItem = dynamic_cast(m_tocTreeWidget->currentItem()); if (tocItem) { slotItemDoubleClicked(tocItem, 0); slotConfigure(); } } void KReportsView::slotNewFromList() { TocItem* tocItem = dynamic_cast(m_tocTreeWidget->currentItem()); if (tocItem) { slotItemDoubleClicked(tocItem, 0); slotDuplicate(); } } void KReportsView::slotDeleteFromList() { TocItem* tocItem = dynamic_cast(m_tocTreeWidget->currentItem()); if (tocItem) { TocItemReport* reportTocItem = dynamic_cast(tocItem); MyMoneyReport& report = reportTocItem->getReport(); // If this report does not have an ID, it's a default report and cannot be deleted if (! report.id().isEmpty() && KMessageBox::Continue == deleteReportDialog(report.name())) { // check if report's tab is open; start from 1 because 0 is toc tab for (int i = 1; i < m_reportTabWidget->count(); ++i) { KReportTab* tab = dynamic_cast(m_reportTabWidget->widget(i)); if (tab->report().id() == report.id()) { slotClose(i); // if open, close it, so no crash when switching to it break; } } MyMoneyFileTransaction ft; MyMoneyFile::instance()->removeReport(report); ft.commit(); } } } void KReportsView::defaultReports(QList& groups) { { ReportGroup list("Income and Expenses", i18n("Income and Expenses")); list.push_back(MyMoneyReport( MyMoneyReport::eExpenseIncome, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentMonth, MyMoneyReport::eDetailAll, i18n("Income and Expenses This Month"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eExpenseIncome, MyMoneyReport::eMonths, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Income and Expenses This Year"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eExpenseIncome, MyMoneyReport::eYears, MyMoneyTransactionFilter::allDates, MyMoneyReport::eDetailAll, i18n("Income and Expenses By Year"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eExpenseIncome, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last12Months, MyMoneyReport::eDetailTop, i18n("Income and Expenses Graph"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartType(MyMoneyReport::eChartLine); list.back().setChartDataLabels(false); list.push_back(MyMoneyReport( MyMoneyReport::eExpenseIncome, MyMoneyReport::eMonths, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailGroup, i18n("Income and Expenses Pie Chart"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartType(MyMoneyReport::eChartPie); list.back().setShowingRowTotals(false); groups.push_back(list); } { ReportGroup list("Net Worth", i18n("Net Worth")); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailTop, i18n("Net Worth By Month"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::today, MyMoneyReport::eDetailTop, i18n("Net Worth Today"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eYears, MyMoneyTransactionFilter::allDates, MyMoneyReport::eDetailTop, i18n("Net Worth By Year"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::next7Days, MyMoneyReport::eDetailTop, i18n("7-day Cash Flow Forecast"), i18n("Default Report") )); list.back().setIncludingSchedules(true); list.back().setColumnsAreDays(true); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last12Months, MyMoneyReport::eDetailTotal, i18n("Net Worth Graph"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartLine); list.push_back(MyMoneyReport( MyMoneyReport::eInstitution, MyMoneyReport::eQCnone, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailTop, i18n("Account Balances by Institution"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eAccountType, MyMoneyReport::eQCnone, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailTop, i18n("Account Balances by Type"), i18n("Default Report") )); groups.push_back(list); } { ReportGroup list("Transactions", i18n("Transactions")); list.push_back(MyMoneyReport( MyMoneyReport::eAccount, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory | MyMoneyReport::eQCtag | MyMoneyReport::eQCbalance, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Transactions by Account"), i18n("Default Report") )); //list.back().setConvertCurrency(false); list.push_back(MyMoneyReport( MyMoneyReport::eCategory, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount | MyMoneyReport::eQCtag, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Transactions by Category"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::ePayee, MyMoneyReport::eQCnumber | MyMoneyReport::eQCcategory | MyMoneyReport::eQCtag, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Transactions by Payee"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eTag, MyMoneyReport::eQCnumber | MyMoneyReport::eQCcategory, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Transactions by Tag"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eMonth, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory | MyMoneyReport::eQCtag, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Transactions by Month"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eWeek, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory | MyMoneyReport::eQCtag, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Transactions by Week"), i18n("Default Report") )); list.push_back(MyMoneyReport( MyMoneyReport::eAccount, MyMoneyReport::eQCloan, MyMoneyTransactionFilter::allDates, MyMoneyReport::eDetailAll, i18n("Loan Transactions"), i18n("Default Report") )); list.back().setLoansOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAccountReconcile, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory | MyMoneyReport::eQCbalance, MyMoneyTransactionFilter::last3Months, MyMoneyReport::eDetailAll, i18n("Transactions by Reconciliation Status"), i18n("Default Report") )); groups.push_back(list); } { ReportGroup list("CashFlow", i18n("Cash Flow")); list.push_back(MyMoneyReport( MyMoneyReport::eCashFlow, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Cash Flow Transactions This Month"), i18n("Default Report") )); groups.push_back(list); } { ReportGroup list("Investments", i18n("Investments")); list.push_back(MyMoneyReport( MyMoneyReport::eTopAccount, MyMoneyReport::eQCaction | MyMoneyReport::eQCshares | MyMoneyReport::eQCprice, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Transactions"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAccountByTopAccount, MyMoneyReport::eQCshares | MyMoneyReport::eQCprice, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Holdings by Account"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eEquityType, MyMoneyReport::eQCshares | MyMoneyReport::eQCprice, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Holdings by Type"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAccountByTopAccount, MyMoneyReport::eQCperformance, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Performance by Account"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eEquityType, MyMoneyReport::eQCperformance, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Performance by Type"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAccountByTopAccount, MyMoneyReport::eQCcapitalgain, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Capital Gains by Account"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eEquityType, MyMoneyReport::eQCcapitalgain, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Investment Capital Gains by Type"), i18n("Default Report") )); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::today, MyMoneyReport::eDetailAll, i18n("Investment Holdings Pie"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartPie); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last12Months, MyMoneyReport::eDetailAll, i18n("Investment Worth Graph"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartLine); list.back().setColumnsAreDays(true); list.back().setInvestmentsOnly(true); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last12Months, MyMoneyReport::eDetailAll, i18n("Investment Price Graph"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartLine); 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( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last12Months, MyMoneyReport::eDetailAll, i18n("Investment Moving Average Price Graph"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartLine); 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( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last30Days, MyMoneyReport::eDetailAll, i18n("Investment Moving Average"), i18n("Default Report") )); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartLine); list.back().setColumnsAreDays(true); list.back().setInvestmentsOnly(true); list.back().setIncludingBudgetActuals(false); list.back().setIncludingMovingAverage(true); list.back().setMovingAverageDays(10); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::last30Days, MyMoneyReport::eDetailAll, i18n("Investment Moving Average vs Actual"), i18n("Default Report") )); list.back().setChartByDefault(true); list.back().setChartCHGridLines(false); list.back().setChartSVGridLines(false); list.back().setChartType(MyMoneyReport::eChartLine); 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( MyMoneyReport::eCategory, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Tax Transactions by Category"), i18n("Default Report") )); list.back().setTax(true); list.push_back(MyMoneyReport( MyMoneyReport::ePayee, MyMoneyReport::eQCnumber | MyMoneyReport::eQCcategory | MyMoneyReport::eQCaccount, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Tax Transactions by Payee"), i18n("Default Report") )); list.back().setTax(true); list.push_back(MyMoneyReport( MyMoneyReport::eCategory, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCaccount, MyMoneyTransactionFilter::lastFiscalYear, MyMoneyReport::eDetailAll, i18n("Tax Transactions by Category Last Fiscal Year"), i18n("Default Report") )); list.back().setTax(true); list.push_back(MyMoneyReport( MyMoneyReport::ePayee, MyMoneyReport::eQCnumber | MyMoneyReport::eQCcategory | MyMoneyReport::eQCaccount, MyMoneyTransactionFilter::lastFiscalYear, MyMoneyReport::eDetailAll, 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( MyMoneyReport::eBudgetActual, MyMoneyReport::eMonths, MyMoneyTransactionFilter::yearToDate, MyMoneyReport::eDetailAll, i18n("Budgeted vs. Actual This Year"), i18n("Default Report") )); list.back().setShowingRowTotals(true); list.back().setBudget("Any", true); list.push_back(MyMoneyReport( MyMoneyReport::eBudgetActual, MyMoneyReport::eMonths, MyMoneyTransactionFilter::yearToMonth, MyMoneyReport::eDetailAll, 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(MyMoneyTransactionFilter::lastYear); } list.push_back(MyMoneyReport( MyMoneyReport::eBudgetActual, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentMonth, MyMoneyReport::eDetailAll, i18n("Monthly Budgeted vs. Actual"), i18n("Default Report") )); list.back().setBudget("Any", true); list.push_back(MyMoneyReport( MyMoneyReport::eBudgetActual, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentYear, MyMoneyReport::eDetailAll, i18n("Yearly Budgeted vs. Actual"), i18n("Default Report") )); list.back().setBudget("Any", true); list.back().setShowingRowTotals(true); list.push_back(MyMoneyReport( MyMoneyReport::eBudget, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentMonth, MyMoneyReport::eDetailAll, i18n("Monthly Budget"), i18n("Default Report") )); list.back().setBudget("Any", false); list.push_back(MyMoneyReport( MyMoneyReport::eBudget, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentYear, MyMoneyReport::eDetailAll, i18n("Yearly Budget"), i18n("Default Report") )); list.back().setBudget("Any", false); list.back().setShowingRowTotals(true); list.push_back(MyMoneyReport( MyMoneyReport::eBudgetActual, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentYear, MyMoneyReport::eDetailGroup, 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(MyMoneyReport::eChartLine); groups.push_back(list); } { ReportGroup list("Forecast", i18n("Forecast")); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::next12Months, MyMoneyReport::eDetailTop, i18n("Forecast By Month"), i18n("Default Report") )); list.back().setIncludingForecast(true); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::nextQuarter, MyMoneyReport::eDetailTop, i18n("Forecast Next Quarter"), i18n("Default Report") )); list.back().setColumnsAreDays(true); list.back().setIncludingForecast(true); list.push_back(MyMoneyReport( MyMoneyReport::eExpenseIncome, MyMoneyReport::eMonths, MyMoneyTransactionFilter::currentYear, MyMoneyReport::eDetailTop, i18n("Income and Expenses Forecast This Year"), i18n("Default Report") )); list.back().setIncludingForecast(true); list.push_back(MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, MyMoneyTransactionFilter::next3Months, MyMoneyReport::eDetailTotal, 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(MyMoneyReport::eChartLine); groups.push_back(list); } { ReportGroup list("Information", i18n("General Information")); list.push_back(MyMoneyReport( MyMoneyReport::eSchedule, MyMoneyReport::eMonths, MyMoneyTransactionFilter::next12Months, MyMoneyReport::eDetailAll, i18n("Schedule Information"), i18n("Default Report") )); list.back().setDetailLevel(MyMoneyReport::eDetailAll); list.push_back(MyMoneyReport( MyMoneyReport::eSchedule, MyMoneyReport::eMonths, MyMoneyTransactionFilter::next12Months, MyMoneyReport::eDetailAll, i18n("Schedule Summary Information"), i18n("Default Report") )); list.back().setDetailLevel(MyMoneyReport::eDetailTop); list.push_back(MyMoneyReport( MyMoneyReport::eAccountInfo, MyMoneyReport::eMonths, MyMoneyTransactionFilter::today, MyMoneyReport::eDetailAll, i18n("Account Information"), i18n("Default Report") )); list.back().setConvertCurrency(false); list.push_back(MyMoneyReport( MyMoneyReport::eAccountLoanInfo, MyMoneyReport::eMonths, MyMoneyTransactionFilter::today, MyMoneyReport::eDetailAll, i18n("Loan Information"), i18n("Default Report") )); list.back().setConvertCurrency(false); groups.push_back(list); } } bool KReportsView::columnsAlreadyAdjusted() { return m_columnsAlreadyAdjusted; } void KReportsView::setColumnsAlreadyAdjusted(bool adjusted) { m_columnsAlreadyAdjusted = adjusted; } void KReportsView::restoreTocExpandState(QMap& expandStates) { for (int 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); } } } } // Make sure, that these definitions are only used within this file // this does not seem to be necessary, but when building RPMs the // build option 'final' is used and all CPP files are concatenated. // So it could well be, that in another CPP file these definitions // are also used. #undef VIEW_LEDGER #undef VIEW_SCHEDULE #undef VIEW_WELCOME #undef VIEW_HOME #undef VIEW_REPORTS