- Update _get_events_for_person to include events where person is involved
- For marriage events, both spouses now have connection lines to the marriage event
- Uses _get_all_persons_for_event to check if person is involved in multi-person events
- Add _get_all_persons_for_event helper to get all persons for an event
(e.g., both spouses for marriage events)
- Add _format_color_for_display helper to format colors for display
- Modify event click handler to select all persons involved in an event
- When clicking a marriage event, both spouses are now selected together
- Event lines are shown for all selected persons
- Add event-to-family cache for efficient family lookup
- Improve marriage event detection using multiple comparison methods
- Show both spouses for marriage events (e.g., 'Date - Marriage - Person1 & Person2')
- Fix label rendering by using set_text instead of set_markup for plain text
- Add fallback logic to ensure marriage events always show date and event type
- Improve family event indexing to associate family events with spouses
- Replaced expander-based person filter with Gtk.TreeView showing hierarchical structure
- Top-level elements are now persons without parents (root persons) instead of families
- Added second three-state checkbox column for descendants (only visible when descendants exist)
- Person checkbox controls the person only, descendants checkbox controls only descendants
- Both checkboxes support three states (all/none/some) based on descendant states
- Implemented recursive tree building showing all descendants under their ancestors
- Handles persons appearing in multiple families with synchronized checkbox states
- Updated filter application to consider both person and descendants checkboxes
- Descendants checkbox is invisible when person has no descendants
When all event types in a category were unchecked, _update_group_checkbox_state
would set the category checkbox to False, which triggered its toggle handler.
This handler would then set all child checkboxes to match the category state,
causing them to be re-checked.
The fix adds an optional updating_flag parameter to _update_group_checkbox_state
that prevents the group toggle handler from firing during programmatic updates.
The flag is set before updating the checkbox state and cleared after, breaking
the recursion cycle.
Changes:
- Modified _update_group_checkbox_state to accept optional updating_flag parameter
- Updated _make_child_toggle_handler to pass updating_flag
- Store category updating flags in _filter_widgets for reuse
- Updated _update_event_type_widgets to use stored updating flags
- Fixed family checkbox initialization to use updating flag as well
- Move connection lines to draw before events so they appear below event icons
- Add PORTRAIT_GAP constant (12px) for spacing between event marker and portrait
- Update portrait and label positioning to account for the gap
- Add small portraits (24px) next to timeline events for person events
- Add larger portraits (120px) in tooltips when hovering over events
- Implement portrait loading from Gramps media_list using media_path_full
- Add portrait drawing using Cairo with circular clipping and border
- Update demo family generator to create portraits using DiceBear Avatars API
- Generate portraits considering age and gender for appropriate appearance
- Add media objects to XML with proper IDs and gallery references
- Use relative paths for media files in demo family XML
- Add helper scripts for debugging Gramps log files
- Fix deprecation warnings for XML element truth value checks
- Clear tooltip_timeout_id at start of show_tooltip callback
- Prevents attempting to remove timeout that already fired and was auto-removed
- Simplifies removal logic by always clearing ID in finally block
This fixes the GLib warning when timeout fires and is automatically removed,
then we try to remove it again manually.
- Add error handling for GLib.source_remove() when source ID is invalid
- Prevents warning: 'Source ID was not found when attempting to remove it'
- Properly clears timeout_id even if removal fails
This fixes the case where a timeout source has already been removed
automatically, leaving a stale source ID that causes warnings.
- Change cache key from EventType (unhashable) to normalized int
- Fixes TypeError: unhashable type: 'EventType' error
- Cache now uses normalized integer as both key and value
This ensures the cache works correctly with non-hashable EventType objects
while maintaining caching benefits for repeated conversions.
- Replace magic numbers 800, 600 with DEFAULT_DRAWING_AREA_WIDTH and DEFAULT_DRAWING_AREA_HEIGHT constants
- Improves consistency and maintainability
This ensures all size references use the same constants.
- Extract DRAWING_AREA_EVENT_MASKS constant to consolidate event mask combination
- Improves maintainability by centralizing event mask configuration
This change makes it easier to modify event handling behavior in one place.
- Replace len() > 0 with direct boolean check for better Pythonic code
- Optimize dictionary iteration by removing unnecessary .keys() calls
These changes improve code readability and follow Python best practices
by using more idiomatic patterns.
- Extract MOUSE_BUTTON_LEFT constant to replace magic number 1
- Extract ZOOM_PERCENTAGE_MULTIPLIER constant for zoom display
- Extract HSV_HUE_MAX_DEGREES constant for color generation
- Improve zoom display calculation readability
These changes improve code maintainability by replacing magic numbers
with named constants that clearly express their purpose.
- Extract DEFAULT_EVENT_SHAPE constant to replace 'square' magic string
- Create _index_event_refs() helper method to reduce duplication in _build_event_to_person_index()
- Use DEFAULT_EVENT_SHAPE constant in _draw_shape() default parameter
These changes improve maintainability by reducing code duplication and
replacing magic strings with named constants.
- Use _normalize_event_type() helper consistently in draw_event_marker()
- Extract label drawing constants (text color, vertical offset, hover colors)
- Extract marker border width and black color constants
- Extract year marker label offset constant
- Create _get_events_for_person() helper to reduce duplication
- Replace len() < 1 with 'not' for better Pythonic code
- Optimize y_positions min/max using sorted list indices
- Extract connection line minimum distance constant
These changes improve code maintainability, reduce duplication, and enhance
readability by replacing magic numbers with named constants.
- Move datetime imports to module level (follows Python best practices)
Removed 3 duplicate imports from inside methods
- Extract remaining hardcoded UI constants
Added FILTER_PAGE_VERTICAL_SPACING, FILTER_CATEGORY_SPACING, FILTER_INDENT_MARGIN
Added TOOLBAR_SPACING, TOOLBAR_ITEM_MARGIN
Added TOOLTIP_SEPARATOR_LENGTH
Replaced all hardcoded spacing/margin values in filter page builders
- Extract common zoom logic into _update_zoom() helper
Reduces duplication across on_zoom_in, on_zoom_out, on_zoom_reset methods
- Consolidate date handler methods
Created _sync_year_spin_from_calendar() and _sync_calendar_from_year_spin() helpers
Created _create_date_from_calendar() helper for date creation
Reduced ~60 lines of duplicated code in date handlers
- Improve cache management
Clear event type normalization cache in _invalidate_cache() to prevent stale data
- Improve error messages with more context
All error messages now specify which operation/component failed
Makes debugging significantly easier
- Extract calendar widget creation into helper method (_create_date_calendar_widget)
Eliminates ~80 lines of duplicated code between from/to date widgets
- Extract place access logic into _get_place_name_for_event() helper
Provides single source of truth for place access with error handling
- Consolidate year spin button updates via _update_year_spin_button() helper
Reduces duplication and ensures consistent behavior
- Split _update_filter_dialog_state() into focused methods:
- _update_event_type_widgets()
- _update_person_filter_widgets()
- _update_date_range_widgets()
- Extract filter check logic into separate methods:
- _apply_event_type_filter()
- _apply_category_filter()
- Improve type hints: change handler return types from Any to Callable[[Gtk.Widget], None]
- Extract UI layout constants (margins, spacing) for better maintainability
- Add event type normalization caching for performance
Cache dictionary avoids repeated conversions
- Optimize event type set operations with pre-computed normalized active types
Improves filter performance significantly
- Add comprehensive type hints to MyTimeline.py methods
- Add type hints to __init__, change_db, and tooltip formatting methods
- Use Any for Gramps-specific types that aren't easily importable
- Refactor generate_demo_family.py to use ElementTree
- Replace string concatenation with xml.etree.ElementTree for proper XML generation
- Add compatibility handling for Python < 3.9 (ET.indent)
- Add EventData, PersonData, and FamilyData dataclasses for better structure
- Add comprehensive type hints to all functions
- Extract magic numbers to named constants
- Add constants for UI dimensions, timeline heights, dialog sizes
- Add constants for date calculations and genealogical year ranges
- Improve code readability and maintainability
- Refactor duplicated code in filter dialog handlers
- Extract common checkbox handler logic into reusable methods
- Create _make_group_toggle_handler and _make_child_toggle_handler
- Eliminate code duplication between event type and family filters
- Improve shell scripts with better error handling
- Add validation for Gramps installation
- Improve error messages with actionable troubleshooting steps
- Use set -euo pipefail for better error detection
- Add better user guidance in error scenarios
- Added TIMELINE_LEFT_SPACING constant for spacing between connection lines and timeline
- Added _calculate_max_connection_line_x() to find rightmost connection line position
- Added _calculate_timeline_x() to dynamically calculate timeline X position
- Timeline now adjusts based on number of selected persons and their connection lines
- Updated on_draw() and find_event_at_position() to use dynamic timeline_x
- Timeline maintains minimum position to prevent overlap with year labels
- Event symbols and text now position relative to connection lines on the left
- Changed from single selected_person_handle to selected_person_handles set
- Added color generation using HSV color space for distinct person colors
- Added unique X positions for each person's vertical connection line
- Updated click handler to toggle persons in/out of selection set
- Refactored draw_person_connections to draw separate colored lines for each person
- Each selected person gets their own colored vertical line at unique X position
- Colors are consistent for each person based on handle hash
- Added helper methods for three-state checkbox management
(_calculate_group_state, _update_group_checkbox_state)
- Replaced category labels with three-state checkboxes in Event Types tab
- Added three-state checkboxes to family expander labels in Persons tab
- Implemented bidirectional state synchronization between group and child checkboxes
- Group checkboxes show checked (all), unchecked (none), or inconsistent (some) states
- Convert plugin from Family-based to Event-based view
* Change category from Families to Events
* Update navigation_type to 'Event'
* Replace FamilyBookmarks with EventBookmarks
* Rewrite collect_events() to show all events in database
* Update goto_handle() to work with event handles
- Update filter dialog to show families with members
* Restructure person filter page with expandable families
* Each family shows father, mother, and children
* Add helper method to generate family display names
- Restore person connection lines
* Re-enable visual connections between events of selected person
* Clicking an event selects the person and shows connections
- Add uninstall script
* Remove plugin files and backup directories
* Clean up any plugin files in subdirectories
- Add Gtk.SpinButton widgets above each calendar for quick year selection
- Implement bidirectional synchronization between year selectors and calendars
- Set year range from 1000 to current year + 10 for genealogical data
- Update clear date range and filter state management to handle year selectors
- Improve UX by allowing direct year input instead of incrementing one year at a time
- Add comprehensive event filtering (event types, categories, persons, date range)
- Implement collapsible Gtk.Expander widgets for event type groups
- Add human-readable event type names in filter dialog
- Add EVENT_CATEGORIES mapping for event categorization
- Add filter state management and filter application logic
- Add filter button to toolbar with active state indication
- Support multiple filter types that can be combined
- Add filter dialog with tabs for event types, categories, persons, and date range
- Implement EVENT_CATEGORIES mapping for event categorization
- Add filter state management (event types, date range, person, category filters)
- Fix EventType normalization for dictionary lookups and comparisons
- Add _normalize_event_type() helper method for consistent EventType handling
- Update event collection to store all events and apply filters
- Add filter button to toolbar with active state indication
- Support multiple filter types that can be combined
- Fix event collection bug (events now stored in all_events before filtering)
- Add _person_matches_handle() helper method to eliminate code duplication
- Replace 3 instances of 'person and person.get_handle() == handle' pattern
- Fix remaining hardcoded font string to use FONT_FAMILY constant
- Improve code consistency and maintainability
Benefits:
- Reduced code duplication
- Centralized person handle comparison logic
- All font strings now use constants
- More readable and maintainable code
- Add comprehensive docstring for __init__ method
- Initialize _temp_surface in __init__ instead of lazy initialization
- Extract font constants (FONT_FAMILY, FONT_SIZE_NORMAL, FONT_SIZE_SMALL, FONT_SIZE_LARGE)
- Replace all hardcoded font strings with constants
- All methods now have docstrings (100% coverage)
Benefits:
- Better initialization clarity
- Centralized font configuration
- Complete documentation coverage
- More maintainable code
Phase 1 - Quick Wins:
- Extract date range calculation to _calculate_date_range() with caching
- Extract Y position calculation to _calculate_y_position()
- Add remaining constants (TOOLTIP_MAX_WIDTH, LABEL_BACKGROUND_PADDING, LABEL_BACKGROUND_RADIUS)
Phase 2 - Refactoring:
- Replace tuple indexing with TimelineEvent dataclass for type safety
- Break down collect_person_events into smaller methods:
* _collect_person_event_refs()
* _process_event_ref()
* _collect_person_events()
- Break down show_tooltip into helper methods:
* _format_person_tooltip()
* _format_single_event_tooltip()
* _get_or_create_tooltip_window()
- Break down draw_event_marker into helper methods:
* _draw_marker_shadow()
* _draw_marker_gradient()
- Break down on_draw into helper methods:
* _draw_background()
* _draw_no_events_message()
* _draw_timeline_axis()
* _draw_events()
Phase 3 - Enhancements:
- Add comprehensive type hints to all methods
- Improve error handling with specific exceptions (AttributeError, KeyError, ValueError)
- Add logging module with appropriate log levels
- Improve all docstrings with parameter and return documentation
- Reuse tooltip window instead of recreating each time
- Improve cache management with hash-based keys instead of context comparison
Code Quality Improvements:
- Type safety: TimelineEvent dataclass replaces error-prone tuple indexing
- Maintainability: Methods are shorter and more focused (28 → 40+ methods)
- Performance: Better caching with hash-based keys
- Readability: Clear method names and comprehensive docstrings
- Debugging: Logging for error tracking
- IDE support: Type hints improve autocomplete and error detection
All linter errors resolved. Code compiles successfully.
- Remove expanded_event_index variable and all related logic
- Remove is_expanded parameters from methods
- Remove expanded field from event tuples (now 6 elements instead of 7)
- Remove EXPANDED_HEIGHT constant
- Remove expanded text display logic from draw_event_label
- Simplify event structure: (date_sort, date_obj, event, person, event_type, y_pos)
- Events now always show single-line text
- Clicking events only selects person (no expansion)
Result: Cleaner code, simpler behavior, reduced file size (49KB from 52KB)
- Allow clicking anywhere on event line to select person (like selecting event)
- Selected events always show single-line text (no multi-line expansion)
- Force is_expanded=False for selected events to prevent text switching
- Always collapse expanded events when selecting person
- Selection and expansion are now completely separate actions
- Move vertical connection line from timeline_x - 40 to x=5
- Position line clearly to the left of year labels (x=90-130)
- Horizontal lines connect vertical line to each event marker
- Improved visual hierarchy: vertical line → year labels → timeline → events
- Fix mouse coordinate transformation to account for zoom level
- Enable whole-line selection (click anywhere on event line to select person)
- Update tooltip to show date first, then event type
- Make connection lines more visible with increased opacity and width
- Improved click detection using scaled coordinates
- Expanded clickable area to include both marker and label regions
- Added 12 different event types (Baptism, Education, Occupation, etc.)
- Fixed missing event references by storing and reusing original events
- Made event generation deterministic with random seed
- Updated gen_person to return both XML and tuple format for event reuse
- All event references now properly defined and validated
- Demo family now includes 240+ additional events for comprehensive testing
- Implement detect_label_overlaps() to prevent text label overlaps
- Automatically adjust Y positions while maintaining chronological order
- Enhanced tooltips to show all events for a person, not just hovered event
- Added person selection on event marker click
- Implement draw_person_connections() to visually connect selected person's events
- Selected person's events highlighted with blue color and connecting lines
- Click on marker selects person, click on label expands event details
- Fixed EventType objects not being hashable by extracting integer value
- Fixed UnboundLocalError by removing variable shadowing of translation function _
- Updated all tuple unpacking to use proper variable names instead of _
- All event types now properly supported with color/shape mapping
- Plugin fully compatible with Gramps 5.1
- Replace get_extents() with get_pixel_size() for correct text measurement
- Fixes ValueError: not enough values to unpack error
- get_pixel_size() returns (width, height) tuple directly in pixels
- Implement build_tree() method required by NavigationView
- Calls goto_handle() with active family to rebuild display
- Fixes TypeError when loading MyTimeline view