ListInDialog.c

/*
ListInDialog
 
A snippet that shows how to (uuuhhhhh) put a list in a dialog.
 
I thought we had this one, but I guess not. It's easy, just create the list
right after you create the dialog, then call LUpdate and LClick in a 
dialog filter to respond to user events.
 
Please see the snippet DialogBits for a more comprehensive treatment of
everything you can do in a dialog (well, almost).
 
This is a 680x0 version, built with the Universal Headers.
 
C.K. Haun
April '94
Are you sure we don't already have a snippet like this????
Oh, I rememeber, that was on the //gs
 
*/
 
#include <Dialogs.h>
#include <Controls.h>
#include <QuickDraw.h>
#include <Windows.h>
#include <ToolUtils.h>
#include <OSUtils.h>
#include <Menus.h>
#include <Fonts.h>
#include <resources.h>
#include <Sound.h>
#include <Traps.h>
#include <Gestalt.h>
#include <Memory.h>
#include <Scrap.h>
#include <TextEdit.h> 
#include <Lists.h>
#include <Events.h>
#include <string.h>
 
#include "TestPrinterClass.h"
#include "SafeNameRegistry.h"
 
enum  {
    kSampleDialog = 512
};
enum  {
    kModelListItem = 3,
    kNameListItem,
    kStatTextItem1,
    kBlocksizePopupItem,
    kRepeatPopupItem,
    kAlignPopupItem
    
};
enum {
    appleID = 128,
    fileID,
    editID,
    blockID
};
 
enum {
    mApple = 0,
    mFile,
    mEdit,
    mBlocksize,
    MENU_COUNT
};
 
#include "ListInDialog.h"
 
ListHandle  gPrinterList, gModelList;                   /* making the list handle a global */
MenuHandle  menus[MENU_COUNT];
Boolean     done;
 
void 
SetupMenus( void )
{
    short               i;
    MenuHandle          *pMenu;
 
    menus[mApple] = GetMenu(appleID);
    AppendResMenu( menus[mApple], (ResType) 'DRVR');
    InsertMenu( menus[mApple], 0 );
 
    for (pMenu = &menus[1], i = 1; i < MENU_COUNT; i++ ) {
        *pMenu = GetMenu( i + appleID );
        InsertMenu(*pMenu++, 0);
    }
 
    DrawMenuBar();
}
 
ListHandle
MakeDialogList( DialogPtr dlg, int item )
{
 
    // this "rect" defines the data bounds of the list. In this case, a
    // one column list
    Rect tempRect;
    short tempItem;
    Handle tempHandle;
    Rect    listRect2   =  {  0, 0, 0, 1 };
    Cell    cp          =  {  0, 0  };
    // setting it up in the Dialog manager's records, 
    GetDialogItem( dlg, item, &tempItem, &tempHandle, &tempRect);
    
    /* inset the rect by 16, which is the width of the scroll bar that will be attached */
    /* to this list */
    tempRect.right -= 16;
    
    /* set the current port to this dialog */
    SetPort(dlg);
    
    /* create the list */
    
    return LNew(&tempRect,  // in the tempRect bounds
        &listRect2,             // with a sinngle column
        cp,                     // default cell size (a cell of 0,0 says that)
        0,                      // no special LDEF, use the standard one
        dlg,                    // put it in this port
        false,                  // do NOT draw initially
        false,                  // does NOT have a grow box space
        false,                  // does NOT scroll horizontally
        true);                  // DOES have a verticle scroll bar
}
 
 
 
/* Here is the filter that handles any List activity */
pascal Boolean theListFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
{
    
    Rect tempR;
    Boolean returnValue = false;    // defaults to me not saying I handled anything
    Boolean theBoolean;
    WindowPtr oldP;
 
    // get the current port, set the port to this dialog
    GetPort(&oldP);
    SetPort(theDialog);
    
    // was this an update event for this dialog?
    if ((theEvent->what == updateEvt) && (theEvent->message == (UInt32)theDialog)) {
        
        FrameOk( theDialog );
        // Update the list.
        LUpdate(theDialog->visRgn, gModelList);
        LUpdate(theDialog->visRgn, gPrinterList);
        
        // get the list rectangle
        // push it outwards one pixel and frame the list
        tempR = (*gModelList)->rView;
        InsetRect(&tempR, -1, -1);
        FrameRect(&tempR);
        
        tempR = (*gPrinterList)->rView;
        InsetRect(&tempR, -1, -1);
        FrameRect(&tempR);
        // NOTE: Do !NOT! return 'true' if you did SOME drawing in response to a dialog update
        // event in your filter!
        // ONLY if you did EVERYTHING should you return 'true', or else you can cause other updating
        // not to occur, which would be Bad
        
    } else {
        // see if this was a mouseDown event
        if (theEvent->what == mouseDown) {
            Point theP;
 
            // we set the port to the dialog on entry to the filter, so a GetMouse will work
            GetMouse(&theP);
            
            // get the list rectangle
            tempR = (*gModelList)->rView;
            
            // add the scroll bar back in for hit testing (remember we took it out earlier)
            tempR.right += 16;
            
            // See if they clicked in our list!
            if (PtInRect(theP, &tempR))
            {
                theBoolean = LClick(theP, 0, gModelList);
                // if they double-clicked the list, return 1, as if the OK button had been pressed
                if (theBoolean)
                    *itemHit = ok;
                else
                    *itemHit = kModelListItem;
                
                // tell the Dialog Manager that we handled this click, it can stop searching for a click-owner
                returnValue = true;
            }
 
            if ( returnValue != true )
            {
                // get the list rectangle
                tempR = (*gPrinterList)->rView;
                
                // add the scroll bar back in for hit testing (remember we took it out earlier)
                tempR.right += 16;
                
                // See if they clicked in our list!
                if (PtInRect(theP, &tempR))
                {
                    theBoolean = LClick(theP, 0, gPrinterList);
                    // if they double-clicked the list, return 1, as if the OK button had been pressed
                    if (theBoolean)
                        *itemHit = ok;
                    else
                        *itemHit = kNameListItem;
                    
                    // tell the Dialog Manager that we handled this click, it can stop searching for a click-owner
                    returnValue = true;
                }
            }
            if ( returnValue == true )
            {
                HiliteOk( theDialog );
            }
        }
    }
   
    // reset the original port
    
    SetPort(oldP);
    
    return(returnValue);
}
 
/*
    Sys7CDEFPopupPrivateDataHdl theMenuData = (Sys7CDEFPopupPrivateDataHdl) (**(ControlHandle)fHItem).contrlData;
 
    return (**theMenuData).mHandle;
*/
 
void
HiliteOk( DialogPtr dlg )
{
    //
    //  enable/disable the okay button if we have an item selected in each list
    //
    Cell    cp;
    Boolean enableOk;
    Rect    tempRect;
    short   tempItem;
    Handle  tempHandle;
 
    cp.h = 0;
    cp.v = 0;
    enableOk = LGetSelect( true, &cp, gModelList);
    if ( enableOk )
    {
        cp.h = 0;
        cp.v = 0;
        enableOk = LGetSelect( true, &cp, gPrinterList);
    }
    GetDialogItem( dlg, ok, &tempItem, &tempHandle, &tempRect);
    HiliteControl( (ControlHandle) tempHandle, enableOk? 0: 255 );
}
 
void
FrameOk( DialogPtr dlg )
{
    //
    //  outline the default ok button
    //
    Cell    cp;
    Boolean enableOk;
    Rect    tempRect;
    short   tempItem;
    Handle  tempHandle;
    RGBColor    gray = { 0x3FFF, 0x3FFF, 0x3FFF },
                black = { 0, 0, 0 };
 
    cp.h = 0;
    cp.v = 0;
    enableOk = LGetSelect( true, &cp, gModelList);
    if ( enableOk )
    {
        cp.h = 0;
        cp.v = 0;
        enableOk = LGetSelect( true, &cp, gPrinterList);
    }
    GetDialogItem( dlg, ok, &tempItem, &tempHandle, &tempRect);
    if ( !enableOk )
        RGBForeColor( &gray );
    InsetRect( &tempRect, -3, -3 );
    PenSize( 3, 3 );
    FrameRoundRect( &tempRect, 16, 16 );
    if ( !enableOk )
        RGBForeColor( &black );
    PenNormal();
 
}
 
void
GetNameFromCell (StringPtr theString, Cell cell, ListHandle hList)
{
    short length;
    
    /*
    The maximum length of the string is the size of a Str255, minus the
    length byteÉ
    */
    length = sizeof(Str255) - 1;
 
    LGetCell((StringPtr)(theString + 1), &length, cell, hList);
    
    /*
    Set the length byte.
    */
    *theString = (unsigned char) length;
}
 
int
GetDialogPopupValue( DialogPtr dlg, int item )
{
    Rect    tempRect;
    short   tempItem;
    Handle  tempHandle;
 
    GetDialogItem( dlg, item, &tempItem, &tempHandle, &tempRect);
    return GetControlValue( (ControlHandle) tempHandle);
}
 
void
SetDialogPopupValue( DialogPtr dlg, int item, int value )
{
    Rect    tempRect;
    short   tempItem;
    Handle  tempHandle;
 
    GetDialogItem( dlg, item, &tempItem, &tempHandle, &tempRect);
 
    SetControlValue( (ControlHandle) tempHandle, value );
}
 
int
ChoosePrinter( char *name, long *blocksize, int *repeats)
//ChoosePrinter( char *name, long *blocksize, int *repeats, int *align )
{
    char        model[255];
    short       length;
    Cell        cp =  {   0, 0 };        // cell to initialize with
    DialogPtr   myDialog = nil; // the dialog we're using
    short       hitItem = 0;    // hitItem for ModalDialog call
 
    static ModalFilterUPP modalFilterUPP;
    
    modalFilterUPP = NewModalFilterProc(theListFilter);
    /* get our dialog. It is created HIDDEN, and shown after I set the */
    /* user item that will hold the list */
 
    myDialog = GetNewDialog(kSampleDialog, nil, (WindowPtr)-1);
    
    // list all the known printer models
    gModelList = MakeDialogList( myDialog, kModelListItem );
    gPrinterList = MakeDialogList( myDialog, kNameListItem );
   
    SetUpList( gModelList, "");      // list all the known printer of the first model
    SetDialogPopupValue( myDialog, kBlocksizePopupItem, 6 );    //  512 byte default blocksize
    SetDialogPopupValue( myDialog, kRepeatPopupItem, 1 );       //  only send file down once
    
    cp.h = 0;
    cp.v = 0;
    length = sizeof(model);
    LGetCell( model, &length, cp, gModelList);
    if ( length > 0 )
    {
        LSetSelect( true, cp, gModelList);      // select the first model
 
        model[ length ] = 0;    // null terminate c-string
        SetUpList( gPrinterList, model );
        length = sizeof(model);
        cp.h = 0;
        cp.v = 0;
        LGetCell( model, &length, cp, gPrinterList);
        if ( length > 0 )
        {
            LSetSelect( true, cp, gPrinterList);    // select the first printer name
        }
    }
    // turn drawing on after the list has been filled
    LSetDrawingMode(true, gModelList);
    LSetDrawingMode(true, gPrinterList);
    HiliteOk( myDialog );   // enable/disable ok button
 
    // show the dialog
    ShowWindow((WindowPtr)myDialog);
    
    /* draw it once */
    DrawDialog(myDialog);
    
    // loop until ModalDialog is done
    do {
        // we have to use a ModalDialog filter, since ModalDialog doesn't
        // automatically handle lists
        ModalDialog(modalFilterUPP, &hitItem);
        
        // switch off what item was hit
        switch (hitItem) {
        case kModelListItem:    
            //
            //  rebuild the list of specific printers
            //
            cp.h = 0;
            cp.v = 0;
            if ( LGetSelect( true, &cp, gModelList) )
            {
                length = sizeof(model);
                LGetCell( model, &length, cp, gModelList);
                model[ length ] = 0;
 
                // create a new list of printer names
                LDispose( gPrinterList );
                gPrinterList = MakeDialogList( myDialog, kNameListItem );
                SetUpList( gPrinterList, model );
                cp.h = 0;
                cp.v = 0;
                LGetCell( model, &length, cp, gPrinterList);
                if ( length > 0 )
                {
                    LSetSelect( true, cp, gPrinterList);    // select the first printer name
                }
                LSetDrawingMode(true, gPrinterList);
                LUpdate( myDialog->visRgn, gPrinterList );
            }
            break;
        default:
            break;
            
        }
        // wait for an OK or Cancel
    }  while (hitItem != ok && hitItem != cancel);
    
    if ( hitItem == ok )
    {
        //
        //  save a reference to the requested printer
        //
        cp.h = 0;
        cp.v = 0;
        if ( LGetSelect( true, &cp, gModelList) )
        {
            length = sizeof(model);
            LGetCell( model, &length, cp, gPrinterList);
            model[ length ] = 0;
            strcpy( name, "Devices:device-tree:PRINTER:" );
            strcat( name, model );
 
            cp.h = 0;
            cp.v = 0;
            if ( LGetSelect( true, &cp, gPrinterList) > 0 )
            {
                length = sizeof(model);
                LGetCell( model, &length, cp, gPrinterList);
                model[ length ] = 0;
                strcat( name, ":" );
                strcat( name, model );
            }
        }
        //
        //  get the current blocksize
        //
        *blocksize = 1L<< (GetDialogPopupValue( myDialog, kBlocksizePopupItem ) - 1);
        //
        //  get the number of times to send the file
        //
        switch( GetDialogPopupValue( myDialog, kRepeatPopupItem ) )
        {
        case 2: *repeats =  2; break;
        case 3: *repeats =  5; break;
        case 4: *repeats = 10; break;
        case 5: *repeats = 20; break;
        case 6: *repeats = 30; break;
        case 7: *repeats = 50; break;
        case 8: *repeats =100; break;
        default:
        case 1: *repeats =  1; break;
        }
        switch( GetDialogPopupValue( myDialog, kAlignPopupItem ) )
        {
        case 1: 
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        default:
        break;
        }
   }
   // don't do anything in this sample
   LDispose( gModelList );
   LDispose( gPrinterList  );
    DisposeDialog(myDialog);
    return hitItem;
}
 
/*-----------------------------------------------------------------------------*
 
    SearchForUSBPrinters
    
    Desc:       Searches thru a printer model entry in the name registry
                looking for a model's printers. When one is found a call is 
                issued to the clients callback routine for further processing
 
    In:         - A pstring full path in the name registry of a printer model
                - A callback routine which gets called when a printer is found
                - A ptr to user data
                
    Out:        None
    
    History:
    
    17 Apr 98   oja     modified to use list manager instead of Chooser
    24 Feb 98   gp      Created
    
 *-----------------------------------------------------------------------------*/
void    
SetUpList( ListHandle theList, char *modelPath )
{
 
    RegEntryID      theModelEntry;      // the model node supported by the driver
    RegEntryID      aPrinterEntry;      // a printer node in the name registry
    RegEntryIterationOp iterOp;         // name registry iterator op code
    RegEntryIter    printerIterator;    // used to iterate child nodes of printer model
    Boolean         donePrinters    = false;    // NameRegistry param tell when we're done
    OSStatus        err             = noErr;    // error from name registry calls
    char            path[256];
    short           listCount = 0;
    Cell            cp;
 
    // name registry only deals with c strings
    strcpy( path, "Devices:device-tree:PRINTER" );
    if ( modelPath[0] != 0 )
    {
        strcat( path, ":" );
        strcat( path, modelPath );
    }
    
    // look up the node for the printer model requested
    err = SafeRegistryEntryIDInit(&theModelEntry);
    if( err == noErr ) 
        err = SafeRegistryCStrEntryLookup( nil, path, &theModelEntry );
    if( err == noErr ) 
    {
        // create an iterator to look at the child nodes for our printer model entry
        iterOp = kRegIterChildren;
 
        err = SafeRegistryEntryIterateCreate( &printerIterator );
        err = SafeRegistryEntryIterateSet(&printerIterator, &theModelEntry);
        
        if( err == noErr )
        {
            // look for a model's connected printers
            do
            {
                Str255                  nodeName;           // the name of the printer
                RegPropertyValueSize    nameSize;   // size of name buffer
 
                err = SafeRegistryEntryIterate( &printerIterator, iterOp, &aPrinterEntry, &donePrinters );
                // grab name of printer in name registyr
                nameSize = sizeof( nodeName );
                if( !donePrinters && err == noErr )
                    err = SafeRegistryPropertyGet( &aPrinterEntry, "name", &nodeName, &nameSize );
                if( !donePrinters && err == noErr )
                {
                    // add the printer to the list
                    listCount = LAddRow(1, listCount + 1, theList);
                    cp.h = 0;
                    cp.v = listCount;
                    LAddToCell(&nodeName, nameSize-1, cp, theList);
                }
                iterOp = kRegIterContinue;
            } while( !donePrinters && err == noErr );
            // end while for printers
        }
        SafeRegistryEntryIterateDispose(&printerIterator);
    }
 
    SafeRegistryEntryIDDispose( &theModelEntry );
 
}
 
// eof