home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: SysTools / SysTools.zip / taman002.zip / TASKMANA.ZIP / src / kContainer.cpp < prev    next >
C/C++ Source or Header  |  2000-04-29  |  36KB  |  1,234 lines

  1. /* $Id: kContainer.cpp,v 1.1 2000/04/29 19:06:34 stknut Exp $
  2.  *
  3.  * kContainer (kClassLib) - Implementation of kContainer.
  4.  *
  5.  * Copyright (c) 1999-2000 knut st. osmundsen
  6.  *
  7.  */
  8.  
  9.  
  10. /*******************************************************************************
  11. *   Defined Constants And Macros                                               *
  12. *******************************************************************************/
  13. #define INCL_WINERRORS
  14. #define INCL_WINSTDCNR
  15. #define INCL_WINSYS
  16. #define INCL_WINMESSAGEMGR
  17. #define INCL_WINWINDOWMGR
  18. #define INCL_WININPUT
  19. #define INCL_WINSCROLLBARS
  20. #define INCL_WINSTATICS
  21.  
  22. /*******************************************************************************
  23. *   Header Files                                                               *
  24. *******************************************************************************/
  25. #include <os2.h>
  26. #ifdef USE_KLIB
  27.     #include <kAssert.h>
  28.     #include <kLog.h>
  29.     #include <kHeap.h>
  30. #endif
  31. #include <stdarg.h>
  32.  
  33. #include "kError.h"
  34. #include "kContainer.h"
  35.  
  36.  
  37.  
  38. /*******************************************************************************
  39. *   Internal Functions                                                         *
  40. *******************************************************************************/
  41. static MRESULT _System forwarder(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  42.  
  43.  
  44.  
  45.  
  46. /**
  47.  * Gets the next pointer from the mini record core.
  48.  * @returns   Pointer to next record. NULL if last.
  49.  */
  50. kCnrMiniRecord *kCnrMiniRecord::getNext()
  51. {
  52.     return(kCnrMiniRecord*)RecordCore.preccNextRecord;
  53. }
  54.  
  55.  
  56.  
  57. /**
  58.  * Gets the next pointer from the record core.
  59.  * @returns   Pointer to next record. NULL if last.
  60.  */
  61. kCnrRecord *kCnrRecord::getNext()
  62. {
  63.     return (kCnrRecord*)RecordCore.preccNextRecord;
  64. }
  65.  
  66.  
  67.  
  68. /**
  69.  * sets the next pointer int the mini record core.
  70.  * @returns   pRecord.
  71.  * @param     pRecord   New next pointer.
  72.  */
  73. kCnrMiniRecord *kCnrMiniRecord::setNext(kCnrMiniRecord *pRecord)
  74. {
  75.     RecordCore.preccNextRecord = (PMINIRECORDCORE)pRecord;
  76.     return pRecord;
  77. }
  78.  
  79.  
  80.  
  81. /**
  82.  * Sets the next pointer in the record core.
  83.  * @returns   pRecord.
  84.  * @param     pRecord   New next pointer.
  85.  */
  86. kCnrRecord *kCnrRecord::setNext(kCnrRecord *pRecord)
  87. {
  88.     RecordCore.preccNextRecord = (PRECORDCORE)pRecord;
  89.     return pRecord;
  90. }
  91.  
  92.  
  93.  
  94. /**
  95.  * If fValidCnrInfo is clear, the container info is requested.
  96.  * @returns   TRUE / FALSE according to result.
  97.  * @remark    This function must be called before using data from the CnrInfo struct.
  98.  */
  99. inline BOOL kCnrBase::validateCnrInfo()
  100. {
  101.     if (!fValidCnrInfo)
  102.     {
  103.         if ((int)WinSendMsg(hwndCnr, CM_QUERYCNRINFO, &CnrInfo, (MPARAM)sizeof(CnrInfo)) == 0)
  104.             return FALSE;
  105.         fValidCnrInfo = TRUE;
  106.     }
  107.     return TRUE;
  108. }
  109.  
  110.  
  111.  
  112. /**
  113.  * Sets container control data.
  114.  * @returns   TRUE / FALSE according to the result.
  115.  * @param     flChanged  Flags which specifies which part of the CnrInfo struct which is to be set.
  116.  * @remark    This is an internal function, which of course means you have the
  117.  *            set the value in the CnrInfo struct before calling this function.
  118.  */
  119. BOOL kCnrBase::setCnrInfo(ULONG flChanged)
  120. {
  121.     return(BOOL)WinSendMsg(hwndCnr, CM_SETCNRINFO, &CnrInfo, (MPARAM)flChanged);
  122. }
  123.  
  124.  
  125.  
  126. /**
  127.  * Determins if this container uses minirecordcore.
  128.  * @returns   TRUE - uses minirecordcore, FALSE - uses recordcore.
  129.  */
  130. BOOL kCnrBase::usesMiniRecord()
  131. {
  132.     return WinQueryWindowULong(hwndCnr, QWL_STYLE) & CCS_MINIRECORDCORE;
  133. }
  134.  
  135.  
  136.  
  137. /**
  138.  * Default command.
  139.  * @param     usCmd     Control id which send/posted the message.
  140.  * @param     usSource  Source id.
  141.  * @param     fPointer  Mouse pointer flag.
  142.  */
  143. VOID kCnrBase::command(USHORT usCmd, USHORT usSource, BOOL fPointer)
  144. {
  145.     /* unreferenced */
  146.     usCmd = usCmd;
  147.     usSource = usSource;
  148.     fPointer = fPointer;
  149. }
  150.  
  151.  
  152.  
  153. /**
  154.  * Initmenu message. Enables and disables menuitems.
  155.  * @param     usMenuId  Control id of menu.
  156.  * @param     hwndMnu   WindowHandle of menu.
  157.  */
  158. VOID kCnrBase::initMenu(USHORT usMenuId, HWND hwndMnu)
  159. {
  160.     /* no action */
  161.  
  162.     /* unreferenced */
  163.     usMenuId = usMenuId;
  164.     hwndMnu = hwndMnu;
  165. }
  166.  
  167.  
  168.  
  169. /**
  170.  * Menuend message.
  171.  * @param     usMenuId  Control id of menu.
  172.  * @param     hwndMnu   WindowHandle of menu.
  173.  */
  174. VOID kCnrBase::menuEnd(USHORT usMenuId, HWND hwndMnu)
  175. {
  176.     /* no action */
  177.  
  178.     /* unreferenced */
  179.     usMenuId = usMenuId;
  180.     hwndMnu = hwndMnu;
  181. }
  182.  
  183.  
  184.  
  185. /**
  186.  * Wraps in an PM Container control.
  187.  * @param     hwndCnr  Window handle to container control.
  188.  */
  189. kCnrBase::kCnrBase(HWND hwndCnr, BOOL fBorder/* = TRUE*/) throw (kError)
  190. : hwndCnr(hwndCnr), hwndBorder(NULLHANDLE),
  191. pfnwpOrg(NULL),
  192. fValidCnrInfo(FALSE)
  193. {
  194.     /* subclass container */
  195.     pfnwpOrg = WinSubclassWindow(hwndCnr, forwarder);
  196.     WinSetWindowULong(hwndCnr, QWL_USER, (ULONG)this);
  197.  
  198.  
  199.     /* get Container info */
  200.     validateCnrInfo();
  201.     fUsesMiniRecord = usesMiniRecord();
  202.  
  203.     /* make border */
  204.     if (fBorder)
  205.     {
  206.         SWP swp;
  207.         WinQueryWindowPos(hwndCnr, &swp);
  208.         hwndBorder = WinCreateWindow(
  209.             WinQueryWindow(hwndCnr, QW_PARENT),
  210.             WC_STATIC,
  211.             NULL,
  212.             SS_FGNDFRAME | WS_VISIBLE,
  213.             swp.x-1,
  214.             swp.y-1,
  215.             swp.cx+2,
  216.             swp.cy+2,
  217.             WinQueryWindow(hwndCnr, QW_OWNER),
  218.             hwndCnr,
  219.             0xFFFFFFFFUL,
  220.             NULL,
  221.             NULL);
  222.     }
  223. }
  224.  
  225.  
  226. /**
  227.  * Frees all record from the container.
  228.  * @remark    The container records must be either a kCnrMiniRecord or kCnrRecord,
  229.  *            according to container style.
  230.  */
  231. kCnrBase::~kCnrBase()
  232. {
  233.     removeAllRecords();
  234.     removeAllDetailFieldInfos();
  235.     WinSubclassWindow(hwndCnr, pfnwpOrg);
  236.     hwndCnr = NULLHANDLE;
  237.     fValidCnrInfo = FALSE;
  238. }
  239.  
  240.  
  241.  
  242. /**
  243.  * Forwards messages to msgLoop if a QWS_USER is registered.
  244.  * When WM_INITDLG, it stores the this pointer (mp2) in QWS_USER.
  245.  * @returns   depended on msg. See PMREF for more.
  246.  * @param     hwnd  Handle of the(this) window receiving the message.
  247.  * @param     msg   Message id. See PMREF for more.
  248.  * @param     mp1   Message paramenter one. See PMREF for more.
  249.  * @param     mp2   Message paramenter two. See PMREF for more.
  250.  * @remark    Forwarder.
  251.  */
  252. static MRESULT _System forwarder(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  253. {
  254.     kCnrBase *pthis;
  255.     PVOID     pv;
  256.  
  257.     pv = (PVOID)WinQueryWindowULong(hwnd, QWL_USER);
  258.     if (pv != NULL)
  259.     {
  260.         pthis = (kCnrBase*)pv;
  261.         return pthis->msgLoop(hwnd, msg, mp1, mp2);
  262.     }
  263.     else
  264.         return WinDefDlgProc(hwnd, msg, mp1, mp2);
  265. }
  266.  
  267.  
  268.  
  269. /**
  270.  * Container (subclass) message loop.
  271.  * @returns   depended on msg. See PMREF for more.
  272.  * @param     hwnd  Handle of the(this) window receiving the message.
  273.  * @param     msg   Message id. See PMREF for more.
  274.  * @param     mp1   Message paramenter one. See PMREF for more.
  275.  * @param     mp2   Message paramenter two. See PMREF for more.
  276.  * @remark    Looks for WM_CHAR msgs with the context menu
  277.  */
  278. MRESULT kCnrBase::msgLoop(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  279. {
  280.     BOOL     fPassOn = TRUE;
  281.     MRESULT  mr      = NULL;
  282.  
  283.     switch (msg)
  284.     {
  285.         case WM_CHAR:
  286.             if (mp2 == (MPARAM)WinQuerySysValue(HWND_DESKTOP, SV_CONTEXTMENU))
  287.             {
  288.                 WinPostMsg(hwnd, WM_CONTEXTMENU, NULL, NULL);
  289.                 fPassOn = FALSE;
  290.                 mr = (MRESULT)TRUE;
  291.             }
  292.             break;
  293.  
  294.         case WM_COMMAND:
  295.             command(SHORT1FROMMP(mp1), SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
  296.             break;
  297.  
  298.         case WM_INITMENU:
  299.             initMenu(SHORT1FROMMP(mp1), (HWND)mp2);
  300.             break;
  301.  
  302.         case WM_MENUEND:
  303.             menuEnd(SHORT1FROMMP(mp1), (HWND)mp2);
  304.             break;
  305.     }
  306.  
  307.     if (fPassOn)
  308.         mr = (*pfnwpOrg)(hwnd, msg, mp1, mp2);
  309.     return mr;
  310. }
  311.  
  312.  
  313.  
  314. /**
  315.  * Allocates a (none-minirecordcore) record.
  316.  * @returns   Pointer to allocated record, or NULL pointer on error.
  317.  * @param     cbRecord  Total bytes to allocate.
  318.  * @param     cRecords  Number of records to allocate. Defaults to 1.
  319.  */
  320. kCnrMiniRecord *kCnrBase::allocMiniRec(ULONG cbRecord, ULONG cRecords /*= 1*/)
  321. {
  322.     if (!fUsesMiniRecord || cbRecord < sizeof(MINIRECORDCORE) || cRecords == 0)
  323.         return NULL;
  324.     fValidCnrInfo = FALSE;
  325.     return(kCnrMiniRecord*)WinSendMsg(hwndCnr, CM_ALLOCRECORD,
  326.                                       (MPARAM)(cbRecord - sizeof(MINIRECORDCORE)),
  327.                                       (MPARAM)cRecords);
  328. }
  329.  
  330.  
  331.  
  332. /**
  333.  * Allocates a (none-minirecordcore) record.
  334.  * @returns   Pointer to allocated record, or NULL pointer on error.
  335.  * @param     cbRecord  Total bytes to allocate.
  336.  * @param     cRecords  Number of records to allocate. Defaults to 1.
  337.  */
  338. kCnrRecord *kCnrBase::allocRec(ULONG cbRecord, ULONG cRecords /*= 1*/)
  339. {
  340.     if (fUsesMiniRecord || cbRecord < sizeof(RECORDCORE) || cRecords == 0)
  341.         return NULL;
  342.     fValidCnrInfo = FALSE;
  343.     return(kCnrRecord*)WinSendMsg(hwndCnr, CM_ALLOCRECORD,
  344.                                   (MPARAM)(cbRecord - sizeof(RECORDCORE)),
  345.                                   (MPARAM)cRecords);
  346. }
  347.  
  348.  
  349.  
  350. /**
  351.  * Allocates an array of field info structs.
  352.  * @returns   Pointer to allocated fieldinfos, or NULL pointer on error.
  353.  * @param     cFieldInfo  Count of structs to allocate.
  354.  */
  355. PFIELDINFO kCnrBase::allocDetailFieldInfo(USHORT cFieldInfo)
  356. {
  357.     fValidCnrInfo = FALSE;
  358.     return(PFIELDINFO)WinSendMsg(hwndCnr, CM_ALLOCDETAILFIELDINFO, (MPARAM)cFieldInfo, NULL);
  359. }
  360.  
  361.  
  362.  
  363. /**
  364.  * Frees an array of field info structs.
  365.  * @returns   Pointer to allocated fieldinfos, or NULL pointer on error.
  366.  * @param     pFieldInfo  Pointer to fieldinfo structs to remove.
  367.  * @param     cFieldInfo  Count of structs to allocate.
  368.  */
  369. BOOL kCnrBase::freeDetailFieldInfo(PFIELDINFO pFieldInfo, USHORT cFieldInfo)
  370. {
  371.     fValidCnrInfo = FALSE;
  372.     return(BOOL)WinSendMsg(hwndCnr, CM_FREEDETAILFIELDINFO, pFieldInfo, (MPARAM)cFieldInfo);
  373. }
  374.  
  375.  
  376.  
  377. /**
  378.  * Inserts record at top.
  379.  * @returns   TRUE / FALSE according to the result.
  380.  * @param     pRecord   Pointer to record which is to be inserted.
  381.  * @param     cRecords  Number of records to insert. Defaults to 1.
  382.  * @remark    The container records must be either a kCnrMiniRecord or kCnrRecord,
  383.  *            according to container style. They must also be allocated using either
  384.  *            allocRec or allocMiniRec.
  385.  */
  386. BOOL kCnrBase::insertAtTop(kCnrMiniRecord *pRecord, ULONG cRecords /*=1*/)
  387. {
  388.     RECORDINSERT recordInsert =
  389.     {
  390.         sizeof(recordInsert),   /*  Structure size. */
  391.         (PRECORDCORE)CMA_FIRST, /*  Record order. */
  392.         NULL,                   /*  Pointer to record parent. */
  393.         TRUE,                   /*  Update flag. */
  394.         CMA_TOP,                /*  Record z-order. */
  395.         cRecords                /*  Number of root-level structures. */
  396.     };
  397.     fValidCnrInfo = FALSE;
  398.     return(BOOL)WinSendMsg(hwndCnr, CM_INSERTRECORD, pRecord, &recordInsert);
  399. }
  400.  
  401.  
  402.  
  403. /**
  404.  * Inserts record at bottom.
  405.  * @returns   TRUE / FALSE according to the result.
  406.  * @param     pRecord  Pointer to record which is to be inserted.
  407.  * @param     cRecords  Number of records to insert. Defaults to 1.
  408.  * @remark    The container records must be either a kCnrMiniRecord or kCnrRecord,
  409.  *            according to container style. They must also be allocated using either
  410.  *            allocRec or allocMiniRec.
  411.  */
  412. BOOL kCnrBase::insertAtBottom(kCnrMiniRecord *pRecord, ULONG cRecords /*=1*/)
  413. {
  414.     RECORDINSERT recordInsert =
  415.     {
  416.         sizeof(recordInsert),   /*  Structure size. */
  417.         (PRECORDCORE)CMA_END,   /*  Record order. */
  418.         NULL,                   /*  Pointer to record parent. */
  419.         TRUE,                   /*  Update flag. */
  420.         CMA_BOTTOM,             /*  Record z-order. */
  421.         cRecords                /*  Number of root-level structures. */
  422.     };
  423.     fValidCnrInfo = FALSE;
  424.     return(BOOL)WinSendMsg(hwndCnr, CM_INSERTRECORD, pRecord, &recordInsert);
  425. }
  426.  
  427.  
  428.  
  429.  
  430. /**
  431.  * Inserts fieldinfo structs into the container.
  432.  * @returns   TRUE / FALSE according to the result.
  433.  * @param     pFieldInfo            Pointer to array of fieldinfo structs to insert.
  434.  * @param     pFieldInfoOrder       CMA_FIRST/CMA_END or pointer to fieldinfo struct.
  435.  * @param     fInvalidateFieldInfo  TRUE: invalidate; FALSE: not invalidate.
  436.  * @param     cFieldInfoInsert      Count of fieldinfo items in the array (pFieldInfo).
  437.  * @remark    The array must be allocated with allocDetailFieldInfo(...).
  438.  */
  439. BOOL kCnrBase::insertDetailFieldInfo(PFIELDINFO pFieldInfo, PFIELDINFO pFieldInfoOrder,
  440.                                      BOOL fInvalidateFieldInfo, ULONG cFieldInfoInsert)
  441. {
  442.     FIELDINFOINSERT FieldInfoInsert =
  443.     {
  444.         sizeof(FIELDINFOINSERT), /* Size of structure.             */
  445.         pFieldInfoOrder,         /* Specifies the order of the     */
  446.         /* FieldInfo structures.          */
  447.         fInvalidateFieldInfo,    /* Invalidate on Insert.          */
  448.         cFieldInfoInsert         /* The number of FieldInfo        */
  449.         /* structures to insert.          */
  450.     };
  451.  
  452.     fValidCnrInfo = FALSE;
  453.     return(int)WinSendMsg(hwndCnr, CM_INSERTDETAILFIELDINFO, pFieldInfo, &FieldInfoInsert) != 0;
  454. }
  455.  
  456.  
  457.  
  458. /**
  459.  * Frees a single record from the container.
  460.  * @param     ppvRecord  Pointer to the record.
  461.  * @remark    1) The record must be allocated using either allocRec or allocMiniRec.
  462.  *            2) Userdata must be freed before calling this function.
  463.  */
  464. BOOL kCnrBase::removeRecord(void *pvRecord)
  465. {
  466.     if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pvRecord,
  467.                         MPFROM2SHORT(1, CMA_FREE)) == -1)
  468.         return FALSE;
  469.  
  470.     fValidCnrInfo = FALSE;
  471.     return TRUE;
  472. }
  473.  
  474.  
  475. /**
  476.  * Frees cRecord number of records from the array of recordpointers passed in.
  477.  * @param     ppvRecord  Pointer to an array of record pointers.
  478.  * @param     cRecord    Count of records to free (accepts negative numbers too).
  479.  * @remark    1) They must be allocated using either allocRec or allocMiniRec.
  480.  *            2) Userdata must be freed before calling this function.
  481.  */
  482. BOOL kCnrBase::removeRecords(void **ppvRecord, ULONG cRecord/*= 1*/)
  483. {
  484.     if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, ppvRecord,
  485.                         MPFROM2SHORT(cRecord, CMA_FREE)) == -1)
  486.         return FALSE;
  487.  
  488.     fValidCnrInfo = FALSE;
  489.     return TRUE;
  490. }
  491.  
  492.  
  493.  
  494. /**
  495.  * Frees cRecord number of records from the top of the container.
  496.  * @param     cRecord  Count of records to free (accepts negative numbers too).
  497.  * @remark    1) They must be allocated using either allocRec or allocMiniRec.
  498.  *            2) Userdata must be freed before calling this function.
  499.  */
  500. BOOL kCnrBase::removeRecordAtTop(LONG cRecord)
  501. {
  502.     validateCnrInfo();
  503.     if (fUsesMiniRecord)
  504.     {
  505.         kCnrMiniRecord *pRecord;
  506.  
  507.         while (cRecord-- > 0 && (pRecord = queryTopRecord()) != NULL)
  508.             if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pRecord, MPFROM2SHORT(1, CMA_FREE)) == -1)
  509.                 return FALSE;
  510.     }
  511.     else
  512.     {
  513.         kCnrRecord *pRecord;
  514.  
  515.         while (cRecord-- > 0 && (pRecord = (kCnrRecord*)queryTopRecord()) != NULL)
  516.             if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pRecord, MPFROM2SHORT(1, CMA_FREE)) == -1)
  517.                 return FALSE;
  518.     }
  519.     fValidCnrInfo = FALSE;
  520.     return TRUE;
  521. }
  522.  
  523.  
  524.  
  525. /**
  526.  * Frees cRecord number of records from the bottom of the container.
  527.  * @param     cRecord  Count of records to free (accepts negative numbers too).
  528.  * @remark    1) They must be allocated using either allocRec or allocMiniRec.
  529.  *            2) Userdata must be freed before calling this function.
  530.  */
  531. BOOL kCnrBase::removeRecordAtBottom(LONG cRecord)
  532. {
  533.     validateCnrInfo();
  534.     if (fUsesMiniRecord)
  535.     {
  536.         kCnrMiniRecord *pRecord;
  537.  
  538.         while (cRecord-- > 0 && (pRecord = queryBottomRecord()) != NULL)
  539.             if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pRecord, MPFROM2SHORT(1, CMA_FREE)) == -1)
  540.                 return FALSE;
  541.     }
  542.     else
  543.     {
  544.         kCnrRecord *pRecord;
  545.  
  546.         while (cRecord-- > 0 && (pRecord = (kCnrRecord*)queryBottomRecord()) != NULL)
  547.             if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pRecord, MPFROM2SHORT(1, CMA_FREE)) == -1)
  548.                 return FALSE;
  549.     }
  550.     fValidCnrInfo = FALSE;
  551.     return TRUE;
  552. }
  553.  
  554.  
  555.  
  556. /**
  557.  * Frees all records from the container.
  558.  * @remark    1) They must be allocated using either allocRec or allocMiniRec.
  559.  *            2) Userdata must be freed before calling this function.
  560.  *            TODO: not error proof.
  561.  */
  562. BOOL kCnrBase::removeAllRecords()
  563. {
  564.     validateCnrInfo();
  565.     if (fUsesMiniRecord)
  566.     {
  567.         kCnrMiniRecord *pRecord;
  568.  
  569.         while ((pRecord = queryTopRecord()) != NULL)
  570.             if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pRecord, MPFROM2SHORT(1, CMA_FREE)) == -1)
  571.                 return FALSE;
  572.     }
  573.     else
  574.     {
  575.         kCnrRecord *pRecord;
  576.  
  577.         while ((pRecord = (kCnrRecord*)queryTopRecord()) != NULL)
  578.             if ((int)WinSendMsg(hwndCnr, CM_REMOVERECORD, &pRecord, MPFROM2SHORT(1, CMA_FREE)) == -1)
  579.                 return FALSE;
  580.     }
  581.     fValidCnrInfo = FALSE;
  582.     return TRUE;
  583. }
  584.  
  585.  
  586.  
  587. /**
  588.  * Removes an array of fieldinfo structs.
  589.  * @returns   TRUE
  590.  * @param     paFieldInfo Pointer to an array of fieldinfo structs to remove.
  591.  * @param     cFieldInfo  Count of structs to remove.
  592.  * @param     usFlags     Remove flags.
  593.  */
  594. BOOL kCnrBase::removeDetailFieldInfo(PFIELDINFO paFieldInfo[], USHORT cFieldInfo, USHORT usFlags)
  595. {
  596.     fValidCnrInfo = FALSE;
  597.     return(int)WinSendMsg(hwndCnr, CM_REMOVEDETAILFIELDINFO, paFieldInfo, MPFROM2SHORT(cFieldInfo, usFlags)) != -1;
  598. }
  599.  
  600.  
  601.  
  602. /**
  603.  * Frees all fieldinfos from the container.
  604.  * @returns   TRUE / FALSE according to the result.
  605.  */
  606. BOOL kCnrBase::removeAllDetailFieldInfos()
  607. {
  608.     PFIELDINFO pFieldInfo;
  609.     BOOL       fRet = TRUE;
  610.  
  611.     while ((pFieldInfo = (PFIELDINFO)WinSendMsg(hwndCnr,
  612.                                                 CM_QUERYDETAILFIELDINFO,
  613.                                                 (MPARAM)CMA_FIRST,
  614.                                                 (MPARAM)CMA_FIRST))       != NULL
  615.            && (int)pFieldInfo != -1)
  616.     {
  617.         if (!removeDetailFieldInfo(&pFieldInfo, 1, CMA_FREE))
  618.         {
  619.             fRet = FALSE;
  620.             break;
  621.         }
  622.     }
  623.  
  624.     fValidCnrInfo = FALSE;
  625.  
  626.     return fRet;
  627. }
  628.  
  629.  
  630.  
  631. /**
  632.  * Invalidates a record.
  633.  * @returns   TRUE / FALSE according to the result.
  634.  * @param     pRecord  Pointer to the record which is to be invalidated.
  635.  * @param     fFlags   Invalidation flags. defaults to CMA_
  636.  */
  637. BOOL kCnrBase::invalidateRecord(kCnrMiniRecord *pRecord, ULONG fFlags/* = CMA_TEXTCHANGED*/)
  638. {
  639.     return(BOOL)WinSendMsg(hwndCnr, CM_INVALIDATERECORD, &pRecord, MPFROM2SHORT(1, fFlags));
  640. }
  641.  
  642.  
  643.  
  644. /**
  645.  * Invalidates multiple records.
  646.  * @returns   TRUE / FALSE according to the result.
  647.  * @param     fFlags    Invalidation flags.
  648.  * @param     cRecords  Count of records to invalidate.
  649.  * @param     ...       'cRecords' number of Pointers to kCnrMiniRecords
  650.  */
  651. BOOL kCnrBase::invalidateRecords(ULONG fFlags, ULONG cRecords, ...)
  652. {
  653.     va_list pArg;
  654.     BOOL fRet;
  655.     kCnrMiniRecord** papRec = new (kCnrMiniRecord**)[cRecords];
  656.     if (papRec == NULL)
  657.         return FALSE;
  658.  
  659.     /* fill papRec */
  660.     va_start(pArg, cRecords);
  661.     for (int i = 0; i < cRecords; i++)
  662.         papRec[i] = va_arg(pArg, kCnrMiniRecord *);
  663.     va_end(pArg);
  664.  
  665.     /* call */
  666.     fRet = invalidateRecords(fFlags, cRecords, papRec);
  667.  
  668.     delete papRec;
  669.  
  670.     return fRet;
  671. }
  672.  
  673.  
  674.  
  675. /**
  676.  * Invalidates multiple records.
  677.  * @returns   TRUE / FALSE according to the result.
  678.  * @param     fFlags    Invalidation flags.
  679.  * @param     cRecords  Count of records to invalidate.
  680.  * @param     papRec    Pointer to a record array of 'cRecords' records.
  681.  */
  682. BOOL kCnrBase::invalidateRecords(ULONG fFlags, ULONG cRecords, kCnrMiniRecord **papRec)
  683. {
  684.     return(BOOL)WinSendMsg(hwndCnr, CM_INVALIDATERECORD, papRec, MPFROM2SHORT(cRecords, fFlags));
  685. }
  686.  
  687.  
  688.  
  689. /**
  690.  * Sets the cDelta value of the container.
  691.  * @returns   TRUE / FALSE according to the result.
  692.  * @param     cDelta  New delta value.
  693.  */
  694. BOOL kCnrBase::setDelta(ULONG cDelta)
  695. {
  696.     if (!validateCnrInfo())
  697.         return FALSE;
  698.     if (CnrInfo.cDelta != cDelta)
  699.     {
  700.         CnrInfo.cDelta = cDelta;
  701.         return setCnrInfo(CMA_DELTA);
  702.     }
  703.  
  704.     return TRUE;
  705. }
  706.  
  707.  
  708.  
  709. /**
  710.  * Sets the flWindowAttr field of the CnrInfo struct.
  711.  * @returns   TRUE / FALSE according to if the update was successful or not.
  712.  * @param     flWindowAttr  New value.
  713.  */
  714. BOOL kCnrBase::setflWindowAttr(ULONG flWindowAttr)
  715. {
  716.     if (!validateCnrInfo())
  717.         return FALSE;
  718.  
  719.     if (CnrInfo.flWindowAttr != flWindowAttr)
  720.     {
  721.         CnrInfo.flWindowAttr = flWindowAttr;
  722.         return setCnrInfo(CMA_FLWINDOWATTR);
  723.     }
  724.  
  725.     return TRUE;
  726. }
  727.  
  728.  
  729.  
  730. /**
  731.  * Sets the window title.
  732.  * @returns   TRUE / FALSE according to if the update was successful or not.
  733.  * @param     pszTitle  Pointer to title string.
  734.  */
  735. BOOL kCnrBase::setTitle(PSZ pszTitle)
  736. {
  737.     if (!validateCnrInfo())
  738.         return FALSE;
  739.  
  740.     if (CnrInfo.pszCnrTitle != pszTitle)
  741.     {
  742.         CnrInfo.pszCnrTitle = pszTitle;
  743.         return setCnrInfo(CMA_CNRTITLE);
  744.     }
  745.  
  746.     return TRUE;
  747. }
  748.  
  749.  
  750.  
  751. /**
  752.  * Sets the pFieldInfoLast field in the CnrInfo struct.
  753.  * @returns   TRUE / FALSE according to if the update was successful or not.
  754.  * @param     pFieldInfoLast  Pointer to the last fieldinfo struct.
  755.  */
  756. BOOL kCnrBase::setLastFieldInfo(PFIELDINFO pFieldInfoLast)
  757. {
  758.     if (!validateCnrInfo())
  759.         return FALSE;
  760.  
  761.     if (CnrInfo.pFieldInfoLast != pFieldInfoLast)
  762.     {
  763.         CnrInfo.pFieldInfoLast = pFieldInfoLast;
  764.         return setCnrInfo(CMA_PFIELDINFOLAST);
  765.     }
  766.  
  767.     return TRUE;
  768. }
  769.  
  770.  
  771.  
  772. /**
  773.  * Sets the emphasis on a record.
  774.  * @returns   TRUE / FALSE according to the result.
  775.  * @param     pRecord
  776.  * @param     fChangeEmphasis     TRUE : Set attributes given in fEmphasisAttribute.
  777.  *                                FALSE: Unset attributes given in fEmphasisAttribute.
  778.  * @param     fEmphasisAttribute  Record emphasis attributes.
  779.  */
  780. BOOL kCnrBase::setRecordEmphasis(kCnrMiniRecord *pRecord, BOOL fChangeEmphasis, USHORT fEmphasisAttribute)
  781. {
  782.     return(BOOL)WinSendMsg(hwndCnr, CM_SETRECORDEMPHASIS,
  783.                            pRecord,
  784.                            MPFROM2SHORT(fChangeEmphasis, fEmphasisAttribute));
  785. }
  786.  
  787.  
  788.  
  789. /**
  790.  * Sets the position.
  791.  * @returns   TRUE / FALSE according to the result.
  792.  * @param     ulPos  Position (record number)
  793.  */
  794. BOOL kCnrBase::setPos(ULONG ulPos)
  795. {
  796.     return(BOOL)WinSendMsg(WinWindowFromID(hwndCnr, CID_VSCROLL), SBM_SETPOS, (MPARAM)ulPos, NULL);
  797. }
  798.  
  799.  
  800.  
  801. /**
  802.  * disables update.
  803.  * @returns   TRUE/FALSE according to result.
  804.  * @remark    Intended used with multiple inserts/removs.
  805.  */
  806. BOOL kCnrBase::disableUpdate()
  807. {
  808.     return WinEnableWindowUpdate(hwndCnr, FALSE);
  809. }
  810.  
  811.  
  812.  
  813. /**
  814.  * Enable update.
  815.  * @returns   TRUE/FALSE according to result.
  816.  * @remark    Intended used with multiple inserts/removs.
  817.  */
  818. BOOL kCnrBase::enableUpdate()
  819. {
  820.     return WinEnableWindowUpdate(hwndCnr, TRUE)
  821.     && WinInvalidateRect(hwndCnr, NULL, TRUE)
  822.     && WinInvalidateRect(WinWindowFromID(hwndCnr, CID_VSCROLL), NULL, TRUE);
  823. }
  824.  
  825.  
  826. /**
  827.  * Resize the container and border frame according to the swpDelta.
  828.  * @returns   success indicator.
  829.  * @param     cx    New height.
  830.  * @param     cy    New width.
  831.  */
  832. BOOL kCnrBase::resize(LONG cx, LONG cy)
  833. {
  834.     /* container */
  835.     if (WinSetWindowPos(hwndCnr, HWND_TOP,
  836.                         0, 0,
  837.                         cx,
  838.                         cy,
  839.                         SWP_SIZE)
  840.         )
  841.     {
  842.         /* border */
  843.         if (hwndBorder != NULLHANDLE)
  844.         {
  845.             if (WinSetWindowPos(hwndBorder, hwndCnr,
  846.                                 0, 0,
  847.                                 cx+2,
  848.                                 cy+2,
  849.                                 SWP_SIZE)
  850.                 )
  851.                 return TRUE;
  852.         }
  853.         else
  854.             return TRUE;
  855.     }
  856.  
  857.     return FALSE;
  858. }
  859.  
  860.  
  861. /**
  862.  * Resize the container and border frame according to the swpDelta.
  863.  * @returns   success indicator.
  864.  * @param     x    Left corner x-coordinate.
  865.  * @param     y    Left corner y-coordinate.
  866.  */
  867. BOOL kCnrBase::setpos(LONG x, LONG y)
  868. {
  869.     /* container */
  870.     if (WinSetWindowPos(hwndCnr, HWND_TOP,
  871.                         x, y,
  872.                         0, 0,
  873.                         SWP_MOVE)
  874.         )
  875.     {
  876.         /* border */
  877.         if (hwndBorder != NULLHANDLE)
  878.         {
  879.             if (WinSetWindowPos(hwndBorder, hwndCnr,
  880.                                 x-1, y-1,
  881.                                 0, 0,
  882.                                 SWP_MOVE)
  883.                 )
  884.                 return TRUE;
  885.         }
  886.         else
  887.             return TRUE;
  888.     }
  889.  
  890.     return FALSE;
  891. }
  892.  
  893.  
  894. /**
  895.  * Resize and mode the dialog.
  896.  * @returns   Success indicator. TRUE / FALSE.
  897.  * @param     x   x-coordinate for left lower corner.
  898.  * @param     y   y-coordinate for left lower corner.
  899.  * @param     cx  Size in x direction (pixels).
  900.  * @param     cy  Size in y direction (pixels).
  901.  */
  902. BOOL kCnrBase::resizeAndMove(LONG x, LONG y, LONG cx, LONG cy)
  903. {
  904.     if (WinSetWindowPos(hwndCnr, NULLHANDLE, x, y, cx, cy, SWP_SIZE | SWP_MOVE))
  905.     {
  906.         if (hwndBorder != NULLHANDLE)
  907.         {
  908.             return WinSetWindowPos(hwndBorder, NULLHANDLE, x-1, y-1, cx+2, cy+2, SWP_SIZE | SWP_MOVE);
  909.         }
  910.         else
  911.             return TRUE;
  912.     }
  913.     return FALSE;
  914. }
  915.  
  916.  
  917. /**
  918.  * Gets the menu-source marked record in the container (if any).
  919.  * @returns   Pointer to menu-source marked record.
  920.  *            If no such record or error a NULL-pointer is returned.
  921.  * @param     pStartRecord  NULL  - first menu-source record is returned.
  922.  *                          Other - pRecord is used as a the start record for the search.
  923.  */
  924. kCnrMiniRecord *kCnrBase::queryMenuSourceRecord(kCnrMiniRecord *pStartRecord/* = NULL*/)
  925. {
  926.     PVOID pv = WinSendMsg(hwndCnr, CM_QUERYRECORDEMPHASIS,
  927.                           pStartRecord != NULL ? (MPARAM)pStartRecord : (MPARAM)CMA_FIRST,
  928.                           (MPARAM)CRA_SOURCE);
  929.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  930. }
  931.  
  932.  
  933.  
  934. /**
  935.  * Gets selected record(s) in the container (if any).
  936.  * @returns   Pointer to selected record.
  937.  *            If no such record or error a NULL-pointer is returned.
  938.  * @param     pStartRecord  NULL  - first selected record is returned.
  939.  *                          Other - pRecord is used as a the start record for the search.
  940.  */
  941. kCnrMiniRecord *kCnrBase::querySelectedRecord(kCnrMiniRecord *pStartRecord/* = NULL*/)
  942. {
  943.     PVOID pv = WinSendMsg(hwndCnr, CM_QUERYRECORDEMPHASIS,
  944.                           pStartRecord == NULL ? (MPARAM)CMA_FIRST : pStartRecord,
  945.                           (MPARAM)CRA_SELECTED);
  946.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  947. }
  948.  
  949.  
  950.  
  951. /**
  952.  * Gets in-use record(s) in the container (if any).
  953.  * @returns   Pointer to in-use record.
  954.  *            If no such record or error a NULL-pointer is returned.
  955.  * @param     pStartRecord  NULL  - first in-use record is returned.
  956.  *                          Other - pRecord is used as a the start record for the search.
  957.  */
  958. kCnrMiniRecord  *kCnrBase::queryInUseRecord(kCnrMiniRecord *pStartRecord/* = NULL*/)
  959. {
  960.     PVOID pv = WinSendMsg(hwndCnr, CM_QUERYRECORDEMPHASIS,
  961.                           pStartRecord == NULL ? (MPARAM)CMA_FIRST : pStartRecord,
  962.                           (MPARAM)CRA_INUSE);
  963.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  964. }
  965.  
  966.  
  967.  
  968. /**
  969.  * Gets cursored record(s) in the container (if any).
  970.  * @returns   Pointer to cursored record.
  971.  *            If no such record or error a NULL-pointer is returned.
  972.  * @param     pStartRecord  NULL  - first cursored record is returned.
  973.  *                          Other - pRecord is used as a the start record for the search.
  974.  */
  975. kCnrMiniRecord  *kCnrBase::queryCursoredRecord(kCnrMiniRecord *pStartRecord/* = NULL*/)
  976. {
  977.     PVOID pv = WinSendMsg(hwndCnr, CM_QUERYRECORDEMPHASIS,
  978.                           pStartRecord == NULL ? (MPARAM)CMA_FIRST : pStartRecord,
  979.                           (MPARAM)CRA_CURSORED);
  980.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  981. }
  982.  
  983.  
  984.  
  985. /**
  986.  * Gets the topmost record in the container.
  987.  * @returns   Pointer to the topmost record in the container.
  988.  *            If no records or error a NULL-pointer is returned.
  989.  */
  990. kCnrMiniRecord *kCnrBase::queryTopRecord()
  991. {
  992.     PVOID pv = WinSendMsg(hwndCnr, CM_QUERYRECORD, NULL, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  993.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  994. }
  995.  
  996.  
  997.  
  998. /**
  999.  * Gets the bottemmost record in the container.
  1000.  * @returns   Pointer the to bottommost record in the container.
  1001.  *            If no records or error a NULL-pointer is returned.
  1002.  */
  1003. kCnrMiniRecord *kCnrBase::queryBottomRecord()
  1004. {
  1005.     PVOID pv = WinSendMsg(hwndCnr, CM_QUERYRECORD, NULL, MPFROM2SHORT(CMA_LAST, CMA_ITEMORDER));
  1006.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  1007. }
  1008.  
  1009.  
  1010.  
  1011. /**
  1012.  * Gets the next record from the given record (or top if NULL is given);
  1013.  * @returns   Pointer to a kCnrMiniRecord.
  1014.  * @param     pStartRecord  Pointer to the start record.(NULL - first record is returned).
  1015.  */
  1016. kCnrMiniRecord *kCnrBase::queryNextRecord(kCnrMiniRecord *pStartRecord/* = NULL*/)
  1017. {
  1018.     PVOID pv;
  1019.  
  1020.     if (pStartRecord == NULL)
  1021.         return queryTopRecord();
  1022.     pv = WinSendMsg(hwndCnr, CM_QUERYRECORD, pStartRecord, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
  1023.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  1024. }
  1025.  
  1026.  
  1027.  
  1028. /**
  1029.  * Gets the previous record from the given record (or top if NULL is given);
  1030.  * @returns   Pointer to a kCnrMiniRecord.
  1031.  * @param     pStartRecord  Pointer to the start record.(NULL - last record is returned).
  1032.  */
  1033. kCnrMiniRecord *kCnrBase::queryPrevRecord(kCnrMiniRecord *pStartRecord/* = NULL*/)
  1034. {
  1035.     PVOID pv;
  1036.  
  1037.     if (pStartRecord == NULL)
  1038.         return queryBottomRecord();
  1039.     pv = WinSendMsg(hwndCnr, CM_QUERYRECORD, pStartRecord, MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER));
  1040.     return(kCnrMiniRecord*)(pv != (void*)-1 ? pv : NULL);
  1041. }
  1042.  
  1043.  
  1044.  
  1045. /**
  1046.  * Gets the number of records in the container.
  1047.  * @returns   number of records in the container.
  1048.  * @precond   Container is ok, hench the validateCnrInfo call will not fail.
  1049.  */
  1050. ULONG kCnrBase::getCountOfRecords()
  1051. {
  1052.     validateCnrInfo();
  1053.     return CnrInfo.cRecords;
  1054. }
  1055.  
  1056.  
  1057.  
  1058. /**
  1059.  * Gets the flWindowAttr in the CnrInfo struct.
  1060.  * @returns   flWindowAttr.
  1061.  * @precond   Container is ok, hench the validateCnrInfo call will not fail.
  1062.  */
  1063. ULONG kCnrBase::getflWindowAttr()
  1064. {
  1065.     validateCnrInfo();
  1066.  
  1067.     return CnrInfo.flWindowAttr;
  1068. }
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076.  
  1077.  
  1078.  
  1079.  
  1080.  
  1081.  
  1082.  
  1083.  
  1084.  
  1085.  
  1086.  
  1087.  
  1088.  
  1089.  
  1090.  
  1091.  
  1092.  
  1093. /**
  1094.  * Sort callback function.
  1095.  * @returns   >  0  when pRecord1  >  pRecord2
  1096.  *            <  0  when pRecord1  <  pRecord2
  1097.  *            == 0  when pRecord1 ==  pRecord2
  1098.  * @param     pRecord1  Pointer to first record.
  1099.  * @param     pRecord2  Pointer to second record.
  1100.  */
  1101. SHORT kDetailCnr::sortCallBack(kCnrMiniRecord *pRecord1, kCnrMiniRecord *pRecord2)
  1102. {
  1103.     pRecord1 = pRecord1;
  1104.     pRecord2 = pRecord2;
  1105.     return 1;
  1106. }
  1107.  
  1108.  
  1109. /**
  1110.  * Container sort function callback and forwarder.
  1111.  * This function calls the sortCallBack function of the container class.
  1112.  * @returns   >  0  when pRecord1  >  pRecord2
  1113.  *            <  0  when pRecord1  <  pRecord2
  1114.  *            == 0  when pRecord1 ==  pRecord2
  1115.  * @param     pRecord1  Pointer to first record.
  1116.  * @param     pRecord2  Pointer to second record.
  1117.  * @param     pvThis    Pointer to kDetailCnr instance data.
  1118.  */
  1119. SHORT _System sortForwarder(PMINIRECORDCORE pRecord1, PMINIRECORDCORE pRecord2, PVOID pvThis)
  1120. {
  1121.     kDetailCnr *pThis = (kDetailCnr*)pvThis;
  1122.     if (pThis != NULL)
  1123.         return pThis->sortCallBack((kCnrMiniRecord*)pRecord1, (kCnrMiniRecord*)pRecord2);
  1124.     return 1;
  1125. }
  1126.  
  1127.  
  1128.  
  1129. /**
  1130.  * Contructor, creates a detail container.
  1131.  * @param     hwndCnr       Handle to container control.
  1132.  * @param     pszTitle      Pointer to title string.
  1133.  * @param     cColumns      Count of coloumns (and fieldinfo structs in paFieldInfo.
  1134.  * @param     paFieldInfo   Pointer to an array of fieldinfo structs containing the basis for
  1135.  *                          creating fieldinfo structs for the container.
  1136.  */
  1137. kDetailCnr::kDetailCnr(HWND hwndCnr, ULONG flWindowAttr, PSZ pszTitle, ULONG cColumns, PFIELDINFO paFieldInfo, BOOL fBorder/* = TRUE*/) throw (kError)
  1138. : kCnrBase(hwndCnr, fBorder)
  1139. {
  1140.     this->cColumns = cColumns;
  1141.  
  1142.     /* set detail-view */
  1143.     flWindowAttr |= CV_DETAIL;
  1144.     setflWindowAttr(flWindowAttr);
  1145.  
  1146.     /* set title if any */
  1147.     if (pszTitle != NULL)
  1148.     {
  1149.         flWindowAttr |= CA_CONTAINERTITLE;
  1150.         setTitle(pszTitle);
  1151.         if (!setflWindowAttr(flWindowAttr))
  1152.             throw ((kError::unused, kError::win));
  1153.     }
  1154.  
  1155.     /* make fieldinfo */
  1156.     PFIELDINFO pFieldInfo;
  1157.     PFIELDINFO pFICur;
  1158.  
  1159.     pFICur = pFieldInfo = allocDetailFieldInfo((USHORT)cColumns);
  1160.     if (pFieldInfo == NULL)
  1161.         throw (kError(kError::unused, kError::win));
  1162.  
  1163.     for (int i = 0; i < cColumns; i++, pFICur = pFICur->pNextFieldInfo)
  1164.     {
  1165.         pFICur->cb         = sizeof(FIELDINFO);           /* size of FIELDINFO struct       */
  1166.         pFICur->flData     = paFieldInfo[i].flData;       /* attributes of field's data     */
  1167.         pFICur->flTitle    = paFieldInfo[i].flTitle;      /* attributes of field's title    */
  1168.         pFICur->pTitleData = paFieldInfo[i].pTitleData;   /* title data (default is string) */
  1169.                                                           /* If CFT_BITMAP, must be HBITMAP */
  1170.         pFICur->offStruct  = paFieldInfo[i].offStruct;    /* offset from RECORDCORE to data */
  1171.         pFICur->cxWidth    = paFieldInfo[i].cxWidth;      /* pointer to user data           */
  1172.  
  1173.         /* determin if title on columns */
  1174.         if (pFICur->pTitleData != NULL)
  1175.             flWindowAttr |= CA_DETAILSVIEWTITLES;
  1176.     }
  1177.  
  1178.     /* set pFieldInfoLast */
  1179.     if (!setLastFieldInfo(pFICur))
  1180.     {
  1181.         freeDetailFieldInfo(pFieldInfo, (USHORT)cColumns);
  1182.         throw ((kError::unused, kError::win));
  1183.     }
  1184.  
  1185.     /* update flWindowAttr */
  1186.     if (flWindowAttr & CA_DETAILSVIEWTITLES)
  1187.     {
  1188.         if (!setflWindowAttr(flWindowAttr))
  1189.         {
  1190.             freeDetailFieldInfo(pFieldInfo, (USHORT)cColumns);
  1191.             throw ((kError::unused, kError::win));
  1192.         }
  1193.     }
  1194.  
  1195.     /* set fieldinfo */
  1196.     if (!insertDetailFieldInfo(pFieldInfo, (PFIELDINFO)CMA_FIRST, TRUE, cColumns))
  1197.     {
  1198.         freeDetailFieldInfo(pFieldInfo, (USHORT)cColumns);
  1199.         throw ((kError::unused, kError::win));
  1200.     }
  1201.  
  1202. }
  1203.  
  1204.  
  1205.  
  1206. /**
  1207.  * Destructor.
  1208.  */
  1209. kDetailCnr::~kDetailCnr()
  1210. {
  1211.     /* do little - base class destructor does it all! */
  1212. }
  1213.  
  1214.  
  1215. /**
  1216.  * disables sorting.
  1217.  * @returns   Success indicator.
  1218.  */
  1219. BOOL kDetailCnr::enableSorting()
  1220. {
  1221.     return (BOOL)WinSendMsg(hwndCnr, CM_SORTRECORD, (MPARAM)sortForwarder, (MPARAM)this);
  1222. }
  1223.  
  1224.  
  1225. /**
  1226.  * disables sorting.
  1227.  * @returns   Success indicator.
  1228.  */
  1229. BOOL kDetailCnr::disableSorting()
  1230. {
  1231.     return (BOOL)WinSendMsg(hwndCnr, CM_SORTRECORD, (MPARAM)sortForwarder, NULL);
  1232. }
  1233.  
  1234.