/* * Copyright 2006-2008 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT license. * * Authors: * Ithamar R. Adema * James Urquhart * Stephan Aßmus */ #include "PartitionList.h" #include "Support.h" #include #include // #pragma mark - BBitmapStringField BBitmapStringField::BBitmapStringField(BBitmap* bitmap, const char* string) : Inherited(string) , fBitmap(bitmap) { } BBitmapStringField::~BBitmapStringField() { delete fBitmap; } void BBitmapStringField::SetBitmap(BBitmap* bitmap) { delete fBitmap; fBitmap = bitmap; // TODO: cause a redraw? } // #pragma mark - PartitionColumn float PartitionColumn::fTextMargin = 0.0; PartitionColumn::PartitionColumn(const char* title, float width, float minWidth, float maxWidth, uint32 truncateMode, alignment align) : Inherited(title, width, minWidth, maxWidth, align), fTruncateMode(truncateMode) { SetWantsEvents(true); } void PartitionColumn::DrawField(BField* field, BRect rect, BView* parent) { if (fTextMargin == 0.0) { // we are the first column to draw something and need to // init the text margin BFont font; parent->GetFont(&font); fTextMargin = ceilf(font.Size() * 0.8); } BBitmapStringField* bitmapField = dynamic_cast(field); BStringField* stringField = dynamic_cast(field); if (bitmapField) { const BBitmap* bitmap = bitmapField->Bitmap(); // figure out the placement float x = 0.0; BRect r = bitmap ? bitmap->Bounds() : BRect(0, 0, 15, 15); float y = rect.top + ((rect.Height() - r.Height()) / 2); float width = 0.0; switch (Alignment()) { default: case B_ALIGN_LEFT: case B_ALIGN_CENTER: x = rect.left + fTextMargin; width = rect.right - (x + r.Width()) - (2 * fTextMargin); r.Set(x + r.Width(), rect.top, rect.right - width, rect.bottom); break; case B_ALIGN_RIGHT: x = rect.right - fTextMargin - r.Width(); width = (x - rect.left - (2 * fTextMargin)); r.Set(rect.left, rect.top, rect.left + width, rect.bottom); break; } if (width != bitmapField->Width()) { BString truncatedString(bitmapField->String()); parent->TruncateString(&truncatedString, fTruncateMode, width + 2); bitmapField->SetClippedString(truncatedString.String()); bitmapField->SetWidth(width); } // draw the bitmap if (bitmap) { parent->SetDrawingMode(B_OP_ALPHA); parent->DrawBitmap(bitmap, BPoint(x, y)); parent->SetDrawingMode(B_OP_OVER); } // draw the string DrawString(bitmapField->ClippedString(), parent, r); } else if (stringField) { float width = rect.Width() - (2 * fTextMargin); if (width != stringField->Width()) { BString truncatedString(stringField->String()); parent->TruncateString(&truncatedString, fTruncateMode, width + 2); stringField->SetClippedString(truncatedString.String()); stringField->SetWidth(width); } DrawString(stringField->ClippedString(), parent, rect); } } bool PartitionColumn::AcceptsField(const BField* field) const { return dynamic_cast(field) != NULL; } // #pragma mark - PartitionListRow static const char* kUnavailableString = ""; enum { kDeviceColumn, kFilesystemColumn, kVolumeNameColumn, kMountedAtColumn, kSizeColumn }; PartitionListRow::PartitionListRow(BPartition* partition) : Inherited() , fPartitionID(partition->ID()) , fParentID(partition->Parent() ? partition->Parent()->ID() : -1) , fOffset(partition->Offset()) , fSize(partition->Size()) { BPath path; partition->GetPath(&path); BBitmap* icon = NULL; if (partition->IsDevice()) { icon_size size = B_MINI_ICON; icon = new BBitmap(BRect(0, 0, size - 1, size - 1), B_RGBA32); if (partition->GetIcon(icon, size) != B_OK) { delete icon; icon = NULL; } } SetField(new BBitmapStringField(icon, path.Path()), kDeviceColumn); if (partition->ContainsFileSystem()) { SetField(new BStringField(partition->ContentType()), kFilesystemColumn); SetField(new BStringField(partition->ContentName()), kVolumeNameColumn); } else { SetField(new BStringField(kUnavailableString), kFilesystemColumn); SetField(new BStringField(kUnavailableString), kVolumeNameColumn); } if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) { SetField(new BStringField(path.Path()), kMountedAtColumn); } else { SetField(new BStringField(kUnavailableString), kMountedAtColumn); } char size[1024]; SetField(new BStringField(string_for_size(partition->Size(), size)), kSizeColumn); } PartitionListRow::PartitionListRow(partition_id parentID, partition_id id, off_t offset, off_t size) : Inherited() , fPartitionID(id) , fParentID(parentID) , fOffset(offset) , fSize(size) { // TODO: design icon for spaces on partitions SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn); SetField(new BStringField(""), kFilesystemColumn); SetField(new BStringField(kUnavailableString), kVolumeNameColumn); SetField(new BStringField(kUnavailableString), kMountedAtColumn); char sizeString[1024]; SetField(new BStringField(string_for_size(size, sizeString)), kSizeColumn); } PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode) : Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true) { AddColumn(new PartitionColumn("Device", 150, 50, 500, B_TRUNCATE_MIDDLE), kDeviceColumn); AddColumn(new PartitionColumn("Filesystem", 100, 50, 500, B_TRUNCATE_MIDDLE), kFilesystemColumn); AddColumn(new PartitionColumn("Volume Name", 130, 50, 500, B_TRUNCATE_MIDDLE), kVolumeNameColumn); AddColumn(new PartitionColumn("Mounted At", 100, 50, 500, B_TRUNCATE_MIDDLE), kMountedAtColumn); AddColumn(new PartitionColumn("Size", 100, 50, 500, B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn); SetSortingEnabled(false); } PartitionListRow* PartitionListView::FindRow(partition_id id, PartitionListRow* parent) { for (int32 i = 0; i < CountRows(parent); i++) { PartitionListRow* item = dynamic_cast(RowAt(i, parent)); if (item != NULL && item->ID() == id) return item; if (CountRows(item) > 0) { // recurse into child rows item = FindRow(id, item); if (item) return item; } } return NULL; } PartitionListRow* PartitionListView::AddPartition(BPartition* partition) { PartitionListRow* partitionrow = FindRow(partition->ID()); // forget about it if this partition is already in the listview if (partitionrow != NULL) return partitionrow; // create the row for this partition partitionrow = new PartitionListRow(partition); // see if this partition has a parent, or should have // a parent (add it in this case) PartitionListRow* parent = NULL; if (partition->Parent() != NULL) { // check if it is in the listview parent = FindRow(partition->Parent()->ID()); // If parent of this partition is not yet in the list if (parent == NULL) { // add it parent = AddPartition(partition->Parent()); } } // find a proper insertion index based on the on-disk offset int32 index = _InsertIndexForOffset(parent, partition->Offset()); // add the row, parent may be NULL (add at top level) AddRow(partitionrow, index, parent); // make sure the row is initially expanded ExpandOrCollapse(partitionrow, true); return partitionrow; } PartitionListRow* PartitionListView::AddSpace(partition_id parentID, partition_id id, off_t offset, off_t size) { // the parent should already be in the listview PartitionListRow* parent = FindRow(parentID); if (!parent) return NULL; // create the row for this partition PartitionListRow* partitionrow = new PartitionListRow(parentID, id, offset, size); // find a proper insertion index based on the on-disk offset int32 index = _InsertIndexForOffset(parent, offset); // add the row, parent may be NULL (add at top level) AddRow(partitionrow, index, parent); // make sure the row is initially expanded ExpandOrCollapse(partitionrow, true); return partitionrow; } int32 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent, off_t offset) const { int32 index = 0; int32 count = CountRows(parent); for (; index < count; index++) { const PartitionListRow* item = dynamic_cast(RowAt(index, parent)); if (item && item->Offset() > offset) break; } return index; }