xref: /haiku/src/kits/tracker/DirMenu.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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 
39 #include <Catalog.h>
40 #include <Debug.h>
41 #include <Directory.h>
42 #include <Locale.h>
43 #include <MenuBar.h>
44 #include <Path.h>
45 #include <Volume.h>
46 #include <VolumeRoster.h>
47 
48 #include "Attributes.h"
49 #include "ContainerWindow.h"
50 #include "DirMenu.h"
51 #include "FSUtils.h"
52 #include "IconMenuItem.h"
53 #include "NavMenu.h"
54 #include "TrackerSettings.h"
55 #include "Utilities.h"
56 
57 
58 #undef B_TRANSLATION_CONTEXT
59 #define B_TRANSLATION_CONTEXT "DirMenu"
60 
61 
62 //	#pragma mark - BDirMenu
63 
64 
65 BDirMenu::BDirMenu(BMenuBar* bar, BMessenger target, uint32 command,
66 	const char* entryName)
67 	:
68 	BPopUpMenu("directories"),
69 	fTarget(target),
70 	fMenuBar(bar),
71 	fCommand(command)
72 {
73 	if (entryName)
74 		fEntryName = entryName;
75 	else
76 		fEntryName = "refs";
77 }
78 
79 
80 BDirMenu::~BDirMenu()
81 {
82 }
83 
84 
85 void
86 BDirMenu::Populate(const BEntry* startEntry, BWindow* originatingWindow,
87 	bool includeStartEntry, bool select, bool reverse, bool addShortcuts,
88 	bool navMenuEntries)
89 {
90 	try {
91 		if (!startEntry)
92 			throw (status_t)B_ERROR;
93 
94 		Model model(startEntry);
95 		ThrowOnInitCheckError(&model);
96 
97 		ModelMenuItem* menu = NULL;
98 
99 		if (fMenuBar) {
100 			menu = new ModelMenuItem(&model, this, true, true);
101 			fMenuBar->AddItem(menu);
102 		}
103 
104 		BEntry entry(*startEntry);
105 
106 		bool showDesktop, showDisksIcon;
107 		{
108 			TrackerSettings settings;
109 			showDesktop = settings.DesktopFilePanelRoot();
110 			showDisksIcon = settings.ShowDisksIcon();
111 		}
112 
113 		// might start one level above startEntry
114 		if (!includeStartEntry) {
115 			BDirectory parent;
116 			BDirectory dir(&entry);
117 
118 			if (!showDesktop && dir.InitCheck() == B_OK
119 				&& dir.IsRootDirectory()) {
120 				// if we're at the root directory skip "mnt" and
121 				// go straight to "/"
122 				parent.SetTo("/");
123 				parent.GetEntry(&entry);
124 			} else
125 				FSGetParentVirtualDirectoryAware(entry, entry);
126 		}
127 
128 		BDirectory desktopDir;
129 		FSGetDeskDir(&desktopDir);
130 		BEntry desktopEntry;
131 		desktopDir.GetEntry(&desktopEntry);
132 
133 		for (;;) {
134 			BNode node(&entry);
135 			ThrowOnInitCheckError(&node);
136 
137 			PoseInfo info;
138 			ReadAttrResult result = ReadAttr(&node, kAttrPoseInfo,
139 				kAttrPoseInfoForeign, B_RAW_TYPE, 0, &info, sizeof(PoseInfo),
140 				&PoseInfo::EndianSwap);
141 
142 			BEntry parentEntry;
143 			bool hitRoot = false;
144 
145 			BDirectory dir(&entry);
146 			if (!showDesktop && dir.InitCheck() == B_OK
147 				&& dir.IsRootDirectory()) {
148 				// if we're at the root directory skip "mnt" and
149 				// go straight to "/"
150 				hitRoot = true;
151 				parentEntry.SetTo("/");
152 			} else
153 				FSGetParentVirtualDirectoryAware(entry, parentEntry);
154 
155 			if (showDesktop) {
156 				BEntry root("/");
157 				// warp from "/" to Desktop properly
158 				if (entry == root) {
159 					if (showDisksIcon)
160 						AddDisksIconToMenu(reverse);
161 					entry = desktopEntry;
162 				}
163 
164 				if (entry == desktopEntry)
165 					hitRoot = true;
166 			}
167 
168 			if (result == kReadAttrFailed || !info.fInvisible
169 				|| (showDesktop && desktopEntry == entry)) {
170 				AddItemToDirMenu(&entry, originatingWindow, reverse,
171 					addShortcuts, navMenuEntries);
172 			}
173 
174 			if (hitRoot) {
175 				if (!showDesktop && showDisksIcon && *startEntry != "/")
176 					AddDisksIconToMenu(reverse);
177 				break;
178 			}
179 
180 			entry = parentEntry;
181 			if (entry.InitCheck() != B_OK)
182 				break;
183 		}
184 
185 		// select last item in menu
186 		if (!select)
187 			return;
188 
189 		ModelMenuItem* item
190 			= dynamic_cast<ModelMenuItem*>(ItemAt(CountItems() - 1));
191 		if (item != NULL) {
192 			item->SetMarked(true);
193 			if (menu) {
194 				entry.SetTo(item->TargetModel()->EntryRef());
195 				ThrowOnError(menu->SetEntry(&entry));
196 			}
197 		}
198 	} catch (status_t err) {
199 		PRINT(("BDirMenu::Populate: caught error %s\n", strerror(err)));
200 		if (!CountItems()) {
201 			BString error;
202 			error << "Error [" << strerror(err) << "] populating menu";
203 			AddItem(new BMenuItem(error.String(), 0));
204 		}
205 	}
206 }
207 
208 
209 void
210 BDirMenu::AddItemToDirMenu(const BEntry* entry, BWindow* originatingWindow,
211 	bool atEnd, bool addShortcuts, bool navMenuEntries)
212 {
213 	Model model(entry);
214 	if (model.InitCheck() != B_OK)
215 		return;
216 
217 	BMessage* message = new BMessage(fCommand);
218 	message->AddRef(fEntryName.String(), model.EntryRef());
219 
220 	// add reference to the container windows model so that we can
221 	// close the window if
222 	BContainerWindow* window = originatingWindow ?
223 		dynamic_cast<BContainerWindow*>(originatingWindow) : 0;
224 	if (window != NULL) {
225 		message->AddData("nodeRefsToClose", B_RAW_TYPE,
226 			window->TargetModel()->NodeRef(), sizeof (node_ref));
227 	}
228 	ModelMenuItem* item;
229 	if (navMenuEntries) {
230 		BNavMenu* subMenu = new BNavMenu(model.Name(), B_REFS_RECEIVED,
231 			fTarget, window);
232 		entry_ref ref;
233 		entry->GetRef(&ref);
234 		subMenu->SetNavDir(&ref);
235 		item = new ModelMenuItem(&model, subMenu);
236 		item->SetLabel(model.Name());
237 		item->SetMessage(message);
238 	} else {
239 		item = new ModelMenuItem(&model, model.Name(), message);
240 	}
241 
242 	if (addShortcuts) {
243 		if (model.IsDesktop())
244 			item->SetShortcut('D', B_COMMAND_KEY);
245 		else if (FSIsHomeDir(entry))
246 			item->SetShortcut('H', B_COMMAND_KEY);
247 	}
248 
249 	if (atEnd)
250 		AddItem(item);
251 	else
252 		AddItem(item, 0);
253 
254 	item->SetTarget(fTarget);
255 
256 	if (fMenuBar != NULL) {
257 		ModelMenuItem* menu
258 			= dynamic_cast<ModelMenuItem*>(fMenuBar->ItemAt(0));
259 		if (menu != NULL) {
260 			ThrowOnError(menu->SetEntry(entry));
261 			item->SetMarked(true);
262 		}
263 	}
264 }
265 
266 
267 void
268 BDirMenu::AddDisksIconToMenu(bool atEnd)
269 {
270 	BEntry entry("/");
271 	Model model(&entry);
272 	if (model.InitCheck() != B_OK)
273 		return;
274 
275 	BMessage* message = new BMessage(fCommand);
276 	message->AddRef(fEntryName.String(), model.EntryRef());
277 
278 	ModelMenuItem* item = new ModelMenuItem(&model,
279 		B_TRANSLATE(B_DISKS_DIR_NAME), message);
280 	if (atEnd)
281 		AddItem(item);
282 	else
283 		AddItem(item, 0);
284 }
285