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 "ExtensionWindow.h" 8 #include "FileTypes.h" 9 #include "FileTypesWindow.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 kMsgExtensionUpdated = 'exup'; 23 const uint32 kMsgAccept = 'acpt'; 24 25 26 static int 27 compare_extensions(const void* _a, const void* _b) 28 { 29 const char* a = *(const char **)_a; 30 const char* b = *(const char **)_b; 31 32 int compare = strcasecmp(a, b); 33 if (compare != 0) 34 return compare; 35 36 // sort lower case characters first 37 return -strcmp(a, b); 38 } 39 40 41 // #pragma mark - 42 43 44 ExtensionWindow::ExtensionWindow(FileTypesWindow* target, BMimeType& type, 45 const char* extension) 46 : BWindow(BRect(100, 100, 350, 200), "Extension", B_MODAL_WINDOW_LOOK, 47 B_MODAL_SUBSET_WINDOW_FEEL, B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE 48 | B_ASYNCHRONOUS_CONTROLS), 49 fTarget(target), 50 fMimeType(type.Type()), 51 fExtension(extension) 52 { 53 BRect rect = Bounds(); 54 BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW); 55 topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 56 AddChild(topView); 57 58 rect.InsetBy(8.0f, 8.0f); 59 fExtensionControl = new BTextControl(rect, "extension", "Extension:", extension, 60 NULL, B_FOLLOW_LEFT_RIGHT); 61 62 float labelWidth = fExtensionControl->StringWidth(fExtensionControl->Label()) + 2.0f; 63 fExtensionControl->SetModificationMessage(new BMessage(kMsgExtensionUpdated)); 64 fExtensionControl->SetDivider(labelWidth); 65 fExtensionControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); 66 67 // filter out invalid characters that can't be part of an extension 68 BTextView* textView = fExtensionControl->TextView(); 69 const char* disallowedCharacters = "/:"; 70 for (int32 i = 0; disallowedCharacters[i]; i++) { 71 textView->DisallowChar(disallowedCharacters[i]); 72 } 73 74 float width, height; 75 fExtensionControl->GetPreferredSize(&width, &height); 76 fExtensionControl->ResizeTo(rect.Width(), height); 77 topView->AddChild(fExtensionControl); 78 79 fAcceptButton = new BButton(rect, "add", extension ? "Done" : "Add", 80 new BMessage(kMsgAccept), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 81 fAcceptButton->ResizeToPreferred(); 82 fAcceptButton->MoveTo(Bounds().Width() - 8.0f - fAcceptButton->Bounds().Width(), 83 Bounds().Height() - 8.0f - fAcceptButton->Bounds().Height()); 84 fAcceptButton->SetEnabled(false); 85 topView->AddChild(fAcceptButton); 86 87 BButton* button = new BButton(rect, "cancel", "Cancel", 88 new BMessage(B_QUIT_REQUESTED), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 89 button->ResizeToPreferred(); 90 button->MoveTo(fAcceptButton->Frame().left - 10.0f - button->Bounds().Width(), 91 fAcceptButton->Frame().top); 92 topView->AddChild(button); 93 94 ResizeTo(labelWidth * 4.0f + 24.0f, fExtensionControl->Bounds().Height() 95 + fAcceptButton->Bounds().Height() + 28.0f); 96 SetSizeLimits(button->Bounds().Width() + fAcceptButton->Bounds().Width() + 26.0f, 97 32767.0f, Frame().Height(), Frame().Height()); 98 99 // omit the leading dot 100 if (fExtension.ByteAt(0) == '.') 101 fExtension.Remove(0, 1); 102 103 fAcceptButton->MakeDefault(true); 104 fExtensionControl->MakeFocus(true); 105 106 target->PlaceSubWindow(this); 107 AddToSubset(target); 108 } 109 110 111 ExtensionWindow::~ExtensionWindow() 112 { 113 } 114 115 116 void 117 ExtensionWindow::MessageReceived(BMessage* message) 118 { 119 switch (message->what) { 120 case kMsgExtensionUpdated: 121 { 122 bool enabled = fExtensionControl->Text() != NULL 123 && fExtensionControl->Text()[0] != '\0'; 124 if (enabled) { 125 // There is some text, but we only accept it, if it 126 // changed the previous extension 127 enabled = strcmp(fExtensionControl->Text(), fExtension.String()); 128 } 129 130 if (fAcceptButton->IsEnabled() != enabled) 131 fAcceptButton->SetEnabled(enabled); 132 break; 133 } 134 135 case kMsgAccept: 136 { 137 const char* newExtension = fExtensionControl->Text(); 138 // omit the leading dot 139 if (newExtension[0] == '.') 140 newExtension++; 141 142 BMessage extensions; 143 status_t status = fMimeType.GetFileExtensions(&extensions); 144 if (status == B_OK) { 145 // replace the entry, and remove any equivalent entries 146 BList list; 147 list.AddItem((void *)newExtension); 148 149 const char* extension; 150 for (int32 i = 0; extensions.FindString("extensions", i, 151 &extension) == B_OK; i++) { 152 if (!strcmp(fExtension.String(), extension) 153 || !strcmp(newExtension, extension)) { 154 // remove this item 155 continue; 156 } 157 158 list.AddItem((void *)extension); 159 } 160 161 list.SortItems(compare_extensions); 162 163 // Copy them to a new message (their memory is still part of the 164 // original BMessage) 165 BMessage newExtensions; 166 for (int32 i = 0; i < list.CountItems(); i++) { 167 newExtensions.AddString("extensions", (const char*)list.ItemAt(i)); 168 } 169 170 status = fMimeType.SetFileExtensions(&newExtensions); 171 } 172 173 if (status != B_OK) 174 error_alert("Could not change file extensions", status); 175 176 PostMessage(B_QUIT_REQUESTED); 177 break; 178 } 179 180 default: 181 BWindow::MessageReceived(message); 182 break; 183 } 184 } 185 186