2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "ApplicationTypeWindow.h"
8 #include "DropTargetListView.h"
11 #include "PreferredAppMenu.h"
12 #include "StringView.h"
13 #include "TypeListWindow.h"
15 #include <Application.h>
21 #include <ControlLook.h>
23 #include <GroupView.h>
24 #include <LayoutBuilder.h>
28 #include <MenuField.h>
32 #include <PopUpMenu.h>
33 #include <RadioButton.h>
35 #include <ScrollView.h>
36 #include <StringView.h>
37 #include <TextControl.h>
45 #undef B_TRANSLATION_CONTEXT
46 #define B_TRANSLATION_CONTEXT "Application Type Window"
49 const uint32 kMsgSave
= 'save';
50 const uint32 kMsgSignatureChanged
= 'sgch';
51 const uint32 kMsgToggleAppFlags
= 'tglf';
52 const uint32 kMsgAppFlagsChanged
= 'afch';
54 const uint32 kMsgIconChanged
= 'icch';
55 const uint32 kMsgTypeIconsChanged
= 'tich';
57 const uint32 kMsgVersionInfoChanged
= 'tvch';
59 const uint32 kMsgTypeSelected
= 'tpsl';
60 const uint32 kMsgAddType
= 'adtp';
61 const uint32 kMsgTypeAdded
= 'tpad';
62 const uint32 kMsgRemoveType
= 'rmtp';
63 const uint32 kMsgTypeRemoved
= 'tprm';
66 //! TextView that filters the tab key to be able to tab-navigate while editing
67 class TabFilteringTextView
: public BTextView
{
69 TabFilteringTextView(const char* name
,
70 uint32 changedMessageWhat
= 0);
71 virtual ~TabFilteringTextView();
73 virtual void InsertText(const char* text
, int32 length
,
74 int32 offset
, const text_run_array
* runs
);
75 virtual void DeleteText(int32 fromOffset
, int32 toOffset
);
76 virtual void KeyDown(const char* bytes
, int32 count
);
77 virtual void TargetedByScrollView(BScrollView
* scroller
);
78 virtual void MakeFocus(bool focused
= true);
81 BScrollView
* fScrollView
;
82 uint32 fChangedMessageWhat
;
86 class SupportedTypeItem
: public BStringItem
{
88 SupportedTypeItem(const char* type
);
89 virtual ~SupportedTypeItem();
91 const char* Type() const { return fType
.String(); }
92 ::Icon
& Icon() { return fIcon
; }
94 void SetIcon(::Icon
* icon
);
95 void SetIcon(entry_ref
& ref
, const char* type
);
97 static int Compare(const void* _a
, const void* _b
);
105 class SupportedTypeListView
: public DropTargetListView
{
107 SupportedTypeListView(const char* name
,
109 type
= B_SINGLE_SELECTION_LIST
,
110 uint32 flags
= B_WILL_DRAW
111 | B_FRAME_EVENTS
| B_NAVIGABLE
);
112 virtual ~SupportedTypeListView();
114 virtual void MessageReceived(BMessage
* message
);
115 virtual bool AcceptsDrag(const BMessage
* message
);
122 TabFilteringTextView::TabFilteringTextView(const char* name
,
123 uint32 changedMessageWhat
)
125 BTextView(name
, B_WILL_DRAW
| B_PULSE_NEEDED
| B_NAVIGABLE
),
127 fChangedMessageWhat(changedMessageWhat
)
132 TabFilteringTextView::~TabFilteringTextView()
138 TabFilteringTextView::InsertText(const char* text
, int32 length
, int32 offset
,
139 const text_run_array
* runs
)
141 BTextView::InsertText(text
, length
, offset
, runs
);
142 if (fChangedMessageWhat
!= 0)
143 Window()->PostMessage(fChangedMessageWhat
);
148 TabFilteringTextView::DeleteText(int32 fromOffset
, int32 toOffset
)
150 BTextView::DeleteText(fromOffset
, toOffset
);
151 if (fChangedMessageWhat
!= 0)
152 Window()->PostMessage(fChangedMessageWhat
);
157 TabFilteringTextView::KeyDown(const char* bytes
, int32 count
)
159 if (bytes
[0] == B_TAB
)
160 BView::KeyDown(bytes
, count
);
162 BTextView::KeyDown(bytes
, count
);
167 TabFilteringTextView::TargetedByScrollView(BScrollView
* scroller
)
169 fScrollView
= scroller
;
174 TabFilteringTextView::MakeFocus(bool focused
)
176 BTextView::MakeFocus(focused
);
179 fScrollView
->SetBorderHighlighted(focused
);
186 SupportedTypeItem::SupportedTypeItem(const char* type
)
190 BMimeType
mimeType(type
);
192 char description
[B_MIME_TYPE_LENGTH
];
193 if (mimeType
.GetShortDescription(description
) == B_OK
&& description
[0])
194 SetText(description
);
198 SupportedTypeItem::~SupportedTypeItem()
204 SupportedTypeItem::SetIcon(::Icon
* icon
)
214 SupportedTypeItem::SetIcon(entry_ref
& ref
, const char* type
)
216 fIcon
.SetTo(ref
, type
);
222 SupportedTypeItem::Compare(const void* _a
, const void* _b
)
224 const SupportedTypeItem
* a
= *(const SupportedTypeItem
**)_a
;
225 const SupportedTypeItem
* b
= *(const SupportedTypeItem
**)_b
;
227 int compare
= strcasecmp(a
->Text(), b
->Text());
231 return strcasecmp(a
->Type(), b
->Type());
238 SupportedTypeListView::SupportedTypeListView(const char* name
,
239 list_view_type type
, uint32 flags
)
241 DropTargetListView(name
, type
, flags
)
246 SupportedTypeListView::~SupportedTypeListView()
252 SupportedTypeListView::MessageReceived(BMessage
* message
)
254 if (message
->WasDropped() && AcceptsDrag(message
)) {
257 for (int32 index
= 0; message
->FindRef("refs", index
++, &ref
) == B_OK
; ) {
259 BNodeInfo
info(&node
);
260 if (node
.InitCheck() != B_OK
|| info
.InitCheck() != B_OK
)
263 // TODO: we could identify the file in case it doesn't have a type...
264 char type
[B_MIME_TYPE_LENGTH
];
265 if (info
.GetType(type
) != B_OK
)
268 // check if that type is already in our list
270 for (int32 i
= CountItems(); i
-- > 0;) {
271 SupportedTypeItem
* item
= (SupportedTypeItem
*)ItemAt(i
);
272 if (!strcmp(item
->Text(), type
)) {
280 AddItem(new SupportedTypeItem(type
));
284 SortItems(&SupportedTypeItem::Compare
);
286 DropTargetListView::MessageReceived(message
);
291 SupportedTypeListView::AcceptsDrag(const BMessage
* message
)
294 return message
->GetInfo("refs", &type
) == B_OK
&& type
== B_REF_TYPE
;
301 ApplicationTypeWindow::ApplicationTypeWindow(BPoint position
,
304 BWindow(BRect(0.0f
, 0.0f
, 250.0f
, 340.0f
).OffsetBySelf(position
),
305 B_TRANSLATE("Application type"), B_TITLED_WINDOW
,
306 B_NOT_ZOOMABLE
| B_ASYNCHRONOUS_CONTROLS
|
307 B_FRAME_EVENTS
| B_AUTO_UPDATE_SIZE_LIMITS
),
308 fChangedProperties(0)
310 float padding
= be_control_look
->DefaultItemSpacing();
311 BAlignment labelAlignment
= be_control_look
->DefaultLabelAlignment();
313 BMenuBar
* menuBar
= new BMenuBar((char*)NULL
);
314 menuBar
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
, B_ALIGN_TOP
));
316 BMenu
* menu
= new BMenu(B_TRANSLATE("File"));
317 fSaveMenuItem
= new BMenuItem(B_TRANSLATE("Save"),
318 new BMessage(kMsgSave
), 'S');
319 fSaveMenuItem
->SetEnabled(false);
320 menu
->AddItem(fSaveMenuItem
);
322 menu
->AddItem(item
= new BMenuItem(
323 B_TRANSLATE("Save into resource file" B_UTF8_ELLIPSIS
), NULL
));
324 item
->SetEnabled(false);
326 menu
->AddSeparatorItem();
327 menu
->AddItem(new BMenuItem(B_TRANSLATE("Close"),
328 new BMessage(B_QUIT_REQUESTED
), 'W', B_COMMAND_KEY
));
329 menuBar
->AddItem(menu
);
333 fSignatureControl
= new BTextControl("signature",
334 B_TRANSLATE("Signature:"), new BMessage(kMsgSignatureChanged
));
335 fSignatureControl
->SetModificationMessage(
336 new BMessage(kMsgSignatureChanged
));
338 // filter out invalid characters that can't be part of a MIME type name
339 BTextView
* textView
= fSignatureControl
->TextView();
340 textView
->SetMaxBytes(B_MIME_TYPE_LENGTH
);
341 const char* disallowedCharacters
= "<>@,;:\"()[]?= ";
342 for (int32 i
= 0; disallowedCharacters
[i
]; i
++) {
343 textView
->DisallowChar(disallowedCharacters
[i
]);
346 // "Application Flags" group
348 BBox
* flagsBox
= new BBox("flagsBox");
350 fFlagsCheckBox
= new BCheckBox("flags", B_TRANSLATE("Application flags"),
351 new BMessage(kMsgToggleAppFlags
));
352 fFlagsCheckBox
->SetValue(B_CONTROL_ON
);
354 fSingleLaunchButton
= new BRadioButton("single",
355 B_TRANSLATE("Single launch"), new BMessage(kMsgAppFlagsChanged
));
357 fMultipleLaunchButton
= new BRadioButton("multiple",
358 B_TRANSLATE("Multiple launch"), new BMessage(kMsgAppFlagsChanged
));
360 fExclusiveLaunchButton
= new BRadioButton("exclusive",
361 B_TRANSLATE("Exclusive launch"), new BMessage(kMsgAppFlagsChanged
));
363 fArgsOnlyCheckBox
= new BCheckBox("args only", B_TRANSLATE("Args only"),
364 new BMessage(kMsgAppFlagsChanged
));
366 fBackgroundAppCheckBox
= new BCheckBox("background",
367 B_TRANSLATE("Background app"), new BMessage(kMsgAppFlagsChanged
));
369 BLayoutBuilder::Grid
<>(flagsBox
, 0, 0)
370 .SetInsets(padding
, padding
* 2, padding
, padding
)
371 .Add(fSingleLaunchButton
, 0, 0).Add(fArgsOnlyCheckBox
, 1, 0)
372 .Add(fMultipleLaunchButton
, 0, 1).Add(fBackgroundAppCheckBox
, 1, 1)
373 .Add(fExclusiveLaunchButton
, 0, 2);
374 flagsBox
->SetLabel(fFlagsCheckBox
);
378 BBox
* iconBox
= new BBox("IconBox");
379 iconBox
->SetLabel(B_TRANSLATE("Icon"));
380 fIconView
= new IconView("icon");
381 fIconView
->SetModificationMessage(new BMessage(kMsgIconChanged
));
382 BLayoutBuilder::Group
<>(iconBox
, B_HORIZONTAL
)
383 .SetInsets(padding
, padding
* 2, padding
, padding
)
386 // "Supported Types" group
388 BBox
* typeBox
= new BBox("typesBox");
389 typeBox
->SetLabel(B_TRANSLATE("Supported types"));
391 fTypeListView
= new SupportedTypeListView("Suppported Types",
392 B_SINGLE_SELECTION_LIST
);
393 fTypeListView
->SetSelectionMessage(new BMessage(kMsgTypeSelected
));
395 BScrollView
* scrollView
= new BScrollView("type scrollview", fTypeListView
,
396 B_FRAME_EVENTS
| B_WILL_DRAW
, false, true);
398 fAddTypeButton
= new BButton("add type",
399 B_TRANSLATE("Add" B_UTF8_ELLIPSIS
), new BMessage(kMsgAddType
));
401 fRemoveTypeButton
= new BButton("remove type", B_TRANSLATE("Remove"),
402 new BMessage(kMsgRemoveType
));
404 fTypeIconView
= new IconView("type icon");
405 BGroupView
* iconHolder
= new BGroupView(B_HORIZONTAL
);
406 iconHolder
->AddChild(fTypeIconView
);
407 fTypeIconView
->SetModificationMessage(new BMessage(kMsgTypeIconsChanged
));
409 BLayoutBuilder::Grid
<>(typeBox
, padding
, padding
)
410 .SetInsets(padding
, padding
* 2, padding
, padding
)
411 .Add(scrollView
, 0, 0, 1, 4)
412 .Add(fAddTypeButton
, 1, 0, 1, 2)
413 .Add(fRemoveTypeButton
, 1, 2, 1, 2)
414 .Add(iconHolder
, 2, 1, 1, 2)
415 .SetColumnWeight(0, 3)
416 .SetColumnWeight(1, 2)
417 .SetColumnWeight(2, 1);
419 iconHolder
->SetExplicitAlignment(
420 BAlignment(B_ALIGN_CENTER
, B_ALIGN_MIDDLE
));
422 // "Version Info" group
424 BBox
* versionBox
= new BBox("versionBox");
425 versionBox
->SetLabel(B_TRANSLATE("Version info"));
427 fMajorVersionControl
= new BTextControl("version major",
428 B_TRANSLATE("Version:"), NULL
, new BMessage(kMsgVersionInfoChanged
));
429 _MakeNumberTextControl(fMajorVersionControl
);
431 fMiddleVersionControl
= new BTextControl("version middle", ".", NULL
,
432 new BMessage(kMsgVersionInfoChanged
));
433 _MakeNumberTextControl(fMiddleVersionControl
);
435 fMinorVersionControl
= new BTextControl("version minor", ".", NULL
,
436 new BMessage(kMsgVersionInfoChanged
));
437 _MakeNumberTextControl(fMinorVersionControl
);
439 fVarietyMenu
= new BPopUpMenu("variety", true, true);
440 fVarietyMenu
->AddItem(new BMenuItem(B_TRANSLATE("Development"),
441 new BMessage(kMsgVersionInfoChanged
)));
442 fVarietyMenu
->AddItem(new BMenuItem(B_TRANSLATE("Alpha"),
443 new BMessage(kMsgVersionInfoChanged
)));
444 fVarietyMenu
->AddItem(new BMenuItem(B_TRANSLATE("Beta"),
445 new BMessage(kMsgVersionInfoChanged
)));
446 fVarietyMenu
->AddItem(new BMenuItem(B_TRANSLATE("Gamma"),
447 new BMessage(kMsgVersionInfoChanged
)));
448 item
= new BMenuItem(B_TRANSLATE("Golden master"),
449 new BMessage(kMsgVersionInfoChanged
));
450 fVarietyMenu
->AddItem(item
);
451 item
->SetMarked(true);
452 fVarietyMenu
->AddItem(new BMenuItem(B_TRANSLATE("Final"),
453 new BMessage(kMsgVersionInfoChanged
)));
455 BMenuField
* varietyField
= new BMenuField("", fVarietyMenu
);
456 fInternalVersionControl
= new BTextControl("version internal", "/", NULL
,
457 new BMessage(kMsgVersionInfoChanged
));
458 fShortDescriptionControl
= new BTextControl("short description",
459 B_TRANSLATE("Short description:"), NULL
,
460 new BMessage(kMsgVersionInfoChanged
));
462 // TODO: workaround for a GCC 4.1.0 bug? Or is that really what the standard says?
463 version_info versionInfo
;
464 fShortDescriptionControl
->TextView()->SetMaxBytes(
465 sizeof(versionInfo
.short_info
));
467 BStringView
* longLabel
= new BStringView(NULL
,
468 B_TRANSLATE("Long description:"));
469 longLabel
->SetExplicitAlignment(labelAlignment
);
470 fLongDescriptionView
= new TabFilteringTextView("long desc",
471 kMsgVersionInfoChanged
);
472 fLongDescriptionView
->SetMaxBytes(sizeof(versionInfo
.long_info
));
474 scrollView
= new BScrollView("desc scrollview", fLongDescriptionView
,
475 B_FRAME_EVENTS
| B_WILL_DRAW
, false, true);
477 // TODO: remove workaround (bug #5678)
478 BSize minScrollSize
= scrollView
->ScrollBar(B_VERTICAL
)->MinSize();
479 minScrollSize
.width
+= fLongDescriptionView
->MinSize().width
;
480 scrollView
->SetExplicitMinSize(minScrollSize
);
482 // Manually set a minimum size for the version text controls
483 // TODO: the same does not work when applied to the layout items
484 float width
= be_plain_font
->StringWidth("99") + 16;
485 fMajorVersionControl
->TextView()->SetExplicitMinSize(
486 BSize(width
, fMajorVersionControl
->MinSize().height
));
487 fMiddleVersionControl
->TextView()->SetExplicitMinSize(
488 BSize(width
, fMiddleVersionControl
->MinSize().height
));
489 fMinorVersionControl
->TextView()->SetExplicitMinSize(
490 BSize(width
, fMinorVersionControl
->MinSize().height
));
491 fInternalVersionControl
->TextView()->SetExplicitMinSize(
492 BSize(width
, fInternalVersionControl
->MinSize().height
));
494 BLayoutBuilder::Grid
<>(versionBox
, padding
/ 2, padding
/ 2)
495 .SetInsets(padding
, padding
* 2, padding
, padding
)
496 .Add(fMajorVersionControl
->CreateLabelLayoutItem(), 0, 0)
497 .Add(fMajorVersionControl
->CreateTextViewLayoutItem(), 1, 0)
498 .Add(fMiddleVersionControl
, 2, 0, 2)
499 .Add(fMinorVersionControl
, 4, 0, 2)
500 .Add(varietyField
, 6, 0, 3)
501 .Add(fInternalVersionControl
, 9, 0, 2)
502 .Add(fShortDescriptionControl
->CreateLabelLayoutItem(), 0, 1)
503 .Add(fShortDescriptionControl
->CreateTextViewLayoutItem(), 1, 1, 10)
504 .Add(longLabel
, 0, 2)
505 .Add(scrollView
, 1, 2, 10, 3)
508 // put it all together
509 BLayoutBuilder::Group
<>(this, B_VERTICAL
, 0)
510 .SetInsets(0, 0, 0, 0)
512 .AddGroup(B_VERTICAL
, padding
)
513 .SetInsets(padding
, padding
, padding
, padding
)
514 .Add(fSignatureControl
)
515 .AddGroup(B_HORIZONTAL
, padding
)
522 SetKeyMenuBar(menuBar
);
524 fSignatureControl
->MakeFocus(true);
525 BMimeType::StartWatching(this);
530 ApplicationTypeWindow::~ApplicationTypeWindow()
532 BMimeType::StopWatching(this);
537 ApplicationTypeWindow::_Title(const BEntry
& entry
)
539 char name
[B_FILE_NAME_LENGTH
];
540 if (entry
.GetName(name
) != B_OK
)
541 strcpy(name
, "\"-\"");
543 BString title
= B_TRANSLATE("%1 application type");
544 title
.ReplaceFirst("%1", name
);
550 ApplicationTypeWindow::_SetTo(const BEntry
& entry
)
552 SetTitle(_Title(entry
).String());
557 BFile
file(&entry
, B_READ_ONLY
);
558 if (file
.InitCheck() != B_OK
)
561 BAppFileInfo
info(&file
);
562 if (info
.InitCheck() != B_OK
)
565 char signature
[B_MIME_TYPE_LENGTH
];
566 if (info
.GetSignature(signature
) != B_OK
)
569 bool gotFlags
= false;
571 if (info
.GetAppFlags(&flags
) == B_OK
)
574 flags
= B_MULTIPLE_LAUNCH
;
576 version_info versionInfo
;
577 if (info
.GetVersionInfo(&versionInfo
, B_APP_VERSION_KIND
) != B_OK
)
578 memset(&versionInfo
, 0, sizeof(version_info
));
582 fSignatureControl
->SetModificationMessage(NULL
);
583 fSignatureControl
->SetText(signature
);
584 fSignatureControl
->SetModificationMessage(
585 new BMessage(kMsgSignatureChanged
));
589 switch (flags
& (B_SINGLE_LAUNCH
| B_MULTIPLE_LAUNCH
| B_EXCLUSIVE_LAUNCH
)) {
590 case B_SINGLE_LAUNCH
:
591 fSingleLaunchButton
->SetValue(B_CONTROL_ON
);
594 case B_EXCLUSIVE_LAUNCH
:
595 fExclusiveLaunchButton
->SetValue(B_CONTROL_ON
);
598 case B_MULTIPLE_LAUNCH
:
600 fMultipleLaunchButton
->SetValue(B_CONTROL_ON
);
604 fArgsOnlyCheckBox
->SetValue((flags
& B_ARGV_ONLY
) != 0);
605 fBackgroundAppCheckBox
->SetValue((flags
& B_BACKGROUND_APP
) != 0);
606 fFlagsCheckBox
->SetValue(gotFlags
);
608 _UpdateAppFlagsEnabled();
613 if (entry
.GetRef(&ref
) == B_OK
)
618 fIconView
->SetModificationMessage(NULL
);
619 fIconView
->SetTo(&fIcon
);
620 fIconView
->SetModificationMessage(new BMessage(kMsgIconChanged
));
624 BMessage supportedTypes
;
625 info
.GetSupportedTypes(&supportedTypes
);
627 for (int32 i
= fTypeListView
->CountItems(); i
-- > 0;) {
628 BListItem
* item
= fTypeListView
->RemoveItem(i
);
633 for (int32 i
= 0; supportedTypes
.FindString("types", i
, &type
) == B_OK
; i
++) {
634 SupportedTypeItem
* item
= new SupportedTypeItem(type
);
637 if (fEntry
.GetRef(&ref
) == B_OK
)
638 item
->SetIcon(ref
, type
);
640 fTypeListView
->AddItem(item
);
642 fTypeListView
->SortItems(&SupportedTypeItem::Compare
);
643 fTypeIconView
->SetModificationMessage(NULL
);
644 fTypeIconView
->SetTo(NULL
);
645 fTypeIconView
->SetModificationMessage(new BMessage(kMsgTypeIconsChanged
));
646 fTypeIconView
->SetEnabled(false);
647 fRemoveTypeButton
->SetEnabled(false);
652 snprintf(text
, sizeof(text
), "%" B_PRId32
, versionInfo
.major
);
653 fMajorVersionControl
->SetText(text
);
654 snprintf(text
, sizeof(text
), "%" B_PRId32
, versionInfo
.middle
);
655 fMiddleVersionControl
->SetText(text
);
656 snprintf(text
, sizeof(text
), "%" B_PRId32
, versionInfo
.minor
);
657 fMinorVersionControl
->SetText(text
);
659 if (versionInfo
.variety
>= (uint32
)fVarietyMenu
->CountItems())
660 versionInfo
.variety
= 0;
661 BMenuItem
* item
= fVarietyMenu
->ItemAt(versionInfo
.variety
);
663 item
->SetMarked(true);
665 snprintf(text
, sizeof(text
), "%" B_PRId32
, versionInfo
.internal
);
666 fInternalVersionControl
->SetText(text
);
668 fShortDescriptionControl
->SetText(versionInfo
.short_info
);
669 fLongDescriptionView
->SetText(versionInfo
.long_info
);
671 // store original data
673 fOriginalInfo
.signature
= signature
;
674 fOriginalInfo
.gotFlags
= gotFlags
;
675 fOriginalInfo
.flags
= gotFlags
? flags
: 0;
676 fOriginalInfo
.versionInfo
= versionInfo
;
677 fOriginalInfo
.supportedTypes
= _SupportedTypes();
678 // The list view has the types sorted possibly differently
679 // to the supportedTypes message, so don't use that here, but
680 // get the sorted message instead.
681 fOriginalInfo
.iconChanged
= false;
682 fOriginalInfo
.typeIconsChanged
= false;
684 fChangedProperties
= 0;
685 _CheckSaveMenuItem(0);
690 ApplicationTypeWindow::_UpdateAppFlagsEnabled()
692 bool enabled
= fFlagsCheckBox
->Value() != B_CONTROL_OFF
;
694 fSingleLaunchButton
->SetEnabled(enabled
);
695 fMultipleLaunchButton
->SetEnabled(enabled
);
696 fExclusiveLaunchButton
->SetEnabled(enabled
);
697 fArgsOnlyCheckBox
->SetEnabled(enabled
);
698 fBackgroundAppCheckBox
->SetEnabled(enabled
);
703 ApplicationTypeWindow::_MakeNumberTextControl(BTextControl
* control
)
705 // filter out invalid characters that can't be part of a MIME type name
706 BTextView
* textView
= control
->TextView();
707 textView
->SetMaxBytes(10);
709 for (int32 i
= 0; i
< 256; i
++) {
711 textView
->DisallowChar(i
);
717 ApplicationTypeWindow::_Save()
720 status_t status
= file
.SetTo(&fEntry
, B_READ_WRITE
);
724 BAppFileInfo
info(&file
);
725 status
= info
.InitCheck();
732 bool gotFlags
= _Flags(flags
);
733 BMessage supportedTypes
= _SupportedTypes();
734 version_info versionInfo
= _VersionInfo();
738 status
= info
.SetSignature(fSignatureControl
->Text());
739 if (status
== B_OK
) {
741 status
= info
.SetAppFlags(flags
);
743 status
= info
.RemoveAppFlags();
746 status
= info
.SetVersionInfo(&versionInfo
, B_APP_VERSION_KIND
);
748 fIcon
.CopyTo(info
, NULL
, true);
750 // supported types and their icons
752 status
= info
.SetSupportedTypes(&supportedTypes
);
754 for (int32 i
= 0; i
< fTypeListView
->CountItems(); i
++) {
755 SupportedTypeItem
* item
= dynamic_cast<SupportedTypeItem
*>(
756 fTypeListView
->ItemAt(i
));
759 item
->Icon().CopyTo(info
, item
->Type(), true);
762 // reset the saved info
763 fOriginalInfo
.signature
= fSignatureControl
->Text();
764 fOriginalInfo
.gotFlags
= gotFlags
;
765 fOriginalInfo
.flags
= flags
;
766 fOriginalInfo
.versionInfo
= versionInfo
;
767 fOriginalInfo
.supportedTypes
= supportedTypes
;
768 fOriginalInfo
.iconChanged
= false;
769 fOriginalInfo
.typeIconsChanged
= false;
771 fChangedProperties
= 0;
772 _CheckSaveMenuItem(0);
777 ApplicationTypeWindow::_CheckSaveMenuItem(uint32 flags
)
779 fChangedProperties
= _NeedsSaving(flags
);
780 fSaveMenuItem
->SetEnabled(fChangedProperties
!= 0);
785 operator!=(const version_info
& a
, const version_info
& b
)
787 return a
.major
!= b
.major
|| a
.middle
!= b
.middle
|| a
.minor
!= b
.minor
788 || a
.variety
!= b
.variety
|| a
.internal
!= b
.internal
789 || strcmp(a
.short_info
, b
.short_info
) != 0
790 || strcmp(a
.long_info
, b
.long_info
) != 0;
795 ApplicationTypeWindow::_NeedsSaving(uint32 _flags
) const
797 uint32 flags
= fChangedProperties
;
798 if (_flags
& CHECK_SIGNATUR
) {
799 if (fOriginalInfo
.signature
!= fSignatureControl
->Text())
800 flags
|= CHECK_SIGNATUR
;
802 flags
&= ~CHECK_SIGNATUR
;
805 if (_flags
& CHECK_FLAGS
) {
807 bool gotFlags
= _Flags(appFlags
);
808 if (fOriginalInfo
.gotFlags
!= gotFlags
809 || fOriginalInfo
.flags
!= appFlags
) {
810 flags
|= CHECK_FLAGS
;
812 flags
&= ~CHECK_FLAGS
;
815 if (_flags
& CHECK_VERSION
) {
816 if (fOriginalInfo
.versionInfo
!= _VersionInfo())
817 flags
|= CHECK_VERSION
;
819 flags
&= ~CHECK_VERSION
;
822 if (_flags
& CHECK_ICON
) {
823 if (fOriginalInfo
.iconChanged
)
826 flags
&= ~CHECK_ICON
;
829 if (_flags
& CHECK_TYPES
) {
830 if (!fOriginalInfo
.supportedTypes
.HasSameData(_SupportedTypes()))
831 flags
|= CHECK_TYPES
;
833 flags
&= ~CHECK_TYPES
;
836 if (_flags
& CHECK_TYPE_ICONS
) {
837 if (fOriginalInfo
.typeIconsChanged
)
838 flags
|= CHECK_TYPE_ICONS
;
840 flags
&= ~CHECK_TYPE_ICONS
;
851 ApplicationTypeWindow::_Flags(uint32
& flags
) const
854 if (fFlagsCheckBox
->Value() != B_CONTROL_OFF
) {
855 if (fSingleLaunchButton
->Value() != B_CONTROL_OFF
)
856 flags
|= B_SINGLE_LAUNCH
;
857 else if (fMultipleLaunchButton
->Value() != B_CONTROL_OFF
)
858 flags
|= B_MULTIPLE_LAUNCH
;
859 else if (fExclusiveLaunchButton
->Value() != B_CONTROL_OFF
)
860 flags
|= B_EXCLUSIVE_LAUNCH
;
862 if (fArgsOnlyCheckBox
->Value() != B_CONTROL_OFF
)
863 flags
|= B_ARGV_ONLY
;
864 if (fBackgroundAppCheckBox
->Value() != B_CONTROL_OFF
)
865 flags
|= B_BACKGROUND_APP
;
873 ApplicationTypeWindow::_SupportedTypes() const
875 BMessage supportedTypes
;
876 for (int32 i
= 0; i
< fTypeListView
->CountItems(); i
++) {
877 SupportedTypeItem
* item
= dynamic_cast<SupportedTypeItem
*>(
878 fTypeListView
->ItemAt(i
));
881 supportedTypes
.AddString("types", item
->Type());
883 return supportedTypes
;
888 ApplicationTypeWindow::_VersionInfo() const
890 version_info versionInfo
;
891 versionInfo
.major
= atol(fMajorVersionControl
->Text());
892 versionInfo
.middle
= atol(fMiddleVersionControl
->Text());
893 versionInfo
.minor
= atol(fMinorVersionControl
->Text());
894 versionInfo
.variety
= fVarietyMenu
->IndexOf(fVarietyMenu
->FindMarked());
895 versionInfo
.internal
= atol(fInternalVersionControl
->Text());
896 strlcpy(versionInfo
.short_info
, fShortDescriptionControl
->Text(),
897 sizeof(versionInfo
.short_info
));
898 strlcpy(versionInfo
.long_info
, fLongDescriptionView
->Text(),
899 sizeof(versionInfo
.long_info
));
908 ApplicationTypeWindow::FrameResized(float width
, float height
)
910 // This works around a flaw of BTextView
911 fLongDescriptionView
->SetTextRect(fLongDescriptionView
->Bounds());
916 ApplicationTypeWindow::MessageReceived(BMessage
* message
)
918 switch (message
->what
) {
919 case kMsgToggleAppFlags
:
920 _UpdateAppFlagsEnabled();
921 _CheckSaveMenuItem(CHECK_FLAGS
);
924 case kMsgSignatureChanged
:
925 _CheckSaveMenuItem(CHECK_SIGNATUR
);
928 case kMsgAppFlagsChanged
:
929 _CheckSaveMenuItem(CHECK_FLAGS
);
932 case kMsgIconChanged
:
933 fOriginalInfo
.iconChanged
= true;
934 _CheckSaveMenuItem(CHECK_ICON
);
937 case kMsgTypeIconsChanged
:
938 fOriginalInfo
.typeIconsChanged
= true;
939 _CheckSaveMenuItem(CHECK_TYPE_ICONS
);
942 case kMsgVersionInfoChanged
:
943 _CheckSaveMenuItem(CHECK_VERSION
);
950 case kMsgTypeSelected
:
953 if (message
->FindInt32("index", &index
) == B_OK
) {
954 SupportedTypeItem
* item
955 = (SupportedTypeItem
*)fTypeListView
->ItemAt(index
);
957 fTypeIconView
->SetModificationMessage(NULL
);
958 fTypeIconView
->SetTo(item
!= NULL
? &item
->Icon() : NULL
);
959 fTypeIconView
->SetModificationMessage(
960 new BMessage(kMsgTypeIconsChanged
));
961 fTypeIconView
->SetEnabled(item
!= NULL
);
962 fRemoveTypeButton
->SetEnabled(item
!= NULL
);
964 _CheckSaveMenuItem(CHECK_TYPES
);
971 BWindow
* window
= new TypeListWindow(NULL
,
972 kMsgTypeAdded
, this);
980 if (message
->FindString("type", &type
) != B_OK
)
983 // check if this type already exists
985 SupportedTypeItem
* newItem
= new SupportedTypeItem(type
);
988 for (int32 i
= fTypeListView
->CountItems(); i
-- > 0;) {
989 SupportedTypeItem
* item
= dynamic_cast<SupportedTypeItem
*>(
990 fTypeListView
->ItemAt(i
));
994 int compare
= strcasecmp(item
->Type(), type
);
996 // type does already exist, select it and bail out
999 fTypeListView
->Select(i
);
1006 if (newItem
== NULL
)
1009 fTypeListView
->AddItem(newItem
, insertAt
);
1010 fTypeListView
->Select(insertAt
);
1012 _CheckSaveMenuItem(CHECK_TYPES
);
1016 case kMsgRemoveType
:
1018 int32 index
= fTypeListView
->CurrentSelection();
1022 delete fTypeListView
->RemoveItem(index
);
1023 fTypeIconView
->SetModificationMessage(NULL
);
1024 fTypeIconView
->SetTo(NULL
);
1025 fTypeIconView
->SetModificationMessage(
1026 new BMessage(kMsgTypeIconsChanged
));
1027 fTypeIconView
->SetEnabled(false);
1028 fRemoveTypeButton
->SetEnabled(false);
1030 _CheckSaveMenuItem(CHECK_TYPES
);
1037 if (message
->FindRef("refs", &ref
) != B_OK
)
1040 // TODO: add to supported types
1044 case B_META_MIME_CHANGED
:
1047 if (message
->FindString("be:type", &type
) != B_OK
1048 || message
->FindInt32("be:which", &which
) != B_OK
)
1051 // TODO: update supported types names
1052 // if (which == B_MIME_TYPE_DELETED)
1054 // _CheckSaveMenuItem(...);
1058 BWindow::MessageReceived(message
);
1064 ApplicationTypeWindow::QuitRequested()
1066 if (_NeedsSaving(CHECK_ALL
) != 0) {
1067 BAlert
* alert
= new BAlert(B_TRANSLATE("Save request"),
1068 B_TRANSLATE("Save changes before closing?"),
1069 B_TRANSLATE("Cancel"), B_TRANSLATE("Don't save"),
1070 B_TRANSLATE("Save"), B_WIDTH_AS_USUAL
, B_OFFSET_SPACING
,
1072 alert
->SetShortcut(0, B_ESCAPE
);
1073 alert
->SetShortcut(1, 'd');
1074 alert
->SetShortcut(2, 's');
1076 int32 choice
= alert
->Go();
1088 be_app
->PostMessage(kMsgTypeWindowClosed
);