1 /* 2 * Copyright 2001-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Axel Dörfler, axeld@pinc-software.de 8 * Jérôme Duval 9 */ 10 11 /*! BShelf stores replicant views that are dropped onto it */ 12 13 14 #include <Beep.h> 15 #include <Dragger.h> 16 #include <Entry.h> 17 #include <File.h> 18 #include <Looper.h> 19 #include <Message.h> 20 #include <MessageFilter.h> 21 #include <Messenger.h> 22 #include <Point.h> 23 #include <PropertyInfo.h> 24 #include <Rect.h> 25 #include <Shelf.h> 26 #include <View.h> 27 28 #include <ViewPrivate.h> 29 #include <ZombieReplicantView.h> 30 31 #include <stdio.h> 32 #include <string.h> 33 34 35 static property_info sShelfPropertyList[] = { 36 { 37 "Replicant", 38 { B_COUNT_PROPERTIES, B_CREATE_PROPERTY }, 39 { B_DIRECT_SPECIFIER }, 40 NULL, 0, 41 }, 42 43 { 44 "Replicant", 45 { B_DELETE_PROPERTY, B_GET_PROPERTY }, 46 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, B_ID_SPECIFIER }, 47 NULL, 0, 48 }, 49 50 { 51 "Replicant", 52 {}, 53 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, B_ID_SPECIFIER }, 54 "... of Replicant {index | name | id} of ...", 0, 55 }, 56 57 { 0, { 0 }, { 0 }, 0, 0 } 58 }; 59 60 static property_info sReplicantPropertyList[] = { 61 { 62 "ID", 63 { B_GET_PROPERTY }, 64 { B_DIRECT_SPECIFIER }, 65 NULL, 0, { B_INT32_TYPE } 66 }, 67 68 { 69 "Name", 70 { B_GET_PROPERTY }, 71 { B_DIRECT_SPECIFIER }, 72 NULL, 0, { B_STRING_TYPE } 73 }, 74 75 { 76 "Signature", 77 { B_GET_PROPERTY }, 78 { B_DIRECT_SPECIFIER }, 79 NULL, 0, { B_STRING_TYPE } 80 }, 81 82 { 83 "Suites", 84 { B_GET_PROPERTY }, 85 { B_DIRECT_SPECIFIER }, 86 NULL, 0, { B_PROPERTY_INFO_TYPE } 87 }, 88 89 { 90 "View", 91 { }, 92 { B_DIRECT_SPECIFIER }, 93 NULL, 0, 94 }, 95 96 { 0, { 0 }, { 0 }, 0, 0 } 97 }; 98 99 100 extern "C" void _ReservedShelf1__6BShelfFv(BShelf *const, int32, 101 const BMessage*, const BView*); 102 103 104 namespace BPrivate { 105 106 struct replicant_data { 107 replicant_data(BMessage *message, BView *view, BDragger *dragger, 108 BDragger::relation relation, unsigned long id, image_id image); 109 replicant_data(); 110 111 static replicant_data* Find(BList const *list, BMessage const *msg); 112 static replicant_data* Find(BList const *list, BView const *view, bool allowZombie); 113 static replicant_data* Find(BList const *list, unsigned long id); 114 115 static int32 IndexOf(BList const *list, BMessage const *msg); 116 static int32 IndexOf(BList const *list, BView const *view, bool allowZombie); 117 static int32 IndexOf(BList const *list, unsigned long id); 118 119 BMessage* message; 120 BView* view; 121 BDragger* dragger; 122 BDragger::relation relation; 123 unsigned long id; 124 image_id image; 125 status_t error; 126 BView* zombie_view; 127 }; 128 129 class ShelfContainerViewFilter : public BMessageFilter { 130 public: 131 ShelfContainerViewFilter(BShelf *shelf, BView *view); 132 133 filter_result Filter(BMessage *msg, BHandler **handler); 134 135 private: 136 filter_result _ObjectDropFilter(BMessage *msg, BHandler **handler); 137 138 BShelf *fShelf; 139 BView *fView; 140 }; 141 142 class ReplicantViewFilter : public BMessageFilter { 143 public: 144 ReplicantViewFilter(BShelf *shelf, BView *view); 145 146 filter_result Filter(BMessage *message, BHandler **handler); 147 148 private: 149 BShelf *fShelf; 150 BView *fView; 151 }; 152 153 } // namespace BPrivate 154 155 156 using BPrivate::replicant_data; 157 using BPrivate::ReplicantViewFilter; 158 using BPrivate::ShelfContainerViewFilter; 159 160 161 // #pragma mark - 162 163 164 /*! \brief Helper function for BShelf::_AddReplicant() 165 */ 166 static status_t 167 send_reply(BMessage* message, status_t status, uint32 uniqueID) 168 { 169 if (message->IsSourceWaiting()) { 170 BMessage reply(B_REPLY); 171 reply.AddInt32("id", uniqueID); 172 reply.AddInt32("error", status); 173 message->SendReply(&reply); 174 } 175 176 return status; 177 } 178 179 180 // #pragma mark - 181 182 183 replicant_data::replicant_data(BMessage *_message, BView *_view, BDragger *_dragger, 184 BDragger::relation _relation, unsigned long _id, image_id _image) 185 : 186 message(_message), 187 view(_view), 188 dragger(NULL), 189 relation(_relation), 190 id(_id), 191 image(_image), 192 error(B_OK), 193 zombie_view(NULL) 194 { 195 } 196 197 198 replicant_data::replicant_data() 199 : 200 message(NULL), 201 view(NULL), 202 dragger(NULL), 203 relation(BDragger::TARGET_UNKNOWN), 204 id(0), 205 image(-1), 206 error(B_ERROR), 207 zombie_view(NULL) 208 { 209 } 210 211 212 //static 213 replicant_data * 214 replicant_data::Find(BList const *list, BMessage const *msg) 215 { 216 int32 i = 0; 217 replicant_data *item; 218 while ((item = (replicant_data*)list->ItemAt(i++)) != NULL) { 219 if (item->message == msg) 220 return item; 221 } 222 223 return NULL; 224 } 225 226 227 //static 228 replicant_data * 229 replicant_data::Find(BList const *list, BView const *view, bool allowZombie) 230 { 231 int32 i = 0; 232 replicant_data *item; 233 while ((item = (replicant_data*)list->ItemAt(i++)) != NULL) { 234 if (item->view == view) 235 return item; 236 237 if (allowZombie && item->zombie_view == view) 238 return item; 239 } 240 241 return NULL; 242 } 243 244 245 //static 246 replicant_data * 247 replicant_data::Find(BList const *list, unsigned long id) 248 { 249 int32 i = 0; 250 replicant_data *item; 251 while ((item = (replicant_data*)list->ItemAt(i++)) != NULL) { 252 if (item->id == id) 253 return item; 254 } 255 256 return NULL; 257 } 258 259 260 //static 261 int32 262 replicant_data::IndexOf(BList const *list, BMessage const *msg) 263 { 264 int32 i = 0; 265 replicant_data *item; 266 while ((item = (replicant_data*)list->ItemAt(i)) != NULL) { 267 if (item->message == msg) 268 return i; 269 i++; 270 } 271 272 return -1; 273 } 274 275 276 //static 277 int32 278 replicant_data::IndexOf(BList const *list, BView const *view, bool allowZombie) 279 { 280 int32 i = 0; 281 replicant_data *item; 282 while ((item = (replicant_data*)list->ItemAt(i)) != NULL) { 283 if (item->view == view) 284 return i; 285 286 if (allowZombie && item->zombie_view == view) 287 return i; 288 i++; 289 } 290 291 return -1; 292 } 293 294 295 //static 296 int32 297 replicant_data::IndexOf(BList const *list, unsigned long id) 298 { 299 int32 i = 0; 300 replicant_data *item; 301 while ((item = (replicant_data*)list->ItemAt(i)) != NULL) { 302 if (item->id == id) 303 return i; 304 i++; 305 } 306 307 return -1; 308 } 309 310 311 // #pragma mark - 312 313 314 ShelfContainerViewFilter::ShelfContainerViewFilter(BShelf *shelf, BView *view) 315 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 316 fShelf(shelf), 317 fView(view) 318 { 319 } 320 321 322 filter_result 323 ShelfContainerViewFilter::Filter(BMessage *msg, BHandler **handler) 324 { 325 filter_result filter = B_DISPATCH_MESSAGE; 326 327 if (msg->what == B_ARCHIVED_OBJECT 328 || msg->what == B_ABOUT_REQUESTED) 329 return _ObjectDropFilter(msg, handler); 330 331 return filter; 332 } 333 334 335 filter_result 336 ShelfContainerViewFilter::_ObjectDropFilter(BMessage *msg, BHandler **_handler) 337 { 338 BView *mouseView = NULL; 339 if (*_handler) 340 mouseView = dynamic_cast<BView*>(*_handler); 341 342 if (msg->WasDropped()) { 343 if (!fShelf->fAllowDragging) { 344 printf("Dragging replicants isn't allowed to this shelf."); 345 beep(); 346 return B_SKIP_MESSAGE; 347 } 348 } 349 350 BPoint point; 351 BPoint offset; 352 353 if (msg->WasDropped()) { 354 point = msg->DropPoint(&offset); 355 point = mouseView->ConvertFromScreen(point - offset); 356 } 357 358 BLooper *looper = NULL; 359 BHandler *handler = msg->ReturnAddress().Target(&looper); 360 361 if (Looper() == looper) { 362 BDragger *dragger = NULL; 363 if (handler) 364 dragger = dynamic_cast<BDragger*>(handler); 365 366 BRect rect; 367 if (dragger->fRelation == BDragger::TARGET_IS_CHILD) 368 rect = dragger->Frame(); 369 else 370 rect = dragger->fTarget->Frame(); 371 rect.OffsetTo(point); 372 point = rect.LeftTop() + fShelf->AdjustReplicantBy(rect, msg); 373 374 if (dragger->fRelation == BDragger::TARGET_IS_PARENT) 375 dragger->fTarget->MoveTo(point); 376 else if (dragger->fRelation == BDragger::TARGET_IS_CHILD) 377 dragger->MoveTo(point); 378 else { 379 //TODO: TARGET_UNKNOWN/TARGET_SIBLING 380 } 381 382 } else { 383 if (fShelf->_AddReplicant(msg, &point, fShelf->fGenCount++) == B_OK) 384 Looper()->DetachCurrentMessage(); 385 } 386 387 return B_SKIP_MESSAGE; 388 } 389 390 391 // #pragma mark - 392 393 394 ReplicantViewFilter::ReplicantViewFilter(BShelf *shelf, BView *view) 395 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 396 fShelf(shelf), 397 fView(view) 398 { 399 } 400 401 402 filter_result 403 ReplicantViewFilter::Filter(BMessage *message, BHandler **handler) 404 { 405 if (message->what == kDeleteReplicant) { 406 if (handler != NULL) 407 *handler = fShelf; 408 message->AddPointer("_target", fView); 409 } 410 return B_DISPATCH_MESSAGE; 411 } 412 413 414 // #pragma mark - 415 416 417 BShelf::BShelf(BView *view, bool allowDrags, const char *shelfType) 418 : BHandler(shelfType) 419 { 420 _InitData(NULL, NULL, view, allowDrags); 421 } 422 423 424 BShelf::BShelf(const entry_ref *ref, BView *view, bool allowDrags, 425 const char *shelfType) 426 : BHandler(shelfType) 427 { 428 _InitData(new BEntry(ref), NULL, view, allowDrags); 429 } 430 431 432 BShelf::BShelf(BDataIO *stream, BView *view, bool allowDrags, 433 const char *shelfType) 434 : BHandler(shelfType) 435 { 436 _InitData(NULL, stream, view, allowDrags); 437 } 438 439 440 BShelf::BShelf(BMessage *data) 441 : BHandler(data) 442 { 443 // TODO: Implement ? 444 } 445 446 447 BShelf::~BShelf() 448 { 449 Save(); 450 451 delete fEntry; 452 } 453 454 455 status_t 456 BShelf::Archive(BMessage *data, bool deep) const 457 { 458 return B_ERROR; 459 } 460 461 462 BArchivable * 463 BShelf::Instantiate(BMessage *data) 464 { 465 return NULL; 466 } 467 468 469 void 470 BShelf::MessageReceived(BMessage *msg) 471 { 472 if (msg->what == kDeleteReplicant) { 473 BView *replicant = NULL; 474 if (msg->FindPointer("_target", (void **)&replicant) == B_OK && replicant != NULL) 475 DeleteReplicant(replicant); 476 477 return; 478 } 479 480 BMessage replyMsg(B_REPLY); 481 status_t err = B_BAD_SCRIPT_SYNTAX; 482 483 BMessage specifier; 484 int32 what; 485 const char *prop; 486 int32 index; 487 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK) 488 return BHandler::MessageReceived(msg); 489 490 switch (msg->what) { 491 case B_DELETE_PROPERTY: 492 case B_GET_PROPERTY: 493 case B_GET_SUPPORTED_SUITES: 494 if (strcmp(prop, "Replicant") == 0) { 495 BMessage reply; 496 int32 i; 497 uint32 ID; 498 BView *replicant = NULL; 499 BMessage *repMessage = NULL; 500 err = _GetProperty(&specifier, &reply); 501 if (err == B_OK) 502 err = reply.FindInt32("index", &i); 503 bool popped = (msg->PopSpecifier()==B_OK); 504 if (err == B_OK && !popped && msg->what == B_DELETE_PROPERTY) { // Delete Replicant 505 err = DeleteReplicant(i); 506 break; 507 } 508 if (err == B_OK && popped 509 && msg->what == B_GET_SUPPORTED_SUITES) { 510 err = replyMsg.AddString("suites", "suite/vnd.Be-replicant"); 511 if (err == B_OK) { 512 BPropertyInfo propInfo(sReplicantPropertyList); 513 err = replyMsg.AddFlat("messages", &propInfo); 514 } 515 break; 516 } 517 if (err == B_OK) 518 repMessage = ReplicantAt(i, &replicant, &ID, &err); 519 if (err == B_OK && replicant) { 520 if (!popped) { // Get Replicant 521 BMessage archive; 522 err = replicant->Archive(&archive); 523 if (err == B_OK) 524 err = replyMsg.AddMessage("result", &archive); 525 break; 526 } 527 // now handles the replicant suite 528 err = B_BAD_SCRIPT_SYNTAX; 529 if (msg->what != B_GET_PROPERTY) 530 break; 531 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK) 532 break; 533 if (strcmp(prop, "ID") == 0) { 534 err = replyMsg.AddInt32("result", ID); 535 } else if (strcmp(prop, "Name") == 0) { 536 err = replyMsg.AddString("result", replicant->Name()); 537 } else if (strcmp(prop, "Signature") == 0) { 538 const char *add_on = NULL; 539 err = repMessage->FindString("add_on", &add_on); 540 if (err == B_OK) 541 err = replyMsg.AddString("result", add_on); 542 } else if (strcmp(prop, "Suites") == 0) { 543 err = replyMsg.AddString("suites", "suite/vnd.Be-replicant"); 544 if (err == B_OK) { 545 BPropertyInfo propInfo(sReplicantPropertyList); 546 err = replyMsg.AddFlat("messages", &propInfo); 547 } 548 } 549 } 550 break; 551 } 552 return BHandler::MessageReceived(msg); 553 554 case B_COUNT_PROPERTIES: 555 if (strcmp(prop, "Replicant") == 0) { 556 err = replyMsg.AddInt32("result", CountReplicants()); 557 break; 558 } 559 return BHandler::MessageReceived(msg); 560 } 561 562 if (err < B_OK) { 563 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 564 565 if (err == B_BAD_SCRIPT_SYNTAX) 566 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 567 else 568 replyMsg.AddString("message", strerror(err)); 569 } 570 571 replyMsg.AddInt32("error", err); 572 msg->SendReply(&replyMsg); 573 } 574 575 576 status_t 577 BShelf::Save() 578 { 579 status_t status = B_ERROR; 580 if (fEntry != NULL) { 581 BFile *file = new BFile(fEntry, B_READ_WRITE); 582 status = file->InitCheck(); 583 if (status < B_OK) { 584 delete file; 585 return status; 586 } 587 fStream = file; 588 } 589 590 if (fStream != NULL) { 591 BMessage message; 592 status = _Archive(&message); 593 if (status == B_OK) 594 status = message.Flatten(fStream); 595 } 596 597 return status; 598 } 599 600 601 void 602 BShelf::SetDirty(bool state) 603 { 604 fDirty = state; 605 } 606 607 608 bool 609 BShelf::IsDirty() const 610 { 611 return fDirty; 612 } 613 614 615 BHandler * 616 BShelf::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, 617 int32 form, const char *property) 618 { 619 BPropertyInfo shelfPropInfo(sShelfPropertyList); 620 BHandler *target = NULL; 621 BView *replicant = NULL; 622 switch (shelfPropInfo.FindMatch(msg, 0, specifier, form, property)) { 623 case 0: 624 case 1: 625 if (msg->PopSpecifier() != B_OK ) { 626 target = this; 627 break; 628 } 629 msg->SetCurrentSpecifier(index); 630 // fall through 631 case 2: { 632 BMessage reply; 633 status_t err = _GetProperty(specifier, &reply); 634 int32 i; 635 uint32 ID; 636 if (err == B_OK) 637 err = reply.FindInt32("index", &i); 638 if (err == B_OK) 639 ReplicantAt(i, &replicant, &ID, &err); 640 641 if (err == B_OK && replicant != NULL) { 642 if (index <= 0 && msg->what == B_GET_SUPPORTED_SUITES) 643 return this; 644 msg->PopSpecifier(); 645 } else { 646 BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD); 647 replyMsg.AddInt32("error", B_BAD_INDEX); 648 replyMsg.AddString("message", "Cannot find replicant at/with specified index/name."); 649 msg->SendReply(&replyMsg); 650 } 651 } 652 break; 653 } 654 655 if (!replicant) { 656 if (target) 657 return target; 658 return BHandler::ResolveSpecifier(msg, index, specifier, form, 659 property); 660 } 661 662 int32 repIndex; 663 status_t err = msg->GetCurrentSpecifier(&repIndex, specifier, &form, &property); 664 if (err) { 665 BMessage reply(B_MESSAGE_NOT_UNDERSTOOD); 666 reply.AddInt32("error", err); 667 msg->SendReply(&reply); 668 return NULL; 669 } 670 671 BPropertyInfo replicantPropInfo(sReplicantPropertyList); 672 switch (replicantPropInfo.FindMatch(msg, 0, specifier, form, property)) { 673 case 0: 674 case 1: 675 case 2: 676 case 3: 677 msg->SetCurrentSpecifier(index); 678 target = this; 679 break; 680 case 4: 681 target = replicant; 682 msg->PopSpecifier(); 683 break; 684 default: 685 break; 686 } 687 if (!target) { 688 BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD); 689 replyMsg.AddInt32("error", B_BAD_SCRIPT_SYNTAX); 690 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 691 msg->SendReply(&replyMsg); 692 } 693 return target; 694 } 695 696 697 status_t 698 BShelf::GetSupportedSuites(BMessage *message) 699 { 700 status_t err; 701 err = message->AddString("suites", "suite/vnd.Be-shelf"); 702 if (err == B_OK) { 703 BPropertyInfo propInfo(sShelfPropertyList); 704 err = message->AddFlat("messages", &propInfo); 705 } 706 if (err == B_OK) 707 return BHandler::GetSupportedSuites(message); 708 return err; 709 } 710 711 712 status_t 713 BShelf::Perform(perform_code d, void *arg) 714 { 715 return BHandler::Perform(d, arg); 716 } 717 718 719 bool 720 BShelf::AllowsDragging() const 721 { 722 return fAllowDragging; 723 } 724 725 726 void 727 BShelf::SetAllowsDragging(bool state) 728 { 729 fAllowDragging = state; 730 } 731 732 733 bool 734 BShelf::AllowsZombies() const 735 { 736 return fAllowZombies; 737 } 738 739 740 void 741 BShelf::SetAllowsZombies(bool state) 742 { 743 fAllowZombies = state; 744 } 745 746 747 bool 748 BShelf::DisplaysZombies() const 749 { 750 return fDisplayZombies; 751 } 752 753 754 void 755 BShelf::SetDisplaysZombies(bool state) 756 { 757 fDisplayZombies = state; 758 } 759 760 761 bool 762 BShelf::IsTypeEnforced() const 763 { 764 return fTypeEnforced; 765 } 766 767 768 void 769 BShelf::SetTypeEnforced(bool state) 770 { 771 fTypeEnforced = state; 772 } 773 774 775 status_t 776 BShelf::SetSaveLocation(BDataIO *data_io) 777 { 778 fDirty = true; 779 780 if (fEntry) { 781 delete fEntry; 782 fEntry = NULL; 783 } 784 785 fStream = data_io; 786 787 return B_OK; 788 } 789 790 791 status_t 792 BShelf::SetSaveLocation(const entry_ref *ref) 793 { 794 fDirty = true; 795 796 if (fEntry) 797 delete fEntry; 798 else 799 fStream = NULL; 800 801 fEntry = new BEntry(ref); 802 803 return B_OK; 804 } 805 806 807 BDataIO * 808 BShelf::SaveLocation(entry_ref *ref) const 809 { 810 entry_ref entry; 811 812 if (fStream && ref) { 813 *ref = entry; 814 return fStream; 815 } 816 if (fEntry) { 817 fEntry->GetRef(&entry); 818 819 if (ref) 820 *ref = entry; 821 822 return NULL; 823 } 824 825 *ref = entry; 826 return NULL; 827 } 828 829 830 status_t 831 BShelf::AddReplicant(BMessage *data, BPoint location) 832 { 833 return _AddReplicant(data, &location, fGenCount++); 834 } 835 836 837 status_t 838 BShelf::DeleteReplicant(BView *replicant) 839 { 840 int32 index = replicant_data::IndexOf(&fReplicants, replicant, true); 841 842 replicant_data *item = (replicant_data*)fReplicants.ItemAt(index); 843 if (item == NULL) 844 return B_BAD_VALUE; 845 846 return _DeleteReplicant(item); 847 } 848 849 850 status_t 851 BShelf::DeleteReplicant(BMessage *data) 852 { 853 int32 index = replicant_data::IndexOf(&fReplicants, data); 854 855 replicant_data *item = (replicant_data*)fReplicants.ItemAt(index); 856 if (!item) 857 return B_BAD_VALUE; 858 859 return _DeleteReplicant(item); 860 } 861 862 863 status_t 864 BShelf::DeleteReplicant(int32 index) 865 { 866 replicant_data *item = (replicant_data*)fReplicants.ItemAt(index); 867 if (!item) 868 return B_BAD_INDEX; 869 870 return _DeleteReplicant(item); 871 } 872 873 874 int32 875 BShelf::CountReplicants() const 876 { 877 return fReplicants.CountItems(); 878 } 879 880 881 BMessage * 882 BShelf::ReplicantAt(int32 index, BView **_view, uint32 *_uniqueID, 883 status_t *_error) const 884 { 885 replicant_data *item = (replicant_data*)fReplicants.ItemAt(index); 886 if (item == NULL) { 887 // no replicant found 888 if (_view) 889 *_view = NULL; 890 if (_uniqueID) 891 *_uniqueID = ~0UL; 892 if (_error) 893 *_error = B_BAD_INDEX; 894 895 return NULL; 896 } 897 898 if (_view) 899 *_view = item->view; 900 if (_uniqueID) 901 *_uniqueID = item->id; 902 if (_error) 903 *_error = item->error; 904 905 return item->message; 906 } 907 908 909 int32 910 BShelf::IndexOf(const BView* replicantView) const 911 { 912 return replicant_data::IndexOf(&fReplicants, replicantView, false); 913 } 914 915 916 int32 917 BShelf::IndexOf(const BMessage *archive) const 918 { 919 return replicant_data::IndexOf(&fReplicants, archive); 920 } 921 922 923 int32 924 BShelf::IndexOf(uint32 id) const 925 { 926 return replicant_data::IndexOf(&fReplicants, id); 927 } 928 929 930 bool 931 BShelf::CanAcceptReplicantMessage(BMessage*) const 932 { 933 return true; 934 } 935 936 937 bool 938 BShelf::CanAcceptReplicantView(BRect, BView*, BMessage*) const 939 { 940 return true; 941 } 942 943 944 BPoint 945 BShelf::AdjustReplicantBy(BRect, BMessage*) const 946 { 947 return B_ORIGIN; 948 } 949 950 951 void 952 BShelf::ReplicantDeleted(int32 index, const BMessage *archive, 953 const BView *replicant) 954 { 955 } 956 957 958 void 959 _ReservedShelf1__6BShelfFv(BShelf *const, int32, const BMessage*, const BView*) 960 { 961 } 962 963 964 void BShelf::_ReservedShelf2() {} 965 void BShelf::_ReservedShelf3() {} 966 void BShelf::_ReservedShelf4() {} 967 void BShelf::_ReservedShelf5() {} 968 void BShelf::_ReservedShelf6() {} 969 void BShelf::_ReservedShelf7() {} 970 void BShelf::_ReservedShelf8() {} 971 972 973 BShelf::BShelf(const BShelf&) 974 { 975 } 976 977 978 BShelf & 979 BShelf::operator=(const BShelf &) 980 { 981 return *this; 982 } 983 984 985 status_t 986 BShelf::_Archive(BMessage *data) const 987 { 988 BHandler::Archive(data); 989 990 data->AddBool("_zom_dsp", DisplaysZombies()); 991 data->AddBool("_zom_alw", AllowsZombies()); 992 data->AddInt32("_sg_cnt", fGenCount); 993 994 BMessage archive('ARCV'); 995 996 // TODO archive replicants 997 998 return B_ERROR; 999 } 1000 1001 1002 void 1003 BShelf::_InitData(BEntry *entry, BDataIO *stream, BView *view, 1004 bool allowDrags) 1005 { 1006 fContainerView = view; 1007 fStream = NULL; 1008 fEntry = entry; 1009 fFilter = NULL; 1010 fGenCount = 1; 1011 fAllowDragging = allowDrags; 1012 fDirty = true; 1013 fDisplayZombies = false; 1014 fAllowZombies = true; 1015 fTypeEnforced = false; 1016 1017 if (entry) 1018 fStream = new BFile(entry, B_READ_ONLY); 1019 else 1020 fStream = stream; 1021 1022 fFilter = new ShelfContainerViewFilter(this, fContainerView); 1023 1024 fContainerView->AddFilter(fFilter); 1025 fContainerView->_SetShelf(this); 1026 1027 if (fStream) { 1028 BMessage archive; 1029 1030 if (archive.Unflatten(fStream) == B_OK) { 1031 bool allowZombies; 1032 if (archive.FindBool("_zom_dsp", &allowZombies) != B_OK) 1033 allowZombies = false; 1034 1035 SetDisplaysZombies(allowZombies); 1036 1037 if (archive.FindBool("_zom_alw", &allowZombies) != B_OK) 1038 allowZombies = true; 1039 1040 SetAllowsZombies(allowZombies); 1041 1042 int32 genCount; 1043 if (!archive.FindInt32("_sg_cnt", &genCount)) 1044 genCount = 1; 1045 1046 // TODO find archived replicants 1047 } 1048 } 1049 } 1050 1051 1052 status_t 1053 BShelf::_DeleteReplicant(replicant_data* item) 1054 { 1055 bool loadedImage = item->message->FindBool(""); 1056 1057 BView *view = item->view; 1058 if (view == NULL) 1059 view = item->zombie_view; 1060 1061 if (view) 1062 view->RemoveSelf(); 1063 1064 if (item->dragger) 1065 item->dragger->RemoveSelf(); 1066 1067 int32 index = replicant_data::IndexOf(&fReplicants, item->message); 1068 1069 // TODO: Test if it's ok here 1070 ReplicantDeleted(index, item->message, view); 1071 1072 fReplicants.RemoveItem(item); 1073 1074 if (loadedImage && item->image >= 0) 1075 unload_add_on(item->image); 1076 1077 delete item; 1078 1079 return B_OK; 1080 } 1081 1082 1083 status_t 1084 BShelf::_AddReplicant(BMessage *data, BPoint *location, uint32 uniqueID) 1085 { 1086 // Check shelf types if needed 1087 if (fTypeEnforced) { 1088 const char *shelfType = NULL; 1089 if (data->FindString("shelf_type", &shelfType) == B_OK && shelfType != NULL) { 1090 if (Name() && strcmp(shelfType, Name()) != 0) { 1091 printf("Replicant was rejected by BShelf: The BShelf's type and the Replicant's type don't match."); 1092 return send_reply(data, B_ERROR, uniqueID); 1093 } else { 1094 printf("Replicant was rejected by BShelf: Replicant indicated a <type> (%s), but the shelf does not.", shelfType); 1095 return send_reply(data, B_ERROR, uniqueID); 1096 } 1097 } else { 1098 printf("Replicant was rejected by BShelf: Replicant did not have a <type>"); 1099 return send_reply(data, B_ERROR, uniqueID); 1100 } 1101 } 1102 1103 // Check if we can accept this message 1104 if (!CanAcceptReplicantMessage(data)) { 1105 printf("Replicant was rejected by BShelf: CanAcceptReplicant() returned false"); 1106 return send_reply(data, B_ERROR, uniqueID); 1107 } 1108 1109 // Check if we can create multiple instances 1110 if (data->FindBool("be:load_each_time")) { 1111 const char *className = NULL; 1112 const char *addOn = NULL; 1113 1114 if (data->FindString("class", &className) == B_OK 1115 && data->FindString("add_on", &addOn) == B_OK) { 1116 int32 i = 0; 1117 replicant_data *item; 1118 const char *replicantClassName = NULL; 1119 const char *replicantAddOn = NULL; 1120 1121 while ((item = (replicant_data*)fReplicants.ItemAt(i++)) != NULL) { 1122 if (item->message->FindString("class", &replicantClassName) == B_OK 1123 && item->message->FindString("add_on", &replicantAddOn) == B_OK 1124 && !strcmp(className, replicantClassName) 1125 && addOn != NULL && replicantAddOn != NULL 1126 && !strcmp(addOn, replicantAddOn)) { 1127 printf("Replicant was rejected. Unique replicant already exists. class=%s, signature=%s", 1128 replicantClassName, replicantAddOn); 1129 return send_reply(data, B_ERROR, uniqueID); 1130 } 1131 } 1132 } 1133 } 1134 1135 BDragger* dragger = NULL; 1136 BView* replicant = NULL; 1137 BDragger::relation relation = BDragger::TARGET_UNKNOWN; 1138 _BZombieReplicantView_* zombie = NULL; 1139 1140 // Instantiate the object, if this fails we have a zombie 1141 image_id image; 1142 BArchivable *archivable = instantiate_object(data, &image); 1143 if (archivable) { 1144 BView *view = dynamic_cast<BView*>(archivable); 1145 BPoint point; 1146 1147 if (location) 1148 point = *location; 1149 else 1150 point = view->Frame().LeftTop(); 1151 1152 // TODO: test me -- there seems to be lots of bugs parked here! 1153 1154 // Check if we have a dragger archived as "__widget" inside the message 1155 BMessage widget; 1156 if (data->FindMessage("__widget", &widget) == B_OK) { 1157 image_id draggerImage = B_ERROR; 1158 replicant = view; 1159 dragger = dynamic_cast<BDragger*>(instantiate_object(&widget, &draggerImage)); 1160 if (dragger != NULL) { 1161 // Replicant is either a sibling or unknown 1162 dragger->_SetViewToDrag(replicant); 1163 relation = BDragger::TARGET_IS_SIBLING; 1164 } 1165 } else { 1166 // Replicant is child of the dragger 1167 if ((dragger = dynamic_cast<BDragger*>(view)) != NULL) { 1168 replicant = dragger->ChildAt(0); 1169 dragger->_SetViewToDrag(replicant); 1170 relation = BDragger::TARGET_IS_CHILD; 1171 } else { 1172 // Replicant is parent of the dragger 1173 replicant = view; 1174 dragger = dynamic_cast<BDragger*>(replicant->FindView("_dragger_")); 1175 1176 if (dragger) 1177 dragger->_SetViewToDrag(replicant); 1178 1179 relation = BDragger::TARGET_IS_PARENT; 1180 } 1181 } 1182 1183 if (dragger != NULL) 1184 dragger->_SetShelf(this); 1185 1186 BRect frame; 1187 if (relation != BDragger::TARGET_IS_CHILD) { 1188 frame = replicant->Frame().OffsetToCopy(point); 1189 fContainerView->AddChild(replicant); 1190 } else 1191 frame = dragger->Frame().OffsetToCopy(point); 1192 1193 if (!CanAcceptReplicantView(frame, replicant, data)) { 1194 // the view has not been accepted 1195 1196 if (relation == BDragger::TARGET_IS_PARENT 1197 || relation == BDragger::TARGET_IS_SIBLING) 1198 delete replicant; 1199 if (relation == BDragger::TARGET_IS_CHILD 1200 || relation == BDragger::TARGET_IS_SIBLING) 1201 delete dragger; 1202 1203 return send_reply(data, B_ERROR, uniqueID); 1204 } 1205 1206 BPoint adjust = AdjustReplicantBy(frame, data); 1207 1208 // TODO: that's probably not correct for all relations (or any?) 1209 view->MoveTo(point + adjust); 1210 1211 // if it's a sibling or a child, we need to add the dragger 1212 if (relation == BDragger::TARGET_IS_SIBLING || relation == BDragger::TARGET_IS_CHILD) 1213 fContainerView->AddChild(dragger); 1214 1215 replicant->AddFilter(new ReplicantViewFilter(this, replicant)); 1216 } else if (fDisplayZombies && fAllowZombies) { 1217 // TODO: the zombies must be adjusted and moved as well! 1218 BRect frame; 1219 if (data->FindRect("_frame", &frame) != B_OK) 1220 frame = BRect(); 1221 1222 if (data->WasDropped()) { 1223 BPoint dropPoint, offset; 1224 dropPoint = data->DropPoint(&offset); 1225 1226 frame.OffsetTo(B_ORIGIN); 1227 frame.OffsetTo(fContainerView->ConvertFromScreen(dropPoint) - offset); 1228 1229 zombie = new _BZombieReplicantView_(frame, B_ERROR); 1230 1231 frame.OffsetTo(B_ORIGIN); 1232 1233 dragger = new BDragger(frame, zombie); 1234 dragger->_SetShelf(this); 1235 dragger->_SetZombied(true); 1236 1237 zombie->AddChild(dragger); 1238 zombie->SetArchive(data); 1239 zombie->AddFilter(new ReplicantViewFilter(this, zombie)); 1240 1241 fContainerView->AddChild(zombie); 1242 } 1243 } 1244 1245 data->RemoveName("_drop_point_"); 1246 data->RemoveName("_drop_offset_"); 1247 1248 replicant_data *item = new replicant_data(data, replicant, dragger, relation, 1249 uniqueID, image); 1250 1251 item->error = B_OK; 1252 item->zombie_view = zombie; 1253 1254 fReplicants.AddItem(item); 1255 1256 return send_reply(data, B_OK, uniqueID); 1257 } 1258 1259 1260 status_t 1261 BShelf::_GetProperty(BMessage *msg, BMessage *reply) 1262 { 1263 uint32 ID; 1264 status_t err = B_ERROR; 1265 BView *replicant = NULL; 1266 switch (msg->what) { 1267 case B_INDEX_SPECIFIER: { 1268 int32 index = -1; 1269 if (msg->FindInt32("index", &index)!=B_OK) 1270 break; 1271 ReplicantAt(index, &replicant, &ID, &err); 1272 break; 1273 } 1274 case B_REVERSE_INDEX_SPECIFIER: { 1275 int32 rindex; 1276 if (msg->FindInt32("index", &rindex) != B_OK) 1277 break; 1278 ReplicantAt(CountReplicants() - rindex, &replicant, &ID, &err); 1279 break; 1280 } 1281 case B_NAME_SPECIFIER: { 1282 const char *name; 1283 if (msg->FindString("name", &name) != B_OK) 1284 break; 1285 for (int32 i=0; i<CountReplicants(); i++) { 1286 BView *view = NULL; 1287 ReplicantAt(i, &view, &ID, &err); 1288 if (err == B_OK) { 1289 if (view->Name() != NULL && 1290 strlen(view->Name()) == strlen(name) && !strcmp(view->Name(), name)) { 1291 replicant = view; 1292 break; 1293 } 1294 err = B_NAME_NOT_FOUND; 1295 } 1296 } 1297 break; 1298 } 1299 case B_ID_SPECIFIER: { 1300 uint32 id; 1301 if (msg->FindInt32("id", (int32 *)&id) != B_OK) 1302 break; 1303 for (int32 i=0; i<CountReplicants(); i++) { 1304 BView *view = NULL; 1305 ReplicantAt(i, &view, &ID, &err); 1306 if (err == B_OK) { 1307 if (ID == id) { 1308 replicant = view; 1309 break; 1310 } 1311 err = B_NAME_NOT_FOUND; 1312 } 1313 } 1314 break; 1315 } 1316 default: 1317 break; 1318 } 1319 1320 if (replicant) { 1321 reply->AddInt32("index", IndexOf(replicant)); 1322 reply->AddInt32("ID", ID); 1323 } 1324 1325 return err; 1326 } 1327