Exemple #1
0
void CmdEdit::parseTask (Task& task, const std::string& after, const std::string& dateformat)
{
  // project
  std::string value = findValue (after, "\n  Project:");
  if (task.get ("project") != value)
  {
    if (value != "")
    {
      context.footnote (STRING_EDIT_PROJECT_MOD);
      task.set ("project", value);
    }
    else
    {
      context.footnote (STRING_EDIT_PROJECT_DEL);
      task.remove ("project");
    }
  }

  // tags
  value = findValue (after, "\n  Tags:");
  std::vector <std::string> tags;
  split (tags, value, ' ');
  task.remove ("tags");
  task.addTags (tags);

  // description.
  value = findMultilineValue (after, "\n  Description:", "\n  Created:");
  if (task.get ("description") != value)
  {
    if (value != "")
    {
      context.footnote (STRING_EDIT_DESC_MOD);
      task.set ("description", value);
    }
    else
      throw std::string (STRING_EDIT_DESC_REMOVE_ERR);
  }

  // entry
  value = findValue (after, "\n  Created:");
  if (value != "")
  {
    std::string formatted = formatDate (task, "entry", dateformat);

    if (formatted != value)
    {
      context.footnote (STRING_EDIT_ENTRY_MOD);
      task.set ("entry", Date(value, dateformat).toEpochString ());
    }
  }
  else
    throw std::string (STRING_EDIT_ENTRY_REMOVE_ERR);

  // start
  value = findValue (after, "\n  Started:");
  if (value != "")
  {
    if (task.get ("start") != "")
    {
      std::string formatted = formatDate (task, "start", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_START_MOD);
        task.set ("start", Date(value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_START_MOD);
      task.set ("start", Date(value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("start") != "")
    {
      context.footnote (STRING_EDIT_START_DEL);
      task.remove ("start");
    }
  }

  // end
  value = findValue (after, "\n  Ended:");
  if (value != "")
  {
    if (task.get ("end") != "")
    {
      std::string formatted = formatDate (task, "end", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_END_MOD);
        task.set ("end", Date(value, dateformat).toEpochString ());
      }
    }
    else if (task.getStatus () != Task::deleted)
      throw std::string (STRING_EDIT_END_SET_ERR);
  }
  else
  {
    if (task.get ("end") != "")
    {
      context.footnote (STRING_EDIT_END_DEL);
      task.setStatus (Task::pending);
      task.remove ("end");
    }
  }

  // scheduled
  value = findValue (after, "\n  Scheduled:");
  if (value != "")
  {
    if (task.get ("scheduled") != "")
    {
      std::string formatted = formatDate (task, "scheduled", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_SCHED_MOD);
        task.set ("scheduled", Date(value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_SCHED_MOD);
      task.set ("scheduled", Date(value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("scheduled") != "")
    {
      context.footnote (STRING_EDIT_SCHED_DEL);
      task.setStatus (Task::pending);
      task.remove ("scheduled");
    }
  }

  // due
  value = findValue (after, "\n  Due:");
  if (value != "")
  {
    if (task.get ("due") != "")
    {
      std::string formatted = formatDate (task, "due", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_DUE_MOD);
        task.set ("due", Date(value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_DUE_MOD);
      task.set ("due", Date(value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("due") != "")
    {
      if (task.getStatus () == Task::recurring ||
          task.get ("parent") != "")
      {
        context.footnote (STRING_EDIT_DUE_DEL_ERR);
      }
      else
      {
        context.footnote (STRING_EDIT_DUE_DEL);
        task.remove ("due");
      }
    }
  }

  // until
  value = findValue (after, "\n  Until:");
  if (value != "")
  {
    if (task.get ("until") != "")
    {
      std::string formatted = formatDate (task, "until", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_UNTIL_MOD);
        task.set ("until", Date(value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_UNTIL_MOD);
      task.set ("until", Date(value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("until") != "")
    {
      context.footnote (STRING_EDIT_UNTIL_DEL);
      task.remove ("until");
    }
  }

  // recur
  value = findValue (after, "\n  Recur:");
  if (value != task.get ("recur"))
  {
    if (value != "")
    {
      Duration d;
      std::string::size_type idx = 0;
      if (d.parse (value, idx))
      {
        context.footnote (STRING_EDIT_RECUR_MOD);
        if (task.get ("due") != "")
        {
          task.set ("recur", value);
          task.setStatus (Task::recurring);
        }
        else
          throw std::string (STRING_EDIT_RECUR_DUE_ERR);
      }
      else
        throw std::string (STRING_EDIT_RECUR_ERR);
    }
    else
    {
      context.footnote (STRING_EDIT_RECUR_DEL);
      task.setStatus (Task::pending);
      task.remove ("recur");
      task.remove ("until");
      task.remove ("mask");
      task.remove ("imask");
    }
  }

  // wait
  value = findValue (after, "\n  Wait until:");
  if (value != "")
  {
    if (task.get ("wait") != "")
    {
      std::string formatted = formatDate (task, "wait", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_WAIT_MOD);
        task.set ("wait", Date(value, dateformat).toEpochString ());
        task.setStatus (Task::waiting);
      }
    }
    else
    {
      context.footnote (STRING_EDIT_WAIT_MOD);
      task.set ("wait", Date(value, dateformat).toEpochString ());
      task.setStatus (Task::waiting);
    }
  }
  else
  {
    if (task.get ("wait") != "")
    {
      context.footnote (STRING_EDIT_WAIT_DEL);
      task.remove ("wait");
      task.setStatus (Task::pending);
    }
  }

  // parent
  value = findValue (after, "\n  Parent:");
  if (value != task.get ("parent"))
  {
    if (value != "")
    {
      context.footnote (STRING_EDIT_PARENT_MOD);
      task.set ("parent", value);
    }
    else
    {
      context.footnote (STRING_EDIT_PARENT_DEL);
      task.remove ("parent");
    }
  }

  // Annotations
  std::map <std::string, std::string> annotations;
  std::string::size_type found = 0;
  while ((found = after.find ("\n  Annotation:", found)) != std::string::npos)
  {
    found += 14;  // Length of "\n  Annotation:".

    std::string::size_type eol = after.find ("\n", found + 1);
    if (eol != std::string::npos)
    {
      std::string value = trim (after.substr (
        found,
        eol - found), "\t ");

      std::string::size_type gap = value.find (" -- ");
      if (gap != std::string::npos)
      {
        // TODO keeping the initial dates even if dateformat approximates them
        // is complex as finding the correspondence between each original line
        // and edited line may be impossible (bug #705). It would be simpler if
        // each annotation was put on a line with a distinguishable id (then
        // for each line: if the annotation is the same, then it is copied; if
        // the annotation is modified, then its original date may be kept; and
        // if there is no corresponding id, then a new unique date is created).
        Date when (value.substr (0, gap), dateformat);

        // This guarantees that if more than one annotation has the same date,
        // that the seconds will be different, thus unique, thus not squashed.
        // Bug #249
        when += (const int) annotations.size ();

        std::stringstream name;
        name << "annotation_" << when.toEpoch ();
        std::string text = trim (value.substr (gap + 4), "\t ");
        annotations.insert (std::make_pair (name.str (), text));
      }
    }
  }

  task.setAnnotations (annotations);

  // Dependencies
  value = findValue (after, "\n  Dependencies:");
  std::vector <std::string> dependencies;
  split (dependencies, value, ",");

  task.remove ("depends");
  std::vector <std::string>::iterator dep;
  for (dep = dependencies.begin (); dep != dependencies.end (); ++dep)
  {
    if (dep->length () >= 7)
      task.addDependency (*dep);
    else
      task.addDependency ((int) strtol (dep->c_str (), NULL, 10));
  }

  // UDAs
  std::map <std::string, Column*>::iterator col;
  for (col = context.columns.begin (); col != context.columns.end (); ++col)
  {
    std::string type = context.config.get ("uda." + col->first + ".type");
    if (type != "")
    {
      std::string value = findValue (after, "\n  UDA " + col->first + ":");
      if ((task.get (col->first) != value) && (type != "date" ||
           (task.get (col->first) != Date (value, dateformat).toEpochString ())) &&
           (type != "duration" ||
           (task.get (col->first) != (std::string) Duration (value) )))
      {
        if (value != "")
        {
          context.footnote (format (STRING_EDIT_UDA_MOD, col->first));

          if (type == "string")
          {
            task.set (col->first, value);
          }
          else if (type == "numeric")
          {
            Nibbler n (value);
            double d;
            if (n.getNumber (d) &&
                n.depleted ())
              task.set (col->first, value);
            else
              throw format (STRING_UDA_NUMERIC, value);
          }
          else if (type == "date")
          {
            Date d (value, dateformat);
            task.set (col->first, d.toEpochString ());
          }
          else if (type == "duration")
          {
            Duration d (value);
            task.set (col->first, (time_t) d);
          }
        }
        else
        {
          context.footnote (format (STRING_EDIT_UDA_DEL, col->first));
          task.remove (col->first);
        }
      }
    }
  }

  // UDA orphans
  std::vector <std::string> orphanValues = findValues (after, "\n  UDA Orphan ");
  std::vector <std::string>::iterator orphan;
  for (orphan = orphanValues.begin (); orphan != orphanValues.end (); ++orphan)
  {
    std::string::size_type colon = orphan->find (':');
    if (colon != std::string::npos)
    {
      std::string name  = trim (orphan->substr (0, colon),  "\t ");
      std::string value = trim (orphan->substr (colon + 1), "\t ");

      if (value != "")
        task.set (name, value);
      else
        task.remove (name);
    }
  }
}
Exemple #2
0
void CmdEdit::parseTask (Task& task, const std::string& after, const std::string& dateformat)
{
  // project
  std::string value = findValue (after, "\n  Project:");
  if (task.get ("project") != value)
  {
    if (value != "")
    {
      context.footnote (STRING_EDIT_PROJECT_MOD);
      task.set ("project", value);
    }
    else
    {
      context.footnote (STRING_EDIT_PROJECT_DEL);
      task.remove ("project");
    }
  }

  // tags
  value = findValue (after, "\n  Tags:");
  std::vector <std::string> tags;
  split (tags, value, ' ');
  task.remove ("tags");
  task.addTags (tags);

  // description.
  value = findMultilineValue (after, "\n  Description:", "\n  Created:");
  if (task.get ("description") != value)
  {
    if (value != "")
    {
      context.footnote (STRING_EDIT_DESC_MOD);
      task.set ("description", value);
    }
    else
      throw std::string (STRING_EDIT_DESC_REMOVE_ERR);
  }

  // entry
  value = findValue (after, "\n  Created:");
  if (value != "")
  {
    std::string formatted = formatDate (task, "entry", dateformat);

    if (formatted != value)
    {
      context.footnote (STRING_EDIT_ENTRY_MOD);
      task.set ("entry", ISO8601d (value, dateformat).toEpochString ());
    }
  }
  else
    throw std::string (STRING_EDIT_ENTRY_REMOVE_ERR);

  // start
  value = findValue (after, "\n  Started:");
  if (value != "")
  {
    if (task.get ("start") != "")
    {
      std::string formatted = formatDate (task, "start", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_START_MOD);
        task.set ("start", ISO8601d (value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_START_MOD);
      task.set ("start", ISO8601d (value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("start") != "")
    {
      context.footnote (STRING_EDIT_START_DEL);
      task.remove ("start");
    }
  }

  // end
  value = findValue (after, "\n  Ended:");
  if (value != "")
  {
    if (task.get ("end") != "")
    {
      std::string formatted = formatDate (task, "end", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_END_MOD);
        task.set ("end", ISO8601d (value, dateformat).toEpochString ());
      }
    }
    else if (task.getStatus () != Task::deleted)
      throw std::string (STRING_EDIT_END_SET_ERR);
  }
  else
  {
    if (task.get ("end") != "")
    {
      context.footnote (STRING_EDIT_END_DEL);
      task.setStatus (Task::pending);
      task.remove ("end");
    }
  }

  // scheduled
  value = findValue (after, "\n  Scheduled:");
  if (value != "")
  {
    if (task.get ("scheduled") != "")
    {
      std::string formatted = formatDate (task, "scheduled", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_SCHED_MOD);
        task.set ("scheduled", ISO8601d (value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_SCHED_MOD);
      task.set ("scheduled", ISO8601d (value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("scheduled") != "")
    {
      context.footnote (STRING_EDIT_SCHED_DEL);
      task.setStatus (Task::pending);
      task.remove ("scheduled");
    }
  }

  // due
  value = findValue (after, "\n  Due:");
  if (value != "")
  {
    if (task.get ("due") != "")
    {
      std::string formatted = formatDate (task, "due", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_DUE_MOD);
        task.set ("due", ISO8601d (value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_DUE_MOD);
      task.set ("due", ISO8601d (value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("due") != "")
    {
      if (task.getStatus () == Task::recurring ||
          task.get ("parent") != "")
      {
        context.footnote (STRING_EDIT_DUE_DEL_ERR);
      }
      else
      {
        context.footnote (STRING_EDIT_DUE_DEL);
        task.remove ("due");
      }
    }
  }

  // until
  value = findValue (after, "\n  Until:");
  if (value != "")
  {
    if (task.get ("until") != "")
    {
      std::string formatted = formatDate (task, "until", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_UNTIL_MOD);
        task.set ("until", ISO8601d (value, dateformat).toEpochString ());
      }
    }
    else
    {
      context.footnote (STRING_EDIT_UNTIL_MOD);
      task.set ("until", ISO8601d (value, dateformat).toEpochString ());
    }
  }
  else
  {
    if (task.get ("until") != "")
    {
      context.footnote (STRING_EDIT_UNTIL_DEL);
      task.remove ("until");
    }
  }

  // recur
  value = findValue (after, "\n  Recur:");
  if (value != task.get ("recur"))
  {
    if (value != "")
    {
      ISO8601p p;
      std::string::size_type idx = 0;
      if (p.parse (value, idx))
      {
        context.footnote (STRING_EDIT_RECUR_MOD);
        if (task.get ("due") != "")
        {
          task.set ("recur", value);
          task.setStatus (Task::recurring);
        }
        else
          throw std::string (STRING_EDIT_RECUR_DUE_ERR);
      }
      else
        throw std::string (STRING_EDIT_RECUR_ERR);
    }
    else
    {
      context.footnote (STRING_EDIT_RECUR_DEL);
      task.setStatus (Task::pending);
      task.remove ("recur");
      task.remove ("until");
      task.remove ("mask");
      task.remove ("imask");
    }
  }

  // wait
  value = findValue (after, "\n  Wait until:");
  if (value != "")
  {
    if (task.get ("wait") != "")
    {
      std::string formatted = formatDate (task, "wait", dateformat);

      if (formatted != value)
      {
        context.footnote (STRING_EDIT_WAIT_MOD);
        task.set ("wait", ISO8601d (value, dateformat).toEpochString ());
        task.setStatus (Task::waiting);
      }
    }
    else
    {
      context.footnote (STRING_EDIT_WAIT_MOD);
      task.set ("wait", ISO8601d (value, dateformat).toEpochString ());
      task.setStatus (Task::waiting);
    }
  }
  else
  {
    if (task.get ("wait") != "")
    {
      context.footnote (STRING_EDIT_WAIT_DEL);
      task.remove ("wait");
      task.setStatus (Task::pending);
    }
  }

  // parent
  value = findValue (after, "\n  Parent:");
  if (value != task.get ("parent"))
  {
    if (value != "")
    {
      context.footnote (STRING_EDIT_PARENT_MOD);
      task.set ("parent", value);
    }
    else
    {
      context.footnote (STRING_EDIT_PARENT_DEL);
      task.remove ("parent");
    }
  }

  // Annotations
  std::map <std::string, std::string> annotations;
  std::string::size_type found = 0;
  while ((found = after.find ("\n  Annotation:", found)) != std::string::npos)
  {
    found += 14;  // Length of "\n  Annotation:".

    auto eol = after.find ("\n", found + 1);
    if (eol != std::string::npos)
    {
      std::string value = trim (after.substr (
        found,
        eol - found), "\t ");

      auto gap = value.find (" -- ");
      if (gap != std::string::npos)
      {
        // TODO keeping the initial dates even if dateformat approximates them
        // is complex as finding the correspondence between each original line
        // and edited line may be impossible (bug #705). It would be simpler if
        // each annotation was put on a line with a distinguishable id (then
        // for each line: if the annotation is the same, then it is copied; if
        // the annotation is modified, then its original date may be kept; and
        // if there is no corresponding id, then a new unique date is created).
        ISO8601d when (value.substr (0, gap), dateformat);

        // If the map already contains a annotation for a given timestamp
        // we need to increment until we find an unused key
        int timestamp = (int) when.toEpoch ();

        std::stringstream name;

        do
        {
          name.str ("");  // Clear
          name << "annotation_" << timestamp;
          timestamp++;
        }
        while (annotations.find (name.str ()) != annotations.end ());

        std::string text = trim (value.substr (gap + 4), "\t ");
        annotations.insert (std::make_pair (name.str (), json::decode (text)));
      }
    }
  }

  task.setAnnotations (annotations);

  // Dependencies
  value = findValue (after, "\n  Dependencies:");
  std::vector <std::string> dependencies;
  split (dependencies, value, ",");

  task.remove ("depends");
  for (auto& dep : dependencies)
  {
    if (dep.length () >= 7)
      task.addDependency (dep);
    else
      task.addDependency ((int) strtol (dep.c_str (), NULL, 10));
  }

  // UDAs
  for (auto& col : context.columns)
  {
    std::string type = context.config.get ("uda." + col.first + ".type");
    if (type != "")
    {
      std::string value = findValue (after, "\n  UDA " + col.first + ":");
      if ((task.get (col.first) != value) && (type != "date" ||
           (task.get (col.first) != ISO8601d (value, dateformat).toEpochString ())) &&
           (type != "duration" ||
           (task.get (col.first) != (std::string) ISO8601p (value))))
      {
        if (value != "")
        {
          context.footnote (format (STRING_EDIT_UDA_MOD, col.first));

          if (type == "string")
          {
            task.set (col.first, value);
          }
          else if (type == "numeric")
          {
            Nibbler n (value);
            double d;
            if (n.getNumber (d) &&
                n.depleted ())
              task.set (col.first, value);
            else
              throw format (STRING_UDA_NUMERIC, value);
          }
          else if (type == "date")
          {
            task.set (col.first, ISO8601d (value, dateformat).toEpochString ());
          }
          else if (type == "duration")
          {
            task.set (col.first, (time_t) ISO8601p (value));
          }
        }
        else
        {
          context.footnote (format (STRING_EDIT_UDA_DEL, col.first));
          task.remove (col.first);
        }
      }
    }
  }

  // UDA orphans
  std::vector <std::string> orphanValues = findValues (after, "\n  UDA Orphan ");
  for (auto& orphan : orphanValues)
  {
    auto colon = orphan.find (':');
    if (colon != std::string::npos)
    {
      std::string name  = trim (orphan.substr (0, colon),  "\t ");
      std::string value = trim (orphan.substr (colon + 1), "\t ");

      if (value != "")
        task.set (name, value);
      else
        task.remove (name);
    }
  }
}