Enhancement - history report

- Implemented history report.
- Improved (not to the point of them working) filters.
- Improved automatic filter construction.
- Removed obsolete members from Task.
- Added tag support to the "add" command.
This commit is contained in:
Paul Beckingham 2009-06-14 12:09:57 -04:00
parent 85e38e67d3
commit 9f6b112003
7 changed files with 89 additions and 111 deletions

View file

@ -173,8 +173,8 @@ std::string Context::dispatch ()
else if (cmd.command == "help") { out = longUsage (); } else if (cmd.command == "help") { out = longUsage (); }
else if (cmd.command == "stats") { out = handleReportStats (); } else if (cmd.command == "stats") { out = handleReportStats (); }
else if (cmd.command == "info") { out = handleInfo (); } else if (cmd.command == "info") { out = handleInfo (); }
/*
else if (cmd.command == "history") { out = handleReportHistory (); } else if (cmd.command == "history") { out = handleReportHistory (); }
/*
else if (cmd.command == "ghistory") { out = handleReportGHistory (); } else if (cmd.command == "ghistory") { out = handleReportGHistory (); }
else if (cmd.command == "calendar") { out = handleReportCalendar (); } else if (cmd.command == "calendar") { out = handleReportCalendar (); }
else if (cmd.command == "summary") { out = handleReportSummary (); } else if (cmd.command == "summary") { out = handleReportSummary (); }
@ -365,6 +365,7 @@ std::cout << "# parse tag addition '" << *arg << "'" << std::endl;
foundSomethingAfterSequence = true; foundSomethingAfterSequence = true;
tagAdditions.push_back (arg->substr (1, std::string::npos)); tagAdditions.push_back (arg->substr (1, std::string::npos));
task.addTag (arg->substr (1, std::string::npos));
} }
// Tags to remove begin with '-'. // Tags to remove begin with '-'.
@ -451,7 +452,7 @@ std::cout << "# parse post-termination description '" << *arg << "'"
} }
} }
if (noVerticalSpace (descCandidate)) if (descCandidate != "" && noVerticalSpace (descCandidate))
task.set ("description", descCandidate); task.set ("description", descCandidate);
// TODO task.validate () // TODO task.validate ()
@ -484,16 +485,46 @@ std::cout << "# parse post-termination description '" << *arg << "'"
void Context::constructFilter () void Context::constructFilter ()
{ {
foreach (att, task) foreach (att, task)
if (att->first != "uuid") {
filter.push_back (att->second);
// TODO this doesn't work. // TODO this doesn't work.
if (task.has ("description")) if (att->first == "description")
{ {
std::vector <std::string> words; std::vector <std::string> words;
split (words, task.get ("description"), ' '); split (words, att->second.value (), ' ');
foreach (word, words) foreach (word, words)
filter.push_back (Att ("description", "contains", *word)); {
filter.push_back (Att ("description", "has", *word));
std::cout << "Context::constructFilter " << att->first << "=" << att->second.value () << std::endl;
}
}
// TODO Don't create a uuid for every task?
// Every task has a unique uuid by default, and it shouldn't be included.
// The mechanism for filtering on tags is +/-<tag>, not tags:foo which
// means that there can only be one tag, "foo".
else if (att->first != "uuid" &&
att->first != "tags")
{
filter.push_back (att->second);
std::cout << "Context::constructFilter " << att->first << "=" << att->second.value () << std::endl;
}
}
// TODO Include Annotations as part of the description?
// Include tagAdditions.
foreach (tag, tagAdditions)
{
filter.push_back (Att ("tags", "has", *tag));
std::cout << "Context::constructFilter tags=+" << *tag << std::endl;
}
// TODO Include tagRemovals.
foreach (tag, tagRemovals)
{
filter.push_back (Att ("tags", "hasnt", *tag));
std::cout << "Context::constructFilter tags=-" << *tag << std::endl;
} }
} }

View file

@ -72,7 +72,7 @@ public:
std::string program; std::string program;
std::vector <std::string> args; std::vector <std::string> args;
Cmd cmd; Cmd cmd;
std::vector <std::string> tagAdditions; std::vector <std::string> tagAdditions; // TODO This is redundant, remove.
std::vector <std::string> tagRemovals; std::vector <std::string> tagRemovals;
private: private:

View file

@ -25,6 +25,7 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> // TODO Remove
#include <sstream> #include <sstream>
#include "Filter.h" #include "Filter.h"
#include "util.h" #include "util.h"
@ -41,6 +42,8 @@ bool Filter::pass (const Record& record) const
// but it doesn't match, fail. // but it doesn't match, fail.
foreach (att, (*this)) foreach (att, (*this))
{ {
// TODO std::cout << "Filter::pass " << att->name () << "=" << att->value () << std::endl;
// If the record doesn't have the attribute, match against a default one. // If the record doesn't have the attribute, match against a default one.
// This is because "att" may contain a modifier like "name.not:X". // This is because "att" may contain a modifier like "name.not:X".
if ((r = record.find (att->name ())) == record.end ()) if ((r = record.find (att->name ())) == record.end ())

View file

@ -74,12 +74,6 @@ public:
private: private:
int determineVersion (const std::string&); int determineVersion (const std::string&);
void legacyParse (const std::string&); void legacyParse (const std::string&);
private:
/*
std::vector<std::string> mTags;
std::vector<std::string> mRemoveTags;
*/
}; };
#endif #endif

View file

@ -73,6 +73,10 @@ std::string handleAdd ()
context.task.set ("priority", defaultPriority); context.task.set ("priority", defaultPriority);
} }
// Include tags.
foreach (tag, context.tagAdditions)
context.task.addTag (*tag);
// Only valid tasks can be added. // Only valid tasks can be added.
context.task.validate (); context.task.validate ();

View file

@ -88,22 +88,7 @@ std::string handleCustomReport (const std::string& report)
context.tdb.load (tasks, context.filter); context.tdb.load (tasks, context.filter);
context.tdb.unlock (); context.tdb.unlock ();
/* // TODO handleRecurrence (tdb, tasks);
// Load all pending tasks.
std::vector <T> tasks;
tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
// Apply filters.
{
std::string ignore;
T filterTask;
parse (filterArgs, ignore, filterTask);
filter (tasks, filterTask); // Filter from custom report
filter (tasks, task); // Filter from command line
}
*/
// Initialize colorization for subsequent auto colorization. // Initialize colorization for subsequent auto colorization.
initializeColorRules (); initializeColorRules ();

View file

@ -818,7 +818,8 @@ std::string handleReportNext ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Year Month Added Completed Deleted // Year Month Added Completed Deleted
// 2006 November 87 63 14 // 2006 November 87 63 14
// 2006 December 21 6 1 // December 21 6 1
// 2007 January 3 12 0
time_t monthlyEpoch (const std::string& date) time_t monthlyEpoch (const std::string& date)
{ {
// Convert any date in epoch form to m/d/y, then convert back // Convert any date in epoch form to m/d/y, then convert back
@ -839,34 +840,33 @@ time_t monthlyEpoch (const std::string& date)
std::string handleReportHistory () std::string handleReportHistory ()
{ {
std::stringstream out; std::map <time_t, int> groups; // Represents any month with data
/* std::map <time_t, int> addedGroup; // Additions by month
std::map <time_t, int> groups; std::map <time_t, int> completedGroup; // Completions by month
std::map <time_t, int> addedGroup; std::map <time_t, int> deletedGroup; // Deletions by month
std::map <time_t, int> completedGroup;
std::map <time_t, int> deletedGroup;
// Scan the pending tasks. // Scan the pending tasks.
std::vector <T> pending; std::vector <Task> tasks;
tdb.allPendingT (pending); context.tdb.lock (context.config.get ("locking", true));
handleRecurrence (tdb, pending); context.tdb.load (tasks, context.filter);
filter (pending, task); context.tdb.unlock ();
for (unsigned int i = 0; i < pending.size (); ++i) // TODO handleRecurrence (tdb, tasks);
{
T task (pending[i]); foreach (task, tasks)
time_t epoch = monthlyEpoch (task.getAttribute ("entry"));
if (epoch)
{ {
time_t epoch = monthlyEpoch (task->get ("entry"));
groups[epoch] = 0; groups[epoch] = 0;
// Every task has an entry date.
if (addedGroup.find (epoch) != addedGroup.end ()) if (addedGroup.find (epoch) != addedGroup.end ())
addedGroup[epoch] = addedGroup[epoch] + 1; addedGroup[epoch] = addedGroup[epoch] + 1;
else else
addedGroup[epoch] = 1; addedGroup[epoch] = 1;
if (task.getStatus () == T::deleted) // All deleted tasks have an end date.
if (task->getStatus () == Task::deleted)
{ {
epoch = monthlyEpoch (task.getAttribute ("end")); epoch = monthlyEpoch (task->get ("end"));
groups[epoch] = 0; groups[epoch] = 0;
if (deletedGroup.find (epoch) != deletedGroup.end ()) if (deletedGroup.find (epoch) != deletedGroup.end ())
@ -874,9 +874,11 @@ std::string handleReportHistory ()
else else
deletedGroup[epoch] = 1; deletedGroup[epoch] = 1;
} }
else if (task.getStatus () == T::completed)
// All completed tasks have an end date.
else if (task->getStatus () == Task::completed)
{ {
epoch = monthlyEpoch (task.getAttribute ("end")); epoch = monthlyEpoch (task->get ("end"));
groups[epoch] = 0; groups[epoch] = 0;
if (completedGroup.find (epoch) != completedGroup.end ()) if (completedGroup.find (epoch) != completedGroup.end ())
@ -885,48 +887,6 @@ std::string handleReportHistory ()
completedGroup[epoch] = 1; completedGroup[epoch] = 1;
} }
} }
}
// Scan the completed tasks.
std::vector <T> completed;
tdb.allCompletedT (completed);
filter (completed, task);
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"));
groups[epoch] = 0;
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"));
groups[epoch] = 0;
if (completedGroup.find (epoch) != completedGroup.end ())
completedGroup[epoch] = completedGroup[epoch] + 1;
else
completedGroup[epoch] = 1;
}
}
}
// Now build the table. // Now build the table.
Table table; Table table;
@ -1019,13 +979,14 @@ std::string handleReportHistory ()
table.addCell (row, 5, (totalAdded - totalCompleted - totalDeleted) / (table.rowCount () - 2)); table.addCell (row, 5, (totalAdded - totalCompleted - totalDeleted) / (table.rowCount () - 2));
} }
std::stringstream out;
if (table.rowCount ()) if (table.rowCount ())
out << optionalBlankLine () out << optionalBlankLine ()
<< table.render () << table.render ()
<< std::endl; << std::endl;
else else
out << "No tasks." << std::endl; out << "No tasks." << std::endl;
*/
return out.str (); return out.str ();
} }