xref: /haiku/src/preferences/media/MidiSettingsView.cpp (revision bc622f6b593445f16011614d1b936c9761096f21)
1 /*
2  * Copyright 2014-2017, 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 
MidiSettingsView()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
AttachedToWindow()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
DetachedFromWindow()89 MidiSettingsView::DetachedFromWindow()
90 {
91 	SettingsView::DetachedFromWindow();
92 
93 	stop_watching(this);
94 }
95 
96 
97 /* virtual */
98 void
MessageReceived(BMessage * message)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()) == 0) {
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 			if (selection < 0)
140 				break;
141 
142 			BStringItem* item = (BStringItem*)fListView->ItemAt(selection);
143 
144 			BEntry entry(item->Text());
145 			BEntry parent;
146 			entry.GetParent(&parent);
147 			entry_ref folderRef;
148 			parent.GetRef(&folderRef);
149 			BMessenger msgr("application/x-vnd.Be-TRAK");
150 			BMessage refMsg(B_REFS_RECEIVED);
151 			refMsg.AddRef("refs",&folderRef);
152 			msgr.SendMessage(&refMsg);
153 			break;
154 		}
155 
156 		default:
157 			SettingsView::MessageReceived(message);
158 			break;
159 	}
160 }
161 
162 
163 void
_RetrieveSoundFontList()164 MidiSettingsView::_RetrieveSoundFontList()
165 {
166 	// TODO: Duplicated code between here
167 	// and BSoftSynth::SetDefaultInstrumentsFile
168 	BStringList paths;
169 	status_t status = BPathFinder::FindPaths(B_FIND_PATH_DATA_DIRECTORY,
170 			"synth", paths);
171 	if (status != B_OK)
172 		return;
173 
174 	fListView->MakeEmpty();
175 
176 	for (int32 i = 0; i < paths.CountStrings(); i++) {
177 		BDirectory directory(paths.StringAt(i).String());
178 		BEntry entry;
179 		if (directory.InitCheck() != B_OK)
180 			continue;
181 		while (directory.GetNextEntry(&entry) == B_OK) {
182 			BNode node(&entry);
183 			BNodeInfo nodeInfo(&node);
184 			char mimeType[B_MIME_TYPE_LENGTH];
185 			// TODO: For some reason the mimetype check fails.
186 			// maybe because the file hasn't yet been sniffed and recognized?
187 			if (nodeInfo.GetType(mimeType) == B_OK
188 				/*&& !strcmp(mimeType, "audio/x-soundfont")*/) {
189 				BPath fullPath = paths.StringAt(i).String();
190 				fullPath.Append(entry.Name());
191 				fListView->AddItem(new BStringItem(fullPath.Path()));
192 			}
193 		}
194 	}
195 }
196 
197 
198 void
_LoadSettings()199 MidiSettingsView::_LoadSettings()
200 {
201 	struct BPrivate::midi_settings settings;
202 	if (BPrivate::read_midi_settings(&settings) == B_OK)
203 		fActiveSoundFont.SetTo(settings.soundfont_file);
204 }
205 
206 
207 void
_SaveSettings()208 MidiSettingsView::_SaveSettings()
209 {
210 	fActiveSoundFont = _SelectedSoundFont();
211 	if (fActiveSoundFont.Length() > 0) {
212 		struct BPrivate::midi_settings settings;
213 		strlcpy(settings.soundfont_file, fActiveSoundFont.String(),
214 			sizeof(settings.soundfont_file));
215 		BPrivate::write_midi_settings(settings);
216 	}
217 }
218 
219 
220 void
_SelectActiveSoundFont()221 MidiSettingsView::_SelectActiveSoundFont()
222 {
223 	int32 count = fListView->CountItems();
224 	if (count == 1) {
225 		fListView->Select(0);
226 		_SaveSettings();
227 		return;
228 	}
229 	for (int32 i = 0; i < fListView->CountItems(); i++) {
230 		BStringItem* item = (BStringItem*)fListView->ItemAt(i);
231 		if (strcmp(item->Text(), fActiveSoundFont.String()) == 0) {
232 			fListView->Select(i);
233 			break;
234 		}
235 	}
236 }
237 
238 
239 BString
_SelectedSoundFont() const240 MidiSettingsView::_SelectedSoundFont() const
241 {
242 	BString string;
243 	int32 selection = fListView->CurrentSelection();
244 	if (selection >= 0) {
245 		BStringItem* item = (BStringItem*)fListView->ItemAt(selection);
246 		if (item != NULL)
247 			string = item->Text();
248 	}
249 
250 	return string;
251 }
252 
253 
254 void
_UpdateSoundFontStatus()255 MidiSettingsView::_UpdateSoundFontStatus()
256 {
257 	if (fListView->IsEmpty()) {
258 		fSoundFontStatus->SetText(
259 			B_TRANSLATE("There are no SoundFonts installed."));
260 		return;
261 	}
262 	int32 selection = fListView->CurrentSelection();
263 	if (selection < 0) {
264 		fSoundFontStatus->SetText(
265 			B_TRANSLATE("Please select a SoundFont."));
266 		return;
267 	}
268 	fSoundFontStatus->SetText("");
269 }
270 
271 
272 void
_WatchFolders()273 MidiSettingsView::_WatchFolders()
274 {
275 	BStringList paths;
276 	BPathFinder().FindPaths(B_FIND_PATH_DATA_DIRECTORY, "synth", paths);
277 	for (int32 i = 0; i < paths.CountStrings(); i++) {
278 		BEntry entry(paths.StringAt(i));
279 		node_ref nref;
280 		entry.GetNodeRef(&nref);
281 
282 		watch_node(&nref, B_WATCH_ALL, this);
283 	}
284 }
285