Tracker InfoWindow: add a tab with file attributes

Now there is no need to resort to listattr and catattr to see the
attributes of a file. You can get them easily, from the GUI.

Limitations:
- No editing support
- Only a few well-known types are handled
- No support for attributes with array of values or otherwise unexpected
  size
- Special handling for B_TIME_FORMAT which is annoyingly of a different
  size between 32 and 64bit systems, making the attribute format
  slightly incompatible.

The window is a bit small to show all the information, so the "Type"
column is put off-view on the right, one can scroll to it if needed.

Vertically there is space for only 4 to 5 entries. It was suggested that
we could merge the permissions and information tabs, making the new
first tab higher, and thus adding more space to this one as well.

Change-Id: I75d192314bc60378c2f058547485cb9c30263485
Reviewed-on: https://review.haiku-os.org/c/haiku/+/1748
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Adrien Destugues
2019-08-26 23:38:18 +00:00
committed by waddlesplash
parent 9bb8d3a40a
commit 84dc116351
4 changed files with 454 additions and 1 deletions
+3 -1
View File
@@ -25,6 +25,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
SharedLibrary $(libtracker) :
AttributeStream.cpp
AttributesView.cpp
AutoMounterSettings.cpp
BackgroundImage.cpp
Bitmaps.cpp
@@ -96,7 +97,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
WidgetAttributeText.cpp
:
be localestub shared translation
be columnlistview localestub shared translation
[ TargetLibstdc++ ] [ TargetLibsupc++ ]
[ MultiArchDefaultGristFiles libshortcuts_shared.a ]
;
@@ -109,6 +110,7 @@ DoCatalogs libtracker.so :
x-vnd.Haiku-libtracker
:
Tracker.cpp
AttributesView.cpp
AutoMounterSettings.cpp
ContainerWindow.cpp
CountView.cpp
@@ -0,0 +1,416 @@
/*
* Copyright (C) 2019 Adrien Destugues <[email protected]>
*
* Distributed under terms of the MIT license.
*/
#include "AttributesView.h"
#include <ColumnListView.h>
#include <ColumnTypes.h>
#include <DateTimeFormat.h>
#include <FormattingConventions.h>
#include <fs_attr.h>
#include <Node.h>
int kValueColumn = 1;
int kTypeColumn = 2;
AttributesView::AttributesView(Model* model)
:
BGroupView(B_VERTICAL, 0),
fListView(new BColumnListView("attrs", 0, B_PLAIN_BORDER))
{
SetName("Attributes");
AddChild(fListView);
float nameWidth = StringWidth("SYS:PACKAGE_FILE") + 16;
float typeWidth = StringWidth("Double-precision floating point number") + 16;
float valueWidth = StringWidth("W") * 64 + 16;
BStringColumn* nameColumn = new BStringColumn("Name", nameWidth, nameWidth,
nameWidth, nameWidth);
BStringColumn* typeColumn = new BStringColumn("Type", typeWidth, typeWidth,
typeWidth, typeWidth);
BStringColumn* valueColumn = new BStringColumn("Value", valueWidth,
valueWidth, valueWidth, valueWidth);
fListView->AddColumn(nameColumn, 0);
fListView->AddColumn(valueColumn, 1);
fListView->AddColumn(typeColumn, 2);
BNode* node = model->Node();
node->RewindAttrs();
char name[B_ATTR_NAME_LENGTH];
BDateTimeFormat dateTimeFormatter;
// Initialize only once for all attributes
while (node->GetNextAttrName(name) == B_OK) {
// Skip well-known attributes already shown elsewhere in the window
if (strcmp(name, "BEOS:TYPE") == 0)
continue;
attr_info info;
node->GetAttrInfo(name, &info);
BRow* row = new BRow;
row->SetField(new BStringField(name), 0);
BString representation;
switch(info.type) {
case B_STRING_TYPE:
case B_MIME_STRING_TYPE:
{
// Use a small buffer, long strings will be truncated
char buffer[64];
ssize_t size = node->ReadAttr(name, info.type, 0, buffer,
sizeof(buffer));
if (size > 0)
representation.SetTo(buffer, size);
break;
}
case B_BOOL_TYPE:
{
if (info.size == sizeof(bool)) {
bool value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation = value ? "yes" : "no";
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(bool));
}
break;
}
case B_INT16_TYPE:
{
if (info.size == sizeof(int16)) {
int16 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRId16, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(int16));
}
break;
}
case B_INT32_TYPE:
{
if (info.size == sizeof(int32)) {
int32 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRId32, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(int32));
}
break;
}
case B_INT64_TYPE:
{
if (info.size == sizeof(int64)) {
int64 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRId64, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(int64));
}
break;
}
case B_INT8_TYPE:
{
if (info.size == sizeof(int8)) {
int8 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRId8, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(int8));
}
break;
}
case B_RECT_TYPE:
{
if (info.size == sizeof(BRect)) {
BRect value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("(%f,%f) (%f,%f)", value.left,
value.top, value.right, value.bottom);
} else {
representation.SetToFormat("<%" B_PRIdOFF " rectangles>",
info.size / sizeof(BRect));
}
break;
}
case B_DOUBLE_TYPE:
{
if (info.size == sizeof(double)) {
double value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%f", value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(double));
}
break;
}
case B_FLOAT_TYPE:
{
if (info.size == sizeof(float)) {
float value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%f", value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(float));
}
break;
}
case B_TIME_TYPE:
{
// Try to handle attributes written on both 32 and 64bit systems
if (info.size == sizeof(int32)) {
int32 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
dateTimeFormatter.Format(representation, value,
B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT);
} else if (info.size == sizeof(int64)) {
int64 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
dateTimeFormatter.Format(representation, value,
B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT);
} else {
representation.SetToFormat("<%" B_PRIdOFF " dates>",
info.size / sizeof(time_t));
}
break;
}
case B_UINT16_TYPE:
{
if (info.size == sizeof(uint16)) {
uint16 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRIu16, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(uint16));
}
break;
}
case B_UINT32_TYPE:
{
if (info.size == sizeof(uint32)) {
uint32 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRIu32, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(uint32));
}
break;
}
case B_UINT64_TYPE:
{
if (info.size == sizeof(uint64)) {
uint64 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRIu64, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(int64));
}
break;
}
case B_UINT8_TYPE:
{
if (info.size == sizeof(uint8)) {
uint8 value;
node->ReadAttr(name, info.type, 0, &value, sizeof(value));
representation.SetToFormat("%" B_PRIu8, value);
} else {
representation.SetToFormat("<%" B_PRIdOFF " values>",
info.size / sizeof(int8));
}
break;
}
default:
representation.SetToFormat("<%" B_PRIdOFF " bytes of data>",
info.size);
break;
}
row->SetField(new BStringField(representation), kValueColumn);
switch(info.type) {
case B_AFFINE_TRANSFORM_TYPE:
row->SetField(new BStringField("Affine transform"),
kTypeColumn);
break;
case B_ALIGNMENT_TYPE:
row->SetField(new BStringField("Alignment"), kTypeColumn);
break;
case B_ANY_TYPE:
row->SetField(new BStringField("Any"), kTypeColumn);
break;
case B_ATOM_TYPE:
row->SetField(new BStringField("Atom"), kTypeColumn);
break;
case B_ATOMREF_TYPE:
row->SetField(new BStringField("Atom reference"), kTypeColumn);
break;
case B_BOOL_TYPE:
row->SetField(new BStringField("Boolean"), kTypeColumn);
break;
case B_CHAR_TYPE:
row->SetField(new BStringField("Character"), kTypeColumn);
break;
case B_COLOR_8_BIT_TYPE:
row->SetField(new BStringField("Palette-indexed picture"),
kTypeColumn);
break;
case B_DOUBLE_TYPE:
row->SetField(new BStringField(
"Double-precision floating point number"), kTypeColumn);
break;
case B_FLOAT_TYPE:
row->SetField(new BStringField("Floating point number"),
kTypeColumn);
break;
case B_GRAYSCALE_8_BIT_TYPE:
row->SetField(new BStringField("Grayscale picture"),
kTypeColumn);
break;
case B_INT16_TYPE:
row->SetField(new BStringField("16-bit integer"), kTypeColumn);
break;
case B_INT32_TYPE:
row->SetField(new BStringField("32-bit integer"), kTypeColumn);
break;
case B_INT64_TYPE:
row->SetField(new BStringField("64-bit integer"), kTypeColumn);
break;
case B_INT8_TYPE:
row->SetField(new BStringField("8-bit integer"), kTypeColumn);
break;
case B_LARGE_ICON_TYPE:
row->SetField(new BStringField("Bitmap icon"), kTypeColumn);
break;
case B_MEDIA_PARAMETER_GROUP_TYPE:
row->SetField(new BStringField("Media parameter group"),
kTypeColumn);
break;
case B_MEDIA_PARAMETER_TYPE:
row->SetField(new BStringField("Media parameter"), kTypeColumn);
break;
case B_MEDIA_PARAMETER_WEB_TYPE:
row->SetField(new BStringField("Media parameter web"),
kTypeColumn);
break;
case B_MESSAGE_TYPE:
row->SetField(new BStringField("Message"), kTypeColumn);
break;
case B_MESSENGER_TYPE:
row->SetField(new BStringField("Messenger"), kTypeColumn);
break;
case B_MIME_TYPE:
row->SetField(new BStringField("MIME Type"), kTypeColumn);
break;
case B_MINI_ICON_TYPE:
row->SetField(new BStringField("Small bitmap icon"),
kTypeColumn);
break;
case B_MONOCHROME_1_BIT_TYPE:
row->SetField(new BStringField("Monochrome picture"),
kTypeColumn);
break;
case B_OBJECT_TYPE:
row->SetField(new BStringField("Object"), kTypeColumn);
break;
case B_OFF_T_TYPE:
row->SetField(new BStringField("File offset"), kTypeColumn);
break;
case B_PATTERN_TYPE:
row->SetField(new BStringField("Drawing pattern"), kTypeColumn);
break;
case B_POINTER_TYPE:
row->SetField(new BStringField("Memory pointer"), kTypeColumn);
break;
case B_POINT_TYPE:
row->SetField(new BStringField("Point"), kTypeColumn);
break;
case B_PROPERTY_INFO_TYPE:
row->SetField(new BStringField("Property info"), kTypeColumn);
break;
case B_RAW_TYPE:
row->SetField(new BStringField("Raw data"), kTypeColumn);
break;
case B_RECT_TYPE:
row->SetField(new BStringField("Rectangle"), kTypeColumn);
break;
case B_REF_TYPE:
row->SetField(new BStringField("Reference"), kTypeColumn);
break;
case B_RGB_32_BIT_TYPE:
row->SetField(new BStringField("True-color picture"),
kTypeColumn);
break;
case B_RGB_COLOR_TYPE:
row->SetField(new BStringField("Color"), kTypeColumn);
break;
case B_SIZE_TYPE:
row->SetField(new BStringField("Geometric size"), kTypeColumn);
break;
case B_SIZE_T_TYPE:
row->SetField(new BStringField("Memory size"), kTypeColumn);
break;
case B_SSIZE_T_TYPE:
row->SetField(new BStringField("Signed memory size"),
kTypeColumn);
break;
case B_STRING_TYPE:
row->SetField(new BStringField("Plain text"), kTypeColumn);
break;
case B_STRING_LIST_TYPE:
row->SetField(new BStringField("Text list"), kTypeColumn);
break;
case B_TIME_TYPE:
row->SetField(new BStringField("Time"), kTypeColumn);
break;
case B_UINT16_TYPE:
row->SetField(new BStringField("16-bit unsigned integer"),
kTypeColumn);
break;
case B_UINT32_TYPE:
row->SetField(new BStringField("32-bit unsigned integer"),
kTypeColumn);
break;
case B_UINT64_TYPE:
row->SetField(new BStringField("64-bit unsigned integer"),
kTypeColumn);
break;
case B_UINT8_TYPE:
row->SetField(new BStringField("8-bit unsigned integer"),
kTypeColumn);
break;
case B_VECTOR_ICON_TYPE:
row->SetField(new BStringField("Icon"), kTypeColumn);
break;
case B_XATTR_TYPE:
row->SetField(new BStringField("Extended attribute"),
kTypeColumn);
break;
case B_NETWORK_ADDRESS_TYPE:
row->SetField(new BStringField("Network address"), kTypeColumn);
break;
case B_MIME_STRING_TYPE:
row->SetField(new BStringField("MIME String"), kTypeColumn);
break;
case B_ASCII_TYPE:
row->SetField(new BStringField("ASCII Text"), kTypeColumn);
break;
default:
row->SetField(new BStringField("(unknown)"), kTypeColumn);
break;
}
fListView->AddRow(row);
}
}
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2019 Adrien Destugues <[email protected]>
*
* Distributed under terms of the MIT license.
*/
#ifndef ATTRIBUTESVIEW_H
#define ATTRIBUTESVIEW_H
#include <ColumnListView.h>
#include <GroupView.h>
#include "Model.h"
namespace BPrivate {
class AttributesView: public BGroupView
{
public:
AttributesView(Model* model);
private:
BColumnListView* fListView;
};
};
#endif /* !ATTRIBUTESVIEW_H */
@@ -64,6 +64,7 @@ All rights reserved.
#include <VolumeRoster.h>
#include "Attributes.h"
#include "AttributesView.h"
#include "AutoLock.h"
#include "Commands.h"
#include "DialogPane.h"
@@ -146,6 +147,9 @@ BInfoWindow::BInfoWindow(Model* model, int32 group_index,
fPermissionsView = new FilePermissionsView(
permissionsBounds, fModel);
tabView->AddTab(fPermissionsView);
tabView->AddTab(new AttributesView(TargetModel()));
// This window accepts messages before being shown, so let's start the
// looper immediately.
Run();