Functionnal version of ImportPanel

This commit is contained in:
Grégory Soutadé 2011-03-23 20:35:29 +01:00
parent 6da33cbe35
commit 35f660b234
18 changed files with 225 additions and 48 deletions

View File

@ -1,4 +1,4 @@
v0.2 (06/03/2011)
v0.2 (23/03/2011)
** User **
Better use of sizers (so better interface!)
@ -14,6 +14,7 @@ v0.2 (06/03/2011)
Add Real mode
Database is now at ~/.kisscount/kc.bdd
Add Debian's packages !!
Add Import Panel and OFX imports
** Dev **
Use a factory to create panels (prepare for plug-in)
@ -22,6 +23,7 @@ v0.2 (06/03/2011)
New database version (2) :
fix_cost for categories
virtual field for account and operation
import_panel
Database checking & upgrading
** Bugs **

View File

@ -7,8 +7,9 @@ CXXFLAGS+=`wx-config --cxxflags` -Wall -Isrc -ggdb
CXXFLAGS+=-I./lib/wxsqlite3-1.9.9/include
CXXFLAGS+=-I./lib/freechart/include
CXXFLAGS+=-Wl,--rpath,"$(LIB_DIR)"
CXXFLAGS+=-DRESSOURCES_ROOT="\"$(SHARE_DIR)\""
#CXXFLAGS+=-DRESSOURCES_ROOT="\"./ressources/\""
#CXXFLAGS+=-DRESSOURCES_ROOT="\"$(SHARE_DIR)\""
# For developpers
CXXFLAGS+=-DRESSOURCES_ROOT="\"./ressources/\""
LDFLAGS+=`wx-config --libs`
LDFLAGS+=-lofx

View File

@ -1 +1,2 @@
http://www.iconarchive.com/category/application-icons.html
http://www.webidev.com/fr/WebiInscrit

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -6,4 +6,5 @@ CREATE TABLE account_amount(id INTEGER PRIMARY KEY, account REFERENCES account(i
CREATE TABLE operation(id INTEGER PRIMARY KEY, parent REFERENCES operation(id), user REFERENCES user(id), account REFERENCES account(id), year INTEGER, month INTEGER, day INTEGER, amount FLOAT, description VARCHAR(255), category REFERENCES category(id), fix_cost CHAR(1), checked CHAR(1), formula VARCHAR(255), transfert REFERENCES operation(id), meta CHAR(1), virtual CHAR(1));
CREATE TABLE category(id INTEGER PRIMARY KEY, user REFERENCES user(id), parent REFERENCES category(id), name VARCHAR(255), backcolor VARCHAR(10), forecolor VARCHAR(10), font VARCHAR(255), fix_cost CHAR(1));
CREATE TABLE preference(id INTEGER PRIMARY KEY, user REFERENCES user(id), name VARCHAR(255), value VARCHAR(255));
INSERT INTO kisscount ("db_version") VALUES ("2");
CREATE TABLE import_pattern(id INTEGER PRIMARY KEY, user REFERENCES user(id), description VARCHAR(255), pattern VARCHAR(255), account REFERENCES account(id), category REFERENCES category(id));
INSERT INTO kisscount ("db_version") VALUES ("2");

View File

@ -607,3 +607,8 @@ ImportEngine* KissCount::GetImportEngine(wxString path)
return NULL;
}
void KissCount::UpdateImportPattern()
{
_db->UpdateImportPattern(_user);
}

View File

@ -111,6 +111,7 @@ public:
wxString GetImportEngineExtensions();
ImportEngine* GetImportEngine(wxString path);
void UpdateImportPattern();
private:
wxUI* _wxUI;
Database* _db;

View File

@ -209,6 +209,7 @@ User* Database::LoadUser(const wxString& name)
User* user;
Account account;
Category category;
ImportPattern importPattern;
std::vector<Account>::iterator it;
@ -314,6 +315,20 @@ User* Database::LoadUser(const wxString& name)
set.Finalize();
req = wxT("SELECT * FROM import_pattern WHERE user='") + user->_id + wxT("'");
EXECUTE_SQL_QUERY_WITH_CODE(req, set, NULL, {delete user;}, {delete user;});
while (set.NextRow())
{
importPattern.pattern = set.GetAsString(wxT("pattern"));
importPattern.account = set.GetAsString(wxT("account"));
importPattern.category = set.GetAsString(wxT("category"));
user->_importPatterns[set.GetAsString(wxT("description"))] = importPattern;
}
set.Finalize();
return user;
}
@ -1725,3 +1740,45 @@ wxString Database::getSharedAccountOwner(const wxString& account)
return set2.GetAsString(wxT("name"));
}
void Database::UpdateImportPattern(User* user)
{
std::map<wxString, ImportPattern>::iterator it;
wxString req, key;
for (it = user->_importPatterns.begin();
it != user->_importPatterns.end();
it++)
{
if (it->second.pattern == NULL_IMPORT_PATTERN) continue;
key = ImportEngine::RemoveUnused(it->first);
req = wxT("UPDATE import_pattern SET ") ;
req += wxT("pattern='") + it->second.pattern + wxT("'");
req += wxT(", account='") + it->second.account + wxT("'");
req += wxT(", category='") + it->second.category + wxT("'");
req += wxT(" WHERE description='") + key + wxT("'");
try
{
if (!_db.ExecuteUpdate(req))
{
req = wxT("INSERT INTO import_pattern ('user', 'description', 'pattern', 'account', 'category') VALUES ('") ;
req += user->_id + wxT("'");
req += wxT(" ,'") + key + wxT("'");
req += wxT(" ,'") + it->second.pattern + wxT("'");
req += wxT(" ,'") + it->second.account + wxT("'");
req += wxT(" ,'") + it->second.category + wxT("'");
req += wxT(")");
EXECUTE_SQL_UPDATE(req, );
}
}
catch (wxSQLite3Exception e)
{
std::cerr << req.mb_str() << "\n" ;
std::cerr << e.GetMessage().mb_str() << "\n" ;
return ;
}
}
}

View File

@ -164,6 +164,8 @@ public:
std::map<wxString, double>* GetNotChecked(User* user, int month, int year);
std::map<wxString, double>* GetVirtualAmount(User* user, int month, int year);
void UpdateImportPattern(User* user);
/* Database Update */
void CheckDatabaseVersion();

View File

@ -64,6 +64,11 @@ static void Version_1_to_2(wxSQLite3Database& _db)
req = wxT("UPDATE operation SET virtual='0'");
UPDATE_TABLE("1", "2", "7");
/* Import Pattern */
req = wxT("CREATE TABLE import_pattern(id INTEGER PRIMARY KEY, user REFERENCES user(id), description VARCHAR(255), pattern VARCHAR(255), account REFERENCES account(id), category REFERENCES category(id))");
UPDATE_TABLE("1", "2", "8");
}
static update_func updates[] = {

View File

@ -73,6 +73,7 @@ public:
void UnGroup(const Operation& op);
void ResolveGroups(int year);
void UpdateImportPattern(User* user);
private:
Database* _db;
};

View File

@ -83,7 +83,7 @@ std::vector<wxString> ExplodeString(wxString& s)
- tail spaces
- every word starting by a number
*/
wxString ImportEngine::RemoveUnused(wxString& s)
wxString ImportEngine::RemoveUnused(const wxString& s)
{
wxString tmp = s, tmp2;
wxString res;
@ -124,9 +124,16 @@ wxString ImportEngine::FindPattern(wxString& orig, wxString& dest)
{
wxString pattern, cur_pat;
int i, a;
std::vector<wxString> tok1 = ExplodeString(orig);
std::vector<wxString> tok2 = ExplodeString(dest);
int size1 = tok1.size(), size2 = tok2.size();
std::vector<wxString> tok1;
std::vector<wxString> tok2;
int size1, size2;
if (orig == dest) return NULL_IMPORT_PATTERN;
tok1 = ExplodeString(orig);
tok2 = ExplodeString(dest);
size1 = tok1.size();
size2 = tok2.size();
for(i=0; i<size2; i++)
{
@ -171,11 +178,20 @@ wxString ImportEngine::FindPattern(wxString& orig, wxString& dest)
void ImportEngine::ApplyPattern(ImportPattern& pattern, Operation& op)
{
std::vector<wxString> tok1 = ExplodeString(pattern.filter);
std::vector<wxString> tok2 = ExplodeString(op.description);
int size1 = tok1.size(), i;
std::vector<wxString> tok1;
std::vector<wxString> tok2;
int size1, i;
long pos;
op.account = pattern.account;
op.category = pattern.category;
if (pattern.pattern == NULL_IMPORT_PATTERN) return;
tok1 = ExplodeString(pattern.pattern);
tok2 = ExplodeString(op.description);
size1 = tok1.size();
op.description = wxT("");
for(i=0; i<size1; i++)
@ -203,8 +219,6 @@ void ImportEngine::ApplyPattern(ImportPattern& pattern, Operation& op)
}
op.description.Trim();
op.account = pattern.account;
op.category = pattern.category;
}
int ImportEngine::UpdatePattern(int pos)
@ -222,7 +236,7 @@ int ImportEngine::UpdatePattern(int pos)
key1 = RemoveUnused(_descriptions[op.id]);
pattern.filter = FindPattern(_descriptions[op.id], op.description);
pattern.pattern = FindPattern(_descriptions[op.id], op.description);
pattern.account = op.account;
pattern.category = op.category;
@ -253,13 +267,13 @@ void ImportEngine::MatchPattern(wxString& originalKey, Operation& op)
if (!_user->_importPatterns.count(key1))
{
pattern.filter = FindPattern(originalKey, op.description);
pattern.pattern = FindPattern(originalKey, op.description);
pattern.account = op.account;
pattern.category = op.category;
_user->_importPatterns[key1] = pattern;
// std::cout << "New pattern " << key1.mb_str() << "\t" << pattern.filter.mb_str() << std::endl;
// std::cout << "New pattern " << key1.mb_str() << "\t" << pattern.pattern.mb_str() << std::endl;
}
else
{
@ -267,3 +281,26 @@ void ImportEngine::MatchPattern(wxString& originalKey, Operation& op)
ApplyPattern(_user->_importPatterns[key1], op);
}
}
std::vector<wxString> ImportEngine::ParseFile()
{
return _unresolvedAccounts;
}
std::vector<Operation>* ImportEngine::GetOperations(std::map<wxString, wxString>& accounts)
{
int i;
for(i=0; i<(int)_operations.size(); i++)
{
if (_operations[i].account.StartsWith(wxT("unknown-")))
_operations[i].account = accounts[_operations[i].account.Mid(8)];
}
if (_kiss->GetOperationOrder() == wxT("ASC"))
std::sort(_operations.begin(), _operations.end(), sortOperations);
else
std::sort(_operations.begin(), _operations.end(), reverseSortOperations);
return &_operations;
}

View File

@ -27,11 +27,13 @@ class KissCount;
class ImportPattern {
public:
wxString filter;
wxString pattern;
wxString account;
wxString category;
} ;
#define NULL_IMPORT_PATTERN wxT("(nil)")
class ImportEngine {
public:
ImportEngine();
@ -42,17 +44,18 @@ public:
virtual wxString GetFileExt();
// Handle the file
virtual bool HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss);
virtual bool HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss)=0;
// Parse the file and return accounts that doesn't match
virtual std::vector<wxString> ParseFile()=0;
virtual std::vector<wxString> ParseFile();
// Final Step
virtual std::vector<Operation>* GetOperations(std::map<wxString, wxString>& accounts)=0;
virtual std::vector<Operation>* GetOperations(std::map<wxString, wxString>& accounts);
void MatchPattern(wxString& key, Operation& op);
int UpdatePattern(int pos);
static wxString RemoveUnused(const wxString& s);
protected:
Database* _db;
User* _user;
@ -67,7 +70,6 @@ protected:
std::vector<Operation> _operations;
std::map<wxString, wxString> _descriptions;
wxString RemoveUnused(wxString& s);
void ApplyPattern(ImportPattern& pattern, Operation& op);
wxString FindPattern(wxString& s1, wxString& s2);
};

View File

@ -43,7 +43,7 @@ int OFXImportEngine::account_cb(const struct OfxAccountData data, void * account
if (!_this->_curAccount.Len())
{
_this->_accounts[account_number] = wxT("unknown-") + account_number;
_this->_curAccount = _this->_accounts[account_number] = wxT("unknown-") + account_number;
_this->_unresolvedAccounts.push_back(account_number);
}
@ -136,18 +136,3 @@ bool OFXImportEngine::HandleFile(const wxString& path, User* user, Database* db,
return !libofx_proc_file(_ctx, path.mb_str(), AUTODETECT);
}
std::vector<wxString> OFXImportEngine::ParseFile()
{
return _unresolvedAccounts;
}
std::vector<Operation>* OFXImportEngine::GetOperations(std::map<wxString, wxString>& accounts)
{
if (_kiss->GetOperationOrder() == wxT("ASC"))
std::sort(_operations.begin(), _operations.end(), sortOperations);
else
std::sort(_operations.begin(), _operations.end(), reverseSortOperations);
return &_operations;
}

View File

@ -29,8 +29,8 @@ public:
~OFXImportEngine();
virtual bool HandleFile(const wxString& path, User* user, Database* db, KissCount* kiss);
virtual std::vector<wxString> ParseFile();
virtual std::vector<Operation>* GetOperations(std::map<wxString, wxString>& accounts);
/* virtual std::vector<wxString> ParseFile(); */
/* virtual std::vector<Operation>* GetOperations(std::map<wxString, wxString>& accounts); */
private:
LibofxContextPtr _ctx;

View File

@ -19,11 +19,12 @@
#include "ImportPanel.h"
enum {OPEN_FILE_ID=1, BUTTON_OPEN_ID, NAME_ID, BUTTON_LOAD_ID, BUTTON_INTEGRATE_ID, OPS_GRID_ID};
enum {OPEN_FILE_ID=1, BUTTON_OPEN_ID, NAME_ID, BUTTON_LOAD_ID, BUTTON_INTEGRATE_ID, CHECK_SAVE_ID, OPS_GRID_ID};
BEGIN_EVENT_TABLE(ImportPanel, wxPanel)
EVT_GRID_CMD_CELL_CHANGE(OPS_GRID_ID, ImportPanel::OnOperationModified)
EVT_BUTTON(BUTTON_OPEN_ID, ImportPanel::OnFile)
EVT_BUTTON(BUTTON_INTEGRATE_ID, ImportPanel::OnIntegrate)
EVT_TEXT_ENTER(OPEN_FILE_ID, ImportPanel::OnFileEnter)
EVT_BUTTON(BUTTON_LOAD_ID, ImportPanel::OnLoadOperations)
EVT_SHOW(ImportPanel::OnShow)
@ -33,7 +34,7 @@ ImportPanel::ImportPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent
{
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL);
_hbox = new wxBoxSizer(wxHORIZONTAL);
wxButton* buttonOpen;
wxRect rect = wxDisplay().GetGeometry();
int w, h;
@ -54,10 +55,13 @@ ImportPanel::ImportPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent
_buttonIntegrate = new wxButton(this, BUTTON_INTEGRATE_ID, wxT("Integrate operations"));
_buttonIntegrate->Disable();
_checkSaveImportPatterns = new wxCheckBox(this, CHECK_SAVE_ID, wxT("Save import patterns"));
hbox->Add(_fileTxt, 0, wxGROW|wxALL, 5);
hbox->Add(buttonOpen, 0, wxALL, 5);
hbox->Add(_buttonLoadOperations, 0, wxALL, 5);
hbox->Add(_buttonIntegrate, 0, wxALL, 5);
hbox->Add(_checkSaveImportPatterns, 0, wxALL, 5);
vbox->Add(hbox, 0);
@ -73,10 +77,10 @@ ImportPanel::ImportPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent
_operationsGrid = new GridAccount(kiss, this, OPS_GRID_ID, false, false, false);
hbox2->Add(staticBoxSizer, 0, wxGROW|wxALL, 15);
hbox2->Add(_operationsGrid, 0, wxGROW|wxALL, 15);
_hbox->Add(staticBoxSizer, 0, wxGROW|wxALL, 15);
_hbox->Add(_operationsGrid, 0, wxGROW|wxALL, 15);
vbox->Add(hbox2, wxGROW);
vbox->Add(_hbox, wxGROW);
Fit();
@ -93,7 +97,7 @@ KissPanel* ImportPanel::CreatePanel()
wxBitmapButton* ImportPanel::GetButton(int id)
{
if (!_KissButton)
_KissButton = new wxBitmapButton(_wxUI, id, wxBitmap(wxT(PREFS_ICON), wxBITMAP_TYPE_PNG), wxDefaultPosition, wxSize(128, 128));
_KissButton = new wxBitmapButton(_wxUI, id, wxBitmap(wxT(IMPORT_ICON), wxBITMAP_TYPE_PNG), wxDefaultPosition, wxSize(128, 128));
return _KissButton;
}
@ -195,8 +199,9 @@ void ImportPanel::ProcessFile()
void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
{
std::map<wxString, wxString> resolvedAccounts;
int i;
int i, nbAccounts;
User* user = _kiss->GetUser();
Account account;
for(i=0; i<_accountsGrid->GetNumberRows(); i++)
{
@ -204,13 +209,57 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
user->GetAccountId(_accountsGrid->GetCellValue(i, 1));
}
nbAccounts = 0;
for(i=0; i<_accountsGrid->GetNumberRows(); i++)
{
if (_accountsGrid->GetCellValue(i, 1) == _("Create one"))
nbAccounts++;
}
if (nbAccounts)
{
wxString message = wxString::Format(wxT("%d"), nbAccounts);
message += _(" account(s) will be created, is it ok ?");
wxMessageDialog dialog(_wxUI, message, wxT("KissCount"), wxYES_NO);
if (dialog.ShowModal() == wxID_NO)
return;
for(i=0; i<_accountsGrid->GetNumberRows(); i++)
{
if (_accountsGrid->GetCellValue(i, 1) == _("Create one"))
{
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);
}
}
_accountsGrid->DeleteRows(0, _accountsGrid->GetNumberRows ());
_wxUI->NeedReload();
}
_operations = _importEngine->GetOperations(resolvedAccounts);
if (_operations->size())
{
_hbox->Detach(_operationsGrid);
delete _operationsGrid;
_operationsGrid = new GridAccount(_kiss, this, OPS_GRID_ID, false, false, false);
_hbox->Add(_operationsGrid, 0, wxGROW|wxALL, 15);
_operationsGrid->LoadOperations(_operations, 0, 0);
_buttonIntegrate->Enable();
_buttonLoadOperations->Disable();
Fit();
}
else
@ -219,6 +268,32 @@ void ImportPanel::OnLoadOperations(wxCommandEvent& WXUNUSED(event))
}
}
void ImportPanel::OnIntegrate(wxCommandEvent& WXUNUSED(event))
{
int i;
if (!_operations->size()) return;
wxMessageDialog dialog(_wxUI, _("Are you sure want to integrate these operations ?"), wxT("KissCount"), wxYES_NO);
if (dialog.ShowModal() == wxID_NO)
return;
_buttonIntegrate->Disable();
for(i=0; i<(int)_operations->size(); i++)
_kiss->AddOperation((*_operations)[i]);
// if (_checkSaveImportPatterns->IsChecked())
_kiss->UpdateImportPattern();
_operations->clear();
_operationsGrid->ClearGrid();
wxMessageBox(_("Operations successfully imported"), wxT("KissCount"), wxICON_INFORMATION | wxOK);
_wxUI->NeedReload();
}
void ImportPanel::OnOperationModified(wxGridEvent& event)
{
int col = event.GetCol();
@ -238,8 +313,6 @@ void ImportPanel::OnOperationModified(wxGridEvent& event)
if (_importEngine->UpdatePattern(row-1) > 1)
_operationsGrid->LoadOperations(_operations, 0, 0);
// sleep(1);
Fit();
update = false;

View File

@ -48,14 +48,17 @@ public:
void OnFile(wxCommandEvent& WXUNUSED(event));
void OnFileEnter(wxCommandEvent& WXUNUSED(event));
void OnLoadOperations(wxCommandEvent& WXUNUSED(event));
void OnIntegrate(wxCommandEvent& WXUNUSED(event));
void OnOperationModified(wxGridEvent& event);
private:
wxBoxSizer *_hbox;
wxGrid* _accountsGrid;
wxTextCtrl* _fileTxt;
GridAccount* _operationsGrid;
ImportEngine* _importEngine;
wxButton* _buttonLoadOperations, *_buttonIntegrate;
wxCheckBox *_checkSaveImportPatterns;
std::vector<Operation>* _operations;
void ProcessFile();

View File

@ -34,6 +34,7 @@
#define STATS_ICON RESSOURCES_ROOT "icons/chart-icon.png"
#define SEARCH_ICON RESSOURCES_ROOT "icons/Search-icon.png"
#define PREFS_ICON RESSOURCES_ROOT "icons/options-icon.png"
#define IMPORT_ICON RESSOURCES_ROOT "icons/import-icon.png"
#define CHANGE_USER_ICON RESSOURCES_ROOT "icons/Clients-icon.png"
#define ABOUT_ICON RESSOURCES_ROOT "icons/windows-users-icon.png"
#define QUIT_ICON RESSOURCES_ROOT "icons/system-log-out.png"