|
|
|
#include <stdint.h>
|
|
|
|
#include <tqmap.h>
|
|
|
|
#include <tqptrstack.h>
|
|
|
|
#include <kmymoney/mymoneyexception.h>
|
|
|
|
|
|
|
|
#ifndef MYMONEYMAP_H
|
|
|
|
#define MYMONEYMAP_H
|
|
|
|
|
|
|
|
#define MY_OWN_DEBUG 0
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Thomas Baumgart
|
|
|
|
*
|
|
|
|
* This template class adds transaction security to the TQMap<> class.
|
|
|
|
* The interface is very simple. Before you perform any changes,
|
|
|
|
* you have to call the startTransaction() method. Then you can use
|
|
|
|
* the insert(), modify() and remove() methods to modify the map.
|
|
|
|
* Changes are recorded and if you are finished, use the
|
|
|
|
* commitTransaction() to finish the transaction. If you want to go
|
|
|
|
* back before you have committed the transaction, use
|
|
|
|
* rollbackTransaction() to set the container to the state it was
|
|
|
|
* in before you called startTransaction().
|
|
|
|
*
|
|
|
|
* The implementation is based on the command pattern, in case
|
|
|
|
* someone is interested.
|
|
|
|
*/
|
|
|
|
template <class Key, class T>
|
|
|
|
class MyMoneyMap : protected TQMap<Key, T>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// typedef TQMapConstIterator<Key, T> const_iterator;
|
|
|
|
|
|
|
|
MyMoneyMap() : TQMap<Key, T>() {}
|
|
|
|
virtual ~MyMoneyMap() {}
|
|
|
|
|
|
|
|
void startTransaction(unsigned long* id = 0)
|
|
|
|
{
|
|
|
|
m_stack.push(new MyMoneyMapStart(this, id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void rollbackTransaction(void)
|
|
|
|
{
|
|
|
|
if(m_stack.count() == 0)
|
|
|
|
throw new MYMONEYEXCEPTION("No transaction started to rollback changes");
|
|
|
|
|
|
|
|
// undo all actions
|
|
|
|
MyMoneyMapAction* action;
|
|
|
|
while(m_stack.count()) {
|
|
|
|
action = m_stack.pop();
|
|
|
|
action->undo();
|
|
|
|
delete action;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool commitTransaction(void)
|
|
|
|
{
|
|
|
|
if(m_stack.count() == 0)
|
|
|
|
throw new MYMONEYEXCEPTION("No transaction started to commit changes");
|
|
|
|
|
|
|
|
bool rc = m_stack.count() > 1;
|
|
|
|
m_stack.setAutoDelete(true);
|
|
|
|
m_stack.clear();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert(const Key& key, const T& obj)
|
|
|
|
{
|
|
|
|
if(m_stack.count() == 0)
|
|
|
|
throw new MYMONEYEXCEPTION("No transaction started to insert new element into container");
|
|
|
|
|
|
|
|
// store object in
|
|
|
|
m_stack.push(new MyMoneyMapInsert(this, key, obj));
|
|
|
|
}
|
|
|
|
|
|
|
|
void modify(const Key& key, const T& obj)
|
|
|
|
{
|
|
|
|
if(m_stack.count() == 0)
|
|
|
|
throw new MYMONEYEXCEPTION("No transaction started to modify element in container");
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// had to take this out, because we use TQPair in one instance as key
|
|
|
|
if(key.isEmpty())
|
|
|
|
throw new MYMONEYEXCEPTION("No key to update object");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_stack.push(new MyMoneyMapModify(this, key, obj));
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove(const Key& key)
|
|
|
|
{
|
|
|
|
if(m_stack.count() == 0)
|
|
|
|
throw new MYMONEYEXCEPTION("No transaction started to remove element from container");
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// had to take this out, because we use TQPair in one instance as key
|
|
|
|
if(key.isEmpty())
|
|
|
|
throw new MYMONEYEXCEPTION("No key to remove object");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_stack.push(new MyMoneyMapRemove(this, key));
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneyMap<Key, T>& operator= (const TQMap<Key, T>& m)
|
|
|
|
{
|
|
|
|
if(m_stack.count() != 0) {
|
|
|
|
throw new MYMONEYEXCEPTION("Cannot assign whole container during transaction");
|
|
|
|
}
|
|
|
|
TQMap<Key, T>::operator=(m);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline TQValueList<T> values(void) const
|
|
|
|
{
|
|
|
|
return TQMap<Key,T>::values();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline TQValueList<Key> keys(void) const
|
|
|
|
{
|
|
|
|
return TQMap<Key,T>::keys();
|
|
|
|
}
|
|
|
|
|
|
|
|
const T& operator[] ( const Key& k ) const
|
|
|
|
{ TQT_CHECK_INVALID_MAP_ELEMENT; return TQMap<Key,T>::operator[](k); }
|
|
|
|
|
|
|
|
inline TQ_TYPENAME TQMap<Key, T>::const_iterator find(const Key& k) const
|
|
|
|
{
|
|
|
|
return TQMap<Key,T>::find(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline TQ_TYPENAME TQMap<Key, T>::const_iterator begin(void) const
|
|
|
|
{
|
|
|
|
return TQMap<Key,T>::begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline TQ_TYPENAME TQMap<Key, T>::const_iterator end(void) const
|
|
|
|
{
|
|
|
|
return TQMap<Key,T>::end();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool contains(const Key& k) const
|
|
|
|
{
|
|
|
|
return find(k) != end();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void map(TQMap<Key, T>& that) const
|
|
|
|
{
|
|
|
|
//TQMap<Key, T>* ptr = dynamic_cast<TQMap<Key, T>* >(this);
|
|
|
|
//that = *ptr;
|
|
|
|
that = *(dynamic_cast<TQMap<Key, T>* >(const_cast<MyMoneyMap<Key, T>* >(this)));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t count(void) const
|
|
|
|
{
|
|
|
|
return TQMap<Key, T>::count();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if MY_OWN_DEBUG
|
|
|
|
void dump(void) const
|
|
|
|
{
|
|
|
|
printf("Container dump\n");
|
|
|
|
printf(" items in container = %d\n", count());
|
|
|
|
printf(" items on stack = %d\n", m_stack.count());
|
|
|
|
|
|
|
|
const_iterator it;
|
|
|
|
for(it = begin(); it != end(); ++it) {
|
|
|
|
printf(" %s \n", it.key().data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
private:
|
|
|
|
class MyMoneyMapAction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyMoneyMapAction(TQMap<Key, T>* container) :
|
|
|
|
m_container(container) {}
|
|
|
|
|
|
|
|
MyMoneyMapAction(TQMap<Key, T>* container, const Key& key, const T& obj) :
|
|
|
|
m_container(container),
|
|
|
|
m_obj(obj),
|
|
|
|
m_key(key) {}
|
|
|
|
|
|
|
|
virtual ~MyMoneyMapAction() {}
|
|
|
|
virtual void undo(void) = 0;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
TQMap<Key, T>* m_container;
|
|
|
|
T m_obj;
|
|
|
|
Key m_key;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MyMoneyMapStart : public MyMoneyMapAction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyMoneyMapStart(TQMap<Key, T>* container, unsigned long* id) :
|
|
|
|
MyMoneyMapAction(container),
|
|
|
|
m_idPtr(id)
|
|
|
|
{
|
|
|
|
if(id != 0)
|
|
|
|
m_id = *id;
|
|
|
|
}
|
|
|
|
virtual ~MyMoneyMapStart() {}
|
|
|
|
void undo(void)
|
|
|
|
{
|
|
|
|
if(m_idPtr != 0)
|
|
|
|
*m_idPtr = m_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned long* m_idPtr;
|
|
|
|
unsigned long m_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MyMoneyMapInsert : public MyMoneyMapAction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyMoneyMapInsert(TQMap<Key, T>* container, const Key& key, const T& obj) :
|
|
|
|
MyMoneyMapAction(container, key, obj)
|
|
|
|
{
|
|
|
|
(*container)[key] = obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~MyMoneyMapInsert() {}
|
|
|
|
void undo(void)
|
|
|
|
{
|
|
|
|
// m_container->remove(m_key) does not work on GCC 4.0.2
|
|
|
|
// using this-> to access those member does the trick
|
|
|
|
this->m_container->remove(this->m_key);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MyMoneyMapRemove : public MyMoneyMapAction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyMoneyMapRemove(TQMap<Key, T>* container, const Key& key) :
|
|
|
|
MyMoneyMapAction(container, key, (*container)[key])
|
|
|
|
{
|
|
|
|
container->remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~MyMoneyMapRemove() {}
|
|
|
|
void undo(void)
|
|
|
|
{
|
|
|
|
(*(this->m_container))[this->m_key] = this->m_obj;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MyMoneyMapModify : public MyMoneyMapAction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyMoneyMapModify(TQMap<Key, T>* container, const Key& key, const T& obj) :
|
|
|
|
MyMoneyMapAction(container, key, (*container)[key])
|
|
|
|
{
|
|
|
|
(*container)[key] = obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~MyMoneyMapModify() {}
|
|
|
|
void undo(void)
|
|
|
|
{
|
|
|
|
(*(this->m_container))[this->m_key] = this->m_obj;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
protected:
|
|
|
|
TQPtrStack<MyMoneyMapAction> m_stack;
|
|
|
|
};
|
|
|
|
|
|
|
|
#if MY_OWN_DEBUG
|
|
|
|
#include <kmymoney/mymoneyaccount.h>
|
|
|
|
#include <kmymoney/mymoneytransaction.h>
|
|
|
|
main()
|
|
|
|
{
|
|
|
|
MyMoneyMap<TQString, MyMoneyAccount> container;
|
|
|
|
MyMoneyMap<TQString, MyMoneyTransaction> ct;
|
|
|
|
|
|
|
|
MyMoneyAccount acc;
|
|
|
|
acc.setName("Test");
|
|
|
|
// this should not be possible
|
|
|
|
// container["a"] = acc;
|
|
|
|
|
|
|
|
TQValueList<MyMoneyAccount> list;
|
|
|
|
list = container.values();
|
|
|
|
|
|
|
|
MyMoneyAccount b;
|
|
|
|
b.setName("Thomas");
|
|
|
|
|
|
|
|
try {
|
|
|
|
container.startTransaction();
|
|
|
|
container.insert("001", acc);
|
|
|
|
container.dump();
|
|
|
|
container.commitTransaction();
|
|
|
|
acc.setName("123");
|
|
|
|
container.startTransaction();
|
|
|
|
container.modify("001", acc);
|
|
|
|
container.dump();
|
|
|
|
container.rollbackTransaction();
|
|
|
|
container.dump();
|
|
|
|
|
|
|
|
container.startTransaction();
|
|
|
|
container.remove(TQString("001"));
|
|
|
|
container.dump();
|
|
|
|
container.rollbackTransaction();
|
|
|
|
container.dump();
|
|
|
|
|
|
|
|
b = container["001"];
|
|
|
|
printf("b.name() = %s\n", b.name().data());
|
|
|
|
|
|
|
|
TQMap<TQString, MyMoneyAccount>::ConstIterator it;
|
|
|
|
it = container.find("001");
|
|
|
|
it = container.begin();
|
|
|
|
|
|
|
|
} catch(MyMoneyException *e) {
|
|
|
|
printf("Caught exception: %s\n", e->what().data());
|
|
|
|
delete e;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQMap<TQString, MyMoneyAccount> map;
|
|
|
|
map["005"] = b;
|
|
|
|
container = map;
|
|
|
|
|
|
|
|
printf("b.name() = %s\n", container["001"].name().data());
|
|
|
|
printf("b.name() = %s\n", container["005"].name().data());
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|