1 /* 2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de. 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 <Catalog.h> 13 #include <ControlLook.h> 14 #include <LayoutBuilder.h> 15 #include <Locale.h> 16 #include <MenuBar.h> 17 #include <MenuField.h> 18 #include <MenuItem.h> 19 #include <Mime.h> 20 #include <PopUpMenu.h> 21 #include <SpaceLayoutItem.h> 22 #include <String.h> 23 #include <StringView.h> 24 #include <TextControl.h> 25 26 #include <string.h> 27 28 29 #undef B_TRANSLATION_CONTEXT 30 #define B_TRANSLATION_CONTEXT "New File Type Window" 31 32 33 const uint32 kMsgSupertypeChosen = 'sptc'; 34 const uint32 kMsgNewSupertypeChosen = 'nstc'; 35 36 const uint32 kMsgNameUpdated = 'nmup'; 37 38 const uint32 kMsgAddType = 'atyp'; 39 40 41 NewFileTypeWindow::NewFileTypeWindow(FileTypesWindow* target, 42 const char* currentType) 43 : 44 BWindow(BRect(100, 100, 350, 200), B_TRANSLATE("New file type"), 45 B_MODAL_WINDOW, B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE 46 | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS ), 47 fTarget(target) 48 { 49 fSupertypesMenu = new BPopUpMenu("supertypes"); 50 BMenuItem* item; 51 BMessage types; 52 if (BMimeType::GetInstalledSupertypes(&types) == B_OK) { 53 const char* type; 54 int32 i = 0; 55 while (types.FindString("super_types", i++, &type) == B_OK) { 56 fSupertypesMenu->AddItem(item = new BMenuItem(type, 57 new BMessage(kMsgSupertypeChosen))); 58 59 // select super type close to the current type 60 if (currentType != NULL) { 61 if (!strncmp(type, currentType, strlen(type))) 62 item->SetMarked(true); 63 } else if (i == 1) 64 item->SetMarked(true); 65 } 66 67 if (i > 1) 68 fSupertypesMenu->AddSeparatorItem(); 69 } 70 71 fSupertypesMenu->AddItem(new BMenuItem(B_TRANSLATE("Add new group"), 72 new BMessage(kMsgNewSupertypeChosen))); 73 BMenuField* typesMenuField = new BMenuField(NULL, fSupertypesMenu); 74 75 BStringView* typesMenuLabel = new BStringView(NULL, B_TRANSLATE("Group:")); 76 // Create a separate label view, otherwise things don't line up right 77 typesMenuLabel->SetAlignment(B_ALIGN_LEFT); 78 typesMenuLabel->SetExplicitAlignment( 79 BAlignment(B_ALIGN_LEFT, B_ALIGN_USE_FULL_HEIGHT)); 80 81 fNameControl = new BTextControl(B_TRANSLATE("Internal name:"), "", NULL); 82 fNameControl->SetModificationMessage(new BMessage(kMsgNameUpdated)); 83 84 // filter out invalid characters that can't be part of a MIME type name 85 BTextView* nameControlTextView = fNameControl->TextView(); 86 const char* disallowedCharacters = "/<>@,;:\"()[]?= "; 87 for (int32 i = 0; disallowedCharacters[i]; i++) { 88 nameControlTextView->DisallowChar(disallowedCharacters[i]); 89 } 90 91 fAddButton = new BButton(B_TRANSLATE("Add type"), 92 new BMessage(kMsgAddType)); 93 94 float padding = be_control_look->DefaultItemSpacing(); 95 96 BLayoutBuilder::Grid<>(this, padding, padding) 97 .SetInsets(padding) 98 .Add(typesMenuLabel, 0, 0) 99 .Add(typesMenuField, 1, 0, 2) 100 .Add(fNameControl->CreateLabelLayoutItem(), 0, 1) 101 .Add(fNameControl->CreateTextViewLayoutItem(), 1, 1, 2) 102 .Add(BSpaceLayoutItem::CreateGlue(), 0, 2) 103 .Add(new BButton(B_TRANSLATE("Cancel"), 104 new BMessage(B_QUIT_REQUESTED)), 1, 2) 105 .Add(fAddButton, 2, 2) 106 .SetColumnWeight(0, 3); 107 108 BAlignment fullSize = BAlignment(B_ALIGN_USE_FULL_WIDTH, 109 B_ALIGN_USE_FULL_HEIGHT); 110 typesMenuField->MenuBar()->SetExplicitAlignment(fullSize); 111 fNameControl->TextView()->SetExplicitAlignment(fullSize); 112 113 BLayoutItem* nameControlLabelItem = fNameControl->CreateLabelLayoutItem(); 114 nameControlLabelItem->SetExplicitMinSize(nameControlLabelItem->MinSize()); 115 // stops fNameControl's label from truncating under certain conditions 116 117 fAddButton->MakeDefault(true); 118 fNameControl->MakeFocus(true); 119 120 target->PlaceSubWindow(this); 121 } 122 123 124 NewFileTypeWindow::~NewFileTypeWindow() 125 { 126 } 127 128 129 void 130 NewFileTypeWindow::MessageReceived(BMessage* message) 131 { 132 switch (message->what) { 133 case kMsgSupertypeChosen: 134 fAddButton->SetLabel(B_TRANSLATE("Add type")); 135 fNameControl->SetLabel(B_TRANSLATE("Internal name:")); 136 fNameControl->MakeFocus(true); 137 InvalidateLayout(true); 138 break; 139 140 case kMsgNewSupertypeChosen: 141 fAddButton->SetLabel(B_TRANSLATE("Add group")); 142 fNameControl->SetLabel(B_TRANSLATE("Group name:")); 143 fNameControl->MakeFocus(true); 144 InvalidateLayout(true); 145 break; 146 147 case kMsgNameUpdated: 148 { 149 bool empty = fNameControl->Text() == NULL 150 || fNameControl->Text()[0] == '\0'; 151 152 if (fAddButton->IsEnabled() == empty) 153 fAddButton->SetEnabled(!empty); 154 break; 155 } 156 157 case kMsgAddType: 158 { 159 BMenuItem* item = fSupertypesMenu->FindMarked(); 160 if (item != NULL) { 161 BString type; 162 if (fSupertypesMenu->IndexOf(item) 163 != fSupertypesMenu->CountItems() - 1) { 164 // add normal type 165 type = item->Label(); 166 type.Append("/"); 167 } 168 169 type.Append(fNameControl->Text()); 170 171 BMimeType mimeType(type.String()); 172 if (mimeType.IsInstalled()) { 173 error_alert(B_TRANSLATE("This file type already exists")); 174 break; 175 } 176 177 status_t status = mimeType.Install(); 178 if (status != B_OK) 179 error_alert(B_TRANSLATE("Could not install file type"), 180 status); 181 else { 182 BMessage update(kMsgSelectNewType); 183 update.AddString("type", type.String()); 184 185 fTarget.SendMessage(&update); 186 } 187 } 188 PostMessage(B_QUIT_REQUESTED); 189 break; 190 } 191 192 default: 193 BWindow::MessageReceived(message); 194 break; 195 } 196 } 197 198 199 bool 200 NewFileTypeWindow::QuitRequested() 201 { 202 fTarget.SendMessage(kMsgNewTypeWindowClosed); 203 return true; 204 } 205 206 207