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