-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 @@ -231,35 +231,32 @@ QWidget *Checkbook::initTransactions() } QWidget *Checkbook::initCharts() { + graphInfo = 0x0; + QWidget *control = new QWidget( mainWidget ); QGridLayout *layout = new QGridLayout( control ); layout->setSpacing( 2 ); layout->setMargin( 4 ); -/* - QLabel *label = new QLabel( control ); - label->setText( tr( "Graph type:" ) ); - layout->addWidget( label, 0, 0 ); + graphWidget = new Graph( control ); + QWhatsThis::add( graphWidget, tr( "Select the desired chart below and then click on the Draw button." ) ); + layout->addMultiCellWidget( graphWidget, 0, 0, 0, 2 ); + graphList = new QComboBox( control ); - graphList->insertItem( tr( "By category" ) ); - graphList->insertItem( tr( "..." ) ); - graphList->insertItem( tr( "..." ) ); - layout->addWidget( graphList, 0, 1 ); -*/ + QWhatsThis::add( graphList, tr( "Click here to select the desired chart type." ) ); + graphList->insertItem( tr( "Account balance" ) ); + graphList->insertItem( tr( "Withdrawals by category" ) ); + graphList->insertItem( tr( "Deposits by category" ) ); - GraphInfo* info = new GraphInfo( GraphInfo::BarChart, 0x0, tr( "Graph Title" ), - tr( "X-Axis" ), tr( "Y-Axis" ) ); - graphWidget = new Graph( control, info ); - QWhatsThis::add( graphWidget, tr( "Charting is not implemented yet." ) ); - layout->addMultiCellWidget( graphWidget, 0, 0, 0, 1 ); + layout->addMultiCellWidget( graphList, 1, 1, 0, 1 ); QPushButton *btn = new QPushButton( Resource::loadPixmap( "checkbook/drawbtn" ), tr( "Draw" ), control ); - QWhatsThis::add( btn, tr( "Click here to draw the chart." ) ); + QWhatsThis::add( btn, tr( "Click here to draw the selected chart." ) ); connect( btn, SIGNAL( clicked() ), this, SLOT( slotDrawGraph() ) ); - layout->addWidget( btn, 1, 1 ); + layout->addWidget( btn, 1, 2 ); return control; } @@ -366,14 +363,12 @@ void Checkbook::accept() config->writeEntry( "Balance", balanceEdit->text() ); config->writeEntry( "Notes", notesEdit->text() ); // Save transactions - TranInfo *tran = transactions.first(); int i = 1; - while ( tran ) + for ( TranInfo *tran = transactions.first(); tran; tran = transactions.next() ) { tran->write( config, i ); - tran = transactions.next(); i++; } config->write(); @@ -508,5 +503,94 @@ void Checkbook::slotDeleteTran() } void Checkbook::slotDrawGraph() { + if ( graphInfo ) + { + delete graphInfo; + } + + switch ( graphList->currentItem() ) + { + case 0 : drawBalanceChart(); + break; + case 1 : drawCategoryChart( TRUE ); + break; + case 2 : drawCategoryChart( FALSE ); + break; + }; + + graphWidget->setGraphInfo( graphInfo ); + graphWidget->drawGraph( TRUE ); +} + +void Checkbook::drawBalanceChart() +{ + DataPointList *list = new DataPointList(); + + float balance = startBalance; + float amount; + QString label; + int i = 0; + int count = transactions.count(); + + for ( TranInfo *tran = transactions.first(); tran; tran = transactions.next() ) + { + i++; + balance -= tran->fee(); + amount = tran->amount(); + if ( tran->withdrawal() ) + { + amount *= -1; + } + balance += amount; + if ( i == 1 || i == count / 2 || i == count ) + { + label = tran->datestr(); + } + else + { + label = ""; + } + list->append( new DataPointInfo( label, balance ) ); + } + + graphInfo = new GraphInfo( GraphInfo::BarChart, list ); +} + +void Checkbook::drawCategoryChart( bool withdrawals ) +{ + DataPointList *list = new DataPointList(); + + TranInfo *tran = transactions.first(); + if ( tran->withdrawal() == withdrawals ) + { + list->append( new DataPointInfo( tran->category(), tran->amount() ) ); + } + tran = transactions.next(); + + DataPointInfo *cat; + for ( ; tran; tran = transactions.next() ) + { + if ( tran->withdrawal() == withdrawals ) + { + // Find category in list + for ( cat = list->first(); cat; cat = list->next() ) + { + if ( cat->label() == tran->category() ) + { + break; + } + } + if ( cat && cat->label() == tran->category() ) + { // Found category, add to transaction to category total + cat->addToValue( tran->amount() ); + } + else + { // Didn't find category, add category to list + list->append( new DataPointInfo( tran->category(), tran->amount() ) ); + } + } + } + + graphInfo = new GraphInfo( GraphInfo::PieChart, list ); } 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 @@ -35,8 +35,9 @@ class OTabWidget; class Graph; +class GraphInfo; class QComboBox; class QLabel; class QLineEdit; class QListView; @@ -84,11 +85,15 @@ class Checkbook : public QDialog float currBalance; // Charts tab QWidget *initCharts(); - //QComboBox *graphList; + GraphInfo *graphInfo; + QComboBox *graphList; Graph *graphWidget; + void drawBalanceChart(); + void drawCategoryChart( bool = TRUE ); + protected slots: void accept(); private slots: 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 @@ -28,15 +28,15 @@ #include "graph.h" #include "graphinfo.h" +#include <qcolor.h> +#include <qfontmetrics.h> #include <qpainter.h> Graph::Graph( QWidget *parent, GraphInfo *d, const QString &name, int flags ) : QWidget( parent, name, flags ) { - setBackgroundMode( QWidget::PaletteBase ); - data = d; graph.setOptimization( QPixmap::BestOptim ); } @@ -81,32 +81,99 @@ void Graph::initGraph() switch ( data->graphType() ) { case GraphInfo::BarChart : { - drawBarChart(); + drawBarChart( width(), height(), data->maxValue() ); } break; case GraphInfo::LineChart : { - drawLineChart(); + //drawLineChart( p, s, min, max ); } break; case GraphInfo::PieChart : { - drawPieChart(); + drawPieChart( width(), height(), data->totalValue() ); } }; } -void Graph::drawBarChart() +void Graph::drawBarChart( int width, int height, float max ) +{ + QPainter p( &graph ); + + // Try to set the font size smaller for text + QFont f = font(); + f.setPointSize( 8 ); + p.setFont( f ); + + int x = 0; + int i = 0; + int n = data->numberDataPoints(); + QFontMetrics fm=fontMetrics(); + int fh = fm.height(); + int fw; + + QColor c( 0, 0, 255); + p.setBrush( c ); + + for (DataPointInfo *dp = data->firstDataPoint(); dp; dp = data->nextDataPoint() ) + { + int bw = ( width - width / 4 - x ) / ( n - i ); + int bh = int( ( height - height / 4 - 1 ) * dp->value() / max ); + p.drawRect( width / 8 + x, height - height / 8 - 1 - bh, bw, bh ); + fw = fm.width( dp->label() ); + p.drawText( width / 8 + x - fw / 2 + bw / 2, height - height / 8, fw, + fh + height / 8, AlignTop | AlignHCenter, dp->label() ); +// WordBreak | AlignTop | AlignHCenter, dp->label() ); + i++; + x += bw; + } +} + +void Graph::drawLineChart( int width, int height, float max ) { - //Find max value in GraphInfo->dataPoints() - make function in GraphInfo!!! } -void Graph::drawLineChart() +void Graph::drawPieChart( int width, int height, float sum ) { + QPainter p( &graph ); + + // Try to set the font size smaller for text + QFont f = font(); + f.setPointSize( 8 ); + p.setFont( f ); + + int n = data->numberDataPoints(); + + int apos = -90 * 16; + + int xd = width - width / 5; + int yd = height - height / 5; + + int i = 0; + + QColor c; + + for (DataPointInfo *dp = data->firstDataPoint(); dp; dp = data->nextDataPoint() ) + { + c.setHsv( ( i *255) / n, 255, 255 ); + p.setBrush( c ); + + int a = int( ( dp->value() * 360.0 ) / sum * 16.0 + 0.5 ); + p.drawPie( width/10, height/10, xd, yd, -apos, -a ); + apos += a; + i++; } -void Graph::drawPieChart() + double apos2 = -90 * 3.14159 / 180; + for (DataPointInfo *dp = data->firstDataPoint(); dp; dp = data->nextDataPoint() ) { + double a = dp->value() *360 / sum * 3.14159 / 180; + int x = int( cos( apos2 + a/2 ) * width * 5/16 + width/2 + 0.5 ); + int y = int( sin( apos2 + a/2 ) * height * 5/16 + height/2 + 0.5 ); + p.drawText( x - width/8, y - height/8, width/4, height/4, WordBreak | AlignCenter, + dp->label() ); + apos2 += a; + } } 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 @@ -32,8 +32,9 @@ #include <qpixmap.h> #include <qwidget.h> class GraphInfo; +class QPainter; class Graph : public QWidget { Q_OBJECT @@ -54,10 +55,10 @@ class Graph : public QWidget QPixmap graph; void initGraph(); - void drawBarChart(); - void drawLineChart(); - void drawPieChart(); + void drawBarChart( int, int, float ); + void drawLineChart( int, int, float ); + void drawPieChart( int, int, float ); }; #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 @@ -37,8 +37,19 @@ GraphInfo::GraphInfo( GraphType type, DataPointList *data, const QString &title, xt = xtitle; yt = ytitle; } +GraphInfo::~GraphInfo() +{ + if ( d ) + { + for ( DataPointInfo *data = d->first(); data; data = d->next() ) + { + delete data; + } + } +} + GraphInfo::GraphType GraphInfo::graphType() { return t; } @@ -57,16 +68,44 @@ void GraphInfo::setDataPoints( DataPointList *data ) { d = data; } -float GraphInfo::maxValue() +DataPointInfo *GraphInfo::firstDataPoint() { - float max; + return( d->first() ); +} +DataPointInfo *GraphInfo::nextDataPoint() +{ + return( d->next() ); } -float GraphInfo::minValue() +int GraphInfo::numberDataPoints() { + return( d->count() ); +} + +float GraphInfo::maxValue() +{ + float max = 0.0; + for ( DataPointInfo *data = d->first(); data; data = d->next() ) + { + if ( data->value() > max ) + { + max = data->value(); + } + } + return max; +} + +float GraphInfo::totalValue() +{ + float sum = 0.0; + for ( DataPointInfo *data = d->first(); data; data = d->next() ) + { + sum += data->value(); + } + return sum; } 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 @@ -42,8 +42,10 @@ class DataPointInfo const QString &label() { return l; } float value() { return v; } + void addToValue( float value ) { v += value; } + private: QString l; float v; }; @@ -56,17 +58,21 @@ class GraphInfo enum GraphType { BarChart, LineChart, PieChart }; GraphInfo( GraphType = BarChart, DataPointList * = 0x0, const QString & = 0x0, const QString & = 0x0, const QString & = 0x0 ); + ~GraphInfo(); GraphInfo::GraphType graphType(); void setGraphType( GraphType ); DataPointList *dataPoints(); void setDataPoints( DataPointList * ); + DataPointInfo *firstDataPoint(); + DataPointInfo *nextDataPoint(); + int numberDataPoints(); float maxValue(); - float minValue(); + float totalValue(); void setGraphTitle( const QString & ); void setXAxisTitle( const QString & ); void setYAxisTitle( const QString & ); |