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 { 80 // Use a small buffer, long strings will be truncated 81 char buffer[64]; 82 ssize_t size = node->ReadAttr(name, info.type, 0, buffer, 83 sizeof(buffer)); 84 if (size > 0) 85 representation.SetTo(buffer, size); 86 break; 87 } 88 case B_BOOL_TYPE: 89 { 90 if (info.size == sizeof(bool)) { 91 bool value; 92 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 93 representation = value ? B_TRANSLATE("yes") 94 : B_TRANSLATE("no"); 95 } else { 96 multiValueFormat.Format(representation, 97 info.size / sizeof(bool)); 98 } 99 break; 100 } 101 case B_INT16_TYPE: 102 { 103 if (info.size == sizeof(int16)) { 104 int16 value; 105 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 106 representation.SetToFormat("%" B_PRId16, value); 107 } else { 108 multiValueFormat.Format(representation, 109 info.size / sizeof(int16)); 110 } 111 break; 112 } 113 case B_INT32_TYPE: 114 { 115 if (info.size == sizeof(int32)) { 116 int32 value; 117 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 118 representation.SetToFormat("%" B_PRId32, value); 119 } else { 120 multiValueFormat.Format(representation, 121 info.size / sizeof(int32)); 122 } 123 break; 124 } 125 case B_INT64_TYPE: 126 { 127 if (info.size == sizeof(int64)) { 128 int64 value; 129 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 130 representation.SetToFormat("%" B_PRId64, value); 131 } else { 132 multiValueFormat.Format(representation, 133 info.size / sizeof(int64)); 134 } 135 break; 136 } 137 case B_INT8_TYPE: 138 { 139 if (info.size == sizeof(int8)) { 140 int8 value; 141 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 142 representation.SetToFormat("%" B_PRId8, value); 143 } else { 144 multiValueFormat.Format(representation, 145 info.size / sizeof(int8)); 146 } 147 break; 148 } 149 case B_RECT_TYPE: 150 { 151 if (info.size == sizeof(BRect)) { 152 BRect value; 153 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 154 representation.SetToFormat("(%g,%g) (%g,%g)", value.left, 155 value.top, value.right, value.bottom); 156 } else { 157 BStringFormat multiRectFormat(B_TRANSLATE( 158 "{0, plural, other{<# rectangles>}}")); 159 multiRectFormat.Format(representation, 160 info.size / sizeof(BRect)); 161 } 162 break; 163 } 164 case B_DOUBLE_TYPE: 165 { 166 if (info.size == sizeof(double)) { 167 double value; 168 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 169 representation.SetToFormat("%f", value); 170 } else { 171 multiValueFormat.Format(representation, 172 info.size / sizeof(double)); 173 } 174 break; 175 } 176 case B_FLOAT_TYPE: 177 { 178 if (info.size == sizeof(float)) { 179 float value; 180 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 181 representation.SetToFormat("%f", value); 182 } else { 183 multiValueFormat.Format(representation, 184 info.size / sizeof(float)); 185 } 186 break; 187 } 188 case B_TIME_TYPE: 189 { 190 // Try to handle attributes written on both 32 and 64bit systems 191 if (info.size == sizeof(int32)) { 192 int32 value; 193 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 194 dateTimeFormatter.Format(representation, value, 195 B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT); 196 } else if (info.size == sizeof(int64)) { 197 int64 value; 198 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 199 dateTimeFormatter.Format(representation, value, 200 B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT); 201 } else { 202 BStringFormat multiDateFormat(B_TRANSLATE( 203 "{0, plural, other{<# dates>}}")); 204 multiDateFormat.Format(representation, 205 info.size / sizeof(time_t)); 206 } 207 break; 208 } 209 case B_UINT16_TYPE: 210 { 211 if (info.size == sizeof(uint16)) { 212 uint16 value; 213 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 214 representation.SetToFormat("%" B_PRIu16, value); 215 } else { 216 multiValueFormat.Format(representation, 217 info.size / sizeof(uint16)); 218 } 219 break; 220 } 221 case B_UINT32_TYPE: 222 { 223 if (info.size == sizeof(uint32)) { 224 uint32 value; 225 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 226 representation.SetToFormat("%" B_PRIu32, value); 227 } else { 228 multiValueFormat.Format(representation, 229 info.size / sizeof(uint32)); 230 } 231 break; 232 } 233 case B_UINT64_TYPE: 234 { 235 if (info.size == sizeof(uint64)) { 236 uint64 value; 237 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 238 representation.SetToFormat("%" B_PRIu64, value); 239 } else { 240 multiValueFormat.Format(representation, 241 info.size / sizeof(uint64)); 242 } 243 break; 244 } 245 case B_UINT8_TYPE: 246 { 247 if (info.size == sizeof(uint8)) { 248 uint8 value; 249 node->ReadAttr(name, info.type, 0, &value, sizeof(value)); 250 representation.SetToFormat("%" B_PRIu8, value); 251 } else { 252 multiValueFormat.Format(representation, 253 info.size / sizeof(uint8)); 254 } 255 break; 256 } 257 default: 258 { 259 BStringFormat sizeFormat(B_TRANSLATE( 260 "{0, plural, one{<# data byte>} other{<# bytes of data>}}")); 261 sizeFormat.Format(representation, info.size); 262 break; 263 } 264 } 265 row->SetField(new BStringField(representation), kValueColumn); 266 267 switch(info.type) { 268 case B_AFFINE_TRANSFORM_TYPE: 269 row->SetField(new BStringField(B_TRANSLATE("Affine transform")), 270 kTypeColumn); 271 break; 272 case B_ALIGNMENT_TYPE: 273 row->SetField(new BStringField(B_TRANSLATE("Alignment")), 274 kTypeColumn); 275 break; 276 case B_ANY_TYPE: 277 row->SetField(new BStringField(B_TRANSLATE("Any")), 278 kTypeColumn); 279 break; 280 case B_ATOM_TYPE: 281 row->SetField(new BStringField(B_TRANSLATE("Atom")), 282 kTypeColumn); 283 break; 284 case B_ATOMREF_TYPE: 285 row->SetField(new BStringField(B_TRANSLATE("Atom reference")), 286 kTypeColumn); 287 break; 288 case B_BOOL_TYPE: 289 row->SetField(new BStringField(B_TRANSLATE("Boolean")), 290 kTypeColumn); 291 break; 292 case B_CHAR_TYPE: 293 row->SetField(new BStringField(B_TRANSLATE("Character")), 294 kTypeColumn); 295 break; 296 case B_COLOR_8_BIT_TYPE: 297 row->SetField(new BStringField(B_TRANSLATE( 298 "Palette-indexed picture")), kTypeColumn); 299 break; 300 case B_DOUBLE_TYPE: 301 row->SetField(new BStringField(B_TRANSLATE( 302 "Double-precision floating point number")), kTypeColumn); 303 break; 304 case B_FLOAT_TYPE: 305 row->SetField(new BStringField(B_TRANSLATE( 306 "Floating point number")), kTypeColumn); 307 break; 308 case B_GRAYSCALE_8_BIT_TYPE: 309 row->SetField(new BStringField(B_TRANSLATE( 310 "Grayscale picture")), kTypeColumn); 311 break; 312 case B_INT16_TYPE: 313 row->SetField(new BStringField(B_TRANSLATE("16-bit integer")), 314 kTypeColumn); 315 break; 316 case B_INT32_TYPE: 317 row->SetField(new BStringField(B_TRANSLATE("32-bit integer")), 318 kTypeColumn); 319 break; 320 case B_INT64_TYPE: 321 row->SetField(new BStringField(B_TRANSLATE("64-bit integer")), 322 kTypeColumn); 323 break; 324 case B_INT8_TYPE: 325 row->SetField(new BStringField(B_TRANSLATE("8-bit integer")), 326 kTypeColumn); 327 break; 328 case B_LARGE_ICON_TYPE: 329 row->SetField(new BStringField(B_TRANSLATE("Bitmap icon")), 330 kTypeColumn); 331 break; 332 case B_MEDIA_PARAMETER_GROUP_TYPE: 333 row->SetField(new BStringField(B_TRANSLATE( 334 "Media parameter group")), kTypeColumn); 335 break; 336 case B_MEDIA_PARAMETER_TYPE: 337 row->SetField(new BStringField(B_TRANSLATE("Media parameter")), 338 kTypeColumn); 339 break; 340 case B_MEDIA_PARAMETER_WEB_TYPE: 341 row->SetField(new BStringField(B_TRANSLATE( 342 "Media parameter web")), kTypeColumn); 343 break; 344 case B_MESSAGE_TYPE: 345 row->SetField(new BStringField(B_TRANSLATE("Message")), 346 kTypeColumn); 347 break; 348 case B_MESSENGER_TYPE: 349 row->SetField(new BStringField(B_TRANSLATE("Messenger")), 350 kTypeColumn); 351 break; 352 case B_MIME_TYPE: 353 row->SetField(new BStringField(B_TRANSLATE("MIME Type")), 354 kTypeColumn); 355 break; 356 case B_MINI_ICON_TYPE: 357 row->SetField(new BStringField(B_TRANSLATE( 358 "Small bitmap icon")), kTypeColumn); 359 break; 360 case B_MONOCHROME_1_BIT_TYPE: 361 row->SetField(new BStringField(B_TRANSLATE( 362 "Monochrome picture")), kTypeColumn); 363 break; 364 case B_OBJECT_TYPE: 365 row->SetField(new BStringField(B_TRANSLATE("Object")), 366 kTypeColumn); 367 break; 368 case B_OFF_T_TYPE: 369 row->SetField(new BStringField(B_TRANSLATE("File offset")), 370 kTypeColumn); 371 break; 372 case B_PATTERN_TYPE: 373 row->SetField(new BStringField(B_TRANSLATE("Drawing pattern")), 374 kTypeColumn); 375 break; 376 case B_POINTER_TYPE: 377 row->SetField(new BStringField(B_TRANSLATE("Memory pointer")), 378 kTypeColumn); 379 break; 380 case B_POINT_TYPE: 381 row->SetField(new BStringField(B_TRANSLATE("Point")), 382 kTypeColumn); 383 break; 384 case B_PROPERTY_INFO_TYPE: 385 row->SetField(new BStringField(B_TRANSLATE("Property info")), 386 kTypeColumn); 387 break; 388 case B_RAW_TYPE: 389 row->SetField(new BStringField(B_TRANSLATE("Raw data")), 390 kTypeColumn); 391 break; 392 case B_RECT_TYPE: 393 row->SetField(new BStringField(B_TRANSLATE("Rectangle")), 394 kTypeColumn); 395 break; 396 case B_REF_TYPE: 397 row->SetField(new BStringField(B_TRANSLATE("Entry ref")), 398 kTypeColumn); 399 break; 400 case B_NODE_REF_TYPE: 401 row->SetField(new BStringField(B_TRANSLATE("Node ref")), 402 kTypeColumn); 403 break; 404 case B_RGB_32_BIT_TYPE: 405 row->SetField(new BStringField(B_TRANSLATE( 406 "True-color picture")), kTypeColumn); 407 break; 408 case B_RGB_COLOR_TYPE: 409 row->SetField(new BStringField(B_TRANSLATE("Color")), 410 kTypeColumn); 411 break; 412 case B_SIZE_TYPE: 413 row->SetField(new BStringField(B_TRANSLATE("Geometric size")), 414 kTypeColumn); 415 break; 416 case B_SIZE_T_TYPE: 417 row->SetField(new BStringField(B_TRANSLATE("Memory size")), 418 kTypeColumn); 419 break; 420 case B_SSIZE_T_TYPE: 421 row->SetField(new BStringField(B_TRANSLATE( 422 "Signed memory size")), kTypeColumn); 423 break; 424 case B_STRING_TYPE: 425 row->SetField(new BStringField(B_TRANSLATE("Plain text")), 426 kTypeColumn); 427 break; 428 case B_STRING_LIST_TYPE: 429 row->SetField(new BStringField(B_TRANSLATE("Text list")), 430 kTypeColumn); 431 break; 432 case B_TIME_TYPE: 433 row->SetField(new BStringField(B_TRANSLATE("Time")), 434 kTypeColumn); 435 break; 436 case B_UINT16_TYPE: 437 row->SetField(new BStringField(B_TRANSLATE( 438 "16-bit unsigned integer")), kTypeColumn); 439 break; 440 case B_UINT32_TYPE: 441 row->SetField(new BStringField(B_TRANSLATE( 442 "32-bit unsigned integer")), kTypeColumn); 443 break; 444 case B_UINT64_TYPE: 445 row->SetField(new BStringField(B_TRANSLATE( 446 "64-bit unsigned integer")), kTypeColumn); 447 break; 448 case B_UINT8_TYPE: 449 row->SetField(new BStringField(B_TRANSLATE( 450 "8-bit unsigned integer")), kTypeColumn); 451 break; 452 case B_VECTOR_ICON_TYPE: 453 row->SetField(new BStringField(B_TRANSLATE("Icon")), 454 kTypeColumn); 455 break; 456 case B_XATTR_TYPE: 457 row->SetField(new BStringField(B_TRANSLATE( 458 "Extended attribute")), kTypeColumn); 459 break; 460 case B_NETWORK_ADDRESS_TYPE: 461 row->SetField(new BStringField(B_TRANSLATE("Network address")), 462 kTypeColumn); 463 break; 464 case B_MIME_STRING_TYPE: 465 row->SetField(new BStringField(B_TRANSLATE("MIME String")), 466 kTypeColumn); 467 break; 468 case B_ASCII_TYPE: 469 row->SetField(new BStringField(B_TRANSLATE("ASCII Text")), 470 kTypeColumn); 471 break; 472 default: 473 row->SetField(new BStringField(B_TRANSLATE("(unknown)")), 474 kTypeColumn); 475 break; 476 } 477 fListView->AddRow(row); 478 } 479 480 int32 rows = fListView->CountRows(NULL); 481 if (rows < 5) 482 rows = 5; 483 BRow* first = fListView->RowAt(0, NULL); 484 if (first != NULL) { 485 float height = first->Height() * (rows + 2); 486 SetExplicitMaxSize(BSize(B_SIZE_UNSET, height)); 487 } 488 489 } 490