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