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