#include <Catalog.h>
#include <Debug.h>
#include <Directory.h>
#include <Locale.h>
#include <MenuBar.h>
#include <Path.h>
#include <Volume.h>
#include <VolumeRoster.h>
#include "Attributes.h"
#include "ContainerWindow.h"
#include "DirMenu.h"
#include "FSUtils.h"
#include "IconMenuItem.h"
#include "NavMenu.h"
#include "TrackerSettings.h"
#include "Utilities.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "DirMenu"
BDirMenu::BDirMenu(BMenuBar* bar, BMessenger target, uint32 command,
const char* entryName)
:
BPopUpMenu("directories"),
fTarget(target),
fMenuBar(bar),
fCommand(command)
{
if (entryName)
fEntryName = entryName;
else
fEntryName = "refs";
}
BDirMenu::~BDirMenu()
{
}
void
BDirMenu::Populate(const BEntry* startEntry, BWindow* source,
bool includeStartEntry, bool select, bool reverse, bool addShortcuts,
bool navMenuEntries)
{
try {
if (!startEntry)
throw (status_t)B_ERROR;
Model model(startEntry);
ThrowOnInitCheckError(&model);
ModelMenuItem* menu = NULL;
if (fMenuBar != NULL) {
menu = new ModelMenuItem(&model, this, true, true);
fMenuBar->AddItem(menu);
}
BEntry entry(*startEntry);
bool showDesktop, showDisksIcon;
{
TrackerSettings settings;
showDesktop = settings.DesktopFilePanelRoot();
showDisksIcon = settings.ShowDisksIcon();
}
if (!includeStartEntry) {
BDirectory parent;
BDirectory dir(&entry);
if (!showDesktop && dir.InitCheck() == B_OK && dir.IsRootDirectory()) {
parent.SetTo("/");
parent.GetEntry(&entry);
} else
FSGetParentVirtualDirectoryAware(entry, entry);
}
BDirectory desktopDir;
FSGetDeskDir(&desktopDir);
BEntry desktopEntry;
desktopDir.GetEntry(&desktopEntry);
for (;;) {
BNode node(&entry);
ThrowOnInitCheckError(&node);
PoseInfo info;
ReadAttrResult result = ReadAttr(&node, kAttrPoseInfo,
kAttrPoseInfoForeign, B_RAW_TYPE, 0, &info, sizeof(PoseInfo),
&PoseInfo::EndianSwap);
BEntry parentEntry;
bool hitRoot = false;
BDirectory dir(&entry);
if (!showDesktop && dir.InitCheck() == B_OK && dir.IsRootDirectory()) {
hitRoot = true;
parentEntry.SetTo("/");
} else
FSGetParentVirtualDirectoryAware(entry, parentEntry);
if (showDesktop) {
BEntry root("/");
if (entry == root) {
if (showDisksIcon)
AddDisksIconToMenu(reverse);
entry = desktopEntry;
}
if (entry == desktopEntry)
hitRoot = true;
}
if (result == kReadAttrFailed || !info.fInvisible
|| (showDesktop && desktopEntry == entry)) {
AddItemToDirMenu(&entry, source, reverse, addShortcuts, navMenuEntries);
}
if (hitRoot) {
if (!showDesktop && showDisksIcon && *startEntry != "/")
AddDisksIconToMenu(reverse);
break;
}
entry = parentEntry;
if (entry.InitCheck() != B_OK)
break;
}
if (!select)
return;
ModelMenuItem* item = dynamic_cast<ModelMenuItem*>(ItemAt(CountItems() - 1));
if (item != NULL) {
item->SetMarked(true);
if (menu) {
entry.SetTo(item->TargetModel()->EntryRef());
ThrowOnError(menu->SetEntry(&entry));
}
}
} catch (status_t err) {
PRINT(("BDirMenu::Populate: caught error %s\n", strerror(err)));
if (!CountItems()) {
BString error;
error << "Error [" << strerror(err) << "] populating menu";
AddItem(new BMenuItem(error.String(), 0));
}
}
}
void
BDirMenu::AddItemToDirMenu(const BEntry* entry, BWindow* source,
bool atEnd, bool addShortcuts, bool navMenuEntries)
{
Model model(entry);
if (model.InitCheck() != B_OK)
return;
BMessage* message = new BMessage(fCommand);
message->AddRef(fEntryName.String(), model.EntryRef());
BContainerWindow* window = dynamic_cast<BContainerWindow*>(source);
if (window != NULL) {
message->AddData("nodeRefsToClose", B_RAW_TYPE,
window->TargetModel()->NodeRef(), sizeof(node_ref));
}
ModelMenuItem* item;
if (navMenuEntries) {
BNavMenu* subMenu = new BNavMenu(model.Name(), fCommand, fTarget, source);
entry_ref ref;
entry->GetRef(&ref);
subMenu->SetNavDir(&ref);
item = new ModelMenuItem(&model, subMenu);
item->SetLabel(model.Name());
item->SetMessage(message);
} else {
item = new ModelMenuItem(&model, model.Name(), message);
}
if (addShortcuts) {
if (model.IsDesktop())
item->SetShortcut('D', B_COMMAND_KEY);
else if (FSIsHomeDir(entry))
item->SetShortcut('H', B_COMMAND_KEY);
}
if (atEnd)
AddItem(item);
else
AddItem(item, 0);
item->SetTarget(fTarget);
if (fMenuBar != NULL) {
ModelMenuItem* menu = dynamic_cast<ModelMenuItem*>(fMenuBar->ItemAt(0));
if (menu != NULL) {
ThrowOnError(menu->SetEntry(entry));
item->SetMarked(true);
}
}
}
void
BDirMenu::AddDisksIconToMenu(bool atEnd)
{
BEntry entry("/");
Model model(&entry);
if (model.InitCheck() != B_OK)
return;
entry_ref ref;
entry.GetRef(&ref);
BMessage* message = new BMessage(fCommand);
message->AddRef(fEntryName.String(), &ref);
BNavMenu* subMenu = new BNavMenu(model.Name(), fCommand, fTarget);
subMenu->SetNavDir(&ref);
ModelMenuItem* item = new ModelMenuItem(&model, subMenu);
item->SetLabel(model.Name());
item->SetMessage(message);
if (atEnd)
AddItem(item);
else
AddItem(item, 0);
item->SetTarget(fTarget);
}