diff --git a/src/preferences/filetypes/FileTypes.cpp b/src/preferences/filetypes/FileTypes.cpp index 92ed50bdec..162869e58b 100644 --- a/src/preferences/filetypes/FileTypes.cpp +++ b/src/preferences/filetypes/FileTypes.cpp @@ -164,7 +164,7 @@ FileTypes::MessageReceived(BMessage *message) case kMsgOpenFilePanel: // the open file panel sends us a message when it's done - fFilePanel->Window()->SetTitle("Open File"); + fFilePanel->Window()->SetTitle("FileTypes: Open File"); fFilePanel->SetMessage(new BMessage(B_REFS_RECEIVED)); if (!fFilePanel->IsShowing()) @@ -172,7 +172,7 @@ FileTypes::MessageReceived(BMessage *message) break; case kMsgOpenSelectPanel: - fFilePanel->Window()->SetTitle("Select Preferred Application"); + fFilePanel->Window()->SetTitle("FileTypes: Select Preferred Application"); fFilePanel->SetMessage(new BMessage(kMsgPreferredAppOpened)); if (!fFilePanel->IsShowing()) @@ -184,7 +184,7 @@ FileTypes::MessageReceived(BMessage *message) break; case kMsgOpenSameAsPanel: - fFilePanel->Window()->SetTitle("Select Same Preferred Application As"); + fFilePanel->Window()->SetTitle("FileTypes: Select Same Preferred Application As"); fFilePanel->SetMessage(new BMessage(kMsgSamePreferredAppAsOpened)); if (!fFilePanel->IsShowing()) diff --git a/src/preferences/filetypes/FileTypesWindow.cpp b/src/preferences/filetypes/FileTypesWindow.cpp index 225ae51666..bf9895f235 100644 --- a/src/preferences/filetypes/FileTypesWindow.cpp +++ b/src/preferences/filetypes/FileTypesWindow.cpp @@ -7,8 +7,8 @@ #include "FileTypes.h" #include "FileTypesWindow.h" #include "MimeTypeListView.h" +#include "NewFileTypeWindow.h" -#include #include #include #include @@ -52,7 +52,6 @@ const uint32 kMsgSamePreferredAppAs = 'spaa'; const uint32 kMsgTypeEntered = 'type'; const uint32 kMsgDescriptionEntered = 'dsce'; - const struct type_map { const char* name; type_code type; @@ -113,7 +112,7 @@ 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 ~AttributeItem(); virtual void DrawItem(BView* owner, BRect itemRect, bool drawEverything = false); @@ -128,9 +127,6 @@ class AttributeItem : public BStringItem { bool fEditable; }; -static void error_alert(const char* message, status_t status = B_OK, - alert_type type = B_WARNING_ALERT); - // #pragma mark - @@ -187,7 +183,7 @@ name_for_type(BString& string, type_code type) } -static void +void error_alert(const char* message, status_t status, alert_type type) { char warning[512]; @@ -501,7 +497,10 @@ AttributeListView::Draw(BRect updateRect) FileTypesWindow::FileTypesWindow(BRect frame) : BWindow(frame, "FileTypes", B_TITLED_WINDOW, - B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) + B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), + fNewTypeWindow(NULL), + fExtensionWindow(NULL), + fAttributeWindow(NULL) { // add the menu @@ -1116,6 +1115,14 @@ FileTypesWindow::_SetType(BMimeType* type, int32 forceUpdate) } +void +FileTypesWindow::PlaceSubWindow(BWindow* window) +{ + window->MoveTo(Frame().left + (Frame().Width() - window->Frame().Width()) / 2.0f, + Frame().top + (Frame().Height() - window->Frame().Height()) / 2.0f); +} + + void FileTypesWindow::MessageReceived(BMessage* message) { @@ -1135,7 +1142,16 @@ FileTypesWindow::MessageReceived(BMessage* message) } case kMsgAddType: - puts("add type"); + { + if (fNewTypeWindow == NULL) { + fNewTypeWindow = new NewFileTypeWindow(this, fCurrentType.Type()); + fNewTypeWindow->Show(); + } else + fNewTypeWindow->Activate(); + break; + } + case kMsgNewTypeWindowClosed: + fNewTypeWindow = NULL; break; case kMsgRemoveType: @@ -1168,6 +1184,14 @@ FileTypesWindow::MessageReceived(BMessage* message) break; } + case kMsgSelectNewType: + { + const char* type; + if (message->FindString("type", &type) == B_OK) + fTypeListView->SelectNewType(type); + break; + } + // File Extensions group case kMsgExtensionSelected: diff --git a/src/preferences/filetypes/FileTypesWindow.h b/src/preferences/filetypes/FileTypesWindow.h index a4afd2836c..2748e19ae6 100644 --- a/src/preferences/filetypes/FileTypesWindow.h +++ b/src/preferences/filetypes/FileTypesWindow.h @@ -6,6 +6,7 @@ #define FILE_TYPES_WINDOW_H +#include #include #include @@ -29,6 +30,8 @@ class FileTypesWindow : public BWindow { virtual void MessageReceived(BMessage* message); virtual bool QuitRequested(); + void PlaceSubWindow(BWindow* window); + private: void _UpdateExtensions(BMimeType* type); void _AdoptPreferredApplication(BMessage* message, bool sameAs); @@ -62,9 +65,19 @@ class FileTypesWindow : public BWindow { BButton* fAddAttributeButton; BButton* fRemoveAttributeButton; + BWindow* fNewTypeWindow; + BWindow* fExtensionWindow; + BWindow* fAttributeWindow; }; static const uint32 kMsgPreferredAppOpened = 'paOp'; static const uint32 kMsgSamePreferredAppAsOpened = 'spaO'; +static const uint32 kMsgSelectNewType = 'slnt'; +static const uint32 kMsgNewTypeWindowClosed = 'ntwc'; + + +extern void error_alert(const char* message, status_t status = B_OK, + alert_type type = B_WARNING_ALERT); + #endif // FILE_TYPES_WINDOW_H diff --git a/src/preferences/filetypes/Jamfile b/src/preferences/filetypes/Jamfile index 0e38c67714..2a167588da 100644 --- a/src/preferences/filetypes/Jamfile +++ b/src/preferences/filetypes/Jamfile @@ -9,6 +9,7 @@ Preference FileTypes : FileTypes.cpp FileTypesWindow.cpp MimeTypeListView.cpp + NewFileTypeWindow.cpp : be tracker : FileTypes.rdef FileTypes.icons.rdef ; diff --git a/src/preferences/filetypes/MimeTypeListView.cpp b/src/preferences/filetypes/MimeTypeListView.cpp index c2f0733add..ac8b38b5e4 100644 --- a/src/preferences/filetypes/MimeTypeListView.cpp +++ b/src/preferences/filetypes/MimeTypeListView.cpp @@ -335,6 +335,11 @@ MimeTypeListView::MessageReceived(BMessage* message) AddItem(item); UpdateItem(item); + + if (!fSelectNewType.ICompare(type)) { + SelectItem(item); + fSelectNewType = ""; + } break; } case B_MIME_TYPE_DELETED: @@ -360,6 +365,57 @@ MimeTypeListView::MessageReceived(BMessage* message) } +/*! + \brief This method makes sure a new MIME type will be selected. + + If it's not in the list yet, it will be selected as soon as it's + added. +*/ +void +MimeTypeListView::SelectNewType(const char* type) +{ + if (SelectType(type)) + return; + + fSelectNewType = type; +} + + +bool +MimeTypeListView::SelectType(const char* type) +{ + MimeTypeItem* item = FindItem(type); + if (item == NULL) + return false; + + SelectItem(item); + return true; +} + + +void +MimeTypeListView::SelectItem(MimeTypeItem* item) +{ + if (item == NULL) { + Select(-1); + return; + } + + // Make sure the item is visible + + BListItem* superItem = item; + while ((superItem = Superitem(superItem)) != NULL) { + Expand(superItem); + } + + // Select it, and make it visible + + int32 index = IndexOf(item); + Select(index); + ScrollToSelection(); +} + + MimeTypeItem* MimeTypeListView::FindItem(const char* type) { @@ -370,7 +426,7 @@ MimeTypeListView::FindItem(const char* type) MimeTypeItem* item = dynamic_cast(FullListItemAt(i)); if (item == NULL) continue; - + if (!strcasecmp(item->Type(), type)) return item; } diff --git a/src/preferences/filetypes/MimeTypeListView.h b/src/preferences/filetypes/MimeTypeListView.h index ff2a7b90f9..fdb0cc4812 100644 --- a/src/preferences/filetypes/MimeTypeListView.h +++ b/src/preferences/filetypes/MimeTypeListView.h @@ -49,6 +49,10 @@ class MimeTypeListView : public BOutlineListView { uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP); virtual ~MimeTypeListView(); + void SelectNewType(const char* type); + bool SelectType(const char* type); + + void SelectItem(MimeTypeItem* item); MimeTypeItem* FindItem(const char* type); void UpdateItem(MimeTypeItem* item); @@ -62,6 +66,8 @@ class MimeTypeListView : public BOutlineListView { private: void _CollectTypes(); void _MakeTypesUnique(MimeTypeItem* underItem = NULL); + + BString fSelectNewType; }; bool mimetype_is_application_signature(BMimeType& type); diff --git a/src/preferences/filetypes/NewFileTypeWindow.cpp b/src/preferences/filetypes/NewFileTypeWindow.cpp new file mode 100644 index 0000000000..8b6c1c97c6 --- /dev/null +++ b/src/preferences/filetypes/NewFileTypeWindow.cpp @@ -0,0 +1,192 @@ +/* + * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "FileTypesWindow.h" +#include "NewFileTypeWindow.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + + +const uint32 kMsgSupertypeChosen = 'sptc'; +const uint32 kMsgNewSupertypeChosen = 'nstc'; + +const uint32 kMsgNameUpdated = 'nmup'; + +const uint32 kMsgAddType = 'atyp'; + + +NewFileTypeWindow::NewFileTypeWindow(FileTypesWindow* target, const char* currentType) + : BWindow(BRect(100, 100, 350, 200), "New File Type", B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE | B_ASYNCHRONOUS_CONTROLS), + fTarget(target) +{ + BRect rect = Bounds(); + BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW); + topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(topView); + + rect.InsetBy(8.0f, 8.0f); + fNameControl = new BTextControl(rect, "internal", "Internal Name:", "", + NULL, B_FOLLOW_LEFT_RIGHT); + + float labelWidth = fNameControl->StringWidth(fNameControl->Label()) + 2.0f; + fNameControl->SetModificationMessage(new BMessage(kMsgNameUpdated)); + fNameControl->SetDivider(labelWidth); + fNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); + + // filter out invalid characters that can't be part of a MIME type name + BTextView* textView = fNameControl->TextView(); + const char* disallowedCharacters = "/<>@,;:\"()[]?="; + for (int32 i = 0; disallowedCharacters[i]; i++) { + textView->DisallowChar(disallowedCharacters[i]); + } + + float width, height; + fNameControl->GetPreferredSize(&width, &height); + fNameControl->ResizeTo(rect.Width(), height); + fNameControl->MoveTo(8.0f, 12.0f + fNameControl->Bounds().Height()); + topView->AddChild(fNameControl); + + fSupertypesMenu = new BPopUpMenu("supertypes"); + BMenuItem* item; + BMessage types; + if (BMimeType::GetInstalledSupertypes(&types) == B_OK) { + const char* type; + int32 i = 0; + while (types.FindString("super_types", i++, &type) == B_OK) { + fSupertypesMenu->AddItem(item = new BMenuItem(type, + new BMessage(kMsgSupertypeChosen))); + + // select super type close to the current type + if (currentType != NULL) { + if (!strncmp(type, currentType, strlen(type))) + item->SetMarked(true); + } else if (i == 1) + item->SetMarked(true); + } + + if (i > 1) + fSupertypesMenu->AddSeparatorItem(); + } + fSupertypesMenu->AddItem(new BMenuItem("Add New Group", + new BMessage(kMsgNewSupertypeChosen))); + + rect.bottom = rect.top + fNameControl->Bounds().Height() + 2.0f; + BMenuField* menuField = new BMenuField(rect, "supertypes", + "Group:", fSupertypesMenu); + menuField->SetDivider(labelWidth); + menuField->SetAlignment(B_ALIGN_RIGHT); + menuField->GetPreferredSize(&width, &height); + menuField->ResizeTo(rect.Width(), height); + topView->AddChild(menuField); + + fAddButton = new BButton(rect, "add", "Add Type", new BMessage(kMsgAddType), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + fAddButton->ResizeToPreferred(); + fAddButton->MoveTo(Bounds().Width() - 8.0f - fAddButton->Bounds().Width(), + Bounds().Height() - 8.0f - fAddButton->Bounds().Height()); + fAddButton->SetEnabled(false); + topView->AddChild(fAddButton); + + BButton* button = new BButton(rect, "cancel", "Cancel", + new BMessage(B_QUIT_REQUESTED), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->MoveTo(fAddButton->Frame().left - 10.0f - button->Bounds().Width(), + fAddButton->Frame().top); + topView->AddChild(button); + + ResizeTo(labelWidth * 4.0f + 24.0f, fNameControl->Bounds().Height() * 3.0f + 34.0f); + SetSizeLimits(button->Bounds().Width() + fAddButton->Bounds().Width() + 26.0f, + 32767.0f, Frame().Height(), Frame().Height()); + + fAddButton->MakeDefault(true); + fNameControl->MakeFocus(true); + + target->PlaceSubWindow(this); +} + + +NewFileTypeWindow::~NewFileTypeWindow() +{ +} + +#include +void +NewFileTypeWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgSupertypeChosen: + fAddButton->SetLabel("Add Type"); + fNameControl->SetLabel("Internal Name:"); + fNameControl->MakeFocus(true); + break; + + case kMsgNewSupertypeChosen: + fAddButton->SetLabel("Add Group"); + fNameControl->SetLabel("Group Name:"); + fNameControl->MakeFocus(true); + break; + + case kMsgNameUpdated: + { + bool empty = fNameControl->Text() == NULL + || fNameControl->Text()[0] == '\0'; + + if (fAddButton->IsEnabled() == empty) + fAddButton->SetEnabled(!empty); + break; + } + + case kMsgAddType: + { + BMenuItem* item = fSupertypesMenu->FindMarked(); + if (item != NULL) { + BString type; + if (fSupertypesMenu->IndexOf(item) != fSupertypesMenu->CountItems() - 1) { + // add normal type + type = item->Label(); + type.Append("/"); + } + + type.Append(fNameControl->Text()); + + BMimeType mimeType(type.String()); + if (mimeType.IsInstalled()) { + error_alert("This file type already exists."); + break; + } + + status_t status = mimeType.Install(); + if (status != B_OK) + error_alert("Could not install file type", status); + else { + BMessage update(kMsgSelectNewType); + update.AddString("type", type.String()); + + fTarget.SendMessage(&update); + } + } + PostMessage(B_QUIT_REQUESTED); + break; + } + } +} + + +bool +NewFileTypeWindow::QuitRequested() +{ + fTarget.SendMessage(kMsgNewTypeWindowClosed); + return true; +} diff --git a/src/preferences/filetypes/NewFileTypeWindow.h b/src/preferences/filetypes/NewFileTypeWindow.h new file mode 100644 index 0000000000..c2384642ef --- /dev/null +++ b/src/preferences/filetypes/NewFileTypeWindow.h @@ -0,0 +1,32 @@ +/* + * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef NEW_FILE_TYPE_WINDOW_H +#define NEW_FILE_TYPE_WINDOW_H + + +#include +#include + +class BButton; +class BMenu; +class BTextControl; + + +class NewFileTypeWindow : public BWindow { + public: + NewFileTypeWindow(FileTypesWindow* target, const char* currentType); + virtual ~NewFileTypeWindow(); + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + + private: + BMessenger fTarget; + BMenu* fSupertypesMenu; + BTextControl* fNameControl; + BButton* fAddButton; +}; + +#endif // NEW_FILE_TYPE_WINDOW_H