home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / MacGofer 0.22d / MacGofer Sources / mac_SFMultiGet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-05  |  11.1 KB  |  470 lines  |  [TEXT/MPS ]

  1. /*
  2.     This code to implement a standard getfile dialog with two lists
  3.     is Copyright  ©1992
  4.  
  5.         Manuel Veloso
  6.         9 High Rock Way #3
  7.         Allston, MA 02134-2414
  8.         
  9.     It is freely available from many public FTP sites.
  10.     
  11.     Portions are Copyright © 1993, Kevin Hammond, Glasgow University.
  12.  
  13.     This code doesn't seem to handle aliases properly.  KH
  14. */
  15.  
  16. #include <StandardFile.h>
  17. #include <Resources.h>
  18. #include <Memory.h>
  19. #include <Lists.h>
  20. #include <Packages.h>
  21. #include <Files.h>
  22. #include <Controls.h>
  23.  
  24. #include "mac.h"
  25.  
  26. #pragma segment SFMultiGet
  27.  
  28. #define SFSaveDisk         0x214        /* Volume number (negative)      */
  29. #define CurDirStore     0x398        /* Current directory        */
  30.  
  31. enum
  32. {
  33.     okButton = 1,
  34.     blank2,
  35.     cancelButton,
  36.     item1,
  37.     ejectButton,
  38.     driveButton,
  39.     sfListBox,
  40.     scrollBar,
  41.     line1,
  42.     blank10,
  43.     filesBox,
  44.     removeButton,
  45.     addButton,
  46.     line,
  47.     myScrollBar,
  48.     kMyDialog = 128
  49. };
  50.  
  51. ListHandle    sfgTheList;                // list of files selected
  52. SFReply        sfgTheReply;            // the sf reply
  53. ControlHandle    sfgTheScrollBar;    // the scrollbar
  54. static int  sfgFileCount;            // how many files are selected
  55.  
  56.  
  57. /*
  58.     NOTE: the refCon of the control holds the # of files in the list AND the # of files
  59.     that are visible. The refCon starts out as a negative #; when a file is added, the
  60.     refCon is incremented. When refCon == 1, that means that scrolling must take place.
  61.     When a file is removed, the refCon is decremented by 1. Presumably, when all files
  62.     are removed the refCon == the original value.
  63. */
  64.  
  65. pascal void setItem(DialogPtr theDialog, short item, Handle theProc);
  66. pascal void hiliteItem(DialogPtr theDialog, short item, short hiliteValue);
  67. pascal void getBox(DialogPtr theDialog, short item, Rect *box);
  68. void addData(void);
  69. void removeCells(void);
  70. Boolean selected(void);
  71. pascal void myItem(DialogPtr theDialog, short itemNumber);
  72. pascal void initList(DialogPtr theDialog);
  73. pascal Boolean myFileFilter(CInfoPBPtr pb);
  74. pascal short myDlgHook(short item, DialogPtr theDialog);
  75. pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event, short *itemHit);
  76. pascal void sfgCleanup(void);
  77. void processData(void);
  78. void handleScrollBar(DialogPtr, EventRecord*);
  79. pascal void scrollProc(ControlHandle theControl, short theCode);
  80.  
  81. pascal void setItem(DialogPtr theDialog, short item, Handle theProc)
  82. {
  83.     short    itemType;
  84.     Rect    box;
  85.     Handle    theControl;
  86.     
  87.     GetDItem(theDialog, item, &itemType, &theControl, &box);
  88.     SetDItem(theDialog, item, itemType, theProc, &box);
  89. }
  90.     
  91. pascal void hiliteItem(DialogPtr theDialog, short item, short hiliteValue)
  92. {
  93.     short    itemType;
  94.     Rect    box;
  95.     Handle    theControl;
  96.     
  97.     GetDItem(theDialog, item, &itemType, &theControl, &box);
  98.     HiliteControl((ControlHandle) theControl, hiliteValue);
  99. }
  100.  
  101. pascal void getBox(DialogPtr theDialog, short item, Rect *box)
  102. {
  103.     short    itemType;
  104.     Handle    theControl;
  105.     
  106.     GetDItem(theDialog, item, &itemType, &theControl, box);
  107. }
  108.  
  109. /*
  110.     Initializes the list within the sfdialog. Sets the useritem to the
  111.     updateProc.
  112. */
  113.  
  114. pascal void initList(DialogPtr theDialog)
  115. {
  116.     Rect        rView, dataBounds;
  117.     Point        cSize = {0, 0};
  118.     short        temp;
  119.     FontInfo    fInfo;
  120.     GrafPtr        oldPort;
  121.     Boolean        good = false;
  122.  
  123.     GetPort(&oldPort);
  124.     SetPort(theDialog);
  125.     getBox(theDialog, filesBox, &rView);
  126.     SetRect(&dataBounds, 0, 0, 3, 0);
  127.     GetFontInfo(&fInfo);
  128.     cSize.h = rView.right;
  129.     cSize.v = fInfo.ascent + fInfo.descent + fInfo.leading;
  130.     sfgTheList = LNew(&rView, &dataBounds, cSize, 0, theDialog, true, false, false, false);
  131.     if (sfgTheList)
  132.     {
  133.         LDoDraw(true, sfgTheList);
  134.         (*sfgTheList)->selFlags = lNoNilHilite + lUseSense + lOnlyOne;
  135.         (*sfgTheList)->listFlags = lDoVAutoscroll;
  136.         LActivate(true, sfgTheList);
  137.         DisableButton(theDialog, removeButton);
  138.         setItem(theDialog, filesBox, (Handle) myItem);
  139.     }
  140.     hiliteItem(theDialog, myScrollBar, 255);
  141.     GetDItem(theDialog, myScrollBar, &temp, (Handle *) &sfgTheScrollBar, &dataBounds);
  142.     SetCRefCon(sfgTheScrollBar, -((rView.bottom - rView.top)/cSize.v));    // # of lines in box, negativized
  143.     SetCtlMin(sfgTheScrollBar, 0);
  144.     SetCtlMax(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar));
  145.     sfgFileCount = 0;
  146.     SetPort(oldPort);
  147.     return;
  148. }
  149.  
  150. pascal void sfgCleanup(void)
  151. {
  152.     if (sfgTheList) LDispose(sfgTheList);
  153. }
  154.  
  155. /*
  156.     Updates the list display, and does sundry drawing activities.
  157. */
  158.  
  159. pascal void myItem(DialogPtr theDialog, short itemNumber)
  160. {
  161.     Rect    box;
  162.     GrafPtr    oldPort;
  163.     
  164.     GetPort(&oldPort);
  165.     SetPort(theDialog);
  166.     
  167.     getBox(theDialog, filesBox, &box);
  168.     InsetRect(&box, -1, -1);
  169.     FrameRect(&box);
  170.     getBox(theDialog, line, &box);
  171.     FrameRect(&box);
  172.     LUpdate(theDialog->visRgn, sfgTheList);
  173.     SetPort(oldPort);
  174. }
  175.  
  176. // false displays the file, true doesn’t.
  177. // Don't display invisible files
  178.  
  179. static int IsDuplicateFile = false;
  180. char duplicateFName[256];
  181. long duplicatedirID;
  182. short duplicatevrefnum;
  183.  
  184. void sfgProcessData();
  185.  
  186.  
  187. static int CheckForDuplicates(name,vrefnum,dirID)
  188. char *name;
  189. short vrefnum;
  190. long dirID;
  191. {
  192.   char buff[32];
  193.   if(*name == '\0')
  194.     return(0);
  195.     
  196.   strcpy(buff,name);
  197.   resolvealias(&buff,&vrefnum,&dirID,FALSE);
  198.   if(strcmp(buff,duplicateFName)==0 && 
  199.      duplicatedirID == dirID && duplicatevrefnum == vrefnum)
  200.     {
  201.       IsDuplicateFile = true;
  202.     }
  203.   return(0);
  204. }
  205.  
  206.  
  207. Boolean IsADuplicate(name,vrefnum,dirID)
  208. char *name;
  209. short vrefnum;
  210. long dirID;
  211. {
  212.   IsDuplicateFile = false;
  213.   pstrcopy(name,duplicateFName);
  214.   p2cstr(duplicateFName);
  215.   duplicatevrefnum = vrefnum;
  216.   duplicatedirID = dirID;
  217.   sfgProcessData(CheckForDuplicates);
  218.   return (IsDuplicateFile);
  219. }
  220.  
  221. /*
  222.     must return item #; if no number, nothing happens. I've remapped the
  223.     add button to the okButton, and vice-versa to avoid lots of excess code.
  224. */
  225.  
  226. pascal short myDlgHook(short item, DialogPtr theDialog)
  227. {
  228.     switch (item)
  229.     {
  230.         case sfHookFirstCall:
  231.             initList(theDialog);
  232.             DisableButton(theDialog, addButton);
  233.             break;
  234.  
  235.         case okButton:            // maps to add!
  236.             addData();
  237.             if(sfgFileCount>0)
  238.               EnableButton(theDialog, addButton);
  239.  
  240.             if (GetCRefCon(sfgTheScrollBar)>0) hiliteItem(theDialog, myScrollBar, 0);
  241.             else hiliteItem(theDialog, myScrollBar, 255);
  242.             item = addButton;
  243.             break;
  244.  
  245.         case addButton:            // maps to ok!
  246.             item = okButton;
  247.             break;
  248.  
  249.         case removeButton:
  250.             removeCells();
  251.             if(sfgFileCount==0)
  252.               DisableButton(theDialog, addButton);
  253.  
  254.             DisableButton(theDialog, removeButton);
  255.             if (GetCRefCon(sfgTheScrollBar)>0) hiliteItem(theDialog, myScrollBar, 0);
  256.             else hiliteItem(theDialog, myScrollBar, 255);
  257.             break;
  258.     }
  259.     return item;
  260. }
  261.  
  262. // false->handle the event || true->ignore the event
  263.  
  264. pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event, short *itemHit)
  265. {
  266.     char  ch = (char) (event->message & charCodeMask);                         /* Convert to ASCII */
  267.  
  268.     switch (event->what)
  269.       {
  270.     
  271.         case mouseDown:
  272.         if (FrontWindow() == theDialog)
  273.           {
  274.             Rect    theView;
  275.             getBox(theDialog, filesBox, &theView);
  276.             GlobalToLocal(&(event->where));
  277.             if (PtInRect(event->where, &theView))
  278.             {
  279.                 LClick(event->where, event->modifiers, sfgTheList);
  280.             }
  281.             else
  282.             {
  283.                 getBox(theDialog, myScrollBar, &theView);
  284.                 if (PtInRect(event->where, &theView))
  285.                 {
  286.                     handleScrollBar(theDialog, event);
  287.                 }
  288.             }
  289.             LocalToGlobal(&(event->where));
  290.             hiliteItem(theDialog, removeButton, selected() ? 0 : 255);
  291.           }
  292.           break;
  293.       
  294.       
  295.         case keyDown:
  296.         case autoKey:
  297.           if((ch == 'l' || ch == 'L') && (event->modifiers & cmdKey) != 0)
  298.             {
  299.               *itemHit = addButton;
  300.               return(true);
  301.             }
  302.           break;
  303.           
  304.       }
  305.  
  306.     return false;
  307. }
  308.  
  309. // are any cells selected?
  310.  
  311. Boolean selected(void)
  312. {
  313.     Cell    theCell = {0, 0};
  314.     
  315.     return LGetSelect(true, &theCell, sfgTheList);
  316. }
  317.  
  318. // remove active cells. Even though there should be only one, I go thru them all anyway.
  319. void removeCells(void)
  320. {
  321.     Cell    theCell = {0, 0};
  322.     
  323.     while(LGetSelect(true, &theCell, sfgTheList))
  324.     {
  325.         --sfgFileCount;
  326.         LDelRow(1, theCell.v, sfgTheList);
  327.         SetCRefCon(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar) -1);    // subtract
  328.         SetCtlMax(sfgTheScrollBar,  GetCRefCon(sfgTheScrollBar));        // set scroll limit
  329.     }
  330. }
  331.  
  332. //    ugly, but effective: the list is 3 columns wide, so I just stuff
  333. //    the other 2 colums with the parID and the vRefNum, respectively.
  334.  
  335. void addData(void)
  336. {
  337.     long    parID;
  338.     short    vRefNum;
  339.     Str32    text;
  340.     short    len;
  341.     Cell    theCell = {0, 0};
  342.     
  343.     parID = *((long *)CurDirStore);
  344.     vRefNum = -1 * (*(short *)SFSaveDisk);
  345.     
  346.     /* Don't allow duplicates */
  347.     if(!IsADuplicate(sfgTheReply.fName,vRefNum,parID))
  348.       {
  349.         theCell.v = (**sfgTheList).dataBounds.bottom+1;
  350.         theCell.v = LAddRow(1, theCell.v, sfgTheList);
  351.     
  352.         len = sfgTheReply.fName[0];
  353.         LSetCell(&(sfgTheReply.fName[1]), len, theCell, sfgTheList);    // name
  354.  
  355.         NumToString(parID, text);
  356.         len = text[0];
  357.         theCell.h++;
  358.         LSetCell(&(text[1]), len, theCell, sfgTheList);                // parent id
  359.     
  360.         parID = vRefNum;
  361.         NumToString(parID, text);
  362.         len = text[0];
  363.         theCell.h++;
  364.         LSetCell(&(text[1]), len, theCell, sfgTheList);                // vrefnum
  365.         SetCRefCon(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar) + 1);    // add 1 file to count
  366.         SetCtlMax(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar));            // set scroll limit
  367.         ++sfgFileCount;
  368.      }
  369. }
  370.  
  371. //    just a test, to make sure all the files are there.
  372.  
  373. void sfgProcessData(processFile)
  374. int (*processFile)();
  375. {
  376.     FSSpec    theFile;
  377.     long    num;
  378.     Str32    text;
  379.     Cell    theCell = {0, 2};
  380.     short    len;
  381.     
  382.     for (theCell.v = 0; theCell.v < (**sfgTheList).dataBounds.bottom; theCell.v++)
  383.     {
  384.         char *fname;
  385.         len = 63;
  386.         LGetCell((theFile.name)+1, &len, theCell, sfgTheList);
  387.         theFile.name[0] = len;
  388.         StringToNum(theFile.name, &(theFile.parID));
  389.         theFile.vRefNum = theFile.parID;
  390.         
  391.         theCell.h--;
  392.         len = 63;
  393.         LGetCell((theFile.name)+1, &len, theCell, sfgTheList);
  394.         theFile.name[0] = len;
  395.         StringToNum(theFile.name, &(theFile.parID));
  396.         
  397.         theCell.h--;
  398.         len = 63;
  399.         LGetCell(theFile.name+1, &len, theCell, sfgTheList);
  400.         theFile.name[0] = len;
  401.         theCell.h = 2;
  402.         fname = (char *) p2cstr(theFile.name);
  403.         resolvealias(&fname,&theFile.vRefNum,&theFile.parID,FALSE);
  404.         processFile(fname,theFile.vRefNum,theFile.parID);
  405.     }
  406. }
  407.  
  408. /*
  409. void main(void)
  410. {
  411.     Point    where = {-1, -1};
  412.         
  413.     // note: the file filter can be omitted, if you want.
  414.     SFPGetFile(where, "\pSelect files:", myFileFilter, -1, nil, myDlgHook, &sfgTheReply, kMyDialog, myFilterProc);
  415.  
  416.     if (sfgTheReply.good)
  417.     {
  418.         processData();
  419.     }
  420.     sfgCleanup();
  421. }
  422. */
  423.  
  424. void handleScrollBar(DialogPtr theDialog, EventRecord *event)
  425. {
  426.     short            thePart, oldVal;
  427.     Point            pt = (*event).where;
  428.     ControlHandle    theControl;
  429.     
  430.     if ((thePart = FindControl(pt, theDialog, &theControl)) == inThumb)
  431.     {
  432.         oldVal = GetCtlValue(theControl);
  433.         thePart = TrackControl(theControl, pt, nil);
  434.         LScroll(0, GetCtlValue(theControl) - oldVal, sfgTheList);
  435.     }
  436.  
  437.     /* Added check for disabled control -- KH */
  438.     else if (thePart != 0)
  439.     {
  440.         thePart = TrackControl(theControl, pt, (ProcPtr) scrollProc);
  441.     }
  442. }
  443.  
  444. pascal void scrollProc(ControlHandle theControl, short theCode)
  445. {
  446.     short    theValue = GetCtlValue(theControl);
  447.     short    maxValue = GetCtlMax(theControl);
  448.     switch (theCode)
  449.     {
  450.         case inPageDown:
  451.         case inDownButton:
  452.             theValue++;
  453.             LScroll(0, 1, sfgTheList);
  454.             break;
  455.         case inPageUp:
  456.         case inUpButton:
  457.             LScroll(0, -1, sfgTheList);
  458.             theValue--;
  459.             break;
  460.  
  461.         /* Added missing case -- KH */            
  462.         case 0:
  463.             return;
  464.     }
  465.  
  466.     /* Original didn't check for out-of-range values!! KH */    
  467.     if(theValue <= maxValue && theValue >= 0)
  468.       SetCtlValue(theControl, theValue);
  469. }
  470.