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 segfault
(thanks to Thomas Lauf). (thanks to Thomas Lauf).
- TI-65 The 'tags' command should support a filter - 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 - TI-67 Summary with parameters shows wrong ids
(thanks to Bodo Graumann) (thanks to Bodo Graumann)
- TI-68 Cannot shorten interval which has been moved into an exclusion. - TI-68 Cannot shorten interval which has been moved into an exclusion.
@ -58,6 +60,8 @@
(Thanks to A M). (Thanks to A M).
- TI-78 Tag parsing broken for tags starting with "or_" - TI-78 Tag parsing broken for tags starting with "or_"
(Thanks to Lukas Barth). (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-90 Let 'continue' accept a date or a date range
- TI-91 Timewarrior does not compile on DragonFly - TI-91 Timewarrior does not compile on DragonFly
(Thanks to Michael Neumann). (Thanks to Michael Neumann).

View file

@ -94,6 +94,18 @@ bool Range::is_ended () const
return end.toEpoch () > 0; 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: // Detect the following overlap cases:
// //

View file

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

View file

@ -103,65 +103,62 @@ static void autoAdjust (
for (auto& overlap : overlaps) for (auto& overlap : overlaps)
debug (" " + overlap.dump ()); debug (" " + overlap.dump ());
// Without (adjust == true), overlapping intervals are an error condition. if (! overlaps.empty ())
if (! adjust && overlaps.size ()) {
throw std::string ("You cannot overlap intervals. Correct the start/end " if (! adjust)
"time, or specify the :adjust hint."); 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. if (start_within_overlap && !end_within_overlap)
/* {
// Closed // 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 [-----] split1.range.end = interval.range.start;
ovl [-----] split2.range.start = interval.range.end;
int [-----] if (split1.range.is_empty ())
ovl [-----] {
database.deleteInterval (overlap);
int [-] }
ovl [-----] else
{
int [-----] database.modifyInterval (overlap, split1);
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 (! split2.range.is_empty ())
{
database.addInterval (split2);
}
}
}
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////