1 /* 2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "DrivesPage.h" 8 9 #include <Catalog.h> 10 #include <ControlLook.h> 11 #include <DiskDeviceRoster.h> 12 #include <DiskDevice.h> 13 #include <LayoutBuilder.h> 14 #include <ListView.h> 15 #include <Path.h> 16 #include <ScrollView.h> 17 #include <TextView.h> 18 19 #include <StringForSize.h> 20 21 #include "BootDrive.h" 22 #include "WizardView.h" 23 24 25 #undef B_TRANSLATION_CONTEXT 26 #define B_TRANSLATION_CONTEXT "DrivesPage" 27 28 29 const uint32 kMsgSelectionChanged = 'slch'; 30 31 32 class DriveItem : public BListItem { 33 public: 34 DriveItem(const BDiskDevice& device, 35 const BootMenuList& menus); 36 virtual ~DriveItem(); 37 38 bool IsInstalled() const; 39 bool CanBeInstalled() const; 40 bool IsBootDrive() const; 41 const char* Path() const { return fPath.Path(); } 42 43 BootDrive* Drive() { return fDrive; } 44 45 protected: 46 virtual void DrawItem(BView* owner, BRect frame, 47 bool complete = false); 48 virtual void Update(BView* owner, const BFont* font); 49 50 private: 51 BootDrive* fDrive; 52 BString fName; 53 BPath fPath; 54 BString fSize; 55 float fBaselineOffset; 56 float fSecondBaselineOffset; 57 float fSizeWidth; 58 status_t fCanBeInstalled; 59 bool fIsInstalled; 60 }; 61 62 63 DriveItem::DriveItem(const BDiskDevice& device, const BootMenuList& menus) 64 : 65 fBaselineOffset(0), 66 fSizeWidth(0) 67 { 68 device.GetPath(&fPath); 69 if (device.Name() != NULL && device.Name()[0]) 70 fName = device.Name(); 71 else if (strstr(fPath.Path(), "usb") != NULL) 72 fName = B_TRANSLATE_COMMENT("USB Drive", "Default disk name"); 73 else 74 fName = B_TRANSLATE_COMMENT("Hard Drive", "Default disk name"); 75 76 fDrive = new BootDrive(fPath.Path()); 77 78 fIsInstalled = fDrive->InstalledMenu(menus) != NULL; 79 fCanBeInstalled = fDrive->CanMenuBeInstalled(menus); 80 81 char buffer[256]; 82 fSize = string_for_size(device.Size(), buffer, sizeof(buffer)); 83 } 84 85 86 DriveItem::~DriveItem() 87 { 88 } 89 90 91 bool 92 DriveItem::IsInstalled() const 93 { 94 return fIsInstalled; 95 } 96 97 98 bool 99 DriveItem::CanBeInstalled() const 100 { 101 return fCanBeInstalled == B_OK; 102 } 103 104 105 bool 106 DriveItem::IsBootDrive() const 107 { 108 return fDrive->IsBootDrive(); 109 } 110 111 112 void 113 DriveItem::DrawItem(BView* owner, BRect frame, bool complete) 114 { 115 owner->PushState(); 116 117 if (IsSelected() || complete) { 118 if (IsSelected()) { 119 owner->SetHighColor(tint_color(owner->LowColor(), B_DARKEN_2_TINT)); 120 owner->SetLowColor(owner->HighColor()); 121 } else 122 owner->SetHighColor(owner->LowColor()); 123 124 owner->FillRect(frame); 125 } 126 127 rgb_color black = {0, 0, 0, 255}; 128 129 if (!IsEnabled()) 130 owner->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT)); 131 else 132 owner->SetHighColor(black); 133 134 // device 135 owner->MovePenTo(frame.left + 4, frame.top + fSecondBaselineOffset); 136 owner->DrawString(fPath.Path()); 137 138 // size 139 owner->MovePenTo(frame.right - 4 - fSizeWidth, frame.top + fBaselineOffset); 140 owner->DrawString(fSize.String()); 141 142 // name 143 BFont boldFont; 144 owner->GetFont(&boldFont); 145 boldFont.SetFace(B_BOLD_FACE); 146 owner->SetFont(&boldFont); 147 148 owner->MovePenTo(frame.left + 4, frame.top + fBaselineOffset); 149 owner->DrawString(fName.String()); 150 151 if (fCanBeInstalled != B_OK) { 152 owner->SetHighColor(140, 0, 0); 153 owner->MovePenBy(fBaselineOffset, 0); 154 owner->DrawString(fCanBeInstalled == B_PARTITION_TOO_SMALL 155 ? B_TRANSLATE_COMMENT("No space available!", "Cannot install") 156 : B_TRANSLATE_COMMENT("Cannot access!", "Cannot install")); 157 } 158 159 owner->PopState(); 160 } 161 162 163 void 164 DriveItem::Update(BView* owner, const BFont* font) 165 { 166 fSizeWidth = font->StringWidth(fSize.String()); 167 168 BFont boldFont(font); 169 boldFont.SetFace(B_BOLD_FACE); 170 float width = 8 + boldFont.StringWidth(fPath.Path()) 171 + be_control_look->DefaultItemSpacing() + fSizeWidth; 172 float pathWidth = font->StringWidth(fPath.Path()); 173 if (width < pathWidth) 174 width = pathWidth; 175 176 SetWidth(width); 177 178 font_height fheight; 179 font->GetHeight(&fheight); 180 181 float lineHeight = ceilf(fheight.ascent) + ceilf(fheight.descent) 182 + ceilf(fheight.leading); 183 184 fBaselineOffset = 2 + ceilf(fheight.ascent + fheight.leading / 2); 185 fSecondBaselineOffset = fBaselineOffset + lineHeight; 186 187 SetHeight(2 * lineHeight + 4); 188 } 189 190 191 // #pragma mark - 192 193 194 DrivesPage::DrivesPage(WizardView* wizardView, const BootMenuList& menus, 195 BMessage* settings, const char* name) 196 : 197 WizardPageView(settings, name), 198 fWizardView(wizardView), 199 fHasInstallableItems(false) 200 { 201 BString text; 202 text << B_TRANSLATE_COMMENT("Drives", "Title") << "\n" 203 << B_TRANSLATE("Please select the drive you want the boot manager to " 204 "be installed to or uninstalled from."); 205 BTextView* description = CreateDescription("description", text); 206 MakeHeading(description); 207 208 fDrivesView = new BListView("drives"); 209 fDrivesView->SetSelectionMessage(new BMessage(kMsgSelectionChanged)); 210 211 BScrollView* scrollView = new BScrollView("scrollView", fDrivesView, 0, 212 false, true); 213 214 SetLayout(new BGroupLayout(B_VERTICAL)); 215 216 BLayoutBuilder::Group<>((BGroupLayout*)GetLayout()) 217 .Add(description, 0.5) 218 .Add(scrollView, 1); 219 220 _UpdateWizardButtons(NULL); 221 _FillDrivesView(menus); 222 } 223 224 225 DrivesPage::~DrivesPage() 226 { 227 } 228 229 230 void 231 DrivesPage::PageCompleted() 232 { 233 DriveItem* item = _SelectedDriveItem(); 234 235 if (fSettings->ReplaceString("disk", item->Path()) != B_OK) 236 fSettings->AddString("disk", item->Path()); 237 } 238 239 240 void 241 DrivesPage::AttachedToWindow() 242 { 243 fDrivesView->SetTarget(this); 244 } 245 246 247 void 248 DrivesPage::MessageReceived(BMessage* message) 249 { 250 switch (message->what) { 251 case kMsgSelectionChanged: 252 { 253 _UpdateWizardButtons(_SelectedDriveItem()); 254 break; 255 } 256 257 default: 258 WizardPageView::MessageReceived(message); 259 break; 260 } 261 } 262 263 264 /*! Builds the list view items, and adds them to fDriveView. 265 Sets the fHasInstallableItems member to indicate if there 266 are any possible install targets. Automatically 267 selects the boot drive. 268 */ 269 void 270 DrivesPage::_FillDrivesView(const BootMenuList& menus) 271 { 272 const char* selected = fSettings->FindString("disk"); 273 274 BDiskDeviceRoster roster; 275 BDiskDevice device; 276 while (roster.GetNextDevice(&device) == B_OK) { 277 if (device.HasMedia() && !device.IsReadOnly()) { 278 DriveItem* item = new DriveItem(device, menus); 279 if (item->CanBeInstalled()) 280 fHasInstallableItems = true; 281 fDrivesView->AddItem(item); 282 283 if ((selected == NULL && item->IsBootDrive()) 284 || (selected != NULL && !strcmp(item->Path(), selected))) { 285 fDrivesView->Select(fDrivesView->CountItems() - 1); 286 _UpdateWizardButtons(item); 287 } 288 } 289 } 290 } 291 292 293 DriveItem* 294 DrivesPage::_SelectedDriveItem() 295 { 296 return (DriveItem*)fDrivesView->ItemAt(fDrivesView->CurrentSelection()); 297 } 298 299 300 void 301 DrivesPage::_UpdateWizardButtons(DriveItem* item) 302 { 303 fWizardView->SetPreviousButtonHidden(!fHasInstallableItems); 304 if (fHasInstallableItems) { 305 fWizardView->SetPreviousButtonLabel( 306 B_TRANSLATE_COMMENT("Uninstall", "Button")); 307 if (item == NULL) { 308 fWizardView->SetPreviousButtonEnabled(false); 309 fWizardView->SetNextButtonEnabled(false); 310 } else { 311 fWizardView->SetPreviousButtonEnabled( 312 item->CanBeInstalled() && item->IsInstalled()); 313 fWizardView->SetNextButtonEnabled(item->CanBeInstalled()); 314 315 fWizardView->SetNextButtonLabel( 316 item->IsInstalled() && item->CanBeInstalled() 317 ? B_TRANSLATE_COMMENT("Update", "Button") 318 : B_TRANSLATE_COMMENT("Install", "Button")); 319 } 320 } else { 321 fWizardView->SetNextButtonLabel( 322 B_TRANSLATE_COMMENT("Quit", "Button")); 323 fWizardView->SetPreviousButtonEnabled(false); 324 fWizardView->SetNextButtonEnabled(false); 325 return; 326 } 327 328 } 329