xref: /haiku/src/preferences/filetypes/NewFileTypeWindow.cpp (revision 125183f9e5c136781f71c879faaeab43fdc3ea7b)
1 /*
2  * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "FileTypes.h"
8 #include "FileTypesWindow.h"
9 #include "NewFileTypeWindow.h"
10 
11 #include <Button.h>
12 #include <Catalog.h>
13 #include <ControlLook.h>
14 #include <GroupLayout.h>
15 #include <GridLayoutBuilder.h>
16 #include <Locale.h>
17 #include <MenuBar.h>
18 #include <MenuField.h>
19 #include <MenuItem.h>
20 #include <Mime.h>
21 #include <PopUpMenu.h>
22 #include <SpaceLayoutItem.h>
23 #include <String.h>
24 #include <StringView.h>
25 #include <TextControl.h>
26 
27 #include <string.h>
28 
29 
30 #undef TR_CONTEXT
31 #define TR_CONTEXT "New File Type Window"
32 
33 
34 const uint32 kMsgSupertypeChosen = 'sptc';
35 const uint32 kMsgNewSupertypeChosen = 'nstc';
36 
37 const uint32 kMsgNameUpdated = 'nmup';
38 
39 const uint32 kMsgAddType = 'atyp';
40 
41 
42 NewFileTypeWindow::NewFileTypeWindow(FileTypesWindow* target,
43 	const char* currentType)
44 	:
45 	BWindow(BRect(100, 100, 350, 200), B_TRANSLATE("New file type"),
46 		B_MODAL_WINDOW, B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE
47 			| B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS ),
48 	fTarget(target)
49 {
50 	fSupertypesMenu = new BPopUpMenu("supertypes");
51 	BMenuItem* item;
52 	BMessage types;
53 	if (BMimeType::GetInstalledSupertypes(&types) == B_OK) {
54 		const char* type;
55 		int32 i = 0;
56 		while (types.FindString("super_types", i++, &type) == B_OK) {
57 			fSupertypesMenu->AddItem(item = new BMenuItem(type,
58 				new BMessage(kMsgSupertypeChosen)));
59 
60 			// select super type close to the current type
61 			if (currentType != NULL) {
62 				if (!strncmp(type, currentType, strlen(type)))
63 					item->SetMarked(true);
64 			} else if (i == 1)
65 				item->SetMarked(true);
66 		}
67 
68 		if (i > 1)
69 			fSupertypesMenu->AddSeparatorItem();
70 	}
71 
72 	fSupertypesMenu->AddItem(new BMenuItem(B_TRANSLATE("Add new group"),
73 		new BMessage(kMsgNewSupertypeChosen)));
74 	BMenuField* typesMenuField = new BMenuField(NULL, fSupertypesMenu);
75 
76 	BStringView* typesMenuLabel = new BStringView(NULL, B_TRANSLATE("Group:"));
77 		// Create a separate label view, otherwise things don't line up right
78 	typesMenuLabel->SetAlignment(B_ALIGN_LEFT);
79 	typesMenuLabel->SetExplicitAlignment(
80 		BAlignment(B_ALIGN_LEFT, B_ALIGN_USE_FULL_HEIGHT));
81 
82 	fNameControl = new BTextControl(B_TRANSLATE("Internal name:"), "", NULL);
83 	fNameControl->SetModificationMessage(new BMessage(kMsgNameUpdated));
84 
85 	// filter out invalid characters that can't be part of a MIME type name
86 	BTextView* nameControlTextView = fNameControl->TextView();
87 	const char* disallowedCharacters = "/<>@,;:\"()[]?=";
88 	for (int32 i = 0; disallowedCharacters[i]; i++) {
89 		nameControlTextView->DisallowChar(disallowedCharacters[i]);
90 	}
91 
92 	fAddButton = new BButton(B_TRANSLATE("Add type"),
93 		new BMessage(kMsgAddType));
94 
95 	float padding = 3.0f;
96 	// if (be_control_look)
97 		// padding = be_control_look->DefaultItemSpacing();
98 
99 	SetLayout(new BGroupLayout(B_VERTICAL));
100 	AddChild(BGridLayoutBuilder(padding, padding)
101 		.SetInsets(padding, padding, padding, padding)
102 		.Add(typesMenuLabel, 0, 0)
103 		.Add(typesMenuField, 1, 0, 2)
104 		.Add(fNameControl->CreateLabelLayoutItem(), 0, 1)
105 		.Add(fNameControl->CreateTextViewLayoutItem(), 1, 1, 2)
106 		.Add(BSpaceLayoutItem::CreateGlue(), 0, 2)
107 		.Add(new BButton(B_TRANSLATE("Cancel"),
108 			new BMessage(B_QUIT_REQUESTED)), 1, 2)
109 		.Add(fAddButton, 2, 2)
110 		.SetColumnWeight(0, 3)
111 		);
112 
113 	BAlignment fullSize = BAlignment(B_ALIGN_USE_FULL_WIDTH,
114 		B_ALIGN_USE_FULL_HEIGHT);
115 	typesMenuField->MenuBar()->SetExplicitAlignment(fullSize);
116 	fNameControl->TextView()->SetExplicitAlignment(fullSize);
117 
118 	BLayoutItem* nameControlLabelItem = fNameControl->CreateLabelLayoutItem();
119 	nameControlLabelItem->SetExplicitMinSize(nameControlLabelItem->MinSize());
120 		// stops fNameControl's label from truncating under certain conditions
121 
122 	fAddButton->MakeDefault(true);
123 	fNameControl->MakeFocus(true);
124 
125 	target->PlaceSubWindow(this);
126 }
127 
128 
129 NewFileTypeWindow::~NewFileTypeWindow()
130 {
131 }
132 
133 
134 void
135 NewFileTypeWindow::MessageReceived(BMessage* message)
136 {
137 	switch (message->what) {
138 		case kMsgSupertypeChosen:
139 			fAddButton->SetLabel(B_TRANSLATE("Add type"));
140 			fNameControl->SetLabel(B_TRANSLATE("Internal name:"));
141 			fNameControl->MakeFocus(true);
142 			InvalidateLayout(true);
143 			break;
144 
145 		case kMsgNewSupertypeChosen:
146 			fAddButton->SetLabel(B_TRANSLATE("Add group"));
147 			fNameControl->SetLabel(B_TRANSLATE("Group name:"));
148 			fNameControl->MakeFocus(true);
149 			InvalidateLayout(true);
150 			break;
151 
152 		case kMsgNameUpdated:
153 		{
154 			bool empty = fNameControl->Text() == NULL
155 				|| fNameControl->Text()[0] == '\0';
156 
157 			if (fAddButton->IsEnabled() == empty)
158 				fAddButton->SetEnabled(!empty);
159 			break;
160 		}
161 
162 		case kMsgAddType:
163 		{
164 			BMenuItem* item = fSupertypesMenu->FindMarked();
165 			if (item != NULL) {
166 				BString type;
167 				if (fSupertypesMenu->IndexOf(item)
168 						!= fSupertypesMenu->CountItems() - 1) {
169 					// add normal type
170 					type = item->Label();
171 					type.Append("/");
172 				}
173 
174 				type.Append(fNameControl->Text());
175 
176 				BMimeType mimeType(type.String());
177 				if (mimeType.IsInstalled()) {
178 					error_alert(B_TRANSLATE("This file type already exists"));
179 					break;
180 				}
181 
182 				status_t status = mimeType.Install();
183 				if (status != B_OK)
184 					error_alert(B_TRANSLATE("Could not install file type"),
185 						status);
186 				else {
187 					BMessage update(kMsgSelectNewType);
188 					update.AddString("type", type.String());
189 
190 					fTarget.SendMessage(&update);
191 				}
192 			}
193 			PostMessage(B_QUIT_REQUESTED);
194 			break;
195 		}
196 
197 		default:
198 			BWindow::MessageReceived(message);
199 			break;
200 	}
201 }
202 
203 
204 bool
205 NewFileTypeWindow::QuitRequested()
206 {
207 	fTarget.SendMessage(kMsgNewTypeWindowClosed);
208 	return true;
209 }
210 
211 
212