home *** CD-ROM | disk | FTP | other *** search
/ linuxmafia.com 2016 / linuxmafia.com.tar / linuxmafia.com / pub / palmos / progect-src-0.20.tar.gz / progect-src-0.20.tar / progect-0.20 / task.c < prev    next >
C/C++ Source or Header  |  2000-10-26  |  73KB  |  2,958 lines

  1. /* -*-Mode:C; tab-width:4; indent-tabs-mode:t; c-file-style:"stroustrup";-*- */
  2. // $Id: task.c,v 1.13 2000/10/22 18:35:27 burgbach Exp $
  3.  
  4. #include <PalmOS.h>
  5. #include "task.h"
  6. #include "progect.h"
  7. #include "progectdb.h"
  8. #include "progectRsc.h"
  9. #include "ToDoDB.h"
  10. #include "MemoDB.h"
  11. #include "AddressDB.h"
  12.  
  13. /****************************************************************************
  14.  * Name : TaskSetAttr
  15.  * Desc : set the attributes of a task
  16.  * Parm : 
  17.  *             -> db to search
  18.  *             -> index of record
  19.  *             -> new attributes
  20.  * Out  : pgErr
  21.  * Auth : lb, 22.08.2000
  22.  ***************************************************************************/
  23. pgErr TaskSetAttr(DmOpenRef dbP, UInt16 index, TaskAttrType attr)
  24. {
  25.     MemHandle h;
  26.     TaskRecordType *p;
  27.  
  28.     h = DmGetRecord(dbP, index);
  29.  
  30. #ifdef __PG_EXTRA_CHECK__
  31.     if (!h)
  32.         return pgError;
  33. #endif
  34.  
  35.     p = MemHandleLock(h);
  36.     DmWrite(p, OffsetOf(TaskRecordType, attr), &attr, sizeof(UInt16));
  37.     MemHandleUnlock(h);
  38.     DmReleaseRecord(dbP, index, true);
  39.  
  40.     return pgOK;
  41. } // pgErr TaskSetAttr(DmOpenRef dbP, UInt16 index, TaskAttrType attr)
  42.  
  43.  
  44.  
  45. /****************************************************************************
  46.  * Name : TaskGetAttr
  47.  * Desc : get the attributes of a task
  48.  * Parm : 
  49.  *             -> db to search
  50.  *             -> index of record
  51.  * Out  : attributes
  52.  * Auth : lb, 22.08.2000
  53.  ***************************************************************************/
  54. TaskAttrType TaskGetAttr(DmOpenRef dbP, UInt16 index)
  55. {
  56.     MemHandle h;
  57.     TaskRecordType *p;
  58.     TaskAttrType attr;
  59.  
  60.     h = DmQueryRecord(dbP, index);
  61.  
  62. #ifdef __PG_EXTRA_CHECK__
  63.     if (!h)
  64.         return 0;
  65. #endif
  66.  
  67.     p = MemHandleLock(h);
  68.     attr = p->attr.bits;
  69.     MemHandleUnlock(h);
  70.  
  71.     return attr;
  72. } // UInt16 TaskGetAttr(DmOpenRef dbP, UInt16 index)
  73.  
  74.  
  75.  
  76. /****************************************************************************
  77.  * Name : TaskSetFormat
  78.  * Desc : set the format of a task
  79.  * Parm : 
  80.  *             -> db to search
  81.  *             -> index of record
  82.  *             -> new format
  83.  * Out  : pgErr
  84.  * Auth : lb, 22.08.2000
  85.  ***************************************************************************/
  86. pgErr TaskSetFormat(DmOpenRef dbP, UInt16 index, TaskFormatType format)
  87. {
  88.     MemHandle h;
  89.     TaskRecordType *p;
  90.  
  91.     h = DmGetRecord(dbP, index);
  92.  
  93. #ifdef __PG_EXTRA_CHECK__
  94.     if (!h)
  95.         return pgError;
  96. #endif
  97.  
  98.     p = MemHandleLock(h);
  99.     DmWrite(p, OffsetOf(TaskRecordType, format), &format, sizeof(UInt16));
  100.     MemHandleUnlock(h);
  101.     DmReleaseRecord(dbP, index, true);
  102.  
  103.     return pgOK;
  104. } // pgErr TaskSetFormat(DmOpenRef dbP, UInt16 index, TaskFormatType format)
  105.  
  106.  
  107.  
  108. /****************************************************************************
  109.  * Name : TaskGetFormat
  110.  * Desc : get the format of a task
  111.  * Parm : 
  112.  *             -> db to search
  113.  *             -> index of record
  114.  * Out  : format
  115.  * Auth : lb, 26.08.2000
  116.  ***************************************************************************/
  117. TaskFormatType TaskGetFormat(DmOpenRef dbP, UInt16 index)
  118. {
  119.     MemHandle h;
  120.     TaskRecordType *p;
  121.     TaskFormatType format;
  122.  
  123.     h = DmQueryRecord(dbP, index);
  124.  
  125. #ifdef __PG_EXTRA_CHECK__
  126.     if (!h)
  127.         return 0;
  128. #endif
  129.  
  130.     p = MemHandleLock(h);
  131.     format = p->format.bits;
  132.     MemHandleUnlock(h);
  133.  
  134.     return format;
  135. } // TaskFormatType TaskGetFormat(DmOpenRef dbP, UInt16 index)
  136.  
  137.  
  138.  
  139. /****************************************************************************
  140.  * Name : TaskSetLevel
  141.  * Desc : set the level of a task
  142.  * Parm : 
  143.  *             -> db to search
  144.  *             -> index of record
  145.  *             -> new level (0-31)
  146.  * Out  : pgErr
  147.  * Auth : lb, 28.07.2000
  148.  * Mod  : lb, 22.08.2000
  149.  *             new preferences scheme
  150.  ***************************************************************************/
  151. pgErr TaskSetLevel(DmOpenRef dbP, UInt16 index, UInt8 level)
  152. {
  153.     TaskAttrType attr;
  154.  
  155.     if (level > 31)
  156.         return pgError;
  157.  
  158.     attr = TaskGetAttr(dbP, index);
  159.     attr.level = level;
  160.     TaskSetAttr(dbP, index, attr);
  161.  
  162.     return pgOK;
  163. } // pgErr TaskSetLevel(DmOpenRef dbP, UInt16 index, UInt8 level)
  164.  
  165.  
  166.  
  167. /****************************************************************************
  168.  * Name : TaskGetLevel
  169.  * Desc : get the level of a task
  170.  * Parm : 
  171.  *             -> db to search
  172.  *             -> index of record
  173.  * Out  : level, 0 if not found
  174.  * Auth : lb, 27.07.2000
  175.  * Mod  : lb, 22.08.2000
  176.  *             new preferences scheme
  177.  ***************************************************************************/
  178. UInt8 TaskGetLevel(DmOpenRef dbP, UInt16 index)
  179. {
  180.     return TaskGetAttr(dbP, index).level;
  181. } // UInt8 TaskGetLevel(DmOpenRef dbP, UInt16 index)
  182.  
  183.  
  184.  
  185. /****************************************************************************
  186.  * Name : TaskSetPriority
  187.  * Desc : set the priority of a task
  188.  * Parm : 
  189.  *             -> db to search
  190.  *             -> index of record
  191.  *             -> new priority
  192.  * Out  : 
  193.  * Auth : lb, 06.08.2000
  194.  * Mod  : lb, 22.08.2000
  195.  *             new preferences scheme
  196.  ***************************************************************************/
  197. pgErr TaskSetPriority(DmOpenRef dbP, UInt16 index, UInt8 priority)
  198. {
  199.     MemHandle h;
  200.     TaskTypePtr p;
  201.  
  202.     h = DmGetRecord(dbP, index);
  203.     p = MemHandleLock(h);
  204.     DmWrite(p, OffsetOf(TaskType, priority), &priority, sizeof(UInt8));
  205.     MemHandleUnlock(h);
  206.     DmReleaseRecord(dbP, index, true);
  207.     return pgOK;
  208. } // void TaskSetPriority(DmOpenRef dbP, UInt16 index, UInt8 priority)
  209.  
  210.  
  211.  
  212. /****************************************************************************
  213.  * Name : TaskGetPriority
  214.  * Desc : get the priority of a task
  215.  * Parm : 
  216.  *             -> db to search
  217.  *             -> index of record
  218.  * Out  : level, 0 if not found
  219.  * Auth : lb, 06.08.2000
  220.  * Mod  : lb, 22.08.2000
  221.  *             new preferences scheme
  222.  ***************************************************************************/
  223. UInt8 TaskGetPriority(DmOpenRef dbP, UInt16 index)
  224. {
  225.     MemHandle h;
  226.     TaskTypePtr p;
  227.     UInt8 priority;
  228.  
  229.     h = DmQueryRecord(dbP, index);
  230.     p = MemHandleLock(h);
  231.     priority = p->priority;
  232.     MemHandleUnlock(h);
  233.     return priority;
  234. } // UInt8 TaskGetPriority(DmOpenRef dbP, UInt16 index)
  235.  
  236.  
  237.  
  238. /****************************************************************************
  239.  * Name : TaskSetHasChild
  240.  * Desc : set the hasChild field of task
  241.  * Parm : 
  242.  *             -> db to search
  243.  *             -> index of the record
  244.  *             -> value of hasChild field
  245.  * Out  : 
  246.  * Auth : lb, 28.07.2000
  247.  * Mod  : lb, 22.08.2000
  248.  *             new preferences scheme
  249.  ***************************************************************************/
  250. pgErr TaskSetHasChild(DmOpenRef dbP, UInt16 index, Boolean hasChild)
  251. {
  252.     TaskAttrType attr;
  253.  
  254.     attr = TaskGetAttr(dbP, index);
  255.     attr.hasChild = hasChild;
  256.     TaskSetAttr(dbP, index, attr);
  257.  
  258.     return pgOK;
  259. } // pgErr TaskSetHasChild(DmOpenRef dbP, UInt16 index, Boolean hasChild)
  260.  
  261.  
  262.  
  263. /****************************************************************************
  264.  * Name : TaskGetHasChild
  265.  * Desc : get the hasChild field of task
  266.  * Parm : 
  267.  *             -> db to search
  268.  *             -> index of the record
  269.  * Out  : hasChild field value
  270.  * Auth : lb, 28.07.2000
  271.  * Mod  : lb, 22.08.2000
  272.  *             new preferences scheme
  273.  ***************************************************************************/
  274. Boolean TaskGetHasChild(DmOpenRef dbP, UInt16 index)
  275. {
  276.     return TaskGetAttr(dbP, index).hasChild;
  277. } // Boolean TaskGetHasChild(DmOpenRef dbP, UInt16 index)
  278.  
  279.  
  280.  
  281. /****************************************************************************
  282.  * Name : TaskSetHasPrev
  283.  * Desc : set the firstChild field of task
  284.  * Parm : 
  285.  *             -> db to search
  286.  *             -> index of the record
  287.  *             -> value of hasPrev field
  288.  * Out  : 
  289.  * Auth : lb, 28.07.2000
  290.  * Mod  : lb, 22.08.2000
  291.  *             new preferences scheme
  292.  ***************************************************************************/
  293. pgErr TaskSetHasPrev(DmOpenRef dbP, UInt16 index, Boolean hasPrev)
  294. {
  295.     TaskAttrType attr;
  296.  
  297.     attr = TaskGetAttr(dbP, index);
  298.     attr.hasPrev = hasPrev;
  299.     TaskSetAttr(dbP, index, attr);
  300.  
  301.     return pgOK;
  302. } // pgErr TaskSetHasPrev(DmOpenRef dbP, UInt16 index, Boolean hasPrev)
  303.  
  304.  
  305.  
  306. /****************************************************************************
  307.  * Name : TaskGetHasPrev
  308.  * Desc : get the firstChild field of task
  309.  * Parm : 
  310.  *             -> db to search
  311.  *             -> index of the record
  312.  * Out  : firstChild field value
  313.  * Auth : lb, 28.07.2000
  314.  * Mod  : lb, 22.08.2000
  315.  *             new preferences scheme
  316.  ***************************************************************************/
  317. Boolean TaskGetHasPrev(DmOpenRef dbP, UInt16 index)
  318. {
  319.     return TaskGetAttr(dbP, index).hasPrev;
  320. } // Boolean TaskGetHasPrev(DmOpenRef dbP, UInt16 index)
  321.  
  322.  
  323.  
  324. /****************************************************************************
  325.  * Name : TaskGetHasNext
  326.  * Desc : get the hasNext field of task
  327.  * Parm : 
  328.  *             -> db to search
  329.  *             -> index of the record
  330.  * Out  : hasNext field value
  331.  * Auth : lb, 28.07.2000
  332.  * Mod  : lb, 22.08.2000
  333.  *             new preferences scheme
  334.  ***************************************************************************/
  335. Boolean TaskGetHasNext(DmOpenRef dbP, UInt16 index)
  336. {
  337.     return TaskGetAttr(dbP, index).hasNext;
  338. } // Boolean TaskGetHasNext(DmOpenRef dbP, UInt16 index)
  339.  
  340.  
  341.  
  342. /****************************************************************************
  343.  * Name : TaskSetHasNext
  344.  * Desc : set the hasNext field of task
  345.  * Parm : 
  346.  *             -> db to search
  347.  *             -> index of the record
  348.  *             -> next field
  349.  * Out  : 
  350.  * Auth : lb, 28.07.2000
  351.  * Mod  : lb, 22.08.2000
  352.  *             new preferences scheme
  353.  ***************************************************************************/
  354. pgErr TaskSetHasNext(DmOpenRef dbP, UInt16 index, Boolean next)
  355. {
  356.     TaskAttrType attr;
  357.  
  358.     attr = TaskGetAttr(dbP, index);
  359.     attr.hasNext = next;
  360.     TaskSetAttr(dbP, index, attr);
  361.  
  362.     return pgOK;
  363. } // pgErr TaskSetHasNext(DmOpenRef dbP, UInt16 index, Boolean next)
  364.  
  365.  
  366.  
  367. /****************************************************************************
  368.  * Name : TaskIsOpened
  369.  * Desc : see if task is opened
  370.  * Parm : 
  371.  *             -> db to search
  372.  *             -> index of the record
  373.  * Out  : 
  374.  * Auth : lb, 01.08.2000
  375.  * Mod  : lb, 22.08.2000
  376.  *             new preferences scheme
  377.  ***************************************************************************/
  378. Boolean TaskIsOpened(DmOpenRef dbP, UInt16 index)
  379. {
  380.     return TaskGetAttr(dbP, index).opened;
  381. } // Boolean TaskIsOpened(DmOpenRef dbP, UInt16 index)
  382.  
  383.  
  384.  
  385. /****************************************************************************
  386.  * Name : TaskIsVisible
  387.  * Desc : true if task is first level, or in an opened hierarchy
  388.  * Parm : 
  389.  *             -> db to search
  390.  *             -> index of the record
  391.  * Out  : 
  392.  * Auth : lb, 02.08.2000
  393.  * Mod  : lb, 24.08.2000
  394.  *             don't look beyond gRefLevel
  395.  ***************************************************************************/
  396. Boolean TaskIsVisible(DmOpenRef dbP, UInt16 index)
  397. {
  398.     UInt8 comp;
  399.     // hide done tasks
  400.     if ((((comp = TaskGetCompleted(dbP, index)) == 10) || comp == ACTION_OK) &&
  401.         gProjectPrefs.hideDoneTasks)
  402.         return false;
  403.  
  404.     while (TaskGetLevel(dbP, index) > gRefLevel + 1)
  405.     {
  406.         index = TaskGetFatherIndex(dbP, index);
  407.         if (!TaskIsOpened(dbP, index))
  408.             return false;
  409.     }
  410.  
  411.     return true;
  412. } // Boolean TaskIsVisible(DmOpenRef dbP, UInt16 index)
  413.  
  414.  
  415.  
  416. /****************************************************************************
  417.  * Name : TaskMakeVisible
  418.  * Desc : open all this task's fathers
  419.  * Parm : 
  420.  *             -> db to search
  421.  *             -> index of the record
  422.  * Out  : 
  423.  * Auth : lb, 19.10.2000
  424.  ***************************************************************************/
  425. void TaskMakeVisible(DmOpenRef dbP, UInt16 index)
  426. {
  427.     UInt8 comp;
  428.     // hide done tasks on => nothing to do, the task is hidden
  429.     if ((((comp = TaskGetCompleted(dbP, index)) == 10) || comp == ACTION_OK) &&
  430.         gProjectPrefs.hideDoneTasks)
  431.         return;
  432.  
  433.     while (TaskGetLevel(dbP, index) > gRefLevel + 1)
  434.     {
  435.         index = TaskGetFatherIndex(dbP, index);
  436.         if (!TaskIsOpened(dbP, index))
  437.             TaskSetOpened(dbP, index, true);
  438.     }
  439. } // void TaskMakeVisible(DmOpenRef dbP, UInt16 index)
  440.  
  441.  
  442.  
  443. /****************************************************************************
  444.  * Name : TaskToggleIsOpened
  445.  * Desc : toggle isOpened flag
  446.  * Parm : 
  447.  *             -> db to search
  448.  *             -> index of the record
  449.  * Out  : 
  450.  * Auth : lb, 01.08.2000
  451.  * Mod  : lb, 22.08.2000
  452.  *             new preferences scheme
  453.  ***************************************************************************/
  454. pgErr TaskToggleIsOpened(DmOpenRef dbP, UInt16 index)
  455. {
  456.     TaskAttrType attr;
  457.     attr = TaskGetAttr(dbP, index);
  458.     attr.opened = !attr.opened;
  459.     TaskSetAttr(dbP, index, attr);
  460.     return pgOK;
  461. } // pgErr TaskToggleIsOpened(DmOpenRef dbP, UInt16 index)
  462.  
  463.  
  464.  
  465. /****************************************************************************
  466.  * Name : TaskSetOpened
  467.  * Desc : set isOpened flag
  468.  * Parm : 
  469.  *             -> db to search
  470.  *             -> index of the record
  471.  * Out  : 
  472.  * Auth : lb, 04.08.2000
  473.  * Mod  : lb, 22.08.2000
  474.  *             new preferences scheme
  475.  * Rem  : bad err handling
  476.  * TODO : better error handling
  477.  ***************************************************************************/
  478. pgErr TaskSetOpened(DmOpenRef dbP, UInt16 index, Boolean value)
  479. {
  480.     TaskAttrType attr;
  481.  
  482.     attr = TaskGetAttr(dbP, index);
  483.     attr.opened = value;
  484.     TaskSetAttr(dbP, index, attr);
  485.  
  486.     return pgOK;
  487. } // pgErr TaskSetOpened(DmOpenRef dbP, UInt16 index, Boolean value)
  488.  
  489.  
  490.  
  491. /****************************************************************************
  492.  * Name : TaskGetFatherIndex
  493.  * Desc : get the father of a task
  494.  * Parm : 
  495.  *             -> db to search
  496.  *             -> index of the record
  497.  * Out  : father, dmMaxRecordIndex if not found
  498.  * Auth : lb, 28.07.2000
  499.  * Rem  : bad err handling
  500.  * TODO : better error handling
  501.  ***************************************************************************/
  502. UInt16 TaskGetFatherIndex(DmOpenRef dbP, UInt16 index)
  503. {
  504.     UInt16 prev = 0;
  505.     UInt16 sindex;
  506.     UInt8 level;
  507.  
  508.     level = TaskGetLevel(dbP, index);
  509.  
  510.     // top level tasks have no father
  511.     if (level == FIRST_LEVEL)
  512.         return prev;
  513.  
  514.     sindex = index - 1;
  515.  
  516.     while (sindex < index)
  517.     {
  518.         if (TaskGetLevel(dbP, sindex) == level - 1)
  519.         {
  520.             prev = sindex;
  521.             break;
  522.         }
  523.         sindex--;
  524.     }
  525.     return prev;
  526. } // UInt16 TaskGetFatherIndex(DmOpenRef dbP, UInt16 index)
  527.  
  528.  
  529.  
  530. /****************************************************************************
  531.  * Name : TaskGetPrevIndex
  532.  * Desc : get the previous of a task
  533.  * Parm : 
  534.  *             -> db to search
  535.  *             -> index of the record
  536.  * Out  : previous, dmMaxRecordIndex if not found
  537.  * Auth : lb, 27.07.2000
  538.  * Rem  : bad err handling
  539.  * TODO : better error handling
  540.  ***************************************************************************/
  541. UInt16 TaskGetPrevIndex(DmOpenRef dbP, UInt16 index)
  542. {
  543.     UInt16 prev = dmMaxRecordIndex;
  544.     UInt16 sindex;
  545.     UInt8  level;
  546.     UInt8  actLevel;
  547.  
  548.     if (!TaskGetHasPrev(dbP, index))
  549.         return prev;
  550.  
  551.     level = TaskGetLevel(dbP, index);
  552.     sindex = index - 1;
  553.  
  554.     while (sindex < index)
  555.     {
  556.         // get level of item sindex
  557.         actLevel = TaskGetLevel(dbP, sindex);
  558.  
  559.         // if it's the same, we found
  560.         if (actLevel == level)
  561.         {
  562.             prev = sindex;
  563.             break;
  564.         }
  565.  
  566.         // if it's less, there's no previous
  567.         if (actLevel < level)
  568.         {
  569.             break;
  570.         }
  571.         sindex--;
  572.     }
  573.     return prev;
  574. } // UInt16 TaskGetPrevIndex(DmOpenRef dbP, UInt16 index)
  575.  
  576.  
  577.  
  578. /****************************************************************************
  579.  * Name : TaskGetPrevIndexByLevel
  580.  * Desc : get the previous of same level from index
  581.  * Parm : 
  582.  *             -> db to search
  583.  *             -> index of the record
  584.  *             -> level to search for
  585.  * Out  : previous, dmMaxRecordIndex if not found
  586.  * Auth : lb, 31.07.2000
  587.  * Rem  : bad err handling
  588.  * TODO : better error handling
  589.  ***************************************************************************/
  590. UInt16 TaskGetPrevIndexByLevel(DmOpenRef dbP, UInt16 index, UInt8 level)
  591. {
  592.     UInt16 prev = dmMaxRecordIndex;
  593.     UInt16 sindex = index - 1;
  594.     UInt8  actLevel;
  595.  
  596.     // cannot search before first item
  597.     if (index == FIRST_INDEX)
  598.         return prev;
  599.  
  600.     // search all preceding items
  601.     while (sindex < index)
  602.     {
  603.         // get level of item sindex
  604.         actLevel = TaskGetLevel(dbP, sindex);
  605.  
  606.         // if it's the same, we found
  607.         if (actLevel == level)
  608.         {
  609.             prev = sindex;
  610.             break;
  611.         }
  612.  
  613.         // if it's less, there's no previous
  614.         if (actLevel < level)
  615.         {
  616.             break;
  617.         }
  618.         sindex--;
  619.     }
  620.  
  621.     return prev;
  622. } // UInt16 TaskGetPrevIndexByLevel(DmOpenRef dbP, UInt16 index, UInt8 level)
  623.  
  624.  
  625.  
  626. /****************************************************************************
  627.  * Name : TaskGetNextIndex
  628.  * Desc : get the next of a task
  629.  * Parm : 
  630.  *             -> index of the record
  631.  * Out  : next, 0 if not found
  632.  * Auth : lb, 27.07.2000
  633.  * Mod  : 01.08.2000
  634.  *             corrected bug that found a next in other branchs
  635.  * Rem  : bad err handling
  636.  * TODO : better error handling
  637.  ***************************************************************************/
  638. UInt16 TaskGetNextIndex(DmOpenRef dbP, UInt16 index)
  639. {
  640.     UInt16 next = 0, lastRecord = DmNumRecords(dbP);
  641.     UInt8 level;
  642.     UInt8 actLevel;
  643.  
  644.     level = TaskGetLevel(dbP, index);
  645.     index++;
  646.  
  647.     while (index < lastRecord)
  648.     {
  649.         actLevel = TaskGetLevel(dbP, index);
  650.         if (actLevel == level)
  651.         {
  652.             next = index;
  653.             break;
  654.         }
  655.  
  656.         if (actLevel < level)
  657.         {
  658.             break;
  659.         }
  660.         index++;
  661.     }
  662.     return next;
  663. } // UInt16 TaskGetNextIndex(DmOpenRef dbP, UInt16 index)
  664.  
  665.  
  666.  
  667. /****************************************************************************
  668.  * Name : TaskGetNextRelativeIndex
  669.  * Desc : get the next of a task, may be the next of a father (TODO be clearer...)
  670.  * Parm : 
  671.  *             -> index of the record
  672.  * Out  : next, 0 if not found
  673.  * Auth : lb, 01.08.2000
  674.  * Mod  : lb, 09.08.2000
  675.  *             - adding support for subtree viewing
  676.  *           lb, 28.09.2000
  677.  *               - return index if index = dmMaxRecordIndex
  678.  * Rem  : bad err handling
  679.  * TODO : better error handling
  680.  ***************************************************************************/
  681. UInt16 TaskGetNextRelativeIndex(DmOpenRef dbP, UInt16 index)
  682. {
  683.     UInt16 next = 0, lastRecord = DmNumRecords(dbP);
  684.     UInt8 level;
  685.     UInt8 actLevel;
  686.  
  687.     if (lastRecord == 0)
  688.         return next;
  689.     
  690.     if (index == dmMaxRecordIndex)
  691.         return index;
  692.  
  693.     level = TaskGetLevel(dbP, index);
  694.     index++;
  695.  
  696.     while (index < lastRecord)
  697.     {
  698.         actLevel = TaskGetLevel(dbP, index);
  699.         //if (actLevel <= level && actLevel >= gRefLevel)
  700.         if (actLevel <= level)
  701.         {
  702.             next = index;
  703.             break;
  704.         }
  705.  
  706.         index++;
  707.     }
  708.     return next;
  709. } // UInt16 TaskGetNextRelativeIndex(DmOpenRef dbP, UInt16 index)
  710.  
  711.  
  712.  
  713. /****************************************************************************
  714.  * Name : TaskSetActionState
  715.  * Desc : set action state of a task
  716.  * Parm : 
  717.  *             -> database pointer
  718.  *             -> index of the record
  719.  *             -> action
  720.  * Out  : 
  721.  * Auth : lb, 03.08.2000
  722.  * Rem  : bad err handling
  723.  * TODO : better error handling
  724.  ***************************************************************************/
  725. pgErr TaskSetActionState(DmOpenRef dbP, UInt16 index, Boolean action)
  726. {
  727.     MemHandle h;
  728.     TaskRecordType *p;
  729.     UInt8 completed;
  730.  
  731.     h = DmGetRecord(dbP, index);
  732.     p = MemHandleLock(h);
  733.     completed = p->completed;
  734.  
  735.     // compute a value for completed
  736.     if (action)
  737.     {
  738.         if (completed < ACTION)
  739.         {
  740.             completed = completed == 10 ? ACTION_OK : ACTION_NO;
  741.         }
  742.     }
  743.     else
  744.     {
  745.         if (completed > ACTION)
  746.         {
  747.             completed = completed == ACTION_OK ? 10 : 0;
  748.         }
  749.     }
  750.  
  751.     DmWrite(p, OffsetOf(TaskRecordType, completed), &completed, sizeof(UInt8));
  752.     MemHandleUnlock(h);
  753.     DmReleaseRecord(dbP, index, true);
  754.     return pgOK;
  755. } // pgErr TaskSetActionState(DmOpenRef dbP, UInt16 index, Boolean action)
  756.  
  757.  
  758.  
  759. /****************************************************************************
  760.  * Name : TaskGetCompleted
  761.  * Desc : get completed value of a task
  762.  * Parm : 
  763.  *             -> database pointer
  764.  *             -> index of the record
  765.  * Out  : 
  766.  * Auth : lb, 04.08.2000
  767.  * Rem  : bad err handling
  768.  * TODO : better error handling
  769.  ***************************************************************************/
  770. UInt8 TaskGetCompleted(DmOpenRef dbP, UInt16 index)
  771. {
  772.     MemHandle h;
  773.     TaskRecordType *p;
  774.     UInt8 value;
  775.  
  776.     h = DmQueryRecord(dbP, index);
  777.     p = MemHandleLock(h);
  778.     value = p->completed;
  779.     MemHandleUnlock(h);
  780.     return value;
  781. } // UInt8 TaskGetCompleted(DmOpenRef dbP, UInt16 index)
  782.  
  783.  
  784.  
  785. /****************************************************************************
  786.  * Name : TaskSetCompleted
  787.  * Desc : set completed value of a task
  788.  * Parm : 
  789.  *             -> database pointer
  790.  *             -> index of the record
  791.  *             -> value
  792.  * Out  : 
  793.  * Auth : lb, 04.08.2000
  794.  * Rem  : bad err handling
  795.  * TODO : better error handling
  796.  ***************************************************************************/
  797. pgErr TaskSetCompleted(DmOpenRef dbP, UInt16 index, UInt8 value)
  798. {
  799.     MemHandle h;
  800.     TaskRecordType *p;
  801.  
  802.     h = DmGetRecord(dbP, index);
  803.     p = MemHandleLock(h);
  804.     DmWrite(p, OffsetOf(TaskRecordType, completed), &value, sizeof(UInt8));
  805.     MemHandleUnlock(h);
  806.     DmReleaseRecord(dbP, index, true);
  807.     return pgOK;
  808. } // pgErr TaskSetCompleted(DmOpenRef dbP, UInt16 index, UInt8 value)
  809.  
  810.  
  811.  
  812. /****************************************************************************
  813.  * Name : TaskGetIsDone
  814.  * Desc : true if the task is 100% done or ACTION_OK
  815.  * Parm : 
  816.  *             -> database pointer
  817.  *             -> index of the record
  818.  * Out  : true if the task is 100% done or ACTION_OK
  819.  * Auth : lb, 09.08.2000
  820.  * Rem  : bad err handling
  821.  * TODO : better error handling
  822.  ***************************************************************************/
  823. Boolean TaskGetIsDone(DmOpenRef dbP, UInt16 index)
  824. {
  825.     MemHandle h;
  826.     TaskRecordType *p;
  827.     UInt8 value;
  828.  
  829.     h = DmQueryRecord(dbP, index);
  830.     p = MemHandleLock(h);
  831.     value = p->completed;
  832.     MemHandleUnlock(h);
  833.     return (value == 10) || (value == ACTION_OK);
  834. } // Boolean TaskGetIsDone(DmOpenRef dbP, UInt16 index)
  835.  
  836.  
  837.  
  838. /****************************************************************************
  839.  * Name : TaskGetActionState
  840.  * Desc : get action state of a task
  841.  * Parm : 
  842.  *             -> database pointer
  843.  *             -> index of the record
  844.  * Out  : action status
  845.  * Auth : lb, 03.08.2000
  846.  * Rem  : bad err handling
  847.  * TODO : better error handling
  848.  ***************************************************************************/
  849. Boolean TaskGetActionState(DmOpenRef dbP, UInt16 index)
  850. {
  851.     MemHandle h;
  852.     TaskRecordType *p;
  853.     UInt8 completed;
  854.  
  855.     h = DmQueryRecord(dbP, index);
  856.     p = MemHandleLock(h);
  857.     completed = p->completed;
  858.     MemHandleUnlock(h);
  859.     return completed > ACTION;
  860. } // Boolean TaskGetActionState(DmOpenRef dbP, UInt16 index)
  861.  
  862.  
  863.  
  864. /****************************************************************************
  865.  * Name : TaskSetDueDate
  866.  * Desc : set the due date of a task
  867.  * Parm : 
  868.  *             -> database pointer
  869.  *             -> index of the record
  870.  *             -> date
  871.  * Out  : 
  872.  * Auth : lb, 06.08.2000
  873.  * Rem  : bad err handling
  874.  * TODO : better error handling
  875.  ***************************************************************************/
  876. pgErr TaskSetDueDate(DmOpenRef dbP, UInt16 index, DateType date)
  877. {
  878.     MemHandle h;
  879.     TaskRecordType *p;
  880.  
  881.     h = DmGetRecord(dbP, index);
  882.     if (h)
  883.     {
  884.         p = MemHandleLock(h);
  885.         if (p)
  886.             DmWrite(p, OffsetOf(TaskRecordType, dueDate), &date, sizeof(DateType));
  887.         MemHandleUnlock(h);
  888.     }
  889.  
  890.     DmReleaseRecord(dbP, index, true);
  891.     return pgOK;
  892. } // pgErr TaskSetDueDate(DmOpenRef dbP, UInt16 index, DateType date)
  893.  
  894.  
  895.  
  896. /****************************************************************************
  897.  * Name : TaskGetDueDate
  898.  * Desc : get the due date of a task
  899.  * Parm : 
  900.  *             -> database pointer
  901.  *             -> index of the record
  902.  * Out  : 
  903.  * Auth : lb, 03.08.2000
  904.  * Rem  : bad err handling
  905.  * TODO : better error handling
  906.  ***************************************************************************/
  907. DateType TaskGetDueDate(DmOpenRef dbP, UInt16 index)
  908. {
  909.     MemHandle h;
  910.     TaskRecordType *p;
  911.     DateType date;
  912.  
  913.     h = DmQueryRecord(dbP, index);
  914.     if (h)
  915.     {
  916.         p = MemHandleLock(h);
  917.         if (p)
  918.             date = p->dueDate;
  919.         MemHandleUnlock(h);
  920.     }
  921.  
  922.     return date;
  923. } // void TaskGetDueDate(DmOpenRef dbP, UInt16 index)
  924.  
  925.  
  926.  
  927. /****************************************************************************
  928.  * Name : TaskSetNote
  929.  * Desc : set the note of a task
  930.  * Parm : 
  931.  *             -> database pointer
  932.  *             -> index of the record
  933.  *             -> pointer to the note (will be copied)
  934.  * Out  : 
  935.  * Auth : lb, 22.08.2000
  936.  * TODO : better error handling
  937.  ***************************************************************************/
  938. pgErr TaskSetNote(DmOpenRef dbP, UInt16 index, Char* note)
  939. {
  940.     MemHandle h, hNew;
  941.     TaskRecordType *p, *pNew;
  942.     UInt32 size, uniqueID;
  943.     TaskFormatType format;
  944.     UInt16 attr, newIndex = DmNumRecords(dbP);
  945.     MemPtr extraBlock = NULL;
  946.     UInt32 extraSize;
  947.  
  948.     extraSize = TaskGetExtraBlock(dbP, index, NULL);
  949.  
  950.     if (extraSize)
  951.     {
  952.         extraBlock = MemPtrNew(extraSize);
  953.         TaskGetExtraBlock(dbP, index, extraBlock);
  954.     }
  955.  
  956.     h = DmQueryRecord(dbP, index);
  957. #ifdef __PG_EXTRA_CHECK__
  958.     if (!h)
  959.         return pgError;
  960. #endif
  961.     p = MemHandleLock(h);
  962.     size = TaskRecordTypeSize + StrLen(&p->description) + StrLen(note)
  963.         + extraSize;
  964.  
  965.     hNew = DmNewRecord(dbP, &newIndex, size);
  966.  
  967.     if (!hNew)
  968.     {
  969.         FrmCustomAlert(AltEmpty, 
  970.             "No space to store the task. Please free some memory and retry.",
  971.             "", "");
  972.         return pgError;
  973.     }
  974.  
  975.     pNew = MemHandleLock(hNew);
  976.  
  977.     // since we created a record, get the old one more time (he was just
  978.     // queried)
  979.     MemHandleUnlock(h);
  980.     p = MemHandleLock(h);
  981.  
  982.     DmWrite(pNew, 0, p, sizeof(TaskRecordType) - 1);
  983.  
  984.     DmStrCopy(pNew, OffsetOf(TaskRecordType, description), &p->description);
  985.     DmStrCopy(pNew, 
  986.         OffsetOf(TaskRecordType, description) + StrLen(&pNew->description) + 1,
  987.         note);
  988.  
  989.     format = p->format.bits;
  990.     format.hasNote = *note ? 1 : 0;
  991.     DmWrite(pNew, OffsetOf(TaskRecordType, format), &format, sizeof(UInt16));
  992.  
  993.     if (extraSize)
  994.     {
  995.         DmWrite(pNew,
  996.             OffsetOf(TaskRecordType, description) + StrLen(&pNew->description)
  997.             + StrLen(note) + 2,
  998.             extraBlock, extraSize);
  999.         
  1000.         MemPtrFree(extraBlock);
  1001.     }
  1002.  
  1003.     MemHandleUnlock(hNew);
  1004.     MemHandleUnlock(h);
  1005.     DmReleaseRecord(dbP, DmNumRecords(dbP) - 1, true);
  1006.  
  1007.     // to allow sync
  1008.     // get the unique ID of original task
  1009.     DmRecordInfo(dbP, index, &attr, &uniqueID, NULL);
  1010.     // delete original task
  1011.     DmRemoveRecord(dbP, index);
  1012.     // move the new task to the good index
  1013.     DmMoveRecord(dbP, DmNumRecords(dbP) - 1, index);
  1014.     // set the unique ID of the new task
  1015.     DmSetRecordInfo(dbP, index, &attr, &uniqueID);
  1016.  
  1017.     return pgOK;
  1018.  
  1019. } // pgErr TaskSetNote(DmOpenRef dbP, UInt16 index, Char* note)
  1020.  
  1021.  
  1022.  
  1023. /****************************************************************************
  1024.  * Name : TaskGetDescription
  1025.  * Desc : get the description of a task
  1026.  * Parm : 
  1027.  *             -> database pointer
  1028.  *             -> index of the record
  1029.  * Out  : pointer to the desc, use it immediately, it could becomme invalid
  1030.  *           reading only !!!
  1031.  * Auth : lb, 22.09.2000
  1032.  *        seagull, 9.10.2000
  1033.  *           - allocate tmp buffer (because unlocked ptr make warnning
  1034.  *             under POSE)
  1035.  *           - support direct linked task.
  1036.  ***************************************************************************/
  1037. Char* TaskGetDescription(DmOpenRef dbP, UInt16 index)
  1038. {
  1039.     char* desc = NULL;
  1040.     MemHandle h = NULL;
  1041.     TaskExtendedRecordType* pTask;
  1042.  
  1043.     h = DmQueryRecord(dbP, index);
  1044.     if (h)
  1045.     {
  1046.         pTask = MemHandleLock(h);
  1047.         if (pTask)
  1048.         {
  1049.             desc = TaskGetDescriptionByTaskPtr(pTask);
  1050.             MemHandleUnlock(h);
  1051.         }
  1052.     }
  1053.     return desc;
  1054. } // Char* TaskGetDescription(DmOpenRef dbP, UInt16 index)
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060. /****************************************************************************
  1061.  * Name : TaskGetDescriptionByTaskPtr
  1062.  * Desc : get the description of a task
  1063.  * Parm : 
  1064.  *             -> Task pointer
  1065.  * Out  : pointer to the desc. must free by caller.
  1066.  * Auth : seagull, 9.10.2000
  1067.  ***************************************************************************/
  1068. Char* TaskGetDescriptionByTaskPtr(TaskExtendedRecordType* pTask)
  1069. {
  1070.     DmOpenRef db = NULL;
  1071.     MemHandle hLink = NULL;
  1072.     char* desc = NULL;
  1073.     char* result = NULL;
  1074.  
  1075.     if (pTask->format.bits.extendedType)
  1076.     {
  1077.         UInt16 index;
  1078.         UInt16 attr;
  1079.         AddrDBRecordType item;
  1080.         
  1081.         if (pTask->format.bits.isMemo)
  1082.         {
  1083.             if (! MemoGetDatabase(&db, dmModeReadOnly) &&
  1084.                 ! DmFindRecordByID(db, pTask->fields.link.uniqueID, &index) &&
  1085.                 ! DmRecordInfo(db, index, &attr, NULL, NULL) &&
  1086.                 ! (attr & dmRecAttrDelete)  )
  1087.             {
  1088.                 hLink = DmQueryRecord(db, index);
  1089.                 desc = MemHandleLock(hLink);
  1090.             }
  1091.         }
  1092.         else if (pTask->format.bits.isContact)
  1093.         {
  1094.             if (! AddrGetDatabase(&db, dmModeReadWrite) &&
  1095.                 ! DmFindRecordByID(db, pTask->fields.link.uniqueID, &index) &&
  1096.                 ! DmRecordInfo(db, index, &attr, NULL, NULL) &&
  1097.                 ! (attr & dmRecAttrDelete)  )
  1098.             {
  1099.                 AddrGetRecord(db, index, &item, &hLink);
  1100.                 desc = item.fields[name];
  1101.             }
  1102.         }
  1103.     }
  1104.     else
  1105.         desc = &pTask->fields.task.description;
  1106.     
  1107.     if (desc)
  1108.     {
  1109.         UInt16 len;
  1110.         char* pp = desc;
  1111.         while (*pp && *pp != '\n') pp++;
  1112.         len = pp - desc;
  1113.         
  1114.         result = MemPtrNew(len + 1);
  1115.         MemMove(result, desc, len);
  1116.         result[len] = '\0';
  1117.     }
  1118.     
  1119.     if (db) DmCloseDatabase(db);
  1120.     if (hLink) MemHandleUnlock(hLink);
  1121.  
  1122.     return result;
  1123. }
  1124.  
  1125.  
  1126.  
  1127.  
  1128. /****************************************************************************
  1129.  * Name : TaskGetNote
  1130.  * Desc : set the note of a task
  1131.  * Parm : 
  1132.  *             -> database pointer
  1133.  *             -> index of the record
  1134.  * Out  : pointer to the note, use it immediately, it could becomme invalid
  1135.  *           reading only !!!
  1136.  * Auth : lb, 22.08.2000
  1137.  * TODO : better error handling
  1138.  ***************************************************************************/
  1139. Char* TaskGetNote(DmOpenRef dbP, UInt16 index)
  1140. {
  1141.     MemHandle h;
  1142.     TaskRecordType *p;
  1143.     Char* note = NULL;
  1144.  
  1145.     h = DmQueryRecord(dbP, index);
  1146.     if (h)
  1147.     {
  1148.         p = MemHandleLock(h);
  1149.         if (!p)
  1150.             return NULL;
  1151.         note = &p->description;
  1152.         // go to the note field
  1153.         note += StrLen(note) + 1;
  1154.         if (note > (Char*)p + MemHandleSize(h))
  1155.         {
  1156.             MemHandleUnlock(h);
  1157.             return NULL;
  1158.         }
  1159.         MemHandleUnlock(h);
  1160.     }
  1161.     return note;
  1162. } // Char* TaskGetNote(DmOpenRef dbP, UInt16 index)
  1163.  
  1164.  
  1165.  
  1166.  
  1167. /****************************************************************************
  1168.  * Name : TaskSetExtraBlockHeadPtr
  1169.  * Desc : get the given extra block of the given task
  1170.  * Parm : 
  1171.  *             -> the task
  1172.  * Out  : 
  1173.  * Auth : lb, 31.08.2000
  1174.  *        seagull, 10.10.2000
  1175.  ***************************************************************************/
  1176. static MemPtr TaskGetExtraBlockHeadPtr(TaskExtendedRecordType* pTask)
  1177. {
  1178.     Char* pExtra;
  1179.  
  1180.     if (pTask->format.bits.extendedType)
  1181.         pExtra = &pTask->fields.link.dbName;
  1182.     else
  1183.         pExtra = &pTask->fields.task.description +
  1184.             StrLen(&pTask->fields.task.description) + 1;
  1185.     pExtra += StrLen(pExtra) + 1;
  1186.     return (MemPtr)pExtra;
  1187. } // static MemPtr TaskGetExtraBlockHeadPtr(TaskExtendedType* pTask)
  1188.  
  1189.  
  1190. /****************************************************************************
  1191.  * Name : TaskSetExtraBlock
  1192.  * Desc : set the given extra block to the given task
  1193.  * Parm : 
  1194.  *             -> database pointer
  1195.  *             -> index of the record
  1196.  *             -> pointer to the block
  1197.  *             -> size of the block    (pass 0 to remove)
  1198.  * Out  : 
  1199.  * Auth : lb, 31.08.2000
  1200.  *        seagull, 10.10.2000
  1201.  ***************************************************************************/
  1202. pgErr TaskSetExtraBlock(DmOpenRef dbP, UInt16 index, MemPtr s, UInt32 size)
  1203. {
  1204.     MemHandle h;
  1205.     TaskExtendedRecordType* p;
  1206.     UInt16 sizeBase;
  1207.  
  1208.     // find and lock it's record
  1209.     h = DmQueryRecord(dbP, index);
  1210. #ifdef __PG_EXTRA_CHECK__
  1211.     if (!h) return pgError;
  1212. #endif
  1213.     p = MemHandleLock(h);
  1214.  
  1215.     sizeBase = (UInt8*)TaskGetExtraBlockHeadPtr(p) - (UInt8*)p;
  1216.  
  1217.     //
  1218.     MemHandleUnlock(h);
  1219.     h = DmResizeRecord(dbP, index, sizeBase + size);
  1220.     if (! h)
  1221.         MessageBox(StrNoMemorySpaces);
  1222.     else
  1223.     {
  1224.         if (size != 0)
  1225.         { // write new extra block
  1226.             h = DmGetRecord(dbP, index);
  1227.             p = MemHandleLock(h);
  1228.             DmWrite(p, sizeBase, s, size);
  1229.             MemHandleUnlock(h);
  1230.             DmReleaseRecord(dbP, index, true);
  1231.         }
  1232.     }
  1233.  
  1234.     return pgOK;
  1235. } // pgErr TaskSetExtraBlock(DmOpenRef dbP, UInt16 index, MemPtr s, UInt32 size)
  1236.  
  1237.  
  1238.  
  1239. /****************************************************************************
  1240.  * Name : TaskGetExtraBlock
  1241.  * Desc : get the given extra block of the given task
  1242.  * Parm : 
  1243.  *             -> database pointer
  1244.  *             -> index of the record
  1245.  *             -> pointer to the block, pass NULL if you don't want it
  1246.  * Out  : size of the block
  1247.  * Auth : lb, 31.08.2000
  1248.  * Rem  : gives size = 0 if no extra block
  1249.  ***************************************************************************/
  1250. UInt32 TaskGetExtraBlock(DmOpenRef dbP, UInt16 index, MemPtr dest)
  1251. {
  1252.     MemHandle h;
  1253.     TaskExtendedRecordType* pTask;
  1254.     MemPtr pExtra;
  1255.     UInt32 sizeExtra;
  1256.  
  1257.     h = DmQueryRecord(dbP, index);
  1258.     pTask = MemHandleLock(h);
  1259.     pExtra = TaskGetExtraBlockHeadPtr(pTask);
  1260.     sizeExtra = (UInt8*)pTask + MemPtrSize(pTask) - (UInt8*)pExtra;
  1261.     if (sizeExtra && dest)
  1262.         MemMove(dest, pExtra, sizeExtra); // ??? miss alignment ???
  1263.  
  1264.     MemHandleUnlock(h);
  1265.  
  1266.     return sizeExtra;
  1267. } // UInt32 TaskGetExtraBlock(DmOpenRef dbP, UInt16 index, MemPtr dest)
  1268.  
  1269.  
  1270.  
  1271. /****************************************************************************
  1272.  * Name : TaskGetToDoUniqueID
  1273.  * Desc : get the uniqueID of the sync ToDo task
  1274.  * Parm : 
  1275.  *             -> database pointer
  1276.  *             -> index of the record
  1277.  * Out  : uniqueID
  1278.  * Auth : lb, 31.08.2000
  1279.  ***************************************************************************/
  1280. UInt32 TaskGetToDoUniqueID(DmOpenRef dbP, UInt16 index)
  1281. {
  1282.     UInt32 uniqueID;
  1283.     UInt16 size = sizeof(uniqueID);
  1284.     if (! TaskGetFormat(dbP, index).hasToDo)
  1285.         return 0;
  1286.  
  1287.     if (pgOK != TaskGetExtraChunk(dbP, index, 
  1288.                                   Extra_Link_ToDo, 0xff,
  1289.                                   (MemPtr)&uniqueID, &size) )
  1290.         return 0;
  1291.  
  1292.     return uniqueID;
  1293. } // UInt32 TaskGetToDoUniqueID(DmOpenRef dbP, UInt16 index)
  1294.  
  1295.  
  1296.  
  1297. /****************************************************************************
  1298.  * Name : TaskCopyExtraBlock
  1299.  * Desc : copy an extra block from a task to another
  1300.  * Parm : 
  1301.  *             -> database pointer
  1302.  *             -> index of the source record
  1303.  *             -> index of the destination record
  1304.  * Out  : 
  1305.  * Auth : lb, 31.08.2000
  1306.  * Rem  : 
  1307.  ***************************************************************************/
  1308. pgErr TaskCopyExtraBlock(DmOpenRef dbP, UInt16 source, UInt16 dest)
  1309. {
  1310.     MemPtr extraBlock;
  1311.     UInt32 extraSize;
  1312.     pgErr status = pgOK;
  1313.  
  1314.     extraSize = TaskGetExtraBlock(dbP, source, NULL);
  1315.     if (extraSize)
  1316.     {
  1317.         extraBlock = MemPtrNew(extraSize);
  1318.  
  1319.         if (!extraBlock)
  1320.             return pgError;
  1321.  
  1322.         TaskGetExtraBlock(dbP, source, extraBlock);
  1323.         status = TaskSetExtraBlock(dbP, dest, extraBlock, extraSize);
  1324.  
  1325.         MemPtrFree(extraBlock);
  1326.     }
  1327.  
  1328.     return status;
  1329.  
  1330. } // pgErr TaskCopyExtraBlock(DmOpenRef dbP, UInt16 source, UInt16 dest)
  1331.  
  1332.  
  1333.  
  1334. /****************************************************************************
  1335.  * Name : TaskInputDueDate
  1336.  * Desc : ask user for a due date
  1337.  * Parm : 
  1338.  *             -> database pointer
  1339.  *             -> index of the record
  1340.  * Out  : 
  1341.  * Auth : lb, 03.08.2000
  1342.  * Rem  : bad err handling
  1343.  * TODO : better error handling
  1344.  ***************************************************************************/
  1345. pgErr TaskInputDueDate(DmOpenRef dbP, UInt16 index)
  1346. {
  1347.     TaskRecordType *p;
  1348.     MemHandle h;
  1349.     DateType date;
  1350.     Boolean selected;
  1351.     UInt16 month, day, year;
  1352.  
  1353.     date = TaskGetDueDate(dbP, index);
  1354.     if (date.month == 0)
  1355.     {
  1356.         date = gToday;
  1357.     }
  1358.  
  1359.     month = date.month;
  1360.     day = date.day;
  1361.     year = date.year + YEAR_OFFSET; // year offset
  1362.     selected = SelectDay(selectDayByDay, &month, &day, &year, "Choose a due date");
  1363.     if (selected)
  1364.     {
  1365.         date.month = month;
  1366.         date.day = day;
  1367.         date.year = year - YEAR_OFFSET;
  1368.         h = DmGetRecord(dbP, index);
  1369.         p = MemHandleLock(h);
  1370.         DmWrite(p, OffsetOf(TaskRecordType, dueDate), &date, sizeof(DateType));
  1371.         MemHandleUnlock(h);
  1372.         DmReleaseRecord(dbP, index, true);
  1373.     }
  1374.     return pgOK;
  1375. } // pgErr TaskInputDueDate(DmOpenRef dbP, UInt16 index)
  1376.  
  1377.  
  1378.  
  1379. /****************************************************************************
  1380.  * Name : TaskSave
  1381.  * Desc : save a record (copy it and create as last index)
  1382.  * In   : 
  1383.  *             -> record to save
  1384.  * Out  : 
  1385.  * Auth : lb, 03.08.2000
  1386.  * Rem  : doesn't handle err codes
  1387.  * Mod  : lb, 07.09.2000
  1388.  *             - keep the same uniqueID and attr
  1389.  ***************************************************************************/
  1390. pgErr TaskSave(UInt16 index)
  1391. {
  1392.     MemHandle hNew, hOld;
  1393.     TaskRecordType *pNew, *pOld;
  1394.     UInt32 size = TaskRecordTypeSize, uniqueID;
  1395.     UInt16 realIndex = dmMaxRecordIndex, attr;
  1396.  
  1397.     // get a handle on the record to save
  1398.     hOld = DmQueryRecord(gdbP, index);
  1399.  
  1400.     // calc the needed size
  1401.     size = MemHandleSize(hOld);
  1402.  
  1403.     // get a handle on a newly created record
  1404.     hNew = DmNewRecord(gdbP, &realIndex, size);
  1405.  
  1406.     // get a pointer on the record
  1407.     pNew = MemHandleLock(hNew);
  1408.  
  1409.     // get a pointer on it
  1410.     pOld = MemHandleLock(hOld);
  1411.  
  1412.     // write the data
  1413.     DmWrite(pNew, 0, pOld, size);
  1414.  
  1415.     // unlock the pointers
  1416.     MemHandleUnlock(hNew);
  1417.     MemHandleUnlock(hOld);
  1418.  
  1419.     // unlock the record
  1420.     DmReleaseRecord(gdbP, realIndex, true);
  1421.  
  1422.     // to allow sync
  1423.     // get the unique ID of original task
  1424.     DmRecordInfo(gdbP, index, &attr, &uniqueID, NULL);
  1425.     // set the unique ID of the new task
  1426.     DmSetRecordInfo(gdbP, realIndex, &attr, &uniqueID);
  1427.     return pgOK;
  1428. } // pgErr TaskSave(UInt16 index)
  1429.  
  1430.  
  1431.  
  1432. /****************************************************************************
  1433.  * Name : TaskGetSaved
  1434.  * Desc : get the saved record (copy from last index)
  1435.  * In   : 
  1436.  *             -> index to put saved record
  1437.  * Out  : 
  1438.  * Auth : lb, 03.08.2000
  1439.  * Rem  : doesn't handle err codes
  1440.  * Mod  : lb, 07.09.2000
  1441.  *             - keep the same uniqueID and attr
  1442.  ***************************************************************************/
  1443. pgErr TaskGetSaved(UInt16 index)
  1444. {
  1445.     MemHandle hNew, hOld;
  1446.     TaskRecordType *pNew, *pOld;
  1447.     UInt32 size = TaskRecordTypeSize, uniqueID;
  1448.     UInt16 attr;
  1449.  
  1450.     // get a handle on the saved record
  1451.     hOld = DmQueryRecord(gdbP, DmNumRecords(gdbP) - 1);
  1452.  
  1453.     // calc the needed size
  1454.     size = MemHandleSize(hOld);
  1455.  
  1456.     // get a handle on a newly created record
  1457.     hNew = DmNewRecord(gdbP, &index, size);
  1458.  
  1459.     // get a pointer on the record
  1460.     pNew = MemHandleLock(hNew);
  1461.  
  1462.     // get a pointer on it
  1463.     pOld = MemHandleLock(hOld);
  1464.  
  1465.     // write the data
  1466.     DmWrite(pNew, 0, pOld, size);
  1467.  
  1468.     // unlock the pointers
  1469.     MemHandleUnlock(hNew);
  1470.     MemHandleUnlock(hOld);
  1471.  
  1472.     // unlock the record
  1473.     DmReleaseRecord(gdbP, index, true);
  1474.  
  1475.     // to allow sync
  1476.     // get the unique ID of original task
  1477.     DmRecordInfo(gdbP, DmNumRecords(gdbP)-1, &attr, &uniqueID, NULL);
  1478.     // set the unique ID of the new task
  1479.     DmSetRecordInfo(gdbP, index, &attr, &uniqueID);
  1480.  
  1481.     // remove saved record
  1482.     DmRemoveRecord(gdbP, DmNumRecords(gdbP) - 1);
  1483.  
  1484.     // remove replaced record
  1485.     DmRemoveRecord(gdbP, index + 1);
  1486.  
  1487.     return pgOK;
  1488. } // pgErr TaskGetSaved(UInt16 index)
  1489.  
  1490.  
  1491.  
  1492. /****************************************************************************
  1493.  * Name : TaskRemoveSaved
  1494.  * Desc : remove the saved record
  1495.  * In   : 
  1496.  * Out  : 
  1497.  * Auth : lb, 03.08.2000
  1498.  * Rem  : doesn't handle err codes
  1499.  ***************************************************************************/
  1500. pgErr TaskRemoveSaved(void)
  1501. {
  1502.     // remove replaced record
  1503.     DmRemoveRecord(gdbP, DmNumRecords(gdbP) - 1);
  1504.     return pgOK;
  1505. } // pgErr TaskRemoveSaved(void)
  1506.  
  1507.  
  1508.  
  1509. /****************************************************************************
  1510.  * Name : TaskRemove
  1511.  * Desc : remove a task and all its children
  1512.  * In   : 
  1513.  *             -> index of the task to remove
  1514.  * Out  : 
  1515.  * Auth : lb, 03.08.2000
  1516.  * Rem  : doesn't handle err codes
  1517.  ***************************************************************************/
  1518. pgErr TaskRemove(DmOpenRef dbP, UInt16 index)
  1519. {
  1520.     Boolean stillChild = false;
  1521.     // as long as I have a child, remove it
  1522.     while (TaskGetHasChild(dbP, index))
  1523.     {
  1524.         TaskRemove(dbP, index + 1);
  1525.     }
  1526.  
  1527.     if (TaskGetHasNext(dbP, index))
  1528.     {
  1529.         if (!TaskGetHasPrev(dbP, index))
  1530.         {
  1531.             TaskSetHasPrev(dbP, index + 1, false);
  1532.         }
  1533.         stillChild = true;
  1534.     }
  1535.  
  1536.     if (TaskGetHasPrev(dbP, index))
  1537.     {
  1538.         if (!TaskGetHasNext(dbP, index))
  1539.         {
  1540.             TaskSetHasNext(dbP, TaskGetPrevIndex(dbP, index), false);
  1541.         }
  1542.         stillChild = true;
  1543.     }
  1544.  
  1545.     if (!stillChild)
  1546.     {
  1547.         if (TaskGetLevel(dbP, index) != 1)
  1548.         {
  1549.             TaskSetHasChild(dbP, TaskGetFatherIndex(dbP, index), false);
  1550.         }
  1551.     }
  1552.  
  1553.     // then, remove me
  1554.     DmRemoveRecord(dbP, index);
  1555.     return pgOK;
  1556. } // pgErr TaskRemove(DmOpenRef dbP, UInt16 index)
  1557.  
  1558.  
  1559.  
  1560. /****************************************************************************
  1561.  * Name : TaskRemoveDone
  1562.  * Desc : remove all done tasks
  1563.  * In   : 
  1564.  * Out  : 
  1565.  * Auth : lb, 29.08.2000
  1566.  * Rem  : doesn't handle err codes
  1567.  ***************************************************************************/
  1568. pgErr TaskRemoveChildren(DmOpenRef dbP, UInt16 index)
  1569. {
  1570.     // as long as I have a child, remove it
  1571.     while (TaskGetHasChild(dbP, index))
  1572.     {
  1573.         TaskRemove(dbP, index + 1);
  1574.     }
  1575.  
  1576.     TaskSetHasChild(gdbP, index, false);
  1577.  
  1578.     return pgOK;
  1579. } // pgErr TaskRemoveChildren(DmOpenRef dbP, UInt16 index)
  1580.  
  1581.  
  1582.  
  1583. /****************************************************************************
  1584.  * Name : TaskRemoveDone
  1585.  * Desc : remove all done tasks
  1586.  * In   : 
  1587.  * Out  : 
  1588.  * Auth : lb, 29.08.2000
  1589.  * Rem  : doesn't handle err codes
  1590.  ***************************************************************************/
  1591. pgErr TaskRemoveDone(DmOpenRef dbP)
  1592. {
  1593.     UInt16 i = 1, status;
  1594.     while (i < DmNumRecords(dbP))
  1595.     {
  1596.         if (((status = TaskGetCompleted(dbP, i)) == 10) || 
  1597.             (status == ACTION_OK))
  1598.         {
  1599.             TaskRemove(dbP, i);
  1600.         }
  1601.         else
  1602.         {
  1603.             i++;
  1604.         }
  1605.     }
  1606.     return pgOK;
  1607. } // pgErr TaskRemoveDone(DmOpenRef dbP)
  1608.  
  1609.  
  1610.  
  1611. /****************************************************************************
  1612.  * Name : TaskRemoveDoneChildren
  1613.  * Desc : remove all done tasks in the children of given task
  1614.  * In   : 
  1615.  * Out  : 
  1616.  * Auth : lb, 29.08.2000
  1617.  * Rem  : doesn't handle err codes
  1618.  ***************************************************************************/
  1619. pgErr TaskRemoveDoneChildren(DmOpenRef dbP, UInt16 index)
  1620. {
  1621.     UInt16 i = index + 1, status, refLevel = TaskGetLevel(dbP, index);
  1622.     while (i < DmNumRecords(dbP) && TaskGetLevel(dbP, i) > refLevel)
  1623.     {
  1624.         if (((status = TaskGetCompleted(dbP, i)) == 10) || 
  1625.             (status == ACTION_OK))
  1626.         {
  1627.             TaskRemove(dbP, i);
  1628.         }
  1629.         else
  1630.         {
  1631.             i++;
  1632.         }
  1633.     }
  1634.     return pgOK;
  1635. } // pgErr TaskRemoveDoneChildren(DmOpenRef dbP, UInt16 index)
  1636.  
  1637.  
  1638.  
  1639. /****************************************************************************
  1640.  * Name : TaskExpandAll
  1641.  * Desc : set opened flag for all tasks
  1642.  * In   : 
  1643.  * Out  : 
  1644.  * Auth : lb, 04.08.2000
  1645.  * Rem  : doesn't handle err codes
  1646.  ***************************************************************************/
  1647. pgErr TaskExpand(DmOpenRef dbP, UInt16 index)
  1648. {
  1649.     UInt16 i, num;
  1650.     UInt8 level;
  1651.  
  1652.     level = TaskGetLevel(dbP, index);
  1653.     num = DmNumRecords(dbP);
  1654.     TaskSetOpened(dbP, index, true);
  1655.     for (i = index + 1; i < num && TaskGetLevel(dbP, i) > level; i++)
  1656.     {
  1657.         TaskSetOpened(dbP, i, true);
  1658.     }
  1659.     return pgOK;
  1660. } // pgErr TaskExpand(DmOpenRef dbP, UInt16 index)
  1661.  
  1662.  
  1663.  
  1664. /****************************************************************************
  1665.  * Name : TaskCollapseAll
  1666.  * Desc : unset opened flag for all tasks
  1667.  * In   : 
  1668.  * Out  : 
  1669.  * Auth : lb, 04.08.2000
  1670.  * Rem  : doesn't handle err codes
  1671.  ***************************************************************************/
  1672. pgErr TaskCollapse(DmOpenRef dbP, UInt16 index)
  1673. {
  1674.     UInt16 i, num;
  1675.     UInt8 level;
  1676.  
  1677.     level = TaskGetLevel(dbP, index);
  1678.     num = DmNumRecords(dbP);
  1679.  
  1680.     // don't collapse task 0 !!!
  1681.     if (index != 0)
  1682.     {
  1683.         TaskSetOpened(dbP, index, false);
  1684.     }
  1685.  
  1686.     for (i = index + 1; i < num && TaskGetLevel(dbP, i) > level; i++)
  1687.     {
  1688.         // don't collapse a task without child, or it'll be closed
  1689.         // when it becomes a child
  1690.         if (TaskGetHasChild(dbP, i))
  1691.         {
  1692.             TaskSetOpened(dbP, i, false);
  1693.         }
  1694.     }
  1695.     return pgOK;
  1696. } // pgErr TaskCollapse(DmOpenRef dbP, UInt16 index)
  1697.  
  1698.  
  1699.  
  1700. /****************************************************************************
  1701.  * Name : TaskCalcCompleted
  1702.  * Desc : calc and set completed by mean of the children
  1703.  * In   : 
  1704.  *             -> database pointer
  1705.  *             -> index of father to calc
  1706.  * Out  : 
  1707.  * Auth : lb, 04.08.2000
  1708.  * Rem  : doesn't handle err codes
  1709.  *           warning : this one doesn't recurse down but UP ! You must call is
  1710.  *                       on a father whose children are up to date !
  1711.  ***************************************************************************/
  1712. pgErr TaskCalcCompleted(DmOpenRef dbP, UInt16 index)
  1713. {
  1714.     UInt16 mean = 0, num = 0, tmp;
  1715.     UInt16 subtask;
  1716.     UInt8  level;
  1717.  
  1718.     if (!TaskGetHasChild(dbP, index))
  1719.         return pgError;
  1720.  
  1721.     level = TaskGetLevel(dbP, index);
  1722.  
  1723.     subtask = index + 1;
  1724.     while (subtask)
  1725.     {
  1726.         tmp = TaskGetCompleted(dbP, subtask);
  1727.         if (tmp > ACTION)
  1728.         {
  1729.             // done = 100%, not done = 0%
  1730.             tmp = (tmp == ACTION_OK ? 10 : 0);
  1731.         }
  1732.         mean += tmp;
  1733.         num++;
  1734.  
  1735.         // this one will return 0 if no brother is found
  1736.         subtask = TaskGetNextIndex(dbP, subtask);
  1737.     }
  1738.     TaskSetCompleted(dbP, index, mean / num);
  1739.  
  1740.     // recurse up, calc for the elders
  1741.     if (level > 1)
  1742.     {
  1743.         TaskCalcCompleted(dbP, TaskGetFatherIndex(dbP, index));
  1744.     }
  1745.     return pgOK;
  1746.  
  1747. } // pgErr TaskCalcCompleted(DmOpenRef dbP, UInt16 index)
  1748.  
  1749.  
  1750.  
  1751. /****************************************************************************
  1752.  * Name : TaskCalcCompletedAll
  1753.  * Desc : calc and set completed by mean of the children for all fathers
  1754.  * In   : 
  1755.  *             -> database pointer
  1756.  * Out  : 
  1757.  * Auth : lb, 04.08.2000
  1758.  * Rem  : doesn't handle err codes
  1759.  *           warning : this one can be lengthy !!!!
  1760.  * TODO : optimize it !!!
  1761.  ***************************************************************************/
  1762. pgErr TaskCalcCompletedAll(DmOpenRef dbP)
  1763. {
  1764.     UInt16 i;
  1765.  
  1766.     // children always comes after parents !
  1767.     for (i = DmNumRecords(dbP) - 1; i > 0; i--)
  1768.     {
  1769.         TaskCalcCompleted(dbP, i); // this one controls if i has a child
  1770.     }
  1771.     return pgOK;
  1772.  
  1773. } // pgErr TaskCalcCompletedAll(DmOpenRef dbP)
  1774.  
  1775.  
  1776.  
  1777. /****************************************************************************
  1778.  * Name : TaskToRight
  1779.  * Desc : task becomes a child of previous one
  1780.  * Prm  : index of future child
  1781.  * Out  : 
  1782.  * Auth : lb, 27.07.2000
  1783.  * Mod  : lb, 28.07.2000
  1784.  *             new method, work by index
  1785.  *           lb, 24.08.2000
  1786.  *               fixed a bug when moving right the last task
  1787.  ***************************************************************************/
  1788. pgErr TaskToRight(DmOpenRef dbP, UInt16 index)
  1789. {
  1790.     UInt16 i;
  1791.     UInt8 actualLevel;
  1792.     UInt16 actual;
  1793.     UInt16 numRec = DmNumRecords(dbP);
  1794.  
  1795.     // can't push the first one, he must be a first level one
  1796.     if (index == FIRST_INDEX)
  1797.         return pgError;
  1798.  
  1799.     // can't push more than previous level + 1
  1800.     if (TaskGetLevel(dbP, index - 1) < TaskGetLevel(dbP, index))
  1801.         return pgError;
  1802.  
  1803.     // if actual has no next, modify previous
  1804.     if (!TaskGetHasNext(dbP, index))
  1805.     {
  1806.         TaskSetHasNext(dbP, actual = TaskGetPrevIndex(dbP, index), false);
  1807.     }
  1808.  
  1809.     // actual loose his next
  1810.     TaskSetHasNext(dbP, index, false);
  1811.  
  1812.     // inc level
  1813.     TaskSetLevel(dbP, index, actualLevel = TaskGetLevel(dbP, index) + 1);
  1814.  
  1815.     // if a previous exist
  1816.     if (TaskGetPrevIndex(dbP, index) != dmMaxRecordIndex)
  1817.     {
  1818.         // tell him he has a next
  1819.         TaskSetHasNext(dbP, TaskGetPrevIndex(dbP, index), true);
  1820.         // actual has a prev
  1821.         TaskSetHasPrev(dbP, index, true);
  1822.     }
  1823.     else
  1824.     {
  1825.         // no previous, actual is a first child
  1826.         // update father
  1827.         TaskSetHasChild(dbP, TaskGetFatherIndex(dbP, index), true);
  1828.         // actual has no previous
  1829.         TaskSetHasPrev(dbP, index, false);
  1830.     }
  1831.  
  1832.     // need to update the children
  1833.     if (TaskGetHasChild(dbP, index))
  1834.     {
  1835.         i = index + 1;
  1836.         // all children go to right without other modification
  1837.         while (i < numRec && TaskGetLevel(dbP, i) >= actualLevel)
  1838.         {
  1839.             TaskSetLevel(dbP, i, TaskGetLevel(dbP, i) + 1);
  1840.             i++;
  1841.         }
  1842.     }
  1843.     return pgOK;
  1844. } // pgErr TaskToRight(UInt16 index)
  1845.  
  1846.  
  1847.  
  1848. /****************************************************************************
  1849.  * Name : TaskToLeft
  1850.  * Desc : TODO fill
  1851.  * Prm  : index of item to be push to left
  1852.  * Out  : 
  1853.  * Auth : lb, 31.07.2000
  1854.  * Rem  : 
  1855.  * Mod  : lb, 09.08.2000
  1856.  *             - update gActualTask for continuous moving
  1857.  *           lb, 24.08.2000
  1858.  *               fixed a bug when moving right the last task
  1859.  ***************************************************************************/
  1860. pgErr TaskToLeft(DmOpenRef dbP, UInt16 index)
  1861. {
  1862.     UInt16 i;
  1863.     UInt8 actualLevel;
  1864.     UInt16 prev;
  1865.     UInt16 father;
  1866.     UInt16 newIndex = index;
  1867.     Boolean needMove = false;
  1868.     UInt16 numRec = DmNumRecords(dbP);
  1869.  
  1870.     // can't push the first one, he must be a first level one
  1871.     if (index == FIRST_INDEX)
  1872.         return pgError;
  1873.  
  1874.     // can't push more than level 1
  1875.     if (TaskGetLevel(dbP, index) == FIRST_LEVEL)
  1876.         return pgError;
  1877.  
  1878.     // to gain some time
  1879.     father = TaskGetFatherIndex(dbP, index);
  1880.  
  1881.     // return if I can't find the father or if it's the root
  1882.     if (!father)
  1883.         return pgError;
  1884.  
  1885.     // if previous exists, update its next
  1886.     if ((prev = TaskGetPrevIndex(dbP, index)) != dmMaxRecordIndex)
  1887.     {
  1888.         TaskSetHasNext(dbP, prev, TaskGetHasNext(dbP, index));
  1889.     }
  1890.     else
  1891.     {
  1892.         // no previous, actual is a first child
  1893.         // update father
  1894.         // father still has child if actual has a next
  1895.         TaskSetHasChild(dbP, father, TaskGetHasNext(dbP, index));
  1896.     }
  1897.  
  1898.     // if actual has a next, next takes actual's prev status
  1899.     if (TaskGetHasNext(dbP, index))
  1900.     {
  1901.         TaskSetHasPrev(dbP, TaskGetNextIndex(dbP, index), TaskGetHasPrev(dbP, index));
  1902.         // actual must be moved outside its parent's scope
  1903.         // that's before father's next
  1904.         needMove = true;
  1905.     }
  1906.  
  1907.     // if father has no next, modify actual
  1908.     if (!TaskGetHasNext(dbP, father))
  1909.     {
  1910.         TaskSetHasNext(dbP, index, false);
  1911.     }
  1912.     else
  1913.     {
  1914.         TaskSetHasNext(dbP, index, true);
  1915.     }
  1916.  
  1917.     TaskSetHasPrev(dbP, index, true);
  1918.  
  1919.     if (needMove)
  1920.     {
  1921.         newIndex = TaskGetNextRelativeIndex(dbP, father);
  1922.         if (newIndex == 0)
  1923.         {
  1924.             newIndex = DmNumRecords(dbP);
  1925.         }
  1926.         DmMoveRecord(dbP, index, newIndex);
  1927.         // we insert after index, so newIndex becomes newIndex-- after insertion
  1928.         newIndex--;
  1929.         gActualTask = newIndex;
  1930.     }
  1931.  
  1932.     // dec level
  1933.     TaskSetLevel(dbP, newIndex, actualLevel = TaskGetLevel(dbP, newIndex) - 1);
  1934.  
  1935.     // father gain a next
  1936.     TaskSetHasNext(dbP, father, true);
  1937.  
  1938.     // need to update the children
  1939.     if (TaskGetHasChild(dbP, newIndex))
  1940.     {
  1941.         newIndex++; // to insert children after actual
  1942.         i = index + 1;
  1943.         // if actual has moved, first child is now index
  1944.         if (needMove)
  1945.         {
  1946.             i--;
  1947.         }
  1948.  
  1949.         // all children go to left, without other modification
  1950.         while (i < numRec && TaskGetLevel(dbP, i) >= actualLevel + 2)
  1951.         {
  1952.             TaskSetLevel(dbP, i, TaskGetLevel(dbP, i) - 1);
  1953.             if (needMove)
  1954.             {
  1955.                 DmMoveRecord(dbP, i, newIndex);
  1956.                 gActualTask--;
  1957.             }
  1958.             else
  1959.             {
  1960.                 i++;
  1961.             }
  1962.         }
  1963.     }
  1964.     return pgOK;
  1965. } // pgErr TaskToLeft(UInt16 index)
  1966.  
  1967.  
  1968.  
  1969. /****************************************************************************
  1970.  * Name : TaskUp
  1971.  * Desc : push a task up
  1972.  * Prm  : 
  1973.  *             -> index of task to push
  1974.  * Out  : Err code
  1975.  * Auth : lb, 01.08.2000
  1976.  * Rem  : 
  1977.  * Mod  : lb, 09.08.2000
  1978.  *             - update gActualTask for continuous moving
  1979.  ***************************************************************************/
  1980. pgErr TaskUp(DmOpenRef dbP, UInt16 index)
  1981. {
  1982.     UInt16 prev;
  1983.     UInt8  level;
  1984.     UInt16 numRec = DmNumRecords(dbP);
  1985.  
  1986.     if (!TaskGetHasPrev(dbP, index))
  1987.         return pgError;
  1988.  
  1989.     // update flags
  1990.     prev = TaskGetPrevIndex(dbP, index);
  1991.     TaskSetHasNext(dbP, prev, TaskGetHasNext(dbP, index));
  1992.     TaskSetHasPrev(dbP, index, TaskGetHasPrev(dbP, prev));
  1993.     TaskSetHasPrev(dbP, prev, true);
  1994.     TaskSetHasNext(dbP, index, true);
  1995.  
  1996.     // move index
  1997.     DmMoveRecord(dbP, index, prev);
  1998.  
  1999.     // update actual task
  2000.     gActualTask = prev;
  2001.  
  2002.     // move children
  2003.     if (TaskGetHasChild(dbP, prev))
  2004.     {
  2005.         level = TaskGetLevel(dbP, prev);
  2006.  
  2007.         // move children behind actual
  2008.         prev++;
  2009.         index++;
  2010.  
  2011.         // while it's a child
  2012.         while (index < numRec && TaskGetLevel(dbP, index) > level)
  2013.         {
  2014.             DmMoveRecord(dbP, index, prev);
  2015.             prev++;
  2016.             index++;
  2017.         }
  2018.     }
  2019.     return pgOK;
  2020. } // pgErr TaskUp(UInt16 index)
  2021.  
  2022.  
  2023.  
  2024. /****************************************************************************
  2025.  * Name : TaskDown
  2026.  * Desc : push a task down
  2027.  * Prm  : 
  2028.  *             -> index of task to push
  2029.  * Out  : Err code
  2030.  * Auth : lb, 02.08.2000
  2031.  * Mod  : lb, 09.08.2000
  2032.  *             - update gActualTask for continuous moving
  2033.  *           lb, 17.08.2000
  2034.  *             - fixed crash when moving a task that has children
  2035.  ***************************************************************************/
  2036. pgErr TaskDown(DmOpenRef dbP, UInt16 index)
  2037. {
  2038.     UInt16 next;
  2039.     UInt32 uniqueID;
  2040.  
  2041.     if (!TaskGetHasNext(dbP, index))
  2042.         return pgError;
  2043.  
  2044.     // to locate the task after it has moved
  2045.     DmRecordInfo(dbP, gActualTask, NULL, &uniqueID, NULL);
  2046.  
  2047.     next = TaskGetNextIndex(dbP, index);
  2048.     TaskUp(dbP, next);
  2049.  
  2050.     // locate the task
  2051.     DmFindRecordByID(dbP, uniqueID, &gActualTask);
  2052.  
  2053.     // update the table, because if the task moved down has children, its
  2054.     // new index is not in the table, and SelectTask will crash with
  2055.     // move = true
  2056.     ProjectTableUpdate();
  2057.     return pgOK;
  2058. } // pgErr TaskDown(UInt16 index)
  2059.  
  2060.  
  2061.  
  2062. /****************************************************************************
  2063.  * Name : TaskPublishToDo
  2064.  * Desc : publish the actual task in the ToDo DB
  2065.  * Prm  : 
  2066.  * Out  : 
  2067.  * Auth : lb, 21.08.2000
  2068.  ***************************************************************************/
  2069. pgErr TaskPublishToDo(DmOpenRef dbP, UInt16 index)
  2070. {
  2071.     DmOpenRef ToDoDB;
  2072.     ToDoItemType task;
  2073.     MemHandle h;
  2074.     TaskRecordType *p;
  2075.     UInt16 todoIndex = 0;
  2076.     Err err = errNone;
  2077.     UInt32 uniqueID;
  2078.     TaskFormatType format;
  2079.  
  2080.     if (TaskGetFormat(dbP, index).hasToDo)
  2081.         return pgOK;
  2082.  
  2083.     // try to open the ToDo database
  2084.     if (ToDoGetDatabase(&ToDoDB, dmModeReadWrite))
  2085.     {
  2086.         FrmCustomAlert(AltEmpty, "Can't open the todo database", "", "");
  2087.         return pgError;
  2088.     }
  2089.  
  2090.     h = DmQueryRecord(dbP, index);
  2091.     if (!h)
  2092.         return pgError;
  2093.  
  2094.     p = MemHandleLock(h);
  2095.  
  2096.     // convert due date format if there's no due date
  2097.     task.dueDate = p->dueDate;
  2098.     if (task.dueDate.month == 0)
  2099.     {
  2100.         *((UInt16 *) &task.dueDate) = toDoNoDueDate;
  2101.     }
  2102.  
  2103.     // convert priority : no => 5
  2104.     task.priority = p->priority;
  2105.     if (!(task.priority > 0 && task.priority < 6))
  2106.     {
  2107.         task.priority = 5;
  2108.     }
  2109.  
  2110.     task.description = &p->description;
  2111.     task.note = "";
  2112.  
  2113.     MemHandleUnlock(h);
  2114.  
  2115.     err = ToDoNewRecord(ToDoDB, &task, 0, &todoIndex);
  2116.     if (err == errNone)
  2117.     {
  2118.         DmRecordInfo(ToDoDB, todoIndex, NULL, &uniqueID, NULL);
  2119.         TaskSetExtraChunk(dbP, index, Extra_Link_ToDo, 0x00,
  2120.                           &uniqueID, sizeof(uniqueID));
  2121.  
  2122.         format = TaskGetFormat(dbP, index);
  2123.         format.hasToDo = 1;
  2124.         TaskSetFormat(dbP, index, format);
  2125.     }
  2126.     else
  2127.     {
  2128.         DEBUG1("Export failed !");
  2129.     }
  2130.  
  2131.     DmCloseDatabase(ToDoDB);
  2132.  
  2133.     return pgOK;
  2134.  
  2135. } // pgErr TaskPublishToDo(DmOpenRef dbP, UInt16 index)
  2136.  
  2137.  
  2138.  
  2139. /****************************************************************************
  2140.  * Name : TaskSetToDoStatus
  2141.  * Desc : update the sync todo
  2142.  * Prm  : 
  2143.  *             -> database
  2144.  *             -> index of task
  2145.  *             -> field to update in : (one at a time)
  2146.  *                toDoPriority,
  2147.  *                toDoComplete,
  2148.  *                toDoDueDate,
  2149.  *                toDoDescription, not yet
  2150.  *                toDoNote, not yet
  2151.  *                toDoCategory, not yet
  2152.  *             -> value    (pass NULL if you don't want it)
  2153.  *             -> priority (")
  2154.  *             -> duedate  (")
  2155.  * Out  : 
  2156.  * Auth : lb, 30.08.2000
  2157.  ***************************************************************************/
  2158. pgErr TaskSetToDoStatus(DmOpenRef dbP, UInt16 index, UInt16 field, 
  2159.     UInt8 value, UInt16 priority, DateType dueDate)
  2160. {
  2161.     DmOpenRef ToDoDB;
  2162.     UInt32 uniqueID;
  2163.     UInt16 todoIndex;
  2164.     UInt16 zero = 0, one = 1;
  2165.     Err err;
  2166.  
  2167.     uniqueID = TaskGetToDoUniqueID(dbP, index);
  2168.  
  2169.     if (!uniqueID)
  2170.         return pgError;
  2171.  
  2172.     // try to open the ToDo database
  2173.     if (ToDoGetDatabase(&ToDoDB, dmModeReadWrite))
  2174.     {
  2175.         FrmCustomAlert(AltEmpty, "Can't open the todo database", "", "");
  2176.         return pgError;
  2177.     }
  2178.  
  2179.     if (DmFindRecordByID(ToDoDB, uniqueID, &todoIndex))
  2180.     {
  2181.         DmCloseDatabase(ToDoDB);
  2182.         DEBUG1("The corresponding ToDo was not found, removing link.");
  2183.         TaskRemoveHasToDo(dbP, index);
  2184.         return pgError;
  2185.     }
  2186.  
  2187.     if (field == toDoPriority)
  2188.     {
  2189.         if (priority > 5 || priority < 1)
  2190.             priority = 5;
  2191.         err = ToDoChangeRecord(ToDoDB, &todoIndex, toDoPriority, 
  2192.             &priority);
  2193.     }
  2194.  
  2195.     if (field == toDoComplete)
  2196.     {
  2197.         err = ToDoChangeRecord(ToDoDB, &todoIndex, toDoComplete, 
  2198.             value == ACTION_OK ? &one : &zero );
  2199.     }
  2200.  
  2201.     if (field == toDoDueDate)
  2202.     {
  2203.         if (dueDate.month == 0)
  2204.             *((UInt16 *) &dueDate) = toDoNoDueDate;
  2205.  
  2206.         err = ToDoChangeRecord(ToDoDB, &todoIndex, toDoDueDate, 
  2207.             (UInt16*)&dueDate);
  2208.     }
  2209.  
  2210. //ToDoRecordFieldType 
  2211. //typedef enum  { 
  2212.     //toDoPriority,
  2213.     //toDoComplete,
  2214.     //toDoDueDate,
  2215.     //toDoDescription,
  2216.     //toDoNote,
  2217.     //toDoCategory } ToDoRecordFieldType;
  2218. //
  2219. //#define completeFlag     0x80
  2220. //#define priorityOnly     ~completeFlag
  2221.  
  2222.     DmCloseDatabase(ToDoDB);
  2223.  
  2224.     return pgOK;
  2225.  
  2226. } // pgErr TaskSetToDoStatus(DmOpenRef dbP, UInt16 index, UInt16 fields, 
  2227. // UInt8 value, UInt8 priority, DateType dueDate)
  2228.  
  2229.  
  2230.  
  2231. /****************************************************************************
  2232.  * Name : TaskUpdateToDo
  2233.  * Desc : update the values of the ToDo
  2234.  * Prm  : 
  2235.  *             -> database
  2236.  *             -> index of task
  2237.  *             <- value    (pass NULL if you don't want it)
  2238.  *             <- priority (")
  2239.  *             <- duedate  (")
  2240.  * Out  : 
  2241.  * Auth : lb, 30.08.2000
  2242.  ***************************************************************************/
  2243. Err TaskUpdateToDo(DmOpenRef dbP, UInt16 index)
  2244. {
  2245.     Err err = errNone;
  2246.     // see if we're synchronized with a ToDo
  2247.     if (TaskGetFormat(dbP, index).hasToDo)
  2248.     {
  2249.         Err err;
  2250.         // check the status in ToDo and update this task
  2251.         err = TaskSetToDoStatus(dbP, index, toDoComplete,
  2252.             TaskGetCompleted(dbP, index),
  2253.             0, gNoDate);
  2254.         err = TaskSetToDoStatus(dbP, index, toDoDueDate,
  2255.             0, 0,
  2256.             TaskGetDueDate(dbP, index));
  2257.         err = TaskSetToDoStatus(dbP, index, toDoPriority,
  2258.             0,
  2259.             TaskGetPriority(dbP, index),
  2260.             gNoDate);
  2261.     }
  2262.     return err;
  2263. } // Err TaskUpdateToDo(DmOpenRef dbP, UInt16 index)
  2264.  
  2265.  
  2266.  
  2267. /****************************************************************************
  2268.  * Name : TaskSyncAll
  2269.  * Desc : Update all the todo linked tasks
  2270.  * Prm  : 
  2271.  * Out  : 
  2272.  * Auth : lb, 30.08.2000
  2273.  ***************************************************************************/
  2274. void TaskSyncAll(void)
  2275. {
  2276.     UInt16 numRec = DmNumRecords(gdbP);
  2277.     UInt16 i;
  2278.     DateType dueDate;
  2279.     UInt8 value, priority;
  2280.  
  2281.     for (i = 1; i < numRec; i++)
  2282.     {
  2283.         // see if we're synchronized with a ToDo
  2284.         if (TaskGetFormat(gdbP, i).hasToDo)
  2285.         {
  2286.             pgErr err;
  2287.             // check the status in ToDo and update this task
  2288.             err = TaskGetToDoStatus(gdbP, i, 
  2289.                 &value, &priority, &dueDate);
  2290.             if (err == pgOK)
  2291.             {
  2292.                 TaskSetCompleted(gdbP, i, value);
  2293.                 TaskSetDueDate(gdbP, i, dueDate);
  2294.                 TaskSetPriority(gdbP, i, priority);
  2295.             }
  2296.         }
  2297.         
  2298.     }
  2299. } // void TaskSyncAll(void)
  2300.  
  2301.  
  2302.  
  2303. /****************************************************************************
  2304.  * Name : TaskRemoveHasToDo
  2305.  * Desc : remove the todo link
  2306.  * Prm  : 
  2307.  *             -> database
  2308.  *             -> index of task
  2309.  * Out  : 
  2310.  * Auth : lb, 30.08.2000
  2311.  ***************************************************************************/
  2312. pgErr TaskRemoveHasToDo(DmOpenRef dbP, UInt16 index)
  2313. {
  2314.     TaskFormatType format;
  2315.     //MemPtr p;
  2316.     //UInt32 size
  2317.     UInt32 uniqueID;
  2318.  
  2319.     // update the format field
  2320.     format = TaskGetFormat(dbP, index);
  2321.     if (format.hasToDo == 0)
  2322.         return pgOK;
  2323.  
  2324.     uniqueID = TaskGetToDoUniqueID(dbP, index);
  2325.  
  2326.     format.hasToDo = 0;
  2327.     TaskSetFormat(dbP, index, format);
  2328.  
  2329.     if (uniqueID)
  2330.     {
  2331.         DmOpenRef ToDoDB;
  2332.         UInt16 todoIndex;
  2333.  
  2334.         // try to open the ToDo database
  2335.         if (ToDoGetDatabase(&ToDoDB, dmModeReadWrite))
  2336.         {
  2337.             FrmCustomAlert(AltEmpty, "Can't open the todo database", "", "");
  2338.             return pgError;
  2339.         }
  2340.  
  2341.         if (DmFindRecordByID(ToDoDB, uniqueID, &todoIndex))
  2342.         {
  2343.             DmCloseDatabase(ToDoDB);
  2344.             return pgError;
  2345.         }
  2346.  
  2347.         DmRemoveRecord(ToDoDB, todoIndex);
  2348.  
  2349.         DmCloseDatabase(ToDoDB);
  2350.     }
  2351.  
  2352.     TaskRemoveExtraChunk(dbP, index, Extra_Link_ToDo, 0xff);
  2353.  
  2354.     return pgOK;
  2355.  
  2356. } // pgErr TaskRemoveHasToDo(DmOpenRef dbP, UInt16 index)
  2357.  
  2358.  
  2359.  
  2360. /****************************************************************************
  2361.  * Name : TaskGetToDoStatus
  2362.  * Desc : check the value of this task in the ToDo database
  2363.  * Prm  : 
  2364.  *             -> database
  2365.  *             -> index of task
  2366.  *             <- value    (pass NULL if you don't want it)
  2367.  *             <- priority (")
  2368.  *             <- duedate  (")
  2369.  * Out  : 
  2370.  * Auth : lb, 30.08.2000
  2371.  * Mod  : lb, 10.09.2000
  2372.  *             - forgot to unlock the handle, fixed
  2373.  ***************************************************************************/
  2374. pgErr TaskGetToDoStatus(DmOpenRef dbP, UInt16 index, UInt8 *value, 
  2375.     UInt8 *priority, DateType *dueDate)
  2376. {
  2377.     DmOpenRef ToDoDB;
  2378.     MemHandle h;
  2379.     ToDoDBRecord *p;
  2380.     UInt32 uniqueID;
  2381.     UInt16 todoIndex;
  2382.     UInt16 attr;
  2383.  
  2384.     uniqueID = TaskGetToDoUniqueID(dbP, index);
  2385.  
  2386.     if (!uniqueID)
  2387.         return pgError;
  2388.  
  2389.     // try to open the ToDo database
  2390.     if (ToDoGetDatabase(&ToDoDB, dmModeReadWrite))
  2391.     {
  2392.         FrmCustomAlert(AltEmpty, "Can't open the todo database", "", "");
  2393.         return pgError;
  2394.     }
  2395.  
  2396.     if (DmFindRecordByID(ToDoDB, uniqueID, &todoIndex))
  2397.     {
  2398.         DmCloseDatabase(ToDoDB);
  2399.         return pgError;
  2400.     }
  2401.  
  2402.     DmRecordInfo(ToDoDB, todoIndex, &attr, NULL, NULL);
  2403.     if (attr & dmRecAttrDelete)
  2404.     {
  2405.         DmCloseDatabase(ToDoDB);
  2406.         TaskRemoveHasToDo(dbP, index);
  2407.         return pgError;
  2408.     }
  2409.  
  2410. // from ToDo files
  2411. //typedef struct {
  2412.     //DateType dueDate;
  2413.     //UInt8 priority;        // high bit is complete flag
  2414.     //char description;
  2415. //} ToDoDBRecord;
  2416. //#define completeFlag     0x80
  2417. //#define priorityOnly     ~completeFlag
  2418.  
  2419.     h = DmQueryRecord(ToDoDB, todoIndex);
  2420.     p = MemHandleLock(h);
  2421.  
  2422.     if (value)
  2423.         *value = p->priority & completeFlag ? ACTION_OK : ACTION_NO;
  2424.     
  2425.     if (priority)
  2426.         *priority = p->priority & priorityOnly;
  2427.  
  2428.     if (dueDate)
  2429.     {
  2430.         *dueDate = p->dueDate;
  2431.         if (*((UInt16 *) dueDate) == toDoNoDueDate)
  2432.         {
  2433.             dueDate->month = 0;
  2434.             dueDate->year = 0;
  2435.             dueDate->day = 0;
  2436.         }
  2437.     }
  2438.  
  2439.     MemHandleUnlock(h);
  2440.  
  2441.     DmCloseDatabase(ToDoDB);
  2442.  
  2443.     return pgOK;
  2444.  
  2445. } // pgErr TaskGetToDoStatus(DmOpenRef dbP, UInt16 index, UInt8 *value, 
  2446. //    UInt8 *priority, DateType *dueDate)
  2447.  
  2448.  
  2449.  
  2450. /****************************************************************************
  2451.  * Name : TaskRepairTree
  2452.  * Desc : try to repair a broken tree
  2453.  * Prm  : 
  2454.  *             -> start : first index to correct (0 to correct all tree)
  2455.  *             -> end   : last index to correct (max numrec - 1)
  2456.  * Out  : 
  2457.  * Auth : lb, 30.08.2000
  2458.  ***************************************************************************/
  2459. pgErr TaskRepairTree(DmOpenRef dbP, UInt16 start, UInt16 stop)
  2460. {
  2461.     UInt16 index = 1, numRec = DmNumRecords(dbP);
  2462.     UInt8 level, nextLevel;
  2463.     UInt16 t;
  2464.  
  2465.     if (numRec < 2)
  2466.         return pgError;
  2467.  
  2468.     // this is true in all cases
  2469.     TaskSetHasPrev(dbP, 1, false);
  2470.     TaskSetHasNext(dbP, numRec - 1, false);
  2471.     TaskSetHasChild(dbP, numRec - 1, false);
  2472.  
  2473.     if (start == 0)
  2474.     {
  2475.         // ensure a good start
  2476.         TaskSetLevel(dbP, 1, 1);
  2477.  
  2478.         // correct the levels + hasChild status
  2479.         for (index = 1; index < numRec - 1; index++)
  2480.         {
  2481.             level = TaskGetLevel(dbP, index);
  2482.             nextLevel = TaskGetLevel(dbP, index + 1);
  2483.  
  2484.             if (nextLevel == 0)
  2485.             {
  2486.                 nextLevel = 1;
  2487.             }
  2488.             if (nextLevel > level)
  2489.             {
  2490.                 TaskSetLevel(dbP, index + 1, level + 1);
  2491.                 TaskSetHasChild(dbP, index, true);
  2492.             }
  2493.             else
  2494.             {
  2495.                 TaskSetHasChild(dbP, index, false);
  2496.             }
  2497.         }
  2498.         start = 1;
  2499.         stop = numRec - 1;
  2500.     }
  2501.     else
  2502.     {
  2503.         if (stop > numRec - 1)
  2504.             stop = numRec - 1;
  2505.     }
  2506.  
  2507.     // correct the hasNext + hasPrev status
  2508.     for (index = start; index < stop; index++)
  2509.     {
  2510.         level = TaskGetLevel(dbP, index);
  2511.         nextLevel = TaskGetLevel(dbP, index + 1);
  2512.  
  2513.         if (nextLevel == level)
  2514.         {
  2515.             TaskSetHasNext(dbP, index, true);
  2516.             TaskSetHasPrev(dbP, index + 1, true);
  2517.         }
  2518.         else if (nextLevel < level)
  2519.         {
  2520.             TaskSetHasNext(dbP, index, false);
  2521.         }
  2522.         else
  2523.         {
  2524.             TaskSetHasPrev(dbP, index + 1, false);
  2525.             // need to search if there's a next below
  2526.             t = index + 1;
  2527.             while((t < numRec - 1) && TaskGetLevel(dbP, t) > level)
  2528.             {
  2529.                 t++;
  2530.             }
  2531.             if (TaskGetLevel(dbP, t) == level)
  2532.             {
  2533.                 TaskSetHasNext(dbP, index, true);
  2534.                 TaskSetHasPrev(dbP, t, true);
  2535.             }
  2536.             else
  2537.             {
  2538.                 TaskSetHasNext(dbP, index, false);
  2539.             }
  2540.         }
  2541.     }
  2542.     return pgOK;
  2543. } // pgErr TaskRepairTree(DmOpenRef dbP, UInt16 start, UInt16 stop)
  2544.  
  2545.  
  2546.  
  2547. /****************************************************************************
  2548.  * Name : TaskToClipboard
  2549.  * Desc : copy the given task (with children) to the clipboard
  2550.  * Prm  : 
  2551.  *             -> database pointer
  2552.  *             -> index of the task to copy
  2553.  *             -> true => copy parent too
  2554.  * Out  : 
  2555.  * Auth : lb, 04.09.2000
  2556.  ***************************************************************************/
  2557. pgErr TaskToClipboard(DmOpenRef dbP, UInt16 index, Boolean withParent)
  2558. {
  2559.     UInt16 clipIndex = 0, i = index, numRec = DmNumRecords(dbP);
  2560.     UInt8 refLevel, level = 0;
  2561.     MemHandle hSrc, hClip;
  2562.     TaskRecordType *pSrc, *pClip;
  2563.     Err err;
  2564.  
  2565.     err = NewClipboard();
  2566.     if (err)
  2567.     {
  2568.         DEBUG1("Cannot create the clipboard, copy canceled.");
  2569.         return pgError;
  2570.     }
  2571.  
  2572.     refLevel = TaskGetLevel(dbP, index);
  2573.  
  2574.     // if we don't want the parent, begin at next one
  2575.     if (!withParent)
  2576.     {
  2577.         i++;
  2578.     }
  2579.  
  2580.     // copy the task and all its children
  2581.     while ((i < numRec && (level = TaskGetLevel(dbP, i)) > refLevel) || 
  2582.         i == index)
  2583.     {
  2584.         clipIndex = dmMaxRecordIndex; // add to the end of the clip
  2585.         hSrc = DmQueryRecord(dbP, i);
  2586.         pSrc = MemHandleLock(hSrc);
  2587.  
  2588.         hClip = DmNewRecord(gClip, &clipIndex, MemPtrSize(pSrc));
  2589.         MemHandleUnlock(hSrc);
  2590.         pSrc = MemHandleLock(hSrc);
  2591.         pClip = MemHandleLock(hClip);
  2592.  
  2593.         DmWrite(pClip, 0, pSrc, MemPtrSize(pSrc));
  2594.  
  2595.         MemHandleUnlock(hClip);
  2596.         MemHandleUnlock(hSrc);
  2597.  
  2598.         DmReleaseRecord(gClip, clipIndex, true);
  2599.  
  2600.         // adapt the level
  2601.         TaskSetLevel(gClip, clipIndex, level - refLevel + 1);
  2602.         
  2603.         // next record
  2604.         i++;
  2605.     }
  2606.  
  2607.     CloseClipboard();
  2608.     return pgOK;
  2609. } // pgErr TaskToClipboard(DmOpenRef dbP, UInt16 index, Boolean withParent)
  2610.  
  2611.  
  2612.  
  2613. /****************************************************************************
  2614.  * Name : TaskFromClipboard
  2615.  * Desc : copy the clipboard as a brother of the given task
  2616.  * Prm  : 
  2617.  *             -> database pointer
  2618.  *             -> index of the brother task
  2619.  *             -> true to paste as children of the given task
  2620.  * Out  : 
  2621.  * Auth : lb, 04.09.2000
  2622.  ***************************************************************************/
  2623. pgErr TaskFromClipboard(DmOpenRef dbP, UInt16 index, Boolean asChildren)
  2624. {
  2625.     UInt16 numRec, i = 1, insertIndex = index;
  2626.     TaskRecordType *pClip, *pDest;
  2627.     MemHandle hClip, hDest;
  2628.     UInt8 refLevel = 0;
  2629.     Err err;
  2630.  
  2631.     err = OpenClipboard();
  2632.     if (err)
  2633.     {
  2634.         DEBUG1("Cannot open the clipboard, paste canceled.");
  2635.         return pgError;
  2636.     }
  2637.  
  2638.     if ((numRec = DmNumRecords(gClip)) < 2)
  2639.     {
  2640.         CloseClipboard();
  2641.         DEBUG1("Clipboard empty");
  2642.         return pgOK;
  2643.     }
  2644.  
  2645.     // insert after selected one, as a brother
  2646.     index = TaskGetNextRelativeIndex(dbP, index);
  2647.     if (!index)
  2648.         index = dmMaxRecordIndex;
  2649.  
  2650.     while (i < numRec)
  2651.     {
  2652.         hClip = DmQueryRecord(gClip, i);
  2653.         pClip = MemHandleLock(hClip);
  2654.         hDest = DmNewRecord(dbP, &index, MemPtrSize(pClip));
  2655.  
  2656.         // reget handle (chunk could have moved, I think...)
  2657.         MemHandleUnlock(hClip);
  2658.         pClip = MemHandleLock(hClip);
  2659.  
  2660.         pDest = MemHandleLock(hDest);
  2661.         DmWrite(pDest, 0, pClip, MemPtrSize(pClip));
  2662.         MemHandleUnlock(hDest);
  2663.         DmReleaseRecord(dbP, index, true);
  2664.         MemHandleUnlock(hClip);
  2665.  
  2666.         if (i == 1)
  2667.         {
  2668.             if (asChildren)
  2669.             {
  2670.                 TaskSetLevel(dbP, index, 
  2671.                     (refLevel = TaskGetLevel(dbP, insertIndex) + 1));
  2672.                 refLevel -= TaskGetLevel(gClip, 1);
  2673.                 TaskSetHasChild(dbP, insertIndex, true);
  2674.             }
  2675.             else
  2676.             {
  2677.                 TaskSetLevel(dbP, index, 
  2678.                     (refLevel = TaskGetLevel(dbP, insertIndex)));
  2679.                 refLevel -= TaskGetLevel(gClip, 1);
  2680.             }
  2681.         }
  2682.         else
  2683.         {
  2684.             TaskSetLevel(dbP, index, pClip->attr.bits.level + refLevel);
  2685.         }
  2686.  
  2687.         i++;
  2688.         index++;
  2689.     }
  2690.     // TODO : this can cause crash when :
  2691.     // - copying a task that has children but no next
  2692.     // - paste it as a brother of a task that has a next
  2693.     // => pasted task has flag no next, but has one => graphical problem
  2694.     // => crash when trying to delete it
  2695.     //TaskRepairTree(gdbP, insertIndex, insertIndex + numRec);
  2696.     // the constrained repair doesn't seem to work well with this case
  2697.     TaskRepairTree(gdbP, 0, 0); // this cause a complete repair, it's slow
  2698.  
  2699.     CloseClipboard();
  2700.     return pgOK;
  2701. } // pgErr TaskFromClipboard(DmOpenRef dbP, UInt16 index, Boolean asChildren)
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.  
  2711.  
  2712.  
  2713.  
  2714.  
  2715.  
  2716.  
  2717.  
  2718.  
  2719.  
  2720. /****************************************************************************
  2721.  * Name : TaskFindExtraChunk
  2722.  * Desc : find chunk of extra block
  2723.  * Prm  : 
  2724.  *             -> extra block ptr
  2725.  *             -> chunk type
  2726.  *             -> sub key. 0xff is wild.
  2727.  * Out  : headder of it chunk if type was found, otherwith return NULL.
  2728.  * Auth : seagull, 27,09,2000
  2729.  ***************************************************************************/
  2730. static ExtraChunkHeadType*
  2731. TaskFindExtraChunkHead(ExtraChunkHeadType* block,
  2732.                        UInt8 type, UInt8 subkey)
  2733. {
  2734.     // NOTE: if type is NULL, this function must be find NULL block.
  2735.     //       see TaskSetExtraChunk
  2736.     for (;;)
  2737.     {
  2738.         if (block->type == type &&
  2739.             (subkey == 0xff || block->subkey == subkey))
  2740.             return block;
  2741.         else if (block->type == Extra_NULL)
  2742.             return NULL;
  2743.         block = NextChunk(block);
  2744.     }
  2745. } //static ExtraChunkHeadType*
  2746. //TaskFindExtraChunkHead(ExtraChunkHeadType const* block,
  2747. //                       UInt8 type, UInt8 subkey)
  2748.  
  2749.  
  2750.  
  2751.  
  2752.  
  2753. /****************************************************************************
  2754.  * Name : TaskGetExtraChunk
  2755.  * Desc : get chunk data of extra block
  2756.  * Prm  : 
  2757.  *             -> database ptr
  2758.  *             -> index
  2759.  *             -> chunk type
  2760.  *          -> subkey
  2761.  *             -> buffer ptr
  2762.  *             -> size ptr
  2763.  * Out  : retrieve body to dest if not NULL and chunk is found.
  2764.  *        set *size to chunk size in bytes.
  2765.  *        return pgOK if chunk was found and buffer size is enoth, 
  2766.  *        otherwith return pgError.
  2767.  * Auth : seagull, 27,09,2000
  2768.  ***************************************************************************/
  2769. pgErr TaskGetExtraChunk(DmOpenRef dbP, UInt16 index, UInt8 type, UInt8 subkey,
  2770.                         MemPtr dest, UInt16* size/*in bytes*/)
  2771. {
  2772.     MemHandle hTask = DmQueryRecord(dbP, index);
  2773.     pgErr err = TaskGetExtraChunkByTaskPtr(
  2774.         (TaskExtendedRecordType*)MemHandleLock(hTask),
  2775.         type, subkey, dest, size);
  2776.  
  2777.     MemHandleUnlock(hTask);
  2778.     return err;
  2779. }//pgErr TaskGetExtraChunk(DmOpenRef dbP, UInt16 index, UInt8 type, UInt8 subkey
  2780. //                        MemPtr dest, UInt16* size/*in bytes*/)
  2781.  
  2782.  
  2783.  
  2784.  
  2785. /****************************************************************************
  2786.  * Name : TaskGetExtraChunkByTaskPtr
  2787.  * Desc : get chunk data of extra block
  2788.  * Prm  : 
  2789.  *             -> Task ptr
  2790.  *             -> chunk type
  2791.  *          -> subkey
  2792.  *             -> buffer ptr
  2793.  *             -> size ptr
  2794.  * Out  : retrieve body to dest if not NULL and chunk is found.
  2795.  *        set *size to chunk size in bytes.
  2796.  *        return pgOK if chunk was found and buffer size is enoth, 
  2797.  *        otherwith return pgError.
  2798.  * Auth : seagull, 27,09,2000
  2799.  ***************************************************************************/
  2800. pgErr TaskGetExtraChunkByTaskPtr(TaskExtendedRecordType* pTask,
  2801.                                  UInt8 type, UInt8 subkey,
  2802.                                  MemPtr dest, UInt16* size/*in bytes*/)
  2803. {
  2804.     pgErr err = pgError;
  2805.     ExtraChunkHeadType* pChunk =
  2806.         (ExtraChunkHeadType*)TaskGetExtraBlockHeadPtr(pTask);
  2807.  
  2808.     if ((MemPtr)pTask + MemPtrSize(pTask) - (MemPtr)pChunk
  2809.         > sizeof(ExtraChunkHeadType) * 2)
  2810.     {
  2811.         pChunk = TaskFindExtraChunkHead(pChunk, type, subkey);
  2812.         if (pChunk != NULL && size != NULL)
  2813.         {
  2814.             if (dest != NULL && pChunk->size <= *size)
  2815.             {
  2816.                 MemMove(dest, pChunk->body, pChunk->size);
  2817.                 err = pgOK;
  2818.             }
  2819.             *size = pChunk->size;
  2820.         }
  2821.         else if (size == NULL)
  2822.             err = pgOK; // return exist/non exist status only.
  2823.     }
  2824.  
  2825.     return err;
  2826. } //pgErr TaskGetExtraChunkByTaskPtr(TaskExtendedRecordType* pTask,
  2827. //                                 UInt8 type, UInt8 subkey,
  2828. //                                 MemPtr dest, UInt16* size/*in bytes*/)
  2829.  
  2830.  
  2831.  
  2832.  
  2833. /****************************************************************************
  2834.  * Name : TaskRemoveExtraChunk
  2835.  * Desc : remove chunk and compaction extra block.
  2836.  * Prm  : 
  2837.  *             -> databse ptr
  2838.  *             -> index
  2839.  *             -> chunk type
  2840.  *             -> subkey
  2841.  * Out  : 
  2842.  * Auth : seagull, 27,09,2000
  2843.  ***************************************************************************/
  2844. void TaskRemoveExtraChunk(DmOpenRef dbP, UInt16 index,
  2845.                           UInt8 type, UInt8 subkey)
  2846. {
  2847.     ExtraChunkHeadType* pChunk;
  2848.     UInt8* pExtra;
  2849.  
  2850.     UInt32 sizeExtra = TaskGetExtraBlock(dbP, index, NULL);
  2851.     if (! sizeExtra) return ; // no bloc
  2852.     if (sizeExtra < 5) // malformed, destroy it
  2853.     {
  2854.         TaskSetExtraBlock(dbP, index, NULL, 0);
  2855.         return;
  2856.     }
  2857.  
  2858.     pExtra = MemPtrNew(sizeExtra);
  2859.     TaskGetExtraBlock(dbP, index, pExtra);
  2860.  
  2861.     pChunk = TaskFindExtraChunkHead((ExtraChunkHeadType*)pExtra,
  2862.                                     type, subkey);
  2863.     if (pChunk) 
  2864.     {   // found it, go to compaction
  2865.         UInt8* src = (UInt8*)NextChunk(pChunk);
  2866.         UInt8* dst = (UInt8*)pChunk;
  2867.         UInt16 sizeChunk = (UInt8*)src - (UInt8*)pChunk;
  2868.  
  2869.         if (((ExtraChunkHeadType*)src)->type == Extra_NULL &&
  2870.             dst == pExtra)
  2871.         {  // Extra block is empty. delete it
  2872.             TaskSetExtraBlock(dbP, index, NULL, 0);
  2873.         }
  2874.         else
  2875.         {
  2876.             while (src < pExtra + sizeExtra)
  2877.                 *dst++ = *src++;
  2878.             TaskSetExtraBlock(dbP, index, pExtra, sizeExtra - sizeChunk);
  2879.         }
  2880.     }
  2881.  
  2882.     MemPtrFree(pExtra);
  2883. }//void TaskRemoveExtraChunk(DmOpenRef dbP, UInt16 index,
  2884. //                          UInt8 type, UInt8 subkey)
  2885.  
  2886.  
  2887.  
  2888. /****************************************************************************
  2889.  * Name : TaskSetExtraChunk
  2890.  * Desc : 
  2891.  * Prm  : 
  2892.  *             -> database ptr
  2893.  *             -> index
  2894.  *             -> chunk type
  2895.  *             -> source buffer
  2896.  *             -> chunk size
  2897.  * Out  : 
  2898.  * Auth : seagull, 27,09,2000
  2899.  ***************************************************************************/
  2900. pgErr    TaskSetExtraChunk(DmOpenRef dbP, UInt16 index,
  2901.                            UInt8 type, UInt8 subkey,
  2902.                            MemPtr src, UInt16 size)
  2903. {
  2904.     // TODO: reuse block if type, subkey and size is equal.
  2905.  
  2906.     MemPtr pExtra = NULL;
  2907.     UInt32 sizeExtra;
  2908.     ExtraChunkHeadType* pChunk = NULL;
  2909.     Boolean bCreateNew = true;
  2910.  
  2911.     TaskRemoveExtraChunk(dbP, index, type, subkey);
  2912.  
  2913.     sizeExtra = TaskGetExtraBlock(dbP, index, NULL);
  2914.     if (sizeExtra)
  2915.     {
  2916.         pExtra = MemPtrNew(sizeExtra + sizeof(ExtraChunkHeadType) + size);
  2917.         if (! pExtra) return pgError;
  2918.         TaskGetExtraBlock(dbP, index, pExtra);
  2919.  
  2920.         pChunk = TaskFindExtraChunkHead((ExtraChunkHeadType*)pExtra,
  2921.                                         Extra_NULL, 0);
  2922.         if (pChunk)
  2923.             bCreateNew = false;
  2924.         else
  2925.         {
  2926.             MemPtrFree(pExtra);
  2927.             DEBUG1("Extra chunk was broken. Deleted");
  2928.         }
  2929.     }
  2930.  
  2931.     if (bCreateNew)
  2932.     {   // *2 is itself and null chunk
  2933.         pExtra = MemPtrNew(sizeof(ExtraChunkHeadType) * 2 + size);
  2934.         if (! pExtra) return pgError;
  2935.         pChunk = pExtra;
  2936.     }
  2937.  
  2938.     // make new chunk
  2939.     pChunk->type = type;
  2940.     pChunk->subkey = subkey;
  2941.     pChunk->size = size;
  2942.     MemMove(pChunk->body, src, size);
  2943.  
  2944.     // make new sentinel
  2945.     pChunk = NextChunk(pChunk);
  2946.     pChunk->type = Extra_NULL;
  2947.     pChunk->subkey = 0;
  2948.     pChunk->size = 0;
  2949.  
  2950.     TaskSetExtraBlock(dbP, index, pExtra, MemPtrSize(pExtra));
  2951.     MemPtrFree(pExtra);
  2952.  
  2953.     return pgOK;
  2954. }
  2955.  
  2956.  
  2957.  
  2958.