ApplicationTypeWindow::ApplicationTypeWindow(BPoint position,
	const BEntry& entry)
	:
	BWindow(BRect(0.0f, 0.0f, 250.0f, 340.0f).OffsetBySelf(position),
		B_TRANSLATE("Application type"), B_TITLED_WINDOW,
		B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS |
			B_FRAME_EVENTS | B_AUTO_UPDATE_SIZE_LIMITS),
	fChangedProperties(0)
{
	float padding = be_control_look->DefaultItemSpacing();
	BAlignment labelAlignment = be_control_look->DefaultLabelAlignment();

	BMenuBar* menuBar = new BMenuBar((char*)NULL);
	menuBar->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));

	BMenu* menu = new BMenu(B_TRANSLATE("File"));
	fSaveMenuItem = new BMenuItem(B_TRANSLATE("Save"),
		new BMessage(kMsgSave), 'S');
	fSaveMenuItem->SetEnabled(false);
	menu->AddItem(fSaveMenuItem);
	BMenuItem* item;
	menu->AddItem(item = new BMenuItem(
		B_TRANSLATE("Save into resource file" B_UTF8_ELLIPSIS), NULL));
	item->SetEnabled(false);

	menu->AddSeparatorItem();
	menu->AddItem(new BMenuItem(B_TRANSLATE("Close"),
		new BMessage(B_QUIT_REQUESTED), 'W', B_COMMAND_KEY));
	menuBar->AddItem(menu);

	// Signature

	fSignatureControl = new BTextControl(B_TRANSLATE("Signature:"), NULL,
		new BMessage(kMsgSignatureChanged));
	fSignatureControl->SetModificationMessage(
		new BMessage(kMsgSignatureChanged));

	// filter out invalid characters that can't be part of a MIME type name
	BTextView* textView = fSignatureControl->TextView();
	textView->SetMaxBytes(B_MIME_TYPE_LENGTH);
	const char* disallowedCharacters = "<>@,;:\"()[]?=";
	for (int32 i = 0; disallowedCharacters[i]; i++) {
		textView->DisallowChar(disallowedCharacters[i]);
	}

	// "Application Flags" group

	BBox* flagsBox = new BBox("flagsBox");

	fFlagsCheckBox = new BCheckBox("flags", B_TRANSLATE("Application flags"),
		new BMessage(kMsgToggleAppFlags));
	fFlagsCheckBox->SetValue(B_CONTROL_ON);

	fSingleLaunchButton = new BRadioButton("single",
		B_TRANSLATE("Single launch"), new BMessage(kMsgAppFlagsChanged));

	fMultipleLaunchButton = new BRadioButton("multiple",
		B_TRANSLATE("Multiple launch"), new BMessage(kMsgAppFlagsChanged));

	fExclusiveLaunchButton = new BRadioButton("exclusive",
		B_TRANSLATE("Exclusive launch"), new BMessage(kMsgAppFlagsChanged));

	fArgsOnlyCheckBox = new BCheckBox("args only", B_TRANSLATE("Args only"),
		new BMessage(kMsgAppFlagsChanged));

	fBackgroundAppCheckBox = new BCheckBox("background",
		B_TRANSLATE("Background app"), new BMessage(kMsgAppFlagsChanged));

	flagsBox->AddChild(BGridLayoutBuilder()
		.Add(fSingleLaunchButton, 0, 0).Add(fArgsOnlyCheckBox, 1, 0)
		.Add(fMultipleLaunchButton, 0, 1).Add(fBackgroundAppCheckBox, 1, 1)
		.Add(fExclusiveLaunchButton, 0, 2)
		.SetInsets(padding, padding, padding, padding));
	flagsBox->SetLabel(fFlagsCheckBox);

	// "Icon" group

	BBox* iconBox = new BBox("IconBox");
	iconBox->SetLabel(B_TRANSLATE("Icon"));
	fIconView = new IconView("icon");
	fIconView->SetModificationMessage(new BMessage(kMsgIconChanged));
	iconBox->AddChild(BGroupLayoutBuilder(B_HORIZONTAL)
		.Add(fIconView)
		.SetInsets(padding, padding, padding, padding));

	// "Supported Types" group

	BBox* typeBox = new BBox("typesBox");
	typeBox->SetLabel(B_TRANSLATE("Supported types"));

	fTypeListView = new SupportedTypeListView("Suppported Types",
		B_SINGLE_SELECTION_LIST);
	fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected));

	BScrollView* scrollView = new BScrollView("type scrollview", fTypeListView,
		B_FRAME_EVENTS | B_WILL_DRAW, false, true);

	fAddTypeButton = new BButton("add type",
		B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddType));

	fRemoveTypeButton = new BButton("remove type", B_TRANSLATE("Remove"),
		new BMessage(kMsgRemoveType));

	fTypeIconView = new IconView("type icon");
	BView* iconHolder = BGroupLayoutBuilder(B_HORIZONTAL).Add(fTypeIconView);
	fTypeIconView->SetModificationMessage(new BMessage(kMsgTypeIconsChanged));

	typeBox->AddChild(BGridLayoutBuilder(padding, padding)
		.Add(scrollView, 0, 0, 1, 4)
		.Add(fAddTypeButton, 1, 0, 1, 2)
		.Add(fRemoveTypeButton, 1, 2, 1, 2)
		.Add(iconHolder, 2, 1, 1, 2)
		.SetInsets(padding, padding, padding, padding)
		.SetColumnWeight(0, 3)
		.SetColumnWeight(1, 2)
		.SetColumnWeight(2, 1));
	iconHolder->SetExplicitAlignment(
		BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE));

	// "Version Info" group

	BBox* versionBox = new BBox("versionBox");
	versionBox->SetLabel(B_TRANSLATE("Version info"));

	fMajorVersionControl = new BTextControl(B_TRANSLATE("Version:"),
		NULL, NULL);
	_MakeNumberTextControl(fMajorVersionControl);

	fMiddleVersionControl = new BTextControl(".", NULL, NULL);
	_MakeNumberTextControl(fMiddleVersionControl);

	fMinorVersionControl = new BTextControl(".", NULL, NULL);
	_MakeNumberTextControl(fMinorVersionControl);

	fVarietyMenu = new BPopUpMenu("variety", true, true);
	fVarietyMenu->AddItem(new BMenuItem(B_TRANSLATE("Development"), NULL));
	fVarietyMenu->AddItem(new BMenuItem(B_TRANSLATE("Alpha"), NULL));
	fVarietyMenu->AddItem(new BMenuItem(B_TRANSLATE("Beta"), NULL));
	fVarietyMenu->AddItem(new BMenuItem(B_TRANSLATE("Gamma"), NULL));
	item = new BMenuItem(B_TRANSLATE("Golden master"), NULL);
	fVarietyMenu->AddItem(item);
	item->SetMarked(true);
	fVarietyMenu->AddItem(new BMenuItem(B_TRANSLATE("Final"), NULL));

	BMenuField* varietyField = new BMenuField("", fVarietyMenu);
	fInternalVersionControl = new BTextControl("/", NULL, NULL);
	fShortDescriptionControl =
		new BTextControl(B_TRANSLATE("Short description:"), NULL, NULL);

	// TODO: workaround for a GCC 4.1.0 bug? Or is that really what the standard says?
	version_info versionInfo;
	fShortDescriptionControl->TextView()->SetMaxBytes(
		sizeof(versionInfo.short_info));

	BStringView* longLabel = new BStringView(NULL,
		B_TRANSLATE("Long description:"));
	longLabel->SetExplicitAlignment(labelAlignment);
	fLongDescriptionView = new TabFilteringTextView("long desc");
	fLongDescriptionView->SetMaxBytes(sizeof(versionInfo.long_info));

	scrollView = new BScrollView("desc scrollview", fLongDescriptionView,
		B_FRAME_EVENTS | B_WILL_DRAW, false, true);

	// TODO: remove workaround (bug #5678)
	BSize minScrollSize = scrollView->ScrollBar(B_VERTICAL)->MinSize();
	minScrollSize.width += fLongDescriptionView->MinSize().width;
	scrollView->SetExplicitMinSize(minScrollSize);

	versionBox->AddChild(BGridLayoutBuilder(padding / 2, padding)
		.Add(fMajorVersionControl->CreateLabelLayoutItem(), 0, 0)
		.Add(fMajorVersionControl->CreateTextViewLayoutItem(), 1, 0)
		.Add(fMiddleVersionControl, 2, 0, 2)
		.Add(fMinorVersionControl, 4, 0, 2)
		.Add(varietyField, 6, 0, 3)
		.Add(fInternalVersionControl, 9, 0, 2)
		.Add(fShortDescriptionControl->CreateLabelLayoutItem(), 0, 1)
		.Add(fShortDescriptionControl->CreateTextViewLayoutItem(), 1, 1, 10)
		.Add(longLabel, 0, 2)
		.Add(scrollView, 1, 2, 10, 3)
		.SetInsets(padding, padding, padding, padding)
		.SetRowWeight(3, 3));

	// put it all together
	SetLayout(new BGroupLayout(B_VERTICAL));
	AddChild(menuBar);
	AddChild(BGroupLayoutBuilder(B_VERTICAL, padding)
		.Add(fSignatureControl)
		.Add(BGroupLayoutBuilder(B_HORIZONTAL, padding)
			.Add(flagsBox, 3)
			.Add(iconBox, 1))
		.Add(typeBox)
		.Add(versionBox)
		.SetInsets(padding, padding, padding, padding));

	SetKeyMenuBar(menuBar);

	fSignatureControl->MakeFocus(true);
	BMimeType::StartWatching(this);
	_SetTo(entry);
}
FileTypesWindow::FileTypesWindow(const BMessage& settings)
	:
	BWindow(_Frame(settings), B_TRANSLATE_SYSTEM_NAME("FileTypes"),
		B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS
		| B_AUTO_UPDATE_SIZE_LIMITS),
	fNewTypeWindow(NULL)
{
	bool showIcons;
	bool showRule;
	if (settings.FindBool("show_icons", &showIcons) != B_OK)
		showIcons = true;
	if (settings.FindBool("show_rule", &showRule) != B_OK)
		showRule = false;

	float padding = be_control_look->DefaultItemSpacing();
	BAlignment labelAlignment = be_control_look->DefaultLabelAlignment();
	BAlignment fullAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);

	// add the menu
	BMenuBar* menuBar = new BMenuBar("");

	BMenu* menu = new BMenu(B_TRANSLATE("File"));
	BMenuItem* item = new BMenuItem(
		B_TRANSLATE("New resource file" B_UTF8_ELLIPSIS), NULL, 'N',
		B_COMMAND_KEY);
	item->SetEnabled(false);
	menu->AddItem(item);

	BMenu* recentsMenu = BRecentFilesList::NewFileListMenu(
		B_TRANSLATE("Open" B_UTF8_ELLIPSIS), NULL, NULL,
		be_app, 10, false, NULL, kSignature);
	item = new BMenuItem(recentsMenu, new BMessage(kMsgOpenFilePanel));
	item->SetShortcut('O', B_COMMAND_KEY);
	menu->AddItem(item);

	menu->AddItem(new BMenuItem(
		B_TRANSLATE("Application types" B_UTF8_ELLIPSIS),
		new BMessage(kMsgOpenApplicationTypesWindow)));
	menu->AddSeparatorItem();

	menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
		new BMessage(B_QUIT_REQUESTED), 'Q', B_COMMAND_KEY));
	menu->SetTargetForItems(be_app);
	menuBar->AddItem(menu);

	menu = new BMenu(B_TRANSLATE("Settings"));
	item = new BMenuItem(B_TRANSLATE("Show icons in list"),
		new BMessage(kMsgToggleIcons));
	item->SetMarked(showIcons);
	item->SetTarget(this);
	menu->AddItem(item);

	item = new BMenuItem(B_TRANSLATE("Show recognition rule"),
		new BMessage(kMsgToggleRule));
	item->SetMarked(showRule);
	item->SetTarget(this);
	menu->AddItem(item);
	menuBar->AddItem(menu);
	menuBar->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));

	// MIME Types list
	BButton* addTypeButton = new BButton("add",
		B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddType));

	fRemoveTypeButton = new BButton("remove", B_TRANSLATE("Remove"),
		new BMessage(kMsgRemoveType) );

	fTypeListView = new MimeTypeListView("typeview", NULL, showIcons, false);
	fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected));
	fTypeListView->SetExplicitMinSize(BSize(200, B_SIZE_UNSET));

	BScrollView* typeListScrollView = new BScrollView("scrollview",
		fTypeListView, B_FRAME_EVENTS | B_WILL_DRAW, false, true);

	// "Icon" group

	fIconView = new TypeIconView("icon");
	fIconBox = new BBox("Icon BBox");
	fIconBox->SetLabel(B_TRANSLATE("Icon"));
	BLayoutBuilder::Group<>(fIconBox, B_VERTICAL, padding)
		.SetInsets(padding)
		.AddGlue(1)
		.Add(fIconView, 3)
		.AddGlue(1);

	// "File Recognition" group

	fRecognitionBox = new BBox("Recognition Box");
	fRecognitionBox->SetLabel(B_TRANSLATE("File recognition"));
	fRecognitionBox->SetExplicitAlignment(fullAlignment);

	fExtensionLabel = new StringView(B_TRANSLATE("Extensions:"), NULL);
	fExtensionLabel->LabelView()->SetExplicitAlignment(labelAlignment);

	fAddExtensionButton = new BButton("add ext",
		B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddExtension));
	fAddExtensionButton->SetExplicitMaxSize(
		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));

	fRemoveExtensionButton = new BButton("remove ext", B_TRANSLATE("Remove"),
		new BMessage(kMsgRemoveExtension));

	fExtensionListView = new ExtensionListView("listview ext",
		B_SINGLE_SELECTION_LIST);
	fExtensionListView->SetSelectionMessage(
		new BMessage(kMsgExtensionSelected));
	fExtensionListView->SetInvocationMessage(
		new BMessage(kMsgExtensionInvoked));

	BScrollView* scrollView = new BScrollView("scrollview ext",
		fExtensionListView, B_FRAME_EVENTS | B_WILL_DRAW, false, true);

	fRuleControl = new BTextControl("rule", B_TRANSLATE("Rule:"), "",
		new BMessage(kMsgRuleEntered));
	fRuleControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
	fRuleControl->Hide();

	BLayoutBuilder::Grid<>(fRecognitionBox, padding, padding / 2)
		.SetInsets(padding, padding * 2, padding, padding)
		.Add(fExtensionLabel->LabelView(), 0, 0)
		.Add(scrollView, 0, 1, 2, 2)
		.Add(fAddExtensionButton, 2, 1)
		.Add(fRemoveExtensionButton, 2, 2)
		.Add(fRuleControl, 0, 3, 3, 1);

	// "Description" group

	fDescriptionBox = new BBox("description BBox");
	fDescriptionBox->SetLabel(B_TRANSLATE("Description"));
	fDescriptionBox->SetExplicitAlignment(fullAlignment);

	fInternalNameView = new StringView(B_TRANSLATE("Internal name:"), NULL);
	fInternalNameView->SetEnabled(false);
	fTypeNameControl = new BTextControl("type", B_TRANSLATE("Type name:"), "",
		new BMessage(kMsgTypeEntered));
	fDescriptionControl = new BTextControl("description",
		B_TRANSLATE("Description:"), "", new BMessage(kMsgDescriptionEntered));

	BLayoutBuilder::Grid<>(fDescriptionBox, padding / 2, padding / 2)
		.SetInsets(padding, padding * 2, padding, padding)
		.Add(fInternalNameView->LabelView(), 0, 0)
		.Add(fInternalNameView->TextView(), 1, 0)
		.Add(fTypeNameControl->CreateLabelLayoutItem(), 0, 1)
		.Add(fTypeNameControl->CreateTextViewLayoutItem(), 1, 1, 2)
		.Add(fDescriptionControl->CreateLabelLayoutItem(), 0, 2)
		.Add(fDescriptionControl->CreateTextViewLayoutItem(), 1, 2, 2);

	// "Preferred Application" group

	fPreferredBox = new BBox("preferred BBox");
	fPreferredBox->SetLabel(B_TRANSLATE("Preferred application"));

	menu = new BPopUpMenu("preferred");
	menu->AddItem(item = new BMenuItem(B_TRANSLATE("None"),
		new BMessage(kMsgPreferredAppChosen)));
	item->SetMarked(true);
	fPreferredField = new BMenuField("preferred", (char*)NULL, menu);

	fSelectButton = new BButton("select",
		B_TRANSLATE("Select" B_UTF8_ELLIPSIS),
		new BMessage(kMsgSelectPreferredApp));

	fSameAsButton = new BButton("same as",
		B_TRANSLATE("Same as" B_UTF8_ELLIPSIS),
		new BMessage(kMsgSamePreferredAppAs));

	BLayoutBuilder::Group<>(fPreferredBox, B_HORIZONTAL, padding)
		.SetInsets(padding, padding * 2, padding, padding)
		.Add(fPreferredField)
		.Add(fSelectButton)
		.Add(fSameAsButton);

	// "Extra Attributes" group

	fAttributeBox = new BBox("Attribute Box");
	fAttributeBox->SetLabel(B_TRANSLATE("Extra attributes"));

	fAddAttributeButton = new BButton("add attr",
		B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddAttribute));
	fAddAttributeButton->SetExplicitMaxSize(
		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));

	fRemoveAttributeButton = new BButton("remove attr", B_TRANSLATE("Remove"),
		new BMessage(kMsgRemoveAttribute));
	fRemoveAttributeButton->SetExplicitMaxSize(
		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));

	fMoveUpAttributeButton = new BButton("move up attr", B_TRANSLATE("Move up"),
		new BMessage(kMsgMoveUpAttribute));
	fMoveUpAttributeButton->SetExplicitMaxSize(
		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
	fMoveDownAttributeButton = new BButton("move down attr",
		B_TRANSLATE("Move down"), new BMessage(kMsgMoveDownAttribute));
	fMoveDownAttributeButton->SetExplicitMaxSize(
		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));

	fAttributeListView = new AttributeListView("listview attr");
	fAttributeListView->SetSelectionMessage(
		new BMessage(kMsgAttributeSelected));
	fAttributeListView->SetInvocationMessage(
		new BMessage(kMsgAttributeInvoked));

	BScrollView* attributesScroller = new BScrollView("scrollview attr",
		fAttributeListView, B_FRAME_EVENTS | B_WILL_DRAW, false, true);

	BLayoutBuilder::Group<>(fAttributeBox, B_HORIZONTAL, padding)
		.SetInsets(padding, padding * 2, padding, padding)
		.Add(attributesScroller, 1.0f)
		.AddGroup(B_VERTICAL, padding / 2, 0.0f)
			.SetInsets(0)
			.Add(fAddAttributeButton)
			.Add(fRemoveAttributeButton)
			.AddStrut(padding)
			.Add(fMoveUpAttributeButton)
			.Add(fMoveDownAttributeButton)
			.AddGlue();

	fMainSplitView = new BSplitView(B_HORIZONTAL, floorf(padding / 2));

	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
		.SetInsets(0)
		.Add(menuBar)
		.AddGroup(B_HORIZONTAL, 0)
			.SetInsets(padding, padding, padding, padding)
			.AddSplit(fMainSplitView)
				.AddGroup(B_VERTICAL, padding)
					.Add(typeListScrollView)
					.AddGroup(B_HORIZONTAL, padding)
						.Add(addTypeButton)
						.Add(fRemoveTypeButton)
						.AddGlue()
						.End()
					.End()
				// Right side
				.AddGroup(B_VERTICAL, padding)
					.AddGroup(B_HORIZONTAL, padding)
						.Add(fIconBox, 1)
						.Add(fRecognitionBox, 3)
						.End()
					.Add(fDescriptionBox)
					.Add(fPreferredBox)
					.Add(fAttributeBox, 5);

	_SetType(NULL);
	_ShowSnifferRule(showRule);

	float leftWeight;
	float rightWeight;
	if (settings.FindFloat("left_split_weight", &leftWeight) != B_OK
		|| settings.FindFloat("right_split_weight", &rightWeight) != B_OK) {
		leftWeight = 0.2;
		rightWeight = 1.0 - leftWeight;
	}
	fMainSplitView->SetItemWeight(0, leftWeight, false);
	fMainSplitView->SetItemWeight(1, rightWeight, true);

	BMimeType::StartWatching(this);
}