/***************************************************************************
kmymoneysplittable . cpp - description
- - - - - - - - - - - - - - - - - - -
begin : Thu Jan 10 2002
copyright : ( C ) 2000 - 2002 by Michael Edwardes
email : mte @ users . sourceforge . net
Javier Campos Morales < javi_c @ users . sourceforge . net >
Felix Rodriguez < frodriguez @ users . sourceforge . net >
John C < thetacoturtle @ users . sourceforge . net >
Thomas Baumgart < ipwizard @ users . sourceforge . net >
Kevin Tambascio < ktambascio @ 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 . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <kdecompat.h>
// ----------------------------------------------------------------------------
// QT Includes
# include <tqglobal.h>
# include <tqpainter.h>
# include <tqcursor.h>
# include <tqapplication.h>
# include <tqtimer.h>
# include <tqlayout.h>
# include <tqeventloop.h>
// ----------------------------------------------------------------------------
// KDE Includes
# include <kglobal.h>
# include <klocale.h>
# include <kiconloader.h>
# include <kmessagebox.h>
# include <kcompletionbox.h>
# include <kpushbutton.h>
# include <kpopupmenu.h>
# include <kstdaccel.h>
# include <kshortcut.h>
// ----------------------------------------------------------------------------
// Project Includes
# include "kmymoneysplittable.h"
# include <kmymoney/mymoneyfile.h>
# include <kmymoney/kmymoneyedit.h>
# include <kmymoney/kmymoneycategory.h>
# include <kmymoney/kmymoneyaccountselector.h>
# include <kmymoney/kmymoneylineedit.h>
# include <kmymoney/mymoneysecurity.h>
# include <kmymoney/kmymoneyglobalsettings.h>
# include "../dialogs/kcurrencycalculator.h"
# include "../mymoney/mymoneyutils.h"
kMyMoneySplitTable : : kMyMoneySplitTable ( TQWidget * parent , const char * name ) :
TQTable ( parent , name ) ,
m_currentRow ( 0 ) ,
m_maxRows ( 0 ) ,
m_editMode ( false ) ,
m_amountWidth ( 80 ) ,
m_editCategory ( 0 ) ,
m_editMemo ( 0 ) ,
m_editAmount ( 0 )
{
// setup the transactions table
setNumRows ( 1 ) ;
setNumCols ( 3 ) ;
horizontalHeader ( ) - > setLabel ( 0 , i18n ( " Category " ) ) ;
horizontalHeader ( ) - > setLabel ( 1 , i18n ( " Memo " ) ) ;
horizontalHeader ( ) - > setLabel ( 2 , i18n ( " Amount " ) ) ;
setSelectionMode ( TQTable : : NoSelection ) ;
setLeftMargin ( 0 ) ;
verticalHeader ( ) - > hide ( ) ;
setColumnStretchable ( 0 , false ) ;
setColumnStretchable ( 1 , false ) ;
setColumnStretchable ( 2 , false ) ;
horizontalHeader ( ) - > setResizeEnabled ( false ) ;
horizontalHeader ( ) - > setMovingEnabled ( false ) ;
horizontalHeader ( ) - > setFont ( KMyMoneyGlobalSettings : : listHeaderFont ( ) ) ;
setVScrollBarMode ( TQScrollView : : AlwaysOn ) ;
// never show a horizontal scroll bar
setHScrollBarMode ( TQScrollView : : AlwaysOff ) ;
// setup the context menu
m_contextMenu = new KPopupMenu ( this ) ;
KIconLoader * il = KGlobal : : iconLoader ( ) ;
m_contextMenu - > insertTitle ( il - > loadIcon ( " transaction " , KIcon : : MainToolbar ) , i18n ( " Split Options " ) ) ;
m_contextMenu - > insertItem ( il - > loadIcon ( " edit " , KIcon : : Small ) , i18n ( " Edit... " ) , this , TQT_SLOT ( slotStartEdit ( ) ) ) ;
m_contextMenuDuplicate = m_contextMenu - > insertItem ( il - > loadIcon ( " editcopy " , KIcon : : Small ) , i18n ( " Duplicate " ) , this , TQT_SLOT ( slotDuplicateSplit ( ) ) ) ;
m_contextMenuDelete = m_contextMenu - > insertItem ( il - > loadIcon ( " delete " , KIcon : : Small ) ,
i18n ( " Delete ... " ) ,
this , TQT_SLOT ( slotDeleteSplit ( ) ) ) ;
connect ( this , TQT_SIGNAL ( clicked ( int , int , int , const TQPoint & ) ) ,
this , TQT_SLOT ( slotSetFocus ( int , int , int , const TQPoint & ) ) ) ;
connect ( this , TQT_SIGNAL ( transactionChanged ( const MyMoneyTransaction & ) ) ,
this , TQT_SLOT ( slotUpdateData ( const MyMoneyTransaction & ) ) ) ;
}
kMyMoneySplitTable : : ~ kMyMoneySplitTable ( )
{
}
void kMyMoneySplitTable : : setup ( const TQMap < TQString , MyMoneyMoney > & priceInfo )
{
m_priceInfo = priceInfo ;
}
const TQColor kMyMoneySplitTable : : rowBackgroundColor ( const int row ) const
{
return ( row % 2 ) ? KMyMoneyGlobalSettings : : listColor ( ) : KMyMoneyGlobalSettings : : listBGColor ( ) ;
}
void kMyMoneySplitTable : : paintCell ( TQPainter * p , int row , int col , const TQRect & r , bool /*selected*/ )
{
TQColorGroup g = colorGroup ( ) ;
TQColor textColor ;
g . setColor ( TQColorGroup : : Base , rowBackgroundColor ( row ) ) ;
p - > setFont ( KMyMoneyGlobalSettings : : listCellFont ( ) ) ;
TQString firsttext = text ( row , col ) ;
TQString qstringCategory ;
TQString qstringMemo ;
int intPos = firsttext . find ( " | " ) ;
if ( intPos > - 1 )
{
qstringCategory = firsttext . left ( intPos ) ;
qstringMemo = firsttext . mid ( intPos + 1 ) ;
}
TQRect rr = r ;
TQRect rr2 = r ;
rr . setX ( 0 ) ;
rr . setY ( 0 ) ;
rr . setWidth ( columnWidth ( col ) ) ;
rr . setHeight ( rowHeight ( row ) ) ;
rr2 . setX ( 2 ) ;
rr2 . setY ( 0 ) ;
rr2 . setWidth ( columnWidth ( col ) - 4 ) ;
rr2 . setHeight ( rowHeight ( row ) ) ;
if ( row = = m_currentRow ) {
TQBrush backgroundBrush ( g . highlight ( ) ) ;
textColor = g . highlightedText ( ) ;
p - > fillRect ( rr , backgroundBrush ) ;
} else {
TQBrush backgroundBrush ( g . base ( ) ) ;
textColor = g . text ( ) ;
p - > fillRect ( rr , backgroundBrush ) ;
}
if ( KMyMoneyGlobalSettings : : showGrid ( ) ) {
p - > setPen ( KMyMoneyGlobalSettings : : listGridColor ( ) ) ;
if ( col ! = 0 )
p - > drawLine ( rr . x ( ) , 0 , rr . x ( ) , rr . height ( ) - 1 ) ; // left frame
p - > drawLine ( rr . x ( ) , rr . y ( ) , rr . width ( ) , 0 ) ; // bottom frame
p - > setPen ( textColor ) ;
}
switch ( col ) {
case 0 : // category
case 1 : // memo
p - > drawText ( rr2 , TQt : : AlignLeft | TQt : : AlignVCenter , text ( row , col ) ) ;
break ;
case 2 : // amount
p - > drawText ( rr2 , TQt : : AlignRight | TQt : : AlignVCenter , firsttext ) ;
break ;
}
}
/** Override the TQTable member function to avoid display of focus */
void kMyMoneySplitTable : : paintFocus ( TQPainter * /* p */ , const TQRect & /*cr*/ )
{
}
void kMyMoneySplitTable : : columnWidthChanged ( int col )
{
for ( int i = 0 ; i < numRows ( ) ; i + + )
updateCell ( i , col ) ;
}
/** Override the TQTable member function to avoid confusion with our own functionality */
void kMyMoneySplitTable : : endEdit ( int /*row*/ , int /*col*/ , bool /*accept*/ , bool /*replace*/ )
{
}
bool kMyMoneySplitTable : : eventFilter ( TQObject * o , TQEvent * e )
{
// MYMONEYTRACER(tracer);
TQKeyEvent * k = TQT_TQKEYEVENT ( e ) ;
bool rc = false ;
int row = currentRow ( ) ;
int lines = visibleHeight ( ) / rowHeight ( 0 ) ;
TQWidget * w ;
if ( e - > type ( ) = = TQEvent : : KeyPress & & ! isEditMode ( ) ) {
rc = true ;
switch ( k - > key ( ) ) {
case TQt : : Key_Up :
if ( row )
slotSetFocus ( row - 1 ) ;
break ;
case TQt : : Key_Down :
if ( row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) )
slotSetFocus ( row + 1 ) ;
break ;
case TQt : : Key_Home :
slotSetFocus ( 0 ) ;
break ;
case TQt : : Key_End :
slotSetFocus ( m_transaction . splits ( ) . count ( ) - 1 ) ;
break ;
case TQt : : Key_PageUp :
if ( lines ) {
while ( lines - - > 0 & & row )
row - - ;
slotSetFocus ( row ) ;
}
break ;
case TQt : : Key_PageDown :
if ( row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) ) {
while ( lines - - > 0 & & row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) )
row + + ;
slotSetFocus ( row ) ;
}
break ;
case TQt : : Key_Delete :
slotDeleteSplit ( ) ;
break ;
case TQt : : Key_Return :
case TQt : : Key_Enter :
if ( row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 )
& & KMyMoneyGlobalSettings : : enterMovesBetweenFields ( ) ) {
slotStartEdit ( ) ;
} else
emit returnPressed ( ) ;
break ;
case TQt : : Key_Escape :
emit escapePressed ( ) ;
break ;
case TQt : : Key_F2 :
slotStartEdit ( ) ;
break ;
default :
rc = true ;
KShortcut copySplit ( i18n ( " Duplicate split " , " CTRL+c " ) ) ;
KShortcut newSplit ( TQKeySequence ( TQt : : CTRL | TQt : : Key_Insert ) ) ;
if ( copySplit . contains ( KKey ( k ) ) ) {
slotDuplicateSplit ( ) ;
} else if ( newSplit . contains ( KKey ( k ) ) ) {
slotSetFocus ( m_transaction . splits ( ) . count ( ) - 1 ) ;
slotStartEdit ( ) ;
} else if ( k - > text ( ) [ 0 ] . isPrint ( ) ) {
w = slotStartEdit ( ) ;
// make sure, the widget receives the key again
TQApplication : : sendEvent ( w , e ) ;
}
break ;
}
} else if ( e - > type ( ) = = TQEvent : : KeyPress & & isEditMode ( ) ) {
bool terminate = true ;
rc = true ;
switch ( k - > key ( ) ) {
// suppress the F2 functionality to start editing in inline edit mode
case TQt : : Key_F2 :
// suppress the cursor movement in inline edit mode
case TQt : : Key_Up :
case TQt : : Key_Down :
case TQt : : Key_PageUp :
case TQt : : Key_PageDown :
break ;
case TQt : : Key_Return :
case TQt : : Key_Enter :
// we cannot call the slot directly, as it destroys the caller of
// this method :-( So we let the event handler take care of calling
// the respective slot using a timeout. For a KLineEdit derived object
// it could be, that at this point the user selected a value from
// a completion list. In this case, we close the completion list and
// do not end editing of the transaction.
if ( o - > inherits ( " KLineEdit " ) ) {
KLineEdit * le = dynamic_cast < KLineEdit * > ( o ) ;
KCompletionBox * box = le - > completionBox ( false ) ;
if ( box & & box - > isVisible ( ) ) {
terminate = false ;
le - > completionBox ( false ) - > hide ( ) ;
}
}
// in case we have the 'enter moves focus between fields', we need to simulate
// a TAB key when the object 'o' points to the category or memo field.
if ( KMyMoneyGlobalSettings : : enterMovesBetweenFields ( ) ) {
if ( TQT_BASE_OBJECT ( o ) = = TQT_BASE_OBJECT ( m_editCategory - > lineEdit ( ) ) | | TQT_BASE_OBJECT ( o ) = = TQT_BASE_OBJECT ( m_editMemo ) ) {
terminate = false ;
TQKeyEvent evt ( e - > type ( ) ,
Key_Tab , 0 , k - > state ( ) , TQString ( ) ,
k - > isAutoRepeat ( ) , k - > count ( ) ) ;
TQApplication : : sendEvent ( o , & evt ) ;
}
}
if ( terminate ) {
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotEndEditKeyboard ( ) ) ) ;
}
break ;
case TQt : : Key_Escape :
// we cannot call the slot directly, as it destroys the caller of
// this method :-( So we let the event handler take care of calling
// the respective slot using a timeout.
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotCancelEdit ( ) ) ) ;
break ;
default :
rc = false ;
break ;
}
} else if ( e - > type ( ) = = TQEvent : : KeyRelease & & ! isEditMode ( ) ) {
// for some reason, we only see a KeyRelease event of the Menu key
// here. In other locations (e.g. Register::eventFilter()) we see
// a KeyPress event. Strange. (ipwizard - 2008-05-10)
switch ( k - > key ( ) ) {
case TQt : : Key_Menu :
// if the very last entry is selected, the delete
// operation is not available otherwise it is
m_contextMenu - > setItemEnabled ( m_contextMenuDelete ,
row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) ) ;
m_contextMenu - > setItemEnabled ( m_contextMenuDuplicate ,
row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) ) ;
m_contextMenu - > exec ( TQCursor : : pos ( ) ) ;
rc = true ;
break ;
default :
break ;
}
}
// if the event has not been processed here, forward it to
// the base class implementation if it's not a key event
if ( rc = = false ) {
if ( e - > type ( ) ! = TQEvent : : KeyPress
& & e - > type ( ) ! = TQEvent : : KeyRelease ) {
rc = TQTable : : eventFilter ( o , e ) ;
}
}
return rc ;
}
void kMyMoneySplitTable : : slotSetFocus ( int realrow , int /* col */ , int button , const TQPoint & /* point */ )
{
MYMONEYTRACER ( tracer ) ;
int row = realrow ;
// adjust row to used area
if ( row > static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) )
row = m_transaction . splits ( ) . count ( ) - 1 ;
if ( row < 0 )
row = 0 ;
// make sure the row will be on the screen
ensureCellVisible ( row , 0 ) ;
if ( button = = Qt : : LeftButton ) { // left mouse button
if ( isEditMode ( ) ) { // in edit mode?
if ( KMyMoneyGlobalSettings : : focusChangeIsEnter ( ) )
slotEndEdit ( ) ;
else
slotCancelEdit ( ) ;
}
if ( row ! = static_cast < int > ( currentRow ( ) ) ) {
// setup new current row and update visible selection
setCurrentCell ( row , 0 ) ;
slotUpdateData ( m_transaction ) ;
}
} else if ( button = = Qt : : RightButton ) {
// context menu is only available when cursor is on
// an existing transaction or the first line after this area
if ( row = = realrow ) {
// setup new current row and update visible selection
setCurrentCell ( row , 0 ) ;
slotUpdateData ( m_transaction ) ;
// if the very last entry is selected, the delete
// operation is not available otherwise it is
m_contextMenu - > setItemEnabled ( m_contextMenuDelete ,
row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) ) ;
m_contextMenu - > setItemEnabled ( m_contextMenuDuplicate ,
row < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 ) ) ;
m_contextMenu - > exec ( TQCursor : : pos ( ) ) ;
}
}
}
void kMyMoneySplitTable : : contentsMousePressEvent ( TQMouseEvent * e )
{
slotSetFocus ( rowAt ( e - > pos ( ) . y ( ) ) , columnAt ( e - > pos ( ) . x ( ) ) , e - > button ( ) , e - > pos ( ) ) ;
}
/* turn off TQTable behaviour */
void kMyMoneySplitTable : : contentsMouseReleaseEvent ( TQMouseEvent * /* e */ )
{
}
void kMyMoneySplitTable : : contentsMouseDoubleClickEvent ( TQMouseEvent * e )
{
MYMONEYTRACER ( tracer ) ;
int col = columnAt ( e - > pos ( ) . x ( ) ) ;
slotSetFocus ( rowAt ( e - > pos ( ) . y ( ) ) , col , e - > button ( ) , e - > pos ( ) ) ;
slotStartEdit ( ) ;
KLineEdit * editWidget = 0 ;
switch ( col ) {
case 1 :
editWidget = m_editMemo ;
break ;
case 2 :
editWidget = dynamic_cast < KLineEdit * > ( m_editAmount - > focusWidget ( ) ) ;
break ;
default :
break ;
}
if ( editWidget ) {
editWidget - > setFocus ( ) ;
editWidget - > selectAll ( ) ;
// we need to call setFocus on the edit widget from the
// main loop again to get the keyboard focus to the widget also
TQTimer : : singleShot ( 0 , editWidget , TQT_SLOT ( setFocus ( ) ) ) ;
}
}
void kMyMoneySplitTable : : setCurrentCell ( int row , int /* col */ )
{
MYMONEYTRACER ( tracer ) ;
if ( row > m_maxRows )
row = m_maxRows ;
m_currentRow = row ;
TQTable : : setCurrentCell ( row , 0 ) ;
TQValueList < MyMoneySplit > list = getSplits ( m_transaction ) ;
if ( row < static_cast < int > ( list . count ( ) ) )
m_split = list [ row ] ;
else
m_split = MyMoneySplit ( ) ;
}
void kMyMoneySplitTable : : setNumRows ( int irows )
{
TQTable : : setNumRows ( irows ) ;
// determine row height according to the edit widgets
// we use the category widget as the base
TQFontMetrics fm ( KMyMoneyGlobalSettings : : listCellFont ( ) ) ;
int height = fm . lineSpacing ( ) + 6 ;
#if 0
// recalculate row height hint
KMyMoneyCategory cat ;
height = TQMAX ( cat . sizeHint ( ) . height ( ) , height ) ;
# endif
verticalHeader ( ) - > setUpdatesEnabled ( false ) ;
for ( int i = 0 ; i < irows ; + + i )
verticalHeader ( ) - > resizeSection ( i , height ) ;
verticalHeader ( ) - > setUpdatesEnabled ( true ) ;
// add or remove scrollbars as required
updateScrollBars ( ) ;
}
void kMyMoneySplitTable : : setTransaction ( const MyMoneyTransaction & t , const MyMoneySplit & s , const MyMoneyAccount & acc )
{
MYMONEYTRACER ( tracer ) ;
m_transaction = t ;
m_account = acc ;
m_hiddenSplit = s ;
setCurrentCell ( 0 , 0 ) ;
slotUpdateData ( m_transaction ) ;
}
const TQValueList < MyMoneySplit > kMyMoneySplitTable : : getSplits ( const MyMoneyTransaction & t ) const
{
TQValueList < MyMoneySplit > list ;
TQValueList < MyMoneySplit > : : Iterator it ;
// get list of splits
list = t . splits ( ) ;
// and ignore the one that should be hidden
for ( it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
if ( ( * it ) . id ( ) = = m_hiddenSplit . id ( ) ) {
list . remove ( it ) ;
break ;
}
}
return list ;
}
void kMyMoneySplitTable : : slotUpdateData ( const MyMoneyTransaction & t )
{
MYMONEYTRACER ( tracer ) ;
unsigned long rowCount = 0 ;
TQValueList < MyMoneySplit > list = getSplits ( t ) ;
updateTransactionTableSize ( ) ;
// fill the part that is used by transactions
TQValueList < MyMoneySplit > : : Iterator it ;
kMyMoneyEdit * valfield = new kMyMoneyEdit ( ) ;
for ( it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
TQString colText ;
MyMoneyMoney value = ( * it ) . value ( ) ;
if ( ! ( * it ) . accountId ( ) . isEmpty ( ) ) {
try {
colText = MyMoneyFile : : instance ( ) - > accountToCategory ( ( * it ) . accountId ( ) ) ;
} catch ( MyMoneyException * e ) {
tqDebug ( " Unexpected exception in kMyMoneySplitTable::slotUpdateData() " ) ;
delete e ;
}
}
TQString amountTxt = value . formatMoney ( m_account . fraction ( ) ) ;
if ( value = = MyMoneyMoney : : autoCalc ) {
amountTxt = i18n ( " will be calculated " ) ;
}
if ( colText . isEmpty ( ) & & ( * it ) . memo ( ) . isEmpty ( ) & & value . isZero ( ) )
amountTxt = TQString ( ) ;
unsigned width = fontMetrics ( ) . width ( amountTxt ) ;
valfield - > setMinimumWidth ( width ) ;
width = valfield - > minimumSizeHint ( ) . width ( ) ;
if ( width > m_amountWidth )
m_amountWidth = width ;
setText ( rowCount , 0 , colText ) ;
setText ( rowCount , 1 , ( * it ) . memo ( ) ) ;
setText ( rowCount , 2 , amountTxt ) ;
rowCount + + ;
}
delete valfield ;
// now clean out the remainder of the table
while ( rowCount < static_cast < unsigned long > ( numRows ( ) ) ) {
setText ( rowCount , 0 , " " ) ;
setText ( rowCount , 1 , " " ) ;
setText ( rowCount , 2 , " " ) ;
+ + rowCount ;
}
}
void kMyMoneySplitTable : : updateTransactionTableSize ( void )
{
// get current size of transactions table
int rowHeight = cellGeometry ( 0 , 0 ) . height ( ) ;
// add half a row to the height to avoid unnecessary toggling when
// changing the number of rows
int tableHeight = ( height ( ) + rowHeight / 2 ) ;
int splitCount = m_transaction . splits ( ) . count ( ) - 1 ;
if ( splitCount < 0 )
splitCount = 0 ;
// see if we need some extra lines to fill the current size with the grid
int numExtraLines = ( tableHeight / rowHeight ) - splitCount ;
if ( numExtraLines < 2 )
numExtraLines = 2 ;
setNumRows ( splitCount + numExtraLines ) ;
// setMaxRows(splitCount);
m_maxRows = splitCount ;
}
void kMyMoneySplitTable : : resizeEvent ( TQResizeEvent * /* ev */ )
{
int w = visibleWidth ( ) - m_amountWidth ;
// resize the columns
setColumnWidth ( 0 , w / 2 ) ;
setColumnWidth ( 1 , w / 2 ) ;
setColumnWidth ( 2 , m_amountWidth ) ;
updateTransactionTableSize ( ) ;
}
void kMyMoneySplitTable : : slotDuplicateSplit ( void )
{
MYMONEYTRACER ( tracer ) ;
TQValueList < MyMoneySplit > list = getSplits ( m_transaction ) ;
if ( m_currentRow < static_cast < int > ( list . count ( ) ) ) {
MyMoneySplit split = list [ m_currentRow ] ;
split . clearId ( ) ;
try {
m_transaction . addSplit ( split ) ;
emit transactionChanged ( m_transaction ) ;
} catch ( MyMoneyException * e ) {
tqDebug ( " Cannot duplicate split: %s " , e - > what ( ) . latin1 ( ) ) ;
delete e ;
}
}
}
void kMyMoneySplitTable : : slotDeleteSplit ( void )
{
MYMONEYTRACER ( tracer ) ;
TQValueList < MyMoneySplit > list = getSplits ( m_transaction ) ;
if ( m_currentRow < static_cast < int > ( list . count ( ) ) ) {
if ( KMessageBox : : warningContinueCancel ( this ,
i18n ( " You are about to delete the selected split. "
" Do you really want to continue? " ) ,
i18n ( " KMyMoney " ) ,
i18n ( " Continue " )
) = = KMessageBox : : Continue ) {
try {
m_transaction . removeSplit ( list [ m_currentRow ] ) ;
// if we removed the last split, select the previous
if ( m_currentRow & & m_currentRow = = static_cast < int > ( list . count ( ) ) - 1 )
setCurrentCell ( m_currentRow - 1 , 0 ) ;
else
setCurrentCell ( m_currentRow , 0 ) ;
emit transactionChanged ( m_transaction ) ;
} catch ( MyMoneyException * e ) {
tqDebug ( " Cannot remove split: %s " , e - > what ( ) . latin1 ( ) ) ;
delete e ;
}
}
}
}
TQWidget * kMyMoneySplitTable : : slotStartEdit ( void )
{
MYMONEYTRACER ( tracer ) ;
return createEditWidgets ( ) ;
}
void kMyMoneySplitTable : : slotEndEdit ( void )
{
endEdit ( false ) ;
}
void kMyMoneySplitTable : : slotEndEditKeyboard ( void )
{
endEdit ( true ) ;
}
void kMyMoneySplitTable : : endEdit ( bool keyBoardDriven )
{
// Don't proceed, if we're not in edit mode
if ( ! m_editCategory )
return ;
MyMoneyFile * file = MyMoneyFile : : instance ( ) ;
MYMONEYTRACER ( tracer ) ;
MyMoneySplit s1 = m_split ;
if ( m_editCategory - > selectedItem ( ) . isEmpty ( ) ) {
KMessageBox : : information ( this , i18n ( " You need to assign a category to this split before it can be entered. " ) , i18n ( " Enter split " ) , " EnterSplitWithEmptyCategory " ) ;
m_editCategory - > setFocus ( ) ;
return ;
}
bool needUpdate = false ;
if ( m_editCategory - > selectedItem ( ) ! = m_split . accountId ( ) ) {
s1 . setAccountId ( m_editCategory - > selectedItem ( ) ) ;
needUpdate = true ;
}
if ( m_editMemo - > text ( ) ! = m_split . memo ( ) ) {
s1 . setMemo ( m_editMemo - > text ( ) ) ;
needUpdate = true ;
}
if ( m_editAmount - > value ( ) ! = m_split . value ( ) ) {
s1 . setValue ( m_editAmount - > value ( ) ) ;
needUpdate = true ;
}
if ( needUpdate ) {
if ( ! s1 . value ( ) . isZero ( ) ) {
MyMoneyAccount cat = file - > account ( s1 . accountId ( ) ) ;
if ( cat . currencyId ( ) ! = m_transaction . commodity ( ) ) {
MyMoneySecurity fromCurrency , toCurrency ;
MyMoneyMoney fromValue , toValue ;
fromCurrency = file - > security ( m_transaction . commodity ( ) ) ;
toCurrency = file - > security ( cat . currencyId ( ) ) ;
// determine the fraction required for this category
int fract = toCurrency . smallestAccountFraction ( ) ;
if ( cat . accountType ( ) = = MyMoneyAccount : : Cash )
fract = toCurrency . smallestCashFraction ( ) ;
// display only positive values to the user
fromValue = s1 . value ( ) . abs ( ) ;
// if we had a price info in the beginning, we use it here
if ( m_priceInfo . find ( cat . currencyId ( ) ) ! = m_priceInfo . end ( ) ) {
toValue = ( fromValue * m_priceInfo [ cat . currencyId ( ) ] ) . convert ( fract ) ;
}
// if the shares are still 0, we need to change that
if ( toValue . isZero ( ) ) {
MyMoneyPrice price = MyMoneyFile : : instance ( ) - > price ( fromCurrency . id ( ) , toCurrency . id ( ) ) ;
// if the price is valid calculate the shares. If it is invalid
// assume a conversion rate of 1.0
if ( price . isValid ( ) ) {
toValue = ( price . rate ( toCurrency . id ( ) ) * fromValue ) . convert ( fract ) ;
} else {
toValue = fromValue ;
}
}
// now present all that to the user
KCurrencyCalculator calc ( fromCurrency ,
toCurrency ,
fromValue ,
toValue ,
m_transaction . postDate ( ) ,
fract ,
this , " currencyCalculator " ) ;
if ( calc . exec ( ) = = TQDialog : : Rejected ) {
return ;
} else {
s1 . setShares ( ( s1 . value ( ) * calc . price ( ) ) . convert ( fract ) ) ;
}
} else {
s1 . setShares ( s1 . value ( ) ) ;
}
} else
s1 . setShares ( s1 . value ( ) ) ;
m_split = s1 ;
try {
if ( m_split . id ( ) . isEmpty ( ) ) {
m_transaction . addSplit ( m_split ) ;
} else {
m_transaction . modifySplit ( m_split ) ;
}
emit transactionChanged ( m_transaction ) ;
} catch ( MyMoneyException * e ) {
tqDebug ( " Cannot add/modify split: %s " , e - > what ( ) . latin1 ( ) ) ;
delete e ;
}
}
this - > setFocus ( ) ;
destroyEditWidgets ( ) ;
slotSetFocus ( currentRow ( ) + 1 ) ;
// if we still have more splits, we start editing right away
// in case we have selected 'enter moves betweeen fields'
if ( keyBoardDriven
& & currentRow ( ) < static_cast < int > ( m_transaction . splits ( ) . count ( ) - 1 )
& & KMyMoneyGlobalSettings : : enterMovesBetweenFields ( ) ) {
slotStartEdit ( ) ;
}
}
void kMyMoneySplitTable : : slotCancelEdit ( void )
{
MYMONEYTRACER ( tracer ) ;
if ( isEditMode ( ) ) {
destroyEditWidgets ( ) ;
this - > setFocus ( ) ;
}
}
bool kMyMoneySplitTable : : isEditMode ( void ) const
{
return m_editMode ;
}
void kMyMoneySplitTable : : destroyEditWidgets ( void )
{
MYMONEYTRACER ( tracer ) ;
disconnect ( MyMoneyFile : : instance ( ) , TQT_SIGNAL ( dataChanged ( ) ) , this , TQT_SLOT ( slotLoadEditWidgets ( ) ) ) ;
clearCellWidget ( m_currentRow , 0 ) ;
clearCellWidget ( m_currentRow , 1 ) ;
clearCellWidget ( m_currentRow , 2 ) ;
clearCellWidget ( m_currentRow + 1 , 0 ) ;
m_editMode = false ;
TQApplication : : eventLoop ( ) - > processEvents ( TQEventLoop : : ExcludeUserInput , 100 ) ;
}
TQWidget * kMyMoneySplitTable : : createEditWidgets ( void )
{
MYMONEYTRACER ( tracer ) ;
TQFont cellFont = KMyMoneyGlobalSettings : : listCellFont ( ) ;
m_tabOrderWidgets . clear ( ) ;
// create the widgets
m_editAmount = new kMyMoneyEdit ( 0 ) ;
m_editAmount - > setFont ( cellFont ) ;
m_editAmount - > setResetButtonVisible ( false ) ;
m_editCategory = new KMyMoneyCategory ( ) ;
m_editCategory - > setHint ( i18n ( " Category " ) ) ;
m_editCategory - > setFont ( cellFont ) ;
connect ( m_editCategory , TQT_SIGNAL ( createItem ( const TQString & , TQString & ) ) , this , TQT_SIGNAL ( createCategory ( const TQString & , TQString & ) ) ) ;
connect ( m_editCategory , TQT_SIGNAL ( objectCreation ( bool ) ) , this , TQT_SIGNAL ( objectCreation ( bool ) ) ) ;
m_editMemo = new kMyMoneyLineEdit ( 0 , 0 , false , AlignLeft | AlignVCenter ) ;
m_editMemo - > setHint ( i18n ( " Memo " ) ) ;
m_editMemo - > setFont ( cellFont ) ;
// create buttons for the mouse users
KIconLoader * il = KGlobal : : iconLoader ( ) ;
m_registerButtonFrame = new TQFrame ( this , " buttonFrame " ) ;
TQPalette palette = m_registerButtonFrame - > palette ( ) ;
palette . setColor ( TQColorGroup : : Background , rowBackgroundColor ( m_currentRow + 1 ) ) ;
m_registerButtonFrame - > setPalette ( palette ) ;
TQHBoxLayout * l = new TQHBoxLayout ( m_registerButtonFrame ) ;
m_registerEnterButton = new KPushButton ( il - > loadIcon ( " button_ok " , KIcon : : Small , KIcon : : SizeSmall ) , TQString ( ) , m_registerButtonFrame , " EnterButton " ) ;
m_registerCancelButton = new KPushButton ( il - > loadIcon ( " button_cancel " , KIcon : : Small , KIcon : : SizeSmall ) , TQString ( ) , m_registerButtonFrame , " CancelButton " ) ;
l - > addWidget ( m_registerEnterButton ) ;
l - > addWidget ( m_registerCancelButton ) ;
l - > addStretch ( 2 ) ;
connect ( m_registerEnterButton , TQT_SIGNAL ( clicked ( ) ) , this , TQT_SLOT ( slotEndEdit ( ) ) ) ;
connect ( m_registerCancelButton , TQT_SIGNAL ( clicked ( ) ) , this , TQT_SLOT ( slotCancelEdit ( ) ) ) ;
// setup tab order
addToTabOrder ( m_editCategory ) ;
addToTabOrder ( m_editMemo ) ;
addToTabOrder ( m_editAmount ) ;
addToTabOrder ( m_registerEnterButton ) ;
addToTabOrder ( m_registerCancelButton ) ;
if ( ! m_split . accountId ( ) . isEmpty ( ) ) {
m_editCategory - > setSelectedItem ( m_split . accountId ( ) ) ;
} else {
// check if the transaction is balanced or not. If not,
// assign the remainder to the amount.
MyMoneyMoney diff ;
TQValueList < MyMoneySplit > list = m_transaction . splits ( ) ;
TQValueList < MyMoneySplit > : : ConstIterator it_s ;
for ( it_s = list . begin ( ) ; it_s ! = list . end ( ) ; + + it_s ) {
if ( ! ( * it_s ) . accountId ( ) . isEmpty ( ) )
diff + = ( * it_s ) . value ( ) ;
}
m_split . setValue ( - diff ) ;
}
m_editMemo - > loadText ( m_split . memo ( ) ) ;
// don't allow automatically calculated values to be modified
if ( m_split . value ( ) = = MyMoneyMoney : : autoCalc ) {
m_editAmount - > setEnabled ( false ) ;
m_editAmount - > loadText ( " will be calculated " ) ;
} else
m_editAmount - > setValue ( m_split . value ( ) ) ;
setCellWidget ( m_currentRow , 0 , m_editCategory ) ;
setCellWidget ( m_currentRow , 1 , m_editMemo ) ;
setCellWidget ( m_currentRow , 2 , m_editAmount ) ;
setCellWidget ( m_currentRow + 1 , 0 , m_registerButtonFrame ) ;
// load e.g. the category widget with the account list
slotLoadEditWidgets ( ) ;
connect ( MyMoneyFile : : instance ( ) , TQT_SIGNAL ( dataChanged ( ) ) , this , TQT_SLOT ( slotLoadEditWidgets ( ) ) ) ;
// setup the keyboard filter for all widgets
for ( TQWidget * w = m_tabOrderWidgets . first ( ) ; w ; w = m_tabOrderWidgets . next ( ) ) {
w - > installEventFilter ( this ) ;
}
m_editCategory - > setFocus ( ) ;
m_editCategory - > lineEdit ( ) - > selectAll ( ) ;
m_editMode = true ;
return m_editCategory - > lineEdit ( ) ;
}
void kMyMoneySplitTable : : slotLoadEditWidgets ( void )
{
// reload category widget
TQString categoryId = m_editCategory - > selectedItem ( ) ;
AccountSet aSet ;
aSet . addAccountGroup ( MyMoneyAccount : : Asset ) ;
aSet . addAccountGroup ( MyMoneyAccount : : Liability ) ;
aSet . addAccountGroup ( MyMoneyAccount : : Income ) ;
aSet . addAccountGroup ( MyMoneyAccount : : Expense ) ;
if ( KMyMoneyGlobalSettings : : expertMode ( ) )
aSet . addAccountGroup ( MyMoneyAccount : : Equity ) ;
// remove the accounts with invalid types at this point
aSet . removeAccountType ( MyMoneyAccount : : CertificateDep ) ;
aSet . removeAccountType ( MyMoneyAccount : : Investment ) ;
aSet . removeAccountType ( MyMoneyAccount : : Stock ) ;
aSet . removeAccountType ( MyMoneyAccount : : MoneyMarket ) ;
aSet . load ( m_editCategory - > selector ( ) ) ;
// if an account is specified then remove it from the widget so that the user
// cannot create a transfer with from and to account being the same account
if ( ! m_account . id ( ) . isEmpty ( ) )
m_editCategory - > selector ( ) - > removeItem ( m_account . id ( ) ) ;
if ( ! categoryId . isEmpty ( ) )
m_editCategory - > setSelectedItem ( categoryId ) ;
}
void kMyMoneySplitTable : : addToTabOrder ( TQWidget * w )
{
if ( w ) {
while ( w - > focusProxy ( ) )
w = TQT_TQWIDGET ( w - > focusProxy ( ) ) ;
m_tabOrderWidgets . append ( w ) ;
}
}
bool kMyMoneySplitTable : : focusNextPrevChild ( bool next )
{
MYMONEYTRACER ( tracer ) ;
bool rc = false ;
if ( m_editCategory ) {
TQWidget * w = 0 ;
TQWidget * currentWidget ;
m_tabOrderWidgets . find ( tqApp - > focusWidget ( ) ) ;
currentWidget = m_tabOrderWidgets . current ( ) ;
w = next ? m_tabOrderWidgets . next ( ) : m_tabOrderWidgets . prev ( ) ;
do {
if ( ! w ) {
w = next ? m_tabOrderWidgets . first ( ) : m_tabOrderWidgets . last ( ) ;
}
if ( w ! = currentWidget
& & ( ( w - > focusPolicy ( ) & TQ_TabFocus ) = = TQ_TabFocus )
& & w - > isVisible ( ) & & w - > isEnabled ( ) ) {
w - > setFocus ( ) ;
rc = true ;
break ;
}
w = next ? m_tabOrderWidgets . next ( ) : m_tabOrderWidgets . prev ( ) ;
} while ( w ! = currentWidget ) ;
} else
rc = TQTable : : focusNextPrevChild ( next ) ;
return rc ;
}
# include "kmymoneysplittable.moc"