1 /* 2 * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "FileTypes.h" 8 #include "FileTypesWindow.h" 9 #include "NewFileTypeWindow.h" 10 11 #include <Button.h> 12 #include <MenuField.h> 13 #include <MenuItem.h> 14 #include <Mime.h> 15 #include <PopUpMenu.h> 16 #include <String.h> 17 #include <TextControl.h> 18 19 #include <string.h> 20 21 22 const uint32 kMsgSupertypeChosen = 'sptc'; 23 const uint32 kMsgNewSupertypeChosen = 'nstc'; 24 25 const uint32 kMsgNameUpdated = 'nmup'; 26 27 const uint32 kMsgAddType = 'atyp'; 28 29 30 NewFileTypeWindow::NewFileTypeWindow(FileTypesWindow* target, const char* currentType) 31 : BWindow(BRect(100, 100, 350, 200), "New file type", B_TITLED_WINDOW, 32 B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE | B_ASYNCHRONOUS_CONTROLS), 33 fTarget(target) 34 { 35 BRect rect = Bounds(); 36 BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW); 37 topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 38 AddChild(topView); 39 40 float labelWidth = be_plain_font->StringWidth("Internal name:") + 2.0f; 41 42 rect.InsetBy(8.0f, 6.0f); 43 fSupertypesMenu = new BPopUpMenu("supertypes"); 44 BMenuItem* item; 45 BMessage types; 46 if (BMimeType::GetInstalledSupertypes(&types) == B_OK) { 47 const char* type; 48 int32 i = 0; 49 while (types.FindString("super_types", i++, &type) == B_OK) { 50 fSupertypesMenu->AddItem(item = new BMenuItem(type, 51 new BMessage(kMsgSupertypeChosen))); 52 53 // select super type close to the current type 54 if (currentType != NULL) { 55 if (!strncmp(type, currentType, strlen(type))) 56 item->SetMarked(true); 57 } else if (i == 1) 58 item->SetMarked(true); 59 } 60 61 if (i > 1) 62 fSupertypesMenu->AddSeparatorItem(); 63 } 64 fSupertypesMenu->AddItem(new BMenuItem("Add new group", 65 new BMessage(kMsgNewSupertypeChosen))); 66 67 BMenuField* menuField = new BMenuField(rect, "supertypes", 68 "Group:", fSupertypesMenu); 69 menuField->SetDivider(labelWidth); 70 menuField->SetAlignment(B_ALIGN_RIGHT); 71 float width, height; 72 menuField->GetPreferredSize(&width, &height); 73 menuField->ResizeTo(rect.Width(), height); 74 topView->AddChild(menuField); 75 76 fNameControl = new BTextControl(rect, "internal", "Internal name:", "", 77 NULL, B_FOLLOW_LEFT_RIGHT); 78 fNameControl->SetModificationMessage(new BMessage(kMsgNameUpdated)); 79 fNameControl->SetDivider(labelWidth); 80 fNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); 81 82 // filter out invalid characters that can't be part of a MIME type name 83 BTextView* textView = fNameControl->TextView(); 84 const char* disallowedCharacters = "/<>@,;:\"()[]?="; 85 for (int32 i = 0; disallowedCharacters[i]; i++) { 86 textView->DisallowChar(disallowedCharacters[i]); 87 } 88 89 fNameControl->GetPreferredSize(&width, &height); 90 fNameControl->ResizeTo(rect.Width(), height); 91 fNameControl->MoveTo(8.0f, 12.0f + menuField->Bounds().Height()); 92 topView->AddChild(fNameControl); 93 94 fAddButton = new BButton(rect, "add", "Add type", new BMessage(kMsgAddType), 95 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 96 fAddButton->ResizeToPreferred(); 97 fAddButton->MoveTo(Bounds().Width() - 8.0f - fAddButton->Bounds().Width(), 98 Bounds().Height() - 8.0f - fAddButton->Bounds().Height()); 99 fAddButton->SetEnabled(false); 100 topView->AddChild(fAddButton); 101 102 BButton* button = new BButton(rect, "cancel", "Cancel", 103 new BMessage(B_QUIT_REQUESTED), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 104 button->ResizeToPreferred(); 105 button->MoveTo(fAddButton->Frame().left - 10.0f - button->Bounds().Width(), 106 fAddButton->Frame().top); 107 topView->AddChild(button); 108 109 ResizeTo(labelWidth * 4.0f + 24.0f, fNameControl->Bounds().Height() 110 + menuField->Bounds().Height() + fAddButton->Bounds().Height() + 30.0f); 111 SetSizeLimits(button->Bounds().Width() + fAddButton->Bounds().Width() + 26.0f, 112 32767.0f, Frame().Height(), Frame().Height()); 113 114 fAddButton->MakeDefault(true); 115 fNameControl->MakeFocus(true); 116 117 target->PlaceSubWindow(this); 118 } 119 120 121 NewFileTypeWindow::~NewFileTypeWindow() 122 { 123 } 124 125 126 void 127 NewFileTypeWindow::MessageReceived(BMessage* message) 128 { 129 switch (message->what) { 130 case kMsgSupertypeChosen: 131 fAddButton->SetLabel("Add type"); 132 fNameControl->SetLabel("Internal name:"); 133 fNameControl->MakeFocus(true); 134 break; 135 136 case kMsgNewSupertypeChosen: 137 fAddButton->SetLabel("Add group"); 138 fNameControl->SetLabel("Group name:"); 139 fNameControl->MakeFocus(true); 140 break; 141 142 case kMsgNameUpdated: 143 { 144 bool empty = fNameControl->Text() == NULL 145 || fNameControl->Text()[0] == '\0'; 146 147 if (fAddButton->IsEnabled() == empty) 148 fAddButton->SetEnabled(!empty); 149 break; 150 } 151 152 case kMsgAddType: 153 { 154 BMenuItem* item = fSupertypesMenu->FindMarked(); 155 if (item != NULL) { 156 BString type; 157 if (fSupertypesMenu->IndexOf(item) != fSupertypesMenu->CountItems() - 1) { 158 // add normal type 159 type = item->Label(); 160 type.Append("/"); 161 } 162 163 type.Append(fNameControl->Text()); 164 165 BMimeType mimeType(type.String()); 166 if (mimeType.IsInstalled()) { 167 error_alert("This file type already exists."); 168 break; 169 } 170 171 status_t status = mimeType.Install(); 172 if (status != B_OK) 173 error_alert("Could not install file type", status); 174 else { 175 BMessage update(kMsgSelectNewType); 176 update.AddString("type", type.String()); 177 178 fTarget.SendMessage(&update); 179 } 180 } 181 PostMessage(B_QUIT_REQUESTED); 182 break; 183 } 184 185 default: 186 BWindow::MessageReceived(message); 187 break; 188 } 189 } 190 191 192 bool 193 NewFileTypeWindow::QuitRequested() 194 { 195 fTarget.SendMessage(kMsgNewTypeWindowClosed); 196 return true; 197 } 198