diff --git a/src/commands/CmdAdd.cpp b/src/commands/CmdAdd.cpp index ee2b43fc5..68dc37460 100644 --- a/src/commands/CmdAdd.cpp +++ b/src/commands/CmdAdd.cpp @@ -63,7 +63,7 @@ int CmdAdd::execute (std::string& output) // Apply the command line modifications to the new task. Arguments modifications = context.args.extract_modifications (); - modify_task (task, modifications); + modify_task_description_replace (task, modifications); apply_defaults (task); // Only valid tasks can be added. diff --git a/src/commands/CmdDelete.cpp b/src/commands/CmdDelete.cpp index fff51b7cb..0948ac4e3 100644 --- a/src/commands/CmdDelete.cpp +++ b/src/commands/CmdDelete.cpp @@ -50,14 +50,12 @@ CmdDelete::CmdDelete () int CmdDelete::execute (std::string& output) { int rc = 0; + int count = 0; std::stringstream out; - context.disallowModification (); - std::vector tasks; context.tdb.lock (context.config.getBoolean ("locking")); context.tdb.loadPending (tasks); - std::vector all = tasks; // Apply filter. std::vector filtered; @@ -69,6 +67,9 @@ int CmdDelete::execute (std::string& output) return 1; } + // Apply the command line modifications to the new task. + Arguments modifications = context.args.extract_modifications (); + // Determine the end date. char endTime[16]; sprintf (endTime, "%u", (unsigned int) time (NULL)); @@ -79,6 +80,9 @@ int CmdDelete::execute (std::string& output) if (task->getStatus () == Task::pending || task->getStatus () == Task::waiting) { + modify_task_annotate (*task, modifications); + apply_defaults (*task); + std::stringstream question; question << "Permanently delete task " << task->id @@ -98,7 +102,7 @@ int CmdDelete::execute (std::string& output) // Scan all pending tasks for siblings of this task, and the parent // itself, and delete them. std::vector ::iterator sibling; - for (sibling = all.begin (); sibling != all.end (); ++sibling) + for (sibling = tasks.begin (); sibling != tasks.end (); ++sibling) { if (sibling->get ("parent") == parent || sibling->get ("uuid") == parent) @@ -110,7 +114,13 @@ int CmdDelete::execute (std::string& output) if (! sibling->has ("end")) sibling->set ("end", endTime); + // Apply the command line modifications to the sibling. + modify_task_annotate (*sibling, modifications); + apply_defaults (*sibling); + + sibling->validate (); context.tdb.update (*sibling); + ++count; if (context.config.getBoolean ("echo.command")) out << "Deleting recurring task " @@ -125,14 +135,16 @@ int CmdDelete::execute (std::string& output) { // Update mask in parent. task->setStatus (Task::deleted); - updateRecurrenceMask (all, *task); + updateRecurrenceMask (tasks, *task); // Don't want a 'delete' to clobber the end date that may have // been written by a 'done' command. if (! task->has ("end")) task->set ("end", endTime); + task->validate (); context.tdb.update (*task); + ++count; out << "Deleting recurring task " << task->id @@ -153,7 +165,9 @@ int CmdDelete::execute (std::string& output) if (! task->has ("end")) task->set ("end", endTime); + task->validate (); context.tdb.update (*task); + ++count; if (context.config.getBoolean ("echo.command")) out << "Deleting task " @@ -183,7 +197,9 @@ int CmdDelete::execute (std::string& output) } } - context.tdb.commit (); + if (count) + context.tdb.commit (); + context.tdb.unlock (); output = out.str (); diff --git a/src/commands/CmdDone.cpp b/src/commands/CmdDone.cpp index bfbf3fb19..b8ac425c7 100644 --- a/src/commands/CmdDone.cpp +++ b/src/commands/CmdDone.cpp @@ -68,6 +68,9 @@ int CmdDone::execute (std::string& output) return 1; } + // Apply the command line modifications to the completed task. + Arguments modifications = context.args.extract_modifications (); + Permission permission; if (filtered.size () > (size_t) context.config.getInteger ("bulk")) permission.bigSequence (); @@ -81,9 +84,7 @@ int CmdDone::execute (std::string& output) { Task before (*task); - // Apply the command line modifications to the new task. - Arguments modifications = context.args.extract_modifications (); - modify_task (*task, modifications); + modify_task_annotate (*task, modifications); apply_defaults (*task); // Add an end date. diff --git a/src/commands/CmdLog.cpp b/src/commands/CmdLog.cpp index 7ce7c8665..e05da47d4 100644 --- a/src/commands/CmdLog.cpp +++ b/src/commands/CmdLog.cpp @@ -63,7 +63,7 @@ int CmdLog::execute (std::string& output) // Apply the command line modifications to the new task. Arguments modifications = context.args.extract_modifications (); - modify_task (task, modifications); + modify_task_description_replace (task, modifications); apply_defaults (task); // Recurring tasks get a special status. diff --git a/src/commands/CmdStart.cpp b/src/commands/CmdStart.cpp index 6c9df28bf..aa65b4cd2 100644 --- a/src/commands/CmdStart.cpp +++ b/src/commands/CmdStart.cpp @@ -27,7 +27,9 @@ #include #include +#include #include +#include #include extern Context context; @@ -46,50 +48,72 @@ CmdStart::CmdStart () int CmdStart::execute (std::string& output) { int rc = 0; -/* + int count = 0; std::stringstream out; - context.disallowModification (); - std::vector tasks; context.tdb.lock (context.config.getBoolean ("locking")); - Filter filter; - context.tdb.loadPending (tasks, filter); + context.tdb.loadPending (tasks); - // Filter sequence. - context.filter.applySequence (tasks, context.sequence); - if (tasks.size () == 0) + // Apply filter. + std::vector filtered; + filter (tasks, filtered); + + if (filtered.size () == 0) { - context.footnote ("No tasks specified."); + context.footnote (STRING_FEEDBACK_NO_TASKS_SP); return 1; } + // Apply the command line modifications to the started task. + Arguments modifications = context.args.extract_modifications (); + + Permission permission; + if (filtered.size () > (size_t) context.config.getInteger ("bulk")) + permission.bigSequence (); + bool nagged = false; std::vector ::iterator task; - for (task = tasks.begin (); task != tasks.end (); ++task) + for (task = filtered.begin (); task != filtered.end (); ++task) { if (! task->has ("start")) { + Task before (*task); + + modify_task_annotate (*task, modifications); + apply_defaults (*task); + + // Add a start time. char startTime[16]; sprintf (startTime, "%u", (unsigned int) time (NULL)); - task->set ("start", startTime); if (context.config.getBoolean ("journal.time")) task->addAnnotation (context.config.get ("journal.time.start.annotation")); - context.tdb.update (*task); + // Only allow valid tasks. + task->validate (); + + if (taskDiff (before, *task)) + { + if (permission.confirmed (before, taskDifferences (before, *task) + STRING_CMD_DONE_PROCEED)) + { + context.tdb.update (*task); + ++count; + + if (context.config.getBoolean ("echo.command")) + out << "Started " + << task->id + << " '" + << task->get ("description") + << "'.\n"; + + dependencyChainOnStart (*task); + } + } - if (context.config.getBoolean ("echo.command")) - out << "Started " - << task->id - << " '" - << task->get ("description") - << "'.\n"; if (!nagged) nagged = nag (*task); - - dependencyChainOnStart (*task); } else { @@ -102,11 +126,12 @@ int CmdStart::execute (std::string& output) } } - context.tdb.commit (); + if (count) + context.tdb.commit (); + context.tdb.unlock (); output = out.str (); -*/ return rc; } diff --git a/src/commands/CmdStop.cpp b/src/commands/CmdStop.cpp index 219184dde..f691c4f5f 100644 --- a/src/commands/CmdStop.cpp +++ b/src/commands/CmdStop.cpp @@ -27,7 +27,9 @@ #include #include +#include #include +#include #include extern Context context; @@ -46,42 +48,64 @@ CmdStop::CmdStop () int CmdStop::execute (std::string& output) { int rc = 0; -/* + int count = 0; std::stringstream out; - context.disallowModification (); - std::vector tasks; context.tdb.lock (context.config.getBoolean ("locking")); - Filter filter; - context.tdb.loadPending (tasks, filter); + context.tdb.loadPending (tasks); - // Filter sequence. - context.filter.applySequence (tasks, context.sequence); - if (tasks.size () == 0) + // Apply filter. + std::vector filtered; + filter (tasks, filtered); + + if (filtered.size () == 0) { - context.footnote ("No tasks specified."); + context.footnote (STRING_FEEDBACK_NO_TASKS_SP); return 1; } + // Apply the command line modifications to the stopped task. + Arguments modifications = context.args.extract_modifications (); + + Permission permission; + if (filtered.size () > (size_t) context.config.getInteger ("bulk")) + permission.bigSequence (); + std::vector ::iterator task; - for (task = tasks.begin (); task != tasks.end (); ++task) + for (task = filtered.begin (); task != filtered.end (); ++task) { if (task->has ("start")) { + Task before (*task); + + modify_task_annotate (*task, modifications); + apply_defaults (*task); + + // Remove the start time. task->remove ("start"); if (context.config.getBoolean ("journal.time")) task->addAnnotation (context.config.get ("journal.time.stop.annotation")); - context.tdb.update (*task); + // Only allow valid tasks. + task->validate (); - if (context.config.getBoolean ("echo.command")) - out << "Stopped " - << task->id - << " '" - << task->get ("description") - << "'.\n"; + if (taskDiff (before, *task)) + { + if (permission.confirmed (before, taskDifferences (before, *task) + STRING_CMD_DONE_PROCEED)) + { + context.tdb.update (*task); + ++count; + + if (context.config.getBoolean ("echo.command")) + out << "Stopped " + << task->id + << " '" + << task->get ("description") + << "'.\n"; + } + } } else { @@ -94,11 +118,12 @@ int CmdStop::execute (std::string& output) } } - context.tdb.commit (); + if (count) + context.tdb.commit (); + context.tdb.unlock (); output = out.str (); -*/ return rc; } diff --git a/src/commands/CmdUndo.cpp b/src/commands/CmdUndo.cpp index ea63795ae..08635615e 100644 --- a/src/commands/CmdUndo.cpp +++ b/src/commands/CmdUndo.cpp @@ -46,7 +46,7 @@ CmdUndo::CmdUndo () //////////////////////////////////////////////////////////////////////////////// int CmdUndo::execute (std::string& output) { - context.disallowModification (); + // TODO Detect attemps to modify the task. context.tdb.lock (context.config.getBoolean ("locking")); context.tdb.undo (); diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp index a534b84b2..a805a2ed3 100644 --- a/src/commands/Command.cpp +++ b/src/commands/Command.cpp @@ -285,10 +285,52 @@ void Command::filter (std::vector & input, std::vector & output) //////////////////////////////////////////////////////////////////////////////// // Apply the modifications in arguments to the task. -void Command::modify_task (Task& task, Arguments& arguments) +void Command::modify_task_description_replace (Task& task, Arguments& arguments) { std::string description; + modify_task (task, arguments, description); + if (description.length ()) + task.set ("description", description); +} + +//////////////////////////////////////////////////////////////////////////////// +void Command::modify_task_description_prepend (Task& task, Arguments& arguments) +{ + std::string description; + modify_task (task, arguments, description); + + if (description.length ()) + task.set ("description", description + " " + task.get ("description")); +} + +//////////////////////////////////////////////////////////////////////////////// +void Command::modify_task_description_append (Task& task, Arguments& arguments) +{ + std::string description; + modify_task (task, arguments, description); + + if (description.length ()) + task.set ("description", task.get ("description") + " " + description); +} + +//////////////////////////////////////////////////////////////////////////////// +void Command::modify_task_annotate (Task& task, Arguments& arguments) +{ + std::string description; + modify_task (task, arguments, description); + + if (description.length ()) + task.addAnnotation (description); +} + +//////////////////////////////////////////////////////////////////////////////// +// Worker function that does all the updates, but never overwrites description. +void Command::modify_task ( + Task& task, + Arguments& arguments, + std::string& description) +{ std::vector ::iterator arg; for (arg = arguments.begin (); arg != arguments.end (); ++arg) { @@ -370,10 +412,6 @@ void Command::modify_task (Task& task, Arguments& arguments) else throw format (STRING_CMD_MOD_UNEXPECTED, arg->_first); } - - // Only update description if one was specified. - if (description.length ()) - task.set ("description", description); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/Command.h b/src/commands/Command.h index 4379551e1..466999da1 100644 --- a/src/commands/Command.h +++ b/src/commands/Command.h @@ -54,7 +54,11 @@ public: protected: void filter (std::vector &, std::vector &); - void modify_task (Task&, Arguments&); + void modify_task_description_replace (Task&, Arguments&); + void modify_task_description_prepend (Task&, Arguments&); + void modify_task_description_append (Task&, Arguments&); + void modify_task_annotate (Task&, Arguments&); + void modify_task (Task&, Arguments&, std::string&); void apply_defaults (Task&); protected: