384 lines
8.9 KiB
C++
384 lines
8.9 KiB
C++
/*
|
|
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include "DrivesPage.h"
|
|
|
|
#include <Catalog.h>
|
|
#include <ControlLook.h>
|
|
#include <DiskDeviceRoster.h>
|
|
#include <DiskDevice.h>
|
|
#include <LayoutBuilder.h>
|
|
#include <ListView.h>
|
|
#include <Path.h>
|
|
#include <ScrollView.h>
|
|
#include <TextView.h>
|
|
#include <Bitmap.h>
|
|
|
|
#include <StringForSize.h>
|
|
|
|
#include "BootDrive.h"
|
|
#include "WizardView.h"
|
|
|
|
|
|
#undef B_TRANSLATION_CONTEXT
|
|
#define B_TRANSLATION_CONTEXT "DrivesPage"
|
|
|
|
|
|
const uint32 kMsgSelectionChanged = 'slch';
|
|
|
|
|
|
class DriveItem : public BListItem {
|
|
public:
|
|
DriveItem(const BDiskDevice& device,
|
|
const BootMenuList& menus);
|
|
virtual ~DriveItem();
|
|
|
|
bool IsInstalled() const;
|
|
bool CanBeInstalled() const;
|
|
bool IsBootDrive() const;
|
|
const char* Path() const { return fPath.Path(); }
|
|
|
|
BootDrive* Drive() { return fDrive; }
|
|
|
|
protected:
|
|
virtual void DrawItem(BView* owner, BRect frame,
|
|
bool complete = false);
|
|
virtual void Update(BView* owner, const BFont* font);
|
|
|
|
private:
|
|
BootDrive* fDrive;
|
|
BBitmap* fIcon;
|
|
BString fName;
|
|
BPath fPath;
|
|
BString fSize;
|
|
float fBaselineOffset;
|
|
float fSecondBaselineOffset;
|
|
float fSizeWidth;
|
|
status_t fCanBeInstalled;
|
|
bool fIsInstalled;
|
|
};
|
|
|
|
|
|
DriveItem::DriveItem(const BDiskDevice& device, const BootMenuList& menus)
|
|
:
|
|
fBaselineOffset(0),
|
|
fSizeWidth(0)
|
|
{
|
|
device.GetPath(&fPath);
|
|
if (device.Name() != NULL && device.Name()[0])
|
|
fName = device.Name();
|
|
else if (strstr(fPath.Path(), "usb") != NULL)
|
|
fName = B_TRANSLATE_COMMENT("USB Drive", "Default disk name");
|
|
else
|
|
fName = B_TRANSLATE_COMMENT("Hard Drive", "Default disk name");
|
|
|
|
fIcon = new BBitmap(BRect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1),
|
|
B_RGBA32);
|
|
if (device.GetIcon(fIcon, B_LARGE_ICON) != B_OK)
|
|
memset(fIcon->Bits(), 0, fIcon->BitsLength());
|
|
|
|
fDrive = new BootDrive(fPath.Path());
|
|
|
|
fIsInstalled = fDrive->InstalledMenu(menus) != NULL;
|
|
fCanBeInstalled = fDrive->CanMenuBeInstalled(menus);
|
|
|
|
char buffer[256];
|
|
fSize = string_for_size(device.Size(), buffer, sizeof(buffer));
|
|
}
|
|
|
|
|
|
DriveItem::~DriveItem()
|
|
{
|
|
delete fDrive;
|
|
delete fIcon;
|
|
}
|
|
|
|
|
|
bool
|
|
DriveItem::IsInstalled() const
|
|
{
|
|
return fIsInstalled;
|
|
}
|
|
|
|
|
|
bool
|
|
DriveItem::CanBeInstalled() const
|
|
{
|
|
return fCanBeInstalled == B_OK;
|
|
}
|
|
|
|
|
|
bool
|
|
DriveItem::IsBootDrive() const
|
|
{
|
|
return fDrive->IsBootDrive();
|
|
}
|
|
|
|
|
|
void
|
|
DriveItem::DrawItem(BView* owner, BRect frame, bool complete)
|
|
{
|
|
owner->PushState();
|
|
owner->SetDrawingMode(B_OP_ALPHA);
|
|
|
|
if (IsSelected() || complete) {
|
|
if (IsSelected()) {
|
|
owner->SetHighColor(ui_color(B_LIST_SELECTED_BACKGROUND_COLOR));
|
|
owner->SetLowColor(owner->HighColor());
|
|
} else
|
|
owner->SetHighColor(owner->LowColor());
|
|
|
|
owner->FillRect(frame);
|
|
}
|
|
|
|
if (!IsEnabled()) {
|
|
rgb_color textColor;
|
|
if (IsSelected())
|
|
textColor = ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR);
|
|
else
|
|
textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
|
|
|
|
if (textColor.red + textColor.green + textColor.blue > 128 * 3)
|
|
owner->SetHighColor(tint_color(textColor, B_DARKEN_1_TINT));
|
|
else
|
|
owner->SetHighColor(tint_color(textColor, B_LIGHTEN_1_TINT));
|
|
} else {
|
|
if (IsSelected())
|
|
owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
|
|
else
|
|
owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
|
|
}
|
|
|
|
|
|
// icon
|
|
owner->MovePenTo(frame.left + 4, frame.top + 1);
|
|
owner->DrawBitmap(fIcon);
|
|
|
|
// device
|
|
owner->MovePenTo(frame.left + 8 + fIcon->Bounds().Width(),
|
|
frame.top + fSecondBaselineOffset);
|
|
owner->DrawString(fPath.Path());
|
|
|
|
// name
|
|
BFont boldFont;
|
|
BFont ownerFont;
|
|
owner->GetFont(&ownerFont);
|
|
owner->GetFont(&boldFont);
|
|
boldFont.SetFace(B_BOLD_FACE);
|
|
owner->SetFont(&boldFont);
|
|
|
|
BPoint namePosition(frame.left + 8 + fIcon->Bounds().Width(),
|
|
frame.top + fBaselineOffset);
|
|
|
|
owner->MovePenTo(namePosition);
|
|
owner->DrawString(fName.String());
|
|
|
|
float nameWidth = owner->StringWidth(fName.String());
|
|
float messageWidth = frame.right - 4 - fSizeWidth
|
|
- (frame.left + 8 + fIcon->Bounds().Width()) - nameWidth
|
|
- fBaselineOffset * 2;
|
|
|
|
if (fCanBeInstalled != B_OK) {
|
|
rgb_color highColor = owner->HighColor();
|
|
owner->SetHighColor(ui_color(B_FAILURE_COLOR));
|
|
owner->MovePenBy(fBaselineOffset, 0);
|
|
const char* message;
|
|
switch (fCanBeInstalled) {
|
|
case B_PARTITION_TOO_SMALL:
|
|
message = B_TRANSLATE_COMMENT("No space available!",
|
|
"Cannot install");
|
|
break;
|
|
case B_ENTRY_NOT_FOUND:
|
|
message = B_TRANSLATE_COMMENT("Incompatible format!",
|
|
"Cannot install");
|
|
break;
|
|
case B_READ_ONLY_DEVICE:
|
|
message = B_TRANSLATE_COMMENT("Read only!",
|
|
"Cannot install");
|
|
break;
|
|
default:
|
|
message = B_TRANSLATE_COMMENT("Cannot access!",
|
|
"Cannot install");
|
|
break;
|
|
}
|
|
BString truncatedMessage = message;
|
|
owner->TruncateString(&truncatedMessage, B_TRUNCATE_END, messageWidth);
|
|
owner->DrawString(truncatedMessage);
|
|
owner->SetHighColor(highColor);
|
|
}
|
|
owner->SetFont(&ownerFont);
|
|
// size
|
|
BPoint sizePosition(frame.right - 4 - fSizeWidth,
|
|
frame.top + fBaselineOffset);
|
|
if (sizePosition.x > namePosition.x + nameWidth) {
|
|
owner->MovePenTo(sizePosition);
|
|
owner->DrawString(fSize.String());
|
|
}
|
|
|
|
owner->PopState();
|
|
}
|
|
|
|
|
|
void
|
|
DriveItem::Update(BView* owner, const BFont* font)
|
|
{
|
|
fSizeWidth = font->StringWidth(fSize.String());
|
|
|
|
BFont boldFont(font);
|
|
boldFont.SetFace(B_BOLD_FACE);
|
|
float width = 8 + boldFont.StringWidth(fPath.Path())
|
|
+ be_control_look->DefaultItemSpacing() + fSizeWidth;
|
|
float pathWidth = font->StringWidth(fPath.Path());
|
|
if (width < pathWidth)
|
|
width = pathWidth;
|
|
|
|
SetWidth(width);
|
|
|
|
font_height fheight;
|
|
font->GetHeight(&fheight);
|
|
|
|
float lineHeight = ceilf(fheight.ascent) + ceilf(fheight.descent)
|
|
+ ceilf(fheight.leading);
|
|
|
|
fBaselineOffset = 2 + ceilf(fheight.ascent + fheight.leading / 2);
|
|
fSecondBaselineOffset = fBaselineOffset + lineHeight;
|
|
|
|
SetHeight(2 * lineHeight + 4);
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
DrivesPage::DrivesPage(WizardView* wizardView, const BootMenuList& menus,
|
|
BMessage* settings, const char* name)
|
|
:
|
|
WizardPageView(settings, name),
|
|
fWizardView(wizardView),
|
|
fHasInstallableItems(false)
|
|
{
|
|
BString text;
|
|
text << B_TRANSLATE_COMMENT("Drives", "Title") << "\n"
|
|
<< B_TRANSLATE("Please select the drive you want the boot manager to "
|
|
"be installed to or uninstalled from.");
|
|
BTextView* description = CreateDescription("description", text);
|
|
MakeHeading(description);
|
|
|
|
fDrivesView = new BListView("drives", B_SINGLE_SELECTION_LIST,
|
|
B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE);
|
|
fDrivesView->SetSelectionMessage(new BMessage(kMsgSelectionChanged));
|
|
|
|
BScrollView* scrollView = new BScrollView("scrollView", fDrivesView, 0,
|
|
false, true);
|
|
|
|
SetLayout(new BGroupLayout(B_VERTICAL));
|
|
|
|
BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
|
|
.Add(description, 0.5)
|
|
.Add(scrollView, 1);
|
|
|
|
_UpdateWizardButtons(NULL);
|
|
_FillDrivesView(menus);
|
|
}
|
|
|
|
|
|
DrivesPage::~DrivesPage()
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
DrivesPage::PageCompleted()
|
|
{
|
|
DriveItem* item = _SelectedDriveItem();
|
|
|
|
if (fSettings->ReplaceString("disk", item->Path()) != B_OK)
|
|
fSettings->AddString("disk", item->Path());
|
|
}
|
|
|
|
|
|
void
|
|
DrivesPage::AttachedToWindow()
|
|
{
|
|
fDrivesView->SetTarget(this);
|
|
}
|
|
|
|
|
|
void
|
|
DrivesPage::MessageReceived(BMessage* message)
|
|
{
|
|
switch (message->what) {
|
|
case kMsgSelectionChanged:
|
|
{
|
|
_UpdateWizardButtons(_SelectedDriveItem());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
WizardPageView::MessageReceived(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*! Builds the list view items, and adds them to fDriveView.
|
|
Sets the fHasInstallableItems member to indicate if there
|
|
are any possible install targets. Automatically
|
|
selects the boot drive.
|
|
*/
|
|
void
|
|
DrivesPage::_FillDrivesView(const BootMenuList& menus)
|
|
{
|
|
const char* selected = fSettings->FindString("disk");
|
|
|
|
BDiskDeviceRoster roster;
|
|
BDiskDevice device;
|
|
while (roster.GetNextDevice(&device) == B_OK) {
|
|
if (device.HasMedia() && !device.IsReadOnly()) {
|
|
DriveItem* item = new DriveItem(device, menus);
|
|
if (item->CanBeInstalled())
|
|
fHasInstallableItems = true;
|
|
fDrivesView->AddItem(item);
|
|
|
|
if ((selected == NULL && item->IsBootDrive())
|
|
|| (selected != NULL && !strcmp(item->Path(), selected))) {
|
|
fDrivesView->Select(fDrivesView->CountItems() - 1);
|
|
_UpdateWizardButtons(item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DriveItem*
|
|
DrivesPage::_SelectedDriveItem()
|
|
{
|
|
return (DriveItem*)fDrivesView->ItemAt(fDrivesView->CurrentSelection());
|
|
}
|
|
|
|
|
|
void
|
|
DrivesPage::_UpdateWizardButtons(DriveItem* item)
|
|
{
|
|
fWizardView->SetPreviousButtonHidden(!fHasInstallableItems);
|
|
fWizardView->SetPreviousButtonLabel(
|
|
B_TRANSLATE_COMMENT("Uninstall", "Button"));
|
|
if (item == NULL) {
|
|
fWizardView->SetPreviousButtonEnabled(false);
|
|
fWizardView->SetNextButtonEnabled(false);
|
|
} else {
|
|
fWizardView->SetPreviousButtonEnabled(
|
|
item->CanBeInstalled() && item->IsInstalled());
|
|
fWizardView->SetNextButtonEnabled(item->CanBeInstalled());
|
|
|
|
fWizardView->SetNextButtonLabel(
|
|
item->IsInstalled() && item->CanBeInstalled()
|
|
? B_TRANSLATE_COMMENT("Update", "Button")
|
|
: B_TRANSLATE_COMMENT("Install", "Button"));
|
|
}
|
|
|
|
}
|