From 0891d3ea63a8bd1b74b1df2d2dae46e00aa65a96 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 1 Jul 2009 00:15:32 -0400 Subject: [PATCH] Enhancement - undo - Implemented new undo command. - Removed old undelete command. - Does not work yet. --- src/Cmd.cpp | 2 - src/TDB.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++++++----- src/i18n.h | 2 +- src/util.cpp | 3 ++ 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/Cmd.cpp b/src/Cmd.cpp index e925e5352..ec3761530 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -132,7 +132,6 @@ void Cmd::load () commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary")); commands.push_back (context.stringtable.get (CMD_TAGS, "tags")); commands.push_back (context.stringtable.get (CMD_TIMESHEET, "timesheet")); - commands.push_back (context.stringtable.get (CMD_UNDELETE, "undelete")); commands.push_back (context.stringtable.get (CMD_UNDO, "undo")); commands.push_back (context.stringtable.get (CMD_VERSION, "version")); @@ -218,7 +217,6 @@ bool Cmd::isWriteCommand () command == context.stringtable.get (CMD_IMPORT, "import") || command == context.stringtable.get (CMD_START, "start") || command == context.stringtable.get (CMD_STOP, "stop") || - command == context.stringtable.get (CMD_UNDELETE, "undelete") || command == context.stringtable.get (CMD_UNDO, "undo")) return true; diff --git a/src/TDB.cpp b/src/TDB.cpp index f7a594b30..11610a7b8 100644 --- a/src/TDB.cpp +++ b/src/TDB.cpp @@ -493,23 +493,131 @@ int TDB::nextId () //////////////////////////////////////////////////////////////////////////////// void TDB::undo () { - // TODO Load all undo.data + std::string location = expandPath (context.config.get ("data.location")); - // TODO Load all pending.data - std::vector allPending; + std::string undoFile = location + "/undo.data"; + std::string pendingFile = location + "/pending.data"; + std::string completedFile = location + "/completed.data"; - // TODO Load all completed.data - std::vector allCompleted; + // load undo.data + std::vector u; + slurp (undoFile, u); - // TODO 'pop' last transaction - // TODO Locate 'new' task + if (u.size () < 3) + throw std::string ("There are no recorded transactions to undo."); - // TODO Confirm - // TODO Overwrite 'old' task, or delete + // pop last tx + u.pop_back (); - // TODO Write all pending.data - // TODO Write all completed.data - // TODO Write all undo.data + std::string current = u.back ().substr (4, std::string::npos); + u.pop_back (); + + std::string prior; + std::string when; + if (u.back ().substr (0, 5) == "time ") + { + when = u.back ().substr (5, std::string::npos); + prior = ""; + } + else + { + prior = u.back ().substr (4, std::string::npos); + u.pop_back (); + when = u.back ().substr (5, std::string::npos); + u.pop_back (); + } + + // confirm + Task priorTask (prior); + Task currentTask (current); + std::cout << "The last modification was that " + << taskDifferences (prior, current) + << std::endl + << std::endl; + + if (!confirm ("Are you sure you want to undo the last update?")) + throw std::string ("No changes made."); + + // Extract identifying uuid. + std::string uuid; + std::string::size_type uuidAtt = current.find ("uuid:\""); + if (uuidAtt != std::string::npos) + uuid = current.substr (uuidAtt, 43); // 43 = uuid:"..." + else + throw std::string ("Cannot locate UUID in task to undo."); + + std::cout << "# " << uuid << std::endl; + + // load pending.data + std::vector p; + slurp (pendingFile, p); + + // is 'current' in pending? + foreach (task, p) + { + if (task->find (uuid) != std::string::npos) + { + // Either revert if there was a prior state, or remove the task. + if (prior != "") + { + *task = prior; + std::cout << "Modified task reverted." << std::endl; + } + else + { + p.erase (task); + std::cout << "Task removed." << std::endl; + } + + // Rewrite files. + spit (pendingFile, p); + spit (undoFile, u); + return; + } + } + + // load completed.data + std::vector c; + slurp (pendingFile, p); + + // is 'current' in completed? + foreach (task, c) + { + if (task->find (uuid) != std::string::npos) + { + // If task now belongs back in pending.data + if (prior.find ("status:\"pending\"") != std::string::npos || + prior.find ("status:\"waiting\"") != std::string::npos || + prior.find ("status:\"recurring\"") != std::string::npos) + { + c.erase (task); + p.push_back (prior); + spit (completedFile, c); + spit (pendingFile, p); + spit (undoFile, u); + std::cout << "Modified task reverted." << std::endl; + } + else + { + *task = prior; + spit (completedFile, c); + spit (undoFile, u); + std::cout << "Modified task reverted." << std::endl; + } + + std::cout << "Undo complete." << std::endl; + return; + } + } + + // Perhaps user hand-edited the data files? + // Perhaps the task was in completed.data, which was still in file format 3? + std::cout << "Task with UUID " + << uuid.substr (6, 36) + << " not found in data." + << std::endl + << "No undo possible." + << std::endl; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/i18n.h b/src/i18n.h index 36e4c649f..3693ec1f9 100644 --- a/src/i18n.h +++ b/src/i18n.h @@ -92,7 +92,7 @@ #define CMD_SUMMARY 223 #define CMD_TAGS 224 #define CMD_TIMESHEET 225 -#define CMD_UNDELETE 226 + #define CMD_UNDO 227 #define CMD_VERSION 228 #define CMD_SHELL 229 diff --git a/src/util.cpp b/src/util.cpp index 1ec2d9050..922bfb7d6 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -513,9 +513,12 @@ std::string taskDifferences (const Task& before, const Task& after) if (out.str ().length () == 0) out << "No changes were made. "; +/* std::stringstream decorated; decorated << "Task " << before.id << " was modified. " << out.str (); return decorated.str (); +*/ + return out.str (); } ////////////////////////////////////////////////////////////////////////////////