xref: /haiku/src/kits/tracker/DirMenu.cpp (revision 040a81419dda83d1014e9dc94936a4cb3f027303)
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