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 // #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 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 // TODO: Should we also delete the view ? 1080 1081 return B_OK; 1082 } 1083 1084 1085 status_t 1086 BShelf::_AddReplicant(BMessage *data, BPoint *location, uint32 uniqueID) 1087 { 1088 // Check shelf types if needed 1089 if (fTypeEnforced) { 1090 const char *shelfType = NULL; 1091 if (data->FindString("shelf_type", &shelfType) == B_OK 1092 && shelfType != NULL) { 1093 if (Name() && strcmp(shelfType, Name()) != 0) { 1094 printf("Replicant was rejected by BShelf: The BShelf's type and the Replicant's type don't match."); 1095 return send_reply(data, B_ERROR, uniqueID); 1096 } else { 1097 printf("Replicant was rejected by BShelf: Replicant indicated a <type> (%s), but the shelf does not.", shelfType); 1098 return send_reply(data, B_ERROR, uniqueID); 1099 } 1100 } else { 1101 printf("Replicant was rejected by BShelf: Replicant did not have a <type>"); 1102 return send_reply(data, B_ERROR, uniqueID); 1103 } 1104 } 1105 1106 // Check if we can accept this message 1107 if (!CanAcceptReplicantMessage(data)) { 1108 printf("Replicant was rejected by BShelf: CanAcceptReplicant() returned false"); 1109 return send_reply(data, B_ERROR, uniqueID); 1110 } 1111 1112 // Check if we can create multiple instances 1113 if (data->FindBool("be:load_each_time")) { 1114 const char *className = NULL; 1115 const char *addOn = NULL; 1116 1117 if (data->FindString("class", &className) == B_OK 1118 && data->FindString("add_on", &addOn) == B_OK) { 1119 int32 i = 0; 1120 replicant_data *item; 1121 const char *replicantClassName = NULL; 1122 const char *replicantAddOn = NULL; 1123 1124 while ((item = (replicant_data*)fReplicants.ItemAt(i++)) != NULL) { 1125 if (item->message->FindString("class", &replicantClassName) == B_OK 1126 && item->message->FindString("add_on", &replicantAddOn) == B_OK 1127 && !strcmp(className, replicantClassName) 1128 && addOn != NULL && replicantAddOn != NULL 1129 && !strcmp(addOn, replicantAddOn)) { 1130 printf("Replicant was rejected. Unique replicant already exists. class=%s, signature=%s", 1131 replicantClassName, replicantAddOn); 1132 return send_reply(data, B_ERROR, uniqueID); 1133 } 1134 } 1135 } 1136 } 1137 1138 BDragger* dragger = NULL; 1139 BView* replicant = NULL; 1140 BDragger::relation relation = BDragger::TARGET_UNKNOWN; 1141 _BZombieReplicantView_* zombie = NULL; 1142 1143 // Instantiate the object, if this fails we have a zombie 1144 image_id image; 1145 BArchivable *archivable = _InstantiateObject(data, &image); 1146 BView *view = dynamic_cast<BView*>(archivable); 1147 if (archivable != NULL && view == NULL) { 1148 printf("Replicant was rejected: it's not a view!"); 1149 return send_reply(data, B_ERROR, uniqueID); 1150 } 1151 1152 if (view != NULL) { 1153 BPoint point; 1154 if (location) 1155 point = *location; 1156 else 1157 point = view->Frame().LeftTop(); 1158 1159 // TODO: test me -- there seems to be lots of bugs parked here! 1160 1161 // Check if we have a dragger archived as "__widget" inside the message 1162 BMessage widget; 1163 if (data->FindMessage("__widget", &widget) == B_OK) { 1164 image_id draggerImage = B_ERROR; 1165 replicant = view; 1166 dragger = dynamic_cast<BDragger*>(_InstantiateObject(&widget, &draggerImage)); 1167 if (dragger != NULL) { 1168 // Replicant is either a sibling or unknown 1169 dragger->_SetViewToDrag(replicant); 1170 relation = BDragger::TARGET_IS_SIBLING; 1171 } 1172 } else { 1173 // Replicant is child of the dragger 1174 if ((dragger = dynamic_cast<BDragger*>(view)) != NULL) { 1175 replicant = dragger->ChildAt(0); 1176 dragger->_SetViewToDrag(replicant); 1177 relation = BDragger::TARGET_IS_CHILD; 1178 } else { 1179 // Replicant is parent of the dragger 1180 replicant = view; 1181 dragger = dynamic_cast<BDragger*>(replicant->FindView("_dragger_")); 1182 1183 if (dragger) 1184 dragger->_SetViewToDrag(replicant); 1185 1186 relation = BDragger::TARGET_IS_PARENT; 1187 } 1188 } 1189 1190 if (dragger != NULL) 1191 dragger->_SetShelf(this); 1192 1193 BRect frame; 1194 if (relation != BDragger::TARGET_IS_CHILD) { 1195 frame = replicant->Frame().OffsetToCopy(point); 1196 fContainerView->AddChild(replicant); 1197 } else 1198 frame = dragger->Frame().OffsetToCopy(point); 1199 1200 if (!CanAcceptReplicantView(frame, replicant, data)) { 1201 // the view has not been accepted 1202 1203 if (relation == BDragger::TARGET_IS_PARENT 1204 || relation == BDragger::TARGET_IS_SIBLING) { 1205 replicant->RemoveSelf(); 1206 delete replicant; 1207 } 1208 if (relation == BDragger::TARGET_IS_CHILD 1209 || relation == BDragger::TARGET_IS_SIBLING) { 1210 dragger->RemoveSelf(); 1211 delete dragger; 1212 } 1213 1214 return send_reply(data, B_ERROR, uniqueID); 1215 } 1216 1217 BPoint adjust = AdjustReplicantBy(frame, data); 1218 1219 // TODO: that's probably not correct for all relations (or any?) 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 replicant->AddFilter(new ReplicantViewFilter(this, replicant)); 1228 } else if (fDisplayZombies && fAllowZombies) { 1229 // TODO: the zombies must be adjusted and moved as well! 1230 BRect frame; 1231 if (data->FindRect("_frame", &frame) != B_OK) 1232 frame = BRect(); 1233 1234 if (data->WasDropped()) { 1235 BPoint dropPoint, offset; 1236 dropPoint = data->DropPoint(&offset); 1237 1238 frame.OffsetTo(B_ORIGIN); 1239 frame.OffsetTo(fContainerView->ConvertFromScreen(dropPoint) - offset); 1240 1241 zombie = new _BZombieReplicantView_(frame, B_ERROR); 1242 1243 frame.OffsetTo(B_ORIGIN); 1244 1245 dragger = new BDragger(frame, zombie); 1246 dragger->_SetShelf(this); 1247 dragger->_SetZombied(true); 1248 1249 zombie->AddChild(dragger); 1250 zombie->SetArchive(data); 1251 zombie->AddFilter(new ReplicantViewFilter(this, zombie)); 1252 1253 fContainerView->AddChild(zombie); 1254 } 1255 } else if (!fAllowZombies) { 1256 // There was no view, and we're not allowed to have any zombies 1257 // in the house 1258 return send_reply(data, B_ERROR, uniqueID); 1259 } 1260 1261 data->RemoveName("_drop_point_"); 1262 data->RemoveName("_drop_offset_"); 1263 1264 replicant_data *item = new replicant_data(data, replicant, dragger, 1265 relation, uniqueID, image); 1266 1267 item->error = B_OK; 1268 item->zombie_view = zombie; 1269 1270 fReplicants.AddItem(item); 1271 1272 return send_reply(data, B_OK, uniqueID); 1273 } 1274 1275 1276 status_t 1277 BShelf::_GetProperty(BMessage *msg, BMessage *reply) 1278 { 1279 uint32 ID; 1280 status_t err = B_ERROR; 1281 BView *replicant = NULL; 1282 switch (msg->what) { 1283 case B_INDEX_SPECIFIER: { 1284 int32 index = -1; 1285 if (msg->FindInt32("index", &index)!=B_OK) 1286 break; 1287 ReplicantAt(index, &replicant, &ID, &err); 1288 break; 1289 } 1290 case B_REVERSE_INDEX_SPECIFIER: { 1291 int32 rindex; 1292 if (msg->FindInt32("index", &rindex) != B_OK) 1293 break; 1294 ReplicantAt(CountReplicants() - rindex, &replicant, &ID, &err); 1295 break; 1296 } 1297 case B_NAME_SPECIFIER: { 1298 const char *name; 1299 if (msg->FindString("name", &name) != B_OK) 1300 break; 1301 for (int32 i=0; i<CountReplicants(); i++) { 1302 BView *view = NULL; 1303 ReplicantAt(i, &view, &ID, &err); 1304 if (err == B_OK) { 1305 if (view->Name() != NULL && 1306 strlen(view->Name()) == strlen(name) && !strcmp(view->Name(), name)) { 1307 replicant = view; 1308 break; 1309 } 1310 err = B_NAME_NOT_FOUND; 1311 } 1312 } 1313 break; 1314 } 1315 case B_ID_SPECIFIER: { 1316 uint32 id; 1317 if (msg->FindInt32("id", (int32 *)&id) != B_OK) 1318 break; 1319 for (int32 i=0; i<CountReplicants(); i++) { 1320 BView *view = NULL; 1321 ReplicantAt(i, &view, &ID, &err); 1322 if (err == B_OK) { 1323 if (ID == id) { 1324 replicant = view; 1325 break; 1326 } 1327 err = B_NAME_NOT_FOUND; 1328 } 1329 } 1330 break; 1331 } 1332 default: 1333 break; 1334 } 1335 1336 if (replicant) { 1337 reply->AddInt32("index", IndexOf(replicant)); 1338 reply->AddInt32("ID", ID); 1339 } 1340 1341 return err; 1342 } 1343 1344 1345 /* static */ 1346 BArchivable * 1347 BShelf::_InstantiateObject(BMessage *archive, image_id *image) 1348 { 1349 // Stay on the safe side. The constructor called by instantiate_object 1350 // could throw an exception, which we catch here. Otherwise our calling app 1351 // could die without notice. 1352 try { 1353 return instantiate_object(archive, image); 1354 } catch (...) { 1355 return NULL; 1356 } 1357 } 1358 1359