diff --git a/src/preferences/filetypes/FileTypesWindow.cpp b/src/preferences/filetypes/FileTypesWindow.cpp index 4192628459..117fa5767b 100644 --- a/src/preferences/filetypes/FileTypesWindow.cpp +++ b/src/preferences/filetypes/FileTypesWindow.cpp @@ -28,9 +28,24 @@ const uint32 kMsgTypeSelected = 'typs'; +const uint32 kMsgAddType = 'atyp'; +const uint32 kMsgRemoveType = 'rtyp'; + const uint32 kMsgExtensionSelected = 'exts'; +const uint32 kMsgExtensionInvoked = 'exti'; +const uint32 kMsgAddExtension = 'aext'; +const uint32 kMsgRemoveExtension = 'rext'; + const uint32 kMsgAttributeSelected = 'atrs'; +const uint32 kMsgAttributeInvoked = 'atri'; +const uint32 kMsgAddAttribute = 'aatr'; +const uint32 kMsgRemoveAttribute = 'ratr'; + const uint32 kMsgPreferredAppChosen = 'papc'; +const uint32 kMsgSelectPreferredApp = 'slpa'; +const uint32 kMsgSamePreferredAppAs = 'spaa'; + +const uint32 kMsgTypeEntered = 'type'; const struct type_map { @@ -412,15 +427,16 @@ FileTypesWindow::FileTypesWindow(BRect frame) topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); AddChild(topView); - BButton* button = new BButton(rect, "add", "Add" B_UTF8_ELLIPSIS, NULL, - B_FOLLOW_BOTTOM); + BButton* button = new BButton(rect, "add", "Add" B_UTF8_ELLIPSIS, + new BMessage(kMsgAddType), B_FOLLOW_BOTTOM); button->ResizeToPreferred(); button->MoveTo(8.0f, topView->Bounds().bottom - 8.0f - button->Bounds().Height()); topView->AddChild(button); rect = button->Frame(); 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(); topView->AddChild(fRemoveTypeButton); @@ -476,12 +492,12 @@ FileTypesWindow::FileTypesWindow(BRect frame) innerRect.left = innerRect.right - button->StringWidth("Remove") - 16.0f; innerRect.bottom = innerRect.top + button->Bounds().Height(); fAddExtensionButton = new BButton(innerRect, "add ext", "Add" B_UTF8_ELLIPSIS, - NULL, B_FOLLOW_RIGHT); + new BMessage(kMsgAddExtension), B_FOLLOW_RIGHT); box->AddChild(fAddExtensionButton); innerRect.OffsetBy(0, innerRect.Height() + 4.0f); - fRemoveExtensionButton = new BButton(innerRect, "remove ext", "Remove", NULL, - B_FOLLOW_RIGHT); + fRemoveExtensionButton = new BButton(innerRect, "remove ext", "Remove", + new BMessage(kMsgRemoveExtension), B_FOLLOW_RIGHT); box->AddChild(fRemoveExtensionButton); 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", B_SINGLE_SELECTION_LIST, B_FOLLOW_LEFT_RIGHT); fExtensionListView->SetSelectionMessage(new BMessage(kMsgExtensionSelected)); + fExtensionListView->SetInvocationMessage(new BMessage(kMsgExtensionInvoked)); + scrollView = new BScrollView("scrollview ext", fExtensionListView, B_FOLLOW_LEFT_RIGHT, B_FRAME_EVENTS | B_WILL_DRAW, false, true); box->AddChild(scrollView); @@ -519,7 +537,7 @@ FileTypesWindow::FileTypesWindow(BRect frame) innerRect.OffsetBy(0, fInternalNameControl->Bounds().Height() + 5.0f); fTypeNameControl = new BTextControl(innerRect, "type", "Type Name:", "", - NULL, B_FOLLOW_LEFT_RIGHT); + new BMessage(kMsgTypeEntered), B_FOLLOW_LEFT_RIGHT); fTypeNameControl->SetDivider(labelWidth); fTypeNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); box->AddChild(fTypeNameControl); @@ -538,13 +556,13 @@ FileTypesWindow::FileTypesWindow(BRect frame) innerRect.top += ceilf(fontHeight.ascent); innerRect.left = innerRect.right - button->StringWidth("Same As" B_UTF8_ELLIPSIS) - 24.0f; innerRect.bottom = innerRect.top + button->Bounds().Height(); - fSameAsButton = new BButton(innerRect, "same as", "Same As" B_UTF8_ELLIPSIS, NULL, - B_FOLLOW_RIGHT); + fSameAsButton = new BButton(innerRect, "same as", "Same As" B_UTF8_ELLIPSIS, + new BMessage(kMsgSamePreferredAppAs), B_FOLLOW_RIGHT); box->AddChild(fSameAsButton); innerRect.OffsetBy(-innerRect.Width() - 6.0f, 0.0f); - fSelectButton = new BButton(innerRect, "select", "Select" B_UTF8_ELLIPSIS, NULL, - B_FOLLOW_RIGHT); + fSelectButton = new BButton(innerRect, "select", "Select" B_UTF8_ELLIPSIS, + new BMessage(kMsgSelectPreferredApp), B_FOLLOW_RIGHT); box->AddChild(fSelectButton); menu = new BPopUpMenu("preferred"); @@ -581,13 +599,13 @@ FileTypesWindow::FileTypesWindow(BRect frame) innerRect.top += ceilf(fontHeight.ascent); innerRect.left = innerRect.right - button->StringWidth("Remove") - 16.0f; innerRect.bottom = innerRect.top + button->Bounds().Height(); - fAddAttributeButton = new BButton(innerRect, "add attr", "Add" B_UTF8_ELLIPSIS, NULL, - B_FOLLOW_RIGHT); + fAddAttributeButton = new BButton(innerRect, "add attr", "Add" B_UTF8_ELLIPSIS, + new BMessage(kMsgAddAttribute), B_FOLLOW_RIGHT); box->AddChild(fAddAttributeButton); innerRect.OffsetBy(0, innerRect.Height() + 4.0f); fRemoveAttributeButton = new BButton(innerRect, "remove attr", "Remove", - NULL, B_FOLLOW_RIGHT); + new BMessage(kMsgRemoveAttribute), B_FOLLOW_RIGHT); box->AddChild(fRemoveAttributeButton); 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", B_FOLLOW_ALL); fAttributeListView->SetSelectionMessage(new BMessage(kMsgAttributeSelected)); + fAttributeListView->SetInvocationMessage(new BMessage(kMsgAttributeInvoked)); + scrollView = new BScrollView("scrollview attr", fAttributeListView, B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW, false, true); box->AddChild(scrollView); @@ -738,6 +758,7 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type) bool lastItemSame = false; const char* lastSignature = NULL; BMenuItem* last = NULL; + BMenuItem* select = NULL; for (int32 index = 0; index < menu->CountItems(); index++) { BMenuItem* item = menu->ItemAt(index); @@ -749,7 +770,7 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type) continue; if (!strcasecmp(signature, preferred)) - item->SetMarked(true); + select = item; if (last == NULL || strcmp(last->Label(), item->Label())) { if (lastItemSame) @@ -770,6 +791,12 @@ FileTypesWindow::_UpdatePreferredApps(BMimeType* type) if (lastItemSame) _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; if (type != NULL) { + if (fCurrentType == *type) + return; + + fCurrentType.SetTo(type->Type()); fInternalNameControl->SetText(type->Type()); - + char description[B_MIME_TYPE_LENGTH]; if (type->GetShortDescription(description) != B_OK) description[0] = '\0'; fTypeNameControl->SetText(description); } else { + fCurrentType.Unset(); fInternalNameControl->SetText(NULL); fTypeNameControl->SetText(NULL); } @@ -831,6 +863,8 @@ FileTypesWindow::MessageReceived(BMessage* message) break; } + // File Extensions group + case kMsgExtensionSelected: { int32 index; @@ -841,6 +875,43 @@ FileTypesWindow::MessageReceived(BMessage* message) 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( + 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: { int32 index; @@ -851,6 +922,18 @@ FileTypesWindow::MessageReceived(BMessage* message) break; } + case kMsgAttributeInvoked: + puts("attr"); + break; + + case kMsgAddAttribute: + puts("add attr"); + break; + + case kMsgRemoveAttribute: + puts("remove attr"); + break; + default: BWindow::MessageReceived(message); } diff --git a/src/preferences/filetypes/FileTypesWindow.h b/src/preferences/filetypes/FileTypesWindow.h index 5ff2d9de6b..248c735586 100644 --- a/src/preferences/filetypes/FileTypesWindow.h +++ b/src/preferences/filetypes/FileTypesWindow.h @@ -6,6 +6,7 @@ #define FILE_TYPES_WINDOW_H +#include #include class BButton; @@ -17,6 +18,7 @@ class BTextControl; class AttributeListView; class IconView; +class MimeTypeListView; class FileTypesWindow : public BWindow { @@ -34,7 +36,9 @@ class FileTypesWindow : public BWindow { void _SetType(BMimeType* type); private: - BOutlineListView* fTypeListView; + BMimeType fCurrentType; + + MimeTypeListView* fTypeListView; BButton* fRemoveTypeButton; IconView* fIconView; diff --git a/src/preferences/filetypes/MimeTypeListView.cpp b/src/preferences/filetypes/MimeTypeListView.cpp index 50876f0fda..222f98577b 100644 --- a/src/preferences/filetypes/MimeTypeListView.cpp +++ b/src/preferences/filetypes/MimeTypeListView.cpp @@ -77,6 +77,7 @@ MimeTypeItem::_SetTo(BMimeType& type) if (IsSupertypeOnly()) { // this is a super type fSupertype = type.Type(); + fDescription = type.Type(); return; } @@ -85,18 +86,32 @@ MimeTypeItem::_SetTo(BMimeType& type) fSubtype.SetTo(subType + 1); // omit the slash + Update(); +} + + +void +MimeTypeItem::Update() +{ + BMimeType type(fType.String()); + char description[B_MIME_TYPE_LENGTH]; if (type.GetShortDescription(description) == B_OK) SetText(description); else SetText(Subtype()); + + fDescription = Text(); } void MimeTypeItem::AddSubtype() { - BString text = Text(); + if (fSubtype == Text()) + return; + + BString text = Description(); text.Append(" ("); text.Append(fSubtype); 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(a); + const MimeTypeItem* typeB = dynamic_cast(b); + + if (typeA != NULL && typeB != NULL) { + int compare = strcasecmp(typeA->Description(), typeB->Description()); + if (compare != 0) + return compare; + } + + const BStringItem* stringA = dynamic_cast(a); + const BStringItem* stringB = dynamic_cast(b); + + if (stringA != NULL && stringB != NULL) + return strcasecmp(stringA->Text(), stringB->Text()); + + return (int)(a - b); +} + + // #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; 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(FullListItemAt(index)); if (item == NULL) continue; - if (last == NULL || MimeTypeItem::Compare(last, item)) { - if (lastItemSame) + if (item->OutlineLevel() < level) { + // left sub-tree + break; + } + + item->SetText(item->Description()); + + if (last == NULL || MimeTypeItem::CompareLabels(last, item)) { + if (lastItemSame) { last->AddSubtype(); + if (Window()) + InvalidateItem(IndexOf(last)); + } lastItemSame = false; last = item; @@ -201,10 +260,43 @@ MimeTypeListView::_CollectTypes() lastItemSame = true; last->AddSubtype(); + if (Window()) + InvalidateItem(IndexOf(last)); last = item; } - if (lastItemSame) + if (lastItemSame) { 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(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) +{ } diff --git a/src/preferences/filetypes/MimeTypeListView.h b/src/preferences/filetypes/MimeTypeListView.h index 418fb9db22..8af9a9166b 100644 --- a/src/preferences/filetypes/MimeTypeListView.h +++ b/src/preferences/filetypes/MimeTypeListView.h @@ -24,11 +24,14 @@ class MimeTypeItem : public BStringItem { const char* Type() const { return fType.String(); } const char* Subtype() const { return fSubtype.String(); } const char* Supertype() const { return fSupertype.String(); } + const char* Description() const { return fDescription.String(); } bool IsSupertypeOnly() const { return fIsSupertype; } + void Update(); void AddSubtype(); static int Compare(const BListItem* a, const BListItem* b); + static int CompareLabels(const BListItem* a, const BListItem* b); private: void _SetTo(BMimeType& type); @@ -36,6 +39,7 @@ class MimeTypeItem : public BStringItem { BString fSupertype; BString fSubtype; BString fType; + BString fDescription; bool fIsSupertype; }; @@ -45,8 +49,12 @@ class MimeTypeListView : public BOutlineListView { uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP); virtual ~MimeTypeListView(); + void UpdateItem(MimeTypeItem* item); + void RemoveItem(MimeTypeItem* item); + private: void _CollectTypes(); + void _MakeTypesUnique(MimeTypeItem* underItem = NULL); }; bool mimetype_is_application_signature(BMimeType& type);