root/src/tests/kits/interface/bshelf/ShelfInspector/InfoWindow.cpp
// 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); 
}