From 98b5ec2da025bfc16eea34f9de9a671d9be2979f Mon Sep 17 00:00:00 2001 From: aiekick Date: Sun, 9 Jun 2024 02:34:49 +0200 Subject: [PATCH] [RFR] : Refactor the account pane view [ADD] : Add a proto Buy/Sell Pane --- .github/workflows/Osx.yml | 4 +- 3rdparty/ImGuiPack | 2 +- README.md | 14 +- apis/CashMePluginApi.h | 2 +- apis/ILayoutPane.h | 2 +- .../LCLBroker/src/Headers/LCLBrokerBuild.h | 4 +- src/Backend/MainBackend.cpp | 13 +- src/Frontend/Components/CodeEditor.cpp | 291 ------ src/Frontend/Components/CodeEditor.h | 55 -- src/Frontend/Dialogs/AccountDialog.cpp | 4 - src/Frontend/Dialogs/BankDialog.cpp | 4 - src/Frontend/Dialogs/CategoryDialog.cpp | 4 - src/Frontend/Dialogs/OperationDialog.cpp | 4 - src/Frontend/Dialogs/TransactionDialog.cpp | 2 - src/Frontend/Dialogs/abstract/ADataDialog.cpp | 5 +- src/Frontend/Dialogs/abstract/ADataDialog.hpp | 2 +- src/Frontend/MainFrontend.cpp | 34 +- src/Frontend/MainFrontend.h | 9 +- src/Headers/CashMeBuild.h | 4 +- src/Headers/DatasDef.h | 5 + src/Models/DataBrokers.cpp | 884 ------------------ src/Models/DataBrokers.h | 137 --- src/Panes/AccountPane.cpp | 841 ++++++++++++++++- src/Panes/AccountPane.h | 112 ++- src/Panes/BudgetPane.cpp | 5 +- src/Panes/BudgetPane.h | 2 +- src/Panes/BuySellPane.cpp | 65 ++ src/Panes/BuySellPane.h | 37 + src/Panes/ConsolePane.cpp | 2 +- src/Panes/ConsolePane.h | 2 +- src/Project/ProjectFile.cpp | 11 +- 31 files changed, 1099 insertions(+), 1463 deletions(-) delete mode 100644 src/Frontend/Components/CodeEditor.cpp delete mode 100644 src/Frontend/Components/CodeEditor.h delete mode 100644 src/Models/DataBrokers.cpp delete mode 100644 src/Models/DataBrokers.h create mode 100644 src/Panes/BuySellPane.cpp create mode 100644 src/Panes/BuySellPane.h diff --git a/.github/workflows/Osx.yml b/.github/workflows/Osx.yml index 937e1b7..eb9d6cc 100644 --- a/.github/workflows/Osx.yml +++ b/.github/workflows/Osx.yml @@ -21,5 +21,5 @@ jobs: - name: upload artifact uses: actions/upload-artifact@v1 with: - name: CashMe_Darwin_x32.app - path: bin/CashMe_Darwin_x32.app + name: CashMe_Darwin_x32 + path: bin/CashMe_Darwin_x32 diff --git a/3rdparty/ImGuiPack b/3rdparty/ImGuiPack index 374de5d..1c1b80f 160000 --- a/3rdparty/ImGuiPack +++ b/3rdparty/ImGuiPack @@ -1 +1 @@ -Subproject commit 374de5d45c8893e5e615f6d9fa07645edaa8efb7 +Subproject commit 1c1b80f9aa9947591e6d3431de7b9f197a56bcd6 diff --git a/README.md b/README.md index 4deac70..22e1507 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ CashMe is a Money Manager. The features are : - - Bank statement imports based on plugins - - Can show Tranactions, with filtering - - Can Update Once/All Transactions - - Can Delete Once/All Transactions - - Can display categories / operations per transactions + * Bank statement imports based on plugins + * Can show Tranactions, with filtering + * Can Update Once/All Transactions + * Can Delete Once/All Transactions + * Can display categories / operations per transactions -THe available plugins are : - - LCL : Can import ofc and pdf files +The available plugins are : + * LCL : Can import ofc and pdf files ## How to Build : diff --git a/apis/CashMePluginApi.h b/apis/CashMePluginApi.h index fbbaa11..b906792 100644 --- a/apis/CashMePluginApi.h +++ b/apis/CashMePluginApi.h @@ -46,7 +46,7 @@ struct PluginPane : public ILayoutPane { bool DrawOverlays(const uint32_t& /*vCurrentFrame*/, const ImRect& /*vRect*/, ImGuiContext* /*vContextPtr*/, void* /*vUserDatas*/) override { return false; } - bool DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImVec2& /*vMaxSize*/, ImGuiContext* /*vContextPtr*/, void* /*vUserDatas*/) override { + bool DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImRect& /*vRect*/, ImGuiContext* /*vContextPtr*/, void* /*vUserDatas*/) override { return false; } diff --git a/apis/ILayoutPane.h b/apis/ILayoutPane.h index a13767d..557cf60 100644 --- a/apis/ILayoutPane.h +++ b/apis/ILayoutPane.h @@ -39,7 +39,7 @@ class ILayoutPane { virtual bool DrawPanes(const uint32_t& vCurrentFrame, bool* vOpened, ImGuiContext* vContextPt, void* vUserDatas) = 0; virtual bool DrawWidgets(const uint32_t& vCurrentFrame, ImGuiContext* vContextPtr, void* vUserDatas) = 0; virtual bool DrawOverlays(const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr, void* vUserDatas) = 0; - virtual bool DrawDialogsAndPopups(const uint32_t& vCurrentFrame, const ImVec2& vMaxSize, ImGuiContext* vContextPtr, void* vUserDatas) = 0; + virtual bool DrawDialogsAndPopups(const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr, void* vUserDatas) = 0; // if for any reason the pane must be hidden temporary, the user can control this here virtual bool CanBeDisplayed() = 0; diff --git a/plugins/LCLBroker/src/Headers/LCLBrokerBuild.h b/plugins/LCLBroker/src/Headers/LCLBrokerBuild.h index f2c607d..4b2c69d 100644 --- a/plugins/LCLBroker/src/Headers/LCLBrokerBuild.h +++ b/plugins/LCLBroker/src/Headers/LCLBrokerBuild.h @@ -1,7 +1,7 @@ #pragma once #define LCLBroker_Prefix "LCLBroker" -#define LCLBroker_BuildNumber 237 +#define LCLBroker_BuildNumber 242 #define LCLBroker_MinorNumber 0 #define LCLBroker_MajorNumber 0 -#define LCLBroker_BuildId "0.0.237" +#define LCLBroker_BuildId "0.0.242" diff --git a/src/Backend/MainBackend.cpp b/src/Backend/MainBackend.cpp index 7202be4..f631c79 100644 --- a/src/Backend/MainBackend.cpp +++ b/src/Backend/MainBackend.cpp @@ -35,7 +35,6 @@ #include #include -#include #include @@ -244,7 +243,7 @@ void MainBackend::m_RenderOffScreen() { void MainBackend::m_MainLoop() { int display_w, display_h; - ImVec2 pos, size; + ImRect viewRect; while (!glfwWindowShouldClose(m_MainWindowPtr)) { ProjectFile::Instance()->NewFrame(); @@ -264,11 +263,13 @@ void MainBackend::m_MainLoop() { ImGuiViewport* viewport = ImGui::GetMainViewport(); if (viewport) { - pos = viewport->WorkPos; - size = viewport->WorkSize; + viewRect.Min = viewport->WorkPos; + viewRect.Max = viewRect.Min + viewport->WorkSize; + } else { + viewRect.Max = ImVec2((float)display_w, (float)display_h); } - MainFrontend::Instance()->Display(m_CurrentFrame, pos, size); + MainFrontend::Instance()->Display(m_CurrentFrame, viewRect); ImGui::Render(); @@ -460,11 +461,9 @@ void MainBackend::m_InitPlugins() { } void MainBackend::m_InitModels() { - DataBrokers::Instance()->init(); } void MainBackend::m_UnitModels() { - DataBrokers::Instance()->unit(); } void MainBackend::m_UnitPlugins() { diff --git a/src/Frontend/Components/CodeEditor.cpp b/src/Frontend/Components/CodeEditor.cpp deleted file mode 100644 index de246a8..0000000 --- a/src/Frontend/Components/CodeEditor.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include - -#include - -#include -#include -#include - -#define FIND_POPUP_TEXT_FIELD_LENGTH 128 - -CodeEditor::CodeEditor(const char* filePath, - int id, - int createdFromFolderView, - OnFocusedCallback onFocusedCallback, - OnShowInFolderViewCallback onShowInFolderViewCallback) { - this->id = id; - this->createdFromFolderView = createdFromFolderView; - this->onFocusedCallback = onFocusedCallback; - this->onShowInFolderViewCallback = onShowInFolderViewCallback; - if (filePath == nullptr) - panelName = "untitled##" + std::to_string((intptr_t)this); - else { - hasAssociatedFile = true; - associatedFile = std::string(filePath); - auto pathObject = std::filesystem::path(filePath); - panelName = pathObject.filename().string() + "##" + std::to_string((intptr_t)this); -#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(__WIN64__) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER) - std::ifstream t(ct::UTF8Decode(filePath)); -#else - std::ifstream t(filePath); -#endif - std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - editor.SetText(str); /* - auto lang = extensionToLanguageDefinition.find(pathObject.extension().string()); - if (lang != extensionToLanguageDefinition.end()) - editor.SetLanguageDefinition(lang->second);*/ - } -} - -CodeEditor::~CodeEditor() { -} - -bool CodeEditor::init() { - if (ImGui::GetIO().Fonts->Fonts.size() == 3U) { - m_CodeFontPtr = ImGui::GetIO().Fonts->Fonts[1]; - } - return true; -} - -void CodeEditor::unit() { -} - -void CodeEditor::OnImGui() { - bool isFocused = ImGui::IsWindowFocused(); - bool requestingGoToLinePopup = false; - bool requestingFindPopup = false; - if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("File")) { - if (hasAssociatedFile && ImGui::MenuItem("Reload", "Ctrl+R")) - OnReloadCommand(); - if (ImGui::MenuItem("Load from")) - OnLoadFromCommand(); - if (ImGui::MenuItem("Save", "Ctrl+S")) - OnSaveCommand(); - /*if (this->hasAssociatedFile && ImGui::MenuItem("Show in file explorer")) - Utils::ShowInFileExplorer(this->associatedFile);*/ - if (this->hasAssociatedFile && this->onShowInFolderViewCallback != nullptr && this->createdFromFolderView > -1 && - ImGui::MenuItem("Show in folder view")) - this->onShowInFolderViewCallback(this->associatedFile, this->createdFromFolderView); - ; - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Edit")) { - bool ro = editor.IsReadOnlyEnabled(); - if (ImGui::MenuItem("Read only mode enabled", nullptr, &ro)) - editor.SetReadOnlyEnabled(ro); - bool ai = editor.IsAutoIndentEnabled(); - if (ImGui::MenuItem("Auto indent on enter enabled", nullptr, &ai)) - editor.SetAutoIndentEnabled(ai); - ImGui::Separator(); - - if (ImGui::MenuItem("Undo", "ALT-Backspace", nullptr, !ro && editor.CanUndo())) - editor.Undo(); - if (ImGui::MenuItem("Redo", "Ctrl+Y", nullptr, !ro && editor.CanRedo())) - editor.Redo(); - - ImGui::Separator(); - - if (ImGui::MenuItem("Copy", "Ctrl+C", nullptr, editor.AnyCursorHasSelection())) - editor.Copy(); - if (ImGui::MenuItem("Cut", "Ctrl+X", nullptr, !ro && editor.AnyCursorHasSelection())) - editor.Cut(); - if (ImGui::MenuItem("Paste", "Ctrl+V", nullptr, !ro && ImGui::GetClipboardText() != nullptr)) - editor.Paste(); - - ImGui::Separator(); - - if (ImGui::MenuItem("Select all", nullptr, nullptr)) - editor.SelectAll(); - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("View")) { - ImGui::SliderInt("Tab size", &tabSize, 1, 8); - ImGui::SliderFloat("Line spacing", &lineSpacing, 1.0f, 2.0f); - editor.SetTabSize(tabSize); - editor.SetLineSpacing(lineSpacing); - static bool showSpaces = editor.IsShowWhitespacesEnabled(); - if (ImGui::MenuItem("Show spaces", nullptr, &showSpaces)) - editor.SetShowWhitespacesEnabled(!(editor.IsShowWhitespacesEnabled())); - static bool showLineNumbers = editor.IsShowLineNumbersEnabled(); - if (ImGui::MenuItem("Show line numbers", nullptr, &showLineNumbers)) - editor.SetShowLineNumbersEnabled(!(editor.IsShowLineNumbersEnabled())); - static bool showShortTabs = editor.IsShortTabsEnabled(); - if (ImGui::MenuItem("Short tabs", nullptr, &showShortTabs)) - editor.SetShortTabsEnabled(!(editor.IsShortTabsEnabled())); - /*if (ImGui::BeginMenu("Language")) - { - for (int i = (int)TextEditor::LanguageDefinitionId::None; i <= (int)TextEditor::LanguageDefinitionId::Hlsl; i++) - { - bool isSelected = i == (int)editor.GetLanguageDefinition(); - if (ImGui::MenuItem(languageDefinitionToName[(TextEditor::LanguageDefinitionId)i], nullptr, &isSelected)) - editor.SetLanguageDefinition((TextEditor::LanguageDefinitionId)i); - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Color scheme")) - { - for (int i = (int)TextEditor::PaletteId::Dark; i <= (int)TextEditor::PaletteId::RetroBlue; i++) - { - bool isSelected = i == (int)editor.GetPalette(); - if (ImGui::MenuItem(colorPaletteToName[(TextEditor::PaletteId)i], nullptr, &isSelected)) - editor.SetPalette((TextEditor::PaletteId)i); - } - ImGui::EndMenu(); - }*/ - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Find")) { - if (ImGui::MenuItem("Go to line", "Ctrl+G")) - requestingGoToLinePopup = true; - if (ImGui::MenuItem("Find", "Ctrl+F")) - requestingFindPopup = true; - ImGui::EndMenu(); - } - - int line, column; - editor.GetCursorPosition(line, column); - ImGui::Text("%6d/%-6d %6d lines | %s | %s", line + 1, column + 1, editor.GetLineCount(), editor.IsOverwriteEnabled() ? "Ovr" : "Ins", - editor.GetLanguageDefinitionName()); - - ImGui::EndMenuBar(); - } - - if (m_CodeFontPtr) { - ImGui::PushFont(m_CodeFontPtr); - isFocused |= editor.Render("TextEditor", isFocused); - ImGui::PopFont(); - } else { - isFocused |= editor.Render("TextEditor", isFocused); - } - - if (isFocused) { - bool ctrlPressed = ImGui::GetIO().KeyCtrl; - if (ctrlPressed) { - if (ImGui::IsKeyDown(ImGuiKey_S)) - OnSaveCommand(); - if (ImGui::IsKeyDown(ImGuiKey_R)) - OnReloadCommand(); - if (ImGui::IsKeyDown(ImGuiKey_G)) - requestingGoToLinePopup = true; - if (ImGui::IsKeyDown(ImGuiKey_F)) - requestingFindPopup = true; - } - } - - if (requestingGoToLinePopup) - ImGui::OpenPopup("go_to_line_popup"); - if (ImGui::BeginPopup("go_to_line_popup")) { - static int targetLine; - ImGui::SetKeyboardFocusHere(); - ImGui::InputInt("Line", &targetLine); - if (ImGui::IsKeyDown(ImGuiKey_Enter) || ImGui::IsKeyDown(ImGuiKey_KeypadEnter)) { - static int targetLineFixed; - targetLineFixed = targetLine < 1 ? 0 : targetLine - 1; - editor.ClearExtraCursors(); - editor.ClearSelections(); - editor.SelectLine(targetLineFixed); - ImGui::CloseCurrentPopup(); - ImGui::GetIO().ClearInputKeys(); - } else if (ImGui::IsKeyDown(ImGuiKey_Escape)) - ImGui::CloseCurrentPopup(); - ImGui::EndPopup(); - } - - if (requestingFindPopup) - ImGui::OpenPopup("find_popup"); - if (ImGui::BeginPopup("find_popup")) { - ImGui::Checkbox("Case sensitive", &ctrlfCaseSensitive); - if (requestingFindPopup) - ImGui::SetKeyboardFocusHere(); - ImGui::InputText("To find", ctrlfTextToFind, FIND_POPUP_TEXT_FIELD_LENGTH, ImGuiInputTextFlags_AutoSelectAll); - const int32_t& toFindTextSize = (int32_t)strlen(ctrlfTextToFind); - if ((ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter)) && toFindTextSize > 0) { - editor.ClearExtraCursors(); - editor.SelectNextOccurrenceOf(ctrlfTextToFind, toFindTextSize, ctrlfCaseSensitive); - } - if (ImGui::Button("Find all") && toFindTextSize > 0) - editor.SelectAllOccurrencesOf(ctrlfTextToFind, toFindTextSize, ctrlfCaseSensitive); - else if (ImGui::IsKeyDown(ImGuiKey_Escape)) - ImGui::CloseCurrentPopup(); - - ImGui::EndPopup(); - } -} - -void CodeEditor::SetSelection(int startLine, int startChar, int endLine, int endChar) { - editor.SetCursorPosition(endLine, endChar); - editor.SelectRegion(startLine, startChar, endLine, endChar); -} - -const char* CodeEditor::GetAssociatedFile() { - if (!hasAssociatedFile) { - return nullptr; - } - return associatedFile.c_str(); -} - -void CodeEditor::OnFolderViewDeleted(int folderViewId) { - if (createdFromFolderView == folderViewId) - createdFromFolderView = -1; -} - -void CodeEditor::SetShowDebugPanel(bool value) { - showDebugPanel = value; -} - -void CodeEditor::SetGlslCode(const std::string& vCode) { - editor.SetLanguageDefinition(TextEditor::LanguageDefinition::Glsl()); - editor.SetText(vCode); -} - -// Commands - -void CodeEditor::OnReloadCommand() { -#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(__WIN64__) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER) - std::ifstream t(ct::UTF8Decode(associatedFile)); -#else - std::ifstream t(associatedFile); -#endif - std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - editor.SetText(str); - undoIndexInDisk = 0; -} - -void CodeEditor::OnLoadFromCommand() { - /*std::vector selection = pfd::open_file("Open file", "", { "Any file", "*" }).result(); - if (selection.size() == 0) - std::cout << "File not loaded\n"; - else - { - std::ifstream t(Utf8ToWstring(selection[0])); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - editor.SetText(str); - auto pathObject = std::filesystem::path(selection[0]); - auto lang = extensionToLanguageDefinition.find(pathObject.extension().string()); - if (lang != extensionToLanguageDefinition.end()) - editor.SetLanguageDefinition(extensionToLanguageDefinition[pathObject.extension().string()]); - } - undoIndexInDisk = -1; // assume they are loading text from some other file*/ -} - -void CodeEditor::OnSaveCommand() { - /*std::string textToSave = editor.GetText(); - std::string destination = hasAssociatedFile ? - associatedFile : - pfd::save_file("Save file", "", { "Any file", "*" }).result(); - if (destination.length() > 0) - { - associatedFile = destination; - hasAssociatedFile = true; - panelName = std::filesystem::path(destination).filename().string() + "##" + std::to_string((int)this); - std::ofstream outFile(Utils::Utf8ToWstring(destination), std::ios::binary); - outFile << textToSave; - outFile.close(); - } - undoIndexInDisk = editor.GetUndoIndex();*/ -} \ No newline at end of file diff --git a/src/Frontend/Components/CodeEditor.h b/src/Frontend/Components/CodeEditor.h deleted file mode 100644 index 8511bf2..0000000 --- a/src/Frontend/Components/CodeEditor.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include - -#define FIND_POPUP_TEXT_FIELD_LENGTH 128 - -class CodeEditor -{ -public: - typedef void (*OnFocusedCallback)(int folderViewId); - typedef void (*OnShowInFolderViewCallback)(const std::string& filePath, int folderViewId); - - CodeEditor(const char* filePath = nullptr, - int id = -1, - int createdFromFolderView = -1, - OnFocusedCallback onFocusedCallback = nullptr, - OnShowInFolderViewCallback onShowInFolderViewCallback = nullptr); - ~CodeEditor(); - bool init(); - void unit(); - - void OnImGui(); - void SetSelection(int startLine, int startChar, int endLine, int endChar); - const char* GetAssociatedFile(); - void OnFolderViewDeleted(int folderViewId); - void SetShowDebugPanel(bool value); - - void SetGlslCode(const std::string& vCode); - -private: - void OnReloadCommand(); - void OnLoadFromCommand(); - void OnSaveCommand(); - -private: - ImFont* m_CodeFontPtr = nullptr; - - int id = -1; - int createdFromFolderView = -1; - - OnFocusedCallback onFocusedCallback = nullptr; - OnShowInFolderViewCallback onShowInFolderViewCallback = nullptr; - - TextEditor editor; - bool showDebugPanel = false; - bool hasAssociatedFile = false; - std::string panelName; - std::string associatedFile; - int tabSize = 4; - float lineSpacing = 1.0f; - int undoIndexInDisk = 0; - - char ctrlfTextToFind[FIND_POPUP_TEXT_FIELD_LENGTH] = ""; - bool ctrlfCaseSensitive = false; -}; \ No newline at end of file diff --git a/src/Frontend/Dialogs/AccountDialog.cpp b/src/Frontend/Dialogs/AccountDialog.cpp index a056d5d..5f8101e 100644 --- a/src/Frontend/Dialogs/AccountDialog.cpp +++ b/src/Frontend/Dialogs/AccountDialog.cpp @@ -1,6 +1,5 @@ #include "AccountDialog.h" #include -#include #include AccountDialog::AccountDialog() : ADataDialog("AccountModalPopup") { @@ -103,7 +102,6 @@ void AccountDialog::m_confirmDialog() { case DataDialogMode::MODE_NONE: default: break; } - DataBrokers::Instance()->RefreshDatas(); } void AccountDialog::m_cancelDialog() { @@ -119,7 +117,6 @@ void AccountDialog::m_confirmDialogCreation() { m_AccountNumberInputText.GetText(), // m_AccountBaseSoldeInputDouble); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } @@ -145,7 +142,6 @@ void AccountDialog::m_confirmDialogUpdate() { m_AccountNumberInputText.GetText(), // m_AccountBaseSoldeInputDouble); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } diff --git a/src/Frontend/Dialogs/BankDialog.cpp b/src/Frontend/Dialogs/BankDialog.cpp index fc6050c..4ee2b99 100644 --- a/src/Frontend/Dialogs/BankDialog.cpp +++ b/src/Frontend/Dialogs/BankDialog.cpp @@ -1,6 +1,5 @@ #include "BankDialog.h" #include -#include #include BankDialog::BankDialog() : ADataDialog("BankModalPopup") { @@ -86,7 +85,6 @@ void BankDialog::m_confirmDialog() { case DataDialogMode::MODE_NONE: default: break; } - DataBrokers::Instance()->RefreshDatas(); } void BankDialog::m_cancelDialog() { @@ -98,7 +96,6 @@ void BankDialog::m_confirmDialogCreation() { m_BankNameInputText.GetText(), // m_BankUrlInputText.GetText()); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } @@ -116,7 +113,6 @@ void BankDialog::m_confirmDialogUpdate() { m_BankNameInputText.GetText(), // m_BankUrlInputText.GetText()); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } diff --git a/src/Frontend/Dialogs/CategoryDialog.cpp b/src/Frontend/Dialogs/CategoryDialog.cpp index ab3a374..a414537 100644 --- a/src/Frontend/Dialogs/CategoryDialog.cpp +++ b/src/Frontend/Dialogs/CategoryDialog.cpp @@ -1,6 +1,5 @@ #include "CategoryDialog.h" #include -#include #include CategoryDialog::CategoryDialog() : ADataDialog("CategoryModalPopup") { @@ -84,7 +83,6 @@ void CategoryDialog::m_confirmDialog() { case DataDialogMode::MODE_NONE: default: break; } - DataBrokers::Instance()->RefreshDatas(); } void CategoryDialog::m_cancelDialog() { @@ -95,7 +93,6 @@ void CategoryDialog::m_confirmDialogCreation() { DataBase::Instance()->AddCategory( // m_CategoryNameInputText.GetText()); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } @@ -111,7 +108,6 @@ void CategoryDialog::m_confirmDialogUpdate() { m_Category.id, // m_CategoryNameInputText.GetText()); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } diff --git a/src/Frontend/Dialogs/OperationDialog.cpp b/src/Frontend/Dialogs/OperationDialog.cpp index 3365250..6930ea5 100644 --- a/src/Frontend/Dialogs/OperationDialog.cpp +++ b/src/Frontend/Dialogs/OperationDialog.cpp @@ -1,6 +1,5 @@ #include "OperationDialog.h" #include -#include #include OperationDialog::OperationDialog() : ADataDialog("OperationModalPopup") { @@ -83,7 +82,6 @@ void OperationDialog::m_confirmDialog() { case DataDialogMode::MODE_NONE: default: break; } - DataBrokers::Instance()->RefreshDatas(); } void OperationDialog::m_cancelDialog() { @@ -94,7 +92,6 @@ void OperationDialog::m_confirmDialogCreation() { DataBase::Instance()->AddOperation( // m_OperationNameInputText.GetText()); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } @@ -110,7 +107,6 @@ void OperationDialog::m_confirmDialogUpdate() { m_Operation.id, // m_OperationNameInputText.GetText()); DataBase::Instance()->CloseDBFile(); - DataBrokers::Instance()->RefreshDatas(); } } diff --git a/src/Frontend/Dialogs/TransactionDialog.cpp b/src/Frontend/Dialogs/TransactionDialog.cpp index 38895d0..d3c3028 100644 --- a/src/Frontend/Dialogs/TransactionDialog.cpp +++ b/src/Frontend/Dialogs/TransactionDialog.cpp @@ -1,6 +1,5 @@ #include "TransactionDialog.h" #include -#include #include #define MULTIPLE_VALUES "Many values" @@ -244,7 +243,6 @@ void TransactionDialog::m_confirmDialog() { case DataDialogMode::MODE_NONE: default: break; } - DataBrokers::Instance()->RefreshDatas(); } void TransactionDialog::m_cancelDialog() { diff --git a/src/Frontend/Dialogs/abstract/ADataDialog.cpp b/src/Frontend/Dialogs/abstract/ADataDialog.cpp index 518c9d5..406ea81 100644 --- a/src/Frontend/Dialogs/abstract/ADataDialog.cpp +++ b/src/Frontend/Dialogs/abstract/ADataDialog.cpp @@ -22,7 +22,8 @@ const bool& ADataDialog::isCurrentModeShown() const { return m_ShowDialogMode.at(static_cast(m_CurrentMode)); } -void ADataDialog::draw(const ImVec2& vPos) { +bool ADataDialog::draw(const ImVec2& vPos) { + bool ret = false; if (isCurrentModeShown()) { ImGui::OpenPopup(m_PopupLabel); ImGui::SetNextWindowPos(vPos, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); @@ -40,6 +41,7 @@ void ADataDialog::draw(const ImVec2& vPos) { if (ImGui::ContrastedButton("Ok")) { m_confirmDialog(); hide(getCurrentMode()); + ret = true; } ImGui::SameLine(); } @@ -50,6 +52,7 @@ void ADataDialog::draw(const ImVec2& vPos) { ImGui::EndPopup(); } } + return ret; } void ADataDialog::m_DisplayAlignedWidget(const float& vWidth, const std::string& vLabel, const float& vOffsetFromStart, std::function vWidget) { diff --git a/src/Frontend/Dialogs/abstract/ADataDialog.hpp b/src/Frontend/Dialogs/abstract/ADataDialog.hpp index 1a12501..a0f0688 100644 --- a/src/Frontend/Dialogs/abstract/ADataDialog.hpp +++ b/src/Frontend/Dialogs/abstract/ADataDialog.hpp @@ -29,7 +29,7 @@ class ADataDialog { void hide(const DataDialogMode& vMode); const DataDialogMode& getCurrentMode() const; const bool& isCurrentModeShown() const; - void draw(const ImVec2& vPos); + bool draw(const ImVec2& vPos); protected: virtual void m_drawContent(const ImVec2& vPos) = 0; diff --git a/src/Frontend/MainFrontend.cpp b/src/Frontend/MainFrontend.cpp index ecc8e0f..b1d9d0c 100644 --- a/src/Frontend/MainFrontend.cpp +++ b/src/Frontend/MainFrontend.cpp @@ -27,11 +27,10 @@ limitations under the License. #include +#include #include #include -#include - -#include +#include #include @@ -77,7 +76,8 @@ bool MainFrontend::init() { LayoutManager::Instance()->AddPane(ConsolePane::Instance(), "Console Pane", "", "BOTTOM", 0.25f, false, false); LayoutManager::Instance()->AddPane(AccountPane::Instance(), "Account Pane", "", "CENTRAL", 0.25f, true, true); - LayoutManager::Instance()->AddPane(BudgetPane::Instance(), "Budget Pane", "", "CENTRAL", 0.0f, true, false); + LayoutManager::Instance()->AddPane(BuySellPane::Instance(), "Buy/Sell Pane", "", "CENTRAL", 0.0f, true, false); + LayoutManager::Instance()->AddPane(BudgetPane::Instance(), "Budget Pane", "", "CENTRAL", 0.0f, false, false); // InitPänes is done in m_InitPanes, because a specific order is needed @@ -102,13 +102,12 @@ bool MainFrontend::isThereAnError() const { return false; } -void MainFrontend::Display(const uint32_t& vCurrentFrame, const ImVec2& vPos, const ImVec2& vSize) { +void MainFrontend::Display(const uint32_t& vCurrentFrame, const ImRect& vRect) { const auto context_ptr = ImGui::GetCurrentContext(); if (context_ptr != nullptr) { const auto& io = ImGui::GetIO(); - m_DisplayPos = vPos; - m_DisplaySize = vSize; + m_DisplayRect = vRect; MainFrontend::sCentralWindowHovered = (ImGui::GetCurrentContext()->HoveredWindow == nullptr); ImGui::CustomStyle::ResetCustomId(); @@ -132,7 +131,7 @@ void MainFrontend::Display(const uint32_t& vCurrentFrame, const ImVec2& vPos, co ProjectFile::Instance()->SetProjectChange(); } - DrawDialogsAndPopups(vCurrentFrame, MainBackend::Instance()->GetDisplaySize(), context_ptr, {}); + DrawDialogsAndPopups(vCurrentFrame, m_DisplayRect, context_ptr, {}); ImGuiThemeHelper::Instance()->Draw(); LayoutManager::Instance()->InitAfterFirstDisplay(io.DisplaySize); @@ -150,10 +149,9 @@ bool MainFrontend::DrawOverlays(const uint32_t& vCurrentFrame, const ImRect& vRe } bool MainFrontend::DrawDialogsAndPopups( - const uint32_t& vCurrentFrame, const ImVec2& vMaxSize, ImGuiContext* vContextPtr, void* vUserDatas) { + const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr, void* vUserDatas) { m_ActionSystem.RunActions(); - LayoutManager::Instance()->DrawDialogsAndPopups(vCurrentFrame, vMaxSize, vContextPtr, vUserDatas); - DataBrokers::Instance()->drawDialogs(m_DisplayPos, m_DisplaySize); + LayoutManager::Instance()->DrawDialogsAndPopups(vCurrentFrame, vRect, vContextPtr, vUserDatas); if (m_ShowImGui) { ImGui::ShowDemoWindow(&m_ShowImGui); } @@ -316,7 +314,7 @@ bool MainFrontend::ShowUnSavedDialog() { ImGui::CloseCurrentPopup(); const char* label = "Save before closing ?"; ImGui::OpenPopup(label); - ImGui::SetNextWindowPos(m_DisplayPos + m_DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowPos(m_DisplayRect.GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); if (ImGui::BeginPopupModal(label, (bool*)0, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) { const auto& width = ImGui::CalcTextSize("Continue without saving").x + ImGui::GetStyle().ItemInnerSpacing.x; @@ -559,8 +557,8 @@ void MainFrontend::Action_UnSavedDialog_Cancel() { bool MainFrontend::Display_NewProjectDialog() { // need to return false to continue to be displayed next frame - ImVec2 min = m_DisplaySize * 0.5f; - ImVec2 max = m_DisplaySize; + ImVec2 max = m_DisplayRect.GetSize(); + ImVec2 min = max * 0.5f; if (ImGuiFileDialog::Instance()->Display("NewProjectDlg", ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking, min, max)) { if (ImGuiFileDialog::Instance()->IsOk()) { @@ -583,8 +581,8 @@ bool MainFrontend::Display_NewProjectDialog() { bool MainFrontend::Display_OpenProjectDialog() { // need to return false to continue to be displayed next frame - ImVec2 min = m_DisplaySize * 0.5f; - ImVec2 max = m_DisplaySize; + ImVec2 max = m_DisplayRect.GetSize(); + ImVec2 min = max * 0.5f; if (ImGuiFileDialog::Instance()->Display("OpenProjectDlg", ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking, min, max)) { if (ImGuiFileDialog::Instance()->IsOk()) { @@ -606,8 +604,8 @@ bool MainFrontend::Display_OpenProjectDialog() { bool MainFrontend::Display_SaveProjectDialog() { // need to return false to continue to be displayed next frame - ImVec2 min = m_DisplaySize * 0.5f; - ImVec2 max = m_DisplaySize; + ImVec2 max = m_DisplayRect.GetSize(); + ImVec2 min = max * 0.5f; if (ImGuiFileDialog::Instance()->Display("SaveProjectDlg", ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking, min, max)) { if (ImGuiFileDialog::Instance()->IsOk()) { diff --git a/src/Frontend/MainFrontend.h b/src/Frontend/MainFrontend.h index a1b6c76..74f8e0a 100644 --- a/src/Frontend/MainFrontend.h +++ b/src/Frontend/MainFrontend.h @@ -25,8 +25,6 @@ limitations under the License. #include -#include - #include #include #include @@ -109,8 +107,7 @@ class MainFrontend : public conf::ConfigAbstract { bool m_ShowImPlot = false; bool m_ShowMetric = false; ImFont* m_ToolbarFontPtr = nullptr; - ImVec2 m_DisplayPos = ImVec2(0, 0); // viewport - ImVec2 m_DisplaySize = ImVec2(1280, 720); + ImRect m_DisplayRect = ImRect(ImVec2(0, 0), ImVec2(1280, 720)); bool m_ShowAboutDialog = false; // show about dlg bool m_SaveDialogIfRequired = false; // open save options dialog (save / save as / continue without saving / cancel) bool m_SaveDialogActionWasDone = false; // if action was done by save options dialog @@ -128,11 +125,11 @@ class MainFrontend : public conf::ConfigAbstract { bool isValid() const; bool isThereAnError() const; - void Display(const uint32_t& vCurrentFrame, const ImVec2& vpos, const ImVec2& vSize); + void Display(const uint32_t& vCurrentFrame, const ImRect& vRect); bool DrawWidgets(const uint32_t& vCurrentFrame, ImGuiContext* vContextPtr, void* vUserDatas); bool DrawOverlays(const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr, void* vUserDatas); - bool DrawDialogsAndPopups(const uint32_t& vCurrentFrame, const ImVec2& vMaxSize, ImGuiContext* vContextPtr, void* vUserDatas); + bool DrawDialogsAndPopups(const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr, void* vUserDatas); void OpenAboutDialog(); diff --git a/src/Headers/CashMeBuild.h b/src/Headers/CashMeBuild.h index 0313d69..1d2d474 100644 --- a/src/Headers/CashMeBuild.h +++ b/src/Headers/CashMeBuild.h @@ -1,7 +1,7 @@ #pragma once #define CashMe_Prefix "CashMe" -#define CashMe_BuildNumber 374 +#define CashMe_BuildNumber 386 #define CashMe_MinorNumber 0 #define CashMe_MajorNumber 0 -#define CashMe_BuildId "0.0.374" +#define CashMe_BuildId "0.0.386" diff --git a/src/Headers/DatasDef.h b/src/Headers/DatasDef.h index 96007d4..accd651 100644 --- a/src/Headers/DatasDef.h +++ b/src/Headers/DatasDef.h @@ -1,10 +1,12 @@ #pragma once #include +#include #include #include #include #include +#include typedef std::string DBFile; typedef uint32_t RowID; @@ -28,6 +30,9 @@ typedef double TransactionSolde; typedef bool TransactionConfirmed; typedef uint32_t TransactionsCount; typedef std::string TransactionHash; +typedef std::string DataBrokerName; +typedef std::string DataBrokerWay; +typedef std::map> DataBrockerContainer; struct Bank { RowID id = 0; diff --git a/src/Models/DataBrokers.cpp b/src/Models/DataBrokers.cpp deleted file mode 100644 index b09b4f3..0000000 --- a/src/Models/DataBrokers.cpp +++ /dev/null @@ -1,884 +0,0 @@ -#include - -#include - -#include - -#include -#include - -#include - -#include - -#include - -#include - -#include -#include -#include - -#define OFFSET_IN_DAYS_FROM_NOW 360 - -bool DataBrokers::init() { - bool ret = true; - m_GetAvailableDataBrokers(); - ret &= m_BankDialog.init(); - ret &= m_AccountDialog.init(); - ret &= m_CategoryDialog.init(); - ret &= m_OperationDialog.init(); - ret &= m_TransactionDialog.init(); - return ret; -} - -void DataBrokers::unit() { - m_BankDialog.init(); - m_AccountDialog.init(); - m_CategoryDialog.init(); - m_OperationDialog.init(); - m_TransactionDialog.unit(); - m_Clear(); -} - -void DataBrokers::load() { - RefreshDatas(); -} - -bool DataBrokers::draw() { - bool change = false; - return change; -} - -void DataBrokers::drawDialogs(const ImVec2& vPos, const ImVec2& vSize) { - const ImVec2 center = vPos + vSize * 0.5f; - m_BankDialog.draw(center); - m_AccountDialog.draw(center); - m_CategoryDialog.draw(center); - m_OperationDialog.draw(center); - m_TransactionDialog.draw(center); - - ImVec2 min = vSize * 0.5f; - ImVec2 max = vSize; - - if (ImGuiFileDialog::Instance()->Display("Import Datas", ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking, min, max)) { - if (ImGuiFileDialog::Instance()->IsOk()) { - const auto& selection = ImGuiFileDialog::Instance()->GetSelection(); - if (!selection.empty()) { - std::vector files; - for (const auto& s : selection) { - files.push_back(s.second); - } - m_ImportFromFiles(files); - } - } - ImGuiFileDialog::Instance()->Close(); - } -} - -void DataBrokers::drawMenu(FrameActionSystem& vFrameActionSystem) { - if (ProjectFile::Instance()->IsProjectLoaded()) { - if (ImGui::BeginMenuBar()) { - m_drawAccountsMenu(vFrameActionSystem); - m_drawCreationMenu(vFrameActionSystem); - m_drawImportMenu(vFrameActionSystem); - m_drawSelectMenu(vFrameActionSystem); -#ifdef _DEBUG - m_drawDebugMenu(vFrameActionSystem); -#endif - ImGui::EndMenuBar(); - } - } -} - -void DataBrokers::DisplayTransactions() { - ImGui::Header("Transactions"); - ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 30.0f); - static auto flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY; - if (ImGui::BeginTable("##Transactions", 10, flags)) { - ImGui::TableSetupScrollFreeze(0, 2); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Dates", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Descriptions", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("Comments", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("Category", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Operation", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Debit", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Credit", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Solde", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Bars", ImGuiTableColumnFlags_WidthFixed); - m_drawSearchRow(); - ImGui::TableHeadersRow(); - int32_t idx = 0; - double max_price = DBL_MIN; - const float& bar_column_width = 100.0f; - auto drawListPtr = ImGui::GetWindowDrawList(); - const float& text_h = ImGui::GetTextLineHeight(); - const float& item_h = ImGui::GetTextLineHeightWithSpacing(); - const auto& bad_color = ImGui::GetColorU32(ImVec4(1, 0, 0, 1)); - const auto& good_color = ImGui::GetColorU32(ImVec4(0, 1, 0, 1)); - m_TransactionsListClipper.Begin((int)m_Datas.transactions_filtered.size(), item_h); - while (m_TransactionsListClipper.Step()) { - max_price = 0.0; - for (idx = m_TransactionsListClipper.DisplayStart; idx < m_TransactionsListClipper.DisplayEnd; ++idx) { - if (idx < 0) { - continue; - } - const auto& t = m_Datas.transactions_filtered.at(idx); - const auto& as = std::abs(t.solde); - if (as > max_price) { - max_price = as; - } - } - - for (idx = m_TransactionsListClipper.DisplayStart; idx < m_TransactionsListClipper.DisplayEnd; ++idx) { - if (idx < 0) { - continue; - } - - auto& t = m_Datas.transactions_filtered.at(idx); - - ImGui::TableNextRow(); - - ImGui::TableNextColumn(); - { - ImGui::PushID(t.id); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - if (ImGui::Checkbox("##check", &t.confirmed)) { - DataBase::Instance()->ConfirmTransaction(t.id, t.confirmed); - } - ImGui::PopStyleVar(); - ImGui::PopID(); - } - - ImGui::TableNextColumn(); - { ImGui::Text(t.date.c_str()); } - - ImGui::TableNextColumn(); - { - ImGui::PushID(&t); - auto is_selected = m_IsRowSelected(t.id); - ImGui::Selectable(t.description.c_str(), &is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); - if (ImGui::IsItemHovered()) { - if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { - m_ResetSelection(); - m_SelectOrDeselectRow(t); - m_TransactionDialog.setTransaction(t); - m_TransactionDialog.show(DataDialogMode::MODE_UPDATE_ONCE); - } else if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - m_SelectOrDeselectRow(t); - } - } - m_HideByFilledRectForHiddenMode("%s", t.description.c_str()); - ImGui::PopID(); - m_drawTransactionMenu(t); - } - - ImGui::TableNextColumn(); - { - ImGui::Text(t.comment.c_str()); - m_HideByFilledRectForHiddenMode("%s", t.comment.c_str()); - } - - ImGui::TableNextColumn(); - { - ImGui::Text(t.category.c_str()); - m_HideByFilledRectForHiddenMode("%s", t.category.c_str()); - } - - ImGui::TableNextColumn(); - { - ImGui::Text(t.operation.c_str()); - m_HideByFilledRectForHiddenMode("%s", t.operation.c_str()); - } - - ImGui::TableNextColumn(); - { - if (t.amount < 0.0) { - ImGui::PushStyleColor(ImGuiCol_Text, bad_color); - ImGui::Text("%.2f", t.amount); - m_HideByFilledRectForHiddenMode("%.2f", t.amount); - ImGui::PopStyleColor(); - } - } - - ImGui::TableNextColumn(); - { - if (t.amount >= 0.0) { - ImGui::PushStyleColor(ImGuiCol_Text, good_color); - ImGui::Text("%.2f", t.amount); - m_HideByFilledRectForHiddenMode("%.2f", t.amount); - ImGui::PopStyleColor(); - } - } - - ImGui::TableNextColumn(); - { - if (t.solde < 0.0) { - ImGui::PushStyleColor(ImGuiCol_Text, bad_color); - ImGui::Text("%.2f", t.solde); - m_HideByFilledRectForHiddenMode("%.2f", t.solde); - ImGui::PopStyleColor(); - } else if (t.solde > 0.0) { - ImGui::PushStyleColor(ImGuiCol_Text, good_color); - ImGui::Text("%.2f", t.solde); - m_HideByFilledRectForHiddenMode("%.2f", t.solde); - ImGui::PopStyleColor(); - } else { - ImGui::Text("%.2f", t.solde); - m_HideByFilledRectForHiddenMode("%.2f", t.solde); - } - } - - ImGui::TableNextColumn(); - { - const auto& cursor = ImGui::GetCursorScreenPos(); - const ImVec2 pMin(cursor.x, cursor.y + text_h * 0.1f); - const ImVec2 pMax(cursor.x + bar_column_width, cursor.y + text_h * 0.9f); - const float pMidX((pMin.x + pMax.x) * 0.5f); - ImGui::SetCursorScreenPos(pMin); - const float bw(bar_column_width * 0.5f * std::abs(t.solde) / (float)max_price); - if (t.solde < 0.0) { - drawListPtr->AddRectFilled(ImVec2(pMidX - bw, pMin.y), ImVec2(pMidX, pMax.y), bad_color); - } else if (t.solde > 0.0) { - drawListPtr->AddRectFilled(ImVec2(pMidX, pMin.y), ImVec2(pMidX + bw, pMax.y), good_color); - } - ImGui::SetCursorScreenPos(pMax); - } - } - } - m_TransactionsListClipper.End(); - ImGui::EndTable(); - } - ImGui::PopStyleVar(); -} - -void DataBrokers::m_drawImportMenu(FrameActionSystem& vFrameActionSystem) { - if (ImGui::BeginMenu("Import")) { - for (const auto& broker : m_DataBrokerModules) { - if (ImGui::BeginMenu(broker.first.c_str())) { - for (const auto& way : broker.second) { - if (ImGui::MenuItem(way.first.c_str())) { - if (way.second != nullptr) { - m_SelectedBroker = way.second; - vFrameActionSystem.Clear(); - vFrameActionSystem.Add([&way]() { - const auto& ext = way.second->getFileExt(); - IGFD::FileDialogConfig config; - config.countSelectionMax = 0; - config.flags = ImGuiFileDialogFlags_Modal; - ImGuiFileDialog::Instance()->OpenDialog("Import Datas", "Import Datas from File", ext.c_str(), config); - return true; - }); - } - } - } - ImGui::EndMenu(); - } - } - ImGui::EndMenu(); - } -} - -void DataBrokers::m_drawSelectMenu(FrameActionSystem& vFrameActionSystem) { - if (ImGui::BeginMenu("Select")) { - if (ImGui::MenuItem("Current rows")) { - m_SelectCurrentRows(); - } - if (ImGui::MenuItem("UnConfirmed entries")) { - m_SelectUnConfirmedTransactions(); - } - if (ImGui::MenuItem("Possible Duplicate entries on Prices and Dates")) { - m_SelectPossibleDuplicateEntryOnPricesAndDates(); - } - if (!m_SelectedTransactions.empty()) { - ImGui::Separator(); - if (ImGui::MenuItem("Reset Selection")) { - m_ResetSelection(); - } - } - ImGui::EndMenu(); - } -} - -void DataBrokers::m_drawDebugMenu(FrameActionSystem& vFrameActionSystem) { - if (ImGui::BeginMenu("Debug")) { - if (ImGui::MenuItem("Refresh")) { - RefreshDatas(); - } - ImGui::Separator(); - ImGui::MenuItem("Hidden Mode", nullptr, &m_HiddenMode); - ImGui::Separator(); - if (ImGui::BeginMenu("Delete Tables")) { - if (ImGui::MenuItem("Banks")) { - DataBase::Instance()->DeleteBanks(); - RefreshDatas(); - } - if (ImGui::MenuItem("Accounts")) { - DataBase::Instance()->DeleteAccounts(); - RefreshDatas(); - } - if (ImGui::MenuItem("Categories")) { - DataBase::Instance()->DeleteCategories(); - RefreshDatas(); - } - if (ImGui::MenuItem("Operations")) { - DataBase::Instance()->DeleteOperations(); - RefreshDatas(); - } - if (ImGui::MenuItem("Transactions")) { - DataBase::Instance()->DeleteTransactions(); - RefreshDatas(); - } - ImGui::EndMenu(); - } - ImGui::EndMenu(); - } -} - -void DataBrokers::m_drawAccountsMenu(FrameActionSystem& vFrameActionSystem) { - if (ImGui::BeginMenu("Accounts")) { - for (const auto& bank : m_Accounts) { - if (ImGui::BeginMenu(bank.first.c_str())) { // bank name - for (const auto& agency : bank.second) { - if (ImGui::BeginMenu(agency.first.c_str())) { // bank agency - static auto flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; - if (ImGui::BeginTable("##MenuAccounts", 4, flags)) { - ImGui::TableSetupScrollFreeze(0, 1); - ImGui::TableSetupColumn("Number", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("Count", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableHeadersRow(); - size_t idx = 0U; - for (const auto& number : agency.second) { - const auto& a = number.second; - ImGui::TableNextRow(); - - ImGui::PushID(a.id); - { - ImGui::TableNextColumn(); - ImGui::PushID(&a); - { - if (ImGui::Selectable(a.number.c_str(), m_SelectedAccountIdx == idx, ImGuiSelectableFlags_SpanAllColumns)) { - m_ResetSelection(); - m_UpdateTransactions(a.id); - m_SelectedAccountIdx = idx; - } - } - ImGui::PopID(); - m_drawAccountMenu(a); - - ImGui::TableNextColumn(); - ImGui::Text(a.name.c_str()); - - ImGui::TableNextColumn(); - ImGui::Text(a.type.c_str()); - - ImGui::TableNextColumn(); - ImGui::Text("%u", a.count); - - } - ImGui::PopID(); - - ++idx; - } - ImGui::EndTable(); - } - ImGui::EndMenu(); - } - } - ImGui::EndMenu(); - } - } - ImGui::EndMenu(); - } -} - -void DataBrokers::m_drawCreationMenu(FrameActionSystem& vFrameActionSystem) { - if (ImGui::BeginMenu("Add")) { - if (ImGui::MenuItem("Bank")) { - m_BankDialog.show(DataDialogMode::MODE_CREATION); - } - if (ImGui::MenuItem("Account")) { - m_AccountDialog.show(DataDialogMode::MODE_CREATION); - } - if (ImGui::MenuItem("Category")) { - m_CategoryDialog.show(DataDialogMode::MODE_CREATION); - } - if (ImGui::MenuItem("Operation")) { - m_OperationDialog.show(DataDialogMode::MODE_CREATION); - } - if (ImGui::MenuItem("Transaction")) { - m_TransactionDialog.show(DataDialogMode::MODE_CREATION); - } - ImGui::EndMenu(); - } -} - -std::string DataBrokers::getXml(const std::string& vOffset, const std::string& vUserDatas) { - UNUSED(vUserDatas); - std::string res; - res += vOffset + "\n"; - // we save all modules not just the one is selected - /*for (const auto& mod : m_DataBrokerModules) { - auto ptr = dynamic_cast(mod.second.get()); - if (ptr != nullptr) { - if (vUserDatas == "app") { - res += ptr->GetXmlSettings(vOffset + "\t", Cash::ISettingsType::APP); - } else if (vUserDatas == "project") { - res += ptr->GetXmlSettings(vOffset + "\t", Cash::ISettingsType::PROJECT); - } else { - CTOOL_DEBUG_BREAK; // ERROR - } - } - }*/ - res += vOffset + "\n"; - return res; -} - -bool DataBrokers::setFromXml(tinyxml2::XMLElement* vElem, tinyxml2::XMLElement* vParent, const std::string& vUserDatas) { - UNUSED(vUserDatas); - - // The value of this child identifies the name of this element - std::string strName; - std::string strValue; - std::string strParentName; - - strName = vElem->Value(); - if (vElem->GetText()) - strValue = vElem->GetText(); - if (vParent != nullptr) - strParentName = vParent->Value(); - - // we load all modules not just the one is selected - /*for (const auto& mod : m_DataBrokerModules) { - auto ptr = dynamic_cast(mod.second.get()); - if (ptr != nullptr) { - if (vUserDatas == "app") { - ptr->SetXmlSettings(strName, strParentName, strValue, Cash::ISettingsType::APP); - RecursParsingConfigChilds(vElem, vUserDatas); - } else if (vUserDatas == "project") { - ptr->SetXmlSettings(strName, strParentName, strValue, Cash::ISettingsType::PROJECT); - RecursParsingConfigChilds(vElem, vUserDatas); - } else { - CTOOL_DEBUG_BREAK; // ERROR - } - } - }*/ - - return true; -} - -void DataBrokers::RefreshDatas() { - m_UpdateBanks(); - m_UpdateCategories(); - m_UpdateOperations(); - m_UpdateAccounts(); -} - -void DataBrokers::m_Clear() { - m_SelectedBroker.reset(); // must be reset before quit since point on the memroy of a plugin - m_DataBrokerModules.clear(); - m_Datas.clear(); -} - -void DataBrokers::m_GetAvailableDataBrokers() { - m_Clear(); - auto modules = PluginManager::Instance()->GetPluginModulesInfos(); - for (const auto& mod : modules) { - if (mod.type == Cash::PluginModuleType::DATA_BROKER) { - auto ptr = std::dynamic_pointer_cast(PluginManager::Instance()->CreatePluginModule(mod.label)); - if (ptr != nullptr) { - m_DataBrokerModules[mod.path][mod.label] = ptr; - } - } - } -} - -void DataBrokers::m_ImportFromFiles(const std::vector vFiles) { - auto ptr = m_SelectedBroker.lock(); - if (ptr != nullptr) { - for (const auto& file : vFiles) { - const auto& stmt = ptr->importBankStatement(file); - if (!stmt.statements.empty()) { - RowID account_id = 0U; - if (DataBase::Instance()->GetAccount(stmt.account.number, account_id)) { - if (DataBase::Instance()->BeginTransaction()) { - for (const auto& s : stmt.statements) { - DataBase::Instance()->AddTransaction( // - account_id, // - s.operation, - s.category, - s.source, - s.source_type, - s.source_sha1, - s.date, - s.description, - s.comment, - s.amount, - s.confirmed, - s.hash); - } - DataBase::Instance()->CommitTransaction(); - m_RefreshFiltering(); - } - } else { - LogVarError("Import interrupted, no account found for %s", stmt.account.number.c_str()); - break; - } - } - } - } -} - -void DataBrokers::m_ResetFiltering() { - m_Datas.transactions_filtered = m_Datas.transactions; - m_Datas.transactions_filtered_rowids = {}; - m_SearchInputTexts = {}; - m_SearchTokens = {}; - m_RefreshFiltering(); -} - -void DataBrokers::m_RefreshFiltering() { - m_Datas.transactions_filtered.clear(); - m_Datas.transactions_filtered_rowids.clear(); - bool use = false; - double solde = m_CurrentBaseSolde; - m_TotalDebit = 0.0; - m_TotalCredit = 0.0; - for (auto tr : m_Datas.transactions) { - use = true; - for (size_t idx = 0; idx < 5; ++idx) { - const auto& tk = m_SearchTokens.at(idx); - if (!tk.empty()) { - use &= (tr.optimized.at(idx).find(tk) != std::string::npos); - } - } - if (use) { - solde += tr.amount; - tr.solde = solde; - m_Datas.transactions_filtered.push_back(tr); - m_Datas.transactions_filtered_rowids.emplace(tr.id); - if (tr.amount < 0.0) { - m_TotalDebit += tr.amount; - } - if (tr.amount > 0.0) { - m_TotalCredit += tr.amount; - } - } - } -} - -void DataBrokers::m_SelectOrDeselectRow(const Transaction& vTransaction) { - if (m_SelectedTransactions.find(vTransaction.id) != m_SelectedTransactions.end()) { - m_SelectedTransactions.erase(vTransaction.id); // deselection - } else { - m_SelectedTransactions.emplace(vTransaction.id); // selection - } -} - -bool DataBrokers::m_IsRowSelected(const RowID& vRowID) const { - return (m_SelectedTransactions.find(vRowID) != m_SelectedTransactions.end()); -} - -void DataBrokers::m_ResetSelection() { - m_SelectedTransactions.clear(); -} - -void DataBrokers::m_SelectCurrentRows() { - m_SelectedTransactions = m_Datas.transactions_filtered_rowids; -} - -void DataBrokers::m_SelectPossibleDuplicateEntryOnPricesAndDates() { - if (m_SelectedAccountIdx < m_Datas.accounts.size()) { - RowID account_id = m_Datas.accounts.at(m_SelectedAccountIdx).id; - m_ResetSelection(); - DataBase::Instance()->GetDuplicateTransactionsOnDatesAndAmount( // - account_id, // - [this](const RowID& vRowID) { - if (m_Datas.transactions_filtered_rowids.find(vRowID) != // - m_Datas.transactions_filtered_rowids.end()) { - m_SelectedTransactions.emplace(vRowID); // select row id - } - }); - } -} - -void DataBrokers::m_SelectUnConfirmedTransactions() { - if (m_SelectedAccountIdx < m_Datas.accounts.size()) { - RowID account_id = m_Datas.accounts.at(m_SelectedAccountIdx).id; - m_ResetSelection(); - DataBase::Instance()->GetUnConfirmedTransactions( // - account_id, // - [this](const RowID& vRowID) { - if (m_Datas.transactions_filtered_rowids.find(vRowID) != // - m_Datas.transactions_filtered_rowids.end()) { - m_SelectedTransactions.emplace(vRowID); // select row id - } - }); - } -} - -bool DataBrokers::m_IsHiddenMode() { - return -#ifdef _DEBUG - m_HiddenMode; -#else - false; -#endif -} - -void DataBrokers::m_HideByFilledRectForHiddenMode(const char* fmt, ...) { - if (m_IsHiddenMode()) { - va_list args; - va_start(args, fmt); - const char *text, *text_end; - ImFormatStringToTempBufferV(&text, &text_end, fmt, args); - if (strlen(text) != 0) { - const float& item_h = ImGui::GetTextLineHeightWithSpacing(); - const auto min = ImGui::GetCursorScreenPos() - ImVec2(0, item_h); - const auto max = min + ImGui::CalcTextSize(text, text_end); - auto drawListPtr = ImGui::GetWindowDrawList(); - drawListPtr->AddRectFilled(min, max, ImGui::GetColorU32(ImGuiCol_Text)); - } - va_end(args); - } -} - -void DataBrokers::m_DisplayAlignedWidget(const float& vWidth, const std::string& vLabel, const float& vOffsetFromStart, std::function vWidget) { - float px = ImGui::GetCursorPosX(); - ImGui::Text("%s", vLabel.c_str()); - ImGui::SameLine(vOffsetFromStart); - const float w = vWidth - (ImGui::GetCursorPosX() - px); - ImGui::PushID(++ImGui::CustomStyle::pushId); - ImGui::PushItemWidth(w); - if (vWidget != nullptr) { - vWidget(); - } - ImGui::PopItemWidth(); - ImGui::PopID(); -} - -void DataBrokers::m_UpdateBanks() { - m_Datas.bankNames.clear(); - DataBase::Instance()->GetBanks( // - [this](const BankName& vUserName, const std::string& /*vUrl*/) { // - m_Datas.bankNames.push_back(vUserName); - }); -} - -void DataBrokers::m_UpdateCategories() { - m_Datas.categoryNames.clear(); - DataBase::Instance()->GetCategories( // - [this](const CategoryName& vCategoryName) { // - m_Datas.categoryNames.push_back(vCategoryName); - }); -} - -void DataBrokers::m_UpdateOperations() { - m_Datas.operationNames.clear(); - DataBase::Instance()->GetOperations( // - [this](const OperationName& vOperationName) { // - m_Datas.operationNames.push_back(vOperationName); - }); -} - -void DataBrokers::m_UpdateAccounts() { - m_Datas.accounts.clear(); - m_Datas.accountNumbers.clear(); - DataBase::Instance()->GetAccounts( // - [this](const RowID& vRowID, - const BankName& vBankName, - const BankAgency& vBankAgency, - const AccountType& vAccountType, - const AccountName& vAccountName, - const AccountNumber& vAccountNumber, - const AccounBaseSolde& vBaseSolde, - const TransactionsCount& vCount) { // - Account a; - a.id = vRowID; - a.bank = vBankName; - a.agency = vBankAgency; - a.type = vAccountType; - a.name = vAccountName; - a.number = vAccountNumber; - a.base_solde = vBaseSolde; - a.count = vCount; - m_Datas.accounts.push_back(a); - m_Datas.accountNumbers.push_back(vAccountNumber); - m_Accounts[vBankName + "##BankName"][vBankAgency + "##BankAgency"][vAccountNumber] = a; - }); - if (m_SelectedAccountIdx < m_Datas.accounts.size()) { - m_UpdateTransactions(m_Datas.accounts.at(m_SelectedAccountIdx).id); - } -} - -void DataBrokers::m_drawAccountMenu(const Account& vAccount) { - ImGui::PushID(vAccount.id); - if (ImGui::BeginPopupContextItem( // - NULL, // - ImGuiPopupFlags_NoOpenOverItems | // - ImGuiPopupFlags_MouseButtonRight | // - ImGuiPopupFlags_NoOpenOverExistingPopup)) { - if (ImGui::MenuItem("Update")) { - m_AccountDialog.setAccount(vAccount); - m_AccountDialog.show(DataDialogMode::MODE_UPDATE_ONCE); - } - if (ImGui::MenuItem("Delete")) { - m_AccountDialog.setAccount(vAccount); - m_AccountDialog.show(DataDialogMode::MODE_DELETE_ONCE); - } - ImGui::EndPopup(); - } - ImGui::PopID(); -} - -void DataBrokers::m_UpdateTransactions(const RowID& vAccountID) { - m_Datas.transactions.clear(); - const auto& zero_based_account_id = vAccountID - 1; - if (zero_based_account_id < m_Datas.accounts.size()) { - double solde = m_CurrentBaseSolde = m_Datas.accounts.at(zero_based_account_id).base_solde; - const auto& account_number = m_Datas.accounts.at(zero_based_account_id).number; - DataBase::Instance()->GetTransactions( // - vAccountID, // - [this, &solde, account_number]( // - const RowID& vTransactionID, - const OperationName& vOperationName, - const CategoryName& vCategoryName, - const SourceName& vSourceName, - const TransactionDate& vTransactionDate, - const TransactionDescription& vTransactionDescription, - const TransactionComment& vTransactionComment, - const TransactionAmount& vTransactionAmount, - const TransactionConfirmed& vConfirmed, - const TransactionHash& vHash) { // - solde += vTransactionAmount; - Transaction t; - t.id = vTransactionID; - t.account = account_number; - t.date = vTransactionDate; - t.optimized[0] = ct::toLower(vTransactionDate); - t.description = vTransactionDescription; - t.optimized[1] = ct::toLower(vTransactionDescription); - t.comment = vTransactionComment; - t.optimized[2] = ct::toLower(vTransactionComment); - t.category = vCategoryName; - t.optimized[3] = ct::toLower(vCategoryName); - t.operation = vOperationName; - t.optimized[4] = ct::toLower(vOperationName); - t.hash = vHash; - t.source = vSourceName; - t.amount = vTransactionAmount; - t.confirmed = vConfirmed; - t.solde = solde; - m_Datas.transactions.push_back(t); - }); - } - m_RefreshFiltering(); -} - -void DataBrokers::m_drawTransactionMenu(const Transaction& vTransaction) { - if (!m_SelectedTransactions.empty()) { - const auto* ptr = &vTransaction; - ImGui::PushID(ptr); - if (ImGui::BeginPopupContextItem( // - NULL, // - ImGuiPopupFlags_NoOpenOverItems | // - ImGuiPopupFlags_MouseButtonRight | // - ImGuiPopupFlags_NoOpenOverExistingPopup)) { - if (ImGui::MenuItem("Update selection")) { - std::vector transactions_to_update; - for (const auto& trans : m_Datas.transactions_filtered) { - if (m_SelectedTransactions.find(trans.id) != m_SelectedTransactions.end()) { - transactions_to_update.push_back(trans); - } - } - if (transactions_to_update.size() > 1U) { - m_TransactionDialog.setTransactionsToUpdate(transactions_to_update); - m_TransactionDialog.show(DataDialogMode::MODE_UPDATE_ALL); - } else if (transactions_to_update.size() == 1U) { - m_TransactionDialog.setTransaction(transactions_to_update.front()); - m_TransactionDialog.show(DataDialogMode::MODE_UPDATE_ONCE); - } - } - if (ImGui::MenuItem("Delete selection")) { - std::vector transactions_to_delete; - for (const auto& trans : m_Datas.transactions_filtered) { - if (m_SelectedTransactions.find(trans.id) != m_SelectedTransactions.end()) { - transactions_to_delete.push_back(trans); - } - } - m_TransactionDialog.setTransactionsToDelete(transactions_to_delete); - m_TransactionDialog.show(DataDialogMode::MODE_DELETE_ALL); - } - ImGui::EndPopup(); - } - ImGui::PopID(); - } -} - -void DataBrokers::m_drawSearchRow() { - bool change = false; - bool reset = false; - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - if (ImGui::ContrastedButton("R", nullptr, nullptr, ImGui::GetColumnWidth(0))) { - reset = true; - } - ImGui::PopStyleVar(); - for (size_t idx = 0; idx < 8; ++idx) { - ImGui::TableNextColumn(); - switch (idx) { - case 0: - case 1: - case 2: - case 3: - case 4: { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - if (m_SearchInputTexts.at(idx).DisplayInputText(ImGui::GetColumnWidth(idx), "", "")) { - m_SearchTokens[idx] = ct::toLower(m_SearchInputTexts.at(idx).GetText()); - change = true; - } - ImGui::PopStyleVar(); - } break; - case 5: { - m_drawAmount(m_TotalDebit); - } break; - case 6: { - m_drawAmount(m_TotalCredit); - } break; - case 7: { - // m_drawAmount(m_CurrentBaseSolde); - } break; - case 8: ImGui::Text("[%u]", (uint32_t)m_Datas.transactions_filtered.size()); break; - default: break; - } - } - if (reset) { - m_ResetFiltering(); - } - if (change) { - m_RefreshFiltering(); - } -} - -void DataBrokers::m_drawAmount(const double& vAmount) { - if (vAmount < 0.0) { - const auto& bad_color = ImGui::GetColorU32(ImVec4(1, 0, 0, 1)); - ImGui::PushStyleColor(ImGuiCol_Text, bad_color); - ImGui::Text("%.2f", vAmount); - m_HideByFilledRectForHiddenMode("%.2f", vAmount); - ImGui::PopStyleColor(); - } else if (vAmount > 0.0) { - const auto& good_color = ImGui::GetColorU32(ImVec4(0, 1, 0, 1)); - ImGui::PushStyleColor(ImGuiCol_Text, good_color); - ImGui::Text("%.2f", vAmount); - m_HideByFilledRectForHiddenMode("%.2f", vAmount); - ImGui::PopStyleColor(); - } else { - ImGui::Text("%.2f", vAmount); - m_HideByFilledRectForHiddenMode("%.2f", vAmount); - } -} diff --git a/src/Models/DataBrokers.h b/src/Models/DataBrokers.h deleted file mode 100644 index 153aa11..0000000 --- a/src/Models/DataBrokers.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -class DataBrokers : public conf::ConfigAbstract { -private: - struct Datas { - std::vector bankNames; - std::vector categoryNames; - std::vector operationNames; - std::vector accounts; - std::vector accountNumbers; - std::vector transactions; - std::vector transactions_filtered; - std::set transactions_filtered_rowids; - void clear() { - accounts.clear(); - bankNames.clear(); - transactions.clear(); - categoryNames.clear(); - accountNumbers.clear(); - operationNames.clear(); - transactions_filtered.clear(); - } - } m_Datas; - -private: - using DataBrokerName = std::string; - using DataBrokerWay = std::string; - std::map> m_DataBrokerModules; - Cash::BankStatementModuleWeak m_SelectedBroker; - ImGuiListClipper m_TransactionsListClipper; - ImGuiListClipper m_TransactionsDeletionListClipper; - size_t m_SelectedAccountIdx = 0U; - - BankDialog m_BankDialog; - AccountDialog m_AccountDialog; - CategoryDialog m_CategoryDialog; - OperationDialog m_OperationDialog; - TransactionDialog m_TransactionDialog; - - TransactionAmount m_CurrentBaseSolde = 0.0; - TransactionAmount m_TotalDebit = 0.0; - TransactionAmount m_TotalCredit = 0.0; - - // search for date, desc, comm, cat, ope - std::array m_SearchInputTexts; - std::array m_SearchTokens; - - // selection - std::set m_SelectedTransactions; - - // accounts display - std::map>> m_Accounts; - - // hidden mode - bool m_HiddenMode = false; - -public: - bool init(); - void unit(); - - void load(); - - bool draw(); - void drawDialogs(const ImVec2& vPos, const ImVec2& vSize); - void drawMenu(FrameActionSystem& vFrameActionSystem); - - void DisplayTransactions(); - - void RefreshDatas(); - - std::string getXml(const std::string& vOffset, const std::string& vUserDatas) override; - bool setFromXml(tinyxml2::XMLElement* vElem, tinyxml2::XMLElement* vParent, const std::string& vUserDatas) override; - -private: - void m_drawAccountsMenu(FrameActionSystem& vFrameActionSystem); - void m_drawCreationMenu(FrameActionSystem& vFrameActionSystem); - void m_drawImportMenu(FrameActionSystem& vFrameActionSystem); - void m_drawSelectMenu(FrameActionSystem& vFrameActionSystem); - void m_drawDebugMenu(FrameActionSystem& vFrameActionSystem); - void m_Clear(); - void m_GetAvailableDataBrokers(); - void m_ImportFromFiles(const std::vector vFiles); - void m_ResetFiltering(); - void m_RefreshFiltering(); - void m_SelectOrDeselectRow(const Transaction& vTransaction); - bool m_IsRowSelected(const RowID& vRowID) const; - void m_ResetSelection(); - void m_SelectCurrentRows(); - void m_SelectPossibleDuplicateEntryOnPricesAndDates(); - void m_SelectUnConfirmedTransactions(); - bool m_IsHiddenMode(); - void m_HideByFilledRectForHiddenMode(const char* fmt, ...); - void m_DisplayAlignedWidget( // - const float& vWidth, - const std::string& vLabel, - const float& vOffsetFromStart, - std::function vWidget); - -private: // ImGui - void m_UpdateBanks(); - void m_UpdateAccounts(); - void m_UpdateCategories(); - void m_UpdateOperations(); - void m_UpdateTransactions(const RowID& vAccountID); - - void m_drawAccountMenu(const Account& vAccount); - void m_drawTransactionMenu(const Transaction& vTransaction); - - void m_drawSearchRow(); - void m_drawAmount(const double& vAmount); - -public: // singleton - static DataBrokers* Instance() { - static DataBrokers _instance; - return &_instance; - } -}; diff --git a/src/Panes/AccountPane.cpp b/src/Panes/AccountPane.cpp index 8f4291f..459fe21 100644 --- a/src/Panes/AccountPane.cpp +++ b/src/Panes/AccountPane.cpp @@ -2,10 +2,13 @@ // PVS-Studio Static Account Analyzer for C, C++ and C#: http://www.viva64.com #include + #include // printf zu + +#include #include -#include #include +#include AccountPane::AccountPane() = default; AccountPane::~AccountPane() { @@ -13,11 +16,23 @@ AccountPane::~AccountPane() { } bool AccountPane::Init() { + bool ret = true; + m_GetAvailableDataBrokers(); + ret &= m_BankDialog.init(); + ret &= m_AccountDialog.init(); + ret &= m_CategoryDialog.init(); + ret &= m_OperationDialog.init(); + ret &= m_TransactionDialog.init(); return true; } void AccountPane::Unit() { - + m_BankDialog.init(); + m_AccountDialog.init(); + m_CategoryDialog.init(); + m_OperationDialog.init(); + m_TransactionDialog.unit(); + m_Clear(); } /////////////////////////////////////////////////////////////////////////////////// @@ -28,7 +43,7 @@ bool AccountPane::DrawPanes(const uint32_t& /*vCurrentFrame*/, bool* vOpened, Im ImGui::SetCurrentContext(vContextPtr); bool change = false; if (vOpened != nullptr && *vOpened) { - static ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_MenuBar; + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_MenuBar; if (ImGui::Begin(GetName().c_str(), vOpened, flags)) { #ifdef USE_DECORATIONS_FOR_RESIZE_CHILD_WINDOWS auto win = ImGui::GetCurrentWindowRead(); @@ -37,10 +52,9 @@ bool AccountPane::DrawPanes(const uint32_t& /*vCurrentFrame*/, bool* vOpened, Im else flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_MenuBar; #endif - if (ProjectFile::Instance()->IsProjectLoaded()){ - DataBrokers::Instance()->drawMenu(MainFrontend::Instance()->GetActionSystemRef()); - //DataBrokers::Instance()->DisplayAccounts(); - DataBrokers::Instance()->DisplayTransactions(); + if (ProjectFile::Instance()->IsProjectLoaded()) { + m_drawMenu(MainFrontend::Instance()->GetActionSystemRef()); + m_displayTransactions(); } } @@ -54,12 +68,821 @@ bool AccountPane::DrawOverlays(const uint32_t& /*vCurrentFrame*/, const ImRect& return false; } -bool AccountPane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImVec2& /*vMaxSize*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { +bool AccountPane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImRect& vRect, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { ImGui::SetCurrentContext(vContextPtr); - return false; + const ImVec2 center = vRect.GetCenter(); + + bool ret = false; + ret |= m_BankDialog.draw(center); + ret |= m_AccountDialog.draw(center); + ret |= m_CategoryDialog.draw(center); + ret |= m_OperationDialog.draw(center); + ret |= m_TransactionDialog.draw(center); + + if (ret) { + m_refreshDatas(); + } + + ImVec2 max = vRect.GetSize(); + ImVec2 min = max * 0.5f; + + if (ImGuiFileDialog::Instance()->Display("Import Datas", ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking, min, max)) { + if (ImGuiFileDialog::Instance()->IsOk()) { + const auto& selection = ImGuiFileDialog::Instance()->GetSelection(); + if (!selection.empty()) { + std::vector files; + for (const auto& s : selection) { + files.push_back(s.second); + } + m_ImportFromFiles(files); + ret = true; + } + } + ImGuiFileDialog::Instance()->Close(); + } + + return ret; } bool AccountPane::DrawWidgets(const uint32_t& /*vCurrentFrame*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { ImGui::SetCurrentContext(vContextPtr); return false; } + +void AccountPane::load() { + m_refreshDatas(); +} + +void AccountPane::m_refreshDatas() { + m_UpdateBanks(); + m_UpdateCategories(); + m_UpdateOperations(); + m_UpdateAccounts(); +} + +void AccountPane::m_drawMenu(FrameActionSystem& vFrameActionSystem) { + if (ProjectFile::Instance()->IsProjectLoaded()) { + if (ImGui::BeginMenuBar()) { + m_drawAccountsMenu(vFrameActionSystem); + m_drawCreationMenu(vFrameActionSystem); + m_drawImportMenu(vFrameActionSystem); + m_drawSelectMenu(vFrameActionSystem); +#ifdef _DEBUG + m_drawDebugMenu(vFrameActionSystem); +#endif + ImGui::EndMenuBar(); + } + } +} + +void AccountPane::m_displayTransactions() { + ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 30.0f); + static auto flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY; + if (ImGui::BeginTable("##Transactions", 10, flags)) { + ImGui::TableSetupScrollFreeze(0, 2); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Dates", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Descriptions", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Comments", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Category", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Operation", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Debit", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Credit", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Solde", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Bars", ImGuiTableColumnFlags_WidthFixed); + m_drawSearchRow(); + ImGui::TableHeadersRow(); + int32_t idx = 0; + double max_price = DBL_MIN; + const float& bar_column_width = 100.0f; + auto drawListPtr = ImGui::GetWindowDrawList(); + const float& text_h = ImGui::GetTextLineHeight(); + const float& item_h = ImGui::GetTextLineHeightWithSpacing(); + const auto& bad_color = ImGui::GetColorU32(ImVec4(1, 0, 0, 1)); + const auto& good_color = ImGui::GetColorU32(ImVec4(0, 1, 0, 1)); + m_TransactionsListClipper.Begin((int)m_Datas.transactions_filtered.size(), item_h); + while (m_TransactionsListClipper.Step()) { + max_price = 0.0; + for (idx = m_TransactionsListClipper.DisplayStart; idx < m_TransactionsListClipper.DisplayEnd; ++idx) { + if (idx < 0) { + continue; + } + const auto& t = m_Datas.transactions_filtered.at(idx); + const auto& as = std::abs(t.solde); + if (as > max_price) { + max_price = as; + } + } + + for (idx = m_TransactionsListClipper.DisplayStart; idx < m_TransactionsListClipper.DisplayEnd; ++idx) { + if (idx < 0) { + continue; + } + + auto& t = m_Datas.transactions_filtered.at(idx); + + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + { + ImGui::PushID(t.id); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + if (ImGui::Checkbox("##check", &t.confirmed)) { + DataBase::Instance()->ConfirmTransaction(t.id, t.confirmed); + } + ImGui::PopStyleVar(); + ImGui::PopID(); + } + + ImGui::TableNextColumn(); + { ImGui::Text(t.date.c_str()); } + + ImGui::TableNextColumn(); + { + ImGui::PushID(&t); + auto is_selected = m_IsRowSelected(t.id); + ImGui::Selectable(t.description.c_str(), &is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); + if (ImGui::IsItemHovered()) { + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + m_ResetSelection(); + m_SelectOrDeselectRow(t); + m_TransactionDialog.setTransaction(t); + m_TransactionDialog.show(DataDialogMode::MODE_UPDATE_ONCE); + } else if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + m_SelectOrDeselectRow(t); + } + } + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%s", t.description.c_str()); + ImGui::PopID(); + m_drawTransactionMenu(t); + } + + ImGui::TableNextColumn(); + { + ImGui::Text(t.comment.c_str()); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%s", t.comment.c_str()); + } + + ImGui::TableNextColumn(); + { + ImGui::Text(t.category.c_str()); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%s", t.category.c_str()); + } + + ImGui::TableNextColumn(); + { + ImGui::Text(t.operation.c_str()); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%s", t.operation.c_str()); + } + + ImGui::TableNextColumn(); + { + if (t.amount < 0.0) { + ImGui::PushStyleColor(ImGuiCol_Text, bad_color); + ImGui::Text("%.2f", t.amount); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", t.amount); + ImGui::PopStyleColor(); + } + } + + ImGui::TableNextColumn(); + { + if (t.amount >= 0.0) { + ImGui::PushStyleColor(ImGuiCol_Text, good_color); + ImGui::Text("%.2f", t.amount); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", t.amount); + ImGui::PopStyleColor(); + } + } + + ImGui::TableNextColumn(); + { + if (t.solde < 0.0) { + ImGui::PushStyleColor(ImGuiCol_Text, bad_color); + ImGui::Text("%.2f", t.solde); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", t.solde); + ImGui::PopStyleColor(); + } else if (t.solde > 0.0) { + ImGui::PushStyleColor(ImGuiCol_Text, good_color); + ImGui::Text("%.2f", t.solde); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", t.solde); + ImGui::PopStyleColor(); + } else { + ImGui::Text("%.2f", t.solde); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", t.solde); + } + } + + ImGui::TableNextColumn(); + { + const auto& cursor = ImGui::GetCursorScreenPos(); + const ImVec2 pMin(cursor.x, cursor.y + text_h * 0.1f); + const ImVec2 pMax(cursor.x + bar_column_width, cursor.y + text_h * 0.9f); + const float pMidX((pMin.x + pMax.x) * 0.5f); + ImGui::SetCursorScreenPos(pMin); + const float bw(bar_column_width * 0.5f * std::abs(t.solde) / (float)max_price); + if (t.solde < 0.0) { + drawListPtr->AddRectFilled(ImVec2(pMidX - bw, pMin.y), ImVec2(pMidX, pMax.y), bad_color); + } else if (t.solde > 0.0) { + drawListPtr->AddRectFilled(ImVec2(pMidX, pMin.y), ImVec2(pMidX + bw, pMax.y), good_color); + } + ImGui::SetCursorScreenPos(pMax); + } + } + } + m_TransactionsListClipper.End(); + ImGui::EndTable(); + } + ImGui::PopStyleVar(); +} + +void AccountPane::m_drawImportMenu(FrameActionSystem& vFrameActionSystem) { + if (ImGui::BeginMenu("Import")) { + for (const auto& broker : m_DataBrokerModules) { + if (ImGui::BeginMenu(broker.first.c_str())) { + for (const auto& way : broker.second) { + if (ImGui::MenuItem(way.first.c_str())) { + if (way.second != nullptr) { + m_SelectedBroker = way.second; + vFrameActionSystem.Clear(); + vFrameActionSystem.Add([&way]() { + const auto& ext = way.second->getFileExt(); + IGFD::FileDialogConfig config; + config.countSelectionMax = 0; + config.flags = ImGuiFileDialogFlags_Modal; + ImGuiFileDialog::Instance()->OpenDialog("Import Datas", "Import Datas from File", ext.c_str(), config); + return true; + }); + } + } + } + ImGui::EndMenu(); + } + } + ImGui::EndMenu(); + } +} + +void AccountPane::m_drawSelectMenu(FrameActionSystem& vFrameActionSystem) { + if (ImGui::BeginMenu("Select")) { + if (ImGui::MenuItem("Current rows")) { + m_SelectCurrentRows(); + } + if (ImGui::MenuItem("UnConfirmed entries")) { + m_SelectUnConfirmedTransactions(); + } + if (ImGui::MenuItem("Possible Duplicate entries on Prices and Dates")) { + m_SelectPossibleDuplicateEntryOnPricesAndDates(); + } + if (!m_SelectedTransactions.empty()) { + ImGui::Separator(); + if (ImGui::MenuItem("Reset Selection")) { + m_ResetSelection(); + } + } + ImGui::EndMenu(); + } +} + +void AccountPane::m_drawDebugMenu(FrameActionSystem& vFrameActionSystem) { + if (ImGui::BeginMenu("Debug")) { + if (ImGui::MenuItem("Refresh")) { + m_refreshDatas(); + } + ImGui::Separator(); + ImGui::MenuItem("Hidden Mode", nullptr, &m_HiddenMode); + ImGui::Separator(); + if (ImGui::BeginMenu("Delete Tables")) { + if (ImGui::MenuItem("Banks")) { + DataBase::Instance()->DeleteBanks(); + m_refreshDatas(); + } + if (ImGui::MenuItem("Accounts")) { + DataBase::Instance()->DeleteAccounts(); + m_refreshDatas(); + } + if (ImGui::MenuItem("Categories")) { + DataBase::Instance()->DeleteCategories(); + m_refreshDatas(); + } + if (ImGui::MenuItem("Operations")) { + DataBase::Instance()->DeleteOperations(); + m_refreshDatas(); + } + if (ImGui::MenuItem("Transactions")) { + DataBase::Instance()->DeleteTransactions(); + m_refreshDatas(); + } + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } +} + +void AccountPane::m_drawAccountsMenu(FrameActionSystem& vFrameActionSystem) { + if (ImGui::BeginMenu("Accounts")) { + for (const auto& bank : m_Accounts) { + if (ImGui::BeginMenu(bank.first.c_str())) { // bank name + for (const auto& agency : bank.second) { + if (ImGui::BeginMenu(agency.first.c_str())) { // bank agency + static auto flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; + if (ImGui::BeginTable("##MenuAccounts", 4, flags)) { + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableSetupColumn("Number", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Count", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableHeadersRow(); + size_t idx = 0U; + for (const auto& number : agency.second) { + const auto& a = number.second; + ImGui::TableNextRow(); + + ImGui::PushID(a.id); + { + ImGui::TableNextColumn(); + ImGui::PushID(&a); + { + if (ImGui::Selectable(a.number.c_str(), m_SelectedAccountIdx == idx, ImGuiSelectableFlags_SpanAllColumns)) { + m_ResetSelection(); + m_UpdateTransactions(a.id); + m_SelectedAccountIdx = idx; + } + } + ImGui::PopID(); + m_drawAccountMenu(a); + + ImGui::TableNextColumn(); + ImGui::Text(a.name.c_str()); + + ImGui::TableNextColumn(); + ImGui::Text(a.type.c_str()); + + ImGui::TableNextColumn(); + ImGui::Text("%u", a.count); + } + ImGui::PopID(); + + ++idx; + } + ImGui::EndTable(); + } + ImGui::EndMenu(); + } + } + ImGui::EndMenu(); + } + } + ImGui::EndMenu(); + } +} + +void AccountPane::m_drawCreationMenu(FrameActionSystem& vFrameActionSystem) { + if (ImGui::BeginMenu("Add")) { + if (ImGui::MenuItem("Bank")) { + m_BankDialog.show(DataDialogMode::MODE_CREATION); + } + if (ImGui::MenuItem("Account")) { + m_AccountDialog.show(DataDialogMode::MODE_CREATION); + } + if (ImGui::MenuItem("Category")) { + m_CategoryDialog.show(DataDialogMode::MODE_CREATION); + } + if (ImGui::MenuItem("Operation")) { + m_OperationDialog.show(DataDialogMode::MODE_CREATION); + } + if (ImGui::MenuItem("Transaction")) { + m_TransactionDialog.show(DataDialogMode::MODE_CREATION); + } + ImGui::EndMenu(); + } +} + +std::string AccountPane::getXml(const std::string& vOffset, const std::string& vUserDatas) { + UNUSED(vUserDatas); + std::string res; + res += vOffset + "\n"; + // we save all modules not just the one is selected + /*for (const auto& mod : m_DataBrokerModules) { + auto ptr = dynamic_cast(mod.second.get()); + if (ptr != nullptr) { + if (vUserDatas == "app") { + res += ptr->GetXmlSettings(vOffset + "\t", Cash::ISettingsType::APP); + } else if (vUserDatas == "project") { + res += ptr->GetXmlSettings(vOffset + "\t", Cash::ISettingsType::PROJECT); + } else { + CTOOL_DEBUG_BREAK; // ERROR + } + } + }*/ + res += vOffset + "\n"; + return res; +} + +bool AccountPane::setFromXml(tinyxml2::XMLElement* vElem, tinyxml2::XMLElement* vParent, const std::string& vUserDatas) { + UNUSED(vUserDatas); + + // The value of this child identifies the name of this element + std::string strName; + std::string strValue; + std::string strParentName; + + strName = vElem->Value(); + if (vElem->GetText()) + strValue = vElem->GetText(); + if (vParent != nullptr) + strParentName = vParent->Value(); + + // we load all modules not just the one is selected + /*for (const auto& mod : m_DataBrokerModules) { + auto ptr = dynamic_cast(mod.second.get()); + if (ptr != nullptr) { + if (vUserDatas == "app") { + ptr->SetXmlSettings(strName, strParentName, strValue, Cash::ISettingsType::APP); + RecursParsingConfigChilds(vElem, vUserDatas); + } else if (vUserDatas == "project") { + ptr->SetXmlSettings(strName, strParentName, strValue, Cash::ISettingsType::PROJECT); + RecursParsingConfigChilds(vElem, vUserDatas); + } else { + CTOOL_DEBUG_BREAK; // ERROR + } + } + }*/ + + return true; +} + +void AccountPane::m_Clear() { + m_SelectedBroker.reset(); // must be reset before quit since point on the memroy of a plugin + m_DataBrokerModules.clear(); + m_Datas.clear(); +} + +void AccountPane::m_GetAvailableDataBrokers() { + m_Clear(); + auto modules = PluginManager::Instance()->GetPluginModulesInfos(); + for (const auto& mod : modules) { + if (mod.type == Cash::PluginModuleType::DATA_BROKER) { + auto ptr = std::dynamic_pointer_cast(PluginManager::Instance()->CreatePluginModule(mod.label)); + if (ptr != nullptr) { + m_DataBrokerModules[mod.path][mod.label] = ptr; + } + } + } +} + +void AccountPane::m_ImportFromFiles(const std::vector vFiles) { + auto ptr = m_SelectedBroker.lock(); + if (ptr != nullptr) { + for (const auto& file : vFiles) { + const auto& stmt = ptr->importBankStatement(file); + if (!stmt.statements.empty()) { + RowID account_id = 0U; + if (DataBase::Instance()->GetAccount(stmt.account.number, account_id)) { + if (DataBase::Instance()->BeginTransaction()) { + for (const auto& s : stmt.statements) { + DataBase::Instance()->AddTransaction( // + account_id, // + s.operation, + s.category, + s.source, + s.source_type, + s.source_sha1, + s.date, + s.description, + s.comment, + s.amount, + s.confirmed, + s.hash); + } + DataBase::Instance()->CommitTransaction(); + m_RefreshFiltering(); + } + } else { + LogVarError("Import interrupted, no account found for %s", stmt.account.number.c_str()); + break; + } + } + } + } +} + +void AccountPane::m_ResetFiltering() { + m_Datas.transactions_filtered = m_Datas.transactions; + m_Datas.transactions_filtered_rowids = {}; + m_SearchInputTexts = {}; + m_SearchTokens = {}; + m_RefreshFiltering(); +} + +void AccountPane::m_RefreshFiltering() { + m_Datas.transactions_filtered.clear(); + m_Datas.transactions_filtered_rowids.clear(); + bool use = false; + double solde = m_CurrentBaseSolde; + m_TotalDebit = 0.0; + m_TotalCredit = 0.0; + for (auto tr : m_Datas.transactions) { + use = true; + for (size_t idx = 0; idx < 5; ++idx) { + const auto& tk = m_SearchTokens.at(idx); + if (!tk.empty()) { + use &= (tr.optimized.at(idx).find(tk) != std::string::npos); + } + } + if (use) { + solde += tr.amount; + tr.solde = solde; + m_Datas.transactions_filtered.push_back(tr); + m_Datas.transactions_filtered_rowids.emplace(tr.id); + if (tr.amount < 0.0) { + m_TotalDebit += tr.amount; + } + if (tr.amount > 0.0) { + m_TotalCredit += tr.amount; + } + } + } +} + +void AccountPane::m_SelectOrDeselectRow(const Transaction& vTransaction) { + if (m_SelectedTransactions.find(vTransaction.id) != m_SelectedTransactions.end()) { + m_SelectedTransactions.erase(vTransaction.id); // deselection + } else { + m_SelectedTransactions.emplace(vTransaction.id); // selection + } +} + +bool AccountPane::m_IsRowSelected(const RowID& vRowID) const { + return (m_SelectedTransactions.find(vRowID) != m_SelectedTransactions.end()); +} + +void AccountPane::m_ResetSelection() { + m_SelectedTransactions.clear(); +} + +void AccountPane::m_SelectCurrentRows() { + m_SelectedTransactions = m_Datas.transactions_filtered_rowids; +} + +void AccountPane::m_SelectPossibleDuplicateEntryOnPricesAndDates() { + if (m_SelectedAccountIdx < m_Datas.accounts.size()) { + RowID account_id = m_Datas.accounts.at(m_SelectedAccountIdx).id; + m_ResetSelection(); + DataBase::Instance()->GetDuplicateTransactionsOnDatesAndAmount( // + account_id, // + [this](const RowID& vRowID) { + if (m_Datas.transactions_filtered_rowids.find(vRowID) != // + m_Datas.transactions_filtered_rowids.end()) { + m_SelectedTransactions.emplace(vRowID); // select row id + } + }); + } +} + +void AccountPane::m_SelectUnConfirmedTransactions() { + if (m_SelectedAccountIdx < m_Datas.accounts.size()) { + RowID account_id = m_Datas.accounts.at(m_SelectedAccountIdx).id; + m_ResetSelection(); + DataBase::Instance()->GetUnConfirmedTransactions( // + account_id, // + [this](const RowID& vRowID) { + if (m_Datas.transactions_filtered_rowids.find(vRowID) != // + m_Datas.transactions_filtered_rowids.end()) { + m_SelectedTransactions.emplace(vRowID); // select row id + } + }); + } +} + +bool AccountPane::m_IsHiddenMode() { + return +#ifdef _DEBUG + m_HiddenMode; +#else + false; +#endif +} + +void AccountPane::m_UpdateBanks() { + m_Datas.bankNames.clear(); + DataBase::Instance()->GetBanks( // + [this](const BankName& vUserName, const std::string& /*vUrl*/) { // + m_Datas.bankNames.push_back(vUserName); + }); +} + +void AccountPane::m_UpdateCategories() { + m_Datas.categoryNames.clear(); + DataBase::Instance()->GetCategories( // + [this](const CategoryName& vCategoryName) { // + m_Datas.categoryNames.push_back(vCategoryName); + }); +} + +void AccountPane::m_UpdateOperations() { + m_Datas.operationNames.clear(); + DataBase::Instance()->GetOperations( // + [this](const OperationName& vOperationName) { // + m_Datas.operationNames.push_back(vOperationName); + }); +} + +void AccountPane::m_UpdateAccounts() { + m_Datas.accounts.clear(); + m_Datas.accountNumbers.clear(); + DataBase::Instance()->GetAccounts( // + [this](const RowID& vRowID, + const BankName& vBankName, + const BankAgency& vBankAgency, + const AccountType& vAccountType, + const AccountName& vAccountName, + const AccountNumber& vAccountNumber, + const AccounBaseSolde& vBaseSolde, + const TransactionsCount& vCount) { // + Account a; + a.id = vRowID; + a.bank = vBankName; + a.agency = vBankAgency; + a.type = vAccountType; + a.name = vAccountName; + a.number = vAccountNumber; + a.base_solde = vBaseSolde; + a.count = vCount; + m_Datas.accounts.push_back(a); + m_Datas.accountNumbers.push_back(vAccountNumber); + m_Accounts[vBankName + "##BankName"][vBankAgency + "##BankAgency"][vAccountNumber] = a; + }); + if (m_SelectedAccountIdx < m_Datas.accounts.size()) { + m_UpdateTransactions(m_Datas.accounts.at(m_SelectedAccountIdx).id); + } +} + +void AccountPane::m_drawAccountMenu(const Account& vAccount) { + ImGui::PushID(vAccount.id); + if (ImGui::BeginPopupContextItem( // + NULL, // + ImGuiPopupFlags_NoOpenOverItems | // + ImGuiPopupFlags_MouseButtonRight | // + ImGuiPopupFlags_NoOpenOverExistingPopup)) { + if (ImGui::MenuItem("Update")) { + m_AccountDialog.setAccount(vAccount); + m_AccountDialog.show(DataDialogMode::MODE_UPDATE_ONCE); + } + if (ImGui::MenuItem("Delete")) { + m_AccountDialog.setAccount(vAccount); + m_AccountDialog.show(DataDialogMode::MODE_DELETE_ONCE); + } + ImGui::EndPopup(); + } + ImGui::PopID(); +} + +void AccountPane::m_UpdateTransactions(const RowID& vAccountID) { + m_Datas.transactions.clear(); + const auto& zero_based_account_id = vAccountID - 1; + if (zero_based_account_id < m_Datas.accounts.size()) { + double solde = m_CurrentBaseSolde = m_Datas.accounts.at(zero_based_account_id).base_solde; + const auto& account_number = m_Datas.accounts.at(zero_based_account_id).number; + DataBase::Instance()->GetTransactions( // + vAccountID, // + [this, &solde, account_number]( // + const RowID& vTransactionID, + const OperationName& vOperationName, + const CategoryName& vCategoryName, + const SourceName& vSourceName, + const TransactionDate& vTransactionDate, + const TransactionDescription& vTransactionDescription, + const TransactionComment& vTransactionComment, + const TransactionAmount& vTransactionAmount, + const TransactionConfirmed& vConfirmed, + const TransactionHash& vHash) { // + solde += vTransactionAmount; + Transaction t; + t.id = vTransactionID; + t.account = account_number; + t.date = vTransactionDate; + t.optimized[0] = ct::toLower(vTransactionDate); + t.description = vTransactionDescription; + t.optimized[1] = ct::toLower(vTransactionDescription); + t.comment = vTransactionComment; + t.optimized[2] = ct::toLower(vTransactionComment); + t.category = vCategoryName; + t.optimized[3] = ct::toLower(vCategoryName); + t.operation = vOperationName; + t.optimized[4] = ct::toLower(vOperationName); + t.hash = vHash; + t.source = vSourceName; + t.amount = vTransactionAmount; + t.confirmed = vConfirmed; + t.solde = solde; + m_Datas.transactions.push_back(t); + }); + } + m_RefreshFiltering(); +} + +void AccountPane::m_drawTransactionMenu(const Transaction& vTransaction) { + if (!m_SelectedTransactions.empty()) { + const auto* ptr = &vTransaction; + ImGui::PushID(ptr); + if (ImGui::BeginPopupContextItem( // + NULL, // + ImGuiPopupFlags_NoOpenOverItems | // + ImGuiPopupFlags_MouseButtonRight | // + ImGuiPopupFlags_NoOpenOverExistingPopup)) { + if (ImGui::MenuItem("Update selection")) { + std::vector transactions_to_update; + for (const auto& trans : m_Datas.transactions_filtered) { + if (m_SelectedTransactions.find(trans.id) != m_SelectedTransactions.end()) { + transactions_to_update.push_back(trans); + } + } + if (transactions_to_update.size() > 1U) { + m_TransactionDialog.setTransactionsToUpdate(transactions_to_update); + m_TransactionDialog.show(DataDialogMode::MODE_UPDATE_ALL); + } else if (transactions_to_update.size() == 1U) { + m_TransactionDialog.setTransaction(transactions_to_update.front()); + m_TransactionDialog.show(DataDialogMode::MODE_UPDATE_ONCE); + } + } + if (ImGui::MenuItem("Delete selection")) { + std::vector transactions_to_delete; + for (const auto& trans : m_Datas.transactions_filtered) { + if (m_SelectedTransactions.find(trans.id) != m_SelectedTransactions.end()) { + transactions_to_delete.push_back(trans); + } + } + m_TransactionDialog.setTransactionsToDelete(transactions_to_delete); + m_TransactionDialog.show(DataDialogMode::MODE_DELETE_ALL); + } + ImGui::EndPopup(); + } + ImGui::PopID(); + } +} + +void AccountPane::m_drawSearchRow() { + bool change = false; + bool reset = false; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + if (ImGui::ContrastedButton("R", nullptr, nullptr, ImGui::GetColumnWidth(0))) { + reset = true; + } + ImGui::PopStyleVar(); + for (size_t idx = 0; idx < 8; ++idx) { + ImGui::TableNextColumn(); + switch (idx) { + case 0: + case 1: + case 2: + case 3: + case 4: { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + if (m_SearchInputTexts.at(idx).DisplayInputText(ImGui::GetColumnWidth(idx), "", "")) { + m_SearchTokens[idx] = ct::toLower(m_SearchInputTexts.at(idx).GetText()); + change = true; + } + ImGui::PopStyleVar(); + } break; + case 5: { + m_drawAmount(m_TotalDebit); + } break; + case 6: { + m_drawAmount(m_TotalCredit); + } break; + case 7: { + // m_drawAmount(m_CurrentBaseSolde); + } break; + case 8: ImGui::Text("[%u]", (uint32_t)m_Datas.transactions_filtered.size()); break; + default: break; + } + } + if (reset) { + m_ResetFiltering(); + } + if (change) { + m_RefreshFiltering(); + } +} + +void AccountPane::m_drawAmount(const double& vAmount) { + if (vAmount < 0.0) { + const auto& bad_color = ImGui::GetColorU32(ImVec4(1, 0, 0, 1)); + ImGui::PushStyleColor(ImGuiCol_Text, bad_color); + ImGui::Text("%.2f", vAmount); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", vAmount); + ImGui::PopStyleColor(); + } else if (vAmount > 0.0) { + const auto& good_color = ImGui::GetColorU32(ImVec4(0, 1, 0, 1)); + ImGui::PushStyleColor(ImGuiCol_Text, good_color); + ImGui::Text("%.2f", vAmount); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", vAmount); + ImGui::PopStyleColor(); + } else { + ImGui::Text("%.2f", vAmount); + ImGui::HideByFilledRectForHiddenMode(m_IsHiddenMode(), "%.2f", vAmount); + } +} diff --git a/src/Panes/AccountPane.h b/src/Panes/AccountPane.h index b3c786f..4c631f3 100644 --- a/src/Panes/AccountPane.h +++ b/src/Panes/AccountPane.h @@ -1,24 +1,118 @@ #pragma once -#include -#include #include #include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include class ProjectFile; -class AccountPane : public AbstractPane { +class AccountPane : public AbstractPane, public conf::ConfigAbstract { private: + struct Datas { + std::vector bankNames; + std::vector categoryNames; + std::vector operationNames; + std::vector accounts; + std::vector accountNumbers; + std::vector transactions; + std::vector transactions_filtered; + std::set transactions_filtered_rowids; + void clear() { + accounts.clear(); + bankNames.clear(); + transactions.clear(); + categoryNames.clear(); + accountNumbers.clear(); + operationNames.clear(); + transactions_filtered.clear(); + } + } m_Datas; + + DataBrockerContainer m_DataBrokerModules; + Cash::BankStatementModuleWeak m_SelectedBroker; + ImGuiListClipper m_TransactionsListClipper; + size_t m_SelectedAccountIdx = 0U; + + BankDialog m_BankDialog; + AccountDialog m_AccountDialog; + CategoryDialog m_CategoryDialog; + OperationDialog m_OperationDialog; + TransactionDialog m_TransactionDialog; + + TransactionAmount m_CurrentBaseSolde = 0.0; + TransactionAmount m_TotalDebit = 0.0; + TransactionAmount m_TotalCredit = 0.0; + + // search for date, desc, comm, cat, ope + std::array m_SearchInputTexts; + std::array m_SearchTokens; + + // selection + std::set m_SelectedTransactions; + + // accounts display + std::map>> m_Accounts; + + // hidden mode + bool m_HiddenMode = false; public: bool Init() override; void Unit() override; bool DrawWidgets(const uint32_t& vCurrentFrame, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; - bool DrawOverlays( - const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; - bool DrawPanes( - const uint32_t& vCurrentFrame, bool* vOpened = nullptr, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; - bool DrawDialogsAndPopups( - const uint32_t& vCurrentFrame, const ImVec2& vMaxSize, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + bool DrawOverlays(const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + bool DrawPanes(const uint32_t& vCurrentFrame, bool* vOpened = nullptr, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + bool DrawDialogsAndPopups(const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + + void load(); + + std::string getXml(const std::string& vOffset, const std::string& vUserDatas) override; + bool setFromXml(tinyxml2::XMLElement* vElem, tinyxml2::XMLElement* vParent, const std::string& vUserDatas) override; + +private: + void m_drawMenu(FrameActionSystem& vFrameActionSystem); + void m_displayTransactions(); + void m_refreshDatas(); + + void m_drawAccountsMenu(FrameActionSystem& vFrameActionSystem); + void m_drawCreationMenu(FrameActionSystem& vFrameActionSystem); + void m_drawImportMenu(FrameActionSystem& vFrameActionSystem); + void m_drawSelectMenu(FrameActionSystem& vFrameActionSystem); + void m_drawDebugMenu(FrameActionSystem& vFrameActionSystem); + void m_Clear(); + void m_GetAvailableDataBrokers(); + void m_ImportFromFiles(const std::vector vFiles); + void m_ResetFiltering(); + void m_RefreshFiltering(); + void m_SelectOrDeselectRow(const Transaction& vTransaction); + bool m_IsRowSelected(const RowID& vRowID) const; + void m_ResetSelection(); + void m_SelectCurrentRows(); + void m_SelectPossibleDuplicateEntryOnPricesAndDates(); + void m_SelectUnConfirmedTransactions(); + bool m_IsHiddenMode(); + + void m_UpdateBanks(); + void m_UpdateAccounts(); + void m_UpdateCategories(); + void m_UpdateOperations(); + void m_UpdateTransactions(const RowID& vAccountID); + + void m_drawAccountMenu(const Account& vAccount); + void m_drawTransactionMenu(const Transaction& vTransaction); + + void m_drawSearchRow(); + void m_drawAmount(const double& vAmount); public: // singleton static std::shared_ptr Instance() { diff --git a/src/Panes/BudgetPane.cpp b/src/Panes/BudgetPane.cpp index b311cc1..707387c 100644 --- a/src/Panes/BudgetPane.cpp +++ b/src/Panes/BudgetPane.cpp @@ -55,9 +55,8 @@ bool BudgetPane::DrawOverlays(const uint32_t& /*vCurrentFrame*/, const ImRect& / return false; } -bool BudgetPane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImVec2& /*vMaxSize*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { - ImGui::SetCurrentContext(vContextPtr); - +bool BudgetPane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImRect& /*vRect*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { + ImGui::SetCurrentContext(vContextPtr); return false; } diff --git a/src/Panes/BudgetPane.h b/src/Panes/BudgetPane.h index b8e79d4..0ab6182 100644 --- a/src/Panes/BudgetPane.h +++ b/src/Panes/BudgetPane.h @@ -19,7 +19,7 @@ class BudgetPane : public AbstractPane { bool DrawPanes( const uint32_t& vCurrentFrame, bool* vOpened = nullptr, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; bool DrawDialogsAndPopups( - const uint32_t& vCurrentFrame, const ImVec2& vMaxSize, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; public: // singleton static std::shared_ptr Instance() { diff --git a/src/Panes/BuySellPane.cpp b/src/Panes/BuySellPane.cpp new file mode 100644 index 0000000..761b8c5 --- /dev/null +++ b/src/Panes/BuySellPane.cpp @@ -0,0 +1,65 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Budget Analyzer for C, C++ and C#: http://www.viva64.com + +#include + +#include // printf zu + +#include + +#include + +BuySellPane::BuySellPane() = default; +BuySellPane::~BuySellPane() { + Unit(); +} + +bool BuySellPane::Init() { + m_EditCombo.init(0, {"TOTO", "TATA", "TITI", "TUTU"}); + return true; +} + +void BuySellPane::Unit() { +} + +/////////////////////////////////////////////////////////////////////////////////// +//// IMGUI PANE /////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// + +bool BuySellPane::DrawPanes(const uint32_t& /*vCurrentFrame*/, bool* vOpened, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { + ImGui::SetCurrentContext(vContextPtr); + bool change = false; + if (vOpened != nullptr && *vOpened) { + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus /* | ImGuiWindowFlags_MenuBar*/; + if (ImGui::Begin(GetName().c_str(), vOpened, flags)) { +#ifdef USE_DECORATIONS_FOR_RESIZE_CHILD_WINDOWS + auto win = ImGui::GetCurrentWindowRead(); + if (win->Viewport->Idx != 0) + flags |= ImGuiWindowFlags_NoResize; // | ImGuiWindowFlags_NoTitleBar; + else + flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus /* | ImGuiWindowFlags_MenuBar*/; +#endif + } + + if (ProjectFile::Instance()->IsProjectLoaded()) { + } + + ImGui::End(); + } + return change; +} + +bool BuySellPane::DrawOverlays(const uint32_t& /*vCurrentFrame*/, const ImRect& /*vRect*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { + ImGui::SetCurrentContext(vContextPtr); + return false; +} + +bool BuySellPane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImRect& /*vRect*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { + ImGui::SetCurrentContext(vContextPtr); + return false; +} + +bool BuySellPane::DrawWidgets(const uint32_t& /*vCurrentFrame*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { + ImGui::SetCurrentContext(vContextPtr); + return false; +} diff --git a/src/Panes/BuySellPane.h b/src/Panes/BuySellPane.h new file mode 100644 index 0000000..e7266f4 --- /dev/null +++ b/src/Panes/BuySellPane.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +class ProjectFile; +class BuySellPane : public AbstractPane { +private: + ImWidgets::QuickStringEditCombo m_EditCombo; + +public: + bool Init() override; + void Unit() override; + bool DrawWidgets(const uint32_t& vCurrentFrame, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + bool DrawOverlays( + const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + bool DrawPanes( + const uint32_t& vCurrentFrame, bool* vOpened = nullptr, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + bool DrawDialogsAndPopups( + const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + +public: // singleton + static std::shared_ptr Instance() { + static std::shared_ptr _instance = std::make_shared(); + return _instance; + } + +public: + BuySellPane(); // Prevent construction + BuySellPane(const BuySellPane&) = default; // Prevent construction by copying + BuySellPane& operator=(const BuySellPane&) { + return *this; + }; // Prevent assignment + virtual ~BuySellPane(); // Prevent unwanted destruction}; +}; diff --git a/src/Panes/ConsolePane.cpp b/src/Panes/ConsolePane.cpp index a1864a0..884fce6 100644 --- a/src/Panes/ConsolePane.cpp +++ b/src/Panes/ConsolePane.cpp @@ -50,7 +50,7 @@ bool ConsolePane::DrawOverlays(const uint32_t& /*vCurrentFrame*/, const ImRect& return false; } -bool ConsolePane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImVec2& /*vMaxSize*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { +bool ConsolePane::DrawDialogsAndPopups(const uint32_t& /*vCurrentFrame*/, const ImRect& /*vRect*/, ImGuiContext* vContextPtr, void* /*vUserDatas*/) { ImGui::SetCurrentContext(vContextPtr); return false; } diff --git a/src/Panes/ConsolePane.h b/src/Panes/ConsolePane.h index 6fcc619..c05d678 100644 --- a/src/Panes/ConsolePane.h +++ b/src/Panes/ConsolePane.h @@ -16,7 +16,7 @@ class ConsolePane : public AbstractPane { bool DrawPanes( const uint32_t& vCurrentFrame, bool* vOpened = nullptr, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; bool DrawDialogsAndPopups( - const uint32_t& vCurrentFrame, const ImVec2& vMaxSize, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; + const uint32_t& vCurrentFrame, const ImRect& vRect, ImGuiContext* vContextPtr = nullptr, void* vUserDatas = nullptr) override; public: // singleton static std::shared_ptr Instance() { diff --git a/src/Project/ProjectFile.cpp b/src/Project/ProjectFile.cpp index 206eeb8..4ac48b0 100644 --- a/src/Project/ProjectFile.cpp +++ b/src/Project/ProjectFile.cpp @@ -21,11 +21,12 @@ limitations under the License. #include #include + #include +#include +#include #include -#include #include -#include ProjectFile::ProjectFile() = default; @@ -98,7 +99,7 @@ bool ProjectFile::LoadAs(const std::string vFilePathName) { m_ProjectFilePath = ps.path; } m_IsLoaded = true; - DataBrokers::Instance()->load(); + AccountPane::Instance()->load(); SetProjectChange(false); } else { Clear(); @@ -200,7 +201,7 @@ std::string ProjectFile::getXml(const std::string& vOffset, const std::string& / str += vOffset + "\n"; const std::string& project_tag = "project"; str += LayoutManager::Instance()->getXml(vOffset + "\t", project_tag); - str += DataBrokers::Instance()->getXml(vOffset + "\t", project_tag); + str += AccountPane::Instance()->getXml(vOffset + "\t", project_tag); str += SettingsDialog::Instance()->getXml(vOffset + "\t", project_tag); str += vOffset + "\n"; return str; @@ -222,7 +223,7 @@ bool ProjectFile::setFromXml(tinyxml2::XMLElement* vElem, tinyxml2::XMLElement* } else if (strName == "project") { const std::string& project_tag = "project"; LayoutManager::Instance()->RecursParsingConfig(vElem, vParent, project_tag); - DataBrokers::Instance()->RecursParsingConfig(vElem, vParent, project_tag); + AccountPane::Instance()->RecursParsingConfig(vElem, vParent, project_tag); SettingsDialog::Instance()->RecursParsingConfig(vElem, vParent, project_tag); }