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