xref: /haiku/src/preferences/filetypes/NewFileTypeWindow.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
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 <MenuField.h>
13 #include <MenuItem.h>
14 #include <Mime.h>
15 #include <PopUpMenu.h>
16 #include <String.h>
17 #include <TextControl.h>
18 
19 #include <string.h>
20 
21 
22 const uint32 kMsgSupertypeChosen = 'sptc';
23 const uint32 kMsgNewSupertypeChosen = 'nstc';
24 
25 const uint32 kMsgNameUpdated = 'nmup';
26 
27 const uint32 kMsgAddType = 'atyp';
28 
29 
30 NewFileTypeWindow::NewFileTypeWindow(FileTypesWindow* target, const char* currentType)
31 	: BWindow(BRect(100, 100, 350, 200), "New file type", B_TITLED_WINDOW,
32 		B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE | B_ASYNCHRONOUS_CONTROLS),
33 	fTarget(target)
34 {
35 	BRect rect = Bounds();
36 	BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
37 	topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
38 	AddChild(topView);
39 
40 	float labelWidth = be_plain_font->StringWidth("Internal name:") + 2.0f;
41 
42 	rect.InsetBy(8.0f, 6.0f);
43 	fSupertypesMenu = new BPopUpMenu("supertypes");
44 	BMenuItem* item;
45 	BMessage types;
46 	if (BMimeType::GetInstalledSupertypes(&types) == B_OK) {
47 		const char* type;
48 		int32 i = 0;
49 		while (types.FindString("super_types", i++, &type) == B_OK) {
50 			fSupertypesMenu->AddItem(item = new BMenuItem(type,
51 				new BMessage(kMsgSupertypeChosen)));
52 
53 			// select super type close to the current type
54 			if (currentType != NULL) {
55 				if (!strncmp(type, currentType, strlen(type)))
56 					item->SetMarked(true);
57 			} else if (i == 1)
58 				item->SetMarked(true);
59 		}
60 
61 		if (i > 1)
62 			fSupertypesMenu->AddSeparatorItem();
63 	}
64 	fSupertypesMenu->AddItem(new BMenuItem("Add new group",
65 		new BMessage(kMsgNewSupertypeChosen)));
66 
67 	BMenuField* menuField = new BMenuField(rect, "supertypes",
68 		"Group:", fSupertypesMenu);
69 	menuField->SetDivider(labelWidth);
70 	menuField->SetAlignment(B_ALIGN_RIGHT);
71 	float width, height;
72 	menuField->GetPreferredSize(&width, &height);
73 	menuField->ResizeTo(rect.Width(), height);
74 	topView->AddChild(menuField);
75 
76 	fNameControl = new BTextControl(rect, "internal", "Internal name:", "",
77 		NULL, B_FOLLOW_LEFT_RIGHT);
78 	fNameControl->SetModificationMessage(new BMessage(kMsgNameUpdated));
79 	fNameControl->SetDivider(labelWidth);
80 	fNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
81 
82 	// filter out invalid characters that can't be part of a MIME type name
83 	BTextView* textView = fNameControl->TextView();
84 	const char* disallowedCharacters = "/<>@,;:\"()[]?=";
85 	for (int32 i = 0; disallowedCharacters[i]; i++) {
86 		textView->DisallowChar(disallowedCharacters[i]);
87 	}
88 
89 	fNameControl->GetPreferredSize(&width, &height);
90 	fNameControl->ResizeTo(rect.Width(), height);
91 	fNameControl->MoveTo(8.0f, 12.0f + menuField->Bounds().Height());
92 	topView->AddChild(fNameControl);
93 
94 	fAddButton = new BButton(rect, "add", "Add type", new BMessage(kMsgAddType),
95 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
96 	fAddButton->ResizeToPreferred();
97 	fAddButton->MoveTo(Bounds().Width() - 8.0f - fAddButton->Bounds().Width(),
98 		Bounds().Height() - 8.0f - fAddButton->Bounds().Height());
99 	fAddButton->SetEnabled(false);
100 	topView->AddChild(fAddButton);
101 
102 	BButton* button = new BButton(rect, "cancel", "Cancel",
103 		new BMessage(B_QUIT_REQUESTED), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
104 	button->ResizeToPreferred();
105 	button->MoveTo(fAddButton->Frame().left - 10.0f - button->Bounds().Width(),
106 		fAddButton->Frame().top);
107 	topView->AddChild(button);
108 
109 	ResizeTo(labelWidth * 4.0f + 24.0f, fNameControl->Bounds().Height()
110 		+ menuField->Bounds().Height() + fAddButton->Bounds().Height() + 30.0f);
111 	SetSizeLimits(button->Bounds().Width() + fAddButton->Bounds().Width() + 26.0f,
112 		32767.0f, Frame().Height(), Frame().Height());
113 
114 	fAddButton->MakeDefault(true);
115 	fNameControl->MakeFocus(true);
116 
117 	target->PlaceSubWindow(this);
118 }
119 
120 
121 NewFileTypeWindow::~NewFileTypeWindow()
122 {
123 }
124 
125 
126 void
127 NewFileTypeWindow::MessageReceived(BMessage* message)
128 {
129 	switch (message->what) {
130 		case kMsgSupertypeChosen:
131 			fAddButton->SetLabel("Add type");
132 			fNameControl->SetLabel("Internal name:");
133 			fNameControl->MakeFocus(true);
134 			break;
135 
136 		case kMsgNewSupertypeChosen:
137 			fAddButton->SetLabel("Add group");
138 			fNameControl->SetLabel("Group name:");
139 			fNameControl->MakeFocus(true);
140 			break;
141 
142 		case kMsgNameUpdated:
143 		{
144 			bool empty = fNameControl->Text() == NULL
145 				|| fNameControl->Text()[0] == '\0';
146 
147 			if (fAddButton->IsEnabled() == empty)
148 				fAddButton->SetEnabled(!empty);
149 			break;
150 		}
151 
152 		case kMsgAddType:
153 		{
154 			BMenuItem* item = fSupertypesMenu->FindMarked();
155 			if (item != NULL) {
156 				BString type;
157 				if (fSupertypesMenu->IndexOf(item) != fSupertypesMenu->CountItems() - 1) {
158 					// add normal type
159 					type = item->Label();
160 					type.Append("/");
161 				}
162 
163 				type.Append(fNameControl->Text());
164 
165 				BMimeType mimeType(type.String());
166 				if (mimeType.IsInstalled()) {
167 					error_alert("This file type already exists.");
168 					break;
169 				}
170 
171 				status_t status = mimeType.Install();
172 				if (status != B_OK)
173 					error_alert("Could not install file type", status);
174 				else {
175 					BMessage update(kMsgSelectNewType);
176 					update.AddString("type", type.String());
177 
178 					fTarget.SendMessage(&update);
179 				}
180 			}
181 			PostMessage(B_QUIT_REQUESTED);
182 			break;
183 		}
184 
185 		default:
186 			BWindow::MessageReceived(message);
187 			break;
188 	}
189 }
190 
191 
192 bool
193 NewFileTypeWindow::QuitRequested()
194 {
195 	fTarget.SendMessage(kMsgNewTypeWindowClosed);
196 	return true;
197 }
198