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