1// InfoWindow.cpp
2// Generated by Interface Elements (Window v2.3) on Feb 23 2004
3// This is a user written class and will not be overwritten.
4
5#include <Beep.h>
6#include <File.h>
7#include <Resources.h>
8#include <StorageKit.h>
9#include <SupportKit.h>
10#include <AppKit.h>
11#include <iostream.h>
12
13#include "InfoWindow.h"
14
15// A couple helpers classes and functions.
16
17struct IDItem : public BStringItem
18{
19				IDItem(const char *name, int32 i);
20	int32	id;
21};
22
23/*------------------------------------------------------------*/
24struct match_info
25{
26	match_info(image_id i) { id = i; found = false; };
27	image_id	id;
28	bool			found;
29};
30
31
32bool match_id(BListItem *item, void *data)
33{
34	match_info *mi = (match_info *) (data);
35	IDItem *my = dynamic_cast<IDItem*>(item);
36	if (my->id == (mi)->id)
37	{
38		(mi)->found = true;
39		return true;
40	}
41	return false;
42}
43
44
45IDItem :: IDItem(const char *name, int32 i)
46	      : BStringItem(name)
47{
48	id = i;
49};
50
51
52
53InfoWindow :: InfoWindow(void)
54						: IEWindow("InfoWindow"),
55							fTickToken( BMessenger(this), new BMessage(CMD_TICK), 500000 ),		// send message periodically
56							fImportLoc(10,15)																									// position of imported replicant
57{
58	Lock();
59		CreateViews();
60	Unlock();
61}
62
63
64InfoWindow::~InfoWindow(void)
65{
66	SetPrefs();
67  if (fPrefs != NULL) delete fPrefs;			// now prefs are saved
68}
69
70
71bool InfoWindow :: QuitRequested()
72{
73	long c = be_app->CountWindows();
74
75	if (c == 1)
76	{
77		be_app->PostMessage(B_QUIT_REQUESTED);
78	}
79	return true;
80}
81
82
83// Handling of user interface and other events
84void InfoWindow::MessageReceived(BMessage *msg)
85{
86
87	switch(msg->what)
88	{
89		case CMD_UPDATE_CONTAINER_ITEM:
90			{
91				BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
92				BMenuItem *theItem = theMenu -> FindItem(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
93				theItem ->  SetMarked(true);
94				PostMessage(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
95			}
96			break;
97
98		case CMD_TICK:
99		{
100			UpdateLists(false);
101			break;
102		}
103
104		case IE_INFOWINDOW_DELETEBUTTON:	// 'DeleteButton' is pressed...
105			{
106				int32	sel = fReplicantList->CurrentSelection();
107				IDItem	*item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel));
108				ASSERT(sel >= 0);
109				ASSERT(item);
110				DeleteReplicant(item->id);
111			}
112			break;
113
114
115
116		case IE_INFOWINDOW_COPYBUTTON:	// 'CopyButton' is pressed...
117			{
118				BAlert	*alert = new BAlert("",
119																		"Warning, not all replicants are importable. Importing a "
120																		"replicant can crash the Container Demo application. Are you "
121																		"willing to give it a try?", "Cancel", "Import", NULL,
122																		B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
123				BInvoker *inv = new BInvoker(new BMessage(CMD_IMPORT_REPLICANT),this);
124				alert->Go(inv);
125			}
126			break;
127
128
129		case CMD_IMPORT_REPLICANT:
130			{
131				// This message was posted by the Alert above. If 'which' is 1 then
132				// the user pressed the Import button. Otherwise they pressed Cancel.
133				int32 r = msg->FindInt32("which");
134				if (r == 1)
135				{
136					int32	sel = fReplicantList->CurrentSelection();
137					IDItem	*item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel));
138					ASSERT(sel >= 0);
139					ASSERT(item);
140					ImportReplicant(item->id);
141				}
142			}
143			break;
144
145
146		case IE_INFOWINDOW_REPLICANTLIST_SELECTION:	// list item is selected in 'ReplicantList'
147			{
148				bool	enabled;
149				enabled = (fReplicantList->CurrentSelection() >= 0);
150				fDeleteRep->SetEnabled(enabled);
151				fCopyRep -> SetEnabled(enabled);
152			}
153			break;
154
155		case IE_INFOWINDOW_REPLICANTLIST_INVOCATION:	// list item is invoked in 'ReplicantList'
156			break;
157
158
159
160		case IE_INFOWINDOW_LIBRARYLIST_SELECTION:	// list item is selected in 'LibraryList'
161			{
162				bool	enabled;
163				enabled = (fLibraryList->CurrentSelection() >= 0);
164				fUnloadLib->SetEnabled(enabled);
165			}
166			break;
167
168		case IE_INFOWINDOW_LIBRARYLIST_INVOCATION:	// list item is invoked in 'LibraryList'
169			break;
170
171		case IE_INFOWINDOW_UNLOADBUTTON:	// 'UnloadButton' is pressed...
172			{
173				BAlert	*alert = new BAlert("",
174																"Warning, unloading a library that is still in use is pretty bad. "
175																"Are you sure you want to unload this library?",
176																"Cancel", "Unload", NULL,
177																B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
178				BInvoker *inv = new BInvoker(new BMessage(CMD_UNLOAD_LIBRARY),this);
179				alert->Go(inv);
180			}
181			break;
182
183		case CMD_UNLOAD_LIBRARY:
184		{
185			// This message was posted by the Alert above. If 'which' is 1 then
186			// the user pressed the Import button. Otherwise they pressed Cancel.
187			int32 r = msg->FindInt32("which");
188			if (r == 1)
189			{
190				int32	sel = fLibraryList->CurrentSelection();
191				IDItem	*item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(sel));
192				ASSERT(sel >= 0);
193				ASSERT(item);
194				unload_add_on(item->id);
195			}
196			break;
197		}
198
199		case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW:
200		case IE_POPUPMENU_TARGETPOPUP_DESKBAR:
201		case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW:
202		{
203			fTarget = MessengerForTarget(msg->what);
204			UpdateLists(true);
205		}
206		break;
207
208		case IE_INFOWINDOW_MAINBAR_FILE_NEW:    // "New" is selected from menu���
209			break;
210
211		case IE_INFOWINDOW_MAINBAR_FILE_OPEN___:    // "Open���" is selected from menu���
212			break;
213
214		case IE_INFOWINDOW_MAINBAR_FILE_SAVE:    // "Save" is selected from menu���
215			break;
216
217		case IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___:    // "Save As���" is selected from menu���
218			break;
219
220		case IE_INFOWINDOW_MAINBAR_FILE_ABOUT___:    // "About���" is selected from menu���
221				PostMessage(B_ABOUT_REQUESTED);
222			break;
223
224		case IE_INFOWINDOW_MAINBAR_FILE_QUIT:    // "Quit" is selected from menu���
225				PostMessage(B_QUIT_REQUESTED);
226			break;
227
228		case IE_INFOWINDOW_MAINBAR_EDIT_UNDO:    // "Undo" is selected from menu���
229			break;
230
231		case IE_INFOWINDOW_MAINBAR_EDIT_CUT:    // "Cut" is selected from menu���
232			break;
233
234		case IE_INFOWINDOW_MAINBAR_EDIT_COPY:    // "Copy" is selected from menu���
235			break;
236
237		case IE_INFOWINDOW_MAINBAR_EDIT_PASTE:    // "Paste" is selected from menu���
238			break;
239
240
241		case B_ABOUT_REQUESTED:
242			{
243				BAlert	*alert = new BAlert("", "XShelfInspector (H.Reh, dr.hartmut.reh@gmx.de) " "\n" "\n"
244																		"Based upon ShelfInspector from Be Inc." "\n"
245																		"The GUI was created with InterfaceElements (Attila Mezei)" "\n"
246																		"Please read the ***Be Sample Code License*** "	"\n"
247																	 ,"OK");
248				alert -> Go(NULL);
249			}
250			break;
251
252
253		default:
254			inherited::MessageReceived(msg);
255			break;
256	}
257
258}
259
260
261void InfoWindow :: EmptyLists()
262{
263	fReplicantList	->	MakeEmpty();
264	fLibraryList		->	MakeEmpty();
265}
266
267
268void InfoWindow::UpdateLists(bool make_empty)
269{
270	bool	deleted_something = false;
271
272	if (!fTarget.IsValid())
273	{
274		EmptyLists();
275		PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION);
276		PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION);
277		return;
278	}
279	if (make_empty)
280	{
281		EmptyLists();
282		deleted_something = true;
283	}
284
285	/*
286	 I'm not worried about the allgorithms used below to maintain the 2 lists.
287	 That isn't the point of this sample app.
288	 */
289
290	image_info	info;
291
292	if (!make_empty)
293	{
294		// walk through the current list of images and remove any that are
295		// no longer loaded
296		IDItem	*item;
297		int32	i = fLibraryList->CountItems();
298		while ((item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(--i))) != NULL)
299		{
300			image_id	id = (image_id) item->id;
301			if (get_image_info(id, &info) != B_OK)
302			{
303				fLibraryList->RemoveItem(item);
304				delete item;
305				deleted_something = true;
306			}
307		}
308	}
309
310	// get all the images for the 'team' of the target. If the image isn't in the
311	// list then add
312	team_id		team = fTarget.Team();
313	int32		cookie = 0;
314
315	while (get_next_image_info(team, &cookie, &info) == B_OK)
316	{
317		match_info	mi(info.id);
318		fLibraryList->DoForEach(match_id, &mi);
319		if (!mi.found)
320		{
321			fLibraryList->AddItem(new IDItem(info.name, info.id));
322		}
323	}
324
325	// Now it's time to deal with the replicant list
326
327	if (!make_empty)
328	{
329		// walk through the current list of replicants and remove any that are
330		// no longer loaded
331		IDItem	*item;
332		int32	i = fReplicantList->CountItems();
333		while ((item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(--i))) != NULL)
334		{
335			int32	uid = item->id;
336			if (IsReplicantLoaded(uid) == false)
337			{
338				fReplicantList->RemoveItem(item);
339				delete item;
340				deleted_something = true;
341			}
342		}
343	}
344
345	// Now get all the replicants from the shelf and make sure that they are in
346	// the list
347	int32	index = 0;
348	int32	uid;
349	while ((uid = GetReplicantAt(index++)) >= B_OK)
350	{
351		// if this uid is already in the list then skip it
352		match_info	mi(uid);
353		fReplicantList->DoForEach(match_id, &mi);
354		if (mi.found)
355		{
356			continue;
357		}
358
359		BMessage	rep_info;
360		if (GetReplicantName(uid, &rep_info) != B_OK)
361		{
362			continue;
363		}
364
365		const char *name;
366		if (rep_info.FindString("result", &name) == B_OK)
367		{
368			fReplicantList->AddItem(new IDItem(name, uid));
369		}
370	}
371
372
373	if (deleted_something)
374	{
375		PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION);
376		PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION);
377	}
378}
379
380
381
382status_t InfoWindow :: GetReplicantName(int32 uid, BMessage *reply) const
383{
384	/*
385	 We send a message to the target shelf, asking it for the Name of the
386	 replicant with the given unique id.
387	 */
388
389	BMessage	request(B_GET_PROPERTY);
390	BMessage	uid_specifier(B_ID_SPECIFIER);	// specifying via ID
391	status_t	err;
392	status_t	e;
393
394	request.AddSpecifier("Name");		// ask for the Name of the replicant
395
396	// IDs are specified using code like the following 3 lines:
397	uid_specifier.AddInt32("id", uid);
398	uid_specifier.AddString("property", "Replicant");
399	request.AddSpecifier(&uid_specifier);
400
401	if ((err = fTarget.SendMessage(&request, reply)) != B_OK)
402		return err;
403
404	if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK))
405		return err ? err : e;
406
407	return B_OK;
408}
409
410bool InfoWindow :: IsReplicantLoaded(int32 uid) const
411{
412	/*
413	 determine if the specified replicant (the unique ID of the replicant)
414	 still exists in the target container/shelf. If we can get the name then the
415	 replicant still exists.
416	 */
417	BMessage	reply;
418	status_t	err = GetReplicantName(uid, &reply);
419	return (err == B_OK);
420}
421
422
423int32 InfoWindow::GetReplicantAt(int32 index) const
424{
425	/*
426	 So here we want to get the Unique ID of the replicant at the given index
427	 in the target Shelf.
428	 */
429
430	BMessage	request(B_GET_PROPERTY);		// We're getting the ID property
431	BMessage	reply;
432	status_t	err;
433
434	request.AddSpecifier("ID");					// want the ID
435	request.AddSpecifier("Replicant", index);	// of the index'th replicant
436
437	if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
438		return err;
439
440	int32	uid;
441	if ((err = reply.FindInt32("result", &uid)) != B_OK)
442		return err;
443
444	return uid;
445}
446
447
448BMessenger InfoWindow :: MessengerForTarget(type_code w) const
449{
450	/*
451	 This function determines the BMessenger to the various Shelf objects
452	 that this app can talk with.
453	 */
454	BMessage	request(B_GET_PROPERTY);
455	BMessenger	to;
456	BMessenger	result;
457
458	request.AddSpecifier("Messenger");
459	request.AddSpecifier("Shelf");
460
461	switch (w)
462	{
463		case IE_POPUPMENU_TARGETPOPUP_DESKBAR:
464		{
465			request.AddSpecifier("View", "Status");
466			request.AddSpecifier("Window", "Deskbar");
467			to = BMessenger("application/x-vnd.Be-TSKB", -1);
468			break;
469		}
470
471		case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW:
472		{
473			// The Desktop is owned by Tracker and the Shelf is in the
474			// View "PoseView" in Window "Desktop"
475			request.AddSpecifier("View", "PoseView");
476			request.AddSpecifier("Window", "/boot/home/Desktop");
477			to = BMessenger("application/x-vnd.Be-TRAK", -1);
478			break;
479		}
480
481		case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW:
482		{
483			// In the COntainer Demo app the View "MainView" in the only window
484			// is the Shelf.
485			request.AddSpecifier("View", "ContainerView");		// Hier werden Replikanten abgelegt
486			request.AddSpecifier("Window", (int32) 0);
487			to = BMessenger(XCONTAINER_APP, -1);
488			// This demo app isn't worried about the Container app going away
489			// (quitting) unexpectedly.
490			break;
491		}
492	}
493
494	BMessage	reply;
495
496	if (to.SendMessage(&request, &reply) == B_OK)
497	{
498		//reply.PrintToStream();
499		reply.FindMessenger("result", &result);
500	}
501	return result;
502}
503
504
505status_t InfoWindow :: DeleteReplicant(int32 uid)
506{
507	// delete the given replicant from the current target shelf
508
509	BMessage	request(B_DELETE_PROPERTY);		// Delete
510	BMessage	uid_specifier(B_ID_SPECIFIER);	// specifying via ID
511	BMessage	reply;
512	status_t	err;
513	status_t	e;
514
515	// IDs are specified using code like the following 3 lines:
516	uid_specifier.AddInt32("id", uid);
517	uid_specifier.AddString("property", "Replicant");
518	request.AddSpecifier(&uid_specifier);
519
520	if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
521		return err;
522
523	if ((err = reply.FindInt32("error", &e)) != B_OK)
524		return err;
525
526	return e;
527}
528
529
530status_t InfoWindow :: ImportReplicant(int32 uid)
531{
532	// Import the given replicant from the current target shelf
533	// That is get a copy and recreate it in the "Container" window of
534	// this app.
535
536	BMessage	request(B_GET_PROPERTY);		// Get will return the archive msg
537	BMessage	uid_specifier(B_ID_SPECIFIER);	// specifying via ID
538	BMessage	reply;
539	status_t	err;
540	status_t	e;
541
542	// IDs are specified using code like the following 3 lines:
543	uid_specifier.AddInt32("id", uid);
544	uid_specifier.AddString("property", "Replicant");
545	request.AddSpecifier(&uid_specifier);
546
547	if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
548		return err;
549
550	if (((err = reply.FindInt32("error", &e)) != B_OK) || (e != B_OK))
551		return err;
552
553	// OK, let's get the archive message
554	BMessage	data;
555	reply.FindMessage("result", &data);
556
557	// Now send this to the container window. If someone closed it then the
558	// Send will fail. Oh well.
559	BMessenger	mess = MessengerForTarget(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
560	BMessage	msg(B_CREATE_PROPERTY);
561
562	msg.AddMessage("data", &data);
563
564	// As this is a Demo I'm not going to worry about some fancy layout
565	// algorithm. Just keep placing new replicants going down the window
566	msg.AddPoint("location", fImportLoc);
567	fImportLoc.y += 40;
568
569	return mess.SendMessage(&msg, &reply);
570}
571
572
573
574// Update the menu items before they appear on screen
575void InfoWindow::MenusBeginning()
576{
577	// Complete the SetEnabled argument or do anything with the source below...
578	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_NEW)->SetEnabled(false);					// "New"
579	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_OPEN___)->SetEnabled(false);			// "Open���"
580	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE)->SetEnabled(false);					// "Save"
581	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___)->SetEnabled(false);		// "Save As���"
582	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_ABOUT___)->SetEnabled(true);			// "About���"
583	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_QUIT)->SetEnabled(true);					// "Quit"
584	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_UNDO)->SetEnabled(false);					// "Undo"
585	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_CUT)->SetEnabled(false);					// "Cut"
586	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_COPY)->SetEnabled(false);					// "Copy"
587	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_PASTE)->SetEnabled(false);				// "Paste"
588}
589
590
591
592
593BMessage *InfoWindow :: ReadMessageFromResource(const char *resName)
594{
595	// Hier wird aus der Resource die Message gelesen
596	app_info 		ai;
597	BFile 	 		file;
598	BResources 	res;
599	size_t 			res_size;
600	const void* res_addr;
601
602	BMessage* archive = new BMessage;
603
604	if( (be_app->GetAppInfo(&ai) != B_OK)
605	 		||(file.SetTo(&ai.ref,B_READ_ONLY) != B_OK)
606	 		||(res.SetTo(&file) != B_OK)
607	 		||((res_addr = res.LoadResource('ARCV',resName,&res_size)) == NULL)
608	 		||(archive -> Unflatten((const char*)res_addr) != B_OK) )
609		// Resource muss 'ARCV' - Typ sein -> in IE einstellen
610		// Resource of type 'ARCV'
611	 {
612	 		delete archive;
613			return NULL;
614	 }
615	return archive;
616}
617
618
619void InfoWindow:: CreateViews()
620{
621	BMessage *archive = ReadMessageFromResource("PopUpMenu");				 // Menu Feld from Resource
622	if (archive)
623	{
624		fMenuField = new BMenuField(archive);
625		delete archive;
626	}
627
628	fMainBox = (BBox *)FindView("MainBox");														// Pointer to MainBox
629	fMainBox->SetLabel(fMenuField);																		// Replace Label
630
631	fReplicantList	 	= (BListView   *) FindView("ReplicantList");
632	fLibraryList	 		= (BListView   *) FindView("LibraryList");
633
634	fDeleteRep	= (BButton *) FindView("DeleteButton");
635	fCopyRep		= (BButton *) FindView("CopyButton");
636	fUnloadLib	= (BButton *) FindView("UnloadButton");
637
638	BScrollView *libScrollView 		= (BScrollView *)FindView("LibraryScroll");
639	BScrollBar	*horLibScrollBar = libScrollView -> ScrollBar(B_HORIZONTAL);
640	horLibScrollBar -> SetRange(0, 400);
641	horLibScrollBar -> SetProportion(0.4);
642
643	BScrollView *repScrollView 	= (BScrollView *)FindView("ReplicantScroll");
644	BScrollBar	*horRepScrollBar = repScrollView -> ScrollBar(B_HORIZONTAL);
645	horRepScrollBar -> SetRange(0, 400);
646	horRepScrollBar -> SetProportion(0.4);
647}
648
649
650void InfoWindow :: GetPrefs()
651{
652	status_t	err;
653	BRect 		windFrame;
654	int32			targetShelf;
655
656	fPrefs = new TPreferences ("XShelfInspector/preferences");			// Name des Prefs-Files
657	if (fPrefs -> InitCheck() != B_OK)															// falls keine Prefs -> erzeugen
658	{
659		windFrame = Frame();																					// Window Frame aus Resource ermitteln
660		fPrefs -> SetRect ("WindowFrame", windFrame );
661
662		targetShelf = IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW;			// XContainerWindow
663		fPrefs -> SetInt32 ("TargetShelf", targetShelf );
664	}
665
666	err = (fPrefs -> FindRect ("WindowFrame", &windFrame) );
667	if (err == B_OK)
668	{
669		ResizeTo(windFrame.Width(), windFrame.Height() );							// Fensterposition und Gr����e
670		MoveTo(windFrame.left, windFrame.top);												// aus Preferences
671	}
672
673	err = (fPrefs -> FindInt32 ("TargetShelf", &targetShelf ) );
674	if (err == B_OK)
675	{
676		BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
677		BMenuItem *theItem = theMenu -> FindItem(targetShelf);
678		theItem -> SetMarked(true);
679		PostMessage(targetShelf);																			// TargetShelf
680	}
681}
682
683
684void InfoWindow :: SetPrefs()
685{
686	fPrefs -> SetRect ("WindowFrame", Frame() );
687
688	BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
689	BMenuItem *theItem = theMenu -> FindMarked();
690	int32 targetShelf  = theItem -> Command();
691	fPrefs -> SetInt32("TargetShelf", targetShelf);
692}
693
694
695