#include "FavoritesMenu.h"
#include <compat/sys/stat.h>
#include <Application.h>
#include <Catalog.h>
#include <FindDirectory.h>
#include <FilePanel.h>
#include <Locale.h>
#include <Message.h>
#include <Path.h>
#include <Query.h>
#include <Roster.h>
#include <functional>
#include <algorithm>
#include "IconMenuItem.h"
#include "PoseView.h"
#include "QueryPoseView.h"
#include "Tracker.h"
#include "Utilities.h"
#include "VirtualDirectoryEntryList.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FavoritesMenu"
FavoritesMenu::FavoritesMenu(const char* title, BMessage* openFolderMessage,
BMessage* openFileMessage, const BMessenger &target,
bool isSavePanel, BRefFilter* filter)
:
BSlowMenu(title),
fOpenFolderMessage(openFolderMessage),
fOpenFileMessage(openFileMessage),
fTarget(target),
fState(kStart),
fIndex(-1),
fSectionItemCount(-1),
fAddedSeparatorForSection(false),
fContainer(NULL),
fItemList(NULL),
fInitialItemCount(0),
fIsSavePanel(isSavePanel),
fRefFilter(filter)
{
}
FavoritesMenu::~FavoritesMenu()
{
delete fOpenFolderMessage;
delete fOpenFileMessage;
delete fContainer;
}
void
FavoritesMenu::SetRefFilter(BRefFilter* filter)
{
fRefFilter = filter;
}
bool
FavoritesMenu::StartBuildingItemList()
{
if (fInitialItemCount == 0)
fInitialItemCount = CountItems();
else {
int32 count = CountItems() - fInitialItemCount;
while (count--)
delete RemoveItem(fInitialItemCount);
}
fUniqueRefCheck.clear();
fState = kStart;
return true;
}
bool
FavoritesMenu::AddNextItem()
{
if (fState == kStart) {
fState = kAddingFavorites;
fSectionItemCount = 0;
fAddedSeparatorForSection = false;
try {
BPath path;
ThrowOnError(find_directory(B_USER_SETTINGS_DIRECTORY,
&path, true));
path.Append(kGoDirectory);
mkdir(path.Path(), 0777);
BEntry entry(path.Path());
Model startModel(&entry, true);
ThrowOnInitCheckError(&startModel);
if (!startModel.IsContainer())
throw B_ERROR;
if (startModel.IsQuery())
fContainer = new QueryEntryListCollection(&startModel);
else if (startModel.IsVirtualDirectory())
fContainer = new VirtualDirectoryEntryList(&startModel);
else {
BDirectory* directory
= dynamic_cast<BDirectory*>(startModel.Node());
if (directory != NULL)
fContainer = new DirectoryEntryList(*directory);
}
ThrowOnInitCheckError(fContainer);
ThrowOnError(fContainer->Rewind());
} catch (...) {
delete fContainer;
fContainer = NULL;
}
}
if (fState == kAddingFavorites) {
entry_ref ref;
if (fContainer != NULL && fContainer->GetNextRef(&ref) == B_OK) {
Model model(&ref, true);
if (model.InitCheck() != B_OK)
return true;
if (!ShouldShowModel(&model))
return true;
BMenuItem* item = BNavMenu::NewModelItem(&model,
model.IsDirectory() ? fOpenFolderMessage : fOpenFileMessage,
fTarget);
if (item == NULL)
return true;
item->SetLabel(ref.name);
if (!fAddedSeparatorForSection) {
fAddedSeparatorForSection = true;
AddItem(new TitledSeparatorItem(B_TRANSLATE("Favorites")));
}
fUniqueRefCheck.push_back(*model.EntryRef());
AddItem(item);
fSectionItemCount++;
return true;
}
fState = kAddingFiles;
fAddedSeparatorForSection = false;
app_info info;
be_app->GetAppInfo(&info);
fItems.MakeEmpty();
int32 apps, docs, folders;
TrackerSettings().RecentCounts(&apps, &docs, &folders);
BRoster().GetRecentDocuments(&fItems, docs, NULL, info.signature);
fIndex = 0;
fSectionItemCount = 0;
}
if (fState == kAddingFiles) {
if (!fIsSavePanel) {
for (;;) {
entry_ref ref;
if (fItems.FindRef("refs", fIndex++, &ref) != B_OK)
break;
Model model(&ref, true);
if (model.InitCheck() != B_OK)
return true;
if (!ShouldShowModel(&model))
return true;
BMenuItem* item = BNavMenu::NewModelItem(&model,
fOpenFileMessage, fTarget);
if (item) {
if (!fAddedSeparatorForSection) {
fAddedSeparatorForSection = true;
AddItem(new TitledSeparatorItem(
B_TRANSLATE("Recent documents")));
}
AddItem(item);
fSectionItemCount++;
return true;
}
}
}
fState = kAddingFolders;
fAddedSeparatorForSection = false;
app_info info;
be_app->GetAppInfo(&info);
fItems.MakeEmpty();
int32 apps, docs, folders;
TrackerSettings().RecentCounts(&apps, &docs, &folders);
BRoster().GetRecentFolders(&fItems, folders, info.signature);
fIndex = 0;
}
if (fState == kAddingFolders) {
for (;;) {
entry_ref ref;
if (fItems.FindRef("refs", fIndex++, &ref) != B_OK)
break;
if (find_if(fUniqueRefCheck.begin(), fUniqueRefCheck.end(),
#if __GNUC__ <= 2
bind2nd(std::equal_to<entry_ref>(), ref)
#else
[ref](entry_ref compared) { return ref == compared; }
#endif
)
!= fUniqueRefCheck.end()) {
continue;
}
Model model(&ref, true);
if (model.InitCheck() != B_OK)
return true;
if (!ShouldShowModel(&model))
return true;
BMenuItem* item = BNavMenu::NewModelItem(&model,
fOpenFolderMessage, fTarget, true);
if (item != NULL) {
if (!fAddedSeparatorForSection) {
fAddedSeparatorForSection = true;
AddItem(new TitledSeparatorItem(
B_TRANSLATE("Recent folders")));
}
AddItem(item);
item->SetEnabled(true);
return true;
}
}
}
return false;
}
void
FavoritesMenu::DoneBuildingItemList()
{
SetTargetForItems(fTarget);
}
void
FavoritesMenu::ClearMenuBuildingState()
{
delete fContainer;
fContainer = NULL;
fState = kDone;
fMenuBuilt = false;
}
bool
FavoritesMenu::ShouldShowModel(const Model* model)
{
if (fIsSavePanel && model->IsFile())
return false;
if (!fRefFilter || model->Node() == NULL)
return true;
struct stat_beos statBeOS;
convert_to_stat_beos(model->StatBuf(), &statBeOS);
return fRefFilter->Filter(model->EntryRef(), model->Node(), &statBeOS,
model->MimeType());
}
RecentsMenu::RecentsMenu(const char* name, int32 which, uint32 what,
BHandler* target)
:
BNavMenu(name, what, target),
fWhich(which),
fRecentsCount(0),
fItemIndex(0)
{
int32 applications;
int32 documents;
int32 folders;
TrackerSettings().RecentCounts(&applications,&documents,&folders);
if (fWhich == 0)
fRecentsCount = documents;
else if (fWhich == 1)
fRecentsCount = applications;
else if (fWhich == 2)
fRecentsCount = folders;
}
void
RecentsMenu::DetachedFromWindow()
{
BMenu::DetachedFromWindow();
}
bool
RecentsMenu::StartBuildingItemList()
{
int32 count = CountItems()-1;
for (int32 index = count; index >= 0; index--) {
BMenuItem* item = ItemAt(index);
ASSERT(item != NULL);
RemoveItem(index);
delete item;
}
return true;
}
bool
RecentsMenu::AddNextItem()
{
if (fRecentsCount > 0 && AddRecents(fRecentsCount))
return true;
fItemIndex = 0;
return false;
}
bool
RecentsMenu::AddRecents(int32 count)
{
if (fItemIndex == 0) {
fRecentList.MakeEmpty();
BRoster roster;
switch(fWhich) {
case 0:
roster.GetRecentDocuments(&fRecentList, count);
break;
case 1:
roster.GetRecentApps(&fRecentList, count);
break;
case 2:
roster.GetRecentFolders(&fRecentList, count);
break;
default:
return false;
break;
}
}
for (;;) {
entry_ref ref;
if (fRecentList.FindRef("refs", fItemIndex++, &ref) != B_OK)
break;
if (ref.name != NULL && strlen(ref.name) > 0) {
Model model(&ref, true);
ModelMenuItem* item = BNavMenu::NewModelItem(&model,
new BMessage(fMessage.what),
Target(), false, NULL, TypesList());
if (item != NULL) {
AddItem(item);
return true;
}
return true;
}
}
return false;
}
void
RecentsMenu::DoneBuildingItemList()
{
if (CountItems() <= 0) {
BMenuItem* item = new BMenuItem(B_TRANSLATE("<No recent items>"), 0);
item->SetEnabled(false);
AddItem(item);
} else
SetTargetForItems(Target());
}
void
RecentsMenu::ClearMenuBuildingState()
{
fMenuBuilt = false;
BNavMenu::ClearMenuBuildingState();
}