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