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