diff --git a/src/Cmd.cpp b/src/Cmd.cpp index ed42a003c..abfd48ca2 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -129,7 +129,6 @@ void Cmd::load () { if (commands.size () == 0) { - commands.push_back ("delete"); commands.push_back ("merge"); commands.push_back ("push"); commands.push_back ("pull"); @@ -201,7 +200,6 @@ bool Cmd::isReadOnlyCommand () bool Cmd::isWriteCommand () { if (command == "merge" || - command == "delete" || command == "pull") return true; diff --git a/src/Context.cpp b/src/Context.cpp index fbdc77791..da584f334 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -249,8 +249,7 @@ int Context::dispatch (std::string &out) Timer t ("Context::dispatch"); // TODO Chain-of-command pattern dispatch. - if (cmd.command == "delete") { rc = handleDelete (out); } - else if (cmd.command == "merge") { tdb.gc (); + if (cmd.command == "merge") { tdb.gc (); handleMerge (out); } else if (cmd.command == "push") { handlePush (out); } else if (cmd.command == "pull") { handlePull (out); } diff --git a/src/command.cpp b/src/command.cpp index f6427592d..66cc80f49 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -226,147 +226,6 @@ void handlePull (std::string&) "'pull.default.uri' entry in your .taskrc file."); } -//////////////////////////////////////////////////////////////////////////////// -int handleDelete (std::string& outs) -{ - int rc = 0; - std::stringstream out; - - context.disallowModification (); - - std::vector tasks; - context.tdb.lock (context.config.getBoolean ("locking")); - Filter filter; - context.tdb.loadPending (tasks, filter); - - // Filter sequence. - std::vector all = tasks; - context.filter.applySequence (tasks, context.sequence); - if (tasks.size () == 0) - { - std::cout << "No tasks specified.\n"; - return 1; - } - - // Determine the end date. - char endTime[16]; - sprintf (endTime, "%u", (unsigned int) time (NULL)); - - foreach (task, tasks) - { - if (task->getStatus () == Task::pending || - task->getStatus () == Task::waiting) - { - std::stringstream question; - question << "Permanently delete task " - << task->id - << " '" - << task->get ("description") - << "'?"; - - if (!context.config.getBoolean ("confirmation") || confirm (question.str ())) - { - // Check for the more complex case of a recurring task. If this is a - // recurring task, get confirmation to delete them all. - std::string parent = task->get ("parent"); - if (parent != "") - { - if (confirm ("This is a recurring task. Do you want to delete all pending recurrences of this same task?")) - { - // Scan all pending tasks for siblings of this task, and the parent - // itself, and delete them. - foreach (sibling, all) - { - if (sibling->get ("parent") == parent || - sibling->get ("uuid") == parent) - { - sibling->setStatus (Task::deleted); - - // Don't want a 'delete' to clobber the end date that may have - // been written by a 'done' command. - if (! sibling->has ("end")) - sibling->set ("end", endTime); - - context.tdb.update (*sibling); - - if (context.config.getBoolean ("echo.command")) - out << "Deleting recurring task " - << sibling->id - << " '" - << sibling->get ("description") - << "'.\n"; - } - } - } - else - { - // Update mask in parent. - task->setStatus (Task::deleted); - updateRecurrenceMask (all, *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); - - context.tdb.update (*task); - - out << "Deleting recurring task " - << task->id - << " '" - << task->get ("description") - << "'.\n"; - - dependencyChainOnComplete (*task); - context.footnote (onProjectChange (*task)); - } - } - else - { - task->setStatus (Task::deleted); - - // 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); - - context.tdb.update (*task); - - if (context.config.getBoolean ("echo.command")) - out << "Deleting task " - << task->id - << " '" - << task->get ("description") - << "'.\n"; - - dependencyChainOnComplete (*task); - context.footnote (onProjectChange (*task)); - } - } - else - { - out << "Task not deleted.\n"; - rc = 1; - } - } - else - { - out << "Task " - << task->id - << " '" - << task->get ("description") - << "' is neither pending nor waiting.\n"; - rc = 1; - } - } - - context.tdb.commit (); - context.tdb.unlock (); - - outs = out.str (); - return rc; -} - //////////////////////////////////////////////////////////////////////////////// int handleModify (std::string& outs) { diff --git a/src/commands/CMakeLists.txt b/src/commands/CMakeLists.txt index 451df72e4..d7c6fa6f3 100644 --- a/src/commands/CMakeLists.txt +++ b/src/commands/CMakeLists.txt @@ -16,6 +16,7 @@ set (commands_SRCS Command.cpp Command.h CmdConfig.cpp CmdConfig.h CmdCount.cpp CmdCount.h CmdCustom.cpp CmdCustom.h + CmdDelete.cpp CmdDelete.h CmdDenotate.cpp CmdDenotate.h CmdDiagnostics.cpp CmdDiagnostics.h CmdDone.cpp CmdDone.h diff --git a/src/commands/CmdDelete.cpp b/src/commands/CmdDelete.cpp new file mode 100644 index 000000000..f3e18e8e6 --- /dev/null +++ b/src/commands/CmdDelete.cpp @@ -0,0 +1,190 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +CmdDelete::CmdDelete () +{ + _keyword = "delete"; + _usage = "task delete ID"; + _description = "Deletes the specified task."; + _read_only = false; + _displays_id = false; +} + +//////////////////////////////////////////////////////////////////////////////// +int CmdDelete::execute (const std::string&, std::string& output) +{ + int rc = 0; + std::stringstream out; + + context.disallowModification (); + + std::vector tasks; + context.tdb.lock (context.config.getBoolean ("locking")); + Filter filter; + context.tdb.loadPending (tasks, filter); + + // Filter sequence. + std::vector all = tasks; + context.filter.applySequence (tasks, context.sequence); + if (tasks.size () == 0) + { + context.footnote ("No tasks specified."); + return 1; + } + + // Determine the end date. + char endTime[16]; + sprintf (endTime, "%u", (unsigned int) time (NULL)); + + std::vector ::iterator task; + for (task = tasks.begin (); task != tasks.end (); ++task) + { + if (task->getStatus () == Task::pending || + task->getStatus () == Task::waiting) + { + std::stringstream question; + question << "Permanently delete task " + << task->id + << " '" + << task->get ("description") + << "'?"; + + if (!context.config.getBoolean ("confirmation") || confirm (question.str ())) + { + // Check for the more complex case of a recurring task. If this is a + // recurring task, get confirmation to delete them all. + std::string parent = task->get ("parent"); + if (parent != "") + { + if (confirm ("This is a recurring task. Do you want to delete all pending recurrences of this same task?")) + { + // 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) + { + if (sibling->get ("parent") == parent || + sibling->get ("uuid") == parent) + { + sibling->setStatus (Task::deleted); + + // Don't want a 'delete' to clobber the end date that may have + // been written by a 'done' command. + if (! sibling->has ("end")) + sibling->set ("end", endTime); + + context.tdb.update (*sibling); + + if (context.config.getBoolean ("echo.command")) + out << "Deleting recurring task " + << sibling->id + << " '" + << sibling->get ("description") + << "'.\n"; + } + } + } + else + { + // Update mask in parent. + task->setStatus (Task::deleted); + updateRecurrenceMask (all, *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); + + context.tdb.update (*task); + + out << "Deleting recurring task " + << task->id + << " '" + << task->get ("description") + << "'.\n"; + + dependencyChainOnComplete (*task); + context.footnote (onProjectChange (*task)); + } + } + else + { + task->setStatus (Task::deleted); + + // 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); + + context.tdb.update (*task); + + if (context.config.getBoolean ("echo.command")) + out << "Deleting task " + << task->id + << " '" + << task->get ("description") + << "'.\n"; + + dependencyChainOnComplete (*task); + context.footnote (onProjectChange (*task)); + } + } + else + { + out << "Task not deleted.\n"; + rc = 1; + } + } + else + { + out << "Task " + << task->id + << " '" + << task->get ("description") + << "' is neither pending nor waiting.\n"; + rc = 1; + } + } + + context.tdb.commit (); + context.tdb.unlock (); + + output = out.str (); + return rc; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdDelete.h b/src/commands/CmdDelete.h new file mode 100644 index 000000000..401d08ca5 --- /dev/null +++ b/src/commands/CmdDelete.h @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_CMDDELETE +#define INCLUDED_CMDDELETE +#define L10N // Localization complete. + +#include +#include + +class CmdDelete : public Command +{ +public: + CmdDelete (); + int execute (const std::string&, std::string&); +}; + +#endif +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdHelp.cpp b/src/commands/CmdHelp.cpp index ddd0155bd..35b2da106 100644 --- a/src/commands/CmdHelp.cpp +++ b/src/commands/CmdHelp.cpp @@ -103,10 +103,6 @@ int CmdHelp::execute (const std::string&, std::string& output) view.set (row, 1, "task ID"); view.set (row, 2, "Specifying an ID without a command invokes the 'info' command."); - row = view.addRow (); - view.set (row, 1, "task delete ID"); - view.set (row, 2, "Deletes the specified task."); - row = view.addRow (); view.set (row, 1, "task merge URL"); view.set (row, 2, "Merges the specified undo.data file with the local data files."); diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp index 14f7f8d30..d5a0bc040 100644 --- a/src/commands/Command.cpp +++ b/src/commands/Command.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,7 @@ void Command::factory (std::map & all) c = new CmdCompletionVersion (); all[c->keyword ()] = c; c = new CmdConfig (); all[c->keyword ()] = c; c = new CmdCount (); all[c->keyword ()] = c; + c = new CmdDelete (); all[c->keyword ()] = c; c = new CmdDenotate (); all[c->keyword ()] = c; c = new CmdDiagnostics (); all[c->keyword ()] = c; c = new CmdDone (); all[c->keyword ()] = c; diff --git a/src/main.h b/src/main.h index cb97c2219..ae5622bd4 100644 --- a/src/main.h +++ b/src/main.h @@ -51,7 +51,6 @@ bool nag (Task&); // command.cpp int handleModify (std::string&); -int handleDelete (std::string&); void handleMerge (std::string&); void handlePush (std::string&); void handlePull (std::string&);