Dependencies

- Supports new "depends" attribute.
- Supports "task <id> depends:1,2".
- Supports "task <id> depends:-1,-2".
- Supports id <--> uuid mapping in TDB.
This commit is contained in:
Paul Beckingham 2010-07-12 01:05:25 -04:00
parent c6f6d405e3
commit 7e5c0eb9a5
6 changed files with 127 additions and 1 deletions

View file

@ -63,6 +63,7 @@ static const char* modifiableNames[] =
"recur",
"until",
"wait",
"depends",
};
// Synonyms on the same line.

View file

@ -304,6 +304,10 @@ int TDB::loadPending (std::vector <Task>& tasks, Filter& filter)
task.id = mId++;
mPending.push_back (task);
// Maintain mapping for ease of link/dependency resolution.
mI2U[task.id] = task.get ("uuid");
mU2I[task.get ("uuid")] = task.id;
}
++line_number;
@ -425,6 +429,8 @@ int TDB::loadCompleted (std::vector <Task>& tasks, Filter& filter)
void TDB::add (const Task& task)
{
mNew.push_back (task);
mI2U[task.id] = task.get ("uuid");
mU2I[task.get ("uuid")] = task.id;
}
////////////////////////////////////////////////////////////////////////////////
@ -1425,6 +1431,26 @@ void TDB::merge (const std::string& mergeFile)
mods.clear();
}
////////////////////////////////////////////////////////////////////////////////
std::string TDB::uuid (int id) const
{
std::map <int, std::string>::const_iterator i;
if ((i = mI2U.find (id)) != mI2U.end ())
return i->second;
return "";
}
////////////////////////////////////////////////////////////////////////////////
int TDB::id (const std::string& uuid) const
{
std::map <std::string, int>::const_iterator i;
if ((i = mU2I.find (uuid)) != mU2I.end ())
return i->second;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
FILE* TDB::openAndLock (const std::string& file)
{

View file

@ -64,6 +64,9 @@ public:
void undo ();
void merge (const std::string&);
std::string uuid (int) const;
int id (const std::string&) const;
private:
FILE* openAndLock (const std::string&);
void writeUndo (const Task&, FILE*);
@ -79,6 +82,9 @@ private:
std::vector <Task> mCompleted; // Contents of pending.data
std::vector <Task> mNew; // Uncommitted new tasks
std::vector <Task> mModified; // Uncommitted modified tasks
std::map <int, std::string> mI2U; // ID -> UUID map
std::map <std::string, int> mU2I; // UUID -> ID map
};
#endif

View file

@ -467,6 +467,72 @@ void Task::removeAnnotations ()
}
}
////////////////////////////////////////////////////////////////////////////////
void Task::addDependency (int id)
{
std::string uuid = context.tdb.uuid (id);
if (uuid == "")
{
std::stringstream s;
s << "Could not create a dependency on task " << id << " - not found.";
throw s.str ();
}
std::string depends = get ("depends");
if (depends.length ())
{
if (depends.find (uuid) == std::string::npos)
set ("depends", depends + "," + uuid);
}
else
set ("depends", uuid);
}
////////////////////////////////////////////////////////////////////////////////
void Task::removeDependency (int id)
{
std::string uuid = context.tdb.uuid (id);
if (uuid == "")
{
std::stringstream s;
s << "Could not find a UUID for id " << id << ".";
throw s.str ();
}
std::vector <std::string> deps;
split (deps, get ("depends"), ',');
std::vector <std::string>::iterator i;
i = std::find (deps.begin (), deps.end (), uuid);
if (i != deps.end ())
{
deps.erase (i);
std::string combined;
join (combined, ",", deps);
set ("depends", combined);
}
}
////////////////////////////////////////////////////////////////////////////////
void Task::getDependencies (std::vector <int>& all) const
{
std::vector <std::string> deps;
split (deps, get ("depends"), ',');
all.clear ();
std::vector <std::string>::iterator i;
for (i = deps.begin (); i != deps.end (); ++i)
all.push_back (context.tdb.id (*i));
}
////////////////////////////////////////////////////////////////////////////////
void Task::getDependencies (std::vector <std::string>& all) const
{
all.clear ();
split (all, get ("depends"), ',');
}
////////////////////////////////////////////////////////////////////////////////
int Task::getTagCount ()
{

View file

@ -73,6 +73,11 @@ public:
void addAnnotation (const std::string&);
void removeAnnotations ();
void addDependency (int);
void removeDependency (int);
void getDependencies (std::vector <int>&) const;
void getDependencies (std::vector <std::string>&) const;
void validate () const;
private:

View file

@ -99,6 +99,8 @@ int handleAdd (std::string &outs)
!context.task.has ("recur"))
throw std::string ("You cannot specify an until date for a non-recurring task.");
// TODO Resolve dependencies.
// Only valid tasks can be added.
context.task.validate ();
@ -164,6 +166,8 @@ int handleLog (std::string &outs)
foreach (tag, context.tagAdditions)
context.task.addTag (*tag);
// TODO Resolve dependencies.
// Only valid tasks can be added.
context.task.validate ();
@ -2231,7 +2235,25 @@ int deltaAttributes (Task& task)
task.setStatus (Task::waiting);
}
if (att->second.value () == "")
// Modifying dependencies requires adding/removing uuids.
else if (att->second.name () == "depends")
{
std::vector <std::string> deps;
split (deps, att->second.value (), ',');
std::vector <std::string>::iterator i;
for (i = deps.begin (); i != deps.end (); i++)
{
int id = atoi (i->c_str ());
if (id < 0)
task.removeDependency (-id);
else
task.addDependency (id);
}
}
// Now the generalized handling.
else if (att->second.value () == "")
task.remove (att->second.name ());
else
// One of the few places where the compound attribute name is used.