1 /* 2 * Copyright 2001-2005, 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 */ 9 10 /** BShelf stores replicant views that are dropped onto it */ 11 12 13 #include <Beep.h> 14 #include <Dragger.h> 15 #include <Entry.h> 16 #include <File.h> 17 #include <Looper.h> 18 #include <Message.h> 19 #include <MessageFilter.h> 20 #include <Messenger.h> 21 #include <Point.h> 22 #include <Rect.h> 23 #include <Shelf.h> 24 #include <View.h> 25 26 #include <ZombieReplicantView.h> 27 28 #include <stdio.h> 29 #include <string.h> 30 31 32 extern "C" void _ReservedShelf1__6BShelfFv(BShelf *const, int32, 33 const BMessage*, const BView*); 34 35 36 class _rep_data_ { 37 private: 38 friend class BShelf; 39 40 _rep_data_(BMessage *message, BView *view, BDragger *dragger, 41 BDragger::relation relation, unsigned long id, image_id image); 42 _rep_data_(); 43 44 static _rep_data_* find(BList const *list, BMessage const *msg); 45 static _rep_data_* find(BList const *list, BView const *view, bool allowZombie); 46 static _rep_data_* find(BList const *list, unsigned long id); 47 48 static int32 index_of(BList const *list, BMessage const *msg); 49 static int32 index_of(BList const *list, BView const *view, bool allowZombie); 50 static int32 index_of(BList const *list, unsigned long id); 51 52 BMessage *fMessage; 53 BView *fView; 54 BDragger *fDragger; 55 BDragger::relation fRelation; 56 unsigned long fId; 57 image_id fImage; 58 status_t fError; 59 BView *fZombieView; 60 }; 61 62 63 class _TContainerViewFilter_ : public BMessageFilter { 64 public: 65 _TContainerViewFilter_(BShelf *shelf, BView *view); 66 virtual ~_TContainerViewFilter_(); 67 68 filter_result Filter(BMessage *msg, BHandler **handler); 69 filter_result ObjectDropFilter(BMessage *msg, BHandler **handler); 70 71 protected: 72 BShelf *fShelf; 73 BView *fView; 74 }; 75 76 77 // #pragma mark - 78 79 80 _rep_data_::_rep_data_(BMessage *message, BView *view, BDragger *dragger, 81 BDragger::relation relation, unsigned long id, image_id image) 82 : 83 fMessage(message), 84 fView(view), 85 fDragger(NULL), 86 fRelation(relation), 87 fId(id), 88 fImage(image), 89 fError(B_OK), 90 fZombieView(NULL) 91 { 92 } 93 94 95 _rep_data_::_rep_data_() 96 : 97 fMessage(NULL), 98 fView(NULL), 99 fDragger(NULL), 100 fRelation(BDragger::TARGET_UNKNOWN), 101 fId(0), 102 fError(B_ERROR), 103 fZombieView(NULL) 104 { 105 } 106 107 108 //static 109 _rep_data_ * 110 _rep_data_::find(BList const *list, BMessage const *msg) 111 { 112 int32 i = 0; 113 _rep_data_ *item; 114 while ((item = (_rep_data_*)list->ItemAt(i++)) != NULL) { 115 if (item->fMessage == msg) 116 return item; 117 } 118 119 return NULL; 120 } 121 122 123 //static 124 _rep_data_ * 125 _rep_data_::find(BList const *list, BView const *view, bool allowZombie) 126 { 127 int32 i = 0; 128 _rep_data_ *item; 129 while ((item = (_rep_data_*)list->ItemAt(i++)) != NULL) { 130 if (item->fView == view) 131 return item; 132 133 if (allowZombie && item->fZombieView == view) 134 return item; 135 } 136 137 return NULL; 138 } 139 140 141 //static 142 _rep_data_ * 143 _rep_data_::find(BList const *list, unsigned long id) 144 { 145 int32 i = 0; 146 _rep_data_ *item; 147 while ((item = (_rep_data_*)list->ItemAt(i++)) != NULL) { 148 if (item->fId == id) 149 return item; 150 } 151 152 return NULL; 153 } 154 155 156 //static 157 int32 158 _rep_data_::index_of(BList const *list, BMessage const *msg) 159 { 160 int32 i = 0; 161 _rep_data_ *item; 162 while ((item = (_rep_data_*)list->ItemAt(i++)) != NULL) { 163 if (item->fMessage == msg) 164 return i; 165 } 166 167 return -1; 168 } 169 170 171 //static 172 int32 173 _rep_data_::index_of(BList const *list, BView const *view, bool allowZombie) 174 { 175 int32 i = 0; 176 _rep_data_ *item; 177 while ((item = (_rep_data_*)list->ItemAt(i++)) != NULL) { 178 if (item->fView == view) 179 return i; 180 181 if (allowZombie && item->fZombieView == view) 182 return i; 183 } 184 185 return -1; 186 } 187 188 189 //static 190 int32 191 _rep_data_::index_of(BList const *list, unsigned long id) 192 { 193 int32 i = 0; 194 _rep_data_ *item; 195 while ((item = (_rep_data_*)list->ItemAt(i++)) != NULL) { 196 if (item->fId == id) 197 return i; 198 } 199 200 return -1; 201 } 202 203 204 // #pragma mark - 205 206 207 _TContainerViewFilter_::_TContainerViewFilter_(BShelf *shelf, BView *view) 208 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) 209 { 210 fShelf = shelf; 211 fView = view; 212 } 213 214 215 _TContainerViewFilter_::~_TContainerViewFilter_() 216 { 217 } 218 219 220 filter_result 221 _TContainerViewFilter_::Filter(BMessage *msg, BHandler **handler) 222 { 223 filter_result filter = B_DISPATCH_MESSAGE; 224 225 if (msg->what == B_ARCHIVED_OBJECT || 226 msg->what == B_ABOUT_REQUESTED) 227 return ObjectDropFilter(msg, handler); 228 229 return filter; 230 } 231 232 233 filter_result 234 _TContainerViewFilter_::ObjectDropFilter(BMessage *msg, BHandler **_handler) 235 { 236 BView *mouseView; 237 238 if (*_handler) 239 mouseView = dynamic_cast<BView*>(*_handler); 240 else 241 mouseView = NULL; 242 243 if (msg->WasDropped()) { 244 if (!fShelf->fAllowDragging) { 245 printf("Dragging replicants isn't allowed to this shelf."); 246 beep(); 247 return B_SKIP_MESSAGE; 248 } 249 } 250 251 BPoint point; 252 BPoint offset; 253 254 if (msg->WasDropped()) { 255 point = msg->DropPoint(&offset); 256 257 point = mouseView->ConvertFromScreen(point - offset); 258 } 259 260 BHandler *handler; 261 BLooper *looper; 262 handler = msg->ReturnAddress().Target(&looper); 263 264 BDragger *dragger; 265 266 if (Looper() == looper) { 267 if (handler) 268 dragger = dynamic_cast<BDragger*>(handler); 269 else 270 dragger = NULL; 271 272 if (dragger->fRelation == BDragger::TARGET_IS_CHILD) { 273 BRect rect = dragger->Frame(); 274 rect.OffsetTo(point); 275 point = fShelf->AdjustReplicantBy(rect, msg); 276 277 } else { 278 BRect rect = dragger->fTarget->Frame(); 279 rect.OffsetTo(point); 280 point = fShelf->AdjustReplicantBy(rect, msg); 281 } 282 283 if (dragger->fRelation == BDragger::TARGET_IS_PARENT) 284 dragger->fTarget->MoveTo(point); 285 else if (dragger->fRelation == BDragger::TARGET_IS_CHILD) 286 dragger->MoveTo(point); 287 else { 288 //TODO: TARGET_UNKNOWN/TARGET_SIBLING 289 } 290 291 } else { 292 if (fShelf->_RealAddReplicant(msg, &point, 0) == B_OK) 293 Looper()->DetachCurrentMessage(); 294 } 295 296 return B_SKIP_MESSAGE; 297 } 298 299 300 // #pragma mark - 301 302 303 class _TReplicantViewFilter_ : public BMessageFilter { 304 public: 305 _TReplicantViewFilter_(BShelf *shelf, BView *view) 306 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) 307 { 308 fShelf = shelf; 309 fView = view; 310 } 311 312 virtual ~_TReplicantViewFilter_() 313 { 314 } 315 316 filter_result Filter(BMessage *, BHandler **) 317 { 318 return B_DISPATCH_MESSAGE; 319 } 320 321 protected: 322 BShelf *fShelf; 323 BView *fView; 324 }; 325 326 327 // #pragma mark - 328 329 330 BShelf::BShelf(BView *view, bool allow_drags, const char *shelf_type) 331 : BHandler(shelf_type) 332 { 333 _InitData(NULL, NULL, view, allow_drags); 334 } 335 336 337 BShelf::BShelf(const entry_ref *ref, BView *view, bool allow_drags, 338 const char *shelf_type) 339 : BHandler(shelf_type) 340 { 341 _InitData(new BEntry(ref), NULL, view, allow_drags); 342 } 343 344 345 BShelf::BShelf(BDataIO *stream, BView *view, bool allow_drags, 346 const char *shelf_type) 347 : BHandler(shelf_type) 348 { 349 _InitData(NULL, stream, view, allow_drags); 350 } 351 352 353 BShelf::BShelf(BMessage *data) 354 : BHandler(data) 355 { 356 // TODO: Implement ? 357 } 358 359 360 BShelf::~BShelf() 361 { 362 Save(); 363 364 delete fEntry; 365 } 366 367 368 status_t 369 BShelf::Archive(BMessage *data, bool deep) const 370 { 371 return B_ERROR; 372 } 373 374 375 BArchivable * 376 BShelf::Instantiate(BMessage *data) 377 { 378 return NULL; 379 } 380 381 382 void 383 BShelf::MessageReceived(BMessage *msg) 384 { 385 } 386 387 388 status_t 389 BShelf::Save() 390 { 391 //TODO 392 return B_ERROR; 393 } 394 395 396 void 397 BShelf::SetDirty(bool state) 398 { 399 fDirty = state; 400 } 401 402 403 bool 404 BShelf::IsDirty() const 405 { 406 return fDirty; 407 } 408 409 410 BHandler * 411 BShelf::ResolveSpecifier(BMessage *msg, int32 index, 412 BMessage *specifier, int32 form, 413 const char *property) 414 { 415 //TODO 416 return NULL; 417 } 418 419 420 status_t 421 BShelf::GetSupportedSuites(BMessage *data) 422 { 423 //TODO 424 return B_ERROR; 425 } 426 427 428 status_t 429 BShelf::Perform(perform_code d, void *arg) 430 { 431 return BHandler::Perform(d, arg); 432 } 433 434 435 bool 436 BShelf::AllowsDragging() const 437 { 438 return fAllowDragging; 439 } 440 441 442 void 443 BShelf::SetAllowsDragging(bool state) 444 { 445 fAllowDragging = state; 446 } 447 448 449 bool 450 BShelf::AllowsZombies() const 451 { 452 return fAllowZombies; 453 } 454 455 456 void 457 BShelf::SetAllowsZombies(bool state) 458 { 459 fAllowZombies = state; 460 } 461 462 463 bool 464 BShelf::DisplaysZombies() const 465 { 466 return fDisplayZombies; 467 } 468 469 470 void 471 BShelf::SetDisplaysZombies(bool state) 472 { 473 fDisplayZombies = state; 474 } 475 476 477 bool 478 BShelf::IsTypeEnforced() const 479 { 480 return fTypeEnforced; 481 } 482 483 484 void 485 BShelf::SetTypeEnforced(bool state) 486 { 487 fTypeEnforced = state; 488 } 489 490 491 status_t 492 BShelf::SetSaveLocation(BDataIO *data_io) 493 { 494 fDirty = true; 495 496 if (fEntry) { 497 delete fEntry; 498 fEntry = NULL; 499 } 500 501 fStream = data_io; 502 503 return B_OK; 504 } 505 506 507 status_t 508 BShelf::SetSaveLocation(const entry_ref *ref) 509 { 510 fDirty = true; 511 512 if (fEntry) 513 delete fEntry; 514 else 515 fStream = NULL; 516 517 fEntry = new BEntry(ref); 518 519 return B_OK; 520 } 521 522 523 BDataIO * 524 BShelf::SaveLocation(entry_ref *ref) const 525 { 526 entry_ref entry; 527 528 if (fStream && ref) { 529 *ref = entry; 530 return fStream; 531 } 532 if (fEntry) { 533 fEntry->GetRef(&entry); 534 535 if (ref) 536 *ref = entry; 537 538 return NULL; 539 } 540 541 *ref = entry; 542 return NULL; 543 } 544 545 546 status_t 547 BShelf::AddReplicant(BMessage *data, BPoint location) 548 { 549 return _RealAddReplicant(data, &location, 0); 550 } 551 552 553 status_t 554 BShelf::DeleteReplicant(BView *replicant) 555 { 556 int32 index = _rep_data_::index_of(&fReplicants, replicant, true); 557 558 _rep_data_ *item = (_rep_data_*)fReplicants.ItemAt(index); 559 if (item == NULL) 560 return B_BAD_VALUE; 561 562 return _DeleteReplicant(item); 563 } 564 565 566 status_t 567 BShelf::DeleteReplicant(BMessage *data) 568 { 569 int32 index = _rep_data_::index_of(&fReplicants, data); 570 571 _rep_data_ *item = (_rep_data_*)fReplicants.ItemAt(index); 572 if (!item) 573 return B_BAD_VALUE; 574 575 return _DeleteReplicant(item); 576 } 577 578 579 status_t 580 BShelf::DeleteReplicant(int32 index) 581 { 582 _rep_data_ *item = (_rep_data_*)fReplicants.ItemAt(index); 583 if (!item) 584 return B_BAD_INDEX; 585 586 return _DeleteReplicant(item); 587 } 588 589 590 int32 591 BShelf::CountReplicants() const 592 { 593 return fReplicants.CountItems(); 594 } 595 596 597 BMessage * 598 BShelf::ReplicantAt(int32 index, BView **_view, uint32 *_uniqueID, 599 status_t *_error) const 600 { 601 _rep_data_ *item = (_rep_data_*)fReplicants.ItemAt(index); 602 if (item == NULL) { 603 // no replicant found 604 if (_view) 605 *_view = NULL; 606 if (_uniqueID) 607 *_uniqueID = ~0UL; 608 if (_error) 609 *_error = B_BAD_INDEX; 610 611 return NULL; 612 } 613 614 if (_view) 615 *_view = item->fView; 616 if (_uniqueID) 617 *_uniqueID = item->fId; 618 if (_error) 619 *_error = item->fError; 620 621 return item->fMessage; 622 } 623 624 625 int32 626 BShelf::IndexOf(const BView *replicant_view) const 627 { 628 return _rep_data_::index_of(&fReplicants, replicant_view, false); 629 } 630 631 632 int32 633 BShelf::IndexOf(const BMessage *archive) const 634 { 635 return _rep_data_::index_of(&fReplicants, archive); 636 } 637 638 639 int32 640 BShelf::IndexOf(uint32 id) const 641 { 642 return _rep_data_::index_of(&fReplicants, id); 643 } 644 645 646 bool 647 BShelf::CanAcceptReplicantMessage(BMessage*) const 648 { 649 return true; 650 } 651 652 653 bool 654 BShelf::CanAcceptReplicantView(BRect, BView*, BMessage*) const 655 { 656 return true; 657 } 658 659 660 BPoint 661 BShelf::AdjustReplicantBy(BRect, BMessage*) const 662 { 663 return B_ORIGIN; 664 } 665 666 667 void 668 BShelf::ReplicantDeleted(int32 index, const BMessage *archive, 669 const BView *replicant) 670 { 671 } 672 673 void 674 _ReservedShelf1__6BShelfFv(BShelf *const, int32, const BMessage*, 675 const BView*) 676 { 677 } 678 679 void BShelf::_ReservedShelf2() {} 680 void BShelf::_ReservedShelf3() {} 681 void BShelf::_ReservedShelf4() {} 682 void BShelf::_ReservedShelf5() {} 683 void BShelf::_ReservedShelf6() {} 684 void BShelf::_ReservedShelf7() {} 685 void BShelf::_ReservedShelf8() {} 686 687 688 BShelf::BShelf(const BShelf&) 689 { 690 } 691 692 693 BShelf & 694 BShelf::operator=(const BShelf &) 695 { 696 return *this; 697 } 698 699 700 status_t 701 BShelf::_Archive(BMessage *data) const 702 { 703 BHandler::Archive(data); 704 705 data->AddBool("_zom_dsp", DisplaysZombies()); 706 data->AddBool("_zom_alw", AllowsZombies()); 707 data->AddInt32("_sg_cnt", fGenCount); 708 709 BMessage archive('ARCV'); 710 711 // TODO archive replicants 712 713 return B_ERROR; 714 } 715 716 717 void 718 BShelf::_InitData(BEntry *entry, BDataIO *stream, BView *view, 719 bool allowDrags) 720 { 721 fContainerView = view; 722 fStream = NULL; 723 fEntry = entry; 724 fFilter = NULL; 725 fGenCount = 1; 726 fAllowDragging = allowDrags; 727 fDirty = true; 728 fDisplayZombies = false; 729 fAllowZombies = true; 730 fTypeEnforced = false; 731 732 if (entry) 733 fStream = new BFile(entry, B_READ_ONLY); 734 else 735 fStream = stream; 736 737 fFilter = new _TContainerViewFilter_(this, fContainerView); 738 739 fContainerView->AddFilter(fFilter); 740 fContainerView->set_shelf(this); 741 742 if (fStream) { 743 BMessage archive; 744 745 if (archive.Unflatten(fStream) == B_OK) { 746 bool allowZombies; 747 if (archive.FindBool("_zom_dsp", &allowZombies) != B_OK) 748 allowZombies = false; 749 750 SetDisplaysZombies(allowZombies); 751 752 if (archive.FindBool("_zom_alw", &allowZombies) != B_OK) 753 allowZombies = true; 754 755 SetAllowsZombies(allowZombies); 756 757 int32 genCount; 758 if (!archive.FindInt32("_sg_cnt", &genCount)) 759 genCount = 1; 760 761 // TODO find archived replicants 762 } 763 } 764 } 765 766 767 status_t 768 BShelf::_DeleteReplicant(_rep_data_* item) 769 { 770 bool loadedImage; 771 item->fMessage->FindBool("", &loadedImage); 772 773 BView *view = item->fView; 774 if (view == NULL) 775 view = item->fZombieView; 776 777 if (view) 778 view->RemoveSelf(); 779 780 if (item->fDragger) 781 item->fDragger->RemoveSelf(); 782 783 fReplicants.RemoveItem(item); 784 785 if (loadedImage && item->fImage >= 0) 786 unload_add_on(item->fImage); 787 788 delete item; 789 790 return B_OK; 791 } 792 793 794 status_t 795 BShelf::_RealAddReplicant(BMessage *data, BPoint *loc, uint32 uid) 796 { 797 BView *replicant = NULL; 798 BDragger *dragger = NULL; 799 BDragger::relation relation = BDragger::TARGET_UNKNOWN; 800 BMessage widget; 801 BMessage reply; 802 image_id image = B_ERROR; 803 image_id image2 = B_ERROR; 804 _BZombieReplicantView_ *zombie = NULL; 805 //bool wasDropped = data->WasDropped(); 806 const char *shelf_type = NULL; 807 808 data->FindString("shelf_type", &shelf_type); 809 810 // Check shelf types if needed 811 if (fTypeEnforced) { 812 if (shelf_type) { 813 if (Name() && strcmp(shelf_type, Name()) != 0) { 814 printf("Replicant was rejected by BShelf: The BShelf's type and the Replicant's type don't match."); 815 return B_ERROR; 816 817 } else { 818 printf("Replicant was rejected by BShelf: Replicant indicated a <type> (%s), but the shelf does not.", shelf_type); 819 return B_ERROR; 820 } 821 822 } else { 823 printf("Replicant was rejected by BShelf: Replicant did not have a <type>"); 824 return B_ERROR; 825 } 826 } 827 828 // Check if we can accept this message 829 if (!CanAcceptReplicantMessage(data)) 830 return B_ERROR; 831 832 // Check if we can create multiple instances 833 if (data->FindBool("be:load_each_time")) { 834 const char *_class = NULL; 835 const char *add_on = NULL; 836 837 if (data->FindString("class", &_class)) { 838 if (data->FindString("add_on", &add_on)) { 839 int32 i = 0; 840 _rep_data_ *item; 841 const char *rep_class = NULL; 842 const char *rep_add_on = NULL; 843 844 while ((item = (_rep_data_*)fReplicants.ItemAt(i++)) !=NULL) { 845 item->fMessage->FindString("class", &rep_class); 846 item->fMessage->FindString("add_on", &rep_add_on); 847 848 if (strcmp(_class, rep_class) == 0) { 849 if (add_on && rep_add_on && strcmp(_class, rep_class) == 0) 850 printf("Replicant was rejected. Unique replicant already exists. class=%s, signature=%s", 851 rep_class, rep_add_on); 852 } 853 } 854 } 855 } 856 } 857 858 // Instantiate the object, if this fails we have a zombie 859 BArchivable *archivable = instantiate_object(data, &image); 860 861 if (archivable) { 862 BView *view = dynamic_cast<BView*>(archivable); 863 BPoint point; 864 865 if (loc) 866 point = *loc; 867 else 868 point = view->Frame().LeftTop(); 869 870 // Check if we have a dragger archived as "__widget" inside the message 871 if (data->FindMessage("__widget", &widget) == B_OK) { 872 BArchivable *archivable2 = instantiate_object(&widget, &image2); 873 874 replicant = view; 875 876 if (archivable2) { 877 if ((dragger = dynamic_cast<BDragger*>(archivable2)) != NULL) { 878 // Replicant is either a sibling or unknown 879 dragger->SetViewToDrag(replicant); 880 } 881 } 882 } else { 883 // Replicant is child of the dragger 884 if ((dragger = dynamic_cast<BDragger*>(view)) != NULL) 885 dragger->SetViewToDrag(replicant = dragger->ChildAt(0)); 886 else { 887 // Replicant is parent of the dragger 888 replicant = view; 889 dragger = dynamic_cast<BDragger*>(replicant->FindView("_dragger_")); 890 891 if (dragger) 892 dragger->SetViewToDrag(replicant); 893 } 894 } 895 896 dragger->SetShelf(this); 897 898 AddFilter(new _TReplicantViewFilter_(this, replicant)); 899 900 fContainerView->AddChild(view); 901 902 } else if (fDisplayZombies && fAllowZombies) { 903 BRect _frame; 904 905 if (data->FindRect("_frame", &_frame) != B_OK) 906 _frame = BRect(); 907 908 if (data->WasDropped()) { 909 BPoint dropPoint, offset; 910 dropPoint = data->DropPoint(&offset); 911 912 _frame.OffsetTo(B_ORIGIN); 913 _frame.OffsetTo(fContainerView->ConvertFromScreen(dropPoint)-offset); 914 915 zombie = new _BZombieReplicantView_(_frame, B_ERROR); 916 917 _frame.OffsetTo(B_ORIGIN); 918 919 BDragger *dragger = new BDragger(_frame, zombie); 920 921 dragger->SetShelf(this); 922 dragger->SetZombied(true); 923 924 zombie->AddChild(dragger); 925 926 AddFilter(new _TReplicantViewFilter_(this, zombie)); 927 928 fContainerView->AddChild(zombie); 929 } 930 } 931 932 data->RemoveName("_drop_point_"); 933 data->RemoveName("_drop_offset_"); 934 935 _rep_data_ *item = new _rep_data_(data, replicant, dragger, relation, uid, 936 image); 937 938 item->fError = B_OK; 939 item->fZombieView = zombie; 940 941 if (zombie) 942 zombie->SetArchive(data); 943 944 fReplicants.AddItem(item); 945 946 if (data->IsSourceWaiting()) { 947 reply.AddInt32("id", uid); 948 reply.AddInt32("error", B_OK); 949 data->SendReply(&reply); 950 } 951 952 //TODO: 953 954 return B_ERROR; 955 } 956 957 958 status_t 959 BShelf::_GetProperty(BMessage *msg, BMessage *reply) 960 { 961 //TODO: Implement 962 return B_ERROR; 963 } 964