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