2 * Copyright 2001-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
6 * Marc Flerackers (mflerackers@androme.be)
7 * Axel Dörfler, axeld@pinc-software.de
10 * Alexandre Deckner, alex@zappotek.com
13 /*! BShelf stores replicant views that are dropped onto it */
19 #include <AutoDeleter.h>
27 #include <MessageFilter.h>
28 #include <Messenger.h>
30 #include <PropertyInfo.h>
35 #include <ViewPrivate.h>
37 #include "ZombieReplicantView.h"
48 typedef std::map
<BString
, std::pair
<image_id
, int32
> > LoadedImageMap
;
51 LoadedImageMap images
;
55 fLock("BShelf loaded image map")
69 static LoadedImages
* Default()
71 if (sDefaultInstance
== NULL
)
72 pthread_once(&sDefaultInitOnce
, &_InitSingleton
);
74 return sDefaultInstance
;
78 static void _InitSingleton()
80 sDefaultInstance
= new LoadedImages
;
86 static pthread_once_t sDefaultInitOnce
;
87 static LoadedImages
* sDefaultInstance
;
90 pthread_once_t
LoadedImages::sDefaultInitOnce
= PTHREAD_ONCE_INIT
;
91 LoadedImages
* LoadedImages::sDefaultInstance
= NULL
;
93 } // unnamed namespace
96 static property_info sShelfPropertyList
[] = {
99 { B_COUNT_PROPERTIES
, B_CREATE_PROPERTY
},
100 { B_DIRECT_SPECIFIER
},
106 { B_DELETE_PROPERTY
, B_GET_PROPERTY
},
107 { B_INDEX_SPECIFIER
, B_REVERSE_INDEX_SPECIFIER
, B_NAME_SPECIFIER
, B_ID_SPECIFIER
},
114 { B_INDEX_SPECIFIER
, B_REVERSE_INDEX_SPECIFIER
, B_NAME_SPECIFIER
, B_ID_SPECIFIER
},
115 "... of Replicant {index | name | id} of ...", 0,
121 static property_info sReplicantPropertyList
[] = {
125 { B_DIRECT_SPECIFIER
},
126 NULL
, 0, { B_INT32_TYPE
}
132 { B_DIRECT_SPECIFIER
},
133 NULL
, 0, { B_STRING_TYPE
}
139 { B_DIRECT_SPECIFIER
},
140 NULL
, 0, { B_STRING_TYPE
}
146 { B_DIRECT_SPECIFIER
},
147 NULL
, 0, { B_PROPERTY_INFO_TYPE
}
153 { B_DIRECT_SPECIFIER
},
163 struct replicant_data
{
164 replicant_data(BMessage
*message
, BView
*view
, BDragger
*dragger
,
165 BDragger::relation relation
, unsigned long id
);
169 static replicant_data
* Find(BList
const *list
, BMessage
const *msg
);
170 static replicant_data
* Find(BList
const *list
, BView
const *view
, bool allowZombie
);
171 static replicant_data
* Find(BList
const *list
, unsigned long id
);
173 static int32
IndexOf(BList
const *list
, BMessage
const *msg
);
174 static int32
IndexOf(BList
const *list
, BView
const *view
, bool allowZombie
);
175 static int32
IndexOf(BList
const *list
, unsigned long id
);
177 status_t
Archive(BMessage
*msg
);
182 BDragger::relation relation
;
188 class ShelfContainerViewFilter
: public BMessageFilter
{
190 ShelfContainerViewFilter(BShelf
*shelf
, BView
*view
);
192 filter_result
Filter(BMessage
*msg
, BHandler
**handler
);
195 filter_result
_ObjectDropFilter(BMessage
*msg
, BHandler
**handler
);
201 class ReplicantViewFilter
: public BMessageFilter
{
203 ReplicantViewFilter(BShelf
*shelf
, BView
*view
);
205 filter_result
Filter(BMessage
*message
, BHandler
**handler
);
212 } // namespace BPrivate
215 using BPrivate::replicant_data
;
216 using BPrivate::ReplicantViewFilter
;
217 using BPrivate::ShelfContainerViewFilter
;
223 /*! \brief Helper function for BShelf::_AddReplicant()
226 send_reply(BMessage
* message
, status_t status
, uint32 uniqueID
)
228 if (message
->IsSourceWaiting()) {
229 BMessage
reply(B_REPLY
);
230 reply
.AddInt32("id", uniqueID
);
231 reply
.AddInt32("error", status
);
232 message
->SendReply(&reply
);
240 find_replicant(BList
&list
, const char *className
, const char *addOn
)
243 replicant_data
*item
;
244 while ((item
= (replicant_data
*)list
.ItemAt(i
++)) != NULL
) {
245 const char *replicantClassName
;
246 const char *replicantAddOn
;
247 if (item
->message
->FindString("class", &replicantClassName
) == B_OK
248 && item
->message
->FindString("add_on", &replicantAddOn
) == B_OK
249 && !strcmp(className
, replicantClassName
)
250 && addOn
!= NULL
&& replicantAddOn
!= NULL
251 && !strcmp(addOn
, replicantAddOn
))
261 replicant_data::replicant_data(BMessage
*_message
, BView
*_view
, BDragger
*_dragger
,
262 BDragger::relation _relation
, unsigned long _id
)
275 replicant_data::replicant_data()
280 relation(BDragger::TARGET_UNKNOWN
),
287 replicant_data::~replicant_data()
293 replicant_data::Archive(BMessage
* msg
)
295 status_t result
= B_OK
;
298 result
= view
->Archive(&archive
);
299 else if (zombie_view
)
300 result
= zombie_view
->Archive(&archive
);
305 msg
->AddInt32("uniqueid", id
);
307 msg
->AddMessage("message", &archive
);
309 pos
= view
->Frame().LeftTop();
310 else if (zombie_view
)
311 pos
= zombie_view
->Frame().LeftTop();
312 msg
->AddPoint("position", pos
);
319 replicant_data::Find(BList
const *list
, BMessage
const *msg
)
322 replicant_data
*item
;
323 while ((item
= (replicant_data
*)list
->ItemAt(i
++)) != NULL
) {
324 if (item
->message
== msg
)
334 replicant_data::Find(BList
const *list
, BView
const *view
, bool allowZombie
)
337 replicant_data
*item
;
338 while ((item
= (replicant_data
*)list
->ItemAt(i
++)) != NULL
) {
339 if (item
->view
== view
)
342 if (allowZombie
&& item
->zombie_view
== view
)
352 replicant_data::Find(BList
const *list
, unsigned long id
)
355 replicant_data
*item
;
356 while ((item
= (replicant_data
*)list
->ItemAt(i
++)) != NULL
) {
367 replicant_data::IndexOf(BList
const *list
, BMessage
const *msg
)
370 replicant_data
*item
;
371 while ((item
= (replicant_data
*)list
->ItemAt(i
)) != NULL
) {
372 if (item
->message
== msg
)
383 replicant_data::IndexOf(BList
const *list
, BView
const *view
, bool allowZombie
)
386 replicant_data
*item
;
387 while ((item
= (replicant_data
*)list
->ItemAt(i
)) != NULL
) {
388 if (item
->view
== view
)
391 if (allowZombie
&& item
->zombie_view
== view
)
402 replicant_data::IndexOf(BList
const *list
, unsigned long id
)
405 replicant_data
*item
;
406 while ((item
= (replicant_data
*)list
->ItemAt(i
)) != NULL
) {
419 ShelfContainerViewFilter::ShelfContainerViewFilter(BShelf
*shelf
, BView
*view
)
420 : BMessageFilter(B_ANY_DELIVERY
, B_ANY_SOURCE
),
428 ShelfContainerViewFilter::Filter(BMessage
*msg
, BHandler
**handler
)
430 filter_result filter
= B_DISPATCH_MESSAGE
;
432 if (msg
->what
== B_ARCHIVED_OBJECT
433 || msg
->what
== B_ABOUT_REQUESTED
)
434 return _ObjectDropFilter(msg
, handler
);
441 ShelfContainerViewFilter::_ObjectDropFilter(BMessage
*msg
, BHandler
**_handler
)
443 BView
*mouseView
= NULL
;
445 mouseView
= dynamic_cast<BView
*>(*_handler
);
447 if (msg
->WasDropped()) {
448 if (!fShelf
->fAllowDragging
)
449 return B_SKIP_MESSAGE
;
455 if (msg
->WasDropped()) {
456 point
= msg
->DropPoint(&offset
);
457 point
= mouseView
->ConvertFromScreen(point
- offset
);
460 BLooper
*looper
= NULL
;
461 BHandler
*handler
= msg
->ReturnAddress().Target(&looper
);
463 if (Looper() == looper
) {
464 BDragger
*dragger
= NULL
;
466 dragger
= dynamic_cast<BDragger
*>(handler
);
469 if (dragger
->fRelation
== BDragger::TARGET_IS_CHILD
)
470 rect
= dragger
->Frame();
472 rect
= dragger
->fTarget
->Frame();
473 rect
.OffsetTo(point
);
474 point
= rect
.LeftTop() + fShelf
->AdjustReplicantBy(rect
, msg
);
476 if (dragger
->fRelation
== BDragger::TARGET_IS_PARENT
)
477 dragger
->fTarget
->MoveTo(point
);
478 else if (dragger
->fRelation
== BDragger::TARGET_IS_CHILD
)
479 dragger
->MoveTo(point
);
481 //TODO: TARGET_UNKNOWN/TARGET_SIBLING
485 if (fShelf
->_AddReplicant(msg
, &point
, fShelf
->fGenCount
++) == B_OK
)
486 Looper()->DetachCurrentMessage();
489 return B_SKIP_MESSAGE
;
496 ReplicantViewFilter::ReplicantViewFilter(BShelf
*shelf
, BView
*view
)
497 : BMessageFilter(B_ANY_DELIVERY
, B_ANY_SOURCE
),
505 ReplicantViewFilter::Filter(BMessage
*message
, BHandler
**handler
)
507 if (message
->what
== kDeleteReplicant
) {
510 message
->AddPointer("_target", fView
);
512 return B_DISPATCH_MESSAGE
;
519 BShelf::BShelf(BView
*view
, bool allowDrags
, const char *shelfType
)
520 : BHandler(shelfType
)
522 _InitData(NULL
, NULL
, view
, allowDrags
);
526 BShelf::BShelf(const entry_ref
*ref
, BView
*view
, bool allowDrags
,
527 const char *shelfType
)
528 : BHandler(shelfType
)
530 _InitData(new BEntry(ref
), NULL
, view
, allowDrags
);
534 BShelf::BShelf(BDataIO
*stream
, BView
*view
, bool allowDrags
,
535 const char *shelfType
)
536 : BHandler(shelfType
)
538 _InitData(NULL
, stream
, view
, allowDrags
);
542 BShelf::BShelf(BMessage
*data
)
553 // we own fStream only when fEntry is set
554 if (fEntry
!= NULL
) {
559 while (fReplicants
.CountItems() > 0) {
560 replicant_data
*data
= (replicant_data
*)fReplicants
.ItemAt(0);
561 fReplicants
.RemoveItem((int32
)0);
565 fContainerView
->_SetShelf(NULL
);
570 BShelf::Archive(BMessage
*data
, bool deep
) const
577 BShelf::Instantiate(BMessage
*data
)
584 BShelf::MessageReceived(BMessage
*msg
)
586 if (msg
->what
== kDeleteReplicant
) {
587 BHandler
*replicant
= NULL
;
588 if (msg
->FindPointer("_target", (void **)&replicant
) == B_OK
) {
589 BView
*view
= dynamic_cast<BView
*>(replicant
);
591 DeleteReplicant(view
);
596 BMessage
replyMsg(B_REPLY
);
597 status_t err
= B_BAD_SCRIPT_SYNTAX
;
603 if (msg
->GetCurrentSpecifier(&index
, &specifier
, &what
, &prop
) != B_OK
)
604 return BHandler::MessageReceived(msg
);
607 case B_DELETE_PROPERTY
:
609 case B_GET_SUPPORTED_SUITES
:
610 if (strcmp(prop
, "Replicant") == 0) {
614 BView
*replicant
= NULL
;
615 BMessage
*repMessage
= NULL
;
616 err
= _GetProperty(&specifier
, &reply
);
618 err
= reply
.FindInt32("index", &i
);
620 if (err
== B_OK
&& msg
->what
== B_DELETE_PROPERTY
) { // Delete Replicant
621 err
= DeleteReplicant(i
);
624 if (err
== B_OK
&& msg
->what
== B_GET_SUPPORTED_SUITES
) {
625 err
= replyMsg
.AddString("suites", "suite/vnd.Be-replicant");
627 BPropertyInfo
propInfo(sReplicantPropertyList
);
628 err
= replyMsg
.AddFlat("messages", &propInfo
);
633 repMessage
= ReplicantAt(i
, &replicant
, &ID
, &err
);
634 if (err
== B_OK
&& replicant
) {
637 err
= replicant
->Archive(&archive
);
638 if (err
== B_OK
&& msg
->GetCurrentSpecifier(&index
, &specifier
, &what
, &prop
) != B_OK
) {
639 err
= replyMsg
.AddMessage("result", &archive
);
642 // now handles the replicant suite
643 err
= B_BAD_SCRIPT_SYNTAX
;
644 if (msg
->what
!= B_GET_PROPERTY
)
646 if (strcmp(prop
, "ID") == 0) {
647 err
= replyMsg
.AddInt32("result", ID
);
648 } else if (strcmp(prop
, "Name") == 0) {
649 err
= replyMsg
.AddString("result", replicant
->Name());
650 } else if (strcmp(prop
, "Signature") == 0) {
651 const char *add_on
= NULL
;
652 err
= repMessage
->FindString("add_on", &add_on
);
654 err
= replyMsg
.AddString("result", add_on
);
655 } else if (strcmp(prop
, "Suites") == 0) {
656 err
= replyMsg
.AddString("suites", "suite/vnd.Be-replicant");
658 BPropertyInfo
propInfo(sReplicantPropertyList
);
659 err
= replyMsg
.AddFlat("messages", &propInfo
);
665 return BHandler::MessageReceived(msg
);
667 case B_COUNT_PROPERTIES
:
668 if (strcmp(prop
, "Replicant") == 0) {
669 err
= replyMsg
.AddInt32("result", CountReplicants());
672 return BHandler::MessageReceived(msg
);
674 case B_CREATE_PROPERTY
:
676 BMessage replicantMsg
;
678 if (msg
->FindMessage("data", &replicantMsg
) == B_OK
679 && msg
->FindPoint("location", &pos
) == B_OK
) {
680 err
= AddReplicant(&replicantMsg
, pos
);
687 replyMsg
.what
= B_MESSAGE_NOT_UNDERSTOOD
;
689 if (err
== B_BAD_SCRIPT_SYNTAX
)
690 replyMsg
.AddString("message", "Didn't understand the specifier(s)");
692 replyMsg
.AddString("message", strerror(err
));
695 replyMsg
.AddInt32("error", err
);
696 msg
->SendReply(&replyMsg
);
703 status_t status
= B_ERROR
;
704 if (fEntry
!= NULL
) {
705 BFile
*file
= new BFile(fEntry
, B_READ_WRITE
| B_ERASE_FILE
);
706 status
= file
->InitCheck();
707 if (status
!= B_OK
) {
715 if (fStream
!= NULL
) {
717 status
= _Archive(&message
);
719 status
= message
.Flatten(fStream
);
727 BShelf::SetDirty(bool state
)
734 BShelf::IsDirty() const
741 BShelf::ResolveSpecifier(BMessage
*msg
, int32 index
, BMessage
*specifier
,
742 int32 form
, const char *property
)
744 BPropertyInfo
shelfPropInfo(sShelfPropertyList
);
745 BHandler
*target
= NULL
;
746 BView
*replicant
= NULL
;
748 switch (shelfPropInfo
.FindMatch(msg
, 0, specifier
, form
, property
)) {
753 if (msg
->PopSpecifier() != B_OK
) {
757 msg
->SetCurrentSpecifier(index
);
761 status_t err
= _GetProperty(specifier
, &reply
);
765 err
= reply
.FindInt32("index", &i
);
767 ReplicantAt(i
, &replicant
, &ID
, &err
);
769 if (err
== B_OK
&& replicant
!= NULL
) {
773 BMessage
replyMsg(B_MESSAGE_NOT_UNDERSTOOD
);
774 replyMsg
.AddInt32("error", B_BAD_INDEX
);
775 replyMsg
.AddString("message", "Cannot find replicant at/with specified index/name.");
776 msg
->SendReply(&replyMsg
);
786 return BHandler::ResolveSpecifier(msg
, index
, specifier
, form
,
791 status_t err
= msg
->GetCurrentSpecifier(&repIndex
, specifier
, &form
, &property
);
793 BMessage
reply(B_MESSAGE_NOT_UNDERSTOOD
);
794 reply
.AddInt32("error", err
);
795 msg
->SendReply(&reply
);
799 BPropertyInfo
replicantPropInfo(sReplicantPropertyList
);
800 switch (replicantPropInfo
.FindMatch(msg
, 0, specifier
, form
, property
)) {
805 msg
->SetCurrentSpecifier(index
);
816 BMessage
replyMsg(B_MESSAGE_NOT_UNDERSTOOD
);
817 replyMsg
.AddInt32("error", B_BAD_SCRIPT_SYNTAX
);
818 replyMsg
.AddString("message", "Didn't understand the specifier(s)");
819 msg
->SendReply(&replyMsg
);
826 BShelf::GetSupportedSuites(BMessage
*message
)
829 err
= message
->AddString("suites", "suite/vnd.Be-shelf");
831 BPropertyInfo
propInfo(sShelfPropertyList
);
832 err
= message
->AddFlat("messages", &propInfo
);
835 return BHandler::GetSupportedSuites(message
);
841 BShelf::Perform(perform_code d
, void *arg
)
843 return BHandler::Perform(d
, arg
);
848 BShelf::AllowsDragging() const
850 return fAllowDragging
;
855 BShelf::SetAllowsDragging(bool state
)
857 fAllowDragging
= state
;
862 BShelf::AllowsZombies() const
864 return fAllowZombies
;
869 BShelf::SetAllowsZombies(bool state
)
871 fAllowZombies
= state
;
876 BShelf::DisplaysZombies() const
878 return fDisplayZombies
;
883 BShelf::SetDisplaysZombies(bool state
)
885 fDisplayZombies
= state
;
890 BShelf::IsTypeEnforced() const
892 return fTypeEnforced
;
897 BShelf::SetTypeEnforced(bool state
)
899 fTypeEnforced
= state
;
904 BShelf::SetSaveLocation(BDataIO
*data_io
)
908 if (fEntry
!= NULL
) {
920 BShelf::SetSaveLocation(const entry_ref
*ref
)
929 fEntry
= new BEntry(ref
);
936 BShelf::SaveLocation(entry_ref
*ref
) const
942 } else if (fEntry
&& ref
)
950 BShelf::AddReplicant(BMessage
*data
, BPoint location
)
952 return _AddReplicant(data
, &location
, fGenCount
++);
957 BShelf::DeleteReplicant(BView
*replicant
)
959 int32 index
= replicant_data::IndexOf(&fReplicants
, replicant
, true);
961 replicant_data
*item
= (replicant_data
*)fReplicants
.ItemAt(index
);
965 return _DeleteReplicant(item
);
970 BShelf::DeleteReplicant(BMessage
*data
)
972 int32 index
= replicant_data::IndexOf(&fReplicants
, data
);
974 replicant_data
*item
= (replicant_data
*)fReplicants
.ItemAt(index
);
978 return _DeleteReplicant(item
);
983 BShelf::DeleteReplicant(int32 index
)
985 replicant_data
*item
= (replicant_data
*)fReplicants
.ItemAt(index
);
989 return _DeleteReplicant(item
);
994 BShelf::CountReplicants() const
996 return fReplicants
.CountItems();
1001 BShelf::ReplicantAt(int32 index
, BView
**_view
, uint32
*_uniqueID
,
1002 status_t
*_error
) const
1004 replicant_data
*item
= (replicant_data
*)fReplicants
.ItemAt(index
);
1006 // no replicant found
1010 *_uniqueID
= ~(uint32
)0;
1012 *_error
= B_BAD_INDEX
;
1018 *_view
= item
->view
;
1020 *_uniqueID
= item
->id
;
1022 *_error
= item
->error
;
1024 return item
->message
;
1029 BShelf::IndexOf(const BView
* replicantView
) const
1031 return replicant_data::IndexOf(&fReplicants
, replicantView
, false);
1036 BShelf::IndexOf(const BMessage
*archive
) const
1038 return replicant_data::IndexOf(&fReplicants
, archive
);
1043 BShelf::IndexOf(uint32 id
) const
1045 return replicant_data::IndexOf(&fReplicants
, id
);
1050 BShelf::CanAcceptReplicantMessage(BMessage
*) const
1057 BShelf::CanAcceptReplicantView(BRect
, BView
*, BMessage
*) const
1064 BShelf::AdjustReplicantBy(BRect
, BMessage
*) const
1071 BShelf::ReplicantDeleted(int32 index
, const BMessage
*archive
,
1072 const BView
*replicant
)
1078 _ReservedShelf1__6BShelfFv(BShelf
*const, int32
, const BMessage
*, const BView
*)
1080 // is not contained in BeOS R5's libbe, so we leave it empty
1084 void BShelf::_ReservedShelf2() {}
1085 void BShelf::_ReservedShelf3() {}
1086 void BShelf::_ReservedShelf4() {}
1087 void BShelf::_ReservedShelf5() {}
1088 void BShelf::_ReservedShelf6() {}
1089 void BShelf::_ReservedShelf7() {}
1090 void BShelf::_ReservedShelf8() {}
1093 BShelf::BShelf(const BShelf
&)
1099 BShelf::operator=(const BShelf
&)
1106 BShelf::_Archive(BMessage
*data
) const
1108 status_t status
= BHandler::Archive(data
);
1112 status
= data
->AddBool("_zom_dsp", DisplaysZombies());
1116 status
= data
->AddBool("_zom_alw", AllowsZombies());
1120 status
= data
->AddInt32("_sg_cnt", fGenCount
);
1124 BMessage
archive('ARCV');
1125 for (int32 i
= 0; i
< fReplicants
.CountItems(); i
++) {
1126 if (((replicant_data
*)fReplicants
.ItemAt(i
))->Archive(&archive
) == B_OK
)
1127 status
= data
->AddMessage("replicant", &archive
);
1130 archive
.MakeEmpty();
1138 BShelf::_InitData(BEntry
*entry
, BDataIO
*stream
, BView
*view
,
1141 fContainerView
= view
;
1146 fAllowDragging
= allowDrags
;
1148 fDisplayZombies
= false;
1149 fAllowZombies
= true;
1150 fTypeEnforced
= false;
1153 fStream
= new BFile(entry
, B_READ_ONLY
);
1157 fFilter
= new ShelfContainerViewFilter(this, fContainerView
);
1159 fContainerView
->AddFilter(fFilter
);
1160 fContainerView
->_SetShelf(this);
1162 if (fStream
!= NULL
) {
1165 if (archive
.Unflatten(fStream
) == B_OK
) {
1167 if (archive
.FindBool("_zom_dsp", &allowZombies
) != B_OK
)
1168 allowZombies
= false;
1170 SetDisplaysZombies(allowZombies
);
1172 if (archive
.FindBool("_zom_alw", &allowZombies
) != B_OK
)
1173 allowZombies
= true;
1175 SetAllowsZombies(allowZombies
);
1178 if (!archive
.FindInt32("_sg_cnt", &genCount
))
1182 for (int32 i
= 0; archive
.FindMessage("replicant", i
, &replicant
)
1185 BMessage
*replMsg
= new BMessage();
1186 ObjectDeleter
<BMessage
> deleter(replMsg
);
1187 replicant
.FindPoint("position", &point
);
1188 if (replicant
.FindMessage("message", replMsg
) == B_OK
)
1189 if (AddReplicant(replMsg
, point
) == B_OK
) {
1190 // Detach the deleter since AddReplicant is taking
1191 // ownership on success. In R2 API this should be
1192 // changed to take always ownership on the message.
1202 BShelf::_DeleteReplicant(replicant_data
* item
)
1204 BView
*view
= item
->view
;
1206 view
= item
->zombie_view
;
1211 if (item
->dragger
!= NULL
)
1212 item
->dragger
->RemoveSelf();
1214 int32 index
= replicant_data::IndexOf(&fReplicants
, item
->message
);
1216 ReplicantDeleted(index
, item
->message
, view
);
1218 fReplicants
.RemoveItem(item
);
1220 if (item
->relation
== BDragger::TARGET_IS_PARENT
1221 || item
->relation
== BDragger::TARGET_IS_SIBLING
) {
1224 if (item
->relation
== BDragger::TARGET_IS_CHILD
1225 || item
->relation
== BDragger::TARGET_IS_SIBLING
) {
1226 delete item
->dragger
;
1229 // Update use count for image and unload if necessary
1230 const char* signature
= NULL
;
1231 if (item
->message
->FindString("add_on", &signature
) == B_OK
1232 && signature
!= NULL
) {
1233 LoadedImages
* loadedImages
= LoadedImages::Default();
1234 AutoLock
<LoadedImages
> lock(loadedImages
);
1235 if (lock
.IsLocked()) {
1236 LoadedImageMap::iterator it
= loadedImages
->images
.find(
1237 BString(signature
));
1239 if (it
!= loadedImages
->images
.end()) {
1240 (*it
).second
.second
--;
1241 if ((*it
).second
.second
<= 0) {
1242 unload_add_on((*it
).second
.first
);
1243 loadedImages
->images
.erase(it
);
1255 //! Takes over ownership of \a data on success only
1257 BShelf::_AddReplicant(BMessage
*data
, BPoint
*location
, uint32 uniqueID
)
1259 // Check shelf types if needed
1260 if (fTypeEnforced
) {
1261 const char *shelfType
= NULL
;
1262 if (data
->FindString("shelf_type", &shelfType
) == B_OK
1263 && shelfType
!= NULL
) {
1264 if (Name() && strcmp(shelfType
, Name()) != 0) {
1265 printf("Replicant was rejected by BShelf: The BShelf's type and the Replicant's type don't match.");
1266 return send_reply(data
, B_ERROR
, uniqueID
);
1268 printf("Replicant was rejected by BShelf: Replicant indicated a <type> (%s), but the shelf does not.", shelfType
);
1269 return send_reply(data
, B_ERROR
, uniqueID
);
1272 printf("Replicant was rejected by BShelf: Replicant did not have a <type>");
1273 return send_reply(data
, B_ERROR
, uniqueID
);
1277 // Check if we can accept this message
1278 if (!CanAcceptReplicantMessage(data
)) {
1279 printf("Replicant was rejected by BShelf::CanAcceptReplicantMessage()");
1280 return send_reply(data
, B_ERROR
, uniqueID
);
1283 // Check if we can create multiple instances
1284 if (data
->FindBool("be:load_each_time")) {
1285 const char *className
= NULL
;
1286 const char *addOn
= NULL
;
1288 if (data
->FindString("class", &className
) == B_OK
1289 && data
->FindString("add_on", &addOn
) == B_OK
) {
1290 if (find_replicant(fReplicants
, className
, addOn
)) {
1291 printf("Replicant was rejected. Unique replicant already exists. class=%s, signature=%s",
1293 return send_reply(data
, B_ERROR
, uniqueID
);
1298 // Instantiate the object, if this fails we have a zombie
1299 image_id image
= -1;
1300 BArchivable
*archivable
= _InstantiateObject(data
, &image
);
1304 if (archivable
!= NULL
) {
1305 view
= dynamic_cast<BView
*>(archivable
);
1308 return send_reply(data
, B_ERROR
, uniqueID
);
1311 BDragger
* dragger
= NULL
;
1312 BView
* replicant
= NULL
;
1313 BDragger::relation relation
= BDragger::TARGET_UNKNOWN
;
1314 _BZombieReplicantView_
* zombie
= NULL
;
1316 const BPoint point
= location
? *location
: view
->Frame().LeftTop();
1317 replicant
= _GetReplicant(data
, view
, point
, dragger
, relation
);
1318 if (replicant
== NULL
)
1319 return send_reply(data
, B_ERROR
, uniqueID
);
1320 } else if (fDisplayZombies
&& fAllowZombies
) {
1321 zombie
= _CreateZombie(data
, dragger
);
1322 } else if (!fAllowZombies
) {
1323 // There was no view, and we're not allowed to have any zombies
1325 return send_reply(data
, B_ERROR
, uniqueID
);
1328 // Update use count for image
1329 const char* signature
= NULL
;
1330 if (data
->FindString("add_on", &signature
) == B_OK
&& signature
!= NULL
) {
1331 LoadedImages
* loadedImages
= LoadedImages::Default();
1332 AutoLock
<LoadedImages
> lock(loadedImages
);
1333 if (lock
.IsLocked()) {
1334 LoadedImageMap::iterator it
= loadedImages
->images
.find(
1335 BString(signature
));
1337 if (it
== loadedImages
->images
.end())
1338 loadedImages
->images
.insert(LoadedImageMap::value_type(
1339 BString(signature
), std::pair
<image_id
, int>(image
, 1)));
1341 (*it
).second
.second
++;
1345 if (zombie
== NULL
) {
1346 data
->RemoveName("_drop_point_");
1347 data
->RemoveName("_drop_offset_");
1350 replicant_data
*item
= new replicant_data(data
, replicant
, dragger
,
1351 relation
, uniqueID
);
1354 item
->zombie_view
= zombie
;
1356 fReplicants
.AddItem(item
);
1358 return send_reply(data
, B_OK
, uniqueID
);
1363 BShelf::_GetReplicant(BMessage
*data
, BView
*view
, const BPoint
&point
,
1364 BDragger
*&dragger
, BDragger::relation
&relation
)
1366 // TODO: test me -- there seems to be lots of bugs parked here!
1367 BView
*replicant
= NULL
;
1368 _GetReplicantData(data
, view
, replicant
, dragger
, relation
);
1370 if (dragger
!= NULL
)
1371 dragger
->_SetViewToDrag(replicant
);
1373 BRect frame
= view
->Frame().OffsetToCopy(point
);
1374 if (!CanAcceptReplicantView(frame
, replicant
, data
)) {
1375 // the view has not been accepted
1376 if (relation
== BDragger::TARGET_IS_PARENT
1377 || relation
== BDragger::TARGET_IS_SIBLING
) {
1380 if (relation
== BDragger::TARGET_IS_CHILD
1381 || relation
== BDragger::TARGET_IS_SIBLING
) {
1387 BPoint adjust
= AdjustReplicantBy(frame
, data
);
1389 if (dragger
!= NULL
)
1390 dragger
->_SetShelf(this);
1392 // TODO: could be not correct for some relations
1393 view
->MoveTo(point
+ adjust
);
1395 // if it's a sibling or a child, we need to add the dragger
1396 if (relation
== BDragger::TARGET_IS_SIBLING
1397 || relation
== BDragger::TARGET_IS_CHILD
)
1398 fContainerView
->AddChild(dragger
);
1400 if (relation
!= BDragger::TARGET_IS_CHILD
)
1401 fContainerView
->AddChild(replicant
);
1403 replicant
->AddFilter(new ReplicantViewFilter(this, replicant
));
1411 BShelf::_GetReplicantData(BMessage
*data
, BView
*view
, BView
*&replicant
,
1412 BDragger
*&dragger
, BDragger::relation
&relation
)
1414 // Check if we have a dragger archived as "__widget" inside the message
1416 if (data
->FindMessage("__widget", &widget
) == B_OK
) {
1417 image_id draggerImage
= B_ERROR
;
1419 dragger
= dynamic_cast<BDragger
*>(_InstantiateObject(&widget
, &draggerImage
));
1420 // Replicant is a sibling, or unknown, if there isn't a dragger
1421 if (dragger
!= NULL
)
1422 relation
= BDragger::TARGET_IS_SIBLING
;
1424 } else if ((dragger
= dynamic_cast<BDragger
*>(view
)) != NULL
) {
1425 // Replicant is child of the dragger
1426 relation
= BDragger::TARGET_IS_CHILD
;
1427 replicant
= dragger
->ChildAt(0);
1430 // Replicant is parent of the dragger
1431 relation
= BDragger::TARGET_IS_PARENT
;
1433 dragger
= dynamic_cast<BDragger
*>(replicant
->FindView("_dragger_"));
1434 // can be NULL, the replicant could not have a dragger at all
1439 _BZombieReplicantView_
*
1440 BShelf::_CreateZombie(BMessage
*data
, BDragger
*&dragger
)
1442 // TODO: the zombies must be adjusted and moved as well!
1444 if (data
->FindRect("_frame", &frame
) != B_OK
)
1447 _BZombieReplicantView_
*zombie
= NULL
;
1448 if (data
->WasDropped()) {
1450 BPoint dropPoint
= data
->DropPoint(&offset
);
1452 frame
.OffsetTo(fContainerView
->ConvertFromScreen(dropPoint
) - offset
);
1454 zombie
= new _BZombieReplicantView_(frame
, B_ERROR
);
1456 frame
.OffsetTo(B_ORIGIN
);
1458 dragger
= new BDragger(frame
, zombie
);
1459 dragger
->_SetShelf(this);
1460 dragger
->_SetZombied(true);
1462 zombie
->AddChild(dragger
);
1463 zombie
->SetArchive(data
);
1464 zombie
->AddFilter(new ReplicantViewFilter(this, zombie
));
1466 fContainerView
->AddChild(zombie
);
1474 BShelf::_GetProperty(BMessage
*msg
, BMessage
*reply
)
1477 status_t err
= B_ERROR
;
1478 BView
*replicant
= NULL
;
1479 switch (msg
->what
) {
1480 case B_INDEX_SPECIFIER
: {
1482 if (msg
->FindInt32("index", &index
)!=B_OK
)
1484 ReplicantAt(index
, &replicant
, &ID
, &err
);
1487 case B_REVERSE_INDEX_SPECIFIER
: {
1489 if (msg
->FindInt32("index", &rindex
) != B_OK
)
1491 ReplicantAt(CountReplicants() - rindex
, &replicant
, &ID
, &err
);
1494 case B_NAME_SPECIFIER
: {
1496 if (msg
->FindString("name", &name
) != B_OK
)
1498 for (int32 i
= 0; i
< CountReplicants(); i
++) {
1500 ReplicantAt(i
, &view
, &ID
, &err
);
1501 if (err
!= B_OK
|| view
== NULL
)
1503 if (view
->Name() != NULL
&& strcmp(view
->Name(), name
) == 0) {
1507 err
= B_NAME_NOT_FOUND
;
1511 case B_ID_SPECIFIER
: {
1513 if (msg
->FindInt32("id", (int32
*)&id
) != B_OK
)
1515 for (int32 i
= 0; i
< CountReplicants(); i
++) {
1517 ReplicantAt(i
, &view
, &ID
, &err
);
1518 if (err
!= B_OK
|| view
== NULL
)
1524 err
= B_NAME_NOT_FOUND
;
1533 reply
->AddInt32("index", IndexOf(replicant
));
1534 reply
->AddInt32("ID", ID
);
1543 BShelf::_InstantiateObject(BMessage
*archive
, image_id
*image
)
1545 // Stay on the safe side. The constructor called by instantiate_object
1546 // could throw an exception, which we catch here. Otherwise our calling app
1547 // could die without notice.
1549 return instantiate_object(archive
, image
);