-rw-r--r-- | noncore/apps/checkbook/checkbook.cpp | 122 | ||||
-rw-r--r-- | noncore/apps/checkbook/checkbook.h | 11 | ||||
-rw-r--r-- | noncore/apps/checkbook/graph.cpp | 85 | ||||
-rw-r--r-- | noncore/apps/checkbook/graph.h | 9 | ||||
-rw-r--r-- | noncore/apps/checkbook/graphinfo.cpp | 45 | ||||
-rw-r--r-- | noncore/apps/checkbook/graphinfo.h | 8 |
6 files changed, 241 insertions, 39 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 @@ -229,39 +229,36 @@ QWidget *Checkbook::initTransactions() return( control ); } 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; } void Checkbook::loadCheckbook() { @@ -364,18 +361,16 @@ void Checkbook::accept() config->writeEntryCrypt( "Number", acctNumEdit->text() ); config->writeEntryCrypt( "PINNumber", pinNumEdit->text() ); 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(); QDialog::accept(); } @@ -506,7 +501,96 @@ void Checkbook::slotDeleteTran() adjustBalance( amount * -1 ); } } 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 @@ -33,12 +33,13 @@ #include <qdialog.h> class OTabWidget; class Graph; +class GraphInfo; class QComboBox; class QLabel; class QLineEdit; class QListView; class QMultiLineEdit; class QString; @@ -81,15 +82,19 @@ class Checkbook : public QDialog QWidget *initTransactions(); QListView *tranTable; QLabel *balanceLabel; float currBalance; // Charts tab - QWidget *initCharts(); - //QComboBox *graphList; - Graph *graphWidget; + QWidget *initCharts(); + GraphInfo *graphInfo; + QComboBox *graphList; + Graph *graphWidget; + + void drawBalanceChart(); + void drawCategoryChart( bool = TRUE ); protected slots: void accept(); private slots: void slotNameChanged( const QString & ); 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 @@ -26,19 +26,19 @@ */ #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 ); } void Graph::setGraphInfo( GraphInfo *d ) @@ -79,34 +79,101 @@ void Graph::initGraph() // Any common stuff here (titles, ???) 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 ) { - //Find max value in GraphInfo->dataPoints() - make function in GraphInfo!!! + 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() +void Graph::drawLineChart( int width, int height, float max ) { } -void Graph::drawPieChart() +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++; + } + + 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 @@ -30,34 +30,35 @@ #define GRAPH_H #include <qpixmap.h> #include <qwidget.h> class GraphInfo; +class QPainter; class Graph : public QWidget { Q_OBJECT public: Graph( QWidget * = 0x0, GraphInfo * = 0x0, const QString & = 0x0, int = 0 ); void setGraphInfo( GraphInfo * ); void drawGraph( bool = FALSE ); - + protected: void paintEvent( QPaintEvent * ); void resizeEvent( QResizeEvent * ); private: GraphInfo *data; 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 @@ -35,12 +35,23 @@ GraphInfo::GraphInfo( GraphType type, DataPointList *data, const QString &title, d = data; gt = 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; } void GraphInfo::setGraphType( GraphType type ) @@ -55,20 +66,48 @@ DataPointList *GraphInfo::dataPoints() void GraphInfo::setDataPoints( DataPointList *data ) { d = data; } -float GraphInfo::maxValue() +DataPointInfo *GraphInfo::firstDataPoint() { - float max; + return( d->first() ); +} +DataPointInfo *GraphInfo::nextDataPoint() +{ + return( d->next() ); +} + +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::minValue() +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 ) { gt = 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 @@ -39,12 +39,14 @@ class DataPointInfo : l( 0x0 ), v( 0.0 ) {} DataPointInfo( const QString &label, float value ) : l( label ), v( value ) {} const QString &label() { return l; } float value() { return v; } + + void addToValue( float value ) { v += value; } private: QString l; float v; }; @@ -54,21 +56,25 @@ class GraphInfo { public: 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 & ); private: |