libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / preferences / filetypes / ApplicationTypesWindow.cpp
blob0afb8632f13dff2fc7bb0fb43ee151d4fcb30e35
1 /*
2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ApplicationTypesWindow.h"
8 #include "FileTypes.h"
9 #include "FileTypesWindow.h"
10 #include "MimeTypeListView.h"
11 #include "StringView.h"
13 #include <AppFileInfo.h>
14 #include <Application.h>
15 #include <Bitmap.h>
16 #include <Box.h>
17 #include <Button.h>
18 #include <Catalog.h>
19 #include <ControlLook.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <MenuField.h>
23 #include <MenuItem.h>
24 #include <MessageFormat.h>
25 #include <Mime.h>
26 #include <NodeInfo.h>
27 #include <Path.h>
28 #include <PopUpMenu.h>
29 #include <Query.h>
30 #include <Roster.h>
31 #include <Screen.h>
32 #include <ScrollView.h>
33 #include <StatusBar.h>
34 #include <StringView.h>
35 #include <TextView.h>
36 #include <Volume.h>
37 #include <VolumeRoster.h>
39 #include <stdio.h>
40 #include <strings.h>
43 // TODO: think about adopting Tracker's info window style here (pressable path)
46 #undef B_TRANSLATION_CONTEXT
47 #define B_TRANSLATION_CONTEXT "Application Types Window"
50 class ProgressWindow : public BWindow {
51 public:
52 ProgressWindow(const char* message, int32 max,
53 volatile bool* signalQuit);
54 virtual ~ProgressWindow();
56 virtual void MessageReceived(BMessage* message);
58 private:
59 BStatusBar* fStatusBar;
60 BButton* fAbortButton;
61 volatile bool* fQuitListener;
64 const uint32 kMsgTypeSelected = 'typs';
65 const uint32 kMsgTypeInvoked = 'typi';
66 const uint32 kMsgRemoveUninstalled = 'runs';
67 const uint32 kMsgEdit = 'edit';
70 const char*
71 variety_to_text(uint32 variety)
73 switch (variety) {
74 case B_DEVELOPMENT_VERSION:
75 return B_TRANSLATE("Development");
76 case B_ALPHA_VERSION:
77 return B_TRANSLATE("Alpha");
78 case B_BETA_VERSION:
79 return B_TRANSLATE("Beta");
80 case B_GAMMA_VERSION:
81 return B_TRANSLATE("Gamma");
82 case B_GOLDEN_MASTER_VERSION:
83 return B_TRANSLATE("Golden master");
84 case B_FINAL_VERSION:
85 return B_TRANSLATE("Final");
88 return "-";
92 // #pragma mark -
95 ProgressWindow::ProgressWindow(const char* message,
96 int32 max, volatile bool* signalQuit)
98 BWindow(BRect(0, 0, 300, 200), B_TRANSLATE("Progress"), B_MODAL_WINDOW_LOOK,
99 B_MODAL_SUBSET_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS |
100 B_NOT_V_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS),
101 fQuitListener(signalQuit)
103 char count[100];
104 snprintf(count, sizeof(count), "/%" B_PRId32, max);
106 fStatusBar = new BStatusBar("status", message, count);
107 fStatusBar->SetMaxValue(max);
108 fAbortButton = new BButton("abort", B_TRANSLATE("Abort"),
109 new BMessage(B_CANCEL));
111 float padding = be_control_look->DefaultItemSpacing();
112 BLayoutBuilder::Group<>(this, B_VERTICAL, padding)
113 .SetInsets(padding, padding, padding, padding)
114 .Add(fStatusBar)
115 .Add(fAbortButton);
117 // center on screen
118 BScreen screen(this);
119 MoveTo(screen.Frame().left + (screen.Frame().Width()
120 - Bounds().Width()) / 2.0f,
121 screen.Frame().top + (screen.Frame().Height()
122 - Bounds().Height()) / 2.0f);
126 ProgressWindow::~ProgressWindow()
131 void
132 ProgressWindow::MessageReceived(BMessage* message)
134 switch (message->what) {
135 case B_UPDATE_STATUS_BAR:
136 char count[100];
137 snprintf(count, sizeof(count), "%" B_PRId32,
138 (int32)fStatusBar->CurrentValue() + 1);
140 fStatusBar->Update(1, NULL, count);
141 break;
143 case B_CANCEL:
144 fAbortButton->SetEnabled(false);
145 if (fQuitListener != NULL)
146 *fQuitListener = true;
147 break;
149 default:
150 BWindow::MessageReceived(message);
151 break;
156 // #pragma mark -
159 ApplicationTypesWindow::ApplicationTypesWindow(const BMessage& settings)
160 : BWindow(_Frame(settings), B_TRANSLATE("Application types"),
161 B_TITLED_WINDOW,
162 B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
164 float padding = be_control_look->DefaultItemSpacing();
165 BAlignment labelAlignment = be_control_look->DefaultLabelAlignment();
166 BAlignment fullWidthTopAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_TOP);
168 // Application list
170 fTypeListView = new MimeTypeListView("listview", "application", true, true);
171 fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected));
172 fTypeListView->SetInvocationMessage(new BMessage(kMsgTypeInvoked));
173 // TODO: this isn't the perfect solution, but otherwise the window contents
174 // will jump chaotically
175 fTypeListView->SetExplicitMinSize(BSize(200, B_SIZE_UNSET));
176 fTypeListView->SetExplicitMaxSize(BSize(250, B_SIZE_UNSET));
178 BScrollView* scrollView = new BScrollView("scrollview", fTypeListView,
179 B_FRAME_EVENTS | B_WILL_DRAW, false, true);
181 BButton* button = new BButton("remove", B_TRANSLATE("Remove uninstalled"),
182 new BMessage(kMsgRemoveUninstalled));
184 // "Information" group
186 BBox* infoBox = new BBox((char*)NULL);
187 infoBox->SetLabel(B_TRANSLATE("Information"));
188 infoBox->SetExplicitAlignment(fullWidthTopAlignment);
190 fNameView = new StringView(B_TRANSLATE("Name:"), NULL);
191 fNameView->TextView()->SetExplicitAlignment(labelAlignment);
192 fNameView->LabelView()->SetExplicitAlignment(labelAlignment);
193 fSignatureView = new StringView(B_TRANSLATE("Signature:"), NULL);
194 fSignatureView->TextView()->SetExplicitAlignment(labelAlignment);
195 fSignatureView->LabelView()->SetExplicitAlignment(labelAlignment);
196 fPathView = new StringView(B_TRANSLATE("Path:"), NULL);
197 fPathView->TextView()->SetExplicitAlignment(labelAlignment);
198 fPathView->LabelView()->SetExplicitAlignment(labelAlignment);
200 BLayoutBuilder::Grid<>(infoBox, padding, padding)
201 .SetInsets(padding, padding * 2, padding, padding)
202 .Add(fNameView->LabelView(), 0, 0)
203 .Add(fNameView->TextView(), 1, 0, 2)
204 .Add(fSignatureView->LabelView(), 0, 1)
205 .Add(fSignatureView->TextView(), 1, 1, 2)
206 .Add(fPathView->LabelView(), 0, 2)
207 .Add(fPathView->TextView(), 1, 2, 2);
209 // "Version" group
211 BBox* versionBox = new BBox("");
212 versionBox->SetLabel(B_TRANSLATE("Version"));
213 versionBox->SetExplicitAlignment(fullWidthTopAlignment);
215 fVersionView = new StringView(B_TRANSLATE("Version:"), NULL);
216 fVersionView->TextView()->SetExplicitAlignment(labelAlignment);
217 fVersionView->LabelView()->SetExplicitAlignment(labelAlignment);
218 fDescriptionLabel = new StringView(B_TRANSLATE("Description:"), NULL);
219 fDescriptionLabel->LabelView()->SetExplicitAlignment(labelAlignment);
220 fDescriptionView = new BTextView("description");
221 fDescriptionView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
222 fDescriptionView->SetLowColor(fDescriptionView->ViewColor());
223 fDescriptionView->MakeEditable(false);
225 BLayoutBuilder::Grid<>(versionBox, padding, padding)
226 .SetInsets(padding, padding * 2, padding, padding)
227 .Add(fVersionView->LabelView(), 0, 0)
228 .Add(fVersionView->TextView(), 1, 0)
229 .Add(fDescriptionLabel->LabelView(), 0, 1)
230 .Add(fDescriptionView, 1, 1, 2, 2);
232 // Launch and Tracker buttons
234 fEditButton = new BButton(B_TRANSLATE("Edit" B_UTF8_ELLIPSIS),
235 new BMessage(kMsgEdit));
236 // launch and tracker buttons get messages in _SetType()
237 fLaunchButton = new BButton(B_TRANSLATE("Launch"));
238 fTrackerButton = new BButton(
239 B_TRANSLATE("Show in Tracker" B_UTF8_ELLIPSIS));
242 BLayoutBuilder::Group<>(this, B_HORIZONTAL, padding)
243 .AddGroup(B_VERTICAL, padding, 3)
244 .Add(scrollView)
245 .AddGroup(B_HORIZONTAL)
246 .Add(button)
247 .AddGlue()
248 .End()
249 .End()
250 .AddGroup(B_VERTICAL, padding)
251 .Add(infoBox)
252 .Add(versionBox)
253 .AddGroup(B_HORIZONTAL, padding)
254 .Add(fEditButton)
255 .Add(fLaunchButton)
256 .Add(fTrackerButton)
257 .AddGlue()
258 .End()
259 .AddGlue(10.0)
260 .End()
262 .SetInsets(B_USE_WINDOW_SPACING);
264 BMimeType::StartWatching(this);
265 _SetType(NULL);
269 ApplicationTypesWindow::~ApplicationTypesWindow()
271 BMimeType::StopWatching(this);
275 BRect
276 ApplicationTypesWindow::_Frame(const BMessage& settings) const
278 BRect rect;
279 if (settings.FindRect("app_types_frame", &rect) == B_OK)
280 return rect;
282 return BRect(100.0f, 100.0f, 540.0f, 480.0f);
286 void
287 ApplicationTypesWindow::_RemoveUninstalled()
289 // Note: this runs in the looper's thread, which isn't that nice
291 int32 removed = 0;
292 volatile bool quit = false;
294 BWindow* progressWindow =
295 new ProgressWindow(
296 B_TRANSLATE("Removing uninstalled application types"),
297 fTypeListView->FullListCountItems(), &quit);
298 progressWindow->AddToSubset(this);
299 progressWindow->Show();
301 for (int32 i = fTypeListView->FullListCountItems(); i-- > 0 && !quit;) {
302 MimeTypeItem* item = dynamic_cast<MimeTypeItem*>
303 (fTypeListView->FullListItemAt(i));
304 progressWindow->PostMessage(B_UPDATE_STATUS_BAR);
306 if (item == NULL)
307 continue;
309 // search for application on all volumes
311 bool found = false;
313 BVolumeRoster volumeRoster;
314 BVolume volume;
315 while (volumeRoster.GetNextVolume(&volume) == B_OK) {
316 if (!volume.KnowsQuery())
317 continue;
319 BQuery query;
320 query.PushAttr("BEOS:APP_SIG");
321 query.PushString(item->Type());
322 query.PushOp(B_EQ);
324 query.SetVolume(&volume);
325 query.Fetch();
327 entry_ref ref;
328 if (query.GetNextRef(&ref) == B_OK) {
329 found = true;
330 break;
334 if (!found) {
335 BMimeType mimeType(item->Type());
336 mimeType.Delete();
338 removed++;
340 // We're blocking the message loop that received the MIME changes,
341 // so we dequeue all waiting messages from time to time
342 if (removed % 10 == 0)
343 UpdateIfNeeded();
347 progressWindow->PostMessage(B_QUIT_REQUESTED);
349 static BMessageFormat format(B_TRANSLATE("{0, plural, "
350 "one{# Application type could be removed} "
351 "other{# Application types could be removed}}"));
352 BString message;
353 format.Format(message, removed);
355 error_alert(message, B_OK, B_INFO_ALERT);
359 void
360 ApplicationTypesWindow::_SetType(BMimeType* type, int32 forceUpdate)
362 bool enabled = type != NULL;
363 bool appFound = true;
365 // update controls
367 if (type != NULL) {
368 if (fCurrentType == *type) {
369 if (!forceUpdate)
370 return;
371 } else
372 forceUpdate = B_EVERYTHING_CHANGED;
374 if (&fCurrentType != type)
375 fCurrentType.SetTo(type->Type());
377 fSignatureView->SetText(type->Type());
379 char description[B_MIME_TYPE_LENGTH];
381 if ((forceUpdate & B_SHORT_DESCRIPTION_CHANGED) != 0) {
382 if (type->GetShortDescription(description) != B_OK)
383 description[0] = '\0';
384 fNameView->SetText(description);
387 entry_ref ref;
388 if ((forceUpdate & B_APP_HINT_CHANGED) != 0
389 && be_roster->FindApp(fCurrentType.Type(), &ref) == B_OK) {
390 // Set launch message
391 BMessenger tracker("application/x-vnd.Be-TRAK");
392 BMessage* message = new BMessage(B_REFS_RECEIVED);
393 message->AddRef("refs", &ref);
395 fLaunchButton->SetMessage(message);
396 fLaunchButton->SetTarget(tracker);
398 // Set path
399 BPath path(&ref);
400 path.GetParent(&path);
401 fPathView->SetText(path.Path());
403 // Set "Show In Tracker" message
404 BEntry entry(path.Path());
405 entry_ref directoryRef;
406 if (entry.GetRef(&directoryRef) == B_OK) {
407 BMessenger tracker("application/x-vnd.Be-TRAK");
408 message = new BMessage(B_REFS_RECEIVED);
409 message->AddRef("refs", &directoryRef);
411 fTrackerButton->SetMessage(message);
412 fTrackerButton->SetTarget(tracker);
413 } else {
414 fTrackerButton->SetMessage(NULL);
415 appFound = false;
417 } else if ((forceUpdate & B_APP_HINT_CHANGED) != 0) {
418 fLaunchButton->SetMessage(NULL);
419 fPathView->SetText(NULL);
420 fTrackerButton->SetMessage(NULL);
423 if (forceUpdate == B_EVERYTHING_CHANGED) {
424 // update version information
426 BFile file(&ref, B_READ_ONLY);
427 if (file.InitCheck() == B_OK) {
428 BAppFileInfo appInfo(&file);
429 version_info versionInfo;
430 if (appInfo.InitCheck() == B_OK
431 && appInfo.GetVersionInfo(&versionInfo, B_APP_VERSION_KIND)
432 == B_OK) {
433 char version[256];
434 snprintf(version, sizeof(version),
435 "%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ", %s/%" B_PRIu32,
436 versionInfo.major, versionInfo.middle,
437 versionInfo.minor,
438 variety_to_text(versionInfo.variety),
439 versionInfo.internal);
440 fVersionView->SetText(version);
441 fDescriptionView->SetText(versionInfo.long_info);
442 } else {
443 fVersionView->SetText(NULL);
444 fDescriptionView->SetText(NULL);
448 } else {
449 fNameView->SetText(NULL);
450 fSignatureView->SetText(NULL);
451 fPathView->SetText(NULL);
453 fVersionView->SetText(NULL);
454 fDescriptionView->SetText(NULL);
457 fNameView->SetEnabled(enabled);
458 fSignatureView->SetEnabled(enabled);
459 fPathView->SetEnabled(enabled);
461 fVersionView->SetEnabled(enabled);
462 fDescriptionLabel->SetEnabled(enabled);
464 fTrackerButton->SetEnabled(enabled && appFound);
465 fLaunchButton->SetEnabled(enabled && appFound);
466 fEditButton->SetEnabled(enabled && appFound);
470 void
471 ApplicationTypesWindow::MessageReceived(BMessage* message)
473 switch (message->what) {
474 case kMsgTypeSelected:
476 int32 index;
477 if (message->FindInt32("index", &index) == B_OK) {
478 MimeTypeItem* item = (MimeTypeItem*)fTypeListView->ItemAt(index);
479 if (item != NULL) {
480 BMimeType type(item->Type());
481 _SetType(&type);
482 } else
483 _SetType(NULL);
485 break;
488 case kMsgTypeInvoked:
490 int32 index;
491 if (message->FindInt32("index", &index) == B_OK) {
492 MimeTypeItem* item = (MimeTypeItem*)fTypeListView->ItemAt(index);
493 if (item != NULL) {
494 BMimeType type(item->Type());
495 entry_ref ref;
496 if (type.GetAppHint(&ref) == B_OK) {
497 BMessage refs(B_REFS_RECEIVED);
498 refs.AddRef("refs", &ref);
500 be_app->PostMessage(&refs);
504 break;
507 case kMsgEdit:
508 fTypeListView->Invoke();
509 break;
511 case kMsgRemoveUninstalled:
512 _RemoveUninstalled();
513 break;
515 case B_META_MIME_CHANGED:
517 const char* type;
518 int32 which;
519 if (message->FindString("be:type", &type) != B_OK
520 || message->FindInt32("be:which", &which) != B_OK) {
521 break;
524 if (fCurrentType.Type() == NULL)
525 break;
527 if (!strcasecmp(fCurrentType.Type(), type)) {
528 if (which != B_MIME_TYPE_DELETED)
529 _SetType(&fCurrentType, which);
530 else
531 _SetType(NULL);
533 break;
536 default:
537 BWindow::MessageReceived(message);
542 bool
543 ApplicationTypesWindow::QuitRequested()
545 BMessage update(kMsgSettingsChanged);
546 update.AddRect("app_types_frame", Frame());
547 be_app_messenger.SendMessage(&update);
549 be_app->PostMessage(kMsgApplicationTypesWindowClosed);
550 return true;