2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "ExtensionWindow.h"
9 #include "FileTypesWindow.h"
13 #include <ControlLook.h>
14 #include <LayoutBuilder.h>
16 #include <MenuField.h>
19 #include <PopUpMenu.h>
21 #include <TextControl.h>
26 #undef B_TRANSLATION_CONTEXT
27 #define B_TRANSLATION_CONTEXT "Extension Window"
30 const uint32 kMsgExtensionUpdated
= 'exup';
31 const uint32 kMsgAccept
= 'acpt';
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
);
44 // sort lower case characters first
49 //! newExtensionsList contains all the entries (char*) which are to be added.
51 merge_extensions(BMimeType
& type
, const BList
& newExtensionsList
,
52 const char* removeExtension
)
55 status_t status
= type
.GetFileExtensions(&extensions
);
59 // replace the entry, and remove any equivalent entries
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
72 mergedList
.RemoveItem(j
);
77 // The item will be added behind "originalCount", so we cannot
78 // remove it accidentally in the next iterations, it's is added
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
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
);
99 replace_extension(BMimeType
& type
, const char* newExtension
,
100 const char* oldExtension
)
103 list
.AddItem((void *)newExtension
);
105 return merge_extensions(type
, list
, oldExtension
);
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
),
119 fMimeType(type
.Type()),
120 fExtension(extension
)
122 fExtensionControl
= new BTextControl(B_TRANSLATE("Extension:"),
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);
163 ExtensionWindow::~ExtensionWindow()
169 ExtensionWindow::MessageReceived(BMessage
* message
)
171 switch (message
->what
) {
172 case kMsgExtensionUpdated
:
174 bool enabled
= fExtensionControl
->Text() != NULL
175 && fExtensionControl
->Text()[0] != '\0';
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
);
189 const char* newExtension
= fExtensionControl
->Text();
190 // omit the leading dot
191 if (newExtension
[0] == '.')
194 status_t status
= replace_extension(fMimeType
, newExtension
,
195 fExtension
.String());
197 error_alert(B_TRANSLATE("Could not change file extensions"),
200 PostMessage(B_QUIT_REQUESTED
);
205 BWindow::MessageReceived(message
);