diff --git a/ChangeLog b/ChangeLog
index bbf41af..ff45129 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,4 @@
-v0.2 (28/05/2011)
+v0.2 (04/07/2011)
** User **
Better use of sizers (so better interface!)
@@ -14,10 +14,12 @@ v0.2 (28/05/2011)
Add Real mode
Database is now at ~/.kisscount/kc.bdd
Add Debian's packages !!
- Add Import Panel, OFX and Grisbi imports
+ Add Import Panel, XML, OFX and Grisbi imports
+ Add Export Panel (only XML)
Add update next months
Change charts and real/virtual mode position
Add "non fix" category to statistics (sum of all non fix categories)
+ Auto completion does not require date to be set
** Dev **
Use a factory to create panels (prepare for plug-in)
diff --git a/src/controller/KissCount.cpp b/src/controller/KissCount.cpp
index f75c109..54793d7 100644
--- a/src/controller/KissCount.cpp
+++ b/src/controller/KissCount.cpp
@@ -104,23 +104,27 @@ double KissCount::CalcAccountAmount(const wxString& id, int month, int year, boo
return _db->CalcAccountAmount(id, month, year, had_values);
}
-void KissCount::UpdateOperation(Operation& op)
+void KissCount::UpdateOperation(Operation& op, bool checkTransfert)
{
// Unlink
- op.transfert = wxT("");
- _user->LinkOrUnlinkOperation(op);
+ if (checkTransfert)
+ {
+ op.transfert = wxT("");
+ _user->LinkOrUnlinkOperation(op);
+ }
- _db->UpdateOperation(_user, op);
+ _db->UpdateOperation(_user, op, checkTransfert);
// Link
- _user->LinkOrUnlinkOperation(op);
+ if (checkTransfert)
+ _user->LinkOrUnlinkOperation(op);
}
-wxString KissCount::AddOperation(Operation& op)
+wxString KissCount::AddOperation(Operation& op, bool checkTransfert)
{
- wxString ret = _db->AddOperation(_user, op);
+ wxString ret = _db->AddOperation(_user, op, checkTransfert);
- if (op.transfert.Length())
+ if (checkTransfert && op.transfert.Length())
_user->LinkOrUnlinkOperation(op);
return ret;
@@ -159,9 +163,9 @@ double KissCount::MetaPositiveAmount(const wxString& id)
return _db->MetaPositiveAmount(id);
}
-void KissCount::SetAccountAmount(int month, int year, const wxString& accountId, double amount)
+void KissCount::SetAccountAmount(const wxString& accountId, int month, int year, double amount)
{
- _db->SetAccountAmount(month, year, accountId, amount);
+ _db->SetAccountAmount(accountId, month, year, amount);
}
wxString KissCount::AddAccount(Account& ac)
@@ -173,7 +177,7 @@ wxString KissCount::AddAccount(Account& ac)
curDate.SetToCurrent();
- SetAccountAmount((int)curDate.GetMonth(), curDate.GetYear(), ac.id, 0.0);
+ SetAccountAmount(ac.id, (int)curDate.GetMonth(), curDate.GetYear(), 0.0);
return ac.id;
}
diff --git a/src/controller/KissCount.h b/src/controller/KissCount.h
index 6b03553..a8d0c42 100644
--- a/src/controller/KissCount.h
+++ b/src/controller/KissCount.h
@@ -40,6 +40,10 @@
s.Replace(wxT("\'"), wxT("\\\'"), true); \
}
+#define UNESCAPE_CHARS(s) { \
+ s.Replace(wxT("\\\""), wxT("\""), true); \
+ s.Replace(wxT("\\\'"), wxT("\'"), true); \
+ }
class wxUI;
class Database;
class ImportEngine;
@@ -62,15 +66,15 @@ public:
void LoadYear(int year, bool force=false);
- wxString AddOperation(Operation& op);
- void UpdateOperation(Operation& op);
+ wxString AddOperation(Operation& op, bool checkTransfert=true);
+ void UpdateOperation(Operation& op, bool checkTransfert=true);
void DeleteOperation(Operation& op);
void DeleteOperations(int month, int year);
double MetaAmount(const wxString& id);
double MetaPositiveAmount(const wxString& id);
double GetAccountAmount(const wxString& id, int month, int year);
- void SetAccountAmount(int month, int year, const wxString& accountId, double value);
+ void SetAccountAmount(const wxString& accountId, int month, int year, double value);
double CalcAccountAmount(const wxString& id, int month, int year, bool* had_values);
wxString AddAccount(Account& ac);
diff --git a/src/model/AccountAmount.h b/src/model/AccountAmount.h
new file mode 100644
index 0000000..79bd690
--- /dev/null
+++ b/src/model/AccountAmount.h
@@ -0,0 +1,44 @@
+/*
+ Copyright 2010-2011 Grégory Soutadé
+
+ This file is part of KissCount.
+
+ KissCount 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 3 of the License, or
+ (at your option) any later version.
+
+ KissCount is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with KissCount. If not, see .
+*/
+
+#ifndef ACCOUNTAMOUNT_H
+#define ACCOUNTAMOUNT_H
+
+class AccountAmount {
+public:
+ wxString account;
+ int month;
+ int year;
+ bool operator()(const AccountAmount& x, const AccountAmount& y) const
+ {
+ long x1, y1;
+
+ if (x.account != y.account)
+ {
+ x.account.ToLong(&x1);
+ y.account.ToLong(&y1);
+
+ return x1 < y1;
+ }
+
+ return (x.year < y.year || ((x.year == y.year) && x.month < y.month));
+ }
+};
+
+#endif
diff --git a/src/model/Database.cpp b/src/model/Database.cpp
index 6e0d8e1..9f6ec23 100644
--- a/src/model/Database.cpp
+++ b/src/model/Database.cpp
@@ -91,10 +91,13 @@ void Database::CreateDatabase()
wxString message = _("No database found, would you like to create a new one ?\n\n");
message += _("!! Warning !! If there was a bug, the old database will be suppressed !");
- wxMessageDialog dialog(NULL, message, wxT("KissCount"), wxYES_NO);
+ if (dirname.DirExists())
+ {
+ wxMessageDialog dialog(NULL, message, wxT("KissCount"), wxYES_NO);
- if (dialog.ShowModal() == wxID_NO)
- throw std::string("No database") ;
+ if (dialog.ShowModal() == wxID_NO)
+ throw std::string("No database") ;
+ }
init_script.open(INIT_SCRIPT);
@@ -400,7 +403,7 @@ double Database::GetAccountAmount(const wxString& id, int month, int year)
res = set.GetDouble(wxT("amount"));
else
{
- SetAccountAmount(month, year, id, 0.0);
+ SetAccountAmount(id, month, year, 0.0);
res = 0.0;
}
@@ -550,11 +553,12 @@ void Database::LinkOrUnlinkOperation(User* user, Operation& op)
}
}
-void Database::UpdateOperation(User* user, Operation& op)
+void Database::UpdateOperation(User* user, Operation& op, bool checkTransfert)
{
wxString req;
- LinkOrUnlinkOperation(user, op);
+ if (checkTransfert)
+ LinkOrUnlinkOperation(user, op);
ESCAPE_CHARS(op.description);
@@ -589,10 +593,11 @@ void Database::UpdateOperation(User* user, Operation& op)
EXECUTE_SQL_UPDATE(req, );
- LinkOrUnlinkOperation(user, op);
+ if (checkTransfert)
+ LinkOrUnlinkOperation(user, op);
}
-wxString Database::AddOperation(User* user, Operation& op)
+wxString Database::AddOperation(User* user, Operation& op, bool checkTransfert)
{
wxString req, res;
wxSQLite3ResultSet set;
@@ -631,7 +636,8 @@ wxString Database::AddOperation(User* user, Operation& op)
op.id = res;
- LinkOrUnlinkOperation(user, op);
+ if (checkTransfert)
+ LinkOrUnlinkOperation(user, op);
return res;
}
@@ -783,7 +789,7 @@ double Database::MetaPositiveAmount(const wxString& id)
return res;
}
-void Database::SetAccountAmount(int month, int year, const wxString& accountId, double amount)
+void Database::SetAccountAmount(const wxString& accountId, int month, int year, double amount)
{
wxString req;
req = wxT("UPDATE account_amount SET ") ;
diff --git a/src/model/Database.h b/src/model/Database.h
index 7e7b15c..e741ef1 100644
--- a/src/model/Database.h
+++ b/src/model/Database.h
@@ -104,8 +104,8 @@ public:
User* LoadUser(const wxString& name);
void LoadYear(User* user, int year);
- void UpdateOperation(User* user, Operation& op);
- wxString AddOperation(User* user, Operation& op);
+ void UpdateOperation(User* user, Operation& op, bool checkTransfert=true);
+ wxString AddOperation(User* user, Operation& op, bool checkTransfert=true);
void DeleteOperation(User* user, Operation& op);
void DeleteOperations(User* user, int month, int year);
bool LoadOperation(User* user, const wxString& id);
@@ -113,7 +113,7 @@ public:
double MetaPositiveAmount(const wxString& id);
double GetAccountAmount(const wxString& id, int month, int year);
- void SetAccountAmount(int month, int year, const wxString& accountId, double amount);
+ void SetAccountAmount(const wxString& accountId, int month, int year, double amount);
double CalcAccountAmount(const wxString& id, int month, int year, bool* had_values);
wxString AddAccount(User* user, Account& ac);
diff --git a/src/model/export/ExportEngine.cpp b/src/model/export/ExportEngine.cpp
index d276358..db65e10 100644
--- a/src/model/export/ExportEngine.cpp
+++ b/src/model/export/ExportEngine.cpp
@@ -42,6 +42,10 @@ bool ExportEngine::SaveFile(std::vector* operations)
int i;
wxString account, category;
AccountAmount accountAmount;
+ int minMonth = -1, minYear = -1;
+ unsigned int maxMonth = -1, maxYear = -1;
+ unsigned int month, year;
+ std::map::iterator it;
if (!operations) return NULL;
@@ -54,23 +58,45 @@ bool ExportEngine::SaveFile(std::vector* operations)
account = (*operations)[i].account;
category = (*operations)[i].category;
- accountAmount.account = account;
- accountAmount.month = (*operations)[i].month;
- accountAmount.year = (*operations)[i].year;
+ if (minYear == -1 || (int)(*operations)[i].year < minYear)
+ maxYear = minYear = (*operations)[i].year;
- if (account.Length())
+ if (minMonth == -1 || ((int)(*operations)[i].month < minMonth && (int)(*operations)[i].year == minYear))
+ maxMonth = minMonth = (*operations)[i].month;
+
+ if ((*operations)[i].year > maxYear)
{
- if (!_accounts.count(account))
- _accounts[account]++;
-
- if (!_accountAmounts.count(accountAmount))
- _accountAmounts[accountAmount] = _kiss->GetAccountAmount(accountAmount.account, accountAmount.month, accountAmount.year);
+ maxYear = (*operations)[i].year;
+ maxMonth = (*operations)[i].month;
}
+ if ((*operations)[i].month > maxMonth && (*operations)[i].year == maxYear)
+ maxMonth = (*operations)[i].month;
+
+ if (account.Length() && !_accounts.count(account))
+ _accounts[account]++;
+
if (category.Length() && !_categories.count(category))
_categories[category]++;
}
+ for(it=_accounts.begin(); it!=_accounts.end(); it++)
+ {
+ month = minMonth;
+ for (year = minYear; year <= maxYear; year++)
+ {
+ for (; !(month > maxMonth && year == maxYear) && month < 12; month++)
+ {
+ accountAmount.account = it->first;
+ accountAmount.month = month;
+ accountAmount.year = year;
+
+ _accountAmounts[accountAmount] = _kiss->GetAccountAmount(accountAmount.account, accountAmount.month, accountAmount.year);
+ }
+ month = 0;
+ }
+ }
+
return true;
}
diff --git a/src/model/export/ExportEngine.h b/src/model/export/ExportEngine.h
index 4ecf2f9..50976f9 100644
--- a/src/model/export/ExportEngine.h
+++ b/src/model/export/ExportEngine.h
@@ -22,30 +22,10 @@
#include
#include
+#include
class KissCount;
-class AccountAmount {
-public:
- wxString account;
- int month;
- int year;
- bool operator()(const AccountAmount& x, const AccountAmount& y) const
- {
- long x1, y1;
-
- if (x.account != y.account)
- {
- x.account.ToLong(&x1);
- y.account.ToLong(&y1);
-
- return x1 < y1;
- }
-
- return (x.year < y.year && x.month < y.month);
- }
-};
-
class ExportEngine {
public:
ExportEngine();
diff --git a/src/model/export/XMLExportEngine.cpp b/src/model/export/XMLExportEngine.cpp
index 1cdf6e2..be78faf 100644
--- a/src/model/export/XMLExportEngine.cpp
+++ b/src/model/export/XMLExportEngine.cpp
@@ -48,15 +48,16 @@ bool XMLExportEngine::SaveAccounts()
account = _user->GetAccount(it->first);
ESCAPE_CHARS(account.name);
+ ESCAPE_CHARS(account.number);
xmlTextWriterStartElement(_writer, (const xmlChar*) "account");
xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "id", (const xmlChar*) account.id.utf8_str().data());
xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "name", (const xmlChar*) account.name.utf8_str().data());
xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "number", (const xmlChar*) account.number.utf8_str().data());
- xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "shared", (const xmlChar*) (account.shared ? "1" : "0"));
+ // xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "shared", (const xmlChar*) (account.shared ? "1" : "0"));
xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "blocked", (const xmlChar*) (account.blocked ? "1" : "0"));
- xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "default", (const xmlChar*) (account._default ? "1" : "0"));
- xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "is_owner", (const xmlChar*) (account.is_owner ? "1" : "0"));
+ // xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "default", (const xmlChar*) (account._default ? "1" : "0"));
+ // xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "is_owner", (const xmlChar*) (account.is_owner ? "1" : "0"));
xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "virtual", (const xmlChar*) (account._virtual ? "1" : "0"));
xmlTextWriterEndElement(_writer);
}
@@ -100,11 +101,11 @@ bool XMLExportEngine::SaveCategories()
rgb = category.backcolor.Blue();
rgb |= category.backcolor.Green() << 8;
rgb |= category.backcolor.Red() << 16;
- xmlTextWriterWriteFormatAttribute(_writer, (const xmlChar*) "backcolor", "%08X", rgb);
+ xmlTextWriterWriteFormatAttribute(_writer, (const xmlChar*) "backcolor", "0x%08X", rgb);
rgb = category.forecolor.Blue();
rgb |= category.forecolor.Green() << 8;
rgb |= category.forecolor.Red() << 16;
- xmlTextWriterWriteFormatAttribute(_writer, (const xmlChar*) "forecolor", "%08X", rgb);
+ xmlTextWriterWriteFormatAttribute(_writer, (const xmlChar*) "forecolor", "0x%08X", rgb);
xmlTextWriterWriteAttribute(_writer, (const xmlChar*) "fix_cost", (const xmlChar*) (category.fix_cost ? "1" : "0"));
xmlTextWriterEndElement(_writer);
}
diff --git a/src/model/import/GrisbiImportEngine.cpp b/src/model/import/GrisbiImportEngine.cpp
index d5d0de1..9fb267d 100644
--- a/src/model/import/GrisbiImportEngine.cpp
+++ b/src/model/import/GrisbiImportEngine.cpp
@@ -44,6 +44,9 @@ void GrisbiImportEngine::LoadAccount(GrisbiImportEngine* _this, const char** att
account_number += key;
+ UNESCAPE_CHARS(name);
+ UNESCAPE_CHARS(account_number);
+
for (i=0; i<(int)_this->_user->_accounts.size(); i++)
{
if (_this->_user->_accounts[i].number == account_number)
@@ -56,6 +59,11 @@ void GrisbiImportEngine::LoadAccount(GrisbiImportEngine* _this, const char** att
_this->_accounts[id] = wxT("unknown-") + account_number;
ac.number = account_number;
ac.name = name;
+ ac.shared = false;
+ ac.blocked = false;
+ ac._default = false;
+ ac.is_owner = true;
+ ac._virtual = false;
_this->_unresolvedAccounts.push_back(ac);
}
@@ -74,6 +82,8 @@ void GrisbiImportEngine::LoadCategory(GrisbiImportEngine* _this, const char** at
id = wxString(attrs[i+1], wxConvUTF8);
}
+ UNESCAPE_CHARS(name);
+
for (i=0; i<(int)_this->_user->_categories.size(); i++)
{
if (_this->_user->_categories[i].name == name)
@@ -86,6 +96,10 @@ void GrisbiImportEngine::LoadCategory(GrisbiImportEngine* _this, const char** at
_this->_categories[id] = wxT("unknown-") + name;
cat.id = id;
cat.name = name;
+ cat.parent = wxT("0");
+ cat.backcolor = OWN_GREEN ;
+ cat.forecolor = *wxBLACK;
+ cat.fix_cost = false;
_this->_unresolvedCategories.push_back(cat);
}
@@ -134,6 +148,8 @@ void GrisbiImportEngine::LoadOperation(GrisbiImportEngine* _this, const char** a
op.description = wxString(attrs[i+1], wxConvUTF8);
}
+ UNESCAPE_CHARS(op.description);
+
_this->_operations.push_back(op);
_this->_descriptions[op.id] = op.description;
@@ -193,7 +209,19 @@ GrisbiImportEngine::~GrisbiImportEngine()
bool GrisbiImportEngine::HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss)
{
+ int res = -1;
+
if (!ImportEngine::HandleFile(path, user, db, kiss)) return false;
- return xmlSAXUserParseFile(&_sax, this, path.mb_str()) >= 0;
+ try
+ {
+ res = xmlSAXUserParseFile(&_sax, this, path.mb_str());
+ }
+ catch (const char* s)
+ {
+ std::cout << "GrisbiImportEngine :: " << s << std::endl;
+ res = -1;
+ }
+
+ return res >= 0;
}
diff --git a/src/model/import/GrisbiImportEngine.h b/src/model/import/GrisbiImportEngine.h
index 4d1c75b..ec238ea 100644
--- a/src/model/import/GrisbiImportEngine.h
+++ b/src/model/import/GrisbiImportEngine.h
@@ -30,8 +30,6 @@ public:
~GrisbiImportEngine();
virtual bool HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss);
- /* virtual std::vector ParseFile(); */
- /* virtual std::vector* GetOperations(std::map& accounts); */
private:
xmlSAXHandler _sax;
diff --git a/src/model/import/ImportEngine.cpp b/src/model/import/ImportEngine.cpp
index c68e642..11fc6ca 100644
--- a/src/model/import/ImportEngine.cpp
+++ b/src/model/import/ImportEngine.cpp
@@ -38,6 +38,7 @@ bool ImportEngine::HandleFile(const wxString& path, User* user, Database* db, Ki
_unresolvedAccounts.clear();
_operations.clear();
_descriptions.clear();
+ _accountAmounts.clear();
return path.EndsWith(_shortExt) || path.EndsWith(_shortExt.Upper());
}
@@ -307,3 +308,8 @@ std::vector* ImportEngine::GetOperations(std::map
return &_operations;
}
+
+const std::map& ImportEngine::GetAccountAmounts()
+{
+ return _accountAmounts;
+}
diff --git a/src/model/import/ImportEngine.h b/src/model/import/ImportEngine.h
index b6949d5..9db452e 100644
--- a/src/model/import/ImportEngine.h
+++ b/src/model/import/ImportEngine.h
@@ -22,6 +22,7 @@
#include
#include
+#include
class KissCount;
@@ -52,10 +53,13 @@ public:
// Final Step
virtual std::vector* GetOperations(std::map& accounts, std::map& categories);
+ const std::map& GetAccountAmounts();
+
void MatchPattern(wxString& key, Operation& op);
int UpdatePattern(int pos);
static wxString RemoveUnused(const wxString& s);
+
protected:
Database* _db;
User* _user;
@@ -71,6 +75,7 @@ protected:
std::vector _unresolvedCategories;
std::vector _operations;
std::map _descriptions;
+ std::map _accountAmounts;
void ApplyPattern(ImportPattern& pattern, Operation& op);
wxString FindPattern(wxString& s1, wxString& s2);
diff --git a/src/model/import/OFXImportEngine.cpp b/src/model/import/OFXImportEngine.cpp
index a5039c5..25e6073 100644
--- a/src/model/import/OFXImportEngine.cpp
+++ b/src/model/import/OFXImportEngine.cpp
@@ -30,6 +30,8 @@ int OFXImportEngine::account_cb(const struct OfxAccountData data, void * account
_this->_curAccount = wxT("");
+ UNESCAPE_CHARS(account_number);
+
for (i=0; i<(int)_this->_user->_accounts.size(); i++)
{
if (_this->_user->_accounts[i].number == account_number)
@@ -46,6 +48,11 @@ int OFXImportEngine::account_cb(const struct OfxAccountData data, void * account
{
_this->_curAccount = _this->_accounts[account_number] = wxT("unknown-") + account_number;
ac.number = account_number;
+ ac.shared = false;
+ ac.blocked = false;
+ ac._default = false;
+ ac.is_owner = true;
+ ac._virtual = false;
_this->_unresolvedAccounts.push_back(ac);
}
@@ -94,6 +101,8 @@ int OFXImportEngine::transaction_cb(const struct OfxTransactionData data, void *
op.description += wxString(data.memo, wxConvUTF8);
}
+ UNESCAPE_CHARS(op.description);
+
_this->_operations.push_back(op);
_this->_descriptions[op.id] = op.description;
diff --git a/src/model/import/XMLImportEngine.cpp b/src/model/import/XMLImportEngine.cpp
new file mode 100644
index 0000000..692b587
--- /dev/null
+++ b/src/model/import/XMLImportEngine.cpp
@@ -0,0 +1,294 @@
+/*
+ Copyright 2010-2011 Grégory Soutadé
+
+ This file is part of KissCount.
+
+ KissCount 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 3 of the License, or
+ (at your option) any later version.
+
+ KissCount is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with KissCount. If not, see .
+*/
+
+#include "XMLImportEngine.h"
+
+static XMLImportEngine xmlImportEngine;
+
+void XMLImportEngine::LoadAccount(XMLImportEngine* _this, const char** attrs)
+{
+ int i;
+ wxString account_number, name, id;
+ Account ac;
+
+ for (i=0; attrs[i]; i+=2)
+ {
+ if (!strcmp(attrs[i], "name"))
+ ac.name = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "id"))
+ ac.id = id = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "number"))
+ ac.number = account_number = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "blocked"))
+ ac.blocked = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+
+ else if (!strcmp(attrs[i], "virtual"))
+ ac._virtual = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+ }
+
+ UNESCAPE_CHARS(ac.name);
+ UNESCAPE_CHARS(ac.number);
+
+ ac._default = false;
+ ac.shared = false;
+ ac.is_owner = true;
+
+ if (account_number.Length())
+ {
+ for (i=0; i<(int)_this->_user->_accounts.size(); i++)
+ {
+ if (_this->_user->_accounts[i].number == account_number)
+ {
+ _this->_accounts[id] = _this->_user->_accounts[i].id;
+ return;
+ }
+ }
+ }
+
+ _this->_accounts[id] = wxT("unknown-") + account_number;
+ _this->_unresolvedAccounts.push_back(ac);
+}
+
+void XMLImportEngine::LoadAccountAmount(XMLImportEngine* _this, const char** attrs)
+{
+ AccountAmount accountAmount;
+ int i;
+ long v;
+ double amount;
+
+ for (i=0; attrs[i]; i+=2)
+ {
+ if (!strcmp(attrs[i], "account"))
+ accountAmount.account = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "month"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&v);
+ accountAmount.month = v;
+ }
+
+ else if (!strcmp(attrs[i], "year"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&v);
+ accountAmount.year = v;
+ }
+
+ else if (!strcmp(attrs[i], "amount"))
+ wxString(attrs[i+1], wxConvUTF8).ToDouble(&amount);
+ }
+
+ _this->_accountAmounts[accountAmount] = amount;
+}
+
+void XMLImportEngine::LoadCategory(XMLImportEngine* _this, const char** attrs)
+{
+ wxString name, id;
+ int i;
+ long rgb;
+ Category cat;
+
+ for (i=0; attrs[i]; i+=2)
+ {
+ if (!strcmp(attrs[i], "name"))
+ cat.name = name = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "id"))
+ cat.id = id = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "font"))
+ cat.font = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "backcolor"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&rgb, 16);
+ cat.backcolor = wxColour((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
+ }
+
+ else if (!strcmp(attrs[i], "forecolor"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&rgb, 16);
+ cat.forecolor = wxColour((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
+ }
+
+ else if (!strcmp(attrs[i], "fix_cost"))
+ cat.fix_cost = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+ }
+
+ UNESCAPE_CHARS(cat.name);
+
+ for (i=0; i<(int)_this->_user->_categories.size(); i++)
+ {
+ if (_this->_user->_categories[i].name == name)
+ {
+ _this->_categories[id] = _this->_user->_categories[i].id;
+ return;
+ }
+ }
+
+ _this->_categories[id] = wxT("unknown-") + name;
+ _this->_unresolvedCategories.push_back(cat);
+}
+
+void XMLImportEngine::LoadOperation(XMLImportEngine* _this, const char** attrs)
+{
+ int i;
+ Operation op;
+ long v;
+ double amount;
+ wxString id;
+
+ for (i=0; attrs[i]; i+=2)
+ {
+ if (!strcmp(attrs[i], "id"))
+ op.id = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "parent"))
+ op.parent = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "day"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&v);
+ op.day = v;
+ }
+
+ else if (!strcmp(attrs[i], "month"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&v);
+ op.month = v;
+ }
+
+ else if (!strcmp(attrs[i], "year"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToLong(&v);
+ op.year = v;
+ }
+
+ else if (!strcmp(attrs[i], "amount"))
+ {
+ wxString(attrs[i+1], wxConvUTF8).ToDouble(&amount);
+ op.amount = amount;
+ }
+
+ else if (!strcmp(attrs[i], "description"))
+ op.description = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "category"))
+ op.category = _this->_categories[wxString(attrs[i+1], wxConvUTF8)];
+
+ else if (!strcmp(attrs[i], "fix_cost"))
+ op.fix_cost = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+
+ else if (!strcmp(attrs[i], "account"))
+ op.account = _this->_accounts[wxString(attrs[i+1], wxConvUTF8)];
+
+ else if (!strcmp(attrs[i], "checked"))
+ op.checked = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+
+ else if (!strcmp(attrs[i], "transfert"))
+ op.transfert = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "formula"))
+ op.formula = wxString(attrs[i+1], wxConvUTF8);
+
+ else if (!strcmp(attrs[i], "meta"))
+ op.meta = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+
+ else if (!strcmp(attrs[i], "virtual"))
+ op._virtual = (wxString(attrs[i+1], wxConvUTF8) == wxT("1"));
+ }
+
+ UNESCAPE_CHARS(op.description);
+
+ _this->_operations.push_back(op);
+ _this->_descriptions[op.id] = op.description;
+
+ _this->MatchPattern(op.description, op);
+}
+
+void XMLImportEngine::XmlStartElement(void* user_data, const xmlChar* name_, const xmlChar** attrs_)
+{
+ XMLImportEngine* _this = (XMLImportEngine*) user_data;
+ int i;
+ const char** attrs = (const char**) attrs_;
+ const char* name = (const char*) name_;
+
+ // if (!first && strcmp(name, "Xml"))
+ // {
+ // throw "Invalid file !";
+ // }
+ // else
+ // first = 1;
+
+ if (!strcmp(name, "kisscount"))
+ {
+ for (i=0; attrs[i]; i+=2)
+ {
+ if (!strcmp(attrs[i], "version") && strcmp(attrs[i+1], "1"))
+ throw "Unsupported version !";
+ }
+ }
+
+ else if (!strcmp(name, "account"))
+ LoadAccount(_this, attrs);
+
+ else if (!strcmp(name, "account_amount"))
+ LoadAccountAmount(_this, attrs);
+
+ else if (!strcmp(name, "category"))
+ LoadCategory(_this, attrs);
+
+ else if (!strcmp(name, "operation"))
+ LoadOperation(_this, attrs);
+}
+
+XMLImportEngine::XMLImportEngine()
+{
+ KissCount::RegisterImportEngine(this);
+
+ _shortExt = wxT("xml");
+ _longExt = _("KissCount xml files (*.xml)|*.xml");
+
+ _sax.startElement = XmlStartElement ;
+}
+
+XMLImportEngine::~XMLImportEngine()
+{
+}
+
+bool XMLImportEngine::HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss)
+{
+ int res = -1 ;
+
+ if (!ImportEngine::HandleFile(path, user, db, kiss)) return false;
+
+ try
+ {
+ res = xmlSAXUserParseFile(&_sax, this, path.mb_str()) >= 0;
+ }
+ catch (const char* s)
+ {
+ std::cout << "XMLImportEngine :: " << s << std::endl;
+ res = -1;
+ }
+
+ return res >= 0;
+}
diff --git a/src/model/import/XMLImportEngine.h b/src/model/import/XMLImportEngine.h
new file mode 100644
index 0000000..2ab355b
--- /dev/null
+++ b/src/model/import/XMLImportEngine.h
@@ -0,0 +1,44 @@
+/*
+ Copyright 2010-2011 Grégory Soutadé
+
+ This file is part of KissCount.
+
+ KissCount 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 3 of the License, or
+ (at your option) any later version.
+
+ KissCount is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with KissCount. If not, see .
+*/
+
+#ifndef XMLIMPORTENGINE_H
+#define XMLIMPORTENGINE_H
+
+#include
+
+#include "ImportEngine.h"
+
+class XMLImportEngine : public ImportEngine {
+public:
+ XMLImportEngine();
+ ~XMLImportEngine();
+
+ virtual bool HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss);
+
+private:
+ xmlSAXHandler _sax;
+
+ static void XmlStartElement(void* user_data, const xmlChar* name_, const xmlChar** attrs_);
+ static void LoadAccount(XMLImportEngine* _this, const char** attrs);
+ static void LoadAccountAmount(XMLImportEngine* _this, const char** attrs);
+ static void LoadCategory(XMLImportEngine* _this, const char** attrs);
+ static void LoadOperation(XMLImportEngine* _this, const char** attrs);
+};
+
+#endif
diff --git a/src/view/AccountPanel.cpp b/src/view/AccountPanel.cpp
index e86beda..25c216a 100644
--- a/src/view/AccountPanel.cpp
+++ b/src/view/AccountPanel.cpp
@@ -715,7 +715,7 @@ void AccountPanel::OnAccountModified(wxGridEvent& event)
_accountsGrid->GetCellValue(row, event.GetCol()).ToDouble(&amount);
- _kiss->SetAccountAmount(_curMonth, _curYear, id, amount);
+ _kiss->SetAccountAmount(id, _curMonth, _curYear, amount);
_accountsInitValues[id] = amount;
UpdateStats();
@@ -1082,7 +1082,7 @@ void AccountPanel::OnUpdateNextMonths(wxCommandEvent& event)
if ((cur_amounts[i] - amount) != deltas[i]) continue;
cur_amounts[i] = amount + deltas[i];
- _kiss->SetAccountAmount(last_month, last_year, user->_accounts[i].id, cur_amounts[i]);
+ _kiss->SetAccountAmount(user->_accounts[i].id, last_month, last_year, cur_amounts[i]);
cur_amounts[i] += _kiss->CalcAccountAmount(user->_accounts[i].id, last_month, last_year, &had_values);
account_updated++;
diff --git a/src/view/ImportPanel.cpp b/src/view/ImportPanel.cpp
index 9b4b9e0..92d246c 100644
--- a/src/view/ImportPanel.cpp
+++ b/src/view/ImportPanel.cpp
@@ -150,8 +150,6 @@ void ImportPanel::OnFileEnter(wxCommandEvent& WXUNUSED(event))
void ImportPanel::ProcessFile()
{
- std::vector accounts;
- std::vector categories;
User* user = _kiss->GetUser();
int i;
wxGridCellChoiceEditor* accountEditor;
@@ -179,9 +177,9 @@ void ImportPanel::ProcessFile()
return ;
}
- _importEngine->ParseFile(accounts, categories);
+ _importEngine->ParseFile(_unresolvedAccounts, _unresolvedCategories);
- if (accounts.size())
+ if (_unresolvedAccounts.size())
{
int nb_accounts = user->GetAccountsNumber();
userAccounts = new wxString[nb_accounts+1];
@@ -195,13 +193,13 @@ void ImportPanel::ProcessFile()
_buttonLoadOperations->Enable();
- _accountsGrid->AppendRows(accounts.size());
+ _accountsGrid->AppendRows(_unresolvedAccounts.size());
- for (i=0; i<(int)accounts.size(); i++)
+ for (i=0; i<(int)_unresolvedAccounts.size(); i++)
{
- _accountsGrid->SetCellValue(i, 0, accounts[i].number);
+ _accountsGrid->SetCellValue(i, 0, _unresolvedAccounts[i].number);
_accountsGrid->SetReadOnly(i, 0);
- _accountsGrid->SetCellValue(i, 1, accounts[i].name);
+ _accountsGrid->SetCellValue(i, 1, _unresolvedAccounts[i].name);
_accountsGrid->SetCellValue(i, 2, userAccounts[0]);
_accountsGrid->SetCellEditor(i, 2, accountEditor);
@@ -211,7 +209,7 @@ void ImportPanel::ProcessFile()
_accountsGrid->Layout();
}
- if (categories.size())
+ if (_unresolvedCategories.size())
{
int nb_categories = user->GetCategoriesNumber();
userCategories = new wxString[nb_categories+1];
@@ -225,11 +223,11 @@ void ImportPanel::ProcessFile()
_buttonLoadOperations->Enable();
- _categoriesGrid->AppendRows(categories.size());
+ _categoriesGrid->AppendRows(_unresolvedCategories.size());
- for (i=0; i<(int)categories.size(); i++)
+ for (i=0; i<(int)_unresolvedCategories.size(); i++)
{
- _categoriesGrid->SetCellValue(i, 0, categories[i].name);
+ _categoriesGrid->SetCellValue(i, 0, _unresolvedCategories[i].name);
_categoriesGrid->SetReadOnly(i, 0);
_categoriesGrid->SetCellValue(i, 2, userCategories[0]);
@@ -240,7 +238,7 @@ void ImportPanel::ProcessFile()
_categoriesGrid->Layout();
}
- if (!accounts.size() && !categories.size())
+ if (!_unresolvedAccounts.size() && !_unresolvedCategories.size())
{
OnLoadOperations(event);
}
@@ -249,19 +247,20 @@ void ImportPanel::ProcessFile()
void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
{
- std::map resolvedAccounts;
- std::map resolvedCategories;
int i, nbAccounts=0, nbCategories=0;
User* user = _kiss->GetUser();
Account account;
Category category;
+ std::map accounts;
+ std::map categories;
+ wxString oldid;
for(i=0; i<_accountsGrid->GetNumberRows(); i++)
{
if (_accountsGrid->GetCellValue(i, 2) == _("Create one"))
nbAccounts++;
else
- resolvedAccounts[_accountsGrid->GetCellValue(i, 0)] =
+ accounts[_accountsGrid->GetCellValue(i, 0)] =
user->GetAccountId(_accountsGrid->GetCellValue(i, 1));
}
@@ -270,7 +269,7 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
if (_categoriesGrid->GetCellValue(i, 2) == _("Create one"))
nbCategories++;
else
- resolvedCategories[_categoriesGrid->GetCellValue(i, 0)] =
+ categories[_categoriesGrid->GetCellValue(i, 0)] =
user->GetAccountId(_categoriesGrid->GetCellValue(i, 1));
}
@@ -297,18 +296,15 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
{
if (_accountsGrid->GetCellValue(i, 2) == _("Create one"))
{
+ account = _unresolvedAccounts[i] ;
if (_accountsGrid->GetCellValue(i, 1).Length())
account.name = _accountsGrid->GetCellValue(i, 1);
else
account.name = _accountsGrid->GetCellValue(i, 0);
account.number = _accountsGrid->GetCellValue(i, 0);
- account.shared = false;
- account.blocked = false;
- account._default = false;
- account.is_owner = true;
- account._virtual = false;
- resolvedAccounts[_accountsGrid->GetCellValue(i, 0)] = _kiss->AddAccount(account);
+ oldid = account.id;
+ _resolvedAccounts[oldid] = accounts[_accountsGrid->GetCellValue(i, 0)] = _kiss->AddAccount(account);
}
}
@@ -318,16 +314,14 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
{
if (_categoriesGrid->GetCellValue(i, 2) == _("Create one"))
{
+ category = _unresolvedCategories[i] ;
if (_categoriesGrid->GetCellValue(i, 1).Length())
category.name = _categoriesGrid->GetCellValue(i, 1);
else
category.name = _categoriesGrid->GetCellValue(i, 0);
- category.parent = wxT("0");
- category.backcolor = OWN_GREEN ;
- category.forecolor = *wxBLACK;
- category.fix_cost = false;
-
- resolvedCategories[_categoriesGrid->GetCellValue(i, 0)] = category.id = _kiss->AddCategory(category);
+
+ oldid = category.id;
+ _resolvedCategories[oldid] = categories[_categoriesGrid->GetCellValue(i, 0)] = category.id = _kiss->AddCategory(category);
}
}
@@ -336,7 +330,7 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
_wxUI->NeedReload();
}
- _operations = _importEngine->GetOperations(resolvedAccounts, resolvedCategories);
+ _operations = _importEngine->GetOperations(accounts, categories);
if (_operations->size())
{
@@ -361,6 +355,12 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
void ImportPanel::OnIntegrate(wxCommandEvent& WXUNUSED(event))
{
int i;
+ std::map mapid;
+ wxString oldid, account;
+ bool update;
+ std::map accountAmounts;
+ std::map::iterator it;
+ double amount;
if (!_operations->size()) return;
@@ -371,9 +371,48 @@ void ImportPanel::OnIntegrate(wxCommandEvent& WXUNUSED(event))
_buttonIntegrate->Disable();
for(i=0; i<(int)_operations->size(); i++)
- _kiss->AddOperation((*_operations)[i]);
+ {
+ oldid = (*_operations)[i].id;
+ _kiss->AddOperation((*_operations)[i], false);
+ mapid[oldid] = (*_operations)[i].id;
+ }
- // if (_checkSaveImportPatterns->IsChecked())
+ for(i=0; i<(int)_operations->size(); i++)
+ {
+ update = false;
+
+ if ((*_operations)[i].parent.Length())
+ {
+ (*_operations)[i].parent = mapid[(*_operations)[i].parent];
+ update = true;
+ }
+
+ if ((*_operations)[i].transfert.Length())
+ {
+ (*_operations)[i].transfert = mapid[(*_operations)[i].transfert];
+ update = true;
+ }
+
+ if (update)
+ _kiss->UpdateOperation((*_operations)[i], false);
+ }
+
+ accountAmounts = _importEngine->GetAccountAmounts();
+
+ for(it=accountAmounts.begin(); it!=accountAmounts.end(); it++)
+ {
+ account = it->first.account;
+
+ if (_resolvedAccounts.count(account))
+ account = _resolvedAccounts[account];
+
+ amount = _kiss->GetAccountAmount(account, it->first.month, it->first.year);
+
+ if (!amount)
+ _kiss->SetAccountAmount(account, it->first.month, it->first.year, it->second);
+ }
+
+ if (_checkSaveImportPatterns->IsChecked())
_kiss->UpdateImportPattern();
_operations->clear();
diff --git a/src/view/ImportPanel.h b/src/view/ImportPanel.h
index 89b460a..8ef365c 100644
--- a/src/view/ImportPanel.h
+++ b/src/view/ImportPanel.h
@@ -61,6 +61,11 @@ private:
wxCheckBox *_checkSaveImportPatterns;
std::vector* _operations;
+ std::vector _unresolvedAccounts;
+ std::vector _unresolvedCategories;
+ std::map _resolvedAccounts;
+ std::map _resolvedCategories;
+
void ProcessFile();
DECLARE_EVENT_TABLE();
diff --git a/src/view/SearchBanner.cpp b/src/view/SearchBanner.cpp
index 3ffd8d9..4ee0d91 100644
--- a/src/view/SearchBanner.cpp
+++ b/src/view/SearchBanner.cpp
@@ -26,11 +26,6 @@ EVT_CALENDAR_SEL_CHANGED(CALENDAR_TO_ID, SearchBanner::OnCalendarToChange)
EVT_TEXT_ENTER(DESCRIPTION_ID, SearchBanner::OnEnter)
END_EVENT_TABLE()
-#define UNESCAPE_CHARS(s) { \
- s.Replace(wxT("\\\""), wxT("\""), true); \
- s.Replace(wxT("\\\'"), wxT("\'"), true); \
- }
-
SearchBanner::SearchBanner(KissCount* kiss, wxPanel *parent, void* caller, OnButtonEnter enterCallback) : wxPanel(parent), _kiss(kiss), _caller(caller), _enterCallback(enterCallback), _operations(NULL)
{
DEFAULT_FONT(font);
@@ -38,7 +33,6 @@ SearchBanner::SearchBanner(KissCount* kiss, wxPanel *parent, void* caller, OnBut
std::vector::iterator accountIt;
std::vector::iterator categoryIt;
wxDateTime firstOfMonth;
- wxRect rect = wxDisplay().GetGeometry();
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
diff --git a/src/view/grid/GridAccount.cpp b/src/view/grid/GridAccount.cpp
index 1f52762..a07d7d4 100644
--- a/src/view/grid/GridAccount.cpp
+++ b/src/view/grid/GridAccount.cpp
@@ -30,11 +30,6 @@
SetCellFont(row, i, font); \
}
-#define UNESCAPE_CHARS(s) { \
- s.Replace(wxT("\\\""), wxT("\""), true); \
- s.Replace(wxT("\\\'"), wxT("\'"), true); \
- }
-
BEGIN_EVENT_TABLE(GridAccount, wxGrid)
EVT_GRID_CELL_LEFT_CLICK(GridAccount::OnCellLeftClick )
END_EVENT_TABLE()
@@ -665,7 +660,7 @@ void GridAccount::OnOperationModified(wxGridEvent& event)
int op_complete = 6, i, last_day;
wxString value ;
wxDateTime date;
- bool need_insertion = false, fix_op=false;
+ bool need_insertion = false;
static bool inModification = false ;
wxColour color ;
unsigned char r, g, b;
@@ -946,8 +941,6 @@ void GridAccount::OnOperationModified(wxGridEvent& event)
UpdateOperation(new_op);
(_displayedOperations)[row] = new_op;
}
-
- fix_op = true;
}
// Add a fixCost
else if (row == _fixCosts)
@@ -957,7 +950,6 @@ void GridAccount::OnOperationModified(wxGridEvent& event)
return ;
}
need_insertion = true;
- fix_op = true;
new_op.fix_cost = true;
new_op.meta = false;
new_op._virtual = false;
@@ -1058,7 +1050,6 @@ void GridAccount::OnOperationModified(wxGridEvent& event)
return ;
}
need_insertion = true;
- fix_op = false;
new_op.fix_cost = false;
new_op.meta = false;
new_op._virtual = false;