1 /* 2 * Copyright 2006-2008 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Ithamar R. Adema <ithamar@unet.nl> 7 * James Urquhart 8 * Stephan Aßmus <superstippi@gmx.de> 9 */ 10 #include "PartitionList.h" 11 #include "Support.h" 12 13 #include <ColumnTypes.h> 14 #include <Path.h> 15 16 17 // #pragma mark - BBitmapStringField 18 19 20 BBitmapStringField::BBitmapStringField(BBitmap* bitmap, const char* string) 21 : Inherited(string) 22 , fBitmap(bitmap) 23 { 24 } 25 26 27 BBitmapStringField::~BBitmapStringField() 28 { 29 delete fBitmap; 30 } 31 32 33 void 34 BBitmapStringField::SetBitmap(BBitmap* bitmap) 35 { 36 delete fBitmap; 37 fBitmap = bitmap; 38 // TODO: cause a redraw? 39 } 40 41 42 // #pragma mark - PartitionColumn 43 44 45 float PartitionColumn::fTextMargin = 0.0; 46 47 48 PartitionColumn::PartitionColumn(const char* title, float width, float minWidth, 49 float maxWidth, uint32 truncateMode, alignment align) 50 : Inherited(title, width, minWidth, maxWidth, align), 51 fTruncateMode(truncateMode) 52 { 53 SetWantsEvents(true); 54 } 55 56 57 void 58 PartitionColumn::DrawField(BField* field, BRect rect, BView* parent) 59 { 60 if (fTextMargin == 0.0) { 61 // we are the first column to draw something and need to 62 // init the text margin 63 BFont font; 64 parent->GetFont(&font); 65 fTextMargin = ceilf(font.Size() * 0.8); 66 } 67 68 BBitmapStringField* bitmapField 69 = dynamic_cast<BBitmapStringField*>(field); 70 BStringField* stringField = dynamic_cast<BStringField*>(field); 71 72 if (bitmapField) { 73 const BBitmap* bitmap = bitmapField->Bitmap(); 74 75 // figure out the placement 76 float x = 0.0; 77 BRect r = bitmap ? bitmap->Bounds() : BRect(0, 0, 15, 15); 78 float y = rect.top + ((rect.Height() - r.Height()) / 2); 79 float width = 0.0; 80 81 switch (Alignment()) { 82 default: 83 case B_ALIGN_LEFT: 84 case B_ALIGN_CENTER: 85 x = rect.left + fTextMargin; 86 width = rect.right - (x + r.Width()) - (2 * fTextMargin); 87 r.Set(x + r.Width(), rect.top, rect.right - width, rect.bottom); 88 break; 89 90 case B_ALIGN_RIGHT: 91 x = rect.right - fTextMargin - r.Width(); 92 width = (x - rect.left - (2 * fTextMargin)); 93 r.Set(rect.left, rect.top, rect.left + width, rect.bottom); 94 break; 95 } 96 97 if (width != bitmapField->Width()) { 98 BString truncatedString(bitmapField->String()); 99 parent->TruncateString(&truncatedString, fTruncateMode, width + 2); 100 bitmapField->SetClippedString(truncatedString.String()); 101 bitmapField->SetWidth(width); 102 } 103 104 // draw the bitmap 105 if (bitmap) { 106 parent->SetDrawingMode(B_OP_ALPHA); 107 parent->DrawBitmap(bitmap, BPoint(x, y)); 108 parent->SetDrawingMode(B_OP_OVER); 109 } 110 111 // draw the string 112 DrawString(bitmapField->ClippedString(), parent, r); 113 114 } else if (stringField) { 115 116 float width = rect.Width() - (2 * fTextMargin); 117 118 if (width != stringField->Width()) { 119 BString truncatedString(stringField->String()); 120 121 parent->TruncateString(&truncatedString, fTruncateMode, width + 2); 122 stringField->SetClippedString(truncatedString.String()); 123 stringField->SetWidth(width); 124 } 125 126 DrawString(stringField->ClippedString(), parent, rect); 127 } 128 } 129 130 bool 131 PartitionColumn::AcceptsField(const BField* field) const 132 { 133 return dynamic_cast<const BStringField*>(field) != NULL; 134 } 135 136 137 // #pragma mark - PartitionListRow 138 139 140 static const char* kUnavailableString = ""; 141 142 enum { 143 kDeviceColumn, 144 kFilesystemColumn, 145 kVolumeNameColumn, 146 kMountedAtColumn, 147 kSizeColumn 148 }; 149 150 151 PartitionListRow::PartitionListRow(BPartition* partition) 152 : Inherited() 153 , fPartitionID(partition->ID()) 154 , fParentID(partition->Parent() ? partition->Parent()->ID() : -1) 155 , fOffset(partition->Offset()) 156 , fSize(partition->Size()) 157 { 158 BPath path; 159 partition->GetPath(&path); 160 161 BBitmap* icon = NULL; 162 if (partition->IsDevice()) { 163 icon_size size = B_MINI_ICON; 164 icon = new BBitmap(BRect(0, 0, size - 1, size - 1), B_RGBA32); 165 if (partition->GetIcon(icon, size) != B_OK) { 166 delete icon; 167 icon = NULL; 168 } 169 } 170 171 SetField(new BBitmapStringField(icon, path.Path()), kDeviceColumn); 172 173 if (partition->ContainsFileSystem()) { 174 SetField(new BStringField(partition->ContentType()), kFilesystemColumn); 175 SetField(new BStringField(partition->ContentName()), kVolumeNameColumn); 176 } else { 177 SetField(new BStringField(kUnavailableString), kFilesystemColumn); 178 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 179 } 180 181 if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) { 182 SetField(new BStringField(path.Path()), kMountedAtColumn); 183 } else { 184 SetField(new BStringField(kUnavailableString), kMountedAtColumn); 185 } 186 187 char size[1024]; 188 SetField(new BStringField(string_for_size(partition->Size(), size)), 189 kSizeColumn); 190 } 191 192 193 PartitionListRow::PartitionListRow(partition_id parentID, partition_id id, 194 off_t offset, off_t size) 195 : Inherited() 196 , fPartitionID(id) 197 , fParentID(parentID) 198 , fOffset(offset) 199 , fSize(size) 200 { 201 // TODO: design icon for spaces on partitions 202 SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn); 203 204 SetField(new BStringField("<empty>"), kFilesystemColumn); 205 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 206 207 SetField(new BStringField(kUnavailableString), kMountedAtColumn); 208 209 char sizeString[1024]; 210 SetField(new BStringField(string_for_size(size, sizeString)), kSizeColumn); 211 } 212 213 214 PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode) 215 : Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true) 216 { 217 AddColumn(new PartitionColumn("Device", 150, 50, 500, 218 B_TRUNCATE_MIDDLE), kDeviceColumn); 219 AddColumn(new PartitionColumn("Filesystem", 100, 50, 500, 220 B_TRUNCATE_MIDDLE), kFilesystemColumn); 221 AddColumn(new PartitionColumn("Volume Name", 130, 50, 500, 222 B_TRUNCATE_MIDDLE), kVolumeNameColumn); 223 AddColumn(new PartitionColumn("Mounted At", 100, 50, 500, 224 B_TRUNCATE_MIDDLE), kMountedAtColumn); 225 AddColumn(new PartitionColumn("Size", 100, 50, 500, 226 B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn); 227 228 SetSortingEnabled(false); 229 } 230 231 232 PartitionListRow* 233 PartitionListView::FindRow(partition_id id, PartitionListRow* parent) 234 { 235 for (int32 i = 0; i < CountRows(parent); i++) { 236 PartitionListRow* item 237 = dynamic_cast<PartitionListRow*>(RowAt(i, parent)); 238 if (item != NULL && item->ID() == id) 239 return item; 240 if (CountRows(item) > 0) { 241 // recurse into child rows 242 item = FindRow(id, item); 243 if (item) 244 return item; 245 } 246 } 247 248 return NULL; 249 } 250 251 252 PartitionListRow* 253 PartitionListView::AddPartition(BPartition* partition) 254 { 255 PartitionListRow* partitionrow = FindRow(partition->ID()); 256 257 // forget about it if this partition is already in the listview 258 if (partitionrow != NULL) 259 return partitionrow; 260 261 // create the row for this partition 262 partitionrow = new PartitionListRow(partition); 263 264 // see if this partition has a parent, or should have 265 // a parent (add it in this case) 266 PartitionListRow* parent = NULL; 267 if (partition->Parent() != NULL) { 268 // check if it is in the listview 269 parent = FindRow(partition->Parent()->ID()); 270 // If parent of this partition is not yet in the list 271 if (parent == NULL) { 272 // add it 273 parent = AddPartition(partition->Parent()); 274 } 275 } 276 277 // find a proper insertion index based on the on-disk offset 278 int32 index = _InsertIndexForOffset(parent, partition->Offset()); 279 280 // add the row, parent may be NULL (add at top level) 281 AddRow(partitionrow, index, parent); 282 283 // make sure the row is initially expanded 284 ExpandOrCollapse(partitionrow, true); 285 286 return partitionrow; 287 } 288 289 290 PartitionListRow* 291 PartitionListView::AddSpace(partition_id parentID, partition_id id, 292 off_t offset, off_t size) 293 { 294 // the parent should already be in the listview 295 PartitionListRow* parent = FindRow(parentID); 296 if (!parent) 297 return NULL; 298 299 // create the row for this partition 300 PartitionListRow* partitionrow = new PartitionListRow(parentID, 301 id, offset, size); 302 303 // find a proper insertion index based on the on-disk offset 304 int32 index = _InsertIndexForOffset(parent, offset); 305 306 // add the row, parent may be NULL (add at top level) 307 AddRow(partitionrow, index, parent); 308 309 // make sure the row is initially expanded 310 ExpandOrCollapse(partitionrow, true); 311 312 return partitionrow; 313 } 314 315 316 int32 317 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent, 318 off_t offset) const 319 { 320 int32 index = 0; 321 int32 count = CountRows(parent); 322 for (; index < count; index++) { 323 const PartitionListRow* item 324 = dynamic_cast<const PartitionListRow*>(RowAt(index, parent)); 325 if (item && item->Offset() > offset) 326 break; 327 } 328 return index; 329 } 330 331 332