/////////////////////////////////////////////////////////////////////////// Arguably does not belong here. This method reads the parse tree and calls Task methods. It could be a standalone function with no loss in access, as well as reducing the object depdendencies of Task. It came from the Command base object, but doesn't really belong there either.
| 1950 | // |
| 1951 | // It came from the Command base object, but doesn't really belong there either. |
| 1952 | void Task::modify(modType type, bool text_required /* = false */) { |
| 1953 | std::string label = " [1;37;43mMODIFICATION[0m "; |
| 1954 | |
| 1955 | // while reading the parse tree, consider DOM references in the context of |
| 1956 | // this task |
| 1957 | auto currentTask = Context::getContext().withCurrentTask(this); |
| 1958 | |
| 1959 | // Need this for later comparison. |
| 1960 | auto originalStatus = getStatus(); |
| 1961 | |
| 1962 | std::string text = ""; |
| 1963 | bool mods = false; |
| 1964 | for (auto& a : Context::getContext().cli2._args) { |
| 1965 | if (a.hasTag("MODIFICATION")) { |
| 1966 | if (a._lextype == Lexer::Type::pair) { |
| 1967 | // 'canonical' is the canonical name. Needs to be said. |
| 1968 | // 'value' requires eval. |
| 1969 | std::string name = a.attribute("canonical"); |
| 1970 | std::string value = a.attribute("value"); |
| 1971 | if (value == "" || value == "''" || value == "\"\"") { |
| 1972 | // Special case: Handle bulk removal of 'tags' and 'depends" virtual |
| 1973 | // attributes |
| 1974 | if (name == "depends") { |
| 1975 | for (auto dep : getDependencyUUIDs()) removeDependency(dep); |
| 1976 | } else if (name == "tags") { |
| 1977 | for (auto tag : getTags()) removeTag(tag); |
| 1978 | } |
| 1979 | |
| 1980 | // ::composeF4 will skip if the value is blank, but the presence of |
| 1981 | // the attribute will prevent ::validate from applying defaults. |
| 1982 | if ((has(name) && get(name) != "") || |
| 1983 | (name == "due" && Context::getContext().config.has("default.due")) || |
| 1984 | (name == "scheduled" && Context::getContext().config.has("default.scheduled")) || |
| 1985 | (name == "project" && Context::getContext().config.has("default.project"))) { |
| 1986 | mods = true; |
| 1987 | set(name, ""); |
| 1988 | } |
| 1989 | |
| 1990 | Context::getContext().debug(label + name + " <-- ''"); |
| 1991 | } else { |
| 1992 | Lexer::dequote(value); |
| 1993 | |
| 1994 | // Get the column info. Some columns are not modifiable. |
| 1995 | Column* column = Context::getContext().columns[name]; |
| 1996 | if (!column || !column->modifiable()) |
| 1997 | throw format("The '{1}' attribute does not allow a value of '{2}'.", name, value); |
| 1998 | |
| 1999 | // Delegate modification to the column object or their base classes. |
| 2000 | if (name == "depends" || name == "tags" || name == "recur" || column->type() == "date" || |
| 2001 | column->type() == "duration" || column->type() == "numeric" || |
| 2002 | column->type() == "string" || column->type() == "uuid") { |
| 2003 | column->modify(*this, value); |
| 2004 | mods = true; |
| 2005 | } |
| 2006 | |
| 2007 | else |
| 2008 | throw format("Unrecognized column type '{1}' for column '{2}'", column->type(), name); |
| 2009 | } |