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