00001 #include <stdint.h>
00002 #include <qmap.h>
00003 #include <qptrstack.h>
00004 #include <kmymoney/mymoneyexception.h>
00005
00006 #ifndef MYMONEYMAP_H
00007 #define MYMONEYMAP_H
00008
00009 #define MY_OWN_DEBUG 0
00010
00027 template <class Key, class T>
00028 class MyMoneyMap : protected QMap<Key, T>
00029 {
00030 public:
00031
00032
00033 MyMoneyMap() : QMap<Key, T>() {}
00034 virtual ~MyMoneyMap() {}
00035
00036 void startTransaction(unsigned long* id = 0)
00037 {
00038 m_stack.push(new MyMoneyMapStart(this, id));
00039 }
00040
00041 void rollbackTransaction(void)
00042 {
00043 if(m_stack.count() == 0)
00044 throw new MYMONEYEXCEPTION("No transaction started to rollback changes");
00045
00046
00047 MyMoneyMapAction* action;
00048 while(m_stack.count()) {
00049 action = m_stack.pop();
00050 action->undo();
00051 delete action;
00052 }
00053 }
00054
00055 bool commitTransaction(void)
00056 {
00057 if(m_stack.count() == 0)
00058 throw new MYMONEYEXCEPTION("No transaction started to commit changes");
00059
00060 bool rc = m_stack.count() > 1;
00061 m_stack.setAutoDelete(true);
00062 m_stack.clear();
00063 return rc;
00064 }
00065
00066 void insert(const Key& key, const T& obj)
00067 {
00068 if(m_stack.count() == 0)
00069 throw new MYMONEYEXCEPTION("No transaction started to insert new element into container");
00070
00071
00072 m_stack.push(new MyMoneyMapInsert(this, key, obj));
00073 }
00074
00075 void modify(const Key& key, const T& obj)
00076 {
00077 if(m_stack.count() == 0)
00078 throw new MYMONEYEXCEPTION("No transaction started to modify element in container");
00079
00080 #if 0
00081
00082 if(key.isEmpty())
00083 throw new MYMONEYEXCEPTION("No key to update object");
00084 #endif
00085
00086 m_stack.push(new MyMoneyMapModify(this, key, obj));
00087 }
00088
00089 void remove(const Key& key)
00090 {
00091 if(m_stack.count() == 0)
00092 throw new MYMONEYEXCEPTION("No transaction started to remove element from container");
00093
00094 #if 0
00095
00096 if(key.isEmpty())
00097 throw new MYMONEYEXCEPTION("No key to remove object");
00098 #endif
00099
00100 m_stack.push(new MyMoneyMapRemove(this, key));
00101 }
00102
00103 MyMoneyMap<Key, T>& operator= (const QMap<Key, T>& m)
00104 {
00105 if(m_stack.count() != 0) {
00106 throw new MYMONEYEXCEPTION("Cannot assign whole container during transaction");
00107 }
00108 QMap<Key, T>::operator=(m);
00109 return *this;
00110 }
00111
00112
00113 inline QValueList<T> values(void) const
00114 {
00115 return QMap<Key,T>::values();
00116 }
00117
00118 inline QValueList<Key> keys(void) const
00119 {
00120 return QMap<Key,T>::keys();
00121 }
00122
00123 const T& operator[] ( const Key& k ) const
00124 { QT_CHECK_INVALID_MAP_ELEMENT; return QMap<Key,T>::operator[](k); }
00125
00126 inline Q_TYPENAME QMap<Key, T>::const_iterator find(const Key& k) const
00127 {
00128 return QMap<Key,T>::find(k);
00129 }
00130
00131 inline Q_TYPENAME QMap<Key, T>::const_iterator begin(void) const
00132 {
00133 return QMap<Key,T>::begin();
00134 }
00135
00136 inline Q_TYPENAME QMap<Key, T>::const_iterator end(void) const
00137 {
00138 return QMap<Key,T>::end();
00139 }
00140
00141 inline bool contains(const Key& k) const
00142 {
00143 return find(k) != end();
00144 }
00145
00146 inline void map(QMap<Key, T>& that) const
00147 {
00148
00149
00150 that = *(dynamic_cast<QMap<Key, T>* >(const_cast<MyMoneyMap<Key, T>* >(this)));
00151 }
00152
00153 inline size_t count(void) const
00154 {
00155 return QMap<Key, T>::count();
00156 }
00157
00158 #if MY_OWN_DEBUG
00159 void dump(void) const
00160 {
00161 printf("Container dump\n");
00162 printf(" items in container = %d\n", count());
00163 printf(" items on stack = %d\n", m_stack.count());
00164
00165 const_iterator it;
00166 for(it = begin(); it != end(); ++it) {
00167 printf(" %s \n", it.key().data());
00168 }
00169 }
00170 #endif
00171
00172 private:
00173 class MyMoneyMapAction
00174 {
00175 public:
00176 MyMoneyMapAction(QMap<Key, T>* container) :
00177 m_container(container) {}
00178
00179 MyMoneyMapAction(QMap<Key, T>* container, const Key& key, const T& obj) :
00180 m_container(container),
00181 m_obj(obj),
00182 m_key(key) {}
00183
00184 virtual ~MyMoneyMapAction() {}
00185 virtual void undo(void) = 0;
00186
00187 protected:
00188 QMap<Key, T>* m_container;
00189 T m_obj;
00190 Key m_key;
00191 };
00192
00193 class MyMoneyMapStart : public MyMoneyMapAction
00194 {
00195 public:
00196 MyMoneyMapStart(QMap<Key, T>* container, unsigned long* id) :
00197 MyMoneyMapAction(container),
00198 m_idPtr(id)
00199 {
00200 if(id != 0)
00201 m_id = *id;
00202 }
00203 virtual ~MyMoneyMapStart() {}
00204 void undo(void)
00205 {
00206 if(m_idPtr != 0)
00207 *m_idPtr = m_id;
00208 }
00209
00210 private:
00211 unsigned long* m_idPtr;
00212 unsigned long m_id;
00213 };
00214
00215 class MyMoneyMapInsert : public MyMoneyMapAction
00216 {
00217 public:
00218 MyMoneyMapInsert(QMap<Key, T>* container, const Key& key, const T& obj) :
00219 MyMoneyMapAction(container, key, obj)
00220 {
00221 (*container)[key] = obj;
00222 }
00223
00224 virtual ~MyMoneyMapInsert() {}
00225 void undo(void)
00226 {
00227
00228
00229 this->m_container->remove(this->m_key);
00230 }
00231 };
00232
00233 class MyMoneyMapRemove : public MyMoneyMapAction
00234 {
00235 public:
00236 MyMoneyMapRemove(QMap<Key, T>* container, const Key& key) :
00237 MyMoneyMapAction(container, key, (*container)[key])
00238 {
00239 container->remove(key);
00240 }
00241
00242 virtual ~MyMoneyMapRemove() {}
00243 void undo(void)
00244 {
00245 (*(this->m_container))[this->m_key] = this->m_obj;
00246 }
00247 };
00248
00249 class MyMoneyMapModify : public MyMoneyMapAction
00250 {
00251 public:
00252 MyMoneyMapModify(QMap<Key, T>* container, const Key& key, const T& obj) :
00253 MyMoneyMapAction(container, key, (*container)[key])
00254 {
00255 (*container)[key] = obj;
00256 }
00257
00258 virtual ~MyMoneyMapModify() {}
00259 void undo(void)
00260 {
00261 (*(this->m_container))[this->m_key] = this->m_obj;
00262 }
00263 };
00264
00265 protected:
00266 QPtrStack<MyMoneyMapAction> m_stack;
00267 };
00268
00269 #if MY_OWN_DEBUG
00270 #include <kmymoney/mymoneyaccount.h>
00271 #include <kmymoney/mymoneytransaction.h>
00272 main()
00273 {
00274 MyMoneyMap<QCString, MyMoneyAccount> container;
00275 MyMoneyMap<QCString, MyMoneyTransaction> ct;
00276
00277 MyMoneyAccount acc;
00278 acc.setName("Test");
00279
00280
00281
00282 QValueList<MyMoneyAccount> list;
00283 list = container.values();
00284
00285 MyMoneyAccount b;
00286 b.setName("Thomas");
00287
00288 try {
00289 container.startTransaction();
00290 container.insert("001", acc);
00291 container.dump();
00292 container.commitTransaction();
00293 acc.setName("123");
00294 container.startTransaction();
00295 container.modify("001", acc);
00296 container.dump();
00297 container.rollbackTransaction();
00298 container.dump();
00299
00300 container.startTransaction();
00301 container.remove(QCString("001"));
00302 container.dump();
00303 container.rollbackTransaction();
00304 container.dump();
00305
00306 b = container["001"];
00307 printf("b.name() = %s\n", b.name().data());
00308
00309 QMap<QCString, MyMoneyAccount>::ConstIterator it;
00310 it = container.find("001");
00311 it = container.begin();
00312
00313 } catch(MyMoneyException *e) {
00314 printf("Caught exception: %s\n", e->what().data());
00315 delete e;
00316 }
00317
00318 QMap<QCString, MyMoneyAccount> map;
00319 map["005"] = b;
00320 container = map;
00321
00322 printf("b.name() = %s\n", container["001"].name().data());
00323 printf("b.name() = %s\n", container["005"].name().data());
00324 }
00325
00326 #endif
00327
00328 #endif