TI-66: Move with :adjust leaves overlapping intervals.

- Implement 'overwrite' overlap resolution strategy
- Add convenience methods to Range
- also fixes TI-85: :adjust creates overlapping interval
This commit is contained in:
Thomas Lauf 2017-12-14 21:49:34 +01:00
parent 963d4ac7ae
commit 48ed980c76
4 changed files with 70 additions and 54 deletions

View file

@ -41,6 +41,8 @@
segfault
(thanks to Thomas Lauf).
- TI-65 The 'tags' command should support a filter
- TI-66 Move with :adjust leaves overlapping intervals.
(thanks to A M)
- TI-67 Summary with parameters shows wrong ids
(thanks to Bodo Graumann)
- TI-68 Cannot shorten interval which has been moved into an exclusion.
@ -58,6 +60,8 @@
(Thanks to A M).
- TI-78 Tag parsing broken for tags starting with "or_"
(Thanks to Lukas Barth).
- TI-85 :adjust creates overlapping interval
(thanks to Tim Ruffing)
- TI-90 Let 'continue' accept a date or a date range
- TI-91 Timewarrior does not compile on DragonFly
(Thanks to Michael Neumann).

View file

@ -94,6 +94,18 @@ bool Range::is_ended () const
return end.toEpoch () > 0;
}
////////////////////////////////////////////////////////////////////////////////
bool Range::is_empty () const
{
return start == end;
}
////////////////////////////////////////////////////////////////////////////////
bool Range::contains (const Datetime &datetime) const
{
return start <= datetime && (! is_ended () || end >= datetime);
}
////////////////////////////////////////////////////////////////////////////////
// Detect the following overlap cases:
//

View file

@ -45,6 +45,9 @@ public:
bool is_open () const;
bool is_started () const;
bool is_ended () const;
bool is_empty () const;
bool contains (const Datetime&) const;
bool overlap (const Range&) const;
bool encloses (const Range&) const;

View file

@ -103,65 +103,62 @@ static void autoAdjust (
for (auto& overlap : overlaps)
debug (" " + overlap.dump ());
// Without (adjust == true), overlapping intervals are an error condition.
if (! adjust && overlaps.size ())
if (! overlaps.empty ())
{
if (! adjust)
throw std::string("You cannot overlap intervals. Correct the start/end "
"time, or specify the :adjust hint.");
// TODO If there is overlap, and the tags are the same, merge.
// implement overwrite resolution, i.e. the new interval overwrites existing intervals
for (auto& overlap : overlaps)
{
bool start_within_overlap = overlap.range.contains (interval.range.start);
bool end_within_overlap = interval.range.end != 0 && overlap.range.contains (interval.range.end);
// TODO Accumulate identifiable and correctable cases here.
/*
// Closed
if (start_within_overlap && !end_within_overlap)
{
// start date of new interval within old interval
Interval modified {overlap};
modified.range.end = interval.range.start;
database.modifyInterval (overlap, modified);
}
else if (!start_within_overlap && end_within_overlap)
{
// end date of new interval within old interval
Interval modified {overlap};
modified.range.start = interval.range.end;
database.modifyInterval (overlap, modified);
}
else if (!start_within_overlap && !end_within_overlap)
{
// new interval encloses old interval
database.deleteInterval (overlap);
}
else
{
// new interval enclosed by old interval
Interval split2 {overlap};
Interval split1 {overlap};
int [-----]
ovl [-----]
split1.range.end = interval.range.start;
split2.range.start = interval.range.end;
int [-----]
ovl [-----]
int [-]
ovl [-----]
int [-----]
ovl [-]
int [-----]
ovl [-----]
// Interval is open
int [--
ovl [-----]
int [--
ovl [-----]
int [--
ovl [-----]
int [--
ovl [-]
int [--
ovl [-----]
// Overlap is open
int [-----]
ovl [--
int [-----]
ovl [--
int [-]
ovl [--
int [-----]
ovl [--
*/
if (split1.range.is_empty ())
{
database.deleteInterval (overlap);
}
else
{
database.modifyInterval (overlap, split1);
}
if (! split2.range.is_empty ())
{
database.addInterval (split2);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////