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:
committed by
waddlesplash
parent
9bb8d3a40a
commit
84dc116351
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user