Integration - "projects" report
- "projects" report converted to 1.8.0. - Relocated code from task.cpp to recur.cpp to allow unit tests to link without includign task.cpp and therefore main. - Removed obsolete sandbox directory. - Fixed bug where Config::load deleted the pre-loaded custom reports. - Fixed bug where Cmd::valid failed to include custom reports properly.
This commit is contained in:
10
src/Cmd.cpp
10
src/Cmd.cpp
@@ -25,7 +25,6 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include "Cmd.h"
|
#include "Cmd.h"
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -59,14 +58,9 @@ bool Cmd::valid (const std::string& input)
|
|||||||
loadCommands ();
|
loadCommands ();
|
||||||
loadCustomReports ();
|
loadCustomReports ();
|
||||||
|
|
||||||
std::string candidate = lowerCase (input);
|
|
||||||
|
|
||||||
std::vector <std::string> matches;
|
std::vector <std::string> matches;
|
||||||
autoComplete (candidate, commands, matches);
|
autoComplete (lowerCase (input), commands, matches);
|
||||||
if (0 == matches.size ())
|
return matches.size () == 1 ? true : false;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -85,8 +85,6 @@ Config::Config (const std::string& file)
|
|||||||
// not tolerated, but blank lines and comments starting with # are allowed.
|
// not tolerated, but blank lines and comments starting with # are allowed.
|
||||||
bool Config::load (const std::string& file)
|
bool Config::load (const std::string& file)
|
||||||
{
|
{
|
||||||
this->clear ();
|
|
||||||
|
|
||||||
std::ifstream in;
|
std::ifstream in;
|
||||||
in.open (file.c_str (), std::ifstream::in);
|
in.open (file.c_str (), std::ifstream::in);
|
||||||
if (in.good ())
|
if (in.good ())
|
||||||
|
|||||||
@@ -92,17 +92,13 @@ void Context::initialize (int argc, char** argv)
|
|||||||
if (locale != "")
|
if (locale != "")
|
||||||
stringtable.load (location + "/strings." + locale);
|
stringtable.load (location + "/strings." + locale);
|
||||||
|
|
||||||
// TODO Handle "--version, -v" right here.
|
// TODO Handle "--version, -v" right here?
|
||||||
|
|
||||||
// init TDB.
|
// init TDB.
|
||||||
std::vector <std::string> all;
|
std::vector <std::string> all;
|
||||||
split (all, location, ',');
|
split (all, location, ',');
|
||||||
foreach (path, all)
|
foreach (path, all)
|
||||||
tdb.location (expandPath (*path));
|
tdb.location (expandPath (*path));
|
||||||
|
|
||||||
// TODO Load pending.data.
|
|
||||||
// TODO Load completed.data.
|
|
||||||
// TODO Load deleted.data.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -112,9 +108,7 @@ int Context::run ()
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
parse (); // Parse command line.
|
parse (); // Parse command line.
|
||||||
// TODO tdb.load (Filter);
|
|
||||||
dispatch (); // Dispatch to command handlers.
|
dispatch (); // Dispatch to command handlers.
|
||||||
// TODO Auto gc.
|
|
||||||
shadow (); // Auto shadow update.
|
shadow (); // Auto shadow update.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,20 +151,19 @@ void Context::dispatch ()
|
|||||||
split (args, defaultCommand, ' ');
|
split (args, defaultCommand, ' ');
|
||||||
std::cout << "[task " << defaultCommand << "]" << std::endl;
|
std::cout << "[task " << defaultCommand << "]" << std::endl;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
loadCustomReports ();
|
/*
|
||||||
|
|
||||||
std::string command;
|
|
||||||
T task;
|
|
||||||
parse (args, command, task);
|
|
||||||
|
|
||||||
bool gcMod = false; // Change occurred by way of gc.
|
bool gcMod = false; // Change occurred by way of gc.
|
||||||
bool cmdMod = false; // Change occurred by way of command type.
|
bool cmdMod = false; // Change occurred by way of command type.
|
||||||
|
*/
|
||||||
std::string out;
|
std::string out;
|
||||||
|
/*
|
||||||
// Read-only commands with no side effects.
|
// Read-only commands with no side effects.
|
||||||
if (command == "export") { out = handleExport (tdb, task); }
|
if (command == "export") { out = handleExport (tdb, task); }
|
||||||
else if (command == "projects") { out = handleProjects (tdb, task); }
|
*/
|
||||||
|
if (cmd.command == "projects") { out = handleProjects (); }
|
||||||
|
/*
|
||||||
else if (command == "tags") { out = handleTags (tdb, task); }
|
else if (command == "tags") { out = handleTags (tdb, task); }
|
||||||
else if (command == "info") { out = handleInfo (tdb, task); }
|
else if (command == "info") { out = handleInfo (tdb, task); }
|
||||||
else if (command == "stats") { out = handleReportStats (tdb, task); }
|
else if (command == "stats") { out = handleReportStats (tdb, task); }
|
||||||
@@ -212,10 +205,9 @@ void Context::dispatch ()
|
|||||||
// and if an actual change occurred (gcMod || cmdMod).
|
// and if an actual change occurred (gcMod || cmdMod).
|
||||||
if (shadow && (gcMod || cmdMod))
|
if (shadow && (gcMod || cmdMod))
|
||||||
updateShadowFile (tdb);
|
updateShadowFile (tdb);
|
||||||
|
|
||||||
return out;
|
|
||||||
*/
|
*/
|
||||||
throw std::string ("unimplemented Context::dispatch");
|
|
||||||
|
std::cout << out;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ task_SOURCES = Config.cpp Date.cpp Record.cpp T.cpp T2.cpp TDB.cpp TDB2.cpp \
|
|||||||
Duration.cpp StringTable.cpp Location.cpp Subst.cpp Keymap.cpp \
|
Duration.cpp StringTable.cpp Location.cpp Subst.cpp Keymap.cpp \
|
||||||
Nibbler.cpp Context.cpp Cmd.cpp color.cpp parse.cpp task.cpp \
|
Nibbler.cpp Context.cpp Cmd.cpp color.cpp parse.cpp task.cpp \
|
||||||
edit.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp \
|
edit.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp \
|
||||||
import.cpp interactive.cpp \
|
import.cpp interactive.cpp recur.cpp \
|
||||||
Config.h Date.h Record.h T.h TDB.h Att.h Filter.h Sequence.h \
|
Config.h Date.h Record.h T.h TDB.h Att.h Filter.h Sequence.h \
|
||||||
Table.h Grid.h Timer.h Duration.h StringTable.h Location.h \
|
Table.h Grid.h Timer.h Duration.h StringTable.h Location.h \
|
||||||
Subst.h Keymap.h Nibbler.h Context.h Cmd.h color.h task.h
|
Subst.h Keymap.h Nibbler.h Context.h Cmd.h color.h task.h
|
||||||
|
|||||||
@@ -92,22 +92,21 @@ std::string handleAdd (TDB& tdb, T& task)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
std::string handleProjects (TDB& tdb, T& task)
|
std::string handleProjects ()
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
|
|
||||||
// Get all the tasks, including deleted ones.
|
context.filter.push_back (Att ("status", "pending"));
|
||||||
std::vector <T> tasks;
|
|
||||||
tdb.pendingT (tasks);
|
std::vector <T2> tasks;
|
||||||
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
|
int quantity = context.tdb.load (tasks, context.filter);
|
||||||
|
|
||||||
// Scan all the tasks for their project name, building a map using project
|
// Scan all the tasks for their project name, building a map using project
|
||||||
// names as keys.
|
// names as keys.
|
||||||
std::map <std::string, int> unique;
|
std::map <std::string, int> unique;
|
||||||
for (unsigned int i = 0; i < tasks.size (); ++i)
|
foreach (t, tasks)
|
||||||
{
|
unique[t->get ("project")] += 1;
|
||||||
T task (tasks[i]);
|
|
||||||
unique[task.getAttribute ("project")] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unique.size ())
|
if (unique.size ())
|
||||||
{
|
{
|
||||||
@@ -138,12 +137,14 @@ std::string handleProjects (TDB& tdb, T& task)
|
|||||||
<< optionalBlankLine ()
|
<< optionalBlankLine ()
|
||||||
<< unique.size ()
|
<< unique.size ()
|
||||||
<< (unique.size () == 1 ? " project" : " projects")
|
<< (unique.size () == 1 ? " project" : " projects")
|
||||||
|
<< " (" << quantity << (quantity == 1 ? " task" : " tasks") << ")"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
out << "No projects."
|
out << "No projects."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
|
context.tdb.unlock ();
|
||||||
return out.str ();
|
return out.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
459
src/recur.cpp
Normal file
459
src/recur.cpp
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// task - a command line task list manager.
|
||||||
|
//
|
||||||
|
// Copyright 2006 - 2009, Paul Beckingham.
|
||||||
|
// 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 <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "Context.h"
|
||||||
|
#include "Date.h"
|
||||||
|
#include "Duration.h"
|
||||||
|
#include "Table.h"
|
||||||
|
#include "TDB.h"
|
||||||
|
#include "T.h"
|
||||||
|
#include "text.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNCURSES
|
||||||
|
#include <ncurses.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Global context for use by all.
|
||||||
|
extern Context context;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Scans all tasks, and for any recurring tasks, determines whether any new
|
||||||
|
// child tasks need to be generated to fill gaps.
|
||||||
|
void handleRecurrence (TDB& tdb, std::vector <T>& tasks)
|
||||||
|
{
|
||||||
|
std::vector <T> modified;
|
||||||
|
|
||||||
|
// Look at all tasks and find any recurring ones.
|
||||||
|
foreach (t, tasks)
|
||||||
|
{
|
||||||
|
if (t->getStatus () == T::recurring)
|
||||||
|
{
|
||||||
|
// Generate a list of due dates for this recurring task, regardless of
|
||||||
|
// the mask.
|
||||||
|
std::vector <Date> due;
|
||||||
|
if (!generateDueDates (*t, due))
|
||||||
|
{
|
||||||
|
std::cout << "Task "
|
||||||
|
<< t->getUUID ()
|
||||||
|
<< " ("
|
||||||
|
<< trim (t->getDescription ())
|
||||||
|
<< ") is past its 'until' date, and has be deleted" << std::endl;
|
||||||
|
|
||||||
|
// Determine the end date.
|
||||||
|
char endTime[16];
|
||||||
|
sprintf (endTime, "%u", (unsigned int) time (NULL));
|
||||||
|
t->setAttribute ("end", endTime);
|
||||||
|
t->setStatus (T::deleted);
|
||||||
|
tdb.modifyT (*t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the mask from the parent task.
|
||||||
|
std::string mask = t->getAttribute ("mask");
|
||||||
|
|
||||||
|
// Iterate over the due dates, and check each against the mask.
|
||||||
|
bool changed = false;
|
||||||
|
unsigned int i = 0;
|
||||||
|
foreach (d, due)
|
||||||
|
{
|
||||||
|
if (mask.length () <= i)
|
||||||
|
{
|
||||||
|
mask += '-';
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
T rec (*t); // Clone the parent.
|
||||||
|
rec.setId (tdb.nextId ()); // Assign a unique id.
|
||||||
|
rec.setUUID (uuid ()); // New UUID.
|
||||||
|
rec.setStatus (T::pending); // Shiny.
|
||||||
|
rec.setAttribute ("parent", t->getUUID ()); // Remember mom.
|
||||||
|
|
||||||
|
char dueDate[16];
|
||||||
|
sprintf (dueDate, "%u", (unsigned int) d->toEpoch ());
|
||||||
|
rec.setAttribute ("due", dueDate); // Store generated due date.
|
||||||
|
|
||||||
|
char indexMask[12];
|
||||||
|
sprintf (indexMask, "%u", (unsigned int) i);
|
||||||
|
rec.setAttribute ("imask", indexMask); // Store index into mask.
|
||||||
|
|
||||||
|
// Add the new task to the vector, for immediate use.
|
||||||
|
modified.push_back (rec);
|
||||||
|
|
||||||
|
// Add the new task to the DB.
|
||||||
|
tdb.addT (rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only modify the parent if necessary.
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
t->setAttribute ("mask", mask);
|
||||||
|
tdb.modifyT (*t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
modified.push_back (*t);
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks = modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Determine a start date (due), an optional end date (until), and an increment
|
||||||
|
// period (recur). Then generate a set of corresponding dates.
|
||||||
|
//
|
||||||
|
// Returns false if the parent recurring task is depleted.
|
||||||
|
bool generateDueDates (T& parent, std::vector <Date>& allDue)
|
||||||
|
{
|
||||||
|
// Determine due date, recur period and until date.
|
||||||
|
Date due (atoi (parent.getAttribute ("due").c_str ()));
|
||||||
|
std::string recur = parent.getAttribute ("recur");
|
||||||
|
|
||||||
|
bool specificEnd = false;
|
||||||
|
Date until;
|
||||||
|
if (parent.getAttribute ("until") != "")
|
||||||
|
{
|
||||||
|
until = Date (atoi (parent.getAttribute ("until").c_str ()));
|
||||||
|
specificEnd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date now;
|
||||||
|
for (Date i = due; ; i = getNextRecurrence (i, recur))
|
||||||
|
{
|
||||||
|
allDue.push_back (i);
|
||||||
|
|
||||||
|
if (specificEnd && i > until)
|
||||||
|
{
|
||||||
|
// If i > until, it means there are no more tasks to generate, and if the
|
||||||
|
// parent mask contains all + or X, then there never will be another task
|
||||||
|
// to generate, and this parent task may be safely reaped.
|
||||||
|
std::string mask = parent.getAttribute ("mask");
|
||||||
|
if (mask.length () == allDue.size () &&
|
||||||
|
mask.find ('-') == std::string::npos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > now)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Date getNextRecurrence (Date& current, std::string& period)
|
||||||
|
{
|
||||||
|
int m = current.month ();
|
||||||
|
int d = current.day ();
|
||||||
|
int y = current.year ();
|
||||||
|
|
||||||
|
// Some periods are difficult, because they can be vague.
|
||||||
|
if (period == "monthly")
|
||||||
|
{
|
||||||
|
if (++m > 12)
|
||||||
|
{
|
||||||
|
m -= 12;
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! Date::valid (m, d, y))
|
||||||
|
--d;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (period == "weekdays")
|
||||||
|
{
|
||||||
|
int dow = current.dayOfWeek ();
|
||||||
|
int days;
|
||||||
|
|
||||||
|
if (dow == 5) days = 3;
|
||||||
|
else if (dow == 6) days = 2;
|
||||||
|
else days = 1;
|
||||||
|
|
||||||
|
return current + (days * 86400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isdigit (period[0]) && period[period.length () - 1] == 'm')
|
||||||
|
{
|
||||||
|
std::string numeric = period.substr (0, period.length () - 1);
|
||||||
|
int increment = atoi (numeric.c_str ());
|
||||||
|
|
||||||
|
m += increment;
|
||||||
|
while (m > 12)
|
||||||
|
{
|
||||||
|
m -= 12;
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! Date::valid (m, d, y))
|
||||||
|
--d;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (period == "quarterly")
|
||||||
|
{
|
||||||
|
m += 3;
|
||||||
|
if (m > 12)
|
||||||
|
{
|
||||||
|
m -= 12;
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! Date::valid (m, d, y))
|
||||||
|
--d;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isdigit (period[0]) && period[period.length () - 1] == 'q')
|
||||||
|
{
|
||||||
|
std::string numeric = period.substr (0, period.length () - 1);
|
||||||
|
int increment = atoi (numeric.c_str ());
|
||||||
|
|
||||||
|
m += 3 * increment;
|
||||||
|
while (m > 12)
|
||||||
|
{
|
||||||
|
m -= 12;
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! Date::valid (m, d, y))
|
||||||
|
--d;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (period == "semiannual")
|
||||||
|
{
|
||||||
|
m += 6;
|
||||||
|
if (m > 12)
|
||||||
|
{
|
||||||
|
m -= 12;
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! Date::valid (m, d, y))
|
||||||
|
--d;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (period == "bimonthly")
|
||||||
|
{
|
||||||
|
m += 2;
|
||||||
|
if (m > 12)
|
||||||
|
{
|
||||||
|
m -= 12;
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! Date::valid (m, d, y))
|
||||||
|
--d;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (period == "biannual" ||
|
||||||
|
period == "biyearly")
|
||||||
|
{
|
||||||
|
y += 2;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (period == "annual" ||
|
||||||
|
period == "yearly")
|
||||||
|
{
|
||||||
|
y += 1;
|
||||||
|
|
||||||
|
// If the due data just happens to be 2/29 in a leap year, then simply
|
||||||
|
// incrementing y is going to create an invalid date.
|
||||||
|
if (m == 2 && d == 29)
|
||||||
|
d = 28;
|
||||||
|
|
||||||
|
return Date (m, d, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the period is an 'easy' one, add it to current, and we're done.
|
||||||
|
int days = 0;
|
||||||
|
try { Duration du (period); days = du; }
|
||||||
|
catch (...) { days = 0; }
|
||||||
|
|
||||||
|
return current + (days * 86400);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// When the status of a recurring child task changes, the parent task must
|
||||||
|
// update it's mask.
|
||||||
|
void updateRecurrenceMask (
|
||||||
|
TDB& tdb,
|
||||||
|
std::vector <T>& all,
|
||||||
|
T& task)
|
||||||
|
{
|
||||||
|
std::string parent = task.getAttribute ("parent");
|
||||||
|
if (parent != "")
|
||||||
|
{
|
||||||
|
std::vector <T>::iterator it;
|
||||||
|
for (it = all.begin (); it != all.end (); ++it)
|
||||||
|
{
|
||||||
|
if (it->getUUID () == parent)
|
||||||
|
{
|
||||||
|
unsigned int index = atoi (task.getAttribute ("imask").c_str ());
|
||||||
|
std::string mask = it->getAttribute ("mask");
|
||||||
|
if (mask.length () > index)
|
||||||
|
{
|
||||||
|
mask[index] = (task.getStatus () == T::pending) ? '-'
|
||||||
|
: (task.getStatus () == T::completed) ? '+'
|
||||||
|
: (task.getStatus () == T::deleted) ? 'X'
|
||||||
|
: '?';
|
||||||
|
|
||||||
|
it->setAttribute ("mask", mask);
|
||||||
|
tdb.modifyT (*it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string mask;
|
||||||
|
for (unsigned int i = 0; i < index; ++i)
|
||||||
|
mask += "?";
|
||||||
|
|
||||||
|
mask += (task.getStatus () == T::pending) ? '-'
|
||||||
|
: (task.getStatus () == T::completed) ? '+'
|
||||||
|
: (task.getStatus () == T::deleted) ? 'X'
|
||||||
|
: '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
return; // No point continuing the loop.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Determines whether a task is overdue. Returns
|
||||||
|
// 0 = not due at all
|
||||||
|
// 1 = imminent
|
||||||
|
// 2 = overdue
|
||||||
|
int getDueState (const std::string& due)
|
||||||
|
{
|
||||||
|
if (due.length ())
|
||||||
|
{
|
||||||
|
Date dt (::atoi (due.c_str ()));
|
||||||
|
|
||||||
|
// rightNow is the current date + time.
|
||||||
|
Date rightNow;
|
||||||
|
Date midnight (rightNow.month (), rightNow.day (), rightNow.year ());
|
||||||
|
|
||||||
|
if (dt < midnight)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
Date nextweek = midnight + 7 * 86400;
|
||||||
|
if (dt < nextweek)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void nag (TDB& tdb, T& task)
|
||||||
|
{
|
||||||
|
std::string nagMessage = context.config.get ("nag", std::string (""));
|
||||||
|
if (nagMessage != "")
|
||||||
|
{
|
||||||
|
// Load all pending tasks.
|
||||||
|
std::vector <T> pending;
|
||||||
|
tdb.allPendingT (pending);
|
||||||
|
|
||||||
|
// Counters.
|
||||||
|
int overdue = 0;
|
||||||
|
int high = 0;
|
||||||
|
int medium = 0;
|
||||||
|
int low = 0;
|
||||||
|
bool isOverdue = false;
|
||||||
|
char pri = ' ';
|
||||||
|
|
||||||
|
// Scan all pending tasks.
|
||||||
|
foreach (t, pending)
|
||||||
|
{
|
||||||
|
if (t->getId () == task.getId ())
|
||||||
|
{
|
||||||
|
if (getDueState (t->getAttribute ("due")) == 2)
|
||||||
|
isOverdue = true;
|
||||||
|
|
||||||
|
std::string priority = t->getAttribute ("priority");
|
||||||
|
if (priority.length ())
|
||||||
|
pri = priority[0];
|
||||||
|
}
|
||||||
|
else if (t->getStatus () == T::pending)
|
||||||
|
{
|
||||||
|
if (getDueState (t->getAttribute ("due")) == 2)
|
||||||
|
overdue++;
|
||||||
|
|
||||||
|
std::string priority = t->getAttribute ("priority");
|
||||||
|
if (priority.length ())
|
||||||
|
{
|
||||||
|
switch (priority[0])
|
||||||
|
{
|
||||||
|
case 'H': high++; break;
|
||||||
|
case 'M': medium++; break;
|
||||||
|
case 'L': low++; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// General form is "if there are no more deserving tasks", suppress the nag.
|
||||||
|
if (isOverdue ) return;
|
||||||
|
if (pri == 'H' && !overdue ) return;
|
||||||
|
if (pri == 'M' && !overdue && !high ) return;
|
||||||
|
if (pri == 'L' && !overdue && !high && !medium ) return;
|
||||||
|
if (pri == ' ' && !overdue && !high && !medium && !low) return;
|
||||||
|
|
||||||
|
// All the excuses are made, all that remains is to nag the user.
|
||||||
|
std::cout << nagMessage << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
1
src/sandbox/.gitignore
vendored
1
src/sandbox/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
1.8
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
PROJECT = 1.8
|
|
||||||
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti -fno-stack-check
|
|
||||||
LFLAGS =
|
|
||||||
LIBS =
|
|
||||||
OBJECTS = main.o ../Context.o ../TDB2.o ../T2.o ../Sequence.o ../Filter.o \
|
|
||||||
../Att.o ../Keymap.o ../Record.o ../StringTable.o ../Location.o \
|
|
||||||
../util.o ../text.o ../Date.o ../Config.o ../Subst.o ../Nibbler.o \
|
|
||||||
../parse.o ../Duration.o ../T.o ../Cmd.o
|
|
||||||
|
|
||||||
all: $(PROJECT)
|
|
||||||
|
|
||||||
install: $(PROJECT)
|
|
||||||
@echo unimplemented
|
|
||||||
|
|
||||||
test: $(PROJECT)
|
|
||||||
@echo unimplemented
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm *.o $(PROJECT)
|
|
||||||
|
|
||||||
.cpp.o: $(INCLUDE)
|
|
||||||
g++ -c $(CFLAGS) $<
|
|
||||||
|
|
||||||
$(PROJECT): $(OBJECTS)
|
|
||||||
g++ $(OBJECTS) $(LFLAGS) $(LIBS) -o $(PROJECT)
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include "Context.h"
|
|
||||||
|
|
||||||
Context context;
|
|
||||||
|
|
||||||
int main (int argc, char** argv)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
context.initialize (argc, argv);
|
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
|
||||||
|
|
||||||
context.filter.push_back (Att ("priority", "L"));
|
|
||||||
|
|
||||||
std::vector <T2> tasks;
|
|
||||||
int quantity = context.tdb.load (tasks, context.filter);
|
|
||||||
std::cout << "# " << quantity << " <-- context.tdb.load" << std::endl;
|
|
||||||
|
|
||||||
context.tdb.unlock ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (std::string e)
|
|
||||||
{
|
|
||||||
std::cerr << e << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::cerr << "task internal error." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
404
src/task.cpp
404
src/task.cpp
@@ -352,409 +352,6 @@ int main (int argc, char** argv)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void nag (TDB& tdb, T& task)
|
|
||||||
{
|
|
||||||
std::string nagMessage = context.config.get ("nag", std::string (""));
|
|
||||||
if (nagMessage != "")
|
|
||||||
{
|
|
||||||
// Load all pending tasks.
|
|
||||||
std::vector <T> pending;
|
|
||||||
tdb.allPendingT (pending);
|
|
||||||
|
|
||||||
// Counters.
|
|
||||||
int overdue = 0;
|
|
||||||
int high = 0;
|
|
||||||
int medium = 0;
|
|
||||||
int low = 0;
|
|
||||||
bool isOverdue = false;
|
|
||||||
char pri = ' ';
|
|
||||||
|
|
||||||
// Scan all pending tasks.
|
|
||||||
foreach (t, pending)
|
|
||||||
{
|
|
||||||
if (t->getId () == task.getId ())
|
|
||||||
{
|
|
||||||
if (getDueState (t->getAttribute ("due")) == 2)
|
|
||||||
isOverdue = true;
|
|
||||||
|
|
||||||
std::string priority = t->getAttribute ("priority");
|
|
||||||
if (priority.length ())
|
|
||||||
pri = priority[0];
|
|
||||||
}
|
|
||||||
else if (t->getStatus () == T::pending)
|
|
||||||
{
|
|
||||||
if (getDueState (t->getAttribute ("due")) == 2)
|
|
||||||
overdue++;
|
|
||||||
|
|
||||||
std::string priority = t->getAttribute ("priority");
|
|
||||||
if (priority.length ())
|
|
||||||
{
|
|
||||||
switch (priority[0])
|
|
||||||
{
|
|
||||||
case 'H': high++; break;
|
|
||||||
case 'M': medium++; break;
|
|
||||||
case 'L': low++; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// General form is "if there are no more deserving tasks", suppress the nag.
|
|
||||||
if (isOverdue ) return;
|
|
||||||
if (pri == 'H' && !overdue ) return;
|
|
||||||
if (pri == 'M' && !overdue && !high ) return;
|
|
||||||
if (pri == 'L' && !overdue && !high && !medium ) return;
|
|
||||||
if (pri == ' ' && !overdue && !high && !medium && !low) return;
|
|
||||||
|
|
||||||
// All the excuses are made, all that remains is to nag the user.
|
|
||||||
std::cout << nagMessage << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Determines whether a task is overdue. Returns
|
|
||||||
// 0 = not due at all
|
|
||||||
// 1 = imminent
|
|
||||||
// 2 = overdue
|
|
||||||
int getDueState (const std::string& due)
|
|
||||||
{
|
|
||||||
if (due.length ())
|
|
||||||
{
|
|
||||||
Date dt (::atoi (due.c_str ()));
|
|
||||||
|
|
||||||
// rightNow is the current date + time.
|
|
||||||
Date rightNow;
|
|
||||||
Date midnight (rightNow.month (), rightNow.day (), rightNow.year ());
|
|
||||||
|
|
||||||
if (dt < midnight)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
Date nextweek = midnight + 7 * 86400;
|
|
||||||
if (dt < nextweek)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Scans all tasks, and for any recurring tasks, determines whether any new
|
|
||||||
// child tasks need to be generated to fill gaps.
|
|
||||||
void handleRecurrence (TDB& tdb, std::vector <T>& tasks)
|
|
||||||
{
|
|
||||||
std::vector <T> modified;
|
|
||||||
|
|
||||||
// Look at all tasks and find any recurring ones.
|
|
||||||
foreach (t, tasks)
|
|
||||||
{
|
|
||||||
if (t->getStatus () == T::recurring)
|
|
||||||
{
|
|
||||||
// Generate a list of due dates for this recurring task, regardless of
|
|
||||||
// the mask.
|
|
||||||
std::vector <Date> due;
|
|
||||||
if (!generateDueDates (*t, due))
|
|
||||||
{
|
|
||||||
std::cout << "Task "
|
|
||||||
<< t->getUUID ()
|
|
||||||
<< " ("
|
|
||||||
<< trim (t->getDescription ())
|
|
||||||
<< ") is past its 'until' date, and has be deleted" << std::endl;
|
|
||||||
|
|
||||||
// Determine the end date.
|
|
||||||
char endTime[16];
|
|
||||||
sprintf (endTime, "%u", (unsigned int) time (NULL));
|
|
||||||
t->setAttribute ("end", endTime);
|
|
||||||
t->setStatus (T::deleted);
|
|
||||||
tdb.modifyT (*t);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the mask from the parent task.
|
|
||||||
std::string mask = t->getAttribute ("mask");
|
|
||||||
|
|
||||||
// Iterate over the due dates, and check each against the mask.
|
|
||||||
bool changed = false;
|
|
||||||
unsigned int i = 0;
|
|
||||||
foreach (d, due)
|
|
||||||
{
|
|
||||||
if (mask.length () <= i)
|
|
||||||
{
|
|
||||||
mask += '-';
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
T rec (*t); // Clone the parent.
|
|
||||||
rec.setId (tdb.nextId ()); // Assign a unique id.
|
|
||||||
rec.setUUID (uuid ()); // New UUID.
|
|
||||||
rec.setStatus (T::pending); // Shiny.
|
|
||||||
rec.setAttribute ("parent", t->getUUID ()); // Remember mom.
|
|
||||||
|
|
||||||
char dueDate[16];
|
|
||||||
sprintf (dueDate, "%u", (unsigned int) d->toEpoch ());
|
|
||||||
rec.setAttribute ("due", dueDate); // Store generated due date.
|
|
||||||
|
|
||||||
char indexMask[12];
|
|
||||||
sprintf (indexMask, "%u", (unsigned int) i);
|
|
||||||
rec.setAttribute ("imask", indexMask); // Store index into mask.
|
|
||||||
|
|
||||||
// Add the new task to the vector, for immediate use.
|
|
||||||
modified.push_back (rec);
|
|
||||||
|
|
||||||
// Add the new task to the DB.
|
|
||||||
tdb.addT (rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only modify the parent if necessary.
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
t->setAttribute ("mask", mask);
|
|
||||||
tdb.modifyT (*t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
modified.push_back (*t);
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks = modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Determine a start date (due), an optional end date (until), and an increment
|
|
||||||
// period (recur). Then generate a set of corresponding dates.
|
|
||||||
//
|
|
||||||
// Returns false if the parent recurring task is depleted.
|
|
||||||
bool generateDueDates (T& parent, std::vector <Date>& allDue)
|
|
||||||
{
|
|
||||||
// Determine due date, recur period and until date.
|
|
||||||
Date due (atoi (parent.getAttribute ("due").c_str ()));
|
|
||||||
std::string recur = parent.getAttribute ("recur");
|
|
||||||
|
|
||||||
bool specificEnd = false;
|
|
||||||
Date until;
|
|
||||||
if (parent.getAttribute ("until") != "")
|
|
||||||
{
|
|
||||||
until = Date (atoi (parent.getAttribute ("until").c_str ()));
|
|
||||||
specificEnd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Date now;
|
|
||||||
for (Date i = due; ; i = getNextRecurrence (i, recur))
|
|
||||||
{
|
|
||||||
allDue.push_back (i);
|
|
||||||
|
|
||||||
if (specificEnd && i > until)
|
|
||||||
{
|
|
||||||
// If i > until, it means there are no more tasks to generate, and if the
|
|
||||||
// parent mask contains all + or X, then there never will be another task
|
|
||||||
// to generate, and this parent task may be safely reaped.
|
|
||||||
std::string mask = parent.getAttribute ("mask");
|
|
||||||
if (mask.length () == allDue.size () &&
|
|
||||||
mask.find ('-') == std::string::npos)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > now)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
Date getNextRecurrence (Date& current, std::string& period)
|
|
||||||
{
|
|
||||||
int m = current.month ();
|
|
||||||
int d = current.day ();
|
|
||||||
int y = current.year ();
|
|
||||||
|
|
||||||
// Some periods are difficult, because they can be vague.
|
|
||||||
if (period == "monthly")
|
|
||||||
{
|
|
||||||
if (++m > 12)
|
|
||||||
{
|
|
||||||
m -= 12;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! Date::valid (m, d, y))
|
|
||||||
--d;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (period == "weekdays")
|
|
||||||
{
|
|
||||||
int dow = current.dayOfWeek ();
|
|
||||||
int days;
|
|
||||||
|
|
||||||
if (dow == 5) days = 3;
|
|
||||||
else if (dow == 6) days = 2;
|
|
||||||
else days = 1;
|
|
||||||
|
|
||||||
return current + (days * 86400);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isdigit (period[0]) && period[period.length () - 1] == 'm')
|
|
||||||
{
|
|
||||||
std::string numeric = period.substr (0, period.length () - 1);
|
|
||||||
int increment = atoi (numeric.c_str ());
|
|
||||||
|
|
||||||
m += increment;
|
|
||||||
while (m > 12)
|
|
||||||
{
|
|
||||||
m -= 12;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! Date::valid (m, d, y))
|
|
||||||
--d;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (period == "quarterly")
|
|
||||||
{
|
|
||||||
m += 3;
|
|
||||||
if (m > 12)
|
|
||||||
{
|
|
||||||
m -= 12;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! Date::valid (m, d, y))
|
|
||||||
--d;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isdigit (period[0]) && period[period.length () - 1] == 'q')
|
|
||||||
{
|
|
||||||
std::string numeric = period.substr (0, period.length () - 1);
|
|
||||||
int increment = atoi (numeric.c_str ());
|
|
||||||
|
|
||||||
m += 3 * increment;
|
|
||||||
while (m > 12)
|
|
||||||
{
|
|
||||||
m -= 12;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! Date::valid (m, d, y))
|
|
||||||
--d;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (period == "semiannual")
|
|
||||||
{
|
|
||||||
m += 6;
|
|
||||||
if (m > 12)
|
|
||||||
{
|
|
||||||
m -= 12;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! Date::valid (m, d, y))
|
|
||||||
--d;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (period == "bimonthly")
|
|
||||||
{
|
|
||||||
m += 2;
|
|
||||||
if (m > 12)
|
|
||||||
{
|
|
||||||
m -= 12;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! Date::valid (m, d, y))
|
|
||||||
--d;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (period == "biannual" ||
|
|
||||||
period == "biyearly")
|
|
||||||
{
|
|
||||||
y += 2;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (period == "annual" ||
|
|
||||||
period == "yearly")
|
|
||||||
{
|
|
||||||
y += 1;
|
|
||||||
|
|
||||||
// If the due data just happens to be 2/29 in a leap year, then simply
|
|
||||||
// incrementing y is going to create an invalid date.
|
|
||||||
if (m == 2 && d == 29)
|
|
||||||
d = 28;
|
|
||||||
|
|
||||||
return Date (m, d, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the period is an 'easy' one, add it to current, and we're done.
|
|
||||||
int days = 0;
|
|
||||||
try { Duration du (period); days = du; }
|
|
||||||
catch (...) { days = 0; }
|
|
||||||
|
|
||||||
return current + (days * 86400);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// When the status of a recurring child task changes, the parent task must
|
|
||||||
// update it's mask.
|
|
||||||
void updateRecurrenceMask (
|
|
||||||
TDB& tdb,
|
|
||||||
std::vector <T>& all,
|
|
||||||
T& task)
|
|
||||||
{
|
|
||||||
std::string parent = task.getAttribute ("parent");
|
|
||||||
if (parent != "")
|
|
||||||
{
|
|
||||||
std::vector <T>::iterator it;
|
|
||||||
for (it = all.begin (); it != all.end (); ++it)
|
|
||||||
{
|
|
||||||
if (it->getUUID () == parent)
|
|
||||||
{
|
|
||||||
unsigned int index = atoi (task.getAttribute ("imask").c_str ());
|
|
||||||
std::string mask = it->getAttribute ("mask");
|
|
||||||
if (mask.length () > index)
|
|
||||||
{
|
|
||||||
mask[index] = (task.getStatus () == T::pending) ? '-'
|
|
||||||
: (task.getStatus () == T::completed) ? '+'
|
|
||||||
: (task.getStatus () == T::deleted) ? 'X'
|
|
||||||
: '?';
|
|
||||||
|
|
||||||
it->setAttribute ("mask", mask);
|
|
||||||
tdb.modifyT (*it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string mask;
|
|
||||||
for (unsigned int i = 0; i < index; ++i)
|
|
||||||
mask += "?";
|
|
||||||
|
|
||||||
mask += (task.getStatus () == T::pending) ? '-'
|
|
||||||
: (task.getStatus () == T::completed) ? '+'
|
|
||||||
: (task.getStatus () == T::deleted) ? 'X'
|
|
||||||
: '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
return; // No point continuing the loop.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void updateShadowFile (TDB& tdb)
|
void updateShadowFile (TDB& tdb)
|
||||||
{
|
{
|
||||||
@@ -856,7 +453,6 @@ std::string runTaskCommand (
|
|||||||
|
|
||||||
// Read-only commands with no side effects.
|
// Read-only commands with no side effects.
|
||||||
if (command == "export") { out = handleExport (tdb, task); }
|
if (command == "export") { out = handleExport (tdb, task); }
|
||||||
else if (command == "projects") { out = handleProjects (tdb, task); }
|
|
||||||
else if (command == "tags") { out = handleTags (tdb, task); }
|
else if (command == "tags") { out = handleTags (tdb, task); }
|
||||||
else if (command == "info") { out = handleInfo (tdb, task); }
|
else if (command == "info") { out = handleInfo (tdb, task); }
|
||||||
else if (command == "stats") { out = handleReportStats (tdb, task); }
|
else if (command == "stats") { out = handleReportStats (tdb, task); }
|
||||||
|
|||||||
16
src/task.h
16
src/task.h
@@ -50,23 +50,25 @@ void allCustomReports (std::vector <std::string>&);
|
|||||||
|
|
||||||
// task.cpp
|
// task.cpp
|
||||||
void gatherNextTasks (const TDB&, T&, std::vector <T>&, std::vector <int>&);
|
void gatherNextTasks (const TDB&, T&, std::vector <T>&, std::vector <int>&);
|
||||||
void nag (TDB&, T&);
|
|
||||||
int getDueState (const std::string&);
|
|
||||||
void handleRecurrence (TDB&, std::vector <T>&);
|
|
||||||
bool generateDueDates (T&, std::vector <Date>&);
|
|
||||||
Date getNextRecurrence (Date&, std::string&);
|
|
||||||
void updateRecurrenceMask (TDB&, std::vector <T>&, T&);
|
|
||||||
void onChangeCallback ();
|
void onChangeCallback ();
|
||||||
std::string runTaskCommand (int, char**, TDB&, bool gc = true, bool shadow = true);
|
std::string runTaskCommand (int, char**, TDB&, bool gc = true, bool shadow = true);
|
||||||
std::string runTaskCommand (std::vector <std::string>&, TDB&, bool gc = false, bool shadow = false);
|
std::string runTaskCommand (std::vector <std::string>&, TDB&, bool gc = false, bool shadow = false);
|
||||||
|
|
||||||
|
// recur.cpp
|
||||||
|
void handleRecurrence (TDB&, std::vector <T>&);
|
||||||
|
Date getNextRecurrence (Date&, std::string&);
|
||||||
|
bool generateDueDates (T&, std::vector <Date>&);
|
||||||
|
void updateRecurrenceMask (TDB&, std::vector <T>&, T&);
|
||||||
|
int getDueState (const std::string&);
|
||||||
|
void nag (TDB&, T&);
|
||||||
|
|
||||||
// command.cpp
|
// command.cpp
|
||||||
std::string handleAdd (TDB&, T&);
|
std::string handleAdd (TDB&, T&);
|
||||||
std::string handleAppend (TDB&, T&);
|
std::string handleAppend (TDB&, T&);
|
||||||
std::string handleExport (TDB&, T&);
|
std::string handleExport (TDB&, T&);
|
||||||
std::string handleDone (TDB&, T&);
|
std::string handleDone (TDB&, T&);
|
||||||
std::string handleModify (TDB&, T&);
|
std::string handleModify (TDB&, T&);
|
||||||
std::string handleProjects (TDB&, T&);
|
std::string handleProjects ();
|
||||||
std::string handleTags (TDB&, T&);
|
std::string handleTags (TDB&, T&);
|
||||||
std::string handleUndelete (TDB&, T&);
|
std::string handleUndelete (TDB&, T&);
|
||||||
std::string handleVersion ();
|
std::string handleVersion ();
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ PROJECT = t.t t2.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \
|
|||||||
parse.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \
|
parse.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \
|
||||||
cmd.t config.t
|
cmd.t config.t
|
||||||
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
|
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
|
||||||
LFLAGS = -L/usr/local/lib
|
LFLAGS = -L/usr/local/lib -lncurses
|
||||||
OBJECTS = ../TDB.o ../TDB2.o ../T.o ../T2.o ../parse.o ../text.o ../Date.o \
|
OBJECTS = ../TDB.o ../TDB2.o ../T.o ../T2.o ../parse.o ../text.o ../Date.o \
|
||||||
../Duration.o ../util.o ../Config.o ../Sequence.o ../Att.o \
|
../Duration.o ../util.o ../Config.o ../Sequence.o ../Att.o \
|
||||||
../Record.o ../StringTable.o ../Subst.o ../Nibbler.o ../Location.o \
|
../Record.o ../StringTable.o ../Subst.o ../Nibbler.o ../Location.o \
|
||||||
../Filter.o ../Context.o ../Keymap.o ../Cmd.o
|
../Filter.o ../Context.o ../Keymap.o ../Cmd.o ../command.o \
|
||||||
|
../report.o ../Table.o ../Grid.o ../color.o ../rules.o ../recur.o
|
||||||
|
|
||||||
all: $(PROJECT)
|
all: $(PROJECT)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user