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_TRANSLATION_CONTEXT 24 #define B_TRANSLATION_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 if (partition->ContainsFileSystem()) 225 SetField(new BStringField(partition->Type()), kFilesystemColumn); 226 else 227 SetField(new BStringField(kUnavailableString), kFilesystemColumn); 228 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 229 } 230 231 if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) { 232 SetField(new BStringField(path.Path()), kMountedAtColumn); 233 } else { 234 SetField(new BStringField(kUnavailableString), kMountedAtColumn); 235 } 236 237 char size[1024]; 238 SetField(new BStringField(string_for_size(partition->Size(), size, 239 sizeof(size))), kSizeColumn); 240 241 if (partition->Parameters() != NULL) { 242 BString parameters; 243 244 // check parameters 245 void* handle = parse_driver_settings_string(partition->Parameters()); 246 if (handle != NULL) { 247 bool active = get_driver_boolean_parameter(handle, "active", false, true); 248 if (active) 249 parameters += B_TRANSLATE("Active"); 250 251 delete_driver_settings(handle); 252 } 253 254 SetField(new BStringField(parameters), kParametersColumn); 255 } else { 256 SetField(new BStringField(kUnavailableString), kParametersColumn); 257 } 258 } 259 260 261 PartitionListRow::PartitionListRow(partition_id parentID, partition_id id, 262 off_t offset, off_t size) 263 : 264 Inherited(), 265 fPartitionID(id), 266 fParentID(parentID), 267 fOffset(offset), 268 fSize(size) 269 { 270 // TODO: design icon for spaces on partitions 271 SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn); 272 273 SetField(new BStringField(B_TRANSLATE("<empty>")), kFilesystemColumn); 274 SetField(new BStringField(kUnavailableString), kVolumeNameColumn); 275 276 SetField(new BStringField(kUnavailableString), kMountedAtColumn); 277 278 char sizeString[1024]; 279 SetField(new BStringField(string_for_size(size, sizeString, 280 sizeof(sizeString))), kSizeColumn); 281 } 282 283 284 // #pragma mark - PartitionListView 285 286 287 PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode) 288 : Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true) 289 { 290 AddColumn(new PartitionColumn(B_TRANSLATE("Device"), 150, 50, 500, 291 B_TRUNCATE_MIDDLE), kDeviceColumn); 292 AddColumn(new PartitionColumn(B_TRANSLATE("File system"), 100, 50, 500, 293 B_TRUNCATE_MIDDLE), kFilesystemColumn); 294 AddColumn(new PartitionColumn(B_TRANSLATE("Volume name"), 130, 50, 500, 295 B_TRUNCATE_MIDDLE), kVolumeNameColumn); 296 AddColumn(new PartitionColumn(B_TRANSLATE("Mounted at"), 100, 50, 500, 297 B_TRUNCATE_MIDDLE), kMountedAtColumn); 298 AddColumn(new PartitionColumn(B_TRANSLATE("Size"), 100, 50, 500, 299 B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn); 300 AddColumn(new PartitionColumn(B_TRANSLATE("Parameters"), 150, 50, 500, 301 B_TRUNCATE_MIDDLE), kParametersColumn); 302 303 SetSortingEnabled(false); 304 } 305 306 307 void 308 PartitionListView::AttachedToWindow() 309 { 310 Inherited::AttachedToWindow(); 311 PartitionColumn::InitTextMargin(ScrollView()); 312 } 313 314 315 PartitionListRow* 316 PartitionListView::FindRow(partition_id id, PartitionListRow* parent) 317 { 318 for (int32 i = 0; i < CountRows(parent); i++) { 319 PartitionListRow* item 320 = dynamic_cast<PartitionListRow*>(RowAt(i, parent)); 321 if (item != NULL && item->ID() == id) 322 return item; 323 if (CountRows(item) > 0) { 324 // recurse into child rows 325 item = FindRow(id, item); 326 if (item) 327 return item; 328 } 329 } 330 331 return NULL; 332 } 333 334 335 PartitionListRow* 336 PartitionListView::AddPartition(BPartition* partition) 337 { 338 PartitionListRow* partitionrow = FindRow(partition->ID()); 339 340 // forget about it if this partition is already in the listview 341 if (partitionrow != NULL) 342 return partitionrow; 343 344 // create the row for this partition 345 partitionrow = new PartitionListRow(partition); 346 347 // see if this partition has a parent, or should have 348 // a parent (add it in this case) 349 PartitionListRow* parent = NULL; 350 if (partition->Parent() != NULL) { 351 // check if it is in the listview 352 parent = FindRow(partition->Parent()->ID()); 353 // If parent of this partition is not yet in the list 354 if (parent == NULL) { 355 // add it 356 parent = AddPartition(partition->Parent()); 357 } 358 } 359 360 // find a proper insertion index based on the on-disk offset 361 int32 index = _InsertIndexForOffset(parent, partition->Offset()); 362 363 // add the row, parent may be NULL (add at top level) 364 AddRow(partitionrow, index, parent); 365 366 // make sure the row is initially expanded 367 ExpandOrCollapse(partitionrow, true); 368 369 return partitionrow; 370 } 371 372 373 PartitionListRow* 374 PartitionListView::AddSpace(partition_id parentID, partition_id id, 375 off_t offset, off_t size) 376 { 377 // the parent should already be in the listview 378 PartitionListRow* parent = FindRow(parentID); 379 if (!parent) 380 return NULL; 381 382 // create the row for this partition 383 PartitionListRow* partitionrow = new PartitionListRow(parentID, 384 id, offset, size); 385 386 // find a proper insertion index based on the on-disk offset 387 int32 index = _InsertIndexForOffset(parent, offset); 388 389 // add the row, parent may be NULL (add at top level) 390 AddRow(partitionrow, index, parent); 391 392 // make sure the row is initially expanded 393 ExpandOrCollapse(partitionrow, true); 394 395 return partitionrow; 396 } 397 398 399 int32 400 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent, 401 off_t offset) const 402 { 403 int32 index = 0; 404 int32 count = CountRows(parent); 405 for (; index < count; index++) { 406 const PartitionListRow* item 407 = dynamic_cast<const PartitionListRow*>(RowAt(index, parent)); 408 if (item && item->Offset() > offset) 409 break; 410 } 411 return index; 412 } 413 414 415