xref: /haiku/src/kits/interface/Shelf.cpp (revision ffcd67bc8277349aebf089d7357716698aafd55b)
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