xref: /haiku/src/preferences/media/MidiSettingsView.cpp (revision 9874150a90d359aae2d7499154dda16d9b37b5fc)
1 /*
2  * Copyright 2014-2016, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "MidiSettingsView.h"
7 
8 #include <MidiSettings.h>
9 
10 #include <Box.h>
11 #include <Catalog.h>
12 #include <Directory.h>
13 #include <Entry.h>
14 #include <FindDirectory.h>
15 #include <GridView.h>
16 #include <LayoutBuilder.h>
17 #include <ListView.h>
18 #include <Locale.h>
19 #include <Node.h>
20 #include <NodeInfo.h>
21 #include <NodeMonitor.h>
22 #include <Path.h>
23 #include <PathFinder.h>
24 #include <ScrollView.h>
25 #include <StringList.h>
26 #include <StringView.h>
27 
28 #include <stdio.h>
29 
30 
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "Midi View"
33 
34 const static uint32 kSelectSoundFont = 'SeSf';
35 const static uint32 kDoubleClick = 'DClk';
36 
37 
38 MidiSettingsView::MidiSettingsView()
39 	:
40 	SettingsView()
41 {
42 	BBox* defaultsBox = new BBox("SoundFonts");
43 	defaultsBox->SetLabel(B_TRANSLATE("SoundFonts"));
44 	BGridView* defaultsGridView = new BGridView();
45 
46 	fListView = new BListView(B_SINGLE_SELECTION_LIST);
47 	fListView->SetSelectionMessage(new BMessage(kSelectSoundFont));
48 	fListView->SetInvocationMessage(new BMessage(kDoubleClick));
49 
50 	BScrollView* scrollView = new BScrollView("ScrollView", fListView,
51 			0, false, true);
52 	BLayoutBuilder::Grid<>(defaultsGridView)
53 		.SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING,
54 				B_USE_DEFAULT_SPACING)
55 		.Add(scrollView, 0, 0);
56 
57 	defaultsBox->AddChild(defaultsGridView);
58 	fSoundFontStatus = new BStringView("SoundFontStatus", "");
59 
60 	BLayoutBuilder::Group<>(this)
61 		.SetInsets(0, 0, 0, 0)
62 		.Add(defaultsBox)
63 		.AddGroup(B_HORIZONTAL)
64 			.AddGlue()
65 			.Add(fSoundFontStatus)
66 			.AddGlue()
67 			.End()
68 		.AddGlue();
69 }
70 
71 
72 /* virtual */
73 void
74 MidiSettingsView::AttachedToWindow()
75 {
76 	SettingsView::AttachedToWindow();
77 
78 	fListView->SetTarget(this);
79 	_LoadSettings();
80 	_RetrieveSoundFontList();
81 	_SelectActiveSoundFont();
82 	_UpdateSoundFontStatus();
83 	_WatchFolders();
84 }
85 
86 
87 /* virtual */
88 void
89 MidiSettingsView::DetachedFromWindow()
90 {
91 	SettingsView::DetachedFromWindow();
92 
93 	stop_watching(this);
94 }
95 
96 
97 /* virtual */
98 void
99 MidiSettingsView::MessageReceived(BMessage* message)
100 {
101 	switch (message->what) {
102 		case B_NODE_MONITOR:
103 		{
104 			int32 selected = fListView->CurrentSelection();
105 			BStringItem* olditem = (BStringItem*)fListView->ItemAt(selected);
106 
107 			_RetrieveSoundFontList();
108 
109 			int32 count = fListView->CountItems();
110 			if (count == 1) {
111 				fListView->Select(0);
112 				_SaveSettings();
113 			} else if (olditem != NULL) {
114 				for (int32 i = 0; i < fListView->CountItems(); i++) {
115 					BStringItem* item = (BStringItem*)fListView->ItemAt(i);
116 					if (!strcmp(item->Text(), olditem->Text())) {
117 						fListView->Select(i);
118 						break;
119 					}
120 				}
121 			}
122 			_UpdateSoundFontStatus();
123 			break;
124 		}
125 		case kSelectSoundFont:
126 		{
127 			int selection = fListView->CurrentSelection();
128 			if (selection < 0)
129 				_SelectActiveSoundFont();
130 			else
131 				_SaveSettings();
132 
133 			_UpdateSoundFontStatus();
134 			break;
135 		}
136 		case kDoubleClick:
137 		{
138 			int selection = fListView->CurrentSelection();
139 			BStringItem* item = (BStringItem*)fListView->ItemAt(selection);
140 
141 			BEntry entry(item->Text());
142 			BEntry parent;
143 			entry.GetParent(&parent);
144 			entry_ref folderRef;
145 			parent.GetRef(&folderRef);
146 			BMessenger msgr("application/x-vnd.Be-TRAK");
147 			BMessage refMsg(B_REFS_RECEIVED);
148 			refMsg.AddRef("refs",&folderRef);
149 			msgr.SendMessage(&refMsg);
150 			break;
151 		}
152 
153 		default:
154 			SettingsView::MessageReceived(message);
155 			break;
156 	}
157 }
158 
159 
160 void
161 MidiSettingsView::_RetrieveSoundFontList()
162 {
163 	// TODO: Duplicated code between here
164 	// and BSoftSynth::SetDefaultInstrumentsFile
165 	BStringList paths;
166 	status_t status = BPathFinder::FindPaths(B_FIND_PATH_DATA_DIRECTORY,
167 			"synth", paths);
168 	if (status != B_OK)
169 		return;
170 
171 	fListView->MakeEmpty();
172 
173 	for (int32 i = 0; i < paths.CountStrings(); i++) {
174 		BDirectory directory(paths.StringAt(i).String());
175 		BEntry entry;
176 		if (directory.InitCheck() != B_OK)
177 			continue;
178 		while (directory.GetNextEntry(&entry) == B_OK) {
179 			BNode node(&entry);
180 			BNodeInfo nodeInfo(&node);
181 			char mimeType[B_MIME_TYPE_LENGTH];
182 			// TODO: For some reason the mimetype check fails.
183 			// maybe because the file hasn't yet been sniffed and recognized?
184 			if (nodeInfo.GetType(mimeType) == B_OK
185 				/*&& !strcmp(mimeType, "audio/x-soundfont")*/) {
186 				BPath fullPath = paths.StringAt(i).String();
187 				fullPath.Append(entry.Name());
188 				fListView->AddItem(new BStringItem(fullPath.Path()));
189 			}
190 		}
191 	}
192 }
193 
194 
195 void
196 MidiSettingsView::_LoadSettings()
197 {
198 	struct BPrivate::midi_settings settings;
199 	if (BPrivate::read_midi_settings(&settings) == B_OK)
200 		fActiveSoundFont = new BString(settings.soundfont_file);
201 }
202 
203 
204 void
205 MidiSettingsView::_SaveSettings()
206 {
207 	fActiveSoundFont = new BString(_SelectedSoundFont());
208 	if (fActiveSoundFont->Length() > 0) {
209 		struct BPrivate::midi_settings settings;
210 		strlcpy(settings.soundfont_file, fActiveSoundFont->String(),
211 			sizeof(settings.soundfont_file));
212 		BPrivate::write_midi_settings(settings);
213 	}
214 }
215 
216 
217 void
218 MidiSettingsView::_SelectActiveSoundFont()
219 {
220 	int32 count = fListView->CountItems();
221 	if (count == 1) {
222 		fListView->Select(0);
223 		_SaveSettings();
224 		return;
225 	}
226 	for (int32 i = 0; i < fListView->CountItems(); i++) {
227 		BStringItem* item = (BStringItem*)fListView->ItemAt(i);
228 		if (!strcmp(item->Text(), fActiveSoundFont->String())) {
229 			fListView->Select(i);
230 			break;
231 		}
232 	}
233 }
234 
235 
236 BString
237 MidiSettingsView::_SelectedSoundFont() const
238 {
239 	BString string;
240 	int32 selection = fListView->CurrentSelection();
241 	if (selection >= 0) {
242 		BStringItem* item = (BStringItem*)fListView->ItemAt(selection);
243 		if (item != NULL)
244 			string = item->Text();
245 	}
246 
247 	return string;
248 }
249 
250 
251 void
252 MidiSettingsView::_UpdateSoundFontStatus()
253 {
254 	if (fListView->IsEmpty()) {
255 		fSoundFontStatus->SetText(
256 			B_TRANSLATE("There are no SoundFont installed."));
257 		return;
258 	}
259 	int32 selection = fListView->CurrentSelection();
260 	if (selection < 0) {
261 		fSoundFontStatus->SetText(
262 			B_TRANSLATE("Please select a SoundFont."));
263 		return;
264 	}
265 	fSoundFontStatus->SetText("");
266 }
267 
268 
269 void
270 MidiSettingsView::_WatchFolders()
271 {
272 	BStringList paths;
273 	BPathFinder().FindPaths(B_FIND_PATH_DATA_DIRECTORY, "synth", paths);
274 	for (int32 i = 0; i < paths.CountStrings(); i++) {
275 		BEntry entry(paths.StringAt(i));
276 		node_ref nref;
277 		entry.GetNodeRef(&nref);
278 
279 		watch_node(&nref, B_WATCH_ALL, this);
280 	}
281 }
282