1 /* 2 * Copyright 2003-2008, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval 7 * Oliver Ruiz Dorantes 8 * Atsushi Takamatsu 9 */ 10 11 12 #include "HWindow.h" 13 #include "HEventList.h" 14 15 #include <stdio.h> 16 17 #include <Alert.h> 18 #include <Application.h> 19 #include <Beep.h> 20 #include <Box.h> 21 #include <Button.h> 22 #include <Catalog.h> 23 #include <ControlLook.h> 24 #include <FindDirectory.h> 25 #include <fs_attr.h> 26 #include <GroupLayoutBuilder.h> 27 #include <Locale.h> 28 #include <MediaFiles.h> 29 #include <MenuBar.h> 30 #include <MenuField.h> 31 #include <MenuItem.h> 32 #include <Node.h> 33 #include <NodeInfo.h> 34 #include <Path.h> 35 #include <Roster.h> 36 #include <ScrollView.h> 37 #include <StringView.h> 38 #include <Sound.h> 39 40 41 #undef B_TRANSLATION_CONTEXT 42 #define B_TRANSLATION_CONTEXT "HWindow" 43 44 static const char kSettingsFile[] = "Sounds_Settings"; 45 46 47 HWindow::HWindow(BRect rect, const char* name) 48 : 49 BWindow(rect, name, B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS), 50 fFilePanel(NULL), 51 fPlayer(NULL) 52 { 53 InitGUI(); 54 55 fFilePanel = new BFilePanel(); 56 fFilePanel->SetTarget(this); 57 58 BPath path; 59 BMessage msg; 60 61 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 62 path.Append(kSettingsFile); 63 BFile file(path.Path(), B_READ_ONLY); 64 65 if (file.InitCheck() == B_OK && msg.Unflatten(&file) == B_OK 66 && msg.FindRect("frame", &fFrame) == B_OK) { 67 MoveTo(fFrame.LeftTop()); 68 ResizeTo(fFrame.Width(), fFrame.Height()); 69 } 70 } 71 } 72 73 74 HWindow::~HWindow() 75 { 76 delete fFilePanel; 77 delete fPlayer; 78 79 BPath path; 80 BMessage msg; 81 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 82 path.Append(kSettingsFile); 83 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); 84 85 if (file.InitCheck() == B_OK) { 86 msg.AddRect("frame", fFrame); 87 msg.Flatten(&file); 88 } 89 } 90 } 91 92 93 void 94 HWindow::InitGUI() 95 { 96 fEventList = new HEventList(); 97 fEventList->SetType(BMediaFiles::B_SOUNDS); 98 fEventList->SetSelectionMode(B_SINGLE_SELECTION_LIST); 99 100 BGroupView* view = new BGroupView(); 101 BBox* box = new BBox("", B_WILL_DRAW | B_FRAME_EVENTS 102 | B_NAVIGABLE_JUMP | B_PULSE_NEEDED); 103 104 BMenu* menu = new BMenu("file"); 105 menu->SetRadioMode(true); 106 menu->SetLabelFromMarked(true); 107 menu->AddSeparatorItem(); 108 menu->AddItem(new BMenuItem(B_TRANSLATE("<none>"), 109 new BMessage(M_NONE_MESSAGE))); 110 menu->AddItem(new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS), 111 new BMessage(M_OTHER_MESSAGE))); 112 BMenuField* menuField = new BMenuField("filemenu", 113 B_TRANSLATE("Sound File:"), menu); 114 menuField->SetDivider(menuField->StringWidth(B_TRANSLATE("Sound File:")) 115 + 10); 116 117 BButton* stopbutton = new BButton("stop", B_TRANSLATE("Stop"), 118 new BMessage(M_STOP_MESSAGE)); 119 stopbutton->SetEnabled(false); 120 121 BButton* playbutton = new BButton("play", B_TRANSLATE("Play"), 122 new BMessage(M_PLAY_MESSAGE)); 123 playbutton->SetEnabled(false); 124 125 const float kInset = be_control_look->DefaultItemSpacing(); 126 view->SetLayout(new BGroupLayout(B_HORIZONTAL)); 127 view->AddChild(BGroupLayoutBuilder(B_VERTICAL, kInset) 128 .AddGroup(B_HORIZONTAL) 129 .Add(menuField) 130 .AddGlue() 131 .End() 132 .AddGroup(B_HORIZONTAL, kInset) 133 .AddGlue() 134 .Add(playbutton) 135 .Add(stopbutton) 136 .End() 137 .SetInsets(kInset, kInset, kInset, kInset) 138 ); 139 140 box->AddChild(view); 141 142 SetLayout(new BGroupLayout(B_HORIZONTAL)); 143 AddChild(BGroupLayoutBuilder(B_VERTICAL) 144 .AddGroup(B_VERTICAL, kInset) 145 .Add(fEventList) 146 .Add(box) 147 .End() 148 .SetInsets(kInset, kInset, kInset, kInset) 149 ); 150 151 // setup file menu 152 SetupMenuField(); 153 BMenuItem* noneItem = menu->FindItem(B_TRANSLATE("<none>")); 154 if (noneItem != NULL) 155 noneItem->SetMarked(true); 156 } 157 158 159 void 160 HWindow::MessageReceived(BMessage* message) 161 { 162 switch (message->what) { 163 case M_OTHER_MESSAGE: 164 { 165 BMenuField* menufield 166 = dynamic_cast<BMenuField*>(FindView("filemenu")); 167 if (menufield == NULL) 168 return; 169 BMenu* menu = menufield->Menu(); 170 171 HEventRow* row = (HEventRow*)fEventList->CurrentSelection(); 172 if (row != NULL) { 173 BPath path(row->Path()); 174 if (path.InitCheck() != B_OK) { 175 BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>")); 176 if (item != NULL) 177 item->SetMarked(true); 178 } else { 179 BMenuItem* item = menu->FindItem(path.Leaf()); 180 if (item != NULL) 181 item->SetMarked(true); 182 } 183 } 184 fFilePanel->Show(); 185 break; 186 } 187 188 case B_SIMPLE_DATA: 189 case B_REFS_RECEIVED: 190 { 191 entry_ref ref; 192 HEventRow* row = (HEventRow*)fEventList->CurrentSelection(); 193 if (message->FindRef("refs", &ref) == B_OK && row != NULL) { 194 BMenuField* menufield 195 = dynamic_cast<BMenuField*>(FindView("filemenu")); 196 if (menufield == NULL) 197 return; 198 BMenu* menu = menufield->Menu(); 199 200 // check audio file 201 BNode node(&ref); 202 BNodeInfo ninfo(&node); 203 char type[B_MIME_TYPE_LENGTH + 1]; 204 ninfo.GetType(type); 205 BMimeType mtype(type); 206 BMimeType superType; 207 mtype.GetSupertype(&superType); 208 if (superType.Type() == NULL 209 || strcmp(superType.Type(), "audio") != 0) { 210 beep(); 211 BAlert* alert = new BAlert("", 212 B_TRANSLATE("This is not an audio file."), 213 B_TRANSLATE("OK"), NULL, NULL, 214 B_WIDTH_AS_USUAL, B_STOP_ALERT); 215 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 216 alert->Go(); 217 break; 218 } 219 220 // add file item 221 BMessage* msg = new BMessage(M_ITEM_MESSAGE); 222 BPath path(&ref); 223 msg->AddRef("refs", &ref); 224 BMenuItem* menuitem = menu->FindItem(path.Leaf()); 225 if (menuitem == NULL) 226 menu->AddItem(menuitem = new BMenuItem(path.Leaf(), msg), 0); 227 // refresh item 228 fEventList->SetPath(BPath(&ref).Path()); 229 // check file menu 230 if (menuitem != NULL) 231 menuitem->SetMarked(true); 232 } 233 break; 234 } 235 236 case M_PLAY_MESSAGE: 237 { 238 HEventRow* row = (HEventRow*)fEventList->CurrentSelection(); 239 if (row != NULL) { 240 const char* path = row->Path(); 241 if (path != NULL) { 242 entry_ref ref; 243 ::get_ref_for_path(path, &ref); 244 delete fPlayer; 245 fPlayer = new BFileGameSound(&ref, false); 246 fPlayer->StartPlaying(); 247 } 248 } 249 break; 250 } 251 252 case M_STOP_MESSAGE: 253 { 254 if (fPlayer == NULL) 255 break; 256 if (fPlayer->IsPlaying()) { 257 fPlayer->StopPlaying(); 258 delete fPlayer; 259 fPlayer = NULL; 260 } 261 break; 262 } 263 264 case M_EVENT_CHANGED: 265 { 266 const char* path; 267 BMenuField* menufield 268 = dynamic_cast<BMenuField*>(FindView("filemenu")); 269 if (menufield == NULL) 270 return; 271 BMenu* menu = menufield->Menu(); 272 273 if (message->FindString("path", &path) == B_OK) { 274 BPath path(path); 275 if (path.InitCheck() != B_OK) { 276 BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>")); 277 if (item != NULL) 278 item->SetMarked(true); 279 } else { 280 BMenuItem* item = menu->FindItem(path.Leaf()); 281 if (item != NULL) 282 item->SetMarked(true); 283 } 284 } 285 break; 286 } 287 288 case M_ITEM_MESSAGE: 289 { 290 entry_ref ref; 291 if (message->FindRef("refs", &ref) == B_OK) 292 fEventList->SetPath(BPath(&ref).Path()); 293 break; 294 } 295 296 case M_NONE_MESSAGE: 297 { 298 fEventList->SetPath(NULL); 299 break; 300 } 301 302 default: 303 BWindow::MessageReceived(message); 304 } 305 } 306 307 308 void 309 HWindow::SetupMenuField() 310 { 311 BMenuField* menufield = dynamic_cast<BMenuField*>(FindView("filemenu")); 312 if (menufield == NULL) 313 return; 314 BMenu* menu = menufield->Menu(); 315 int32 count = fEventList->CountRows(); 316 for (int32 i = 0; i < count; i++) { 317 HEventRow* row = (HEventRow*)fEventList->RowAt(i); 318 if (row == NULL) 319 continue; 320 321 BPath path(row->Path()); 322 if (path.InitCheck() != B_OK) 323 continue; 324 if (menu->FindItem(path.Leaf())) 325 continue; 326 327 BMessage* msg = new BMessage(M_ITEM_MESSAGE); 328 entry_ref ref; 329 ::get_ref_for_path(path.Path(), &ref); 330 msg->AddRef("refs", &ref); 331 menu->AddItem(new BMenuItem(path.Leaf(), msg), 0); 332 } 333 334 BPath path; 335 BDirectory dir; 336 BEntry entry; 337 BPath item_path; 338 339 status_t err = find_directory(B_BEOS_SOUNDS_DIRECTORY, &path); 340 if (err == B_OK) 341 err = dir.SetTo(path.Path()); 342 while (err == B_OK) { 343 err = dir.GetNextEntry(&entry, true); 344 if (entry.InitCheck() != B_NO_ERROR) 345 break; 346 347 entry.GetPath(&item_path); 348 349 if (menu->FindItem(item_path.Leaf())) 350 continue; 351 352 BMessage* msg = new BMessage(M_ITEM_MESSAGE); 353 entry_ref ref; 354 ::get_ref_for_path(item_path.Path(), &ref); 355 msg->AddRef("refs", &ref); 356 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0); 357 } 358 359 err = find_directory(B_USER_SOUNDS_DIRECTORY, &path); 360 if (err == B_OK) 361 err = dir.SetTo(path.Path()); 362 while (err == B_OK) { 363 err = dir.GetNextEntry(&entry, true); 364 if (entry.InitCheck() != B_NO_ERROR) 365 break; 366 367 entry.GetPath(&item_path); 368 369 if (menu->FindItem(item_path.Leaf())) 370 continue; 371 372 BMessage* msg = new BMessage(M_ITEM_MESSAGE); 373 entry_ref ref; 374 375 ::get_ref_for_path(item_path.Path(), &ref); 376 msg->AddRef("refs", &ref); 377 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0); 378 } 379 380 err = find_directory(B_COMMON_SOUNDS_DIRECTORY, &path); 381 if (err == B_OK) 382 err = dir.SetTo(path.Path()); 383 while (err == B_OK) { 384 err = dir.GetNextEntry(&entry, true); 385 if (entry.InitCheck() != B_NO_ERROR) 386 break; 387 388 entry.GetPath(&item_path); 389 390 if (menu->FindItem(item_path.Leaf())) 391 continue; 392 393 BMessage* msg = new BMessage(M_ITEM_MESSAGE); 394 entry_ref ref; 395 396 ::get_ref_for_path(item_path.Path(), &ref); 397 msg->AddRef("refs", &ref); 398 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0); 399 } 400 401 } 402 403 404 void 405 HWindow::Pulse() 406 { 407 HEventRow* row = (HEventRow*)fEventList->CurrentSelection(); 408 BMenuField* menufield = dynamic_cast<BMenuField*>(FindView("filemenu")); 409 BButton* button = dynamic_cast<BButton*>(FindView("play")); 410 BButton* stop = dynamic_cast<BButton*>(FindView("stop")); 411 412 if (menufield == NULL || button == NULL || stop == NULL) 413 return; 414 415 if (row != NULL) { 416 menufield->SetEnabled(true); 417 418 const char* path = row->Path(); 419 if (path != NULL && strcmp(path, "")) 420 button->SetEnabled(true); 421 else 422 button->SetEnabled(false); 423 } else { 424 menufield->SetEnabled(false); 425 button->SetEnabled(false); 426 } 427 428 if (fPlayer != NULL) { 429 if (fPlayer->IsPlaying()) 430 stop->SetEnabled(true); 431 else 432 stop->SetEnabled(false); 433 } else 434 stop->SetEnabled(false); 435 } 436 437 438 void 439 HWindow::DispatchMessage(BMessage* message, BHandler* handler) 440 { 441 if (message->what == B_PULSE) 442 Pulse(); 443 BWindow::DispatchMessage(message, handler); 444 } 445 446 447 bool 448 HWindow::QuitRequested() 449 { 450 fFrame = Frame(); 451 452 fEventList->RemoveAll(); 453 be_app->PostMessage(B_QUIT_REQUESTED); 454 return true; 455 } 456