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