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