vfs: check userland buffers before reading them.
[haiku.git] / src / kits / tracker / Navigator.cpp
blob0f5eee9ba2fffd157411fd93e14da34be5b40d4e
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
36 #include "Navigator.h"
38 #include <ControlLook.h>
39 #include <TextControl.h>
40 #include <Window.h>
42 #include "Bitmaps.h"
43 #include "Commands.h"
44 #include "FSUtils.h"
45 #include "Tracker.h"
48 namespace BPrivate {
50 static const int32 kMaxHistory = 32;
55 // #pragma mark - BNavigator
58 BNavigator::BNavigator(const Model* model)
60 BToolBar(),
61 fBackHistory(8, true),
62 fForwHistory(8, true)
64 // Get initial path
65 model->GetPath(&fPath);
67 fLocation = new BTextControl("Location", "", "",
68 new BMessage(kNavigatorCommandLocation));
69 fLocation->SetDivider(0);
71 GroupLayout()->SetInsets(0.0f, 0.0f, B_USE_HALF_ITEM_INSETS, 1.0f);
72 // 1px bottom inset used for border
74 // Needed to draw the bottom border
75 SetFlags(Flags() | B_WILL_DRAW);
76 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
80 BNavigator::~BNavigator()
85 void
86 BNavigator::AttachedToWindow()
88 // Set up toolbar items
89 BBitmap* bmpBack = new BBitmap(BRect(0, 0, 19, 19), B_RGBA32);
90 GetTrackerResources()->GetIconResource(R_ResBackNav, B_MINI_ICON,
91 bmpBack);
92 AddAction(kNavigatorCommandBackward, this, bmpBack);
93 SetActionEnabled(kNavigatorCommandBackward, false);
94 delete bmpBack;
96 BBitmap* bmpForw = new BBitmap(BRect(0, 0, 19, 19), B_RGBA32);
97 GetTrackerResources()->GetIconResource(R_ResForwNav, B_MINI_ICON,
98 bmpForw);
99 AddAction(kNavigatorCommandForward, this, bmpForw);
100 SetActionEnabled(kNavigatorCommandForward, false);
101 delete bmpForw;
103 BBitmap* bmpUp = new BBitmap(BRect(0, 0, 19, 19), B_RGBA32);
104 GetTrackerResources()->GetIconResource(R_ResUpNav, B_MINI_ICON,
105 bmpUp);
106 AddAction(kNavigatorCommandUp, this, bmpUp);
107 SetActionEnabled(kNavigatorCommandUp, false);
108 delete bmpUp;
110 AddView(fLocation);
111 fLocation->SetTarget(this);
115 void
116 BNavigator::AllAttached()
118 // Inital setup of widget states
119 UpdateLocation(0, kActionSet);
123 void
124 BNavigator::Draw(BRect updateRect)
126 // Draw a 1px bottom border, like BMenuBar
127 BRect rect(Bounds());
128 rgb_color base = LowColor();
129 uint32 flags = 0;
131 be_control_look->DrawBorder(this, rect, updateRect, base,
132 B_PLAIN_BORDER, flags, BControlLook::B_BOTTOM_BORDER);
134 _inherited::Draw(rect & updateRect);
138 void
139 BNavigator::MessageReceived(BMessage* message)
141 switch (message->what) {
142 case kNavigatorCommandBackward:
143 GoBackward((modifiers() & B_OPTION_KEY) == B_OPTION_KEY);
144 break;
146 case kNavigatorCommandForward:
147 GoForward((modifiers() & B_OPTION_KEY) == B_OPTION_KEY);
148 break;
150 case kNavigatorCommandUp:
151 GoUp((modifiers() & B_OPTION_KEY) == B_OPTION_KEY);
152 break;
154 case kNavigatorCommandLocation:
155 GoTo();
156 break;
158 case kNavigatorCommandSetFocus:
159 fLocation->MakeFocus();
160 break;
162 default:
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);
175 message.AddRef("refs", &ref);
176 message.AddInt32("action", kActionSet);
177 Window()->PostMessage(&message);
184 void
185 BNavigator::GoBackward(bool option)
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);
196 void
197 BNavigator::GoForward(bool option)
199 if (fForwHistory.CountItems() >= 1) {
200 BEntry entry;
201 if (entry.SetTo(fForwHistory.LastItem()->Path()) == B_OK)
202 SendNavigationMessage(kActionForward, &entry, option);
207 void
208 BNavigator::GoUp(bool option)
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);
220 void
221 BNavigator::SendNavigationMessage(NavigationAction action, BEntry* entry,
222 bool option)
224 entry_ref ref;
226 if (entry->GetRef(&ref) == B_OK) {
227 BMessage message;
228 message.AddRef("refs", &ref);
229 message.AddInt32("action", action);
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;
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));
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).
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);
271 LockLooper();
277 void
278 BNavigator::GoTo()
280 BString pathname = fLocation->Text();
282 if (pathname.Compare("") == 0)
283 pathname = "/";
285 BEntry entry;
286 entry_ref ref;
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;
297 if (Window() && Window()->TargetModel()) {
298 Window()->TargetModel()->GetPath(&path);
299 fLocation->SetText(path.Path());
305 void
306 BNavigator::UpdateLocation(const Model* newmodel, int32 action)
308 if (newmodel)
309 newmodel->GetPath(&fPath);
311 // Modify history according to commands
312 switch (action) {
313 case kActionBackward:
314 fForwHistory.AddItem(fBackHistory.RemoveItemAt(
315 fBackHistory.CountItems() - 1));
316 break;
318 case kActionForward:
319 fBackHistory.AddItem(fForwHistory.RemoveItemAt(
320 fForwHistory.CountItems() - 1));
321 break;
323 case kActionUpdatePath:
324 break;
326 default:
327 fForwHistory.MakeEmpty();
328 fBackHistory.AddItem(new BPath(fPath));
330 while (fBackHistory.CountItems() > kMaxHistory)
331 fBackHistory.RemoveItem(fBackHistory.FirstItem(), true);
332 break;
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);
343 // Enable history buttons if history contains something
344 SetActionEnabled(kNavigatorCommandForward, fForwHistory.CountItems() > 0);
345 SetActionEnabled(kNavigatorCommandBackward, fBackHistory.CountItems() > 1);
347 // Avoid loss of selection and cursor position
348 if (action != kActionLocation)
349 fLocation->SetText(fPath.Path());