Recurring Tasks - upgrades and bug fixes

- Improved (fixed) logical consistency checks that prevent the
  addition of a recurrence frequency without a due date.
- Improved (fixed) logical consistency checks that prevent the
  addition of an until date with a recurrence frequency.
- When a recurring task is modified, all sibling instances, as well
  as the parent task now get modified.
- When a recurring task is appended, all sibling instances, as well
  as the parent task now get modified.
- Updated documentation.
- It is now possible to upgrade a regular task to a recurring task,
  which is triggered by the "recur" attribute.
This commit is contained in:
Paul Beckingham 2009-03-25 01:08:13 -04:00
parent 5ec0d569a9
commit 1a656f0f60
7 changed files with 92 additions and 37 deletions

View file

@ -56,7 +56,7 @@ public:
const std::string getDescription () const { return mDescription; }
void setDescription (const std::string& description) { mDescription = description; }
int getAnnotationCount () const { return mAnnotations.size (); }
int getAnnotationCount () const { return mAnnotations.size (); }
void getSubstitution (std::string&, std::string&) const;
void setSubstitution (const std::string&, const std::string&);

View file

@ -674,12 +674,30 @@ std::string handleModify (TDB& tdb, T& task, Config& conf)
{
std::stringstream out;
std::vector <T> all;
tdb.pendingT (all);
tdb.allPendingT (all);
// Lookup the complete task.
T complete = findT (task.getId (), all);
// Perform some logical consistency checks.
if (task.getAttribute ("recur") != "" &&
task.getAttribute ("due") == "" &&
complete.getAttribute ("due") == "")
throw std::string ("You cannot specify a recurring task without a due date.");
if (task.getAttribute ("until") != "" &&
task.getAttribute ("recur") == "" &&
complete.getAttribute ("recur") == "")
throw std::string ("You cannot specify an until date for a non-recurring task.");
int count = 0;
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
if (it->getId () == task.getId ())
if (it->getId () == complete.getId () || // Self
(complete.getAttribute ("parent") != "" &&
it->getAttribute ("parent") == complete.getAttribute ("parent")) || // Sibling
it->getUUID () == complete.getAttribute ("parent")) // Parent
{
T original (*it);
@ -725,8 +743,14 @@ std::string handleModify (TDB& tdb, T& task, Config& conf)
if (i->second == "")
original.removeAttribute (i->first);
else
{
original.setAttribute (i->first, i->second);
// If a "recur" attribute is added, upgrade to a recurring task.
if (i->first == "recur")
original.setStatus (T::recurring);
}
++changes;
}
@ -748,16 +772,18 @@ std::string handleModify (TDB& tdb, T& task, Config& conf)
}
if (changes)
{
original.setId (task.getId ());
tdb.modifyT (original);
}
return out.str ();
++count;
}
}
throw std::string ("Task not found.");
if (count == 0)
throw std::string ("Task not found.");
if (conf.get ("echo.command", true))
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
return out.str ();
}
@ -766,12 +792,19 @@ std::string handleAppend (TDB& tdb, T& task, Config& conf)
{
std::stringstream out;
std::vector <T> all;
tdb.pendingT (all);
tdb.allPendingT (all);
// Lookup the complete task.
T complete = findT (task.getId (), all);
int count = 0;
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
if (it->getId () == task.getId ())
if (it->getId () == complete.getId () || // Self
(complete.getAttribute ("parent") != "" &&
it->getAttribute ("parent") == complete.getAttribute ("parent")) || // Sibling
it->getUUID () == complete.getAttribute ("parent")) // Parent
{
T original (*it);
@ -843,23 +876,26 @@ std::string handleAppend (TDB& tdb, T& task, Config& conf)
if (changes)
{
original.setId (task.getId ());
tdb.modifyT (original);
if (conf.get ("echo.command", true))
out << "Appended '"
<< task.getDescription ()
<< "' to task "
<< task.getId ()
<< original.getId ()
<< std::endl;
}
return out.str ();
++count;
}
}
throw std::string ("Task not found.");
if (count == 0)
throw std::string ("Task not found.");
if (conf.get ("echo.command", true))
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
return out.str ();
}
@ -983,3 +1019,14 @@ std::string handleAnnotate (TDB& tdb, T& task, Config& conf)
}
////////////////////////////////////////////////////////////////////////////////
T findT (int id, const std::vector <T>& all)
{
std::vector <T>::const_iterator it;
for (it = all.begin (); it != all.end (); ++it)
if (id == it->getId ())
return *it;
return T ();
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -475,14 +475,6 @@ void parse (
}
}
if (task.getAttribute ("recur") != "" &&
task.getAttribute ("due") == "")
throw std::string ("You cannot specify a recurring task without a due date.");
if (task.getAttribute ("until") != "" &&
task.getAttribute ("recur") == "")
throw std::string ("You cannot specify an until date for a non-recurring task.");
if (validDescription (descCandidate))
task.setDescription (descCandidate);
}

View file

@ -89,6 +89,7 @@ std::string handleStop (TDB&, T&, Config&);
std::string handleUndo (TDB&, T&, Config&);
std::string handleColor (Config&);
std::string handleAnnotate (TDB&, T&, Config&);
T findT (int, const std::vector <T>&);
// report.cpp
void filter (std::vector<T>&, T&);