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:
committed by
waddlesplash
parent
d632c685a0
commit
bc8427c522
@@ -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
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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, ¶ms, mimeTypes);
|
EachAddon(AddOneAddon, ¶ms, 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)
|
||||||
|
|||||||
@@ -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*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user