1 /* 2 * Copyright (c) 2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved. 3 * Distributed under the terms of the MIT/X11 license. 4 * 5 * Copyright (c) 1999 Mike Steed. You are free to use and distribute this software 6 * as long as it is accompanied by it's documentation and this copyright notice. 7 * The software comes with no warranty, etc. 8 */ 9 10 11 #include "ControlsView.h" 12 13 #include <Bitmap.h> 14 #include <Box.h> 15 #include <TabView.h> 16 #include <NodeMonitor.h> 17 #include <Path.h> 18 #include <PopUpMenu.h> 19 #include <SupportDefs.h> 20 #include <Volume.h> 21 #include <VolumeRoster.h> 22 #include <Window.h> 23 24 #include <LayoutBuilder.h> 25 26 #include "Common.h" 27 #include "VolumeView.h" 28 29 30 class VolumeTab: public BTab { 31 public: 32 VolumeTab(BVolume* volume); 33 virtual ~VolumeTab(); 34 35 BVolume* Volume() const 36 { return fVolume; } 37 float IconWidth() const; 38 39 virtual void DrawLabel(BView* owner, BRect frame); 40 41 private: 42 BBitmap* fIcon; 43 BVolume* fVolume; 44 }; 45 46 47 VolumeTab::VolumeTab(BVolume* volume) 48 : 49 BTab(), 50 fIcon(new BBitmap(BRect(0, 0, 15, 15), B_RGBA32)), 51 fVolume(volume) 52 { 53 if (fVolume->GetIcon(fIcon, B_MINI_ICON) < B_OK) { 54 delete fIcon; 55 fIcon = NULL; 56 } 57 } 58 59 60 float 61 VolumeTab::IconWidth() const 62 { 63 if (fIcon != NULL) 64 // add a small margin 65 return fIcon->Bounds().Width() + kSmallHMargin; 66 else 67 return 0.0f; 68 } 69 70 71 void 72 VolumeTab::DrawLabel(BView* owner, BRect frame) 73 { 74 owner->SetDrawingMode(B_OP_OVER); 75 if (fIcon != NULL) { 76 owner->MovePenTo(frame.left + kSmallHMargin, 77 (frame.top + frame.bottom - fIcon->Bounds().Height()) / 2.0); 78 owner->DrawBitmap(fIcon); 79 } 80 81 font_height fh; 82 owner->GetFontHeight(&fh); 83 84 owner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR)); 85 owner->DrawString(Label(), 86 BPoint(frame.left + IconWidth() + kSmallHMargin, 87 (frame.top + frame.bottom - fh.ascent - fh.descent) / 2.0 88 + fh.ascent)); 89 } 90 91 92 VolumeTab::~VolumeTab() 93 { 94 delete fIcon; 95 delete fVolume; 96 } 97 98 99 // #pragma mark - 100 101 102 class ControlsView::VolumeTabView: public BTabView { 103 public: 104 VolumeTabView(); 105 virtual ~VolumeTabView(); 106 107 virtual void AttachedToWindow(); 108 virtual void MessageReceived(BMessage* message); 109 virtual BRect TabFrame(int32 index) const; 110 111 BVolume* FindDeviceFor(dev_t device, 112 bool invoke = false); 113 114 private: 115 void _AddVolume(dev_t device); 116 void _RemoveVolume(dev_t device); 117 118 BVolumeRoster* fVolumeRoster; 119 }; 120 121 122 ControlsView::VolumeTabView::VolumeTabView() 123 : 124 BTabView("volume_tabs", B_WIDTH_FROM_LABEL) 125 { 126 } 127 128 129 ControlsView::VolumeTabView::~VolumeTabView() 130 { 131 fVolumeRoster->StopWatching(); 132 delete fVolumeRoster; 133 } 134 135 136 BRect 137 ControlsView::VolumeTabView::TabFrame(int32 index) const 138 { 139 float height = BTabView::TabFrame(index).Height(); 140 float x = 0.0f; 141 for (int32 i = 0; i < index; i++) { 142 x += StringWidth(TabAt(i)->Label()) + 3.0f * kSmallHMargin 143 + ((VolumeTab*)TabAt(i))->IconWidth(); 144 } 145 146 return BRect(x, 0.0f, 147 x + StringWidth(TabAt(index)->Label()) + 3.0f * kSmallHMargin 148 + ((VolumeTab*)TabAt(index))->IconWidth(), 149 height); 150 } 151 152 153 void 154 ControlsView::VolumeTabView::AttachedToWindow() 155 { 156 // Populate the menu with the persistent volumes. 157 fVolumeRoster = new BVolumeRoster(); 158 159 BVolume tempVolume; 160 while (fVolumeRoster->GetNextVolume(&tempVolume) == B_OK) { 161 if (tempVolume.IsPersistent()) { 162 BVolume* volume = new BVolume(tempVolume); 163 VolumeTab *item = new VolumeTab(volume); 164 char name[B_PATH_NAME_LENGTH]; 165 volume->GetName(name); 166 AddTab(new VolumeView(name, volume), item); 167 } 168 } 169 170 // Begin watching mount and unmount events. 171 fVolumeRoster->StartWatching(BMessenger(this)); 172 } 173 174 175 void 176 ControlsView::VolumeTabView::MessageReceived(BMessage* message) 177 { 178 switch (message->what) { 179 case B_NODE_MONITOR: 180 switch (message->FindInt32("opcode")) { 181 case B_DEVICE_MOUNTED: 182 _AddVolume(message->FindInt32("new device")); 183 break; 184 185 case B_DEVICE_UNMOUNTED: 186 _RemoveVolume(message->FindInt32("device")); 187 break; 188 } 189 break; 190 191 case kBtnRescan: 192 ViewForTab(Selection())->MessageReceived(message); 193 break; 194 195 case B_SIMPLE_DATA: 196 case B_REFS_RECEIVED: 197 { 198 entry_ref ref; 199 200 for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { 201 BEntry entry(&ref, true); 202 BPath path; 203 entry.GetPath(&path); 204 dev_t device = dev_for_path(path.Path()); 205 206 for (int j = 0; VolumeTab* item = (VolumeTab*)TabAt(j); j++) { 207 if (item->Volume()->Device() == device) { 208 Select(j); 209 ((VolumeView*)(item->View()))->SetPath(path); 210 break; 211 } 212 } 213 } 214 break; 215 } 216 217 default: 218 BTabView::MessageReceived(message); 219 break; 220 } 221 } 222 223 224 BVolume* 225 ControlsView::VolumeTabView::FindDeviceFor(dev_t device, bool invoke) 226 { 227 BVolume* volume = NULL; 228 229 // Iterate through items looking for a BVolume representing this device. 230 for (int i = 0; VolumeTab* item = (VolumeTab*)TabAt(i); i++) { 231 if (item->Volume()->Device() == device) { 232 volume = item->Volume(); 233 if (invoke) 234 Select(i); 235 break; 236 } 237 } 238 239 return volume; 240 } 241 242 243 void 244 ControlsView::VolumeTabView::_AddVolume(dev_t device) 245 { 246 // Make sure the volume is not already in the menu. 247 for (int i = 0; VolumeTab* item = (VolumeTab*)TabAt(i); i++) { 248 if (item->Volume()->Device() == device) 249 return; 250 } 251 252 BVolume* volume = new BVolume(device); 253 254 VolumeTab* item = new VolumeTab(volume); 255 char name[B_PATH_NAME_LENGTH]; 256 volume->GetName(name); 257 258 AddTab(new VolumeView(name, volume), item); 259 Invalidate(); 260 } 261 262 263 void 264 ControlsView::VolumeTabView::_RemoveVolume(dev_t device) 265 { 266 for (int i = 0; VolumeTab* item = (VolumeTab*)TabAt(i); i++) { 267 if (item->Volume()->Device() == device) { 268 if (i == 0) 269 Select(1); 270 else 271 Select(i - 1); 272 RemoveTab(i); 273 delete item; 274 return; 275 } 276 } 277 } 278 279 280 // #pragma mark - 281 282 283 ControlsView::ControlsView() 284 : 285 BView(NULL, B_WILL_DRAW) 286 { 287 SetLayout(new BGroupLayout(B_VERTICAL)); 288 fVolumeTabView = new VolumeTabView(); 289 AddChild(BLayoutBuilder::Group<>(B_VERTICAL) 290 .Add(fVolumeTabView) 291 ); 292 } 293 294 295 void 296 ControlsView::MessageReceived(BMessage* msg) 297 { 298 switch (msg->what) { 299 case B_SIMPLE_DATA: 300 case B_REFS_RECEIVED: 301 fVolumeTabView->MessageReceived(msg); 302 break; 303 304 case kBtnRescan: 305 fVolumeTabView->MessageReceived(msg); 306 break; 307 308 default: 309 BView::MessageReceived(msg); 310 } 311 } 312 313 314 ControlsView::~ControlsView() 315 { 316 } 317 318 319 void 320 ControlsView::ShowInfo(const FileInfo* info) 321 { 322 ((VolumeView*)fVolumeTabView->ViewForTab( 323 fVolumeTabView->Selection()))->ShowInfo(info); 324 } 325 326 327 void 328 ControlsView::SetRescanEnabled(bool enabled) 329 { 330 ((VolumeView*)fVolumeTabView->ViewForTab( 331 fVolumeTabView->Selection()))->SetRescanEnabled(enabled); 332 } 333 334 335 BVolume* 336 ControlsView::FindDeviceFor(dev_t device, bool invoke) 337 { 338 return fVolumeTabView->FindDeviceFor(device, invoke); 339 } 340