Open Tracker License
Terms and Conditions
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice applies to all licensees
and shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Be Incorporated shall not be
used in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from Be Incorporated.
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
of Be Incorporated in the United States and other countries. Other brand product
names are registered trademarks or trademarks of their respective holders.
All rights reserved.
*/
#include "ContainerWindow.h"
#include <Alert.h>
#include <Application.h>
#include <AppFileInfo.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <GridView.h>
#include <GroupLayout.h>
#include <Keymap.h>
#include <Locale.h>
#include <MenuItem.h>
#include <MenuBar.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <PopUpMenu.h>
#include <Roster.h>
#include <Screen.h>
#include <UnicodeChar.h>
#include <Volume.h>
#include <VolumeRoster.h>
#include <WindowPrivate.h>
#include <fs_attr.h>
#include <image.h>
#include <strings.h>
#include <stdlib.h>
#include <algorithm>
#include <memory>
#include "Attributes.h"
#include "AttributeStream.h"
#include "AutoLock.h"
#include "BackgroundImage.h"
#include "Commands.h"
#include "CountView.h"
#include "DeskWindow.h"
#include "FavoritesMenu.h"
#include "FindPanel.h"
#include "FSClipboard.h"
#include "FSUndoRedo.h"
#include "FSUtils.h"
#include "IconMenuItem.h"
#include "OpenWithWindow.h"
#include "MimeTypes.h"
#include "MountMenu.h"
#include "Navigator.h"
#include "NavMenu.h"
#include "PoseView.h"
#include "QueryContainerWindow.h"
#include "SelectionWindow.h"
#include "TitleView.h"
#include "Tracker.h"
#include "TrackerSettings.h"
#include "Thread.h"
#include "TemplatesMenu.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ContainerWindow"
#ifdef _IMPEXP_BE
_IMPEXP_BE
#endif
void do_minimize_team(BRect zoomRect, team_id team, bool zoom);
const float kDragSlop = 3.0f;
namespace BPrivate {
class DraggableContainerIcon : public BView {
public:
DraggableContainerIcon();
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint);
virtual void MouseMoved(BPoint point, uint32, const BMessage*);
virtual void Draw(BRect updateRect);
private:
uint32 fDragButton;
BPoint fClickPoint;
bool fDragStarted;
};
}
struct AddOneAddonParams {
BObjectList<BMenuItem>* primaryList;
BObjectList<BMenuItem>* secondaryList;
};
struct StaggerOneParams {
bool rectFromParent;
};
const int32 kWindowStaggerBy = 17;
BRect BContainerWindow::sNewWindRect(85, 50, 548, 280);
LockingList<AddonShortcut>* BContainerWindow::fAddonsList
= new LockingList<struct AddonShortcut>(10, true);
namespace BPrivate {
filter_result
ActivateWindowFilter(BMessage*, BHandler** target, BMessageFilter*)
{
BView* view = dynamic_cast<BView*>(*target);
if (view != NULL
&& dynamic_cast<BPoseView*>(view) == NULL
&& dynamic_cast<DraggableContainerIcon*>(view) == NULL
&& view->Window() != NULL) {
view->Window()->Activate(true);
}
return B_DISPATCH_MESSAGE;
}
int
CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
{
return strcasecmp(item1->Label(), item2->Label());
}
}
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);
(*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);
image_id addonImage;
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;
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 message_received\n"));
unload_add_on(addonImage);
goto end;
}
(*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
AddOneAddon(const Model* model, const char* name, uint32 shortcut,
uint32 modifiers, bool primary, void* context,
BContainerWindow* window, BMenu* menu)
{
AddOneAddonParams* params = (AddOneAddonParams*)context;
BMessage* message = new BMessage(kLoadAddOn);
message->AddRef("refs", model->EntryRef());
ModelMenuItem* item = new ModelMenuItem(model, name, message,
(char)shortcut, modifiers);
const entry_ref* addonRef = model->EntryRef();
AddOnMenuGenerate(addonRef, menu, window);
if (primary)
params->primaryList->AddItem(item);
else
params->secondaryList->AddItem(item);
return false;
}
static int32
AddOnThread(BMessage* refsMessage, entry_ref addonRef, entry_ref directoryRef)
{
std::auto_ptr<BMessage> refsMessagePtr(refsMessage);
BEntry entry(&addonRef);
BPath path;
status_t result = entry.InitCheck();
if (result == B_OK)
result = entry.GetPath(&path);
if (result == B_OK) {
image_id addonImage = load_add_on(path.Path());
if (addonImage >= 0) {
void (*processRefs)(entry_ref, BMessage*, void*);
result = get_image_symbol(addonImage, "process_refs", 2,
(void**)&processRefs);
if (result >= 0) {
(*processRefs)(directoryRef, refsMessagePtr.get(), NULL);
unload_add_on(addonImage);
return B_OK;
} else
PRINT(("couldn't find process_refs\n"));
unload_add_on(addonImage);
} else
result = addonImage;
}
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
NodeHasSavedState(const BNode* node)
{
attr_info info;
return node->GetAttrInfo(kAttrWindowFrame, &info) == B_OK;
}
static bool
OffsetFrameOne(const char* DEBUG_ONLY(name), uint32, off_t, void* castToRect,
void* castToParams)
{
ASSERT(strcmp(name, kAttrWindowFrame) == 0);
StaggerOneParams* params = (StaggerOneParams*)castToParams;
if (!params->rectFromParent)
return false;
if (!castToRect)
return false;
((BRect*)castToRect)->OffsetBy(kWindowStaggerBy, kWindowStaggerBy);
return true;
}
static void
AddMimeTypeString(BStringList& list, Model* model)
{
if (model == NULL)
return;
const char* modelMimeType = model->MimeType();
if (modelMimeType == NULL || *modelMimeType == '\0')
return;
BString type = BString(modelMimeType);
if (list.HasString(type, true))
return;
list.Add(type);
}
DraggableContainerIcon::DraggableContainerIcon()
:
BView("DraggableContainerIcon", B_WILL_DRAW),
fDragButton(0),
fDragStarted(false)
{
}
void
DraggableContainerIcon::MouseDown(BPoint where)
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
ThrowOnAssert(window != NULL);
if (window->IsTrash() || window->IsPrintersDir())
return;
uint32 buttons;
window->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
if (IconCache::sIconCache->IconHitTest(where, window->TargetModel(),
kNormalIcon, B_MINI_ICON)) {
fDragButton = buttons
& (B_PRIMARY_MOUSE_BUTTON | B_SECONDARY_MOUSE_BUTTON);
fDragStarted = false;
fClickPoint = where;
} else
fDragButton = 0;
if (!fDragButton)
Window()->Activate(true);
}
void
DraggableContainerIcon::MouseUp(BPoint)
{
if (!fDragStarted)
Window()->Activate(true);
fDragButton = 0;
fDragStarted = false;
}
void
DraggableContainerIcon::MouseMoved(BPoint where, uint32, const BMessage*)
{
if (fDragButton == 0 || fDragStarted
|| (abs((int32)(where.x - fClickPoint.x)) <= kDragSlop
&& abs((int32)(where.y - fClickPoint.y)) <= kDragSlop))
return;
BContainerWindow* window = static_cast<BContainerWindow*>(Window());
Model* model = window->TargetModel();
BFont font;
GetFont(&font);
font_height fontHeight;
font.GetHeight(&fontHeight);
float height = ceilf(fontHeight.ascent + fontHeight.descent
+ fontHeight.leading + 2 + Bounds().Height() + 8);
BRect rect(0, 0, std::max(Bounds().Width(),
font.StringWidth(model->Name()) + 4), height);
BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true);
dragBitmap->Lock();
BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
dragBitmap->AddChild(view);
view->SetOrigin(0, 0);
BRect clipRect(view->Bounds());
BRegion newClip;
newClip.Set(clipRect);
view->ConstrainClippingRegion(&newClip);
view->SetHighColor(0, 0, 0, 0);
view->FillRect(view->Bounds());
view->SetDrawingMode(B_OP_ALPHA);
rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
textColor.alpha = 128;
view->SetHighColor(textColor);
view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
float hIconOffset = (rect.Width() - Bounds().Width()) / 2;
IconCache::sIconCache->Draw(model, view, BPoint(hIconOffset, 0),
kNormalIcon, B_MINI_ICON, true);
BString nameString = model->Name();
if (view->StringWidth(model->Name()) > rect.Width())
view->TruncateString(&nameString, B_TRUNCATE_END, rect.Width() - 5);
float leftText = (view->StringWidth(nameString.String())
- Bounds().Width()) / 2;
view->MovePenTo(BPoint(hIconOffset - leftText + 2, Bounds().Height()
+ (fontHeight.ascent + 2)));
view->DrawString(nameString.String());
view->Sync();
dragBitmap->Unlock();
BMessage message(B_SIMPLE_DATA);
message.AddRef("refs", model->EntryRef());
message.AddPoint("click_pt", fClickPoint);
BPoint tmpLoc;
uint32 button;
GetMouse(&tmpLoc, &button);
if (button)
message.AddInt32("buttons", (int32)button);
if ((button & B_PRIMARY_MOUSE_BUTTON) != 0) {
message.AddInt32("be:actions", (modifiers() & B_OPTION_KEY) != 0
? B_COPY_TARGET : B_MOVE_TARGET);
}
fDragStarted = true;
fDragButton = 0;
DragMessage(&message, dragBitmap, B_OP_ALPHA,
BPoint(fClickPoint.x + hIconOffset, fClickPoint.y), this);
}
void
DraggableContainerIcon::Draw(BRect updateRect)
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
ThrowOnAssert(window != NULL);
BRect rect(Bounds());
rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
be_control_look->DrawBorder(this, rect, updateRect, base, B_PLAIN_BORDER,
0, BControlLook::B_BOTTOM_BORDER);
be_control_look->DrawMenuBarBackground(this, rect, updateRect, base, 0,
BControlLook::B_ALL_BORDERS & ~BControlLook::B_LEFT_BORDER);
SetDrawingMode(B_OP_ALPHA);
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
float iconOffsetX = (Bounds().Width() - B_MINI_ICON) / 2;
float iconOffsetY = (Bounds().Height() - B_MINI_ICON) / 2;
IconCache::sIconCache->Draw(window->TargetModel(), this,
BPoint(iconOffsetX, iconOffsetY), kNormalIcon, B_MINI_ICON, true);
}
BContainerWindow::BContainerWindow(LockingList<BWindow>* list,
uint32 containerWindowFlags, window_look look, window_feel feel,
uint32 flags, uint32 workspace, bool useLayouts, bool isDeskWindow)
:
BWindow(InitialWindowRect(feel), "TrackerWindow", look, feel, flags,
workspace),
fUseLayouts(useLayouts),
fMenuContainer(NULL),
fPoseContainer(NULL),
fBorderedView(NULL),
fVScrollBarContainer(NULL),
fCountContainer(NULL),
fFileContextMenu(NULL),
fWindowContextMenu(NULL),
fDropContextMenu(NULL),
fVolumeContextMenu(NULL),
fTrashContextMenu(NULL),
fDragContextMenu(NULL),
fMoveToItem(NULL),
fCopyToItem(NULL),
fCreateLinkItem(NULL),
fOpenWithItem(NULL),
fNavigationItem(NULL),
fMenuBar(NULL),
fDraggableIcon(NULL),
fNavigator(NULL),
fPoseView(NULL),
fWindowList(list),
fAttrMenu(NULL),
fWindowMenu(NULL),
fFileMenu(NULL),
fArrangeByMenu(NULL),
fSelectionWindow(NULL),
fTaskLoop(NULL),
fIsTrash(false),
fInTrash(false),
fIsPrinters(false),
fIsDesktop(isDeskWindow),
fContainerWindowFlags(containerWindowFlags),
fBackgroundImage(NULL),
fSavedZoomRect(0, 0, -1, -1),
fContextMenu(NULL),
fDragMessage(NULL),
fCachedTypesList(NULL),
fStateNeedsSaving(false),
fSaveStateIsEnabled(true),
fIsWatchingPath(false)
{
InitIconPreloader();
if (list != NULL) {
ASSERT(list->IsLocked());
list->AddItem(this);
}
if (useLayouts) {
SetFlags(Flags() | B_AUTO_UPDATE_SIZE_LIMITS);
fRootLayout = new BGroupLayout(B_VERTICAL, 0);
fRootLayout->SetInsets(0);
SetLayout(fRootLayout);
fRootLayout->Owner()->AdoptSystemColors();
if (!fIsDesktop) {
fMenuContainer = new BGroupView(B_HORIZONTAL, 0);
fRootLayout->AddView(fMenuContainer);
fPoseContainer = new BGridView(0.0, 0.0);
fRootLayout->AddView(fPoseContainer);
fBorderedView = new BorderedView;
fPoseContainer->GridLayout()->AddView(fBorderedView, 0, 1);
fCountContainer = new BGroupView(B_HORIZONTAL, 0);
fPoseContainer->GridLayout()->AddView(fCountContainer, 0, 2);
}
}
AddCommonFilter(new BMessageFilter(B_MOUSE_DOWN, ActivateWindowFilter));
Run();
TTracker* tracker = dynamic_cast<TTracker*>(be_app);
if (tracker != NULL && tracker->Lock()) {
tracker->StartWatching(this, kWindowsShowFullPathChanged);
tracker->StartWatching(this, kSingleWindowBrowseChanged);
tracker->StartWatching(this, kShowNavigatorChanged);
tracker->StartWatching(this, kDontMoveFilesToTrashChanged);
tracker->Unlock();
}
AddShortcut('Z', B_COMMAND_KEY, new BMessage(B_UNDO), this);
AddShortcut('Z', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO), this);
}
BContainerWindow::~BContainerWindow()
{
ASSERT(IsLocked());
TTracker* tracker = dynamic_cast<TTracker*>(be_app);
if (tracker != NULL && tracker->Lock()) {
tracker->StopWatching(this, kWindowsShowFullPathChanged);
tracker->StopWatching(this, kSingleWindowBrowseChanged);
tracker->StopWatching(this, kShowNavigatorChanged);
tracker->StopWatching(this, kDontMoveFilesToTrashChanged);
tracker->Unlock();
}
delete fTaskLoop;
delete fBackgroundImage;
delete fDragMessage;
delete fCachedTypesList;
if (fSelectionWindow != NULL && fSelectionWindow->Lock())
fSelectionWindow->Quit();
}
BRect
BContainerWindow::InitialWindowRect(window_feel feel)
{
if (feel != kDesktopWindowFeel)
return sNewWindRect;
BRect result = sNewWindRect;
result.OffsetTo(0, 0);
return result;
}
void
BContainerWindow::Minimize(bool minimize)
{
if (minimize && (modifiers() & B_OPTION_KEY) != 0)
do_minimize_team(BRect(0, 0, 0, 0), be_app->Team(), true);
else
_inherited::Minimize(minimize);
}
bool
BContainerWindow::QuitRequested()
{
if (CurrentMessage() != NULL
&& ((CurrentMessage()->FindInt32("modifiers") & B_CONTROL_KEY)) != 0) {
be_app->PostMessage(kCloseAllWindows);
}
Hide();
return true;
}
void
BContainerWindow::Quit()
{
if (fNavigationItem) {
BMenu* menu = fNavigationItem->Menu();
if (menu != NULL)
menu->RemoveItem(fNavigationItem);
delete fNavigationItem;
fNavigationItem = NULL;
}
if (fOpenWithItem != NULL && fOpenWithItem->Menu() == NULL) {
delete fOpenWithItem;
fOpenWithItem = NULL;
}
if (fMoveToItem != NULL && fMoveToItem->Menu() == NULL) {
delete fMoveToItem;
fMoveToItem = NULL;
}
if (fCopyToItem != NULL && fCopyToItem->Menu() == NULL) {
delete fCopyToItem;
fCopyToItem = NULL;
}
if (fCreateLinkItem != NULL && fCreateLinkItem->Menu() == NULL) {
delete fCreateLinkItem;
fCreateLinkItem = NULL;
}
if (fAttrMenu != NULL && fAttrMenu->Supermenu() == NULL) {
delete fAttrMenu;
fAttrMenu = NULL;
}
delete fFileContextMenu;
fFileContextMenu = NULL;
delete fWindowContextMenu;
fWindowContextMenu = NULL;
delete fDropContextMenu;
fDropContextMenu = NULL;
delete fVolumeContextMenu;
fVolumeContextMenu = NULL;
delete fDragContextMenu;
fDragContextMenu = NULL;
int32 windowCount = 0;
if (fWindowList != NULL) {
AutoLock<LockingList<BWindow> > lock(fWindowList);
if (lock.IsLocked()) {
fWindowList->RemoveItem(this, false);
windowCount = fWindowList->CountItems();
}
}
if (StateNeedsSaving())
SaveState();
if (fWindowList != NULL && windowCount == 0)
be_app->PostMessage(B_QUIT_REQUESTED);
_inherited::Quit();
}
BPoseView*
BContainerWindow::NewPoseView(Model* model, uint32 viewMode)
{
return new BPoseView(model, viewMode);
}
void
BContainerWindow::UpdateIfTrash(Model* model)
{
BEntry entry(model->EntryRef());
if (entry.InitCheck() == B_OK) {
fIsTrash = model->IsTrash();
fInTrash = FSInTrashDir(model->EntryRef());
fIsPrinters = FSIsPrintersDir(&entry);
}
}
void
BContainerWindow::CreatePoseView(Model* model)
{
UpdateIfTrash(model);
fPoseView = NewPoseView(model, kListMode);
fBorderedView->GroupLayout()->AddView(fPoseView);
fBorderedView->GroupLayout()->SetInsets(1, 0, 1, 1);
fBorderedView->EnableBorderHighlight(false);
TrackerSettings settings;
if (settings.SingleWindowBrowse() && model->IsDirectory()
&& !fPoseView->IsFilePanel()) {
fNavigator = new BNavigator(model);
fPoseContainer->GridLayout()->AddView(fNavigator, 0, 0, 2);
if (!settings.ShowNavigator())
fNavigator->Hide();
}
SetPathWatchingEnabled(settings.ShowNavigator()
|| settings.ShowFullPathInTitleBar());
}
void
BContainerWindow::AddContextMenus()
{
fFileContextMenu = new BPopUpMenu("FileContext", false, false);
fFileContextMenu->SetFont(be_plain_font);
AddFileContextMenus(fFileContextMenu);
fVolumeContextMenu = new BPopUpMenu("VolumeContext", false, false);
fVolumeContextMenu->SetFont(be_plain_font);
AddVolumeContextMenus(fVolumeContextMenu);
fWindowContextMenu = new BPopUpMenu("WindowContext", false, false);
fWindowContextMenu->SetFont(be_plain_font);
AddWindowContextMenus(fWindowContextMenu);
fDropContextMenu = new BPopUpMenu("DropContext", false, false);
fDropContextMenu->SetFont(be_plain_font);
AddDropContextMenus(fDropContextMenu);
fDragContextMenu = new BSlowContextMenu("DragContext");
fTrashContextMenu = new BPopUpMenu("TrashContext", false, false);
fTrashContextMenu->SetFont(be_plain_font);
AddTrashContextMenus(fTrashContextMenu);
}
void
BContainerWindow::RepopulateMenus()
{
if (fMoveToItem && fMoveToItem->Menu())
fMoveToItem->Menu()->RemoveItem(fMoveToItem);
if (fCopyToItem && fCopyToItem->Menu())
fCopyToItem->Menu()->RemoveItem(fCopyToItem);
if (fCreateLinkItem && fCreateLinkItem->Menu())
fCreateLinkItem->Menu()->RemoveItem(fCreateLinkItem);
if (fOpenWithItem && fOpenWithItem->Menu()) {
fOpenWithItem->Menu()->RemoveItem(fOpenWithItem);
delete fOpenWithItem;
fOpenWithItem = NULL;
}
if (fNavigationItem) {
BMenu* menu = fNavigationItem->Menu();
if (menu) {
menu->RemoveItem(fNavigationItem);
BMenuItem* item = menu->RemoveItem((int32)0);
ASSERT(item != fNavigationItem);
delete item;
}
}
delete fFileContextMenu;
fFileContextMenu = new BPopUpMenu("FileContext", false, false);
fFileContextMenu->SetFont(be_plain_font);
AddFileContextMenus(fFileContextMenu);
delete fWindowContextMenu;
fWindowContextMenu = new BPopUpMenu("WindowContext", false, false);
fWindowContextMenu->SetFont(be_plain_font);
AddWindowContextMenus(fWindowContextMenu);
if (fMenuBar != NULL) {
fMenuBar->RemoveItem(fFileMenu);
delete fFileMenu;
fFileMenu = new BMenu(B_TRANSLATE("File"));
AddFileMenu(fFileMenu);
fMenuBar->AddItem(fFileMenu);
fMenuBar->RemoveItem(fWindowMenu);
delete fWindowMenu;
fWindowMenu = new BMenu(B_TRANSLATE("Window"));
fMenuBar->AddItem(fWindowMenu);
AddWindowMenu(fWindowMenu);
fMenuBar->RemoveItem(fAttrMenu);
delete fAttrMenu;
fAttrMenu = new BMenu(B_TRANSLATE("Attributes"));
NewAttributeMenu(fAttrMenu);
if (PoseView()->ViewMode() == kListMode)
ShowAttributeMenu();
PopulateArrangeByMenu(fArrangeByMenu);
int32 selectCount = PoseView()->SelectionList()->CountItems();
SetupOpenWithMenu(fFileMenu);
SetupMoveCopyMenus(selectCount ? PoseView()->SelectionList()
->FirstItem()->TargetModel()->EntryRef() : NULL,
fFileMenu);
}
}
void
BContainerWindow::Init(const BMessage* message)
{
BEntry entry;
ASSERT(fPoseView != NULL);
if (fPoseView == NULL)
return;
if (NeedsDefaultStateSetup())
SetUpDefaultState();
if (ShouldAddScrollBars())
fPoseView->AddScrollBars();
fMoveToItem = new BMenuItem(new BNavMenu(B_TRANSLATE("Move to"),
kMoveSelectionTo, this));
fCopyToItem = new BMenuItem(new BNavMenu(B_TRANSLATE("Copy to"),
kCopySelectionTo, this));
fCreateLinkItem = new BMenuItem(new BNavMenu(B_TRANSLATE("Create link"),
kCreateLink, this), new BMessage(kCreateLink));
TrackerSettings settings;
if (ShouldAddMenus()) {
fMenuBar = new BMenuBar("MenuBar");
fMenuContainer->GroupLayout()->AddView(fMenuBar);
AddMenus();
if (!TargetModel()->IsRoot() && !IsTrash())
_AddFolderIcon();
} else {
AddShortcuts();
}
AddContextMenus();
AddShortcut('T', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(kDelete),
PoseView());
AddShortcut('K', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(kCleanupAll),
PoseView());
AddShortcut('Q', B_COMMAND_KEY | B_OPTION_KEY | B_SHIFT_KEY
| B_CONTROL_KEY, new BMessage(kQuitTracker));
AddShortcut(B_DOWN_ARROW, B_COMMAND_KEY, new BMessage(kOpenSelection),
PoseView());
SetSingleWindowBrowseShortcuts(settings.SingleWindowBrowse());
#if DEBUG
AddShortcut('D', B_COMMAND_KEY | B_CONTROL_KEY, new BMessage('dbug'),
PoseView());
AddShortcut('C', B_COMMAND_KEY | B_CONTROL_KEY, new BMessage('dpcc'),
PoseView());
AddShortcut('F', B_COMMAND_KEY | B_CONTROL_KEY, new BMessage('dpfl'),
PoseView());
AddShortcut('F', B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY,
new BMessage('dpfL'), PoseView());
#endif
BKeymap keymap;
keymap.SetToCurrent();
BObjectList<const char> unmodified(3, true);
if (keymap.GetModifiedCharacters("+", B_SHIFT_KEY, 0, &unmodified)
== B_OK) {
int32 count = unmodified.CountItems();
for (int32 i = 0; i < count; i++) {
uint32 key = BUnicodeChar::FromUTF8(unmodified.ItemAt(i));
if (!HasShortcut(key, 0)) {
BMessage* increaseSize = new BMessage(kIconMode);
increaseSize->AddInt32("scale", 1);
AddShortcut(key, B_COMMAND_KEY, increaseSize, PoseView());
}
}
}
unmodified.MakeEmpty();
if (message != NULL)
RestoreState(*message);
else
RestoreState();
if (ShouldAddMenus() && PoseView()->ViewMode() == kListMode) {
ShowAttributeMenu();
}
MarkAttributeMenu(fAttrMenu);
CheckScreenIntersect();
if (fBackgroundImage != NULL && !fIsDesktop
&& PoseView()->ViewMode() != kListMode) {
fBackgroundImage->Show(PoseView(), current_workspace());
}
Show();
SetFlags(Flags() & ~B_NO_WORKSPACE_ACTIVATION);
}
void
BContainerWindow::InitLayout()
{
fBorderedView->GroupLayout()->AddView(0, fPoseView->TitleView());
BLayoutItem* item = fCountContainer->GroupLayout()->AddView(
fPoseView->CountView());
item->SetExplicitMinSize(BSize(kCountViewWidth, B_H_SCROLL_BAR_HEIGHT));
item->SetExplicitMaxSize(BSize(kCountViewWidth, B_SIZE_UNSET));
fMenuContainer->GroupLayout()->SetInsets(0, 0, -1, 0);
fPoseContainer->GridLayout()->SetInsets(-1, 0, -1, -1);
fCountContainer->GroupLayout()->SetInsets(0, -1, 0, 0);
if (fPoseView->VScrollBar() != NULL) {
fVScrollBarContainer = new BGroupView(B_VERTICAL, 0);
fVScrollBarContainer->GroupLayout()->AddView(fPoseView->VScrollBar());
fVScrollBarContainer->GroupLayout()->SetInsets(-1, -1, 0, 0);
fPoseContainer->GridLayout()->AddView(fVScrollBarContainer, 1, 1);
}
if (fPoseView->HScrollBar() != NULL) {
BGroupView* hScrollBarContainer = new BGroupView(B_VERTICAL, 0);
hScrollBarContainer->GroupLayout()->AddView(fPoseView->HScrollBar());
hScrollBarContainer->GroupLayout()->SetInsets(0, -1, 0, -1);
fCountContainer->GroupLayout()->AddView(hScrollBarContainer);
}
}
void
BContainerWindow::RestoreState()
{
UpdateTitle();
WindowStateNodeOpener opener(this, false);
RestoreWindowState(opener.StreamNode());
fPoseView->Init(opener.StreamNode());
RestoreStateCommon();
}
void
BContainerWindow::RestoreState(const BMessage &message)
{
UpdateTitle();
RestoreWindowState(message);
fPoseView->Init(message);
RestoreStateCommon();
}
void
BContainerWindow::RestoreStateCommon()
{
if (!fIsDesktop && fUseLayouts)
InitLayout();
if (BootedInSafeMode())
return;
WindowStateNodeOpener opener(this, false);
if (!TargetModel()->IsRoot() && opener.Node() != NULL) {
fBackgroundImage = BackgroundImage::GetBackgroundImage(
opener.Node(), fIsDesktop);
}
BNode defaultingNode;
if (fBackgroundImage == NULL && !fIsDesktop
&& DefaultStateSourceNode(kDefaultFolderTemplate, &defaultingNode)) {
fBackgroundImage = BackgroundImage::GetBackgroundImage(&defaultingNode,
fIsDesktop);
}
}
void
BContainerWindow::UpdateTitle()
{
if (TrackerSettings().ShowFullPathInTitleBar()) {
BPath path;
TargetModel()->GetPath(&path);
SetTitle(path.Path());
} else {
SetTitle(TargetModel()->Name());
}
if (Navigator() != NULL) {
Navigator()->UpdateLocation(PoseView()->TargetModel(),
kActionUpdatePath);
}
}
void
BContainerWindow::UpdateBackgroundImage()
{
if (BootedInSafeMode())
return;
WindowStateNodeOpener opener(this, false);
if (!TargetModel()->IsRoot() && opener.Node() != NULL) {
fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
opener.Node(), fIsDesktop, PoseView());
}
BNode defaultingNode;
if (!fBackgroundImage && !fIsDesktop
&& DefaultStateSourceNode(kDefaultFolderTemplate, &defaultingNode)) {
fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage,
&defaultingNode, fIsDesktop, PoseView());
}
}
void
BContainerWindow::FrameResized(float, float)
{
if (PoseView() != NULL && !fIsDesktop) {
BRect extent = PoseView()->Extent();
float offsetX = extent.left - PoseView()->Bounds().left;
float offsetY = extent.top - PoseView()->Bounds().top;
BPoint scroll(B_ORIGIN);
if (offsetX < 0 && PoseView()->Bounds().right > extent.right
&& Bounds().Width() > fPreviousBounds.Width()) {
scroll.x = std::max(fPreviousBounds.Width() - Bounds().Width(),
offsetX);
}
if (offsetY < 0 && PoseView()->Bounds().bottom > extent.bottom
&& Bounds().Height() > fPreviousBounds.Height()) {
scroll.y = std::max(fPreviousBounds.Height() - Bounds().Height(),
offsetY);
}
if (scroll != B_ORIGIN)
PoseView()->ScrollBy(scroll.x, scroll.y);
PoseView()->UpdateScrollRange();
PoseView()->ResetPosePlacementHint();
}
fPreviousBounds = Bounds();
fStateNeedsSaving = true;
}
void
BContainerWindow::FrameMoved(BPoint)
{
fStateNeedsSaving = true;
}
void
BContainerWindow::WorkspacesChanged(uint32, uint32)
{
fStateNeedsSaving = true;
}
void
BContainerWindow::ViewModeChanged(uint32 oldMode, uint32 newMode)
{
if (fBackgroundImage == NULL)
return;
if (newMode == kListMode)
fBackgroundImage->Remove();
else if (oldMode == kListMode)
fBackgroundImage->Show(PoseView(), current_workspace());
}
void
BContainerWindow::CheckScreenIntersect()
{
BScreen screen(this);
BRect screenFrame(screen.Frame());
BRect frame(Frame());
if (sNewWindRect.bottom > screenFrame.bottom)
sNewWindRect.OffsetTo(85, 50);
if (sNewWindRect.right > screenFrame.right)
sNewWindRect.OffsetTo(85, 50);
if (!frame.Intersects(screenFrame))
MoveTo(sNewWindRect.LeftTop());
}
void
BContainerWindow::SaveState(bool hide)
{
if (SaveStateIsEnabled()) {
WindowStateNodeOpener opener(this, true);
if (opener.StreamNode() != NULL)
SaveWindowState(opener.StreamNode());
if (hide)
Hide();
if (opener.StreamNode())
fPoseView->SaveState(opener.StreamNode());
fStateNeedsSaving = false;
}
}
void
BContainerWindow::SaveState(BMessage& message) const
{
if (SaveStateIsEnabled()) {
SaveWindowState(message);
fPoseView->SaveState(message);
}
}
bool
BContainerWindow::StateNeedsSaving() const
{
return fPoseView != NULL && (fStateNeedsSaving || fPoseView->StateNeedsSaving());
}
status_t
BContainerWindow::GetLayoutState(BNode* node, BMessage* message)
{
if (node == NULL || message == NULL)
return B_BAD_VALUE;
status_t result = node->InitCheck();
if (result != B_OK)
return result;
node->RewindAttrs();
char attrName[256];
while (node->GetNextAttrName(attrName) == B_OK) {
attr_info info;
if (node->GetAttrInfo(attrName, &info) != B_OK)
continue;
if (strcmp(attrName, kAttrWindowFrame) != 0
&& strcmp(attrName, kAttrColumns) != 0
&& strcmp(attrName, kAttrViewState) != 0
&& strcmp(attrName, kAttrColumnsForeign) != 0
&& strcmp(attrName, kAttrViewStateForeign) != 0) {
continue;
}
char* buffer = new char[info.size];
if (node->ReadAttr(attrName, info.type, 0, buffer,
(size_t)info.size) == info.size) {
message->AddData(attrName, info.type, buffer, (ssize_t)info.size);
}
delete[] buffer;
}
return B_OK;
}
status_t
BContainerWindow::SetLayoutState(BNode* node, const BMessage* message)
{
status_t result = node->InitCheck();
if (result != B_OK)
return result;
for (int32 globalIndex = 0; ;) {
#if B_BEOS_VERSION_DANO
const char* name;
#else
char* name;
#endif
type_code type;
int32 count;
status_t result = message->GetInfo(B_ANY_TYPE, globalIndex, &name,
&type, &count);
if (result != B_OK)
break;
for (int32 index = 0; index < count; index++) {
const void* buffer;
ssize_t size;
result = message->FindData(name, type, index, &buffer, &size);
if (result != B_OK) {
PRINT(("error reading %s \n", name));
return result;
}
if (node->WriteAttr(name, type, 0, buffer,
(size_t)size) != size) {
PRINT(("error writing %s \n", name));
return result;
}
globalIndex++;
}
}
return B_OK;
}
bool
BContainerWindow::ShouldAddMenus() const
{
return true;
}
bool
BContainerWindow::ShouldAddScrollBars() const
{
return true;
}
Model*
BContainerWindow::TargetModel() const
{
return fPoseView->TargetModel();
}
void
BContainerWindow::SelectionChanged()
{
}
void
BContainerWindow::Zoom(BPoint, float, float)
{
BRect oldZoomRect(fSavedZoomRect);
fSavedZoomRect = Frame();
ResizeToFit();
if (fSavedZoomRect == Frame() && oldZoomRect.IsValid())
ResizeTo(oldZoomRect.Width(), oldZoomRect.Height());
}
void
BContainerWindow::ResizeToFit()
{
BScreen screen(this);
BRect screenFrame(screen.Frame());
screenFrame.InsetBy(5, 5);
BMessage decoratorSettings;
GetDecoratorSettings(&decoratorSettings);
float tabHeight = 15;
BRect tabRect;
if (decoratorSettings.FindRect("tab frame", &tabRect) == B_OK)
tabHeight = tabRect.Height();
screenFrame.top += tabHeight;
BRect frame(Frame());
float widthDiff = frame.Width() - PoseView()->Frame().Width();
float heightDiff = frame.Height() - PoseView()->Frame().Height();
BPoint leftTop(frame.LeftTop());
leftTop.ConstrainTo(screenFrame);
frame.OffsetTo(leftTop);
BRect extent(PoseView()->Extent());
frame.right = frame.left + extent.Width() + widthDiff;
frame.bottom = frame.top + extent.Height() + heightDiff;
frame = frame & screenFrame;
ResizeTo(frame.Width(), frame.Height());
MoveTo(frame.LeftTop());
PoseView()->DisableScrollBars();
PoseView()->ScrollBy(
extent.left - PoseView()->Bounds().left,
extent.top - PoseView()->Bounds().top);
PoseView()->UpdateScrollRange();
PoseView()->EnableScrollBars();
}
void
BContainerWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_CUT:
case B_COPY:
case B_PASTE:
case kCutMoreSelectionToClipboard:
case kCopyMoreSelectionToClipboard:
case kPasteLinksFromClipboard:
{
BView* view = CurrentFocus();
if (dynamic_cast<BTextView*>(view) == NULL) {
if (fPoseView != NULL)
fPoseView->MessageReceived(message);
} else {
if (message->what == B_CUT || message->what == B_COPY
|| message->what == B_PASTE) {
view->MessageReceived(message);
}
}
break;
}
case B_UNDO: {
BView* view = CurrentFocus();
if (dynamic_cast<BTextView*>(view) == NULL) {
FSUndo();
} else {
view->MessageReceived(message);
}
break;
}
case B_REDO: {
BView* view = CurrentFocus();
if (dynamic_cast<BTextView*>(view) == NULL) {
FSRedo();
} else {
view->MessageReceived(message);
}
break;
}
case kNewFolder:
PostMessage(message, PoseView());
break;
case kRestoreState:
if (message->HasMessage("state")) {
BMessage state;
message->FindMessage("state", &state);
Init(&state);
} else
Init();
break;
case kResizeToFit:
ResizeToFit();
break;
case kLoadAddOn:
LoadAddOn(message);
break;
case kCopySelectionTo:
{
entry_ref ref;
if (message->FindRef("refs", &ref) != B_OK)
break;
BRoster().AddToRecentFolders(&ref);
Model model(&ref);
if (model.InitCheck() != B_OK)
break;
if (*model.NodeRef() == *TargetModel()->NodeRef())
PoseView()->DuplicateSelection();
else
PoseView()->MoveSelectionInto(&model, this, true);
break;
}
case kMoveSelectionTo:
{
entry_ref ref;
if (message->FindRef("refs", &ref) != B_OK)
break;
BRoster().AddToRecentFolders(&ref);
Model model(&ref);
if (model.InitCheck() != B_OK)
break;
PoseView()->MoveSelectionInto(&model, this, false, true);
break;
}
case kCreateLink:
case kCreateRelativeLink:
{
entry_ref ref;
if (message->FindRef("refs", &ref) == B_OK) {
BRoster().AddToRecentFolders(&ref);
Model model(&ref);
if (model.InitCheck() != B_OK)
break;
PoseView()->MoveSelectionInto(&model, this, false, false,
message->what == kCreateLink,
message->what == kCreateRelativeLink);
} else if (!TargetModel()->IsQuery()
&& !TargetModel()->IsVirtualDirectory()) {
PoseView()->MoveSelectionInto(TargetModel(), this, false, false,
message->what == kCreateLink,
message->what == kCreateRelativeLink);
}
break;
}
case kShowSelectionWindow:
ShowSelectionWindow();
break;
case kSelectMatchingEntries:
PoseView()->SelectMatchingEntries(message);
break;
case kFindButton:
(new FindWindow())->Show();
break;
case kQuitTracker:
be_app->PostMessage(B_QUIT_REQUESTED);
break;
case kRestoreBackgroundImage:
UpdateBackgroundImage();
break;
case kSwitchDirectory:
{
entry_ref ref;
if (message->FindRef("refs", &ref) == B_OK) {
BEntry entry;
if (entry.SetTo(&ref) == B_OK) {
if (StateNeedsSaving())
SaveState(false);
bool wasInTrash = IsTrash() || InTrash();
bool isRoot = PoseView()->TargetModel()->IsRoot();
WindowStateNodeOpener opener(this, false);
opener.SetTo(&entry, false);
PoseView()->SwitchDir(&ref, opener.StreamNode());
fIsTrash = FSIsTrashDir(&entry);
fInTrash = FSInTrashDir(&ref);
if (wasInTrash ^ (IsTrash() || InTrash())
|| isRoot != PoseView()->TargetModel()->IsRoot())
RepopulateMenus();
if (Navigator() != NULL) {
int32 action = kActionSet;
if (message->FindInt32("action", &action) != B_OK) {
action = kActionSet;
}
Navigator()->UpdateLocation(PoseView()->TargetModel(),
action);
}
TrackerSettings settings;
if (settings.ShowNavigator()
|| settings.ShowFullPathInTitleBar()) {
SetPathWatchingEnabled(true);
}
SetSingleWindowBrowseShortcuts(
settings.SingleWindowBrowse());
if (fMenuBar != NULL) {
if (!TargetModel()->IsRoot() && !IsTrash()) {
if (fDraggableIcon != NULL) {
IconCache::sIconCache->IconChanged(
TargetModel());
fDraggableIcon->Invalidate();
} else
_AddFolderIcon();
} else if (fDraggableIcon != NULL)
fDraggableIcon->RemoveSelf();
}
UpdateTitle();
}
}
break;
}
case B_REFS_RECEIVED:
if (Dragging()) {
entry_ref ref;
if (message->FindRef("refs", &ref) == B_OK) {
fWaitingForRefs = false;
BEntry entry(&ref, true);
if (!FSIsPrintersDir(&entry)) {
if (entry.InitCheck() == B_OK
&& entry.IsDirectory()) {
Model targetModel(&entry, true, false);
BPoint dropPoint;
uint32 buttons;
PoseView()->GetMouse(&dropPoint, &buttons, true);
PoseView()->HandleDropCommon(fDragMessage,
&targetModel, NULL, PoseView(), dropPoint);
}
}
}
DragStop();
}
break;
case B_TRACKER_ADDON_MESSAGE:
{
_PassMessageToAddOn(message);
break;
}
case B_OBSERVER_NOTICE_CHANGE:
{
int32 observerWhat;
if (message->FindInt32("be:observe_change_what", &observerWhat)
== B_OK) {
TrackerSettings settings;
switch (observerWhat) {
case kWindowsShowFullPathChanged:
UpdateTitle();
if (!IsPathWatchingEnabled()
&& settings.ShowFullPathInTitleBar()) {
SetPathWatchingEnabled(true);
}
if (IsPathWatchingEnabled()
&& !(settings.ShowNavigator()
|| settings.ShowFullPathInTitleBar())) {
SetPathWatchingEnabled(false);
}
break;
case kSingleWindowBrowseChanged:
if (settings.SingleWindowBrowse()
&& !Navigator()
&& TargetModel()->IsDirectory()
&& !PoseView()->IsFilePanel()
&& !PoseView()->IsDesktopWindow()) {
fNavigator = new BNavigator(TargetModel());
fPoseContainer->GridLayout()->AddView(fNavigator,
0, 0, 2);
fNavigator->Hide();
SetPathWatchingEnabled(settings.ShowNavigator()
|| settings.ShowFullPathInTitleBar());
}
if (!settings.SingleWindowBrowse()
&& !fIsDesktop && TargetModel()->IsDesktop()) {
this->Quit();
}
SetSingleWindowBrowseShortcuts(
settings.SingleWindowBrowse());
break;
case kShowNavigatorChanged:
ShowNavigator(settings.ShowNavigator());
if (!IsPathWatchingEnabled()
&& settings.ShowNavigator()) {
SetPathWatchingEnabled(true);
}
if (IsPathWatchingEnabled()
&& !(settings.ShowNavigator()
|| settings.ShowFullPathInTitleBar())) {
SetPathWatchingEnabled(false);
}
SetSingleWindowBrowseShortcuts(
settings.SingleWindowBrowse());
break;
case kDontMoveFilesToTrashChanged:
{
bool dontMoveToTrash
= settings.DontMoveFilesToTrash();
BMenuItem* item
= fFileContextMenu->FindItem(kMoveToTrash);
if (item != NULL) {
item->SetLabel(dontMoveToTrash
? B_TRANSLATE("Delete")
: B_TRANSLATE("Move to Trash"));
}
if (fMenuBar && fFileMenu) {
item = fFileMenu->FindItem(kMoveToTrash);
if (item != NULL) {
item->SetLabel(dontMoveToTrash
? B_TRANSLATE("Delete")
: B_TRANSLATE("Move to Trash"));
}
}
UpdateIfNeeded();
break;
}
default:
_inherited::MessageReceived(message);
break;
}
}
break;
}
case B_NODE_MONITOR:
UpdateTitle();
break;
default:
_inherited::MessageReceived(message);
break;
}
}
void
BContainerWindow::SetCutItem(BMenu* menu)
{
BMenuItem* item;
if ((item = menu->FindItem(B_CUT)) == NULL
&& (item = menu->FindItem(kCutMoreSelectionToClipboard)) == NULL)
return;
item->SetEnabled(PoseView()->SelectionList()->CountItems() > 0
|| PoseView() != CurrentFocus());
if (modifiers() & B_SHIFT_KEY) {
item->SetLabel(B_TRANSLATE("Cut more"));
item->SetShortcut('X', B_COMMAND_KEY | B_SHIFT_KEY);
item->SetMessage(new BMessage(kCutMoreSelectionToClipboard));
} else {
item->SetLabel(B_TRANSLATE("Cut"));
item->SetShortcut('X', B_COMMAND_KEY);
item->SetMessage(new BMessage(B_CUT));
}
}
void
BContainerWindow::SetCopyItem(BMenu* menu)
{
BMenuItem* item;
if ((item = menu->FindItem(B_COPY)) == NULL
&& (item = menu->FindItem(kCopyMoreSelectionToClipboard)) == NULL) {
return;
}
item->SetEnabled(PoseView()->SelectionList()->CountItems() > 0
|| PoseView() != CurrentFocus());
if (modifiers() & B_SHIFT_KEY) {
item->SetLabel(B_TRANSLATE("Copy more"));
item->SetShortcut('C', B_COMMAND_KEY | B_SHIFT_KEY);
item->SetMessage(new BMessage(kCopyMoreSelectionToClipboard));
} else {
item->SetLabel(B_TRANSLATE("Copy"));
item->SetShortcut('C', B_COMMAND_KEY);
item->SetMessage(new BMessage(B_COPY));
}
}
void
BContainerWindow::SetPasteItem(BMenu* menu)
{
BMenuItem* item;
if ((item = menu->FindItem(B_PASTE)) == NULL
&& (item = menu->FindItem(kPasteLinksFromClipboard)) == NULL) {
return;
}
item->SetEnabled(FSClipboardHasRefs() || PoseView() != CurrentFocus());
if (modifiers() & B_SHIFT_KEY) {
item->SetLabel(B_TRANSLATE("Paste links"));
item->SetShortcut('V', B_COMMAND_KEY | B_SHIFT_KEY);
item->SetMessage(new BMessage(kPasteLinksFromClipboard));
} else {
item->SetLabel(B_TRANSLATE("Paste"));
item->SetShortcut('V', B_COMMAND_KEY);
item->SetMessage(new BMessage(B_PASTE));
}
}
void
BContainerWindow::SetArrangeMenu(BMenu* menu)
{
BMenuItem* item;
if ((item = menu->FindItem(kCleanup)) == NULL
&& (item = menu->FindItem(kCleanupAll)) == NULL) {
return;
}
item->Menu()->SetEnabled(PoseView()->CountItems() > 0
&& (PoseView()->ViewMode() != kListMode));
BMenu* arrangeMenu;
if (modifiers() & B_SHIFT_KEY) {
item->SetLabel(B_TRANSLATE("Clean up all"));
item->SetShortcut('K', B_COMMAND_KEY | B_SHIFT_KEY);
item->SetMessage(new BMessage(kCleanupAll));
arrangeMenu = item->Menu();
} else {
item->SetLabel(B_TRANSLATE("Clean up"));
item->SetShortcut('K', B_COMMAND_KEY);
item->SetMessage(new BMessage(kCleanup));
arrangeMenu = item->Menu();
}
MarkArrangeByMenu(arrangeMenu);
}
void
BContainerWindow::SetCloseItem(BMenu* menu)
{
BMenuItem* item;
if ((item = menu->FindItem(B_QUIT_REQUESTED)) == NULL
&& (item = menu->FindItem(kCloseAllWindows)) == NULL) {
return;
}
if (modifiers() & B_SHIFT_KEY) {
item->SetLabel(B_TRANSLATE("Close all"));
item->SetShortcut('W', B_COMMAND_KEY | B_SHIFT_KEY);
item->SetTarget(be_app);
item->SetMessage(new BMessage(kCloseAllWindows));
} else {
item->SetLabel(B_TRANSLATE("Close"));
item->SetShortcut('W', B_COMMAND_KEY);
item->SetTarget(this);
item->SetMessage(new BMessage(B_QUIT_REQUESTED));
}
}
bool
BContainerWindow::IsShowing(const node_ref* node) const
{
return PoseView()->Represents(node);
}
bool
BContainerWindow::IsShowing(const entry_ref* entry) const
{
return PoseView()->Represents(entry);
}
void
BContainerWindow::AddMenus()
{
fFileMenu = new BMenu(B_TRANSLATE("File"));
AddFileMenu(fFileMenu);
fMenuBar->AddItem(fFileMenu);
fWindowMenu = new BMenu(B_TRANSLATE("Window"));
fMenuBar->AddItem(fWindowMenu);
AddWindowMenu(fWindowMenu);
fAttrMenu = new BMenu(B_TRANSLATE("Attributes"));
NewAttributeMenu(fAttrMenu);
PopulateArrangeByMenu(fArrangeByMenu);
}
void
BContainerWindow::AddFileMenu(BMenu* menu)
{
if (!PoseView()->IsFilePanel()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS),
new BMessage(kFindButton), 'F'));
}
if (!TargetModel()->IsQuery() && !TargetModel()->IsVirtualDirectory()
&& !IsTrash() && !IsPrintersDir() && !TargetModel()->IsRoot()) {
if (!PoseView()->IsFilePanel()) {
TemplatesMenu* templatesMenu = new TemplatesMenu(PoseView(),
B_TRANSLATE("New"));
menu->AddItem(templatesMenu);
templatesMenu->SetTargetForItems(PoseView());
} else {
menu->AddItem(new BMenuItem(B_TRANSLATE("New folder"),
new BMessage(kNewFolder), 'N'));
}
}
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Open"),
new BMessage(kOpenSelection), 'O'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Get info"),
new BMessage(kGetInfo), 'I'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Edit name"),
new BMessage(kEditItem), 'E'));
if (IsTrash() || InTrash()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Restore"),
new BMessage(kRestoreFromTrash)));
if (IsTrash()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"),
new BMessage(kEmptyTrash)), 0);
menu->AddItem(new BSeparatorItem(), 1);
}
} else if (IsPrintersDir()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Add printer" B_UTF8_ELLIPSIS),
new BMessage(kAddPrinter), 'N'), 0);
menu->AddItem(new BSeparatorItem(), 1);
menu->AddItem(new BMenuItem(B_TRANSLATE("Make active printer"),
new BMessage(kMakeActivePrinter)));
} else if (TargetModel()->IsRoot()) {
BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"),
new BMessage(kUnmountVolume), 'U');
item->SetEnabled(false);
menu->AddItem(item);
menu->AddItem(new BMenuItem(
B_TRANSLATE("Mount settings" B_UTF8_ELLIPSIS),
new BMessage(kRunAutomounterSettings)));
} else {
menu->AddItem(new BMenuItem(B_TRANSLATE("Duplicate"),
new BMessage(kDuplicateSelection), 'D'));
menu->AddItem(new BMenuItem(TrackerSettings().DontMoveFilesToTrash()
? B_TRANSLATE("Delete") : B_TRANSLATE("Move to Trash"),
new BMessage(kMoveToTrash), 'T'));
menu->AddSeparatorItem();
}
BMenuItem* cutItem = NULL;
BMenuItem* copyItem = NULL;
BMenuItem* pasteItem = NULL;
if (!IsPrintersDir()) {
menu->AddSeparatorItem();
if (!TargetModel()->IsRoot()) {
cutItem = new(std::nothrow) BMenuItem(B_TRANSLATE("Cut"),
new BMessage(B_CUT), 'X');
menu->AddItem(cutItem);
copyItem = new(std::nothrow) BMenuItem(B_TRANSLATE("Copy"),
new BMessage(B_COPY), 'C');
menu->AddItem(copyItem);
pasteItem = new(std::nothrow) BMenuItem(B_TRANSLATE("Paste"),
new BMessage(B_PASTE), 'V');
menu->AddItem(pasteItem);
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Identify"),
new BMessage(kIdentifyEntry)));
}
BMenu* addOnMenuItem = new BMenu(B_TRANSLATE("Add-ons"));
addOnMenuItem->SetFont(be_plain_font);
menu->AddItem(addOnMenuItem);
}
menu->SetTargetForItems(PoseView());
if (cutItem != NULL)
cutItem->SetTarget(this);
if (copyItem != NULL)
copyItem->SetTarget(this);
if (pasteItem != NULL)
pasteItem->SetTarget(this);
}
void
BContainerWindow::AddWindowMenu(BMenu* menu)
{
BMenuItem* item;
BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view"));
BMessage* message = new BMessage(kIconMode);
message->AddInt32("size", 32);
item = new BMenuItem(B_TRANSLATE("32 x 32"), message);
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
message = new BMessage(kIconMode);
message->AddInt32("size", 40);
item = new BMenuItem(B_TRANSLATE("40 x 40"), message);
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
message = new BMessage(kIconMode);
message->AddInt32("size", 48);
item = new BMenuItem(B_TRANSLATE("48 x 48"), message);
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
message = new BMessage(kIconMode);
message->AddInt32("size", 64);
item = new BMenuItem(B_TRANSLATE("64 x 64"), message);
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
message = new BMessage(kIconMode);
message->AddInt32("size", 96);
item = new BMenuItem(B_TRANSLATE("96 x 96"), message);
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
message = new BMessage(kIconMode);
message->AddInt32("size", 128);
item = new BMenuItem(B_TRANSLATE("128 x 128"), message);
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
iconSizeMenu->AddSeparatorItem();
message = new BMessage(kIconMode);
message->AddInt32("scale", 0);
item = new BMenuItem(B_TRANSLATE("Decrease size"), message, '-');
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
message = new BMessage(kIconMode);
message->AddInt32("scale", 1);
item = new BMenuItem(B_TRANSLATE("Increase size"), message, '+');
item->SetTarget(PoseView());
iconSizeMenu->AddItem(item);
menu->AddItem(iconSizeMenu);
iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY);
iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode));
iconSizeMenu->Superitem()->SetTarget(PoseView());
item = new BMenuItem(B_TRANSLATE("Mini icon view"),
new BMessage(kMiniIconMode), '2');
item->SetTarget(PoseView());
menu->AddItem(item);
BMenu* listViewMenu = new BMenu(B_TRANSLATE("List view"));
message = new BMessage(kListMode);
message->AddInt32("icon_size", B_MINI_ICON);
item = new BMenuItem(listViewMenu, message);
item->SetShortcut('3', B_COMMAND_KEY);
item->SetTarget(PoseView());
menu->AddItem(item);
message = new BMessage(kListMode);
message->AddInt32("icon_size", B_MINI_ICON);
item = new BMenuItem(B_TRANSLATE("Mini"), message);
item->SetTarget(PoseView());
listViewMenu->AddItem(item);
message = new BMessage(kListMode);
message->AddInt32("icon_size", B_LARGE_ICON);
item = new BMenuItem(B_TRANSLATE("Large"), message);
item->SetTarget(PoseView());
listViewMenu->AddItem(item);
listViewMenu->SetTargetForItems(PoseView());
menu->AddSeparatorItem();
item = new BMenuItem(B_TRANSLATE("Resize to fit"),
new BMessage(kResizeToFit), 'Y');
item->SetTarget(this);
menu->AddItem(item);
fArrangeByMenu = new BMenu(B_TRANSLATE("Arrange by"));
menu->AddItem(fArrangeByMenu);
item = new BMenuItem(B_TRANSLATE("Select" B_UTF8_ELLIPSIS),
new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY);
item->SetTarget(PoseView());
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Select all"),
new BMessage(B_SELECT_ALL), 'A');
item->SetTarget(PoseView());
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Invert selection"),
new BMessage(kInvertSelection), 'S');
item->SetTarget(PoseView());
menu->AddItem(item);
if (!IsTrash()) {
item = new BMenuItem(B_TRANSLATE("Open parent"),
new BMessage(kOpenParentDir), B_UP_ARROW);
item->SetTarget(PoseView());
menu->AddItem(item);
}
item = new BMenuItem(B_TRANSLATE("Close"),
new BMessage(B_QUIT_REQUESTED), 'W');
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Close all in workspace"),
new BMessage(kCloseAllInWorkspace), 'Q');
item->SetTarget(be_app);
menu->AddItem(item);
menu->AddSeparatorItem();
item = new BMenuItem(B_TRANSLATE("Preferences" B_UTF8_ELLIPSIS),
new BMessage(kShowSettingsWindow));
item->SetTarget(be_app);
menu->AddItem(item);
}
void
BContainerWindow::AddShortcuts()
{
ASSERT(!IsTrash());
ASSERT(!PoseView()->IsFilePanel());
ASSERT(!TargetModel()->IsQuery());
ASSERT(!TargetModel()->IsVirtualDirectory());
AddShortcut('X', B_COMMAND_KEY | B_SHIFT_KEY,
new BMessage(kCutMoreSelectionToClipboard), this);
AddShortcut('C', B_COMMAND_KEY | B_SHIFT_KEY,
new BMessage(kCopyMoreSelectionToClipboard), this);
AddShortcut('F', B_COMMAND_KEY,
new BMessage(kFindButton), PoseView());
AddShortcut('N', B_COMMAND_KEY,
new BMessage(kNewFolder), PoseView());
AddShortcut('O', B_COMMAND_KEY,
new BMessage(kOpenSelection), PoseView());
AddShortcut('I', B_COMMAND_KEY,
new BMessage(kGetInfo), PoseView());
AddShortcut('E', B_COMMAND_KEY,
new BMessage(kEditItem), PoseView());
AddShortcut('D', B_COMMAND_KEY,
new BMessage(kDuplicateSelection), PoseView());
AddShortcut('T', B_COMMAND_KEY,
new BMessage(kMoveToTrash), PoseView());
AddShortcut('K', B_COMMAND_KEY,
new BMessage(kCleanup), PoseView());
AddShortcut('A', B_COMMAND_KEY,
new BMessage(B_SELECT_ALL), PoseView());
AddShortcut('S', B_COMMAND_KEY,
new BMessage(kInvertSelection), PoseView());
AddShortcut('A', B_COMMAND_KEY | B_SHIFT_KEY,
new BMessage(kShowSelectionWindow), PoseView());
AddShortcut('G', B_COMMAND_KEY,
new BMessage(kEditQuery), PoseView());
AddShortcut('U', B_COMMAND_KEY,
new BMessage(kUnmountVolume), PoseView());
AddShortcut(B_UP_ARROW, B_COMMAND_KEY,
new BMessage(kOpenParentDir), PoseView());
AddShortcut('O', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(kOpenSelectionWith), PoseView());
BMessage* decreaseSize = new BMessage(kIconMode);
decreaseSize->AddInt32("scale", 0);
AddShortcut('-', B_COMMAND_KEY, decreaseSize, PoseView());
BMessage* increaseSize = new BMessage(kIconMode);
increaseSize->AddInt32("scale", 1);
AddShortcut('+', B_COMMAND_KEY, increaseSize, PoseView());
}
void
BContainerWindow::MenusBeginning()
{
if (fMenuBar == NULL)
return;
if (CurrentMessage() != NULL && CurrentMessage()->what == B_MOUSE_DOWN) {
fPoseView->CommitActivePose();
}
int32 selectCount = PoseView()->SelectionList()->CountItems();
SetupOpenWithMenu(fFileMenu);
SetupMoveCopyMenus(selectCount
? PoseView()->SelectionList()->FirstItem()->TargetModel()->EntryRef()
: NULL, fFileMenu);
if (TargetModel()->IsRoot()) {
BVolume boot;
BVolumeRoster().GetBootVolume(&boot);
bool ejectableVolumeSelected = false;
int32 count = PoseView()->SelectionList()->CountItems();
for (int32 index = 0; index < count; index++) {
Model* model
= PoseView()->SelectionList()->ItemAt(index)->TargetModel();
if (model->IsVolume()) {
BVolume volume;
volume.SetTo(model->NodeRef()->device);
if (volume != boot) {
ejectableVolumeSelected = true;
break;
}
}
}
BMenuItem* item = fMenuBar->FindItem(kUnmountVolume);
if (item != NULL)
item->SetEnabled(ejectableVolumeSelected);
}
UpdateMenu(fMenuBar, kMenuBarContext);
AddMimeTypesToMenu(fAttrMenu);
if (IsPrintersDir()) {
EnableNamedMenuItem(fFileMenu, B_TRANSLATE("Make active printer"),
selectCount == 1);
}
}
void
BContainerWindow::MenusEnded()
{
DeleteSubmenu(fNavigationItem);
DeleteSubmenu(fMoveToItem);
DeleteSubmenu(fCopyToItem);
DeleteSubmenu(fCreateLinkItem);
DeleteSubmenu(fOpenWithItem);
}
void
BContainerWindow::SetupNavigationMenu(const entry_ref* ref, BMenu* parent)
{
if (fNavigationItem != NULL) {
BMenu* menu = fNavigationItem->Menu();
if (menu != NULL) {
menu->RemoveItem(fNavigationItem);
BMenuItem* item = menu->RemoveItem((int32)0);
ASSERT(item != fNavigationItem);
delete item;
}
}
if (ref == NULL)
ref = TargetModel()->EntryRef();
BEntry entry;
if (entry.SetTo(ref) != B_OK)
return;
Model model(&entry);
entry_ref resolvedRef;
if (model.InitCheck() != B_OK
|| (!model.IsContainer() && !model.IsSymLink())) {
return;
}
if (model.IsSymLink()) {
if (entry.SetTo(model.EntryRef(), true) != B_OK)
return;
Model resolvedModel(&entry);
if (resolvedModel.InitCheck() != B_OK || !resolvedModel.IsContainer())
return;
entry.GetRef(&resolvedRef);
ref = &resolvedRef;
}
if (fNavigationItem == NULL) {
fNavigationItem = new ModelMenuItem(&model,
new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, this));
}
BNavMenu* navMenu = dynamic_cast<BNavMenu*>(fNavigationItem->Submenu());
navMenu->SetNavDir(ref);
fNavigationItem->SetLabel(model.Name());
fNavigationItem->SetEntry(&entry);
parent->AddItem(fNavigationItem, 0);
parent->AddItem(new BSeparatorItem(), 1);
BMessage* message = new BMessage(B_REFS_RECEIVED);
message->AddRef("refs", ref);
fNavigationItem->SetMessage(message);
fNavigationItem->SetTarget(be_app);
if (!Dragging())
parent->SetTrackingHook(NULL, NULL);
}
void
BContainerWindow::SetUpEditQueryItem(BMenu* menu)
{
ASSERT(menu);
int32 selectCount = PoseView()->SelectionList()->CountItems();
bool queryInSelection = false;
if (selectCount && selectCount < 100) {
for (int32 index = 0; index < selectCount; index++) {
BPose* pose = PoseView()->SelectionList()->ItemAt(index);
Model model(pose->TargetModel()->EntryRef(), true);
if (model.InitCheck() != B_OK)
continue;
if (model.IsQuery() || model.IsQueryTemplate()) {
queryInSelection = true;
break;
}
}
}
bool poseViewIsQuery = TargetModel()->IsQuery();
BMenuItem* item = menu->FindItem(kEditQuery);
if (!poseViewIsQuery && !queryInSelection && item != NULL)
item->Menu()->RemoveItem(item);
else if ((poseViewIsQuery || queryInSelection) && item == NULL) {
item = menu->FindItem(kOpenSelection);
if (item) {
int32 itemIndex = item->Menu()->IndexOf(item);
BMenuItem* query = new BMenuItem(B_TRANSLATE("Edit query"),
new BMessage(kEditQuery), 'G');
item->Menu()->AddItem(query, itemIndex + 1);
query->SetTarget(PoseView());
}
}
}
void
BContainerWindow::SetupOpenWithMenu(BMenu* parent)
{
if (fOpenWithItem) {
BMenu* menu = fOpenWithItem->Menu();
if (menu != NULL)
menu->RemoveItem(fOpenWithItem);
delete fOpenWithItem;
fOpenWithItem = 0;
}
if (PoseView()->SelectionList()->CountItems() == 0) {
return;
}
if (TargetModel()->IsRoot()) {
return;
}
BMenuItem* item = parent->FindItem(kOpenSelection);
int32 count = PoseView()->SelectionList()->CountItems();
if (count == 0)
return;
BMessage message(B_REFS_RECEIVED);
for (int32 index = 0; index < count; index++) {
BPose* pose = PoseView()->SelectionList()->ItemAt(index);
message.AddRef("refs", pose->TargetModel()->EntryRef());
}
message.AddMessenger("TrackerViewToken", BMessenger(PoseView()));
int32 index = item->Menu()->IndexOf(item);
fOpenWithItem = new BMenuItem(
new OpenWithMenu(B_TRANSLATE("Open with" B_UTF8_ELLIPSIS),
&message, this, be_app), new BMessage(kOpenSelectionWith));
fOpenWithItem->SetTarget(PoseView());
fOpenWithItem->SetShortcut('O', B_COMMAND_KEY | B_CONTROL_KEY);
item->Menu()->AddItem(fOpenWithItem, index + 1);
}
void
BContainerWindow::PopulateMoveCopyNavMenu(BNavMenu* navMenu, uint32 what,
const entry_ref* ref, bool addLocalOnly)
{
BVolume volume;
BVolumeRoster volumeRoster;
BDirectory directory;
BEntry entry;
BPath path;
Model model;
dev_t device = ref->device;
int32 volumeCount = 0;
navMenu->RemoveItems(0, navMenu->CountItems(), true);
volumeRoster.Rewind();
while (volumeRoster.GetNextVolume(&volume) == B_OK)
if (!volume.IsReadOnly() && volume.IsPersistent())
volumeCount++;
if (entry.SetTo(ref) == B_OK
&& entry.GetParent(&entry) == B_OK
&& model.SetTo(&entry) == B_OK) {
BNavMenu* menu = new BNavMenu(B_TRANSLATE("Current folder"), what,
this);
menu->SetNavDir(model.EntryRef());
menu->SetShowParent(true);
BMenuItem* item = new SpecialModelMenuItem(&model,menu);
item->SetMessage(new BMessage((uint32)what));
navMenu->AddItem(item);
}
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append("Tracker");
if (entry.SetTo(path.Path()) == B_OK
&& model.SetTo(&entry) == B_OK) {
BMenu* menu = new RecentsMenu(B_TRANSLATE("Recent folders"),
kRecentFolders, what, this);
BMenuItem* item = new SpecialModelMenuItem(&model,menu);
item->SetMessage(new BMessage((uint32)what));
navMenu->AddItem(item);
}
}
FSGetBootDeskDir(&directory);
if (directory.InitCheck() == B_OK
&& directory.GetEntry(&entry) == B_OK
&& model.SetTo(&entry) == B_OK)
navMenu->AddNavDir(&model, what, this, true);
if (find_directory(B_USER_DIRECTORY, &path) == B_OK
&& entry.SetTo(path.Path()) == B_OK
&& model.SetTo(&entry) == B_OK)
navMenu->AddNavDir(&model, what, this, true);
navMenu->AddSeparatorItem();
if (addLocalOnly || volumeCount < 2) {
if (volume.SetTo(device) == B_OK
&& volume.GetRootDirectory(&directory) == B_OK
&& directory.GetEntry(&entry) == B_OK
&& model.SetTo(&entry) == B_OK) {
navMenu->AddNavDir(&model, what, this, false);
navMenu->SetNavDir(model.EntryRef());
}
} else {
volumeRoster.Rewind();
while (volumeRoster.GetNextVolume(&volume) == B_OK) {
if (volume.IsReadOnly() || !volume.IsPersistent())
continue;
if (volume.GetRootDirectory(&directory) == B_OK
&& directory.GetEntry(&entry) == B_OK
&& model.SetTo(&entry) == B_OK) {
navMenu->AddNavDir(&model, what, this, true);
}
}
}
}
void
BContainerWindow::SetupMoveCopyMenus(const entry_ref* item_ref, BMenu* parent)
{
if (IsTrash() || InTrash() || IsPrintersDir() || !fMoveToItem
|| !fCopyToItem || !fCreateLinkItem || TargetModel()->IsRoot()) {
return;
}
uint32 modifierKeys = modifiers();
int32 index;
BMenuItem* trash = parent->FindItem(kMoveToTrash);
if (trash)
index = parent->IndexOf(trash) + 2;
else
index = 0;
if (fMoveToItem->Menu() != parent) {
if (fMoveToItem->Menu())
fMoveToItem->Menu()->RemoveItem(fMoveToItem);
parent->AddItem(fMoveToItem, index++);
}
if (fCopyToItem->Menu() != parent) {
if (fCopyToItem->Menu())
fCopyToItem->Menu()->RemoveItem(fCopyToItem);
parent->AddItem(fCopyToItem, index++);
}
if (fCreateLinkItem->Menu() != parent) {
if (fCreateLinkItem->Menu())
fCreateLinkItem->Menu()->RemoveItem(fCreateLinkItem);
parent->AddItem(fCreateLinkItem, index);
}
if (modifierKeys & B_SHIFT_KEY)
fCreateLinkItem->SetLabel(B_TRANSLATE("Create relative link"));
else
fCreateLinkItem->SetLabel(B_TRANSLATE("Create link"));
fMoveToItem->SetEnabled(false);
fCopyToItem->SetEnabled(false);
fCreateLinkItem->SetEnabled(false);
BEntry entry;
if (entry.SetTo(item_ref) != B_OK)
return;
Model tempModel(&entry);
if (tempModel.InitCheck() != B_OK)
return;
if (tempModel.IsRoot() || tempModel.IsVolume())
return;
PopulateMoveCopyNavMenu(dynamic_cast<BNavMenu*>(fMoveToItem->Submenu()),
kMoveSelectionTo, item_ref, true);
PopulateMoveCopyNavMenu(dynamic_cast<BNavMenu*>(fCopyToItem->Submenu()),
kCopySelectionTo, item_ref, false);
if (modifierKeys & B_SHIFT_KEY) {
fCreateLinkItem->SetMessage(new BMessage(kCreateRelativeLink));
PopulateMoveCopyNavMenu(dynamic_cast<BNavMenu*>
(fCreateLinkItem->Submenu()),
kCreateRelativeLink, item_ref, false);
} else {
fCreateLinkItem->SetMessage(new BMessage(kCreateLink));
PopulateMoveCopyNavMenu(dynamic_cast<BNavMenu*>
(fCreateLinkItem->Submenu()),
kCreateLink, item_ref, false);
}
fMoveToItem->SetEnabled(true);
fCopyToItem->SetEnabled(true);
fCreateLinkItem->SetEnabled(true);
BMenuItem* identifyItem = parent->FindItem(kIdentifyEntry);
if (identifyItem != NULL) {
if (modifierKeys & B_SHIFT_KEY) {
identifyItem->SetLabel(B_TRANSLATE("Force identify"));
identifyItem->Message()->ReplaceBool("force", true);
} else {
identifyItem->SetLabel(B_TRANSLATE("Identify"));
identifyItem->Message()->ReplaceBool("force", false);
}
}
}
uint32
BContainerWindow::ShowDropContextMenu(BPoint loc)
{
BPoint global(loc);
PoseView()->ConvertToScreen(&global);
PoseView()->CommitActivePose();
BMenuItem* item = fDropContextMenu->FindItem(kCreateLink);
if (item == NULL)
item = fDropContextMenu->FindItem(kCreateRelativeLink);
if (item && (modifiers() & B_SHIFT_KEY)) {
item->SetLabel(B_TRANSLATE("Create relative link here"));
item->SetMessage(new BMessage(kCreateRelativeLink));
} else if (item) {
item->SetLabel(B_TRANSLATE("Create link here"));
item->SetMessage(new BMessage(kCreateLink));
}
item = fDropContextMenu->Go(global, true, true);
if (item)
return item->Command();
return 0;
}
void
BContainerWindow::ShowContextMenu(BPoint loc, const entry_ref* ref, BView*)
{
ASSERT(IsLocked());
BPoint global(loc);
PoseView()->ConvertToScreen(&global);
PoseView()->CommitActivePose();
if (ref != NULL) {
Model model(ref);
if (model.IsTrash()) {
if (fTrashContextMenu->Window() || Dragging())
return;
DeleteSubmenu(fNavigationItem);
EnableNamedMenuItem(fTrashContextMenu, kEmptyTrash,
static_cast<TTracker*>(be_app)->TrashFull());
SetupNavigationMenu(ref, fTrashContextMenu);
fTrashContextMenu->Go(global, true, true, true);
} else {
bool showAsVolume = false;
bool filePanel = PoseView()->IsFilePanel();
if (Dragging()) {
fContextMenu = NULL;
BEntry entry;
model.GetEntry(&entry);
if (!FSIsPrintersDir(&entry)
&& !fDragContextMenu->IsShowing()) {
fDragContextMenu->ClearMenu();
BEntry resolvedEntry(ref, true);
if (!resolvedEntry.IsDirectory())
return;
entry_ref resolvedRef;
resolvedEntry.GetRef(&resolvedRef);
fDragContextMenu->SetNavDir(&resolvedRef);
fDragContextMenu->SetTypesList(fCachedTypesList);
fDragContextMenu->SetTarget(BMessenger(this));
BPoseView* poseView = PoseView();
if (poseView != NULL) {
BMessenger target(poseView);
fDragContextMenu->InitTrackingHook(
&BPoseView::MenuTrackingHook, &target,
fDragMessage);
}
fDragContextMenu->Go(global, true, false, true);
}
return;
} else if (TargetModel()->IsRoot() || model.IsVolume()) {
fContextMenu = fVolumeContextMenu;
showAsVolume = true;
} else
fContextMenu = fFileContextMenu;
if (fContextMenu != NULL) {
if (fContextMenu->Window())
return;
else
MenusEnded();
if (model.InitCheck() == B_OK) {
if (showAsVolume) {
EnableNamedMenuItem(fContextMenu, kDuplicateSelection,
false);
EnableNamedMenuItem(fContextMenu, kMoveToTrash, false);
EnableNamedMenuItem(fContextMenu, kIdentifyEntry,
false);
bool ejectableVolumeSelected = false;
BVolume boot;
BVolumeRoster().GetBootVolume(&boot);
BVolume volume;
volume.SetTo(model.NodeRef()->device);
if (volume != boot)
ejectableVolumeSelected = true;
EnableNamedMenuItem(fContextMenu,
B_TRANSLATE("Unmount"), ejectableVolumeSelected);
}
}
SetupNavigationMenu(ref, fContextMenu);
if (!showAsVolume && !filePanel) {
SetupMoveCopyMenus(ref, fContextMenu);
SetupOpenWithMenu(fContextMenu);
}
UpdateMenu(fContextMenu, kPosePopUpContext);
fContextMenu->Go(global, true, true, true);
}
}
} else if (fWindowContextMenu != NULL) {
if (fWindowContextMenu->Window())
return;
if (fIsDesktop)
RepopulateMenus();
MenusEnded();
SetupNavigationMenu(ref, fWindowContextMenu);
UpdateMenu(fWindowContextMenu, kWindowPopUpContext);
fWindowContextMenu->Go(global, true, true, true);
}
fContextMenu = NULL;
}
void
BContainerWindow::AddFileContextMenus(BMenu* menu)
{
menu->AddItem(new BMenuItem(B_TRANSLATE("Open"),
new BMessage(kOpenSelection), 'O'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Get info"),
new BMessage(kGetInfo), 'I'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Edit name"),
new BMessage(kEditItem), 'E'));
if (!IsTrash() && !InTrash() && !IsPrintersDir()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Duplicate"),
new BMessage(kDuplicateSelection), 'D'));
}
if (!IsTrash() && !InTrash()) {
menu->AddItem(new BMenuItem(TrackerSettings().DontMoveFilesToTrash()
? B_TRANSLATE("Delete") : B_TRANSLATE("Move to Trash"),
new BMessage(kMoveToTrash), 'T'));
if (!IsPrintersDir()) {
menu->AddSeparatorItem();
}
} else {
menu->AddItem(new BMenuItem(B_TRANSLATE("Delete"),
new BMessage(kDelete), 0));
menu->AddItem(new BMenuItem(B_TRANSLATE("Restore"),
new BMessage(kRestoreFromTrash), 0));
}
#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
menu->AddSeparatorItem();
BMenuItem* cutItem = new BMenuItem(B_TRANSLATE("Cut"),
new BMessage(B_CUT), 'X');
menu->AddItem(cutItem);
BMenuItem* copyItem = new BMenuItem(B_TRANSLATE("Copy"),
new BMessage(B_COPY), 'C');
menu->AddItem(copyItem);
#endif
menu->AddSeparatorItem();
BMessage* message = new BMessage(kIdentifyEntry);
message->AddBool("force", false);
menu->AddItem(new BMenuItem(B_TRANSLATE("Identify"), message));
BMenu* addOnMenuItem = new BMenu(B_TRANSLATE("Add-ons"));
addOnMenuItem->SetFont(be_plain_font);
menu->AddItem(addOnMenuItem);
menu->SetTargetForItems(PoseView());
#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
cutItem->SetTarget(this);
copyItem->SetTarget(this);
#endif
}
void
BContainerWindow::AddVolumeContextMenus(BMenu* menu)
{
menu->AddItem(new BMenuItem(B_TRANSLATE("Open"),
new BMessage(kOpenSelection), 'O'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Get info"),
new BMessage(kGetInfo), 'I'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Edit name"),
new BMessage(kEditItem), 'E'));
menu->AddSeparatorItem();
menu->AddItem(new MountMenu(B_TRANSLATE("Mount")));
BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"),
new BMessage(kUnmountVolume), 'U');
item->SetEnabled(false);
menu->AddItem(item);
menu->AddSeparatorItem();
menu->AddItem(new BMenu(B_TRANSLATE("Add-ons")));
menu->SetTargetForItems(PoseView());
}
void
BContainerWindow::AddWindowContextMenus(BMenu* menu)
{
Model* targetModel = TargetModel();
ASSERT(targetModel != NULL);
bool needSeparator = true;
if (IsTrash()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"),
new BMessage(kEmptyTrash)));
} else if (IsPrintersDir()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Add printer" B_UTF8_ELLIPSIS),
new BMessage(kAddPrinter), 'N'));
} else if (InTrash() || targetModel->IsRoot()) {
needSeparator = false;
} else {
TemplatesMenu* templatesMenu = new TemplatesMenu(PoseView(),
B_TRANSLATE("New"));
menu->AddItem(templatesMenu);
templatesMenu->SetTargetForItems(PoseView());
templatesMenu->SetFont(be_plain_font);
}
if (needSeparator)
menu->AddSeparatorItem();
#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
BMenuItem* pasteItem = new BMenuItem("Paste", new BMessage(B_PASTE), 'V');
menu->AddItem(pasteItem);
menu->AddSeparatorItem();
#endif
BMenu* arrangeBy = new BMenu(B_TRANSLATE("Arrange by"));
PopulateArrangeByMenu(arrangeBy);
menu->AddItem(arrangeBy);
menu->AddItem(new BMenuItem(B_TRANSLATE("Select" B_UTF8_ELLIPSIS),
new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY));
menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"),
new BMessage(B_SELECT_ALL), 'A'));
if (!IsTrash()) {
menu->AddItem(new BMenuItem(B_TRANSLATE("Open parent"),
new BMessage(kOpenParentDir), B_UP_ARROW));
}
if (targetModel->IsRoot()) {
menu->AddSeparatorItem();
menu->AddItem(new MountMenu(B_TRANSLATE("Mount")));
}
menu->AddSeparatorItem();
BMenu* addOnMenuItem = new BMenu(B_TRANSLATE("Add-ons"));
addOnMenuItem->SetFont(be_plain_font);
menu->AddItem(addOnMenuItem);
#if DEBUG
menu->AddSeparatorItem();
BMenuItem* testing = new BMenuItem("Test icon cache",
new BMessage(kTestIconCache));
menu->AddItem(testing);
#endif
menu->SetTargetForItems(PoseView());
#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU
pasteItem->SetTarget(this);
#endif
}
void
BContainerWindow::AddDropContextMenus(BMenu* menu)
{
menu->AddItem(new BMenuItem(B_TRANSLATE("Create link here"),
new BMessage(kCreateLink)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Move here"),
new BMessage(kMoveSelectionTo)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Copy here"),
new BMessage(kCopySelectionTo)));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Cancel"),
new BMessage(kCancelButton)));
}
void
BContainerWindow::AddTrashContextMenus(BMenu* menu)
{
menu->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"),
new BMessage(kEmptyTrash)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Open"),
new BMessage(kOpenSelection), 'O'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Get info"),
new BMessage(kGetInfo), 'I'));
menu->SetTargetForItems(PoseView());
}
void
BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
uint32 shortcut, uint32 modifiers, bool primary, void* context,
BContainerWindow* window, BMenu* menu),
void* passThru, BStringList& mimeTypes, BMenu* menu)
{
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 (mimeTypes.CountStrings() > 0) {
BFile file(item->model->EntryRef(), B_READ_ONLY);
if (file.InitCheck() == B_OK) {
BAppFileInfo info(&file);
if (info.InitCheck() == B_OK) {
bool secondary = true;
BMessage message;
if (info.GetSupportedTypes(&message) == B_OK) {
type_code typeCode;
int32 count;
if (message.GetInfo("types", &typeCode,
&count) == B_OK) {
secondary = false;
}
}
if (!secondary) {
for (int32 i = mimeTypes.CountStrings();
!primary && i-- > 0;) {
BString type = mimeTypes.StringAt(i);
if (info.IsSupportedType(type.String())) {
BMimeType mimeType(type.String());
if (info.Supports(&mimeType))
primary = true;
else
secondary = true;
}
}
}
if (!secondary && !primary)
continue;
}
}
}
((eachAddon)(item->model, item->model->Name(), item->key,
item->modifiers, primary, passThru, this, menu));
}
}
}
void
BContainerWindow::BuildMimeTypeList(BStringList& mimeTypes)
{
int32 count = PoseView()->SelectionList()->CountItems();
if (count <= 0) {
AddMimeTypeString(mimeTypes, TargetModel());
} else {
_UpdateSelectionMIMEInfo();
for (int32 index = 0; index < count; index++) {
BPose* pose = PoseView()->SelectionList()->ItemAt(index);
AddMimeTypeString(mimeTypes, pose->TargetModel());
if (pose->TargetModel()->IsSymLink()) {
Model* resolved = new Model(
pose->TargetModel()->EntryRef(), true, true);
if (resolved->InitCheck() == B_OK)
AddMimeTypeString(mimeTypes, resolved);
delete resolved;
}
}
}
}
void
BContainerWindow::BuildAddOnMenu(BMenu* parentMenu)
{
BMenuItem* item = parentMenu->FindItem(B_TRANSLATE("Add-ons"));
if (parentMenu->IndexOf(item) == 0) {
item = parentMenu->ItemAt(parentMenu->CountItems() - 1);
}
if (item == NULL)
return;
BFont font;
parentMenu->GetFont(&font);
BMenu* menu = item->Submenu();
if (menu == NULL)
return;
menu->SetFont(&font);
for (;;) {
item = menu->RemoveItem((int32)0);
if (!item)
break;
delete item;
}
BObjectList<BMenuItem> primaryList;
BObjectList<BMenuItem> secondaryList;
BStringList mimeTypes(10);
BuildMimeTypeList(mimeTypes);
AddOneAddonParams params;
params.primaryList = &primaryList;
params.secondaryList = &secondaryList;
EachAddon(AddOneAddon, ¶ms, mimeTypes, parentMenu);
primaryList.SortItems(CompareLabels);
secondaryList.SortItems(CompareLabels);
int32 count = primaryList.CountItems();
for (int32 index = 0; index < count; index++)
menu->AddItem(primaryList.ItemAt(index));
if (count > 0)
menu->AddSeparatorItem();
count = secondaryList.CountItems();
for (int32 index = 0; index < count; index++)
menu->AddItem(secondaryList.ItemAt(index));
menu->SetTargetForItems(this);
}
void
BContainerWindow::UpdateMenu(BMenu* menu, UpdateMenuContext context)
{
const int32 selectCount = PoseView()->SelectionList()->CountItems();
const int32 count = PoseView()->CountItems();
if (context == kMenuBarContext) {
EnableNamedMenuItem(menu, kOpenSelection, selectCount > 0);
EnableNamedMenuItem(menu, kGetInfo, selectCount > 0);
EnableNamedMenuItem(menu, kIdentifyEntry, selectCount > 0);
EnableNamedMenuItem(menu, kMoveToTrash, selectCount > 0);
EnableNamedMenuItem(menu, kRestoreFromTrash, selectCount > 0);
EnableNamedMenuItem(menu, kDelete, selectCount > 0);
EnableNamedMenuItem(menu, kDuplicateSelection, selectCount > 0);
}
Model* selectedModel = NULL;
if (selectCount == 1) {
selectedModel = PoseView()->SelectionList()->FirstItem()->
TargetModel();
}
if (context == kMenuBarContext || context == kPosePopUpContext) {
SetUpEditQueryItem(menu);
EnableNamedMenuItem(menu, kEditItem, selectCount == 1
&& (context == kPosePopUpContext || !PoseView()->ActivePose())
&& selectedModel != NULL
&& !selectedModel->IsDesktop()
&& !selectedModel->IsRoot()
&& !selectedModel->IsTrash()
&& !selectedModel->HasLocalizedName());
SetCutItem(menu);
SetCopyItem(menu);
SetPasteItem(menu);
}
if (context == kMenuBarContext || context == kWindowPopUpContext) {
uint32 viewMode = PoseView()->ViewMode();
BMenu* iconSizeMenu = NULL;
if (BMenuItem* item = menu->FindItem(kIconMode))
iconSizeMenu = item->Submenu();
if (iconSizeMenu != NULL) {
if (viewMode == kIconMode) {
int32 iconSize = PoseView()->IconSizeInt();
BMenuItem* item = iconSizeMenu->ItemAt(0);
for (int32 i = 0; (item = iconSizeMenu->ItemAt(i)) != NULL;
i++) {
BMessage* message = item->Message();
if (message == NULL) {
item->SetMarked(false);
continue;
}
int32 size;
if (message->FindInt32("size", &size) != B_OK)
size = -1;
item->SetMarked(iconSize == size);
}
} else {
BMenuItem* item;
for (int32 i = 0; (item = iconSizeMenu->ItemAt(i)) != NULL; i++)
item->SetMarked(false);
}
}
BMenu* listSizeMenu = NULL;
if (BMenuItem* item = menu->FindItem(kListMode))
listSizeMenu = item->Submenu();
if (listSizeMenu != NULL) {
if (viewMode == kListMode) {
int32 iconSize = PoseView()->IconSizeInt();
BMenuItem* item = listSizeMenu->ItemAt(0);
for (int32 i = 0; (item = listSizeMenu->ItemAt(i)) != NULL;
i++) {
BMessage* message = item->Message();
if (message == NULL) {
item->SetMarked(false);
continue;
}
int32 size;
if (message->FindInt32("icon_size", &size) != B_OK)
size = -1;
item->SetMarked(iconSize == size);
}
} else {
BMenuItem* item;
for (int32 i = 0; (item = listSizeMenu->ItemAt(i)) != NULL; i++)
item->SetMarked(false);
}
}
MarkNamedMenuItem(menu, kIconMode, viewMode == kIconMode);
MarkNamedMenuItem(menu, kListMode, viewMode == kListMode);
MarkNamedMenuItem(menu, kMiniIconMode, viewMode == kMiniIconMode);
SetCloseItem(menu);
SetArrangeMenu(menu);
SetPasteItem(menu);
BEntry entry(TargetModel()->EntryRef());
BDirectory parent;
entry_ref ref;
BEntry root("/");
bool parentIsRoot = (entry.GetParent(&parent) == B_OK
&& parent.GetEntry(&entry) == B_OK
&& entry.GetRef(&ref) == B_OK
&& entry == root);
EnableNamedMenuItem(menu, kOpenParentDir, !TargetModel()->IsDesktop()
&& !TargetModel()->IsRoot()
&& (!parentIsRoot
|| TrackerSettings().SingleWindowBrowse()
|| TrackerSettings().ShowDisksIcon()
|| (modifiers() & B_CONTROL_KEY) != 0));
EnableNamedMenuItem(menu, kEmptyTrash, count > 0);
EnableNamedMenuItem(menu, B_SELECT_ALL, count > 0);
BMenuItem* item = menu->FindItem(B_TRANSLATE("New"));
if (item != NULL) {
TemplatesMenu* templatesMenu = dynamic_cast<TemplatesMenu*>(
item->Submenu());
if (templatesMenu != NULL)
templatesMenu->UpdateMenuState();
}
}
BuildAddOnMenu(menu);
}
BMessage*
BContainerWindow::AddOnMessage(int32 what)
{
BMessage* message = new BMessage(what);
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
BContainerWindow::LoadAddOn(BMessage* message)
{
UpdateIfNeeded();
entry_ref addonRef;
status_t result = message->FindRef("refs", &addonRef);
if (result != B_OK) {
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;
}
BMessage* refs = AddOnMessage(B_REFS_RECEIVED);
LaunchInNewThread("Add-on", B_NORMAL_PRIORITY, &AddOnThread, refs,
addonRef, *TargetModel()->EntryRef());
}
void
BContainerWindow::_UpdateSelectionMIMEInfo()
{
BPose* pose;
int32 index = 0;
while ((pose = PoseView()->SelectionList()->ItemAt(index++)) != NULL) {
BString mimeType(pose->TargetModel()->MimeType());
if (!mimeType.Length() || mimeType.ICompare(B_FILE_MIMETYPE) == 0) {
pose->TargetModel()->Mimeset(true);
if (pose->TargetModel()->IsSymLink()) {
Model* resolved = new Model(pose->TargetModel()->EntryRef(),
true, true);
if (resolved->InitCheck() == B_OK) {
mimeType.SetTo(resolved->MimeType());
if (!mimeType.Length()
|| mimeType.ICompare(B_FILE_MIMETYPE) == 0) {
resolved->Mimeset(true);
}
}
delete resolved;
}
}
}
}
void
BContainerWindow::_AddFolderIcon()
{
if (fMenuBar == NULL) {
return;
}
float iconSize = fMenuBar->Bounds().Height() - 2;
if (iconSize < 16)
iconSize = 16;
fDraggableIcon = new(std::nothrow) DraggableContainerIcon();
if (fDraggableIcon != NULL) {
BLayoutItem* item = fMenuContainer->GroupLayout()->AddView(
fDraggableIcon);
item->SetExplicitMinSize(BSize(iconSize + 5, iconSize));
item->SetExplicitMaxSize(BSize(iconSize + 5, item->MaxSize().Height()));
fMenuBar->SetBorders(
BControlLook::B_ALL_BORDERS & ~BControlLook::B_RIGHT_BORDER);
}
}
void
BContainerWindow::_PassMessageToAddOn(BMessage* message)
{
LaunchInNewThread("Add-on-Pass-Message", B_NORMAL_PRIORITY,
&RunAddOnMessageThread, new BMessage(*message), (void*)NULL);
}
BMenuItem*
BContainerWindow::NewAttributeMenuItem(const char* label, const char* name,
int32 type, float width, int32 align, bool editable, bool statField)
{
return NewAttributeMenuItem(label, name, type, NULL, width, align,
editable, statField);
}
BMenuItem*
BContainerWindow::NewAttributeMenuItem(const char* label, const char* name,
int32 type, const char* displayAs, float width, int32 align,
bool editable, bool statField)
{
BMessage* message = new BMessage(kAttributeItem);
message->AddString("attr_name", name);
message->AddInt32("attr_type", type);
message->AddInt32("attr_hash", (int32)AttrHashString(name, (uint32)type));
message->AddFloat("attr_width", width);
message->AddInt32("attr_align", align);
if (displayAs != NULL)
message->AddString("attr_display_as", displayAs);
message->AddBool("attr_editable", editable);
message->AddBool("attr_statfield", statField);
BMenuItem* menuItem = new BMenuItem(label, message);
menuItem->SetTarget(PoseView());
return menuItem;
}
void
BContainerWindow::NewAttributeMenu(BMenu* menu)
{
ASSERT(PoseView());
BMenuItem* item;
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Copy layout"),
new BMessage(kCopyAttributes)));
item->SetTarget(PoseView());
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Paste layout"),
new BMessage(kPasteAttributes)));
item->SetTarget(PoseView());
menu->AddSeparatorItem();
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Name"),
kAttrStatName, B_STRING_TYPE, 145, B_ALIGN_LEFT, true, true));
if (gLocalizedNamePreferred) {
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Real name"),
kAttrRealName, B_STRING_TYPE, 145, B_ALIGN_LEFT, true, true));
}
menu->AddItem(NewAttributeMenuItem (B_TRANSLATE("Size"), kAttrStatSize,
B_OFF_T_TYPE, 80, B_ALIGN_RIGHT, false, true));
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Modified"),
kAttrStatModified, B_TIME_TYPE, 150, B_ALIGN_LEFT, false, true));
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Created"),
kAttrStatCreated, B_TIME_TYPE, 150, B_ALIGN_LEFT, false, true));
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Kind"),
kAttrMIMEType, B_MIME_STRING_TYPE, 145, B_ALIGN_LEFT, false, false));
if (IsTrash() || InTrash()) {
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Original name"),
kAttrOriginalPath, B_STRING_TYPE, 225, B_ALIGN_LEFT, false,
false));
} else {
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Location"), kAttrPath,
B_STRING_TYPE, 225, B_ALIGN_LEFT, false, false));
}
#ifdef OWNER_GROUP_ATTRIBUTES
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Owner"), kAttrStatOwner,
B_STRING_TYPE, 60, B_ALIGN_LEFT, false, true));
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Group"), kAttrStatGroup,
B_STRING_TYPE, 60, B_ALIGN_LEFT, false, true));
#endif
menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Permissions"),
kAttrStatMode, B_STRING_TYPE, 80, B_ALIGN_LEFT, false, true));
}
void
BContainerWindow::ShowAttributeMenu()
{
ASSERT(fAttrMenu);
fMenuBar->AddItem(fAttrMenu);
}
void
BContainerWindow::HideAttributeMenu()
{
ASSERT(fAttrMenu);
fMenuBar->RemoveItem(fAttrMenu);
}
void
BContainerWindow::MarkAttributeMenu()
{
MarkAttributeMenu(fAttrMenu);
}
void
BContainerWindow::MarkAttributeMenu(BMenu* menu)
{
if (!menu)
return;
int32 count = menu->CountItems();
for (int32 index = 0; index < count; index++) {
BMenuItem* item = menu->ItemAt(index);
int32 attrHash;
if (item->Message()) {
if (item->Message()->FindInt32("attr_hash", &attrHash) == B_OK)
item->SetMarked(PoseView()->ColumnFor((uint32)attrHash) != 0);
else
item->SetMarked(false);
}
BMenu* submenu = item->Submenu();
if (submenu) {
int32 count2 = submenu->CountItems();
for (int32 subindex = 0; subindex < count2; subindex++) {
item = submenu->ItemAt(subindex);
if (item->Message()) {
if (item->Message()->FindInt32("attr_hash", &attrHash)
== B_OK) {
item->SetMarked(PoseView()->ColumnFor((uint32)attrHash)
!= 0);
} else
item->SetMarked(false);
}
}
}
}
}
void
BContainerWindow::MarkArrangeByMenu(BMenu* menu)
{
if (!menu)
return;
int32 count = menu->CountItems();
for (int32 index = 0; index < count; index++) {
BMenuItem* item = menu->ItemAt(index);
if (item->Message()) {
uint32 attrHash;
if (item->Message()->FindInt32("attr_hash",
(int32*)&attrHash) == B_OK) {
item->SetMarked(PoseView()->PrimarySort() == attrHash);
} else if (item->Command() == kArrangeReverseOrder)
item->SetMarked(PoseView()->ReverseSort());
}
}
}
void
BContainerWindow::AddMimeTypesToMenu()
{
AddMimeTypesToMenu(fAttrMenu);
}
BMenu*
BContainerWindow::AddMimeMenu(const BMimeType& mimeType, bool isSuperType,
BMenu* menu, int32 start)
{
AutoLock<BLooper> _(menu->Looper());
if (!mimeType.IsValid())
return NULL;
for (int32 i = start; BMenuItem* item = menu->ItemAt(i); i++) {
BMessage* message = item->Message();
if (message == NULL)
continue;
const char* type;
if (message->FindString("mimetype", &type) == B_OK
&& !strcmp(mimeType.Type(), type)) {
return item->Submenu();
}
}
BMessage attrInfo;
char description[B_MIME_TYPE_LENGTH];
const char* label = mimeType.Type();
if (!mimeType.IsInstalled())
return NULL;
if (mimeType.GetAttrInfo(&attrInfo) != B_OK)
return NULL;
if (mimeType.GetShortDescription(description) == B_OK && description[0])
label = description;
BMenu* mimeMenu = NULL;
if (isSuperType) {
mimeMenu = new BMenu(label);
BFont font;
menu->GetFont(&font);
mimeMenu->SetFont(&font);
}
int32 index = -1;
const char* publicName;
while (attrInfo.FindString("attr:public_name", ++index, &publicName)
== B_OK) {
if (!attrInfo.FindBool("attr:viewable", index)) {
continue;
}
int32 type;
int32 align;
int32 width;
bool editable;
const char* attrName;
if (attrInfo.FindString("attr:name", index, &attrName) != B_OK
|| attrInfo.FindInt32("attr:type", index, &type) != B_OK
|| attrInfo.FindBool("attr:editable", index, &editable) != B_OK
|| attrInfo.FindInt32("attr:width", index, &width) != B_OK
|| attrInfo.FindInt32("attr:alignment", index, &align) != B_OK)
continue;
BString displayAs;
attrInfo.FindString("attr:display_as", index, &displayAs);
if (mimeMenu == NULL) {
mimeMenu = new BMenu(label);
BFont font;
menu->GetFont(&font);
mimeMenu->SetFont(&font);
}
mimeMenu->AddItem(NewAttributeMenuItem(publicName, attrName, type,
displayAs.String(), width, align, editable, false));
}
if (mimeMenu == NULL)
return NULL;
BMessage* message = new BMessage(kMIMETypeItem);
message->AddString("mimetype", mimeType.Type());
menu->AddItem(new IconMenuItem(mimeMenu, message, mimeType.Type()));
return mimeMenu;
}
void
BContainerWindow::AddMimeTypesToMenu(BMenu* menu)
{
if (!menu)
return;
int32 start = menu->CountItems();
while (start > 0 && menu->ItemAt(start - 1)->Submenu() != NULL) {
delete menu->RemoveItem(start - 1);
start--;
}
if (start > 0
&& dynamic_cast<BSeparatorItem*>(menu->ItemAt(start - 1)) == NULL)
menu->AddSeparatorItem();
BPath path;
if (TargetModel() != NULL) {
TargetModel()->GetPath(&path);
if (path.InitCheck() == B_OK
&& strstr(path.Path(), "/" kQueryTemplates "/") != NULL) {
BString name(TargetModel()->Name());
name.ReplaceFirst('_', '/');
PoseView()->AddMimeType(name.String());
}
}
int32 typeCount = PoseView()->CountMimeTypes();
for (int32 index = 0; index < typeCount; index++) {
BMimeType mimeType(PoseView()->MimeTypeAt(index));
if (mimeType.InitCheck() == B_OK) {
BMimeType superType;
mimeType.GetSupertype(&superType);
if (superType.InitCheck() == B_OK) {
BMenu* superMenu = AddMimeMenu(superType, true, menu, start);
if (superMenu != NULL) {
AddMimeMenu(mimeType, false, superMenu, 0);
}
}
}
}
for (int32 index = 0; index < typeCount; index++) {
BMimeType mimeType(PoseView()->MimeTypeAt(index));
BMimeType superType;
mimeType.GetSupertype(&superType);
BMenu* superMenu = AddMimeMenu(superType, true, menu, start);
if (superMenu == NULL)
continue;
int32 itemsFound = 0;
int32 menusFound = 0;
for (int32 i = 0; BMenuItem* item = superMenu->ItemAt(i); i++) {
if (item->Submenu() != NULL)
menusFound++;
else
itemsFound++;
}
if (itemsFound == 0) {
if (menusFound != 0) {
while (BMenuItem* item = superMenu->RemoveItem((int32)0)) {
menu->AddItem(item);
}
}
menu->RemoveItem(superMenu->Superitem());
delete superMenu->Superitem();
}
}
BMenuItem* item = menu->ItemAt(menu->CountItems() - 1);
if (dynamic_cast<BSeparatorItem*>(item) != NULL) {
menu->RemoveItem(item);
delete item;
}
MarkAttributeMenu(menu);
}
BHandler*
BContainerWindow::ResolveSpecifier(BMessage* message, int32 index,
BMessage* specifier, int32 form, const char* property)
{
if (strcmp(property, "Poses") == 0) {
message->PopSpecifier();
return PoseView();
}
return _inherited::ResolveSpecifier(message, index, specifier,
form, property);
}
PiggybackTaskLoop*
BContainerWindow::DelayedTaskLoop()
{
if (!fTaskLoop)
fTaskLoop = new PiggybackTaskLoop;
return fTaskLoop;
}
bool
BContainerWindow::NeedsDefaultStateSetup()
{
if (TargetModel() == NULL)
return false;
if (TargetModel()->IsRoot()) {
return false;
}
WindowStateNodeOpener opener(this, false);
if (opener.StreamNode() == NULL) {
return false;
}
return !NodeHasSavedState(opener.Node());
}
bool
BContainerWindow::DefaultStateSourceNode(const char* name, BNode* result,
bool createNew, bool createFolder)
{
BPath settingsPath;
if (FSFindTrackerSettingsDir(&settingsPath) != B_OK)
return false;
BDirectory dir(settingsPath.Path());
BPath path(settingsPath);
path.Append(name);
if (!BEntry(path.Path()).Exists()) {
if (!createNew)
return false;
BPath tmpPath(settingsPath);
for (;;) {
const char* nextSlash = strchr(name, '/');
if (!nextSlash)
break;
BString tmp;
tmp.SetTo(name, nextSlash - name);
tmpPath.Append(tmp.String());
mkdir(tmpPath.Path(), 0777);
name = nextSlash + 1;
if (!name[0]) {
return false;
}
}
if (createFolder) {
if (mkdir(path.Path(), 0777) < 0)
return false;
} else {
BFile file;
if (dir.CreateFile(name, &file) != B_OK)
return false;
}
}
result->SetTo(path.Path());
return result->InitCheck() == B_OK;
}
void
BContainerWindow::SetUpDefaultState()
{
BNode defaultingNode;
bool gotDefaultingNode = 0;
bool shouldStagger = false;
ASSERT(TargetModel() != NULL);
PRINT(("folder %s does not have any saved state\n", TargetModel()->Name()));
WindowStateNodeOpener opener(this, true);
if (opener.StreamNode() == NULL)
return;
if (!TargetModel()->IsRoot()) {
BDirectory deskDir;
FSGetDeskDir(&deskDir);
BEntry entry(TargetModel()->EntryRef());
BNode parent;
if (FSGetParentVirtualDirectoryAware(entry, parent) == B_OK
&& parent != deskDir) {
PRINT(("looking at parent for state\n"));
if (NodeHasSavedState(&parent)) {
PRINT(("got state from parent\n"));
defaultingNode = parent;
gotDefaultingNode = true;
shouldStagger = true;
}
}
}
if (!gotDefaultingNode
&& !DefaultStateSourceNode(kDefaultFolderTemplate, &defaultingNode,
true)) {
return;
}
if (fIsDesktop) {
return;
}
const char* allowAttrs[] = {
kAttrWindowFrame,
kAttrWindowWorkspace,
kAttrViewState,
kAttrViewStateForeign,
kAttrColumns,
kAttrColumnsForeign,
0
};
StaggerOneParams params;
params.rectFromParent = shouldStagger;
SelectiveAttributeTransformer frameOffsetter(kAttrWindowFrame,
OffsetFrameOne, ¶ms);
SelectiveAttributeTransformer scrollOriginCleaner(kAttrViewState,
ClearViewOriginOne, ¶ms);
AttributeStreamMemoryNode memoryNode;
NamesToAcceptAttrFilter filter(allowAttrs);
AttributeStreamFileNode fileNode(&defaultingNode);
*opener.StreamNode() << scrollOriginCleaner << frameOffsetter
<< memoryNode << filter << fileNode;
}
void
BContainerWindow::RestoreWindowState(AttributeStreamNode* node)
{
if (node == NULL || fIsDesktop) {
return;
}
const char* rectAttributeName;
const char* workspaceAttributeName;
if (TargetModel()->IsRoot()) {
rectAttributeName = kAttrDisksFrame;
workspaceAttributeName = kAttrDisksWorkspace;
} else {
rectAttributeName = kAttrWindowFrame;
workspaceAttributeName = kAttrWindowWorkspace;
}
BRect frame(Frame());
if (node->Read(rectAttributeName, 0, B_RECT_TYPE, sizeof(BRect), &frame)
== sizeof(BRect)) {
MoveTo(frame.LeftTop());
ResizeTo(frame.Width(), frame.Height());
} else
sNewWindRect.OffsetBy(kWindowStaggerBy, kWindowStaggerBy);
fPreviousBounds = Bounds();
uint32 workspace;
if (((fContainerWindowFlags & kRestoreWorkspace) != 0)
&& node->Read(workspaceAttributeName, 0, B_INT32_TYPE, sizeof(uint32),
&workspace) == sizeof(uint32))
SetWorkspaces(workspace);
if ((fContainerWindowFlags & kIsHidden) != 0)
Minimize(true);
int32 size = node->Contains(kAttrWindowDecor, B_RAW_TYPE);
if (size > 0) {
char buffer[size];
if (((fContainerWindowFlags & kRestoreDecor) != 0)
&& node->Read(kAttrWindowDecor, 0, B_RAW_TYPE, size, buffer)
== size) {
BMessage decorSettings;
if (decorSettings.Unflatten(buffer) == B_OK)
SetDecoratorSettings(decorSettings);
}
}
}
void
BContainerWindow::RestoreWindowState(const BMessage& message)
{
if (fIsDesktop) {
return;
}
const char* rectAttributeName;
const char* workspaceAttributeName;
if (TargetModel()->IsRoot()) {
rectAttributeName = kAttrDisksFrame;
workspaceAttributeName = kAttrDisksWorkspace;
} else {
rectAttributeName = kAttrWindowFrame;
workspaceAttributeName = kAttrWindowWorkspace;
}
BRect frame(Frame());
if (message.FindRect(rectAttributeName, &frame) == B_OK) {
MoveTo(frame.LeftTop());
ResizeTo(frame.Width(), frame.Height());
} else
sNewWindRect.OffsetBy(kWindowStaggerBy, kWindowStaggerBy);
uint32 workspace;
if ((fContainerWindowFlags & kRestoreWorkspace)
&& message.FindInt32(workspaceAttributeName,
(int32*)&workspace) == B_OK) {
SetWorkspaces(workspace);
}
if (fContainerWindowFlags & kIsHidden)
Minimize(true);
BMessage decorSettings;
if ((fContainerWindowFlags & kRestoreDecor)
&& message.FindMessage(kAttrWindowDecor, &decorSettings) == B_OK) {
SetDecoratorSettings(decorSettings);
}
}
void
BContainerWindow::SaveWindowState(AttributeStreamNode* node)
{
if (fIsDesktop) {
return;
}
ASSERT(node != NULL);
const char* rectAttributeName;
const char* workspaceAttributeName;
if (TargetModel() != NULL && TargetModel()->IsRoot()) {
rectAttributeName = kAttrDisksFrame;
workspaceAttributeName = kAttrDisksWorkspace;
} else {
rectAttributeName = kAttrWindowFrame;
workspaceAttributeName = kAttrWindowWorkspace;
}
BRect frame(Frame());
node->Write(rectAttributeName, 0, B_RECT_TYPE, sizeof(BRect), &frame);
uint32 workspaces = Workspaces();
node->Write(workspaceAttributeName, 0, B_INT32_TYPE, sizeof(uint32),
&workspaces);
BMessage decorSettings;
if (GetDecoratorSettings(&decorSettings) == B_OK) {
int32 size = decorSettings.FlattenedSize();
char buffer[size];
if (decorSettings.Flatten(buffer, size) == B_OK) {
node->Write(kAttrWindowDecor, 0, B_RAW_TYPE, size, buffer);
}
}
}
void
BContainerWindow::SaveWindowState(BMessage& message) const
{
const char* rectAttributeName;
const char* workspaceAttributeName;
if (TargetModel() != NULL && TargetModel()->IsRoot()) {
rectAttributeName = kAttrDisksFrame;
workspaceAttributeName = kAttrDisksWorkspace;
} else {
rectAttributeName = kAttrWindowFrame;
workspaceAttributeName = kAttrWindowWorkspace;
}
BRect frame(Frame());
message.AddRect(rectAttributeName, frame);
message.AddInt32(workspaceAttributeName, (int32)Workspaces());
BMessage decorSettings;
if (GetDecoratorSettings(&decorSettings) == B_OK) {
message.AddMessage(kAttrWindowDecor, &decorSettings);
}
}
status_t
BContainerWindow::DragStart(const BMessage* dragMessage)
{
if (dragMessage == NULL)
return B_ERROR;
if (Dragging()
&& SpringLoadedFolderCompareMessages(dragMessage, fDragMessage)) {
return B_OK;
}
SpringLoadedFolderCacheDragData(dragMessage, &fDragMessage,
&fCachedTypesList);
fWaitingForRefs = true;
return B_OK;
}
void
BContainerWindow::DragStop()
{
delete fDragMessage;
fDragMessage = NULL;
delete fCachedTypesList;
fCachedTypesList = NULL;
fWaitingForRefs = false;
}
void
BContainerWindow::ShowSelectionWindow()
{
if (fSelectionWindow == NULL) {
fSelectionWindow = new SelectionWindow(this);
fSelectionWindow->Show();
} else if (fSelectionWindow->Lock()) {
fSelectionWindow->MoveCloseToMouse();
if (fSelectionWindow->IsHidden())
fSelectionWindow->Show();
fSelectionWindow->Unlock();
}
}
void
BContainerWindow::ShowNavigator(bool show)
{
if (PoseView()->IsDesktopWindow() || !TargetModel()->IsDirectory()
|| fPoseView->IsFilePanel()) {
return;
}
if (show) {
if (Navigator() && !Navigator()->IsHidden())
return;
if (Navigator() == NULL) {
fNavigator = new BNavigator(TargetModel());
fPoseContainer->GridLayout()->AddView(fNavigator, 0, 0, 2);
}
if (Navigator()->IsHidden())
Navigator()->Show();
if (PoseView()->VScrollBar())
PoseView()->UpdateScrollRange();
} else {
if (!Navigator() || Navigator()->IsHidden())
return;
if (PoseView()->VScrollBar())
PoseView()->UpdateScrollRange();
fNavigator->Hide();
}
}
void
BContainerWindow::SetSingleWindowBrowseShortcuts(bool enabled)
{
if (PoseView()->IsDesktopWindow())
return;
if (enabled) {
if (!Navigator())
return;
RemoveShortcut(B_DOWN_ARROW, B_COMMAND_KEY | B_OPTION_KEY);
RemoveShortcut(B_UP_ARROW, B_COMMAND_KEY);
RemoveShortcut(B_UP_ARROW, B_COMMAND_KEY | B_OPTION_KEY);
AddShortcut(B_LEFT_ARROW, B_COMMAND_KEY,
new BMessage(kNavigatorCommandBackward), Navigator());
AddShortcut(B_RIGHT_ARROW, B_COMMAND_KEY,
new BMessage(kNavigatorCommandForward), Navigator());
AddShortcut(B_UP_ARROW, B_COMMAND_KEY,
new BMessage(kNavigatorCommandUp), Navigator());
AddShortcut(B_LEFT_ARROW, B_OPTION_KEY | B_COMMAND_KEY,
new BMessage(kNavigatorCommandBackward), Navigator());
AddShortcut(B_RIGHT_ARROW, B_OPTION_KEY | B_COMMAND_KEY,
new BMessage(kNavigatorCommandForward), Navigator());
AddShortcut(B_UP_ARROW, B_OPTION_KEY | B_COMMAND_KEY,
new BMessage(kNavigatorCommandUp), Navigator());
AddShortcut(B_DOWN_ARROW, B_OPTION_KEY | B_COMMAND_KEY,
new BMessage(kOpenSelection), PoseView());
AddShortcut('L', B_COMMAND_KEY,
new BMessage(kNavigatorCommandSetFocus), Navigator());
} else {
RemoveShortcut(B_LEFT_ARROW, B_COMMAND_KEY);
RemoveShortcut(B_RIGHT_ARROW, B_COMMAND_KEY);
RemoveShortcut(B_UP_ARROW, B_COMMAND_KEY);
RemoveShortcut(B_LEFT_ARROW, B_OPTION_KEY | B_COMMAND_KEY);
RemoveShortcut(B_RIGHT_ARROW, B_OPTION_KEY | B_COMMAND_KEY);
RemoveShortcut(B_UP_ARROW, B_OPTION_KEY | B_COMMAND_KEY);
RemoveShortcut(B_DOWN_ARROW, B_COMMAND_KEY | B_OPTION_KEY);
AddShortcut(B_DOWN_ARROW, B_COMMAND_KEY | B_OPTION_KEY,
new BMessage(kOpenSelection), PoseView());
AddShortcut(B_UP_ARROW, B_COMMAND_KEY,
new BMessage(kOpenParentDir), PoseView());
AddShortcut(B_UP_ARROW, B_COMMAND_KEY | B_OPTION_KEY,
new BMessage(kOpenParentDir), PoseView());
RemoveShortcut('L', B_COMMAND_KEY);
}
}
void
BContainerWindow::SetPathWatchingEnabled(bool enable)
{
if (IsPathWatchingEnabled()) {
stop_watching(this);
fIsWatchingPath = false;
}
if (enable) {
if (TargetModel() != NULL) {
BEntry entry;
TargetModel()->GetEntry(&entry);
status_t err;
do {
err = entry.GetParent(&entry);
if (err != B_OK)
break;
char name[B_FILE_NAME_LENGTH];
entry.GetName(name);
if (strcmp(name, "/") == 0)
break;
node_ref ref;
entry.GetNodeRef(&ref);
watch_node(&ref, B_WATCH_NAME, this);
} while (err == B_OK);
fIsWatchingPath = err == B_OK;
} else
fIsWatchingPath = false;
}
}
void
BContainerWindow::PulseTaskLoop()
{
if (fTaskLoop)
fTaskLoop->PulseMe();
}
void
BContainerWindow::PopulateArrangeByMenu(BMenu* menu)
{
if (!fAttrMenu || !menu)
return;
BMenuItem* item;
while ((item = menu->RemoveItem((int32)0)) != NULL)
delete item;
int32 itemCount = fAttrMenu->CountItems();
for (int32 i = 0; i < itemCount; i++) {
item = fAttrMenu->ItemAt(i);
if (item->Command() == kAttributeItem) {
BMessage* message = new BMessage(*(item->Message()));
message->what = kArrangeBy;
BMenuItem* newItem = new BMenuItem(item->Label(), message);
newItem->SetTarget(PoseView());
menu->AddItem(newItem);
}
}
menu->AddSeparatorItem();
item = new BMenuItem(B_TRANSLATE("Reverse order"),
new BMessage(kArrangeReverseOrder));
item->SetTarget(PoseView());
menu->AddItem(item);
menu->AddSeparatorItem();
item = new BMenuItem(B_TRANSLATE("Clean up"), new BMessage(kCleanup),
'K');
item->SetTarget(PoseView());
menu->AddItem(item);
}
WindowStateNodeOpener::WindowStateNodeOpener(BContainerWindow* window,
bool forWriting)
:
fModelOpener(NULL),
fNode(NULL),
fStreamNode(NULL)
{
if (window->TargetModel() && window->TargetModel()->IsRoot()) {
BDirectory dir;
if (FSGetDeskDir(&dir) == B_OK) {
fNode = new BDirectory(dir);
fStreamNode = new AttributeStreamFileNode(fNode);
}
} else if (window->TargetModel()){
fModelOpener = new ModelNodeLazyOpener(window->TargetModel(),
forWriting, false);
if (fModelOpener->IsOpen(forWriting)) {
fStreamNode = new AttributeStreamFileNode(
fModelOpener->TargetModel()->Node());
}
}
}
WindowStateNodeOpener::~WindowStateNodeOpener()
{
delete fModelOpener;
delete fNode;
delete fStreamNode;
}
void
WindowStateNodeOpener::SetTo(const BDirectory* node)
{
delete fModelOpener;
delete fNode;
delete fStreamNode;
fModelOpener = NULL;
fNode = new BDirectory(*node);
fStreamNode = new AttributeStreamFileNode(fNode);
}
void
WindowStateNodeOpener::SetTo(const BEntry* entry, bool forWriting)
{
delete fModelOpener;
delete fNode;
delete fStreamNode;
fModelOpener = NULL;
fNode = new BFile(entry, (uint32)(forWriting ? O_RDWR : O_RDONLY));
fStreamNode = new AttributeStreamFileNode(fNode);
}
void
WindowStateNodeOpener::SetTo(Model* model, bool forWriting)
{
delete fModelOpener;
delete fNode;
delete fStreamNode;
fNode = NULL;
fStreamNode = NULL;
fModelOpener = new ModelNodeLazyOpener(model, forWriting, false);
if (fModelOpener->IsOpen(forWriting)) {
fStreamNode = new AttributeStreamFileNode(
fModelOpener->TargetModel()->Node());
}
}
AttributeStreamNode*
WindowStateNodeOpener::StreamNode() const
{
return fStreamNode;
}
BNode*
WindowStateNodeOpener::Node() const
{
if (!fStreamNode)
return NULL;
if (fNode)
return fNode;
return fModelOpener->TargetModel()->Node();
}
BorderedView::BorderedView()
:
BGroupView(B_VERTICAL, 0),
fEnableBorderHighlight(true)
{
GroupLayout()->SetInsets(1);
}
void
BorderedView::WindowActivated(bool active)
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
if (window == NULL)
return;
if (window->PoseView()->IsFocus())
PoseViewFocused(active);
}
void BorderedView::EnableBorderHighlight(bool enable)
{
fEnableBorderHighlight = enable;
PoseViewFocused(false);
}
void
BorderedView::PoseViewFocused(bool focused)
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
if (window == NULL)
return;
color_which base = B_DOCUMENT_BACKGROUND_COLOR;
float tint = B_DARKEN_2_TINT;
if (focused && window->IsActive() && fEnableBorderHighlight) {
base = B_KEYBOARD_NAVIGATION_COLOR;
tint = B_NO_TINT;
}
BScrollBar* hScrollBar = window->PoseView()->HScrollBar();
if (hScrollBar != NULL)
hScrollBar->SetBorderHighlighted(focused);
BScrollBar* vScrollBar = window->PoseView()->VScrollBar();
if (vScrollBar != NULL)
vScrollBar->SetBorderHighlighted(focused);
SetViewUIColor(base, tint);
Invalidate();
}
void
BorderedView::Pulse()
{
BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
if (window != NULL)
window->PulseTaskLoop();
}