1 // InfoWindow.cpp 2 // Generated by Interface Elements (Window v2.3) on Feb 23 2004 3 // This is a user written class and will not be overwritten. 4 5 #include <Beep.h> 6 #include <File.h> 7 #include <Resources.h> 8 #include <StorageKit.h> 9 #include <SupportKit.h> 10 #include <AppKit.h> 11 #include <iostream.h> 12 13 #include "InfoWindow.h" 14 15 // A couple helpers classes and functions. 16 17 struct IDItem : public BStringItem 18 { 19 IDItem(const char *name, int32 i); 20 int32 id; 21 }; 22 23 /*------------------------------------------------------------*/ 24 struct match_info 25 { 26 match_info(image_id i) { id = i; found = false; }; 27 image_id id; 28 bool found; 29 }; 30 31 32 bool match_id(BListItem *item, void *data) 33 { 34 match_info *mi = (match_info *) (data); 35 IDItem *my = dynamic_cast<IDItem*>(item); 36 if (my->id == (mi)->id) 37 { 38 (mi)->found = true; 39 return true; 40 } 41 return false; 42 } 43 44 45 IDItem :: IDItem(const char *name, int32 i) 46 : BStringItem(name) 47 { 48 id = i; 49 }; 50 51 52 53 InfoWindow :: InfoWindow(void) 54 : IEWindow("InfoWindow"), 55 fTickToken( BMessenger(this), new BMessage(CMD_TICK), 500000 ), // send message periodically 56 fImportLoc(10,15) // position of imported replicant 57 { 58 Lock(); 59 CreateViews(); 60 Unlock(); 61 } 62 63 64 InfoWindow::~InfoWindow(void) 65 { 66 SetPrefs(); 67 if (fPrefs != NULL) delete fPrefs; // now prefs are saved 68 } 69 70 71 bool InfoWindow :: QuitRequested() 72 { 73 long c = be_app->CountWindows(); 74 75 if (c == 1) 76 { 77 be_app->PostMessage(B_QUIT_REQUESTED); 78 } 79 return true; 80 } 81 82 83 // Handling of user interface and other events 84 void InfoWindow::MessageReceived(BMessage *msg) 85 { 86 87 switch(msg->what) 88 { 89 case CMD_UPDATE_CONTAINER_ITEM: 90 { 91 BMenu *theMenu =(BMenu *)(fMenuField -> Menu()); 92 BMenuItem *theItem = theMenu -> FindItem(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW); 93 theItem -> SetMarked(true); 94 PostMessage(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW); 95 } 96 break; 97 98 case CMD_TICK: 99 { 100 UpdateLists(false); 101 break; 102 } 103 104 case IE_INFOWINDOW_DELETEBUTTON: // 'DeleteButton' is pressed... 105 { 106 int32 sel = fReplicantList->CurrentSelection(); 107 IDItem *item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel)); 108 ASSERT(sel >= 0); 109 ASSERT(item); 110 DeleteReplicant(item->id); 111 } 112 break; 113 114 115 116 case IE_INFOWINDOW_COPYBUTTON: // 'CopyButton' is pressed... 117 { 118 BAlert *alert = new BAlert("", 119 "Warning, not all replicants are importable. Importing a " 120 "replicant can crash the Container Demo application. Are you " 121 "willing to give it a try?", "Cancel", "Import", NULL, 122 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); 123 BInvoker *inv = new BInvoker(new BMessage(CMD_IMPORT_REPLICANT),this); 124 alert->Go(inv); 125 } 126 break; 127 128 129 case CMD_IMPORT_REPLICANT: 130 { 131 // This message was posted by the Alert above. If 'which' is 1 then 132 // the user pressed the Import button. Otherwise they pressed Cancel. 133 int32 r = msg->FindInt32("which"); 134 if (r == 1) 135 { 136 int32 sel = fReplicantList->CurrentSelection(); 137 IDItem *item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel)); 138 ASSERT(sel >= 0); 139 ASSERT(item); 140 ImportReplicant(item->id); 141 } 142 } 143 break; 144 145 146 case IE_INFOWINDOW_REPLICANTLIST_SELECTION: // list item is selected in 'ReplicantList' 147 { 148 bool enabled; 149 enabled = (fReplicantList->CurrentSelection() >= 0); 150 fDeleteRep->SetEnabled(enabled); 151 fCopyRep -> SetEnabled(enabled); 152 } 153 break; 154 155 case IE_INFOWINDOW_REPLICANTLIST_INVOCATION: // list item is invoked in 'ReplicantList' 156 break; 157 158 159 160 case IE_INFOWINDOW_LIBRARYLIST_SELECTION: // list item is selected in 'LibraryList' 161 { 162 bool enabled; 163 enabled = (fLibraryList->CurrentSelection() >= 0); 164 fUnloadLib->SetEnabled(enabled); 165 } 166 break; 167 168 case IE_INFOWINDOW_LIBRARYLIST_INVOCATION: // list item is invoked in 'LibraryList' 169 break; 170 171 case IE_INFOWINDOW_UNLOADBUTTON: // 'UnloadButton' is pressed... 172 { 173 BAlert *alert = new BAlert("", 174 "Warning, unloading a library that is still in use is pretty bad. " 175 "Are you sure you want to unload this library?", 176 "Cancel", "Unload", NULL, 177 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); 178 BInvoker *inv = new BInvoker(new BMessage(CMD_UNLOAD_LIBRARY),this); 179 alert->Go(inv); 180 } 181 break; 182 183 case CMD_UNLOAD_LIBRARY: 184 { 185 // This message was posted by the Alert above. If 'which' is 1 then 186 // the user pressed the Import button. Otherwise they pressed Cancel. 187 int32 r = msg->FindInt32("which"); 188 if (r == 1) 189 { 190 int32 sel = fLibraryList->CurrentSelection(); 191 IDItem *item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(sel)); 192 ASSERT(sel >= 0); 193 ASSERT(item); 194 unload_add_on(item->id); 195 } 196 break; 197 } 198 199 case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW: 200 case IE_POPUPMENU_TARGETPOPUP_DESKBAR: 201 case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW: 202 { 203 fTarget = MessengerForTarget(msg->what); 204 UpdateLists(true); 205 } 206 break; 207 208 case IE_INFOWINDOW_MAINBAR_FILE_NEW: // "New" is selected from menu… 209 break; 210 211 case IE_INFOWINDOW_MAINBAR_FILE_OPEN___: // "Open…" is selected from menu… 212 break; 213 214 case IE_INFOWINDOW_MAINBAR_FILE_SAVE: // "Save" is selected from menu… 215 break; 216 217 case IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___: // "Save As…" is selected from menu… 218 break; 219 220 case IE_INFOWINDOW_MAINBAR_FILE_ABOUT___: // "About…" is selected from menu… 221 PostMessage(B_ABOUT_REQUESTED); 222 break; 223 224 case IE_INFOWINDOW_MAINBAR_FILE_QUIT: // "Quit" is selected from menu… 225 PostMessage(B_QUIT_REQUESTED); 226 break; 227 228 case IE_INFOWINDOW_MAINBAR_EDIT_UNDO: // "Undo" is selected from menu… 229 break; 230 231 case IE_INFOWINDOW_MAINBAR_EDIT_CUT: // "Cut" is selected from menu… 232 break; 233 234 case IE_INFOWINDOW_MAINBAR_EDIT_COPY: // "Copy" is selected from menu… 235 break; 236 237 case IE_INFOWINDOW_MAINBAR_EDIT_PASTE: // "Paste" is selected from menu… 238 break; 239 240 241 case B_ABOUT_REQUESTED: 242 { 243 BAlert *alert = new BAlert("", "XShelfInspector (H.Reh, dr.hartmut.reh@gmx.de) " "\n" "\n" 244 "Based upon ShelfInspector from Be Inc." "\n" 245 "The GUI was created with InterfaceElements (Attila Mezei)" "\n" 246 "Please read the ***Be Sample Code License*** " "\n" 247 ,"OK"); 248 alert -> Go(NULL); 249 } 250 break; 251 252 253 default: 254 inherited::MessageReceived(msg); 255 break; 256 } 257 258 } 259 260 261 void InfoWindow :: EmptyLists() 262 { 263 fReplicantList -> MakeEmpty(); 264 fLibraryList -> MakeEmpty(); 265 } 266 267 268 void InfoWindow::UpdateLists(bool make_empty) 269 { 270 bool deleted_something = false; 271 272 if (!fTarget.IsValid()) 273 { 274 EmptyLists(); 275 PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION); 276 PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION); 277 return; 278 } 279 if (make_empty) 280 { 281 EmptyLists(); 282 deleted_something = true; 283 } 284 285 /* 286 I'm not worried about the allgorithms used below to maintain the 2 lists. 287 That isn't the point of this sample app. 288 */ 289 290 image_info info; 291 292 if (!make_empty) 293 { 294 // walk through the current list of images and remove any that are 295 // no longer loaded 296 IDItem *item; 297 int32 i = fLibraryList->CountItems(); 298 while ((item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(--i))) != NULL) 299 { 300 image_id id = (image_id) item->id; 301 if (get_image_info(id, &info) != B_OK) 302 { 303 fLibraryList->RemoveItem(item); 304 delete item; 305 deleted_something = true; 306 } 307 } 308 } 309 310 // get all the images for the 'team' of the target. If the image isn't in the 311 // list then add 312 team_id team = fTarget.Team(); 313 int32 cookie = 0; 314 315 while (get_next_image_info(team, &cookie, &info) == B_OK) 316 { 317 match_info mi(info.id); 318 fLibraryList->DoForEach(match_id, &mi); 319 if (!mi.found) 320 { 321 fLibraryList->AddItem(new IDItem(info.name, info.id)); 322 } 323 } 324 325 // Now it's time to deal with the replicant list 326 327 if (!make_empty) 328 { 329 // walk through the current list of replicants and remove any that are 330 // no longer loaded 331 IDItem *item; 332 int32 i = fReplicantList->CountItems(); 333 while ((item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(--i))) != NULL) 334 { 335 int32 uid = item->id; 336 if (IsReplicantLoaded(uid) == false) 337 { 338 fReplicantList->RemoveItem(item); 339 delete item; 340 deleted_something = true; 341 } 342 } 343 } 344 345 // Now get all the replicants from the shelf and make sure that they are in 346 // the list 347 int32 index = 0; 348 int32 uid; 349 while ((uid = GetReplicantAt(index++)) >= B_OK) 350 { 351 // if this uid is already in the list then skip it 352 match_info mi(uid); 353 fReplicantList->DoForEach(match_id, &mi); 354 if (mi.found) 355 { 356 continue; 357 } 358 359 BMessage rep_info; 360 if (GetReplicantName(uid, &rep_info) != B_OK) 361 { 362 continue; 363 } 364 365 const char *name; 366 if (rep_info.FindString("result", &name) == B_OK) 367 { 368 fReplicantList->AddItem(new IDItem(name, uid)); 369 } 370 } 371 372 373 if (deleted_something) 374 { 375 PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION); 376 PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION); 377 } 378 } 379 380 381 382 status_t InfoWindow :: GetReplicantName(int32 uid, BMessage *reply) const 383 { 384 /* 385 We send a message to the target shelf, asking it for the Name of the 386 replicant with the given unique id. 387 */ 388 389 BMessage request(B_GET_PROPERTY); 390 BMessage uid_specifier(B_ID_SPECIFIER); // specifying via ID 391 status_t err; 392 status_t e; 393 394 request.AddSpecifier("Name"); // ask for the Name of the replicant 395 396 // IDs are specified using code like the following 3 lines: 397 uid_specifier.AddInt32("id", uid); 398 uid_specifier.AddString("property", "Replicant"); 399 request.AddSpecifier(&uid_specifier); 400 401 if ((err = fTarget.SendMessage(&request, reply)) != B_OK) 402 return err; 403 404 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 405 return err ? err : e; 406 407 return B_OK; 408 } 409 410 bool InfoWindow :: IsReplicantLoaded(int32 uid) const 411 { 412 /* 413 determine if the specified replicant (the unique ID of the replicant) 414 still exists in the target container/shelf. If we can get the name then the 415 replicant still exists. 416 */ 417 BMessage reply; 418 status_t err = GetReplicantName(uid, &reply); 419 return (err == B_OK); 420 } 421 422 423 int32 InfoWindow::GetReplicantAt(int32 index) const 424 { 425 /* 426 So here we want to get the Unique ID of the replicant at the given index 427 in the target Shelf. 428 */ 429 430 BMessage request(B_GET_PROPERTY); // We're getting the ID property 431 BMessage reply; 432 status_t err; 433 434 request.AddSpecifier("ID"); // want the ID 435 request.AddSpecifier("Replicant", index); // of the index'th replicant 436 437 if ((err = fTarget.SendMessage(&request, &reply)) != B_OK) 438 return err; 439 440 int32 uid; 441 if ((err = reply.FindInt32("result", &uid)) != B_OK) 442 return err; 443 444 return uid; 445 } 446 447 448 BMessenger InfoWindow :: MessengerForTarget(type_code w) const 449 { 450 /* 451 This function determines the BMessenger to the various Shelf objects 452 that this app can talk with. 453 */ 454 BMessage request(B_GET_PROPERTY); 455 BMessenger to; 456 BMessenger result; 457 458 request.AddSpecifier("Messenger"); 459 request.AddSpecifier("Shelf"); 460 461 switch (w) 462 { 463 case IE_POPUPMENU_TARGETPOPUP_DESKBAR: 464 { 465 request.AddSpecifier("View", "Status"); 466 request.AddSpecifier("Window", "Deskbar"); 467 to = BMessenger("application/x-vnd.Be-TSKB", -1); 468 break; 469 } 470 471 case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW: 472 { 473 // The Desktop is owned by Tracker and the Shelf is in the 474 // View "PoseView" in Window "Desktop" 475 request.AddSpecifier("View", "PoseView"); 476 request.AddSpecifier("Window", "/boot/home/Desktop"); 477 to = BMessenger("application/x-vnd.Be-TRAK", -1); 478 break; 479 } 480 481 case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW: 482 { 483 // In the COntainer Demo app the View "MainView" in the only window 484 // is the Shelf. 485 request.AddSpecifier("View", "ContainerView"); // Hier werden Replikanten abgelegt 486 request.AddSpecifier("Window", (int32) 0); 487 to = BMessenger(XCONTAINER_APP, -1); 488 // This demo app isn't worried about the Container app going away 489 // (quitting) unexpectedly. 490 break; 491 } 492 } 493 494 BMessage reply; 495 496 if (to.SendMessage(&request, &reply) == B_OK) 497 { 498 //reply.PrintToStream(); 499 reply.FindMessenger("result", &result); 500 } 501 return result; 502 } 503 504 505 status_t InfoWindow :: DeleteReplicant(int32 uid) 506 { 507 // delete the given replicant from the current target shelf 508 509 BMessage request(B_DELETE_PROPERTY); // Delete 510 BMessage uid_specifier(B_ID_SPECIFIER); // specifying via ID 511 BMessage reply; 512 status_t err; 513 status_t e; 514 515 // IDs are specified using code like the following 3 lines: 516 uid_specifier.AddInt32("id", uid); 517 uid_specifier.AddString("property", "Replicant"); 518 request.AddSpecifier(&uid_specifier); 519 520 if ((err = fTarget.SendMessage(&request, &reply)) != B_OK) 521 return err; 522 523 if ((err = reply.FindInt32("error", &e)) != B_OK) 524 return err; 525 526 return e; 527 } 528 529 530 status_t InfoWindow :: ImportReplicant(int32 uid) 531 { 532 // Import the given replicant from the current target shelf 533 // That is get a copy and recreate it in the "Container" window of 534 // this app. 535 536 BMessage request(B_GET_PROPERTY); // Get will return the archive msg 537 BMessage uid_specifier(B_ID_SPECIFIER); // specifying via ID 538 BMessage reply; 539 status_t err; 540 status_t e; 541 542 // IDs are specified using code like the following 3 lines: 543 uid_specifier.AddInt32("id", uid); 544 uid_specifier.AddString("property", "Replicant"); 545 request.AddSpecifier(&uid_specifier); 546 547 if ((err = fTarget.SendMessage(&request, &reply)) != B_OK) 548 return err; 549 550 if (((err = reply.FindInt32("error", &e)) != B_OK) || (e != B_OK)) 551 return err; 552 553 // OK, let's get the archive message 554 BMessage data; 555 reply.FindMessage("result", &data); 556 557 // Now send this to the container window. If someone closed it then the 558 // Send will fail. Oh well. 559 BMessenger mess = MessengerForTarget(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW); 560 BMessage msg(B_CREATE_PROPERTY); 561 562 msg.AddMessage("data", &data); 563 564 // As this is a Demo I'm not going to worry about some fancy layout 565 // algorithm. Just keep placing new replicants going down the window 566 msg.AddPoint("location", fImportLoc); 567 fImportLoc.y += 40; 568 569 return mess.SendMessage(&msg, &reply); 570 } 571 572 573 574 // Update the menu items before they appear on screen 575 void InfoWindow::MenusBeginning() 576 { 577 // Complete the SetEnabled argument or do anything with the source below... 578 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_NEW)->SetEnabled(false); // "New" 579 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_OPEN___)->SetEnabled(false); // "Open…" 580 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE)->SetEnabled(false); // "Save" 581 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___)->SetEnabled(false); // "Save As…" 582 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_ABOUT___)->SetEnabled(true); // "About…" 583 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_QUIT)->SetEnabled(true); // "Quit" 584 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_UNDO)->SetEnabled(false); // "Undo" 585 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_CUT)->SetEnabled(false); // "Cut" 586 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_COPY)->SetEnabled(false); // "Copy" 587 KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_PASTE)->SetEnabled(false); // "Paste" 588 } 589 590 591 592 593 BMessage *InfoWindow :: ReadMessageFromResource(const char *resName) 594 { 595 // Hier wird aus der Resource die Message gelesen 596 app_info ai; 597 BFile file; 598 BResources res; 599 size_t res_size; 600 const void* res_addr; 601 602 BMessage* archive = new BMessage; 603 604 if( (be_app->GetAppInfo(&ai) != B_OK) 605 ||(file.SetTo(&ai.ref,B_READ_ONLY) != B_OK) 606 ||(res.SetTo(&file) != B_OK) 607 ||((res_addr = res.LoadResource('ARCV',resName,&res_size)) == NULL) 608 ||(archive -> Unflatten((const char*)res_addr) != B_OK) ) 609 // Resource muss 'ARCV' - Typ sein -> in IE einstellen 610 // Resource of type 'ARCV' 611 { 612 delete archive; 613 return NULL; 614 } 615 return archive; 616 } 617 618 619 void InfoWindow:: CreateViews() 620 { 621 BMessage *archive = ReadMessageFromResource("PopUpMenu"); // Menu Feld from Resource 622 if (archive) 623 { 624 fMenuField = new BMenuField(archive); 625 delete archive; 626 } 627 628 fMainBox = (BBox *)FindView("MainBox"); // Pointer to MainBox 629 fMainBox->SetLabel(fMenuField); // Replace Label 630 631 fReplicantList = (BListView *) FindView("ReplicantList"); 632 fLibraryList = (BListView *) FindView("LibraryList"); 633 634 fDeleteRep = (BButton *) FindView("DeleteButton"); 635 fCopyRep = (BButton *) FindView("CopyButton"); 636 fUnloadLib = (BButton *) FindView("UnloadButton"); 637 638 BScrollView *libScrollView = (BScrollView *)FindView("LibraryScroll"); 639 BScrollBar *horLibScrollBar = libScrollView -> ScrollBar(B_HORIZONTAL); 640 horLibScrollBar -> SetRange(0, 400); 641 horLibScrollBar -> SetProportion(0.4); 642 643 BScrollView *repScrollView = (BScrollView *)FindView("ReplicantScroll"); 644 BScrollBar *horRepScrollBar = repScrollView -> ScrollBar(B_HORIZONTAL); 645 horRepScrollBar -> SetRange(0, 400); 646 horRepScrollBar -> SetProportion(0.4); 647 } 648 649 650 void InfoWindow :: GetPrefs() 651 { 652 status_t err; 653 BRect windFrame; 654 int32 targetShelf; 655 656 fPrefs = new TPreferences ("XShelfInspector/preferences"); // Name des Prefs-Files 657 if (fPrefs -> InitCheck() != B_OK) // falls keine Prefs -> erzeugen 658 { 659 windFrame = Frame(); // Window Frame aus Resource ermitteln 660 fPrefs -> SetRect ("WindowFrame", windFrame ); 661 662 targetShelf = IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW; // XContainerWindow 663 fPrefs -> SetInt32 ("TargetShelf", targetShelf ); 664 } 665 666 err = (fPrefs -> FindRect ("WindowFrame", &windFrame) ); 667 if (err == B_OK) 668 { 669 ResizeTo(windFrame.Width(), windFrame.Height() ); // Fensterposition und Größe 670 MoveTo(windFrame.left, windFrame.top); // aus Preferences 671 } 672 673 err = (fPrefs -> FindInt32 ("TargetShelf", &targetShelf ) ); 674 if (err == B_OK) 675 { 676 BMenu *theMenu =(BMenu *)(fMenuField -> Menu()); 677 BMenuItem *theItem = theMenu -> FindItem(targetShelf); 678 theItem -> SetMarked(true); 679 PostMessage(targetShelf); // TargetShelf 680 } 681 } 682 683 684 void InfoWindow :: SetPrefs() 685 { 686 fPrefs -> SetRect ("WindowFrame", Frame() ); 687 688 BMenu *theMenu =(BMenu *)(fMenuField -> Menu()); 689 BMenuItem *theItem = theMenu -> FindMarked(); 690 int32 targetShelf = theItem -> Command(); 691 fPrefs -> SetInt32("TargetShelf", targetShelf); 692 } 693 694 695