Commands - summary

- Migrated handleReportSummary to CmdSummary.
This commit is contained in:
Paul Beckingham 2011-05-30 12:49:45 -04:00
parent 61c2e2b439
commit 75e651626d
9 changed files with 226 additions and 139 deletions

View file

@ -134,7 +134,6 @@ void Cmd::load ()
commands.push_back ("delete"); commands.push_back ("delete");
commands.push_back ("done"); commands.push_back ("done");
commands.push_back ("import"); commands.push_back ("import");
commands.push_back ("summary");
commands.push_back ("timesheet"); commands.push_back ("timesheet");
commands.push_back ("undo"); commands.push_back ("undo");
commands.push_back ("merge"); commands.push_back ("merge");
@ -199,7 +198,6 @@ bool Cmd::isReadOnlyCommand ()
if (command == "_query" || if (command == "_query" ||
command == "calendar" || command == "calendar" ||
command == "push" || command == "push" ||
command == "summary" ||
command == "timesheet" || command == "timesheet" ||
validCustom (command)) validCustom (command))
return true; return true;

View file

@ -249,8 +249,7 @@ int Context::dispatch (std::string &out)
Timer t ("Context::dispatch"); Timer t ("Context::dispatch");
// TODO Chain-of-command pattern dispatch. // TODO Chain-of-command pattern dispatch.
if (cmd.command == "summary") { rc = handleReportSummary (out); } if (cmd.command == "calendar") { rc = handleReportCalendar (out); }
else if (cmd.command == "calendar") { rc = handleReportCalendar (out); }
else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); } else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); }
else if (cmd.command == "done") { rc = handleDone (out); } else if (cmd.command == "done") { rc = handleDone (out); }
else if (cmd.command == "delete") { rc = handleDelete (out); } else if (cmd.command == "delete") { rc = handleDelete (out); }

View file

@ -35,6 +35,7 @@ set (commands_SRCS Command.cpp Command.h
CmdStart.cpp CmdStart.h CmdStart.cpp CmdStart.h
CmdStatistics.cpp CmdStatistics.h CmdStatistics.cpp CmdStatistics.h
CmdStop.cpp CmdStop.h CmdStop.cpp CmdStop.h
CmdSummary.cpp CmdSummary.h
CmdTags.cpp CmdTags.h CmdTags.cpp CmdTags.h
CmdTip.cpp CmdTip.h CmdTip.cpp CmdTip.h
CmdUrgency.cpp CmdUrgency.h CmdUrgency.cpp CmdUrgency.h

View file

@ -115,10 +115,6 @@ int CmdHelp::execute (const std::string&, std::string& output)
view.set (row, 1, "task done ID [tags] [attrs] [desc...]"); view.set (row, 1, "task done ID [tags] [attrs] [desc...]");
view.set (row, 2, "Marks the specified task as completed."); view.set (row, 2, "Marks the specified task as completed.");
row = view.addRow ();
view.set (row, 1, "task summary");
view.set (row, 2, "Shows a report of task status by project.");
row = view.addRow (); row = view.addRow ();
view.set (row, 1, "task timesheet [weeks]"); view.set (row, 1, "task timesheet [weeks]");
view.set (row, 2, "Shows a weekly report of tasks completed and started."); view.set (row, 2, "Shows a weekly report of tasks completed and started.");

180
src/commands/CmdSummary.cpp Normal file
View file

@ -0,0 +1,180 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <sstream>
#include <Context.h>
#include <ViewText.h>
#include <Duration.h>
#include <text.h>
#include <main.h>
#include <CmdSummary.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdSummary::CmdSummary ()
{
_keyword = "summary";
_usage = "task summary";
_description = "Shows a report of task status by project.";
_read_only = true;
_displays_id = false;
}
////////////////////////////////////////////////////////////////////////////////
// Project Remaining Avg Age Complete 0% 100%
// A 12 13d 55% XXXXXXXXXXXXX-----------
// B 109 3d 12h 10% XXX---------------------
int CmdSummary::execute (const std::string&, std::string& output)
{
int rc = 0;
// Scan the pending tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Generate unique list of project names from all pending tasks.
std::map <std::string, bool> allProjects;
std::vector <Task>::iterator task;
for (task = tasks.begin (); task != tasks.end (); ++task)
if (task->getStatus () == Task::pending)
allProjects[task->get ("project")] = false;
// Initialize counts, sum.
std::map <std::string, int> countPending;
std::map <std::string, int> countCompleted;
std::map <std::string, double> sumEntry;
std::map <std::string, int> counter;
time_t now = time (NULL);
// Initialize counters.
std::map <std::string, bool>::iterator project;
for (project = allProjects.begin (); project != allProjects.end (); ++project)
{
countPending [project->first] = 0;
countCompleted [project->first] = 0;
sumEntry [project->first] = 0.0;
counter [project->first] = 0;
}
// Count the various tasks.
for (task = tasks.begin (); task != tasks.end (); ++task)
{
std::string project = task->get ("project");
++counter[project];
if (task->getStatus () == Task::pending ||
task->getStatus () == Task::waiting)
{
++countPending[project];
time_t entry = atoi (task->get ("entry").c_str ());
if (entry)
sumEntry[project] = sumEntry[project] + (double) (now - entry);
}
else if (task->getStatus () == Task::completed)
{
++countCompleted[project];
time_t entry = atoi (task->get ("entry").c_str ());
time_t end = atoi (task->get ("end").c_str ());
if (entry && end)
sumEntry[project] = sumEntry[project] + (double) (end - entry);
}
}
// Create a table for output.
ViewText view;
view.width (context.getWidth ());
view.add (Column::factory ("string", "Project"));
view.add (Column::factory ("string.right", "Remaining"));
view.add (Column::factory ("string.right", "Avg age"));
view.add (Column::factory ("string.right", "Complete"));
view.add (Column::factory ("string", "0% 100%"));
Color bar_color (context.config.get ("color.summary.bar"));
Color bg_color (context.config.get ("color.summary.background"));
int barWidth = 30;
std::map <std::string, bool>::iterator i;
for (i = allProjects.begin (); i != allProjects.end (); ++i)
{
if (countPending[i->first] > 0)
{
int row = view.addRow ();
view.set (row, 0, (i->first == "" ? "(none)" : i->first));
view.set (row, 1, countPending[i->first]);
if (counter[i->first])
view.set (row, 2, Duration ((int) (sumEntry[i->first] / (double)counter[i->first])).format ());
int c = countCompleted[i->first];
int p = countPending[i->first];
int completedBar = (c * barWidth) / (c + p);
std::string bar;
std::string subbar;
if (context.color ())
{
bar += bar_color.colorize (std::string ( completedBar, ' '));
bar += bg_color.colorize (std::string (barWidth - completedBar, ' '));
}
else
{
bar += std::string ( completedBar, '=')
+ std::string (barWidth - completedBar, ' ');
}
view.set (row, 4, bar);
char percent[12];
sprintf (percent, "%d%%", 100 * c / (c + p));
view.set (row, 3, percent);
}
}
std::stringstream out;
if (view.rows ())
out << optionalBlankLine ()
<< view.render ()
<< optionalBlankLine ()
<< view.rows ()
<< (view.rows () == 1 ? " project" : " projects")
<< "\n";
else {
out << "No projects.\n";
rc = 1;
}
output = out.str ();
return rc;
}
////////////////////////////////////////////////////////////////////////////////

42
src/commands/CmdSummary.h Normal file
View file

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_CMDSUMMARY
#define INCLUDED_CMDSUMMARY
#define L10N // Localization complete.
#include <string>
#include <Command.h>
class CmdSummary : public Command
{
public:
CmdSummary ();
int execute (const std::string&, std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -57,6 +57,7 @@
#include <CmdStart.h> #include <CmdStart.h>
#include <CmdStatistics.h> #include <CmdStatistics.h>
#include <CmdStop.h> #include <CmdStop.h>
#include <CmdSummary.h>
#include <CmdTags.h> #include <CmdTags.h>
#include <CmdTip.h> #include <CmdTip.h>
#include <CmdUrgency.h> #include <CmdUrgency.h>
@ -108,6 +109,7 @@ void Command::factory (std::map <std::string, Command*>& all)
c = new CmdStart (); all[c->keyword ()] = c; c = new CmdStart (); all[c->keyword ()] = c;
c = new CmdStatistics (); all[c->keyword ()] = c; c = new CmdStatistics (); all[c->keyword ()] = c;
c = new CmdStop (); all[c->keyword ()] = c; c = new CmdStop (); all[c->keyword ()] = c;
c = new CmdSummary (); all[c->keyword ()] = c;
c = new CmdTags (); all[c->keyword ()] = c; c = new CmdTags (); all[c->keyword ()] = c;
c = new CmdTip (); all[c->keyword ()] = c; c = new CmdTip (); all[c->keyword ()] = c;
c = new CmdUrgency (); all[c->keyword ()] = c; c = new CmdUrgency (); all[c->keyword ()] = c;

View file

@ -66,7 +66,6 @@ int deltaAttributes (Task&);
int deltaSubstitutions (Task&); int deltaSubstitutions (Task&);
// report.cpp // report.cpp
int handleReportSummary (std::string&);
int handleReportCalendar (std::string&); int handleReportCalendar (std::string&);
int handleReportTimesheet (std::string&); int handleReportTimesheet (std::string&);
std::string getFullDescription (Task&, const std::string&); std::string getFullDescription (Task&, const std::string&);

View file

@ -51,136 +51,6 @@ static void countTasks (const std::vector <Task>&, const std::string&, const std
extern Context context; extern Context context;
////////////////////////////////////////////////////////////////////////////////
// Project Remaining Avg Age Complete 0% 100%
// A 12 13d 55% XXXXXXXXXXXXX-----------
// B 109 3d 12h 10% XXX---------------------
int handleReportSummary (std::string& outs)
{
int rc = 0;
// Scan the pending tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
// Generate unique list of project names from all pending tasks.
std::map <std::string, bool> allProjects;
std::vector <Task>::iterator task;
for (task = tasks.begin (); task != tasks.end (); ++task)
if (task->getStatus () == Task::pending)
allProjects[task->get ("project")] = false;
// Initialize counts, sum.
std::map <std::string, int> countPending;
std::map <std::string, int> countCompleted;
std::map <std::string, double> sumEntry;
std::map <std::string, int> counter;
time_t now = time (NULL);
// Initialize counters.
foreach (project, allProjects)
{
countPending [project->first] = 0;
countCompleted [project->first] = 0;
sumEntry [project->first] = 0.0;
counter [project->first] = 0;
}
// Count the various tasks.
for (task = tasks.begin (); task != tasks.end (); ++task)
{
std::string project = task->get ("project");
++counter[project];
if (task->getStatus () == Task::pending ||
task->getStatus () == Task::waiting)
{
++countPending[project];
time_t entry = atoi (task->get ("entry").c_str ());
if (entry)
sumEntry[project] = sumEntry[project] + (double) (now - entry);
}
else if (task->getStatus () == Task::completed)
{
++countCompleted[project];
time_t entry = atoi (task->get ("entry").c_str ());
time_t end = atoi (task->get ("end").c_str ());
if (entry && end)
sumEntry[project] = sumEntry[project] + (double) (end - entry);
}
}
// Create a table for output.
ViewText view;
view.width (context.getWidth ());
view.add (Column::factory ("string", "Project"));
view.add (Column::factory ("string.right", "Remaining"));
view.add (Column::factory ("string.right", "Avg age"));
view.add (Column::factory ("string.right", "Complete"));
view.add (Column::factory ("string", "0% 100%"));
Color bar_color (context.config.get ("color.summary.bar"));
Color bg_color (context.config.get ("color.summary.background"));
int barWidth = 30;
foreach (i, allProjects)
{
if (countPending[i->first] > 0)
{
int row = view.addRow ();
view.set (row, 0, (i->first == "" ? "(none)" : i->first));
view.set (row, 1, countPending[i->first]);
if (counter[i->first])
view.set (row, 2, Duration ((int) (sumEntry[i->first] / (double)counter[i->first])).format ());
int c = countCompleted[i->first];
int p = countPending[i->first];
int completedBar = (c * barWidth) / (c + p);
std::string bar;
std::string subbar;
if (context.color ())
{
bar += bar_color.colorize (std::string ( completedBar, ' '));
bar += bg_color.colorize (std::string (barWidth - completedBar, ' '));
}
else
{
bar += std::string ( completedBar, '=')
+ std::string (barWidth - completedBar, ' ');
}
view.set (row, 4, bar);
char percent[12];
sprintf (percent, "%d%%", 100 * c / (c + p));
view.set (row, 3, percent);
}
}
std::stringstream out;
if (view.rows ())
out << optionalBlankLine ()
<< view.render ()
<< optionalBlankLine ()
<< view.rows ()
<< (view.rows () == 1 ? " project" : " projects")
<< "\n";
else {
out << "No projects.\n";
rc = 1;
}
outs = out.str ();
return rc;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int handleReportTimesheet (std::string& outs) int handleReportTimesheet (std::string& outs)
{ {