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