1 /*
2  * Copyright 2005-2006  Ace Jones <acejones@users.sourceforge.net>
3  * Copyright 2005-2018  Thomas Baumgart <tbaumgart@kde.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef PIVOTGRID_H
20 #define PIVOTGRID_H
21 
22 // ----------------------------------------------------------------------------
23 // QT Includes
24 
25 #include <QMap>
26 #include <QList>
27 
28 // ----------------------------------------------------------------------------
29 // KDE Includes
30 
31 // ----------------------------------------------------------------------------
32 // Project Includes
33 
34 #include "reportaccount.h"
35 #include "mymoneymoney.h"
36 
37 namespace reports
38 {
39 
40 enum ERowType {eActual, eBudget, eBudgetDiff, eForecast, eAverage, ePrice };
41 
42 /**
43   * The fundamental data construct of this class is a 'grid'.  It is organized as follows:
44   *
45   * A 'Row' is a row of money values, each column is a month.  The first month corresponds to
46   * m_beginDate.
47   *
48   * A 'Row Pair' is two rows of money values.  Each column is the SAME month.  One row is the
49   * 'actual' values for the period, the other row is the 'budgetted' values for the same
50   * period.  For ease of implementation, a Row Pair is implemented as a Row which contains
51   * another Row.  The inherited Row is the 'actual', the contained row is the 'Budget'.
52   *
53   * An 'Inner Group' contains a rows for each subordinate account within a single top-level
54   * account.  It also contains a mapping from the account descriptor for the subordinate account
55   * to its row data.  So if we have an Expense account called "Computers", with sub-accounts called
56   * "Hardware", "Software", and "Peripherals", there will be one Inner Group for "Computers"
57   * which contains three Rows.
58   *
59   * An 'Outer Group' contains Inner Row Groups for all the top-level accounts in a given
60   * account class.  Account classes are Expense, Income, Asset, Liability.  In the case above,
61   * the "Computers" Inner Group is contained within the "Expense" Outer Group.
62   *
63   * A 'Grid' is the set of all Outer Groups contained in this report.
64   *
65   */
66 class PivotCell: public MyMoneyMoney
67 {
68   KMM_MYMONEY_UNIT_TESTABLE
69 
70 public:
PivotCell()71   PivotCell() : m_stockSplit(MyMoneyMoney::ONE), m_cellUsed(false) {}
72   explicit PivotCell(const MyMoneyMoney& value);
73   virtual ~PivotCell();
74   static PivotCell stockSplit(const MyMoneyMoney& factor);
75   PivotCell operator += (const PivotCell& right);
76   PivotCell operator += (const MyMoneyMoney& value);
77   const QString formatMoney(int fraction, bool showThousandSeparator = true) const;
78   const QString formatMoney(const QString& currency, const int prec, bool showThousandSeparator = true) const;
79   MyMoneyMoney calculateRunningSum(const MyMoneyMoney& runningSum);
80   MyMoneyMoney cellBalance(const MyMoneyMoney& _balance);
isUsed()81   bool isUsed() const {
82     return m_cellUsed;
83   }
84 private:
85   MyMoneyMoney m_stockSplit;
86   MyMoneyMoney m_postSplit;
87   bool m_cellUsed;
88 };
89 class PivotGridRow: public QList<PivotCell>
90 {
91 public:
92 
93   explicit PivotGridRow(unsigned _numcolumns = 0) {
94     for (uint i = 0; i < _numcolumns; i++)
95       append(PivotCell());
96   }
97   MyMoneyMoney m_total;
98 };
99 
100 class PivotGridRowSet: public QMap<ERowType, PivotGridRow>
101 {
102 public:
103   explicit PivotGridRowSet(unsigned _numcolumns = 0);
104 };
105 
106 class PivotInnerGroup: public QMap<ReportAccount, PivotGridRowSet>
107 {
108 public:
m_total(_numcolumns)109   explicit PivotInnerGroup(unsigned _numcolumns = 0): m_total(_numcolumns) {}
110 
111   PivotGridRowSet m_total;
112 };
113 
114 class PivotOuterGroup: public QMap<QString, PivotInnerGroup>
115 {
116 public:
m_total(_numcolumns)117   explicit PivotOuterGroup(unsigned _numcolumns = 0, unsigned _sort = m_kDefaultSortOrder, bool _inverted = false): m_total(_numcolumns), m_inverted(_inverted), m_sortOrder(_sort) {}
118   bool operator<(const PivotOuterGroup& _right) const {
119     if (m_sortOrder != _right.m_sortOrder)
120       return m_sortOrder < _right.m_sortOrder;
121     else
122       return m_displayName < _right.m_displayName;
123   }
124   PivotGridRowSet m_total;
125 
126   // An inverted outergroup means that all values placed in subordinate rows
127   // should have their sign inverted from typical cash-flow notation.  Also it
128   // means that when the report is summed, the values should be inverted again
129   // so that the grand total is really "non-inverted outergroup MINUS inverted outergroup".
130   bool m_inverted;
131 
132   // The localized name of the group for display in the report. Outergoups need this
133   // independently, because they will lose their association with the TGrid when the
134   // report is rendered.
135   QString m_displayName;
136 
137   // lower numbers sort toward the top of the report. defaults to 100, which is a nice
138   // middle-of-the-road value
139   unsigned m_sortOrder;
140 
141   // default sort order
142   static const unsigned m_kDefaultSortOrder;
143 };
144 class PivotGrid: public QMap<QString, PivotOuterGroup>
145 {
146 public:
147   PivotGridRowSet rowSet(QString id);
148 
149   PivotGridRowSet m_total;
150 };
151 
152 }
153 
154 #endif
155 // PIVOTGRID_H
156