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