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