home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / CNRSAMP.ZIP / CNRBAS.ZIP / CNRBAS.C next >
Text File  |  1992-12-15  |  37KB  |  1,057 lines

  1. /* ===================================================================*/
  2. /*            Basic Container Sample program for ColoradOS/2          */
  3. /* ------------------------------------------------------------------ */
  4. /*                                                                    */
  5. /*  Functional Description:                                           */
  6. /*                                                                    */
  7. /*    This program demonstrates an application using a basic          */
  8. /*    container window.  All views of the container are utilized.     */
  9. /*    This sample program is not intended to show all of the          */
  10. /*    container's features or function, but to provide a simple       */
  11. /*    example of how to program to the container utilizing some       */
  12. /*    of the more basic and common functions.  The function           */
  13. /*    shown in this sample includes:                                  */
  14. /*                                                                    */
  15. /*    - setting up a container window                                 */
  16. /*    - setting up various container views                            */
  17. /*    - switching between the container views                         */
  18. /*    - allocating record memory                                      */
  19. /*    - setting up records                                            */
  20. /*    - inserting records                                             */
  21. /*    - freeing resources when the application is closed              */
  22. /*                                                                    */
  23. /*  For: Programming the OS/2 Container Control - ColoradOS/2,        */
  24. /*       January, 11-15 1993, Colorado Springs, Colorado.             */
  25. /*                                                                    */
  26. /*  Compiled using: IBM C Set/2 1.0                                   */
  27. /*                                                                    */
  28. /*  By: Peter P. Brightbill                                           */
  29. /*      Peter F. Haggar                                               */
  30. /*                                                                    */
  31. /*  Copyright (C) 1992, IBM Corporation                               */
  32. /* ===================================================================*/
  33. #define INCL_WINWINDOWMGR
  34. #define INCL_WINSYS
  35. #define INCL_WINPOINTERS
  36. #define INCL_WINSTDCNR
  37. #include <os2.h>
  38. #include <stdlib.h>
  39. #include <cnrbas.h>
  40.  
  41. void main(void)
  42. {
  43.   HAB   hab;
  44.   HMQ   hmq;
  45.   QMSG  qmsg;
  46.   HWND  hwndFrame;
  47.   HWND  hwndClient;
  48.   ULONG fcf = FCF_TITLEBAR | FCF_SIZEBORDER | FCF_SYSMENU |
  49.               FCF_ICON | FCF_MENU | FCF_MINMAX | FCF_SHELLPOSITION;
  50.  
  51.   hab = WinInitialize (0);
  52.   hmq = WinCreateMsgQueue (hab, 0);
  53.  
  54.   /* Register the Container sample window class.  Also reserve 4 bytes
  55.    * of memory to store a pointer to our control block.
  56.    */
  57.   WinRegisterClass (hab, "Container Sample",
  58.                     CnrSampleWndProc, 0, 4);
  59.  
  60.   /* Create a standard frame window. */
  61.   hwndFrame = WinCreateStdWindow (HWND_DESKTOP, /* Handle of desktop  */
  62.                            WS_VISIBLE,          /* Window style       */
  63.                            &fcf,                /* Creation flags     */
  64.                            "Container Sample",  /* Client Class name  */
  65.                            "Container Sample",  /* Title Bar text     */
  66.                            0,                   /* client wnd style   */
  67.                            NULLHANDLE,          /* hwnd of resources  */
  68.                            SAMPLE_MENU_ID,      /* ID of Resources    */
  69.                            &hwndClient);        /* handle of Client   */
  70.  
  71.   while (WinGetMsg (hab, &qmsg, NULLHANDLE, 0, 0))
  72.   {
  73.     WinDispatchMsg (hab, &qmsg);
  74.   }
  75.  
  76.   WinDestroyWindow (hwndFrame);
  77.   WinDestroyMsgQueue (hmq);
  78.   WinTerminate (hab);
  79. }
  80.  
  81. /*----------------------------------------------------------------------
  82.  Function Name: CnrSampleWndProc
  83.  
  84.  Description:
  85.    This is the window procedure for the client are of our window.  It is
  86.    also the owner of the container control window.
  87.  
  88.  Parameters:
  89.    (HWND)    hwnd - The handle of the client window.
  90.    (ULONG)   msg  - The message to be processed.
  91.    (MRESULT) mp1  - The first message parameter for the message.
  92.    (MRESULT) mp2  - The second message parameter for the message.
  93. ----------------------------------------------------------------------*/
  94. MRESULT EXPENTRY CnrSampleWndProc (HWND hwnd, ULONG msg,
  95.                                    MRESULT mp1, MRESULT mp2)
  96. {
  97.   SWP          swp;
  98.   HPS          hps;
  99.   RECTL        rect;
  100.   CNRINFO      CnrInfo;
  101.   PSAMPLEINFO  pSampleInfo;
  102.  
  103.   switch (msg)
  104.   {
  105.     case WM_CREATE:
  106.       /* Create the container window.  If it creates successfully,
  107.        * return FALSE, otherwise return TRUE to indicate an error.
  108.        */
  109.       if (CreateCnr (hwnd))
  110.       {
  111.         return ((MRESULT)FALSE);
  112.       }
  113.       else
  114.       {
  115.         return ((MRESULT)TRUE);
  116.       }
  117.  
  118.     case WM_PAINT:
  119.       hps = WinBeginPaint (hwnd, NULLHANDLE, &rect);
  120.       WinFillRect (hps, &rect, SYSCLR_BACKGROUND);
  121.       WinEndPaint (hps);
  122.     break;
  123.  
  124.     case WM_SIZE:
  125.       /* Size the container window to cover the entire client area.
  126.        * General note: When setting the position of only 1 window, for
  127.        * performance reasons, use WinSetMultWindowPos instead of
  128.        * WinSetWindowPos.  The reason for this is because when
  129.        * setting the position of 1 window with WinSetWindowPos,
  130.        * inside of PMWIN, WinSetWindowPos calls WinSetMultWindowPos
  131.        * with a value of 1.  Therefore, coding as we do below shortens
  132.        * the code path as well as execution time.  This will not
  133.        * make or break your application, but is a good tip...also
  134.        * good for as a trivia question at your next office party.
  135.        */
  136.       swp.fl = SWP_MOVE | SWP_SIZE;
  137.       swp.x = swp.y = 0;
  138.       swp.cx = SHORT1FROMMP(mp2);
  139.       swp.cy = SHORT2FROMMP(mp2);
  140.       swp.hwndInsertBehind = NULLHANDLE;
  141.       swp.hwnd = WinWindowFromID (hwnd, CNR_SAMPLE_ID);
  142.       WinSetMultWindowPos (WinQueryAnchorBlock (hwnd), &swp, 1);
  143.     break;
  144.  
  145.     case WM_DESTROY:
  146.       /* When the user double clicks on the system menu of our frame
  147.        * window, or chooses the QUIT option from our menu, call a
  148.        * function to free up the resources utilized by this application.
  149.        */
  150.       CleanupCnr (hwnd);
  151.     break;
  152.  
  153.     case WM_COMMAND:
  154.       /* Get the pointer to our application's control block. */
  155.       pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  156.  
  157.       /* The following messages are received when the user chooses
  158.        * one of the menu options on our action bar.
  159.        */
  160.       switch (SHORT1FROMMP(mp1))
  161.       {
  162.         case TEXTV_ID:
  163.           /* Switch the container to Text view. */
  164.           CnrInfo.flWindowAttr = CV_TEXT;
  165.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  166.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR));
  167.         break;
  168.  
  169.         case TEXTV_FLOWED_ID:
  170.           /* Switch the container to Flowed Text view. */
  171.           CnrInfo.flWindowAttr = CV_TEXT | CV_FLOW;
  172.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  173.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR));
  174.         break;
  175.  
  176.         case NAMEV_ID:
  177.           /* Switch the container to Name view with a container
  178.            * title.
  179.            */
  180.           CnrInfo.flWindowAttr = CV_NAME | CA_CONTAINERTITLE |
  181.                                  CA_TITLESEPARATOR;
  182.           CnrInfo.pszCnrTitle = pSampleInfo->pszCnrTitle;
  183.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  184.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR |
  185.                                                     CMA_CNRTITLE));
  186.         break;
  187.  
  188.         case NAMEV_FLOWED_ID:
  189.           /* Switch the container to Flowed Name view with a
  190.            * container title.
  191.            */
  192.           CnrInfo.flWindowAttr = CV_NAME | CV_FLOW;
  193.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  194.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR));
  195.         break;
  196.  
  197.         case ICONV_ID:
  198.           /* Set the container to Icon view with a container title,
  199.            * then arrange it so the records display orderly.
  200.            */
  201.           CnrInfo.flWindowAttr = CV_ICON | CA_CONTAINERTITLE |
  202.                                  CA_TITLESEPARATOR;
  203.           CnrInfo.pszCnrTitle = pSampleInfo->pszCnrTitle;
  204.  
  205.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  206.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR |
  207.                                                     CMA_CNRTITLE));
  208.           WinSendMsg (pSampleInfo->hwndCnr, CM_ARRANGE, NULL, NULL);
  209.         break;
  210.  
  211.         case TREEV_ID:
  212.           /* Switch the container to Tree view.  If this is the
  213.            * first time the user has requested Tree view, populate
  214.            * it first.  Also, add the container title to Tree view.
  215.            */
  216.           if (!pSampleInfo->bTreePopulated)
  217.           {
  218.             if (PopulateTree (hwnd))
  219.             {
  220.               pSampleInfo->bTreePopulated = TRUE;
  221.             }
  222.             else
  223.             {
  224.               return ((MRESULT)NULL);
  225.             }
  226.           }
  227.           CnrInfo.flWindowAttr = CV_TREE | CV_ICON | CA_TREELINE |
  228.                                  CA_CONTAINERTITLE | CA_TITLESEPARATOR;
  229.           CnrInfo.pszCnrTitle = pSampleInfo->pszCnrTitle;
  230.  
  231.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  232.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR |
  233.                                                     CMA_CNRTITLE));
  234.         break;
  235.  
  236.         case DETAILSV_ID:
  237.           /* Switch the container to Details view.  Set the
  238.            * splitbar in the middle of the container window.
  239.            */
  240.           WinQueryWindowRect (pSampleInfo->hwndCnr, &rect);
  241.           CnrInfo.flWindowAttr = CV_DETAIL | CA_DETAILSVIEWTITLES;
  242.           CnrInfo.xVertSplitbar = rect.xRight / 2;
  243.           CnrInfo.pFieldInfoLast = pSampleInfo->pFieldInfoLast;
  244.           WinSendMsg (pSampleInfo->hwndCnr, CM_SETCNRINFO,
  245.                       MPFROMP(&CnrInfo), MPFROMLONG(CMA_FLWINDOWATTR |
  246.                       CMA_XVERTSPLITBAR | CMA_PFIELDINFOLAST));
  247.         break;
  248.  
  249.         case SAMPLE_MENU_QUIT:
  250.           /* The user has requested to quit the application.  Post
  251.            * a WM_QUIT to ourselves and bail.
  252.            */
  253.           WinPostMsg (hwnd, WM_QUIT, 0, 0);
  254.         break;
  255.  
  256.         default:
  257.           return (WinDefWindowProc (hwnd, msg, mp1, mp2));
  258.       }
  259.       break;
  260.  
  261.     default:
  262.       return (WinDefWindowProc (hwnd, msg, mp1, mp2));
  263.   }
  264.   return (0);
  265. }
  266.  
  267. /*----------------------------------------------------------------------
  268.  Function Name: CreateCnr
  269.  
  270.  Description:
  271.    This function creates a container window, then populates the
  272.    container with 5 records.
  273.  
  274.  Parameters:
  275.    (HWND) hwnd - The handle of the client window that we are creating
  276.                  the container in.
  277.  
  278.  Return Values:
  279.    (BOOL)  TRUE  - Successful creation of the container window.
  280.            FALSE - Container window not created successfully due to
  281.                    an error.
  282. ----------------------------------------------------------------------*/
  283. BOOL CreateCnr (HWND hwnd)
  284. {
  285.   HWND         hwndCnr;
  286.   PSAMPLEINFO  pSampleInfo;
  287.   CNRINFO      CnrInfo;
  288.   BOOL         rc = TRUE;
  289.  
  290.   /* Create the container window. */
  291.   hwndCnr = WinCreateWindow (hwnd,                    /* Parent       */
  292.                          WC_CONTAINER,                /* Class        */
  293.                          NULL,                        /* Window text  */
  294.                          WS_VISIBLE | CCS_READONLY |  /* Window style */
  295.                          CCS_EXTENDSEL | CCS_MINIRECORDCORE,
  296.                          0,0,                         /* x,y          */
  297.                          0,0,                         /* cx, cy       */
  298.                          hwnd,                        /* Owner        */
  299.                          HWND_TOP,                    /* placement    */
  300.                          CNR_SAMPLE_ID,               /* Window ID    */
  301.                          NULL,                        /* Control data */
  302.                          NULL);                       /* presparams   */
  303.  
  304.   /* If the window is created successfully, allocate some memory
  305.    * for our control block and initialize it to 0.  Then, set the
  306.    * information in it and store a pointer to this structure in the
  307.    * window words we reserved on the WinRegisterClass call.
  308.    */
  309.   if (hwndCnr)
  310.   {
  311.     pSampleInfo = malloc (sizeof(SAMPLEINFO));
  312.     if (pSampleInfo)
  313.     {
  314.       memset (pSampleInfo, 0, sizeof(SAMPLEINFO));
  315.       pSampleInfo->hwndCnr = hwndCnr;
  316.       WinSetWindowPtr (hwnd, QWL_USER, pSampleInfo);
  317.  
  318.       /* Give the container a title and a horizontal separator to
  319.        * separate the title from the viewport.  Store a pointer to
  320.        * the container title in our control block since we will
  321.        * need it whenever the user switches to a view that we want
  322.        * to display the title in.
  323.        */
  324.       pSampleInfo->pszCnrTitle = malloc(TEXT_SIZE);
  325.       if (pSampleInfo->pszCnrTitle)
  326.       {
  327.         strcpy (pSampleInfo->pszCnrTitle,
  328.                 "Basic Container\r\nSample Program");
  329.         CnrInfo.pszCnrTitle = pSampleInfo->pszCnrTitle;
  330.         CnrInfo.flWindowAttr = CV_ICON | CA_CONTAINERTITLE |
  331.                                CA_TITLESEPARATOR;
  332.         WinSendMsg (hwndCnr,
  333.                     CM_SETCNRINFO,
  334.                     MPFROMP(&CnrInfo),
  335.                     MPFROMLONG(CMA_CNRTITLE | CMA_FLWINDOWATTR));
  336.  
  337.         /* Populate the container with 5 records.  This function will
  338.          * also set up the details view information for each record.
  339.          */
  340.         if (!PopulateCnr (hwnd))
  341.         {
  342.           rc = FALSE;
  343.         }
  344.       }
  345.       else
  346.       {
  347.         rc = FALSE;  /* Out of memory error */
  348.       }
  349.     }
  350.     else
  351.     {
  352.       rc = FALSE; /* Out of memory error */
  353.     }
  354.   }
  355.   else
  356.   {
  357.     rc = FALSE; /* Creation error */
  358.   }
  359.  
  360.   if (!rc)
  361.   {
  362.     if (hwndCnr)
  363.     {
  364.       WinDestroyWindow (hwndCnr);
  365.     }
  366.     if (pSampleInfo)
  367.     {
  368.       if (pSampleInfo->pszCnrTitle)
  369.       {
  370.         free (pSampleInfo->pszCnrTitle);
  371.       }
  372.       free (pSampleInfo);
  373.     }
  374.   }
  375.   else
  376.   {
  377.     /* Give the container the focus and return. */
  378.     WinSetFocus (HWND_DESKTOP, hwndCnr);
  379.   }
  380.   return (rc);
  381. }
  382.  
  383. /*----------------------------------------------------------------------
  384.  Function Name: PopulateCnr
  385.  
  386.  Description:
  387.    This function allocates 5 container records, assigns the appropriate
  388.    information, including the information needed for details view and
  389.    finally inserts the 5 records into the container.
  390.  
  391.  Parameters:
  392.    (HWND) hwnd - The handle of the client window.
  393.  
  394.  Return Values:
  395.    (BOOL)  TRUE  - Records inserted successfully.
  396.            FALSE - Records not inserted due to an error.
  397. ----------------------------------------------------------------------*/
  398. BOOL PopulateCnr (HWND hwnd)
  399. {
  400.   PSAMPLEINFO    pSampleInfo;
  401.   PPERSONRECORD  pPersonRec;
  402.   PPERSONRECORD  pPersonRecFirst;
  403.   HPOINTER       hptrPersonIcon;
  404.   USHORT         i;
  405.   RECORDINSERT   RecordInsert;
  406.   BOOL           rc = TRUE;
  407.   ULONG          ulNumRecords = 5;
  408.  
  409.   /* Get the pointer to our control block. */
  410.   pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  411.  
  412.   /* Load the person icon that will be used by the container in views
  413.    * which show icons.  These icons are used multiple times, but
  414.    * be sure to only load them once and reuse the HPOINTER.
  415.    */
  416.   pSampleInfo->hptrPersonIcon = WinLoadPointer (HWND_DESKTOP,
  417.                                                 NULLHANDLE,
  418.                                                 ID_PERSON_ICON);
  419.  
  420.   /* Load the job icon that will be used for the child records
  421.    * in Tree View.
  422.    */
  423.   pSampleInfo->hptrJobIcon = WinLoadPointer (HWND_DESKTOP,
  424.                                              NULLHANDLE,
  425.                                              ID_JOB_ICON);
  426.  
  427.   /* Allocate and insert the fieldinfo structures. */
  428.   if (!SetupAndAddFieldInfos (hwnd))
  429.   {
  430.     return (FALSE);
  431.   }
  432.  
  433.   /* Allocate a linked list of records.  Note how MP1 is calculated.
  434.    * It is the number of ADDITIONAL bytes that you want the container
  435.    * to allocate per record.  Since PERSONRECORD contains a
  436.    * MINIRECORDCORE, we subtract it out.  Now if you ever change the
  437.    * size of PERSONRECORD by adding or subtracting any extra fields,
  438.    * this code will not have to change.
  439.    */
  440.   pPersonRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  441.                                        CM_ALLOCRECORD,
  442.                                        MPFROMLONG(sizeof(PERSONRECORD) -
  443.                                        sizeof(MINIRECORDCORE)),
  444.                                        MPFROMLONG(ulNumRecords));
  445.  
  446.   /* Save a pointer to the front of the list of records returned.  This
  447.    * will be used when we insert the records at the bottom of this
  448.    * function.
  449.    */
  450.   pPersonRecFirst = pPersonRec;
  451.  
  452.   /* Loop through all the records assigning the necessary
  453.    * information.
  454.    */
  455.   i = 1;
  456.   while ((pPersonRec) && (rc))
  457.   {
  458.     pPersonRec->MiniRec.hptrIcon = pSampleInfo->hptrPersonIcon;
  459.     pPersonRec->MiniRec.pszIcon = malloc (TEXT_SIZE);
  460.  
  461.     /* If we successfully allocated the memory, copy the text string
  462.      * to the pszIcon field and go to the next record in the linked
  463.      * list.
  464.      */
  465.     if (pPersonRec->MiniRec.pszIcon)
  466.     {
  467.       /* Set up the record specific data for each record, including
  468.        * the details view data.
  469.        */
  470.       switch (i)
  471.       {
  472.         case 1:
  473.           strcpy (pPersonRec->MiniRec.pszIcon, "Peter Haggar");
  474.           strcpy (pPersonRec->szMiddleInit, "F");
  475.           pPersonRec->pszMiddleInit = pPersonRec->szMiddleInit;
  476.           pPersonRec->DateOfBirth.month = 2;
  477.           pPersonRec->DateOfBirth.day   = 3;
  478.           pPersonRec->DateOfBirth.year  = 65;
  479.           pPersonRec->TimeOfBirth.hours   = 3;
  480.           pPersonRec->TimeOfBirth.minutes = 30;
  481.           pPersonRec->TimeOfBirth.seconds = 0;
  482.           pPersonRec->CurrentAge = 27;
  483.           pPersonRec->usJob = JR_DEVELOPMENT;
  484.         break;
  485.  
  486.         case 2:
  487.           strcpy (pPersonRec->MiniRec.pszIcon, "Peter Brightbill");
  488.           strcpy (pPersonRec->szMiddleInit, "P");
  489.           pPersonRec->pszMiddleInit = pPersonRec->szMiddleInit;
  490.           pPersonRec->DateOfBirth.month = 1;
  491.           pPersonRec->DateOfBirth.day   = 23;
  492.           pPersonRec->DateOfBirth.year  = 65;
  493.           pPersonRec->TimeOfBirth.hours   = 17;
  494.           pPersonRec->TimeOfBirth.minutes = 10;
  495.           pPersonRec->TimeOfBirth.seconds = 47;
  496.           pPersonRec->CurrentAge = 27;
  497.           pPersonRec->usJob = JR_DEVELOPMENT;
  498.         break;
  499.  
  500.         case 3:
  501.           strcpy (pPersonRec->MiniRec.pszIcon, "Bob Jones");
  502.           strcpy (pPersonRec->szMiddleInit, "T");
  503.           pPersonRec->pszMiddleInit = pPersonRec->szMiddleInit;
  504.           pPersonRec->DateOfBirth.month = 7;
  505.           pPersonRec->DateOfBirth.day   = 11;
  506.           pPersonRec->DateOfBirth.year  = 54;
  507.           pPersonRec->TimeOfBirth.hours   = 10;
  508.           pPersonRec->TimeOfBirth.minutes = 56;
  509.           pPersonRec->TimeOfBirth.seconds = 19;
  510.           pPersonRec->CurrentAge = 38;
  511.           pPersonRec->usJob = JR_SUPPORT;
  512.         break;
  513.  
  514.         case 4:
  515.           strcpy (pPersonRec->MiniRec.pszIcon, "Joe Shmo");
  516.           strcpy (pPersonRec->szMiddleInit, "D");
  517.           pPersonRec->pszMiddleInit = pPersonRec->szMiddleInit;
  518.           pPersonRec->DateOfBirth.month = 10;
  519.           pPersonRec->DateOfBirth.day   = 29;
  520.           pPersonRec->DateOfBirth.year  = 70;
  521.           pPersonRec->TimeOfBirth.hours   = 23;
  522.           pPersonRec->TimeOfBirth.minutes = 5;
  523.           pPersonRec->TimeOfBirth.seconds = 36;
  524.           pPersonRec->CurrentAge = 22;
  525.           pPersonRec->usJob = JR_SUPPORT;
  526.         break;
  527.  
  528.         case 5:
  529.           strcpy (pPersonRec->MiniRec.pszIcon, "John Public");
  530.           strcpy (pPersonRec->szMiddleInit, "Q");
  531.           pPersonRec->pszMiddleInit = pPersonRec->szMiddleInit;
  532.           pPersonRec->DateOfBirth.month = 5;
  533.           pPersonRec->DateOfBirth.day   = 17;
  534.           pPersonRec->DateOfBirth.year  = 61;
  535.           pPersonRec->TimeOfBirth.hours   = 19;
  536.           pPersonRec->TimeOfBirth.minutes = 3;
  537.           pPersonRec->TimeOfBirth.seconds = 9;
  538.           pPersonRec->CurrentAge = 31;
  539.           pPersonRec->usJob = JR_DEVELOPMENT;
  540.         break;
  541.       }
  542.       pPersonRec = (PPERSONRECORD)pPersonRec->MiniRec.preccNextRecord;
  543.       i++;
  544.     }
  545.     else
  546.     {
  547.       rc = FALSE;
  548.     }
  549.   }
  550.  
  551.   /* Now that we have the data assigned, insert the records in the
  552.    * container.  First set up the RECORDINSERT structure which tells
  553.    * the container how to insert the records.
  554.    */
  555.   RecordInsert.cb = sizeof(RECORDINSERT);
  556.   RecordInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST;
  557.   RecordInsert.pRecordParent = NULL;
  558.   RecordInsert.zOrder = CMA_TOP;
  559.   RecordInsert.cRecordsInsert = ulNumRecords;
  560.   RecordInsert.fInvalidateRecord = TRUE;
  561.  
  562.   /* Since the container will be coming up in Icon view, after inserting
  563.    * the records, send the CM_ARRANGE message to arrange the icons in
  564.    * the container viewport.
  565.    */
  566.   if (WinSendMsg (pSampleInfo->hwndCnr,
  567.                   CM_INSERTRECORD,
  568.                   MPFROMP(pPersonRecFirst),
  569.                   MPFROMP(&RecordInsert)))
  570.   {
  571.     WinSendMsg (pSampleInfo->hwndCnr, CM_ARRANGE, NULL, NULL);
  572.   }
  573.   else
  574.   {
  575.     rc = FALSE;
  576.   }
  577.  
  578.   return (rc);
  579. }
  580.  
  581. /*----------------------------------------------------------------------
  582.  Function Name: SetupAndAddFieldInfos
  583.  
  584.  Description:
  585.    This function allocates, sets up, and inserts the 6 FieldInfo
  586.    structures that are used to describe each column for the Details
  587.    view.
  588.  
  589.  Parameters:
  590.    (HWND) hwnd - The handle of the client window.
  591.  
  592.  Return Values:
  593.    (BOOL)  TRUE  - FieldInfo structures successfully inserted.
  594.            FALSE - FieldInfo structures not inserted due to an error.
  595. ----------------------------------------------------------------------*/
  596. BOOL SetupAndAddFieldInfos (HWND hwnd)
  597. {
  598.   PSAMPLEINFO      pSampleInfo;
  599.   PFIELDINFO       pFieldInfo;
  600.   PFIELDINFO       pFieldInfoFirst;
  601.   FIELDINFOINSERT  FieldInfoInsert;
  602.   BOOL             rc = TRUE;
  603.   USHORT           usNumFieldInfo = 6;
  604.   USHORT           i = 1;
  605.  
  606.   /* Get the pointer to our control block. */
  607.   pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  608.  
  609.   /* Allocate the 6 FieldInfo structures used for the columns in
  610.    * Details view.
  611.    */
  612.   pFieldInfo = WinSendMsg (pSampleInfo->hwndCnr,
  613.                            CM_ALLOCDETAILFIELDINFO,
  614.                            MPFROMSHORT(usNumFieldInfo),
  615.                            NULL);
  616.  
  617.   pFieldInfoFirst = pFieldInfo;
  618.  
  619.   /* Loop through each FieldInfo and assign the data as necessary.
  620.    * Pay particular attention to the offStruct field.  This tells
  621.    * the container at what offset from the beginning of the
  622.    * RECORDCORE/MINIRECORDCORE to find the data that is to be
  623.    * displayed in the column.
  624.    */
  625.   while ((pFieldInfo) && (rc))
  626.   {
  627.     switch (i)
  628.     {
  629.       case 1:
  630.         pFieldInfo->flTitle = CFA_BITMAPORICON;
  631.         pFieldInfo->pTitleData = (PVOID)pSampleInfo->hptrPersonIcon;
  632.         pFieldInfo->flData = CFA_BITMAPORICON | CFA_HORZSEPARATOR |
  633.                              CFA_SEPARATOR;
  634.         pFieldInfo->offStruct = FIELDOFFSET(PERSONRECORD,
  635.                                             MiniRec.hptrIcon);
  636.       break;
  637.  
  638.       case 2:
  639.         pSampleInfo->pFieldInfoLast = pFieldInfo;
  640.         pFieldInfo->flTitle = CFA_STRING;
  641.         pFieldInfo->pTitleData = malloc(TEXT_SIZE);
  642.         if (pFieldInfo->pTitleData)
  643.         {
  644.           strcpy(pFieldInfo->pTitleData, "Name");
  645.           pFieldInfo->flData = CFA_STRING | CFA_HORZSEPARATOR;
  646.           pFieldInfo->offStruct = FIELDOFFSET(PERSONRECORD,
  647.                                               MiniRec.pszIcon);
  648.         }
  649.         else
  650.         {
  651.           rc = FALSE;
  652.         }
  653.       break;
  654.  
  655.       case 3:
  656.         pFieldInfo->flTitle = CFA_STRING;
  657.         pFieldInfo->pTitleData = malloc(TEXT_SIZE);
  658.         if (pFieldInfo->pTitleData)
  659.         {
  660.           strcpy(pFieldInfo->pTitleData, "Middle Initial");
  661.           pFieldInfo->flData = CFA_STRING | CFA_CENTER |
  662.                                CFA_HORZSEPARATOR;
  663.           pFieldInfo->offStruct = FIELDOFFSET(PERSONRECORD,
  664.                                               pszMiddleInit);
  665.         }
  666.         else
  667.         {
  668.           rc = FALSE;
  669.         }
  670.       break;
  671.  
  672.       case 4:
  673.         pFieldInfo->flTitle = CFA_STRING;
  674.         pFieldInfo->pTitleData = malloc(TEXT_SIZE);
  675.         if (pFieldInfo->pTitleData)
  676.         {
  677.           strcpy(pFieldInfo->pTitleData, "Date of Birth");
  678.           pFieldInfo->flData = CFA_DATE | CFA_RIGHT | CFA_HORZSEPARATOR;
  679.           pFieldInfo->offStruct = FIELDOFFSET(PERSONRECORD,
  680.                                               DateOfBirth);
  681.         }
  682.         else
  683.         {
  684.           rc = FALSE;
  685.         }
  686.       break;
  687.  
  688.       case 5:
  689.         pFieldInfo->flTitle = CFA_STRING;
  690.         pFieldInfo->pTitleData = malloc(TEXT_SIZE);
  691.         if (pFieldInfo->pTitleData)
  692.         {
  693.           strcpy(pFieldInfo->pTitleData, "Time of Birth");
  694.           pFieldInfo->flData = CFA_TIME | CFA_RIGHT | CFA_HORZSEPARATOR;
  695.           pFieldInfo->offStruct = FIELDOFFSET(PERSONRECORD,
  696.                                               TimeOfBirth);
  697.         }
  698.         else
  699.         {
  700.           rc = FALSE;
  701.         }
  702.       break;
  703.  
  704.       case 6:
  705.         pFieldInfo->flTitle = CFA_STRING | CFA_CENTER;
  706.         pFieldInfo->pTitleData = malloc(TEXT_SIZE);
  707.         if (pFieldInfo->pTitleData)
  708.         {
  709.           strcpy(pFieldInfo->pTitleData, "Current\r\nAge");
  710.           pFieldInfo->flData = CFA_ULONG | CFA_RIGHT |
  711.                                CFA_HORZSEPARATOR;
  712.           pFieldInfo->offStruct = FIELDOFFSET(PERSONRECORD,
  713.                                               CurrentAge);
  714.         }
  715.         else
  716.         {
  717.           rc = FALSE;
  718.         }
  719.       break;
  720.     }
  721.     pFieldInfo = pFieldInfo->pNextFieldInfo;
  722.     i++;
  723.   }
  724.  
  725.   if (rc)
  726.   {
  727.     FieldInfoInsert.cb = sizeof(FIELDINFOINSERT);
  728.     FieldInfoInsert.pFieldInfoOrder = (PFIELDINFO)CMA_FIRST;
  729.     FieldInfoInsert.cFieldInfoInsert = usNumFieldInfo;
  730.     FieldInfoInsert.fInvalidateFieldInfo = FALSE;
  731.     WinSendMsg (pSampleInfo->hwndCnr, CM_INSERTDETAILFIELDINFO,
  732.                 MPFROMP(pFieldInfoFirst), MPFROMP(&FieldInfoInsert));
  733.   }
  734.  
  735.   return (rc);
  736. }
  737.  
  738. /*----------------------------------------------------------------------
  739.  Function Name: PopulateTree
  740.  
  741.  Description:
  742.    This functions adds 3 child records to each of the records that are
  743.    currently in the container.
  744.  
  745.  Parameters:
  746.    (HWND) hwnd - The handle of the client window.
  747.  
  748.  Return Values:
  749.    (BOOL)  TRUE  - Tree view children inserted successfully.
  750.            FALSE - Tree view children not inserted due to an error.
  751. ----------------------------------------------------------------------*/
  752. BOOL PopulateTree (HWND hwnd)
  753. {
  754.   PSAMPLEINFO    pSampleInfo;
  755.   PPERSONRECORD  pPersonRec;
  756.   BOOL           rc = TRUE;
  757.  
  758.   /* Get the pointer to our control block. */
  759.   pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  760.  
  761.   /* Get the first root item in the tree.  Add its children, then
  762.    * continue adding the children of the next root level item.
  763.    */
  764.   pPersonRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  765.                                           CM_QUERYRECORD,
  766.                                           NULL,
  767.                               MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  768.  
  769.   while ((pPersonRec) && (rc))
  770.   {
  771.     if (AddChildren (hwnd, pPersonRec))
  772.     {
  773.       pPersonRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  774.                                               CM_QUERYRECORD,
  775.                                               MPFROMP(pPersonRec),
  776.                                  MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
  777.     }
  778.     else
  779.     {
  780.       rc = FALSE;
  781.     }
  782.   }
  783.  
  784.   return (rc);
  785. }
  786.  
  787. /*----------------------------------------------------------------------
  788.  Function Name: AddChildren
  789.  
  790.  Description:
  791.    This function allocates the record memory for each child record and
  792.    inserts them as children of the parent record passed in as the
  793.    second parameter.
  794.  
  795.  Parameters:
  796.    (HWND) hwnd                - The handle of the client window.
  797.    (PPERSONRECORD) pParentRec - The parent record for the children
  798.                                 records we are creating.
  799.  
  800.  Return Values:
  801.    (BOOL)  TRUE  - Children records inserted successfully.
  802.            FALSE - Children records not inserted due to an error.
  803. ----------------------------------------------------------------------*/
  804. BOOL AddChildren (HWND hwnd, PPERSONRECORD pParentRec)
  805. {
  806.   PSAMPLEINFO    pSampleInfo;
  807.   PPERSONRECORD  pChildRec;
  808.   PPERSONRECORD  pChildRecFirst;
  809.   RECORDINSERT   RecordInsert;
  810.   BOOL           rc = TRUE;
  811.   ULONG          ulNumChildren = 3;
  812.  
  813.   /* Get the pointer to our control block. */
  814.   pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  815.  
  816.   /* Allocate the 3 records which will be used as children. */
  817.   pChildRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  818.                                        CM_ALLOCRECORD,
  819.                                        MPFROMLONG(sizeof(PERSONRECORD) -
  820.                                        sizeof(MINIRECORDCORE)),
  821.                                        MPFROMLONG(ulNumChildren));
  822.  
  823.   pChildRecFirst = pChildRec;
  824.  
  825.   /* Go through each record and assign the data as necessary. */
  826.   pChildRec->MiniRec.hptrIcon = pSampleInfo->hptrJobIcon;
  827.   pChildRec->MiniRec.pszIcon = malloc(TEXT_SIZE);
  828.   if (pChildRec->MiniRec.pszIcon)
  829.   {
  830.     if (pParentRec->usJob == JR_DEVELOPMENT)
  831.     {
  832.       strcpy (pChildRec->MiniRec.pszIcon, "Design");
  833.     }
  834.     else
  835.     {
  836.       strcpy (pChildRec->MiniRec.pszIcon, "Planning");
  837.     }
  838.   }
  839.   else
  840.   {
  841.     rc = FALSE;
  842.   }
  843.  
  844.   if (rc)
  845.   {
  846.     pChildRec = (PPERSONRECORD)pChildRec->MiniRec.preccNextRecord;
  847.     pChildRec->MiniRec.hptrIcon = pSampleInfo->hptrJobIcon;
  848.     pChildRec->MiniRec.pszIcon = malloc(TEXT_SIZE);
  849.     if (pChildRec->MiniRec.pszIcon)
  850.     {
  851.       if (pParentRec->usJob == JR_DEVELOPMENT)
  852.       {
  853.         strcpy (pChildRec->MiniRec.pszIcon, "Coding");
  854.       }
  855.       else
  856.       {
  857.         strcpy (pChildRec->MiniRec.pszIcon, "Function\r\nTest");
  858.       }
  859.     }
  860.     else
  861.     {
  862.       rc = FALSE;
  863.     }
  864.   }
  865.  
  866.   if (rc)
  867.   {
  868.     pChildRec = (PPERSONRECORD)pChildRec->MiniRec.preccNextRecord;
  869.     pChildRec->MiniRec.hptrIcon = pSampleInfo->hptrJobIcon;
  870.     pChildRec->MiniRec.pszIcon = malloc(TEXT_SIZE);
  871.     if (pChildRec->MiniRec.pszIcon)
  872.     {
  873.       /* \r\n or \n will work to create a multi line entry. */
  874.       if (pParentRec->usJob == JR_DEVELOPMENT)
  875.       {
  876.         strcpy (pChildRec->MiniRec.pszIcon, "Unit\nTest");
  877.       }
  878.       else
  879.       {
  880.         strcpy (pChildRec->MiniRec.pszIcon, "Documentation");
  881.       }
  882.     }
  883.     else
  884.     {
  885.       rc = FALSE;
  886.     }
  887.   }
  888.  
  889.   /* If no errors, set up the RECORDINSERT structure and insert the
  890.    * child records.  Notice that we set the pRecordParent field of
  891.    * the RECORDINSERT structure to the parent record passed in.
  892.    */
  893.   if (rc)
  894.   {
  895.      RecordInsert.cb = sizeof(RECORDINSERT);
  896.      RecordInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST;
  897.      RecordInsert.pRecordParent = (PRECORDCORE)pParentRec;
  898.      RecordInsert.zOrder = CMA_TOP;
  899.      RecordInsert.cRecordsInsert = ulNumChildren;
  900.      RecordInsert.fInvalidateRecord = TRUE;
  901.  
  902.      WinSendMsg (pSampleInfo->hwndCnr,
  903.                  CM_INSERTRECORD,
  904.                  MPFROMP(pChildRecFirst),
  905.                  MPFROMP(&RecordInsert));
  906.   }
  907.   return (rc);
  908. }
  909.  
  910. /*----------------------------------------------------------------------
  911.  Function Name: CleanupCnr
  912.  
  913.  Description:
  914.    This function is called when this application is closed and will
  915.    free all the memory and resources used by this application.
  916.  
  917.  Parameters:
  918.    (HWND) hwnd - The handle of the client window.
  919.  
  920.  Notes:
  921.    It is not necessary to remove and free all of the container records
  922.    when the application is closed.  The container as part of its
  923.    WM_DESTROY processing will do this for you.
  924.  
  925.  Return Values:
  926.    VOID
  927. ----------------------------------------------------------------------*/
  928. VOID CleanupCnr (HWND hwnd)
  929. {
  930.   PSAMPLEINFO    pSampleInfo;
  931.   PPERSONRECORD  pPersonRec;
  932.   PFIELDINFO     pFieldInfo;
  933.  
  934.   /* Get the pointer to our control block. */
  935.   pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  936.  
  937.   /* Make sure it is still valid */
  938.   if (pSampleInfo)
  939.   {
  940.     /* Zip through all the records and free the memory we previously
  941.      * allocated for the text string.
  942.      */
  943.     pPersonRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  944.                                             CM_QUERYRECORD,
  945.                                             NULL,
  946.                                MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  947.     while (pPersonRec)
  948.     {
  949.       if (pPersonRec->MiniRec.pszIcon)
  950.       {
  951.         free (pPersonRec->MiniRec.pszIcon);
  952.       }
  953.  
  954.       /* For each record, we need to also clean up the memory
  955.        * used for its child records.
  956.        */
  957.       CleanupChildren (hwnd, pPersonRec);
  958.  
  959.       /* Get the next record and continue. */
  960.       pPersonRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  961.                                               CM_QUERYRECORD,
  962.                                               MPFROMP(pPersonRec),
  963.                                  MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
  964.     }
  965.  
  966.     /* Zip through all the fieldinfo's and free the memory we previously
  967.      * allocated for the title text strings.
  968.      */
  969.     pFieldInfo = WinSendMsg (pSampleInfo->hwndCnr,
  970.                              CM_QUERYDETAILFIELDINFO,
  971.                              NULL,
  972.                              MPFROMSHORT(CMA_FIRST));
  973.     while (pFieldInfo)
  974.     {
  975.       /* If the title data for this column is a string, free the
  976.        * string memory.
  977.        */
  978.       if (!(pFieldInfo->flTitle & CFA_BITMAPORICON))
  979.       {
  980.         if (pFieldInfo->pTitleData)
  981.         {
  982.           free (pFieldInfo->pTitleData);
  983.         }
  984.       }
  985.  
  986.       /* Go to the next fieldinfo in the container. */
  987.       pFieldInfo = WinSendMsg (pSampleInfo->hwndCnr,
  988.                                CM_QUERYDETAILFIELDINFO,
  989.                                MPFROMP(pFieldInfo),
  990.                                MPFROMSHORT(CMA_NEXT));
  991.     }
  992.  
  993.     /* Free the icons we used. */
  994.     WinDestroyPointer (pSampleInfo->hptrPersonIcon);
  995.     WinDestroyPointer (pSampleInfo->hptrJobIcon);
  996.  
  997.     /* Free the container title text string memory we stored in our
  998.      * control block.
  999.      */
  1000.     if (pSampleInfo->pszCnrTitle)
  1001.     {
  1002.       free (pSampleInfo->pszCnrTitle);
  1003.     }
  1004.  
  1005.     /* Finally, free the SAMPLEINFO control block. */
  1006.     free (pSampleInfo);
  1007.   }
  1008.   return;
  1009. }
  1010.  
  1011. /*----------------------------------------------------------------------
  1012.  Function Name: CleanupChildren
  1013.  
  1014.  Description:
  1015.    This function will free the resources of the child records used in
  1016.    the Tree view.
  1017.  
  1018.  Parameters:
  1019.    (HWND) hwnd                - The handle of the client window.
  1020.    (PPERSONRECORD) pParentRec - Pointer to the parent record whose
  1021.                                 child records we will be processing.
  1022.  
  1023.  Return Values:
  1024.    VOID
  1025. ----------------------------------------------------------------------*/
  1026. VOID CleanupChildren (HWND hwnd, PPERSONRECORD pParentRec)
  1027. {
  1028.   PSAMPLEINFO    pSampleInfo;
  1029.   PPERSONRECORD  pChildRec;
  1030.  
  1031.   /* Get the pointer to our control block. */
  1032.   pSampleInfo = (PSAMPLEINFO)WinQueryWindowPtr (hwnd, QWL_USER);
  1033.  
  1034.   /* Get the first child record for the parent record passed in. */
  1035.   pChildRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  1036.                                          CM_QUERYRECORD,
  1037.                                          MPFROMP(pParentRec),
  1038.                            MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER));
  1039.  
  1040.   /* Go through each child record, freeing the memory for the text
  1041.    * string in each.
  1042.    */
  1043.   while (pChildRec)
  1044.   {
  1045.     if (pChildRec->MiniRec.pszIcon)
  1046.     {
  1047.       free (pChildRec->MiniRec.pszIcon);
  1048.     }
  1049.  
  1050.     pChildRec = (PPERSONRECORD)WinSendMsg (pSampleInfo->hwndCnr,
  1051.                                            CM_QUERYRECORD,
  1052.                                            MPFROMP(pChildRec),
  1053.                               MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
  1054.   }
  1055.   return;
  1056. }
  1057.