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 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()) == 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 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 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 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 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 240 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 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 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