Enhancement - all attribute modifiers working

- Implemented before, below, under, after, above, over.
This commit is contained in:
Paul Beckingham 2009-06-20 15:37:01 -04:00
parent 3bed6bb573
commit cbecec263a
5 changed files with 97 additions and 28 deletions

View file

@ -70,12 +70,12 @@ static const char* modifierNames[] =
"after", "over", "above", "after", "over", "above",
"none", "none",
"any", "any",
"is", "is", "equals",
"isnt", "not", "isnt", "not",
"has", "contains", "has", "contains",
"hasnt", "hasnt",
"startswith", "startswith", "left",
"endswith", "endswith", "right",
}; };
#define NUM_INTERNAL_NAMES (sizeof (internalNames) / sizeof (internalNames[0])) #define NUM_INTERNAL_NAMES (sizeof (internalNames) / sizeof (internalNames[0]))
@ -385,7 +385,7 @@ bool Att::validMod (const std::string& mod)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// The type of an attribute is useful for modifier evaluation. // The type of an attribute is useful for modifier evaluation.
std::string type (const std::string& name) std::string Att::type (const std::string& name) const
{ {
if (name == "due" || if (name == "due" ||
name == "until" || name == "until" ||
@ -468,14 +468,17 @@ void Att::parse (Nibbler& n)
// Record that does not have modifiers, but may have a value. // Record that does not have modifiers, but may have a value.
bool Att::match (const Att& other) const bool Att::match (const Att& other) const
{ {
// If there are no mods, just perform a straight compare on value. // All matches are assumed to pass, any short-circuit on non-match.
if (mMod == "" && mValue != other.mValue)
return false;
// Assume a match, and short-circuit on mismatch. // If there are no mods, just perform a straight compare on value.
if (mMod == "")
{
if (mValue != other.mValue)
return false;
}
// is = equal. Nop. // is = equal. Nop.
else if (mMod == "is") // TODO i18n else if (mMod == "is" || mMod == "equals") // TODO i18n
{ {
if (mValue != other.mValue) if (mValue != other.mValue)
return false; return false;
@ -503,7 +506,7 @@ bool Att::match (const Att& other) const
} }
// startswith = first characters must match. // startswith = first characters must match.
else if (mMod == "startswith") // TODO i18n else if (mMod == "startswith" || mMod == "left") // TODO i18n
{ {
if (other.mValue.length () < mValue.length ()) if (other.mValue.length () < mValue.length ())
return false; return false;
@ -513,7 +516,7 @@ bool Att::match (const Att& other) const
} }
// endswith = last characters must match. // endswith = last characters must match.
else if (mMod == "endswith") // TODO i18n else if (mMod == "endswith" || mMod == "right") // TODO i18n
{ {
if (other.mValue.length () < mValue.length ()) if (other.mValue.length () < mValue.length ())
return false; return false;
@ -541,16 +544,62 @@ bool Att::match (const Att& other) const
// before = under = below = < // before = under = below = <
else if (mMod == "before" || mMod == "under" || mMod == "below") else if (mMod == "before" || mMod == "under" || mMod == "below")
{ {
// TODO Typed compare std::string which = type (mName);
if (which == "duration")
{
Duration literal (mValue);
Duration variable ((time_t)::atoi (other.mValue.c_str ()));
if (!(variable < literal))
return false; return false;
} }
else if (which == "date")
{
Date literal (mValue);
Date variable ((time_t)::atoi (other.mValue.c_str ()));
if (! (variable < literal))
return false;
}
else if (which == "number")
{
if (::atoi (mValue.c_str ()) >= ::atoi (other.mValue.c_str ()))
return false;
}
else if (which == "text")
{
if (::strcmp (mValue.c_str (), other.mValue.c_str ()) <= 0)
return false;
}
}
// after = over = above = > // after = over = above = >
else if (mMod == "after" || mMod == "over" || mMod == "above") else if (mMod == "after" || mMod == "over" || mMod == "above")
{ {
// TODO Typed compare std::string which = type (mName);
if (which == "duration")
{
Duration literal (mValue);
Duration variable ((time_t)::atoi (other.mValue.c_str ()));
if (! (variable > literal))
return false; return false;
} }
else if (which == "date")
{
Date literal (mValue);
Date variable ((time_t)::atoi (other.mValue.c_str ()));
if (! (variable > literal))
return false;
}
else if (which == "number")
{
if (::atoi (mValue.c_str ()) <= ::atoi (other.mValue.c_str ()))
return false;
}
else if (which == "text")
{
if (::strcmp (mValue.c_str (), other.mValue.c_str ()) >= 0)
return false;
}
}
return true; return true;
} }

View file

@ -49,7 +49,7 @@ public:
static bool validNameValue (const std::string&, const std::string&, const std::string&); static bool validNameValue (const std::string&, const std::string&, const std::string&);
static bool validNameValue (std::string&, std::string&, std::string&); static bool validNameValue (std::string&, std::string&, std::string&);
static bool validMod (const std::string&); static bool validMod (const std::string&);
static std::string type (const std::string&); std::string type (const std::string&) const;
void parse (const std::string&); void parse (const std::string&);
void parse (Nibbler&); void parse (Nibbler&);
bool match (const Att&) const; bool match (const Att&) const;

View file

@ -540,7 +540,7 @@ void Context::autoFilter (Task& t, Filter& f)
foreach (att, t) foreach (att, t)
{ {
// Words are found in the description using the .has modifier. // Words are found in the description using the .has modifier.
if (att->first == "description") if (att->first == "description" && att->second.mod () == "")
{ {
std::vector <std::string> words; std::vector <std::string> words;
split (words, att->second.value (), ' '); split (words, att->second.value (), ' ');
@ -552,7 +552,7 @@ void Context::autoFilter (Task& t, Filter& f)
} }
// Projects are matched left-most. // Projects are matched left-most.
else if (att->first == "project") else if (att->first == "project" && att->second.mod () == "")
{ {
f.push_back (Att ("project", "startswith", att->second.value ())); f.push_back (Att ("project", "startswith", att->second.value ()));
debug ("auto filter: " + att->first + ".startswith:" + att->second.value ()); debug ("auto filter: " + att->first + ".startswith:" + att->second.value ());
@ -564,14 +564,27 @@ void Context::autoFilter (Task& t, Filter& f)
{ {
} }
// Every task has a unique uuid by default, and it shouldn't be included. // Every task has a unique uuid by default, and it shouldn't be included,
// The mechanism for filtering on tags is +/-<tag>, not tags:foo which // because it is guaranteed to not match.
// means that there can only be one tag, "foo". else if (att->first == "uuid")
else if (att->first != "uuid" && {
att->first != "tags") }
// The mechanism for filtering on tags is +/-<tag>.
else if (att->first == "tags")
{
}
// Generic attribute matching.
else
{ {
f.push_back (att->second); f.push_back (att->second);
debug ("auto filter: " + att->first + ":" + att->second.value ()); debug ("auto filter: " +
att->first +
(att->second.mod () != "" ?
("." + att->second.mod () + ":") :
":") +
att->second.value ());
} }
} }

View file

@ -39,6 +39,12 @@ Duration::Duration ()
{ {
} }
////////////////////////////////////////////////////////////////////////////////
Duration::Duration (time_t input)
{
mDays = input;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Duration::Duration (const std::string& input) Duration::Duration (const std::string& input)
{ {

View file

@ -34,6 +34,7 @@ class Duration
{ {
public: public:
Duration (); // Default constructor Duration (); // Default constructor
Duration (time_t); // Default constructor
Duration (const std::string&); // Parse Duration (const std::string&); // Parse
bool operator< (const Duration&); bool operator< (const Duration&);
bool operator> (const Duration&); bool operator> (const Duration&);