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