-rw-r--r-- | noncore/apps/checkbook/checkbook.cpp | 122 | ||||
-rw-r--r-- | noncore/apps/checkbook/checkbook.h | 7 | ||||
-rw-r--r-- | noncore/apps/checkbook/graph.cpp | 85 | ||||
-rw-r--r-- | noncore/apps/checkbook/graph.h | 7 | ||||
-rw-r--r-- | noncore/apps/checkbook/graphinfo.cpp | 45 | ||||
-rw-r--r-- | noncore/apps/checkbook/graphinfo.h | 8 |
6 files changed, 238 insertions, 36 deletions
diff --git a/noncore/apps/checkbook/checkbook.cpp b/noncore/apps/checkbook/checkbook.cpp index 20b42b5..77c1f57 100644 --- a/noncore/apps/checkbook/checkbook.cpp +++ b/noncore/apps/checkbook/checkbook.cpp | |||
@@ -232,33 +232,30 @@ QWidget *Checkbook::initTransactions() | |||
232 | 232 | ||
233 | QWidget *Checkbook::initCharts() | 233 | QWidget *Checkbook::initCharts() |
234 | { | 234 | { |
235 | graphInfo = 0x0; | ||
236 | |||
235 | QWidget *control = new QWidget( mainWidget ); | 237 | QWidget *control = new QWidget( mainWidget ); |
236 | 238 | ||
237 | QGridLayout *layout = new QGridLayout( control ); | 239 | QGridLayout *layout = new QGridLayout( control ); |
238 | layout->setSpacing( 2 ); | 240 | layout->setSpacing( 2 ); |
239 | layout->setMargin( 4 ); | 241 | layout->setMargin( 4 ); |
240 | 242 | ||
241 | /* | 243 | graphWidget = new Graph( control ); |
242 | QLabel *label = new QLabel( control ); | 244 | QWhatsThis::add( graphWidget, tr( "Select the desired chart below and then click on the Draw button." ) ); |
243 | label->setText( tr( "Graph type:" ) ); | 245 | layout->addMultiCellWidget( graphWidget, 0, 0, 0, 2 ); |
244 | layout->addWidget( label, 0, 0 ); | 246 | |
245 | graphList = new QComboBox( control ); | 247 | graphList = new QComboBox( control ); |
246 | graphList->insertItem( tr( "By category" ) ); | 248 | QWhatsThis::add( graphList, tr( "Click here to select the desired chart type." ) ); |
247 | graphList->insertItem( tr( "..." ) ); | 249 | graphList->insertItem( tr( "Account balance" ) ); |
248 | graphList->insertItem( tr( "..." ) ); | 250 | graphList->insertItem( tr( "Withdrawals by category" ) ); |
249 | layout->addWidget( graphList, 0, 1 ); | 251 | graphList->insertItem( tr( "Deposits by category" ) ); |
250 | */ | ||
251 | 252 | ||
252 | GraphInfo* info = new GraphInfo( GraphInfo::BarChart, 0x0, tr( "Graph Title" ), | 253 | layout->addMultiCellWidget( graphList, 1, 1, 0, 1 ); |
253 | tr( "X-Axis" ), tr( "Y-Axis" ) ); | ||
254 | graphWidget = new Graph( control, info ); | ||
255 | QWhatsThis::add( graphWidget, tr( "Charting is not implemented yet." ) ); | ||
256 | layout->addMultiCellWidget( graphWidget, 0, 0, 0, 1 ); | ||
257 | 254 | ||
258 | QPushButton *btn = new QPushButton( Resource::loadPixmap( "checkbook/drawbtn" ), tr( "Draw" ), control ); | 255 | QPushButton *btn = new QPushButton( Resource::loadPixmap( "checkbook/drawbtn" ), tr( "Draw" ), control ); |
259 | QWhatsThis::add( btn, tr( "Click here to draw the chart." ) ); | 256 | QWhatsThis::add( btn, tr( "Click here to draw the selected chart." ) ); |
260 | connect( btn, SIGNAL( clicked() ), this, SLOT( slotDrawGraph() ) ); | 257 | connect( btn, SIGNAL( clicked() ), this, SLOT( slotDrawGraph() ) ); |
261 | layout->addWidget( btn, 1, 1 ); | 258 | layout->addWidget( btn, 1, 2 ); |
262 | 259 | ||
263 | return control; | 260 | return control; |
264 | } | 261 | } |
@@ -367,12 +364,10 @@ void Checkbook::accept() | |||
367 | config->writeEntry( "Notes", notesEdit->text() ); | 364 | config->writeEntry( "Notes", notesEdit->text() ); |
368 | 365 | ||
369 | // Save transactions | 366 | // Save transactions |
370 | TranInfo *tran = transactions.first(); | ||
371 | int i = 1; | 367 | int i = 1; |
372 | while ( tran ) | 368 | for ( TranInfo *tran = transactions.first(); tran; tran = transactions.next() ) |
373 | { | 369 | { |
374 | tran->write( config, i ); | 370 | tran->write( config, i ); |
375 | tran = transactions.next(); | ||
376 | i++; | 371 | i++; |
377 | } | 372 | } |
378 | config->write(); | 373 | config->write(); |
@@ -509,4 +504,93 @@ void Checkbook::slotDeleteTran() | |||
509 | 504 | ||
510 | void Checkbook::slotDrawGraph() | 505 | void Checkbook::slotDrawGraph() |
511 | { | 506 | { |
507 | if ( graphInfo ) | ||
508 | { | ||
509 | delete graphInfo; | ||
510 | } | ||
511 | |||
512 | switch ( graphList->currentItem() ) | ||
513 | { | ||
514 | case 0 : drawBalanceChart(); | ||
515 | break; | ||
516 | case 1 : drawCategoryChart( TRUE ); | ||
517 | break; | ||
518 | case 2 : drawCategoryChart( FALSE ); | ||
519 | break; | ||
520 | }; | ||
521 | |||
522 | graphWidget->setGraphInfo( graphInfo ); | ||
523 | graphWidget->drawGraph( TRUE ); | ||
524 | } | ||
525 | |||
526 | void Checkbook::drawBalanceChart() | ||
527 | { | ||
528 | DataPointList *list = new DataPointList(); | ||
529 | |||
530 | float balance = startBalance; | ||
531 | float amount; | ||
532 | QString label; | ||
533 | int i = 0; | ||
534 | int count = transactions.count(); | ||
535 | |||
536 | for ( TranInfo *tran = transactions.first(); tran; tran = transactions.next() ) | ||
537 | { | ||
538 | i++; | ||
539 | balance -= tran->fee(); | ||
540 | amount = tran->amount(); | ||
541 | if ( tran->withdrawal() ) | ||
542 | { | ||
543 | amount *= -1; | ||
544 | } | ||
545 | balance += amount; | ||
546 | if ( i == 1 || i == count / 2 || i == count ) | ||
547 | { | ||
548 | label = tran->datestr(); | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | label = ""; | ||
553 | } | ||
554 | list->append( new DataPointInfo( label, balance ) ); | ||
555 | } | ||
556 | |||
557 | graphInfo = new GraphInfo( GraphInfo::BarChart, list ); | ||
558 | } | ||
559 | |||
560 | void Checkbook::drawCategoryChart( bool withdrawals ) | ||
561 | { | ||
562 | DataPointList *list = new DataPointList(); | ||
563 | |||
564 | TranInfo *tran = transactions.first(); | ||
565 | if ( tran->withdrawal() == withdrawals ) | ||
566 | { | ||
567 | list->append( new DataPointInfo( tran->category(), tran->amount() ) ); | ||
568 | } | ||
569 | tran = transactions.next(); | ||
570 | |||
571 | DataPointInfo *cat; | ||
572 | for ( ; tran; tran = transactions.next() ) | ||
573 | { | ||
574 | if ( tran->withdrawal() == withdrawals ) | ||
575 | { | ||
576 | // Find category in list | ||
577 | for ( cat = list->first(); cat; cat = list->next() ) | ||
578 | { | ||
579 | if ( cat->label() == tran->category() ) | ||
580 | { | ||
581 | break; | ||
582 | } | ||
583 | } | ||
584 | if ( cat && cat->label() == tran->category() ) | ||
585 | { // Found category, add to transaction to category total | ||
586 | cat->addToValue( tran->amount() ); | ||
587 | } | ||
588 | else | ||
589 | { // Didn't find category, add category to list | ||
590 | list->append( new DataPointInfo( tran->category(), tran->amount() ) ); | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | |||
595 | graphInfo = new GraphInfo( GraphInfo::PieChart, list ); | ||
512 | } | 596 | } |
diff --git a/noncore/apps/checkbook/checkbook.h b/noncore/apps/checkbook/checkbook.h index 01f1115..287788a 100644 --- a/noncore/apps/checkbook/checkbook.h +++ b/noncore/apps/checkbook/checkbook.h | |||
@@ -36,6 +36,7 @@ | |||
36 | class OTabWidget; | 36 | class OTabWidget; |
37 | 37 | ||
38 | class Graph; | 38 | class Graph; |
39 | class GraphInfo; | ||
39 | class QComboBox; | 40 | class QComboBox; |
40 | class QLabel; | 41 | class QLabel; |
41 | class QLineEdit; | 42 | class QLineEdit; |
@@ -85,9 +86,13 @@ class Checkbook : public QDialog | |||
85 | 86 | ||
86 | // Charts tab | 87 | // Charts tab |
87 | QWidget *initCharts(); | 88 | QWidget *initCharts(); |
88 | //QComboBox *graphList; | 89 | GraphInfo *graphInfo; |
90 | QComboBox *graphList; | ||
89 | Graph *graphWidget; | 91 | Graph *graphWidget; |
90 | 92 | ||
93 | void drawBalanceChart(); | ||
94 | void drawCategoryChart( bool = TRUE ); | ||
95 | |||
91 | protected slots: | 96 | protected slots: |
92 | void accept(); | 97 | void accept(); |
93 | 98 | ||
diff --git a/noncore/apps/checkbook/graph.cpp b/noncore/apps/checkbook/graph.cpp index bae92da..a0d8b78 100644 --- a/noncore/apps/checkbook/graph.cpp +++ b/noncore/apps/checkbook/graph.cpp | |||
@@ -29,13 +29,13 @@ | |||
29 | #include "graph.h" | 29 | #include "graph.h" |
30 | #include "graphinfo.h" | 30 | #include "graphinfo.h" |
31 | 31 | ||
32 | #include <qcolor.h> | ||
33 | #include <qfontmetrics.h> | ||
32 | #include <qpainter.h> | 34 | #include <qpainter.h> |
33 | 35 | ||
34 | Graph::Graph( QWidget *parent, GraphInfo *d, const QString &name, int flags ) | 36 | Graph::Graph( QWidget *parent, GraphInfo *d, const QString &name, int flags ) |
35 | : QWidget( parent, name, flags ) | 37 | : QWidget( parent, name, flags ) |
36 | { | 38 | { |
37 | setBackgroundMode( QWidget::PaletteBase ); | ||
38 | |||
39 | data = d; | 39 | data = d; |
40 | 40 | ||
41 | graph.setOptimization( QPixmap::BestOptim ); | 41 | graph.setOptimization( QPixmap::BestOptim ); |
@@ -82,31 +82,98 @@ void Graph::initGraph() | |||
82 | { | 82 | { |
83 | case GraphInfo::BarChart : | 83 | case GraphInfo::BarChart : |
84 | { | 84 | { |
85 | drawBarChart(); | 85 | drawBarChart( width(), height(), data->maxValue() ); |
86 | } | 86 | } |
87 | break; | 87 | break; |
88 | case GraphInfo::LineChart : | 88 | case GraphInfo::LineChart : |
89 | { | 89 | { |
90 | drawLineChart(); | 90 | //drawLineChart( p, s, min, max ); |
91 | } | 91 | } |
92 | break; | 92 | break; |
93 | case GraphInfo::PieChart : | 93 | case GraphInfo::PieChart : |
94 | { | 94 | { |
95 | drawPieChart(); | 95 | drawPieChart( width(), height(), data->totalValue() ); |
96 | } | 96 | } |
97 | }; | 97 | }; |
98 | } | 98 | } |
99 | 99 | ||
100 | void Graph::drawBarChart() | 100 | void Graph::drawBarChart( int width, int height, float max ) |
101 | { | ||
102 | QPainter p( &graph ); | ||
103 | |||
104 | // Try to set the font size smaller for text | ||
105 | QFont f = font(); | ||
106 | f.setPointSize( 8 ); | ||
107 | p.setFont( f ); | ||
108 | |||
109 | int x = 0; | ||
110 | int i = 0; | ||
111 | int n = data->numberDataPoints(); | ||
112 | QFontMetrics fm=fontMetrics(); | ||
113 | int fh = fm.height(); | ||
114 | int fw; | ||
115 | |||
116 | QColor c( 0, 0, 255); | ||
117 | p.setBrush( c ); | ||
118 | |||
119 | for (DataPointInfo *dp = data->firstDataPoint(); dp; dp = data->nextDataPoint() ) | ||
120 | { | ||
121 | int bw = ( width - width / 4 - x ) / ( n - i ); | ||
122 | int bh = int( ( height - height / 4 - 1 ) * dp->value() / max ); | ||
123 | p.drawRect( width / 8 + x, height - height / 8 - 1 - bh, bw, bh ); | ||
124 | fw = fm.width( dp->label() ); | ||
125 | p.drawText( width / 8 + x - fw / 2 + bw / 2, height - height / 8, fw, | ||
126 | fh + height / 8, AlignTop | AlignHCenter, dp->label() ); | ||
127 | // WordBreak | AlignTop | AlignHCenter, dp->label() ); | ||
128 | i++; | ||
129 | x += bw; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | void Graph::drawLineChart( int width, int height, float max ) | ||
101 | { | 134 | { |
102 | //Find max value in GraphInfo->dataPoints() - make function in GraphInfo!!! | ||
103 | } | 135 | } |
104 | 136 | ||
105 | void Graph::drawLineChart() | 137 | void Graph::drawPieChart( int width, int height, float sum ) |
106 | { | 138 | { |
139 | QPainter p( &graph ); | ||
140 | |||
141 | // Try to set the font size smaller for text | ||
142 | QFont f = font(); | ||
143 | f.setPointSize( 8 ); | ||
144 | p.setFont( f ); | ||
145 | |||
146 | int n = data->numberDataPoints(); | ||
147 | |||
148 | int apos = -90 * 16; | ||
149 | |||
150 | int xd = width - width / 5; | ||
151 | int yd = height - height / 5; | ||
152 | |||
153 | int i = 0; | ||
154 | |||
155 | QColor c; | ||
156 | |||
157 | for (DataPointInfo *dp = data->firstDataPoint(); dp; dp = data->nextDataPoint() ) | ||
158 | { | ||
159 | c.setHsv( ( i *255) / n, 255, 255 ); | ||
160 | p.setBrush( c ); | ||
161 | |||
162 | int a = int( ( dp->value() * 360.0 ) / sum * 16.0 + 0.5 ); | ||
163 | p.drawPie( width/10, height/10, xd, yd, -apos, -a ); | ||
164 | apos += a; | ||
165 | i++; | ||
107 | } | 166 | } |
108 | 167 | ||
109 | void Graph::drawPieChart() | 168 | double apos2 = -90 * 3.14159 / 180; |
169 | for (DataPointInfo *dp = data->firstDataPoint(); dp; dp = data->nextDataPoint() ) | ||
110 | { | 170 | { |
171 | double a = dp->value() *360 / sum * 3.14159 / 180; | ||
172 | int x = int( cos( apos2 + a/2 ) * width * 5/16 + width/2 + 0.5 ); | ||
173 | int y = int( sin( apos2 + a/2 ) * height * 5/16 + height/2 + 0.5 ); | ||
174 | p.drawText( x - width/8, y - height/8, width/4, height/4, WordBreak | AlignCenter, | ||
175 | dp->label() ); | ||
176 | apos2 += a; | ||
177 | } | ||
111 | } | 178 | } |
112 | 179 | ||
diff --git a/noncore/apps/checkbook/graph.h b/noncore/apps/checkbook/graph.h index 7379be7..40b23cd 100644 --- a/noncore/apps/checkbook/graph.h +++ b/noncore/apps/checkbook/graph.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <qwidget.h> | 33 | #include <qwidget.h> |
34 | 34 | ||
35 | class GraphInfo; | 35 | class GraphInfo; |
36 | class QPainter; | ||
36 | 37 | ||
37 | class Graph : public QWidget | 38 | class Graph : public QWidget |
38 | { | 39 | { |
@@ -55,9 +56,9 @@ class Graph : public QWidget | |||
55 | QPixmap graph; | 56 | QPixmap graph; |
56 | 57 | ||
57 | void initGraph(); | 58 | void initGraph(); |
58 | void drawBarChart(); | 59 | void drawBarChart( int, int, float ); |
59 | void drawLineChart(); | 60 | void drawLineChart( int, int, float ); |
60 | void drawPieChart(); | 61 | void drawPieChart( int, int, float ); |
61 | }; | 62 | }; |
62 | 63 | ||
63 | #endif | 64 | #endif |
diff --git a/noncore/apps/checkbook/graphinfo.cpp b/noncore/apps/checkbook/graphinfo.cpp index 7b06bdb..ec6a465 100644 --- a/noncore/apps/checkbook/graphinfo.cpp +++ b/noncore/apps/checkbook/graphinfo.cpp | |||
@@ -38,6 +38,17 @@ GraphInfo::GraphInfo( GraphType type, DataPointList *data, const QString &title, | |||
38 | yt = ytitle; | 38 | yt = ytitle; |
39 | } | 39 | } |
40 | 40 | ||
41 | GraphInfo::~GraphInfo() | ||
42 | { | ||
43 | if ( d ) | ||
44 | { | ||
45 | for ( DataPointInfo *data = d->first(); data; data = d->next() ) | ||
46 | { | ||
47 | delete data; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | |||
41 | GraphInfo::GraphType GraphInfo::graphType() | 52 | GraphInfo::GraphType GraphInfo::graphType() |
42 | { | 53 | { |
43 | return t; | 54 | return t; |
@@ -58,14 +69,42 @@ void GraphInfo::setDataPoints( DataPointList *data ) | |||
58 | d = data; | 69 | d = data; |
59 | } | 70 | } |
60 | 71 | ||
61 | float GraphInfo::maxValue() | 72 | DataPointInfo *GraphInfo::firstDataPoint() |
62 | { | 73 | { |
63 | float max; | 74 | return( d->first() ); |
75 | } | ||
64 | 76 | ||
77 | DataPointInfo *GraphInfo::nextDataPoint() | ||
78 | { | ||
79 | return( d->next() ); | ||
65 | } | 80 | } |
66 | 81 | ||
67 | float GraphInfo::minValue() | 82 | int GraphInfo::numberDataPoints() |
68 | { | 83 | { |
84 | return( d->count() ); | ||
85 | } | ||
86 | |||
87 | float GraphInfo::maxValue() | ||
88 | { | ||
89 | float max = 0.0; | ||
90 | for ( DataPointInfo *data = d->first(); data; data = d->next() ) | ||
91 | { | ||
92 | if ( data->value() > max ) | ||
93 | { | ||
94 | max = data->value(); | ||
95 | } | ||
96 | } | ||
97 | return max; | ||
98 | } | ||
99 | |||
100 | float GraphInfo::totalValue() | ||
101 | { | ||
102 | float sum = 0.0; | ||
103 | for ( DataPointInfo *data = d->first(); data; data = d->next() ) | ||
104 | { | ||
105 | sum += data->value(); | ||
106 | } | ||
107 | return sum; | ||
69 | } | 108 | } |
70 | 109 | ||
71 | void GraphInfo::setGraphTitle( const QString &title ) | 110 | void GraphInfo::setGraphTitle( const QString &title ) |
diff --git a/noncore/apps/checkbook/graphinfo.h b/noncore/apps/checkbook/graphinfo.h index 4ad1dc9..620da74 100644 --- a/noncore/apps/checkbook/graphinfo.h +++ b/noncore/apps/checkbook/graphinfo.h | |||
@@ -43,6 +43,8 @@ class DataPointInfo | |||
43 | const QString &label() { return l; } | 43 | const QString &label() { return l; } |
44 | float value() { return v; } | 44 | float value() { return v; } |
45 | 45 | ||
46 | void addToValue( float value ) { v += value; } | ||
47 | |||
46 | private: | 48 | private: |
47 | QString l; | 49 | QString l; |
48 | float v; | 50 | float v; |
@@ -57,15 +59,19 @@ class GraphInfo | |||
57 | 59 | ||
58 | GraphInfo( GraphType = BarChart, DataPointList * = 0x0, | 60 | GraphInfo( GraphType = BarChart, DataPointList * = 0x0, |
59 | const QString & = 0x0, const QString & = 0x0, const QString & = 0x0 ); | 61 | const QString & = 0x0, const QString & = 0x0, const QString & = 0x0 ); |
62 | ~GraphInfo(); | ||
60 | 63 | ||
61 | GraphInfo::GraphType graphType(); | 64 | GraphInfo::GraphType graphType(); |
62 | void setGraphType( GraphType ); | 65 | void setGraphType( GraphType ); |
63 | 66 | ||
64 | DataPointList *dataPoints(); | 67 | DataPointList *dataPoints(); |
65 | void setDataPoints( DataPointList * ); | 68 | void setDataPoints( DataPointList * ); |
69 | DataPointInfo *firstDataPoint(); | ||
70 | DataPointInfo *nextDataPoint(); | ||
71 | int numberDataPoints(); | ||
66 | 72 | ||
67 | float maxValue(); | 73 | float maxValue(); |
68 | float minValue(); | 74 | float totalValue(); |
69 | 75 | ||
70 | void setGraphTitle( const QString & ); | 76 | void setGraphTitle( const QString & ); |
71 | void setXAxisTitle( const QString & ); | 77 | void setXAxisTitle( const QString & ); |