Tracker: Allow add-ons to dynamically extend popup menu.

An add-on may now add custom entries to the popup menu, in order
to provide more than one action.

Change-Id: Ib4726c0c1e70c59e3ba4d752df24b76cfee1c4a4
This commit is contained in:
Hrishi Hiraskar
2018-07-19 14:00:48 +00:00
committed by waddlesplash
parent d632c685a0
commit bc8427c522
4 changed files with 155 additions and 23 deletions
+7 -2
View File
@@ -7,8 +7,13 @@
struct entry_ref; struct entry_ref;
class BMessage; class BMessage;
class BMenu;
class BHandler;
extern "C" void process_refs(entry_ref directory, BMessage* refs, extern "C" {
void* reserved); void process_refs(entry_ref directory, BMessage* refs, void* reserved);
void populate_menu(BMessage* msg, BMenu* menu, BHandler* handler);
void message_received(BMessage* msg);
}
#endif // _TRACKER_ADDON_H #endif // _TRACKER_ADDON_H
+1
View File
@@ -69,6 +69,7 @@ enum {
B_ZOOM = '_WZM', B_ZOOM = '_WZM',
B_COLORS_UPDATED = '_CLU', B_COLORS_UPDATED = '_CLU',
B_FONTS_UPDATED = '_FNU', B_FONTS_UPDATED = '_FNU',
B_TRACKER_ADDON_MESSAGE = '_TAM',
_APP_MENU_ = '_AMN', _APP_MENU_ = '_AMN',
_BROWSER_MENUS_ = '_BRM', _BROWSER_MENUS_ = '_BRM',
_MENU_EVENT_ = '_MEV', _MENU_EVENT_ = '_MEV',
+141 -20
View File
@@ -178,9 +178,100 @@ CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
} // namespace BPrivate } // namespace BPrivate
static int32
AddOnMenuGenerate(const entry_ref* addonRef, BMenu* menu,
BContainerWindow* window)
{
BEntry entry(addonRef);
BPath path;
status_t result = entry.InitCheck();
if (result != B_OK)
return result;
result = entry.GetPath(&path);
if (result != B_OK)
return result;
image_id addonImage = load_add_on(path.Path());
if (addonImage < 0)
return addonImage;
void (*populateMenu)(BMessage*, BMenu*, BHandler*);
result = get_image_symbol(addonImage, "populate_menu", 2,
(void**)&populateMenu);
if (result < 0) {
PRINT(("Couldn't find populate_menu\n"));
unload_add_on(addonImage);
return result;
}
BMessage* message = window->AddOnMessage(B_TRACKER_ADDON_MESSAGE);
message->AddRef("addon_ref", addonRef);
// call add-on code
(*populateMenu)(message, menu, window->PoseView());
unload_add_on(addonImage);
return B_OK;
}
static status_t
RunAddOnMessageThread(BMessage *message, void *)
{
entry_ref addonRef;
BEntry entry;
BPath path;
status_t result = message->FindRef("addon_ref", &addonRef);
if (result != B_OK)
goto end;
entry = BEntry(&addonRef);
result = entry.InitCheck();
if (result != B_OK)
goto end;
result = entry.GetPath(&path);
if (result != B_OK)
goto end;
image_id addonImage = load_add_on(path.Path());
if (addonImage < 0) {
result = addonImage;
goto end;
}
void (*messageReceived)(BMessage*);
result = get_image_symbol(addonImage, "message_received", 2,
(void**)&messageReceived);
if (result < 0) {
PRINT(("Couldn't find populate_menu\n"));
unload_add_on(addonImage);
goto end;
}
// call add-on code
(*messageReceived)(message);
unload_add_on(addonImage);
return B_OK;
end:
BString buffer(B_TRANSLATE("Error %error loading add-On %name."));
buffer.ReplaceFirst("%error", strerror(result));
buffer.ReplaceFirst("%name", addonRef.name);
BAlert* alert = new BAlert("", buffer.String(), B_TRANSLATE("Cancel"),
0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
return result;
}
static bool static bool
AddOneAddon(const Model* model, const char* name, uint32 shortcut, AddOneAddon(const Model* model, const char* name, uint32 shortcut,
uint32 modifiers, bool primary, void* context) uint32 modifiers, bool primary, void* context,
BContainerWindow* window, BMenu* menu)
{ {
AddOneAddonParams* params = (AddOneAddonParams*)context; AddOneAddonParams* params = (AddOneAddonParams*)context;
@@ -190,6 +281,9 @@ AddOneAddon(const Model* model, const char* name, uint32 shortcut,
ModelMenuItem* item = new ModelMenuItem(model, name, message, ModelMenuItem* item = new ModelMenuItem(model, name, message,
(char)shortcut, modifiers); (char)shortcut, modifiers);
const entry_ref* addonRef = model->EntryRef();
AddOnMenuGenerate(addonRef, menu, window);
if (primary) if (primary)
params->primaryList->AddItem(item); params->primaryList->AddItem(item);
else else
@@ -1613,6 +1707,12 @@ BContainerWindow::MessageReceived(BMessage* message)
} }
break; break;
case B_TRACKER_ADDON_MESSAGE:
{
_PassMessageToAddOn(message);
break;
}
case B_OBSERVER_NOTICE_CHANGE: case B_OBSERVER_NOTICE_CHANGE:
{ {
int32 observerWhat; int32 observerWhat;
@@ -2981,8 +3081,9 @@ BContainerWindow::AddTrashContextMenus(BMenu* menu)
void void
BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*, BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
uint32 shortcut, uint32 modifiers, bool primary, void* context), uint32 shortcut, uint32 modifiers, bool primary, void* context,
void* passThru, BStringList& mimeTypes) BContainerWindow* window, BMenu* menu),
void* passThru, BStringList& mimeTypes, BMenu* menu)
{ {
AutoLock<LockingList<AddonShortcut> > lock(fAddonsList); AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
if (lock.IsLocked()) { if (lock.IsLocked()) {
@@ -3029,7 +3130,7 @@ BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
} }
} }
((eachAddon)(item->model, item->model->Name(), item->key, ((eachAddon)(item->model, item->model->Name(), item->key,
item->modifiers, primary, passThru)); item->modifiers, primary, passThru, this, menu));
} }
} }
} }
@@ -3062,22 +3163,22 @@ BContainerWindow::BuildMimeTypeList(BStringList& mimeTypes)
void void
BContainerWindow::BuildAddOnMenu(BMenu* menu) BContainerWindow::BuildAddOnMenu(BMenu* parentMenu)
{ {
BMenuItem* item = menu->FindItem(B_TRANSLATE("Add-ons")); BMenuItem* item = parentMenu->FindItem(B_TRANSLATE("Add-ons"));
if (menu->IndexOf(item) == 0) { if (parentMenu->IndexOf(item) == 0) {
// the folder of the context menu seems to be named "Add-Ons" // the folder of the context menu seems to be named "Add-Ons"
// so we just take the last menu item, which is correct if not // so we just take the last menu item, which is correct if not
// build with debug option // build with debug option
item = menu->ItemAt(menu->CountItems() - 1); item = parentMenu->ItemAt(parentMenu->CountItems() - 1);
} }
if (item == NULL) if (item == NULL)
return; return;
BFont font; BFont font;
menu->GetFont(&font); parentMenu->GetFont(&font);
menu = item->Submenu(); BMenu* menu = item->Submenu();
if (menu == NULL) if (menu == NULL)
return; return;
@@ -3102,7 +3203,7 @@ BContainerWindow::BuildAddOnMenu(BMenu* menu)
// build a list of the MIME types of the selected items // build a list of the MIME types of the selected items
EachAddon(AddOneAddon, &params, mimeTypes); EachAddon(AddOneAddon, &params, mimeTypes, parentMenu);
primaryList.SortItems(CompareLabels); primaryList.SortItems(CompareLabels);
secondaryList.SortItems(CompareLabels); secondaryList.SortItems(CompareLabels);
@@ -3256,6 +3357,26 @@ BContainerWindow::UpdateMenu(BMenu* menu, UpdateMenuContext context)
} }
BMessage*
BContainerWindow::AddOnMessage(int32 what)
{
BMessage* message = new BMessage(what);
// add selected refs to message
BObjectList<BPose>* selectionList = PoseView()->SelectionList();
int32 index = 0;
BPose* pose;
while ((pose = selectionList->ItemAt(index++)) != NULL)
message->AddRef("refs", pose->TargetModel()->EntryRef());
message->AddRef("dir_ref", TargetModel()->EntryRef());
message->AddMessenger("TrackerViewToken", BMessenger(PoseView()));
return message;
}
void void
BContainerWindow::LoadAddOn(BMessage* message) BContainerWindow::LoadAddOn(BMessage* message)
{ {
@@ -3276,15 +3397,7 @@ BContainerWindow::LoadAddOn(BMessage* message)
} }
// add selected refs to message // add selected refs to message
BMessage* refs = new BMessage(B_REFS_RECEIVED); BMessage* refs = AddOnMessage(B_REFS_RECEIVED);
BObjectList<BPose>* selectionList = PoseView()->SelectionList();
int32 index = 0;
BPose* pose;
while ((pose = selectionList->ItemAt(index++)) != NULL)
refs->AddRef("refs", pose->TargetModel()->EntryRef());
refs->AddMessenger("TrackerViewToken", BMessenger(PoseView()));
LaunchInNewThread("Add-on", B_NORMAL_PRIORITY, &AddOnThread, refs, LaunchInNewThread("Add-on", B_NORMAL_PRIORITY, &AddOnThread, refs,
addonRef, *TargetModel()->EntryRef()); addonRef, *TargetModel()->EntryRef());
@@ -3342,6 +3455,14 @@ BContainerWindow::_AddFolderIcon()
} }
void
BContainerWindow::_PassMessageToAddOn(BMessage* message)
{
LaunchInNewThread("Add-on-Pass-Message", B_NORMAL_PRIORITY,
&RunAddOnMessageThread, new BMessage(*message), (void*)NULL);
}
BMenuItem* BMenuItem*
BContainerWindow::NewAttributeMenuItem(const char* label, const char* name, BContainerWindow::NewAttributeMenuItem(const char* label, const char* name,
int32 type, float width, int32 align, bool editable, bool statField) int32 type, float width, int32 align, bool editable, bool statField)
+6 -1
View File
@@ -189,7 +189,11 @@ public:
// add-on iteration // add-on iteration
void EachAddon(bool (*)(const Model*, const char*, uint32 shortcut, void EachAddon(bool (*)(const Model*, const char*, uint32 shortcut,
uint32 modifiers, bool primary, void*), void*, BStringList&); uint32 modifiers, bool primary, void*, BContainerWindow*, BMenu*),
void*, BStringList&, BMenu*);
BMessage* AddOnMessage(int32);
entry_ref GetCurrentDirRef();
BPopUpMenu* ContextMenu(); BPopUpMenu* ContextMenu();
@@ -342,6 +346,7 @@ private:
void _UpdateSelectionMIMEInfo(); void _UpdateSelectionMIMEInfo();
void _AddFolderIcon(); void _AddFolderIcon();
void _PassMessageToAddOn(BMessage*);
}; };