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