/************************* * * * * * * * * * * * * *************************** Copyright (c) 1999-2005 Ryan Bobko ryan@ostrich-emulators.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************* * * * * * * * * * * * * ***************************/ #include "qhaccgrwin.h" #include "qhacc.h" #include "plugins.h" #include "qhacctable.h" #include "qhaccutils.h" #include "guiconstants.h" #include "qhaccprefdlg.h" #include "qhacclineedits.h" #include "qhaccsubsetwin.h" #include "qhaccconstants.h" #include "qhaccgrwin.moc" #include #include #include #include #include #include #include #include #include #include #include /********************/ /** GRAPHCONTROL **/ /********************/ QHaccDocControl::QHaccDocControl( QHacc * e, uint lid, QWidget * w, const char * n ) : QFrame( w, n ){ engine=e; QDate de=QDate::currentDate(); de=de.addDays( 1+de.daysInMonth()-de.day() ); //...through the current month start=new QHaccDateEdit( de, this ); end=new QHaccDateEdit( de, this ); start->setAlignment( AlignCenter ); end->setAlignment( AlignCenter ); QGridLayout * layout=new QGridLayout( this, 10, 1 ); QLabel * lbl=new QLabel( tr( "start date" ), this ); int row=0; layout->addMultiCellWidget( lbl, row, row, 0, 0, AlignCenter ); row++; layout->addMultiCellWidget( start, row, row, 0, 0 ); row++; lbl=new QLabel( tr( "end date" ), this ); layout->addMultiCellWidget( lbl, row, row, 0, 0, AlignCenter ); row++; layout->addMultiCellWidget( end, row, row, 0, 0 ); row++; lbl=new QLabel( tr( "type" ), this ); typer=new QComboBox( false, this ); layout->addMultiCellWidget( lbl, row, row, 0, 0, AlignCenter ); row++; layout->addMultiCellWidget( typer, row, row, 0, 0 ); row++; llbl=new QLabel( tr( "journal" ), this ); journaler=new QComboBox( false, this ); auto_ptr led=engine->getLs(); journaler->insertItem( tr( "All Journals" ) ); int selled=0; for( uint i=0; irows(); i++ ){ Journal l=led->at( i ); journaler->insertItem( l.gets( QC::LNAME ) ); if( l[QC::LID]==lid ) selled=i+1; // item is appended to the cb, right? } journaler->setCurrentItem( selled ); layout->addMultiCellWidget( llbl, row, row, 0, 0, AlignCenter ); row++; layout->addMultiCellWidget( journaler, row, row, 0, 0 ); row++; lbl=new QLabel( tr( "accounts" ), this ); pick=new QListBox( this ); pick->setSelectionMode( QListBox::Extended ); layout->addMultiCellWidget( lbl, row, row, 0, 0, AlignCenter ); row++; layout->addMultiCellWidget( pick, row, row, 0, 0 ); row++; QPushButton * prefsb=new QPushButton( tr( "Set Preferences" ), this ); layout->addMultiCellWidget( prefsb, row, row, 0, 0, 0 ); row++; QPushButton * printb=new QPushButton( tr( "Print" ), this ); layout->addMultiCellWidget( printb, row, row, 0, 0, 0 ); connect( prefsb, SIGNAL( clicked() ), SLOT( getPrefs() ) ); connect( printb, SIGNAL( clicked() ), SLOT( print() ) ); } QHaccDocControl::~QHaccDocControl(){} void QHaccDocControl::readPrefs( bool initial ){ //cout<<"qdc readprefs()"<getDate(); start->setDate( de.addMonths( 0-engine->getIP( "GRAPHTIME" ) ) ); const QString str="HIDEJOURNALS"; changeP( str, engine->getBP( str ) ); connect( start, SIGNAL( dateChanged( QDate ) ), SLOT( newValues() ) ); connect( end, SIGNAL( dateChanged( QDate ) ), SLOT( newValues() ) ); connect( pick, SIGNAL( selectionChanged() ), SLOT( newValues() ) ); connect( journaler, SIGNAL( activated( int ) ), SLOT( newValues() ) ); connect( typer, SIGNAL( activated( int ) ), SLOT( newType( int ) ) ); } } void QHaccDocControl::setPickMode( QListBox::SelectionMode m ){ pick->setSelectionMode( m ); } void QHaccDocControl::getPrefs(){ // pop the prefs dialog, opened to graphing tab ( new PrefsDlg( engine, 1, this ) )->show(); } void QHaccDocControl::newType( int t ) { emit typeChanged( t ); } void QHaccDocControl::setEnv( QDate starter, QDate ender, bool esel, bool emulti ){ pick->setEnabled( esel ); pick->setSelectionMode( emulti ? QListBox::Extended : QListBox::Single ); start->setDate( starter ); end->setDate( ender ); } void QHaccDocControl::newValues(){ QStringList alist; for( uint i=0; icount(); i++ ){ if( pick->isSelected( i ) ) alist.append( pick->text( i ) ); } uint jid=0; if( journaler->isVisible() ) jid=journaler->currentItem(); else{ auto_ptr ls=engine->getLs(); jid=ls->at( engine->getIP( "JOURNALINDEX" ) )[QC::LID].getu(); } emit dataChanged( jid, alist, start->getDate(), end->getDate() ); } void QHaccDocControl::changeP( const QString& str, bool b ){ if( str=="GRAPHDELTAS" ) newValues(); else if( str=="HIDEJOURNALS" ){ if( b ){ journaler->hide(); llbl->hide(); } else{ journaler->show(); llbl->show(); } newValues(); } } void QHaccDocControl::changeP( const QString& str, QString ){ if( str=="DATEFORMAT" || str=="DATESEPARATOR" ) { start->refresh(); end->refresh(); } } void QHaccDocControl::changeP( const QString& str, float ){ if( str=="ALTCURRENCYFACTOR" ) newValues(); } void QHaccDocControl::setPicks( QStringList s, int i ){ pick->clear(); pick->insertStringList( s ); pick->setSelected( i, true ); pick->setCurrentItem( i ); } void QHaccDocControl::setTypes( QStringList s, int i ){ typer->clear(); typer->insertStringList( s ); typer->setCurrentItem( i ); } void QHaccDocControl::print(){ emit printCalled(); } /* * * * * * * * * * * * * * * * * * * */ /* * Base for Reporters and Graphers * */ /* * * * * * * * * * * * * * * * * * * */ QHaccDocDisplay::QHaccDocDisplay( QHacc * e, QWidget * w, const char * n ) : QFrame( w, n ) { engine=e; accounts=new QHaccTable( QC::ACOLS, QC::ACOLTYPES ); accounts->setPK( QC::AID ); journalid=0; } QHaccDocDisplay::~QHaccDocDisplay() {} void QHaccDocDisplay::setData( uint lid, const QHaccTable& accts, const QDate& s, const QDate& e ){ accounts->clear(); accounts->load( &accts ); journalid=lid; start=s; end=e; refresh(); } void QHaccDocDisplay::readPrefs( bool initial ){ if( initial ){ connect( engine, SIGNAL( changedP( const QString&, bool ) ), this, SLOT( refresh() ) ); connect( engine, SIGNAL( updatedA( const Account&, const Account& ) ), this, SLOT( updA( const Account&, const Account& ) ) ); } } void QHaccDocDisplay::isetType(){} void QHaccDocDisplay::setType( int t ){ type=t; isetType(); refresh(); } void QHaccDocDisplay::irefresh(){} void QHaccDocDisplay::refresh(){ irefresh(); } void QHaccDocDisplay::refreshA( const Account& a ){ uint idx=0; if( accounts->contains( QC::AID, a[QC::AID], idx ) ) refresh(); } void QHaccDocDisplay::updA( const Account&, const Account& newy ){ refreshA( newy ); } void QHaccDocDisplay::print( QPrinter * p ) const { iprint( p ); } void QHaccDocDisplay::iprint( QPrinter * ) const {} /* * * * * * * * * * * */ /* Base for Reporters */ /* * * * * * * * * * * */ QHaccReporter::QHaccReporter( QHacc * e, QWidget * w, const char * n ) : QHaccDocDisplay( e, w, n ){ viewer=new QTextEdit( this ); viewer->setFont( QFont( "Courier" ) ); viewer->setReadOnly( true ); QBoxLayout * layout=new QBoxLayout( this, QBoxLayout::TopToBottom ); layout->add( viewer ); viewer->setTextFormat( PlainText ); plugin=0; } QHaccReporter::~QHaccReporter(){ disconnect(); delete accounts; engine->destroyPlugin( QHacc::PIREPORTER, plugin ); } void QHaccReporter::irefresh(){ if( plugin ){ QString title; auto_ptr data=plugin->generate( journalid, accounts, start, end, title ); viewer->setText( plugin->writereport( title, data.get() ) ); } else viewer->setText( tr( "Default report plugin not found." ) ); } void QHaccReporter::iprint( QPrinter * printer ) const { QPainter p; if( !p.begin( printer ) ) return; QPaintDeviceMetrics metrics( printer ); QFontMetrics fm=p.fontMetrics(); p.setFont( viewer->font() ); int page=1, yPos=0; const int MARG=60, FMLS=fm.lineSpacing(), LIMIT=metrics.height()-MARG-FMLS; const int MW=metrics.width(), MH=metrics.height(); QString today=QHaccDateEdit::getDateString( QDate::currentDate() ); const int LINES=viewer->lines(); const bool FORJ=( plugin->info().descr()=="JOURNAL" ); for( int i=0; itext( i+more )==" " ) keepGoing=false; else more++; } } else more=1; //cout<<"new paragraph is "<text( i+j )<LIMIT ) { yPos=metrics.height(); p.drawText( MARG, MH-MARG, MW, FMLS, ExpandTabs | DontClip, tr( "page" )+" "+QString::number( page++ )+" - "+today ); printer->newPage(); // no more room on this page yPos=0; // back to top of page } for( int j=0; jtext( i ) ); yPos+=FMLS; if( FORJ ) i++; } if( FORJ ){ // journals should print a blank line after every splitgroup p.drawText( MARG, MARG+yPos, MW, FMLS, ExpandTabs | DontClip, "" ); yPos+=FMLS; } } if( MARG+yPos info( engine->getPluginInfo( QHacc::PIREPORTER ) ); engine->destroyPlugin( QHacc::PIREPORTER, plugin ); plugin=0; QHaccPlugin * pi=0; int isz=( int )info.size(); if( 0<=type && typegetPluginFor( QHacc::PIREPORTER, info[type].stub()+":", pi ); if( pi ){ plugin=( QHaccReportPlugin * )pi; plugin->setup( engine ); bool esel, emulti; plugin->selected( start, end, esel, emulti ); emit selected( start, end, esel, emulti ); } } } /* * * * * * * * * * */ /* Base for Graphers */ /* * * * * * * * * * */ QHaccGrapher::QHaccGrapher( QHacc * e, QWidget * w, const char * n ) : QHaccDocDisplay( e, w, n ){ plugin=0; } QHaccGrapher::~QHaccGrapher(){ disconnect(); engine->destroyPlugin( QHacc::PIGRAPHER, plugin ); } void QHaccGrapher::irefresh(){ if( plugin ){ plugin->setData( journalid, *accounts, start, end ); repaint( false ); } } void QHaccGrapher::drawContents( QPainter * p ){ if( plugin ) plugin->paint( p, rect() ); else p->drawText( rect(), Qt::AlignCenter, tr( "Default graph plugin not found." ) ); } void QHaccGrapher::isetType(){ vector info( engine->getPluginInfo( QHacc::PIGRAPHER ) ); engine->destroyPlugin( QHacc::PIGRAPHER, plugin ); plugin=0; QHaccPlugin * pi=0; int isz=( int )info.size(); if( 0<=type && typegetPluginFor( QHacc::PIGRAPHER, info[type].stub()+":", pi ); if( pi ){ plugin=( QHaccGraphPlugin * )pi; plugin->setup( engine ); } } } void QHaccGrapher::mouseReleaseEvent( QMouseEvent * qme ){ if( !plugin ) return; Account acct; vector crit=plugin->describeMouse( qme->pos() ); // see if one of our criteria is for account. If not, we won't // open a subset window for( uint i=0; igetA( crit[i].model().getu() ); } } if( !acct.isNull() ){ QHaccSubsetWin * win=new QHaccSubsetWin( engine ); win->show(); win->setAL( acct, engine->getL( journalid ) ); win->setSelectors( crit ); } } void QHaccGrapher::iprint( QPrinter * printer ) const { if( !plugin ) return; QPainter p; if( !p.begin( printer ) ) return; const int MARG=60, MARG2=120; QPaintDeviceMetrics metrics( printer ); //const QSize sizer( metrics.height(), metrics.width() ); plugin->paint( &p, QRect( MARG, MARG, metrics.width()-MARG2, metrics.height()-MARG2 ) ); // label the graph QFontMetrics fm=p.fontMetrics(); QString text; if( accounts->rows()==1 ) text=accounts->at( 0 ).gets( QC::ANAME )+" "; text.append( QHaccDateEdit::getDateString( start )+" - "+ QHaccDateEdit::getDateString( end ) ); p.drawText( MARG2, MARG+fm.height(), text ); p.end(); } /*********************/ /** QHACCGRDIALOG **/ /*********************/ QHaccGRDialog::QHaccGRDialog( QHacc * e, DisplayType type, const Account& a, const Journal& l, QWidget * w, const char * n ) : QDialog( w, n, false, WDestructiveClose ){ engine=e; printer=0; QPushButton * dismiss=new QPushButton( tr( "Dismiss" ), this ); control=new QHaccDocControl( engine, l[QC::LID].getu(), this ); QString pref; QStringList types; int pitype; if( type==REPORT ){ display=new QHaccReporter( engine, this ); setCaption( tr( "QHacc Report" ) ); pref="REPORTTYPE"; pitype=QHacc::PIREPORTER; } else{ display=new QHaccGrapher( engine, this ); setCaption( tr( "QHacc Graph" ) ); pref="GRAPHTYPE"; pitype=QHacc::PIGRAPHER; } vector info( engine->getPluginInfo( pitype ) ); for( vector::iterator it=info.begin(); it!=info.end(); it++ ) types+=it->descr(); QStringList str; // this is our list of things we can display uint naccts=0, idx=0; const int ID=0, PID=1, NAME=2; vector cols; cols.push_back( QC::AID ); cols.push_back( QC::APID ); cols.push_back( QC::ANAME ); auto_ptr temp=engine->getAs( TableGet( cols ) ); QHaccTable table( *temp ); // first, cycle through and make sure we're // going to use the full name of the account. // we need to update the table, so the index // we're about to make will sort correctly naccts=table.rows(); for( uint i=0; igetFNameOfA( acct[PID].getu() ); if( !fname.isEmpty() ) fname+=QC::ASEP; fname+=acct[NAME].gets(); table.updateWhere( TableSelect( ID, acct[ID] ), TableUpdate( NAME, fname ) ); } // now, cycle through again add all the accounts to the stringlist // for display. Also, figure out the index of the account we want // to display first, so it can be highlighted in the picklist QHaccTableIndex nidx( &table, NAME, CTSTRING ); for( uint i=0; igetIP( pref ); control->setTypes( types, PICK ); control->setPicks( str, idx ); QGridLayout * layout=new QGridLayout( this, 10, 10, 2, 2 ); layout->addMultiCellWidget( control, 0, 9, 0, 1 ); layout->addMultiCellWidget( display, 0, 8, 2, 9 ); layout->addMultiCellWidget( dismiss, 9, 9, 2, 9 ); connect( dismiss, SIGNAL( clicked() ), SLOT( close() ) ); connect( control, SIGNAL( dataChanged( uint, QStringList, QDate, QDate ) ), SLOT( changeData( uint, QStringList, QDate, QDate ) ) ); connect( control, SIGNAL( typeChanged( int ) ), SLOT( changeType( int ) ) ); connect( control, SIGNAL( printCalled() ), SLOT( print() ) ); connect( display, SIGNAL( selected( QDate, QDate, bool, bool ) ), control, SLOT( setEnv( QDate, QDate, bool, bool ) ) ); resize( 550, 450 ); display->setType( PICK ); control->newValues(); // force a refresh } QHaccGRDialog::~QHaccGRDialog(){ delete printer; } void QHaccGRDialog::print(){ if( !printer ){ printer=new QPrinter(); printer->setPageSize( QPrinter::Letter ); } if( printer->setup( this ) ) display->print( printer ); } void QHaccGRDialog::changeType( int t ){ display->setType( t ); } void QHaccGRDialog::changeData( uint lid, QStringList picks, QDate start, QDate end ){ QHaccTable data( QC::ACOLS ); for ( QStringList::Iterator it=picks.begin(); it!=picks.end(); ++it ) data.add( engine->getA( *it ) ); display->setData( lid, data, start, end ); } void QHaccGRDialog::save(){ engine->setSP( "GRDWINSIZE", QString::number( width() )+ " "+QString::number( height() ) ); } void QHaccGRDialog::readPrefs( bool initial ){ QString str=engine->getSP( "GRDWINSIZE" ); if( !str.isEmpty() ){ QString vals[2]; Utils::parser( str, " ", 0, vals, 2 ); resize( vals[0].toInt(), vals[1].toInt() ); } control->readPrefs( initial ); display->readPrefs( initial ); } void QHaccGRDialog::done( int r ){ save(); QDialog::done( r ); }