diff --git a/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp b/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp
index 047a15e1f..2b9f3ef42 100644
--- a/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp
+++ b/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp
@@ -1,674 +1,680 @@
/***************************************************************************
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
***************************************************************************/
/***************************************************************************
* *
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include
#include
#include
#include
#include
#include
#include
#include
// ----------------------------------------------------------------------------
// Project Includes
#include
#include
#include
#include
+#include
#include
#include
#include
#include "ui_kfindtransactiondlgdecl.h"
KReportConfigurationFilterDlg::KReportConfigurationFilterDlg(
MyMoneyReport report, QWidget *parent)
: KFindTransactionDlg(parent, report.rowType() == MyMoneyReport::Row::Account),
m_tab2(0),
m_tab3(0),
m_tabChart(0),
m_initialState(report),
m_currentState(report)
{
//
// Rework labeling
//
setWindowTitle(i18n("Report Configuration"));
delete m_ui->TextLabel1;
//
// Rework the buttons
//
// the Apply button is always enabled
disconnect(SIGNAL(selectionNotEmpty(bool)));
enableButtonApply(true);
setButtonGuiItem(KDialog::Apply, KStandardGuiItem::ok());
setButtonToolTip(KDialog::Apply, i18nc("@info:tooltip for report configuration apply button", "Apply the configuration changes to the report"));
//
// Add new tabs
//
m_tab1 = new kMyMoneyReportConfigTab1Decl(m_ui->m_criteriaTab);
m_tab1->setObjectName("kMyMoneyReportConfigTab1");
m_ui->m_criteriaTab->insertTab(0, m_tab1, i18n("Report"));
if (m_initialState.reportType() == MyMoneyReport::Report::PivotTable) {
m_tab2 = new kMyMoneyReportConfigTab2Decl(m_ui->m_criteriaTab);
m_tab2->setObjectName("kMyMoneyReportConfigTab2");
m_ui->m_criteriaTab->insertTab(1, m_tab2, i18n("Rows/Columns"));
connect(m_tab2->findChild("m_comboRows"), SIGNAL(activated(int)), this, SLOT(slotRowTypeChanged(int)));
connect(m_tab2->findChild("m_comboColumns"), SIGNAL(activated(int)), this, SLOT(slotColumnTypeChanged(int)));
connect(m_tab2->findChild("m_comboRows"), SIGNAL(activated(int)), this, SLOT(slotUpdateColumnsCombo()));
connect(m_tab2->findChild("m_comboColumns"), SIGNAL(activated(int)), this, SLOT(slotUpdateColumnsCombo()));
//control the state of the includeTransfer check
connect(m_ui->m_categoriesView, SIGNAL(stateChanged()), this, SLOT(slotUpdateCheckTransfers()));
m_tabChart = new kMyMoneyReportConfigTabChartDecl(m_ui->m_criteriaTab);
m_tabChart->setObjectName("kMyMoneyReportConfigTabChart");
m_ui->m_criteriaTab->insertTab(2, m_tabChart, i18n("Chart"));
} else if (m_initialState.reportType() == MyMoneyReport::Report::QueryTable) {
// eInvestmentHoldings is a special-case report, and you cannot configure the
// rows & columns of that report.
if (m_initialState.rowType() < MyMoneyReport::Row::AccountByTopAccount) {
m_tab3 = new kMyMoneyReportConfigTab3Decl(m_ui->m_criteriaTab);
m_tab3->setObjectName("kMyMoneyReportConfigTab3");
m_ui->m_criteriaTab->insertTab(1, m_tab3, i18n("Rows/Columns"));
}
}
m_ui->m_criteriaTab->setCurrentIndex(m_ui->m_criteriaTab->indexOf(m_tab1));
m_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) {
m_budgets.push_back(*it_b);
}
//
// Now set up the widgets with proper values
//
slotReset();
}
KReportConfigurationFilterDlg::~KReportConfigurationFilterDlg()
{
}
void KReportConfigurationFilterDlg::slotSearch()
{
// setup the filter from the dialog widgets
setupFilter();
// Copy the m_filter over to the filter part of m_currentConfig.
m_currentState.assignFilter(m_filter);
// Then extract the report properties
m_currentState.setName(m_tab1->findChild("m_editName")->text());
m_currentState.setComment(m_tab1->findChild("m_editComment")->text());
m_currentState.setConvertCurrency(m_tab1->findChild("m_checkCurrency")->isChecked());
m_currentState.setFavorite(m_tab1->findChild("m_checkFavorite")->isChecked());
m_currentState.setSkipZero(m_tab1->findChild("m_skipZero")->isChecked());
if (m_tab2) {
MyMoneyReport::DetailLevel::Type dl[4] = { MyMoneyReport::DetailLevel::All, MyMoneyReport::DetailLevel::Top, MyMoneyReport::DetailLevel::Group, MyMoneyReport::DetailLevel::Total };
m_currentState.setDetailLevel(dl[m_tab2->findChild("m_comboDetail")->currentIndex()]);
// modify the rowtype only if the widget is enabled
if (m_tab2->findChild("m_comboRows")->isEnabled()) {
MyMoneyReport::Row::Type rt[2] = { MyMoneyReport::Row::ExpenseIncome, MyMoneyReport::Row::AssetLiability };
m_currentState.setRowType(rt[m_tab2->findChild("m_comboRows")->currentIndex()]);
}
m_currentState.setShowingRowTotals(false);
if (m_tab2->findChild("m_comboRows")->currentIndex() == 0)
m_currentState.setShowingRowTotals(m_tab2->findChild("m_checkTotalColumn")->isChecked());
MyMoneyReport::Column::Type ct[6] = { MyMoneyReport::Column::Days, MyMoneyReport::Column::Weeks, MyMoneyReport::Column::Months, MyMoneyReport::Column::BiMonths, MyMoneyReport::Column::Quarters, MyMoneyReport::Column::Years };
bool dy[6] = { true, true, false, false, false, false };
m_currentState.setColumnType(ct[m_tab2->findChild("m_comboColumns")->currentIndex()]);
//TODO (Ace) This should be implicit in the call above. MMReport needs fixin'
m_currentState.setColumnsAreDays(dy[m_tab2->findChild("m_comboColumns")->currentIndex()]);
m_currentState.setIncludingSchedules(m_tab2->findChild("m_checkScheduled")->isChecked());
m_currentState.setIncludingTransfers(m_tab2->findChild("m_checkTransfers")->isChecked());
m_currentState.setIncludingUnusedAccounts(m_tab2->findChild("m_checkUnused")->isChecked());
if (m_tab2->findChild("m_comboBudget")->isEnabled()) {
m_currentState.setBudget(m_budgets[m_tab2->findChild("m_comboBudget")->currentItem()].id(), m_initialState.rowType() == MyMoneyReport::Row::BudgetActual);
} else {
m_currentState.setBudget(QString(), false);
}
//set moving average days
if (m_tab2->findChild("m_movingAverageDays")->isEnabled()) {
m_currentState.setMovingAverageDays(m_tab2->findChild("m_movingAverageDays")->value());
}
} else if (m_tab3) {
MyMoneyReport::Row::Type rtq[8] = { MyMoneyReport::Row::Category, MyMoneyReport::Row::TopCategory, MyMoneyReport::Row::Tag, MyMoneyReport::Row::Payee, MyMoneyReport::Row::Account, MyMoneyReport::Row::TopAccount, MyMoneyReport::Row::Month, MyMoneyReport::Row::Week };
m_currentState.setRowType(rtq[m_tab3->findChild("m_comboOrganizeBy")->currentIndex()]);
unsigned qc = MyMoneyReport::QueryColumns::None;
if (m_currentState.queryColumns() & MyMoneyReport::QueryColumns::Loan)
// once a loan report, always a loan report
qc = MyMoneyReport::QueryColumns::Loan;
if (m_tab3->findChild("m_checkNumber")->isChecked())
qc |= MyMoneyReport::QueryColumns::Number;
if (m_tab3->findChild("m_checkPayee")->isChecked())
qc |= MyMoneyReport::QueryColumns::Payee;
if (m_tab3->findChild("m_checkTag")->isChecked())
qc |= MyMoneyReport::QueryColumns::Tag;
if (m_tab3->findChild("m_checkCategory")->isChecked())
qc |= MyMoneyReport::QueryColumns::Category;
if (m_tab3->findChild("m_checkMemo")->isChecked())
qc |= MyMoneyReport::QueryColumns::Memo;
if (m_tab3->findChild("m_checkAccount")->isChecked())
qc |= MyMoneyReport::QueryColumns::Account;
if (m_tab3->findChild("m_checkReconciled")->isChecked())
qc |= MyMoneyReport::QueryColumns::Reconciled;
if (m_tab3->findChild("m_checkAction")->isChecked())
qc |= MyMoneyReport::QueryColumns::Action;
if (m_tab3->findChild("m_checkShares")->isChecked())
qc |= MyMoneyReport::QueryColumns::Shares;
if (m_tab3->findChild("m_checkPrice")->isChecked())
qc |= MyMoneyReport::QueryColumns::Price;
if (m_tab3->findChild("m_checkBalance")->isChecked())
qc |= MyMoneyReport::QueryColumns::Balance;
m_currentState.setQueryColumns(static_cast(qc));
m_currentState.setTax(m_tab3->findChild("m_checkTax")->isChecked());
m_currentState.setInvestmentsOnly(m_tab3->findChild("m_checkInvestments")->isChecked());
m_currentState.setLoansOnly(m_tab3->findChild("m_checkLoans")->isChecked());
m_currentState.setDetailLevel(m_tab3->findChild("m_checkHideSplitDetails")->isChecked() ?
MyMoneyReport::DetailLevel::None : MyMoneyReport::DetailLevel::All);
}
if (m_tabChart) {
MyMoneyReport::Chart::Type ct[5] = { MyMoneyReport::Chart::Line, MyMoneyReport::Chart::Bar, MyMoneyReport::Chart::StackedBar, MyMoneyReport::Chart::Pie, MyMoneyReport::Chart::Ring };
m_currentState.setChartType(ct[m_tabChart->findChild("m_comboType")->currentIndex()]);
+ MyMoneyReport::ChartPalette::Type cp[4] = { MyMoneyReport::ChartPalette::Application, MyMoneyReport::ChartPalette::Default, MyMoneyReport::ChartPalette::Rainbow, MyMoneyReport::ChartPalette::Subdued };
+ m_currentState.setChartPalette(cp[m_tabChart->findChild("m_chartPalette")->currentIndex()]);
m_currentState.setChartGridLines(m_tabChart->findChild("m_checkGridLines")->isChecked());
m_currentState.setChartDataLabels(m_tabChart->findChild("m_checkValues")->isChecked());
m_currentState.setChartByDefault(m_tabChart->findChild("m_checkShowChart")->isChecked());
m_currentState.setChartLineWidth(m_tabChart->findChild("m_lineWidth")->value());
}
// setup the date lock
MyMoneyTransactionFilter::dateOptionE range = m_ui->m_dateRange->currentItem();
m_currentState.setDateFilter(range);
done(true);
}
void KReportConfigurationFilterDlg::slotRowTypeChanged(int row)
{
m_tab2->findChild("m_checkTotalColumn")->setEnabled(row == 0);
}
void KReportConfigurationFilterDlg::slotColumnTypeChanged(int row)
{
if ((m_tab2->findChild("m_comboBudget")->isEnabled() && row < 2)) {
m_tab2->findChild("m_comboColumns")->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false);
}
}
void KReportConfigurationFilterDlg::slotUpdateColumnsCombo()
{
const int monthlyIndex = 2;
const int incomeExpenseIndex = 0;
const bool isIncomeExpenseForecast = m_currentState.isIncludingForecast() && m_tab2->findChild("m_comboRows")->currentIndex() == incomeExpenseIndex;
if (isIncomeExpenseForecast && m_tab2->findChild("m_comboColumns")->currentIndex() != monthlyIndex) {
m_tab2->findChild("m_comboColumns")->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false);
}
}
void KReportConfigurationFilterDlg::slotReset()
{
//
// Set up the widget from the initial filter
//
m_currentState = m_initialState;
//
// Report Properties
//
m_tab1->findChild("m_editName")->setText(m_initialState.name());
m_tab1->findChild("m_editComment")->setText(m_initialState.comment());
m_tab1->findChild("m_checkCurrency")->setChecked(m_initialState.isConvertCurrency());
m_tab1->findChild("m_checkFavorite")->setChecked(m_initialState.isFavorite());
if (m_initialState.isIncludingPrice() || m_initialState.isSkippingZero()) {
m_tab1->findChild("m_skipZero")->setChecked(m_initialState.isSkippingZero());
} else {
m_tab1->findChild("m_skipZero")->setEnabled(false);
}
if (m_tab2) {
KComboBox *combo = m_tab2->findChild("m_comboDetail");
switch (m_initialState.detailLevel()) {
case MyMoneyReport::DetailLevel::None:
case MyMoneyReport::DetailLevel::End:
case MyMoneyReport::DetailLevel::All:
combo->setCurrentItem(i18nc("All accounts", "All"), false);
break;
case MyMoneyReport::DetailLevel::Top:
combo->setCurrentItem(i18n("Top-Level"), false);
break;
case MyMoneyReport::DetailLevel::Group:
combo->setCurrentItem(i18n("Groups"), false);
break;
case MyMoneyReport::DetailLevel::Total:
combo->setCurrentItem(i18n("Totals"), false);
break;
}
combo = m_tab2->findChild("m_comboRows");
switch (m_initialState.rowType()) {
case MyMoneyReport::Row::ExpenseIncome:
case MyMoneyReport::Row::Budget:
case MyMoneyReport::Row::BudgetActual:
combo->setCurrentItem(i18n("Income & Expenses"), false); // income / expense
break;
default:
combo->setCurrentItem(i18n("Assets & Liabilities"), false); // asset / liability
break;
}
m_tab2->findChild("m_checkTotalColumn")->setChecked(m_initialState.isShowingRowTotals());
slotRowTypeChanged(combo->currentIndex());
combo = m_tab2->findChild("m_comboColumns");
if (m_initialState.isColumnsAreDays()) {
switch (m_initialState.columnType()) {
case MyMoneyReport::Column::NoColumns:
case MyMoneyReport::Column::Days:
combo->setCurrentItem(i18nc("@item the columns will display daily data", "Daily"), false);
break;
case MyMoneyReport::Column::Weeks:
combo->setCurrentItem(i18nc("@item the columns will display weekly data", "Weekly"), false);
break;
default:
break;
}
} else {
switch (m_initialState.columnType()) {
case MyMoneyReport::Column::NoColumns:
case MyMoneyReport::Column::Months:
combo->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false);
break;
case MyMoneyReport::Column::BiMonths:
combo->setCurrentItem(i18nc("@item the columns will display bi-monthly data", "Bi-Monthly"), false);
break;
case MyMoneyReport::Column::Quarters:
combo->setCurrentItem(i18nc("@item the columns will display quarterly data", "Quarterly"), false);
break;
case MyMoneyReport::Column::Years:
combo->setCurrentItem(i18nc("@item the columns will display yearly data", "Yearly"), false);
break;
default:
break;
}
}
//load budgets combo
if (m_initialState.rowType() == MyMoneyReport::Row::Budget
|| m_initialState.rowType() == MyMoneyReport::Row::BudgetActual) {
m_tab2->findChild("m_comboRows")->setEnabled(false);
m_tab2->findChild("m_budgetFrame")->setEnabled(!m_budgets.empty());
int i = 0;
for (QVector::const_iterator it_b = m_budgets.constBegin(); it_b != m_budgets.constEnd(); ++it_b) {
m_tab2->findChild("m_comboBudget")->insertItem((*it_b).name(), i);
//set the current selected item
if ((m_initialState.budget() == "Any" && (*it_b).budgetStart().year() == QDate::currentDate().year())
|| m_initialState.budget() == (*it_b).id())
m_tab2->findChild("m_comboBudget")->setCurrentItem(i);
i++;
}
}
//set moving average days spinbox
QSpinBox *spinbox = m_tab2->findChild("m_movingAverageDays");
spinbox->setEnabled(m_initialState.isIncludingMovingAverage());
if (m_initialState.isIncludingMovingAverage()) {
spinbox->setValue(m_initialState.movingAverageDays());
}
m_tab2->findChild("m_checkScheduled")->setChecked(m_initialState.isIncludingSchedules());
m_tab2->findChild("m_checkTransfers")->setChecked(m_initialState.isIncludingTransfers());
m_tab2->findChild("m_checkUnused")->setChecked(m_initialState.isIncludingUnusedAccounts());
} else if (m_tab3) {
KComboBox *combo = m_tab3->findChild("m_comboOrganizeBy");
switch (m_initialState.rowType()) {
case MyMoneyReport::Row::NoRows:
case MyMoneyReport::Row::Category:
combo->setCurrentItem(i18n("Categories"), false);
break;
case MyMoneyReport::Row::TopCategory:
combo->setCurrentItem(i18n("Top Categories"), false);
break;
case MyMoneyReport::Row::Tag:
combo->setCurrentItem(i18n("Tags"), false);
break;
case MyMoneyReport::Row::Payee:
combo->setCurrentItem(i18n("Payees"), false);
break;
case MyMoneyReport::Row::Account:
combo->setCurrentItem(i18n("Accounts"), false);
break;
case MyMoneyReport::Row::TopAccount:
combo->setCurrentItem(i18n("Top Accounts"), false);
break;
case MyMoneyReport::Row::Month:
combo->setCurrentItem(i18n("Month"), false);
break;
case MyMoneyReport::Row::Week:
combo->setCurrentItem(i18n("Week"), false);
break;
default:
throw MYMONEYEXCEPTION("KReportConfigurationFilterDlg::slotReset(): QueryTable report has invalid rowtype");
}
unsigned qc = m_initialState.queryColumns();
m_tab3->findChild("m_checkNumber")->setChecked(qc & MyMoneyReport::QueryColumns::Number);
m_tab3->findChild("m_checkPayee")->setChecked(qc & MyMoneyReport::QueryColumns::Payee);
m_tab3->findChild("m_checkTag")->setChecked(qc & MyMoneyReport::QueryColumns::Tag);
m_tab3->findChild("m_checkCategory")->setChecked(qc & MyMoneyReport::QueryColumns::Category);
m_tab3->findChild("m_checkMemo")->setChecked(qc & MyMoneyReport::QueryColumns::Memo);
m_tab3->findChild("m_checkAccount")->setChecked(qc & MyMoneyReport::QueryColumns::Account);
m_tab3->findChild("m_checkReconciled")->setChecked(qc & MyMoneyReport::QueryColumns::Reconciled);
m_tab3->findChild("m_checkAction")->setChecked(qc & MyMoneyReport::QueryColumns::Action);
m_tab3->findChild("m_checkShares")->setChecked(qc & MyMoneyReport::QueryColumns::Shares);
m_tab3->findChild("m_checkPrice")->setChecked(qc & MyMoneyReport::QueryColumns::Price);
m_tab3->findChild("m_checkBalance")->setChecked(qc & MyMoneyReport::QueryColumns::Balance);
m_tab3->findChild("m_checkTax")->setChecked(m_initialState.isTax());
m_tab3->findChild("m_checkInvestments")->setChecked(m_initialState.isInvestmentsOnly());
m_tab3->findChild("m_checkLoans")->setChecked(m_initialState.isLoansOnly());
m_tab3->findChild("m_checkHideSplitDetails")->setChecked
(m_initialState.detailLevel() == MyMoneyReport::DetailLevel::None);
}
if (m_tabChart) {
KMyMoneyGeneralCombo* combo = m_tabChart->findChild("m_comboType");
switch (m_initialState.chartType()) {
case MyMoneyReport::Chart::None:
combo->setCurrentItem(MyMoneyReport::Chart::Line);
break;
case MyMoneyReport::Chart::Line:
case MyMoneyReport::Chart::Bar:
case MyMoneyReport::Chart::StackedBar:
case MyMoneyReport::Chart::Pie:
case MyMoneyReport::Chart::Ring:
combo->setCurrentItem(m_initialState.chartType());
break;
case MyMoneyReport::Chart::End:
throw MYMONEYEXCEPTION("KReportConfigurationFilterDlg::slotReset(): Report has invalid charttype");
}
+ // keep in sync with kMyMoneyReportConfigTabChartDecl::kMyMoneyReportConfigTabChartDecl
+ KMyMoneyGeneralCombo* palette = m_tabChart->findChild("m_chartPalette");
+ palette->setCurrentIndex(m_initialState.chartPalette());
m_tabChart->findChild("m_checkGridLines")->setChecked(m_initialState.isChartGridLines());
m_tabChart->findChild("m_checkValues")->setChecked(m_initialState.isChartDataLabels());
m_tabChart->findChild("m_checkShowChart")->setChecked(m_initialState.isChartByDefault());
m_tabChart->findChild("m_lineWidth")->setValue(m_initialState.chartLineWidth());
}
//
// Text Filter
//
QRegExp textfilter;
if (m_initialState.textFilter(textfilter)) {
m_ui->m_textEdit->setText(textfilter.pattern());
m_ui->m_caseSensitive->setChecked(Qt::CaseSensitive == textfilter.caseSensitivity());
m_ui->m_regExp->setChecked(QRegExp::RegExp == textfilter.patternSyntax());
m_ui->m_textNegate->setCurrentIndex(m_initialState.isInvertingText());
}
//
// Type & State Filters
//
int type;
if (m_initialState.firstType(type))
m_ui->m_typeBox->setCurrentIndex(type);
int state;
if (m_initialState.firstState(state))
m_ui->m_stateBox->setCurrentIndex(state);
//
// Validity Filters
//
int validity;
if (m_initialState.firstValidity(validity))
m_ui->m_validityBox->setCurrentIndex(validity);
//
// Number Filter
//
QString nrFrom, nrTo;
if (m_initialState.numberFilter(nrFrom, nrTo)) {
if (nrFrom == nrTo) {
m_ui->m_nrEdit->setEnabled(true);
m_ui->m_nrFromEdit->setEnabled(false);
m_ui->m_nrToEdit->setEnabled(false);
m_ui->m_nrEdit->setText(nrFrom);
m_ui->m_nrFromEdit->setText(QString());
m_ui->m_nrToEdit->setText(QString());
m_ui->m_nrButton->setChecked(true);
m_ui->m_nrRangeButton->setChecked(false);
} else {
m_ui->m_nrEdit->setEnabled(false);
m_ui->m_nrFromEdit->setEnabled(true);
m_ui->m_nrToEdit->setEnabled(false);
m_ui->m_nrEdit->setText(QString());
m_ui->m_nrFromEdit->setText(nrFrom);
m_ui->m_nrToEdit->setText(nrTo);
m_ui->m_nrButton->setChecked(false);
m_ui->m_nrRangeButton->setChecked(true);
}
} else {
m_ui->m_nrEdit->setEnabled(true);
m_ui->m_nrFromEdit->setEnabled(false);
m_ui->m_nrToEdit->setEnabled(false);
m_ui->m_nrEdit->setText(QString());
m_ui->m_nrFromEdit->setText(QString());
m_ui->m_nrToEdit->setText(QString());
m_ui->m_nrButton->setChecked(true);
m_ui->m_nrRangeButton->setChecked(false);
}
//
// Amount Filter
//
MyMoneyMoney from, to;
if (m_initialState.amountFilter(from, to)) { // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&);
if (from == to) {
m_ui->m_amountEdit->setEnabled(true);
m_ui->m_amountFromEdit->setEnabled(false);
m_ui->m_amountToEdit->setEnabled(false);
m_ui->m_amountEdit->loadText(QString::number(from.toDouble()));
m_ui->m_amountFromEdit->loadText(QString());
m_ui->m_amountToEdit->loadText(QString());
m_ui->m_amountButton->setChecked(true);
m_ui->m_amountRangeButton->setChecked(false);
} else {
m_ui->m_amountEdit->setEnabled(false);
m_ui->m_amountFromEdit->setEnabled(true);
m_ui->m_amountToEdit->setEnabled(true);
m_ui->m_amountEdit->loadText(QString());
m_ui->m_amountFromEdit->loadText(QString::number(from.toDouble()));
m_ui->m_amountToEdit->loadText(QString::number(to.toDouble()));
m_ui->m_amountButton->setChecked(false);
m_ui->m_amountRangeButton->setChecked(true);
}
} else {
m_ui->m_amountEdit->setEnabled(true);
m_ui->m_amountFromEdit->setEnabled(false);
m_ui->m_amountToEdit->setEnabled(false);
m_ui->m_amountEdit->loadText(QString());
m_ui->m_amountFromEdit->loadText(QString());
m_ui->m_amountToEdit->loadText(QString());
m_ui->m_amountButton->setChecked(true);
m_ui->m_amountRangeButton->setChecked(false);
}
//
// Payees Filter
//
QStringList payees;
if (m_initialState.payees(payees)) {
if (payees.empty()) {
m_ui->m_emptyPayeesButton->setChecked(true);
} else {
selectAllItems(m_ui->m_payeesView, false);
selectItems(m_ui->m_payeesView, payees, true);
}
} else {
selectAllItems(m_ui->m_payeesView, true);
}
//
// Tags Filter
//
QStringList tags;
if (m_initialState.tags(tags)) {
if (tags.empty()) {
m_ui->m_emptyTagsButton->setChecked(true);
} else {
selectAllItems(m_ui->m_tagsView, false);
selectItems(m_ui->m_tagsView, tags, true);
}
} else {
selectAllItems(m_ui->m_tagsView, true);
}
//
// Accounts Filter
//
QStringList accounts;
if (m_initialState.accounts(accounts)) {
m_ui->m_accountsView->selectAllItems(false);
m_ui->m_accountsView->selectItems(accounts, true);
} else
m_ui->m_accountsView->selectAllItems(true);
//
// Categories Filter
//
if (m_initialState.categories(accounts)) {
m_ui->m_categoriesView->selectAllItems(false);
m_ui->m_categoriesView->selectItems(accounts, true);
} else
m_ui->m_categoriesView->selectAllItems(true);
//
// Date Filter
//
// the following call implies a call to slotUpdateSelections,
// that's why we call it last
m_initialState.updateDateFilter();
QDate dateFrom, dateTo;
if (m_initialState.dateFilter(dateFrom, dateTo)) {
if (m_initialState.isUserDefined()) {
m_ui->m_dateRange->setCurrentItem(MyMoneyTransactionFilter::userDefined);
m_ui->m_fromDate->setDate(dateFrom);
m_ui->m_toDate->setDate(dateTo);
} else {
m_ui->m_fromDate->setDate(dateFrom);
m_ui->m_toDate->setDate(dateTo);
KFindTransactionDlg::slotDateChanged();
}
} else {
m_ui->m_dateRange->setCurrentItem(MyMoneyTransactionFilter::allDates);
slotDateRangeChanged(MyMoneyTransactionFilter::allDates);
}
slotRightSize();
}
void KReportConfigurationFilterDlg::slotDateChanged()
{
if (m_ui->m_dateRange->currentItem() != MyMoneyTransactionFilter::userDefined) {
KFindTransactionDlg::slotDateChanged();
}
slotUpdateSelections();
}
void KReportConfigurationFilterDlg::slotShowHelp()
{
KToolInvocation::invokeHelp("details.reports.config");
}
//TODO Fix the reports and engine to include transfers even if categories are filtered - bug #1523508
void KReportConfigurationFilterDlg::slotUpdateCheckTransfers()
{
QCheckBox* cb = m_tab2->findChild("m_checkTransfers");
if (!m_ui->m_categoriesView->allItemsSelected()) {
cb->setChecked(false);
cb->setDisabled(true);
} else {
cb->setEnabled(true);
}
}
diff --git a/kmymoney/mymoney/mymoneyreport.cpp b/kmymoney/mymoney/mymoneyreport.cpp
index fa326bc25..117defc7f 100644
--- a/kmymoney/mymoney/mymoneyreport.cpp
+++ b/kmymoney/mymoney/mymoneyreport.cpp
@@ -1,889 +1,899 @@
/***************************************************************************
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 "reportdebug.h"
const QStringList MyMoneyReport::Row::kText = 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 MyMoneyReport::Report::Type MyMoneyReport::Report::kTypeArray[] = { NoReport, PivotTable, PivotTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, QueryTable, PivotTable, PivotTable, InfoTable, InfoTable, InfoTable, QueryTable, QueryTable, NoReport };
const QStringList MyMoneyReport::Column::kTypeText = 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 QueryColumns::Type
// and shift the bit for QueryColumns::end one position to the left
const QStringList MyMoneyReport::QueryColumns::kText = QString("none,number,payee,category,tag,memo,account,reconcileflag,action,shares,price,performance,loan,balance").split(',');
const QStringList MyMoneyReport::DetailLevel::kText = QString("none,all,top,group,total,invalid").split(',');
const QStringList MyMoneyReport::Chart::kText = QString("none,line,bar,pie,ring,stackedbar,invalid").split(',');
+const QStringList MyMoneyReport::ChartPalette::kText = QString("application,default,rainbow,subdued").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 kValidityText = QString("any,valid,invalid").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 kAccountTypeText = QString("unknown,checkings,savings,cash,creditcard,loan,certificatedep,investment,moneymarket,asset,liability,currency,income,expense,assetloan,stock,equity,invalid").split(',');
QString MyMoneyReport::Row::toString(Type type)
{
switch(type) {
case NoRows : return "NoRows";
case AssetLiability : return "AssetLiability";
case ExpenseIncome : return "ExpenseIncome";
case Category : return "Category";
case TopCategory : return "TopCategory";
case Account : return "Account";
case Tag : return "Tag";
case Payee : return "Payee";
case Month : return "Month";
case Week : return "Week";
case TopAccount : return "TopAccount";
case AccountByTopAccount: return "AccountByTopAccount";
case EquityType : return "EquityType";
case AccountType : return "AccountType";
case Institution : return "Institution";
case Budget : return "Budget";
case BudgetActual : return "BudgetActual";
case Schedule : return "Schedule";
case AccountInfo : return "AccountInfo";
case AccountLoanInfo : return "AccountLoanInfo";
case AccountReconcile : return "AccountReconcile";
case CashFlow : return "CashFlow";
default : return "undefined";
}
}
QString MyMoneyReport::Report::toString(Type type)
{
switch(type) {
case NoReport: return "NoReport";
case PivotTable: return "PivotTable";
case QueryTable: return "QueryTable";
case InfoTable: return "InfoTable";
default: return "undefined";
}
}
MyMoneyReport::MyMoneyReport() :
m_name("Unconfigured Pivot Table Report"),
m_detailLevel(DetailLevel::None),
m_convertCurrency(true),
m_favorite(false),
m_tax(false),
m_investments(false),
m_loans(false),
m_reportType(Report::kTypeArray[Row::ExpenseIncome]),
m_rowType(Row::ExpenseIncome),
m_columnType(Column::Months),
m_columnsAreDays(false),
m_queryColumns(QueryColumns::None),
m_dateLock(userDefined),
m_accountGroupFilter(false),
m_chartType(Chart::Line),
m_chartDataLabels(true),
m_chartGridLines(true),
m_chartByDefault(false),
+ m_chartPalette(ChartPalette::Application),
m_includeSchedules(false),
m_includeTransfers(false),
m_includeBudgetActuals(false),
m_includeUnusedAccounts(false),
m_showRowTotals(false),
m_includeForecast(false),
m_includeMovingAverage(false),
m_movingAverageDays(0),
m_includePrice(false),
m_includeAveragePrice(false),
m_mixedTime(false),
m_currentDateColumn(0),
m_skipZero(false)
{
m_chartLineWidth = m_lineWidth;
}
MyMoneyReport::MyMoneyReport(const QString& id, const MyMoneyReport& right) :
MyMoneyObject(id),
+ m_chartPalette(ChartPalette::Application),
m_movingAverageDays(0),
m_currentDateColumn(0)
{
*this = right;
setId(id);
}
MyMoneyReport::MyMoneyReport(Row::Type _rt, unsigned _ct, dateOptionE _dl, DetailLevel::Type _ss, const QString& _name, const QString& _comment) :
m_name(_name),
m_comment(_comment),
m_detailLevel(_ss),
m_convertCurrency(true),
m_favorite(false),
m_tax(false),
m_investments(false),
m_loans(false),
m_reportType(Report::kTypeArray[_rt]),
m_rowType(_rt),
m_columnType(Column::Months),
m_columnsAreDays(false),
m_queryColumns(QueryColumns::None),
m_dateLock(_dl),
m_accountGroupFilter(false),
m_chartType(Chart::Line),
m_chartDataLabels(true),
m_chartGridLines(true),
m_chartByDefault(false),
+ m_chartPalette(ChartPalette::Application),
m_includeSchedules(false),
m_includeTransfers(false),
m_includeBudgetActuals(false),
m_includeUnusedAccounts(false),
m_showRowTotals(false),
m_includeForecast(false),
m_includeMovingAverage(false),
m_movingAverageDays(0),
m_includePrice(false),
m_includeAveragePrice(false),
m_mixedTime(false),
m_currentDateColumn(0),
m_skipZero(false)
{
//set initial values
m_chartLineWidth = m_lineWidth;
//set report type
if (m_reportType == Report::PivotTable)
m_columnType = static_cast(_ct);
if (m_reportType == Report::QueryTable)
m_queryColumns = static_cast(_ct);
setDateFilter(_dl);
//throw exception if the type is inconsistent
if ((_rt > static_cast(sizeof(Report::kTypeArray) / sizeof(Report::kTypeArray[0])))
|| (m_reportType == Report::NoReport))
throw MYMONEYEXCEPTION("Invalid report type");
//add the corresponding account groups
if (_rt == MyMoneyReport::Row::AssetLiability) {
addAccountGroup(MyMoneyAccount::Asset);
addAccountGroup(MyMoneyAccount::Liability);
m_showRowTotals = true;
}
if (_rt == MyMoneyReport::Row::Account) {
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::Row::ExpenseIncome) {
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::Row::Budget || _rt == MyMoneyReport::Row::BudgetActual) {
addAccountGroup(MyMoneyAccount::Expense);
addAccountGroup(MyMoneyAccount::Income);
}
if (_rt == MyMoneyReport::Row::AccountInfo) {
addAccountGroup(MyMoneyAccount::Asset);
addAccountGroup(MyMoneyAccount::Liability);
}
//cash flow reports show splits for all account groups
if (_rt == MyMoneyReport::Row::CashFlow) {
addAccountGroup(MyMoneyAccount::Expense);
addAccountGroup(MyMoneyAccount::Income);
addAccountGroup(MyMoneyAccount::Asset);
addAccountGroup(MyMoneyAccount::Liability);
}
#ifdef DEBUG_REPORTS
QDebug dbg = qDebug();
dbg << _name << Row::toString(_rt) << Report::toString(m_reportType);
foreach(const MyMoneyAccount::accountTypeE accountType, m_accountGroups)
dbg << MyMoneyAccount::accountTypeToString(accountType);
if (m_accounts.size() > 0)
dbg << m_accounts;
#endif
}
MyMoneyReport::MyMoneyReport(const QDomElement& node) :
MyMoneyObject(node),
+ m_chartPalette(ChartPalette::Application),
m_currentDateColumn(0)
{
// properly initialize the object before reading it
*this = MyMoneyReport();
if (!read(node))
clearId();
}
void MyMoneyReport::clear()
{
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(Row::Type _rt)
{
m_rowType = _rt;
m_reportType = Report::kTypeArray[_rt];
m_accountGroupFilter = false;
m_accountGroups.clear();
if (_rt == MyMoneyReport::Row::AssetLiability) {
addAccountGroup(MyMoneyAccount::Asset);
addAccountGroup(MyMoneyAccount::Liability);
}
if (_rt == MyMoneyReport::Row::ExpenseIncome) {
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::Row::ExpenseIncome)
|| 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::Row::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;
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.
writeBaseXML(*doc, e);
if (anonymous) {
e.setAttribute("name", m_id);
e.setAttribute("comment", QString(m_comment).fill('x'));
} else {
e.setAttribute("name", m_name);
e.setAttribute("comment", m_comment);
}
e.setAttribute("group", m_group);
e.setAttribute("convertcurrency", m_convertCurrency);
e.setAttribute("favorite", m_favorite);
e.setAttribute("tax", m_tax);
e.setAttribute("investments", m_investments);
e.setAttribute("loans", m_loans);
e.setAttribute("rowtype", Row::kText[m_rowType]);
e.setAttribute("datelock", kDateLockText[m_dateLock]);
e.setAttribute("includeschedules", m_includeSchedules);
e.setAttribute("columnsaredays", m_columnsAreDays);
e.setAttribute("includestransfers", m_includeTransfers);
if (!m_budgetId.isEmpty())
e.setAttribute("budget", m_budgetId);
e.setAttribute("includesactuals", m_includeBudgetActuals);
e.setAttribute("includeunused", m_includeUnusedAccounts);
e.setAttribute("includesforecast", m_includeForecast);
e.setAttribute("includesprice", m_includePrice);
e.setAttribute("includesaverageprice", m_includeAveragePrice);
e.setAttribute("mixedtime", m_mixedTime);
e.setAttribute("includesmovingaverage", m_includeMovingAverage);
if (m_includeMovingAverage)
e.setAttribute("movingaveragedays", m_movingAverageDays);
if (m_chartType < 0 || m_chartType >= Chart::kText.size()) {
qDebug("m_chartType out of bounds with %d on report of type %d. Default to none.", m_chartType, m_reportType);
e.setAttribute("charttype", Chart::kText[0]);
} else {
e.setAttribute("charttype", Chart::kText[m_chartType]);
}
e.setAttribute("chartdatalabels", m_chartDataLabels);
e.setAttribute("chartgridlines", m_chartGridLines);
e.setAttribute("chartbydefault", m_chartByDefault);
e.setAttribute("chartlinewidth", m_chartLineWidth);
+ e.setAttribute("chartpalette", ChartPalette::kText[m_chartPalette]);
e.setAttribute("skipZero", m_skipZero);
if (m_reportType == Report::PivotTable) {
e.setAttribute("type", "pivottable 1.15");
e.setAttribute("detail", DetailLevel::kText[m_detailLevel]);
e.setAttribute("columntype", Column::kTypeText[m_columnType]);
e.setAttribute("showrowtotals", m_showRowTotals);
} else if (m_reportType == Report::QueryTable) {
e.setAttribute("type", "querytable 1.14");
QStringList columns;
unsigned qc = m_queryColumns;
unsigned it_qc = QueryColumns::Begin;
unsigned index = 1;
while (it_qc != QueryColumns::End) {
if (qc & it_qc)
columns += QueryColumns::kText[index];
it_qc *= 2;
index++;
}
e.setAttribute("querycolumns", columns.join(","));
} else if (m_reportType == Report::InfoTable) {
e.setAttribute("type", "infotable 1.0");
e.setAttribute("detail", DetailLevel::kText[m_detailLevel]);
e.setAttribute("showrowtotals", m_showRowTotals);
}
//
// Text Filter
//
QRegExp textfilter;
if (textFilter(textfilter)) {
QDomElement f = doc->createElement("TEXT");
f.setAttribute("pattern", textfilter.pattern());
f.setAttribute("casesensitive", (textfilter.caseSensitivity() == Qt::CaseSensitive) ? 1 : 0);
f.setAttribute("regex", (textfilter.patternSyntax() == QRegExp::Wildcard) ? 1 : 0);
f.setAttribute("inverttext", 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("TYPE");
p.setAttribute("type", 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("STATE");
p.setAttribute("state", kStateText[*it_state]);
e.appendChild(p);
++it_state;
}
}
//
// validity Filters
//
QList validitylist;
if (validities(validitylist) && ! validitylist.empty()) {
// iterate over validities, and add each one
QList::const_iterator it_validity = validitylist.constBegin();
while (it_validity != validitylist.constEnd()) {
QDomElement p = doc->createElement("VALIDITY");
p.setAttribute("validity", kValidityText[*it_validity]);
e.appendChild(p);
++it_validity;
}
}
//
// Number Filter
//
QString nrFrom, nrTo;
if (numberFilter(nrFrom, nrTo)) {
QDomElement f = doc->createElement("NUMBER");
f.setAttribute("from", nrFrom);
f.setAttribute("to", nrTo);
e.appendChild(f);
}
//
// Amount Filter
//
MyMoneyMoney from, to;
if (amountFilter(from, to)) { // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&);
QDomElement f = doc->createElement("AMOUNT");
f.setAttribute("from", from.toString());
f.setAttribute("to", to.toString());
e.appendChild(f);
}
//
// Payees Filter
//
QStringList payeelist;
if (payees(payeelist)) {
if (payeelist.empty()) {
QDomElement p = doc->createElement("PAYEE");
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("PAYEE");
p.setAttribute("id", *it_payee);
e.appendChild(p);
++it_payee;
}
}
}
//
// Tags Filter
//
QStringList taglist;
if (tags(taglist)) {
if (taglist.empty()) {
QDomElement p = doc->createElement("TAG");
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("TAG");
p.setAttribute("id", *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("ACCOUNTGROUP");
p.setAttribute("group", 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("ACCOUNT");
p.setAttribute("id", *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("CATEGORY");
p.setAttribute("id", *it_account);
e.appendChild(p);
++it_account;
}
}
//
// Date Filter
//
if (m_dateLock == userDefined) {
QDate dateFrom, dateTo;
if (dateFilter(dateFrom, dateTo)) {
QDomElement f = doc->createElement("DATES");
if (dateFrom.isValid())
f.setAttribute("from", dateFrom.toString(Qt::ISODate));
if (dateTo.isValid())
f.setAttribute("to", 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)
bool result = false;
if (
"REPORT" == e.tagName()
&&
(
(e.attribute("type").indexOf("pivottable 1.") == 0)
||
(e.attribute("type").indexOf("querytable 1.") == 0)
||
(e.attribute("type").indexOf("infotable 1.") == 0)
)
) {
result = true;
clear();
int i;
m_name = e.attribute("name");
m_comment = e.attribute("comment", "Extremely old report");
//set report type
if (!e.attribute("type").indexOf("pivottable")) {
m_reportType = MyMoneyReport::Report::PivotTable;
} else if (!e.attribute("type").indexOf("querytable")) {
m_reportType = MyMoneyReport::Report::QueryTable;
} else if (!e.attribute("type").indexOf("infotable")) {
m_reportType = MyMoneyReport::Report::InfoTable;
} else {
m_reportType = MyMoneyReport::Report::NoReport;
}
// Removed the line that screened out loading reports that are called
// "Default Report". It's possible for the user to change the comment
// to this, and we'd hate for it to break as a result.
m_group = e.attribute("group");
m_id = e.attribute("id");
//check for reports with older settings which didn't have the detail attribute
if (e.hasAttribute("detail")) {
i = DetailLevel::kText.indexOf(e.attribute("detail", "all"));
if (i != -1)
m_detailLevel = static_cast(i);
} else if (e.attribute("showsubaccounts", "0").toUInt()) {
//set to show all accounts
m_detailLevel = DetailLevel::All;
} else {
//set to show the top level account instead
m_detailLevel = DetailLevel::Top;
}
m_convertCurrency = e.attribute("convertcurrency", "1").toUInt();
m_favorite = e.attribute("favorite", "0").toUInt();
m_tax = e.attribute("tax", "0").toUInt();
m_investments = e.attribute("investments", "0").toUInt();
m_loans = e.attribute("loans", "0").toUInt();
m_includeSchedules = e.attribute("includeschedules", "0").toUInt();
m_columnsAreDays = e.attribute("columnsaredays", "0").toUInt();
m_includeTransfers = e.attribute("includestransfers", "0").toUInt();
if (e.hasAttribute("budget"))
m_budgetId = e.attribute("budget");
m_includeBudgetActuals = e.attribute("includesactuals", "0").toUInt();
m_includeUnusedAccounts = e.attribute("includeunused", "0").toUInt();
m_includeForecast = e.attribute("includesforecast", "0").toUInt();
m_includePrice = e.attribute("includesprice", "0").toUInt();
m_includeAveragePrice = e.attribute("includesaverageprice", "0").toUInt();
m_mixedTime = e.attribute("mixedtime", "0").toUInt();
m_includeMovingAverage = e.attribute("includesmovingaverage", "0").toUInt();
m_skipZero = e.attribute("skipZero", "0").toUInt();
if (m_includeMovingAverage)
m_movingAverageDays = e.attribute("movingaveragedays", "1").toUInt();
//only load chart data if it is a pivot table
m_chartType = static_cast(0);
if (m_reportType == Report::PivotTable) {
i = Chart::kText.indexOf(e.attribute("charttype"));
if (i >= 0)
m_chartType = static_cast(i);
// if it is invalid, set to first type
if (m_chartType >= Chart::End)
m_chartType = Chart::Line;
m_chartDataLabels = e.attribute("chartdatalabels", "1").toUInt();
m_chartGridLines = e.attribute("chartgridlines", "1").toUInt();
m_chartByDefault = e.attribute("chartbydefault", "0").toUInt();
m_chartLineWidth = e.attribute("chartlinewidth", QString(m_lineWidth)).toUInt();
} else {
m_chartDataLabels = true;
m_chartGridLines = true;
m_chartByDefault = false;
m_chartLineWidth = 1;
}
+ i = ChartPalette::kText.indexOf(e.attribute("chartpalette", "application"));
+ if (i >= 0)
+ m_chartPalette = static_cast(i);
+
QString datelockstr = e.attribute("datelock", "userdefined");
// Handle the pivot 1.2/query 1.1 case where the values were saved as
// numbers
bool ok = false;
i = datelockstr.toUInt(&ok);
if (!ok) {
i = kDateLockText.indexOf(datelockstr);
if (i == -1)
i = userDefined;
}
setDateFilter(static_cast(i));
i = Row::kText.indexOf(e.attribute("rowtype", "expenseincome"));
if (i != -1) {
setRowType(static_cast(i));
// recent versions of KMyMoney always showed a total column for
// income/expense reports. We turn it on for backward compatibility
// here. If the total column is turned off, the flag will be reset
// in the next step
if (i == Row::ExpenseIncome)
m_showRowTotals = true;
}
if (e.hasAttribute("showrowtotals"))
m_showRowTotals = e.attribute("showrowtotals").toUInt();
i = Column::kTypeText.indexOf(e.attribute("columntype", "months"));
if (i != -1)
setColumnType(static_cast(i));
unsigned qc = 0;
QStringList columns = e.attribute("querycolumns", "none").split(',');
QStringList::const_iterator it_column = columns.constBegin();
while (it_column != columns.constEnd()) {
i = QueryColumns::kText.indexOf(*it_column);
if (i > 0)
qc |= (1 << (i - 1));
++it_column;
}
setQueryColumns(static_cast(qc));
QDomNode child = e.firstChild();
while (!child.isNull() && child.isElement()) {
QDomElement c = child.toElement();
if ("TEXT" == c.tagName() && c.hasAttribute("pattern")) {
setTextFilter(QRegExp(c.attribute("pattern"),
c.attribute("casesensitive", "1").toUInt()
? Qt::CaseSensitive : Qt::CaseInsensitive,
c.attribute("regex", "1").toUInt()
? QRegExp::Wildcard : QRegExp::RegExp),
c.attribute("inverttext", "0").toUInt());
}
if ("TYPE" == c.tagName() && c.hasAttribute("type")) {
i = kTypeText.indexOf(c.attribute("type"));
if (i != -1)
addType(i);
}
if ("STATE" == c.tagName() && c.hasAttribute("state")) {
i = kStateText.indexOf(c.attribute("state"));
if (i != -1)
addState(i);
}
if ("VALIDITY" == c.tagName() && c.hasAttribute("validity")) {
i = kValidityText.indexOf(c.attribute("validity"));
if (i != -1)
addValidity(i);
}
if ("NUMBER" == c.tagName()) {
setNumberFilter(c.attribute("from"), c.attribute("to"));
}
if ("AMOUNT" == c.tagName()) {
setAmountFilter(MyMoneyMoney(c.attribute("from", "0/100")), MyMoneyMoney(c.attribute("to", "0/100")));
}
if ("DATES" == c.tagName()) {
QDate from, to;
if (c.hasAttribute("from"))
from = QDate::fromString(c.attribute("from"), Qt::ISODate);
if (c.hasAttribute("to"))
to = QDate::fromString(c.attribute("to"), Qt::ISODate);
MyMoneyTransactionFilter::setDateFilter(from, to);
}
if ("PAYEE" == c.tagName()) {
addPayee(c.attribute("id"));
}
if ("TAG" == c.tagName()) {
addTag(c.attribute("id"));
}
if ("CATEGORY" == c.tagName() && c.hasAttribute("id")) {
addCategory(c.attribute("id"));
}
if ("ACCOUNT" == c.tagName() && c.hasAttribute("id")) {
addAccount(c.attribute("id"));
}
if ("ACCOUNTGROUP" == c.tagName() && c.hasAttribute("group")) {
i = kAccountTypeText.indexOf(c.attribute("group"));
if (i != -1)
addAccountGroup(static_cast(i));
}
child = child.nextSibling();
}
}
return result;
}
void MyMoneyReport::writeXML(QDomDocument& document, QDomElement& parent) const
{
QDomElement el = document.createElement("REPORT");
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;
}
diff --git a/kmymoney/mymoney/mymoneyreport.h b/kmymoney/mymoney/mymoneyreport.h
index 9be413e8f..94fe7c21a 100644
--- a/kmymoney/mymoney/mymoneyreport.h
+++ b/kmymoney/mymoney/mymoneyreport.h
@@ -1,731 +1,747 @@
/***************************************************************************
mymoneyreport.h
-------------------
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. *
* *
***************************************************************************/
#ifndef MYMONEYREPORT_H
#define MYMONEYREPORT_H
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
class QDomElement;
class QDomDocument;
// ----------------------------------------------------------------------------
// Project Includes
#include
#include
#include
#include
/**
* 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 KMM_MYMONEY_EXPORT MyMoneyReport: public MyMoneyObject, public MyMoneyTransactionFilter
{
public:
// When adding a new row type, be sure to add a corresponding entry in kTypeArray
class Row {
public:
enum Type { NoRows = 0, AssetLiability, ExpenseIncome, Category, TopCategory, Account, Tag, Payee, Month, Week, TopAccount, AccountByTopAccount, EquityType, AccountType, Institution, Budget, BudgetActual, Schedule, AccountInfo, AccountLoanInfo, AccountReconcile, CashFlow};
/**
* Return row type as string.
*
* @param type type to get string for
* @return row type converted to string
*/
static QString toString(Type type);
static const QStringList kText;
};
class Report {
public:
enum Type { NoReport = 0, PivotTable, QueryTable, InfoTable };
/**
* Return report type as string.
*
* @param type report type to get string for
* @return report type converted to string
*/
static QString toString(Type type);
static const Type kTypeArray[];
};
class Column {
public:
enum Type { NoColumns = 0, Days = 1, Months = 1, BiMonths = 2, Quarters = 3, Weeks = 7, Years = 12 };
static const QStringList kTypeText;
};
// if you add bits to this bitmask, start with the value currently assigned to end and update its value afterwards
// also don't forget to add column names to QueryColumns::kText in mymoneyreport.cpp
class QueryColumns {
public:
enum Type { None = 0x0, Begin = 0x1, Number = 0x1, Payee = 0x2, Category = 0x4, Tag = 0x8, Memo = 0x10, Account = 0x20, Reconciled = 0x40, Action = 0x80, Shares = 0x100, Price = 0x200, Performance = 0x400, Loan = 0x800, Balance = 0x1000, End = 0x2000 };
static const QStringList kText;
};
class DetailLevel {
public:
enum Type { None = 0, All, Top, Group, Total, End };
static const QStringList kText;
};
class Chart {
public:
enum Type { None = 0, Line, Bar, Pie, Ring, StackedBar, End };
static const QStringList kText;
};
+ class ChartPalette {
+ public:
+ enum Type { Application = 0, Default, Rainbow, Subdued };
+ static const QStringList kText;
+ };
+
public:
MyMoneyReport();
MyMoneyReport(Row::Type _rt, unsigned _ct, dateOptionE _dl, DetailLevel::Type _ss, const QString& _name, const QString& _comment);
MyMoneyReport(const QString& id, const MyMoneyReport& right);
/**
* This constructor creates an object based on the data found in the
* QDomElement referenced by @p node. If problems arise, the @p id of
* the object is cleared (see MyMoneyObject::clearId()).
*/
MyMoneyReport(const QDomElement& node);
// Simple get operations
const QString& name() const {
return m_name;
}
bool isShowingRowTotals() const {
return (m_showRowTotals);
}
Report::Type reportType() const {
return m_reportType;
}
Row::Type rowType() const {
return m_rowType;
}
Column::Type columnType() const {
return m_columnType;
}
bool isRunningSum() const {
return (m_rowType == Row::AssetLiability);
}
bool isConvertCurrency() const {
return m_convertCurrency;
}
unsigned columnPitch() const {
return static_cast(m_columnType);
}
bool isShowingColumnTotals() const {
return m_convertCurrency;
}
const QString& comment() const {
return m_comment;
}
QueryColumns::Type queryColumns() const {
return m_queryColumns;
}
const QString& group() const {
return m_group;
}
bool isFavorite() const {
return m_favorite;
}
bool isTax() const {
return m_tax;
}
bool isInvestmentsOnly() const {
return m_investments;
}
bool isLoansOnly() const {
return m_loans;
}
DetailLevel::Type detailLevel() const {
return m_detailLevel;
}
Chart::Type chartType() const {
return m_chartType;
}
bool isChartDataLabels() const {
return m_chartDataLabels;
}
bool isChartGridLines() const {
return m_chartGridLines;
}
bool isChartByDefault() const {
return m_chartByDefault;
}
uint chartLineWidth() const {
return m_chartLineWidth;
}
+ ChartPalette::Type chartPalette() const {
+ return m_chartPalette;
+ }
bool isIncludingSchedules() const {
return m_includeSchedules;
}
bool isColumnsAreDays() const {
return m_columnsAreDays;
}
bool isIncludingTransfers() const {
return m_includeTransfers;
}
bool isIncludingUnusedAccounts() const {
return m_includeUnusedAccounts;
}
bool hasBudget() const {
return !m_budgetId.isEmpty();
}
const QString& budget() const {
return m_budgetId;
}
bool isIncludingBudgetActuals() const {
return m_includeBudgetActuals;
}
bool isIncludingForecast() const {
return m_includeForecast;
}
bool isIncludingMovingAverage() const {
return m_includeMovingAverage;
}
int movingAverageDays() const {
return m_movingAverageDays;
}
bool isIncludingPrice() const {
return m_includePrice;
}
bool isIncludingAveragePrice() const {
return m_includeAveragePrice;
}
bool isUserDefined() const {
return m_dateLock == userDefined;
}
bool isMixedTime() const {
return m_mixedTime;
}
int currentDateColumn() const {
return m_currentDateColumn;
}
/**
* @see #m_skipZero
*/
bool isSkippingZero() const {
return m_skipZero;
}
// Simple set operations
void setName(const QString& _s) {
m_name = _s;
}
void setConvertCurrency(bool _f) {
m_convertCurrency = _f;
}
void setRowType(Row::Type _rt);
void setColumnType(Column::Type _ct) {
m_columnType = _ct;
}
void setComment(const QString& _comment) {
m_comment = _comment;
}
void setGroup(const QString& _group) {
m_group = _group;
}
void setFavorite(bool _f) {
m_favorite = _f;
}
void setQueryColumns(QueryColumns::Type _qc) {
m_queryColumns = _qc;
}
void setTax(bool _f) {
m_tax = _f;
}
void setInvestmentsOnly(bool _f) {
m_investments = _f; if (_f) m_loans = false;
}
void setLoansOnly(bool _f) {
m_loans = _f; if (_f) m_investments = false;
}
void setDetailLevel(DetailLevel::Type _detail) {
m_detailLevel = _detail;
}
void setChartType(Chart::Type _type) {
m_chartType = _type;
}
void setChartDataLabels(bool _f) {
m_chartDataLabels = _f;
}
void setChartGridLines(bool _f) {
m_chartGridLines = _f;
}
void setChartByDefault(bool _f) {
m_chartByDefault = _f;
}
void setChartLineWidth(uint _f) {
m_chartLineWidth = _f;
}
+ void setChartPalette(ChartPalette::Type _f) {
+ m_chartPalette = _f;
+ }
void setIncludingSchedules(bool _f) {
m_includeSchedules = _f;
}
void setColumnsAreDays(bool _f) {
m_columnsAreDays = _f;
}
void setIncludingTransfers(bool _f) {
m_includeTransfers = _f;
}
void setIncludingUnusedAccounts(bool _f) {
m_includeUnusedAccounts = _f;
}
void setShowingRowTotals(bool _f) {
m_showRowTotals = _f;
}
void setIncludingBudgetActuals(bool _f) {
m_includeBudgetActuals = _f;
}
void setIncludingForecast(bool _f) {
m_includeForecast = _f;
}
void setIncludingMovingAverage(bool _f) {
m_includeMovingAverage = _f;
}
void setMovingAverageDays(int _days) {
m_movingAverageDays = _days;
}
void setIncludingPrice(bool _f) {
m_includePrice = _f;
}
void setIncludingAveragePrice(bool _f) {
m_includeAveragePrice = _f;
}
void setMixedTime(bool _f) {
m_mixedTime = _f;
}
void setCurrentDateColumn(int _f) {
m_currentDateColumn = _f;
}
/**
* @see #m_skipZero
*/
void setSkipZero(int _f) {
m_skipZero = _f;
}
/**
* 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) {
m_budgetId = _budget; m_includeBudgetActuals = _fa;
}
/**
* This method allows you to clear the underlying transaction filter
*/
void clear();
/**
* 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) {
MyMoneyTransactionFilter::operator=(_filter);
}
/**
* 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(dateOptionE _u) {
m_dateLock = _u;
if (_u != userDefined)
MyMoneyTransactionFilter::setDateFilter(_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) {
MyMoneyTransactionFilter::setDateFilter(_db, _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() {
if (m_dateLock != userDefined) MyMoneyTransactionFilter::setDateFilter(m_dateLock);
}
/**
* 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(MyMoneyAccount::accountTypeE 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(MyMoneyAccount::accountTypeE 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 writes this report to the DOM element @p e,
* within the DOM document @p doc.
*
* @param e The element which should be populated with info from this report
* @param doc The document which we can use to create new sub-elements
* if needed
* @param anonymous Whether the sensitive parts of the report should be
* masked
*/
void write(QDomElement& e, QDomDocument *doc, bool anonymous = false) const;
/**
* This method reads a report from the DOM element @p e, and
* populates this report with the results.
*
* @param e The element from which the report should be read
*
* @return bool True if a report was successfully loaded from the
* element @p e. If false is returned, the contents of this report
* object are undefined.
*/
bool read(const QDomElement& e);
/**
* This method creates a QDomElement for the @p document
* under the parent node @p parent. (This version overwrites the
* MMObject base class.)
*
* @param document reference to QDomDocument
* @param parent reference to QDomElement parent node
*/
virtual void writeXML(QDomDocument& document, QDomElement& parent) 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.
*/
virtual bool hasReferenceTo(const QString& id) const;
/**
* This method allows to modify the default lineWidth for graphs.
* The default is 2.
*/
static void setLineWidth(int width);
private:
/**
* 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
*/
DetailLevel::Type m_detailLevel;
/**
* 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
*/
Report::Type m_reportType;
/**
* What sort of values should show up on the ROWS of this report
*/
Row::Type 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.
*/
Column::Type 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
*/
enum QueryColumns::Type 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
*/
dateOptionE 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
*/
Chart::Type 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_chartGridLines;
/**
* 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;
+ /**
+ * Color palette used for the chart of this report
+ */
+ ChartPalette::Type m_chartPalette;
/**
* 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 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 dinamically and thus it is not saved in the file
*/
int m_currentDateColumn;
/**
* This member keeps the current setting for line graphs lineWidth.
* @sa setLineWidth()
*/
static int m_lineWidth;
/**
* 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;
};
/**
* Make it possible to hold @ref MyMoneyReport objects inside @ref QVariant objects.
*/
Q_DECLARE_METATYPE(MyMoneyReport)
#endif // MYMONEYREPORT_H
diff --git a/kmymoney/reports/kreportchartview.cpp b/kmymoney/reports/kreportchartview.cpp
index 97270100c..c95c45058 100644
--- a/kmymoney/reports/kreportchartview.cpp
+++ b/kmymoney/reports/kreportchartview.cpp
@@ -1,650 +1,664 @@
/***************************************************************************
kreportchartview.cpp
-------------------
begin : Sun Aug 14 2005
copyright : (C) 2004-2005 by Ace Jones
email :
***************************************************************************/
/***************************************************************************
* *
* 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 "kreportchartview.h"
#include
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include
#include
#include
// ----------------------------------------------------------------------------
// Project Includes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kmymoneyglobalsettings.h"
#include
#include
using namespace reports;
KReportChartView::KReportChartView(QWidget* parent) :
KDChart::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())
{
// ********************************************************************
// 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);
//Line diagram
KDChart::LineDiagram* diagram = new KDChart::LineDiagram;
diagram->setModel(&m_model);
this->coordinatePlane()->replaceDiagram(diagram);
}
void KReportChartView::drawPivotChart(const PivotGrid &grid, const MyMoneyReport &config, int numberColumns, const QStringList& columnHeadings, const QList& rowTypeList, const QStringList& columnTypeHeaderList)
{
//set the number of columns
setNumColumns(numberColumns);
//set skipZero
m_skipZero = config.isSkippingZero();
//remove existing headers
while (headerFooters().count() > 0) {
HeaderFooter* delHeader = headerFooters().at(0);
takeHeaderFooter(delHeader);
delete delHeader;
}
//make sure the model is clear
m_model.removeColumns(0, m_model.columnCount());
m_model.removeRows(0, m_model.rowCount());
//set the new header
HeaderFooter* header = new HeaderFooter(this);
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 MyMoneyReport::Chart::None:
case MyMoneyReport::Chart::End:
case MyMoneyReport::Chart::Line: {
KDChart::LineDiagram* diagram = new KDChart::LineDiagram;
if (config.isSkippingZero()) {
LineAttributes attributes = diagram->lineAttributes();
attributes.setMissingValuesPolicy(LineAttributes::MissingValuesAreBridged);
diagram->setLineAttributes(attributes);
}
CartesianCoordinatePlane* cartesianPlane = new CartesianCoordinatePlane;
replaceCoordinatePlane(cartesianPlane);
coordinatePlane()->replaceDiagram(diagram);
break;
}
case MyMoneyReport::Chart::Bar: {
KDChart::BarDiagram* diagram = new KDChart::BarDiagram;
CartesianCoordinatePlane* cartesianPlane = new CartesianCoordinatePlane;
replaceCoordinatePlane(cartesianPlane);
coordinatePlane()->replaceDiagram(diagram);
break;
}
case MyMoneyReport::Chart::StackedBar: {
KDChart::BarDiagram* diagram = new KDChart::BarDiagram;
CartesianCoordinatePlane* cartesianPlane = new CartesianCoordinatePlane;
replaceCoordinatePlane(cartesianPlane);
diagram->setType(BarDiagram::Stacked);
coordinatePlane()->replaceDiagram(diagram);
break;
}
case MyMoneyReport::Chart::Pie: {
KDChart::PieDiagram* diagram = new KDChart::PieDiagram;
PolarCoordinatePlane* polarPlane = new PolarCoordinatePlane;
replaceCoordinatePlane(polarPlane);
coordinatePlane()->replaceDiagram(diagram);
setAccountSeries(false);
setSeriesTotals(true);
break;
}
case MyMoneyReport::Chart::Ring: {
KDChart::RingDiagram* diagram = new KDChart::RingDiagram;
PolarCoordinatePlane* polarPlane = new PolarCoordinatePlane;
replaceCoordinatePlane(polarPlane);
polarPlane->replaceDiagram(diagram);
//chartView.params()->setRelativeRingThickness( true );
setAccountSeries(false);
break;
}
}
//get the diagram for later use
AbstractDiagram* planeDiagram = coordinatePlane()->diagram();
planeDiagram->setAntiAliasing(true);
//set grid attributes
GridAttributes gridAttr(coordinatePlane()->globalGridAttributes());
gridAttr.setGridVisible(config.isChartGridLines());
coordinatePlane()->setGlobalGridAttributes(gridAttr);
- //the palette - we set it here because it is a property of the diagram
- switch (KMyMoneySettings::chartsPalette()) {
- case 0:
+ // setup chart color palette
+ switch (config.chartPalette()) {
+ case MyMoneyReport::ChartPalette::Application:
+ switch (KMyMoneySettings::chartsPalette()) {
+ case 0:
+ planeDiagram->useDefaultColors();
+ break;
+ case 1:
+ planeDiagram->useRainbowColors();
+ break;
+ case 2:
+ default:
+ planeDiagram->useSubduedColors();
+ break;
+ }
+ break;
+ case MyMoneyReport::ChartPalette::Default:
planeDiagram->useDefaultColors();
break;
- case 1:
+ case MyMoneyReport::ChartPalette::Rainbow:
planeDiagram->useRainbowColors();
break;
- case 2:
default:
+ case MyMoneyReport::ChartPalette::Subdued:
planeDiagram->useSubduedColors();
break;
}
//the legend will be used later
Legend* legend = new Legend(planeDiagram, this);
legend->setTitleText(i18nc("Chart legend title", "Legend"));
//set up the axes for cartesian diagrams
if (config.chartType() == MyMoneyReport::Chart::Line ||
config.chartType() == MyMoneyReport::Chart::Bar ||
config.chartType() == MyMoneyReport::Chart::StackedBar) {
//set x axis
CartesianAxis *xAxis = new CartesianAxis();
xAxis->setPosition(CartesianAxis::Bottom);
xAxis->setTitleText(i18n("Time"));
TextAttributes xAxisTitleTextAttr(xAxis->titleTextAttributes());
xAxisTitleTextAttr.setMinimalFontSize(KGlobalSettings::generalFont().pointSize());
xAxisTitleTextAttr.setPen(m_foregroundBrush.color());
xAxis->setTitleTextAttributes(xAxisTitleTextAttr);
TextAttributes xAxisTextAttr(xAxis->textAttributes());
xAxisTextAttr.setPen(m_foregroundBrush.color());
xAxisTextAttr.setAutoRotate(true);
xAxis->setTextAttributes(xAxisTextAttr);
RulerAttributes xAxisRulerAttr(xAxis->rulerAttributes());
xAxisRulerAttr.setTickMarkPen(m_foregroundBrush.color());
xAxisRulerAttr.setShowRulerLine(true);
xAxis->setRulerAttributes(xAxisRulerAttr);
//set y axis
KBalanceAxis *yAxis = new KBalanceAxis();
yAxis->setPosition(CartesianAxis::Left);
// TODO
// if the chart shows prices and no balance
// the axis title should be 'Price'
if (config.isIncludingPrice()) {
yAxis->setTitleText(i18n("Price"));
} else {
yAxis->setTitleText(i18n("Balance"));
}
TextAttributes yAxisTitleTextAttr(yAxis->titleTextAttributes());
yAxisTitleTextAttr.setMinimalFontSize(KGlobalSettings::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);
//add the axes to the corresponding diagram
if (config.chartType() == MyMoneyReport::Chart::Line) {
KDChart::LineDiagram* lineDiagram = qobject_cast(planeDiagram);
lineDiagram->addAxis(xAxis);
lineDiagram->addAxis(yAxis);
} else if (config.chartType() == MyMoneyReport::Chart::Bar ||
config.chartType() == MyMoneyReport::Chart::StackedBar) {
KDChart::BarDiagram* barDiagram = qobject_cast(planeDiagram);
barDiagram->addAxis(xAxis);
barDiagram->addAxis(yAxis);
}
}
switch (config.detailLevel()) {
case MyMoneyReport::DetailLevel::None:
case MyMoneyReport::DetailLevel::End:
case MyMoneyReport::DetailLevel::All: {
int rowNum = 0;
// iterate over outer groups
PivotGrid::const_iterator it_outergroup = grid.begin();
while (it_outergroup != grid.end()) {
// iterate over inner groups
PivotOuterGroup::const_iterator it_innergroup = (*it_outergroup).begin();
while (it_innergroup != (*it_outergroup).end()) {
//
// Rows
//
QString innergroupdata;
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() != MyMoneyAccount::Investment) {
//iterate row types
for (int i = 0; i < rowTypeList.size(); ++i) {
//skip the budget difference rowset
if (rowTypeList[i] != eBudgetDiff) {
QString legendText;
//only show the column type in the header if there is more than one type
if (rowTypeList.size() > 1) {
legendText = QString(columnTypeHeaderList[i] + " - " + it_row.key().name());
} else {
legendText = QString(it_row.key().name());
}
//set the cell value and tooltip
rowNum = drawPivotRowSet(rowNum, it_row.value(), rowTypeList[i], legendText, 1, numColumns());
//set the legend text
legend->setText(rowNum - 1, legendText);
}
}
}
++it_row;
}
++it_innergroup;
}
++it_outergroup;
}
}
break;
case MyMoneyReport::DetailLevel::Top: {
int rowNum = 0;
// iterate over outer groups
PivotGrid::const_iterator it_outergroup = grid.begin();
while (it_outergroup != grid.end()) {
// 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 < rowTypeList.size(); ++i) {
//skip the budget difference rowset
if (rowTypeList[i] != eBudgetDiff) {
QString legendText;
//only show the column type in the header if there is more than one type
if (rowTypeList.size() > 1) {
legendText = QString(columnTypeHeaderList[i] + " - " + it_innergroup.key());
} else {
legendText = QString(it_innergroup.key());
}
//set the cell value and tooltip
rowNum = drawPivotRowSet(rowNum, (*it_innergroup).m_total, rowTypeList[i], legendText, 1, numColumns());
//set the legend text
legend->setText(rowNum - 1, legendText);
}
}
++it_innergroup;
}
++it_outergroup;
}
}
break;
case MyMoneyReport::DetailLevel::Group: {
int rowNum = 0;
// iterate over outer groups
PivotGrid::const_iterator it_outergroup = grid.begin();
while (it_outergroup != grid.end()) {
//iterate row types
for (int i = 0; i < rowTypeList.size(); ++i) {
//skip the budget difference rowset
if (rowTypeList[i] != eBudgetDiff) {
QString legendText;
//only show the column type in the header if there is more than one type
if (rowTypeList.size() > 1) {
legendText = QString(columnTypeHeaderList[i] + " - " + it_outergroup.key());
} else {
legendText = QString(it_outergroup.key());
}
//set the cell value and tooltip
rowNum = drawPivotRowSet(rowNum, (*it_outergroup).m_total, rowTypeList[i], legendText, 1, numColumns());
//set the legend
legend->setText(rowNum - 1, legendText);
}
}
++it_outergroup;
}
//if selected, show totals too
if (config.isShowingRowTotals()) {
//iterate row types
for (int i = 0; i < rowTypeList.size(); ++i) {
//skip the budget difference rowset
if (rowTypeList[i] != eBudgetDiff) {
QString legendText;
//only show the column type in the header if there is more than one type
if (rowTypeList.size() > 1) {
legendText = QString(columnTypeHeaderList[i] + " - " + i18nc("Total balance", "Total"));
} else {
legendText = QString(i18nc("Total balance", "Total"));
}
//set the cell value
rowNum = drawPivotRowSet(rowNum, grid.m_total, rowTypeList[i], legendText, 1, numColumns());
//set the legend
legend->setText(rowNum - 1, legendText);
}
}
}
}
break;
case MyMoneyReport::DetailLevel::Total: {
int rowNum = 0;
//iterate row types
for (int i = 0; i < rowTypeList.size(); ++i) {
//skip the budget difference rowset
if (rowTypeList[i] != eBudgetDiff) {
QString legendText;
//only show the column type in the header if there is more than one type
if (rowTypeList.size() > 1) {
legendText = QString(columnTypeHeaderList[i] + " - " + i18nc("Total balance", "Total"));
} else {
legendText = QString(i18nc("Total balance", "Total"));
}
if (config.isMixedTime() && (rowTypeList[i] == eActual || rowTypeList[i] == eForecast)) {
if (rowTypeList[i] == eActual) {
rowNum = drawPivotRowSet(rowNum, grid.m_total, rowTypeList[i], legendText, 1, config.currentDateColumn());
} else if (rowTypeList[i] == eForecast) {
rowNum = drawPivotRowSet(rowNum, grid.m_total, rowTypeList[i], legendText, config.currentDateColumn(), numColumns());
} else {
rowNum = drawPivotRowSet(rowNum, grid.m_total, rowTypeList[i], legendText, 1, numColumns());
}
} else {
//set cell value
rowNum = drawPivotRowSet(rowNum, grid.m_total, rowTypeList[i], legendText, 1, numColumns());
}
//set legend text
legend->setText(rowNum - 1, legendText);
}
}
}
break;
}
// Set up X axis labels (ie "abscissa" to use the technical term)
QStringList abscissaNames;
if (accountSeries()) { // if not, we will set these up while putting in the chart values.
int column = 1;
while (column < numColumns()) {
abscissaNames += QString(columnHeadings[column++]).replace(" ", " ");
}
m_model.setVerticalHeaderLabels(abscissaNames);
}
//assign model to the diagram
planeDiagram->setModel(&m_model);
//set the legend basic attributes
//this is done after adding the legend because the values are overridden when adding the legend to the chart
for (uint i = static_cast(KMyMoneyGlobalSettings::maximumLegendItems()); i < legend->datasetCount(); ++i) {
legend->setDatasetHidden(i, true);
}
legend->setTitleText(i18nc("Chart lines legend", "Legend"));
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);
legend->setLegendStyle(KDChart::Legend::MarkersAndLines);
replaceLegend(legend);
// set the text attributes after calling replaceLegend() otherwise fon sizes will get overwritten
qreal generalFontSize = KGlobalSettings::generalFont().pointSizeF();
if (generalFontSize == -1)
generalFontSize = 8; // this is a fallback if the fontsize was specified in pixels
TextAttributes legendTextAttr(legend->textAttributes());
legendTextAttr.setPen(m_foregroundBrush.color());
legendTextAttr.setFontSize(KDChart::Measure(generalFontSize, KDChartEnums::MeasureCalculationModeAbsolute));
legend->setTextAttributes(legendTextAttr);
TextAttributes legendTitleTextAttr(legend->titleTextAttributes());
legendTitleTextAttr.setPen(m_foregroundBrush.color());
legendTitleTextAttr.setFontSize(KDChart::Measure(generalFontSize + 4, KDChartEnums::MeasureCalculationModeAbsolute));
legend->setTitleTextAttributes(legendTitleTextAttr);
//this sets the line width only for line diagrams
setLineWidth(config.chartLineWidth());
//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);
markerAttr.setMarkerSize(QSize(8, 8));
dataValueAttr.setMarkerAttributes(markerAttr);
TextAttributes dataValueTextAttr(dataValueAttr.textAttributes());
dataValueTextAttr.setPen(m_foregroundBrush.color());
dataValueTextAttr.setFontSize(KDChart::Measure(generalFontSize, KDChartEnums::MeasureCalculationModeAbsolute));
dataValueAttr.setTextAttributes(dataValueTextAttr);
dataValueAttr.setVisible(config.isChartDataLabels());
dataValueAttr.setDecimalDigits(MyMoneyMoney::denomToPrec(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction()));
planeDiagram->setDataValueAttributes(dataValueAttr);
planeDiagram->setAllowOverlappingDataValueTexts(true);
if (qMin(static_cast(KMyMoneyGlobalSettings::maximumLegendItems()), legend->datasetCount()) < 2) {
// the legend is needed only if at least two data sets are rendered
removeLegend();
}
// fix vertical plane range in case only one value is displayed
CartesianCoordinatePlane* plane = dynamic_cast(coordinatePlane());
if (plane) {
QPair range = plane->verticalRange();
double center = (range.first + range.second) / 2.0;
if (fabs(range.first - range.second) < 0.01) {
range.first = center - 1.001;
range.second = center + 1.001;
plane->setVerticalRange(range);
}
}
}
unsigned KReportChartView::drawPivotRowSet(int rowNum, const PivotGridRowSet& rowSet, const ERowType rowType, const QString& legendText, int startColumn, int endColumn)
{
//if endColumn is invalid, make it the same as numColumns
if (endColumn == 0) {
endColumn = numColumns();
}
// Columns
if (seriesTotals()) {
double value = rowSet[rowType].m_total.toDouble();
//set the tooltip
QString toolTip = QString("%1
%2
")
.arg(legendText)
.arg(value, 0, 'f', 2);
if (accountSeries()) {
//set the cell value
this->setDataCell(rowNum, 0, value);
this->setCellTip(rowNum, 0, toolTip);
} else {
this->setDataCell(0, rowNum, value);
this->setCellTip(0, rowNum, toolTip);
}
} else {
int column = startColumn;
while (column <= endColumn && column < numColumns()) {
double value = rowSet[rowType][column].toDouble();
//if zero and set to skip, increase column and continue with next value
if (m_skipZero && rowSet[rowType][column].isZero()) {
++column;
continue;
} else {
QString toolTip = QString("%1
%2
")
.arg(legendText)
.arg(value, 0, 'f', 2);
if (accountSeries()) {
this->setDataCell(column - 1, rowNum, value);
this->setCellTip(column - 1, rowNum, toolTip);
} else {
this->setDataCell(rowNum, column - 1, value);
this->setCellTip(rowNum, column - 1, toolTip);
}
}
++column;
}
}
return ++rowNum;
}
void KReportChartView::setDataCell(int row, int column, const double data)
{
if (coordinatePlane()->diagram()->datasetDimension() != 1)
return;
justifyModelSize(row + 1, column + 1);
const QModelIndex index = m_model.index(row, column);
m_model.setData(index, QVariant(data), Qt::DisplayRole);
}
void KReportChartView::setCellTip(int row, int column, QString tip)
{
if (coordinatePlane()->diagram()->datasetDimension() != 1)
return;
justifyModelSize(row + 1, column + 1);
const QModelIndex index = m_model.index(row, column);
m_model.setData(index, QVariant(tip), Qt::ToolTipRole);
}
/**
* 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)
{
if (qobject_cast(coordinatePlane()->diagram())) {
LineDiagram* lineDiagram = qobject_cast(coordinatePlane()->diagram());
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)
{
// 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();
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/widgets/kmymoneyreportconfigtabchartdecl.ui b/kmymoney/widgets/kmymoneyreportconfigtabchartdecl.ui
index acf7b2e29..844dc45ad 100644
--- a/kmymoney/widgets/kmymoneyreportconfigtabchartdecl.ui
+++ b/kmymoney/widgets/kmymoneyreportconfigtabchartdecl.ui
@@ -1,177 +1,204 @@
kMyMoneyReportConfigTabChartDecl
0
0
600
- 174
+ 183
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
+ -
+
+
-
+
+
+ Chart Palette
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
-
<p>Select this option to show horizontal and vertical grid lines on the chart.</p>
Show grid lines
-
<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
-
-
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
KComboBox
KComboBox
QComboBox
diff --git a/kmymoney/widgets/kmymoneyreportconfigtabimpl.cpp b/kmymoney/widgets/kmymoneyreportconfigtabimpl.cpp
index 245ac3010..743675294 100644
--- a/kmymoney/widgets/kmymoneyreportconfigtabimpl.cpp
+++ b/kmymoney/widgets/kmymoneyreportconfigtabimpl.cpp
@@ -1,93 +1,98 @@
/* This file is part of the KDE project
Copyright (C) 2009 Laurent Montel
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 "kmymoneyreportconfigtabimpl.h"
#include "ui_kmymoneyreportconfigtab1decl.h"
#include "ui_kmymoneyreportconfigtab2decl.h"
#include "ui_kmymoneyreportconfigtab3decl.h"
#include "ui_kmymoneyreportconfigtabchartdecl.h"
#include "mymoney/mymoneyreport.h"
kMyMoneyReportConfigTab1Decl::kMyMoneyReportConfigTab1Decl(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::kMyMoneyReportConfigTab1Decl;
ui->setupUi(this);
}
kMyMoneyReportConfigTab1Decl::~kMyMoneyReportConfigTab1Decl()
{
delete ui;
}
kMyMoneyReportConfigTab2Decl::kMyMoneyReportConfigTab2Decl(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::kMyMoneyReportConfigTab2Decl;
ui->setupUi(this);
}
kMyMoneyReportConfigTab2Decl::~kMyMoneyReportConfigTab2Decl()
{
delete ui;
}
kMyMoneyReportConfigTab3Decl::kMyMoneyReportConfigTab3Decl(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::kMyMoneyReportConfigTab3Decl;
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);
}
kMyMoneyReportConfigTab3Decl::~kMyMoneyReportConfigTab3Decl()
{
delete ui;
}
kMyMoneyReportConfigTabChartDecl::kMyMoneyReportConfigTabChartDecl(QWidget *parent)
: QWidget(parent)
{
ui = new Ui::kMyMoneyReportConfigTabChartDecl;
ui->setupUi(this);
ui->m_comboType->addItem(i18nc("type of graphic chart", "Line"), MyMoneyReport::Chart::Line);
ui->m_comboType->addItem(i18nc("type of graphic chart", "Bar"), MyMoneyReport::Chart::Bar);
ui->m_comboType->addItem(i18nc("type of graphic chart", "Stacked Bar"), MyMoneyReport::Chart::StackedBar);
ui->m_comboType->addItem(i18nc("type of graphic chart", "Pie"), MyMoneyReport::Chart::Pie);
ui->m_comboType->addItem(i18nc("type of graphic chart", "Ring"), MyMoneyReport::Chart::Ring);
+
+ ui->m_chartPalette->addItem(i18nc("chart palette", "Use application setting"), MyMoneyReport::ChartPalette::Application);
+ ui->m_chartPalette->addItem(i18nc("chart palette", "Default"), MyMoneyReport::ChartPalette::Default);
+ ui->m_chartPalette->addItem(i18nc("chart palette", "Rainbowed"), MyMoneyReport::ChartPalette::Rainbow);
+ ui->m_chartPalette->addItem(i18nc("chart palette", "Subdued"), MyMoneyReport::ChartPalette::Subdued);
}
kMyMoneyReportConfigTabChartDecl::~kMyMoneyReportConfigTabChartDecl()
{
delete ui;
}