Some more work in progress, still far from finished:

* The extra attributes of a MIME type are now shown as well.
* The preferred applications are now not only grouped by level of support,
  but are also sorted alphabetically, and get the app signature as part
  of the label in case two (or more) apps have the same name.
* And more :)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16357 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-02-12 12:59:21 +00:00
parent ca228cbfcb
commit 2602f6e9c2
3 changed files with 375 additions and 19 deletions

View File

@ -28,11 +28,30 @@
const uint32 kMsgTypeSelected = 'typs'; const uint32 kMsgTypeSelected = 'typs';
const uint32 kMsgExtensionSelected = 'exts';
const uint32 kMsgAttributeSelected = 'atrs';
const uint32 kMsgPreferredAppChosen = 'papc';
const struct type_map {
const char* name;
type_code type;
} kTypeMap[] = {
{"String", B_STRING_TYPE},
{"Boolean", B_BOOL_TYPE},
{"Integer 8 bit", B_INT8_TYPE},
{"Integer 16 bit", B_INT16_TYPE},
{"Integer 32 bit", B_INT32_TYPE},
{"Integer 64 bit", B_INT64_TYPE},
{"Float", B_FLOAT_TYPE},
{"Double", B_DOUBLE_TYPE},
{"Time", B_TIME_TYPE},
{NULL, 0}
};
class IconView : public BControl { class IconView : public BControl {
public: public:
IconView(BRect rect, const char* name, BMessage* message); IconView(BRect frame, const char* name, BMessage* message);
virtual ~IconView(); virtual ~IconView();
void SetTo(BMimeType* type); void SetTo(BMimeType* type);
@ -49,9 +68,85 @@ class IconView : public BControl {
BBitmap* fIcon; BBitmap* fIcon;
}; };
class AttributeListView : public BListView {
public:
AttributeListView(BRect frame, const char* name, uint32 resizingMode);
virtual ~AttributeListView();
IconView::IconView(BRect rect, const char* name, BMessage* message) void SetTo(BMimeType* type);
: BControl(rect, name, NULL, message,
virtual void Draw(BRect updateRect);
private:
void _DeleteItems();
};
class AttributeItem : public BStringItem {
public:
AttributeItem(const char* name, const char* publicName, type_code type,
int32 alignment, int32 width, bool visible, bool editable);
~AttributeItem();
virtual void DrawItem(BView* owner, BRect itemRect,
bool drawEverything = false);
private:
BString fName;
BString fPublicName;
type_code fType;
int32 fAlignment;
int32 fWidth;
bool fVisible;
bool fEditable;
};
// #pragma mark -
static int
compare_menu_items(const void* _a, const void* _b)
{
BMenuItem* a = *(BMenuItem**)_a;
BMenuItem* b = *(BMenuItem**)_b;
return strcasecmp(a->Label(), b->Label());
}
static void
name_for_type(BString& string, type_code type)
{
for (int32 i = 0; kTypeMap[i].name != NULL; i++) {
if (kTypeMap[i].type == type) {
string = kTypeMap[i].name;
return;
}
}
char buffer[32];
buffer[0] = '\'';
buffer[1] = 0xff & (type >> 24);
buffer[2] = 0xff & (type >> 16);
buffer[3] = 0xff & (type >> 8);
buffer[4] = 0xff & (type);
buffer[5] = '\'';
buffer[6] = 0;
for (int16 i = 0;i < 4;i++) {
if (buffer[i] < ' ')
buffer[i] = '.';
}
snprintf(buffer + 6, sizeof(buffer), " (0x%lx)", type);
string = buffer;
}
// #pragma mark -
IconView::IconView(BRect frame, const char* name, BMessage* message)
: BControl(frame, name, NULL, message,
B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW),
fIcon(NULL) fIcon(NULL)
{ {
@ -72,7 +167,7 @@ IconView::SetTo(BMimeType* type)
if (type != NULL) { if (type != NULL) {
if (fIcon == NULL) if (fIcon == NULL)
fIcon = new BBitmap(BRect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1), B_CMAP8); fIcon = new BBitmap(BRect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1), B_CMAP8);
if (type->GetIcon(fIcon, B_LARGE_ICON) == B_OK) { if (type->GetIcon(fIcon, B_LARGE_ICON) == B_OK) {
Invalidate(); Invalidate();
return; return;
@ -95,10 +190,10 @@ IconView::Draw(BRect updateRect)
DrawBitmap(fIcon, BPoint(0, 0)); DrawBitmap(fIcon, BPoint(0, 0));
} else if (IsEnabled()) { } else if (IsEnabled()) {
BRect rect = Bounds(); BRect rect = Bounds();
rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT); rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT); rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
BeginLineArray(8); BeginLineArray(8);
AddLine(BPoint(rect.left, rect.bottom), AddLine(BPoint(rect.left, rect.bottom),
@ -132,6 +227,151 @@ IconView::Draw(BRect updateRect)
// #pragma mark - // #pragma mark -
AttributeItem::AttributeItem(const char* name, const char* publicName,
type_code type, int32 alignment, int32 width, bool visible,
bool editable)
: BStringItem(publicName),
fName(name),
fType(type),
fAlignment(alignment),
fWidth(width),
fVisible(visible),
fEditable(editable)
{
}
AttributeItem::~AttributeItem()
{
}
void
AttributeItem::DrawItem(BView* owner, BRect frame, bool drawEverything)
{
BStringItem::DrawItem(owner, frame, drawEverything);
rgb_color highColor = owner->HighColor();
rgb_color lowColor = owner->LowColor();
if (IsSelected())
owner->SetLowColor(tint_color(lowColor, B_DARKEN_2_TINT));
rgb_color black = {0, 0, 0, 255};
if (!IsEnabled())
owner->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
else
owner->SetHighColor(black);
owner->MovePenTo(frame.left + frame.Width() / 2.0f + 5.0f, owner->PenLocation().y);
BString type;
name_for_type(type, fType);
owner->DrawString(type.String());
owner->SetHighColor(tint_color(owner->ViewColor(), B_DARKEN_1_TINT));
float middle = frame.left + frame.Width() / 2.0f;
owner->StrokeLine(BPoint(middle, 0.0f), BPoint(middle, frame.bottom));
owner->SetHighColor(highColor);
owner->SetLowColor(lowColor);
}
// #pragma mark -
AttributeListView::AttributeListView(BRect frame, const char* name,
uint32 resizingMode)
: BListView(frame, name, B_SINGLE_SELECTION_LIST, resizingMode)
{
}
AttributeListView::~AttributeListView()
{
_DeleteItems();
}
void
AttributeListView::_DeleteItems()
{
for (int32 i = CountItems(); i-- > 0;) {
delete ItemAt(i);
}
MakeEmpty();
}
void
AttributeListView::SetTo(BMimeType* type)
{
_DeleteItems();
// fill it again
if (type == NULL)
return;
BMessage attributes;
if (type->GetAttrInfo(&attributes) != B_OK)
return;
const char* publicName;
int32 i = 0;
while (attributes.FindString("attr:public_name", i, &publicName) == B_OK) {
const char* name;
if (attributes.FindString("attr:name", i, &name) != B_OK)
name = "-";
type_code type;
if (attributes.FindInt32("attr:type", i, (int32 *)&type) != B_OK)
type = B_STRING_TYPE;
bool editable;
if (attributes.FindBool("attr:editable", i, &editable) != B_OK)
editable = false;
bool visible;
if (attributes.FindBool("attr:viewable", i, &visible) != B_OK)
visible = false;
bool extra;
if (attributes.FindBool("attr:extra", i, &extra) != B_OK)
extra = false;
int32 alignment;
if (attributes.FindInt32("attr:alignment", i, &alignment) != B_OK)
alignment = B_ALIGN_LEFT;
int32 width;
if (attributes.FindInt32("attr:width", i, &width) != B_OK)
width = 50;
AddItem(new AttributeItem(name, publicName, type, alignment, width,
visible, editable));
i++;
}
}
void
AttributeListView::Draw(BRect updateRect)
{
BListView::Draw(updateRect);
SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
float middle = Bounds().Width() / 2.0f;
StrokeLine(BPoint(middle, 0.0f), BPoint(middle, Bounds().bottom));
}
// #pragma mark -
FileTypesWindow::FileTypesWindow(BRect frame) FileTypesWindow::FileTypesWindow(BRect frame)
: BWindow(frame, "FileTypes", B_TITLED_WINDOW, : BWindow(frame, "FileTypes", B_TITLED_WINDOW,
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
@ -251,6 +491,7 @@ FileTypesWindow::FileTypesWindow(BRect frame)
// take scrollview border into account // take scrollview border into account
fExtensionListView = new BListView(innerRect, "listview ext", fExtensionListView = new BListView(innerRect, "listview ext",
B_SINGLE_SELECTION_LIST, B_FOLLOW_LEFT_RIGHT); B_SINGLE_SELECTION_LIST, B_FOLLOW_LEFT_RIGHT);
fExtensionListView->SetSelectionMessage(new BMessage(kMsgExtensionSelected));
scrollView = new BScrollView("scrollview ext", fExtensionListView, scrollView = new BScrollView("scrollview ext", fExtensionListView,
B_FOLLOW_LEFT_RIGHT, B_FRAME_EVENTS | B_WILL_DRAW, false, true); B_FOLLOW_LEFT_RIGHT, B_FRAME_EVENTS | B_WILL_DRAW, false, true);
box->AddChild(scrollView); box->AddChild(scrollView);
@ -312,13 +553,21 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect.right = innerRect.left - 6.0f; innerRect.right = innerRect.left - 6.0f;
innerRect.left = 8.0f; innerRect.left = 8.0f;
fPreferredField = new BMenuField(innerRect, "preferred", NULL, menu, BView* constrainingView = new BView(innerRect, NULL, B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW);
B_FOLLOW_LEFT_RIGHT); constrainingView->SetViewColor(topView->ViewColor());
fPreferredField = new BMenuField(innerRect.OffsetToCopy(B_ORIGIN), "preferred",
NULL, menu);
float width, height; float width, height;
fPreferredField->GetPreferredSize(&width, &height); fPreferredField->GetPreferredSize(&width, &height);
fPreferredField->ResizeTo(innerRect.Width(), height); fPreferredField->ResizeTo(innerRect.Width(), height);
fPreferredField->MoveBy(0.0f, (innerRect.Height() - height) / 2.0f); fPreferredField->MoveBy(0.0f, (innerRect.Height() - height) / 2.0f);
box->AddChild(fPreferredField); constrainingView->AddChild(fPreferredField);
// we embed the menu field in another view to make it behave like
// we want so that it can't obscure other elements with larger
// labels
box->AddChild(constrainingView);
// "Extra Attributes" group // "Extra Attributes" group
@ -346,9 +595,10 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect.top = 8.0f + ceilf(fontHeight.ascent); innerRect.top = 8.0f + ceilf(fontHeight.ascent);
innerRect.bottom = box->Bounds().bottom - 10.0f; innerRect.bottom = box->Bounds().bottom - 10.0f;
// take scrollview border into account // take scrollview border into account
BListView* listView = new BListView(innerRect, "listview attr", fAttributeListView = new AttributeListView(innerRect, "listview attr",
B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); B_FOLLOW_ALL);
scrollView = new BScrollView("scrollview attr", listView, fAttributeListView->SetSelectionMessage(new BMessage(kMsgAttributeSelected));
scrollView = new BScrollView("scrollview attr", fAttributeListView,
B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW, false, true); B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW, false, true);
box->AddChild(scrollView); box->AddChild(scrollView);
@ -395,6 +645,20 @@ FileTypesWindow::_UpdateExtensions(BMimeType* type)
} }
void
FileTypesWindow::_AddSignature(BMenuItem* item, const char* signature)
{
const char* subType = strchr(signature, '/');
if (subType == NULL)
return;
char label[B_MIME_TYPE_LENGTH];
snprintf(label, sizeof(label), "%s (%s)", item->Label(), subType + 1);
item->SetLabel(label);
}
void void
FileTypesWindow::_UpdatePreferredApps(BMimeType* type) FileTypesWindow::_UpdatePreferredApps(BMimeType* type)
{ {
@ -421,28 +685,91 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type)
if (applications.FindInt32("be:sub", &lastFullSupport) != B_OK) if (applications.FindInt32("be:sub", &lastFullSupport) != B_OK)
lastFullSupport = -1; lastFullSupport = -1;
BList subList;
BList superList;
const char* signature; const char* signature;
int32 i = 0; int32 i = 0;
while (applications.FindString("applications", i, &signature) == B_OK) { while (applications.FindString("applications", i, &signature) == B_OK) {
char name[B_FILE_NAME_LENGTH]; char name[B_FILE_NAME_LENGTH];
BMenuItem *item; BMenuItem *item;
BMessage* message = new BMessage(kMsgPreferredAppChosen);
message->AddString("signature", signature);
BMimeType applicationType(signature); BMimeType applicationType(signature);
if (applicationType.GetShortDescription(name) == B_OK) if (applicationType.GetShortDescription(name) == B_OK)
item = new BMenuItem(name, NULL); item = new BMenuItem(name, message);
else else
item = new BMenuItem(signature, NULL); item = new BMenuItem(signature, message);
// Add type separator if (i < lastFullSupport)
if (i == 0 || i == lastFullSupport) subList.AddItem(item);
menu->AddSeparatorItem(); else
superList.AddItem(item);
i++;
}
// sort lists
subList.SortItems(compare_menu_items);
superList.SortItems(compare_menu_items);
// add lists to the menu
if (subList.CountItems() != 0 || superList.CountItems() != 0)
menu->AddSeparatorItem();
for (int32 i = 0; i < subList.CountItems(); i++) {
menu->AddItem((BMenuItem*)subList.ItemAt(i));
}
// Add type separator
if (superList.CountItems() != 0 && subList.CountItems() != 0)
menu->AddSeparatorItem();
for (int32 i = 0; i < superList.CountItems(); i++) {
menu->AddItem((BMenuItem*)superList.ItemAt(i));
}
// make items unique and select current choice
bool lastItemSame = false;
const char* lastSignature = NULL;
BMenuItem* last = NULL;
for (int32 index = 0; index < menu->CountItems(); index++) {
BMenuItem* item = menu->ItemAt(index);
if (item == NULL)
continue;
if (item->Message() == NULL
|| item->Message()->FindString("signature", &signature) != B_OK)
continue;
if (!strcasecmp(signature, preferred)) if (!strcasecmp(signature, preferred))
item->SetMarked(true); item->SetMarked(true);
menu->AddItem(item); if (last == NULL || strcmp(last->Label(), item->Label())) {
i++; if (lastItemSame)
_AddSignature(last, lastSignature);
lastItemSame = false;
last = item;
lastSignature = signature;
continue;
}
lastItemSame = true;
_AddSignature(last, lastSignature);
last = item;
lastSignature = signature;
} }
if (lastItemSame)
_AddSignature(last, lastSignature);
} }
@ -466,6 +793,7 @@ FileTypesWindow::_SetType(BMimeType* type)
_UpdateExtensions(type); _UpdateExtensions(type);
_UpdatePreferredApps(type); _UpdatePreferredApps(type);
fIconView->SetTo(type); fIconView->SetTo(type);
fAttributeListView->SetTo(type);
fIconView->SetEnabled(enabled); fIconView->SetEnabled(enabled);
@ -490,6 +818,7 @@ FileTypesWindow::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case kMsgTypeSelected: case kMsgTypeSelected:
{
int32 index; int32 index;
if (message->FindInt32("index", &index) == B_OK) { if (message->FindInt32("index", &index) == B_OK) {
MimeTypeItem* item = (MimeTypeItem*)fTypeListView->ItemAt(index); MimeTypeItem* item = (MimeTypeItem*)fTypeListView->ItemAt(index);
@ -500,6 +829,27 @@ FileTypesWindow::MessageReceived(BMessage* message)
_SetType(NULL); _SetType(NULL);
} }
break; break;
}
case kMsgExtensionSelected:
{
int32 index;
if (message->FindInt32("index", &index) == B_OK) {
BStringItem* item = (BStringItem*)fExtensionListView->ItemAt(index);
fRemoveExtensionButton->SetEnabled(item != NULL);
}
break;
}
case kMsgAttributeSelected:
{
int32 index;
if (message->FindInt32("index", &index) == B_OK) {
AttributeItem* item = (AttributeItem*)fAttributeListView->ItemAt(index);
fRemoveAttributeButton->SetEnabled(item != NULL);
}
break;
}
default: default:
BWindow::MessageReceived(message); BWindow::MessageReceived(message);

View File

@ -15,6 +15,7 @@ class BMimeType;
class BOutlineListView; class BOutlineListView;
class BTextControl; class BTextControl;
class AttributeListView;
class IconView; class IconView;
@ -28,6 +29,7 @@ class FileTypesWindow : public BWindow {
private: private:
void _UpdateExtensions(BMimeType* type); void _UpdateExtensions(BMimeType* type);
void _AddSignature(BMenuItem* item, const char* signature);
void _UpdatePreferredApps(BMimeType* type); void _UpdatePreferredApps(BMimeType* type);
void _SetType(BMimeType* type); void _SetType(BMimeType* type);
@ -48,6 +50,7 @@ class FileTypesWindow : public BWindow {
BButton* fSelectButton; BButton* fSelectButton;
BButton* fSameAsButton; BButton* fSameAsButton;
AttributeListView* fAttributeListView;
BButton* fAddAttributeButton; BButton* fAddAttributeButton;
BButton* fRemoveAttributeButton; BButton* fRemoveAttributeButton;

View File

@ -203,5 +203,8 @@ MimeTypeListView::_CollectTypes()
last->AddSubtype(); last->AddSubtype();
last = item; last = item;
} }
if (lastItemSame)
last->AddSubtype();
} }