Skip to content

Commit

Permalink
Add filter view: the GUI side, no actually filtering
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
humdingerb committed Jul 17, 2024
1 parent 7d56c53 commit 5138269
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 30 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
181 changes: 181 additions & 0 deletions src/FilterView.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#include <Catalog.h>
#include <GridLayout.h>
#include <LayoutBuilder.h>
#include <Messenger.h>
#include <String.h>
#include <StringView.h>
#include <Window.h>
#include <stdlib.h>

#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)
{
BMenu* 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)
{
if (fPeriodMenu->LockLooper()) {
fPeriodMenu->SetTargetForItems(this);
fPeriodMenu->UnlockLooper();
}
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);
if (fPeriodMenu->LockLooper()) {
fPeriodMenu->ItemAt(0L)->SetMarked(true);
fPeriodMenu->UnlockLooper();
}
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("");

}
45 changes: 45 additions & 0 deletions src/FilterView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef FILTERVIEW_H
#define FILTERVIEW_H

#include <Button.h>
#include <Menu.h>
#include <TextControl.h>
#include <View.h>


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
51 changes: 24 additions & 27 deletions src/RegisterView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "AccountListItem.h"
#include "CheckView.h"
#include "Database.h"
#include "FilterView.h"
#include "MainWindow.h"
#include "QuickTrackerItem.h"

Expand All @@ -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));
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand All @@ -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;
}
Loading

0 comments on commit 5138269

Please sign in to comment.