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