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
AttributesView(Model * model)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