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 } else 119 entry.GetParent(&parent); 120 121 parent.GetEntry(&entry); 122 } 123 124 BDirectory desktopDir; 125 FSGetDeskDir(&desktopDir); 126 BEntry desktopEntry; 127 desktopDir.GetEntry(&desktopEntry); 128 129 for (;;) { 130 BNode node(&entry); 131 ThrowOnInitCheckError(&node); 132 133 PoseInfo info; 134 ReadAttrResult result = ReadAttr(&node, kAttrPoseInfo, 135 kAttrPoseInfoForeign, B_RAW_TYPE, 0, &info, sizeof(PoseInfo), 136 &PoseInfo::EndianSwap); 137 138 BDirectory parent; 139 entry.GetParent(&parent); 140 141 bool hitRoot = false; 142 143 BDirectory dir(&entry); 144 if (!showDesktop && dir.InitCheck() == B_OK 145 && dir.IsRootDirectory()) { 146 // if we're at the root directory skip "mnt" and 147 // go straight to "/" 148 hitRoot = true; 149 parent.SetTo("/"); 150 } 151 152 if (showDesktop) { 153 BEntry root("/"); 154 // warp from "/" to Desktop properly 155 if (entry == root) { 156 if (showDisksIcon) 157 AddDisksIconToMenu(reverse); 158 entry = desktopEntry; 159 } 160 161 if (entry == desktopEntry) 162 hitRoot = true; 163 } 164 165 if (result == kReadAttrFailed || !info.fInvisible 166 || (showDesktop && desktopEntry == entry)) { 167 AddItemToDirMenu(&entry, originatingWindow, reverse, 168 addShortcuts, navMenuEntries); 169 } 170 171 if (hitRoot) { 172 if (!showDesktop && showDisksIcon && *startEntry != "/") 173 AddDisksIconToMenu(reverse); 174 break; 175 } 176 177 parent.GetEntry(&entry); 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