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