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_TRANSLATE_CONTEXT 58 #define B_TRANSLATE_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 // if we're at the root directory skip "mnt" and go straight to "/" 113 if (!showDesktop && dir.InitCheck() == B_OK && dir.IsRootDirectory()) 114 parent.SetTo("/"); 115 else 116 entry.GetParent(&parent); 117 118 parent.GetEntry(&entry); 119 } 120 121 BDirectory desktopDir; 122 FSGetDeskDir(&desktopDir); 123 BEntry desktopEntry; 124 desktopDir.GetEntry(&desktopEntry); 125 126 for (;;) { 127 BNode node(&entry); 128 ThrowOnInitCheckError(&node); 129 130 PoseInfo info; 131 ReadAttrResult result = ReadAttr(&node, kAttrPoseInfo, 132 kAttrPoseInfoForeign, B_RAW_TYPE, 0, &info, sizeof(PoseInfo), 133 &PoseInfo::EndianSwap); 134 135 BDirectory parent; 136 entry.GetParent(&parent); 137 138 bool hitRoot = false; 139 140 // if we're at the root directory skip "mnt" and go straight to "/" 141 BDirectory dir(&entry); 142 if (!showDesktop && dir.InitCheck() == B_OK && dir.IsRootDirectory()) { 143 hitRoot = true; 144 parent.SetTo("/"); 145 } 146 147 if (showDesktop) { 148 BEntry root("/"); 149 // warp from "/" to Desktop properly 150 if (entry == root) { 151 if (showDisksIcon) 152 AddDisksIconToMenu(reverse); 153 entry = desktopEntry; 154 } 155 156 if (entry == desktopEntry) 157 hitRoot = true; 158 } 159 160 if (result == kReadAttrFailed || !info.fInvisible 161 || (showDesktop && desktopEntry == entry)) { 162 AddItemToDirMenu(&entry, originatingWindow, reverse, 163 addShortcuts, navMenuEntries); 164 } 165 166 if (hitRoot) { 167 if (!showDesktop && showDisksIcon && *startEntry != "/") 168 AddDisksIconToMenu(reverse); 169 break; 170 } 171 172 parent.GetEntry(&entry); 173 } 174 175 // select last item in menu 176 if (!select) 177 return; 178 179 ModelMenuItem *item = dynamic_cast<ModelMenuItem *>(ItemAt(CountItems() - 1)); 180 if (item) { 181 item->SetMarked(true); 182 if (menu) { 183 entry.SetTo(item->TargetModel()->EntryRef()); 184 ThrowOnError(menu->SetEntry(&entry)); 185 } 186 } 187 } catch (status_t err) { 188 PRINT(("BDirMenu::Populate: caught error %s\n", strerror(err))); 189 if (!CountItems()) { 190 BString error; 191 error << "Error [" << strerror(err) << "] populating menu"; 192 AddItem(new BMenuItem(error.String(), 0)); 193 } 194 } 195 } 196 197 198 void 199 BDirMenu::AddItemToDirMenu(const BEntry *entry, BWindow *originatingWindow, 200 bool atEnd, bool addShortcuts, bool navMenuEntries) 201 { 202 Model model(entry); 203 if (model.InitCheck() != B_OK) 204 return; 205 206 BMessage *message = new BMessage(fCommand); 207 message->AddRef(fEntryName.String(), model.EntryRef()); 208 209 // add reference to the container windows model so that we can 210 // close the window if 211 BContainerWindow *window = originatingWindow ? 212 dynamic_cast<BContainerWindow *>(originatingWindow) : 0; 213 if (window) 214 message->AddData("nodeRefsToClose", B_RAW_TYPE, window->TargetModel()->NodeRef(), 215 sizeof (node_ref)); 216 ModelMenuItem *item; 217 if (navMenuEntries) { 218 BNavMenu* subMenu = new BNavMenu(model.Name(), B_REFS_RECEIVED, fTarget, 219 window); 220 entry_ref ref; 221 entry->GetRef(&ref); 222 subMenu->SetNavDir(&ref); 223 item = new ModelMenuItem(&model, subMenu); 224 item->SetLabel(model.Name()); 225 item->SetMessage(message); 226 } else { 227 item = new ModelMenuItem(&model, model.Name(), message); 228 } 229 230 if (addShortcuts) { 231 if (model.IsDesktop()) 232 item->SetShortcut('D', B_COMMAND_KEY); 233 else if (FSIsHomeDir(entry)) 234 item->SetShortcut('H', B_COMMAND_KEY); 235 } 236 237 if (atEnd) 238 AddItem(item); 239 else 240 AddItem(item, 0); 241 242 item->SetTarget(fTarget); 243 244 if (fMenuBar) { 245 ModelMenuItem *menu = dynamic_cast<ModelMenuItem *>(fMenuBar->ItemAt(0)); 246 if (menu) { 247 ThrowOnError(menu->SetEntry(entry)); 248 item->SetMarked(true); 249 } 250 } 251 } 252 253 254 void 255 BDirMenu::AddDisksIconToMenu(bool atEnd) 256 { 257 BEntry entry("/"); 258 Model model(&entry); 259 if (model.InitCheck() != B_OK) 260 return; 261 262 BMessage *message = new BMessage(fCommand); 263 message->AddRef(fEntryName.String(), model.EntryRef()); 264 265 ModelMenuItem* item = new ModelMenuItem(&model, B_TRANSLATE("Disks"), 266 message); 267 if (atEnd) 268 AddItem(item); 269 else 270 AddItem(item, 0); 271 } 272 273