RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / preferences / filetypes / PreferredAppMenu.cpp
blob4882821b234e892074bbc3e06007a60c48595c64
1 /*
2 * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "FileTypes.h"
8 #include "PreferredAppMenu.h"
10 #include <Alert.h>
11 #include <AppFileInfo.h>
12 #include <Catalog.h>
13 #include <Locale.h>
14 #include <Menu.h>
15 #include <MenuItem.h>
16 #include <Mime.h>
17 #include <NodeInfo.h>
18 #include <String.h>
20 #include <stdio.h>
21 #include <strings.h>
24 #undef B_TRANSLATION_CONTEXT
25 #define B_TRANSLATION_CONTEXT "Preferred App Menu"
28 static int
29 compare_menu_items(const void* _a, const void* _b)
31 BMenuItem* a = *(BMenuItem**)_a;
32 BMenuItem* b = *(BMenuItem**)_b;
34 return strcasecmp(a->Label(), b->Label());
38 static bool
39 is_application_in_message(BMessage& applications, const char* app)
41 const char* signature;
42 int32 i = 0;
43 while (applications.FindString("applications", i++, &signature) == B_OK) {
44 if (!strcasecmp(signature, app))
45 return true;
48 return false;
52 static void
53 add_signature(BMenuItem* item, const char* signature)
55 const char* subType = strchr(signature, '/');
56 if (subType == NULL)
57 return;
59 char label[B_MIME_TYPE_LENGTH];
60 snprintf(label, sizeof(label), "%s (%s)", item->Label(), subType + 1);
62 item->SetLabel(label);
66 static BMenuItem*
67 create_application_item(const char* signature, uint32 what)
69 char name[B_FILE_NAME_LENGTH];
71 BMessage* message = new BMessage(what);
72 message->AddString("signature", signature);
74 BMimeType applicationType(signature);
75 if (applicationType.GetShortDescription(name) == B_OK)
76 return new BMenuItem(name, message);
78 return new BMenuItem(signature, message);
82 // #pragma mark - Public functions
85 void
86 update_preferred_app_menu(BMenu* menu, BMimeType* type, uint32 what,
87 const char* preferredFrom)
89 // clear menu (but leave the first entry, ie. "None")
91 for (int32 i = menu->CountItems(); i-- > 1;) {
92 delete menu->RemoveItem(i);
95 // fill it again
97 menu->ItemAt(0)->SetMarked(true);
99 BMessage applications;
100 if (type == NULL || type->GetSupportingApps(&applications) != B_OK)
101 return;
103 char preferred[B_MIME_TYPE_LENGTH];
104 if (type->GetPreferredApp(preferred) != B_OK)
105 preferred[0] = '\0';
107 int32 lastFullSupport;
108 if (applications.FindInt32("be:sub", &lastFullSupport) != B_OK)
109 lastFullSupport = -1;
111 BList subList;
112 BList superList;
114 const char* signature;
115 int32 i = 0;
116 while (applications.FindString("applications", i, &signature) == B_OK) {
117 BMenuItem* item = create_application_item(signature, what);
119 if (i < lastFullSupport)
120 subList.AddItem(item);
121 else
122 superList.AddItem(item);
124 i++;
127 // sort lists
129 subList.SortItems(compare_menu_items);
130 superList.SortItems(compare_menu_items);
132 // add lists to the menu
134 if (subList.CountItems() != 0 || superList.CountItems() != 0)
135 menu->AddSeparatorItem();
137 for (int32 i = 0; i < subList.CountItems(); i++) {
138 menu->AddItem((BMenuItem*)subList.ItemAt(i));
141 // Add type separator
142 if (superList.CountItems() != 0 && subList.CountItems() != 0)
143 menu->AddSeparatorItem();
145 for (int32 i = 0; i < superList.CountItems(); i++) {
146 menu->AddItem((BMenuItem*)superList.ItemAt(i));
149 // make items unique and select current choice
151 bool lastItemSame = false;
152 const char* lastSignature = NULL;
153 BMenuItem* last = NULL;
154 BMenuItem* select = NULL;
156 for (int32 index = 0; index < menu->CountItems(); index++) {
157 BMenuItem* item = menu->ItemAt(index);
158 if (item == NULL)
159 continue;
161 if (item->Message() == NULL
162 || item->Message()->FindString("signature", &signature) != B_OK)
163 continue;
165 if ((preferredFrom == NULL && !strcasecmp(signature, preferred))
166 || (preferredFrom != NULL
167 && !strcasecmp(signature, preferredFrom))) {
168 select = item;
171 if (last == NULL || strcmp(last->Label(), item->Label())) {
172 if (lastItemSame)
173 add_signature(last, lastSignature);
175 lastItemSame = false;
176 last = item;
177 lastSignature = signature;
178 continue;
181 lastItemSame = true;
182 add_signature(last, lastSignature);
184 last = item;
185 lastSignature = signature;
188 if (lastItemSame)
189 add_signature(last, lastSignature);
191 if (select != NULL) {
192 // We don't select the item earlier, so that the menu field can
193 // pick up the signature as well as label.
194 select->SetMarked(true);
195 } else if ((preferredFrom == NULL && preferred[0])
196 || (preferredFrom != NULL && preferredFrom[0])) {
197 // The preferred application is not an application that support
198 // this file type!
199 BMenuItem* item = create_application_item(preferredFrom
200 ? preferredFrom : preferred, what);
202 menu->AddSeparatorItem();
203 menu->AddItem(item);
204 item->SetMarked(item);
209 status_t
210 retrieve_preferred_app(BMessage* message, bool sameAs, const char* forType,
211 BString& preferredApp)
213 entry_ref ref;
214 if (message == NULL || message->FindRef("refs", &ref) != B_OK)
215 return B_BAD_VALUE;
217 BFile file(&ref, B_READ_ONLY);
218 status_t status = file.InitCheck();
220 char preferred[B_MIME_TYPE_LENGTH];
222 if (status == B_OK) {
223 if (sameAs) {
224 // get preferred app from file
225 BNodeInfo nodeInfo(&file);
226 status = nodeInfo.InitCheck();
227 if (status == B_OK) {
228 if (nodeInfo.GetPreferredApp(preferred) != B_OK)
229 preferred[0] = '\0';
231 if (!preferred[0]) {
232 // get MIME type from file
233 char type[B_MIME_TYPE_LENGTH];
234 if (nodeInfo.GetType(type) == B_OK) {
235 BMimeType mimeType(type);
236 mimeType.GetPreferredApp(preferred);
240 } else {
241 // get application signature
242 BAppFileInfo appInfo(&file);
243 status = appInfo.InitCheck();
245 if (status == B_OK && appInfo.GetSignature(preferred) != B_OK)
246 preferred[0] = '\0';
250 if (status != B_OK) {
251 error_alert(B_TRANSLATE("File could not be opened"),
252 status, B_STOP_ALERT);
253 return status;
256 if (!preferred[0]) {
257 error_alert(sameAs
258 ? B_TRANSLATE("Could not retrieve preferred application of this "
259 "file")
260 : B_TRANSLATE("Could not retrieve application signature"));
261 return B_ERROR;
264 // Check if the application chosen supports this type
266 BMimeType mimeType(forType);
267 bool found = false;
269 BMessage applications;
270 if (mimeType.GetSupportingApps(&applications) == B_OK
271 && is_application_in_message(applications, preferred))
272 found = true;
274 applications.MakeEmpty();
276 if (!found && mimeType.GetWildcardApps(&applications) == B_OK
277 && is_application_in_message(applications, preferred))
278 found = true;
280 if (!found) {
281 // warn user
282 BMimeType appType(preferred);
283 char description[B_MIME_TYPE_LENGTH];
284 if (appType.GetShortDescription(description) != B_OK)
285 description[0] = '\0';
287 char warning[512];
288 snprintf(warning, sizeof(warning), B_TRANSLATE("The application "
289 "\"%s\" does not support this file type.\n"
290 "Are you sure you want to set it anyway?"),
291 description[0] ? description : preferred);
293 BAlert* alert = new BAlert(B_TRANSLATE("FileTypes request"), warning,
294 B_TRANSLATE("Set preferred application"), B_TRANSLATE("Cancel"),
295 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
296 alert->SetShortcut(1, B_ESCAPE);
297 if (alert->Go() == 1)
298 return B_ERROR;
301 preferredApp = preferred;
302 return B_OK;