diff --git a/src/kits/tracker/Commands.h b/src/kits/tracker/Commands.h index 120d39f910..10a4d9934e 100644 --- a/src/kits/tracker/Commands.h +++ b/src/kits/tracker/Commands.h @@ -68,7 +68,7 @@ const uint32 kPasteLinksFromClipboard = 'Tplc'; const uint32 kCancelSelectionToClipboard = 'Tesc'; const uint32 kClipboardPosesChanged = 'Tcpc'; -const uint32 kEditItem = 'Tedt'; +const uint32 kEditName = 'Tedt'; const uint32 kEditQuery = 'Qedt'; const uint32 kNewFolder = 'Tnwf'; const uint32 kNewEntryFromTemplate = 'Tnwe'; diff --git a/src/kits/tracker/ContainerWindow.cpp b/src/kits/tracker/ContainerWindow.cpp index c549f2fcd6..5ee876870b 100644 --- a/src/kits/tracker/ContainerWindow.cpp +++ b/src/kits/tracker/ContainerWindow.cpp @@ -88,6 +88,7 @@ All rights reserved. #include "PoseView.h" #include "QueryContainerWindow.h" #include "SelectionWindow.h" +#include "Shortcuts.h" #include "TemplatesMenu.h" #include "Thread.h" #include "TitleView.h" @@ -178,8 +179,7 @@ AddOnMenuGenerate(const entry_ref* addOnRef, BMenu* menu, BContainerWindow* wind return addOnImage; void (*populateMenu)(BMessage*, BMenu*, BHandler*); - result = get_image_symbol(addOnImage, "populate_menu", 2, - (void**)&populateMenu); + result = get_image_symbol(addOnImage, "populate_menu", 2, (void**)&populateMenu); if (result < 0) { PRINT(("Couldn't find populate_menu\n")); unload_add_on(addOnImage); @@ -263,8 +263,7 @@ AddOneAddOn(const Model* model, const char* name, uint32 shortcut, ModelMenuItem* item; try { - item = new ModelMenuItem(model, name, message, - (char)shortcut, modifiers); + item = new ModelMenuItem(model, name, message, (char)shortcut, modifiers); } catch (...) { delete message; return; @@ -385,8 +384,9 @@ BContainerWindow::BContainerWindow(LockingList* list, uint32 openFlags, fBorderedView(NULL), fVScrollBarContainer(NULL), fCountContainer(NULL), + fShortcuts(NULL), fContextMenu(NULL), - fFileContextMenu(NULL), + fPoseContextMenu(NULL), fWindowContextMenu(NULL), fDropContextMenu(NULL), fVolumeContextMenu(NULL), @@ -396,7 +396,9 @@ BContainerWindow::BContainerWindow(LockingList* list, uint32 openFlags, fCopyToItem(NULL), fCreateLinkItem(NULL), fOpenWithItem(NULL), + fEditQueryItem(NULL), fNavigationItem(NULL), + fNewTemplatesItem(NULL), fMenuBar(NULL), fDraggableIcon(NULL), fNavigator(NULL), @@ -404,7 +406,7 @@ BContainerWindow::BContainerWindow(LockingList* list, uint32 openFlags, fAttrMenu(NULL), fWindowMenu(NULL), fFileMenu(NULL), - fArrangeByMenu(NULL), + fArrangeByItem(NULL), fSelectionWindow(NULL), fTaskLoop(NULL), fStateNeedsSaving(false), @@ -480,6 +482,7 @@ BContainerWindow::~BContainerWindow() delete fBackgroundImage; delete fDragMessage; delete fCachedTypesList; + delete fShortcuts; if (fSelectionWindow != NULL && fSelectionWindow->Lock()) fSelectionWindow->Quit(); @@ -539,58 +542,39 @@ BContainerWindow::QuitRequested() void BContainerWindow::Quit() { - // get rid of context menus - if (fNavigationItem) { - BMenu* menu = fNavigationItem->Menu(); - if (menu != NULL) - menu->RemoveItem(fNavigationItem); + // delete detached menus in reverse chronological order + // we're quitting, don't bother setting NULL - 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) { + if (fCreateLinkItem != NULL && fCreateLinkItem->Menu() == NULL) delete fCreateLinkItem; - fCreateLinkItem = NULL; - } + if (fCopyToItem != NULL && fCopyToItem->Menu() == NULL) + delete fCopyToItem; + if (fMoveToItem != NULL && fMoveToItem->Menu() == NULL) + delete fMoveToItem; - if (fAttrMenu != NULL && fAttrMenu->Supermenu() == NULL) { + if (fOpenWithItem != NULL && fOpenWithItem->Menu() == NULL) + delete fOpenWithItem; + if (fEditQueryItem != NULL && fEditQueryItem->Menu() == NULL) + delete fEditQueryItem; + + if (fNewTemplatesItem != NULL && fNewTemplatesItem->Menu() == NULL) + delete fNewTemplatesItem; + + if (fNavigationItem != NULL && fNavigationItem->Menu() == NULL) + delete fNavigationItem; + + if (fAttrMenu != NULL && fAttrMenu->Supermenu() == NULL) delete fAttrMenu; - fAttrMenu = NULL; - } - delete fFileContextMenu; - fFileContextMenu = NULL; + if (fArrangeByItem != NULL && fArrangeByItem->Menu() == NULL) + delete fArrangeByItem; + delete fPoseContextMenu; delete fWindowContextMenu; - fWindowContextMenu = NULL; - delete fDropContextMenu; - fDropContextMenu = NULL; - delete fVolumeContextMenu; - fVolumeContextMenu = NULL; - delete fDragContextMenu; - fDragContextMenu = NULL; - delete fTrashContextMenu; - fTrashContextMenu = NULL; int32 windowCount = 0; @@ -646,93 +630,89 @@ void BContainerWindow::AddContextMenus() { // create context sensitive menus - fFileContextMenu = new BPopUpMenu("FileContext", false, false); - AddFileContextMenus(fFileContextMenu); + fPoseContextMenu = new BPopUpMenu("PoseContext", false, false); + AddPoseContextMenu(fPoseContextMenu); fVolumeContextMenu = new BPopUpMenu("VolumeContext", false, false); - AddVolumeContextMenus(fVolumeContextMenu); + AddVolumeContextMenu(fVolumeContextMenu); fWindowContextMenu = new BPopUpMenu("WindowContext", false, false); - AddWindowContextMenus(fWindowContextMenu); + AddWindowContextMenu(fWindowContextMenu); fDropContextMenu = new BPopUpMenu("DropContext", false, false); - AddDropContextMenus(fDropContextMenu); + AddDropContextMenu(fDropContextMenu); fDragContextMenu = new BPopUpNavMenu("DragContext"); // will get added and built dynamically in ShowContextMenu fTrashContextMenu = new BPopUpMenu("TrashContext", false, false); - AddTrashContextMenus(fTrashContextMenu); + AddTrashContextMenu(fTrashContextMenu); +} + + +void +BContainerWindow::DetachSubmenus() +{ + // detach menus in reverse chronological order + if (fCreateLinkItem != NULL && fCreateLinkItem->Menu() != NULL) + fCreateLinkItem->Menu()->RemoveItem(fCreateLinkItem); + if (fCopyToItem != NULL && fCopyToItem->Menu() != NULL) + fCopyToItem->Menu()->RemoveItem(fCopyToItem); + if (fMoveToItem != NULL && fMoveToItem->Menu() != NULL) + fMoveToItem->Menu()->RemoveItem(fMoveToItem); + + if (fOpenWithItem != NULL && fOpenWithItem->Menu() != NULL) + fOpenWithItem->Menu()->RemoveItem(fOpenWithItem); + if (fEditQueryItem != NULL && fEditQueryItem->Menu() != NULL) + fEditQueryItem->Menu()->RemoveItem(fEditQueryItem); + + if (fNewTemplatesItem != NULL && fNewTemplatesItem->Menu() != NULL) + fNewTemplatesItem->Menu()->RemoveItem(fNewTemplatesItem); + + if (fNavigationItem != NULL && fNavigationItem->Menu() != NULL) { + // delete separator first + delete fNavigationItem->Menu()->RemoveItem( + fNavigationItem->Menu()->IndexOf(fNavigationItem) + 1); + fNavigationItem->Menu()->RemoveItem(fNavigationItem); + } } void BContainerWindow::RepopulateMenus() { - // Avoid these menus to be destroyed: - if (fMoveToItem != NULL && fMoveToItem->Menu() != NULL) - fMoveToItem->Menu()->RemoveItem(fMoveToItem); + DetachSubmenus(); - if (fCopyToItem != NULL && fCopyToItem->Menu() != NULL) - fCopyToItem->Menu()->RemoveItem(fCopyToItem); + if (fMenuBar != NULL) { + if (fFileMenu != NULL) { + fMenuBar->RemoveItem(fFileMenu); + delete fFileMenu; + } - if (fCreateLinkItem != NULL && fCreateLinkItem->Menu() != NULL) - fCreateLinkItem->Menu()->RemoveItem(fCreateLinkItem); + if (fWindowMenu != NULL) { + fMenuBar->RemoveItem(fWindowMenu); + delete fWindowMenu; + } - if (fOpenWithItem != NULL && fOpenWithItem->Menu() != NULL) { - fOpenWithItem->Menu()->RemoveItem(fOpenWithItem); - delete fOpenWithItem; - fOpenWithItem = NULL; - } + if (fAttrMenu != NULL) { + fMenuBar->RemoveItem(fAttrMenu); + delete fAttrMenu; + } - 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 (ShouldAddMenus()) { + AddMenus(); + if (PoseView()->ViewMode() == kListMode) + fMenuBar->AddItem(fAttrMenu); } } - delete fFileContextMenu; - fFileContextMenu = new BPopUpMenu("FileContext", false, false); - AddFileContextMenus(fFileContextMenu); + delete fPoseContextMenu; + fPoseContextMenu = new BPopUpMenu("PoseContext", false, false); + AddPoseContextMenu(fPoseContextMenu); delete fWindowContextMenu; fWindowContextMenu = new BPopUpMenu("WindowContext", false, false); - 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); - - // just create the attribute, decide to add it later - fMenuBar->RemoveItem(fAttrMenu); - delete fAttrMenu; - fAttrMenu = new BMenu(B_TRANSLATE("Attributes")); - NewAttributesMenu(fAttrMenu); - if (PoseView()->ViewMode() == kListMode) - ShowAttributesMenu(); - - PopulateArrangeByMenu(fArrangeByMenu); - - int32 selectCount = PoseView()->CountSelected(); - - SetupOpenWithMenu(fFileMenu); - SetupMoveCopyMenus(selectCount ? PoseView()->SelectionList() - ->FirstItem()->TargetModel()->EntryRef() : NULL, - fFileMenu); - } + AddWindowContextMenu(fWindowContextMenu); } @@ -750,12 +730,19 @@ BContainerWindow::Init(const BMessage* message) if (ShouldAddScrollBars()) PoseView()->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)); + fShortcuts = new TShortcuts(this); + + fEditQueryItem = Shortcuts()->EditQueryItem(); + + const char* name = Shortcuts()->MoveToLabel(); + fMoveToItem = Shortcuts()->MoveToItem(new BNavMenu(name, kMoveSelectionTo, this)); + name = Shortcuts()->CopyToLabel(); + fCopyToItem = Shortcuts()->CopyToItem(new BNavMenu(name, kCopySelectionTo, this)); + name = Shortcuts()->CreateLinkLabel(); + fCreateLinkItem = Shortcuts()->CreateLinkItem(new BNavMenu(name, kCreateLink, this)); + + name = Shortcuts()->NewTemplatesLabel(); + fNewTemplatesItem = Shortcuts()->NewTemplatesItem(new TemplatesMenu(PoseView(), name)); TrackerSettings settings; @@ -934,6 +921,89 @@ BContainerWindow::RestoreStateCommon() } +void +BContainerWindow::OpenParent() +{ + BEntry entry(TargetModel()->EntryRef()); + if (entry.InitCheck() != B_OK) + return; + + BEntry parentEntry; + if (FSGetParentVirtualDirectoryAware(entry, parentEntry) != B_OK) + return; + + entry_ref setToRef; + parentEntry.GetRef(&setToRef); + const entry_ref* parent = &setToRef; + + // need to send switch message for spatial mode + BMessage message(kSwitchDirectory); + message.AddRef("refs", parent); + MessageReceived(&message); +} + + +void +BContainerWindow::SwitchDirectory(const entry_ref* ref) +{ + BEntry entry; + if (entry.SetTo(ref, true) != B_OK || entry.InitCheck() != B_OK) + return; + + if (StateNeedsSaving()) + SaveState(false); + + bool wasInTrash = TargetModel()->IsTrash() || TargetModel()->InTrash(); + bool wasRoot = TargetModel()->IsRoot(); + bool wasVolume = TargetModel()->IsVolume(); + + // Switch dir and apply new state + WindowStateNodeOpener opener(this, false); + opener.SetTo(&entry, false); + + // Update pose view and set directory type + PoseView()->SwitchDir(ref, opener.StreamNode()); + + if (wasInTrash ^ (TargetModel()->IsTrash() || TargetModel()->InTrash()) + || wasRoot != TargetModel()->IsRoot() || wasVolume != TargetModel()->IsVolume()) { + RepopulateMenus(); + } + + // skip the rest on file panel + if (PoseView()->IsFilePanel()) + return; + + TrackerSettings settings; + if (settings.ShowNavigator() || settings.ShowFullPathInTitleBar()) + SetPathWatchingEnabled(true); + + SetSingleWindowBrowseShortcuts(settings.SingleWindowBrowse()); + + // Update draggable folder icon + if (fMenuBar != NULL) { + if (!TargetModel()->IsRoot() && !TargetModel()->IsTrash()) { + // Folder icon should be visible, but in single + // window navigation, it might not be. + if (fDraggableIcon != NULL) { + IconCache::sIconCache->IconChanged(TargetModel()); + if (fDraggableIcon->IsHidden()) + fDraggableIcon->Show(); + fDraggableIcon->Invalidate(); + } else { + // draggable icon visible + _AddFolderIcon(); + } + } else if (fDraggableIcon != NULL) { + // hide for Root or Trash + fDraggableIcon->Hide(); + } + } + + // Update window title + UpdateTitle(); +} + + void BContainerWindow::UpdateTitle() { @@ -963,16 +1033,16 @@ BContainerWindow::UpdateBackgroundImage() if (!TargetModel()->IsRoot() && opener.Node() != NULL) { fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage, opener.Node(), - PoseView()->IsDesktop(), PoseView()); + TargetModel()->IsDesktop(), PoseView()); } // look for background image info in the window's node BNode defaultingNode; - if (!fBackgroundImage && !PoseView()->IsDesktop() + if (!fBackgroundImage && !TargetModel()->IsDesktop() && DefaultStateSourceNode(kDefaultFolderTemplate, &defaultingNode)) { // look for background image info in the source for defaults fBackgroundImage = BackgroundImage::Refresh(fBackgroundImage, &defaultingNode, - PoseView()->IsDesktop(), PoseView()); + TargetModel()->IsDesktop(), PoseView()); } } @@ -980,7 +1050,7 @@ BContainerWindow::UpdateBackgroundImage() void BContainerWindow::FrameResized(float, float) { - if (PoseView() != NULL && !PoseView()->IsDesktop()) { + if (PoseView() != NULL && !TargetModel()->IsDesktop()) { BRect extent = PoseView()->Extent(); float offsetX = extent.left - PoseView()->Bounds().left; float offsetY = extent.top - PoseView()->Bounds().top; @@ -1322,7 +1392,7 @@ BContainerWindow::MessageReceived(BMessage* message) } case kOpenParentDir: - PostMessage(message, PoseView()); + OpenParent(); break; case kNewFolder: @@ -1438,95 +1508,53 @@ BContainerWindow::MessageReceived(BMessage* message) if (message->FindRef("refs", &ref) != B_OK) break; - BEntry entry; - if (entry.SetTo(&ref) != B_OK) - break; + if (!PoseView()->IsFilePanel() && !TrackerSettings().SingleWindowBrowse()) { + message->what = B_REFS_RECEIVED; + const node_ref* nodeRef = TargetModel()->NodeRef(); - if (StateNeedsSaving()) - SaveState(false); + // add information about the child, so that we can select it in the parent view + message->AddData("nodeRefToSelect", B_RAW_TYPE, nodeRef, sizeof(node_ref)); - bool wasInTrash = TargetModel()->IsTrash() || TargetModel()->InTrash(); - bool wasRoot = TargetModel()->IsRoot(); - bool wasVolume = TargetModel()->IsVolume(); + if ((modifiers() & B_OPTION_KEY) != 0) { + // if option down, add instructions to close the parent + message->AddData("nodeRefsToClose", B_RAW_TYPE, nodeRef, sizeof(node_ref)); + } - // Switch dir and apply new state - WindowStateNodeOpener opener(this, false); - opener.SetTo(&entry, false); + be_app->PostMessage(message); + } else { + SwitchDirectory(&ref); - // Update pose view and set directory type - PoseView()->SwitchDir(&ref, opener.StreamNode()); - - if (wasInTrash ^ (TargetModel()->IsTrash() || TargetModel()->InTrash()) - || wasRoot != TargetModel()->IsRoot() || wasVolume != TargetModel()->IsVolume()) { - RepopulateMenus(); - } - - // skip the rest for file panel - if (PoseView()->IsFilePanel()) - break; - - if (Navigator() != NULL) { - // update Navigation bar - int32 action = message->GetInt32("action", kActionSet); - Navigator()->UpdateLocation(TargetModel(), action); - } - - TrackerSettings settings; - if (settings.ShowNavigator() || settings.ShowFullPathInTitleBar()) - SetPathWatchingEnabled(true); - - SetSingleWindowBrowseShortcuts(settings.SingleWindowBrowse()); - - // Update draggable folder icon - if (fMenuBar != NULL) { - if (!TargetModel()->IsRoot() && !TargetModel()->IsTrash()) { - // Folder icon should be visible, but in single - // window navigation, it might not be. - if (fDraggableIcon != NULL) { - IconCache::sIconCache->IconChanged(TargetModel()); - if (fDraggableIcon->IsHidden()) - fDraggableIcon->Show(); - fDraggableIcon->Invalidate(); - } else { - // draggable icon visible - _AddFolderIcon(); - } - } else if (fDraggableIcon != NULL) { - // hide for Root or Trash - fDraggableIcon->Hide(); + if (Navigator() != NULL) { + // update Navigation bar + int32 action = message->GetInt32("action", kActionSet); + Navigator()->UpdateLocation(TargetModel(), action); } } - - // Update window title - UpdateTitle(); break; } case B_REFS_RECEIVED: - if (Dragging()) { - // ref in this message is the target, - // the end point of the drag + { + if (!Dragging()) + break; - entry_ref ref; - if (message->FindRef("refs", &ref) == B_OK) { - fWaitingForRefs = false; - BEntry entry(&ref, true); - // don't copy to printers dir - 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); - } - } + // ref in this message is the target, the end point of the drag + entry_ref ref; + if (message->FindRef("refs", &ref) == B_OK) { + fWaitingForRefs = false; + BEntry entry(&ref, true); + // don't copy to printers dir + if (entry.InitCheck() == B_OK && entry.IsDirectory() && !FSIsPrintersDir(&entry)) { + Model target(&entry, true, false); + BPoint where; + uint32 buttons; + PoseView()->GetMouse(&where, &buttons, true); + PoseView()->HandleDropCommon(fDragMessage, &target, NULL, PoseView(), where); } - DragStop(); } + DragStop(); break; + } case B_TRACKER_ADDON_MESSAGE: { @@ -1643,147 +1671,6 @@ BContainerWindow::MessageReceived(BMessage* message) } -void -BContainerWindow::SetCutItem(BMenu* menu) -{ - BMenuItem* item; - if ((item = menu->FindItem(B_CUT)) == NULL - && (item = menu->FindItem(kCutMoreSelectionToClipboard)) == NULL) { - return; - } - - if (PoseView() != CurrentFocus()) - item->SetEnabled(dynamic_cast(CurrentFocus()) != NULL); - else { - if (TargetModel()->IsRoot() || TargetModel()->IsTrash() - || TargetModel()->IsVirtualDirectory()) { - // cannot cut files in root, trash or in a virtual directory - item->SetEnabled(false); - } else { - item->SetEnabled(PoseView()->CountSelected() > 0 - && !PoseView()->SelectedVolumeIsReadOnly()); - } - } - - if ((modifiers() & B_SHIFT_KEY) != 0) { - 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; - } - - if (PoseView() != CurrentFocus()) - item->SetEnabled(dynamic_cast(CurrentFocus()) != NULL); - else - item->SetEnabled(PoseView()->CountSelected() > 0); - - if ((modifiers() & B_SHIFT_KEY) != 0) { - 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; - } - - if (PoseView() != CurrentFocus()) - item->SetEnabled(dynamic_cast(CurrentFocus()) != NULL); - else { - item->SetEnabled(FSClipboardHasRefs() - && !PoseView()->TargetVolumeIsReadOnly()); - } - - if ((modifiers() & B_SHIFT_KEY) != 0) { - 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) != 0) { - 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) != 0) { - 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 { @@ -1804,145 +1691,133 @@ BContainerWindow::AddMenus() fFileMenu = new BMenu(B_TRANSLATE("File")); AddFileMenu(fFileMenu); fMenuBar->AddItem(fFileMenu); + fWindowMenu = new BMenu(B_TRANSLATE("Window")); fMenuBar->AddItem(fWindowMenu); AddWindowMenu(fWindowMenu); - // just create the attribute, decide to add it later + + // create Attributes menu, add it later fAttrMenu = new BMenu(B_TRANSLATE("Attributes")); NewAttributesMenu(fAttrMenu); - PopulateArrangeByMenu(fArrangeByMenu); + + // create "Arrange By >" menu, add it later + fArrangeByItem = NewArrangeByMenu(); } void BContainerWindow::AddFileMenu(BMenu* menu) { - BMenuItem* item; - - if (!PoseView()->IsFilePanel()) { - menu->AddItem(new BMenuItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS), - new BMessage(kFindButton), 'F')); + if (TargetModel()->IsTrash()) { + // add as first item in menu + menu->AddItem(Shortcuts()->EmptyTrashItem()); + menu->AddItem(new BSeparatorItem()); + } else if (TargetModel()->IsPrintersDir()) { + // add as first item in menu + menu->AddItem(Shortcuts()->AddPrinterItem()); + menu->AddItem(new BSeparatorItem()); } - if (!TargetModel()->IsQuery() && !TargetModel()->IsVirtualDirectory() - && !TargetModel()->IsTrash() && !TargetModel()->IsPrintersDir() - && !TargetModel()->IsRoot()) { - if (!PoseView()->IsFilePanel()) { - TemplatesMenu* templatesMenu = new TemplatesMenu(PoseView(), - B_TRANSLATE("New")); - menu->AddItem(templatesMenu); - templatesMenu->SetTargetForItems(PoseView()); - } else { - item = new BMenuItem(B_TRANSLATE("New folder"), - new BMessage(kNewFolder), 'N'); - menu->AddItem(item); - } - } + menu->AddItem(Shortcuts()->FindItem()); + if (ShouldHaveNewFolderItem()) + menu->AddItem(Shortcuts()->NewFolderItem()); 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')); + menu->AddItem(Shortcuts()->OpenItem()); + // "Edit query" and "Open with..." inserted here, + // see UpdateMenu(), SetupEditQueryItem() and SetupOpenWithMenu() + menu->AddItem(Shortcuts()->GetInfoItem()); + menu->AddItem(Shortcuts()->EditNameItem()); + + if (TargetModel()->IsPrintersDir()) { + menu->AddItem(Shortcuts()->MakeActivePrinterItem()); + return; // we're done with printers directory + } + + if (TargetModel()->IsRoot()) { + menu->AddItem(Shortcuts()->UnmountItem()); + menu->AddItem(new BMenuItem(B_TRANSLATE("Mount settings" B_UTF8_ELLIPSIS), + new BMessage(kRunAutomounterSettings))); + } if (TargetModel()->IsTrash() || TargetModel()->InTrash()) { - menu->AddItem(new BMenuItem(B_TRANSLATE("Restore"), - new BMessage(kRestoreFromTrash))); - if (TargetModel()->IsTrash()) { - // add as first item in menu - menu->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"), - new BMessage(kEmptyTrash)), 0); - menu->AddItem(new BSeparatorItem(), 1); - } - } else if (TargetModel()->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()) { - 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))); + menu->AddItem(Shortcuts()->DeleteItem()); + menu->AddItem(Shortcuts()->RestoreItem()); } else { - item = new BMenuItem(B_TRANSLATE("Duplicate"), - new BMessage(kDuplicateSelection), 'D'); - item->SetEnabled(PoseView()->CanMoveToTrashOrDuplicate()); - menu->AddItem(item); - - item = new BMenuItem(B_TRANSLATE("Move to Trash"), - new BMessage(kMoveSelectionToTrash), 'T'); - item->SetEnabled(PoseView()->CanMoveToTrashOrDuplicate()); - menu->AddItem(item); - - menu->AddSeparatorItem(); - - // The "Move To", "Copy To", "Create Link" menus are inserted - // at this place, have a look at: - // BContainerWindow::SetupMoveCopyMenus() + menu->AddItem(Shortcuts()->DuplicateItem()); + menu->AddItem(Shortcuts()->MoveToTrashItem()); } - BMenuItem* cutItem = NULL; - BMenuItem* copyItem = NULL; - BMenuItem* pasteItem = NULL; - if (!TargetModel()->IsPrintersDir()) { + menu->AddSeparatorItem(); + + // The "Move To", "Copy To", "Create Link" menus are inserted here, + // have a look at UpdateMenu() and SetupMoveCopyMenus(). + + if (!TargetModel()->IsRoot() && !TargetModel()->IsTrash() && !TargetModel()->InTrash()) { + menu->AddItem(Shortcuts()->CutItem()); + menu->AddItem(Shortcuts()->CopyItem()); + menu->AddItem(Shortcuts()->PasteItem()); 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")); - menu->AddItem(addOnMenuItem); } - menu->SetTargetForItems(PoseView()); - if (cutItem != NULL) - cutItem->SetTarget(this); - - if (copyItem != NULL) - copyItem->SetTarget(this); - - if (pasteItem != NULL) - pasteItem->SetTarget(this); + if (!TargetModel()->IsRoot()) + menu->AddItem(Shortcuts()->IdentifyItem()); + menu->AddItem(new BMenuItem(new BMenu(Shortcuts()->AddOnsLabel()))); } void BContainerWindow::AddWindowMenu(BMenu* menu) { + AddIconSizeMenu(menu); + + BMenuItem* item = new BMenuItem(B_TRANSLATE("List view"), new BMessage(kListMode), '3'); + item->SetTarget(PoseView()); + menu->AddItem(item); + menu->AddSeparatorItem(); + + menu->AddItem(Shortcuts()->ResizeToFitItem()); + // "Arrange by >" menu inserted here, + // see UpdateMenu() and SetupArrangeByMenu() + menu->AddItem(Shortcuts()->SelectItem()); + menu->AddItem(Shortcuts()->SelectAllItem()); + menu->AddItem(Shortcuts()->InvertSelectionItem()); + if (!TargetModel()->IsTrash()) + menu->AddItem(Shortcuts()->OpenParentItem()); + menu->AddItem(Shortcuts()->CloseItem()); + menu->AddItem(Shortcuts()->CloseAllInWorkspaceItem()); + menu->AddSeparatorItem(); + + item = new BMenuItem("Preferences" B_UTF8_ELLIPSIS, new BMessage(kShowSettingsWindow), ','); + item->SetTarget(be_app); + menu->AddItem(item); +} + + +void +BContainerWindow::AddIconSizeMenu(BMenu* menu) +{ + if (menu == NULL) + return; + BMenuItem* item; - - BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view")); - - static const uint32 kIconSizes[] = { 32, 40, 48, 64, 96, 128 }; BMessage* message; + BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view")); + iconSizeMenu->SetRadioMode(true); + + static const uint32 kIconSizes[] = { 32, 40, 48, 64, 96, 128 }; + + BString label; + const char* format; + const char* comment = "The '×' is the Unicode multiplication sign U+00D7"; + uint32 iconSize; for (uint32 i = 0; i < sizeof(kIconSizes) / sizeof(uint32); ++i) { - uint32 iconSize = kIconSizes[i]; + iconSize = kIconSizes[i]; message = new BMessage(kIconMode); message->AddInt32("size", iconSize); - BString label; - label.SetToFormat(B_TRANSLATE_COMMENT("%" B_PRId32" × %" B_PRId32, - "The '×' is the Unicode multiplication sign U+00D7"), - iconSize, iconSize); + format = B_TRANSLATE_COMMENT("%" B_PRId32 " × %" B_PRId32, comment); + label.SetToFormat(format, iconSize, iconSize); item = new BMenuItem(label, message); item->SetTarget(PoseView()); iconSizeMenu->AddItem(item); @@ -1964,67 +1839,15 @@ BContainerWindow::AddWindowMenu(BMenu* menu) // A sub menu where the super item can be invoked. 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); - - item = new BMenuItem(B_TRANSLATE("List view"), - new BMessage(kListMode), '3'); - item->SetTarget(PoseView()); - menu->AddItem(item); - - 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(this); - menu->AddItem(item); - - item = new BMenuItem(B_TRANSLATE("Invert selection"), - new BMessage(kInvertSelection), 'S'); - item->SetTarget(PoseView()); - menu->AddItem(item); - - if (!TargetModel()->IsTrash()) { - item = new BMenuItem(B_TRANSLATE("Open parent"), - new BMessage(kOpenParentDir), B_UP_ARROW); - item->SetTarget(PoseView()); - menu->AddItem(item); + BMenuItem* iconSizeSuperItem = iconSizeMenu->Superitem(); + if (iconSizeSuperItem != NULL) { + iconSizeSuperItem->SetShortcut('1', B_COMMAND_KEY); + iconSizeSuperItem->SetMessage(new BMessage(kIconMode)); + iconSizeSuperItem->SetTarget(PoseView()); } - 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); + item = new BMenuItem(B_TRANSLATE("Mini icon view"), new BMessage(kMiniIconMode), '2'); + item->SetTarget(PoseView()); menu->AddItem(item); } @@ -2042,38 +1865,23 @@ BContainerWindow::AddShortcuts() 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(kMoveSelectionToTrash), 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('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(kEditName), PoseView()); + AddShortcut('D', B_COMMAND_KEY, new BMessage(kDuplicateSelection), PoseView()); + AddShortcut('T', B_COMMAND_KEY, new BMessage(kMoveSelectionToTrash), 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()); // it is ok to add a global Edit query shortcut here, PoseView will // filter out cases where selected pose is not a query - 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()); + 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); @@ -2097,42 +1905,11 @@ BContainerWindow::MenusBeginning() PoseView()->CommitActivePose(); } - // File menu - int32 selectCount = PoseView()->SelectionList()->CountItems(); + if (fFileMenu != NULL) + UpdateMenu(fFileMenu, kFileMenuContext); - SetupOpenWithMenu(fFileMenu); - SetupMoveCopyMenus(selectCount - ? PoseView()->SelectionList()->FirstItem()->TargetModel()->EntryRef() - : NULL, fFileMenu); - - if (TargetModel()->IsRoot()) { - BVolume boot; - BVolumeRoster().GetBootVolume(&boot); - - bool ejectableVolumeSelected = false; - for (int32 index = 0; index < selectCount; 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 (TargetModel()->IsPrintersDir()) - EnableNamedMenuItem(fFileMenu, kMakeActivePrinter, selectCount == 1); + if (fWindowMenu != NULL) + UpdateMenu(fWindowMenu, kWindowMenuContext); } @@ -2140,32 +1917,35 @@ void BContainerWindow::MenusEnded() { // when we're done we want to clear nav menus for next time - DeleteSubmenu(fNavigationItem); - DeleteSubmenu(fMoveToItem); - DeleteSubmenu(fCopyToItem); DeleteSubmenu(fCreateLinkItem); + DeleteSubmenu(fCopyToItem); + DeleteSubmenu(fMoveToItem); DeleteSubmenu(fOpenWithItem); + DeleteSubmenu(fNavigationItem); } void -BContainerWindow::SetupNavigationMenu(const entry_ref* ref, BMenu* parent) +BContainerWindow::SetupNavigationMenu(BMenu* parent, const entry_ref* ref) { + ASSERT(parent); + // start by removing nav item (and separator) from old menu - 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 (fNavigationItem != NULL && fNavigationItem->Menu() != NULL) { + // delete separator first + delete fNavigationItem->Menu()->RemoveItem( + fNavigationItem->Menu()->IndexOf(fNavigationItem) + 1); + fNavigationItem->Menu()->RemoveItem(fNavigationItem); } // if we weren't passed a ref then we're navigating this window if (ref == NULL) ref = TargetModel()->EntryRef(); + // bail out if we shouldn't have a navigation item + if (!ShouldHaveNavigationMenu(ref)) + return; + BEntry entry; if (entry.SetTo(ref) != B_OK) return; @@ -2191,10 +1971,10 @@ BContainerWindow::SetupNavigationMenu(const entry_ref* ref, BMenu* parent) ref = &resolvedRef; } - if (fNavigationItem == NULL) { - fNavigationItem = new ModelMenuItem(&model, - new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, this)); - } + // always build a fresh navigation menu + delete fNavigationItem; + fNavigationItem + = new ModelMenuItem(&model, new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, this)); // setup a navigation menu item which will dynamically load items // as menu items are traversed @@ -2217,106 +1997,153 @@ BContainerWindow::SetupNavigationMenu(const entry_ref* ref, BMenu* parent) void -BContainerWindow::SetupEditQueryItem(BMenu* menu) +BContainerWindow::SetupEditQueryItem(BMenu* parent) { - ASSERT(menu); - // File menu - int32 selectCount = PoseView()->CountSelected(); + SetupEditQueryItem(parent, TargetModel()->EntryRef()); +} - // add Edit query if appropriate - bool queryInSelection = false; - if (selectCount && selectCount < 100) { - // only do this for a limited number of selected poses - // if any queries selected, add an edit query menu item - 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; +void +BContainerWindow::SetupEditQueryItem(BMenu* parent, const entry_ref* ref) +{ + ASSERT(parent); - if (model.IsQuery() || model.IsQueryTemplate()) { - queryInSelection = true; - break; - } - } - } + // start by removing "Edit query" from old menu + if (fEditQueryItem != NULL && fEditQueryItem->Menu() != NULL) + fEditQueryItem->Menu()->RemoveItem(fEditQueryItem); - bool poseViewIsQuery = TargetModel()->IsQuery(); - // if the view is a query pose view, add edit query menu item + // if ref unset assume window ref + if (ref == NULL) + ref = TargetModel()->EntryRef(); - BMenuItem* item = menu->FindItem(kEditQuery); - if (!poseViewIsQuery && !queryInSelection && item != NULL) - item->Menu()->RemoveItem(item); - else if ((poseViewIsQuery || queryInSelection) && item == NULL) { - // add edit query item after Open - 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()); - } - } + ASSERT(ref); + + // bail out if "Open" item or index not found + BMenuItem* openItem = parent->FindItem(kOpenSelection); + int32 openIndex = parent->IndexOf(openItem); + if (openItem == NULL || openIndex == B_ERROR) + return; + + // add "Edit query" item between "Open" and "Open with..." + parent->AddItem(fEditQueryItem, openIndex + 1); + + Shortcuts()->UpdateEditQueryItem(fEditQueryItem); } void BContainerWindow::SetupOpenWithMenu(BMenu* parent) { - // start by removing nav item (and separator) from old menu - if (fOpenWithItem) { - BMenu* menu = fOpenWithItem->Menu(); - if (menu != NULL) - menu->RemoveItem(fOpenWithItem); + SetupOpenWithMenu(parent, TargetModel()->EntryRef()); +} - delete fOpenWithItem; - fOpenWithItem = 0; - } - int32 selectCount = PoseView()->CountSelected(); - if (selectCount <= 0) { - // no selection, nothing to open - return; - } +void +BContainerWindow::SetupOpenWithMenu(BMenu* parent, const entry_ref* ref) +{ + ASSERT(parent); - if (TargetModel()->IsRoot()) { - // don't add ourselves if we are root - return; - } + // start by removing "Open with..." item from old menu + if (fOpenWithItem != NULL && fOpenWithItem->Menu() != NULL) + fOpenWithItem->Menu()->RemoveItem(fOpenWithItem); // ToDo: // check if only item in selection list is the root // and do not add if true - // add after "Open" - BMenuItem* item = parent->FindItem(kOpenSelection); + // if ref unset assume window ref + if (ref == NULL) + ref = TargetModel()->EntryRef(); + + ASSERT(ref); + + // bail out if we shouldn't have an "Open with..." parent + if (!ShouldHaveOpenWithMenu(ref)) + return; + + // bail out if "Open" item not found + BMenuItem* openItem = parent->FindItem(kOpenSelection); + if (openItem == NULL) + return; + + // bail out if index of "Open" item not found + int32 openIndex = parent->IndexOf(openItem); + if (openIndex == B_ERROR) + return; // build a list of all refs to open BMessage message(B_REFS_RECEIVED); + BPose* pose; + int32 selectCount = PoseView()->CountSelected(); for (int32 index = 0; index < selectCount; index++) { - BPose* pose = PoseView()->SelectionList()->ItemAt(index); + pose = PoseView()->SelectionList()->ItemAt(index); message.AddRef("refs", pose->TargetModel()->EntryRef()); } // add Tracker token so that refs received recipients can script us 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); + // always build a fresh "Open with..." menu + delete fOpenWithItem; + fOpenWithItem = Shortcuts()->OpenWithItem( + new OpenWithMenu(Shortcuts()->OpenWithLabel(), &message, this, be_app)); - item->Menu()->AddItem(fOpenWithItem, index + 1); + parent->AddItem(fOpenWithItem, openIndex + 1); + Shortcuts()->UpdateOpenWithItem(fOpenWithItem); } void -BContainerWindow::PopulateMoveCopyNavMenu(BNavMenu* navMenu, uint32 what, - const entry_ref* ref, bool addLocalOnly) +BContainerWindow::SetupNewTemplatesMenu(BMenu* parent, MenuContext context) +{ + ASSERT(parent); + + // start by removing "New >" item from the old menu + if (fNewTemplatesItem != NULL && fNewTemplatesItem->Menu() != NULL) + fNewTemplatesItem->Menu()->RemoveItem(fNewTemplatesItem); + + // no "New folder" item or menu for this window type, bail + if (!ShouldHaveNewFolderItem()) + return; + + // file panel does not have a menu, only "New folder" + BMenuItem* newFolderItem = parent->FindItem(kNewFolder); + if (PoseView()->IsFilePanel()) + return Shortcuts()->UpdateNewFolderItem(newFolderItem); + + // we should have a "New >" menu at this point + TemplatesMenu* newTemplatesMenu = (TemplatesMenu*)fNewTemplatesItem->Submenu(); + ASSERT(newTemplatesMenu); + + // update templates menu state + newTemplatesMenu->UpdateMenuState(); + + // no templates found, update "New folder" instead, bail + if (newTemplatesMenu->CountTemplates() == 0) + return Shortcuts()->UpdateNewFolderItem(newFolderItem); + + int32 newFolderIndex = parent->IndexOf(newFolderItem); + if (newFolderItem != NULL && newFolderIndex != B_ERROR) { + // replace "New folder" with "New >" menu + parent->RemoveItem(newFolderItem); + parent->AddItem(fNewTemplatesItem, newFolderIndex); + delete newFolderItem; + } else { + // we already have a "New >" menu + if (context == kWindowPopUpContext) + parent->AddItem(fNewTemplatesItem, 2); + else if (context == kFileMenuContext) + parent->AddItem(fNewTemplatesItem, 1); + } + + // update "New >" menu status + Shortcuts()->UpdateNewTemplatesItem(fNewTemplatesItem); +} + + +void +BContainerWindow::PopulateMoveCopyNavMenu(BNavMenu* navMenu, uint32 what, const entry_ref* ref, + bool addLocalOnly) { BVolume volume; BVolumeRoster volumeRoster; @@ -2419,102 +2246,79 @@ BContainerWindow::PopulateMoveCopyNavMenu(BNavMenu* navMenu, uint32 what, void -BContainerWindow::SetupMoveCopyMenus(const entry_ref* item_ref, BMenu* parent) +BContainerWindow::SetupMoveCopyMenus(BMenu* parent, const entry_ref* ref) { - if (TargetModel()->IsTrash() || TargetModel()->InTrash() || TargetModel()->IsPrintersDir() - || fMoveToItem == NULL || fCopyToItem == NULL || fCreateLinkItem == NULL - || TargetModel()->IsRoot()) { + // bail out if items are not setup yet, this should never happen + if (fMoveToItem == NULL || fCopyToItem == NULL || fCreateLinkItem == NULL) return; + + // start off by removing the items from the old menu + if (fMoveToItem->Menu() != NULL) + fMoveToItem->Menu()->RemoveItem(fMoveToItem); + if (fCopyToItem->Menu() != NULL) + fCopyToItem->Menu()->RemoveItem(fCopyToItem); + if (fCreateLinkItem->Menu() != NULL) { + // remove and delete separator first + delete fCreateLinkItem->Menu()->RemoveItem( + fCreateLinkItem->Menu()->IndexOf(fCreateLinkItem) + 1); + fCreateLinkItem->Menu()->RemoveItem(fCreateLinkItem); } + // if ref unset assume window ref + if (ref == NULL) + ref = TargetModel()->EntryRef(); + + // bail out if we shouldn't have "Move to/Copy to/Create Link" menus + if (!ShouldHaveMoveCopyMenus(ref)) + return; + + // bail out if "Move to Trash" or "Delete" item not found + BMenuItem* moveToTrashItem + = Shortcuts()->FindItem(parent, kMoveSelectionToTrash, kDeleteSelection); + int32 index = parent->IndexOf(moveToTrashItem); + if (moveToTrashItem == NULL || index == B_ERROR) + return; + + // skip past "Move to Trash" and separator + index += 2; + // re-parent items to this menu since they're shared - BMenuItem* trash = parent->FindItem(kMoveSelectionToTrash); - int32 index = trash != NULL ? parent->IndexOf(trash) + 2 : 0; - - if (fMoveToItem->Menu() != parent) { - if (fMoveToItem->Menu() != NULL) - fMoveToItem->Menu()->RemoveItem(fMoveToItem); - - parent->AddItem(fMoveToItem, index++); - } - - if (fCopyToItem->Menu() != parent) { - if (fCopyToItem->Menu() != NULL) - fCopyToItem->Menu()->RemoveItem(fCopyToItem); - - parent->AddItem(fCopyToItem, index++); - } - - if (fCreateLinkItem->Menu() != parent) { - if (fCreateLinkItem->Menu() != NULL) - fCreateLinkItem->Menu()->RemoveItem(fCreateLinkItem); - - parent->AddItem(fCreateLinkItem, index); - } + parent->AddItem(fMoveToItem, index++); + parent->AddItem(fCopyToItem, index++); + parent->AddItem(fCreateLinkItem, index++); + parent->AddItem(new BSeparatorItem(), index); // Set the "Create Link" item label here so it // appears correctly when menus are disabled, too. - if ((modifiers() & B_SHIFT_KEY) != 0) - fCreateLinkItem->SetLabel(B_TRANSLATE("Create relative link")); - else - fCreateLinkItem->SetLabel(B_TRANSLATE("Create link")); + Shortcuts()->UpdateCreateLinkItem(fCreateLinkItem); // only enable once the menus are built fMoveToItem->SetEnabled(false); fCopyToItem->SetEnabled(false); fCreateLinkItem->SetEnabled(false); - // get ref for item which is selected - BEntry entry; - if (entry.SetTo(item_ref) != B_OK) - return; - - Model tempModel(&entry); - if (tempModel.InitCheck() != B_OK) - return; - - if (tempModel.IsRoot() || tempModel.IsVolume()) + // not for root or Trash or trashed items + Model model(ref); + if (model.IsRoot() || model.IsTrash() || model.InTrash()) return; // configure "Move to" menu item - PopulateMoveCopyNavMenu(dynamic_cast(fMoveToItem->Submenu()), - kMoveSelectionTo, item_ref, true); + PopulateMoveCopyNavMenu(dynamic_cast(fMoveToItem->Submenu()), kMoveSelectionTo, ref, + true); // configure "Copy to" menu item // add all mounted volumes (except the one this item lives on) - PopulateMoveCopyNavMenu(dynamic_cast(fCopyToItem->Submenu()), - kCopySelectionTo, item_ref, false); + PopulateMoveCopyNavMenu(dynamic_cast(fCopyToItem->Submenu()), kCopySelectionTo, ref, + false); // Set "Create Link" menu item message and // add all mounted volumes (except the one this item lives on) - if ((modifiers() & B_SHIFT_KEY) != 0) { - fCreateLinkItem->SetMessage(new BMessage(kCreateRelativeLink)); - PopulateMoveCopyNavMenu(dynamic_cast - (fCreateLinkItem->Submenu()), - kCreateRelativeLink, item_ref, false); - } else { - fCreateLinkItem->SetMessage(new BMessage(kCreateLink)); - PopulateMoveCopyNavMenu(dynamic_cast - (fCreateLinkItem->Submenu()), - kCreateLink, item_ref, false); - } + PopulateMoveCopyNavMenu(dynamic_cast(fCreateLinkItem->Submenu()), + (modifiers() & B_SHIFT_KEY) != 0 ? kCreateRelativeLink : kCreateLink, ref, false); - fMoveToItem->SetEnabled(PoseView()->CountSelected() > 0 - && !PoseView()->SelectedVolumeIsReadOnly()); - fCopyToItem->SetEnabled(PoseView()->CountSelected() > 0); - fCreateLinkItem->SetEnabled(PoseView()->CountSelected() > 0); - - // Set the "Identify" item label - BMenuItem* identifyItem = parent->FindItem(kIdentifyEntry); - if (identifyItem != NULL) { - if ((modifiers() & B_SHIFT_KEY) != 0) { - identifyItem->SetLabel(B_TRANSLATE("Force identify")); - identifyItem->Message()->ReplaceBool("force", true); - } else { - identifyItem->SetLabel(B_TRANSLATE("Identify")); - identifyItem->Message()->ReplaceBool("force", false); - } - } + Shortcuts()->UpdateMoveToItem(parent->FindItem(kMoveSelectionTo)); + Shortcuts()->UpdateCopyToItem(parent->FindItem(kCopySelectionTo)); + Shortcuts()->UpdateCreateLinkItem(parent->FindItem(Shortcuts()->CreateLinkCommand())); } @@ -2526,32 +2330,22 @@ BContainerWindow::ShowDropContextMenu(BPoint where, BPoseView* source) PoseView()->ConvertToScreen(&global); PoseView()->CommitActivePose(); - // Change the "Create Link" item - allow user to - // create relative links with the Shift key down. - BMenuItem* item = fDropContextMenu->FindItem(kCreateLink); - if (item == NULL) - item = fDropContextMenu->FindItem(kCreateRelativeLink); + Shortcuts()->UpdateCreateLinkHereItem( + fDropContextMenu->FindItem(Shortcuts()->CreateLinkHereCommand())); - if (item != NULL && (modifiers() & B_SHIFT_KEY) != 0) { - item->SetLabel(B_TRANSLATE("Create relative link here")); - item->SetMessage(new BMessage(kCreateRelativeLink)); - } else if (item != NULL) { - item->SetLabel(B_TRANSLATE("Create link here")); - item->SetMessage(new BMessage(kCreateLink)); - } + BMenuItem* item; int32 itemCount = fDropContextMenu->CountItems(); - for(int32 i = 0; i < itemCount - 2; i++) { + for (int32 index = 0; index < itemCount - 2; index++) { // separator item and Cancel item are skipped - item = fDropContextMenu->ItemAt(i); + item = fDropContextMenu->ItemAt(index); if (item == NULL) break; - if (item->Command() == kMoveSelectionTo && source != NULL) { - item->SetEnabled(!source->SelectedVolumeIsReadOnly() - && !PoseView()->TargetVolumeIsReadOnly()); - } else - item->SetEnabled(!PoseView()->TargetVolumeIsReadOnly()); + if (item->Command() == kMoveSelectionTo && source != NULL) + Shortcuts()->UpdateMoveToItem(item); + else + item->SetEnabled(PoseView()->TargetVolumeIsReadOnly() == false); } item = fDropContextMenu->Go(global, true, true); @@ -2573,127 +2367,77 @@ BContainerWindow::ShowContextMenu(BPoint where, const entry_ref* ref) if (ref != NULL) { // clicked on a pose, show file or volume context menu Model model(ref); + if (model.InitCheck() != B_OK) + return; // bail out, do not show context menu - if (model.IsTrash()) { - if (fTrashContextMenu->Window() || Dragging()) - return; + if (Dragging()) { + fContextMenu = NULL; - DeleteSubmenu(fNavigationItem); + BEntry entry; + model.GetEntry(&entry); - // selected item was trash, show the trash context menu instead + // only show for directories (directory, volume, root) + // + // don't show a popup for the trash or printers + // trash is handled in DeskWindow + // + // since this menu is opened asynchronously + // we need to make sure we don't open it more + // than once, the IsShowing flag is set in + // SlowContextPopup::AttachedToWindow and + // reset in DetachedFromWindow + // see the notes in SlowContextPopup::AttachedToWindow - EnableNamedMenuItem(fTrashContextMenu, kEmptyTrash, - static_cast(be_app)->TrashFull()); + if (!FSIsPrintersDir(&entry) && !fDragContextMenu->IsShowing()) { + fDragContextMenu->ClearMenu(); - SetupNavigationMenu(ref, fTrashContextMenu); + // in case the ref is a symlink, resolve it + // only pop open for directories + BEntry resolvedEntry(ref, true); + if (!resolvedEntry.IsDirectory()) + return; - fContextMenu = fTrashContextMenu; - } else { - bool showAsVolume = false; - bool isFilePanel = PoseView()->IsFilePanel(); + entry_ref resolvedRef; + resolvedEntry.GetRef(&resolvedRef); - if (Dragging()) { - fContextMenu = NULL; - - BEntry entry; - model.GetEntry(&entry); - - // only show for directories (directory, volume, root) - // - // don't show a popup for the trash or printers - // trash is handled in DeskWindow - // - // since this menu is opened asynchronously - // we need to make sure we don't open it more - // than once, the IsShowing flag is set in - // SlowContextPopup::AttachedToWindow and - // reset in DetachedFromWindow - // see the notes in SlowContextPopup::AttachedToWindow - - if (!FSIsPrintersDir(&entry) - && !fDragContextMenu->IsShowing()) { - //printf("ShowContextMenu - target is %s %i\n", - // ref->name, IsShowing(ref)); - fDragContextMenu->ClearMenu(); - - // in case the ref is a symlink, resolve it - // only pop open for directories - BEntry resolvedEntry(ref, true); - if (!resolvedEntry.IsDirectory()) - return; - - entry_ref resolvedRef; - resolvedEntry.GetRef(&resolvedRef); - - // use the resolved ref for the menu - 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); - } - - // this is now asynchronous so that we don't - // deadlock in Window::Quit, - fDragContextMenu->Go(global); + // use the resolved ref for the menu + 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); } - return; - } else if (model.IsRoot() || model.IsVolume()) { - fContextMenu = fVolumeContextMenu; - showAsVolume = true; - } else { - fContextMenu = fFileContextMenu; + // this is now asynchronous so that we don't + // deadlock in Window::Quit, + fDragContextMenu->Go(global); } - if (fContextMenu == NULL) - return; - - // bail out before cleanup if popup window is already open - if (fContextMenu->Window() != NULL) - return; - - // clean up items from last context menu - MenusEnded(); - - if (fContextMenu == fFileContextMenu) { - // Add all mounted volumes (except the one this item lives on.) - BNavMenu* navMenu = dynamic_cast( - fCreateLinkItem->Submenu()); - PopulateMoveCopyNavMenu(navMenu, - fCreateLinkItem->Message()->what, ref, false); - } else if (showAsVolume) { - // non-volume enable/disable copy, move, identify - EnableNamedMenuItem(fContextMenu, kDuplicateSelection, false); - EnableNamedMenuItem(fContextMenu, kMoveSelectionToTrash, false); - EnableNamedMenuItem(fContextMenu, kIdentifyEntry, false); - - // volume model, enable/disable the Unmount item - 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 && !isFilePanel) { - SetupMoveCopyMenus(ref, fContextMenu); - SetupOpenWithMenu(fContextMenu); - } - - UpdateMenu(fContextMenu, kPosePopUpContext); + return; } + + if (model.IsTrash()) + fContextMenu = fTrashContextMenu; + else if (model.IsVolume()) + fContextMenu = fVolumeContextMenu; + else + fContextMenu = fPoseContextMenu; + + // bail out before cleanup if popup window is already open + if (fContextMenu->Window() != NULL) + return; + + // clean up items from last context menu + MenusEnded(); + + // setup nav menu + SetupNavigationMenu(fContextMenu, ref); + + // update the rest + UpdateMenu(fContextMenu, kPosePopUpContext, ref); } else if (fWindowContextMenu != NULL) { // clicked on a window, show window context menu fContextMenu = fWindowContextMenu; @@ -2706,213 +2450,146 @@ BContainerWindow::ShowContextMenu(BPoint where, const entry_ref* ref) MenusEnded(); // setup nav menu - SetupNavigationMenu(TargetModel()->EntryRef(), fContextMenu); + SetupNavigationMenu(fContextMenu, TargetModel()->EntryRef()); // update the rest UpdateMenu(fContextMenu, kWindowPopUpContext); } - // context menu invalid or popup window is already open - if (fContextMenu == NULL || fContextMenu->Window() != NULL) - return; - + // synchronous Go() fContextMenu->Go(global, true, true, true); fContextMenu = NULL; } void -BContainerWindow::AddFileContextMenus(BMenu* menu) +BContainerWindow::AddPoseContextMenu(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->AddItem(Shortcuts()->OpenItem()); + // "Edit query" and "Open with..." inserted here, + // see UpdateMenus(), SetupEditQueryItem() and SetupOpenWithMenu() + menu->AddItem(Shortcuts()->GetInfoItem()); + menu->AddItem(Shortcuts()->EditNameItem()); - BMessage* message = new BMessage(kDuplicateSelection); - if (!(TargetModel()->IsTrash() || TargetModel()->InTrash() || TargetModel()->IsPrintersDir())) - menu->AddItem(new BMenuItem(B_TRANSLATE("Duplicate"), message, 'D')); - - if (!(TargetModel()->IsTrash() || TargetModel()->InTrash())) { - message = new BMessage(kMoveSelectionToTrash); - menu->AddItem( new BMenuItem(B_TRANSLATE("Move to Trash"), message, 'T')); - if (!TargetModel()->IsPrintersDir()) { - // add separator for copy to/move to items (navigation items) - menu->AddSeparatorItem(); - } - } else { - message = new BMessage(kDeleteSelection); - menu->AddItem(new BMenuItem(B_TRANSLATE("Delete"), message, 0)); - message = new BMessage(kRestoreSelectionFromTrash); - menu->AddItem(new BMenuItem(B_TRANSLATE("Restore"), message, 0)); + if (TargetModel()->InTrash()) { + menu->AddItem(Shortcuts()->DeleteItem()); + menu->AddItem(Shortcuts()->RestoreItem()); + } else if (!TargetModel()->InTrash()) { + menu->AddItem(Shortcuts()->DuplicateItem()); + menu->AddItem(Shortcuts()->MoveToTrashItem()); } - -#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); - BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"), - new BMessage(B_PASTE), 'V'); - menu->AddItem(pasteItem); -#endif menu->AddSeparatorItem(); - message = new BMessage(kIdentifyEntry); - message->AddBool("force", false); - menu->AddItem(new BMenuItem(B_TRANSLATE("Identify"), message)); + // The "Move To", "Copy To", "Create Link" menus are inserted here, + // have a look at UpdateMenu() and SetupMoveCopyMenus(). - BMenu* addOnMenuItem = new BMenu(B_TRANSLATE("Add-ons")); - menu->AddItem(addOnMenuItem); - - // set targets as needed - menu->SetTargetForItems(PoseView()); #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU - cutItem->SetTarget(this); - copyItem->SetTarget(this); - pasteItem->SetTarget(this); + if (!TargetModel()->IsPrintersDir() && !TargetModel()->IsRoot() && !TargetModel()->IsTrash() + && !TargetModel()->InTrash()) { + menu->AddItem(Shortcuts()->CutItem()); + menu->AddItem(Shortcuts()->CopyItem()); + menu->AddItem(Shortcuts()->PasteItem()); + menu->AddSeparatorItem(); + } #endif + + menu->AddItem(Shortcuts()->IdentifyItem()); + menu->AddItem(new BMenuItem(new BMenu(Shortcuts()->AddOnsLabel()))); } void -BContainerWindow::AddVolumeContextMenus(BMenu* menu) +BContainerWindow::AddVolumeContextMenu(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->AddItem(Shortcuts()->OpenItem()); + menu->AddItem(Shortcuts()->GetInfoItem()); + menu->AddItem(Shortcuts()->EditNameItem()); menu->AddSeparatorItem(); -#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU - menu->AddItem(new BMenuItem(B_TRANSLATE("Paste"), - new BMessage(B_PASTE), 'V')); + menu->AddItem(Shortcuts()->MountItem(new MountMenu(Shortcuts()->MountLabel()))); + menu->AddItem(Shortcuts()->UnmountItem()); menu->AddSeparatorItem(); -#endif - menu->AddItem(new BMenu(B_TRANSLATE("Add-ons"))); - - menu->SetTargetForItems(PoseView()); + menu->AddItem(new BMenuItem(new BMenu(Shortcuts()->AddOnsLabel()))); } void -BContainerWindow::AddWindowContextMenus(BMenu* menu) +BContainerWindow::AddWindowContextMenu(BMenu* menu) { // create context sensitive menu for empty area of window // since we check view mode before display, this should be a radio // mode menu - Model* targetModel = TargetModel(); - ASSERT(targetModel != NULL); - - bool needSeparator = true; if (TargetModel()->IsTrash()) { - menu->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"), - new BMessage(kEmptyTrash))); - } else if (TargetModel()->IsPrintersDir()) { - menu->AddItem(new BMenuItem(B_TRANSLATE("Add printer" B_UTF8_ELLIPSIS), - new BMessage(kAddPrinter), 'N')); - } else if (targetModel->InTrash() || targetModel->IsRoot()) { - needSeparator = false; - } else 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->AddItem(Shortcuts()->EmptyTrashItem()); + menu->AddSeparatorItem(); } - if (needSeparator) + if (ShouldHaveNewFolderItem()) { + menu->AddItem(Shortcuts()->NewFolderItem()); menu->AddSeparatorItem(); + } + + if (TargetModel()->IsDesktop()) { + AddIconSizeMenu(menu); + menu->AddSeparatorItem(); + } #ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU - BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"), - new BMessage(B_PASTE), 'V'); - pasteItem->SetEnabled(FSClipboardHasRefs() - && !PoseView()->TargetVolumeIsReadOnly()); - menu->AddItem(pasteItem); - menu->AddSeparatorItem(); + if (!(TargetModel()->IsPrintersDir() || TargetModel()->IsVolume() || TargetModel()->IsRoot() + || TargetModel()->IsTrash() || TargetModel()->InTrash())) { + menu->AddItem(Shortcuts()->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 (!TargetModel()->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"))); - } - + if (TargetModel()->IsDesktop()) // "Clean up" on Desktop + menu->AddItem(Shortcuts()->CleanupItem()); + // else "Arrange by >" menu inserted here, + // see UpdateMenu() and SetupArrangeByMenu() + menu->AddItem(Shortcuts()->SelectItem()); + menu->AddItem(Shortcuts()->SelectAllItem()); + if (!TargetModel()->IsTrash() && !TargetModel()->IsDesktop()) + menu->AddItem(Shortcuts()->OpenParentItem()); menu->AddSeparatorItem(); - BMenu* addOnMenuItem = new BMenu(B_TRANSLATE("Add-ons")); - menu->AddItem(addOnMenuItem); + + if (!PoseView()->IsFilePanel()) { + if (TargetModel()->IsRoot() || TargetModel()->IsDesktop()) { + menu->AddItem(Shortcuts()->MountItem(new MountMenu(Shortcuts()->MountLabel()))); + menu->AddSeparatorItem(); + } + } + + menu->AddItem(new BMenuItem(new BMenu(Shortcuts()->AddOnsLabel()))); #if DEBUG menu->AddSeparatorItem(); BMenuItem* testing = new BMenuItem("Test icon cache", new BMessage(kTestIconCache)); menu->AddItem(testing); -#endif - - // target items as needed - menu->SetTargetForItems(PoseView()); -#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU - pasteItem->SetTarget(this); + testing->SetTarget(PoseView()); #endif } void -BContainerWindow::AddDropContextMenus(BMenu* menu) +BContainerWindow::AddDropContextMenu(BMenu* menu) { - menu->AddItem(new BMenuItem(B_TRANSLATE("Move here"), - new BMessage(kMoveSelectionTo))); - menu->AddItem(new BMenuItem(B_TRANSLATE("Copy here"), - new BMessage(kCopySelectionTo))); - 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->AddItem(new BMenuItem(B_TRANSLATE("Create link here"), new BMessage(kCreateLink))); menu->AddSeparatorItem(); - menu->AddItem(new BMenuItem(B_TRANSLATE("Cancel"), - new BMessage(kCancelButton))); + menu->AddItem(new BMenuItem(B_TRANSLATE("Cancel"), new BMessage(kCancelButton))); } void -BContainerWindow::AddTrashContextMenus(BMenu* menu) +BContainerWindow::AddTrashContextMenu(BMenu* menu) { - // setup special trash context 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()); + menu->AddItem(Shortcuts()->EmptyTrashItem()); + menu->AddItem(Shortcuts()->OpenItem()); + menu->AddItem(Shortcuts()->GetInfoItem()); } @@ -2942,16 +2619,13 @@ BContainerWindow::EachAddOn(void (*eachAddOn)(const Model*, const char*, if (info.GetSupportedTypes(&message) == B_OK) { type_code typeCode; int32 count; - if (message.GetInfo("types", &typeCode, - &count) == B_OK) { + if (message.GetInfo("types", &typeCode, &count) == B_OK) secondary = false; - } } // check all supported types if it has some set if (!secondary) { - for (int32 i = mimeTypes.CountStrings(); - !primary && i-- > 0;) { + for (int32 i = mimeTypes.CountStrings(); !primary && i-- > 0;) { BString type = mimeTypes.StringAt(i); if (info.IsSupportedType(type.String())) { BMimeType mimeType(type.String()); @@ -3001,33 +2675,40 @@ BContainerWindow::BuildMimeTypeList(BStringList& mimeTypes) void -BContainerWindow::BuildAddOnsMenu(BMenu* parentMenu) +BContainerWindow::BuildAddOnsMenu(BMenu* parent) { - BMenuItem* item = parentMenu->FindItem(B_TRANSLATE("Add-ons")); - if (parentMenu->IndexOf(item) == 0) { + BMenuItem* addOnsItem = parent->FindItem(Shortcuts()->AddOnsLabel()); + if (parent->IndexOf(addOnsItem) == 0) { // the folder of the context menu seems to be named "Add-Ons" // so we just take the last menu item, which is correct if not // build with debug option - item = parentMenu->ItemAt(parentMenu->CountItems() - 1); - } - if (item == NULL) - return; - - BFont font; { - AutoLock _(parentMenu->Looper()); - parentMenu->GetFont(&font); +#if DEBUG + addOnsItem = parent->ItemAt(parent->CountItems() - 3); +#else + addOnsItem = parent->ItemAt(parent->CountItems() - 1); +#endif } - BMenu* menu = item->Submenu(); - if (menu == NULL) + if (addOnsItem == NULL) return; - menu->SetFont(&font); + BMenu* addOnsMenu = addOnsItem->Submenu(); + if (addOnsMenu == NULL) + return; + + // use a scope block for AutoLock + { + BFont font; + AutoLock _(parent->Looper()); + parent->GetFont(&font); + addOnsMenu->SetFont(&font); + } // found add-ons menu, empty it first + BMenuItem* item; for (;;) { - item = menu->RemoveItem((int32)0); - if (!item) + item = addOnsMenu->RemoveItem((int32)0); + if (item == NULL) break; delete item; } @@ -3043,108 +2724,168 @@ BContainerWindow::BuildAddOnsMenu(BMenu* parentMenu) // build a list of the MIME types of the selected items - EachAddOn(AddOneAddOn, ¶ms, mimeTypes, parentMenu); + EachAddOn(AddOneAddOn, ¶ms, mimeTypes, parent); primaryList.SortItems(CompareLabels); secondaryList.SortItems(CompareLabels); int32 count = primaryList.CountItems(); for (int32 index = 0; index < count; index++) - menu->AddItem(primaryList.ItemAt(index)); + addOnsMenu->AddItem(primaryList.ItemAt(index)); if (count > 0) - menu->AddSeparatorItem(); + addOnsMenu->AddSeparatorItem(); count = secondaryList.CountItems(); for (int32 index = 0; index < count; index++) - menu->AddItem(secondaryList.ItemAt(index)); + addOnsMenu->AddItem(secondaryList.ItemAt(index)); - menu->SetTargetForItems(this); + Shortcuts()->UpdateAddOnsItem(addOnsItem); } void -BContainerWindow::UpdateMenu(BMenu* menu, UpdateMenuContext context) +BContainerWindow::UpdateMenu(BMenu* menu, MenuContext context, const entry_ref* ref) { - const int32 selectCount = PoseView()->CountSelected(); - const int32 poseCount = PoseView()->CountItems(); + // update shared shortcut item's target and enabled state + Shortcuts()->Update(menu); - if (context == kMenuBarContext) { - EnableNamedMenuItem(menu, kOpenSelection, selectCount > 0); - EnableNamedMenuItem(menu, kIdentifyEntry, selectCount > 0); - EnableNamedMenuItem(menu, kRestoreFromTrash, selectCount > 0); - EnableNamedMenuItem(menu, kDeleteSelection, PoseView()->CanMoveToTrashOrDuplicate()); + if (context == kFileMenuContext) + UpdateFileMenu(menu); + else if (context == kWindowMenuContext) + UpdateWindowMenu(menu); + else if (context == kPosePopUpContext) + UpdatePoseContextMenu(menu, ref); + else if (context == kWindowPopUpContext) + UpdateWindowContextMenu(menu); +} + + +void +BContainerWindow::UpdateFileMenu(BMenu* menu) +{ + SetupNewTemplatesMenu(menu, kFileMenuContext); + + UpdateFileMenuOrPoseContextMenu(menu, kFileMenuContext); +} + + +void +BContainerWindow::UpdatePoseContextMenu(BMenu* menu, const entry_ref* ref) +{ + // ref must be set in pose pop up context + ASSERT(ref); + + UpdateFileMenuOrPoseContextMenu(menu, kPosePopUpContext, ref); +} + + +void +BContainerWindow::UpdateFileMenuOrPoseContextMenu(BMenu* menu, MenuContext context, + const entry_ref* ref) +{ + // ref must be set in pose pop up context + if (context == kPosePopUpContext) + ASSERT(ref); + + // if ref unset assume window ref + if (ref == NULL) + ref = TargetModel()->EntryRef(); + + // "Open with..." menu inserted after Open + if (context == kPosePopUpContext) { + if (ShouldHaveOpenWithMenu(ref)) + SetupOpenWithMenu(menu, ref); + } else if (context == kFileMenuContext) { + if (ShouldHaveOpenWithMenu()) + SetupOpenWithMenu(menu); } - if (context == kMenuBarContext || context == kPosePopUpContext) { - SetupEditQueryItem(menu); - - EnableNamedMenuItem(menu, kEditItem, PoseView()->CanEditName()); - EnableNamedMenuItem(menu, kMoveSelectionToTrash, PoseView()->CanMoveToTrashOrDuplicate()); - EnableNamedMenuItem(menu, kDuplicateSelection, PoseView()->CanMoveToTrashOrDuplicate()); - - SetCutItem(menu); - SetCopyItem(menu); - SetPasteItem(menu); + // "Edit query" inserted before "Open with..." + if (context == kPosePopUpContext) { + if (ShouldHaveEditQueryItem(ref)) + SetupEditQueryItem(menu, ref); + } else { + if (ShouldHaveEditQueryItem()) + SetupEditQueryItem(menu); } - if (context == kMenuBarContext || context == kWindowPopUpContext) { - if (!PoseView()->IsFilePanel()) - EnableNamedMenuItem(menu, B_TRANSLATE("New"), !PoseView()->TargetVolumeIsReadOnly()); - else - EnableNamedMenuItem(menu, kNewFolder, !PoseView()->TargetVolumeIsReadOnly()); + // "Move To", "Copy To", "Create Link" menus inserted after "Move to Trash" + if (ShouldHaveMoveCopyMenus(ref)) + SetupMoveCopyMenus(menu, ref); - uint32 viewMode = PoseView()->ViewMode(); + BuildAddOnsMenu(menu); +} - BMenu* iconSizeMenu = NULL; - if (BMenuItem* item = menu->FindItem(kIconMode)) - iconSizeMenu = item->Submenu(); +void +BContainerWindow::UpdateWindowMenu(BMenu* menu) +{ + UpdateWindowMenuOrWindowContextMenu(menu, kWindowMenuContext); +} + + +void +BContainerWindow::UpdateWindowContextMenu(BMenu* menu) +{ + SetupNewTemplatesMenu(menu, kWindowPopUpContext); + + UpdateWindowMenuOrWindowContextMenu(menu, kWindowPopUpContext); + + BuildAddOnsMenu(menu); +} + + +void +BContainerWindow::UpdateWindowMenuOrWindowContextMenu(BMenu* menu, MenuContext context) +{ + // insert "Arrange by >" menu before "Select ..." + SetupArrangeByMenu(menu); + + // update icon menus + uint32 viewMode = PoseView()->ViewMode(); + + // update icon size submenu + BMenuItem* iconModeItem = menu->FindItem(kIconMode); + if (iconModeItem != NULL) { + BMenu* iconSizeMenu = iconModeItem->Submenu(); if (iconSizeMenu != NULL) { if (viewMode == kIconMode) { + // mark the current icon size + BMenuItem* item; + BMessage* message; int32 iconSize = PoseView()->UnscaledIconSizeInt(); - BMenuItem* item = iconSizeMenu->ItemAt(0); - for (int32 i = 0; (item = iconSizeMenu->ItemAt(i)) != NULL; - i++) { - BMessage* message = item->Message(); + int32 itemCount = iconSizeMenu->CountItems(); + for (int32 index = 0; index < itemCount; index++) { + item = iconSizeMenu->ItemAt(index); + if (item == NULL) + continue; + + 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); + + bool sizeMatches = (iconSize == message->GetInt32("size", -1)); + item->SetMarked(sizeMatches); + + // radio mode + if (sizeMatches) + break; } } else { - BMenuItem* item; - for (int32 i = 0; (item = iconSizeMenu->ItemAt(i)) != NULL; i++) - item->SetMarked(false); + // unmark the marked item + BMenuItem* marked = iconSizeMenu->FindMarked(); + if (marked != NULL) + marked->SetMarked(false); } } - - MarkNamedMenuItem(menu, kIconMode, viewMode == kIconMode); - MarkNamedMenuItem(menu, kListMode, viewMode == kListMode); - MarkNamedMenuItem(menu, kMiniIconMode, viewMode == kMiniIconMode); - - SetCloseItem(menu); - SetArrangeMenu(menu); - SetPasteItem(menu); - - EnableNamedMenuItem(menu, kOpenParentDir, !PoseView()->ParentIsRoot()); - EnableNamedMenuItem(menu, kEmptyTrash, poseCount > 0); - EnableNamedMenuItem(menu, B_SELECT_ALL, poseCount > 0); - - BMenuItem* item = menu->FindItem(B_TRANSLATE("New")); - if (item != NULL) { - TemplatesMenu* templatesMenu = dynamic_cast( - item->Submenu()); - if (templatesMenu != NULL) - templatesMenu->UpdateMenuState(); - } } - BuildAddOnsMenu(menu); + MarkNamedMenuItem(menu, kIconMode, viewMode == kIconMode); + MarkNamedMenuItem(menu, kListMode, viewMode == kListMode); + MarkNamedMenuItem(menu, kMiniIconMode, viewMode == kMiniIconMode); } @@ -3195,6 +2936,76 @@ BContainerWindow::LoadAddOn(BMessage* message) } +bool +BContainerWindow::ShouldHaveNavigationMenu(const entry_ref* ref) +{ + if (ref == NULL) { + if (PoseView()->CountSelected() > 0) + ref = PoseView()->SelectionList()->FirstItem()->TargetModel()->EntryRef(); + else + ref = TargetModel()->EntryRef(); + } + + return !PoseView()->IsFilePanel() && !Model(ref).IsQuery(); +} + + +bool +BContainerWindow::ShouldHaveOpenWithMenu(const entry_ref* ref) +{ + if (PoseView()->IsFilePanel()) + return false; + + if (ref == NULL) + ref = TargetModel()->EntryRef(); + + Model model(ref); + if (model.IsPrintersDir()) + return false; + + return !(model.InTrash() || model.IsTrash() || model.IsRoot() || model.IsVolume()); +} + + +bool +BContainerWindow::ShouldHaveEditQueryItem(const entry_ref* ref) +{ + if (ref == NULL) + return FSIsQueriesDir(TargetModel()->EntryRef()); + + Model model(ref); + return model.IsQuery() || model.IsQueryTemplate(); +} + + +bool +BContainerWindow::ShouldHaveMoveCopyMenus(const entry_ref* ref) +{ + if (PoseView()->IsFilePanel()) + return false; + + if (ref == NULL) + ref = TargetModel()->EntryRef(); + + Model model(ref); + if (model.IsPrintersDir()) + return false; + + return !(model.IsTrash() || model.InTrash()); +} + + +bool +BContainerWindow::ShouldHaveNewFolderItem() +{ + if (TargetModel()->IsPrintersDir()) + return false; + + return !(TargetModel()->IsQuery() || TargetModel()->IsRoot() || TargetModel()->IsTrash() + || TargetModel()->InTrash() || TargetModel()->IsVirtualDirectory()); +} + + // #pragma mark - BContainerWindow private methods @@ -3318,12 +3129,28 @@ BContainerWindow::NewAttributeMenuItem(const char* label, const char* name, } +void +BContainerWindow::NewAttributesMenu() +{ + if (fAttrMenu != NULL) + delete fAttrMenu; + + fAttrMenu = new BMenu(B_TRANSLATE("Attributes")); + + NewAttributesMenu(fAttrMenu); +} + + void BContainerWindow::NewAttributesMenu(BMenu* menu) { ASSERT(PoseView()); + // empty menu BMenuItem* item; + while ((item = menu->RemoveItem((int32)0)) != NULL) + delete item; + menu->AddItem(item = new BMenuItem(B_TRANSLATE("Copy layout"), new BMessage(kCopyAttributes))); item->SetTarget(PoseView()); @@ -3371,6 +3198,8 @@ BContainerWindow::NewAttributesMenu(BMenu* menu) menu->AddItem(NewAttributeMenuItem(B_TRANSLATE("Permissions"), kAttrStatMode, B_STRING_TYPE, 80, B_ALIGN_LEFT, false, true)); + + MarkAttributesMenu(menu); } @@ -3403,9 +3232,12 @@ BContainerWindow::MarkAttributesMenu(BMenu* menu) if (menu == NULL) return; - int32 count = menu->CountItems(); - for (int32 index = 0; index < count; index++) { - BMenuItem* item = menu->ItemAt(index); + BMenuItem* item; + BMenu* submenu; + int32 submenuCount; + int32 itemCount = menu->CountItems(); + for (int32 index = 0; index < itemCount; index++) { + item = menu->ItemAt(index); int32 attrHash; if (item->Message() != NULL) { if (item->Message()->FindInt32("attr_hash", &attrHash) == B_OK) @@ -3414,53 +3246,24 @@ BContainerWindow::MarkAttributesMenu(BMenu* menu) item->SetMarked(false); } - BMenu* submenu = item->Submenu(); - if (submenu != NULL) { - int32 count2 = submenu->CountItems(); - for (int32 subindex = 0; subindex < count2; subindex++) { - item = submenu->ItemAt(subindex); - if (item->Message() != NULL) { - if (item->Message()->FindInt32("attr_hash", &attrHash) - == B_OK) { - item->SetMarked(PoseView()->ColumnFor((uint32)attrHash) - != 0); - } else - item->SetMarked(false); - } - } + submenu = item->Submenu(); + if (submenu == NULL) + continue; + + submenuCount = submenu->CountItems(); + for (int32 subindex = 0; subindex < submenuCount; subindex++) { + item = submenu->ItemAt(subindex); + if (item == NULL || item->Message() == NULL) + continue; + 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 == NULL) - return; - - int32 count = menu->CountItems(); - for (int32 index = 0; index < count; index++) { - BMenuItem* item = menu->ItemAt(index); - if (item->Message() != NULL) { - 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); -} - - // Adds a menu for a specific MIME type if it doesn't exist already. // Returns the menu, if it existed or not. BMenu* @@ -3556,6 +3359,89 @@ BContainerWindow::AddMimeMenu(const BMimeType& mimeType, bool isSuperType, } +BMenuItem* +BContainerWindow::NewArrangeByMenu() +{ + // must have an Attributes menu for "Arrange by >" + ASSERT(fAttrMenu); + + // create a new "Arrange by >" menu + BMenu* menu = new BMenu(Shortcuts()->ArrangeByLabel()); + + // add Attributes items to "Arrange by >" + BMenuItem* item; + int32 attrCount = fAttrMenu->CountItems(); + for (int32 i = 3; i < attrCount; i++) { + // skip over "Copy layout", "Paste layout" and separator + item = fAttrMenu->ItemAt(i); + if (item == NULL || item->Message() == NULL) + continue; + + item = new BMenuItem(item->Label(), new BMessage(*item->Message())); + item->Message()->what = kArrangeBy; + menu->AddItem(item); + } + menu->AddSeparatorItem(); + + menu->AddItem(Shortcuts()->ReverseOrderItem()); + menu->AddSeparatorItem(); + + menu->AddItem(Shortcuts()->CleanupItem()); + + return new BMenuItem(menu); +} + + +void +BContainerWindow::SetupArrangeByMenu(BMenu* parent) +{ + // first remove "Arrange by >" from the old menu + if (fArrangeByItem != NULL && fArrangeByItem->Menu() != NULL) + fArrangeByItem->Menu()->RemoveItem(fArrangeByItem); + + // bail out if no parent menu to add to + if (parent == NULL) + return; + + // update "Clean up" on Desktop and bail out + if (TargetModel()->IsDesktop()) { + Shortcuts()->UpdateCleanupItem(Shortcuts()->FindItem(parent, kCleanup, kCleanupAll)); + return; + } + + // bail out if no "Select ..." item found + int32 selectIndex = parent->IndexOf(parent->FindItem(kShowSelectionWindow)); + if (selectIndex == B_ERROR) + return; + + // add "Arrange by >" menu before "Select..." + parent->AddItem(fArrangeByItem, selectIndex); + + // mark items + uint32 attrHash; + int32 itemCount = fArrangeByItem->Submenu()->CountItems(); + for (int32 index = 0; index < itemCount; index++) { + BMenuItem* item = fArrangeByItem->Submenu()->ItemAt(index); + if (item == NULL || item->Message() == NULL) + continue; + + if (item->Message()->FindInt32("attr_hash", (int32*)&attrHash) == B_OK) + item->SetMarked(PoseView()->PrimarySort() == attrHash); + else if (item->Message()->what == kArrangeReverseOrder) + item->SetMarked(PoseView()->ReverseSort()); + } + + Shortcuts()->UpdateArrangeByItem(fArrangeByItem); +} + + +void +BContainerWindow::AddMimeTypesToMenu() +{ + AddMimeTypesToMenu(fAttrMenu); +} + + void BContainerWindow::AddMimeTypesToMenu(BMenu* menu) { @@ -3800,7 +3686,7 @@ BContainerWindow::SetupDefaultState() return; } - if (PoseView()->IsDesktop()) { + if (TargetModel()->IsDesktop()) { // don't copy over the attributes if we are the Desktop return; } @@ -3841,7 +3727,7 @@ BContainerWindow::SetupDefaultState() void BContainerWindow::RestoreWindowState(AttributeStreamNode* node) { - if (node == NULL || PoseView()->IsDesktop()) { + if (node == NULL || TargetModel()->IsDesktop()) { // don't restore any window state if we are the Desktop return; } @@ -3899,7 +3785,7 @@ BContainerWindow::RestoreWindowState(AttributeStreamNode* node) void BContainerWindow::RestoreWindowState(const BMessage& message) { - if (PoseView()->IsDesktop()) { + if (TargetModel()->IsDesktop()) { // don't restore any window state if we are the Desktop return; } @@ -4081,11 +3967,11 @@ BContainerWindow::ShowSelectionWindow() void BContainerWindow::ShowNavigator(bool show) { - if (PoseView()->IsDesktop() || !TargetModel()->IsDirectory() || PoseView()->IsFilePanel()) + if (TargetModel()->IsDesktop() || !TargetModel()->IsDirectory() || PoseView()->IsFilePanel()) return; if (show) { - if (Navigator() != NULL && !Navigator()->IsHidden()) + if (Navigator() && !Navigator()->IsHidden()) return; if (Navigator() == NULL) { @@ -4099,7 +3985,7 @@ BContainerWindow::ShowNavigator(bool show) if (PoseView()->VScrollBar()) PoseView()->UpdateScrollRange(); } else { - if (Navigator() == NULL || Navigator()->IsHidden()) + if (!Navigator() || Navigator()->IsHidden()) return; if (PoseView()->VScrollBar()) @@ -4113,11 +3999,11 @@ BContainerWindow::ShowNavigator(bool show) void BContainerWindow::SetSingleWindowBrowseShortcuts(bool enabled) { - if (PoseView()->IsDesktop()) + if (TargetModel()->IsDesktop()) return; if (enabled) { - if (Navigator() == NULL) + if (!Navigator()) return; RemoveShortcut(B_DOWN_ARROW, B_COMMAND_KEY | B_OPTION_KEY); @@ -4211,44 +4097,6 @@ BContainerWindow::PulseTaskLoop() } -void -BContainerWindow::PopulateArrangeByMenu(BMenu* menu) -{ - if (!fAttrMenu || !menu) - return; - // empty fArrangeByMenu... - 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); -} - - // #pragma mark - WindowStateNodeOpener diff --git a/src/kits/tracker/ContainerWindow.h b/src/kits/tracker/ContainerWindow.h index 3bf1935d74..c3c2e18d85 100644 --- a/src/kits/tracker/ContainerWindow.h +++ b/src/kits/tracker/ContainerWindow.h @@ -63,6 +63,8 @@ class Model; class ModelNodeLazyOpener; class BorderedView; class SelectionWindow; +class TShortcuts; +class TemplatesMenu; #define kDefaultFolderTemplate "DefaultFolderTemplate" @@ -132,6 +134,7 @@ public: Model* TargetModel() const; BPoseView* PoseView() const; + TShortcuts* Shortcuts() const; BNavigator* Navigator() const; virtual void SelectionChanged(); @@ -142,6 +145,8 @@ public: void RestoreStateCommon(); virtual void SaveState(bool hide = true); virtual void SaveState(BMessage &) const; + virtual void SwitchDirectory(const entry_ref* ref); + virtual void OpenParent(); void UpdateTitle(); bool StateNeedsSaving() const; @@ -155,21 +160,27 @@ public: // calls for inheriting window size, attribute layout, etc. // deprecated - virtual void AddMimeTypesToMenu(BMenu*); void AddMimeTypesToMenu(); - virtual void MarkAttributesMenu(BMenu*); - void MarkAttributesMenu(); + void AddMimeTypesToMenu(BMenu*); + + BMenuItem* NewArrangeByMenu(); + virtual void SetupArrangeByMenu(BMenu*); void MarkArrangeByMenu(BMenu*); + BMenuItem* NewAttributeMenuItem(const char* label, const char* name, int32 type, float width, int32 align, bool editable, bool statField); BMenuItem* NewAttributeMenuItem(const char* label, const char* name, int32 type, const char* displayAs, float width, int32 align, bool editable, bool statField); - virtual void NewAttributesMenu(BMenu*); + void NewAttributesMenu(); + virtual void NewAttributesMenu(BMenu*); + void MarkAttributesMenu(); + virtual void MarkAttributesMenu(BMenu*); void HideAttributesMenu(); void ShowAttributesMenu(); + PiggybackTaskLoop* DelayedTaskLoop(); // use for RunLater queueing void PulseTaskLoop(); @@ -196,6 +207,14 @@ public: void SetPathWatchingEnabled(bool); bool IsPathWatchingEnabled(void) const; +protected: + enum MenuContext { + kFileMenuContext, + kWindowMenuContext, + kPosePopUpContext, + kWindowPopUpContext + }; + protected: virtual BPoseView* NewPoseView(Model*, uint32); // instantiate a different flavor of BPoseView for different @@ -217,42 +236,42 @@ protected: // desktop window virtual void AddFileMenu(BMenu* menu); virtual void AddWindowMenu(BMenu* menu); + virtual void AddIconSizeMenu(BMenu* menu); virtual void AddContextMenus(); + virtual void AddPoseContextMenu(BMenu*); + virtual void AddWindowContextMenu(BMenu*); + virtual void AddVolumeContextMenu(BMenu*); + virtual void AddDropContextMenu(BMenu*); + virtual void AddTrashContextMenu(BMenu*); - virtual void AddFileContextMenus(BMenu*); - virtual void AddWindowContextMenus(BMenu*); - virtual void AddVolumeContextMenus(BMenu*); - virtual void AddDropContextMenus(BMenu*); - virtual void AddTrashContextMenus(BMenu*); - + virtual void DetachSubmenus(); virtual void RepopulateMenus(); - void PopulateArrangeByMenu(BMenu*); - virtual void SetCutItem(BMenu*); - virtual void SetCopyItem(BMenu*); - virtual void SetPasteItem(BMenu*); - virtual void SetArrangeMenu(BMenu*); - virtual void SetCloseItem(BMenu*); - virtual void SetupNavigationMenu(const entry_ref*, BMenu*); - virtual void SetupMoveCopyMenus(const entry_ref*, BMenu*); + virtual void SetupNavigationMenu(BMenu*, const entry_ref*); + virtual void SetupMoveCopyMenus(BMenu*, const entry_ref*); virtual void PopulateMoveCopyNavMenu(BNavMenu*, uint32, const entry_ref*, bool); virtual void SetupOpenWithMenu(BMenu*); + virtual void SetupOpenWithMenu(BMenu*, const entry_ref* ref); + virtual void SetupNewTemplatesMenu(BMenu*, MenuContext context); virtual void SetupEditQueryItem(BMenu*); + virtual void SetupEditQueryItem(BMenu*, const entry_ref* ref); virtual void SetupDiskMenu(BMenu*); virtual void BuildAddOnsMenu(BMenu*); void BuildMimeTypeList(BStringList& mimeTypes); - enum UpdateMenuContext { - kMenuBarContext, - kPosePopUpContext, - kWindowPopUpContext - }; - - virtual void UpdateMenu(BMenu* menu, UpdateMenuContext context); + virtual void UpdateMenu(BMenu* menu, MenuContext context, + const entry_ref* ref = NULL); + virtual void UpdateFileMenu(BMenu* menu); + virtual void UpdatePoseContextMenu(BMenu* menu, const entry_ref* ref); + virtual void UpdateFileMenuOrPoseContextMenu(BMenu* menu, MenuContext context, + const entry_ref* ref = NULL); + virtual void UpdateWindowMenu(BMenu* menu); + virtual void UpdateWindowContextMenu(BMenu* menu); + virtual void UpdateWindowMenuOrWindowContextMenu(BMenu* menu, MenuContext context); BMenu* AddMimeMenu(const BMimeType& mimeType, bool isSuperType, BMenu* menu, int32 start); @@ -270,6 +289,12 @@ protected: uint32 fOpenFlags; bool fUsesLayout; + bool ShouldHaveNavigationMenu(const entry_ref* = NULL); + bool ShouldHaveOpenWithMenu(const entry_ref* = NULL); + bool ShouldHaveEditQueryItem(const entry_ref* = NULL); + bool ShouldHaveMoveCopyMenus(const entry_ref* = NULL); + bool ShouldHaveNewFolderItem(); + BGroupLayout* fRootLayout; BGroupView* fMenuContainer; BGridView* fPoseContainer; @@ -277,8 +302,9 @@ protected: BGroupView* fVScrollBarContainer; BGroupView* fCountContainer; + TShortcuts* fShortcuts; BPopUpMenu* fContextMenu; - BPopUpMenu* fFileContextMenu; + BPopUpMenu* fPoseContextMenu; BPopUpMenu* fWindowContextMenu; BPopUpMenu* fDropContextMenu; BPopUpMenu* fVolumeContextMenu; @@ -288,7 +314,9 @@ protected: BMenuItem* fCopyToItem; BMenuItem* fCreateLinkItem; BMenuItem* fOpenWithItem; + BMenuItem* fEditQueryItem; ModelMenuItem* fNavigationItem; + BMenuItem* fNewTemplatesItem; BMenuBar* fMenuBar; DraggableContainerIcon* fDraggableIcon; BNavigator* fNavigator; @@ -296,7 +324,7 @@ protected: BMenu* fAttrMenu; BMenu* fWindowMenu; BMenu* fFileMenu; - BMenu* fArrangeByMenu; + BMenuItem* fArrangeByItem; SelectionWindow* fSelectionWindow; @@ -391,6 +419,13 @@ BContainerWindow::PoseView() const } +inline TShortcuts* +BContainerWindow::Shortcuts() const +{ + return fShortcuts; +} + + inline void BContainerWindow::SetupDiskMenu(BMenu*) { diff --git a/src/kits/tracker/DeskWindow.cpp b/src/kits/tracker/DeskWindow.cpp index a6f9d04cf4..979cf3c488 100644 --- a/src/kits/tracker/DeskWindow.cpp +++ b/src/kits/tracker/DeskWindow.cpp @@ -64,6 +64,7 @@ All rights reserved. #include "KeyInfos.h" #include "MountMenu.h" #include "PoseView.h" +#include "Shortcuts.h" #include "TemplatesMenu.h" #include "Tracker.h" @@ -194,21 +195,17 @@ BDeskWindow::BDeskWindow(LockingList* windowList, uint32 openFlags) fNodeRef(NULL), fShortcutsSettings(NULL) { - // Add icon view switching shortcuts. These are displayed in the context - // menu, although they obviously don't work from those menu items. - BMessage* message = new BMessage(kIconMode); - AddShortcut('1', B_COMMAND_KEY, message, PoseView()); - - message = new BMessage(kMiniIconMode); - AddShortcut('2', B_COMMAND_KEY, message, PoseView()); - - message = new BMessage(kIconMode); - message->AddInt32("scale", 1); - AddShortcut('+', B_COMMAND_KEY, message, PoseView()); - - message = new BMessage(kIconMode); - message->AddInt32("scale", 0); - AddShortcut('-', B_COMMAND_KEY, message, PoseView()); + // create pose view + BDirectory deskDir; + if (FSGetDeskDir(&deskDir) == B_OK) { + BEntry entry; + deskDir.GetEntry(&entry); + Model* model = new Model(&entry, true); + if (model->InitCheck() == B_OK) + CreatePoseView(model); + else + delete model; + } } @@ -254,6 +251,40 @@ BDeskWindow::Init(const BMessage*) if (fDeskShelf != NULL) fDeskShelf->SetDisplaysZombies(true); } + + // Add icon view switching shortcuts. These are displayed in the context + // menu, although they obviously don't work from those menu items. + BMessage* message = new BMessage(kIconMode); + AddShortcut('1', B_COMMAND_KEY, message, PoseView()); + + message = new BMessage(kMiniIconMode); + AddShortcut('2', B_COMMAND_KEY, message, PoseView()); + + message = new BMessage(kIconMode); + message->AddInt32("scale", 1); + AddShortcut('+', B_COMMAND_KEY, message, PoseView()); + + message = new BMessage(kIconMode); + message->AddInt32("scale", 0); + AddShortcut('-', B_COMMAND_KEY, message, PoseView()); + + if (TrackerSettings().ShowDisksIcon()) { + // create model for root of everything + BEntry entry("/"); + Model model(&entry); + if (model.InitCheck() == B_OK) { + // add the root icon to desktop window + BMessage message; + message.what = B_NODE_MONITOR; + message.AddInt32("opcode", B_ENTRY_CREATED); + message.AddInt32("device", model.NodeRef()->device); + message.AddInt64("node", model.NodeRef()->node); + message.AddInt64("directory", model.EntryRef()->directory); + message.AddString("name", model.EntryRef()->name); + + PostMessage(&message, PoseView()); + } + } } @@ -435,92 +466,6 @@ BDeskWindow::CreatePoseView(Model* model) } -void -BDeskWindow::AddWindowContextMenus(BMenu* menu) -{ - TemplatesMenu* tempateMenu = new TemplatesMenu(PoseView(), - B_TRANSLATE("New")); - - menu->AddItem(tempateMenu); - tempateMenu->SetTargetForItems(PoseView()); - - menu->AddSeparatorItem(); - - BMenu* iconSizeMenu = new BMenu(B_TRANSLATE("Icon view")); - BMenuItem* item; - - static const uint32 kIconSizes[] = { 32, 40, 48, 64, 96, 128 }; - BMessage* message; - - for (uint32 i = 0; i < sizeof(kIconSizes) / sizeof(uint32); ++i) { - uint32 iconSize = kIconSizes[i]; - message = new BMessage(kIconMode); - message->AddInt32("size", iconSize); - BString label; - label.SetToFormat(B_TRANSLATE_COMMENT("%" B_PRId32" × %" B_PRId32, - "The '×' is the Unicode multiplication sign U+00D7"), - iconSize, iconSize); - item = new BMenuItem(label, message); - item->SetMarked(PoseView()->IconSizeInt() == iconSize); - 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); - - // A sub menu where the super item can be invoked. - menu->AddItem(iconSizeMenu); - iconSizeMenu->Superitem()->SetShortcut('1', B_COMMAND_KEY); - iconSizeMenu->Superitem()->SetMessage(new BMessage(kIconMode)); - iconSizeMenu->Superitem()->SetTarget(PoseView()); - iconSizeMenu->Superitem()->SetMarked(PoseView()->ViewMode() == kIconMode); - - item = new BMenuItem(B_TRANSLATE("Mini icon view"), - new BMessage(kMiniIconMode), '2'); - item->SetMarked(PoseView()->ViewMode() == kMiniIconMode); - menu->AddItem(item); - - menu->AddSeparatorItem(); - -#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU - BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"), - new BMessage(B_PASTE), 'V'); - menu->AddItem(pasteItem); - menu->AddSeparatorItem(); -#endif - menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"), - new BMessage(kCleanup), 'K')); - 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')); - - menu->AddSeparatorItem(); - menu->AddItem(new MountMenu(B_TRANSLATE("Mount"))); - - menu->AddSeparatorItem(); - menu->AddItem(new BMenu(B_TRANSLATE("Add-ons"))); - - // target items as needed - menu->SetTargetForItems(PoseView()); -#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU - pasteItem->SetTarget(this); -#endif -} - - void BDeskWindow::WorkspaceActivated(int32 workspace, bool state) { diff --git a/src/kits/tracker/DeskWindow.h b/src/kits/tracker/DeskWindow.h index a535673810..dc63f34b0f 100644 --- a/src/kits/tracker/DeskWindow.h +++ b/src/kits/tracker/DeskWindow.h @@ -71,7 +71,6 @@ public: void SaveDesktopPoseLocations(); protected: - virtual void AddWindowContextMenus(BMenu*); virtual BPoseView* NewPoseView(Model*, uint32); virtual void WorkspaceActivated(int32, bool); diff --git a/src/kits/tracker/FilePanel.cpp b/src/kits/tracker/FilePanel.cpp index 749ef04568..7ca770c06b 100644 --- a/src/kits/tracker/FilePanel.cpp +++ b/src/kits/tracker/FilePanel.cpp @@ -296,7 +296,7 @@ BFilePanel::SetPanelDirectory(const entry_ref* ref) if (!lock) return; - static_cast(fWindow)->SetTo(ref); + static_cast(fWindow)->SwitchDirectory(ref); } @@ -312,7 +312,7 @@ BFilePanel::SetPanelDirectory(const char* path) if (!lock) return; - static_cast(fWindow)->SetTo(&ref); + static_cast(fWindow)->SwitchDirectory(&ref); } diff --git a/src/kits/tracker/FilePanelPriv.cpp b/src/kits/tracker/FilePanelPriv.cpp index aef5a354e5..37399b6ae2 100644 --- a/src/kits/tracker/FilePanelPriv.cpp +++ b/src/kits/tracker/FilePanelPriv.cpp @@ -77,6 +77,7 @@ All rights reserved. #include "IconMenuItem.h" #include "MimeTypes.h" #include "NavMenu.h" +#include "Shortcuts.h" #include "Tracker.h" #include "Utilities.h" @@ -114,11 +115,7 @@ key_down_filter(BMessage* message, BHandler** handler, BMessageFilter* filter) if (filter == NULL) return B_DISPATCH_MESSAGE; - BLooper* looper = filter->Looper(); - if (looper == NULL) - return B_DISPATCH_MESSAGE; - - TFilePanel* panel = dynamic_cast(looper); + TFilePanel* panel = dynamic_cast(filter->Looper()); if (panel == NULL || panel->TrackingMenu()) return B_DISPATCH_MESSAGE; @@ -135,11 +132,11 @@ key_down_filter(BMessage* message, BHandler** handler, BMessageFilter* filter) if ((modifiers & B_COMMAND_KEY) != 0) { switch (key) { case B_UP_ARROW: - looper->PostMessage(kOpenParentDir); + BMessenger(panel).SendMessage(kOpenParentDir); return B_SKIP_MESSAGE; case 'w': - looper->PostMessage(kCancelButton); + BMessenger(panel).SendMessage(kCancelButton); return B_SKIP_MESSAGE; default: @@ -151,9 +148,9 @@ key_down_filter(BMessage* message, BHandler** handler, BMessageFilter* filter) if (view->ActivePose() != NULL) view->CommitActivePose(false); else if (view->IsTypeAheadFiltering()) - looper->PostMessage(B_CANCEL, *handler); + BMessenger(panel).SendMessage(B_CANCEL, *handler); else - looper->PostMessage(kCancelButton); + BMessenger(panel).SendMessage(kCancelButton); return B_SKIP_MESSAGE; } @@ -183,6 +180,7 @@ TFilePanel::TFilePanel(file_panel_mode mode, BMessenger* target, const BEntry* s fClientObject(NULL), fSelectionIterator(0), fMessage(NULL), + fFavoritesMenu(NULL), fHideWhenDone(hideWhenDone), fIsTrackingMenu(false), fDefaultStateRestored(false) @@ -212,8 +210,10 @@ TFilePanel::TFilePanel(file_panel_mode mode, BMessenger* target, const BEntry* s else fMessage = new BMessage(B_REFS_RECEIVED); - gLocalizedNamePreferred - = BLocaleRoster::Default()->IsFilesystemTranslationPreferred(); + // no new template menu in file panel + fNewTemplatesItem = NULL; + + gLocalizedNamePreferred = BLocaleRoster::Default()->IsFilesystemTranslationPreferred(); // check for legal starting directory Model* model = new Model(); @@ -357,21 +357,18 @@ TFilePanel::MessageDropFilter(BMessage* message, BHandler**, BMessageFilter* fil entry.GetRef(&ref); - panel->fTaskLoop->RunLater(NewMemberFunctionObjectWithResult - (&TFilePanel::SelectChildInParent, panel, - const_cast(&ref), - const_cast(&child)), - ref == *panel->TargetModel()->EntryRef() ? 0 : 100000, 200000, - 5000000); - // if the target directory is already current, we won't - // delay the initial selection try + // don't delay the initial selection try if the target directory is already current + panel->fTaskLoop->RunLater( + NewMemberFunctionObjectWithResult(&TFilePanel::SelectChildInParent, panel, + const_cast(&ref), const_cast(&child)), + ref == *panel->TargetModel()->EntryRef() ? 0 : 100000, 200000, 5000000); // also set the save name to the dragged in entry if (panel->IsSavePanel()) panel->SetSaveText(path.Leaf()); } - panel->SetTo(&ref); + panel->SwitchDirectory(&ref); return B_SKIP_MESSAGE; } @@ -412,7 +409,7 @@ TFilePanel::FSFilter(BMessage* message, BHandler**, BMessageFilter* filter) // but not wind title if (*(panel->TargetModel()->NodeRef()) == itemNode) { panel->TargetModel()->UpdateEntryRef(&dirNode, name); - panel->SetTo(panel->TargetModel()->EntryRef()); + panel->SwitchDirectory(panel->TargetModel()->EntryRef()); return B_SKIP_MESSAGE; } break; @@ -439,9 +436,7 @@ TFilePanel::FSFilter(BMessage* message, BHandler**, BMessageFilter* filter) root.GetEntry(&entry); entry.GetRef(&ref); - panel->SwitchDirToDesktopIfNeeded(ref); - - panel->SetTo(&ref); + panel->SwitchDirectory(&ref); return B_SKIP_MESSAGE; } break; @@ -544,25 +539,37 @@ TFilePanel::SetRefFilter(BRefFilter* filter) void -TFilePanel::SetTo(const entry_ref* ref) +TFilePanel::SwitchDirectory(const entry_ref* ref) { if (ref == NULL) return; entry_ref setToRef(*ref); bool isDesktop = SwitchDirToDesktopIfNeeded(setToRef); - BEntry entry(&setToRef); - if (entry.InitCheck() != B_OK || !entry.IsDirectory()) + BEntry entry(&setToRef, true); + if (entry.InitCheck() != B_OK) return; PoseView()->SetIsDesktop(isDesktop); - PoseView()->SwitchDir(&setToRef); - SwitchDirMenuTo(&setToRef); + _inherited::SwitchDirectory(&setToRef); AddShortcut('H', B_COMMAND_KEY, new BMessage(kSwitchToHome)); // our shortcut got possibly removed because the home // menu item got removed - we shouldn't really have to do // this - this is a workaround for a kit bug. + + // update the menu field + for (int32 index = fDirMenu->CountItems() - 1; index >= 0; index--) + delete fDirMenu->RemoveItem(index); + + fDirMenuField->MenuBar()->RemoveItem((int32)0); + fDirMenu->Populate(&entry, 0, true, true, false, true); + + ModelMenuItem* item = dynamic_cast(fDirMenuField->MenuBar()->ItemAt(0)); + ASSERT(item); + + // set dir menu to the new directory + item->SetEntry(&entry); } @@ -711,8 +718,7 @@ TFilePanel::Init(const BMessage*) fDirMenuField->MenuBar()->SetMaxContentWidth(rect.Width() - 26.0f); // Make room for the icon - fDirMenu = new BDirMenu(fDirMenuField->MenuBar(), - this, kSwitchDirectory, "refs"); + fDirMenu = new BDirMenu(fDirMenuField->MenuBar(), this, kSwitchDirectory, "refs"); BEntry entry(TargetModel()->EntryRef()); if (entry.InitCheck() == B_OK) @@ -786,20 +792,18 @@ TFilePanel::Init(const BMessage*) else fBackView->AddChild(fPoseContainer); + fShortcuts = new TShortcuts(this); + AddShortcut('W', B_COMMAND_KEY, new BMessage(kCancelButton)); AddShortcut('H', B_COMMAND_KEY, new BMessage(kSwitchToHome)); - AddShortcut('A', B_COMMAND_KEY | B_SHIFT_KEY, - new BMessage(kShowSelectionWindow)); + AddShortcut('A', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(kShowSelectionWindow)); AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), this); - AddShortcut('S', B_COMMAND_KEY, new BMessage(kInvertSelection), - PoseView()); + AddShortcut('S', B_COMMAND_KEY, new BMessage(kInvertSelection), PoseView()); AddShortcut('Y', B_COMMAND_KEY, new BMessage(kResizeToFit), PoseView()); AddShortcut(B_DOWN_ARROW, B_COMMAND_KEY, new BMessage(kOpenDir)); - AddShortcut(B_DOWN_ARROW, B_COMMAND_KEY | B_OPTION_KEY, - new BMessage(kOpenDir)); + AddShortcut(B_DOWN_ARROW, B_COMMAND_KEY | B_OPTION_KEY, new BMessage(kOpenDir)); AddShortcut(B_UP_ARROW, B_COMMAND_KEY, new BMessage(kOpenParentDir)); - AddShortcut(B_UP_ARROW, B_COMMAND_KEY | B_OPTION_KEY, - new BMessage(kOpenParentDir)); + AddShortcut(B_UP_ARROW, B_COMMAND_KEY | B_OPTION_KEY, new BMessage(kOpenParentDir)); if (!fIsSavePanel && (fNodeFlavors & B_DIRECTORY_NODE) == 0) default_button->SetEnabled(false); @@ -808,54 +812,10 @@ TFilePanel::Init(const BMessage*) RestoreState(); - AddMenus(); + if (ShouldAddMenus()) + AddMenus(); AddContextMenus(); - FavoritesMenu* favorites = new FavoritesMenu(B_TRANSLATE("Favorites"), - new BMessage(kSwitchDirectory), new BMessage(B_REFS_RECEIVED), - BMessenger(this), IsSavePanel(), fPoseView->RefFilter()); - favorites->AddItem(new BMenuItem(B_TRANSLATE("Add current folder"), - new BMessage(kAddCurrentDir))); - favorites->AddItem(new BMenuItem( - B_TRANSLATE("Edit favorites" B_UTF8_ELLIPSIS), - new BMessage(kEditFavorites))); - - fMenuBar->AddItem(favorites); - - // configure menus - BMenuItem* item = fMenuBar->FindItem(B_TRANSLATE("Window")); - if (item) { - fMenuBar->RemoveItem(item); - delete item; - } - - item = fMenuBar->FindItem(B_TRANSLATE("File")); - if (item) { - BMenu* menu = item->Submenu(); - if (menu) { - item = menu->FindItem(kOpenSelection); - if (item && menu->RemoveItem(item)) - delete item; - - // remove add-ons menu, identifier menu, separator - item = menu->FindItem(B_TRANSLATE("Add-ons")); - if (item) { - int32 index = menu->IndexOf(item); - delete menu->RemoveItem(index); - delete menu->RemoveItem(--index); - delete menu->RemoveItem(--index); - } - - // remove separator - item = menu->FindItem(B_CUT); - if (item) { - item = menu->ItemAt(menu->IndexOf(item)-1); - if (item && menu->RemoveItem(item)) - delete item; - } - } - } - PoseView()->ScrollTo(B_ORIGIN); PoseView()->UpdateScrollRange(); PoseView()->ScrollTo(B_ORIGIN); @@ -886,6 +846,67 @@ TFilePanel::Init(const BMessage*) } +void +TFilePanel::AddMenus() +{ + // File + + fFileMenu = new BMenu(B_TRANSLATE("File")); + AddFileMenu(fFileMenu); + fMenuBar->AddItem(fFileMenu); + + // Favorites + + fFavoritesMenu = new FavoritesMenu(B_TRANSLATE("Favorites"), new BMessage(kSwitchDirectory), + new BMessage(B_REFS_RECEIVED), BMessenger(this), IsSavePanel(), Filter()); + AddFavoritesMenu(fFavoritesMenu); + fMenuBar->AddItem(fFavoritesMenu); +} + + +void +TFilePanel::AddFileMenu(BMenu* menu) +{ + menu->AddItem(Shortcuts()->NewFolderItem()); + menu->AddItem(new BSeparatorItem()); + + menu->AddItem(Shortcuts()->GetInfoItem()); + menu->AddItem(Shortcuts()->EditNameItem()); + if (TargetModel()->IsTrash() || TargetModel()->InTrash()) { + menu->AddItem(Shortcuts()->DeleteItem()); + menu->AddItem(Shortcuts()->RestoreItem()); + } else { + menu->AddItem(Shortcuts()->DuplicateItem()); + menu->AddItem(Shortcuts()->MoveToTrashItem()); + } + + if (!TargetModel()->IsPrintersDir() || TargetModel()->IsRoot() || TargetModel()->IsTrash() + || TargetModel()->InTrash()) { + menu->AddSeparatorItem(); + menu->AddItem(Shortcuts()->CutItem()); + menu->AddItem(Shortcuts()->CopyItem()); + menu->AddItem(Shortcuts()->PasteItem()); + } +} + + +void +TFilePanel::AddWindowMenu(BMenu* menu) +{ + // no window menu on file panel +} + + +void +TFilePanel::AddFavoritesMenu(BMenu* menu) +{ + const char* name = B_TRANSLATE("Add current folder"); + menu->AddItem(new BMenuItem(name, new BMessage(kAddCurrentDir))); + name = B_TRANSLATE("Edit favorites" B_UTF8_ELLIPSIS); + menu->AddItem(new BMenuItem(name, new BMessage(kEditFavorites))); +} + + void TFilePanel::RestoreState() { @@ -961,103 +982,71 @@ TFilePanel::RestoreWindowState(const BMessage &message) void -TFilePanel::AddFileContextMenus(BMenu* menu) +TFilePanel::AddPoseContextMenu(BMenu* menu) { - 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->AddItem(new BMenuItem(B_TRANSLATE("Duplicate"), - new BMessage(kDuplicateSelection), 'D')); - menu->AddItem(new BMenuItem(B_TRANSLATE("Move to Trash"), - new BMessage(kMoveSelectionToTrash), 'T')); + menu->AddItem(Shortcuts()->GetInfoItem()); + menu->AddItem(Shortcuts()->EditNameItem()); + if (TargetModel()->InTrash()) { + menu->AddItem(Shortcuts()->DeleteItem()); + menu->AddItem(Shortcuts()->RestoreItem()); + } else { + menu->AddItem(Shortcuts()->DuplicateItem()); + menu->AddItem(Shortcuts()->MoveToTrashItem()); + } 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); -#if CUT_COPY_PASTE_IN_CONTEXT_MENU - BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"), - new BMessage(B_PASTE), 'V'); - menu->AddItem(pasteItem); -#endif - - menu->SetTargetForItems(PoseView()); - cutItem->SetTarget(this); - copyItem->SetTarget(this); -#if CUT_COPY_PASTE_IN_CONTEXT_MENU - pasteItem->SetTarget(this); + menu->AddItem(Shortcuts()->CutItem()); + menu->AddItem(Shortcuts()->CopyItem()); +#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU + menu->AddItem(Shortcuts()->PasteItem()); #endif } void -TFilePanel::AddVolumeContextMenus(BMenu* menu) +TFilePanel::AddVolumeContextMenu(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->AddItem(Shortcuts()->OpenItem()); + menu->AddItem(Shortcuts()->GetInfoItem()); + menu->AddItem(Shortcuts()->EditNameItem()); -#if CUT_COPY_PASTE_IN_CONTEXT_MENU +#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU menu->AddSeparatorItem(); - BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"), - new BMessage(B_PASTE), 'V'); -#endif - - menu->SetTargetForItems(PoseView()); -#if CUT_COPY_PASTE_IN_CONTEXT_MENU - pasteItem->SetTarget(this); + menu->AddItem(Shortcuts()->PasteItem()); #endif } void -TFilePanel::AddWindowContextMenus(BMenu* menu) +TFilePanel::AddWindowContextMenu(BMenu* menu) { - BMenuItem* item = new BMenuItem(B_TRANSLATE("New folder"), - new BMessage(kNewFolder), 'N'); - item->SetTarget(PoseView()); - menu->AddItem(item); - menu->AddSeparatorItem(); + menu->AddItem(Shortcuts()->NewFolderItem()); + menu->AddItem(new BSeparatorItem()); -#if CUT_COPY_PASTE_IN_CONTEXT_MENU - item = new BMenuItem(B_TRANSLATE("Paste"), new BMessage(B_PASTE), 'V'); - item->SetTarget(this); - menu->AddItem(item); +#ifdef CUT_COPY_PASTE_IN_CONTEXT_MENU + menu->AddItem(Shortcuts()->PasteItem()); menu->AddSeparatorItem(); #endif - 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(this); - menu->AddItem(item); - - item = new BMenuItem(B_TRANSLATE("Invert selection"), - new BMessage(kInvertSelection), 'S'); - item->SetTarget(PoseView()); - menu->AddItem(item); - - item = new BMenuItem(B_TRANSLATE("Go to parent"), - new BMessage(kOpenParentDir), B_UP_ARROW); - item->SetTarget(this); - menu->AddItem(item); + menu->AddItem(Shortcuts()->SelectItem()); + menu->AddItem(Shortcuts()->SelectAllItem()); + menu->AddItem(Shortcuts()->InvertSelectionItem()); + menu->AddItem(Shortcuts()->OpenParentItem()); } void -TFilePanel::AddDropContextMenus(BMenu*) +TFilePanel::AddTrashContextMenu(BMenu* menu) { + // use default window context menu on Trash + AddWindowContextMenu(menu); +} + + +void +TFilePanel::AddDropContextMenu(BMenu*) +{ + // do nothing here so drop context menu doesn't get added } @@ -1073,17 +1062,7 @@ TFilePanel::MenusBeginning() PoseView()->CommitActivePose(); } - EnableNamedMenuItem(fMenuBar, kNewFolder, !TargetModel()->IsRoot() - && !PoseView()->TargetVolumeIsReadOnly()); - EnableNamedMenuItem(fMenuBar, kDuplicateSelection, - PoseView()->CanMoveToTrashOrDuplicate()); - EnableNamedMenuItem(fMenuBar, kMoveSelectionToTrash, - PoseView()->CanMoveToTrashOrDuplicate()); - EnableNamedMenuItem(fMenuBar, kEditItem, PoseView()->CanEditName()); - - SetCutItem(fMenuBar); - SetCopyItem(fMenuBar); - SetPasteItem(fMenuBar); + UpdateMenu(fFileMenu, kFileMenuContext); fIsTrackingMenu = true; } @@ -1097,64 +1076,74 @@ TFilePanel::MenusEnded() void -TFilePanel::ShowContextMenu(BPoint where, const entry_ref* ref) +TFilePanel::DetachSubmenus() { - ASSERT(IsLocked()); - BPoint global(where); - PoseView()->ConvertToScreen(&global); - PoseView()->CommitActivePose(); - - if (ref != NULL) { - // clicked on a pose, show file or volume context menu - Model model(ref); - if (model.InitCheck() != B_OK) - return; // bail out, do not show context menu - - if (TargetModel()->IsRoot() || model.IsVolume()) { - // Volume context menu - fContextMenu = fVolumeContextMenu; - EnableNamedMenuItem(fContextMenu, kOpenSelection, true); - EnableNamedMenuItem(fContextMenu, kEditItem, - PoseView()->CanEditName()); - - SetPasteItem(fContextMenu); - } else { - // File context menu - fContextMenu = fFileContextMenu; - EnableNamedMenuItem(fContextMenu, kEditItem, - PoseView()->CanEditName()); - EnableNamedMenuItem(fContextMenu, kDuplicateSelection, - PoseView()->CanMoveToTrashOrDuplicate()); - EnableNamedMenuItem(fContextMenu, kMoveSelectionToTrash, - PoseView()->CanMoveToTrashOrDuplicate()); - - SetCutItem(fContextMenu); - SetCopyItem(fContextMenu); - SetPasteItem(fContextMenu); - } - } else { - // Window context menu - fContextMenu = fWindowContextMenu; - EnableNamedMenuItem(fContextMenu, kNewFolder, - !TargetModel()->IsRoot() - && !PoseView()->TargetVolumeIsReadOnly()); - EnableNamedMenuItem(fContextMenu, kOpenParentDir, - !TargetModel()->IsRoot()); - - SetPasteItem(fContextMenu); - } - - // context menu invalid or popup window is already open - if (fContextMenu == NULL || fContextMenu->Window() != NULL) - return; - - fContextMenu->Go(global, true, true, true); - fContextMenu = NULL; + // no submenus to detatch in file panel } void -TFilePanel::SetupNavigationMenu(const entry_ref*, BMenu*) +TFilePanel::UpdateFileMenu(BMenu*) +{ + // nothing more to do +} + + +void +TFilePanel::UpdateFileMenuOrPoseContextMenu(BMenu*, MenuContext, const entry_ref*) +{ + // nothing more to do +} + + +void +TFilePanel::UpdateWindowMenu(BMenu*) +{ + // no window menu on file panel +} + + +void +TFilePanel::UpdateWindowContextMenu(BMenu*) +{ + // nothing more to do +} + + +void +TFilePanel::UpdateWindowMenuOrWindowContextMenu(BMenu*, MenuContext) +{ + // nothing more to do +} + + +void +TFilePanel::RepopulateMenus() +{ + if (fMenuBar != NULL && fFileMenu != NULL) { + fMenuBar->RemoveItem(fFileMenu); + delete fFileMenu; + if (ShouldAddMenus()) { + fFileMenu = new BMenu(B_TRANSLATE("File")); + TFilePanel::AddFileMenu(fFileMenu); + fMenuBar->AddItem(fFileMenu, 0); + } + } + + delete fPoseContextMenu; + fPoseContextMenu = new BPopUpMenu("PoseContext", false, false); + fPoseContextMenu->SetFont(be_plain_font); + TFilePanel::AddPoseContextMenu(fPoseContextMenu); + + delete fWindowContextMenu; + fWindowContextMenu = new BPopUpMenu("WindowContext", false, false); + fWindowContextMenu->SetFont(be_plain_font); + TFilePanel::AddWindowContextMenu(fWindowContextMenu); +} + + +void +TFilePanel::SetupNavigationMenu(BMenu*, const entry_ref*) { // do nothing here so nav menu doesn't get added } @@ -1230,84 +1219,77 @@ TFilePanel::MessageReceived(BMessage* message) switch (message->what) { case B_REFS_RECEIVED: + { // item was double clicked in file panel (PoseView) or from the favorites menu - if (message->FindRef("refs", &ref) == B_OK) { - BEntry entry(&ref, true); - if (entry.InitCheck() == B_OK) { - // Double-click on dir or link-to-dir ALWAYS opens the - // dir. If more than one dir is selected, the first is - // entered. - if (entry.IsDirectory()) { - entry.GetRef(&ref); - bool isDesktop = SwitchDirToDesktopIfNeeded(ref); + if (message->FindRef("refs", &ref) != B_OK) + break; - PoseView()->SetIsDesktop(isDesktop); - entry.SetTo(&ref); - PoseView()->SwitchDir(&ref); - SwitchDirMenuTo(&ref); - } else { - // Otherwise, we have a file or a link to a file. - // AdjustButton has already tested the flavor if it comes from the file - // panel; all we have to do is see if the button is enabled. - // In other cases, however, we can't rely on that. So first check for - // TrackerViewToken in the message to see if it's coming from the pose view - if (message->HasMessenger("TrackerViewToken")) { - BButton* button = dynamic_cast(FindView("default button")); - if (button == NULL || !button->IsEnabled()) - break; - } + BEntry entry(&ref, true); + if (entry.InitCheck() != B_OK) + break; - if (IsSavePanel()) { - int32 count = 0; - type_code type; - message->GetInfo("refs", &type, &count); - - // Don't allow saves of multiple files - if (count > 1) { - ShowCenteredAlert( - B_TRANSLATE( - "Sorry, saving more than one " - "item is not allowed."), - B_TRANSLATE("Cancel")); - } else { - // if we are a savepanel, set up the - // filepanel correctly then pass control - // so we follow the same path as if the user - // clicked the save button - - // set the 'name' fld to the current ref's - // name notify the panel that the default - // button should be enabled - SetSaveText(ref.name); - SelectionChanged(); - - HandleSaveButton(); - } - break; - } - - // send handler a message and close - BMessage openMessage(*fMessage); - for (int32 index = 0; ; index++) { - if (message->FindRef("refs", index, &ref) != B_OK) - break; - openMessage.AddRef("refs", &ref); - } - OpenSelectionCommon(&openMessage); - } + // Double-click on dir or link-to-dir ALWAYS opens the dir. + // If more than one dir is selected the first one is opened. + if (entry.IsDirectory()) { + SwitchDirectory(&ref); + } else { + // Otherwise, we have a file or a link to a file. + // AdjustButton has already tested the flavor if it comes from the file + // panel; all we have to do is see if the button is enabled. + // In other cases, however, we can't rely on that. So first check for + // TrackerViewToken in the message to see if it's coming from the pose view + if (message->HasMessenger("TrackerViewToken")) { + BButton* button = dynamic_cast(FindView("default button")); + if (button == NULL || !button->IsEnabled()) + break; } + + if (IsSavePanel()) { + int32 count = 0; + type_code type; + message->GetInfo("refs", &type, &count); + + // Don't allow saves of multiple files + if (count > 1) { + const char* sorry + = B_TRANSLATE("Sorry, saving more than one item is not allowed."); + ShowCenteredAlert(sorry, B_TRANSLATE("Cancel")); + } else { + // if we are a savepanel, set up the + // filepanel correctly then pass control + // so we follow the same path as if the user + // clicked the save button + + // set the 'name' fld to the current ref's + // name notify the panel that the default + // button should be enabled + SetSaveText(ref.name); + SelectionChanged(); + + HandleSaveButton(); + } + break; + } + + // send handler a message and close + BMessage openMessage(*fMessage); + for (int32 index = 0;; index++) { + if (message->FindRef("refs", index, &ref) != B_OK) + break; + openMessage.AddRef("refs", &ref); + } + OpenSelectionCommon(&openMessage); } break; + } case kSwitchDirectory: { entry_ref ref; - // this comes from dir menu or nav menu, so switch directories - if (message->FindRef("refs", &ref) == B_OK) { - BEntry entry(&ref, true); - if (entry.GetRef(&ref) == B_OK) - SetTo(&ref); - } + if (message->FindRef("refs", &ref) != B_OK) + break; + + SwitchDirectory(&ref); break; } @@ -1320,7 +1302,7 @@ TFilePanel::MessageReceived(BMessage* message) break; } - SetTo(&ref); + SwitchDirectory(&ref); break; } @@ -1387,8 +1369,7 @@ TFilePanel::MessageReceived(BMessage* message) if (fIsSavePanel) { if (PoseView()->IsFocus() && PoseView()->CountSelected() == 1) { - Model* model = (PoseView()->SelectionList()-> - FirstItem())->TargetModel(); + Model* model = (PoseView()->SelectionList()->FirstItem())->TargetModel(); if (model->ResolveIfLink()->IsDirectory()) { PoseView()->CommitActivePose(); PoseView()->OpenSelection(); @@ -1404,20 +1385,21 @@ TFilePanel::MessageReceived(BMessage* message) case B_OBSERVER_NOTICE_CHANGE: { int32 observerWhat; - if (message->FindInt32("be:observe_change_what", &observerWhat) - == B_OK) { + if (message->FindInt32("be:observe_change_what", &observerWhat) == B_OK) { switch (observerWhat) { case kDesktopFilePanelRootChanged: { - bool desktopIsRoot = true; - if (message->FindBool("DesktopFilePanelRoot", - &desktopIsRoot) == B_OK) { - TrackerSettings(). - SetDesktopFilePanelRoot(desktopIsRoot); + bool desktopIsRoot; + if (message->FindBool("DesktopFilePanelRoot", &desktopIsRoot) == B_OK + && TrackerSettings().DesktopFilePanelRoot() != desktopIsRoot) { + TrackerSettings().SetDesktopFilePanelRoot(desktopIsRoot); + SwitchDirectory(TargetModel()->EntryRef()); } - SetTo(TargetModel()->EntryRef()); break; } + + default: + break; } } break; @@ -1441,7 +1423,7 @@ TFilePanel::OpenDirectory() if (model->ResolveIfLink()->IsDirectory()) { BMessage message(B_REFS_RECEIVED); message.AddRef("refs", model->EntryRef()); - PostMessage(&message); + BMessenger(this).SendMessage(&message); } } @@ -1449,52 +1431,29 @@ TFilePanel::OpenDirectory() void TFilePanel::OpenParent() { - if (!CanOpenParent()) - return; + BEntry entry(TargetModel()->EntryRef()); + Model oldModel(*PoseView()->TargetModel()); + const node_ref* oldNode = oldModel.NodeRef(); BEntry parentEntry; - BDirectory dir; - - Model oldModel(*PoseView()->TargetModel()); - BEntry entry(oldModel.EntryRef()); - - if (entry.InitCheck() == B_OK - && entry.GetParent(&dir) == B_OK - && dir.GetEntry(&parentEntry) == B_OK - && entry != parentEntry) { - - entry_ref ref; - parentEntry.GetRef(&ref); - - PoseView()->SetIsDesktop(SwitchDirToDesktopIfNeeded(ref)); - PoseView()->SwitchDir(&ref); - SwitchDirMenuTo(&ref); - - // Make sure the child gets selected in the new view - // once it shows up. - fTaskLoop->RunLater(NewMemberFunctionObjectWithResult - (&TFilePanel::SelectChildInParent, this, - const_cast(&ref), - oldModel.NodeRef()), 100000, 200000, 5000000); - } -} - - -bool -TFilePanel::CanOpenParent() const -{ - if (TrackerSettings().DesktopFilePanelRoot()) { - // don't allow opening Desktop folder's parent - if (TargetModel()->IsDesktop()) - return false; + if (TrackerSettings().DesktopFilePanelRoot() && FSIsRootDir(&entry)) { + // open parent on root, set to Desktop + BDirectory desktopDir; + if (FSGetDeskDir(&desktopDir) != B_OK || desktopDir.GetEntry(&parentEntry) != B_OK) + return; + } else if (FSGetParentVirtualDirectoryAware(entry, parentEntry) != B_OK) { + return; } - // block on "/" - BEntry root("/"); - node_ref rootRef; - root.GetNodeRef(&rootRef); + entry_ref setToRef; + parentEntry.GetRef(&setToRef); + const entry_ref* parent = &setToRef; + SwitchDirectory(parent); - return rootRef != *TargetModel()->NodeRef(); + // Make sure the child gets selected in the new view once it shows up. + fTaskLoop->RunLater( + NewMemberFunctionObjectWithResult(&TFilePanel::SelectChildInParent, this, parent, oldNode), + 100000, 200000, 5000000); } @@ -1510,19 +1469,17 @@ TFilePanel::SwitchDirToDesktopIfNeeded(entry_ref &ref) return false; BEntry entry(&ref); - BEntry root("/"); BDirectory desktopDir; FSGetDeskDir(&desktopDir); - if (FSIsDeskDir(&entry) - // navigated into non-boot desktop, switch to boot desktop - || (entry == root && !settings.ShowDisksIcon())) { - // hit "/" level, map to desktop + if (FSIsDeskDir(&entry) || (!settings.ShowDisksIcon() && FSIsRootDir(&entry))) { + // navigated into desktop folder or hit "root" level, switch to Desktop desktopDir.GetEntry(&entry); entry.GetRef(&ref); return true; } + return FSIsDeskDir(&entry); } @@ -1723,25 +1680,6 @@ TFilePanel::HandleOpenButton() } -void -TFilePanel::SwitchDirMenuTo(const entry_ref* ref) -{ - BEntry entry(ref); - for (int32 index = fDirMenu->CountItems() - 1; index >= 0; index--) - delete fDirMenu->RemoveItem(index); - - fDirMenuField->MenuBar()->RemoveItem((int32)0); - fDirMenu->Populate(&entry, 0, true, true, false, true); - - ModelMenuItem* item = dynamic_cast( - fDirMenuField->MenuBar()->ItemAt(0)); - ASSERT(item != NULL); - - if (item != NULL) - item->SetEntry(&entry); -} - - void TFilePanel::WindowActivated(bool active) { @@ -1897,9 +1835,9 @@ BFilePanelPoseView::ShowVolumes(bool visible, bool showShared) AddRootPoses(true, showShared); } - TFilePanel* filepanel = dynamic_cast(Window()); - if (filepanel != NULL && TargetModel() != NULL) - filepanel->SetTo(TargetModel()->EntryRef()); + TFilePanel* panel = dynamic_cast(Window()); + if (panel != NULL && TargetModel() != NULL) + panel->SwitchDirectory(TargetModel()->EntryRef()); } @@ -1912,8 +1850,7 @@ BFilePanelPoseView::AdaptToVolumeChange(BMessage* message) message->FindBool("ShowDisksIcon", &showDisksIcon); message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop); - message->FindBool("MountSharedVolumesOntoDesktop", - &mountSharedVolumesOntoDesktop); + message->FindBool("MountSharedVolumesOntoDesktop", &mountSharedVolumesOntoDesktop); BEntry entry("/"); Model model(&entry); @@ -1931,8 +1868,7 @@ BFilePanelPoseView::AdaptToVolumeChange(BMessage* message) monitorMsg.AddInt64("directory", model.EntryRef()->directory); monitorMsg.AddString("name", model.EntryRef()->name); TrackerSettings().SetShowDisksIcon(showDisksIcon); - if (Window() != NULL) - Window()->PostMessage(&monitorMsg, this); + Window()->PostMessage(&monitorMsg, this); } ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop); @@ -1946,8 +1882,7 @@ BFilePanelPoseView::AdaptToDesktopIntegrationChange(BMessage* message) bool mountSharedVolumesOntoDesktop = true; message->FindBool("MountVolumesOntoDesktop", &mountVolumesOnDesktop); - message->FindBool("MountSharedVolumesOntoDesktop", - &mountSharedVolumesOntoDesktop); + message->FindBool("MountSharedVolumesOntoDesktop", &mountSharedVolumesOntoDesktop); ShowVolumes(false, mountSharedVolumesOntoDesktop); ShowVolumes(mountVolumesOnDesktop, mountSharedVolumesOntoDesktop); diff --git a/src/kits/tracker/FilePanelPriv.h b/src/kits/tracker/FilePanelPriv.h index bfbc000bfa..341a48a397 100644 --- a/src/kits/tracker/FilePanelPriv.h +++ b/src/kits/tracker/FilePanelPriv.h @@ -73,14 +73,13 @@ public: virtual void MenusBeginning(); virtual void MenusEnded(); virtual void DispatchMessage(BMessage* message, BHandler* handler); - virtual void ShowContextMenu(BPoint, const entry_ref*); void SetClientObject(BFilePanel*); void SetRefFilter(BRefFilter*); void SetNodeFlavors(uint32 nodeFlavors) { fNodeFlavors = nodeFlavors; } void SetSaveText(const char* text); void SetButtonLabel(file_panel_button, const char* text); - void SetTo(const entry_ref* ref); + virtual void SwitchDirectory(const entry_ref*); virtual void SelectionChanged(); void HandleOpenButton(); void HandleSaveButton(); @@ -115,12 +114,26 @@ protected: virtual void RestoreWindowState(const BMessage&); virtual void RestoreState(const BMessage&); - virtual void AddFileContextMenus(BMenu*); - virtual void AddVolumeContextMenus(BMenu*); - virtual void AddWindowContextMenus(BMenu*); - virtual void AddDropContextMenus(BMenu*); + virtual void AddMenus(); + virtual void AddFileMenu(BMenu* menu); + virtual void AddWindowMenu(BMenu* menu); + virtual void AddFavoritesMenu(BMenu* menu); - virtual void SetupNavigationMenu(const entry_ref*, BMenu*); + virtual void AddPoseContextMenu(BMenu*); + virtual void AddVolumeContextMenu(BMenu*); + virtual void AddWindowContextMenu(BMenu*); + virtual void AddDropContextMenu(BMenu*); + virtual void AddTrashContextMenu(BMenu*); + + virtual void UpdateFileMenu(BMenu*); + virtual void UpdateFileMenuOrPoseContextMenu(BMenu*, MenuContext, const entry_ref* = NULL); + virtual void UpdateWindowMenu(BMenu*); + virtual void UpdateWindowContextMenu(BMenu*); + virtual void UpdateWindowMenuOrWindowContextMenu(BMenu*, MenuContext); + + virtual void DetachSubmenus(); + virtual void RepopulateMenus(); + virtual void SetupNavigationMenu(BMenu*, const entry_ref*); virtual void OpenDirectory(); virtual void OpenParent(); virtual void WindowActivated(bool state); @@ -134,8 +147,6 @@ protected: private: bool SwitchDirToDesktopIfNeeded(entry_ref &ref); - bool CanOpenParent() const; - void SwitchDirMenuTo(const entry_ref* ref); void AdjustButton(); bool SelectChildInParent(const entry_ref* parent, const node_ref* child); void OpenSelectionCommon(BMessage*); @@ -150,6 +161,7 @@ private: BFilePanel* fClientObject; int32 fSelectionIterator; BMessage* fMessage; + BMenu* fFavoritesMenu; BString fButtonText; bool fHideWhenDone; bool fIsTrackingMenu; diff --git a/src/kits/tracker/Jamfile b/src/kits/tracker/Jamfile index f9fead87f7..f29fa14677 100644 --- a/src/kits/tracker/Jamfile +++ b/src/kits/tracker/Jamfile @@ -74,6 +74,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { SelectionWindow.cpp Settings.cpp SettingsViews.cpp + Shortcuts.cpp SlowMenu.cpp StatusWindow.cpp TaskLoop.cpp @@ -138,6 +139,7 @@ DoCatalogs libtracker.so : RegExp.cpp SelectionWindow.cpp SettingsViews.cpp + Shortcuts.cpp StatusWindow.cpp TemplatesMenu.cpp TextWidget.cpp diff --git a/src/kits/tracker/PoseView.cpp b/src/kits/tracker/PoseView.cpp index 3734df9f49..1703e7078c 100644 --- a/src/kits/tracker/PoseView.cpp +++ b/src/kits/tracker/PoseView.cpp @@ -92,6 +92,7 @@ All rights reserved. #include "MimeTypes.h" #include "Navigator.h" #include "Pose.h" +#include "Shortcuts.h" #include "Tests.h" #include "Thread.h" #include "Tracker.h" @@ -1656,7 +1657,7 @@ void BPoseView::AddPosesCompleted() { BContainerWindow* window = ContainerWindow(); - if (window != NULL) + if (window != NULL && window->ShouldAddMenus()) window->AddMimeTypesToMenu(); // if we're not in icon mode then we need to check for poses that @@ -2440,7 +2441,7 @@ BPoseView::MessageReceived(BMessage* message) IdentifySelection(message->GetBool("force", false)); break; - case kEditItem: + case kEditName: { if (ActivePose()) break; @@ -6232,17 +6233,14 @@ BPoseView::DeleteSelection(bool selectNext, bool confirm) if (selectCount <= 0) return; - if (!CheckVolumeReadOnly( - fSelectionList->ItemAt(0)->TargetModel()->EntryRef())) { + if (!CheckVolumeReadOnly(fSelectionList->ItemAt(0)->TargetModel()->EntryRef())) return; - } - BObjectList* entriesToDelete - = new BObjectList(selectCount, true); + BObjectList* entriesToDelete = new BObjectList(selectCount, true); for (int32 index = 0; index < selectCount; index++) { - entriesToDelete->AddItem(new entry_ref( - *fSelectionList->ItemAt(index)->TargetModel()->EntryRef())); + entry_ref* ref = new entry_ref(*fSelectionList->ItemAt(index)->TargetModel()->EntryRef()); + entriesToDelete->AddItem(ref); } Delete(entriesToDelete, selectNext, confirm); @@ -6271,8 +6269,7 @@ BPoseView::RestoreSelectionFromTrash(bool selectNext) void BPoseView::Delete(const entry_ref &ref, bool selectNext, bool confirm) { - BObjectList* entriesToDelete - = new BObjectList(1, true); + BObjectList* entriesToDelete = new BObjectList(1, true); entriesToDelete->AddItem(new entry_ref(ref)); Delete(entriesToDelete, selectNext, confirm); @@ -6287,8 +6284,7 @@ BPoseView::Delete(BObjectList* list, bool selectNext, bool confirm) return; } - BObjectList* taskList = - new BObjectList(2, true); + BObjectList* taskList = new BObjectList(2, true); // first move selection to trash, taskList->AddItem(NewFunctionObject(FSDeleteRefList, list, false, confirm)); @@ -6311,8 +6307,7 @@ BPoseView::Delete(BObjectList* list, bool selectNext, bool confirm) // deleted Model* targetModel = TargetModel(); ASSERT(targetModel != NULL); - taskList->AddItem(NewMemberFunctionObject( - &TTracker::SelectPoseAtLocationSoon, tracker, + taskList->AddItem(NewMemberFunctionObject(&TTracker::SelectPoseAtLocationSoon, tracker, *targetModel->NodeRef(), pointInPose)); } } @@ -6330,8 +6325,7 @@ BPoseView::RestoreItemsFromTrash(BObjectList* list, bool selectNext) return; } - BObjectList* taskList = - new BObjectList(2, true); + BObjectList* taskList = new BObjectList(2, true); // first restoree selection taskList->AddItem(NewFunctionObject(FSRestoreRefList, list, false)); @@ -6354,8 +6348,7 @@ BPoseView::RestoreItemsFromTrash(BObjectList* list, bool selectNext) // restored Model* targetModel = TargetModel(); ASSERT(targetModel != NULL); - taskList->AddItem(NewMemberFunctionObject( - &TTracker::SelectPoseAtLocationSoon, tracker, + taskList->AddItem(NewMemberFunctionObject(&TTracker::SelectPoseAtLocationSoon, tracker, *targetModel->NodeRef(), pointInPose)); } } @@ -6391,8 +6384,7 @@ BPoseView::DoMoveToTrash() if (TargetModel()->IsTrash()) return DeleteSelection(true, false); - bool shiftDown = (Window()->CurrentMessage()->FindInt32("modifiers") - & B_SHIFT_KEY) != 0; + bool shiftDown = (Window()->CurrentMessage()->FindInt32("modifiers") & B_SHIFT_KEY) != 0; if (shiftDown) DeleteSelection(); else @@ -6751,7 +6743,7 @@ BPoseView::KeyDown(const char* bytes, int32 count) if (message != NULL) { int32 key; if (message->FindInt32("key", &key) == B_OK && key == B_F2_KEY) - Window()->PostMessage(kEditItem, this); + Window()->PostMessage(kEditName, this); } break; } @@ -7472,7 +7464,7 @@ BPoseView::WasClickInPath(const BPose* pose, int32 index, if (entry.GetRef(&ref) == B_OK) { BMessage message(B_REFS_RECEIVED); message.AddRef("refs", &ref); - be_app->PostMessage(&message); + Window()->PostMessage(&message); return true; } @@ -8596,54 +8588,53 @@ BPoseView::SetDefaultPrinter() void BPoseView::OpenParent() { - if (ParentIsRoot()) + if (!CanOpenParent()) return; - BEntry entry(TargetModel()->EntryRef()); - entry_ref ref; - if (FSGetParentVirtualDirectoryAware(entry, entry) != B_OK || entry.GetRef(&ref) != B_OK) - return; - - BMessage message(B_REFS_RECEIVED); - message.AddRef("refs", &ref); - - if (dynamic_cast(be_app) != NULL) { - // add information about the child, so that we can select it in the parent view - message.AddData("nodeRefToSelect", B_RAW_TYPE, TargetModel()->NodeRef(), sizeof(node_ref)); - - if ((modifiers() & B_OPTION_KEY) != 0 && !IsFilePanel()) { - // if option down, add instructions to close the parent - message.AddData("nodeRefsToClose", B_RAW_TYPE, TargetModel()->NodeRef(), - sizeof(node_ref)); - } - } - - if (TrackerSettings().SingleWindowBrowse()) { - BMessage msg(kSwitchDirectory); - msg.AddRef("refs", &ref); - Window()->PostMessage(&msg); - } else { - be_app->PostMessage(&message); - } + BMessage message(kOpenParentDir); + message.AddRef("refs", TargetModel()->EntryRef()); + Window()->PostMessage(&message); } bool -BPoseView::ParentIsRoot() +BPoseView::CanOpenParent() { - if (IsDesktop() || TargetModel()->IsRoot()) - return true; + TrackerSettings settings; + BEntry entry(TargetModel()->EntryRef()); + + // first determine if current entry is root + if (IsFilePanel()) { + if (settings.DesktopFilePanelRoot()) { + if (TargetModel()->IsDesktop()) + return false; + } else if (TargetModel()->IsRoot()) { + return false; + } + } else { + // deny Desktop, allow Desktop folder + if (IsDesktop() || TargetModel()->IsRoot()) + return false; + } // override by holding control key if ((modifiers() & B_CONTROL_KEY) != 0) + return true; + + // file panel can go below root to Desktop + if (IsFilePanel() && settings.DesktopFilePanelRoot()) + return true; + + BEntry parentEntry; + if (FSGetParentVirtualDirectoryAware(entry, parentEntry) != B_OK) return false; - BEntry entry(TargetModel()->EntryRef()); - bool isRoot = FSGetParentVirtualDirectoryAware(entry, entry) == B_OK && FSIsRootDir(&entry); - if (isRoot && (TrackerSettings().SingleWindowBrowse() || TrackerSettings().ShowDisksIcon())) - return false; + // if show disks is on still one more level to go + bool parentIsRoot = FSIsRootDir(&parentEntry); + if (parentIsRoot && settings.ShowDisksIcon()) + return true; - return isRoot; + return !parentIsRoot; } @@ -8692,8 +8683,7 @@ BPoseView::ClearSelection() break; } } else { - int32 startIndex = FirstIndexAtOrBelow( - (int32)(bounds.top - IconPoseHeight()), true); + int32 startIndex = FirstIndexAtOrBelow((int32)(bounds.top - IconPoseHeight()), true); int32 poseCount = fVSPoseList->CountItems(); for (int32 index = startIndex; index < poseCount; index++) { BPose* pose = fVSPoseList->ItemAt(index); @@ -8758,8 +8748,7 @@ BPoseView::ShowSelection(bool show) break; } } else { - int32 startIndex = FirstIndexAtOrBelow( - (int32)(bounds.top - IconPoseHeight()), true); + int32 startIndex = FirstIndexAtOrBelow((int32)(bounds.top - IconPoseHeight()), true); int32 poseCount = fVSPoseList->CountItems(); for (int32 index = startIndex; index < poseCount; index++) { BPose* pose = fVSPoseList->ItemAt(index); diff --git a/src/kits/tracker/PoseView.h b/src/kits/tracker/PoseView.h index c52e049a0f..eb19c5f398 100644 --- a/src/kits/tracker/PoseView.h +++ b/src/kits/tracker/PoseView.h @@ -276,7 +276,7 @@ public: void UnmountSelectedVolumes(); virtual void OpenParent(); - virtual bool ParentIsRoot(); + virtual bool CanOpenParent(); virtual void OpenSelection(BPose* clicked_pose = NULL, int32* index = NULL); diff --git a/src/kits/tracker/QueryContainerWindow.cpp b/src/kits/tracker/QueryContainerWindow.cpp index 63aaf05f69..2f15548025 100644 --- a/src/kits/tracker/QueryContainerWindow.cpp +++ b/src/kits/tracker/QueryContainerWindow.cpp @@ -46,6 +46,7 @@ All rights reserved. #include "Commands.h" #include "QueryContainerWindow.h" #include "QueryPoseView.h" +#include "Shortcuts.h" // #pragma mark - BQueryContainerWindow @@ -93,28 +94,23 @@ BQueryContainerWindow::AddWindowMenu(BMenu* menu) { BMenuItem* item; - item = new BMenuItem(B_TRANSLATE("Resize to fit"), - new BMessage(kResizeToFit), 'Y'); + item = Shortcuts()->ResizeToFitItem(); item->SetTarget(this); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Select" B_UTF8_ELLIPSIS), - new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY); + item = Shortcuts()->SelectItem(); item->SetTarget(PoseView()); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Select all"), - new BMessage(B_SELECT_ALL), 'A'); + item = Shortcuts()->SelectAllItem(); item->SetTarget(PoseView()); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Invert selection"), - new BMessage(kInvertSelection), 'S'); + item = Shortcuts()->InvertSelectionItem(); item->SetTarget(PoseView()); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Close"), - new BMessage(B_QUIT_REQUESTED), 'W'); + item = Shortcuts()->CloseItem(); item->SetTarget(this); menu->AddItem(item); } @@ -123,15 +119,11 @@ BQueryContainerWindow::AddWindowMenu(BMenu* menu) void BQueryContainerWindow::AddWindowContextMenus(BMenu* menu) { - BMenuItem* resizeItem = new BMenuItem(B_TRANSLATE("Resize to fit"), - new BMessage(kResizeToFit), 'Y'); + BMenuItem* resizeItem = Shortcuts()->ResizeToFitItem(); menu->AddItem(resizeItem); - 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')); - BMenuItem* closeItem = new BMenuItem(B_TRANSLATE("Close"), - new BMessage(B_QUIT_REQUESTED), 'W'); + menu->AddItem(Shortcuts()->SelectItem()); + menu->AddItem(Shortcuts()->SelectAllItem()); + BMenuItem* closeItem = Shortcuts()->CloseItem(); menu->AddItem(closeItem); // target items as needed diff --git a/src/kits/tracker/Shortcuts.cpp b/src/kits/tracker/Shortcuts.cpp new file mode 100644 index 0000000000..b349faee3c --- /dev/null +++ b/src/kits/tracker/Shortcuts.cpp @@ -0,0 +1,1488 @@ +/* + * Copyright 2020-2024 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ + + +#include "Shortcuts.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Commands.h" +#include "FSClipboard.h" +#include "FSUtils.h" +#include "Model.h" +#include "Pose.h" +#include "Tracker.h" +#include "TrackerSettings.h" +#include "Utilities.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "ContainerWindow" + + +TShortcuts::TShortcuts() + : + fContainerWindow(NULL), + fInWindow(false) +{ + // the dumb version: for adding and limited updates +} + + +TShortcuts::TShortcuts(BContainerWindow* window) + : + fContainerWindow(window), + fInWindow(window != NULL) +{ + // the smart version: update methods work +} + + +// #pragma mark - Shortcuts build methods + + +BMenuItem* +TShortcuts::AddOnsItem() +{ + return new BMenuItem(AddOnsLabel(), NULL); +} + + +const char* +TShortcuts::AddOnsLabel() +{ + return B_TRANSLATE("Add-ons"); +} + + +BMenuItem* +TShortcuts::AddPrinterItem() +{ + return new BMenuItem(AddPrinterLabel(), new BMessage(kAddPrinter)); +} + + +const char* +TShortcuts::AddPrinterLabel() +{ + return B_TRANSLATE("Add printer" B_UTF8_ELLIPSIS); +} + + +BMenuItem* +TShortcuts::ArrangeByItem() +{ + return new BMenuItem(ArrangeByLabel(), NULL); +} + + +const char* +TShortcuts::ArrangeByLabel() +{ + return B_TRANSLATE("Arrange by"); +} + + +BMenuItem* +TShortcuts::CleanupItem() +{ + return new BMenuItem(CleanupLabel(), new BMessage(kCleanup), 'K'); +} + + +const char* +TShortcuts::CleanupLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Clean up all"); + else + return B_TRANSLATE("Clean up"); +} + + +int32 +TShortcuts::CleanupCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kCleanupAll; + else + return kCleanup; +} + + +BMenuItem* +TShortcuts::CloseItem() +{ + return new BMenuItem(CloseLabel(), new BMessage(B_QUIT_REQUESTED), 'W'); +} + + +const char* +TShortcuts::CloseLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Close all"); + else + return B_TRANSLATE("Close"); +} + + +int32 +TShortcuts::CloseCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kCloseAllWindows; + else + return B_QUIT_REQUESTED; +} + + +BMenuItem* +TShortcuts::CloseAllInWorkspaceItem() +{ + return new BMenuItem(CloseAllInWorkspaceLabel(), new BMessage(kCloseAllInWorkspace), 'Q'); +} + + +const char* +TShortcuts::CloseAllInWorkspaceLabel() +{ + return B_TRANSLATE("Close all in workspace"); +} + + +BMenuItem* +TShortcuts::CopyItem() +{ + return new BMenuItem(CopyLabel(), new BMessage(B_COPY), 'C'); +} + + +const char* +TShortcuts::CopyLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Copy more"); + else + return B_TRANSLATE("Copy"); +} + + +int32 +TShortcuts::CopyCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kCopyMoreSelectionToClipboard; + else + return B_COPY; +} + + +BMenuItem* +TShortcuts::CopyToItem() +{ + return new BMenuItem(CopyToLabel(), new BMessage(kCopySelectionTo)); +} + + +BMenuItem* +TShortcuts::CopyToItem(BMenu* menu) +{ + return new BMenuItem(menu, new BMessage(kCopySelectionTo)); +} + + +const char* +TShortcuts::CopyToLabel() +{ + return B_TRANSLATE("Copy to"); +} + + +BMenuItem* +TShortcuts::CreateLinkItem() +{ + return new BMenuItem(CreateLinkLabel(), new BMessage(kCreateLink)); +} + + +BMenuItem* +TShortcuts::CreateLinkItem(BMenu* menu) +{ + return new BMenuItem(menu, new BMessage(kCreateLink)); +} + + +const char* +TShortcuts::CreateLinkLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Create relative link"); + else + return B_TRANSLATE("Create link"); +} + + +int32 +TShortcuts::CreateLinkCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kCreateRelativeLink; + else + return kCreateLink; +} + + +BMenuItem* +TShortcuts::CreateLinkHereItem() +{ + return new BMenuItem(CreateLinkHereLabel(), new BMessage(kCreateLink)); +} + + +const char* +TShortcuts::CreateLinkHereLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Create relative link here"); + else + return B_TRANSLATE("Create link here"); +} + + +int32 +TShortcuts::CreateLinkHereCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kCreateRelativeLink; + else + return kCreateLink; +} + + +BMenuItem* +TShortcuts::CutItem() +{ + return new BMenuItem(CutLabel(), new BMessage(B_CUT), 'X'); +} + + +const char* +TShortcuts::CutLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Cut more"); + else + return B_TRANSLATE("Cut"); +} + + +int32 +TShortcuts::CutCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kCutMoreSelectionToClipboard; + else + return B_CUT; +} + + +BMenuItem* +TShortcuts::DeleteItem() +{ + return new BMenuItem(DeleteLabel(), new BMessage(kDeleteSelection)); +} + + +const char* +TShortcuts::DeleteLabel() +{ + return B_TRANSLATE("Delete"); +} + + +BMenuItem* +TShortcuts::DuplicateItem() +{ + return new BMenuItem(DuplicateLabel(), new BMessage(kDuplicateSelection), 'D'); +} + + +const char* +TShortcuts::DuplicateLabel() +{ + return B_TRANSLATE("Duplicate"); +} + + +BMenuItem* +TShortcuts::EditNameItem() +{ + return new BMenuItem(EditNameLabel(), new BMessage(kEditName), 'E'); +} + + +const char* +TShortcuts::EditNameLabel() +{ + return B_TRANSLATE("Edit name"); +} + + +BMenuItem* +TShortcuts::EditQueryItem() +{ + return new BMenuItem(EditQueryLabel(), new BMessage(kEditQuery), 'G'); +} + + +const char* +TShortcuts::EditQueryLabel() +{ + return B_TRANSLATE("Edit query"); +} + + +BMenuItem* +TShortcuts::EmptyTrashItem() +{ + return new BMenuItem(EmptyTrashLabel(), new BMessage(kEmptyTrash)); +} + + +const char* +TShortcuts::EmptyTrashLabel() +{ + return B_TRANSLATE("Empty Trash"); +} + + +BMenuItem* +TShortcuts::FindItem() +{ + return new BMenuItem(FindLabel(), new BMessage(kFindButton), 'F'); +} + + +const char* +TShortcuts::FindLabel() +{ + return B_TRANSLATE("Find" B_UTF8_ELLIPSIS); +} + + +BMenuItem* +TShortcuts::GetInfoItem() +{ + return new BMenuItem(GetInfoLabel(), new BMessage(kGetInfo), 'I'); +} + + +const char* +TShortcuts::GetInfoLabel() +{ + return B_TRANSLATE("Get info"); +} + + +BMenuItem* +TShortcuts::IdentifyItem() +{ + BMessage* message = new BMessage(kIdentifyEntry); + BMenuItem* item = new BMenuItem(IdentifyLabel(), message); + message->AddBool("force", (modifiers() & B_SHIFT_KEY) != 0); + + if (fInWindow) + item->SetTarget(PoseView()); + + return item; +} + + +const char* +TShortcuts::IdentifyLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Force identify"); + else + return B_TRANSLATE("Identify"); +} + + +BMenuItem* +TShortcuts::InvertSelectionItem() +{ + return new BMenuItem(InvertSelectionLabel(), new BMessage(kInvertSelection), 'S'); +} + + +const char* +TShortcuts::InvertSelectionLabel() +{ + return B_TRANSLATE("Invert selection"); +} + + +BMenuItem* +TShortcuts::MakeActivePrinterItem() +{ + return new BMenuItem(MakeActivePrinterLabel(), new BMessage(kMakeActivePrinter)); +} + + +const char* +TShortcuts::MakeActivePrinterLabel() +{ + return B_TRANSLATE("Make active printer"); +} + + +BMenuItem* +TShortcuts::MountItem() +{ + return new BMenuItem(MountLabel(), new BMessage(kMountVolume)); +} + + +BMenuItem* +TShortcuts::MountItem(BMenu* menu) +{ + return new BMenuItem(menu, new BMessage(kMountVolume)); +} + + +const char* +TShortcuts::MountLabel() +{ + return B_TRANSLATE("Mount"); +} + + +BMenuItem* +TShortcuts::MoveToItem() +{ + return new BMenuItem(MoveToLabel(), new BMessage(kMoveSelectionTo)); +} + + +BMenuItem* +TShortcuts::MoveToItem(BMenu* menu) +{ + return new BMenuItem(menu, new BMessage(kMoveSelectionTo)); +} + + +const char* +TShortcuts::MoveToLabel() +{ + return B_TRANSLATE("Move to"); +} + + +BMenuItem* +TShortcuts::MoveToTrashItem() +{ + return new BMenuItem(MoveToTrashLabel(), new BMessage(kMoveSelectionToTrash), 'T'); +} + + +const char* +TShortcuts::MoveToTrashLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Delete"); + else + return B_TRANSLATE("Move to Trash"); +} + + +int32 +TShortcuts::MoveToTrashCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kDeleteSelection; + else + return kMoveSelectionToTrash; +} + + +BMenuItem* +TShortcuts::NewFolderItem() +{ + return new BMenuItem(NewFolderLabel(), new BMessage(kNewFolder), 'N'); +} + + +const char* +TShortcuts::NewFolderLabel() +{ + return B_TRANSLATE("New folder"); +} + + +BMenuItem* +TShortcuts::NewTemplatesItem() +{ + return new BMenuItem(B_TRANSLATE("New"), new BMessage(kNewEntryFromTemplate)); +} + + +BMenuItem* +TShortcuts::NewTemplatesItem(BMenu* menu) +{ + return new BMenuItem(menu, new BMessage(kNewEntryFromTemplate)); +} + + +const char* +TShortcuts::NewTemplatesLabel() +{ + return B_TRANSLATE("New"); +} + + +BMenuItem* +TShortcuts::OpenItem() +{ + return new BMenuItem(OpenLabel(), new BMessage(kOpenSelection), 'O'); +} + + +const char* +TShortcuts::OpenLabel() +{ + return B_TRANSLATE("Open"); +} + + +BMenuItem* +TShortcuts::OpenParentItem() +{ + return new BMenuItem(OpenParentLabel(), new BMessage(kOpenParentDir), B_UP_ARROW); +} + + +const char* +TShortcuts::OpenParentLabel() +{ + return B_TRANSLATE("Open parent"); +} + + +BMenuItem* +TShortcuts::OpenWithItem() +{ + return new BMenuItem(OpenWithLabel(), new BMessage(kOpenSelectionWith)); +} + + +BMenuItem* +TShortcuts::OpenWithItem(BMenu* menu) +{ + return new BMenuItem(menu, new BMessage(kOpenSelectionWith)); +} + + +const char* +TShortcuts::OpenWithLabel() +{ + return B_TRANSLATE("Open with" B_UTF8_ELLIPSIS); +} + + +BMenuItem* +TShortcuts::PasteItem() +{ + return new BMenuItem(PasteLabel(), new BMessage(B_PASTE), 'V'); +} + + +const char* +TShortcuts::PasteLabel() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return B_TRANSLATE("Paste links"); + else + return B_TRANSLATE("Paste"); +} + + +int32 +TShortcuts::PasteCommand() +{ + if ((modifiers() & B_SHIFT_KEY) != 0) + return kPasteLinksFromClipboard; + else + return B_PASTE; +} + + +BMenuItem* +TShortcuts::ResizeToFitItem() +{ + return new BMenuItem(ResizeToFitLabel(), new BMessage(kResizeToFit), 'Y'); +} + + +const char* +TShortcuts::ResizeToFitLabel() +{ + return B_TRANSLATE("Resize to fit"); +} + + +BMenuItem* +TShortcuts::RestoreItem() +{ + return new BMenuItem(RestoreLabel(), new BMessage(kRestoreSelectionFromTrash)); +} + + +const char* +TShortcuts::RestoreLabel() +{ + return B_TRANSLATE("Restore"); +} + + +BMenuItem* +TShortcuts::ReverseOrderItem() +{ + return new BMenuItem(ReverseOrderLabel(), new BMessage(kArrangeReverseOrder)); +} + + +const char* +TShortcuts::ReverseOrderLabel() +{ + return B_TRANSLATE("Reverse order"); +} + + +BMenuItem* +TShortcuts::SelectItem() +{ + return new BMenuItem(SelectLabel(), new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY); +} + + +const char* +TShortcuts::SelectLabel() +{ + return B_TRANSLATE("Select" B_UTF8_ELLIPSIS); +} + + +BMenuItem* +TShortcuts::SelectAllItem() +{ + return new BMenuItem(SelectAllLabel(), new BMessage(B_SELECT_ALL), 'A', B_SHIFT_KEY); +} + + +const char* +TShortcuts::SelectAllLabel() +{ + return B_TRANSLATE("Select all"); +} + + +BMenuItem* +TShortcuts::UnmountItem() +{ + return new BMenuItem(UnmountLabel(), new BMessage(kUnmountVolume), 'U'); +} + + +const char* +TShortcuts::UnmountLabel() +{ + return B_TRANSLATE("Unmount"); +} + + +// #pragma mark - Shortcuts update methods + + +void +TShortcuts::Update(BMenu* menu) +{ + if (menu == NULL) + return; + + int32 itemCount = menu->CountItems(); + for (int32 index = 0; index < itemCount; index++) { + BMenuItem* item = menu->ItemAt(index); + if (item == NULL || item->Message() == NULL) + continue; + + switch (item->Message()->what) { + case kAddPrinter: + UpdateAddPrinterItem(item); + break; + + case kCleanup: + case kCleanupAll: + UpdateCleanupItem(item); + break; + + case B_COPY: + case kCopyMoreSelectionToClipboard: + UpdateCopyItem(item); + break; + + case kCopySelectionTo: + UpdateCopyToItem(item); + break; + + case kCreateLink: + case kCreateRelativeLink: + UpdateCreateLinkItem(item); + break; + + case B_CUT: + case kCutMoreSelectionToClipboard: + UpdateCutItem(item); + break; + + case kDeleteSelection: + // delete command used by a different item in Trash + if (IsTrash() || InTrash()) + UpdateDeleteItem(item); + else + UpdateMoveToTrashItem(item); + break; + + case kDuplicateSelection: + UpdateDuplicateItem(item); + break; + + case kEditName: + UpdateEditNameItem(item); + break; + + case kEditQuery: + UpdateEditQueryItem(item); + break; + + case kEmptyTrash: + UpdateEmptyTrashItem(item); + break; + + case kFindButton: + UpdateFindItem(item); + break; + + case kGetInfo: + UpdateGetInfoItem(item); + break; + + case kIdentifyEntry: + UpdateIdentifyItem(item); + break; + + case kInvertSelection: + UpdateInvertSelectionItem(item); + break; + + case kMakeActivePrinter: + UpdateMakeActivePrinterItem(item); + break; + + case kMoveSelectionTo: + UpdateMoveToItem(item); + break; + + case kMoveSelectionToTrash: + UpdateMoveToTrashItem(item); + break; + + case kNewFolder: + UpdateNewFolderItem(item); + break; + + case kNewEntryFromTemplate: + UpdateNewTemplatesItem(item); + break; + + case kOpenSelection: + UpdateOpenItem(item); + break; + + case kOpenParentDir: + UpdateOpenParentItem(item); + break; + + case B_PASTE: + case kPasteLinksFromClipboard: + UpdatePasteItem(item); + break; + + case kResizeToFit: + UpdateResizeToFitItem(item); + break; + + case kRestoreSelectionFromTrash: + UpdateRestoreItem(item); + break; + + case kArrangeReverseOrder: + UpdateReverseOrderItem(item); + break; + + case B_SELECT_ALL: + UpdateSelectAllItem(item); + break; + + case kShowSelectionWindow: + UpdateSelectItem(item); + break; + + case B_QUIT_REQUESTED: + case kCloseAllWindows: + UpdateCloseItem(item); + break; + + case kCloseAllInWorkspace: + UpdateCloseAllInWorkspaceItem(item); + break; + + case kUnmountVolume: + UpdateUnmountItem(item); + break; + + default: + break; + } + } +} + + +void +TShortcuts::UpdateAddOnsItem(BMenuItem* item) +{ + if (item == NULL || item->Submenu() == NULL) + return; + + item->SetEnabled(item->Submenu()->CountItems() > 0); + + if (fInWindow) + item->Submenu()->SetTargetForItems(fContainerWindow); +} + + +void +TShortcuts::UpdateAddPrinterItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetEnabled(true); + item->SetTarget(be_app); +} + + +void +TShortcuts::UpdateArrangeByItem(BMenuItem* item) +{ + if (item == NULL || item->Submenu() == NULL) + return; + + if (fInWindow) { + item->SetEnabled(PoseView()->ViewMode() != kListMode); + item->Submenu()->SetTargetForItems(PoseView()); + } +} + + +void +TShortcuts::UpdateCleanupItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(CleanupLabel()); + item->Message()->what = CleanupCommand(); + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY | (modifiers() & B_SHIFT_KEY)); + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateCloseAllInWorkspaceItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetEnabled(true); + item->SetTarget(be_app); +} + + +void +TShortcuts::UpdateCloseItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(CloseLabel()); + item->Message()->what = CloseCommand(); + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY | (modifiers() & B_SHIFT_KEY)); + + if (fInWindow) { + if ((modifiers() & B_SHIFT_KEY) != 0) + item->SetTarget(be_app); + else + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateCopyItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(CopyLabel()); + item->Message()->what = CopyCommand(); + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY | (modifiers() & B_SHIFT_KEY)); + + if (fInWindow) { + item->SetEnabled(IsCurrentFocusOnTextView() || HasSelection()); + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateCopyToItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateCreateLinkItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(CreateLinkLabel()); + item->Message()->what = CreateLinkCommand(); + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateCreateLinkHereItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(CreateLinkHereLabel()); + item->Message()->what = CreateLinkHereCommand(); + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateCutItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(CutLabel()); + item->Message()->what = CutCommand(); + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY | (modifiers() & B_SHIFT_KEY)); + + if (fInWindow) { + if (IsCurrentFocusOnTextView()) + item->SetEnabled(true); + else if (IsRoot() || IsTrash() || IsVirtualDirectory()) + item->SetEnabled(false); + else + item->SetEnabled(HasSelection() && TargetIsReadOnly() == false); + + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateDeleteItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(B_TRANSLATE("Delete")); + item->Message()->what = kDeleteSelection; + if (item->Shortcut() != 0) + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY); + + if (fInWindow) { + item->SetEnabled(HasSelection() && !SelectionIsReadOnly()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateDuplicateItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(PoseView()->CanMoveToTrashOrDuplicate()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateEditNameItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(PoseView()->CanEditName()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateEditQueryItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateEmptyTrashItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(static_cast(be_app)->TrashFull()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateFindItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateGetInfoItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateIdentifyItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(IdentifyLabel()); + item->Message()->ReplaceBool("force", (modifiers() & B_SHIFT_KEY) != 0); + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateInvertSelectionItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateMakeActivePrinterItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(PoseView()->CountSelected() == 1); + item->SetTarget(be_app); + } +} + + +void +TShortcuts::UpdateMoveToItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(HasSelection() && !SelectionIsReadOnly()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateMoveToTrashItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (item->Shortcut() == 0) { + // make sure this is the real Move to Trash item, not the Delete item in Trash + item->SetLabel(B_TRANSLATE("Delete")); + item->Message()->what = kDeleteSelection; + } else { + item->SetLabel(MoveToTrashLabel()); + item->Message()->what = MoveToTrashCommand(); + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY | (modifiers() & B_SHIFT_KEY)); + } + + if (fInWindow) { + item->SetEnabled(HasSelection() && !SelectionIsReadOnly()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateNewFolderItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(!(IsRoot() || IsTrash() || InTrash()) && TargetIsReadOnly() == false); + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateNewTemplatesItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(TargetIsReadOnly() == false); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateOpenItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateOpenParentItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(PoseView()->CanOpenParent()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateOpenWithItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetShortcut('O', B_COMMAND_KEY | B_CONTROL_KEY); + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdatePasteItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(PasteLabel()); + item->Message()->what = PasteCommand(); + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY | (modifiers() & B_SHIFT_KEY)); + + if (fInWindow) { + bool isPastable = FSClipboardHasRefs() && !SelectionIsReadOnly() && !IsTrash(); + item->SetEnabled(IsCurrentFocusOnTextView() || isPastable); + + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateResizeToFitItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateRestoreItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(HasSelection()); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateReverseOrderItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateSelectItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(PoseView()); + } +} + + +void +TShortcuts::UpdateSelectAllItem(BMenuItem* item) +{ + if (item == NULL) + return; + + if (fInWindow) { + item->SetEnabled(true); + item->SetTarget(fContainerWindow); + } +} + + +void +TShortcuts::UpdateUnmountItem(BMenuItem* item) +{ + if (item == NULL) + return; + + item->SetLabel(UnmountLabel()); + item->Message()->what = kUnmountVolume; + item->SetShortcut(item->Shortcut(), B_COMMAND_KEY); + + if (fInWindow) { + item->SetEnabled(PoseView()->CanUnmountSelection()); + item->SetTarget(PoseView()); + } +} + + +// #pragma mark - Shortcuts convenience methods + + +BMenuItem* +TShortcuts::FindItem(BMenu* menu, int32 command1, int32 command2) +{ + // find menu item by either of a pair of commands + BMenuItem* item1 = menu->FindItem(command1); + BMenuItem* item2 = menu->FindItem(command2); + if (item1 == NULL && item2 == NULL) + return NULL; + + return item1 != NULL ? item1 : item2; +} + + +bool +TShortcuts::IsCurrentFocusOnTextView() const +{ + // used to redirect cut/copy/paste and other text-based shortcuts + if (!fInWindow) + return false; + + BWindow* window = fContainerWindow; + return dynamic_cast(window->CurrentFocus()) != NULL; +} + + +bool +TShortcuts::IsDesktop() const +{ + return fInWindow && PoseView()->TargetModel()->IsDesktop(); +} + + +bool +TShortcuts::IsQuery() const +{ + return fInWindow && PoseView()->TargetModel()->IsQuery(); +} + + +bool +TShortcuts::IsQueryTemplate() const +{ + return fInWindow && PoseView()->TargetModel()->IsQueryTemplate(); +} + + +bool +TShortcuts::IsRoot() const +{ + return fInWindow && PoseView()->TargetModel()->IsRoot(); +} + + +bool +TShortcuts::InTrash() const +{ + return fInWindow && PoseView()->TargetModel()->InTrash(); +} + + +bool +TShortcuts::IsTrash() const +{ + return fInWindow && PoseView()->TargetModel()->IsTrash(); +} + + +bool +TShortcuts::IsVirtualDirectory() const +{ + return PoseView()->TargetModel()->IsVirtualDirectory(); +} + + +bool +TShortcuts::IsVolume() const +{ + return fInWindow && PoseView()->TargetModel()->IsVolume(); +} + + +bool +TShortcuts::HasSelection() const +{ + return fInWindow && PoseView()->CountSelected() > 0; +} + + +bool +TShortcuts::SelectionIsReadOnly() const +{ + return fInWindow && PoseView()->SelectedVolumeIsReadOnly(); +} + + +bool +TShortcuts::TargetIsReadOnly() const +{ + return fInWindow && PoseView()->TargetVolumeIsReadOnly(); +} diff --git a/src/kits/tracker/Shortcuts.h b/src/kits/tracker/Shortcuts.h new file mode 100644 index 0000000000..581566070f --- /dev/null +++ b/src/kits/tracker/Shortcuts.h @@ -0,0 +1,230 @@ +/* + * Copyright 2020-2024 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ +#ifndef _SHORTCUTS_H +#define _SHORTCUTS_H + + +#include + +#include "ContainerWindow.h" + + +class BMenu; +class BMenuItem; + + +namespace BPrivate { + +class BPoseView; + + +class TShortcuts { +public: + TShortcuts(); + TShortcuts(BContainerWindow* window); + + // build item + + BMenuItem* AddOnsItem(); + const char* AddOnsLabel(); + + BMenuItem* ArrangeByItem(); + const char* ArrangeByLabel(); + + BMenuItem* AddPrinterItem(); + const char* AddPrinterLabel(); + + BMenuItem* CleanupItem(); + const char* CleanupLabel(); + int32 CleanupCommand(); + + BMenuItem* CloseItem(); + const char* CloseLabel(); + int32 CloseCommand(); + + BMenuItem* CloseAllInWorkspaceItem(); + const char* CloseAllInWorkspaceLabel(); + + BMenuItem* CopyItem(); + const char* CopyLabel(); + int32 CopyCommand(); + + BMenuItem* CopyToItem(); + BMenuItem* CopyToItem(BMenu*); + const char* CopyToLabel(); + + BMenuItem* CreateLinkItem(); + BMenuItem* CreateLinkItem(BMenu*); + const char* CreateLinkLabel(); + int32 CreateLinkCommand(); + + BMenuItem* CreateLinkHereItem(); + const char* CreateLinkHereLabel(); + int32 CreateLinkHereCommand(); + + BMenuItem* CutItem(); + const char* CutLabel(); + int32 CutCommand(); + + BMenuItem* DeleteItem(); + const char* DeleteLabel(); + + BMenuItem* DuplicateItem(); + const char* DuplicateLabel(); + + BMenuItem* EditNameItem(); + const char* EditNameLabel(); + + BMenuItem* EditQueryItem(); + const char* EditQueryLabel(); + + BMenuItem* EmptyTrashItem(); + const char* EmptyTrashLabel(); + + BMenuItem* FindItem(); + const char* FindLabel(); + + BMenuItem* GetInfoItem(); + const char* GetInfoLabel(); + + BMenuItem* IdentifyItem(); + const char* IdentifyLabel(); + + BMenuItem* InvertSelectionItem(); + const char* InvertSelectionLabel(); + + BMenuItem* MakeActivePrinterItem(); + const char* MakeActivePrinterLabel(); + + BMenuItem* MountItem(); + BMenuItem* MountItem(BMenu*); + const char* MountLabel(); + + BMenuItem* MoveToItem(); + BMenuItem* MoveToItem(BMenu*); + const char* MoveToLabel(); + + BMenuItem* MoveToTrashItem(); + const char* MoveToTrashLabel(); + int32 MoveToTrashCommand(); + + BMenuItem* NewFolderItem(); + const char* NewFolderLabel(); + + BMenuItem* NewTemplatesItem(); + BMenuItem* NewTemplatesItem(BMenu*); + const char* NewTemplatesLabel(); + + BMenuItem* OpenItem(); + const char* OpenLabel(); + + BMenuItem* OpenParentItem(); + const char* OpenParentLabel(); + + BMenuItem* OpenWithItem(); + BMenuItem* OpenWithItem(BMenu*); + const char* OpenWithLabel(); + + BMenuItem* PasteItem(); + const char* PasteLabel(); + int32 PasteCommand(); + + BMenuItem* RestoreItem(); + const char* RestoreLabel(); + + BMenuItem* ReverseOrderItem(); + const char* ReverseOrderLabel(); + + BMenuItem* ResizeToFitItem(); + const char* ResizeToFitLabel(); + + BMenuItem* SelectItem(); + const char* SelectLabel(); + + BMenuItem* SelectAllItem(); + const char* SelectAllLabel(); + + BMenuItem* UnmountItem(); + const char* UnmountLabel(); + + // update item + + void Update(BMenu*); + + void UpdateAddOnsItem(BMenuItem*); + void UpdateAddPrinterItem(BMenuItem*); + void UpdateArrangeByItem(BMenuItem*); + void UpdateCleanupItem(BMenuItem*); + void UpdateCloseAllInWorkspaceItem(BMenuItem*); + void UpdateCloseItem(BMenuItem*); + void UpdateCopyItem(BMenuItem*); + void UpdateCopyToItem(BMenuItem*); + void UpdateCreateLinkItem(BMenuItem*); + void UpdateCreateLinkHereItem(BMenuItem*); + void UpdateCutItem(BMenuItem*); + void UpdateDeleteItem(BMenuItem*); + void UpdateDuplicateItem(BMenuItem*); + void UpdateEditNameItem(BMenuItem*); + void UpdateEditQueryItem(BMenuItem*); + void UpdateEmptyTrashItem(BMenuItem*); + void UpdateFindItem(BMenuItem*); + void UpdateGetInfoItem(BMenuItem*); + void UpdateIdentifyItem(BMenuItem*); + void UpdateInvertSelectionItem(BMenuItem*); + void UpdateMakeActivePrinterItem(BMenuItem*); + void UpdateMoveToItem(BMenuItem*); + void UpdateMoveToTrashItem(BMenuItem*); + void UpdateNewFolderItem(BMenuItem*); + void UpdateNewTemplatesItem(BMenuItem*); + void UpdateOpenItem(BMenuItem*); + void UpdateOpenParentItem(BMenuItem*); + void UpdateOpenWithItem(BMenuItem*); + void UpdatePasteItem(BMenuItem*); + void UpdateResizeToFitItem(BMenuItem*); + void UpdateRestoreItem(BMenuItem*); + void UpdateReverseOrderItem(BMenuItem*); + void UpdateSelectItem(BMenuItem*); + void UpdateSelectAllItem(BMenuItem*); + void UpdateUnmountItem(BMenuItem*); + + // convenience methods + + BMenuItem* FindItem(BMenu* menu, int32 command1, int32 command2); + BPoseView* PoseView() const; + + bool IsCurrentFocusOnTextView() const; + bool IsDesktop() const; + bool IsQuery() const; + bool IsQueryTemplate() const; + bool IsRoot() const; + bool InTrash() const; + bool IsTrash() const; + bool IsVirtualDirectory() const; + bool IsVolume() const; + bool HasSelection() const; + bool SelectionIsReadOnly() const; + bool TargetIsReadOnly() const; + +private: + BContainerWindow* fContainerWindow; + bool fInWindow; +}; + + +inline BPoseView* +TShortcuts::PoseView() const +{ + return fInWindow ? fContainerWindow->PoseView() : NULL; +} + +} // namespace BPrivate + +using namespace BPrivate; + + +#endif // _SHORTCUTS_H diff --git a/src/kits/tracker/Tracker.cpp b/src/kits/tracker/Tracker.cpp index 91dd2cce0f..c7c63b5e94 100644 --- a/src/kits/tracker/Tracker.cpp +++ b/src/kits/tracker/Tracker.cpp @@ -289,41 +289,13 @@ TTracker::TTracker() gLaunchLooper = new LaunchLooper(); gLaunchLooper->Run(); - // open desktop window - BContainerWindow* deskWindow = NULL; - BDirectory deskDir; - if (FSGetDeskDir(&deskDir) == B_OK) { - // create desktop - BEntry entry; - deskDir.GetEntry(&entry); - Model* model = new Model(&entry, true); - if (model->InitCheck() == B_OK) { - AutoLock lock(&fWindowList); - deskWindow = new BDeskWindow(&fWindowList); - AutoLock windowLock(deskWindow); - deskWindow->CreatePoseView(model); - deskWindow->Init(); + // create Desktop window and lock it + AutoLock lock(&fWindowList); + BContainerWindow* deskWindow = new BDeskWindow(&fWindowList); + AutoLock windowLock(deskWindow); - if (TrackerSettings().ShowDisksIcon()) { - // create model for root of everything - BEntry entry("/"); - Model model(&entry); - if (model.InitCheck() == B_OK) { - // add the root icon to desktop window - BMessage message; - message.what = B_NODE_MONITOR; - message.AddInt32("opcode", B_ENTRY_CREATED); - message.AddInt32("device", model.NodeRef()->device); - message.AddInt64("node", model.NodeRef()->node); - message.AddInt64("directory", - model.EntryRef()->directory); - message.AddString("name", model.EntryRef()->name); - deskWindow->PostMessage(&message, deskWindow->PoseView()); - } - } - } else - delete model; - } + // init Desktop now that pose view is created and window is locked + deskWindow->Init(); } diff --git a/src/kits/tracker/VirtualDirectoryWindow.cpp b/src/kits/tracker/VirtualDirectoryWindow.cpp index ae960377f2..4b3b4cec8f 100644 --- a/src/kits/tracker/VirtualDirectoryWindow.cpp +++ b/src/kits/tracker/VirtualDirectoryWindow.cpp @@ -49,6 +49,7 @@ All rights reserved. #include #include "Commands.h" +#include "Shortcuts.h" #include "VirtualDirectoryManager.h" #include "VirtualDirectoryPoseView.h" @@ -134,33 +135,27 @@ VirtualDirectoryWindow::AddWindowMenu(BMenu* menu) { BMenuItem* item; - item = new BMenuItem(B_TRANSLATE("Resize to fit"), - new BMessage(kResizeToFit), 'Y'); + item = Shortcuts()->ResizeToFitItem(); item->SetTarget(this); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Select" B_UTF8_ELLIPSIS), - new BMessage(kShowSelectionWindow), 'A', B_SHIFT_KEY); + item = Shortcuts()->SelectItem(); item->SetTarget(PoseView()); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Select all"), - new BMessage(B_SELECT_ALL), 'A'); + item = Shortcuts()->SelectAllItem(); item->SetTarget(this); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Invert selection"), - new BMessage(kInvertSelection), 'S'); + item = Shortcuts()->InvertSelectionItem(); item->SetTarget(PoseView()); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Open parent"), - new BMessage(kOpenParentDir), B_UP_ARROW); + item = Shortcuts()->OpenParentItem(); item->SetTarget(PoseView()); menu->AddItem(item); - item = new BMenuItem(B_TRANSLATE("Close"), - new BMessage(B_QUIT_REQUESTED), 'W'); + item = Shortcuts()->CloseItem(); item->SetTarget(this); menu->AddItem(item); } @@ -169,15 +164,11 @@ VirtualDirectoryWindow::AddWindowMenu(BMenu* menu) void VirtualDirectoryWindow::AddWindowContextMenus(BMenu* menu) { - BMenuItem* resizeItem = new BMenuItem(B_TRANSLATE("Resize to fit"), - new BMessage(kResizeToFit), 'Y'); + BMenuItem* resizeItem = Shortcuts()->ResizeToFitItem(); menu->AddItem(resizeItem); - 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')); - BMenuItem* closeItem = new BMenuItem(B_TRANSLATE("Close"), - new BMessage(B_QUIT_REQUESTED), 'W'); + menu->AddItem(Shortcuts()->SelectItem()); + menu->AddItem(Shortcuts()->SelectAllItem()); + BMenuItem* closeItem = Shortcuts()->CloseItem(); menu->AddItem(closeItem); // target items as needed menu->SetTargetForItems(PoseView()); diff --git a/src/kits/tracker/infowindow/HeaderView.cpp b/src/kits/tracker/infowindow/HeaderView.cpp index 70933cd545..430a5e1b67 100644 --- a/src/kits/tracker/infowindow/HeaderView.cpp +++ b/src/kits/tracker/infowindow/HeaderView.cpp @@ -55,6 +55,7 @@ All rights reserved. #include "Model.h" #include "NavMenu.h" #include "PoseView.h" +#include "Shortcuts.h" #include "Tracker.h" @@ -333,7 +334,7 @@ HeaderView::MouseDown(BPoint where) Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); if (SecondaryMouseButtonDown(modifiers(), buttons)) { // Show contextual menu - BPopUpMenu* contextMenu = new BPopUpMenu("FileContext", false, false); + BPopUpMenu* contextMenu = new BPopUpMenu("PoseContext", false, false); if (contextMenu != NULL) { BuildContextMenu(contextMenu); contextMenu->SetAsyncAutoDestruct(true); @@ -581,17 +582,14 @@ HeaderView::BuildContextMenu(BMenu* parent) navigationItem->SetTarget(be_app); } - parent->AddItem(new BMenuItem(B_TRANSLATE("Open"), - new BMessage(kOpenSelection), 'O')); + parent->AddItem(TShortcuts().OpenItem()); if (!model.IsDesktop() && !model.IsRoot() && !model.IsTrash()) { - parent->AddItem(new BMenuItem(B_TRANSLATE("Edit name"), - new BMessage(kEditItem), 'E')); + parent->AddItem(TShortcuts().EditNameItem()); parent->AddSeparatorItem(); if (fModel->IsVolume()) { - BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"), - new BMessage(kUnmountVolume), 'U'); + BMenuItem* item = TShortcuts().UnmountItem(); parent->AddItem(item); // volume model, enable/disable the Unmount item BVolume boot; @@ -604,12 +602,10 @@ HeaderView::BuildContextMenu(BMenu* parent) } if (!model.IsRoot() && !model.IsVolume() && !model.IsTrash()) - parent->AddItem(new BMenuItem(B_TRANSLATE("Identify"), - new BMessage(kIdentifyEntry))); + parent->AddItem(TShortcuts().IdentifyItem()); if (model.IsTrash()) - parent->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"), - new BMessage(kEmptyTrash))); + parent->AddItem(TShortcuts().EmptyTrashItem()); BMenuItem* sizeItem = NULL; if (model.IsDirectory() && !model.IsVolume() && !model.IsRoot()) { diff --git a/src/kits/tracker/infowindow/InfoWindow.cpp b/src/kits/tracker/infowindow/InfoWindow.cpp index 8b80ac441f..72c3020b6f 100644 --- a/src/kits/tracker/infowindow/InfoWindow.cpp +++ b/src/kits/tracker/infowindow/InfoWindow.cpp @@ -113,7 +113,7 @@ BInfoWindow::BInfoWindow(Model* model, int32 group_index, if (list != NULL) list->AddItem(this); - AddShortcut('E', 0, new BMessage(kEditItem)); + AddShortcut('E', 0, new BMessage(kEditName)); AddShortcut('O', 0, new BMessage(kOpenSelection)); AddShortcut('U', 0, new BMessage(kUnmountVolume)); AddShortcut('P', 0, new BMessage(kPermissionsSelected)); @@ -266,7 +266,7 @@ BInfoWindow::MessageReceived(BMessage* message) break; } - case kEditItem: + case kEditName: { BEntry entry(fModel->EntryRef()); fHeaderView->BeginEditingTitle();