Example #1
0
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 <std::string> beforeAtts;
  Task::const_iterator att;
  for (att = before.begin (); att != before.end (); ++att)
    beforeAtts.push_back (att->first);

  std::vector <std::string> afterAtts;
  for (att = after.begin (); att != after.end (); ++att)
    afterAtts.push_back (att->first);

  std::vector <std::string> beforeOnly;
  std::vector <std::string> afterOnly;
  listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly);

  if (beforeOnly.size () !=
      afterOnly.size ())
    return true;

  std::vector <std::string>::iterator name;
  for (name = beforeAtts.begin (); name != beforeAtts.end (); ++name)
    if (*name              != "uuid" &&
        before.get (*name) != after.get (*name))
      return true;

  return false;
}
Example #2
0
void ColumnParent::render (
  std::vector <std::string>& lines,
  Task& task,
  int width,
  Color& color)
{
  if (task.has (_name))
  {
    // f30cb9c3-3fc0-483f-bfb2-3bf134f00694  default
    //                             34f00694  short
    if (_style == "default" ||
        _style == "long")
    {
      lines.push_back (color.colorize (leftJustify (task.get (_name), width)));
    }

    else if (_style == "short")
    {
      if (task.has (_name))
        lines.push_back (color.colorize (leftJustify (task.get (_name).substr (28), width)));
      else
        lines.push_back (color.colorize (leftJustify ("", width)));
    }
  }
}
Example #3
0
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 <std::string> beforeAtts;
  foreach (att, before)
    beforeAtts.push_back (att->first);

  std::vector <std::string> afterAtts;
  foreach (att, after)
    afterAtts.push_back (att->first);

  std::vector <std::string> beforeOnly;
  std::vector <std::string> 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;
}
Example #4
0
void TDB2::update (
  Task& task,
  const bool add_to_backlog,
  const bool addition /* = false */)
{
  // Validate to add metadata.
  task.validate (false);

  // If the task already exists, it is a modification, else addition.
  Task original;
  if (not addition && get (task.get ("uuid"), original))
  {
    // Update only if the tasks differ
    if (task == original)
      return;

    if (add_to_backlog)
    {
      // All locally modified tasks are timestamped, implicitly overwriting any
      // changes the user or hooks tried to apply to the "modified" attribute.
      task.setAsNow ("modified");
    }

    // Update the task, wherever it is.
    if (!pending.modify_task (task))
      completed.modify_task (task);

    // time <time>
    // old <task>
    // new <task>
    // ---
    undo.add_line ("time " + ISO8601d ().toEpochString () + "\n");
    undo.add_line ("old " + original.composeF4 () + "\n");
    undo.add_line ("new " + task.composeF4 () + "\n");
    undo.add_line ("---\n");
  }
  else
  {
    // Add new task to either pending or completed.
    std::string status = task.get ("status");
    if (status == "completed" ||
        status == "deleted")
      completed.add_task (task);
    else
      pending.add_task (task);

    // Add undo data lines:
    //   time <time>
    //   new <task>
    //   ---
    undo.add_line ("time " + ISO8601d ().toEpochString () + "\n");
    undo.add_line ("new " + task.composeF4 () + "\n");
    undo.add_line ("---\n");
  }

  // Add task to backlog.
  if (add_to_backlog)
    backlog.add_line (task.composeJSON () + "\n");
}
Example #5
0
std::string onProjectChange (Task& task1, Task& task2)
{
    if (task1.get ("project") == task2.get ("project"))
        return onProjectChange (task1);

    std::string messages = onProjectChange (task1);
    messages            += onProjectChange (task2);

    return messages;
}
Example #6
0
////////////////////////////////////////////////////////////////////////////////
// Implements:
//    Deleting task 123 'This is a test'
//
// The 'effect' string should contain:
//    {1}    ID
//    {2}    Description
void feedback_affected (const std::string& effect, const Task& task)
{
  if (context.verbose ("affected"))
  {
    if (task.id)
      std::cout << format (effect, task.id, task.get ("description"))
                << "\n";
    else
      std::cout << format (effect, task.get ("uuid"), task.get ("description"))
                << "\n";
  }
}
Example #7
0
std::string onProjectChange (Task& task1, Task& task2)
{
  if (task1.get ("project") == task2.get ("project"))
    return onProjectChange (task1, false);

  std::string messages1 = onProjectChange (task1);
  std::string messages2 = onProjectChange (task2);

  if (messages1.length () && messages2.length ())
    return messages1 + '\n' + messages2;

  return messages1 + messages2;
}
Example #8
0
////////////////////////////////////////////////////////////////////////////////
// Implements:
//    Deleting task 123 'This is a test'
//
// The 'effect' string should contain:
//    {1}    ID
//    {2}    Description
void feedback_affected (const std::string& effect, const Task& task)
{
    if (context.verbose ("affected") ||
            context.config.getBoolean ("echo.command")) // Deprecated 2.0
    {
        if (task.id)
            std::cout << format (effect, task.id, task.get ("description"))
                      << "\n";
        else
            std::cout << format (effect, task.get ("uuid"), task.get ("description"))
                      << "\n";
    }
}
Example #9
0
static void colorizeKeyword (Task& task, const std::string& rule, const Color& base, Color& c, bool merge)
{
  // Observe the case sensitivity setting.
  bool sensitive = context.config.getBoolean ("search.case.sensitive");

  // The easiest thing to check is the description, because it is just one
  // attribute.
  if (find (task.get ("description"), rule.substr (14), sensitive) != std::string::npos)
    applyColor (base, c, merge);

  // Failing the description check, look at all annotations, returning on the
  // first match.
  else
  {
    for (auto& it : task)
    {
      if (it.first.substr (0, 11) == "annotation_" &&
          find (it.second, rule.substr (14), sensitive) != std::string::npos)
      {
        applyColor (base, c, merge);
        return;
      }
    }
  }
}
Example #10
0
bool TF2::modify_task (const Task& task)
{
  std::string uuid = task.get ("uuid");

  if (context.cli2.getCommand () == "import")
  {
    // Update map used for faster lookup
    auto i = _tasks_map.find (uuid);
    if (i != _tasks_map.end ())
    {
      i->second = task;
    }
  }

  for (auto& i : _tasks)
  {
    if (i.get ("uuid") == uuid)
    {
      // Modify in-place.
      i = task;
      _modified_tasks.push_back (task);
      _dirty = true;

      return true;
    }
  }

  return false;
}
Example #11
0
const std::vector <Task> TDB2::children (Task& task)
{
  std::vector <Task> results;
  std::string parent = task.get ("uuid");

  // First load and scan pending.
  if (! pending._loaded_tasks)
    pending.load_tasks ();

  for (auto& i : pending._tasks)
  {
    // Do not include self in results.
    if (i.id != task.id)
    {
      // Do not include completed or deleted tasks.
      if (i.getStatus () != Task::completed &&
          i.getStatus () != Task::deleted)
      {
        // If task has the same parent, it is a sibling.
        if (i.get ("parent") == parent)
          results.push_back (i);
      }
    }
  }

  return results;
}
Example #12
0
static void colorizeKeyword (Task& task, const std::string& rule, const Color& base, Color& c)
{
  // Observe the case sensitivity setting.
  bool sensitive = context.config.getBoolean ("search.case.sensitive");

  // The easiest thing to check is the description, because it is just one
  // attribute.
  if (find (task.get ("description"), rule.substr (14), sensitive) != std::string::npos)
    c.blend (base);

  // Failing the description check, look at all annotations, returning on the
  // first match.
  else
  {
    Task::iterator it;
    for (it = task.begin (); it != task.end (); ++it)
    {
      if (it->first.substr (0, 11) == "annotation_" &&
          find (it->second, rule.substr (14), sensitive) != std::string::npos)
      {
        c.blend (base);
        return;
      }
    }
  }
}
Example #13
0
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnTags::measure (Task& task, int& minimum, int& maximum)
{

       if (_style == "indicator") minimum = maximum = context.config.get ("tag.indicator").length ();
  else if (_style == "count")     minimum = maximum = 3;
  else if (_style == "default" ||
           _style == "list")
  {
    std::string tags = task.get (_name);
    minimum = 0;
    maximum = tags.length ();

    if (maximum)
    {
      std::vector <std::string> all;
      split (all, tags, ',');
      std::vector <std::string>::iterator i;
      for (i = all.begin (); i != all.end (); ++i)
        if ((int)i->length () > minimum)
          minimum = i->length () + 1;
    }
  }
  else
    throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
}
Example #14
0
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnBg::measure (Task& task, int& minimum, int& maximum)
{
  std::string bg = task.get (_name);

  minimum = longestWord (bg);
  maximum = bg.length ();
}
Example #15
0
void ColumnUDA::render (
  std::vector <std::string>& lines,
  Task& task,
  int width,
  Color& color)
{
  if (task.has (_name))
  {
    if (_style == "default")
    {
      std::string value = task.get (_name);
      if (_type == "date")
      {
        // Determine the output date format, which uses a hierarchy of definitions.
        //   rc.report.<report>.dateformat
        //   rc.dateformat.report
        //   rc.dateformat.
        std::string format = context.config.get ("report." + _report + ".dateformat");
        if (format == "")
          format = context.config.get ("dateformat.report");
        if (format == "")
          format = context.config.get ("dateformat");

        lines.push_back (
          color.colorize (
            leftJustify (
              Date ((time_t) strtol (value.c_str (), NULL, 10))
                .toString (format), width)));
      }
      else if (_type == "duration")
      {
        lines.push_back (
          color.colorize (
            rightJustify (
              Duration (value).formatISO (),
              width)));
      }
      else if (_type == "string")
      {
        std::vector <std::string> raw;
        wrapText (raw, value, width, _hyphenate);

        std::vector <std::string>::iterator i;
        for (i = raw.begin (); i != raw.end (); ++i)
          lines.push_back (color.colorize (leftJustify (*i, width)));
      }
      else if (_type == "numeric")
      {
        lines.push_back (color.colorize (rightJustify (value, width)));
      }
    }
    else if (_style == "indicator")
    {
      if (task.has (_name))
        lines.push_back (
          color.colorize (
            rightJustify (context.config.get ("uda." + _name + ".indicator"), width)));
    }
  }
}
Example #16
0
////////////////////////////////////////////////////////////////////////////////
// Returns true if the supplied task adds a cycle to the dependency chain.
bool dependencyIsCircular (const Task& task)
{
  std::stack <Task> s;
  std::vector <std::string> deps_current;

  std::string task_uuid = task.get ("uuid");

  s.push (task);
  while (!s.empty ())
  {
    Task& current = s.top ();
    current.getDependencies (deps_current);

    // This is a basic depth first search that always terminates given the
    // assumption that any cycles in the dependency graph must have been
    // introduced by the task that is being checked.
    // Since any previous cycles would have been prevented by this very
    // function, this is a reasonable assumption.
    for (unsigned int i = 0; i < deps_current.size (); i++)
    {
      context.tdb2.get (deps_current[i], current);

      if (task_uuid == current.get ("uuid"))
        {
          // Cycle found, initial task reached for the second time!
          return true;
        }

      s.push (current);
    }
    s.pop ();
  }

  return false;
}
Example #17
0
std::string onExpiration (Task& task)
{
  std::stringstream msg;

  if (context.verbose ("affected"))
    msg << format (STRING_FEEDBACK_EXPIRED, task.id, task.get ("description"));

  return msg.str ();
}
Example #18
0
void ColumnMask::render (
  std::vector <std::string>& lines,
  Task& task,
  int,
  Color& color)
{
  if (task.has (_name))
    lines.push_back (color.colorize (task.get ("mask")));
}
    virtual std::size_t
    push(Task task)
    {
        // Precondition verification:
        assert(nullptr != task.get());
        assert(!m_cancelled);

        // Tries to push the task in the form of message to the input queue:
        return m_input_queue->push(task);
    }
Example #20
0
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnMask::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{
  minimum = maximum = 0;
  if (task.has (_name))
  {
    minimum = maximum = task.get ("mask").length ();

    if (_style != "default")
      throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
  }
}
Example #21
0
static void colorizeOverdue (Task& task, const Color& base, Color& c)
{
  if (task.has ("due"))
  {
    Task::status status = task.getStatus ();
    if (status != Task::completed &&
        status != Task::deleted   &&
        getDueState (task.get ("due")) == 3)
      c.blend (base);
  }
}
Example #22
0
void dependencyGetBlocked (const Task& task, std::vector <Task>& blocked)
{
  std::string uuid = task.get ("uuid");

  const std::vector <Task>& all = context.tdb2.pending.get_tasks ();
  std::vector <Task>::const_iterator it;
  for (it = all.begin (); it != all.end (); ++it)
    if ((it->getStatus () == Task::pending  ||
         it->getStatus () == Task::waiting) &&
        it->has ("depends")                 &&
        it->get ("depends").find (uuid) != std::string::npos)
      blocked.push_back (*it);
}
Example #23
0
static void colorizeProject (Task& task, const std::string& rule, const Color& base, Color& c)
{
  // Observe the case sensitivity setting.
  bool sensitive = context.config.getBoolean ("search.case.sensitive");

  std::string project = task.get ("project");
  std::string rule_trunc = rule.substr (14);

  // Match project names leftmost.
  if (rule_trunc.length () <= project.length ())
    if (compare (rule_trunc, project.substr (0, rule_trunc.length ()), sensitive))
      c.blend (base);
}
Example #24
0
std::string CmdEdit::formatDuration (
  Task& task,
  const std::string& attribute)
{
  std::string value = task.get (attribute);
  if (value.length ())
  {
    Duration dur (value);
    value = dur.formatSeconds ();
  }

  return value;
}
Example #25
0
File: Task.cpp Project: nigeil/task
////////////////////////////////////////////////////////////////////////////////
// The uuid and id attributes must be exempt from comparison.
bool Task::operator== (const Task& other)
{
  if (size () != other.size ())
    return false;

  Task::iterator i;
  for (i = this->begin (); i != this->end (); ++i)
    if (i->first != "uuid" &&
        i->second != other.get (i->first))
      return false;

  return true;
}
Example #26
0
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
//
void ColumnUDA::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{
  minimum = maximum = 0;

  if (task.has (_name))
  {
    if (_style == "default")
    {
      std::string value = task.get (_name);
      if (value != "")
      {
        if (_type == "date")
        {
          // Determine the output date format, which uses a hierarchy of definitions.
          //   rc.report.<report>.dateformat
          //   rc.dateformat.report
          //   rc.dateformat
          Date date ((time_t) strtol (value.c_str (), NULL, 10));
          std::string format = context.config.get ("report." + _report + ".dateformat");
          if (format == "")
            format = context.config.get ("dateformat.report");
          if (format == "")
            format = context.config.get ("dateformat");

          minimum = maximum = Date::length (format);
        }
        else if (_type == "duration")
        {
          minimum = maximum = utf8_width (Duration (value).formatISO ());
        }
        else if (_type == "string")
        {
          std::string stripped = Color::strip (value);
          maximum = longestLine (stripped);
          minimum = longestWord (stripped);
        }
        else if (_type == "numeric")
        {
          minimum = maximum = utf8_width (value);
        }
      }
    }
    else if (_style == "indicator")
    {
      if (task.has (_name))
        minimum = maximum = utf8_width (context.config.get ("uda." + _name + ".indicator"));
    }
    else
      throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
  }
}
Example #27
0
std::string CmdEdit::formatDate (
  Task& task,
  const std::string& attribute,
  const std::string& dateformat)
{
  std::string value = task.get (attribute);
  if (value.length ())
  {
    Date dt (value);
    value = dt.toString (dateformat);
  }

  return value;
}
Example #28
0
void dependencyGetBlocking (const Task& task, std::vector <Task>& blocking)
{
  std::string depends = task.get ("depends");
  if (depends != "")
  {
    const std::vector <Task>& all = context.tdb2.pending.get_tasks ();
    std::vector <Task>::const_iterator it;
    for (it = all.begin (); it != all.end (); ++it)
      if ((it->getStatus () == Task::pending  ||
           it->getStatus () == Task::waiting) &&
          depends.find (it->get ("uuid")) != std::string::npos)
        blocking.push_back (*it);
  }
}
Example #29
0
void TF2::add_task (Task& task)
{
  _tasks.push_back (task);           // For subsequent queries
  _added_tasks.push_back (task);     // For commit/synch

  // For faster lookup
  if (context.cli2.getCommand () == "import")
    _tasks_map.insert (std::pair<std::string, Task> (task.get("uuid"), task));

  Task::status status = task.getStatus ();
  if (task.id == 0 &&
      (status == Task::pending   ||
       status == Task::recurring ||
       status == Task::waiting))
  {
    task.id = context.tdb2.next_id ();
  }

  _I2U[task.id] = task.get ("uuid");
  _U2I[task.get ("uuid")] = task.id;

  _dirty = true;
}
Example #30
0
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnRecur::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{
  if (_style == "default" ||
      _style == "duration")
  {
    minimum = maximum = Duration (task.get ("recur")).formatCompact ().length ();
  }
  else if (_style == "indicator")
  {
    if (task.has (_name))
      minimum = maximum = context.config.get ("recurrence.indicator").length ();
  }
  else
    throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
}