1 /* 2 * Copyright (C) 2019-2020 Adrien Destugues <pulkomandy@pulkomandy.tk> 3 * 4 * Distributed under terms of the MIT license. 5 */ 6 7 #include "AttributesView.h" 8 9 #include <Catalog.h> 10 #include <ColumnListView.h> 11 #include <ColumnTypes.h> 12 #include <DateTimeFormat.h> 13 #include <FormattingConventions.h> 14 #include <fs_attr.h> 15 #include <Node.h> 16 #include <StringFormat.h> 17 18 19 #undef B_TRANSLATION_CONTEXT 20 #define B_TRANSLATION_CONTEXT "AttributesView" 21 22 int kValueColumn = 1; 23 int kTypeColumn = 2; 24 25 26 AttributesView::AttributesView(Model* model) 27 : 28 BGroupView(B_VERTICAL, 0), 29 fListView(new BColumnListView("attrs", 0, B_PLAIN_BORDER, false)) 30 { 31 SetName(B_TRANSLATE("Attributes")); 32 AddChild(fListView); 33 GroupLayout()->SetInsets(-1, -1, -1, -1); 34 35 float nameWidth = StringWidth("SYS:PACKAGE_FILE") + 16; 36 float typeMaxWidth = StringWidth(B_TRANSLATE( 37 "Double-precision floating point number")) + 16; 38 float typeWidth = StringWidth(B_TRANSLATE("64-bit unsigned integer")) + 16; 39 float valueMaxWidth = StringWidth("W") * 64 + 16; 40 float valueWidth = StringWidth("(94.00, 95.00) (1920, 1080)") + 16; 41 BStringColumn* nameColumn = new BStringColumn(B_TRANSLATE("Name"), 42 nameWidth, nameWidth, nameWidth, 0); 43 BStringColumn* typeColumn = new BStringColumn(B_TRANSLATE("Type"), 44 typeWidth, typeWidth, typeMaxWidth, 0); 45 BStringColumn* valueColumn = new BStringColumn(B_TRANSLATE("Value"), 46 valueWidth, valueWidth, valueMaxWidth, 0); 47 48 fListView->AddColumn(nameColumn, 0); 49 fListView->AddColumn(valueColumn, 1); 50 fListView->AddColumn(typeColumn, 2); 51 52 SetExplicitMinSize(BSize(typeWidth + valueWidth + nameWidth + 40, 53 B_SIZE_UNSET)); 54 55 BNode* node = model->Node(); 56 57 node->RewindAttrs(); 58 char name[B_ATTR_NAME_LENGTH]; 59 60 // Initialize formatters only once for all attributes 61 BDateTimeFormat dateTimeFormatter; 62 BStringFormat multiValueFormat(B_TRANSLATE( 63 "{0, plural, other{<# values>}}")); 64 65 while (node->GetNextAttrName(name) == B_OK) { 66 // Skip well-known attributes already shown elsewhere in the window 67 if (strcmp(name, "BEOS:TYPE") == 0) 68 continue; 69 70 attr_info info; 71 node->GetAttrInfo(name, &info); 72 BRow* row = new BRow; 73 row->SetField(new BStringField(name), 0); 74 75 BString representation; 76 switch(info.type) { 77 case B_STRING_TYPE: 78 case B_MIME_STRING_TYPE: 79 case 'MSIG': 80 case 'MSDC': 81 case 'MPTH': 82 { 83 // Use a small buffer, long strings will be truncated 84 char buffer[64]; 85 ssize_t size = node->ReadAttr(name, info.type, 0, buffer, 86 sizeof(buffer)); 87 if (size > 0) 88 representation.SetTo(buffer, size); 89 break; 90 } 91 case B_BOOL_TYPE: 92 { 93 if (info.size == sizeof(bool)) { 94 bool value; 95 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 96 representation = value ? B_TRANSLATE("yes") 97 : B_TRANSLATE("no"); 98 } else { 99 multiValueFormat.Format(representation, 100 info.size / sizeof(bool)); 101 } 102 break; 103 } 104 case B_INT16_TYPE: 105 { 106 if (info.size == sizeof(int16)) { 107 int16 value; 108 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 109 representation.SetToFormat("%" B_PRId16, value); 110 } else { 111 multiValueFormat.Format(representation, 112 info.size / sizeof(int16)); 113 } 114 break; 115 } 116 case B_INT32_TYPE: 117 { 118 if (info.size == sizeof(int32)) { 119 int32 value; 120 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 121 representation.SetToFormat("%" B_PRId32, value); 122 } else { 123 multiValueFormat.Format(representation, 124 info.size / sizeof(int32)); 125 } 126 break; 127 } 128 case B_INT64_TYPE: 129 { 130 if (info.size == sizeof(int64)) { 131 int64 value; 132 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 133 representation.SetToFormat("%" B_PRId64, value); 134 } else { 135 multiValueFormat.Format(representation, 136 info.size / sizeof(int64)); 137 } 138 break; 139 } 140 case B_INT8_TYPE: 141 { 142 if (info.size == sizeof(int8)) { 143 int8 value; 144 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 145 representation.SetToFormat("%" B_PRId8, value); 146 } else { 147 multiValueFormat.Format(representation, 148 info.size / sizeof(int8)); 149 } 150 break; 151 } 152 case B_RECT_TYPE: 153 { 154 if (info.size == sizeof(BRect)) { 155 BRect value; 156 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 157 representation.SetToFormat("(%g,%g) (%g,%g)", value.left, 158 value.top, value.right, value.bottom); 159 } else { 160 BStringFormat multiRectFormat(B_TRANSLATE( 161 "{0, plural, other{<# rectangles>}}")); 162 multiRectFormat.Format(representation, 163 info.size / sizeof(BRect)); 164 } 165 break; 166 } 167 case B_DOUBLE_TYPE: 168 { 169 if (info.size == sizeof(double)) { 170 double value; 171 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 172 representation.SetToFormat("%f", value); 173 } else { 174 multiValueFormat.Format(representation, 175 info.size / sizeof(double)); 176 } 177 break; 178 } 179 case B_FLOAT_TYPE: 180 { 181 if (info.size == sizeof(float)) { 182 float value; 183 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 184 representation.SetToFormat("%f", value); 185 } else { 186 multiValueFormat.Format(representation, 187 info.size / sizeof(float)); 188 } 189 break; 190 } 191 case B_TIME_TYPE: 192 { 193 // Try to handle attributes written on both 32 and 64bit systems 194 if (info.size == sizeof(int32)) { 195 int32 value; 196 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 197 dateTimeFormatter.Format(representation, value, 198 B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT); 199 } else if (info.size == sizeof(int64)) { 200 int64 value; 201 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 202 dateTimeFormatter.Format(representation, value, 203 B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT); 204 } else { 205 BStringFormat multiDateFormat(B_TRANSLATE( 206 "{0, plural, other{<# dates>}}")); 207 multiDateFormat.Format(representation, 208 info.size / sizeof(time_t)); 209 } 210 break; 211 } 212 case B_UINT16_TYPE: 213 { 214 if (info.size == sizeof(uint16)) { 215 uint16 value; 216 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 217 representation.SetToFormat("%" B_PRIu16, value); 218 } else { 219 multiValueFormat.Format(representation, 220 info.size / sizeof(uint16)); 221 } 222 break; 223 } 224 case B_UINT32_TYPE: 225 { 226 if (info.size == sizeof(uint32)) { 227 uint32 value; 228 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 229 representation.SetToFormat("%" B_PRIu32, value); 230 } else { 231 multiValueFormat.Format(representation, 232 info.size / sizeof(uint32)); 233 } 234 break; 235 } 236 case B_UINT64_TYPE: 237 { 238 if (info.size == sizeof(uint64)) { 239 uint64 value; 240 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 241 representation.SetToFormat("%" B_PRIu64, value); 242 } else { 243 multiValueFormat.Format(representation, 244 info.size / sizeof(uint64)); 245 } 246 break; 247 } 248 case B_UINT8_TYPE: 249 { 250 if (info.size == sizeof(uint8)) { 251 uint8 value; 252 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 253 representation.SetToFormat("%" B_PRIu8, value); 254 } else { 255 multiValueFormat.Format(representation, 256 info.size / sizeof(uint8)); 257 } 258 break; 259 } 260 default: 261 { 262 BStringFormat sizeFormat(B_TRANSLATE( 263 "{0, plural, one{<# data byte>} other{<# bytes of data>}}")); 264 sizeFormat.Format(representation, info.size); 265 break; 266 } 267 } 268 row->SetField(new BStringField(representation), kValueColumn); 269 270 switch(info.type) { 271 case B_AFFINE_TRANSFORM_TYPE: 272 row->SetField(new BStringField(B_TRANSLATE("Affine transform")), 273 kTypeColumn); 274 break; 275 case B_ALIGNMENT_TYPE: 276 row->SetField(new BStringField(B_TRANSLATE("Alignment")), 277 kTypeColumn); 278 break; 279 case B_ANY_TYPE: 280 row->SetField(new BStringField(B_TRANSLATE("Any")), 281 kTypeColumn); 282 break; 283 case B_ATOM_TYPE: 284 row->SetField(new BStringField(B_TRANSLATE("Atom")), 285 kTypeColumn); 286 break; 287 case B_ATOMREF_TYPE: 288 row->SetField(new BStringField(B_TRANSLATE("Atom reference")), 289 kTypeColumn); 290 break; 291 case B_BOOL_TYPE: 292 row->SetField(new BStringField(B_TRANSLATE("Boolean")), 293 kTypeColumn); 294 break; 295 case B_CHAR_TYPE: 296 row->SetField(new BStringField(B_TRANSLATE("Character")), 297 kTypeColumn); 298 break; 299 case B_COLOR_8_BIT_TYPE: 300 row->SetField(new BStringField(B_TRANSLATE( 301 "Palette-indexed picture")), kTypeColumn); 302 break; 303 case B_DOUBLE_TYPE: 304 row->SetField(new BStringField(B_TRANSLATE( 305 "Double-precision floating point number")), kTypeColumn); 306 break; 307 case B_FLOAT_TYPE: 308 row->SetField(new BStringField(B_TRANSLATE( 309 "Floating point number")), kTypeColumn); 310 break; 311 case B_GRAYSCALE_8_BIT_TYPE: 312 row->SetField(new BStringField(B_TRANSLATE( 313 "Grayscale picture")), kTypeColumn); 314 break; 315 case B_INT16_TYPE: 316 row->SetField(new BStringField(B_TRANSLATE("16-bit integer")), 317 kTypeColumn); 318 break; 319 case B_INT32_TYPE: 320 row->SetField(new BStringField(B_TRANSLATE("32-bit integer")), 321 kTypeColumn); 322 break; 323 case B_INT64_TYPE: 324 row->SetField(new BStringField(B_TRANSLATE("64-bit integer")), 325 kTypeColumn); 326 break; 327 case B_INT8_TYPE: 328 row->SetField(new BStringField(B_TRANSLATE("8-bit integer")), 329 kTypeColumn); 330 break; 331 case B_LARGE_ICON_TYPE: 332 row->SetField(new BStringField(B_TRANSLATE("Bitmap icon")), 333 kTypeColumn); 334 break; 335 case B_MEDIA_PARAMETER_GROUP_TYPE: 336 row->SetField(new BStringField(B_TRANSLATE( 337 "Media parameter group")), kTypeColumn); 338 break; 339 case B_MEDIA_PARAMETER_TYPE: 340 row->SetField(new BStringField(B_TRANSLATE("Media parameter")), 341 kTypeColumn); 342 break; 343 case B_MEDIA_PARAMETER_WEB_TYPE: 344 row->SetField(new BStringField(B_TRANSLATE( 345 "Media parameter web")), kTypeColumn); 346 break; 347 case B_MESSAGE_TYPE: 348 row->SetField(new BStringField(B_TRANSLATE("Message")), 349 kTypeColumn); 350 break; 351 case B_MESSENGER_TYPE: 352 row->SetField(new BStringField(B_TRANSLATE("Messenger")), 353 kTypeColumn); 354 break; 355 case B_MIME_TYPE: 356 row->SetField(new BStringField(B_TRANSLATE("MIME Type")), 357 kTypeColumn); 358 break; 359 case B_MINI_ICON_TYPE: 360 row->SetField(new BStringField(B_TRANSLATE( 361 "Small bitmap icon")), kTypeColumn); 362 break; 363 case B_MONOCHROME_1_BIT_TYPE: 364 row->SetField(new BStringField(B_TRANSLATE( 365 "Monochrome picture")), kTypeColumn); 366 break; 367 case B_OBJECT_TYPE: 368 row->SetField(new BStringField(B_TRANSLATE("Object")), 369 kTypeColumn); 370 break; 371 case B_OFF_T_TYPE: 372 row->SetField(new BStringField(B_TRANSLATE("File offset")), 373 kTypeColumn); 374 break; 375 case B_PATTERN_TYPE: 376 row->SetField(new BStringField(B_TRANSLATE("Drawing pattern")), 377 kTypeColumn); 378 break; 379 case B_POINTER_TYPE: 380 row->SetField(new BStringField(B_TRANSLATE("Memory pointer")), 381 kTypeColumn); 382 break; 383 case B_POINT_TYPE: 384 row->SetField(new BStringField(B_TRANSLATE("Point")), 385 kTypeColumn); 386 break; 387 case B_PROPERTY_INFO_TYPE: 388 row->SetField(new BStringField(B_TRANSLATE("Property info")), 389 kTypeColumn); 390 break; 391 case B_RAW_TYPE: 392 row->SetField(new BStringField(B_TRANSLATE("Raw data")), 393 kTypeColumn); 394 break; 395 case B_RECT_TYPE: 396 row->SetField(new BStringField(B_TRANSLATE("Rectangle")), 397 kTypeColumn); 398 break; 399 case B_REF_TYPE: 400 row->SetField(new BStringField(B_TRANSLATE("Entry ref")), 401 kTypeColumn); 402 break; 403 case B_NODE_REF_TYPE: 404 row->SetField(new BStringField(B_TRANSLATE("Node ref")), 405 kTypeColumn); 406 break; 407 case B_RGB_32_BIT_TYPE: 408 row->SetField(new BStringField(B_TRANSLATE( 409 "True-color picture")), kTypeColumn); 410 break; 411 case B_RGB_COLOR_TYPE: 412 row->SetField(new BStringField(B_TRANSLATE("Color")), 413 kTypeColumn); 414 break; 415 case B_SIZE_TYPE: 416 row->SetField(new BStringField(B_TRANSLATE("Geometric size")), 417 kTypeColumn); 418 break; 419 case B_SIZE_T_TYPE: 420 row->SetField(new BStringField(B_TRANSLATE("Memory size")), 421 kTypeColumn); 422 break; 423 case B_SSIZE_T_TYPE: 424 row->SetField(new BStringField(B_TRANSLATE( 425 "Signed memory size")), kTypeColumn); 426 break; 427 case B_STRING_TYPE: 428 row->SetField(new BStringField(B_TRANSLATE("Plain text")), 429 kTypeColumn); 430 break; 431 case B_STRING_LIST_TYPE: 432 row->SetField(new BStringField(B_TRANSLATE("Text list")), 433 kTypeColumn); 434 break; 435 case B_TIME_TYPE: 436 row->SetField(new BStringField(B_TRANSLATE("Time")), 437 kTypeColumn); 438 break; 439 case B_UINT16_TYPE: 440 row->SetField(new BStringField(B_TRANSLATE( 441 "16-bit unsigned integer")), kTypeColumn); 442 break; 443 case B_UINT32_TYPE: 444 row->SetField(new BStringField(B_TRANSLATE( 445 "32-bit unsigned integer")), kTypeColumn); 446 break; 447 case B_UINT64_TYPE: 448 row->SetField(new BStringField(B_TRANSLATE( 449 "64-bit unsigned integer")), kTypeColumn); 450 break; 451 case B_UINT8_TYPE: 452 row->SetField(new BStringField(B_TRANSLATE( 453 "8-bit unsigned integer")), kTypeColumn); 454 break; 455 case B_VECTOR_ICON_TYPE: 456 row->SetField(new BStringField(B_TRANSLATE("Icon")), 457 kTypeColumn); 458 break; 459 case B_XATTR_TYPE: 460 row->SetField(new BStringField(B_TRANSLATE( 461 "Extended attribute")), kTypeColumn); 462 break; 463 case B_NETWORK_ADDRESS_TYPE: 464 row->SetField(new BStringField(B_TRANSLATE("Network address")), 465 kTypeColumn); 466 break; 467 case B_MIME_STRING_TYPE: 468 row->SetField(new BStringField(B_TRANSLATE("MIME String")), 469 kTypeColumn); 470 break; 471 case 'MSIG': 472 row->SetField(new BStringField(B_TRANSLATE("MIME Signature")), 473 kTypeColumn); 474 break; 475 case 'MSDC': 476 row->SetField(new BStringField(B_TRANSLATE("MIME Description")), 477 kTypeColumn); 478 break; 479 case 'MPTH': 480 row->SetField(new BStringField(B_TRANSLATE("MIME Path")), 481 kTypeColumn); 482 break; 483 case B_ASCII_TYPE: 484 row->SetField(new BStringField(B_TRANSLATE("ASCII Text")), 485 kTypeColumn); 486 break; 487 default: 488 row->SetField(new BStringField(B_TRANSLATE("(unknown)")), 489 kTypeColumn); 490 break; 491 } 492 fListView->AddRow(row); 493 } 494 495 int32 rows = fListView->CountRows(NULL); 496 if (rows < 5) 497 rows = 5; 498 BRow* first = fListView->RowAt(0, NULL); 499 if (first != NULL) { 500 float height = first->Height() * (rows + 2); 501 SetExplicitMaxSize(BSize(B_SIZE_UNSET, height)); 502 } 503 504 } 505