Add inspection context menu action.

- TableCellContextMenuTracker now supports menus that don't have a settings
  submenu, since some variables won't have renderer settings but will still
  have context actions.

- Add _GetContextActionsForNode() to retrieve the list of contextual actions
  available for a given model node. Currently this is only adds an action
  to inspect the memory address of the highlighted value, but will be extended
  for other actions later.
This commit is contained in:
Rene Gollent 2012-07-15 14:28:20 -04:00
parent ae8018310a
commit 17ef26a9f8
2 changed files with 113 additions and 32 deletions

View File

@ -37,6 +37,7 @@
#include "Value.h"
#include "ValueHandler.h"
#include "ValueHandlerRoster.h"
#include "ValueLocation.h"
#include "ValueNode.h"
#include "ValueNodeContainer.h"
#include "Variable.h"
@ -492,11 +493,19 @@ public:
ContextActionList* preSettingsActions = NULL,
ContextActionList* postSettingsActions = NULL)
{
fRendererSettings = rendererSettings;
fRendererSettings->AcquireReference();
if (rendererSettings == NULL && preSettingsActions == NULL
&& postSettingsActions == NULL) {
return B_BAD_VALUE;
}
fRendererSettingsMenu = rendererSettingsMenu;
fRendererSettingsMenu->AcquireReference();
if (rendererSettings != NULL) {
fRendererSettings = rendererSettings;
fRendererSettings->AcquireReference();
fRendererSettingsMenu = rendererSettingsMenu;
fRendererSettingsMenu->AcquireReference();
}
fContextMenu = new(std::nothrow) ContextMenu(fParent,
"table cell settings popup");
@ -504,39 +513,52 @@ public:
return B_NO_MEMORY;
status_t error = B_OK;
if (preSettingsActions != NULL) {
if (preSettingsActions != NULL
&& preSettingsActions->CountItems() > 0) {
error = _AddActionItems(preSettingsActions);
if (error != B_OK)
return error;
if (fRendererSettingsMenu != NULL || postSettingsActions != NULL)
fContextMenu->AddSeparatorItem();
}
error = fRendererSettingsMenu->AddToMenu(fContextMenu, 0);
if (error != B_OK)
return error;
if (fRendererSettingsMenu != NULL) {
error = fRendererSettingsMenu->AddToMenu(fContextMenu,
fContextMenu->CountItems());
if (error != B_OK)
return error;
if (postSettingsActions != NULL)
fContextMenu->AddSeparatorItem();
}
if (postSettingsActions != NULL) {
error = _AddActionItems(postSettingsActions);
if (error != B_OK)
return error;
}
AutoLocker<Settings> settingsLocker(fRendererSettings);
fRendererSettings->AddListener(this);
fRendererMenuAdded = true;
if (fRendererSettings != NULL) {
AutoLocker<Settings> settingsLocker(fRendererSettings);
fRendererSettings->AddListener(this);
fRendererMenuAdded = true;
}
return B_OK;
}
void ShowMenu(BPoint screenWhere)
{
fRendererSettingsMenu->PrepareToShow(fParentLooper);
if (fRendererMenuAdded)
fRendererSettingsMenu->PrepareToShow(fParentLooper);
for (int32 i = 0; i < fContextMenu->CountItems(); i++) {
ActionMenuItem* item = dynamic_cast<ActionMenuItem*>(
fContextMenu->ItemAt(i));
if (item != NULL)
item->PrepareToShow(fParentLooper, fContextMenu);
item->PrepareToShow(fParentLooper, fParent.Target(NULL));
}
fMenuPreparedToShow = true;
@ -551,13 +573,15 @@ public:
bool stillActive = false;
if (fMenuPreparedToShow) {
stillActive = fRendererSettingsMenu->Finish(fParentLooper, force);
if (fRendererMenuAdded)
stillActive = fRendererSettingsMenu->Finish(fParentLooper,
force);
for (int32 i = 0; i < fContextMenu->CountItems(); i++) {
ActionMenuItem* item = dynamic_cast<ActionMenuItem*>(
fContextMenu->ItemAt(i));
if (item != NULL) {
stillActive |= item->Finish(fParentLooper, fContextMenu,
force);
stillActive |= item->Finish(fParentLooper,
fParent.Target(NULL), force);
}
}
@ -1462,6 +1486,15 @@ void
VariablesView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_SHOW_INSPECTOR_WINDOW:
{
// TODO: it'd probably be more ideal to extend the context
// action mechanism to allow one to specify an explicit
// target for each action rather than them all defaulting
// to targetting here.
Looper()->PostMessage(message);
break;
}
case MSG_VALUE_NODE_CHANGED:
{
ValueNodeChild* nodeChild;
@ -1644,25 +1677,39 @@ VariablesView::TreeTableCellMouseDown(TreeTable* table,
if (node == NULL)
return;
Settings* settings = NULL;
SettingsMenu* settingsMenu = NULL;
BReference<SettingsMenu> settingsMenuReference;
status_t error = B_OK;
TableCellValueRenderer* cellRenderer = node->TableCellRenderer();
if (cellRenderer == NULL)
return;
Settings* settings = cellRenderer->GetSettings();
if (settings == NULL)
return;
SettingsMenu* settingsMenu;
status_t error = node->GetValueHandler()->CreateTableCellValueSettingsMenu(
node->GetValue(), settings, settingsMenu);
BReference<SettingsMenu> settingsMenuReference(settingsMenu, true);
if (error != B_OK)
return;
if (cellRenderer != NULL) {
settings = cellRenderer->GetSettings();
if (settings != NULL) {
error = node->GetValueHandler()
->CreateTableCellValueSettingsMenu(node->GetValue(), settings,
settingsMenu);
settingsMenuReference.SetTo(settingsMenu, true);
if (error != B_OK)
return;
}
}
TableCellContextMenuTracker* tracker = new(std::nothrow)
TableCellContextMenuTracker(node, Looper(), this);
BReference<TableCellContextMenuTracker> trackerReference(tracker);
if (tracker == NULL || tracker->Init(settings, settingsMenu) != B_OK)
ContextActionList* preActionList = new(std::nothrow) ContextActionList;
if (preActionList == NULL)
return;
BPrivate::ObjectDeleter<ContextActionList> preActionListDeleter(
preActionList);
error = _GetContextActionsForNode(node, preActionList);
if (error != B_OK)
return;
if (tracker == NULL || tracker->Init(settings, settingsMenu, preActionList) != B_OK)
return;
fTableCellContextMenuTracker = trackerReference.Detach();
@ -1729,6 +1776,39 @@ VariablesView::_RequestNodeValue(ModelNode* node)
}
status_t
VariablesView::_GetContextActionsForNode(ModelNode* node,
ContextActionList* actions)
{
ValueLocation* location = node->NodeChild()->Location();
// if the location's stored somewhere other than in memory,
// then we won't be able to inspect it this way.
if (location->PieceAt(0).type != VALUE_PIECE_LOCATION_MEMORY)
return B_OK;
BMessage* message = new BMessage(MSG_SHOW_INSPECTOR_WINDOW);
if (message == NULL)
return B_NO_MEMORY;
ObjectDeleter<BMessage> messageDeleter(message);
message->AddUInt64("address", location->PieceAt(0).address);
ActionMenuItem* item = new(std::nothrow) ActionMenuItem("Inspect",
message);
if (item == NULL)
return B_NO_MEMORY;
messageDeleter.Detach();
ObjectDeleter<ActionMenuItem> actionDeleter(item);
if (!actions->AddItem(item))
return B_NO_MEMORY;
actionDeleter.Detach();
return B_OK;
}
void
VariablesView::_FinishContextMenu(bool force)
{

View File

@ -68,8 +68,9 @@ private:
void _Init();
void _RequestNodeValue(ModelNode* node);
status_t _GetContextActionsForNode(ModelNode* node,
ContextActionList* actions);
void _FinishContextMenu(bool force);
void _SaveViewState() const;
void _RestoreViewState();
status_t _AddViewStateDescendentNodeInfos(