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