Find Panel: Implement Folder Filtering

This commit introduces folder filtering to the Find Panel and associated
results window.

--> Features:
	--> Directory Selection: Users can select directories using the
	"Select a Directory..." option, now available in the same menu
	as volume selection.

	--> File Panel Integration: Upon selecting this option, a File
	panel will appear, displaying only folders or symlinks to
	folders for selection.

	--> Folder Filter Management: Selected Folders are shown in the
	same menu, with the corresponding menu item marked. Clicking on
	the menu item removes the folder filter.

	--> Recursive Search: The folder filters are combined using the
	OR method. Results will show items from any selected folder,
	recursively checking all subfolders.

--> Bug Fixes
	--> Resolved an issue with the saving functionality when resetting
	volumes or loading a query.

Change-Id: I8eaab6ad8ebd3de09944a8bcf03f100c451225ae
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7845
Reviewed-by: Niels Sascha Reedijk <[email protected]>
This commit is contained in:
calisto-mathias
2024-08-14 19:19:10 +00:00
committed by Niels Sascha Reedijk
parent c8dfbad953
commit 78c0fc35a7
5 changed files with 563 additions and 75 deletions
+407 -69
View File
@@ -133,7 +133,6 @@ static const char* operatorLabels[] = {
B_TRANSLATE_MARK("after")
};
namespace BPrivate {
class MostUsedNames {
@@ -212,6 +211,26 @@ MoreOptionsStruct::QueryTemporary(const BNode* node)
// #pragma mark - FindWindow
int32
GetNumberOfVolumes()
{
static int32 numberOfVolumes = -1;
if (numberOfVolumes >= 0)
return numberOfVolumes;
int32 count = 0;
BVolumeRoster volumeRoster;
BVolume volume;
while (volumeRoster.GetNextVolume(&volume) == B_OK) {
if (volume.IsPersistent() && volume.KnowsQuery() && volume.KnowsAttr())
++count;
}
numberOfVolumes = count;
return numberOfVolumes;
}
FindWindow::FindWindow(const entry_ref* newRef, bool editIfTemplateOnly)
:
BWindow(BRect(), B_TRANSLATE("Find"), B_TITLED_WINDOW,
@@ -667,6 +686,25 @@ FindWindow::SaveQueryAttributes(BNode* file, bool queryTemplate)
}
void
MarkVolumeAccordingToDirectoryFilter(BMenu* menu, entry_ref* ref)
{
int32 startingIndex = 2;
int32 endingIndex = 2 + GetNumberOfVolumes();
for (int32 index = startingIndex; index < endingIndex; ++index) {
BMenuItem* item = menu->ItemAt(index);
if (item->IsMarked())
continue;
BMessage* message = item->Message();
dev_t device;
if (message->FindInt32("device", &device) != B_OK)
continue;
if (device == ref->device)
item->SetMarked(true);
}
}
status_t
FindWindow::SaveQueryAsAttributes(BNode* file, BEntry* entry, bool queryTemplate,
const BMessage* oldAttributes, const BPoint* oldLocation, bool temporary)
@@ -697,42 +735,41 @@ FindWindow::SaveQueryAsAttributes(BNode* file, BEntry* entry, bool queryTemplate
int32 tmp = 1;
file->WriteAttr("_trk/recentQuery", B_INT32_TYPE, 0, &tmp, sizeof(int32));
// write some useful info to help locate the volume to query
BMenuItem* item = fBackground->VolMenu()->FindMarked();
if (item != NULL) {
dev_t dev;
BMessage message;
uint32 count = 0;
fBackground->SaveDirectoryFiltersToFile(file);
int32 itemCount = fBackground->VolMenu()->CountItems();
for (int32 index = 2; index < itemCount; index++) {
BMenuItem* item = fBackground->VolMenu()->ItemAt(index);
BMenu* volMenu = fBackground->VolMenu();
ASSERT(volMenu != NULL);
if (!item->IsMarked())
continue;
int32 numberOfDirectoryFilters = fBackground->fDirectoryFilters.CountItems();
for (int32 i = 0; i < numberOfDirectoryFilters; ++i)
MarkVolumeAccordingToDirectoryFilter(volMenu, fBackground->fDirectoryFilters.ItemAt(i));
if (item->Message()->FindInt32("device", &dev) != B_OK)
continue;
bool addAllVolumes = volMenu->ItemAt(0)->IsMarked();
int32 numberOfVolumes = GetNumberOfVolumes();
BMessage messageContainingVolumeInfo;
for (int32 i = 2; i < numberOfVolumes + 2; ++i) {
BMenuItem* volumeMenuItem = volMenu->ItemAt(i);
BMessage* messageOfVolumeMenuItem = volumeMenuItem->Message();
dev_t device;
if (messageOfVolumeMenuItem->FindInt32("device", &device) != B_OK)
continue;
count++;
BVolume volume(dev);
EmbedUniqueVolumeInfo(&message, &volume);
if (volumeMenuItem->IsMarked() || addAllVolumes) {
BVolume volume(device);
EmbedUniqueVolumeInfo(&messageContainingVolumeInfo, &volume);
}
}
if (count > 0) {
// do we need to embed any volumes
ssize_t size = message.FlattenedSize();
BString buffer;
status_t result = message.Flatten(buffer.LockBuffer(size), size);
if (result == B_OK) {
if (file->WriteAttr(kAttrQueryVolume, B_MESSAGE_TYPE, 0,
buffer.String(), (size_t)size) != size) {
return B_IO_ERROR;
}
}
buffer.UnlockBuffer();
ssize_t flattenedSize = messageContainingVolumeInfo.FlattenedSize();
if (flattenedSize > 0) {
BString bufferString;
char* buffer = bufferString.LockBuffer(flattenedSize);
messageContainingVolumeInfo.Flatten(buffer, flattenedSize);
if (fFile->WriteAttr(kAttrQueryVolume, B_MESSAGE_TYPE, 0, buffer,
static_cast<size_t>(flattenedSize))
!= flattenedSize) {
return B_ERROR;
}
// default to query for everything
}
file->WriteAttr("_trk/temporary", B_BOOL_TYPE, 0, &temporary, sizeof(temporary));
@@ -1056,6 +1093,7 @@ FindWindow::MessageReceived(BMessage* message)
SwitchToTemplate(&ref);
UpdateFileReferences(&ref);
fBackground->LoadDirectoryFiltersFromFile(fFile);
fSaveQueryOrTemplateItem->SetEnabled(true);
break;
}
@@ -1081,16 +1119,32 @@ FindWindow::MessageReceived(BMessage* message)
}
bool
FolderFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* stat,
const char* mimeType)
{
ASSERT(node->InitCheck() == B_OK);
if (node->IsDirectory()) {
return true;
} else if (node->IsSymLink()) {
BEntry entry(ref, true);
return entry.IsDirectory();
}
return false;
}
// #pragma mark - FindPanel
FindPanel::FindPanel(BFile* node, FindWindow* parent, bool fromTemplate,
bool editTemplateOnly)
FindPanel::FindPanel(BFile* node, FindWindow* parent, bool fromTemplate, bool editTemplateOnly)
:
BView("MainView", B_WILL_DRAW),
fMode(kByNameItem),
fAttrGrid(NULL),
fDraggableIcon(NULL)
fDraggableIcon(NULL),
fDirectorySelectPanel(NULL),
fAddSeparatorItemState(true)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
SetLowUIColor(ViewUIColor());
@@ -1125,6 +1179,12 @@ FindPanel::FindPanel(BFile* node, FindWindow* parent, bool fromTemplate,
BMenuField* volumeField = new BMenuField("", B_TRANSLATE("On"), fVolMenu);
volumeField->SetDivider(volumeField->StringWidth(volumeField->Label()) + 8);
AddVolumes(fVolMenu);
fVolMenu->AddSeparatorItem();
if (fDirectoryFilters.CountItems() > 0)
fVolMenu->AddSeparatorItem();
fVolMenu->AddItem(new BMenuItem(B_TRANSLATE("Select folders" B_UTF8_ELLIPSIS),
new BMessage(kSelectDirectoryFilter)));
LoadDirectoryFiltersFromFile(node);
// add Search button
BButton* button;
@@ -1186,6 +1246,192 @@ FindPanel::FindPanel(BFile* node, FindWindow* parent, bool fromTemplate,
FindPanel::~FindPanel()
{
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++)
delete fDirectoryFilters.RemoveItemAt(i);
}
status_t
FindPanel::AddDirectoryFiltersToMenu(BMenu* menu, BHandler* target)
{
if (menu == NULL)
return B_BAD_VALUE;
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* filter = fDirectoryFilters.ItemAt(i);
if (filter != NULL)
FindPanel::AddDirectoryFilterItemToMenu(menu, filter, target);
}
return B_OK;
}
void
FindPanel::LoadDirectoryFiltersFromFile(const BNode* node)
{
if (node == NULL)
return;
struct attr_info info;
if (node->GetAttrInfo("_trk/directories", &info) != B_OK)
return;
BString bufferString;
char* buffer = bufferString.LockBuffer(info.size);
if (node->ReadAttr("_trk/directories", B_MESSAGE_TYPE, 0, buffer, (size_t)info.size)
!= info.size) {
return;
}
BMessage message;
if (message.Unflatten(buffer) != B_OK)
return;
int32 count;
if (message.GetInfo("refs", NULL, &count) != B_OK)
return;
for (int32 i = 0; i < count; i++) {
entry_ref ref;
if (message.FindRef("refs", i, &ref) != B_OK)
continue;
BEntry entry(&ref);
if (entry.InitCheck() == B_OK && entry.Exists() && !entry.IsDirectory())
continue;
AddDirectoryFilter(&ref);
}
bufferString.UnlockBuffer();
}
status_t
FindPanel::AddDirectoryFilterItemToMenu(BMenu* menu, const entry_ref* ref, BHandler* target,
int32 index)
{
if (menu == NULL || ref == NULL || target == NULL)
return B_BAD_VALUE;
BEntry entry(ref, true);
if (entry.InitCheck() != B_OK)
return B_ERROR;
if (entry.Exists() && entry.IsDirectory()) {
entry_ref symlinkTraversedDirectory;
entry.GetRef(&symlinkTraversedDirectory);
// Adding the options into the fVolMenu
Model model(&entry);
BMenuItem* item = new ModelMenuItem(&model, model.Name(), NULL);
BMessage* message = new BMessage(kRemoveDirectoryFilter);
message->AddPointer("pointer", item);
message->AddRef("refs", &symlinkTraversedDirectory);
item->SetMessage(message);
item->SetMarked(true);
item->SetTarget(target);
bool status = false;
if (index == -1)
status = menu->AddItem(item);
else
status = menu->AddItem(item, index);
return status ? B_OK : B_ERROR;
} else if (!entry.IsDirectory()) {
return B_NOT_A_DIRECTORY;
} else {
return B_ENTRY_NOT_FOUND;
}
}
status_t
FindPanel::AddDirectoryFilter(const entry_ref* ref, bool addToMenu)
{
if (ref == NULL)
return B_BAD_VALUE;
// Check for Duplicate Entry
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* item = fDirectoryFilters.ItemAt(i);
if (ref != NULL && item != NULL && *item == *ref)
return B_CANCELED;
}
status_t error = B_OK;
if (addToMenu) {
if (fAddSeparatorItemState) {
BMenuItem* addDirectoriesItem = fVolMenu->RemoveItem(fVolMenu->CountItems() - 1);
error = FindPanel::AddDirectoryFilterItemToMenu(fVolMenu, ref, this);
fVolMenu->AddSeparatorItem();
fVolMenu->AddItem(addDirectoriesItem);
fAddSeparatorItemState = false;
} else {
int32 index = fVolMenu->CountItems() - 2;
error = FindPanel::AddDirectoryFilterItemToMenu(fVolMenu, ref, this, index);
}
UnmarkDisks();
}
if (error == B_OK) {
fDirectoryFilters.AddItem(new entry_ref(*ref));
return B_OK;
} else {
return B_ERROR;
}
}
void
FindPanel::RemoveDirectoryFilter(const entry_ref* ref)
{
ASSERT(ref != NULL);
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* item = fDirectoryFilters.ItemAt(i);
if (item != NULL && ref != NULL && (*item) == (*ref))
fDirectoryFilters.RemoveItemAt(i);
}
}
status_t
FindPanel::SaveDirectoryFiltersToFile(BNode* node)
{
if (node->InitCheck() != B_OK)
return B_NO_INIT;
// Store the entry_refs of the fDirectoryFilters to a BMessage
// So that it can be serialized.
BMessage message;
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* ref = fDirectoryFilters.ItemAt(i);
if (message.AddRef("refs", ref) != B_OK)
return B_ERROR;
}
// Serialize and Write the Attribute
ssize_t size = message.FlattenedSize();
BString bufferString;
char* buffer = bufferString.LockBuffer(size);
if (message.Flatten(buffer, size) == B_OK) {
if (node->WriteAttr("_trk/directories", B_MESSAGE_TYPE, 0, buffer, (size_t)size) != size)
return B_IO_ERROR;
else
return B_OK;
}
return B_ERROR;
}
@@ -1294,6 +1540,8 @@ FindPanel::ResizeMenuField(BMenuField* menuField)
}
}
width = std::max(width, menuField->StringWidth(B_TRANSLATE("Multiple selections")));
float maxWidth = be_control_look->DefaultItemSpacing() * 20;
size.width = std::min(width + padding, maxWidth);
menuField->SetExplicitSize(size);
@@ -1318,38 +1566,35 @@ PopUpMenuSetTitle(BMenu* menu, const char* title)
void
FindPanel::ShowVolumeMenuLabel()
{
if (fVolMenu->ItemAt(0)->IsMarked()) {
// "all disks" selected
PopUpMenuSetTitle(fVolMenu, fVolMenu->ItemAt(0)->Label());
return;
}
// find out if more than one items are marked
int32 count = fVolMenu->CountItems();
int32 countSelected = 0;
BMenuItem* tmpItem = NULL;
for (int32 index = 2; index < count; index++) {
BMenuItem* item = fVolMenu->ItemAt(index);
if (item->IsMarked()) {
countSelected++;
tmpItem = item;
int32 totalVolumes = GetNumberOfVolumes();
int32 selectedVolumesCount = 0;
BMenuItem* lastSelectedVolumeItem = NULL;
for (int32 i = 2; i < totalVolumes + 2; ++i) {
BMenuItem* volumeItem = fVolMenu->ItemAt(i);
if (volumeItem->IsMarked()) {
++selectedVolumesCount;
lastSelectedVolumeItem = volumeItem;
}
}
if (countSelected == 0) {
// no disk selected, for now revert to search all disks
// ToDo:
// show no disks here and add a check that will not let the
// query go if the user doesn't pick at least one
if (fDirectoryFilters.CountItems() > 1) {
PopUpMenuSetTitle(fVolMenu, B_TRANSLATE_COMMENT("multiple selections",
"The user has selected multiple menu items"));
} else if (fDirectoryFilters.CountItems() == 1) {
PopUpMenuSetTitle(fVolMenu, fDirectoryFilters.ItemAt(0)->name);
} else if (selectedVolumesCount == 0 || selectedVolumesCount == totalVolumes) {
fVolMenu->ItemAt(0)->SetMarked(true);
PopUpMenuSetTitle(fVolMenu, fVolMenu->ItemAt(0)->Label());
} else if (countSelected > 1)
// if more than two disks selected, don't use the disk name
// as a label
PopUpMenuSetTitle(fVolMenu, B_TRANSLATE("multiple disks"));
else {
ASSERT(tmpItem);
PopUpMenuSetTitle(fVolMenu, tmpItem->Label());
} else if (selectedVolumesCount == 1) {
fVolMenu->ItemAt(0)->SetMarked(false);
PopUpMenuSetTitle(fVolMenu, lastSelectedVolumeItem->Label());
} else {
fVolMenu->ItemAt(0)->SetMarked(false);
PopUpMenuSetTitle(fVolMenu, B_TRANSLATE_COMMENT("multiple selections",
"The user has selected multiple menu items"));
}
}
@@ -1403,6 +1648,18 @@ FindPanel::Draw(BRect)
}
void
FindPanel::UnmarkDisks()
{
int32 startingIndex = 2;
int32 endingIndex = 2 + GetNumberOfVolumes();
for (int32 i = startingIndex; i < endingIndex; ++i)
fVolMenu->ItemAt(i)->SetMarked(false);
fVolMenu->ItemAt(0)->SetMarked(false);
}
void
FindPanel::MessageReceived(BMessage* message)
{
@@ -1427,8 +1684,18 @@ FindPanel::MessageReceived(BMessage* message)
if (dev == -1) {
// all disks selected, uncheck everything else
int32 count = menu->CountItems();
for (int32 index = 2; index < count; index++)
int32 count = 0;
BVolumeRoster roster;
BVolume volume;
while (roster.GetNextVolume(&volume) == B_OK) {
if (volume.IsPersistent() && volume.KnowsQuery()) {
BDirectory root;
if (volume.GetRootDirectory(&root) != B_OK)
continue;
count++;
}
}
for (int32 index = 2; index < count + 2; index++)
menu->ItemAt(index)->SetMarked(false);
// make all disks the title and check it
@@ -1450,12 +1717,74 @@ FindPanel::MessageReceived(BMessage* message)
}
}
}
int32 count = fVolMenu->CountItems();
int32 startingIndex = 3 + GetNumberOfVolumes();
int32 endingIndex = count - 2;
for (int32 i = startingIndex; i < endingIndex; ++i) {
BMenuItem* menuItem = fVolMenu->ItemAt(i);
BMessage* message = menuItem->Message();
entry_ref ref;
if (!message || message->FindRef("refs", &ref) != B_OK)
continue;
RemoveDirectoryFilter(&ref);
menuItem->SetMarked(false);
}
// make sure the right label is showing
ShowVolumeMenuLabel();
break;
}
case kSelectDirectoryFilter:
{
if (fDirectorySelectPanel == NULL) {
BRefFilter* filter = new FolderFilter();
fDirectorySelectPanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL,
B_DIRECTORY_NODE, true, new BMessage(kAddDirectoryFilters), filter);
}
fDirectorySelectPanel->Window()->SetTitle(B_TRANSLATE("Select folders"));
fDirectorySelectPanel->Show();
break;
}
case kAddDirectoryFilters:
{
int32 count;
message->GetInfo("refs", NULL, &count);
for (int32 i = 0; i < count; i++) {
entry_ref ref;
status_t error = message->FindRef("refs", i, &ref);
if (error == B_OK)
AddDirectoryFilter(&ref);
}
ShowVolumeMenuLabel();
break;
}
case kRemoveDirectoryFilter:
{
BMenuItem* item;
entry_ref ref;
if (message->FindPointer("pointer", (void**)&item) == B_OK
&& message->FindRef("refs", &ref) == B_OK) {
if (item->IsMarked()) {
RemoveDirectoryFilter(&ref);
item->SetMarked(false);
} else {
AddDirectoryFilter(&ref, false);
item->SetMarked(true);
UnmarkDisks();
}
ShowVolumeMenuLabel();
}
break;
}
case kByAttributeItem:
case kByNameItem:
case kByFormulaItem:
@@ -2331,19 +2660,21 @@ FindPanel::AddRecentQueries(BMenu* menu, bool addSaveAsItem, const BMessenger* t
struct attr_info info;
if (node.GetAttrInfo(kAttrQueryLastChange, &info) != B_OK)
continue;
if (info.type == B_MESSAGE_TYPE) {
char* buffer = new char[info.size];
BString bufferString;
char* buffer = bufferString.LockBuffer(info.size);
BMessage message;
if (node.ReadAttr(kAttrQueryLastChange, B_MESSAGE_TYPE, 0, buffer,
static_cast<size_t>(info.size))
!= info.size || message.Unflatten(buffer) != B_OK)
continue;
bufferString.UnlockBuffer();
int32 count;
if (message.GetInfo(kAttrQueryLastChange, NULL, &count) != B_OK)
continue;
for (int32 i = 0; i < count; i++) {
int32 time;
if (message.FindInt32(kAttrQueryLastChange, i, &time)
@@ -2725,7 +3056,8 @@ FindPanel::RestoreWindowState(const BNode* node)
}
// get volumes to perform query on
bool searchAllVolumes = true;
int32 selectedVolumes = 0;
attr_info info;
if (node->GetAttrInfo(kAttrQueryVolume, &info) == B_OK) {
@@ -2744,8 +3076,8 @@ FindPanel::RestoreWindowState(const BNode* node)
if (result == B_OK) {
char name[256];
volume.GetName(name);
SelectItemWithLabel(fVolMenu, name);
searchAllVolumes = false;
if (SelectItemWithLabel(fVolMenu, name) != -1)
++selectedVolumes;
} else if (result != B_DEV_BAD_DRIVE_NUM)
// if B_DEV_BAD_DRIVE_NUM, the volume just isn't
// mounted this time around, keep looking for more
@@ -2756,8 +3088,14 @@ FindPanel::RestoreWindowState(const BNode* node)
}
delete[] buffer;
}
LoadDirectoryFiltersFromFile(node);
// mark or unmark "All disks"
fVolMenu->ItemAt(0)->SetMarked(searchAllVolumes);
if (selectedVolumes == GetNumberOfVolumes()) {
fVolMenu->ItemAt(0)->SetMarked(true);
for (int32 i = 0; i < GetNumberOfVolumes() + 2; ++i)
fVolMenu->ItemAt(i)->SetMarked(false);
}
ShowVolumeMenuLabel();
switch (Mode()) {
+30 -1
View File
@@ -36,9 +36,10 @@ All rights reserved.
#include <ByteOrder.h>
#include <FilePanel.h>
#include <ObjectList.h>
#include <Window.h>
#include <View.h>
#include <Window.h>
#include "DialogPane.h"
#include "MimeTypeList.h"
@@ -81,6 +82,10 @@ const uint32 kOpenLoadQueryPanel = 'Folo';
const uint32 kTemporaryOptionClicked = 'FTCl';
const uint32 kSearchInTrashOptionClicked = 'FSCl';
const uint32 kSelectDirectoryFilter = 'FSeD';
const uint32 kAddDirectoryFilters = 'FAdF';
const uint32 kRemoveDirectoryFilter = 'FRmD';
#ifdef _IMPEXP_TRACKER
_IMPEXP_TRACKER
#endif
@@ -246,6 +251,9 @@ public:
bool includeTemporaryQueries = true,
bool includePersistedQueries = true);
status_t SaveDirectoryFiltersToFile(BNode*);
void LoadDirectoryFiltersFromFile(const BNode*);
private:
// populates the type menu
void AddMimeTypesToMenu();
@@ -299,6 +307,17 @@ private:
void ResizeMenuField(BMenuField*);
status_t AddDirectoryFiltersToMenu(BMenu*, BHandler* target);
status_t AddDirectoryFilter(const entry_ref* ref, bool addToMenu = true);
void RemoveDirectoryFilter(const entry_ref* ref);
static status_t AddDirectoryFilterItemToMenu(BMenu*, const entry_ref* ref,
BHandler* target, int32 index = -1);
void UnmarkDisks();
void MarkDiskAccordingToDirectoryFilter(entry_ref*);
public:
BObjectList<entry_ref> fDirectoryFilters;
private:
uint32 fMode;
BGridLayout* fAttrGrid;
@@ -313,6 +332,10 @@ private:
DraggableIcon* fDraggableIcon;
BFilePanel* fDirectorySelectPanel;
bool fAddSeparatorItemState;
typedef BView _inherited;
friend class RecentQueriesPopUp;
@@ -381,6 +404,12 @@ protected:
virtual void Draw(BRect);
};
class FolderFilter : public BRefFilter {
public:
virtual bool Filter(const entry_ref*, BNode*, struct stat_beos*, const char*);
};
} // namespace BPrivate
using namespace BPrivate;
+1 -1
View File
@@ -1385,7 +1385,6 @@ BPoseView::AddPosesTask(void* castToParams)
AddPosesParams* params = (AddPosesParams*)castToParams;
BMessenger target(params->target);
entry_ref ref(params->ref);
delete params;
AutoLockingMessenger lock(target);
@@ -1456,6 +1455,7 @@ BPoseView::AddPosesTask(void* castToParams)
// have to node monitor ahead of time because Model will
// cache up the file type and preferred app
// OK to call when poseView is not locked
model = new Model(&dirNode, &itemNode, eptr->d_name, false);
result = model->InitCheck();
modelChunkIndex++;
+118 -3
View File
@@ -94,6 +94,45 @@ BQueryPoseView::~BQueryPoseView()
}
bool
FolderFilterFunction(const entry_ref* directory, const entry_ref* model)
{
if (directory == NULL || model == NULL)
return false;
BPath directoryPath(directory);
BPath modelPath(model);
if (directoryPath.InitCheck() != B_OK || modelPath.InitCheck() != B_OK)
return false;
char* requiredDirectoryPath = const_cast<char*>(directoryPath.Path());
strcat(requiredDirectoryPath, "/");
// only supports searching completely in the directories as well as subdirectories for now.
return strncmp(requiredDirectoryPath, modelPath.Path(), strlen(requiredDirectoryPath)) == 0;
}
bool
QueryRefFilter::PassThroughDirectoryFilters(const entry_ref* ref) const
{
int32 count = fDirectoryFilters.CountItems();
bool passed = count == 0;
// in this context, even if the model passes through a single filter, it is considered
// as the folder selections are combined with OR! and not AND!
for (int32 i = 0; i < count; i++) {
entry_ref* filterDirectory = fDirectoryFilters.ItemAt(i);
if (FolderFilterFunction(filterDirectory, ref)) {
passed = true;
break;
}
}
return passed;
}
void
BQueryPoseView::MessageReceived(BMessage* message)
{
@@ -322,7 +361,11 @@ BQueryPoseView::InitDirentIterator(const entry_ref* ref)
delta);
}
SetRefFilter(new QueryRefFilter(fQueryListContainer->ShowResultsFromTrash()));
QueryRefFilter* filter = new QueryRefFilter(fQueryListContainer->ShowResultsFromTrash());
TargetModel()->OpenNode();
filter->LoadDirectoryFiltersFromFile(TargetModel()->Node());
TargetModel()->CloseNode();
SetRefFilter(filter);
return fQueryListContainer->Clone();
}
@@ -391,13 +434,85 @@ QueryRefFilter::QueryRefFilter(bool showResultsFromTrash)
}
QueryRefFilter::~QueryRefFilter()
{
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++)
delete fDirectoryFilters.RemoveItemAt(0);
}
status_t
QueryRefFilter::LoadDirectoryFiltersFromFile(const BNode* node)
{
// params checking
if (node == NULL || node->InitCheck() != B_OK)
return B_BAD_VALUE;
struct attr_info info;
status_t error = node->GetAttrInfo("_trk/directories", &info);
if (error != B_OK)
return error;
BString bufferString;
char* buffer = bufferString.LockBuffer(info.size);
if (node->ReadAttr("_trk/directories", B_MESSAGE_TYPE, 0, buffer, info.size) != info.size)
return B_ERROR;
BMessage message;
error = message.Unflatten(buffer);
if (error != B_OK)
return error;
int32 count;
if ((error = message.GetInfo("refs", NULL, &count)) != B_OK)
return error;
for (int32 i = 0; i < count; i++) {
entry_ref ref;
if ((error = message.FindRef("refs", i, &ref)) != B_OK)
continue;
AddDirectoryFilter(&ref);
}
return B_OK;
}
status_t
QueryRefFilter::AddDirectoryFilter(const entry_ref* ref)
{
if (ref == NULL)
return B_BAD_VALUE;
// checking for duplicates
int32 count = fDirectoryFilters.CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* item = fDirectoryFilters.ItemAt(i);
if (ref != NULL && item != NULL && *item == *ref)
return B_CANCELED;
}
BEntry entry(ref, true);
if (entry.InitCheck() != B_OK || !entry.Exists() || !entry.IsDirectory())
return B_ERROR;
entry_ref symlinkTraversedRef;
entry.GetRef(&symlinkTraversedRef);
fDirectoryFilters.AddItem(new entry_ref(symlinkTraversedRef));
return B_OK;
}
bool
QueryRefFilter::Filter(const entry_ref* ref, BNode* node, stat_beos* st,
const char* filetype)
{
TTracker* tracker = dynamic_cast<TTracker*>(be_app);
return !(!fShowResultsFromTrash && tracker != NULL
&& tracker->InTrashNode(ref));
return !(!fShowResultsFromTrash && tracker != NULL && tracker->InTrashNode(ref))
&& PassThroughDirectoryFilters(ref);
}
+7 -1
View File
@@ -96,11 +96,17 @@ private:
class QueryRefFilter : public BRefFilter {
public:
QueryRefFilter(bool showResultsFromTrash);
bool Filter(const entry_ref* ref, BNode* node, stat_beos* st,
virtual ~QueryRefFilter();
virtual bool Filter(const entry_ref* ref, BNode* node, stat_beos* st,
const char* filetype);
status_t LoadDirectoryFiltersFromFile(const BNode*);
status_t AddDirectoryFilter(const entry_ref*);
bool PassThroughDirectoryFilters(const entry_ref*) const;
private:
bool fShowResultsFromTrash;
BObjectList<entry_ref> fDirectoryFilters;
};