- Implemented "task ghistory" command to draw a bar chart.

This commit is contained in:
Paul Beckingham 2008-06-27 00:15:06 -04:00
parent 5c91a0d963
commit 6066cc3bab
6 changed files with 238 additions and 4 deletions

View file

@ -17,6 +17,7 @@ represents a feature release, and the Z represents a patch.
reports have been run (and therefore TDB::gc run) reports have been run (and therefore TDB::gc run)
+ Added averages to the "task history" report + Added averages to the "task history" report
+ Added ability to override ~/.taskrc with rc:<file> + Added ability to override ~/.taskrc with rc:<file>
+ Added bar chart history report "task ghistory"
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason + Bug: Fixed where Esc[0m sequences were being emitted for no good reason
+ Bug: Fixed underlined table headers when color is turned off + Bug: Fixed underlined table headers when color is turned off

View file

@ -415,10 +415,12 @@ with no arguments will generate a help message that lists all these commands.
% task history % task history
Year Month Added Completed Deleted Net Year Month Added Completed Deleted Net
2008 March 21 16 0 5 2008 March 21 16 0 5
April 13 11 1 1 April 13 11 1 1
May 8 14 3 -9 May 8 14 3 -9
Average 14 13 1 -1
This shows that for the three months that task has been used, March and April This shows that for the three months that task has been used, March and April
saw the total number of tasks increase, but in May the number decreased as saw the total number of tasks increase, but in May the number decreased as
@ -426,6 +428,23 @@ with no arguments will generate a help message that lists all these commands.
% task ghistory
--------------
This report shows you an overview of how many tasks were added, completed and
deleted, by month, as does "task history", but as a bar chart. It looks like this:
% task history
Year Month Added/Completed/Deleted
2008 March +++++++++++++++++++++XXXXXXXXXXXXXXXX
April +++++++++++++XXXXXXXXXXX-
May ++++++++XXXXXXXXXXXXXX---
With color enabled, the bars contain the size of each bar.
% task calendar % task calendar
--------------- ---------------

View file

@ -51,6 +51,7 @@
<li>Added "task undelete" feature to restore a (very) recently deleted <li>Added "task undelete" feature to restore a (very) recently deleted
task task
<li>Added averages to the "task history" report <li>Added averages to the "task history" report
<li>Added bar chart history report "task ghistory"
<li>Added support for rc:&lt;file&gt; to allow override of the default <li>Added support for rc:&lt;file&gt; to allow override of the default
~/.taskrc file ~/.taskrc file
<li>Fixed bug where Esc[0m sequences were being emitted for no good reason <li>Fixed bug where Esc[0m sequences were being emitted for no good reason
@ -1090,6 +1091,7 @@ on_white on_bright_white</code></pre>
task tags task tags
task summary task summary
task history task history
task ghistory
task next task next
task calendar task calendar
task active task active

View file

@ -126,6 +126,7 @@ static const char* commands[] =
"export", "export",
"help", "help",
"history", "history",
"ghistory",
"info", "info",
"list", "list",
"long", "long",

View file

@ -140,6 +140,10 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task history"); table.addCell (row, 1, "task history");
table.addCell (row, 2, "Shows a report of task history, by month"); table.addCell (row, 2, "Shows a report of task history, by month");
row = table.addRow ();
table.addCell (row, 1, "task ghistory");
table.addCell (row, 2, "Shows a graphical report of task history, by month");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task next"); table.addCell (row, 1, "task next");
table.addCell (row, 2, "Shows the most important tasks for each project"); table.addCell (row, 2, "Shows the most important tasks for each project");
@ -304,6 +308,7 @@ int main (int argc, char** argv)
else if (command == "summary") handleReportSummary (tdb, task, conf); else if (command == "summary") handleReportSummary (tdb, task, conf);
else if (command == "next") handleReportNext (tdb, task, conf); else if (command == "next") handleReportNext (tdb, task, conf);
else if (command == "history") handleReportHistory (tdb, task, conf); else if (command == "history") handleReportHistory (tdb, task, conf);
else if (command == "ghistory") handleReportGHistory (tdb, task, conf);
else if (command == "calendar") handleReportCalendar (tdb, task, conf); else if (command == "calendar") handleReportCalendar (tdb, task, conf);
else if (command == "active") handleReportActive (tdb, task, conf); else if (command == "active") handleReportActive (tdb, task, conf);
else if (command == "overdue") handleReportOverdue (tdb, task, conf); else if (command == "overdue") handleReportOverdue (tdb, task, conf);
@ -1719,6 +1724,211 @@ void handleReportHistory (const TDB& tdb, T& task, Config& conf)
std::cout << "No tasks." << std::endl; std::cout << "No tasks." << std::endl;
} }
////////////////////////////////////////////////////////////////////////////////
void handleReportGHistory (const TDB& tdb, T& task, Config& conf)
{
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true))
{
WINDOW* w = initscr ();
width = w->_maxx + 1;
endwin ();
}
#endif
int widthOfBar = width - 15; // strlen ("2008 September ")
std::map <time_t, int> groups;
std::map <time_t, int> addedGroup;
std::map <time_t, int> completedGroup;
std::map <time_t, int> deletedGroup;
// Scan the pending tasks.
std::vector <T> pending;
tdb.allPendingT (pending);
for (unsigned int i = 0; i < pending.size (); ++i)
{
T task (pending[i]);
time_t epoch = monthlyEpoch (task.getAttribute ("entry"));
if (epoch)
{
groups[epoch] = 0;
if (addedGroup.find (epoch) != addedGroup.end ())
addedGroup[epoch] = addedGroup[epoch] + 1;
else
addedGroup[epoch] = 1;
if (task.getStatus () == T::deleted)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
if (deletedGroup.find (epoch) != deletedGroup.end ())
deletedGroup[epoch] = deletedGroup[epoch] + 1;
else
deletedGroup[epoch] = 1;
}
else if (task.getStatus () == T::completed)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
if (completedGroup.find (epoch) != completedGroup.end ())
completedGroup[epoch] = completedGroup[epoch] + 1;
else
completedGroup[epoch] = 1;
}
}
}
// Scan the completed tasks.
std::vector <T> completed;
tdb.allCompletedT (completed);
for (unsigned int i = 0; i < completed.size (); ++i)
{
T task (completed[i]);
time_t epoch = monthlyEpoch (task.getAttribute ("entry"));
if (epoch)
{
groups[epoch] = 0;
if (addedGroup.find (epoch) != addedGroup.end ())
addedGroup[epoch] = addedGroup[epoch] + 1;
else
addedGroup[epoch] = 1;
epoch = monthlyEpoch (task.getAttribute ("end"));
if (task.getStatus () == T::deleted)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
if (deletedGroup.find (epoch) != deletedGroup.end ())
deletedGroup[epoch] = deletedGroup[epoch] + 1;
else
deletedGroup[epoch] = 1;
}
else if (task.getStatus () == T::completed)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
if (completedGroup.find (epoch) != completedGroup.end ())
completedGroup[epoch] = completedGroup[epoch] + 1;
else
completedGroup[epoch] = 1;
}
}
}
// Now build the table.
Table table;
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("Year");
table.addColumn ("Month");
table.addColumn ("Added/Completed/Deleted");
if (conf.get ("color", true))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
}
// Determine the longest line.
int maxLine = 0;
foreach (i, groups)
{
int line = addedGroup[i->first] + completedGroup[i->first] + deletedGroup[i->first];
if (line > maxLine)
maxLine = line;
}
if (maxLine > 0)
{
int totalAdded = 0;
int totalCompleted = 0;
int totalDeleted = 0;
int priorYear = 0;
int row = 0;
foreach (i, groups)
{
row = table.addRow ();
totalAdded += addedGroup[i->first];
totalCompleted += completedGroup[i->first];
totalDeleted += deletedGroup[i->first];
Date dt (i->first);
int m, d, y;
dt.toMDY (m, d, y);
if (y != priorYear)
{
table.addCell (row, 0, y);
priorYear = y;
}
table.addCell (row, 1, Date::monthName(m));
unsigned int addedBar = (widthOfBar * addedGroup[i->first]) / maxLine;
unsigned int completedBar = (widthOfBar * completedGroup[i->first]) / maxLine;
unsigned int deletedBar = (widthOfBar * deletedGroup[i->first]) / maxLine;
std::string bar;
if (conf.get ("color", true))
{
char number[24];
sprintf (number, "%d", addedGroup[i->first]);
std::string aBar = number;
while (aBar.length () < addedBar)
aBar = " " + aBar;
sprintf (number, "%d", completedGroup[i->first]);
std::string cBar = number;
while (cBar.length () < completedBar)
cBar = " " + cBar;
sprintf (number, "%d", deletedGroup[i->first]);
std::string dBar = number;
while (dBar.length () < deletedBar)
dBar = " " + dBar;
bar = Text::colorize (Text::black, Text::on_green, aBar);
bar += Text::colorize (Text::black, Text::on_yellow, cBar);
bar += Text::colorize (Text::black, Text::on_red, dBar);
}
else
{
std::string aBar = ""; while (aBar.length () < addedBar) aBar += "+";
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "+";
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "+";
bar = aBar + cBar + dBar;
}
table.addCell (row, 2, bar);
}
}
if (table.rowCount ())
{
std::cout << optionalBlankLine (conf)
<< table.render ()
<< std::endl;
if (conf.get ("color", true))
std::cout << "Legend: "
<< Text::colorize (Text::black, Text::on_green, "added")
<< ", "
<< Text::colorize (Text::black, Text::on_yellow, "completed")
<< ", "
<< Text::colorize (Text::black, Text::on_red, "deleted")
<< std::endl;
else
std::cout << "Legend: + added, X completed, - deleted" << std::endl;
}
else
std::cout << "No tasks." << std::endl;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// A summary of the command usage. Not useful to users, but used to display // A summary of the command usage. Not useful to users, but used to display
// usage statistics for feedback. // usage statistics for feedback.

View file

@ -69,6 +69,7 @@ void handleCompleted (const TDB&, T&, Config&);
void handleReportSummary (const TDB&, T&, Config&); void handleReportSummary (const TDB&, T&, Config&);
void handleReportNext (const TDB&, T&, Config&); void handleReportNext (const TDB&, T&, Config&);
void handleReportHistory (const TDB&, T&, Config&); void handleReportHistory (const TDB&, T&, Config&);
void handleReportGHistory (const TDB&, T&, Config&);
void handleReportUsage (const TDB&, T&, Config&); void handleReportUsage (const TDB&, T&, Config&);
void handleReportCalendar (const TDB&, T&, Config&); void handleReportCalendar (const TDB&, T&, Config&);
void handleReportActive (const TDB&, T&, Config&); void handleReportActive (const TDB&, T&, Config&);