2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "ApplicationTypesWindow.h"
9 #include "FileTypesWindow.h"
10 #include "MimeTypeListView.h"
11 #include "StringView.h"
13 #include <AppFileInfo.h>
14 #include <Application.h>
19 #include <ControlLook.h>
20 #include <LayoutBuilder.h>
22 #include <MenuField.h>
24 #include <MessageFormat.h>
28 #include <PopUpMenu.h>
32 #include <ScrollView.h>
33 #include <StatusBar.h>
34 #include <StringView.h>
37 #include <VolumeRoster.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
{
52 ProgressWindow(const char* message
, int32 max
,
53 volatile bool* signalQuit
);
54 virtual ~ProgressWindow();
56 virtual void MessageReceived(BMessage
* message
);
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';
71 variety_to_text(uint32 variety
)
74 case B_DEVELOPMENT_VERSION
:
75 return B_TRANSLATE("Development");
77 return B_TRANSLATE("Alpha");
79 return B_TRANSLATE("Beta");
81 return B_TRANSLATE("Gamma");
82 case B_GOLDEN_MASTER_VERSION
:
83 return B_TRANSLATE("Golden master");
85 return B_TRANSLATE("Final");
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
)
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
)
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()
132 ProgressWindow::MessageReceived(BMessage
* message
)
134 switch (message
->what
) {
135 case B_UPDATE_STATUS_BAR
:
137 snprintf(count
, sizeof(count
), "%" B_PRId32
,
138 (int32
)fStatusBar
->CurrentValue() + 1);
140 fStatusBar
->Update(1, NULL
, count
);
144 fAbortButton
->SetEnabled(false);
145 if (fQuitListener
!= NULL
)
146 *fQuitListener
= true;
150 BWindow::MessageReceived(message
);
159 ApplicationTypesWindow::ApplicationTypesWindow(const BMessage
& settings
)
160 : BWindow(_Frame(settings
), B_TRANSLATE("Application types"),
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
);
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);
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)
245 .AddGroup(B_HORIZONTAL
)
250 .AddGroup(B_VERTICAL
, padding
)
253 .AddGroup(B_HORIZONTAL
, padding
)
262 .SetInsets(B_USE_WINDOW_SPACING
);
264 BMimeType::StartWatching(this);
269 ApplicationTypesWindow::~ApplicationTypesWindow()
271 BMimeType::StopWatching(this);
276 ApplicationTypesWindow::_Frame(const BMessage
& settings
) const
279 if (settings
.FindRect("app_types_frame", &rect
) == B_OK
)
282 return BRect(100.0f
, 100.0f
, 540.0f
, 480.0f
);
287 ApplicationTypesWindow::_RemoveUninstalled()
289 // Note: this runs in the looper's thread, which isn't that nice
292 volatile bool quit
= false;
294 BWindow
* 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
);
309 // search for application on all volumes
313 BVolumeRoster volumeRoster
;
315 while (volumeRoster
.GetNextVolume(&volume
) == B_OK
) {
316 if (!volume
.KnowsQuery())
320 query
.PushAttr("BEOS:APP_SIG");
321 query
.PushString(item
->Type());
324 query
.SetVolume(&volume
);
328 if (query
.GetNextRef(&ref
) == B_OK
) {
335 BMimeType
mimeType(item
->Type());
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)
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}}"));
353 format
.Format(message
, removed
);
355 error_alert(message
, B_OK
, B_INFO_ALERT
);
360 ApplicationTypesWindow::_SetType(BMimeType
* type
, int32 forceUpdate
)
362 bool enabled
= type
!= NULL
;
363 bool appFound
= true;
368 if (fCurrentType
== *type
) {
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
);
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
);
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
);
414 fTrackerButton
->SetMessage(NULL
);
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
)
434 snprintf(version
, sizeof(version
),
435 "%" B_PRIu32
".%" B_PRIu32
".%" B_PRIu32
", %s/%" B_PRIu32
,
436 versionInfo
.major
, versionInfo
.middle
,
438 variety_to_text(versionInfo
.variety
),
439 versionInfo
.internal
);
440 fVersionView
->SetText(version
);
441 fDescriptionView
->SetText(versionInfo
.long_info
);
443 fVersionView
->SetText(NULL
);
444 fDescriptionView
->SetText(NULL
);
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
);
471 ApplicationTypesWindow::MessageReceived(BMessage
* message
)
473 switch (message
->what
) {
474 case kMsgTypeSelected
:
477 if (message
->FindInt32("index", &index
) == B_OK
) {
478 MimeTypeItem
* item
= (MimeTypeItem
*)fTypeListView
->ItemAt(index
);
480 BMimeType
type(item
->Type());
488 case kMsgTypeInvoked
:
491 if (message
->FindInt32("index", &index
) == B_OK
) {
492 MimeTypeItem
* item
= (MimeTypeItem
*)fTypeListView
->ItemAt(index
);
494 BMimeType
type(item
->Type());
496 if (type
.GetAppHint(&ref
) == B_OK
) {
497 BMessage
refs(B_REFS_RECEIVED
);
498 refs
.AddRef("refs", &ref
);
500 be_app
->PostMessage(&refs
);
508 fTypeListView
->Invoke();
511 case kMsgRemoveUninstalled
:
512 _RemoveUninstalled();
515 case B_META_MIME_CHANGED
:
519 if (message
->FindString("be:type", &type
) != B_OK
520 || message
->FindInt32("be:which", &which
) != B_OK
) {
524 if (fCurrentType
.Type() == NULL
)
527 if (!strcasecmp(fCurrentType
.Type(), type
)) {
528 if (which
!= B_MIME_TYPE_DELETED
)
529 _SetType(&fCurrentType
, which
);
537 BWindow::MessageReceived(message
);
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
);