1/* 2 * Copyright 2013, Stephan A��mus <superstippi@gmx.de>. 3 * Copyright 2019-2020, Andrew Lindesay <apl@lindesay.co.nz>. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7#include "FilterView.h" 8 9#include <algorithm> 10#include <stdio.h> 11 12#include <AutoLocker.h> 13#include <Catalog.h> 14#include <CheckBox.h> 15#include <LayoutBuilder.h> 16#include <MenuField.h> 17#include <MenuItem.h> 18#include <Messenger.h> 19#include <PopUpMenu.h> 20#include <TextControl.h> 21 22#include "Model.h" 23#include "support.h" 24 25 26#undef B_TRANSLATION_CONTEXT 27#define B_TRANSLATION_CONTEXT "FilterView" 28 29 30FilterView::FilterView() 31 : 32 BGroupView("filter view", B_VERTICAL) 33{ 34 // Construct category popup 35 BPopUpMenu* showMenu = new BPopUpMenu(B_TRANSLATE("Category")); 36 fShowField = new BMenuField("category", B_TRANSLATE("Category:"), showMenu); 37 38 // Construct search terms field 39 fSearchTermsText = new BTextControl("search terms", 40 B_TRANSLATE("Search terms:"), "", NULL); 41 fSearchTermsText->SetModificationMessage( 42 new BMessage(MSG_SEARCH_TERMS_MODIFIED)); 43 44 BSize minSearchSize = fSearchTermsText->MinSize(); 45 float minSearchWidth 46 = be_plain_font->StringWidth(fSearchTermsText->Label()) 47 + be_plain_font->StringWidth("XXX") * 6; 48 minSearchWidth = std::max(minSearchSize.width, minSearchWidth); 49 minSearchSize.width = minSearchWidth; 50 fSearchTermsText->SetExplicitMinSize(minSearchSize); 51 float maxSearchWidth = minSearchWidth * 2; 52 fSearchTermsText->SetExplicitMaxSize(BSize(maxSearchWidth, B_SIZE_UNSET)); 53 54 // Build layout 55 BLayoutBuilder::Group<>(this) 56 .AddGroup(B_HORIZONTAL) 57 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 1.2f) 58 .Add(fShowField, 0.0f) 59 .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)) 60 .End() 61 .AddGlue(0.5f) 62 .Add(fSearchTermsText, 1.0f) 63 .End() 64 65 .SetInsets(B_USE_DEFAULT_SPACING) 66 ; 67} 68 69 70FilterView::~FilterView() 71{ 72} 73 74 75void 76FilterView::AttachedToWindow() 77{ 78 fShowField->Menu()->SetTargetForItems(Window()); 79 fSearchTermsText->SetTarget(this); 80 fSearchTermsText->MakeFocus(); 81} 82 83 84void 85FilterView::MessageReceived(BMessage* message) 86{ 87 switch (message->what) { 88 case MSG_SEARCH_TERMS_MODIFIED: 89 { 90 BMessage searchTerms(MSG_SEARCH_TERMS_MODIFIED); 91 searchTerms.AddString("search terms", fSearchTermsText->Text()); 92 Window()->PostMessage(&searchTerms); 93 break; 94 } 95 96 default: 97 BGroupView::MessageReceived(message); 98 break; 99 } 100} 101 102 103void 104FilterView::AdoptModel(Model& model) 105{ 106 // Adopt categories 107 BMenu* showMenu = fShowField->Menu(); 108 showMenu->RemoveItems(0, showMenu->CountItems(), true); 109 110 showMenu->AddItem(new BMenuItem(B_TRANSLATE("All categories"), 111 new BMessage(MSG_CATEGORY_SELECTED))); 112 113 AutoLocker<BLocker> locker(model.Lock()); 114 int32 categoryCount = model.CountCategories(); 115 116 if (categoryCount > 0) { 117 showMenu->AddItem(new BSeparatorItem()); 118 _AddCategoriesToMenu(model, showMenu); 119 } 120 121 showMenu->SetEnabled(categoryCount > 0); 122 123 if (!_SelectCategoryCode(showMenu, model.Category())) 124 showMenu->ItemAt(0)->SetMarked(true); 125} 126 127 128/*! Tries to mark the menu item that corresponds to the supplied 129 category code. If the supplied code was found and the item marked 130 then the method will return true. 131*/ 132 133/*static*/ bool 134FilterView::_SelectCategoryCode(BMenu* menu, const BString& code) 135{ 136 for (int32 i = 0; i < menu->CountItems(); i++) { 137 BMenuItem* item = menu->ItemAt(i); 138 if (_MatchesCategoryCode(item, code)) { 139 item->SetMarked(true); 140 return true; 141 } 142 } 143 return false; 144} 145 146 147/*static*/ bool 148FilterView::_MatchesCategoryCode(BMenuItem* item, const BString& code) 149{ 150 BMessage* message = item->Message(); 151 if (message == NULL) 152 return false; 153 BString itemCode; 154 message->FindString("code", &itemCode); 155 return itemCode == code; 156} 157 158 159/*static*/ void 160FilterView::_AddCategoriesToMenu(Model& model, BMenu* menu) 161{ 162 int count = model.CountCategories(); 163 for (int i = 0; i < count; i++) { 164 const CategoryRef& category = model.CategoryAtIndex(i); 165 BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); 166 message->AddString("code", category->Code()); 167 BMenuItem* item = new BMenuItem(category->Name(), message); 168 menu->AddItem(item); 169 } 170} 171