From 17ef26a9f8319415aa24e54aae6cfdbea1624071 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Sun, 15 Jul 2012 14:28:20 -0400 Subject: [PATCH] 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. --- .../gui/team_window/VariablesView.cpp | 142 ++++++++++++++---- .../gui/team_window/VariablesView.h | 3 +- 2 files changed, 113 insertions(+), 32 deletions(-) diff --git a/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp b/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp index 85a26a291e..04ad5d457b 100644 --- a/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp @@ -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 settingsLocker(fRendererSettings); - fRendererSettings->AddListener(this); - - fRendererMenuAdded = true; + if (fRendererSettings != NULL) { + AutoLocker 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( 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( 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 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 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 trackerReference(tracker); - if (tracker == NULL || tracker->Init(settings, settingsMenu) != B_OK) + + ContextActionList* preActionList = new(std::nothrow) ContextActionList; + if (preActionList == NULL) + return; + + BPrivate::ObjectDeleter 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 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 actionDeleter(item); + if (!actions->AddItem(item)) + return B_NO_MEMORY; + + actionDeleter.Detach(); + return B_OK; +} + + void VariablesView::_FinishContextMenu(bool force) { diff --git a/src/apps/debugger/user_interface/gui/team_window/VariablesView.h b/src/apps/debugger/user_interface/gui/team_window/VariablesView.h index d1fa54b55b..30f3149fa9 100644 --- a/src/apps/debugger/user_interface/gui/team_window/VariablesView.h +++ b/src/apps/debugger/user_interface/gui/team_window/VariablesView.h @@ -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(