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