xref: /haiku/src/kits/tracker/DirMenu.cpp (revision 74252cefbcf266291fb069466189b4734eb05455)
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 			} else
119 				entry.GetParent(&parent);
120 
121 			parent.GetEntry(&entry);
122 		}
123 
124 		BDirectory desktopDir;
125 		FSGetDeskDir(&desktopDir);
126 		BEntry desktopEntry;
127 		desktopDir.GetEntry(&desktopEntry);
128 
129 		for (;;) {
130 			BNode node(&entry);
131 			ThrowOnInitCheckError(&node);
132 
133 			PoseInfo info;
134 			ReadAttrResult result = ReadAttr(&node, kAttrPoseInfo,
135 				kAttrPoseInfoForeign, B_RAW_TYPE, 0, &info, sizeof(PoseInfo),
136 				&PoseInfo::EndianSwap);
137 
138 			BDirectory parent;
139 			entry.GetParent(&parent);
140 
141 			bool hitRoot = false;
142 
143 			BDirectory dir(&entry);
144 			if (!showDesktop && dir.InitCheck() == B_OK
145 				&& dir.IsRootDirectory()) {
146 				// if we're at the root directory skip "mnt" and
147 				// go straight to "/"
148 				hitRoot = true;
149 				parent.SetTo("/");
150 			}
151 
152 			if (showDesktop) {
153 				BEntry root("/");
154 				// warp from "/" to Desktop properly
155 				if (entry == root) {
156 					if (showDisksIcon)
157 						AddDisksIconToMenu(reverse);
158 					entry = desktopEntry;
159 				}
160 
161 				if (entry == desktopEntry)
162 					hitRoot = true;
163 			}
164 
165 			if (result == kReadAttrFailed || !info.fInvisible
166 				|| (showDesktop && desktopEntry == entry)) {
167 				AddItemToDirMenu(&entry, originatingWindow, reverse,
168 					addShortcuts, navMenuEntries);
169 			}
170 
171 			if (hitRoot) {
172 				if (!showDesktop && showDisksIcon && *startEntry != "/")
173 					AddDisksIconToMenu(reverse);
174 				break;
175 			}
176 
177 			parent.GetEntry(&entry);
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