xref: /haiku/src/kits/tracker/infowindow/AttributesView.cpp (revision 26d22ee8dc5db3cea88354d0536f5dd9950b6bcf)
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