xref: /haiku/src/kits/tracker/Navigator.cpp (revision 6d2f2ec177bf615a117a7428d71be4330545b320)
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 
36 #include "Navigator.h"
37 
38 #include <TextControl.h>
39 #include <Window.h>
40 
41 #include "Bitmaps.h"
42 #include "Commands.h"
43 #include "FSUtils.h"
44 #include "Tracker.h"
45 
46 
47 namespace BPrivate {
48 
49 static const int32 kMaxHistory = 32;
50 
51 }
52 
53 
54 //	#pragma mark - BNavigator
55 
56 
57 BNavigator::BNavigator(const Model* model)
58 	:
59 	BToolBar(),
60 	fBackHistory(8, true),
61 	fForwHistory(8, true)
62 {
63 	// Get initial path
64 	model->GetPath(&fPath);
65 
66 	fLocation = new BTextControl("Location", "", "",
67 		new BMessage(kNavigatorCommandLocation));
68 	fLocation->SetDivider(0);
69 
70 	GroupLayout()->SetInsets(0, 0, B_USE_HALF_ITEM_INSETS, 0);
71 }
72 
73 
74 BNavigator::~BNavigator()
75 {
76 }
77 
78 
79 void
80 BNavigator::AttachedToWindow()
81 {
82 	// Set up toolbar items
83 	BBitmap* bmpBack = new BBitmap(BRect(0, 0, 19, 19), B_RGBA32);
84 	GetTrackerResources()->GetIconResource(R_ResBackNav, B_MINI_ICON,
85 		bmpBack);
86 	AddAction(kNavigatorCommandBackward, this, bmpBack);
87 	SetActionEnabled(kNavigatorCommandBackward, false);
88 	delete bmpBack;
89 
90 	BBitmap* bmpForw = new BBitmap(BRect(0, 0, 19, 19), B_RGBA32);
91 	GetTrackerResources()->GetIconResource(R_ResForwNav, B_MINI_ICON,
92 		bmpForw);
93 	AddAction(kNavigatorCommandForward, this, bmpForw);
94 	SetActionEnabled(kNavigatorCommandForward, false);
95 	delete bmpForw;
96 
97 	BBitmap* bmpUp = new BBitmap(BRect(0, 0, 19, 19), B_RGBA32);
98 	GetTrackerResources()->GetIconResource(R_ResUpNav, B_MINI_ICON,
99 		bmpUp);
100 	AddAction(kNavigatorCommandUp, this, bmpUp);
101 	SetActionEnabled(kNavigatorCommandUp, false);
102 	delete bmpUp;
103 
104 	AddView(fLocation);
105 	fLocation->SetTarget(this);
106 }
107 
108 
109 void
110 BNavigator::AllAttached()
111 {
112 	// Inital setup of widget states
113 	UpdateLocation(0, kActionSet);
114 }
115 
116 
117 void
118 BNavigator::MessageReceived(BMessage* message)
119 {
120 	switch (message->what) {
121 		case kNavigatorCommandBackward:
122 			GoBackward((modifiers() & B_OPTION_KEY) == B_OPTION_KEY);
123 			break;
124 
125 		case kNavigatorCommandForward:
126 			GoForward((modifiers() & B_OPTION_KEY) == B_OPTION_KEY);
127 			break;
128 
129 		case kNavigatorCommandUp:
130 			GoUp((modifiers() & B_OPTION_KEY) == B_OPTION_KEY);
131 			break;
132 
133 		case kNavigatorCommandLocation:
134 			GoTo();
135 			break;
136 
137 		case kNavigatorCommandSetFocus:
138 			fLocation->MakeFocus();
139 			break;
140 
141 		default:
142 		{
143 			// Catch any dropped refs and try to switch to this new directory
144 			entry_ref ref;
145 			if (message->FindRef("refs", &ref) == B_OK) {
146 				BMessage message(kSwitchDirectory);
147 				BEntry entry(&ref, true);
148 				if (!entry.IsDirectory()) {
149 					entry.GetRef(&ref);
150 					BPath path(&ref);
151 					path.GetParent(&path);
152 					get_ref_for_path(path.Path(), &ref);
153 				}
154 				message.AddRef("refs", &ref);
155 				message.AddInt32("action", kActionSet);
156 				Window()->PostMessage(&message);
157 			}
158 		}
159 	}
160 }
161 
162 
163 void
164 BNavigator::GoBackward(bool option)
165 {
166 	int32 itemCount = fBackHistory.CountItems();
167 	if (itemCount >= 2 && fBackHistory.ItemAt(itemCount - 2)) {
168 		BEntry entry;
169 		if (entry.SetTo(fBackHistory.ItemAt(itemCount - 2)->Path()) == B_OK)
170 			SendNavigationMessage(kActionBackward, &entry, option);
171 	}
172 }
173 
174 
175 void
176 BNavigator::GoForward(bool option)
177 {
178 	if (fForwHistory.CountItems() >= 1) {
179 		BEntry entry;
180 		if (entry.SetTo(fForwHistory.LastItem()->Path()) == B_OK)
181 			SendNavigationMessage(kActionForward, &entry, option);
182 	}
183 }
184 
185 
186 void
187 BNavigator::GoUp(bool option)
188 {
189 	BEntry entry;
190 	if (entry.SetTo(fPath.Path()) == B_OK) {
191 		BEntry parentEntry;
192 		if (entry.GetParent(&parentEntry) == B_OK) {
193 			SendNavigationMessage(kActionUp, &parentEntry, option);
194 		}
195 	}
196 }
197 
198 
199 void
200 BNavigator::SendNavigationMessage(NavigationAction action, BEntry* entry,
201 	bool option)
202 {
203 	entry_ref ref;
204 
205 	if (entry->GetRef(&ref) == B_OK) {
206 		BMessage message;
207 		message.AddRef("refs", &ref);
208 		message.AddInt32("action", action);
209 
210 		// get the node of this folder for selecting it in the new location
211 		const node_ref* nodeRef;
212 		if (Window() && Window()->TargetModel())
213 			nodeRef = Window()->TargetModel()->NodeRef();
214 		else
215 			nodeRef = NULL;
216 
217 		// if the option key was held down, open in new window (send message
218 		// to be_app) otherwise send message to this window. TTracker
219 		// (be_app) understands nodeRefToSlection, BContainerWindow doesn't,
220 		// so we have to select the item manually
221 		if (option) {
222 			message.what = B_REFS_RECEIVED;
223 			if (nodeRef != NULL) {
224 				message.AddData("nodeRefToSelect", B_RAW_TYPE, nodeRef,
225 					sizeof(node_ref));
226 			}
227 			be_app->PostMessage(&message);
228 		} else {
229 			message.what = kSwitchDirectory;
230 			Window()->PostMessage(&message);
231 			UnlockLooper();
232 				// This is to prevent a dead-lock situation.
233 				// SelectChildInParentSoon() eventually locks the
234 				// TaskLoop::fLock. Later, when StandAloneTaskLoop::Run()
235 				// runs, it also locks TaskLoop::fLock and subsequently
236 				// locks this window's looper. Therefore we can't call
237 				// SelectChildInParentSoon with our Looper locked,
238 				// because we would get different orders of locking
239 				// (thus the risk of dead-locking).
240 				//
241 				// Todo: Change the locking behaviour of
242 				// StandAloneTaskLoop::Run() and subsequently called
243 				// functions.
244 			if (nodeRef != NULL) {
245 				TTracker* tracker = dynamic_cast<TTracker*>(be_app);
246 				if (tracker != NULL)
247 					tracker->SelectChildInParentSoon(&ref, nodeRef);
248 			}
249 
250 			LockLooper();
251 		}
252 	}
253 }
254 
255 
256 void
257 BNavigator::GoTo()
258 {
259 	BString pathname = fLocation->Text();
260 
261 	if (pathname.Compare("") == 0)
262 		pathname = "/";
263 
264 	BEntry entry;
265 	entry_ref ref;
266 
267 	if (entry.SetTo(pathname.String()) == B_OK
268 		&& entry.GetRef(&ref) == B_OK) {
269 		BMessage message(kSwitchDirectory);
270 		message.AddRef("refs", &ref);
271 		message.AddInt32("action", kActionLocation);
272 		Window()->PostMessage(&message);
273 	} else {
274 		BPath path;
275 
276 		if (Window() && Window()->TargetModel()) {
277 			Window()->TargetModel()->GetPath(&path);
278 			fLocation->SetText(path.Path());
279 		}
280 	}
281 }
282 
283 
284 void
285 BNavigator::UpdateLocation(const Model* newmodel, int32 action)
286 {
287 	if (newmodel)
288 		newmodel->GetPath(&fPath);
289 
290 	// Modify history according to commands
291 	switch (action) {
292 		case kActionBackward:
293 			fForwHistory.AddItem(fBackHistory.RemoveItemAt(
294 				fBackHistory.CountItems() - 1));
295 			break;
296 
297 		case kActionForward:
298 			fBackHistory.AddItem(fForwHistory.RemoveItemAt(
299 				fForwHistory.CountItems() - 1));
300 			break;
301 
302 		case kActionUpdatePath:
303 			break;
304 
305 		default:
306 			fForwHistory.MakeEmpty();
307 			fBackHistory.AddItem(new BPath(fPath));
308 
309 			while (fBackHistory.CountItems() > kMaxHistory)
310 				fBackHistory.RemoveItem(fBackHistory.FirstItem(), true);
311 			break;
312 	}
313 
314 	// Enable Up button when there is any parent
315 	BEntry entry;
316 	if (entry.SetTo(fPath.Path()) == B_OK) {
317 		BEntry parentEntry;
318 		bool enable = entry.GetParent(&parentEntry) == B_OK;
319 		SetActionEnabled(kNavigatorCommandUp, enable);
320 	}
321 
322 	// Enable history buttons if history contains something
323 	SetActionEnabled(kNavigatorCommandForward, fForwHistory.CountItems() > 0);
324 	SetActionEnabled(kNavigatorCommandBackward, fBackHistory.CountItems() > 1);
325 
326 	// Avoid loss of selection and cursor position
327 	if (action != kActionLocation)
328 		fLocation->SetText(fPath.Path());
329 }
330