diff --git a/timetagger/app/dialogs.py b/timetagger/app/dialogs.py index 76604ec..b56f55c 100644 --- a/timetagger/app/dialogs.py +++ b/timetagger/app/dialogs.py @@ -1892,6 +1892,13 @@ def submit(self): # Prevent multiple timers at once if self._record.t1 == self._record.t2: self._stop_all_running_records(self._record.t1) + # Handle overlapping records if enabled (only for non-running records) + if ( + window.simplesettings.get("split_overlapping_records") + and self._record.t1 != self._record.t2 + and self._lmode in ("new", "edit") + ): + self._split_overlapping_records(self._record) # Apply window.store.records.put(self._record) super().submit(self._record) @@ -1905,6 +1912,56 @@ def submit(self): elif self._lmode == "stop": self._canvas.pomodoro_dialog.stop() + def _split_overlapping_records(self, new_record): + """Split existing records that overlap with the new record.""" + t1, t2 = new_record.t1, new_record.t2 + + # Get overlapping records + overlapping_records = window.store.records.get_records(t1, t2) + + for key, existing in overlapping_records.items(): + # Skip the record being edited + if existing.key == new_record.key: + continue + # Skip running records + if existing.t1 == existing.t2: + continue + + # Check overlap type: + # - existing.t1 < t1 and existing.t2 > t2: new record is fully inside existing + # - existing.t1 >= t1 and existing.t2 <= t2: existing is fully inside new (do nothing) + # - existing.t1 < t1 and existing.t2 > t1 and existing.t2 <= t2: partial overlap at start + # - existing.t1 >= t1 and existing.t1 < t2 and existing.t2 > t2: partial overlap at end + + if existing.t1 < t1 and existing.t2 > t2: + # New record is fully inside existing - split into two records + # First part: existing.t1 to new_record.t1 + # Second part: new_record.t2 to existing.t2 + first_part = existing.copy() + first_part.t2 = t1 + + second_part = window.store.records.create(t2, existing.t2, existing.ds) + + window.store.records.put(first_part) + window.store.records.put(second_part) + + elif existing.t1 >= t1 and existing.t2 <= t2: + # Existing record is fully inside the new record - no action needed + # The user is placing a record that completely covers this one + pass + + elif existing.t1 < t1 and existing.t2 > t1 and existing.t2 <= t2: + # Partial overlap at start - trim end of existing record + trimmed = existing.copy() + trimmed.t2 = t1 + window.store.records.put(trimmed) + + elif existing.t1 >= t1 and existing.t1 < t2 and existing.t2 > t2: + # Partial overlap at end - trim start of existing record + trimmed = existing.copy() + trimmed.t1 = t2 + window.store.records.put(trimmed) + def resume_record(self): """Start a new record with the same description.""" # The resume button should only be visible for non-running records, but @@ -3957,9 +4014,12 @@ def open(self, callback=None):