diff --git a/MyTimeline.py b/MyTimeline.py
index 207fcd2..b1512d5 100644
--- a/MyTimeline.py
+++ b/MyTimeline.py
@@ -431,7 +431,7 @@ class MyTimelineView(NavigationView):
"""
View for displaying a vertical timeline of all events in the database.
Shows all events with modern design and interactivity, allowing selection
- and filtering of events by type, category, person, and date range.
+ and filtering of events by type, category, and person.
"""
def __init__(self, pdata: Any, dbstate: Any, uistate: Any, nav_group: int = 0) -> None:
@@ -486,8 +486,6 @@ class MyTimelineView(NavigationView):
# Filter state
self.filter_enabled: bool = False
self.active_event_types: Set[EventType] = set() # Empty = all enabled
- self.date_range_filter: Optional[Tuple[int, int]] = None # (min_date, max_date) in sort values
- self.date_range_explicit: bool = False # Track if date range was explicitly set
self.person_filter: Optional[Set[str]] = None # Set of person handles to include, None = all
self.category_filter: Optional[Set[str]] = None # Set of event categories to include, None = all
self.all_events: List[TimelineEvent] = [] # Store all events before filtering
@@ -690,9 +688,6 @@ class MyTimelineView(NavigationView):
response = self.filter_dialog.run()
if response == Gtk.ResponseType.APPLY:
self._apply_filter_dialog_settings()
- elif response == Gtk.ResponseType.CLOSE:
- pass # Just close
-
self.filter_dialog.hide()
def _calculate_group_state(self, child_checkboxes: List[Gtk.CheckButton]) -> str:
@@ -718,14 +713,22 @@ class MyTimelineView(NavigationView):
return 'some'
def _update_group_checkbox_state(self, group_checkbox: Gtk.CheckButton,
- child_checkboxes: List[Gtk.CheckButton]) -> None:
+ child_checkboxes: List[Gtk.CheckButton],
+ updating_flag: Optional[List[bool]] = None) -> None:
"""
Update a group checkbox state based on child checkboxes.
Args:
group_checkbox: The parent group checkbox to update.
child_checkboxes: List of child checkboxes.
+ updating_flag: Optional list with single boolean to prevent recursion.
+ If provided, will be set to True during update to prevent
+ the group checkbox's toggle handler from firing.
"""
+ # Set updating flag to prevent recursion if provided
+ if updating_flag is not None:
+ updating_flag[0] = True
+
state = self._calculate_group_state(child_checkboxes)
if state == 'all':
@@ -736,6 +739,10 @@ class MyTimelineView(NavigationView):
group_checkbox.set_inconsistent(False)
else: # 'some'
group_checkbox.set_inconsistent(True)
+
+ # Clear updating flag after update
+ if updating_flag is not None:
+ updating_flag[0] = False
def _make_group_toggle_handler(self, child_checkboxes: List[Gtk.CheckButton],
updating_flag: List[bool]) -> Callable[[Gtk.Widget], None]:
@@ -784,7 +791,7 @@ class MyTimelineView(NavigationView):
def handler(widget: Gtk.Widget) -> None:
if updating_flag[0]:
return
- self._update_group_checkbox_state(group_checkbox, child_checkboxes)
+ self._update_group_checkbox_state(group_checkbox, child_checkboxes, updating_flag)
return handler
@@ -831,10 +838,6 @@ class MyTimelineView(NavigationView):
person_page = self._build_person_filter_page()
notebook.append_page(person_page, Gtk.Label(label=_("Persons")))
- # Date Range Filter Page
- date_page = self._build_date_range_filter_page()
- notebook.append_page(date_page, Gtk.Label(label=_("Date Range")))
-
content_area.show_all()
return dialog
@@ -869,6 +872,7 @@ class MyTimelineView(NavigationView):
category_boxes = {}
category_checkboxes = {}
category_event_types = {} # Map category to list of event types
+ category_updating_flags = {} # Map category to updating flag list
# First pass: collect event types by category
for event_type_obj in EVENT_COLORS:
@@ -905,6 +909,7 @@ class MyTimelineView(NavigationView):
# Flag to prevent recursion between category and child checkboxes
updating_category = [False]
+ category_updating_flags[category] = updating_category
# Connect category checkbox to toggle all children
category_checkbox.connect("toggled",
@@ -918,6 +923,7 @@ class MyTimelineView(NavigationView):
self._filter_widgets['event_type_checkboxes'] = event_type_checkboxes
self._filter_widgets['category_checkboxes'] = category_checkboxes
self._filter_widgets['category_event_types'] = category_event_types
+ self._filter_widgets['category_updating_flags'] = category_updating_flags
scrolled.add(box)
return scrolled
@@ -978,182 +984,6 @@ class MyTimelineView(NavigationView):
scrolled.add(box)
return scrolled
- def _create_date_calendar_widget(self, label: str, year_changed_handler: Callable,
- date_selected_handler: Callable,
- month_changed_handler: Callable,
- calendar_key: str, spin_key: str,
- current_year: int, min_year: int, max_year: int) -> Tuple[Gtk.Frame, Gtk.Calendar, Gtk.SpinButton]:
- """
- Create a date calendar widget with year selector.
-
- Args:
- label: Label for the frame.
- year_changed_handler: Handler for year spin button changes.
- date_selected_handler: Handler for calendar date selection.
- month_changed_handler: Handler for calendar month changes.
- calendar_key: Key to store calendar widget in _filter_widgets.
- spin_key: Key to store spin button widget in _filter_widgets.
- current_year: Initial year value.
- min_year: Minimum year for the spin button.
- max_year: Maximum year for the spin button.
-
- Returns:
- Tuple containing (frame, calendar, spin_button).
- """
- frame = Gtk.Frame(label=label)
- frame.set_label_align(0.5, 0.5)
-
- container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=CALENDAR_CONTAINER_SPACING)
- container.set_margin_start(CALENDAR_CONTAINER_MARGIN)
- container.set_margin_end(CALENDAR_CONTAINER_MARGIN)
- container.set_margin_top(CALENDAR_CONTAINER_MARGIN)
- container.set_margin_bottom(CALENDAR_CONTAINER_MARGIN)
-
- # Year selector
- year_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=YEAR_SELECTOR_SPACING)
- year_label = Gtk.Label(label=_("Year:"))
- year_adjustment = Gtk.Adjustment(
- value=current_year,
- lower=min_year,
- upper=max_year,
- step_increment=1,
- page_increment=10
- )
- year_spin = Gtk.SpinButton()
- year_spin.set_adjustment(year_adjustment)
- year_spin.set_numeric(True)
- year_spin.set_update_policy(Gtk.SpinButtonUpdatePolicy.IF_VALID)
- year_spin.set_width_chars(6)
- year_spin.connect("value-changed", year_changed_handler)
-
- year_box.pack_start(year_label, False, False, 0)
- year_box.pack_start(year_spin, False, False, 0)
- container.pack_start(year_box, False, False, 0)
-
- # Calendar
- calendar = Gtk.Calendar()
- calendar.set_display_options(
- Gtk.CalendarDisplayOptions.SHOW_HEADING |
- Gtk.CalendarDisplayOptions.SHOW_DAY_NAMES |
- Gtk.CalendarDisplayOptions.SHOW_WEEK_NUMBERS
- )
- calendar.connect("day-selected", date_selected_handler)
- calendar.connect("month-changed", month_changed_handler)
- container.pack_start(calendar, True, True, 0)
-
- frame.add(container)
-
- # Store widgets
- self._filter_widgets[calendar_key] = calendar
- self._filter_widgets[spin_key] = year_spin
-
- return frame, calendar, year_spin
-
- def _build_date_range_filter_page(self) -> Gtk.Widget:
- """
- Build the date range filter page with date chooser widgets.
-
- Returns:
- Gtk.Widget: The date range filter page.
- """
- scrolled = Gtk.ScrolledWindow()
- scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
-
- box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=FILTER_PAGE_SPACING)
- box.set_margin_start(FILTER_PAGE_MARGIN)
- box.set_margin_end(FILTER_PAGE_MARGIN)
- box.set_margin_top(FILTER_PAGE_MARGIN)
- box.set_margin_bottom(FILTER_PAGE_MARGIN)
-
- info_label = Gtk.Label(label=_("Select date range to filter events. Leave unselected to show all dates."))
- info_label.set_line_wrap(True)
- box.pack_start(info_label, False, False, 0)
-
- # Calendar container
- calendar_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=CALENDAR_HORIZONTAL_SPACING)
- calendar_box.set_homogeneous(True)
-
- # Year range for genealogical data
- current_year = datetime.date.today().year
- min_year = MIN_GENEALOGICAL_YEAR
- max_year = current_year + 10
-
- # Create From date calendar widget
- from_frame, from_calendar, from_year_spin = self._create_date_calendar_widget(
- label=_("From Date"),
- year_changed_handler=self._on_from_year_changed,
- date_selected_handler=self._on_from_date_selected,
- month_changed_handler=self._on_from_calendar_changed,
- calendar_key='date_from_calendar',
- spin_key='date_from_year_spin',
- current_year=current_year,
- min_year=min_year,
- max_year=max_year
- )
- calendar_box.pack_start(from_frame, True, True, 0)
-
- # Create To date calendar widget
- to_frame, to_calendar, to_year_spin = self._create_date_calendar_widget(
- label=_("To Date"),
- year_changed_handler=self._on_to_year_changed,
- date_selected_handler=self._on_to_date_selected,
- month_changed_handler=self._on_to_calendar_changed,
- calendar_key='date_to_calendar',
- spin_key='date_to_year_spin',
- current_year=current_year,
- min_year=min_year,
- max_year=max_year
- )
- calendar_box.pack_start(to_frame, True, True, 0)
-
- box.pack_start(calendar_box, True, True, 0)
-
- # Clear button
- clear_button = Gtk.Button(label=_("Clear Dates"))
- clear_button.connect("clicked", self._on_clear_date_range)
- button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
- button_box.pack_start(clear_button, False, False, 0)
- box.pack_start(button_box, False, False, 0)
-
- # Validation label
- self.date_validation_label = Gtk.Label()
- self.date_validation_label.set_line_wrap(True)
- self.date_validation_label.set_markup("")
- box.pack_start(self.date_validation_label, False, False, 0)
-
- scrolled.add(box)
- return scrolled
-
- def _set_validation_message(self, message: str) -> None:
- """
- Set the date validation label message.
-
- Args:
- message: Message text to display (empty string to clear).
- """
- if hasattr(self, 'date_validation_label'):
- if message:
- self.date_validation_label.set_markup(
- f"{message}"
- )
- else:
- self.date_validation_label.set_text("")
-
- def _update_year_spin_button(self, spin_key: str, year: int, handler: Callable) -> None:
- """
- Update a year spin button value, blocking signals during update.
-
- Args:
- spin_key: Key to find the spin button in _filter_widgets.
- year: Year value to set.
- handler: Handler function to block/unblock during update.
- """
- if spin_key in self._filter_widgets:
- year_spin = self._filter_widgets[spin_key]
- year_spin.handler_block_by_func(handler)
- year_spin.set_value(year)
- year_spin.handler_unblock_by_func(handler)
-
def _update_event_type_widgets(self) -> None:
"""
Update event type filter widgets to reflect current filter state.
@@ -1170,6 +1000,7 @@ class MyTimelineView(NavigationView):
# Update category checkboxes based on their children's states
if 'category_checkboxes' in self._filter_widgets and 'category_event_types' in self._filter_widgets:
+ category_updating_flags = self._filter_widgets.get('category_updating_flags', {})
for category, category_checkbox in self._filter_widgets['category_checkboxes'].items():
# Get child checkboxes for this category
event_types_in_category = self._filter_widgets['category_event_types'].get(category, [])
@@ -1178,8 +1009,10 @@ class MyTimelineView(NavigationView):
for et in event_types_in_category
if et in self._filter_widgets['event_type_checkboxes']
]
+ # Get the updating flag for this category to prevent recursion
+ updating_flag = category_updating_flags.get(category)
# Update category checkbox state based on children
- self._update_group_checkbox_state(category_checkbox, child_checkboxes)
+ self._update_group_checkbox_state(category_checkbox, child_checkboxes, updating_flag)
def _update_person_filter_widgets(self) -> None:
"""
@@ -1282,7 +1115,7 @@ class MyTimelineView(NavigationView):
self._make_child_toggle_handler(family_checkbox, child_checkboxes, updating_family))
# Initialize family checkbox state
- self._update_group_checkbox_state(family_checkbox, child_checkboxes)
+ self._update_group_checkbox_state(family_checkbox, child_checkboxes, updating_family)
expander.add(members_box)
self._filter_widgets['family_expanders'][family_handle] = expander
@@ -1292,47 +1125,6 @@ class MyTimelineView(NavigationView):
except (AttributeError, KeyError) as e:
logger.warning(f"Error updating person filter widgets in filter dialog: {e}", exc_info=True)
- def _update_date_range_widgets(self) -> None:
- """
- Update date range filter widgets to reflect current filter state.
- """
- if 'date_from_calendar' not in self._filter_widgets or 'date_to_calendar' not in self._filter_widgets:
- return
-
- from_calendar = self._filter_widgets['date_from_calendar']
- to_calendar = self._filter_widgets['date_to_calendar']
-
- if self.date_range_filter and self.date_range_explicit:
- min_sort, max_sort = self.date_range_filter
- # Convert sort values back to dates for calendar display
- # Approximate conversion: extract year from sort value
- # Sort value is roughly: year * DATE_SORT_YEAR_MULTIPLIER + month * DATE_SORT_MONTH_MULTIPLIER + day
- from_year = min_sort // DATE_SORT_YEAR_MULTIPLIER
- to_year = max_sort // DATE_SORT_YEAR_MULTIPLIER
-
- # Set calendar years (approximate)
- current_from_year, current_from_month, current_from_day = from_calendar.get_date()
- current_to_year, current_to_month, current_to_day = to_calendar.get_date()
-
- from_calendar.select_month(current_from_month, from_year)
- to_calendar.select_month(current_to_month, to_year)
-
- # Update year spin buttons
- self._update_year_spin_button('date_from_year_spin', from_year, self._on_from_year_changed)
- self._update_year_spin_button('date_to_year_spin', to_year, self._on_to_year_changed)
- else:
- # Reset to current date
- now = datetime.date.today()
- from_calendar.select_month(now.month - 1, now.year)
- to_calendar.select_month(now.month - 1, now.year)
-
- # Reset year spin buttons
- self._update_year_spin_button('date_from_year_spin', now.year, self._on_from_year_changed)
- self._update_year_spin_button('date_to_year_spin', now.year, self._on_to_year_changed)
-
- # Clear validation message
- self._set_validation_message("")
-
def _update_filter_dialog_state(self) -> None:
"""
Update the filter dialog widgets to reflect current filter state.
@@ -1343,7 +1135,6 @@ class MyTimelineView(NavigationView):
# Update each filter type's widgets
self._update_event_type_widgets()
self._update_person_filter_widgets()
- self._update_date_range_widgets()
def _on_filter_dialog_response(self, dialog: Gtk.Dialog, response_id: int) -> None:
"""
@@ -1358,8 +1149,6 @@ class MyTimelineView(NavigationView):
self.filter_enabled = False
self.active_event_types = set()
self._update_normalized_active_event_types() # Invalidate cache
- self.date_range_filter = None
- self.date_range_explicit = False
self.person_filter = None
self.category_filter = None
self.apply_filters()
@@ -1372,10 +1161,23 @@ class MyTimelineView(NavigationView):
# Update event type filter
if 'event_type_checkboxes' in self._filter_widgets:
active_types = set()
+ total_types = len(self._filter_widgets['event_type_checkboxes'])
for event_type, checkbox in self._filter_widgets['event_type_checkboxes'].items():
if checkbox.get_active():
active_types.add(event_type)
- self.active_event_types = active_types if len(active_types) < len(self._filter_widgets['event_type_checkboxes']) else set()
+
+ # Logic:
+ # - If all types are selected: active_event_types = empty set (meaning "all enabled", no filtering)
+ # - If some types are unselected: active_event_types = set of selected types (filter to show only these)
+ # - If no types are selected: active_event_types = empty set, but filter_enabled will be False
+ # (unless other filters are active), so no events will show (correct behavior)
+ if len(active_types) == total_types:
+ # All types are selected - no filtering needed
+ self.active_event_types = set()
+ else:
+ # Some or no types are selected - filter to only show selected types
+ # (If active_types is empty, this means no events will match, which is correct)
+ self.active_event_types = active_types
self._update_normalized_active_event_types() # Update cache
# Update category filter
@@ -1396,54 +1198,9 @@ class MyTimelineView(NavigationView):
all_persons = set(self._filter_widgets['person_checkboxes'])
self.person_filter = active_persons if active_persons != all_persons else None
- # Update date range filter from calendar widgets
- if 'date_from_calendar' in self._filter_widgets and 'date_to_calendar' in self._filter_widgets:
- from_calendar = self._filter_widgets['date_from_calendar']
- to_calendar = self._filter_widgets['date_to_calendar']
-
- # Check if dates were explicitly set (stored in widget data)
- # We'll use a simple approach: if user clicked calendars, use the dates
- # For now, we'll always use calendar dates if they're valid
- # The "Clear Dates" button will reset the explicit flag
-
- # Get Date objects from calendar selections
- from_date = self._create_date_from_calendar(from_calendar)
- to_date = self._create_date_from_calendar(to_calendar)
-
- if from_date is None or to_date is None:
- # Show error message for invalid dates
- self._set_validation_message(_('Error: Invalid date in date range filter'))
- logger.warning("Error parsing date range in filter dialog: invalid date from calendar")
- self.date_range_filter = None
- self.date_range_explicit = False
- return
-
- min_sort = from_date.get_sort_value()
- max_sort = to_date.get_sort_value()
-
- # Validate date range
- if min_sort > max_sort:
- # Show error message
- self._set_validation_message(_('Error: From date must be before To date'))
- self.date_range_filter = None
- self.date_range_explicit = False
- return
- else:
- # Clear error message
- self._set_validation_message("")
-
- # Set filter - user has selected dates in calendars
- self.date_range_filter = (min_sort, max_sort)
- self.date_range_explicit = True
- else:
- # No calendar widgets, clear filter
- self.date_range_filter = None
- self.date_range_explicit = False
-
# Enable filter if any filter is active
self.filter_enabled = (
self.active_event_types or
- (self.date_range_filter is not None and self.date_range_explicit) or
self.person_filter is not None or
self.category_filter is not None
)
@@ -1485,185 +1242,6 @@ class MyTimelineView(NavigationView):
for checkbox in self._filter_widgets['event_type_checkboxes'].values():
checkbox.set_active(False)
- def _sync_year_spin_from_calendar(self, calendar: Gtk.Calendar, spin_key: str, handler: Callable) -> None:
- """
- Update year spin button to match calendar date.
-
- Args:
- calendar: The calendar widget.
- spin_key: Key to find the spin button in _filter_widgets.
- handler: Handler function to block/unblock during update.
- """
- if spin_key in self._filter_widgets:
- year, month, day = calendar.get_date()
- year_spin = self._filter_widgets[spin_key]
- year_spin.handler_block_by_func(handler)
- year_spin.set_value(year)
- year_spin.handler_unblock_by_func(handler)
-
- def _sync_calendar_from_year_spin(self, calendar_key: str, new_year: int) -> None:
- """
- Update calendar to match year spin button value.
-
- Args:
- calendar_key: Key to find the calendar in _filter_widgets.
- new_year: The new year value to set.
- """
- if calendar_key in self._filter_widgets:
- calendar = self._filter_widgets[calendar_key]
- current_year, current_month, current_day = calendar.get_date()
- # Update calendar to new year, keeping same month and day
- calendar.select_month(current_month, new_year)
-
- def _create_date_from_calendar(self, calendar: Gtk.Calendar) -> Optional[Date]:
- """
- Create a Date object from calendar selection.
-
- Args:
- calendar: The calendar widget.
-
- Returns:
- Optional[Date]: Date object if successful, None otherwise.
- """
- try:
- year, month, day = calendar.get_date()
- # Note: month from calendar is 0-11, Date.set_yr_mon_day expects 1-12
- date_obj = Date()
- date_obj.set_yr_mon_day(year, month + 1, day)
- return date_obj
- except (ValueError, AttributeError, TypeError) as e:
- logger.debug(f"Error creating date from calendar: {e}")
- return None
-
- def _on_from_date_selected(self, calendar: Gtk.Calendar) -> None:
- """
- Handle From date calendar selection.
-
- Args:
- calendar: The calendar widget that was selected.
- """
- self._sync_year_spin_from_calendar(calendar, 'date_from_year_spin', self._on_from_year_changed)
- self._validate_date_range()
-
- def _on_to_date_selected(self, calendar: Gtk.Calendar) -> None:
- """
- Handle To date calendar selection.
-
- Args:
- calendar: The calendar widget that was selected.
- """
- self._sync_year_spin_from_calendar(calendar, 'date_to_year_spin', self._on_to_year_changed)
- self._validate_date_range()
-
- def _on_from_calendar_changed(self, calendar: Gtk.Calendar) -> None:
- """
- Handle From calendar month/year change.
-
- Args:
- calendar: The calendar widget that changed.
- """
- self._sync_year_spin_from_calendar(calendar, 'date_from_year_spin', self._on_from_year_changed)
-
- def _on_to_calendar_changed(self, calendar: Gtk.Calendar) -> None:
- """
- Handle To calendar month/year change.
-
- Args:
- calendar: The calendar widget that changed.
- """
- self._sync_year_spin_from_calendar(calendar, 'date_to_year_spin', self._on_to_year_changed)
-
- def _on_from_year_changed(self, spin_button: Gtk.SpinButton) -> None:
- """
- Handle From year spin button change.
-
- Args:
- spin_button: The year spin button that changed.
- """
- new_year = int(spin_button.get_value())
- self._sync_calendar_from_year_spin('date_from_calendar', new_year)
- self._validate_date_range()
-
- def _on_to_year_changed(self, spin_button: Gtk.SpinButton) -> None:
- """
- Handle To year spin button change.
-
- Args:
- spin_button: The year spin button that changed.
- """
- new_year = int(spin_button.get_value())
- self._sync_calendar_from_year_spin('date_to_calendar', new_year)
- self._validate_date_range()
-
- def _on_clear_date_range(self, button: Gtk.Button) -> None:
- """
- Clear the date range selection.
-
- Args:
- button: The clear button that was clicked.
- """
- if 'date_from_calendar' in self._filter_widgets and 'date_to_calendar' in self._filter_widgets:
- from_calendar = self._filter_widgets['date_from_calendar']
- to_calendar = self._filter_widgets['date_to_calendar']
-
- # Reset to current date (calendars always show a date)
- # Get current date and set calendars to it
- now = datetime.date.today()
- from_calendar.select_month(now.month - 1, now.year) # month is 0-11
- from_calendar.select_day(now.day)
- to_calendar.select_month(now.month - 1, now.year)
- to_calendar.select_day(now.day)
-
- # Reset year spin buttons
- if 'date_from_year_spin' in self._filter_widgets:
- from_year_spin = self._filter_widgets['date_from_year_spin']
- from_year_spin.handler_block_by_func(self._on_from_year_changed)
- from_year_spin.set_value(now.year)
- from_year_spin.handler_unblock_by_func(self._on_from_year_changed)
-
- if 'date_to_year_spin' in self._filter_widgets:
- to_year_spin = self._filter_widgets['date_to_year_spin']
- to_year_spin.handler_block_by_func(self._on_to_year_changed)
- to_year_spin.set_value(now.year)
- to_year_spin.handler_unblock_by_func(self._on_to_year_changed)
-
- # Clear validation message
- self._set_validation_message("")
-
- # Mark that date range should not be applied
- self.date_range_explicit = False
-
- def _validate_date_range(self) -> None:
- """
- Validate that From date is not after To date.
- """
- if 'date_from_calendar' not in self._filter_widgets or 'date_to_calendar' not in self._filter_widgets:
- return
-
- from_calendar = self._filter_widgets['date_from_calendar']
- to_calendar = self._filter_widgets['date_to_calendar']
-
- from_year, from_month, from_day = from_calendar.get_date()
- to_year, to_month, to_day = to_calendar.get_date()
-
- # Use helper method to create dates
- from_date = self._create_date_from_calendar(from_calendar)
- to_date = self._create_date_from_calendar(to_calendar)
-
- if from_date is None or to_date is None:
- return
-
- try:
- from_sort = from_date.get_sort_value()
- to_sort = to_date.get_sort_value()
-
- if from_sort > to_sort:
- self._set_validation_message(_('Warning: From date is after To date'))
- else:
- self._set_validation_message("")
- except (ValueError, AttributeError, TypeError):
- pass
-
def build_tree(self) -> None:
"""
Rebuilds the current display. Called when the view becomes visible.
@@ -1986,9 +1564,15 @@ class MyTimelineView(NavigationView):
if not self.active_event_types:
self._normalized_active_event_types = None
else:
- self._normalized_active_event_types = {
- self._normalize_event_type(et) for et in self.active_event_types
- }
+ # Normalize all event types and create a set
+ # Ensure we have at least one normalized type
+ normalized_set = {self._normalize_event_type(et) for et in self.active_event_types}
+ if normalized_set:
+ self._normalized_active_event_types = normalized_set
+ else:
+ # If normalization failed for all types, something is wrong
+ # Set to None to indicate no filtering (show all events)
+ self._normalized_active_event_types = None
def _apply_event_type_filter(self, event: TimelineEvent) -> bool:
"""
@@ -2000,11 +1584,15 @@ class MyTimelineView(NavigationView):
Returns:
bool: True if event passes filter, False otherwise.
"""
+ # If no event type filter is active (empty set means "all enabled"), pass all events
if not self.active_event_types:
return True
# Use pre-computed normalized set if available, otherwise compute it
if self._normalized_active_event_types is None:
self._update_normalized_active_event_types()
+ # If normalized set is still None or empty, something went wrong - pass all events
+ if self._normalized_active_event_types is None or not self._normalized_active_event_types:
+ return True
# Normalize event.event_type and compare with normalized active_event_types
event_type_normalized = self._normalize_event_type(event.event_type)
return event_type_normalized in self._normalized_active_event_types
@@ -2043,10 +1631,6 @@ class MyTimelineView(NavigationView):
if not self._apply_event_type_filter(event):
continue
- # Check date range filter
- if not self._is_date_in_range(event.date_sort):
- continue
-
# Check person filter
person_handle = event.person.get_handle() if event.person else None
if not self._is_person_included(person_handle):
@@ -2109,21 +1693,6 @@ class MyTimelineView(NavigationView):
normalized_type = self._normalize_event_type(event_type)
return normalized_type in self._normalized_active_event_types
- def _is_date_in_range(self, date_sort: int) -> bool:
- """
- Check if a date is within the filter range.
-
- Args:
- date_sort: The date sort value to check.
-
- Returns:
- bool: True if date is in range (or no filter active), False otherwise.
- """
- if not self.date_range_filter or not self.date_range_explicit:
- return True
- min_date, max_date = self.date_range_filter
- return min_date <= date_sort <= max_date
-
def _is_person_included(self, person_handle: Optional[str]) -> bool:
"""
Check if a person is included in the filter.