Initial implementation of #9755.

- ImageFunctionsView now contains a text input allowing one to specify a
filter for its contained functions.
- When in filtered mode, the previous flattened view is used rather than
the hierarchical tree.
- The matching portion of the string is highlighted. However, currently
only simple string matches are supported.
This commit is contained in:
Rene Gollent
2013-06-05 22:02:42 -04:00
parent cc27aad6b0
commit 58535f5a9a
2 changed files with 180 additions and 7 deletions
@@ -11,7 +11,10 @@
#include <new> #include <new>
#include <set> #include <set>
#include <LayoutBuilder.h>
#include <MessageRunner.h>
#include <StringList.h> #include <StringList.h>
#include <TextControl.h>
#include <AutoDeleter.h> #include <AutoDeleter.h>
@@ -25,6 +28,15 @@
#include "Tracing.h" #include "Tracing.h"
static const uint32 MSG_FUNCTION_FILTER_CHANGED = 'mffc';
static const uint32 MSG_FUNCTION_TYPING_TIMEOUT = 'mftt';
static const uint32 kKeypressTimeout = 250000;
// from ColumnTypes.cpp
static const float kTextMargin = 8.0;
// #pragma mark - SourcePathComponentNode // #pragma mark - SourcePathComponentNode
@@ -151,6 +163,65 @@ private:
}; };
// #pragma mark - HighlightingTableColumn
class ImageFunctionsView::HighlightingTableColumn : public StringTableColumn {
public:
HighlightingTableColumn(int32 modelIndex, const char* title, float width,
float minWidth, float maxWidth, uint32 truncate,
alignment align = B_ALIGN_LEFT)
:
StringTableColumn(modelIndex, title, width, minWidth, maxWidth,
truncate, align),
fFilter(),
fFilterWidth(0.0)
{
}
void SetFilter(const BString& filter)
{
fFilter = filter;
fFilterWidth = 0.0;
}
virtual void DrawValue(const BVariant& value, BRect rect,
BView* targetView)
{
StringTableColumn::DrawValue(value, rect, targetView);
if (!fFilter.IsEmpty()) {
if (fFilterWidth == 0.0)
fFilterWidth = targetView->StringWidth(fFilter);
// TODO: handle this case as well
if (fField.HasClippedString())
return;
const char* fieldString = fField.String();
const char* filterMatch = strstr(fieldString, fFilter.String());
if (filterMatch == NULL)
return;
targetView->PushState();
BRect fillRect(rect);
fillRect.left += kTextMargin + targetView->StringWidth(
fieldString, filterMatch - fieldString);
fillRect.right = fillRect.left + fFilterWidth;
targetView->SetLowColor(255, 255, 0, 255);
targetView->SetDrawingMode(B_OP_MIN);
targetView->FillRect(fillRect, B_SOLID_LOW);
targetView->PopState();
}
}
private:
BString fFilter;
float fFilterWidth;
};
// #pragma mark - FunctionsTableModel // #pragma mark - FunctionsTableModel
@@ -198,6 +269,7 @@ public:
LocatableFile* currentFile = NULL; LocatableFile* currentFile = NULL;
BStringList pathComponents; BStringList pathComponents;
bool applyFilter = !fCurrentFilter.IsEmpty();
int32 functionCount = fImageDebugInfo->CountFunctions(); int32 functionCount = fImageDebugInfo->CountFunctions();
for (int32 i = 0; i < functionCount; i++) { for (int32 i = 0; i < functionCount; i++) {
FunctionInstance* instance = fImageDebugInfo->FunctionAt(i); FunctionInstance* instance = fImageDebugInfo->FunctionAt(i);
@@ -213,6 +285,13 @@ public:
} }
LocatableFile* sourceFile = instance->SourceFile(); LocatableFile* sourceFile = instance->SourceFile();
BString sourcePath;
if (sourceFile != NULL)
sourceFile->GetPath(sourcePath);
if (applyFilter && !_FilterFunction(instance, sourcePath))
continue;
if (sourceFile == NULL) { if (sourceFile == NULL) {
if (!_AddFunctionNode(sourcelessNode, instance, NULL)) if (!_AddFunctionNode(sourcelessNode, instance, NULL))
return; return;
@@ -221,9 +300,14 @@ public:
if (sourceFile != currentFile) { if (sourceFile != currentFile) {
currentFile = sourceFile; currentFile = sourceFile;
if (!_GetSourcePathComponents(currentFile, pathComponents.MakeEmpty();
if (applyFilter) {
pathComponents.Add(sourcePath);
} else {
if (!_GetSourcePathComponents(currentFile,
pathComponents)) { pathComponents)) {
return; return;
}
} }
} }
@@ -351,6 +435,13 @@ public:
return false; return false;
} }
void SetFilter(const char* filter)
{
fCurrentFilter = filter;
SetImageDebugInfo(fImageDebugInfo);
}
private: private:
bool _GetSourcePathComponents(LocatableFile* currentFile, bool _GetSourcePathComponents(LocatableFile* currentFile,
BStringList& pathComponents) BStringList& pathComponents)
@@ -360,8 +451,6 @@ private:
if (sourcePath.IsEmpty()) if (sourcePath.IsEmpty())
return false; return false;
pathComponents.MakeEmpty();
int32 startIndex = 0; int32 startIndex = 0;
if (sourcePath[0] == '/') if (sourcePath[0] == '/')
startIndex = 1; startIndex = 1;
@@ -438,6 +527,15 @@ private:
return true; return true;
} }
bool _FilterFunction(FunctionInstance* instance, const BString& sourcePath)
{
if (instance->PrettyName().IFindFirst(fCurrentFilter) >= 0)
return true;
return sourcePath.IFindFirst(fCurrentFilter) >= 0;
}
private: private:
typedef BObjectList<SourcePathComponentNode> ChildPathComponentList; typedef BObjectList<SourcePathComponentNode> ChildPathComponentList;
@@ -445,6 +543,7 @@ private:
ImageDebugInfo* fImageDebugInfo; ImageDebugInfo* fImageDebugInfo;
ChildPathComponentList fChildPathComponents; ChildPathComponentList fChildPathComponents;
SourcePathComponentNode* fSourcelessNode; SourcePathComponentNode* fSourcelessNode;
BString fCurrentFilter;
}; };
@@ -455,9 +554,12 @@ ImageFunctionsView::ImageFunctionsView(Listener* listener)
: :
BGroupView(B_VERTICAL), BGroupView(B_VERTICAL),
fImageDebugInfo(NULL), fImageDebugInfo(NULL),
fFilterField(NULL),
fFunctionsTable(NULL), fFunctionsTable(NULL),
fFunctionsTableModel(NULL), fFunctionsTableModel(NULL),
fListener(listener) fListener(listener),
fHighlightingColumn(NULL),
fLastFilterKeypress(0)
{ {
SetName("Functions"); SetName("Functions");
} }
@@ -544,6 +646,45 @@ ImageFunctionsView::SetFunction(FunctionInstance* function)
} }
void
ImageFunctionsView::AttachedToWindow()
{
BView::AttachedToWindow();
fFilterField->SetTarget(this);
}
void
ImageFunctionsView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_FUNCTION_FILTER_CHANGED:
{
fLastFilterKeypress = system_time();
BMessage keypressMessage(MSG_FUNCTION_TYPING_TIMEOUT);
BMessageRunner::StartSending(BMessenger(this), &keypressMessage,
kKeypressTimeout, 1);
break;
}
case MSG_FUNCTION_TYPING_TIMEOUT:
{
if (system_time() - fLastFilterKeypress >= kKeypressTimeout) {
fFunctionsTableModel->SetFilter(fFilterField->Text());
fHighlightingColumn->SetFilter(fFilterField->Text());
_ExpandFilteredNodes();
}
break;
}
default:
BView::MessageReceived(message);
break;
}
}
void void
ImageFunctionsView::LoadSettings(const BMessage& settings) ImageFunctionsView::LoadSettings(const BMessage& settings)
{ {
@@ -591,11 +732,17 @@ ImageFunctionsView::_Init()
{ {
fFunctionsTable = new TreeTable("functions", 0, B_FANCY_BORDER); fFunctionsTable = new TreeTable("functions", 0, B_FANCY_BORDER);
AddChild(fFunctionsTable->ToView()); AddChild(fFunctionsTable->ToView());
AddChild(fFilterField = new BTextControl("filtertext", "Filter:",
NULL, NULL));
fFilterField->SetModificationMessage(new BMessage(
MSG_FUNCTION_FILTER_CHANGED));
fFunctionsTable->SetSortingEnabled(false); fFunctionsTable->SetSortingEnabled(false);
// columns // columns
fFunctionsTable->AddColumn(new StringTableColumn(0, "File/Function", 300, fFunctionsTable->AddColumn(fHighlightingColumn
100, 1000, B_TRUNCATE_BEGINNING, B_ALIGN_LEFT)); = new HighlightingTableColumn(0, "File/Function", 300, 100, 1000,
B_TRUNCATE_BEGINNING, B_ALIGN_LEFT));
fFunctionsTableModel = new FunctionsTableModel(); fFunctionsTableModel = new FunctionsTableModel();
fFunctionsTable->SetTreeTableModel(fFunctionsTableModel); fFunctionsTable->SetTreeTableModel(fFunctionsTableModel);
@@ -605,6 +752,23 @@ ImageFunctionsView::_Init()
} }
void
ImageFunctionsView::_ExpandFilteredNodes()
{
if (fFilterField->TextView()->TextLength() == 0)
return;
for (int32 i = 0; i < fFunctionsTableModel->CountChildren(
fFunctionsTableModel); i++) {
TreeTablePath path;
path.AddComponent(i);
fFunctionsTable->SetNodeExpanded(path, true, true);
}
fFunctionsTable->ResizeAllColumnsToPreferred();
}
// #pragma mark - Listener // #pragma mark - Listener
@@ -12,6 +12,7 @@
#include "Team.h" #include "Team.h"
class BTextControl;
class FunctionInstance; class FunctionInstance;
@@ -31,12 +32,15 @@ public:
void SetImageDebugInfo( void SetImageDebugInfo(
ImageDebugInfo* imageDebugInfo); ImageDebugInfo* imageDebugInfo);
void SetFunction(FunctionInstance* function); void SetFunction(FunctionInstance* function);
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
void LoadSettings(const BMessage& settings); void LoadSettings(const BMessage& settings);
status_t SaveSettings(BMessage& settings); status_t SaveSettings(BMessage& settings);
private: private:
class FunctionsTableModel; class FunctionsTableModel;
class HighlightingTableColumn;
class SourcePathComponentNode; class SourcePathComponentNode;
private: private:
@@ -45,11 +49,16 @@ private:
void _Init(); void _Init();
void _ExpandFilteredNodes();
private: private:
ImageDebugInfo* fImageDebugInfo; ImageDebugInfo* fImageDebugInfo;
BTextControl* fFilterField;
TreeTable* fFunctionsTable; TreeTable* fFunctionsTable;
FunctionsTableModel* fFunctionsTableModel; FunctionsTableModel* fFunctionsTableModel;
Listener* fListener; Listener* fListener;
HighlightingTableColumn* fHighlightingColumn;
bigtime_t fLastFilterKeypress;
}; };