fat: Greatly simplify and clean up dosfs_get_file_map().
[haiku.git] / src / preferences / filetypes / ExtensionWindow.cpp
blob0abd8e7d501d295f7dead8d4e0f8220ca8b7c0eb
1 /*
2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ExtensionWindow.h"
8 #include "FileTypes.h"
9 #include "FileTypesWindow.h"
11 #include <Button.h>
12 #include <Catalog.h>
13 #include <ControlLook.h>
14 #include <LayoutBuilder.h>
15 #include <Locale.h>
16 #include <MenuField.h>
17 #include <MenuItem.h>
18 #include <Mime.h>
19 #include <PopUpMenu.h>
20 #include <String.h>
21 #include <TextControl.h>
23 #include <strings.h>
26 #undef B_TRANSLATION_CONTEXT
27 #define B_TRANSLATION_CONTEXT "Extension Window"
30 const uint32 kMsgExtensionUpdated = 'exup';
31 const uint32 kMsgAccept = 'acpt';
34 static int
35 compare_extensions(const void* _a, const void* _b)
37 const char* a = *(const char **)_a;
38 const char* b = *(const char **)_b;
40 int compare = strcasecmp(a, b);
41 if (compare != 0)
42 return compare;
44 // sort lower case characters first
45 return -strcmp(a, b);
49 //! newExtensionsList contains all the entries (char*) which are to be added.
50 status_t
51 merge_extensions(BMimeType& type, const BList& newExtensionsList,
52 const char* removeExtension)
54 BMessage extensions;
55 status_t status = type.GetFileExtensions(&extensions);
56 if (status < B_OK)
57 return status;
59 // replace the entry, and remove any equivalent entries
60 BList mergedList;
61 mergedList.AddList(&newExtensionsList);
62 int32 originalCount = mergedList.CountItems();
64 const char* extension;
65 for (int32 i = 0; extensions.FindString("extensions", i,
66 &extension) == B_OK; i++) {
68 for (int32 j = originalCount; j-- > 0;) {
69 if (!strcmp((const char*)mergedList.ItemAt(j), extension)) {
70 // Do not add this old item again, since it's already
71 // there.
72 mergedList.RemoveItem(j);
73 originalCount--;
77 // The item will be added behind "originalCount", so we cannot
78 // remove it accidentally in the next iterations, it's is added
79 // for good.
80 if (removeExtension == NULL || strcmp(removeExtension, extension))
81 mergedList.AddItem((void *)extension);
84 mergedList.SortItems(compare_extensions);
86 // Copy them to a new message (their memory is still part of the
87 // original BMessage)
88 BMessage newExtensions;
89 for (int32 i = 0; i < mergedList.CountItems(); i++) {
90 newExtensions.AddString("extensions",
91 (const char*)mergedList.ItemAt(i));
94 return type.SetFileExtensions(&newExtensions);
98 status_t
99 replace_extension(BMimeType& type, const char* newExtension,
100 const char* oldExtension)
102 BList list;
103 list.AddItem((void *)newExtension);
105 return merge_extensions(type, list, oldExtension);
109 // #pragma mark -
112 ExtensionWindow::ExtensionWindow(FileTypesWindow* target, BMimeType& type,
113 const char* extension)
114 : BWindow(BRect(100, 100, 350, 200), B_TRANSLATE("Extension"),
115 B_MODAL_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL,
116 B_NOT_ZOOMABLE | B_NOT_RESIZABLE
117 | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
118 fTarget(target),
119 fMimeType(type.Type()),
120 fExtension(extension)
122 fExtensionControl = new BTextControl(B_TRANSLATE("Extension:"),
123 extension, NULL);
124 fExtensionControl->SetModificationMessage(
125 new BMessage(kMsgExtensionUpdated));
126 fExtensionControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_LEFT);
128 // filter out invalid characters that can't be part of an extension
129 BTextView* textView = fExtensionControl->TextView();
130 const char* disallowedCharacters = "/:";
131 for (int32 i = 0; disallowedCharacters[i]; i++) {
132 textView->DisallowChar(disallowedCharacters[i]);
135 fAcceptButton = new BButton(extension
136 ? B_TRANSLATE("Done") : B_TRANSLATE("Add"),
137 new BMessage(kMsgAccept));
138 fAcceptButton->SetEnabled(false);
140 BButton* cancelButton = new BButton(B_TRANSLATE("Cancel"),
141 new BMessage(B_QUIT_REQUESTED));
143 float padding = be_control_look->DefaultItemSpacing();
144 BLayoutBuilder::Grid<>(this, padding, padding)
145 .SetInsets(padding, padding, padding, padding)
146 .AddTextControl(fExtensionControl, 0, 0, B_ALIGN_HORIZONTAL_UNSET, 1, 2)
147 .Add(BSpaceLayoutItem::CreateGlue(), 0, 1)
148 .Add(cancelButton, 1, 1)
149 .Add(fAcceptButton, 2, 1);
151 // omit the leading dot
152 if (fExtension.ByteAt(0) == '.')
153 fExtension.Remove(0, 1);
155 fAcceptButton->MakeDefault(true);
156 fExtensionControl->MakeFocus(true);
158 target->PlaceSubWindow(this);
159 AddToSubset(target);
163 ExtensionWindow::~ExtensionWindow()
168 void
169 ExtensionWindow::MessageReceived(BMessage* message)
171 switch (message->what) {
172 case kMsgExtensionUpdated:
174 bool enabled = fExtensionControl->Text() != NULL
175 && fExtensionControl->Text()[0] != '\0';
176 if (enabled) {
177 // There is some text, but we only accept it, if it
178 // changed the previous extension
179 enabled = strcmp(fExtensionControl->Text(), fExtension.String());
182 if (fAcceptButton->IsEnabled() != enabled)
183 fAcceptButton->SetEnabled(enabled);
184 break;
187 case kMsgAccept:
189 const char* newExtension = fExtensionControl->Text();
190 // omit the leading dot
191 if (newExtension[0] == '.')
192 newExtension++;
194 status_t status = replace_extension(fMimeType, newExtension,
195 fExtension.String());
196 if (status != B_OK)
197 error_alert(B_TRANSLATE("Could not change file extensions"),
198 status);
200 PostMessage(B_QUIT_REQUESTED);
201 break;
204 default:
205 BWindow::MessageReceived(message);
206 break;