From 854c96781fe549edd14468ad98cb9071a4aaf68f Mon Sep 17 00:00:00 2001 From: Humdinger Date: Wed, 17 Jul 2024 17:29:57 +0200 Subject: [PATCH] Add filter view: the GUI side, no actually filtering * Add BMenu to choose a time period to filter, e.g. "This month". * Add BTextControls to filter for payee, category, memo, amount. * Add BMenu to choose <= or = or >= for the amount filtering. * Add BButtons to "Clear" the filter or "Filter" with the current settings. * When filtering is invoked, send a BMessage to the RegisterView with all the filter settings. For the fPeriodMenu and fCompareMenus, the index of the marked menu item is added to the BMessage. The order of the fPeriodMenu items should reflect filter_period_field in RegisterView.h. Those will be used when parsing the BMessage for the actual filtering. As the fCompareMenu only holds 3 items, we'll just test for 0, 1, 2. * Removed GetAccountViewWidth() because the new filter view will determine the width of the left sidebar, not the widest account name. --- Makefile | 1 + src/FilterView.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++ src/FilterView.h | 45 +++++++++++ src/RegisterView.cpp | 51 ++++++------- src/RegisterView.h | 22 +++++- 5 files changed, 264 insertions(+), 30 deletions(-) create mode 100644 src/FilterView.cpp create mode 100644 src/FilterView.h diff --git a/Makefile b/Makefile index 02f2763..7ebf1ee 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ SRCS = \ src/Database.cpp \ src/DateBox.cpp \ src/DStringList.cpp \ + src/FilterView.cpp \ src/Fixed.cpp \ src/HelpButton.cpp \ src/Import.cpp \ diff --git a/src/FilterView.cpp b/src/FilterView.cpp new file mode 100644 index 0000000..a2b8996 --- /dev/null +++ b/src/FilterView.cpp @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FilterView.h" +#include "RegisterView.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "FilterView" + + +FilterView::FilterView(const char* name, int32 flags) + : BView(name, flags | B_FRAME_EVENTS), + fMessenger(NULL) +{ + fPeriodMenu = new BMenu("timeperiod"); + // Important: keep the order according to filter_period_field in RegisterView.h + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("All transactions"), new BMessage(M_FILTER_CHANGED))); + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("This month"), new BMessage(M_FILTER_CHANGED))); + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("Last month"), new BMessage(M_FILTER_CHANGED))); + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("This quarter"), new BMessage(M_FILTER_CHANGED))); + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("Last quarter"), new BMessage(M_FILTER_CHANGED))); + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("This year"), new BMessage(M_FILTER_CHANGED))); + fPeriodMenu->AddItem(new BMenuItem(B_TRANSLATE("Last year"), new BMessage(M_FILTER_CHANGED))); + + fPeriodMenu->SetLabelFromMarked(true); + fPeriodMenu->SetRadioMode(true); + fPeriodMenu->ItemAt(0L)->SetMarked(true); + + BMenuField* periodField = new BMenuField("periodfield", B_TRANSLATE("Period:"), fPeriodMenu); + + float maxwidth = 0; + for (int32 i = 0; i < fPeriodMenu->CountItems(); i++) { + BMenuItem* item = fPeriodMenu->ItemAt(i); + float labelwidth = StringWidth(item->Label()); + maxwidth = MAX(labelwidth, maxwidth); + } + fPeriodMenu->SetExplicitSize(BSize(maxwidth + 20, B_SIZE_UNSET)); + + BString label(B_TRANSLATE_CONTEXT("Payee", "CommonTerms")); + label << ":"; + fPayee = new BTextControl("payee", label, NULL, new BMessage(M_FILTER_CHANGED)); + + label = B_TRANSLATE_CONTEXT("Category", "CommonTerms"); + label << ":"; + fCategory = new BTextControl("category", label, NULL, new BMessage(M_FILTER_CHANGED)); + + label = B_TRANSLATE_CONTEXT("Memo", "CommonTerms"); + label << ":"; + fMemo = new BTextControl("memo", label, NULL, new BMessage(M_FILTER_CHANGED)); + + fCompareMenu = new BMenu(""); + fCompareMenu->AddItem(new BMenuItem("≦", new BMessage(M_FILTER_CHANGED))); + fCompareMenu->AddItem(new BMenuItem("=", new BMessage(M_FILTER_CHANGED))); + fCompareMenu->AddItem(new BMenuItem("≧", new BMessage(M_FILTER_CHANGED))); + + fCompareMenu->SetLabelFromMarked(true); + fCompareMenu->SetRadioMode(true); + fCompareMenu->ItemAt(0L)->SetMarked(true); + + BMenuField* compareField = new BMenuField("compareField", "", fCompareMenu); + compareField->SetExplicitSize(BSize(StringWidth("≦") * 2, B_SIZE_UNSET)); + + label = B_TRANSLATE_CONTEXT("Amount", "CommonTerms"); + label << ":"; + fAmount = new BTextControl("amount", label, NULL, new BMessage(M_FILTER_CHANGED)); + + fClear = new BButton("clearbutton", B_TRANSLATE("Clear"), new BMessage(M_CLEAR_FILTER)); + fFilter = new BButton("startbutton", B_TRANSLATE("Filter"), new BMessage(M_START_FILTER)); + + // clang-format off + BView* amountWidget = new BView("amountWidget", B_WILL_DRAW); + BLayoutBuilder::Group<>(amountWidget, B_HORIZONTAL, -2) + .Add(compareField) + .Add(fAmount->CreateTextViewLayoutItem()) + .End(); + + BLayoutBuilder::Group<>(this, B_VERTICAL, 0) + .SetInsets(0) + .AddGrid(0.0, B_USE_SMALL_SPACING) + .Add(periodField->CreateLabelLayoutItem(), 0, 0) + .Add(periodField->CreateMenuBarLayoutItem(), 1, 0) + .Add(fPayee->CreateLabelLayoutItem(), 0, 1) + .Add(fPayee->CreateTextViewLayoutItem(), 1, 1) + .Add(fCategory->CreateLabelLayoutItem(), 0, 2) + .Add(fCategory->CreateTextViewLayoutItem(), 1, 2) + .Add(fMemo->CreateLabelLayoutItem(), 0, 3) + .Add(fMemo->CreateTextViewLayoutItem(),1, 3) + .Add(new BStringView("amountlabel", label), 0, 4) + .Add(amountWidget, 1, 4) + .End() + .AddStrut(B_USE_BIG_SPACING) + .AddGroup(B_HORIZONTAL) + .Add(fClear) + .Add(fFilter) + .End() + .End(); + // clang-format on +} + + +FilterView::~FilterView(void) +{ +} + + +void +FilterView::AttachedToWindow(void) +{ + fPeriodMenu->SetTargetForItems(this); + fCompareMenu->SetTargetForItems(this); + fPayee->SetTarget(this); + fCategory->SetTarget(this); + fMemo->SetTarget(this); + fAmount->SetTarget(this); + fClear->SetTarget(this); + fFilter->SetTarget(this); +} + + +void +FilterView::MessageReceived(BMessage* msg) +{ + int32 start; + BString string; + switch (msg->what) { + case M_START_FILTER: + case M_FILTER_CHANGED: + { + BMessage filterMsg(M_FILTER); + filterMsg.AddString("payee", fPayee->Text()); + filterMsg.AddString("category", fCategory->Text()); + filterMsg.AddString("memo", fMemo->Text()); + filterMsg.AddString("amount", fAmount->Text()); + filterMsg.AddInt32("moreless", fCompareMenu->FindMarkedIndex()); + filterMsg.AddInt32("period", fPeriodMenu->FindMarkedIndex()); + + fMessenger->SendMessage(&filterMsg); + break; + } + case M_CLEAR_FILTER: + { + fPayee->SetText(""); + fCategory->SetText(""); + fMemo->SetText(""); + fAmount->SetText(""); + fCompareMenu->ItemAt(0L)->SetMarked(true); + fPeriodMenu->ItemAt(0L)->SetMarked(true); + break; + } + default: + { + BView::MessageReceived(msg); + } + } +} + + +void +FilterView::MakeEmpty(void) +{ + fPeriodMenu->ItemAt(0L)->SetMarked(true); + fPayee->SetText(""); + fCategory->SetText(""); + fMemo->SetText(""); + fCompareMenu->ItemAt(0L)->SetMarked(true); + fAmount->SetText(""); + +} diff --git a/src/FilterView.h b/src/FilterView.h new file mode 100644 index 0000000..01e0510 --- /dev/null +++ b/src/FilterView.h @@ -0,0 +1,45 @@ +#ifndef FILTERVIEW_H +#define FILTERVIEW_H + +#include +#include +#include +#include + + +enum { + M_FILTER_CHANGED = 'flch', + M_CLEAR_FILTER = 'clar', + M_START_FILTER = 'strt', +}; + + +class FilterView : public BView { +public: + FilterView(const char* name, int32 flags); + ~FilterView(void); + + void AttachedToWindow(void); + void MessageReceived(BMessage* msg); + + void SetMessenger(BMessenger* msgr) { fMessenger = msgr; }; + +private: + void MakeEmpty(void); + + BMenu* fPeriodMenu; + BMenu* fCompareMenu; + + BTextControl* fPayee; + BTextControl* fCategory; + BTextControl* fMemo; + BTextControl* fAmount; + + BButton* fClear; + BButton* fFilter; + + BMessenger* fMessenger; +}; + + +#endif diff --git a/src/RegisterView.cpp b/src/RegisterView.cpp index db1eded..952c890 100644 --- a/src/RegisterView.cpp +++ b/src/RegisterView.cpp @@ -10,6 +10,7 @@ #include "AccountListItem.h" #include "CheckView.h" #include "Database.h" +#include "FilterView.h" #include "MainWindow.h" #include "QuickTrackerItem.h" @@ -18,17 +19,12 @@ #define B_TRANSLATION_CONTEXT "RegisterView" -enum { - M_SELECT_ACCOUNT = 'slac', - M_SELECT_CURRENT -}; - RegisterView::RegisterView(const char* name, int32 flags) : BView(name, flags | B_FRAME_EVENTS) { SetViewUIColor(B_PANEL_BACKGROUND_COLOR); - float width = GetAccountViewWidth(); + // Accounts BStringView* accountLabel = new BStringView("accountlabel", B_TRANSLATE("Accounts")); accountLabel->SetFont(be_bold_font); accountLabel->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); @@ -37,11 +33,11 @@ RegisterView::RegisterView(const char* name, int32 flags) fAccountView = new BListView("accountview", B_SINGLE_SELECTION_LIST); fAccountView->SetSelectionMessage(new BMessage(M_SELECT_ACCOUNT)); fAccountView->SetInvocationMessage(new BMessage(M_SHOW_ACCOUNT_SETTINGS)); - fAccountView->SetExplicitSize(BSize(GetAccountViewWidth(), B_SIZE_UNSET)); fAccountScroller = new BScrollView("accountscroll", fAccountView, 0, false, true); fAccountScroller->SetViewColor(ViewColor()); + // Checkview fCheckView = new CheckView("checkview", B_WILL_DRAW); gDatabase.AddObserver(fCheckView); @@ -51,6 +47,7 @@ RegisterView::RegisterView(const char* name, int32 flags) acc->AddObserver(this); } + // Transactions list BStringView* transactionlabel = new BStringView("transactionlabel", B_TRANSLATE("Transactions")); transactionlabel->SetFont(be_bold_font); @@ -60,11 +57,23 @@ RegisterView::RegisterView(const char* name, int32 flags) gDatabase.AddObserver(fTransactionView); gDatabase.AddObserver(this); + // Filter + BBox* filterBox = new BBox("filterbox"); + filterBox->SetLabel(B_TRANSLATE("Filter")); + fFilterView = new FilterView("filterview", B_WILL_DRAW); + + // QuickTracker BBox* qtBox = new BBox("qtbox"); qtBox->SetLabel(B_TRANSLATE("QuickTracker")); QTNetWorthItem* qtItem = new QTNetWorthItem("networth"); // clang-format off + BLayoutBuilder::Group<>(filterBox, B_VERTICAL, 0) + .SetInsets(B_USE_DEFAULT_SPACING, B_USE_BIG_SPACING, + B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) + .Add(fFilterView) + .End(); + BLayoutBuilder::Group<>(qtBox, B_VERTICAL, 0) .SetInsets(B_USE_DEFAULT_SPACING, B_USE_BIG_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) @@ -79,6 +88,8 @@ RegisterView::RegisterView(const char* name, int32 flags) .Add(accountLabel) .Add(fAccountScroller, 2) .AddStrut(B_USE_DEFAULT_SPACING) + .Add(filterBox) + .AddStrut(B_USE_DEFAULT_SPACING) .Add(qtBox) .End() .AddGroup(B_VERTICAL, 0) @@ -97,6 +108,7 @@ void RegisterView::AttachedToWindow(void) { fAccountView->SetTarget(this); + fFilterView->SetMessenger(new BMessenger(this)); // If the selection done is before being attached to the window, the message is // never received. @@ -133,6 +145,11 @@ RegisterView::MessageReceived(BMessage* msg) Window()->PostMessage(M_SHOW_ACCOUNT_SETTINGS); break; } + case M_FILTER: + { + msg->PrintToStream(); + break; + } default: { BView::MessageReceived(msg); @@ -178,10 +195,6 @@ RegisterView::HandleNotify(const uint64& value, const BMessage* msg) } fCheckView->SetFieldsEnabled(!acc->IsClosed()); } - - // Adjust the AccountView width every time there is a change - fAccountView->SetExplicitSize(BSize(GetAccountViewWidth(), B_SIZE_UNSET)); - fAccountView->Relayout(); } else if (value & WATCH_TRANSACTION) { if (value & WATCH_CREATE || value & WATCH_DELETE || value & WATCH_CHANGE) fAccountView->Invalidate(); @@ -204,19 +217,3 @@ RegisterView::SelectAccount(const int32& index) fAccountView->Select(index); } - -float -RegisterView::GetAccountViewWidth() -{ - // Min width is the fixed width of QuickTracker - float width = be_plain_font->StringWidth(B_TRANSLATE("Balance")) - + be_plain_font->StringWidth(": $99,999,999.00"); - - for (int32 i = 0; i < gDatabase.CountAccounts(); i++) { - Account* acc = gDatabase.AccountAt(i); - - float namewidth = be_bold_font->StringWidth(acc->Name()) + B_V_SCROLL_BAR_WIDTH + 10; - width = (namewidth > width) ? namewidth : width; - } - return width; -} \ No newline at end of file diff --git a/src/RegisterView.h b/src/RegisterView.h index 604f218..7cbff91 100644 --- a/src/RegisterView.h +++ b/src/RegisterView.h @@ -8,8 +8,25 @@ #include "TransactionView.h" class CheckView; +class FilterView; + +enum { + M_SHOW_ACCOUNT_SETTINGS = 'acst', + M_SELECT_ACCOUNT = 'slac', + M_SELECT_CURRENT = 'slcu', + M_FILTER = 'filt', +}; + +typedef enum { + ALL_TRANSACTIONS = 0, + THIS_MONTH, + LAST_MONTH, + THIS_QUARTER, + LAST_QUARTER, + THIS_YEAR, + LAST_YEAR +} filter_period_field; -#define M_SHOW_ACCOUNT_SETTINGS 'acst' class RegisterView : public BView, public Observer { public: @@ -29,9 +46,8 @@ class RegisterView : public BView, public Observer { bool SelectLastTransaction(void) { return fTransactionView->SelectLast(); } private: - float GetAccountViewWidth(void); - CheckView* fCheckView; + FilterView* fFilterView; BListView* fAccountView; BScrollView* fAccountScroller; TransactionView* fTransactionView;