author | drw <drw> | 2002-11-02 21:45:56 (UTC) |
---|---|---|
committer | drw <drw> | 2002-11-02 21:45:56 (UTC) |
commit | 2dc81c48428222533e5479947d9ad318e464bafa (patch) (side-by-side diff) | |
tree | 2e3570d18f3574c49ffc8aaf287bac4822ff3a11 | |
parent | 5e1893923a9ddf1e2bd3e8f9c0dd264d86b8d98d (diff) | |
download | opie-2dc81c48428222533e5479947d9ad318e464bafa.zip opie-2dc81c48428222533e5479947d9ad318e464bafa.tar.gz opie-2dc81c48428222533e5479947d9ad318e464bafa.tar.bz2 |
Implementing charting...
-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 @@ -223,51 +223,48 @@ QWidget *Checkbook::initTransactions() layout->addWidget( btn, 2, 1 ); btn = new QPushButton( Resource::loadPixmap( "trash" ), tr( "Delete" ), control ); QWhatsThis::add( btn, tr( "Select a checkbook and then click here to delete it." ) ); connect( btn, SIGNAL( clicked() ), this, SLOT( slotDeleteTran() ) ); layout->addWidget( btn, 2, 2 ); 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() { transactions.clear(); Config config(filename, Config::File); // Load info config.setGroup( "Account" ); @@ -358,30 +355,28 @@ void Checkbook::accept() Config *config = new Config(filename, Config::File); // Save info config->setGroup( "Account" ); config->writeEntry( "Type", typeList->currentText() ); config->writeEntry( "Bank", bankEdit->text() ); 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(); } void Checkbook::slotNameChanged( const QString &newname ) { name = newname; filename = filedir; filename.append( newname ); @@ -500,13 +495,102 @@ void Checkbook::slotDeleteTran() } transactions.remove( traninfo ); delete traninfo; delete curritem; 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 @@ -27,24 +27,25 @@ */ #ifndef CHECKBOOK_H #define CHECKBOOK_H #include "traninfo.h" #include <qdialog.h> class OTabWidget; class Graph; +class GraphInfo; class QComboBox; class QLabel; class QLineEdit; class QListView; class QMultiLineEdit; class QString; class Checkbook : public QDialog { Q_OBJECT public: @@ -75,27 +76,31 @@ class Checkbook : public QDialog QLineEdit *pinNumEdit; QLineEdit *balanceEdit; QMultiLineEdit *notesEdit; float startBalance; // Transactions tab 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 & ); void slotStartingBalanceChanged( const QString & ); void slotNewTran(); void slotEditTran(); void slotDeleteTran(); void slotDrawGraph(); }; 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 @@ -20,31 +20,31 @@ : = ...= . :.=- You should have received a copy of the GNU -. .:....=;==+<; General Public License along with this file; -_. . . )=. = see the file COPYING. If not, write to the -- :-=` Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #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 ) { data = d; } void Graph::drawGraph( bool regen ) { @@ -73,40 +73,107 @@ void Graph::initGraph() if ( !data ) { return; } // 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 @@ -24,40 +24,41 @@ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef GRAPH_H #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 @@ -29,52 +29,91 @@ #include "graphinfo.h" GraphInfo::GraphInfo( GraphType type, DataPointList *data, const QString &title, const QString &xtitle, const QString &ytitle ) { t = type; 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 ) { t = type; } DataPointList *GraphInfo::dataPoints() { return d; } 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; } void GraphInfo::setXAxisTitle( const QString &xtitle ) { xt = xtitle; } 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 @@ -33,48 +33,54 @@ #include <qstringlist.h> class DataPointInfo { public: 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; }; typedef QList<DataPointInfo> DataPointList; 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: GraphType t; DataPointList *d; QString gt; QString xt; QString yt; }; |