|
|
|
/***************************************************************************
|
|
|
|
kmymoneyaccounttree.cpp - description
|
|
|
|
-------------------
|
|
|
|
begin : Sat Jan 1 2005
|
|
|
|
copyright : (C) 2005 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 <tqpoint.h>
|
|
|
|
#include <tqevent.h>
|
|
|
|
#include <tqdragobject.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqheader.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// KDE Includes
|
|
|
|
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Project Includes
|
|
|
|
|
|
|
|
#include <kmymoney/mymoneyfile.h>
|
|
|
|
#include <kmymoney/kmymoneyaccounttree.h>
|
|
|
|
#include <kmymoney/kmymoneyglobalsettings.h>
|
|
|
|
|
|
|
|
#include <kmymoney/kmymoneyutils.h>
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBase::KMyMoneyAccountTreeBase(TQWidget* parent, const char* name) :
|
|
|
|
KListView(parent, name),
|
|
|
|
m_accountConnections(false),
|
|
|
|
m_institutionConnections(false),
|
|
|
|
m_queuedSort(0)
|
|
|
|
{
|
|
|
|
setRootIsDecorated(true);
|
|
|
|
setAllColumnsShowFocus(true);
|
|
|
|
|
|
|
|
m_nameColumn = addColumn(i18n("Account"));
|
|
|
|
setColumnWidthMode(m_nameColumn, TQListView::Manual);
|
|
|
|
|
|
|
|
m_typeColumn = -1;
|
|
|
|
m_balanceColumn = -1;
|
|
|
|
m_valueColumn = -1;
|
|
|
|
|
|
|
|
setMultiSelection(false);
|
|
|
|
|
|
|
|
setResizeMode(TQListView::LastColumn);
|
|
|
|
setShowSortIndicator(true);
|
|
|
|
setSorting(0);
|
|
|
|
|
|
|
|
header()->setResizeEnabled(true);
|
|
|
|
|
|
|
|
setDragEnabled(false);
|
|
|
|
setAcceptDrops(false);
|
|
|
|
setItemsMovable(false);
|
|
|
|
setDropVisualizer(false);
|
|
|
|
setDropHighlighter(true);
|
|
|
|
|
|
|
|
// setup a default
|
|
|
|
m_baseCurrency.setSmallestAccountFraction(100);
|
|
|
|
m_baseCurrency.setSmallestCashFraction(100);
|
|
|
|
|
|
|
|
connect(this, TQT_SIGNAL(dropped(TQDropEvent*,TQListViewItem*,TQListViewItem*)), this, TQT_SLOT(slotObjectDropped(TQDropEvent*,TQListViewItem*,TQListViewItem*)));
|
|
|
|
connect(this, TQT_SIGNAL(selectionChanged(TQListViewItem*)), this, TQT_SLOT(slotSelectObject(TQListViewItem*)));
|
|
|
|
connect(this, TQT_SIGNAL(contextMenu(KListView*, TQListViewItem* , const TQPoint&)), this, TQT_SLOT(slotOpenContextMenu(KListView*, TQListViewItem*, const TQPoint&)));
|
|
|
|
connect(this, TQT_SIGNAL(doubleClicked(TQListViewItem*,const TQPoint&,int)), this, TQT_SLOT(slotOpenObject(TQListViewItem*)));
|
|
|
|
|
|
|
|
// drag and drop timer connections
|
|
|
|
connect( &m_autoopenTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotOpenFolder() ) );
|
|
|
|
connect( &m_autoscrollTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotAutoScroll() ) );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBase::~KMyMoneyAccountTreeBase()
|
|
|
|
{
|
|
|
|
if (!m_configGroup.isEmpty())
|
|
|
|
saveLayout(KGlobal::config(), m_configGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::restoreLayout(const TQString& group)
|
|
|
|
{
|
|
|
|
if (!m_configGroup.isEmpty())
|
|
|
|
return; // already done
|
|
|
|
// make sure to use the previous settings. If no settings are found
|
|
|
|
// we use equal distribution of all fields as an initial setting
|
|
|
|
// TODO this only makes the first column invisible if settings exist setColumnWidth(0, 0);
|
|
|
|
m_configGroup = group;
|
|
|
|
KListView::restoreLayout(KGlobal::config(), m_configGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::showType(void)
|
|
|
|
{
|
|
|
|
m_typeColumn = addColumn(i18n("Type"));
|
|
|
|
setColumnWidthMode(m_typeColumn, TQListView::Manual);
|
|
|
|
setColumnAlignment(m_typeColumn, TQt::AlignLeft);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::showValue(void)
|
|
|
|
{
|
|
|
|
m_balanceColumn = addColumn(i18n("Total Balance"));
|
|
|
|
setColumnWidthMode(m_balanceColumn, TQListView::Manual);
|
|
|
|
setColumnAlignment(m_balanceColumn, TQt::AlignRight);
|
|
|
|
|
|
|
|
m_valueColumn = addColumn(i18n("Total Value"));
|
|
|
|
setColumnWidthMode(m_valueColumn, TQListView::Manual);
|
|
|
|
setColumnAlignment(m_valueColumn, TQt::AlignRight);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::connectNotify(const char * /* s */)
|
|
|
|
{
|
|
|
|
// update drag and drop settings
|
|
|
|
m_accountConnections = (receivers(TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&))) != 0);
|
|
|
|
m_institutionConnections = (receivers(TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&))) != 0);
|
|
|
|
setDragEnabled(m_accountConnections | m_institutionConnections);
|
|
|
|
setAcceptDrops(m_accountConnections | m_institutionConnections);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::disconnectNotify(const char * /* s */)
|
|
|
|
{
|
|
|
|
// update drag and drop settings
|
|
|
|
m_accountConnections = (receivers(TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&))) != 0);
|
|
|
|
m_institutionConnections = (receivers(TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&))) != 0);
|
|
|
|
setDragEnabled(m_accountConnections | m_institutionConnections);
|
|
|
|
setAcceptDrops(m_accountConnections | m_institutionConnections);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::setSectionHeader(const TQString& txt)
|
|
|
|
{
|
|
|
|
header()->setLabel(nameColumn(), txt);
|
|
|
|
}
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem* KMyMoneyAccountTreeBase::selectedItem(void) const
|
|
|
|
{
|
|
|
|
return dynamic_cast<KMyMoneyAccountTreeBaseItem *>(KListView::selectedItem());
|
|
|
|
}
|
|
|
|
|
|
|
|
const KMyMoneyAccountTreeBaseItem* KMyMoneyAccountTreeBase::findItem(const TQString& id) const
|
|
|
|
{
|
|
|
|
// tried to use a TQListViewItemIterator but that does not fit
|
|
|
|
// with the constness of this method. Arghhh.
|
|
|
|
|
|
|
|
TQListViewItem* p = firstChild();
|
|
|
|
while(p) {
|
|
|
|
// item found, check for the id
|
|
|
|
KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(p);
|
|
|
|
if(item && item->id() == id)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// item did not match, search the next one
|
|
|
|
TQListViewItem* next = p->firstChild();
|
|
|
|
if(!next) {
|
|
|
|
while((next = p->nextSibling()) == 0) {
|
|
|
|
p = p->parent();
|
|
|
|
if(!p)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dynamic_cast<KMyMoneyAccountTreeBaseItem*>(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMyMoneyAccountTreeBase::dropAccountOnAccount(const MyMoneyAccount& accFrom, const MyMoneyAccount& accTo) const
|
|
|
|
{
|
|
|
|
bool rc = false;
|
|
|
|
|
|
|
|
// it does not make sense to reparent an account to oneself
|
|
|
|
// or to reparent it to it's current parent
|
|
|
|
if(accTo.id() != accFrom.id()
|
|
|
|
&& accFrom.parentAccountId() != accTo.id()) {
|
|
|
|
// Moving within a group is generally ok
|
|
|
|
rc = accTo.accountGroup() == accFrom.accountGroup();
|
|
|
|
|
|
|
|
// now check for exceptions
|
|
|
|
if(rc) {
|
|
|
|
if(accTo.accountType() == MyMoneyAccount::Investment
|
|
|
|
&& !accFrom.isInvest())
|
|
|
|
rc = false;
|
|
|
|
|
|
|
|
else if(accFrom.isInvest()
|
|
|
|
&& accTo.accountType() != MyMoneyAccount::Investment)
|
|
|
|
rc = false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if(accFrom.accountGroup() == MyMoneyAccount::Income
|
|
|
|
&& accTo.accountGroup() == MyMoneyAccount::Expense)
|
|
|
|
rc = true;
|
|
|
|
|
|
|
|
if(accFrom.accountGroup() == MyMoneyAccount::Expense
|
|
|
|
&& accTo.accountGroup() == MyMoneyAccount::Income)
|
|
|
|
rc = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it's generally ok to drop here, make sure that
|
|
|
|
// the accTo does not have a child with the same name
|
|
|
|
const KMyMoneyAccountTreeBaseItem* to = findItem(accTo.id());
|
|
|
|
if(to) {
|
|
|
|
to = dynamic_cast<KMyMoneyAccountTreeBaseItem*> (to->firstChild());
|
|
|
|
while(to && rc) {
|
|
|
|
if(to->isAccount()) {
|
|
|
|
const MyMoneyAccount& acc = dynamic_cast<const MyMoneyAccount&>(to->itemObject());
|
|
|
|
if(acc.name() == accFrom.name())
|
|
|
|
rc = false;
|
|
|
|
}
|
|
|
|
to = dynamic_cast<KMyMoneyAccountTreeBaseItem*> (to->nextSibling());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMyMoneyAccountTreeBase::acceptDrag(TQDropEvent* event) const
|
|
|
|
{
|
|
|
|
bool rc;
|
|
|
|
|
|
|
|
if((rc = (acceptDrops()) && (event->source() == viewport()))) {
|
|
|
|
rc = false;
|
|
|
|
KMyMoneyAccountTreeBaseItem* to = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(itemAt( contentsToViewport(event->pos()) ));
|
|
|
|
TQString fromId(event->encodedData("text/plain"));
|
|
|
|
const KMyMoneyAccountTreeBaseItem* from = findItem(fromId);
|
|
|
|
|
|
|
|
// we can only move accounts around
|
|
|
|
if(!from->isAccount())
|
|
|
|
from = 0;
|
|
|
|
|
|
|
|
if(to && from && !to->isChildOf(from)) {
|
|
|
|
const MyMoneyAccount& accFrom = dynamic_cast<const MyMoneyAccount&>(from->itemObject());
|
|
|
|
|
|
|
|
if(to->isAccount() && m_accountConnections) {
|
|
|
|
const MyMoneyAccount& accTo = dynamic_cast<const MyMoneyAccount&>(to->itemObject());
|
|
|
|
rc = dropAccountOnAccount(accFrom, accTo);
|
|
|
|
|
|
|
|
} else if(to->isInstitution() && m_institutionConnections) {
|
|
|
|
// Moving a non-stock account to an institution is ok
|
|
|
|
if(!accFrom.isInvest())
|
|
|
|
rc = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::startDrag(void)
|
|
|
|
{
|
|
|
|
TQListViewItem* item = currentItem();
|
|
|
|
KMyMoneyAccountTreeBaseItem* p = dynamic_cast<KMyMoneyAccountTreeBaseItem *>(item);
|
|
|
|
if(!p)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(p->isAccount()) {
|
|
|
|
TQTextDrag* drag = new TQTextDrag(p->id(), viewport());
|
|
|
|
drag->setSubtype("plain");
|
|
|
|
|
|
|
|
// use the icon that is attached to the item to be dragged
|
|
|
|
if (p->pixmap(0)) {
|
|
|
|
TQPixmap pixmap(*p->pixmap(0));
|
|
|
|
TQPoint hotspot( pixmap.width() / 2, pixmap.height() / 2 );
|
|
|
|
drag->setPixmap(pixmap, hotspot);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (drag->dragMove() && drag->target() != viewport())
|
|
|
|
emit moved();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotObjectDropped(TQDropEvent* event, TQListViewItem* /* parent */, TQListViewItem* /* after */)
|
|
|
|
{
|
|
|
|
m_autoopenTimer.stop();
|
|
|
|
slotStopAutoScroll();
|
|
|
|
if(dropHighlighter())
|
|
|
|
cleanItemHighlighter();
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem* newParent = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(m_dropItem);
|
|
|
|
if(newParent) {
|
|
|
|
TQString fromId(event->encodedData("text/plain"));
|
|
|
|
const KMyMoneyAccountTreeBaseItem* from = findItem(fromId);
|
|
|
|
|
|
|
|
// we can only move accounts around
|
|
|
|
if(!from->isAccount())
|
|
|
|
from = 0;
|
|
|
|
|
|
|
|
if(from) {
|
|
|
|
const MyMoneyAccount& accFrom = dynamic_cast<const MyMoneyAccount&>(from->itemObject());
|
|
|
|
if(newParent->isAccount()) {
|
|
|
|
const MyMoneyAccount& accTo = dynamic_cast<const MyMoneyAccount&>(newParent->itemObject());
|
|
|
|
if(dropAccountOnAccount(accFrom, accTo)) {
|
|
|
|
emit reparent(accFrom, accTo);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if(newParent->isInstitution()) {
|
|
|
|
if(!accFrom.isInvest()) {
|
|
|
|
const MyMoneyInstitution& institution = dynamic_cast<const MyMoneyInstitution&>(newParent->itemObject());
|
|
|
|
emit reparent(accFrom, institution);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotSelectObject(TQListViewItem* i)
|
|
|
|
{
|
|
|
|
emit selectObject(MyMoneyInstitution());
|
|
|
|
emit selectObject(MyMoneyAccount());
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(i);
|
|
|
|
if(item != 0) {
|
|
|
|
emit selectObject(item->itemObject());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotOpenContextMenu(KListView* lv, TQListViewItem* i, const TQPoint&)
|
|
|
|
{
|
|
|
|
Q_UNUSED(lv);
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem *>(i);
|
|
|
|
if(item) {
|
|
|
|
emit selectObject(item->itemObject());
|
|
|
|
|
|
|
|
// Create a copy of the item since the original might be destroyed
|
|
|
|
// during processing of this signal.
|
|
|
|
if(item->isInstitution()) {
|
|
|
|
MyMoneyInstitution institution = dynamic_cast<const MyMoneyInstitution&>(item->itemObject());
|
|
|
|
emit openContextMenu(institution);
|
|
|
|
} else {
|
|
|
|
MyMoneyAccount account = dynamic_cast<const MyMoneyAccount&>(item->itemObject());
|
|
|
|
emit openContextMenu(account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotOpenObject(TQListViewItem* i)
|
|
|
|
{
|
|
|
|
KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem *>(i);
|
|
|
|
if(item) {
|
|
|
|
// Create a copy of the item since the original might be destroyed
|
|
|
|
// during processing of this signal.
|
|
|
|
if(item->isAccount()) {
|
|
|
|
MyMoneyAccount acc = dynamic_cast<const MyMoneyAccount&>(item->itemObject());
|
|
|
|
emit openObject(acc);
|
|
|
|
} else if(item->isInstitution()) {
|
|
|
|
MyMoneyInstitution inst = dynamic_cast<const MyMoneyInstitution&>(item->itemObject());
|
|
|
|
emit openObject(inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* drag and drop support inspired partially from KMail */
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
static const int autoscrollMargin = 16;
|
|
|
|
static const int initialScrollTime = 30;
|
|
|
|
static const int initialScrollAccel = 5;
|
|
|
|
static const int autoopenTime = 750;
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotOpenFolder(void)
|
|
|
|
{
|
|
|
|
m_autoopenTimer.stop();
|
|
|
|
if ( m_dropItem && !m_dropItem->isOpen() ) {
|
|
|
|
m_dropItem->setOpen( TRUE );
|
|
|
|
m_dropItem->repaint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotStartAutoScroll(void)
|
|
|
|
{
|
|
|
|
if ( !m_autoscrollTimer.isActive() ) {
|
|
|
|
m_autoscrollTime = initialScrollTime;
|
|
|
|
m_autoscrollAccel = initialScrollAccel;
|
|
|
|
m_autoscrollTimer.start( m_autoscrollTime );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotStopAutoScroll(void)
|
|
|
|
{
|
|
|
|
m_autoscrollTimer.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotAutoScroll(void)
|
|
|
|
{
|
|
|
|
// don't show a highlighter during scrolling
|
|
|
|
cleanItemHighlighter();
|
|
|
|
|
|
|
|
TQPoint p = viewport()->mapFromGlobal( TQCursor::pos() );
|
|
|
|
|
|
|
|
if ( m_autoscrollAccel-- <= 0 && m_autoscrollTime ) {
|
|
|
|
m_autoscrollAccel = initialScrollAccel;
|
|
|
|
m_autoscrollTime--;
|
|
|
|
m_autoscrollTimer.start( m_autoscrollTime );
|
|
|
|
}
|
|
|
|
int l = TQMAX(1,(initialScrollTime-m_autoscrollTime));
|
|
|
|
|
|
|
|
int dx=0,dy=0;
|
|
|
|
if ( p.y() < autoscrollMargin ) {
|
|
|
|
dy = -l;
|
|
|
|
} else if ( p.y() > visibleHeight()-autoscrollMargin ) {
|
|
|
|
dy = +l;
|
|
|
|
}
|
|
|
|
if ( p.x() < autoscrollMargin ) {
|
|
|
|
dx = -l;
|
|
|
|
} else if ( p.x() > visibleWidth()-autoscrollMargin ) {
|
|
|
|
dx = +l;
|
|
|
|
}
|
|
|
|
if ( dx || dy ) {
|
|
|
|
scrollBy(dx, dy);
|
|
|
|
} else {
|
|
|
|
slotStopAutoScroll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::contentsDragMoveEvent(TQDragMoveEvent* e)
|
|
|
|
{
|
|
|
|
TQPoint vp = contentsToViewport(e->pos());
|
|
|
|
TQRect inside_margin((contentsX() > 0) ? autoscrollMargin : 0,
|
|
|
|
(contentsY() > 0) ? autoscrollMargin : 0,
|
|
|
|
visibleWidth() - ((contentsX() + visibleWidth() < contentsWidth())
|
|
|
|
? autoscrollMargin*2 : 0),
|
|
|
|
visibleHeight() - ((contentsY() + visibleHeight() < contentsHeight())
|
|
|
|
? autoscrollMargin*2 : 0));
|
|
|
|
|
|
|
|
bool accepted = false;
|
|
|
|
TQListViewItem *i = itemAt( vp );
|
|
|
|
if ( i ) {
|
|
|
|
accepted = acceptDrag(e);
|
|
|
|
if(accepted && !m_autoscrollTimer.isActive()) {
|
|
|
|
if (dropHighlighter()) {
|
|
|
|
TQRect tmpRect = drawItemHighlighter(0, i);
|
|
|
|
if (tmpRect != m_lastDropHighlighter) {
|
|
|
|
cleanItemHighlighter();
|
|
|
|
m_lastDropHighlighter = tmpRect;
|
|
|
|
viewport()->repaint(tmpRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !inside_margin.contains(vp) ) {
|
|
|
|
slotStartAutoScroll();
|
|
|
|
e->accept(TQRect(0,0,0,0)); // Keep sending move events
|
|
|
|
m_autoopenTimer.stop();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if(accepted)
|
|
|
|
e->accept();
|
|
|
|
else
|
|
|
|
e->ignore();
|
|
|
|
if ( i != m_dropItem ) {
|
|
|
|
m_autoopenTimer.stop();
|
|
|
|
m_dropItem = i;
|
|
|
|
m_autoopenTimer.start( autoopenTime );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( accepted ) {
|
|
|
|
switch ( e->action() ) {
|
|
|
|
case TQDropEvent::Copy:
|
|
|
|
case TQDropEvent::Link:
|
|
|
|
break;
|
|
|
|
case TQDropEvent::Move:
|
|
|
|
e->acceptAction();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
e->ignore();
|
|
|
|
m_autoopenTimer.stop();
|
|
|
|
m_dropItem = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!accepted && dropHighlighter())
|
|
|
|
cleanItemHighlighter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::cleanItemHighlighter(void)
|
|
|
|
{
|
|
|
|
if(m_lastDropHighlighter.isValid()) {
|
|
|
|
TQRect rect=m_lastDropHighlighter;
|
|
|
|
m_lastDropHighlighter = TQRect();
|
|
|
|
// make sure, we repaint a bit more. that's important during
|
|
|
|
// autoscroll. if we don't do that, parts of the highlighter
|
|
|
|
// do not get removed
|
|
|
|
rect.moveBy(-1, -1);
|
|
|
|
rect.setSize(rect.size() + TQSize(2,2));
|
|
|
|
viewport()->repaint(rect, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::viewportPaintEvent(TQPaintEvent* e)
|
|
|
|
{
|
|
|
|
TQListView::viewportPaintEvent(e);
|
|
|
|
|
|
|
|
if (m_lastDropHighlighter.isValid() && e->rect().intersects(m_lastDropHighlighter)) {
|
|
|
|
TQPainter painter(viewport());
|
|
|
|
|
|
|
|
// This is where we actually draw the drop-highlighter
|
|
|
|
style().tqdrawPrimitive(TQStyle::PE_FocusRect, &painter, m_lastDropHighlighter, colorGroup(),
|
|
|
|
TQStyle::Style_FocusAtBorder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
|
|
const MyMoneyObject& KMyMoneyAccountTreeBaseItem::itemObject(void) const
|
|
|
|
{
|
|
|
|
if(m_type == Institution)
|
|
|
|
return m_institution;
|
|
|
|
return m_account;
|
|
|
|
}
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem::KMyMoneyAccountTreeBaseItem(KListView *parent, const MyMoneyInstitution& institution) :
|
|
|
|
KListViewItem(parent),
|
|
|
|
m_totalValue(MyMoneyMoney(0)),
|
|
|
|
m_negative(false),
|
|
|
|
m_institution(institution),
|
|
|
|
m_type(Institution)
|
|
|
|
{
|
|
|
|
setName();
|
|
|
|
}
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem::KMyMoneyAccountTreeBaseItem(KListView *parent, const MyMoneyAccount& account, const MyMoneySecurity& security, const TQString& name) :
|
|
|
|
KListViewItem(parent),
|
|
|
|
m_security(security),
|
|
|
|
m_totalValue(MyMoneyMoney(0)),
|
|
|
|
m_account(account),
|
|
|
|
m_negative(false),
|
|
|
|
m_type(Account)
|
|
|
|
{
|
|
|
|
if(!name.isEmpty()) {
|
|
|
|
// we do not want to modify the original account
|
|
|
|
MyMoneyAccount acc(account);
|
|
|
|
acc.setName(name);
|
|
|
|
m_account = acc;
|
|
|
|
}
|
|
|
|
setName();
|
|
|
|
}
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem::KMyMoneyAccountTreeBaseItem(KMyMoneyAccountTreeBaseItem *parent, const MyMoneyAccount& account, const TQValueList<MyMoneyPrice>& price, const MyMoneySecurity& security) :
|
|
|
|
KListViewItem(parent),
|
|
|
|
m_price(price),
|
|
|
|
m_security(security),
|
|
|
|
m_totalValue(MyMoneyMoney(0)),
|
|
|
|
m_account(account),
|
|
|
|
m_negative(false),
|
|
|
|
m_type(Account)
|
|
|
|
{
|
|
|
|
setName();
|
|
|
|
}
|
|
|
|
|
|
|
|
KMyMoneyAccountTreeBaseItem::~KMyMoneyAccountTreeBaseItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString& KMyMoneyAccountTreeBaseItem::id(void) const
|
|
|
|
{
|
|
|
|
if(m_type == Institution)
|
|
|
|
return m_institution.id();
|
|
|
|
return m_account.id();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMyMoneyAccountTreeBaseItem::isChildOf(const TQListViewItem* const item) const
|
|
|
|
{
|
|
|
|
TQListViewItem *p = parent();
|
|
|
|
while(p && p != item) {
|
|
|
|
p = p->parent();
|
|
|
|
}
|
|
|
|
return (p != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneyMoney KMyMoneyAccountTreeBaseItem::value() const
|
|
|
|
{
|
|
|
|
// calculate the new value by running down the price list
|
|
|
|
MyMoneyMoney result = balance();
|
|
|
|
TQValueList<MyMoneyPrice>::const_iterator it_p;
|
|
|
|
TQString security = m_security.id();
|
|
|
|
for(it_p = m_price.begin(); it_p != m_price.end(); ++it_p) {
|
|
|
|
result = (result * (MyMoneyMoney(1,1) / (*it_p).rate(security))).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision()));
|
|
|
|
if((*it_p).from() == security)
|
|
|
|
security = (*it_p).to();
|
|
|
|
else
|
|
|
|
security = (*it_p).from();
|
|
|
|
}
|
|
|
|
if (listView())
|
|
|
|
result = result.convert(listView()->baseCurrency().smallestAccountFraction());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::setName()
|
|
|
|
{
|
|
|
|
KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
|
|
|
|
if (!lv)
|
|
|
|
return;
|
|
|
|
if (isInstitution()) {
|
|
|
|
setPixmap(lv->nameColumn(), m_institution.pixmap());
|
|
|
|
setText(lv->nameColumn(), m_institution.name());
|
|
|
|
} else {
|
|
|
|
setPixmap(lv->nameColumn(), m_account.accountPixmap(false, 22));
|
|
|
|
setText(lv->nameColumn(), m_account.name());
|
|
|
|
#ifndef KMM_DESIGNER
|
|
|
|
if(lv->typeColumn()>=0 && !MyMoneyFile::instance()->isStandardAccount(m_account.id()))
|
|
|
|
setText(lv->typeColumn(), KMyMoneyUtils::accountTypeToString(m_account.accountType()));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::fillColumns()
|
|
|
|
{
|
|
|
|
KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
|
|
|
|
if (!lv)
|
|
|
|
return;
|
|
|
|
if (lv->valueColumn()<0)
|
|
|
|
return;
|
|
|
|
// show the top accounts always in total value
|
|
|
|
if((isOpen() || m_account.accountList().count() == 0) && parent()) {
|
|
|
|
|
|
|
|
// only show the balance, if its a different security/currency
|
|
|
|
if(m_security.id() != listView()->baseCurrency().id()) {
|
|
|
|
setText(lv->balanceColumn(), balance().formatMoney(m_security));
|
|
|
|
}
|
|
|
|
setText(lv->valueColumn(), m_value.formatMoney(listView()->baseCurrency()) + " ");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
setText(lv->balanceColumn(), " ");
|
|
|
|
if(parent())
|
|
|
|
setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()) + " ");
|
|
|
|
else
|
|
|
|
setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::updateAccount(bool forceTotalUpdate)
|
|
|
|
{
|
|
|
|
MyMoneyMoney oldValue = m_value;
|
|
|
|
m_value = value();
|
|
|
|
|
|
|
|
fillColumns();
|
|
|
|
|
|
|
|
// check if we need to tell upstream account objects in the tree
|
|
|
|
// that the value has changed
|
|
|
|
if(oldValue != m_value || forceTotalUpdate) {
|
|
|
|
adjustTotalValue(m_value - oldValue);
|
|
|
|
if (listView())
|
|
|
|
listView()->emitValueChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::setOpen(bool open)
|
|
|
|
{
|
|
|
|
if (open == isOpen())
|
|
|
|
return;
|
|
|
|
KListViewItem::setOpen(open);
|
|
|
|
fillColumns();
|
|
|
|
|
|
|
|
if(listView())
|
|
|
|
listView()->queueSort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::adjustTotalValue(const MyMoneyMoney& diff)
|
|
|
|
{
|
|
|
|
m_totalValue += diff;
|
|
|
|
|
|
|
|
// if the entry has no children,
|
|
|
|
// or it is the top entry
|
|
|
|
// or it is currently not open
|
|
|
|
// we need to display the value of it
|
|
|
|
KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
|
|
|
|
if(!lv)
|
|
|
|
return;
|
|
|
|
if(!firstChild() || !parent() || (!isOpen() && firstChild())) {
|
|
|
|
if(firstChild())
|
|
|
|
setText(lv->balanceColumn(), " ");
|
|
|
|
if(parent())
|
|
|
|
setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()) + " ");
|
|
|
|
else
|
|
|
|
setText(lv->valueColumn(), m_totalValue.formatMoney(listView()->baseCurrency()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// now make sure, the upstream accounts also get notified about the value change
|
|
|
|
KMyMoneyAccountTreeBaseItem* p = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(parent());
|
|
|
|
if(p != 0) {
|
|
|
|
p->adjustTotalValue(diff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int KMyMoneyAccountTreeBaseItem::compare(TQListViewItem* i, int col, bool ascending) const
|
|
|
|
{
|
|
|
|
KMyMoneyAccountTreeBaseItem* item = dynamic_cast<KMyMoneyAccountTreeBaseItem*>(i);
|
|
|
|
// do special sorting only if
|
|
|
|
// a) name
|
|
|
|
// b) account
|
|
|
|
// c) and different group
|
|
|
|
// d) value column
|
|
|
|
// in all other cases use the standard sorting
|
|
|
|
KMyMoneyAccountTreeBase* lv = dynamic_cast<KMyMoneyAccountTreeBase*>(listView());
|
|
|
|
if(lv && item) {
|
|
|
|
if (col == lv->nameColumn()) {
|
|
|
|
if(m_account.accountGroup() != item->m_account.accountGroup())
|
|
|
|
return (m_account.accountGroup() - item->m_account.accountGroup());
|
|
|
|
} else if (col == lv->balanceColumn() || col == lv->valueColumn()) {
|
|
|
|
MyMoneyMoney result = MyMoneyMoney(text(col)) - MyMoneyMoney(item->text(col));
|
|
|
|
if(result.isNegative())
|
|
|
|
return -1;
|
|
|
|
if(result.isZero())
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// do standard sorting here
|
|
|
|
return KListViewItem::compare(i, col, ascending);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::paintCell(TQPainter *p, const TQColorGroup & cg, int column, int width, int align)
|
|
|
|
{
|
|
|
|
TQColorGroup cg2(cg);
|
|
|
|
|
|
|
|
//set item background
|
|
|
|
if(isAlternate())
|
|
|
|
cg2.setColor(TQColorGroup::Base, KMyMoneyGlobalSettings::listColor());
|
|
|
|
else
|
|
|
|
cg2.setColor(TQColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
|
|
|
|
|
|
|
|
#ifndef KMM_DESIGNER
|
|
|
|
// display base accounts in bold
|
|
|
|
TQFont font = KMyMoneyGlobalSettings::listCellFont();
|
|
|
|
if(!parent())
|
|
|
|
font.setBold(true);
|
|
|
|
|
|
|
|
// strike out closed accounts
|
|
|
|
if(m_account.isClosed())
|
|
|
|
font.setStrikeOut(true);
|
|
|
|
|
|
|
|
p->setFont(font);
|
|
|
|
#endif
|
|
|
|
//set text color
|
|
|
|
TQColor textColour;
|
|
|
|
if(m_negative == true) {
|
|
|
|
textColour = KMyMoneyGlobalSettings::listNegativeValueColor(); //if the item is marked is marked as negative, all columns will be painted negative
|
|
|
|
} else {
|
|
|
|
textColour = m_columnsColor[column]; //otherwise, respect the color for each column
|
|
|
|
}
|
|
|
|
cg2.setColor(TQColorGroup::Text, textColour);
|
|
|
|
|
|
|
|
TQListViewItem::paintCell(p, cg2, column, width, align);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::expandCollapseAll(bool expand)
|
|
|
|
{
|
|
|
|
TQListViewItemIterator it(this);
|
|
|
|
TQListViewItem* p;
|
|
|
|
while((p = it.current()) != 0) {
|
|
|
|
p->setOpen(expand);
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotExpandAll(void)
|
|
|
|
{
|
|
|
|
expandCollapseAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotCollapseAll(void)
|
|
|
|
{
|
|
|
|
expandCollapseAll(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::queueSort(void)
|
|
|
|
{
|
|
|
|
if (sortColumn() == balanceColumn() || sortColumn() == valueColumn()) {
|
|
|
|
++m_queuedSort;
|
|
|
|
TQTimer::singleShot(100, this, TQT_SLOT(slotActivateSort()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBase::slotActivateSort(void)
|
|
|
|
{
|
|
|
|
--m_queuedSort;
|
|
|
|
if(!m_queuedSort)
|
|
|
|
KListView::sort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::setNegative(bool isNegative)
|
|
|
|
{
|
|
|
|
m_negative = isNegative;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMyMoneyAccountTreeBaseItem::setText( int column, const TQString &text, const bool &negative)
|
|
|
|
{
|
|
|
|
//if negative set the map to negative color according to KMyMoneySettings
|
|
|
|
if(negative) {
|
|
|
|
m_columnsColor[column] = KMyMoneyGlobalSettings::listNegativeValueColor();
|
|
|
|
} else {
|
|
|
|
m_columnsColor[column] = TQColorGroup::Text;
|
|
|
|
}
|
|
|
|
|
|
|
|
KListViewItem::setText(column, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "kmymoneyaccounttreebase.moc"
|
|
|
|
// vim:cin:si:ai:et:ts=2:sw=2:
|