xref: /haiku/src/preferences/filetypes/ApplicationTypeWindow.cpp (revision abe0393b82740ff6ae905a42694bfa88181cb979)
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 "ApplicationTypeWindow.h"
8 #include "FileTypes.h"
9 #include "IconView.h"
10 #include "PreferredAppMenu.h"
11 #include "StringView.h"
12 #include "TypeListWindow.h"
13 
14 #include <Application.h>
15 #include <Bitmap.h>
16 #include <Box.h>
17 #include <Button.h>
18 #include <CheckBox.h>
19 #include <File.h>
20 #include <ListView.h>
21 #include <MenuBar.h>
22 #include <MenuField.h>
23 #include <MenuItem.h>
24 #include <Mime.h>
25 #include <NodeInfo.h>
26 #include <PopUpMenu.h>
27 #include <RadioButton.h>
28 #include <ScrollView.h>
29 #include <TextControl.h>
30 
31 #include <stdio.h>
32 
33 
34 const uint32 kMsgAddType = 'adtp';
35 const uint32 kMsgRemoveType = 'rmtp';
36 
37 
38 ApplicationTypeWindow::ApplicationTypeWindow(BPoint position, const BEntry& entry)
39 	: BWindow(BRect(0.0f, 0.0f, 250.0f, 340.0f).OffsetBySelf(position),
40 		"Application Type", B_TITLED_WINDOW,
41 		B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
42 {
43 	// add the menu
44 
45 	BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), NULL);
46 	AddChild(menuBar);
47 
48 	BMenu* menu = new BMenu("File");
49 	menu->AddItem(new BMenuItem("Save", NULL, 'S', B_COMMAND_KEY));
50 	menu->AddItem(new BMenuItem("Save Into Resource File" B_UTF8_ELLIPSIS,
51 		NULL));
52 
53 	menu->AddSeparatorItem();
54 	menu->AddItem(new BMenuItem("Close", new BMessage(B_QUIT_REQUESTED),
55 		'W', B_COMMAND_KEY));
56 	menuBar->AddItem(menu);
57 
58 	// Top view and signature
59 
60 	BRect rect = Bounds();
61 	rect.top = menuBar->Bounds().Height() + 1.0f;
62 	BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
63 	topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
64 	AddChild(topView);
65 
66 	rect = topView->Bounds().InsetByCopy(8.0f, 8.0f);
67 	fSignatureControl = new BTextControl(rect, "signature", "Signature:", NULL,
68 		NULL, B_FOLLOW_LEFT_RIGHT);
69 	fSignatureControl->SetDivider(fSignatureControl->StringWidth(
70 		fSignatureControl->Label()) + 4.0f);
71 	float width, height;
72 	fSignatureControl->GetPreferredSize(&width, &height);
73 	fSignatureControl->ResizeTo(rect.Width(), height);
74 	topView->AddChild(fSignatureControl);
75 
76 	// filter out invalid characters that can't be part of a MIME type name
77 	BTextView* textView = fSignatureControl->TextView();
78 	const char* disallowedCharacters = "/<>@,;:\"()[]?=";
79 	for (int32 i = 0; disallowedCharacters[i]; i++) {
80 		textView->DisallowChar(disallowedCharacters[i]);
81 	}
82 
83 	// "Application Flags" group
84 
85 	BFont font(be_bold_font);
86 	font_height fontHeight;
87 	font.GetHeight(&fontHeight);
88 
89 	width = font.StringWidth("Icon") + 16.0f;
90 	if (width < B_LARGE_ICON + 16.0f)
91 		width = B_LARGE_ICON + 16.0f;
92 
93 	rect.top = fSignatureControl->Frame().bottom + 4.0f;
94 	rect.bottom = rect.top + 100.0f;
95 	rect.right -= width + 8.0f;
96 	BBox* box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT);
97 	topView->AddChild(box);
98 
99 	fFlagsCheckBox = new BCheckBox(rect, "flags", "Application Flags",
100 		NULL); //new BMessage(kMsgFlagChanged));
101 	fFlagsCheckBox->SetValue(B_CONTROL_ON);
102 	fFlagsCheckBox->ResizeToPreferred();
103 	box->SetLabel(fFlagsCheckBox);
104 
105 	rect.top = fFlagsCheckBox->Bounds().Height() + 4.0f;
106 	fSingleLaunchButton = new BRadioButton(rect, "single", "Single Launch", NULL);
107 	fSingleLaunchButton->ResizeToPreferred();
108 	box->AddChild(fSingleLaunchButton);
109 
110 	rect.OffsetBy(0.0f, fSingleLaunchButton->Bounds().Height() + 0.0f);
111 	fMultipleLaunchButton = new BRadioButton(rect, "multiple", "Multiple Launch", NULL);
112 	fMultipleLaunchButton->ResizeToPreferred();
113 	box->AddChild(fMultipleLaunchButton);
114 
115 	rect.OffsetBy(0.0f, fSingleLaunchButton->Bounds().Height() + 0.0f);
116 	fExclusiveLaunchButton = new BRadioButton(rect, "exclusive", "Exclusive Launch", NULL);
117 	fExclusiveLaunchButton->ResizeToPreferred();
118 	box->AddChild(fExclusiveLaunchButton);
119 
120 	rect.top = fSingleLaunchButton->Frame().top;
121 	rect.left = fExclusiveLaunchButton->Frame().right + 4.0f;
122 	fArgsOnlyCheckBox = new BCheckBox(rect, "args only", "Args Only", NULL);
123 	fArgsOnlyCheckBox->ResizeToPreferred();
124 	box->AddChild(fArgsOnlyCheckBox);
125 
126 	rect.top += fArgsOnlyCheckBox->Bounds().Height();
127 	fBackgroundAppCheckBox = new BCheckBox(rect, "background", "Background App", NULL);
128 	fBackgroundAppCheckBox->ResizeToPreferred();
129 	box->AddChild(fBackgroundAppCheckBox);
130 
131 	box->ResizeTo(box->Bounds().Width(), fExclusiveLaunchButton->Frame().bottom + 8.0f);
132 
133 	// "Icon" group
134 
135 	rect = box->Frame();
136 #ifdef __HAIKU__
137 	rect.top += box->TopBorderOffset();
138 #endif
139 	rect.left = rect.right + 8.0f;
140 	rect.right += width + 8.0f;
141 	float iconBoxWidth = rect.Width();
142 	box = new BBox(rect, NULL, B_FOLLOW_RIGHT | B_FOLLOW_TOP);
143 	box->SetLabel("Icon");
144 #ifdef __HAIKU__
145 	box->MoveBy(0.0f, -box->TopBorderOffset());
146 	box->ResizeBy(0.0f, box->TopBorderOffset());
147 #endif
148 	topView->AddChild(box);
149 
150 	rect = BRect(8.0f, 0.0f, 7.0f + B_LARGE_ICON, B_LARGE_ICON - 1.0f);
151 #ifdef __HAIKU__
152 	rect.OffsetBy(0.0f, (box->Bounds().Height() + box->TopBorderOffset()
153 		- rect.Height()) / 2.0f);
154 #else
155 	rect.OffsetBy(0.0f, (box->Bounds().Height() - rect.Height()) / 2.0f);
156 #endif
157 	if (rect.top < fontHeight.ascent + fontHeight.descent + 4.0f)
158 		rect.top = fontHeight.ascent + fontHeight.descent + 4.0f;
159 	fIconView = new IconView(rect, "icon");
160 	box->AddChild(fIconView);
161 
162 	// "Supported Types" group
163 
164 	rect.top = box->Frame().bottom + 8.0f;
165 	rect.bottom = rect.top + box->Bounds().Height();
166 	rect.left = 8.0f;
167 	rect.right = Bounds().Width() - 8.0f;
168 	box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT);
169 	box->SetLabel("Supported Types");
170 	topView->AddChild(box);
171 
172 	rect = box->Bounds().InsetByCopy(8.0f, 6.0f);
173 	rect.top += ceilf(fontHeight.ascent);
174 	fAddTypeButton = new BButton(rect, "add type", "Add" B_UTF8_ELLIPSIS,
175 		new BMessage(kMsgAddType), B_FOLLOW_RIGHT);
176 	fAddTypeButton->ResizeToPreferred();
177 	fAddTypeButton->MoveBy(rect.right - fAddTypeButton->Bounds().Width()
178 		- B_LARGE_ICON - 16.0f, 0.0f);
179 	box->AddChild(fAddTypeButton);
180 
181 	rect = fAddTypeButton->Frame();
182 	rect.OffsetBy(0, rect.Height() + 4.0f);
183 	fRemoveTypeButton = new BButton(rect, "remove type", "Remove",
184 		new BMessage(kMsgRemoveType), B_FOLLOW_RIGHT);
185 	box->AddChild(fRemoveTypeButton);
186 
187 	rect.right = rect.left - 10.0f - B_V_SCROLL_BAR_WIDTH;
188 	rect.left = 10.0f;
189 	rect.top = 8.0f + ceilf(fontHeight.ascent);
190 	rect.bottom -= 2.0f;
191 		// take scrollview border into account
192 	fTypeListView = new BListView(rect, "type listview",
193 		B_SINGLE_SELECTION_LIST, B_FOLLOW_LEFT_RIGHT);
194 //	fTypeListView->SetSelectionMessage(new BMessage(kMsgExtensionSelected));
195 //	fTypeListView->SetInvocationMessage(new BMessage(kMsgExtensionInvoked));
196 
197 	BScrollView* scrollView = new BScrollView("type scrollview", fTypeListView,
198 		B_FOLLOW_LEFT_RIGHT, B_FRAME_EVENTS | B_WILL_DRAW, false, true);
199 	box->AddChild(scrollView);
200 
201 	box->ResizeTo(box->Bounds().Width(), fRemoveTypeButton->Frame().bottom + 8.0f);
202 
203 	rect.left = fRemoveTypeButton->Frame().right + 8.0f;
204 #ifdef __HAIKU__
205 	rect.top = (box->Bounds().Height() + box->TopBorderOffset() - B_LARGE_ICON) / 2.0f;
206 #else
207 	rect.top = (box->Bounds().Height() - B_LARGE_ICON) / 2.0f;
208 #endif
209 	rect.right = rect.left + B_LARGE_ICON - 1.0f;
210 	rect.bottom = rect.top + B_LARGE_ICON - 1.0f;
211 	fTypeIconView = new IconView(rect, "type icon", B_FOLLOW_RIGHT | B_FOLLOW_TOP);
212 	box->AddChild(fTypeIconView);
213 
214 	// "Version Info" group
215 
216 	rect.top = box->Frame().bottom + 8.0f;
217 	rect.bottom = rect.top + box->Bounds().Height();
218 	rect.left = 8.0f;
219 	rect.right = Bounds().Width() - 8.0f;
220 	box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT);
221 		// the resizing mode will later be set to B_FOLLOW_ALL
222 	box->SetLabel("Version Info");
223 	topView->AddChild(box);
224 
225 	BMenuField* menuField;
226 	BPopUpMenu *popUpMenu;
227 	BMenuItem* item;
228 #if 0
229 	popUpMenu = new BPopUpMenu("version info", true, true);
230 	item = new BMenuItem("Version Info", NULL);
231 	item->SetMarked(true);
232 	popUpMenu->AddItem(item);
233 	item = new BMenuItem("System Version Info", NULL);
234 	popUpMenu->AddItem(item);
235 
236 	menuField = new BMenuField(BRect(0, 0, 100, 15),
237 		"version kind", NULL, popUpMenu, true);
238 	menuField->ResizeToPreferred();
239 	box->SetLabel(menuField);
240 #endif
241 
242 	rect.top = 4.0f + ceilf(fontHeight.ascent + fontHeight.descent);
243 	fMajorVersionControl = new BTextControl(rect, "major", "Version:", NULL,
244 		NULL);
245 	fMajorVersionControl->SetDivider(fMajorVersionControl->StringWidth(
246 		fMajorVersionControl->Label()) + 4.0f);
247 	fMajorVersionControl->GetPreferredSize(&width, &height);
248 	width = 12.0f + fMajorVersionControl->StringWidth("99");
249 	fMajorVersionControl->ResizeTo(fMajorVersionControl->Divider() + width, height);
250 	box->AddChild(fMajorVersionControl);
251 
252 	rect.left = fMajorVersionControl->Frame().right;
253 	fMiddleVersionControl = new BTextControl(rect, "middle", ".", NULL,
254 		NULL);
255 	fMiddleVersionControl->SetDivider(fMiddleVersionControl->StringWidth(
256 		fMiddleVersionControl->Label()) + 4.0f);
257 	fMiddleVersionControl->ResizeTo(fMiddleVersionControl->Divider() + width, height);
258 	box->AddChild(fMiddleVersionControl);
259 
260 	rect.left = fMiddleVersionControl->Frame().right;
261 	fMinorVersionControl = new BTextControl(rect, "middle", ".", NULL,
262 		NULL);
263 	fMinorVersionControl->SetDivider(fMinorVersionControl->StringWidth(
264 		fMinorVersionControl->Label()) + 4.0f);
265 	fMinorVersionControl->ResizeTo(fMinorVersionControl->Divider() + width, height);
266 	box->AddChild(fMinorVersionControl);
267 
268 	popUpMenu = new BPopUpMenu("variety", true, true);
269 	popUpMenu->AddItem(new BMenuItem("Development", NULL));
270 	popUpMenu->AddItem(new BMenuItem("Alpha", NULL));
271 	popUpMenu->AddItem(new BMenuItem("Beta", NULL));
272 	popUpMenu->AddItem(new BMenuItem("Gamma", NULL));
273 	popUpMenu->AddItem(item = new BMenuItem("Golden Master", NULL));
274 	item->SetMarked(true);
275 	popUpMenu->AddItem(new BMenuItem("Final", NULL));
276 
277 	rect.top--;
278 		// BMenuField oddity
279 	rect.left = fMinorVersionControl->Frame().right + 6.0f;
280 	menuField = new BMenuField(rect,
281 		"variety", NULL, popUpMenu, true);
282 	menuField->ResizeToPreferred();
283 	box->AddChild(menuField);
284 
285 	rect.top++;
286 	rect.left = menuField->Frame().right;
287 	rect.right = rect.left + 30.0f;
288 	fInternalVersionControl = new BTextControl(rect, "internal", "/", NULL,
289 		NULL);
290 	fInternalVersionControl->SetDivider(fInternalVersionControl->StringWidth(
291 		fInternalVersionControl->Label()) + 4.0f);
292 	fInternalVersionControl->ResizeTo(fInternalVersionControl->Divider() + width, height);
293 	box->AddChild(fInternalVersionControl);
294 
295 	rect = box->Bounds().InsetByCopy(8.0f, 0.0f);
296 	rect.top = fInternalVersionControl->Frame().bottom + 8.0f;
297 	fShortDescriptionControl = new BTextControl(rect, "short desc", "Short Description:",
298 		NULL, NULL, B_FOLLOW_LEFT_RIGHT);
299 	float labelWidth = fShortDescriptionControl->StringWidth(
300 		fShortDescriptionControl->Label()) + 4.0f;
301 	fShortDescriptionControl->SetDivider(labelWidth);
302 	fShortDescriptionControl->GetPreferredSize(&width, &height);
303 	fShortDescriptionControl->ResizeTo(rect.Width(), height);
304 	box->AddChild(fShortDescriptionControl);
305 
306 	rect.OffsetBy(0.0f, fShortDescriptionControl->Bounds().Height() + 5.0f);
307 	rect.right = rect.left + labelWidth;
308 	StringView* label = new StringView(rect, NULL, "Long Description:", NULL);
309 	label->SetDivider(labelWidth);
310 	box->AddChild(label);
311 
312 	rect.left = rect.right + 3.0f;
313 	rect.top += 1.0f;
314 	rect.right = box->Bounds().Width() - 8.0f;
315 	rect.bottom = rect.top + fShortDescriptionControl->Bounds().Height() * 3.0f - 1.0f;
316 	fLongDescriptionView = new BTextView(rect, "long desc",
317 		rect.OffsetToCopy(B_ORIGIN), B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS);
318 
319 	scrollView = new BScrollView("desc scrollview", fLongDescriptionView,
320 		B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW, false, false);
321 	box->ResizeTo(box->Bounds().Width(), scrollView->Frame().bottom + 8.0f);
322 	box->AddChild(scrollView);
323 
324 	// Adjust window size and limits
325 
326 	width = fInternalVersionControl->Frame().right + 16.0f;
327 	float minWidth = fBackgroundAppCheckBox->Frame().right + iconBoxWidth + 32.0f;
328 	if (width > minWidth)
329 		minWidth = width;
330 
331 	ResizeTo(Bounds().Width() > minWidth ? Bounds().Width() : minWidth,
332 		box->Frame().bottom + topView->Frame().top + 8.0f);
333 	SetSizeLimits(minWidth, 32767.0f, Bounds().Height(), 32767.0f);
334 	box->SetResizingMode(B_FOLLOW_ALL);
335 
336 	fSignatureControl->MakeFocus(true);
337 
338 	BMimeType::StartWatching(this);
339 	_SetTo(entry);
340 }
341 
342 
343 ApplicationTypeWindow::~ApplicationTypeWindow()
344 {
345 	BMimeType::StopWatching(this);
346 }
347 
348 
349 BString
350 ApplicationTypeWindow::_Title(const BEntry& entry)
351 {
352 	char name[B_FILE_NAME_LENGTH];
353 	if (entry.GetName(name) != B_OK)
354 		strcpy(name, "\"-\"");
355 
356 	BString title(name);
357 	title.Append(" Application Type");
358 	return title;
359 }
360 
361 
362 void
363 ApplicationTypeWindow::_SetTo(const BEntry& entry)
364 {
365 	SetTitle(_Title(entry).String());
366 	fEntry = entry;
367 }
368 
369 
370 void
371 ApplicationTypeWindow::MessageReceived(BMessage* message)
372 {
373 	switch (message->what) {
374 		case B_SIMPLE_DATA:
375 		{
376 			entry_ref ref;
377 			if (message->FindRef("refs", &ref) != B_OK)
378 				break;
379 
380 			// TODO: add to supported types
381 			break;
382 		}
383 
384 		case B_META_MIME_CHANGED:
385 			const char* type;
386 			int32 which;
387 			if (message->FindString("be:type", &type) != B_OK
388 				|| message->FindInt32("be:which", &which) != B_OK)
389 				break;
390 
391 			// TODO: update supported types names
392 //			if (which == B_MIME_TYPE_DELETED)
393 			break;
394 
395 		default:
396 			BWindow::MessageReceived(message);
397 	}
398 }
399 
400 
401 bool
402 ApplicationTypeWindow::QuitRequested()
403 {
404 	be_app->PostMessage(kMsgTypeWindowClosed);
405 	return true;
406 }
407 
408