⛏️ index : haiku.git

// InfoWindow.cpp
// Generated by Interface Elements (Window v2.3) on Feb 23 2004
// This is a user written class and will not be overwritten.

#include <Beep.h>
#include <File.h>
#include <Resources.h>
#include <StorageKit.h>
#include <SupportKit.h>
#include <AppKit.h>
#include <iostream.h>

#include "InfoWindow.h"

// A couple helpers classes and functions.

struct IDItem : public BStringItem 
{
				IDItem(const char *name, int32 i);
	int32	id;
};

/*------------------------------------------------------------*/
struct match_info 
{
	match_info(image_id i) { id = i; found = false; };
	image_id	id;
	bool			found;
};


bool match_id(BListItem *item, void *data)
{
	match_info *mi = (match_info *) (data);
	IDItem *my = dynamic_cast<IDItem*>(item);
	if (my->id == (mi)->id) 
	{
		(mi)->found = true;
		return true;
	}
	return false;
}


IDItem :: IDItem(const char *name, int32 i)
	      : BStringItem(name) 
{ 
	id = i; 
};



InfoWindow :: InfoWindow(void)
						: IEWindow("InfoWindow"),
							fTickToken( BMessenger(this), new BMessage(CMD_TICK), 500000 ),		// send message periodically
							fImportLoc(10,15)																									// position of imported replicant
{
	Lock();
		CreateViews();		
	Unlock();
}


InfoWindow::~InfoWindow(void)
{
	SetPrefs();
  if (fPrefs != NULL) delete fPrefs;			// now prefs are saved
}


bool InfoWindow :: QuitRequested()
{
	long c = be_app->CountWindows();

	if (c == 1) 
	{
		be_app->PostMessage(B_QUIT_REQUESTED);
	}
	return true;
}


// Handling of user interface and other events
void InfoWindow::MessageReceived(BMessage *msg)
{

	switch(msg->what)
	{
		case CMD_UPDATE_CONTAINER_ITEM: 
			{
				BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
				BMenuItem *theItem = theMenu -> FindItem(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
				theItem ->  SetMarked(true);
				PostMessage(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
			}
			break;

		case CMD_TICK: 
		{
			UpdateLists(false);
			break;
		}
	
		case IE_INFOWINDOW_DELETEBUTTON:	// 'DeleteButton' is pressed...
			{
				int32	sel = fReplicantList->CurrentSelection();
				IDItem	*item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel));
				ASSERT(sel >= 0);
				ASSERT(item);
				DeleteReplicant(item->id);
			}
			break;



		case IE_INFOWINDOW_COPYBUTTON:	// 'CopyButton' is pressed...
			{
				BAlert	*alert = new BAlert("",
																		"Warning, not all replicants are importable. Importing a "
																		"replicant can crash the Container Demo application. Are you "
																		"willing to give it a try?", "Cancel", "Import", NULL,
																		B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
				BInvoker *inv = new BInvoker(new BMessage(CMD_IMPORT_REPLICANT),this);				
				alert->Go(inv);				
			}
			break;


		case CMD_IMPORT_REPLICANT: 
			{
				// This message was posted by the Alert above. If 'which' is 1 then
				// the user pressed the Import button. Otherwise they pressed Cancel.
				int32 r = msg->FindInt32("which");
				if (r == 1) 
				{
					int32	sel = fReplicantList->CurrentSelection();
					IDItem	*item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(sel));
					ASSERT(sel >= 0);
					ASSERT(item);
					ImportReplicant(item->id);
				}
			}
			break;


		case IE_INFOWINDOW_REPLICANTLIST_SELECTION:	// list item is selected in 'ReplicantList' 
			{
				bool	enabled;
				enabled = (fReplicantList->CurrentSelection() >= 0);
				fDeleteRep->SetEnabled(enabled);
				fCopyRep -> SetEnabled(enabled);
			}
			break;

		case IE_INFOWINDOW_REPLICANTLIST_INVOCATION:	// list item is invoked in 'ReplicantList' 
			break;



		case IE_INFOWINDOW_LIBRARYLIST_SELECTION:	// list item is selected in 'LibraryList' 
			{
				bool	enabled;
				enabled = (fLibraryList->CurrentSelection() >= 0);
				fUnloadLib->SetEnabled(enabled);
			}
			break;

		case IE_INFOWINDOW_LIBRARYLIST_INVOCATION:	// list item is invoked in 'LibraryList' 
			break;

		case IE_INFOWINDOW_UNLOADBUTTON:	// 'UnloadButton' is pressed...
			{
				BAlert	*alert = new BAlert("",
																"Warning, unloading a library that is still in use is pretty bad. "
																"Are you sure you want to unload this library?",
																"Cancel", "Unload", NULL,
																B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
				BInvoker *inv = new BInvoker(new BMessage(CMD_UNLOAD_LIBRARY),this);				
				alert->Go(inv);				
			}
			break;

		case CMD_UNLOAD_LIBRARY: 
		{
			// This message was posted by the Alert above. If 'which' is 1 then
			// the user pressed the Import button. Otherwise they pressed Cancel.
			int32 r = msg->FindInt32("which");
			if (r == 1) 
			{
				int32	sel = fLibraryList->CurrentSelection();
				IDItem	*item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(sel));
				ASSERT(sel >= 0);
				ASSERT(item);
				unload_add_on(item->id);
			}
			break;			
		}

		case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW:
		case IE_POPUPMENU_TARGETPOPUP_DESKBAR:
		case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW:
		{
			fTarget = MessengerForTarget(msg->what);
			UpdateLists(true);	
		}
		break;

		case IE_INFOWINDOW_MAINBAR_FILE_NEW:    // "New" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_FILE_OPEN___:    // "Open…" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_FILE_SAVE:    // "Save" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___:    // "Save As…" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_FILE_ABOUT___:    // "About…" is selected from menu…
				PostMessage(B_ABOUT_REQUESTED);
			break;

		case IE_INFOWINDOW_MAINBAR_FILE_QUIT:    // "Quit" is selected from menu…
				PostMessage(B_QUIT_REQUESTED);
			break;

		case IE_INFOWINDOW_MAINBAR_EDIT_UNDO:    // "Undo" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_EDIT_CUT:    // "Cut" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_EDIT_COPY:    // "Copy" is selected from menu…
			break;

		case IE_INFOWINDOW_MAINBAR_EDIT_PASTE:    // "Paste" is selected from menu…
			break;


		case B_ABOUT_REQUESTED: 
			{
				BAlert	*alert = new BAlert("", "XShelfInspector (H.Reh, dr.hartmut.reh@gmx.de) " "\n" "\n"
																		"Based upon ShelfInspector from Be Inc." "\n"
																		"The GUI was created with InterfaceElements (Attila Mezei)" "\n"
																		"Please read the ***Be Sample Code License*** "	"\n"															
																	 ,"OK");
				alert -> Go(NULL);
			}
			break;


		default:
			inherited::MessageReceived(msg);
			break;
	}

}


void InfoWindow :: EmptyLists()
{
	fReplicantList	->	MakeEmpty();
	fLibraryList		->	MakeEmpty();
}


void InfoWindow::UpdateLists(bool make_empty)
{
	bool	deleted_something = false;
	
	if (!fTarget.IsValid()) 
	{
		EmptyLists();
		PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION);
		PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION);
		return;
	}
	if (make_empty) 
	{
		EmptyLists();
		deleted_something = true;
	}
	
	/*
	 I'm not worried about the allgorithms used below to maintain the 2 lists.
	 That isn't the point of this sample app.
	 */

	image_info	info;

	if (!make_empty) 
	{
		// walk through the current list of images and remove any that are
		// no longer loaded
		IDItem	*item;
		int32	i = fLibraryList->CountItems();
		while ((item = dynamic_cast<IDItem*>(fLibraryList->ItemAt(--i))) != NULL) 
		{
			image_id	id = (image_id) item->id;
			if (get_image_info(id, &info) != B_OK) 
			{
				fLibraryList->RemoveItem(item);
				delete item;
				deleted_something = true;
			}
		}
	}
	
	// get all the images for the 'team' of the target. If the image isn't in the
	// list then add
	team_id		team = fTarget.Team();
	int32		cookie = 0;
	
	while (get_next_image_info(team, &cookie, &info) == B_OK) 
	{
		match_info	mi(info.id);
		fLibraryList->DoForEach(match_id, &mi);
		if (!mi.found) 
		{
			fLibraryList->AddItem(new IDItem(info.name, info.id));
		}
	}
	
	// Now it's time to deal with the replicant list
	
	if (!make_empty) 
	{
		// walk through the current list of replicants and remove any that are
		// no longer loaded
		IDItem	*item;
		int32	i = fReplicantList->CountItems();
		while ((item = dynamic_cast<IDItem*>(fReplicantList->ItemAt(--i))) != NULL) 
		{
			int32	uid = item->id;
			if (IsReplicantLoaded(uid) == false) 
			{
				fReplicantList->RemoveItem(item);
				delete item;
				deleted_something = true;
			}
		}
	}
	
	// Now get all the replicants from the shelf and make sure that they are in
	// the list
	int32	index = 0;
	int32	uid;
	while ((uid = GetReplicantAt(index++)) >= B_OK) 
	{
		// if this uid is already in the list then skip it
		match_info	mi(uid);
		fReplicantList->DoForEach(match_id, &mi);
		if (mi.found) 
		{
			continue;
		}
		
		BMessage	rep_info;
		if (GetReplicantName(uid, &rep_info) != B_OK) 
		{
			continue;
		}
		
		const char *name;
		if (rep_info.FindString("result", &name) == B_OK) 
		{
			fReplicantList->AddItem(new IDItem(name, uid));
		}
	}
		
	
	if (deleted_something) 
	{
		PostMessage(IE_INFOWINDOW_REPLICANTLIST_SELECTION);
		PostMessage(IE_INFOWINDOW_LIBRARYLIST_SELECTION);
	}
}



status_t InfoWindow :: GetReplicantName(int32 uid, BMessage *reply) const
{
	/*
	 We send a message to the target shelf, asking it for the Name of the 
	 replicant with the given unique id.
	 */
	 
	BMessage	request(B_GET_PROPERTY);
	BMessage	uid_specifier(B_ID_SPECIFIER);	// specifying via ID
	status_t	err;
	status_t	e;
	
	request.AddSpecifier("Name");		// ask for the Name of the replicant
	
	// IDs are specified using code like the following 3 lines:
	uid_specifier.AddInt32("id", uid);
	uid_specifier.AddString("property", "Replicant");
	request.AddSpecifier(&uid_specifier);
	
	if ((err = fTarget.SendMessage(&request, reply)) != B_OK)
		return err;
	
	if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK))
		return err ? err : e;
	
	return B_OK;
}

bool InfoWindow :: IsReplicantLoaded(int32 uid) const
{
	/*
	 determine if the specified replicant (the unique ID of the replicant)
	 still exists in the target container/shelf. If we can get the name then the 
	 replicant still exists.
	 */
	BMessage	reply;	
	status_t	err = GetReplicantName(uid, &reply);
	return (err == B_OK);
}


int32 InfoWindow::GetReplicantAt(int32 index) const
{
	/*
	 So here we want to get the Unique ID of the replicant at the given index
	 in the target Shelf.
	 */
	 
	BMessage	request(B_GET_PROPERTY);		// We're getting the ID property
	BMessage	reply;
	status_t	err;
	
	request.AddSpecifier("ID");					// want the ID
	request.AddSpecifier("Replicant", index);	// of the index'th replicant
	
	if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
		return err;
	
	int32	uid;
	if ((err = reply.FindInt32("result", &uid)) != B_OK) 
		return err;
	
	return uid;
}


BMessenger InfoWindow :: MessengerForTarget(type_code w) const
{
	/*
	 This function determines the BMessenger to the various Shelf objects
	 that this app can talk with.
	 */
	BMessage	request(B_GET_PROPERTY);
	BMessenger	to;
	BMessenger	result;

	request.AddSpecifier("Messenger");
	request.AddSpecifier("Shelf");
	
	switch (w) 
	{
		case IE_POPUPMENU_TARGETPOPUP_DESKBAR: 
		{
			request.AddSpecifier("View", "Status");
			request.AddSpecifier("Window", "Deskbar");
			to = BMessenger("application/x-vnd.Be-TSKB", -1);
			break;
		}
		
		case IE_POPUPMENU_TARGETPOPUP_DESKTOP_WINDOW: 
		{
			// The Desktop is owned by Tracker and the Shelf is in the
			// View "PoseView" in Window "Desktop"
			request.AddSpecifier("View", "PoseView");
			request.AddSpecifier("Window", "/boot/home/Desktop");			
			to = BMessenger("application/x-vnd.Be-TRAK", -1);
			break;
		}
		
		case IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW: 
		{
			// In the COntainer Demo app the View "MainView" in the only window
			// is the Shelf.
			request.AddSpecifier("View", "ContainerView");		// Hier werden Replikanten abgelegt
			request.AddSpecifier("Window", (int32) 0);
			to = BMessenger(XCONTAINER_APP, -1);
			// This demo app isn't worried about the Container app going away
			// (quitting) unexpectedly.
			break;
		}
	}
	
	BMessage	reply;
	
	if (to.SendMessage(&request, &reply) == B_OK) 
	{
		//reply.PrintToStream();
		reply.FindMessenger("result", &result);
	}
	return result;
}


status_t InfoWindow :: DeleteReplicant(int32 uid)
{
	// delete the given replicant from the current target shelf
	 
	BMessage	request(B_DELETE_PROPERTY);		// Delete
	BMessage	uid_specifier(B_ID_SPECIFIER);	// specifying via ID
	BMessage	reply;
	status_t	err;
	status_t	e;
	
	// IDs are specified using code like the following 3 lines:
	uid_specifier.AddInt32("id", uid);
	uid_specifier.AddString("property", "Replicant");
	request.AddSpecifier(&uid_specifier);
	
	if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
		return err;
	
	if ((err = reply.FindInt32("error", &e)) != B_OK)
		return err;
	
	return e;
}


status_t InfoWindow :: ImportReplicant(int32 uid)
{
	// Import the given replicant from the current target shelf
	// That is get a copy and recreate it in the "Container" window of
	// this app.
	 
	BMessage	request(B_GET_PROPERTY);		// Get will return the archive msg
	BMessage	uid_specifier(B_ID_SPECIFIER);	// specifying via ID
	BMessage	reply;
	status_t	err;
	status_t	e;
			
	// IDs are specified using code like the following 3 lines:
	uid_specifier.AddInt32("id", uid);
	uid_specifier.AddString("property", "Replicant");
	request.AddSpecifier(&uid_specifier);
	
	if ((err = fTarget.SendMessage(&request, &reply)) != B_OK)
		return err;
	
	if (((err = reply.FindInt32("error", &e)) != B_OK) || (e != B_OK))
		return err;
	
	// OK, let's get the archive message
	BMessage	data;
	reply.FindMessage("result", &data);
	
	// Now send this to the container window. If someone closed it then the
	// Send will fail. Oh well.
	BMessenger	mess = MessengerForTarget(IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW);
	BMessage	msg(B_CREATE_PROPERTY);
	
	msg.AddMessage("data", &data);
	
	// As this is a Demo I'm not going to worry about some fancy layout
	// algorithm. Just keep placing new replicants going down the window
	msg.AddPoint("location", fImportLoc);
	fImportLoc.y += 40;
	
	return mess.SendMessage(&msg, &reply);
}



// Update the menu items before they appear on screen
void InfoWindow::MenusBeginning()
{
	// Complete the SetEnabled argument or do anything with the source below...
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_NEW)->SetEnabled(false);					// "New"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_OPEN___)->SetEnabled(false);			// "Open…"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE)->SetEnabled(false);					// "Save"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_SAVE_AS___)->SetEnabled(false);		// "Save As…"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_ABOUT___)->SetEnabled(true);			// "About…"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_FILE_QUIT)->SetEnabled(true);					// "Quit"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_UNDO)->SetEnabled(false);					// "Undo"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_CUT)->SetEnabled(false);					// "Cut"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_COPY)->SetEnabled(false);					// "Copy"
	KeyMenuBar()->FindItem(IE_INFOWINDOW_MAINBAR_EDIT_PASTE)->SetEnabled(false);				// "Paste"
}




BMessage *InfoWindow :: ReadMessageFromResource(const char *resName) 
{
	// Hier wird aus der Resource die Message gelesen
	app_info 		ai;
	BFile 	 		file;
	BResources 	res;
	size_t 			res_size;
	const void* res_addr;
	
	BMessage* archive = new BMessage;
	 	  
	if( (be_app->GetAppInfo(&ai) != B_OK)
	 		||(file.SetTo(&ai.ref,B_READ_ONLY) != B_OK)
	 		||(res.SetTo(&file) != B_OK)
	 		||((res_addr = res.LoadResource('ARCV',resName,&res_size)) == NULL)
	 		||(archive -> Unflatten((const char*)res_addr) != B_OK) )  
		// Resource muss 'ARCV' - Typ sein -> in IE einstellen
		// Resource of type 'ARCV'
	 {
	 		delete archive;
			return NULL;
	 }
	return archive;
}


void InfoWindow:: CreateViews()
{
	BMessage *archive = ReadMessageFromResource("PopUpMenu");				 // Menu Feld from Resource
	if (archive)
	{		
		fMenuField = new BMenuField(archive);
		delete archive;
	}

	fMainBox = (BBox *)FindView("MainBox");														// Pointer to MainBox
	fMainBox->SetLabel(fMenuField);																		// Replace Label
	
	fReplicantList	 	= (BListView   *) FindView("ReplicantList");
	fLibraryList	 		= (BListView   *) FindView("LibraryList");
		
	fDeleteRep	= (BButton *) FindView("DeleteButton");
	fCopyRep		= (BButton *) FindView("CopyButton");
	fUnloadLib	= (BButton *) FindView("UnloadButton");
	
	BScrollView *libScrollView 		= (BScrollView *)FindView("LibraryScroll");
	BScrollBar	*horLibScrollBar = libScrollView -> ScrollBar(B_HORIZONTAL);
	horLibScrollBar -> SetRange(0, 400);
	horLibScrollBar -> SetProportion(0.4);	

	BScrollView *repScrollView 	= (BScrollView *)FindView("ReplicantScroll");
	BScrollBar	*horRepScrollBar = repScrollView -> ScrollBar(B_HORIZONTAL);
	horRepScrollBar -> SetRange(0, 400);
	horRepScrollBar -> SetProportion(0.4);	
}


void InfoWindow :: GetPrefs()
{
	status_t	err;
	BRect 		windFrame;
	int32			targetShelf;
	
	fPrefs = new TPreferences ("XShelfInspector/preferences");			// Name des Prefs-Files
	if (fPrefs -> InitCheck() != B_OK)															// falls keine Prefs -> erzeugen
	{
		windFrame = Frame();																					// Window Frame aus Resource ermitteln
		fPrefs -> SetRect ("WindowFrame", windFrame );		
		
		targetShelf = IE_POPUPMENU_TARGETPOPUP_XCONTAINER_WINDOW;			// XContainerWindow
		fPrefs -> SetInt32 ("TargetShelf", targetShelf );			
	}

	err = (fPrefs -> FindRect ("WindowFrame", &windFrame) );
	if (err == B_OK)
	{
		ResizeTo(windFrame.Width(), windFrame.Height() );							// Fensterposition und Grâße
		MoveTo(windFrame.left, windFrame.top);												// aus Preferences		 
	}
	
	err = (fPrefs -> FindInt32 ("TargetShelf", &targetShelf ) );
	if (err == B_OK)
	{
		BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
		BMenuItem *theItem = theMenu -> FindItem(targetShelf);		
		theItem -> SetMarked(true);
		PostMessage(targetShelf);																			// TargetShelf
	} 
}


void InfoWindow :: SetPrefs()
{
	fPrefs -> SetRect ("WindowFrame", Frame() );
	
	BMenu *theMenu =(BMenu *)(fMenuField -> Menu());
	BMenuItem *theItem = theMenu -> FindMarked();
	int32 targetShelf  = theItem -> Command();	
	fPrefs -> SetInt32("TargetShelf", targetShelf);	
}