1 /* 2 * Copyright 2006-2009 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::sTextMargin = 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 BBitmapStringField* bitmapField 61 = dynamic_cast<BBitmapStringField*>(field); 62 BStringField* stringField = dynamic_cast<BStringField*>(field); 63 64 if (bitmapField) { 65 const BBitmap* bitmap = bitmapField->Bitmap(); 66 67 // figure out the placement 68 float x = 0.0; 69 BRect r = bitmap ? bitmap->Bounds() : BRect(0, 0, 15, 15); 70 float y = rect.top + ((rect.Height() - r.Height()) / 2); 71 float width = 0.0; 72 73 switch (Alignment()) { 74 default: 75 case B_ALIGN_LEFT: 76 case B_ALIGN_CENTER: 77 x = rect.left + sTextMargin; 78 width = rect.right - (x + r.Width()) - (2 * sTextMargin); 79 r.Set(x + r.Width(), rect.top, rect.right - width, rect.bottom); 80 break; 81 82 case B_ALIGN_RIGHT: 83 x = rect.right - sTextMargin - r.Width(); 84 width = (x - rect.left - (2 * sTextMargin)); 85 r.Set(rect.left, rect.top, rect.left + width, rect.bottom); 86 break; 87 } 88 89 if (width != bitmapField->Width()) { 90 BString truncatedString(bitmapField->String()); 91 parent->TruncateString(&truncatedString, fTruncateMode, width + 2); 92 bitmapField->SetClippedString(truncatedString.String()); 93 bitmapField->SetWidth(width); 94 } 95 96 // draw the bitmap 97 if (bitmap) { 98 parent->SetDrawingMode(B_OP_ALPHA); 99 parent->DrawBitmap(bitmap, BPoint(x, y)); 100 parent->SetDrawingMode(B_OP_OVER); 101 } 102 103 // draw the string 104 DrawString(bitmapField->ClippedString(), parent, r); 105 106 } else if (stringField) { 107 108 float width = rect.Width() - (2 * sTextMargin); 109 110 if (width != stringField->Width()) { 111 BString truncatedString(stringField->String()); 112 113 parent->TruncateString(&truncatedString, fTruncateMode, width + 2); 114 stringField->SetClippedString(truncatedString.String()); 115 stringField->SetWidth(width); 116 } 117 118 DrawString(stringField->ClippedString(), parent, rect); 119 } 120 } 121 122 123 float 124 PartitionColumn::GetPreferredWidth(BField *_field, BView* parent) const 125 { 126 BBitmapStringField* bitmapField 127 = dynamic_cast<BBitmapStringField*>(_field); 128 BStringField* stringField = dynamic_cast<BStringField*>(_field); 129 130 float parentWidth = Inherited::GetPreferredWidth(_field, parent); 131 float width = 0.0; 132 133 if (bitmapField) { 134 const BBitmap* bitmap = bitmapField->Bitmap(); 135 BFont font; 136 parent->GetFont(&font); 137 width = font.StringWidth(bitmapField->String()) + 3 * sTextMargin; 138 if (bitmap) 139 width += bitmap->Bounds().Width(); 140 else 141 width += 16; 142 } else if (stringField) { 143 BFont font; 144 parent->GetFont(&font); 145 width = font.StringWidth(stringField->String()) + 2 * sTextMargin; 146 } 147 return max_c(width, parentWidth); 148 } 149 150 151 bool 152 PartitionColumn::AcceptsField(const BField* field) const 153 { 154 return dynamic_cast<const BStringField*>(field) != NULL; 155 } 156 157 158 void 159 PartitionColumn::InitTextMargin(BView* parent) 160 { 161 BFont font; 162 parent->GetFont(&font); 163 sTextMargin = ceilf(font.Size() * 0.8); 164 } 165 166 167 // #pragma mark - PartitionListRow 168 169 170 static const char* kUnavailableString = ""; 171 172 enum { 173 kDeviceColumn, 174 kFilesystemColumn, 175 kVolumeNameColumn, 176 kMountedAtColumn, 177 kSizeColumn 178 }; 179 180 181 PartitionListRow::PartitionListRow(BPartition* partition) 182 : Inherited(), 183 fPartitionID(partition->ID()), 184 fParentID(partition->Parent() ? partition->Parent()->ID() : -1), 185 fOffset(partition->Offset()), 186 fSize(partition->Size()) 187 { 188 BPath path; 189 partition->GetPath(&path); 190 191 BBitmap* icon = NULL; 192 if (partition->IsDevice()) { 193 icon_size size = B_MINI_ICON; 194 icon = new BBitmap(BRect(0, 0, size - 1, size - 1), B_RGBA32); 195 if (partition->GetIcon(icon, size) != B_OK) { 196 delete icon; 197 icon = NULL; 198 } 199 } 200 201 SetField(new BBitmapStringField(icon, path.Path()), kDeviceColumn); 202 203 if (partition->ContainsFileSystem()) { 204 SetField(new BStringField(partition->ContentType()), kFilesystemColumn); 205 SetField(new BStringField(partition->ContentName()), kVolumeNameColumn); 206 } else if (partition->CountChildren() > 0) { 207 SetField(new BStringField(kUnavailableString), kFilesystemColumn); 208 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 209 } else { 210 SetField(new BStringField(partition->Type()), kFilesystemColumn); 211 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 212 } 213 214 if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) { 215 SetField(new BStringField(path.Path()), kMountedAtColumn); 216 } else { 217 SetField(new BStringField(kUnavailableString), kMountedAtColumn); 218 } 219 220 char size[1024]; 221 SetField(new BStringField(string_for_size(partition->Size(), size)), 222 kSizeColumn); 223 } 224 225 226 PartitionListRow::PartitionListRow(partition_id parentID, partition_id id, 227 off_t offset, off_t size) 228 : Inherited(), 229 fPartitionID(id), 230 fParentID(parentID), 231 fOffset(offset), 232 fSize(size) 233 { 234 // TODO: design icon for spaces on partitions 235 SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn); 236 237 SetField(new BStringField("<empty>"), kFilesystemColumn); 238 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 239 240 SetField(new BStringField(kUnavailableString), kMountedAtColumn); 241 242 char sizeString[1024]; 243 SetField(new BStringField(string_for_size(size, sizeString)), kSizeColumn); 244 } 245 246 247 // #pragma mark - PartitionListView 248 249 250 PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode) 251 : Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true) 252 { 253 AddColumn(new PartitionColumn("Device", 150, 50, 500, 254 B_TRUNCATE_MIDDLE), kDeviceColumn); 255 AddColumn(new PartitionColumn("File system", 100, 50, 500, 256 B_TRUNCATE_MIDDLE), kFilesystemColumn); 257 AddColumn(new PartitionColumn("Volume name", 130, 50, 500, 258 B_TRUNCATE_MIDDLE), kVolumeNameColumn); 259 AddColumn(new PartitionColumn("Mounted at", 100, 50, 500, 260 B_TRUNCATE_MIDDLE), kMountedAtColumn); 261 AddColumn(new PartitionColumn("Size", 100, 50, 500, 262 B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn); 263 264 SetSortingEnabled(false); 265 } 266 267 268 void 269 PartitionListView::AttachedToWindow() 270 { 271 Inherited::AttachedToWindow(); 272 PartitionColumn::InitTextMargin(ScrollView()); 273 } 274 275 276 PartitionListRow* 277 PartitionListView::FindRow(partition_id id, PartitionListRow* parent) 278 { 279 for (int32 i = 0; i < CountRows(parent); i++) { 280 PartitionListRow* item 281 = dynamic_cast<PartitionListRow*>(RowAt(i, parent)); 282 if (item != NULL && item->ID() == id) 283 return item; 284 if (CountRows(item) > 0) { 285 // recurse into child rows 286 item = FindRow(id, item); 287 if (item) 288 return item; 289 } 290 } 291 292 return NULL; 293 } 294 295 296 PartitionListRow* 297 PartitionListView::AddPartition(BPartition* partition) 298 { 299 PartitionListRow* partitionrow = FindRow(partition->ID()); 300 301 // forget about it if this partition is already in the listview 302 if (partitionrow != NULL) 303 return partitionrow; 304 305 // create the row for this partition 306 partitionrow = new PartitionListRow(partition); 307 308 // see if this partition has a parent, or should have 309 // a parent (add it in this case) 310 PartitionListRow* parent = NULL; 311 if (partition->Parent() != NULL) { 312 // check if it is in the listview 313 parent = FindRow(partition->Parent()->ID()); 314 // If parent of this partition is not yet in the list 315 if (parent == NULL) { 316 // add it 317 parent = AddPartition(partition->Parent()); 318 } 319 } 320 321 // find a proper insertion index based on the on-disk offset 322 int32 index = _InsertIndexForOffset(parent, partition->Offset()); 323 324 // add the row, parent may be NULL (add at top level) 325 AddRow(partitionrow, index, parent); 326 327 // make sure the row is initially expanded 328 ExpandOrCollapse(partitionrow, true); 329 330 return partitionrow; 331 } 332 333 334 PartitionListRow* 335 PartitionListView::AddSpace(partition_id parentID, partition_id id, 336 off_t offset, off_t size) 337 { 338 // the parent should already be in the listview 339 PartitionListRow* parent = FindRow(parentID); 340 if (!parent) 341 return NULL; 342 343 // create the row for this partition 344 PartitionListRow* partitionrow = new PartitionListRow(parentID, 345 id, offset, size); 346 347 // find a proper insertion index based on the on-disk offset 348 int32 index = _InsertIndexForOffset(parent, offset); 349 350 // add the row, parent may be NULL (add at top level) 351 AddRow(partitionrow, index, parent); 352 353 // make sure the row is initially expanded 354 ExpandOrCollapse(partitionrow, true); 355 356 return partitionrow; 357 } 358 359 360 int32 361 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent, 362 off_t offset) const 363 { 364 int32 index = 0; 365 int32 count = CountRows(parent); 366 for (; index < count; index++) { 367 const PartitionListRow* item 368 = dynamic_cast<const PartitionListRow*>(RowAt(index, parent)); 369 if (item && item->Offset() > offset) 370 break; 371 } 372 return index; 373 } 374 375 376