diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e22789434..6171216ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,14 +4,14 @@ include_directories (${CMAKE_SOURCE_DIR}/src set (task_SRCS API.cpp API.h Att.cpp Att.h Cmd.cpp Cmd.h Color.cpp Color.h Config.cpp Config.h Context.cpp Context.h Date.cpp Date.h Directory.cpp Directory.h Duration.cpp Duration.h File.cpp - File.h Filter.cpp Filter.h Grid.cpp Grid.h Hooks.cpp Hooks.h - JSON.cpp JSON.h Keymap.cpp Keymap.h Lisp.cpp Lisp.h Location.cpp - Location.h Nibbler.cpp Nibbler.h Path.cpp Path.h Permission.cpp - Permission.h Record.cpp Record.h Rectangle.cpp Rectangle.h - Sequence.cpp Sequence.h Subst.cpp Subst.h TDB.cpp TDB.h Table.cpp - Table.h Task.cpp Task.h Taskmod.cpp Taskmod.h Thread.cpp Thread.h - Timer.cpp Timer.h Transport.cpp Transport.h TransportSSH.cpp - TransportSSH.h TransportRSYNC.cpp TransportRSYNC.h + File.h Filter.cpp Filter.h feedback.cpp Grid.cpp Grid.h Hooks.cpp + Hooks.h JSON.cpp JSON.h Keymap.cpp Keymap.h Lisp.cpp Lisp.h + Location.cpp Location.h Nibbler.cpp Nibbler.h Path.cpp Path.h + Permission.cpp Permission.h Record.cpp Record.h Rectangle.cpp + Rectangle.h Sequence.cpp Sequence.h Subst.cpp Subst.h TDB.cpp + TDB.h Table.cpp Table.h Task.cpp Task.h Taskmod.cpp Taskmod.h + Thread.cpp Thread.h Timer.cpp Timer.h Transport.cpp Transport.h + TransportSSH.cpp TransportSSH.h TransportRSYNC.cpp TransportRSYNC.h TransportCurl.cpp TransportCurl.h Tree.cpp Tree.h burndown.cpp command.cpp custom.cpp dependency.cpp diag.cpp edit.cpp export.cpp history.cpp i18n.h import.cpp interactive.cpp diff --git a/src/feedback.cpp b/src/feedback.cpp new file mode 100644 index 000000000..dbcf6803b --- /dev/null +++ b/src/feedback.cpp @@ -0,0 +1,298 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include "../cmake.h" + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +bool taskDiff (const Task& before, const Task& after) +{ + // Attributes are all there is, so figure the different attribute names + // between before and after. + std::vector beforeAtts; + foreach (att, before) + beforeAtts.push_back (att->first); + + std::vector afterAtts; + foreach (att, after) + afterAtts.push_back (att->first); + + std::vector beforeOnly; + std::vector afterOnly; + listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); + + if (beforeOnly.size () != + afterOnly.size ()) + return true; + + foreach (name, beforeAtts) + if (*name != "uuid" && + before.get (*name) != after.get (*name)) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string taskDifferences (const Task& before, const Task& after) +{ + // Attributes are all there is, so figure the different attribute names + // between before and after. + std::vector beforeAtts; + foreach (att, before) + beforeAtts.push_back (att->first); + + std::vector afterAtts; + foreach (att, after) + afterAtts.push_back (att->first); + + std::vector beforeOnly; + std::vector afterOnly; + listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); + + // Now start generating a description of the differences. + std::stringstream out; + foreach (name, beforeOnly) + out << " - " + << ucFirst(*name) + << " will be deleted.\n"; + + foreach (name, afterOnly) + { + if (*name == "depends") + { + std::vector deps_after; + after.getDependencies (deps_after); + std::string to; + join (to, ", ", deps_after); + + out << " - " + << "Dependencies" + << " will be set to '" + << to + << "'.\n"; + } + else + out << " - " + << ucFirst(*name) + << " will be set to '" + << renderAttribute (*name, after.get (*name)) + << "'.\n"; + } + + foreach (name, beforeAtts) + if (*name != "uuid" && + before.get (*name) != after.get (*name)) + { + if (*name == "depends") + { + std::vector deps_before; + before.getDependencies (deps_before); + std::string from; + join (from, ", ", deps_before); + + std::vector deps_after; + after.getDependencies (deps_after); + std::string to; + join (to, ", ", deps_after); + + out << " - " + << "Dependencies" + << " will be changed from '" + << from + << "' to '" + << to + << "'.\n"; + } + else + out << " - " + << ucFirst(*name) + << " will be changed from '" + << renderAttribute (*name, before.get (*name)) + << "' to '" + << renderAttribute (*name, after.get (*name)) + << "'.\n"; + } + + + // Shouldn't just say nothing. + if (out.str ().length () == 0) + out << " - No changes will be made.\n"; + + return out.str (); +} + +//////////////////////////////////////////////////////////////////////////////// +std::string taskInfoDifferences (const Task& before, const Task& after) +{ + // Attributes are all there is, so figure the different attribute names + // between before and after. + std::vector beforeAtts; + foreach (att, before) + beforeAtts.push_back (att->first); + + std::vector afterAtts; + foreach (att, after) + afterAtts.push_back (att->first); + + std::vector beforeOnly; + std::vector afterOnly; + listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly); + + // Now start generating a description of the differences. + std::stringstream out; + foreach (name, beforeOnly) + { + if (*name == "depends") + { + std::vector deps_before; + before.getDependencies (deps_before); + std::string from; + join (from, ", ", deps_before); + + out << "Dependencies '" + << from + << "' deleted.\n"; + } + else if (name->substr (0, 11) == "annotation_") + { + out << "Annotation '" + << before.get (*name) + << "' deleted.\n"; + } + else + { + out << ucFirst (*name) + << " deleted.\n"; + } + } + + foreach (name, afterOnly) + { + if (*name == "depends") + { + std::vector deps_after; + after.getDependencies (deps_after); + std::string to; + join (to, ", ", deps_after); + + out << "Dependencies" + << " set to '" + << to + << "'.\n"; + } + else if (name->substr (0, 11) == "annotation_") + { + out << "Annotation of '" + << after.get (*name) + << "' added.\n"; + } + else + out << ucFirst(*name) + << " set to '" + << renderAttribute (*name, after.get (*name)) + << "'.\n"; + } + + foreach (name, beforeAtts) + if (*name != "uuid" && + before.get (*name) != after.get (*name) && + before.get (*name) != "" && after.get (*name) != "") + { + if (*name == "depends") + { + std::vector deps_before; + before.getDependencies (deps_before); + std::string from; + join (from, ", ", deps_before); + + std::vector deps_after; + after.getDependencies (deps_after); + std::string to; + join (to, ", ", deps_after); + + out << "Dependencies" + << " changed from '" + << from + << "' to '" + << to + << "'.\n"; + } + else if (name->substr (0, 11) == "annotation_") + { + out << "Annotation changed to '" + << after.get (*name) + << "'.\n"; + } + else + out << ucFirst(*name) + << " changed from '" + << renderAttribute (*name, before.get (*name)) + << "' to '" + << renderAttribute (*name, after.get (*name)) + << "'.\n"; + } + + // Shouldn't just say nothing. + if (out.str ().length () == 0) + out << "No changes made.\n"; + + return out.str (); +} + +//////////////////////////////////////////////////////////////////////////////// +std::string renderAttribute (const std::string& name, const std::string& value) +{ + Att a; + if (a.type (name) == "date" && + value != "") + { + Date d ((time_t)::atoi (value.c_str ())); + return d.toString (context.config.get ("dateformat")); + } + + return value; +} + +//////////////////////////////////////////////////////////////////////////////// +// TODO Implement all the post-command feedback here. This includes project +// completion percentages, "3 tasks modified", all warnings, and so on. +std::string feedback (const Task& before, const Task& after) +{ +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/main.h b/src/main.h index cd1c57761..4f8ab5908 100644 --- a/src/main.h +++ b/src/main.h @@ -161,6 +161,13 @@ void dependencyChainOnComplete (Task&); void dependencyChainOnStart (Task&); void dependencyChainOnModify (Task&, Task&); +// feedback.cpp +bool taskDiff (const Task&, const Task&); +std::string taskDifferences (const Task&, const Task&); +std::string taskInfoDifferences (const Task&, const Task&); +std::string renderAttribute (const std::string&, const std::string&); +std::string feedback (const Task&, const Task&); + // list template /////////////////////////////////////////////////////////////////////////////// template bool listDiff (const T& left, const T& right) diff --git a/src/util.h b/src/util.h index 4108b052c..275d85bd7 100644 --- a/src/util.h +++ b/src/util.h @@ -68,10 +68,6 @@ const std::string uuid (); int flock (int, int); #endif -bool taskDiff (const Task&, const Task&); -std::string taskDifferences (const Task&, const Task&); -std::string taskInfoDifferences (const Task&, const Task&); -std::string renderAttribute (const std::string&, const std::string&); std::string compressIds (const std::vector &); #endif