Enhancement - wait status

- Supports the new Task::waiting status.
- Supports: task <id> wait:<date>
- Supports: task <id> wait:
- Supports: task waiting
This commit is contained in:
Paul Beckingham 2009-06-21 22:42:32 -04:00
parent 40bde9e765
commit 329a78039a
12 changed files with 131 additions and 16 deletions

View file

@ -62,6 +62,7 @@ static const char* modifiableNames[] =
"due",
"recur",
"until",
"wait",
};
// Synonyms on the same line.
@ -324,8 +325,9 @@ bool Att::validNameValue (
Text::guessColor (value);
}
else if (name == "due" ||
name == "until")
else if (name == "due" ||
name == "until" ||
name == "wait")
{
// Validate and convert to epoch.
if (value != "")
@ -356,6 +358,7 @@ bool Att::validNameValue (
candidates.push_back ("completed");
candidates.push_back ("deleted");
candidates.push_back ("recurring");
candidates.push_back ("waiting");
autoComplete (value, candidates, matches);
if (matches.size () == 1)
@ -363,7 +366,7 @@ bool Att::validNameValue (
else
throw std::string ("\"") +
value +
"\" is not a valid status. Use 'pending', 'completed', 'deleted' or 'recurring'.";
"\" is not a valid status. Use 'pending', 'completed', 'deleted', 'recurring' or 'waiting'.";
}
else if (! validInternalName (name) &&
@ -388,11 +391,12 @@ bool Att::validMod (const std::string& mod)
// The type of an attribute is useful for modifier evaluation.
std::string Att::type (const std::string& name) const
{
if (name == "due" ||
if (name == "due" ||
name == "until" ||
name == "start" ||
name == "entry" ||
name == "end")
name == "end" ||
name == "wait")
return "date";
else if (name == "recur")

View file

@ -218,6 +218,12 @@ void Config::createDefault (const std::string& home)
fprintf (out, "report.recurring.sort=due+,priority-,project+\n"); // TODO i18n
fprintf (out, "report.recurring.filter=status:pending parent.any:\n"); // TODO i18n
fprintf (out, "report.waiting.description=Lists all waiting tasks matching the specified criteria\n"); // TODO i18n
fprintf (out, "report.waiting.columns=id,project,priority,wait,age,description\n"); // TODO i18n
fprintf (out, "report.waiting.labels=ID,Project,Pri,Wait,Age,Description\n"); // TODO i18n
fprintf (out, "report.waiting.sort=wait+,priority-,project+\n"); // TODO i18n
fprintf (out, "report.waiting.filter=status:waiting\n"); // TODO i18n
fclose (out);
std::cout << "Done." << std::endl; // TODO i18n
@ -290,6 +296,12 @@ void Config::setDefaults ()
set ("report.recurring.labels", "ID,Project,Pri,Due,Recur,Active,Age,Description"); // TODO i18n
set ("report.recurring.sort", "due+,priority-,project+"); // TODO i18n
set ("report.recurring.filter", "status:pending parent.any:"); // TODO i18n
set ("report.waiting.description", "Lists all waiting tasks matching the specified criteria"); // TODO i18n
set ("report.waiting.columns", "id,project,priority,wait,age,description"); // TODO i18n
set ("report.waiting.labels", "ID,Project,Pri,Wait,Age,Description"); // TODO i18n
set ("report.waiting.sort", "wait+,priority-,project+"); // TODO i18n
set ("report.waiting.filter", "status:waiting"); // TODO i18n
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -168,7 +168,9 @@ int TDB::load (std::vector <Task>& tasks, Filter& filter)
{
++numberStatusClauses;
if (att->mod () == "" && att->value () == "pending")
if (att->mod () == "" &&
(att->value () == "pending" ||
att->value () == "waiting"))
++numberSimpleStatusClauses;
}
}
@ -391,6 +393,7 @@ void TDB::upgrade ()
int TDB::gc ()
{
int count = 0;
Date now;
// Set up a second TDB.
Filter filter;
@ -417,6 +420,15 @@ int TDB::gc ()
completed.push_back (*task);
++count;
}
else if (s == Task::waiting)
{
// Wake up tasks that are waiting.
Date wait_date (::atoi (task->get ("wait").c_str ()));
if (now > wait_date)
task->setStatus (Task::pending);
still_pending.push_back (*task);
}
else
still_pending.push_back (*task);
}

View file

@ -93,6 +93,7 @@ Task::status Task::textToStatus (const std::string& input)
else if (input == "completed") return Task::completed; // TODO i18n
else if (input == "deleted") return Task::deleted; // TODO i18n
else if (input == "recurring") return Task::recurring; // TODO i18n
else if (input == "waiting") return Task::waiting; // TODO i18n
return Task::pending;
}
@ -104,6 +105,7 @@ std::string Task::statusToText (Task::status s)
else if (s == Task::completed) return "completed"; // TODO i18n
else if (s == Task::deleted) return "deleted"; // TODO i18n
else if (s == Task::recurring) return "recurring"; // TODO i18n
else if (s == Task::waiting) return "waiting"; // TODO i18n
return "pending";
}
@ -169,9 +171,9 @@ void Task::legacyParse (const std::string& line)
set ("uuid", line.substr (0, 36));
Task::status status = line[37] == '+' ? completed
: line[37] == 'X' ? deleted
: line[37] == 'r' ? recurring
: pending;
: line[37] == 'X' ? deleted
: line[37] == 'r' ? recurring
: pending;
set ("status", statusToText (status)); // No i18n
@ -226,9 +228,9 @@ void Task::legacyParse (const std::string& line)
set ("uuid", line.substr (0, 36));
Task::status status = line[37] == '+' ? completed
: line[37] == 'X' ? deleted
: line[37] == 'r' ? recurring
: pending;
: line[37] == 'X' ? deleted
: line[37] == 'r' ? recurring
: pending;
set ("status", statusToText (status)); // No i18n

View file

@ -45,7 +45,7 @@ public:
std::string composeCSV () const;
// Status values.
enum status {pending, completed, deleted, recurring /* , retired, deferred */};
enum status {pending, completed, deleted, recurring, waiting};
// Public data.
int id;

View file

@ -60,6 +60,8 @@ std::string handleAdd ()
context.task.setStatus (Task::recurring);
context.task.set ("mask", "");
}
else if (context.task.has ("wait"))
context.task.setStatus (Task::waiting);
else
context.task.setStatus (Task::pending);
@ -1216,6 +1218,15 @@ int deltaAttributes (Task& task)
att->first != "description" &&
att->first != "tags")
{
// Modifying "wait" changes status.
if (att->first == "wait")
{
if (att->second.value () == "")
task.setStatus (Task::pending);
else
task.setStatus (Task::waiting);
}
if (att->second.value () == "")
task.remove (att->first);
else

View file

@ -368,6 +368,26 @@ std::string handleCustomReport (const std::string& report)
table.addCell (row, columnCount, "+");
}
else if (*col == "wait")
{
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Wait");
table.setColumnWidth (columnCount, Table::minimum);
table.setColumnJustification (columnCount, Table::right);
int row = 0;
std::string wait;
foreach (task, tasks)
{
wait = task->get ("wait");
if (wait != "")
{
Date dt (::atoi (wait.c_str ()));
wait = dt.toString (context.config.get ("dateformat", "m/d/Y"));
table.addCell (row++, columnCount, wait);
}
}
}
// Common to all columns.
// Add underline.
if ((context.config.get (std::string ("color"), true) || context.config.get (std::string ("_forcecolor"), false)) &&
@ -403,7 +423,8 @@ std::string handleCustomReport (const std::string& report)
Table::ascendingPriority :
Table::descendingPriority));
else if (column == "entry" || column == "start" || column == "due")
else if (column == "entry" || column == "start" || column == "due" ||
column == "wait")
table.sortOn (columnIndex[column],
(direction == '+' ?
Table::ascendingDate :

View file

@ -150,6 +150,7 @@ static std::string formatTask (Task task)
<< " Due: " << formatDate (task, "due") << std::endl
<< " Until: " << formatDate (task, "until") << std::endl
<< " Recur: " << task.get ("recur") << std::endl
<< " Wait until: " << task.get ("wait") << std::endl
<< " Parent: " << task.get ("parent") << std::endl
<< " Foreground color: " << task.get ("fg") << std::endl
<< " Background color: " << task.get ("bg") << std::endl
@ -403,6 +404,36 @@ static void parseTask (Task& task, const std::string& after)
}
}
// wait
value = findDate (after, "Wait until:");
if (value != "")
{
Date edited (::atoi (value.c_str ()));
if (task.get ("wait") != "")
{
Date original (::atoi (task.get ("wait").c_str ()));
if (!original.sameDay (edited))
{
std::cout << "Wait date modified." << std::endl;
task.set ("wait", value);
}
}
else
{
std::cout << "Wait date modified." << std::endl;
task.set ("wait", value);
}
}
else
{
if (task.get ("wait") != "")
{
std::cout << "Wait date removed." << std::endl;
task.remove ("wait");
}
}
// parent
value = findValue (after, "Parent:");
if (value != task.get ("parent"))

View file

@ -565,6 +565,7 @@ static std::string importTask_1_6_0 (const std::vector <std::string>& lines)
else if (fields[f] == "'recurring'") task.setStatus (Task::recurring);
else if (fields[f] == "'deleted'") task.setStatus (Task::deleted);
else if (fields[f] == "'completed'") task.setStatus (Task::completed);
else if (fields[f] == "'waiting'") task.setStatus (Task::waiting);
break;
case 2: // 'tags'
@ -1063,6 +1064,7 @@ static std::string importCSV (const std::vector <std::string>& lines)
if (value == "recurring") task.setStatus (Task::recurring);
else if (value == "deleted") task.setStatus (Task::deleted);
else if (value == "completed") task.setStatus (Task::completed);
else if (value == "waiting") task.setStatus (Task::waiting);
else task.setStatus (Task::pending);
}

View file

@ -347,6 +347,7 @@ void updateRecurrenceMask (
mask[index] = (task.getStatus () == Task::pending) ? '-'
: (task.getStatus () == Task::completed) ? '+'
: (task.getStatus () == Task::deleted) ? 'X'
: (task.getStatus () == Task::waiting) ? 'W'
: '?';
it->set ("mask", mask);
@ -361,6 +362,7 @@ void updateRecurrenceMask (
mask += (task.getStatus () == Task::pending) ? '-'
: (task.getStatus () == Task::completed) ? '+'
: (task.getStatus () == Task::deleted) ? 'X'
: (task.getStatus () == Task::waiting) ? 'W'
: '?';
}

View file

@ -242,6 +242,7 @@ std::string longUsage ()
<< " fg: Foreground color" << "\n"
<< " bg: Background color" << "\n"
<< " limit: Desired number of rows in report" << "\n"
<< " wait: Date until task becomes pending" << "\n"
<< "\n"
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
<< " before (synonyms under, below)" << "\n"
@ -416,6 +417,15 @@ std::string handleInfo ()
}
}
// wait
if (task->has ("wait"))
{
row = table.addRow ();
table.addCell (row, 0, "Waiting until");
Date dt (::atoi (task->get ("wait").c_str ()));
table.addCell (row, 1, dt.toString (context.config.get ("dateformat", "m/d/Y")));
}
// start
if (task->has ("start"))
{
@ -539,7 +549,8 @@ std::string handleReportSummary ()
std::string project = task->get ("project");
++counter[project];
if (task->getStatus () == Task::pending)
if (task->getStatus () == Task::pending ||
task->getStatus () == Task::waiting)
{
++countPending[project];
@ -1646,6 +1657,7 @@ std::string handleReportStats ()
int deletedT = 0;
int pendingT = 0;
int completedT = 0;
int waitingT = 0;
int taggedT = 0;
int annotationsT = 0;
int recurringT = 0;
@ -1662,6 +1674,7 @@ std::string handleReportStats ()
if (it->getStatus () == Task::pending) ++pendingT;
if (it->getStatus () == Task::completed) ++completedT;
if (it->getStatus () == Task::recurring) ++recurringT;
if (it->getStatus () == Task::waiting) ++waitingT;
time_t entry = ::atoi (it->get ("entry").c_str ());
if (entry < earliest) earliest = entry;
@ -1721,6 +1734,10 @@ std::string handleReportStats ()
table.addCell (row, 0, "Pending");
table.addCell (row, 1, pendingT);
row = table.addRow ();
table.addCell (row, 0, "Waiting");
table.addCell (row, 1, waitingT);
row = table.addRow ();
table.addCell (row, 0, "Recurring");
table.addCell (row, 1, recurringT);

View file

@ -76,7 +76,8 @@ void validReportColumns (const std::vector <std::string>& columns)
*it != "recurrence_indicator" &&
*it != "tag_indicator" &&
*it != "description_only" &&
*it != "description")
*it != "description" &&
*it != "wait")
bad.push_back (*it);
if (bad.size ())