Tracker: store default add-ons shortcuts in resource

* Default shortcuts for add-ons are now stored within the binary as a resource
(it was previously appended to the file name, as Open Terminal-T, for example)
* Use ~/config/shortcuts_settings to override those default shortcuts
(editable with Shortcuts preflet)
* Tracker avoid rescanning the add-ons directories when unnecessary
* Monitor the shortcuts_settings to apply changes on the fly
* Fallback to default shortcuts whenever appropriate (settings file deleted, etc.)
* Should fix #4446 (with resource rather than attributes)
This commit is contained in:
Philippe Saint-Pierre
2013-07-11 12:38:41 -04:00
parent 41e6527c1f
commit d058a4aed2
5 changed files with 308 additions and 206 deletions
+43 -141
View File
@@ -145,6 +145,8 @@ const int32 kWindowStaggerBy = 17;
BRect BContainerWindow::sNewWindRect(85, 50, 548, 280);
LockingList<AddonShortcut>* BContainerWindow::fAddonsList
= new LockingList<struct AddonShortcut>(10, true);
namespace BPrivate {
@@ -165,48 +167,6 @@ ActivateWindowFilter(BMessage*, BHandler** target, BMessageFilter*)
}
static void
StripShortcut(const Model* model, char* result, uint32 &shortcut)
{
// model name (possibly localized) for the menu item label
strlcpy(result, model->Name(), B_FILE_NAME_LENGTH);
// check if there is a shortcut in the model name
uint32 length = strlen(result);
if (length > 2 && result[length - 2] == '-') {
shortcut = result[length - 1];
result[length - 2] = '\0';
return;
}
// check if there is a shortcut in the filename
char* refName = model->EntryRef()->name;
length = strlen(refName);
if (length > 2 && refName[length - 2] == '-') {
shortcut = refName[length - 1];
return;
}
shortcut = '\0';
}
static const Model*
MatchOne(const Model* model, void* castToName)
{
char buffer[B_FILE_NAME_LENGTH];
uint32 dummy;
StripShortcut(model, buffer, dummy);
if (strcmp(buffer, (const char*)castToName) == 0) {
// found match, bail out
return model;
}
return 0;
}
int
CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
{
@@ -217,8 +177,8 @@ CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
static bool
AddOneAddon(const Model* model, const char* name, uint32 shortcut,
bool primary, void* context)
AddOneAddon(const Model* model, const char* name, uint32 shortcut,
uint32 modifiers, bool primary, void* context)
{
AddOneAddonParams* params = (AddOneAddonParams*)context;
@@ -226,7 +186,7 @@ AddOneAddon(const Model* model, const char* name, uint32 shortcut,
message->AddRef("refs", model->EntryRef());
ModelMenuItem* item = new ModelMenuItem(model, name, message,
(char)shortcut, B_OPTION_KEY);
(char)shortcut, modifiers);
if (primary)
params->primaryList->AddItem(item);
@@ -2919,114 +2879,56 @@ BContainerWindow::AddTrashContextMenus(BMenu* menu)
void
BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
uint32 shortcut, bool primary, void* context), void* passThru,
BObjectList<BString> &mimeTypes)
uint32 shortcut, uint32 modifiers, bool primary, void* context),
void* passThru, BObjectList<BString> &mimeTypes)
{
BObjectList<Model> uniqueList(10, true);
BPath path;
bool bail = false;
if (find_directory(B_BEOS_ADDONS_DIRECTORY, &path) == B_OK)
bail = EachAddon(path, eachAddon, &uniqueList, passThru, mimeTypes);
AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
if (lock.IsLocked()) {
for (int i = fAddonsList->CountItems() - 1; i >= 0; i--) {
struct AddonShortcut* item = fAddonsList->ItemAt(i);
bool primary = false;
if (!bail && find_directory(B_USER_ADDONS_DIRECTORY, &path) == B_OK)
bail = EachAddon(path, eachAddon, &uniqueList, passThru, mimeTypes);
if (mimeTypes.CountItems()) {
BFile file(item->model->EntryRef(), B_READ_ONLY);
if (file.InitCheck() == B_OK) {
BAppFileInfo info(&file);
if (info.InitCheck() == B_OK) {
bool secondary = true;
if (!bail && find_directory(B_COMMON_ADDONS_DIRECTORY, &path) == B_OK)
EachAddon(path, eachAddon, &uniqueList, passThru, mimeTypes);
}
// does this add-on has types set at all?
BMessage message;
if (info.GetSupportedTypes(&message) == B_OK) {
type_code type;
int32 count;
if (message.GetInfo("types", &type,
&count) == B_OK)
secondary = false;
}
bool
BContainerWindow::EachAddon(BPath &path, bool (*eachAddon)(const Model*,
const char*, uint32 shortcut, bool primary, void*),
BObjectList<Model>* uniqueList, void* params,
BObjectList<BString> &mimeTypes)
{
path.Append("Tracker");
BDirectory dir;
BEntry entry;
if (dir.SetTo(path.Path()) != B_OK)
return false;
dir.Rewind();
while (dir.GetNextEntry(&entry) == B_OK) {
Model* model = new Model(&entry);
if (model->InitCheck() == B_OK && model->IsSymLink()) {
// resolve symlinks
Model* resolved = new Model(model->EntryRef(), true, true);
if (resolved->InitCheck() == B_OK)
model->SetLinkTo(resolved);
else
delete resolved;
}
if (model->InitCheck() != B_OK
|| !model->ResolveIfLink()->IsExecutable()) {
delete model;
continue;
}
// check if it supports at least one of the selected entries
bool primary = false;
if (mimeTypes.CountItems()) {
BFile file(&entry, B_READ_ONLY);
if (file.InitCheck() == B_OK) {
BAppFileInfo info(&file);
if (info.InitCheck() == B_OK) {
bool secondary = true;
// does this add-on has types set at all?
BMessage message;
if (info.GetSupportedTypes(&message) == B_OK) {
type_code type;
int32 count;
if (message.GetInfo("types", &type, &count) == B_OK)
secondary = false;
}
// check all supported types if it has some set
if (!secondary) {
for (int32 i = mimeTypes.CountItems();
!primary && i-- > 0;) {
BString* type = mimeTypes.ItemAt(i);
if (info.IsSupportedType(type->String())) {
BMimeType mimeType(type->String());
if (info.Supports(&mimeType))
primary = true;
else
secondary = true;
// check all supported types if it has some set
if (!secondary) {
for (int32 i = mimeTypes.CountItems();
!primary && i-- > 0;) {
BString* type = mimeTypes.ItemAt(i);
if (info.IsSupportedType(type->String())) {
BMimeType mimeType(type->String());
if (info.Supports(&mimeType))
primary = true;
else
secondary = true;
}
}
}
}
if (!secondary && !primary) {
delete model;
continue;
if (!secondary && !primary)
continue;
}
}
}
((eachAddon)(item->model, item->model->Name(), item->key,
item->modifiers, primary, passThru));
}
char name[B_FILE_NAME_LENGTH];
uint32 key;
StripShortcut(model, name, key);
// do a uniqueness check
if (uniqueList->EachElement(MatchOne, name)) {
// found one already in the list
delete model;
continue;
}
uniqueList->AddItem(model);
if ((eachAddon)(model, name, key, primary, params))
return true;
}
return false;
}