1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 // ToDo: 36 // get rid of fMenuBar, SetMenuBar and related mess 37 38 #include <Catalog.h> 39 #include <Debug.h> 40 #include <Directory.h> 41 #include <Locale.h> 42 #include <MenuBar.h> 43 #include <Path.h> 44 #include <Volume.h> 45 #include <VolumeRoster.h> 46 47 #include "Attributes.h" 48 #include "ContainerWindow.h" 49 #include "DirMenu.h" 50 #include "FSUtils.h" 51 #include "IconMenuItem.h" 52 #include "NavMenu.h" 53 #include "TrackerSettings.h" 54 #include "Utilities.h" 55 56 57 #undef B_TRANSLATION_CONTEXT 58 #define B_TRANSLATION_CONTEXT "DirMenu" 59 60 61 BDirMenu::BDirMenu(BMenuBar* bar, BMessenger target, uint32 command, 62 const char* entryName) 63 : 64 BPopUpMenu("directories"), 65 fTarget(target), 66 fMenuBar(bar), 67 fCommand(command) 68 { 69 SetFont(be_plain_font); 70 if (entryName) 71 fEntryName = entryName; 72 else 73 fEntryName = "refs"; 74 } 75 76 77 BDirMenu::~BDirMenu() 78 { 79 } 80 81 82 void 83 BDirMenu::Populate(const BEntry* startEntry, BWindow* originatingWindow, 84 bool includeStartEntry, bool select, bool reverse, bool addShortcuts, 85 bool navMenuEntries) 86 { 87 try { 88 if (!startEntry) 89 throw (status_t)B_ERROR; 90 91 Model model(startEntry); 92 ThrowOnInitCheckError(&model); 93 94 ModelMenuItem* menu = new ModelMenuItem(&model, this, true, true); 95 96 if (fMenuBar) 97 fMenuBar->AddItem(menu); 98 99 BEntry entry(*startEntry); 100 101 bool showDesktop, showDisksIcon; 102 { 103 TrackerSettings settings; 104 showDesktop = settings.DesktopFilePanelRoot(); 105 showDisksIcon = settings.ShowDisksIcon(); 106 } 107 108 // might start one level above startEntry 109 if (!includeStartEntry) { 110 BDirectory parent; 111 BDirectory dir(&entry); 112 113 if (!showDesktop && dir.InitCheck() == B_OK 114 && dir.IsRootDirectory()) { 115 // if we're at the root directory skip "mnt" and 116 // go straight to "/" 117 parent.SetTo("/"); 118 parent.GetEntry(&entry); 119 } else 120 FSGetParentVirtualDirectoryAware(entry, entry); 121 } 122 123 BDirectory desktopDir; 124 FSGetDeskDir(&desktopDir); 125 BEntry desktopEntry; 126 desktopDir.GetEntry(&desktopEntry); 127 128 for (;;) { 129 BNode node(&entry); 130 ThrowOnInitCheckError(&node); 131 132 PoseInfo info; 133 ReadAttrResult result = ReadAttr(&node, kAttrPoseInfo, 134 kAttrPoseInfoForeign, B_RAW_TYPE, 0, &info, sizeof(PoseInfo), 135 &PoseInfo::EndianSwap); 136 137 BEntry parentEntry; 138 bool hitRoot = false; 139 140 BDirectory dir(&entry); 141 if (!showDesktop && dir.InitCheck() == B_OK 142 && dir.IsRootDirectory()) { 143 // if we're at the root directory skip "mnt" and 144 // go straight to "/" 145 hitRoot = true; 146 parentEntry.SetTo("/"); 147 } else 148 FSGetParentVirtualDirectoryAware(entry, parentEntry); 149 150 if (showDesktop) { 151 BEntry root("/"); 152 // warp from "/" to Desktop properly 153 if (entry == root) { 154 if (showDisksIcon) 155 AddDisksIconToMenu(reverse); 156 entry = desktopEntry; 157 } 158 159 if (entry == desktopEntry) 160 hitRoot = true; 161 } 162 163 if (result == kReadAttrFailed || !info.fInvisible 164 || (showDesktop && desktopEntry == entry)) { 165 AddItemToDirMenu(&entry, originatingWindow, reverse, 166 addShortcuts, navMenuEntries); 167 } 168 169 if (hitRoot) { 170 if (!showDesktop && showDisksIcon && *startEntry != "/") 171 AddDisksIconToMenu(reverse); 172 break; 173 } 174 175 entry = parentEntry; 176 if (entry.InitCheck() != B_OK) 177 break; 178 } 179 180 // select last item in menu 181 if (!select) 182 return; 183 184 ModelMenuItem* item 185 = dynamic_cast<ModelMenuItem*>(ItemAt(CountItems() - 1)); 186 if (item) { 187 item->SetMarked(true); 188 if (menu) { 189 entry.SetTo(item->TargetModel()->EntryRef()); 190 ThrowOnError(menu->SetEntry(&entry)); 191 } 192 } 193 } catch (status_t err) { 194 PRINT(("BDirMenu::Populate: caught error %s\n", strerror(err))); 195 if (!CountItems()) { 196 BString error; 197 error << "Error [" << strerror(err) << "] populating menu"; 198 AddItem(new BMenuItem(error.String(), 0)); 199 } 200 } 201 } 202 203 204 void 205 BDirMenu::AddItemToDirMenu(const BEntry* entry, BWindow* originatingWindow, 206 bool atEnd, bool addShortcuts, bool navMenuEntries) 207 { 208 Model model(entry); 209 if (model.InitCheck() != B_OK) 210 return; 211 212 BMessage* message = new BMessage(fCommand); 213 message->AddRef(fEntryName.String(), model.EntryRef()); 214 215 // add reference to the container windows model so that we can 216 // close the window if 217 BContainerWindow* window = originatingWindow ? 218 dynamic_cast<BContainerWindow*>(originatingWindow) : 0; 219 if (window) 220 message->AddData("nodeRefsToClose", B_RAW_TYPE, 221 window->TargetModel()->NodeRef(), sizeof (node_ref)); 222 ModelMenuItem* item; 223 if (navMenuEntries) { 224 BNavMenu* subMenu = new BNavMenu(model.Name(), B_REFS_RECEIVED, 225 fTarget, window); 226 entry_ref ref; 227 entry->GetRef(&ref); 228 subMenu->SetNavDir(&ref); 229 item = new ModelMenuItem(&model, subMenu); 230 item->SetLabel(model.Name()); 231 item->SetMessage(message); 232 } else { 233 item = new ModelMenuItem(&model, model.Name(), message); 234 } 235 236 if (addShortcuts) { 237 if (model.IsDesktop()) 238 item->SetShortcut('D', B_COMMAND_KEY); 239 else if (FSIsHomeDir(entry)) 240 item->SetShortcut('H', B_COMMAND_KEY); 241 } 242 243 if (atEnd) 244 AddItem(item); 245 else 246 AddItem(item, 0); 247 248 item->SetTarget(fTarget); 249 250 if (fMenuBar) { 251 ModelMenuItem* menu 252 = dynamic_cast<ModelMenuItem*>(fMenuBar->ItemAt(0)); 253 if (menu) { 254 ThrowOnError(menu->SetEntry(entry)); 255 item->SetMarked(true); 256 } 257 } 258 } 259 260 261 void 262 BDirMenu::AddDisksIconToMenu(bool atEnd) 263 { 264 BEntry entry("/"); 265 Model model(&entry); 266 if (model.InitCheck() != B_OK) 267 return; 268 269 BMessage* message = new BMessage(fCommand); 270 message->AddRef(fEntryName.String(), model.EntryRef()); 271 272 ModelMenuItem* item = new ModelMenuItem(&model, B_TRANSLATE("Disks"), 273 message); 274 if (atEnd) 275 AddItem(item); 276 else 277 AddItem(item, 0); 278 } 279