You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmymoney/kmymoney2/widgets/transactionform.cpp

468 lines
13 KiB

/***************************************************************************
transactionform.cpp
-------------------
begin : Sun May 14 2006
copyright : (C) 2006 by Thomas Baumgart
email : Thomas Baumgart <ipwizard@users.sourceforge.net>
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
// ----------------------------------------------------------------------------
// QT Includes
#include <qstring.h>
#include <qpainter.h>
#include <qtimer.h>
#include <qapplication.h>
#include <qlayout.h>
#include <qtabbar.h>
#include <qpalette.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <klocale.h>
#include <kglobal.h>
#include <kdebug.h>
#include <kcombobox.h>
// ----------------------------------------------------------------------------
// Project Includes
#include <kmymoney/kmymoneydateinput.h>
#include <kmymoney/kmymoneyedit.h>
#include <kmymoney/kmymoneycategory.h>
#include "transactionform.h"
#include "../kmymoneyutils.h"
#include "../kmymoneyglobalsettings.h"
using namespace KMyMoneyTransactionForm;
TabBar::TabBar(QWidget* parent, const char* name) :
QTabBar(parent, name),
m_signalType(SignalNormal)
{
connect(this, SIGNAL(selected(int)), this, SLOT(slotTabSelected(int)));
}
TabBar::SignalEmissionE TabBar::setSignalEmission(TabBar::SignalEmissionE type)
{
TabBar::SignalEmissionE _type = m_signalType;
m_signalType = type;
return _type;
}
int TabBar::currentTab(void) const
{
QMap<int, int>::const_iterator it;
it = m_idMap.find(QTabBar::currentTab());
if(it != m_idMap.end())
return *it;
return -1;
}
void TabBar::setCurrentTab(int id)
{
if (tab(id)) // there are no tabs in an expense/income ledger
if (tab(id)->isEnabled())
setCurrentTab(tab(id));
}
QTab* TabBar::tab(int id) const
{
/* if a QAccel calls setCurrentTab, id will be as set by qt.
* however if we call it programmatically, id will
* be our own id. We do tell QTab about our id but
* in qt3.3 I (woro) am not able to make sure that
* QAccel also gets it. See registeritem.h: We defined
* new values for our own ids which should lie way
* outside of the range that qt uses
*/
QTab *result=QTabBar::tab(id);
QMap<int, int>::const_iterator it;
for(it = m_idMap.begin(); it != m_idMap.end(); ++it)
if(*it == id)
result=QTabBar::tab(it.key());
return result;
}
void TabBar::setCurrentTab(QTab* tab)
{
if(m_signalType != SignalNormal)
blockSignals(true);
QTabBar::setCurrentTab(tab);
if(m_signalType != SignalNormal)
blockSignals(false);
if(m_signalType == SignalAlways)
emit selected(tab->identifier());
}
void TabBar::addTab(QTab* tab, int id)
{
QTabBar::addTab(tab);
setIdentifier(tab, id);
}
void TabBar::setIdentifier(QTab* tab, int newId)
{
m_idMap[tab->identifier()] = newId;
}
void TransactionForm::enableTabBar(bool b)
{
m_tabBar->setEnabled(b);
}
void TabBar::slotTabSelected(int id)
{
QMap<int, int>::const_iterator it;
it = m_idMap.find(id);
if(it != m_idMap.end())
emit tabSelected(*it);
else
emit tabSelected(id);
}
void TabBar::show(void)
{
// make sure we don't emit a signal when simply showing the widget
if(m_signalType != SignalNormal)
blockSignals(true);
QTabBar::show();
if(m_signalType != SignalNormal)
blockSignals(false);
}
void TabBar::copyTabs(const TabBar* otabbar)
{
// remove all existing tabs
while(count()) {
removeTab(tabAt(0));
}
// now create new ones. copy text, icon and identifier
for(int i=0; i < otabbar->count(); ++i) {
QTab* otab = otabbar->tabAt(i);
QTab* ntab = new QTab(otab->text());
int nid = QTabBar::addTab(ntab);
m_idMap[nid] = otabbar->m_idMap[otab->identifier()];
ntab->setEnabled(otab->isEnabled());
if(otab->identifier() == otabbar->currentTab())
setCurrentTab(ntab);
}
}
TransactionForm::TransactionForm(QWidget *parent, const char *name) :
TransactionEditorContainer(parent, name),
m_transaction(0),
m_tabBar(0)
{
setBackgroundOrigin(QTable::WindowOrigin);
setFrameShape( QTable::NoFrame);
setShowGrid( false );
setSelectionMode( QTable::NoSelection );
verticalHeader()->hide();
horizontalHeader()->hide();
setLeftMargin(0);
setTopMargin(0);
setReadOnly(true); // display only
// make sure, that the table is 'invisible' by setting up the right background
// keep the original color group for painting the cells though
QPalette p = palette();
QColorGroup cg = p.active();
m_cellColorGroup = cg;
cg.setBrush(QColorGroup::Base, cg.brush(QColorGroup::Background));
p.setActive(cg);
p.setInactive(cg);
p.setDisabled(cg);
setPalette(p);
// never show vertical scroll bars
setVScrollBarMode(QScrollView::AlwaysOff);
slotSetTransaction(0);
}
void TransactionForm::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
{
// the QTable::drawContents() method does not honor the block update flag
// so we take care of it here
if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
return;
QTable::drawContents(p, cx, cy, cw, ch);
}
bool TransactionForm::focusNextPrevChild(bool next)
{
return QFrame::focusNextPrevChild(next);
}
void TransactionForm::clear(void)
{
slotSetTransaction(0);
}
void TransactionForm::slotSetTransaction(KMyMoneyRegister::Transaction* transaction)
{
m_transaction = transaction;
bool enabled = isUpdatesEnabled();
setUpdatesEnabled(false);
if(m_transaction) {
// the next call sets up a back pointer to the form and also sets up the col and row span
// as well as the tab of the form
m_transaction->setupForm(this);
} else {
setNumRows(5);
setNumCols(1);
}
kMyMoneyDateInput dateInput(0, "editDate");
KMyMoneyCategory category(0, "category", true);
// extract the maximal sizeHint height
int height = QMAX(dateInput.sizeHint().height(), category.sizeHint().height());
for(int row = 0; row < numRows(); ++row) {
if(!transaction || transaction->showRowInForm(row)) {
showRow(row);
QTable::setRowHeight(row, height);
} else
hideRow(row);
}
// adjust vertical size of form table
height *= numRows();
setMaximumHeight(height);
setMinimumHeight(height);
setUpdatesEnabled(enabled);
// force resizeing of the columns
QTimer::singleShot(0, this, SLOT(resize()));
}
void TransactionForm::paintCell(QPainter* painter, int row, int col, const QRect& r, bool selected, const QColorGroup& /* cg */)
{
if(m_transaction) {
m_transaction->paintFormCell(painter, row, col, r, selected, m_cellColorGroup);
}
}
TabBar* TransactionForm::tabBar(QWidget* parent)
{
if(!m_tabBar && parent) {
// determine the height of the objects in the table
// create the tab bar
m_tabBar = new TabBar( parent );
m_tabBar->setSignalEmission(TabBar::SignalAlways);
m_tabBar->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)0, 0, 0, m_tabBar->sizePolicy().hasHeightForWidth() ) );
connect(m_tabBar, SIGNAL(tabSelected(int)), this, SLOT(slotActionSelected(int)));
}
return m_tabBar;
}
void TransactionForm::slotActionSelected(int id)
{
emit newTransaction(static_cast<KMyMoneyRegister::Action>(id));
}
void TransactionForm::setupForm(const MyMoneyAccount& acc)
{
// remove all tabs from the tabbar
QTab* tab;
for(tab = m_tabBar->tabAt(0); tab; tab = m_tabBar->tabAt(0)) {
m_tabBar->removeTab(tab);
}
m_tabBar->show();
// important: one needs to add the new tabs first and then
// change the identifier. Otherwise, addTab() will assign
// a different value
switch(acc.accountType()) {
default:
tab = new QTab(i18n("&Deposit"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
tab = new QTab(i18n("&Transfer"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
tab = new QTab(i18n("&Withdrawal"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
break;
case MyMoneyAccount::CreditCard:
tab = new QTab(i18n("&Payment"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
tab = new QTab(i18n("&Transfer"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
tab = new QTab(i18n("&Charge"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
break;
case MyMoneyAccount::Liability:
case MyMoneyAccount::Loan:
tab = new QTab(i18n("&Decrease"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
tab = new QTab(i18n("&Transfer"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
tab = new QTab(i18n("&Increase"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
break;
case MyMoneyAccount::Asset:
case MyMoneyAccount::AssetLoan:
tab = new QTab(i18n("&Increase"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionDeposit);
tab = new QTab(i18n("&Transfer"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionTransfer);
tab = new QTab(i18n("&Decrease"));
m_tabBar->addTab(tab, KMyMoneyRegister::ActionWithdrawal);
break;
case MyMoneyAccount::Income:
case MyMoneyAccount::Expense:
case MyMoneyAccount::Investment:
case MyMoneyAccount::Stock:
m_tabBar->hide();
break;
}
}
void TransactionForm::resize(void)
{
resize(ValueColumn1);
}
void TransactionForm::resize(int col)
{
bool enabled = isUpdatesEnabled();
setUpdatesEnabled(false);
// resize the register
int w = visibleWidth();
int nc = numCols();
// check which space we need
if(nc >= LabelColumn1 && columnWidth(LabelColumn1))
adjustColumn(LabelColumn1);
if(nc >= LabelColumn2 && columnWidth(LabelColumn2))
adjustColumn(LabelColumn2);
if(nc >= ValueColumn2 && columnWidth(ValueColumn2))
adjustColumn(ValueColumn2);
for(int i = 0; i < nc; ++i) {
if(i == col)
continue;
w -= columnWidth(i);
}
if(col < nc && w >= 0)
setColumnWidth(col, w);
setUpdatesEnabled(enabled);
updateContents();
}
// needed to duplicate this here, as the QTable::tableSize method is private :-(
QSize TransactionForm::tableSize(void) const
{
return QSize(columnPos(numCols()-1) + columnWidth(numCols()-1) + 10,
rowPos(numRows()-1) + rowHeight(numRows()-1) + 10);
}
QSize TransactionForm::sizeHint(void) const
{
// I've taken this from qtable.cpp, QTable::sizeHint()
int vmargin = QApplication::reverseLayout() ? rightMargin() : leftMargin();
return QSize(tableSize().width() + vmargin + 5, tableSize().height() + topMargin() + 10);
}
void TransactionForm::adjustColumn(Column col)
{
int w = 0;
// preset the width of the right value column with the width of
// the possible edit widgets so that they fit if they pop up
if(col == ValueColumn2) {
kMyMoneyDateInput dateInput;
kMyMoneyEdit valInput;
w = QMAX(dateInput.sizeHint().width(), valInput.sizeHint().width());
}
if(m_transaction) {
QString txt;
QFontMetrics fontMetrics(KMyMoneyGlobalSettings::listCellFont());
// scan through the rows
for ( int i = numRows()-1; i >= 0; --i ) {
int align;
m_transaction->formCellText(txt, align, i, static_cast<int>(col), 0);
QWidget* cw = cellWidget(i, col);
if(cw) {
w = QMAX(w, cw->sizeHint().width()+10);
}
w = QMAX(w, fontMetrics.width(txt)+10);
}
}
if(col < numCols())
setColumnWidth( col, w );
}
void TransactionForm::arrangeEditWidgets(QMap<QString, QWidget*>& editWidgets, KMyMoneyRegister::Transaction* t)
{
t->arrangeWidgetsInForm(editWidgets);
resize(ValueColumn1);
}
void TransactionForm::tabOrder(QWidgetList& tabOrderWidgets, KMyMoneyRegister::Transaction* t) const
{
t->tabOrderInForm(tabOrderWidgets);
}
void TransactionForm::removeEditWidgets(QMap<QString, QWidget*>& editWidgets)
{
QMap<QString, QWidget*>::iterator it;
for(it = editWidgets.begin(); it != editWidgets.end(); ) {
if((*it)->parentWidget() == this) {
editWidgets.remove(it);
it = editWidgets.begin();
} else
++it;
}
for(int row = 0; row < numRows(); ++row) {
for(int col = 0; col < numCols(); ++col) {
if(cellWidget(row, col))
clearCellWidget(row, col);
}
}
resize(ValueColumn1);
// delete all remaining edit widgets (e.g. tabbar)
for(it = editWidgets.begin(); it != editWidgets.end(); ) {
delete (*it); // ->deleteLater();
editWidgets.remove(it);
it = editWidgets.begin();
}
}
#include "transactionform.moc"