* You can now change a MIME type's name as well as its preferred application.

* The menu field will now show the app's signature initially as well, if it's
  part of the item's label (wasn't picked up before, because BMenuItem::SetMarked()
  was called before the signature was added to the label).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16359 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-02-12 14:27:22 +00:00
parent d940ea1189
commit 3069c9573a
4 changed files with 211 additions and 24 deletions

View File

@ -28,9 +28,24 @@
const uint32 kMsgTypeSelected = 'typs'; const uint32 kMsgTypeSelected = 'typs';
const uint32 kMsgAddType = 'atyp';
const uint32 kMsgRemoveType = 'rtyp';
const uint32 kMsgExtensionSelected = 'exts'; const uint32 kMsgExtensionSelected = 'exts';
const uint32 kMsgExtensionInvoked = 'exti';
const uint32 kMsgAddExtension = 'aext';
const uint32 kMsgRemoveExtension = 'rext';
const uint32 kMsgAttributeSelected = 'atrs'; const uint32 kMsgAttributeSelected = 'atrs';
const uint32 kMsgAttributeInvoked = 'atri';
const uint32 kMsgAddAttribute = 'aatr';
const uint32 kMsgRemoveAttribute = 'ratr';
const uint32 kMsgPreferredAppChosen = 'papc'; const uint32 kMsgPreferredAppChosen = 'papc';
const uint32 kMsgSelectPreferredApp = 'slpa';
const uint32 kMsgSamePreferredAppAs = 'spaa';
const uint32 kMsgTypeEntered = 'type';
const struct type_map { const struct type_map {
@ -412,15 +427,16 @@ FileTypesWindow::FileTypesWindow(BRect frame)
topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(topView); AddChild(topView);
BButton* button = new BButton(rect, "add", "Add" B_UTF8_ELLIPSIS, NULL, BButton* button = new BButton(rect, "add", "Add" B_UTF8_ELLIPSIS,
B_FOLLOW_BOTTOM); new BMessage(kMsgAddType), B_FOLLOW_BOTTOM);
button->ResizeToPreferred(); button->ResizeToPreferred();
button->MoveTo(8.0f, topView->Bounds().bottom - 8.0f - button->Bounds().Height()); button->MoveTo(8.0f, topView->Bounds().bottom - 8.0f - button->Bounds().Height());
topView->AddChild(button); topView->AddChild(button);
rect = button->Frame(); rect = button->Frame();
rect.OffsetBy(rect.Width() + 8.0f, 0.0f); rect.OffsetBy(rect.Width() + 8.0f, 0.0f);
fRemoveTypeButton = new BButton(rect, "remove", "Remove", NULL, B_FOLLOW_BOTTOM); fRemoveTypeButton = new BButton(rect, "remove", "Remove",
new BMessage(kMsgRemoveType), B_FOLLOW_BOTTOM);
fRemoveTypeButton->ResizeToPreferred(); fRemoveTypeButton->ResizeToPreferred();
topView->AddChild(fRemoveTypeButton); topView->AddChild(fRemoveTypeButton);
@ -476,12 +492,12 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect.left = innerRect.right - button->StringWidth("Remove") - 16.0f; innerRect.left = innerRect.right - button->StringWidth("Remove") - 16.0f;
innerRect.bottom = innerRect.top + button->Bounds().Height(); innerRect.bottom = innerRect.top + button->Bounds().Height();
fAddExtensionButton = new BButton(innerRect, "add ext", "Add" B_UTF8_ELLIPSIS, fAddExtensionButton = new BButton(innerRect, "add ext", "Add" B_UTF8_ELLIPSIS,
NULL, B_FOLLOW_RIGHT); new BMessage(kMsgAddExtension), B_FOLLOW_RIGHT);
box->AddChild(fAddExtensionButton); box->AddChild(fAddExtensionButton);
innerRect.OffsetBy(0, innerRect.Height() + 4.0f); innerRect.OffsetBy(0, innerRect.Height() + 4.0f);
fRemoveExtensionButton = new BButton(innerRect, "remove ext", "Remove", NULL, fRemoveExtensionButton = new BButton(innerRect, "remove ext", "Remove",
B_FOLLOW_RIGHT); new BMessage(kMsgRemoveExtension), B_FOLLOW_RIGHT);
box->AddChild(fRemoveExtensionButton); box->AddChild(fRemoveExtensionButton);
innerRect.right = innerRect.left - 10.0f - B_V_SCROLL_BAR_WIDTH; innerRect.right = innerRect.left - 10.0f - B_V_SCROLL_BAR_WIDTH;
@ -492,6 +508,8 @@ FileTypesWindow::FileTypesWindow(BRect frame)
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)); fExtensionListView->SetSelectionMessage(new BMessage(kMsgExtensionSelected));
fExtensionListView->SetInvocationMessage(new BMessage(kMsgExtensionInvoked));
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);
@ -519,7 +537,7 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect.OffsetBy(0, fInternalNameControl->Bounds().Height() + 5.0f); innerRect.OffsetBy(0, fInternalNameControl->Bounds().Height() + 5.0f);
fTypeNameControl = new BTextControl(innerRect, "type", "Type Name:", "", fTypeNameControl = new BTextControl(innerRect, "type", "Type Name:", "",
NULL, B_FOLLOW_LEFT_RIGHT); new BMessage(kMsgTypeEntered), B_FOLLOW_LEFT_RIGHT);
fTypeNameControl->SetDivider(labelWidth); fTypeNameControl->SetDivider(labelWidth);
fTypeNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); fTypeNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
box->AddChild(fTypeNameControl); box->AddChild(fTypeNameControl);
@ -538,13 +556,13 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect.top += ceilf(fontHeight.ascent); innerRect.top += ceilf(fontHeight.ascent);
innerRect.left = innerRect.right - button->StringWidth("Same As" B_UTF8_ELLIPSIS) - 24.0f; innerRect.left = innerRect.right - button->StringWidth("Same As" B_UTF8_ELLIPSIS) - 24.0f;
innerRect.bottom = innerRect.top + button->Bounds().Height(); innerRect.bottom = innerRect.top + button->Bounds().Height();
fSameAsButton = new BButton(innerRect, "same as", "Same As" B_UTF8_ELLIPSIS, NULL, fSameAsButton = new BButton(innerRect, "same as", "Same As" B_UTF8_ELLIPSIS,
B_FOLLOW_RIGHT); new BMessage(kMsgSamePreferredAppAs), B_FOLLOW_RIGHT);
box->AddChild(fSameAsButton); box->AddChild(fSameAsButton);
innerRect.OffsetBy(-innerRect.Width() - 6.0f, 0.0f); innerRect.OffsetBy(-innerRect.Width() - 6.0f, 0.0f);
fSelectButton = new BButton(innerRect, "select", "Select" B_UTF8_ELLIPSIS, NULL, fSelectButton = new BButton(innerRect, "select", "Select" B_UTF8_ELLIPSIS,
B_FOLLOW_RIGHT); new BMessage(kMsgSelectPreferredApp), B_FOLLOW_RIGHT);
box->AddChild(fSelectButton); box->AddChild(fSelectButton);
menu = new BPopUpMenu("preferred"); menu = new BPopUpMenu("preferred");
@ -581,13 +599,13 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect.top += ceilf(fontHeight.ascent); innerRect.top += ceilf(fontHeight.ascent);
innerRect.left = innerRect.right - button->StringWidth("Remove") - 16.0f; innerRect.left = innerRect.right - button->StringWidth("Remove") - 16.0f;
innerRect.bottom = innerRect.top + button->Bounds().Height(); innerRect.bottom = innerRect.top + button->Bounds().Height();
fAddAttributeButton = new BButton(innerRect, "add attr", "Add" B_UTF8_ELLIPSIS, NULL, fAddAttributeButton = new BButton(innerRect, "add attr", "Add" B_UTF8_ELLIPSIS,
B_FOLLOW_RIGHT); new BMessage(kMsgAddAttribute), B_FOLLOW_RIGHT);
box->AddChild(fAddAttributeButton); box->AddChild(fAddAttributeButton);
innerRect.OffsetBy(0, innerRect.Height() + 4.0f); innerRect.OffsetBy(0, innerRect.Height() + 4.0f);
fRemoveAttributeButton = new BButton(innerRect, "remove attr", "Remove", fRemoveAttributeButton = new BButton(innerRect, "remove attr", "Remove",
NULL, B_FOLLOW_RIGHT); new BMessage(kMsgRemoveAttribute), B_FOLLOW_RIGHT);
box->AddChild(fRemoveAttributeButton); box->AddChild(fRemoveAttributeButton);
innerRect.right = innerRect.left - 10.0f - B_V_SCROLL_BAR_WIDTH; innerRect.right = innerRect.left - 10.0f - B_V_SCROLL_BAR_WIDTH;
@ -598,6 +616,8 @@ FileTypesWindow::FileTypesWindow(BRect frame)
fAttributeListView = new AttributeListView(innerRect, "listview attr", fAttributeListView = new AttributeListView(innerRect, "listview attr",
B_FOLLOW_ALL); B_FOLLOW_ALL);
fAttributeListView->SetSelectionMessage(new BMessage(kMsgAttributeSelected)); fAttributeListView->SetSelectionMessage(new BMessage(kMsgAttributeSelected));
fAttributeListView->SetInvocationMessage(new BMessage(kMsgAttributeInvoked));
scrollView = new BScrollView("scrollview attr", fAttributeListView, 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);
@ -738,6 +758,7 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type)
bool lastItemSame = false; bool lastItemSame = false;
const char* lastSignature = NULL; const char* lastSignature = NULL;
BMenuItem* last = NULL; BMenuItem* last = NULL;
BMenuItem* select = NULL;
for (int32 index = 0; index < menu->CountItems(); index++) { for (int32 index = 0; index < menu->CountItems(); index++) {
BMenuItem* item = menu->ItemAt(index); BMenuItem* item = menu->ItemAt(index);
@ -749,7 +770,7 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type)
continue; continue;
if (!strcasecmp(signature, preferred)) if (!strcasecmp(signature, preferred))
item->SetMarked(true); select = item;
if (last == NULL || strcmp(last->Label(), item->Label())) { if (last == NULL || strcmp(last->Label(), item->Label())) {
if (lastItemSame) if (lastItemSame)
@ -770,6 +791,12 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type)
if (lastItemSame) if (lastItemSame)
_AddSignature(last, lastSignature); _AddSignature(last, lastSignature);
if (select != NULL) {
// We don't select the item earlier, so that the menu field can
// pick up the signature as well as label.
select->SetMarked(true);
}
} }
@ -779,13 +806,18 @@ FileTypesWindow::_SetType(BMimeType* type)
bool enabled = type != NULL; bool enabled = type != NULL;
if (type != NULL) { if (type != NULL) {
if (fCurrentType == *type)
return;
fCurrentType.SetTo(type->Type());
fInternalNameControl->SetText(type->Type()); fInternalNameControl->SetText(type->Type());
char description[B_MIME_TYPE_LENGTH]; char description[B_MIME_TYPE_LENGTH];
if (type->GetShortDescription(description) != B_OK) if (type->GetShortDescription(description) != B_OK)
description[0] = '\0'; description[0] = '\0';
fTypeNameControl->SetText(description); fTypeNameControl->SetText(description);
} else { } else {
fCurrentType.Unset();
fInternalNameControl->SetText(NULL); fInternalNameControl->SetText(NULL);
fTypeNameControl->SetText(NULL); fTypeNameControl->SetText(NULL);
} }
@ -831,6 +863,8 @@ FileTypesWindow::MessageReceived(BMessage* message)
break; break;
} }
// File Extensions group
case kMsgExtensionSelected: case kMsgExtensionSelected:
{ {
int32 index; int32 index;
@ -841,6 +875,43 @@ FileTypesWindow::MessageReceived(BMessage* message)
break; break;
} }
case kMsgExtensionInvoked:
puts("ext");
break;
case kMsgAddExtension:
puts("add ext");
break;
case kMsgRemoveExtension:
puts("remove ext");
break;
// Description group
case kMsgTypeEntered:
{
fCurrentType.SetShortDescription(fTypeNameControl->Text());
MimeTypeItem* item = dynamic_cast<MimeTypeItem*>(
fTypeListView->ItemAt(fTypeListView->CurrentSelection()));
if (item != NULL)
fTypeListView->UpdateItem(item);
break;
}
// Preferred Application group
case kMsgPreferredAppChosen:
{
const char* signature;
if (message->FindString("signature", &signature) == B_OK)
fCurrentType.SetPreferredApp(signature);
break;
}
// Extra Attributes group
case kMsgAttributeSelected: case kMsgAttributeSelected:
{ {
int32 index; int32 index;
@ -851,6 +922,18 @@ FileTypesWindow::MessageReceived(BMessage* message)
break; break;
} }
case kMsgAttributeInvoked:
puts("attr");
break;
case kMsgAddAttribute:
puts("add attr");
break;
case kMsgRemoveAttribute:
puts("remove attr");
break;
default: default:
BWindow::MessageReceived(message); BWindow::MessageReceived(message);
} }

View File

@ -6,6 +6,7 @@
#define FILE_TYPES_WINDOW_H #define FILE_TYPES_WINDOW_H
#include <Mime.h>
#include <Window.h> #include <Window.h>
class BButton; class BButton;
@ -17,6 +18,7 @@ class BTextControl;
class AttributeListView; class AttributeListView;
class IconView; class IconView;
class MimeTypeListView;
class FileTypesWindow : public BWindow { class FileTypesWindow : public BWindow {
@ -34,7 +36,9 @@ class FileTypesWindow : public BWindow {
void _SetType(BMimeType* type); void _SetType(BMimeType* type);
private: private:
BOutlineListView* fTypeListView; BMimeType fCurrentType;
MimeTypeListView* fTypeListView;
BButton* fRemoveTypeButton; BButton* fRemoveTypeButton;
IconView* fIconView; IconView* fIconView;

View File

@ -77,6 +77,7 @@ MimeTypeItem::_SetTo(BMimeType& type)
if (IsSupertypeOnly()) { if (IsSupertypeOnly()) {
// this is a super type // this is a super type
fSupertype = type.Type(); fSupertype = type.Type();
fDescription = type.Type();
return; return;
} }
@ -85,18 +86,32 @@ MimeTypeItem::_SetTo(BMimeType& type)
fSubtype.SetTo(subType + 1); fSubtype.SetTo(subType + 1);
// omit the slash // omit the slash
Update();
}
void
MimeTypeItem::Update()
{
BMimeType type(fType.String());
char description[B_MIME_TYPE_LENGTH]; char description[B_MIME_TYPE_LENGTH];
if (type.GetShortDescription(description) == B_OK) if (type.GetShortDescription(description) == B_OK)
SetText(description); SetText(description);
else else
SetText(Subtype()); SetText(Subtype());
fDescription = Text();
} }
void void
MimeTypeItem::AddSubtype() MimeTypeItem::AddSubtype()
{ {
BString text = Text(); if (fSubtype == Text())
return;
BString text = Description();
text.Append(" ("); text.Append(" (");
text.Append(fSubtype); text.Append(fSubtype);
text.Append(")"); text.Append(")");
@ -127,6 +142,28 @@ MimeTypeItem::Compare(const BListItem* a, const BListItem* b)
} }
int
MimeTypeItem::CompareLabels(const BListItem* a, const BListItem* b)
{
const MimeTypeItem* typeA = dynamic_cast<const MimeTypeItem*>(a);
const MimeTypeItem* typeB = dynamic_cast<const MimeTypeItem*>(b);
if (typeA != NULL && typeB != NULL) {
int compare = strcasecmp(typeA->Description(), typeB->Description());
if (compare != 0)
return compare;
}
const BStringItem* stringA = dynamic_cast<const BStringItem*>(a);
const BStringItem* stringB = dynamic_cast<const BStringItem*>(b);
if (stringA != NULL && stringB != NULL)
return strcasecmp(stringA->Text(), stringB->Text());
return (int)(a - b);
}
// #pragma mark - // #pragma mark -
@ -178,21 +215,43 @@ MimeTypeListView::_CollectTypes()
} }
} }
FullListSortItems(&MimeTypeItem::Compare); _MakeTypesUnique();
}
// make double entries unique
void
MimeTypeListView::_MakeTypesUnique(MimeTypeItem* underItem)
{
SortItemsUnder(underItem, false, &MimeTypeItem::Compare);
bool lastItemSame = false; bool lastItemSame = false;
MimeTypeItem* last = NULL; MimeTypeItem* last = NULL;
for (index = 0; index < FullListCountItems(); index++) { int32 index = 0;
uint32 level = 0;
if (underItem != NULL) {
index = FullListIndexOf(underItem) + 1;
level = underItem->OutlineLevel() + 1;
}
for (; index < FullListCountItems(); index++) {
MimeTypeItem* item = dynamic_cast<MimeTypeItem*>(FullListItemAt(index)); MimeTypeItem* item = dynamic_cast<MimeTypeItem*>(FullListItemAt(index));
if (item == NULL) if (item == NULL)
continue; continue;
if (last == NULL || MimeTypeItem::Compare(last, item)) { if (item->OutlineLevel() < level) {
if (lastItemSame) // left sub-tree
break;
}
item->SetText(item->Description());
if (last == NULL || MimeTypeItem::CompareLabels(last, item)) {
if (lastItemSame) {
last->AddSubtype(); last->AddSubtype();
if (Window())
InvalidateItem(IndexOf(last));
}
lastItemSame = false; lastItemSame = false;
last = item; last = item;
@ -201,10 +260,43 @@ MimeTypeListView::_CollectTypes()
lastItemSame = true; lastItemSame = true;
last->AddSubtype(); last->AddSubtype();
if (Window())
InvalidateItem(IndexOf(last));
last = item; last = item;
} }
if (lastItemSame) if (lastItemSame) {
last->AddSubtype(); last->AddSubtype();
if (Window())
InvalidateItem(IndexOf(last));
}
}
void
MimeTypeListView::UpdateItem(MimeTypeItem* item)
{
int32 selected = -1;
if (IndexOf(item) == CurrentSelection())
selected = CurrentSelection();
item->Update();
_MakeTypesUnique(dynamic_cast<MimeTypeItem*>(Superitem(item)));
if (selected != -1) {
int32 index = IndexOf(item);
if (index != selected) {
Select(index);
ScrollToSelection();
}
}
if (Window())
InvalidateItem(IndexOf(item));
}
void
MimeTypeListView::RemoveItem(MimeTypeItem* item)
{
} }

View File

@ -24,11 +24,14 @@ class MimeTypeItem : public BStringItem {
const char* Type() const { return fType.String(); } const char* Type() const { return fType.String(); }
const char* Subtype() const { return fSubtype.String(); } const char* Subtype() const { return fSubtype.String(); }
const char* Supertype() const { return fSupertype.String(); } const char* Supertype() const { return fSupertype.String(); }
const char* Description() const { return fDescription.String(); }
bool IsSupertypeOnly() const { return fIsSupertype; } bool IsSupertypeOnly() const { return fIsSupertype; }
void Update();
void AddSubtype(); void AddSubtype();
static int Compare(const BListItem* a, const BListItem* b); static int Compare(const BListItem* a, const BListItem* b);
static int CompareLabels(const BListItem* a, const BListItem* b);
private: private:
void _SetTo(BMimeType& type); void _SetTo(BMimeType& type);
@ -36,6 +39,7 @@ class MimeTypeItem : public BStringItem {
BString fSupertype; BString fSupertype;
BString fSubtype; BString fSubtype;
BString fType; BString fType;
BString fDescription;
bool fIsSupertype; bool fIsSupertype;
}; };
@ -45,8 +49,12 @@ class MimeTypeListView : public BOutlineListView {
uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP); uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP);
virtual ~MimeTypeListView(); virtual ~MimeTypeListView();
void UpdateItem(MimeTypeItem* item);
void RemoveItem(MimeTypeItem* item);
private: private:
void _CollectTypes(); void _CollectTypes();
void _MakeTypesUnique(MimeTypeItem* underItem = NULL);
}; };
bool mimetype_is_application_signature(BMimeType& type); bool mimetype_is_application_signature(BMimeType& type);