Feature: scheduled date

- Supports 'scheduled' date for tasks, which represent the earliest opportunity
  to work on a task.
- Added unit tests for urgency.
- Implemented color rule.
- Added scheduled to 'info' report.
- Updated assorted documentation.
- Removed comments in default rc because they are never seen.
- Added (broken) 'ready' report, which is like 'next' but only for ready tasks.
This commit is contained in:
Paul Beckingham 2012-05-13 17:19:22 -04:00
parent d08f189769
commit 98f215b1b5
17 changed files with 308 additions and 91 deletions

View file

@ -140,12 +140,13 @@ std::string Config::_defaults =
"urgency.blocking.coefficient=8.0 # Urgency coefficient for blocking tasks\n"
"urgency.priority.coefficient=6.0 # Urgency coefficient for priorities\n"
"urgency.active.coefficient=4.0 # Urgency coefficient for active tasks\n"
"urgency.scheduled.coefficient=5.0 # Urgency coefficient for scheduled tasks\n"
"urgency.age.coefficient=2.0 # Urgency coefficient for age\n"
"urgency.annotations.coefficient=1.0 # Urgency coefficient for annotations\n"
"urgency.tags.coefficient=1.0 # Urgency coefficient for tags\n"
"urgency.project.coefficient=1.0 # Urgency coefficient for projects\n"
"urgency.blocked.coefficient=-5.0 # Urgency coefficient for blocked tasks\n"
"urgency.waiting.coefficient=-3.0 # Urgency coefficient for waiting status\n"
"urgency.waiting.coefficient=-3.0 # Urgency coefficient for waiting status\n"
"urgency.age.max=365 # Maximum age in days\n"
"\n"
"#urgency.user.project.foo.coefficient=5.0 # Urgency coefficients for 'foo' project\n"
@ -315,138 +316,101 @@ std::string Config::_defaults =
"\n"
"# Reports\n"
"\n"
"# task long\n"
"report.long.description=Lists all pending tasks\n"
"report.long.columns=id,project,priority,entry,start,due,recur,due.countdown,entry.age,depends,tags,description\n"
"report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Countdown,Age,Deps,Tags,Description\n"
"report.long.sort=due+,priority-,project+\n"
"report.long.filter=status:pending\n"
"#report.long.dateformat=m/d/Y\n"
"#report.long.annotations=full\n"
"\n"
"# task list\n"
"report.list.description=Lists all pending tasks\n"
"report.list.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.list.sort=due+,priority-,start-,project+\n"
"report.list.filter=status:pending\n"
"#report.list.dateformat=m/d/Y\n"
"#report.list.annotations=full\n"
"\n"
"# task ls\n"
"report.ls.description=Minimal listing of all pending tasks\n"
"report.ls.columns=id,project,priority,description\n"
"report.ls.labels=ID,Project,Pri,Description\n"
"report.ls.sort=priority-,project+\n"
"report.ls.filter=status:pending\n"
"#report.ls.dateformat=m/d/Y\n"
"#report.ls.annotations=full\n"
"\n"
"# task minimal\n"
"report.minimal.description=Minimal listing of all pending tasks\n"
"report.minimal.columns=id,project,description.truncated\n"
"report.minimal.labels=ID,Project,Description\n"
"report.minimal.sort=project+,description+\n"
"report.minimal.filter=status:pending\n"
"#report.minimal.dateformat=m/d/Y\n"
"#report.minimal.annotations=full\n"
"\n"
"# task newest\n"
"report.newest.description=Shows the newest tasks\n"
"report.newest.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.newest.sort=id-\n"
"report.newest.filter=status:pending limit:10\n"
"#report.newest.dateformat=m/d/Y\n"
"#report.newest.annotations=full\n"
"\n"
"# task oldest\n"
"report.oldest.description=Shows the oldest tasks\n"
"report.oldest.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.oldest.sort=id+\n"
"report.oldest.filter=status:pending limit:10\n"
"#report.oldest.dateformat=m/d/Y\n"
"#report.oldest.annotations=full\n"
"\n"
"# task overdue\n"
"report.overdue.description=Lists overdue tasks\n"
"report.overdue.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.overdue.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.overdue.sort=due+,priority-,start-,project+\n"
"report.overdue.filter=status:pending due.before:now\n"
"#report.overdue.dateformat=m/d/Y\n"
"#report.overdue.annotations=full\n"
"\n"
"# task active\n"
"report.active.description=Lists active tasks\n"
"report.active.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.active.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.active.sort=due+,priority-,project+\n"
"report.active.filter=status:pending start.any:\n"
"#report.active.dateformat=m/d/Y\n"
"#report.active.annotations=full\n"
"\n"
"# task completed\n"
"report.completed.description=Lists completed tasks\n"
"report.completed.columns=end,project,priority,entry.age,description,uuid\n"
"report.completed.labels=Complete,Project,Pri,Age,Description,UUID\n"
"report.completed.sort=end+,priority-,project+\n"
"report.completed.filter=status:completed\n"
"#report.completed.dateformat=m/d/Y\n"
"#report.completed.annotations=full\n"
"\n"
"# task recurring\n"
"report.recurring.description=Lists recurring tasks\n"
"report.recurring.columns=id,project,priority,due,recur,start.active,entry.age,description\n"
"report.recurring.labels=ID,Project,Pri,Due,Recur,Active,Age,Description\n"
"report.recurring.sort=due+,priority-,start-,project+\n"
"report.recurring.filter=status:pending parent.any:\n"
"#report.recurring.dateformat=m/d/Y\n"
"#report.recurring.annotations=full\n"
"\n"
"# task waiting\n"
"report.waiting.description=Lists all waiting tasks\n"
"report.waiting.columns=id,project,priority,wait,entry.age,description\n"
"report.waiting.labels=ID,Project,Pri,Wait,Age,Description\n"
"report.waiting.sort=wait+,priority-,project+\n"
"report.waiting.filter=status:waiting\n"
"#report.waiting.dateformat=m/d/Y\n"
"#report.waiting.annotations=full\n"
"\n"
"# task all\n"
"report.all.description=Lists all pending and completed tasks\n"
"report.all.columns=id,status,project,priority,due,end,start.active,entry.age,description\n"
"report.all.labels=ID,Status,Project,Pri,Due,Completed,Active,Age,Description\n"
"report.all.sort=entry+\n"
"report.all.filter=status.not:deleted\n"
"#report.all.dateformat=m/d/Y\n"
"#report.all.annotations=full\n"
"\n"
"# task next\n"
"report.next.description=Lists the most urgent tasks\n"
"report.next.columns=id,project,priority,due,start.active,entry.age,urgency,description\n"
"report.next.filter=status:pending limit:page\n"
"report.next.labels=ID,Project,Pri,Due,A,Age,Urgency,Description\n"
"report.next.sort=urgency-,due+,priority-,start-,project+\n"
"#report.next.dateformat=m/d/Y\n"
"#report.next.annotations=full\n"
"\n"
"# task blocked\n"
"report.ready.description=Lists the most urgent tasks\n"
"report.ready.columns=id,project,priority,due,start.active,entry.age,urgency,description\n"
"report.ready.filter=status:pending limit:page wait.none: (scheduled.none: or scheduled.before:now)\n"
"report.ready.labels=ID,Project,Pri,Due,A,Age,Urgency,Description\n"
"report.ready.sort=urgency-,due+,priority-,start-,project+\n"
"\n"
"report.blocked.description=Lists all blocked tasks\n"
"report.blocked.columns=id,depends,project,priority,due,start.active,entry.age,description\n"
"report.blocked.labels=ID,Deps,Project,Pri,Due,Active,Age,Description\n"
"report.blocked.sort=due+,priority-,start-,project+\n"
"report.blocked.filter=status:pending depends.any:\n"
"#report.blocked.dateformat=m/d/Y\n"
"\n"
"# task unblocked\n"
"report.unblocked.description=Lists all unblocked tasks\n"
"report.unblocked.columns=id,depends,project,priority,due,start.active,entry.age,description\n"
"report.unblocked.labels=ID,Deps,Project,Pri,Due,Active,Age,Description\n"
"report.unblocked.sort=due+,priority-,start-,project+\n"
"report.unblocked.filter=status:pending depends.none:\n"
"#report.unblocked.dateformat=m/d/Y\n"
"\n";
////////////////////////////////////////////////////////////////////////////////

View file

@ -53,6 +53,7 @@ static std::map <std::string, float> coefficients;
float urgencyPriorityCoefficient = 0.0;
float urgencyProjectCoefficient = 0.0;
float urgencyActiveCoefficient = 0.0;
float urgencyScheduledCoefficient = 0.0;
float urgencyWaitingCoefficient = 0.0;
float urgencyBlockedCoefficient = 0.0;
float urgencyAnnotationsCoefficient = 0.0;
@ -74,6 +75,7 @@ void initializeUrgencyCoefficients ()
urgencyPriorityCoefficient = context.config.getReal ("urgency.priority.coefficient");
urgencyProjectCoefficient = context.config.getReal ("urgency.project.coefficient");
urgencyActiveCoefficient = context.config.getReal ("urgency.active.coefficient");
urgencyScheduledCoefficient = context.config.getReal ("urgency.scheduled.coefficient");
urgencyWaitingCoefficient = context.config.getReal ("urgency.waiting.coefficient");
urgencyBlockedCoefficient = context.config.getReal ("urgency.blocked.coefficient");
urgencyAnnotationsCoefficient = context.config.getReal ("urgency.annotations.coefficient");
@ -1131,35 +1133,14 @@ void Task::validate ()
// 2) To provide suitable warnings about odd states
// When a task has a due date, other dates should conform.
if (has ("due"))
{
Date due (get_date ("due"));
// Verify wait < due
if (has ("wait"))
{
Date wait (get_date ("wait"));
if (wait > due)
context.footnote (STRING_TASK_VALID_WAIT);
}
Date entry (get_date ("entry"));
if (has ("start"))
{
Date start (get_date ("start"));
if (entry > start)
context.footnote (STRING_TASK_VALID_START);
}
if (has ("end"))
{
Date end (get_date ("end"));
if (entry > end)
context.footnote (STRING_TASK_VALID_END);
}
}
// Date relationships.
validate_before ("wait", "due");
validate_before ("entry", "start");
validate_before ("entry", "end");
validate_before ("wait", "scheduled");
validate_before ("scheduled", "start");
validate_before ("scheduled", "due");
validate_before ("scheduled", "end");
// 3) To generate errors when the inconsistencies are not fixable
@ -1196,6 +1177,19 @@ void Task::validate ()
}
}
void Task::validate_before (const std::string& left, const std::string& right)
{
if (has (left) &&
has (right))
{
Date date_left (get_date (left));
Date date_right (get_date (right));
if (date_left > date_right)
context.footnote (format (STRING_TASK_VALID_BEFORE, left, right));
}
}
////////////////////////////////////////////////////////////////////////////////
int Task::determineVersion (const std::string& line)
{
@ -1290,6 +1284,7 @@ float Task::urgency_c () const
value += fabsf (urgencyPriorityCoefficient) > epsilon ? (urgency_priority () * urgencyPriorityCoefficient) : 0.0;
value += fabsf (urgencyProjectCoefficient) > epsilon ? (urgency_project () * urgencyProjectCoefficient) : 0.0;
value += fabsf (urgencyActiveCoefficient) > epsilon ? (urgency_active () * urgencyActiveCoefficient) : 0.0;
value += fabsf (urgencyScheduledCoefficient) > epsilon ? (urgency_scheduled () * urgencyScheduledCoefficient) : 0.0;
value += fabsf (urgencyWaitingCoefficient) > epsilon ? (urgency_waiting () * urgencyWaitingCoefficient) : 0.0;
value += fabsf (urgencyBlockedCoefficient) > epsilon ? (urgency_blocked () * urgencyBlockedCoefficient) : 0.0;
value += fabsf (urgencyAnnotationsCoefficient) > epsilon ? (urgency_annotations () * urgencyAnnotationsCoefficient) : 0.0;
@ -1305,6 +1300,7 @@ float Task::urgency_c () const
<< "# pri " << (urgency_priority () * urgencyPriorityCoefficient)
<< "# pro " << (urgency_project () * urgencyProjectCoefficient)
<< "# act " << (urgency_active () * urgencyActiveCoefficient)
<< "# sch " << (urgency_scheduled () * urgencyScheduledCoefficient)
<< "# wai " << (urgency_waiting () * urgencyWaitingCoefficient)
<< "# blk " << (urgency_blocked () * urgencyBlockedCoefficient)
<< "# ann " << (urgency_annotations () * urgencyAnnotationsCoefficient)
@ -1394,6 +1390,16 @@ float Task::urgency_active () const
return 0.0;
}
////////////////////////////////////////////////////////////////////////////////
float Task::urgency_scheduled () const
{
if (has ("scheduled") &&
get_date ("scheduled") < time (NULL))
return 1.0;
return 0.0;
}
////////////////////////////////////////////////////////////////////////////////
float Task::urgency_waiting () const
{

View file

@ -110,10 +110,12 @@ public:
private:
int determineVersion (const std::string&);
void legacyParse (const std::string&);
void validate_before (const std::string&, const std::string&);
inline float urgency_priority () const;
inline float urgency_project () const;
inline float urgency_active () const;
inline float urgency_scheduled () const;
inline float urgency_waiting () const;
inline float urgency_blocked () const;
inline float urgency_annotations () const;

View file

@ -21,6 +21,7 @@ set (columns_SRCS Column.cpp Column.h
ColPriority.cpp ColPriority.h
ColProject.cpp ColProject.h
ColRecur.cpp ColRecur.h
ColScheduled.cpp ColScheduled.h
ColStart.cpp ColStart.h
ColStatus.cpp ColStatus.h
ColString.cpp ColString.h

View file

@ -0,0 +1,118 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#define L10N // Localization complete.
#include <stdlib.h>
#include <Context.h>
#include <ColScheduled.h>
#include <Date.h>
#include <Duration.h>
#include <text.h>
#include <i18n.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
ColumnScheduled::ColumnScheduled ()
{
_name = "scheduled";
_label = STRING_COLUMN_LABEL_SCHED;
_styles.push_back ("countdown");
Date now;
now += 125;
_examples.push_back (Duration (now - Date ()).formatCompact ());
}
////////////////////////////////////////////////////////////////////////////////
ColumnScheduled::~ColumnScheduled ()
{
}
////////////////////////////////////////////////////////////////////////////////
bool ColumnScheduled::validate (std::string& value)
{
return ColumnDate::validate (value);
}
////////////////////////////////////////////////////////////////////////////////
// Overriden so that style <----> label are linked.
// Note that you can not determine which gets called first.
void ColumnScheduled::setStyle (const std::string& value)
{
_style = value;
if (_style == "countdown" && _label == STRING_COLUMN_LABEL_DUE)
_label = STRING_COLUMN_LABEL_COUNT;
}
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnScheduled::measure (Task& task, int& minimum, int& maximum)
{
minimum = maximum = 0;
if (task.has (_name))
{
if (_style == "countdown")
{
Date date ((time_t) strtol (task.get (_name).c_str (), NULL, 10));
Date now;
minimum = maximum = Duration (now - date).format ().length ();
}
else
ColumnDate::measure (task, minimum, maximum);
}
}
////////////////////////////////////////////////////////////////////////////////
void ColumnScheduled::render (
std::vector <std::string>& lines,
Task& task,
int width,
Color& color)
{
if (task.has (_name))
{
if (_style == "countdown")
{
Date date ((time_t) strtol (task.get (_name).c_str (), NULL, 10));
Date now;
lines.push_back (
color.colorize (
rightJustify (
Duration (now - date).format (), width)));
}
else
ColumnDate::render (lines, task, width, color);
}
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,47 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_COLSCHED
#define INCLUDED_COLSCHED
#define L10N // Localization complete.
#include <ColDate.h>
class ColumnScheduled : public ColumnDate
{
public:
ColumnScheduled ();
~ColumnScheduled ();
bool validate (std::string&);
void setStyle (const std::string&);
void measure (Task&, int&, int&);
void render (std::vector <std::string>&, Task&, int, Color&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -43,6 +43,7 @@
#include <ColPriority.h>
#include <ColProject.h>
#include <ColRecur.h>
#include <ColScheduled.h>
#include <ColStart.h>
#include <ColStatus.h>
#include <ColString.h>
@ -94,6 +95,7 @@ Column* Column::factory (const std::string& name, const std::string& report)
else if (column_name == "priority") c = new ColumnPriority ();
else if (column_name == "project") c = new ColumnProject ();
else if (column_name == "recur") c = new ColumnRecur ();
else if (column_name == "scheduled") c = new ColumnScheduled ();
else if (column_name == "start") c = new ColumnStart ();
else if (column_name == "status") c = new ColumnStatus ();
else if (column_name == "tags") c = new ColumnTags ();
@ -137,6 +139,7 @@ void Column::factory (std::map <std::string, Column*>& all)
c = new ColumnPriority (); all[c->_name] = c;
c = new ColumnProject (); all[c->_name] = c;
c = new ColumnRecur (); all[c->_name] = c;
c = new ColumnScheduled (); all[c->_name] = c;
c = new ColumnStart (); all[c->_name] = c;
c = new ColumnStatus (); all[c->_name] = c;
c = new ColumnTags (); all[c->_name] = c;

View file

@ -159,6 +159,7 @@ std::string CmdEdit::formatTask (Task task)
<< " Created: " << formatDate (task, "entry") << "\n"
<< " Started: " << formatDate (task, "start") << "\n"
<< " Ended: " << formatDate (task, "end") << "\n"
<< " Scheduled: " << formatDate (task, "scheduled") << "\n"
<< " Due: " << formatDate (task, "due") << "\n"
<< " Until: " << formatDate (task, "until") << "\n"
<< " Recur: " << task.get ("recur") << "\n"
@ -344,6 +345,37 @@ void CmdEdit::parseTask (Task& task, const std::string& after)
}
}
// scheduled
value = findValue (after, "\n Scheduled:");
if (value != "")
{
if (task.get ("scheduled") != "")
{
Date original (task.get_date ("scheduled"));
std::string formatted = original.toString (context.config.get ("dateformat"));
if (formatted != value)
{
context.footnote (STRING_EDIT_SCHED_MOD);
task.set ("scheduled", value);
}
}
else
{
context.footnote (STRING_EDIT_SCHED_MOD);
task.set ("scheduled", value);
}
}
else
{
if (task.get ("scheduled") != "")
{
context.footnote (STRING_EDIT_SCHED_DEL);
task.setStatus (Task::pending);
task.remove ("scheduled");
}
}
// due
value = findValue (after, "\n Due:");
if (value != "")

View file

@ -244,6 +244,14 @@ int CmdInfo::execute (std::string& output)
view.set (row, 1, Date (task->get_date ("wait")).toString (dateformat));
}
// scheduled
if (task->has ("scheduled"))
{
row = view.addRow ();
view.set (row, 0, STRING_COLUMN_LABEL_SCHED);
view.set (row, 1, Date (task->get_date ("scheduled")).toString (dateformat));
}
// start
if (task->has ("start"))
{

View file

@ -112,6 +112,7 @@ int CmdShow::execute (std::string& output)
" color.pri.M"
" color.pri.none"
" color.recurring"
" color.scheduled"
" color.summary.background"
" color.summary.bar"
" color.sync.added"
@ -185,6 +186,7 @@ int CmdShow::execute (std::string& output)
" taskd.credentials"
" undo.style"
" urgency.active.coefficient"
" urgency.scheduled.coefficient"
" urgency.annotations.coefficient"
" urgency.blocked.coefficient"
" urgency.blocking.coefficient"

View file

@ -182,6 +182,7 @@
#define STRING_COLUMN_LABEL_COLUMN "Columns"
#define STRING_COLUMN_LABEL_STYLES "Supported Formats"
#define STRING_COLUMN_LABEL_EXAMPLES "Example"
#define STRING_COLUMN_LABEL_SCHED "Scheduled"
// Column Examples
#define STRING_COLUMN_EXAMPLES_TAGS "home @chore"
@ -615,6 +616,8 @@
#define STRING_EDIT_END_MOD "End date modified."
#define STRING_EDIT_END_DEL "End date removed."
#define STRING_EDIT_END_SET_ERR "Cannot set a done date on a pending task."
#define STRING_EDIT_SCHED_MOD "Scheduled date modified."
#define STRING_EDIT_SCHED_DEL "Scheduled date removed."
#define STRING_EDIT_DUE_MOD "Due date modified."
#define STRING_EDIT_DUE_DEL "Due date removed."
#define STRING_EDIT_DUE_DEL_ERR "Cannot remove a due date from a recurring task."
@ -761,9 +764,7 @@
#define STRING_TASK_DEPEND_CIRCULAR "Circular dependency detected and disallowed."
#define STRING_TASK_VALID_DESC "A task must have a description."
#define STRING_TASK_VALID_BLANK "Cannot add a task that is blank."
#define STRING_TASK_VALID_WAIT "Warning: You have specified a 'wait' date that is after the 'due' date."
#define STRING_TASK_VALID_START "Warning: You have specified a 'start' date that is before the 'entry' date."
#define STRING_TASK_VALID_END "Warning: You have specified an 'end' date that is before the 'entry' date."
#define STRING_TASK_VALID_BEFORE "Warning: You have specified that the '{1}' date is after the '{2}' date."
#define STRING_TASK_VALID_REC_DUE "A recurring task must also have a 'due' date."
#define STRING_TASK_VALID_UNTIL "Only recurring tasks may have an 'until' date."
#define STRING_TASK_VALID_RECUR "The recurrence value '{1}' is not valid."
@ -873,12 +874,14 @@
" priority: Priority\n" \
" due: Due date\n" \
" recur: Recurrence frequency\n" \
" until: Recurrence end date\n" \
" until: Expiration date of a task\n" \
" limit: Desired number of rows in report, or 'page'\n" \
" wait: Date until task becomes pending\n" \
" entry: Date task was created\n" \
" end: Date task was completed/deleted\n" \
" start: Date task was started\n" \
" scheduled: Date task is scheduled to start\n" \
" depends: Other tasks that this task depends upon\n" \
"\n" \
"Attribute modifiers make filters more precise. Supported modifiers are:\n" \
" before (synonyms under, below)\n" \

View file

@ -139,6 +139,14 @@ static void colorizeActive (Task& task, const std::string& rule, Color& c)
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeScheduled (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial () &&
task.has ("scheduled"))
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeTag (Task& task, const std::string& rule, Color& c)
{
@ -291,6 +299,7 @@ void autoColorize (Task& task, Color& c)
else if (*r == "color.pri.H") colorizePriorityH (task, *r, c);
else if (*r == "color.pri.none") colorizePriorityNone (task, *r, c);
else if (*r == "color.active") colorizeActive (task, *r, c);
else if (*r == "color.scheduled") colorizeScheduled (task, *r, c);
else if (*r == "color.project.none") colorizeProjectNone (task, *r, c);
else if (*r == "color.tag.none") colorizeTagNone (task, *r, c);
else if (*r == "color.due") colorizeDue (task, *r, c);