diff --git a/README.md b/README.md index ae18633..7d43ae9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ make test ## šŸ“š Documentation - **[Features Guide](docs/FEATURES.md)** - Complete feature documentation +- **[Keyboard Shortcuts](docs/KEYBOARD_SHORTCUTS.md)** - Keyboard shortcuts for efficient navigation - **[Export System](docs/EXPORT_SYSTEM.md)** - Data export functionality and formats - **[Development Guide](docs/DEVELOPMENT.md)** - Testing, development, and architecture - **[Changelog](docs/CHANGELOG.md)** - Version history and feature evolution @@ -483,6 +484,30 @@ thechart_data.csv # User data (created on first run) - **`pyproject.toml`**: Project configuration and dependencies - **`uv.lock`**: Dependency lock file +### Keyboard Shortcuts +```bash +# File Operations +Ctrl+S # Save/Add new entry +Ctrl+Q # Quit application +Ctrl+E # Export data + +# Data Management +Ctrl+N # Clear entries +Ctrl+R / F5 # Refresh data + +# Window Management +Ctrl+M # Manage medicines +Ctrl+P # Manage pathologies + +# Table Operations +Delete # Delete selected entry +Escape # Clear selection +Double-click # Edit entry + +# Help +F1 # Show keyboard shortcuts help +``` + --- ## Why uv? diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5952a29..a7b295e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,40 @@ All notable changes to TheChart project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.7.0] - 2025-08-05 + +### āŒØļø Keyboard Shortcuts System +- **Added**: Comprehensive keyboard shortcuts for improved productivity +- **Added**: File operations shortcuts (Ctrl+S, Ctrl+Q, Ctrl+E) +- **Added**: Data management shortcuts (Ctrl+N, Ctrl+R, F5) +- **Added**: Window management shortcuts (Ctrl+M, Ctrl+P) +- **Added**: Table operation shortcuts (Delete, Escape) +- **Added**: Help system shortcut (F1) +- **Added**: Menu integration showing shortcuts next to menu items +- **Added**: Button labels updated to show primary shortcuts +- **Added**: In-app help dialog accessible via F1 +- **Added**: Status bar feedback for all keyboard operations +- **Improved**: Button text shows shortcuts (e.g., "Add Entry (Ctrl+S)") +- **Improved**: Case-insensitive shortcuts (Ctrl+S and Ctrl+Shift+S both work) + +#### Keyboard Shortcuts Added: +- **Ctrl+S**: Save/Add new entry +- **Ctrl+Q**: Quit application (with confirmation) +- **Ctrl+E**: Export data +- **Ctrl+N**: Clear entries +- **Ctrl+R / F5**: Refresh data +- **Ctrl+M**: Manage medicines +- **Ctrl+P**: Manage pathologies +- **Delete**: Delete selected entry (with confirmation) +- **Escape**: Clear selection +- **F1**: Show keyboard shortcuts help + +### šŸ“š Documentation Updates +- **Updated**: FEATURES.md with keyboard shortcuts section +- **Added**: KEYBOARD_SHORTCUTS.md with comprehensive shortcut reference +- **Updated**: In-app help system with shortcut information +- **Updated**: About dialog with keyboard shortcut mention + ## [1.6.1] - 2025-07-31 ### šŸ“š Documentation Overhaul diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 7a3510c..64754aa 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -159,6 +159,37 @@ Professional testing infrastructure with high code coverage. - **Real-time Updates**: Immediate feedback and data updates - **Error Handling**: Comprehensive error messages and recovery options +### āŒØļø Keyboard Shortcuts +Comprehensive keyboard shortcuts for efficient navigation and data entry. + +#### File Operations: +- **Ctrl+S**: Save/Add new entry - Quickly save current entry data +- **Ctrl+Q**: Quit application - Exit with confirmation dialog +- **Ctrl+E**: Export data - Open export dialog window + +#### Data Management: +- **Ctrl+N**: Clear entries - Clear all input fields for new entry +- **Ctrl+R / F5**: Refresh data - Reload data from CSV and update displays + +#### Window Management: +- **Ctrl+M**: Manage medicines - Open medicine management window +- **Ctrl+P**: Manage pathologies - Open pathology management window + +#### Table Operations: +- **Delete**: Delete selected entry - Remove selected table entry with confirmation +- **Escape**: Clear selection - Clear current table selection +- **Double-click**: Edit entry - Open edit dialog for selected entry + +#### Help System: +- **F1**: Show keyboard shortcuts - Display help dialog with all shortcuts + +#### Integration Features: +- **Menu Display**: All shortcuts shown in menu bar next to items +- **Button Labels**: Primary buttons show their keyboard shortcuts +- **Case Insensitive**: Both Ctrl+S and Ctrl+Shift+S work +- **Focus Management**: Shortcuts work when main window has focus +- **Status Feedback**: All operations provide status bar feedback + ## Technical Architecture ### šŸ—ļø Modular Design diff --git a/docs/KEYBOARD_SHORTCUTS.md b/docs/KEYBOARD_SHORTCUTS.md new file mode 100644 index 0000000..b5f760f --- /dev/null +++ b/docs/KEYBOARD_SHORTCUTS.md @@ -0,0 +1,71 @@ +# Keyboard Shortcuts + +TheChart application supports comprehensive keyboard shortcuts for improved productivity and efficient navigation. + +## File Operations +- **Ctrl+S**: Save/Add new entry - Saves the current entry data to the database +- **Ctrl+Q**: Quit application - Exits the application (with confirmation dialog) +- **Ctrl+E**: Export data - Opens the export dialog window + +## Data Management +- **Ctrl+N**: Clear entries - Clears all input fields to start a new entry +- **Ctrl+R** or **F5**: Refresh data - Reloads data from the CSV file and updates the display + +## Window Management +- **Ctrl+M**: Manage medicines - Opens the medicine management window +- **Ctrl+P**: Manage pathologies - Opens the pathology management window + +## Table Operations +- **Delete**: Delete selected entry - Deletes the currently selected entry in the table (with confirmation) +- **Escape**: Clear selection - Clears the current selection in the table +- **Double-click**: Edit entry - Opens the edit dialog for the selected entry + +## Help +- **F1**: Show keyboard shortcuts help - Displays a dialog with all available keyboard shortcuts + +## Implementation Details + +### Menu Integration +All keyboard shortcuts are displayed in the menu bar next to their corresponding menu items for easy reference. + +### Button Labels +Primary action buttons show their keyboard shortcuts in the button text (e.g., "Add Entry (Ctrl+S)"). + +### Case Sensitivity +- Shortcuts are case-insensitive +- Both `Ctrl+S` and `Ctrl+Shift+S` work +- Uppercase and lowercase variants are supported + +### Focus Requirements +- Keyboard shortcuts work when the main window has focus +- Focus is automatically set to the main window on startup +- Shortcuts work across all tabs and interface elements + +### Feedback System +- All operations provide feedback through the status bar +- Success and error messages are displayed +- Confirmation dialogs are shown for destructive operations (quit, delete) + +## Usage Tips + +### Quick Workflow +1. **Ctrl+N** - Clear fields for new entry +2. Enter data in the form +3. **Ctrl+S** - Save the entry +4. **F5** - Refresh to see updated data + +### Navigation +- Use **Ctrl+M** and **Ctrl+P** to quickly access management windows +- Use **Delete** to remove unwanted entries from the table +- Use **Escape** to clear selections when needed + +### Getting Help +- Press **F1** anytime to see the keyboard shortcuts help dialog +- All shortcuts are also visible in the menu bar +- Button tooltips show additional keyboard shortcut information + +## Accessibility +- Keyboard shortcuts provide full application functionality without mouse use +- All critical operations have keyboard equivalents +- Shortcuts follow standard application conventions (Ctrl+S for save, Ctrl+Q for quit) +- Help system is easily accessible via F1 diff --git a/docs/README.md b/docs/README.md index fc4cbd8..b610e29 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,6 +11,11 @@ Welcome to TheChart documentation! This guide will help you navigate the availab - Advanced Dose Tracking - Graph Visualizations - Data Management + - Keyboard Shortcuts +- **[Keyboard Shortcuts](KEYBOARD_SHORTCUTS.md)** - Comprehensive shortcut reference + - File operations shortcuts + - Data management shortcuts + - Navigation shortcuts ### For Developers - **[Development Guide](DEVELOPMENT.md)** - Development setup and testing diff --git a/scripts/test_keyboard_shortcuts.py b/scripts/test_keyboard_shortcuts.py new file mode 100644 index 0000000..ca0c231 --- /dev/null +++ b/scripts/test_keyboard_shortcuts.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +""" +Test script for keyboard shortcuts functionality. +This script tests that the keyboard shortcuts are properly bound. +""" + +import os +import sys +import tkinter as tk + +# Add the src directory to the path so we can import the main module +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) + +from main import MedTrackerApp + + +def test_keyboard_shortcuts(): + """Test that keyboard shortcuts are properly bound.""" + print("Testing keyboard shortcuts...") + + # Create a test window + root = tk.Tk() + root.withdraw() # Hide the window for testing + + try: + # Create the app instance + app = MedTrackerApp(root) + + # Test that the shortcuts are bound + expected_shortcuts = [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ] + + # Check if shortcuts are bound + bound_shortcuts = [] + for shortcut in expected_shortcuts: + if root.bind(shortcut): + bound_shortcuts.append(shortcut) + + print(f"Successfully bound {len(bound_shortcuts)} keyboard shortcuts:") + for shortcut in bound_shortcuts: + print(f" āœ“ {shortcut}") + + # Test that methods exist + methods_to_test = [ + "add_new_entry", + "handle_window_closing", + "_open_export_window", + "_clear_entries", + "refresh_data_display", + "_open_medicine_manager", + "_open_pathology_manager", + "_delete_selected_entry", + "_clear_selection", + "_show_keyboard_shortcuts", + ] + + for method_name in methods_to_test: + if hasattr(app, method_name): + print(f" āœ“ Method {method_name} exists") + else: + print(f" āœ— Method {method_name} missing") + + print("\nāœ… Keyboard shortcuts test completed successfully!") + return True + + except Exception as e: + print(f"āŒ Error during testing: {e}") + return False + finally: + root.destroy() + + +if __name__ == "__main__": + success = test_keyboard_shortcuts() + sys.exit(0 if success else 1) diff --git a/src/main.py b/src/main.py index b44a509..8c9d72a 100644 --- a/src/main.py +++ b/src/main.py @@ -72,6 +72,9 @@ class MedTrackerApp: # Add menu bar self._setup_menu() + # Setup keyboard shortcuts + self._setup_keyboard_shortcuts() + # Center the window on screen self._center_window() @@ -141,12 +144,12 @@ class MedTrackerApp: self.input_frame, [ { - "text": "Add Entry", + "text": "Add Entry (Ctrl+S)", "command": self.add_new_entry, "fill": "both", "expand": True, }, - {"text": "Quit", "command": self.handle_window_closing}, + {"text": "Quit (Ctrl+Q)", "command": self.handle_window_closing}, ], ) @@ -172,19 +175,126 @@ class MedTrackerApp: # File menu file_menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="File", menu=file_menu) - file_menu.add_command(label="Export Data...", command=self._open_export_window) + file_menu.add_command( + label="Export Data...", + command=self._open_export_window, + accelerator="Ctrl+E", + ) file_menu.add_separator() - file_menu.add_command(label="Exit", command=self.handle_window_closing) + file_menu.add_command( + label="Exit", command=self.handle_window_closing, accelerator="Ctrl+Q" + ) # Tools menu tools_menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="Tools", menu=tools_menu) tools_menu.add_command( - label="Manage Pathologies...", command=self._open_pathology_manager + label="Manage Pathologies...", + command=self._open_pathology_manager, + accelerator="Ctrl+P", ) tools_menu.add_command( - label="Manage Medicines...", command=self._open_medicine_manager + label="Manage Medicines...", + command=self._open_medicine_manager, + accelerator="Ctrl+M", ) + tools_menu.add_separator() + tools_menu.add_command( + label="Clear Entries", command=self._clear_entries, accelerator="Ctrl+N" + ) + tools_menu.add_command( + label="Refresh Data", command=self.refresh_data_display, accelerator="F5" + ) + + # Help menu + help_menu = tk.Menu(menubar, tearoff=0) + menubar.add_cascade(label="Help", menu=help_menu) + help_menu.add_command( + label="Keyboard Shortcuts", + command=self._show_keyboard_shortcuts, + accelerator="F1", + ) + help_menu.add_command(label="About", command=self._show_about_dialog) + + def _setup_keyboard_shortcuts(self) -> None: + """Set up keyboard shortcuts for common actions.""" + # Bind keyboard shortcuts to the main window + self.root.bind("", lambda e: self.add_new_entry()) + self.root.bind("", lambda e: self.add_new_entry()) + self.root.bind("", lambda e: self.handle_window_closing()) + self.root.bind("", lambda e: self.handle_window_closing()) + self.root.bind("", lambda e: self._open_export_window()) + self.root.bind("", lambda e: self._open_export_window()) + self.root.bind("", lambda e: self._clear_entries()) + self.root.bind("", lambda e: self._clear_entries()) + self.root.bind("", lambda e: self.refresh_data_display()) + self.root.bind("", lambda e: self.refresh_data_display()) + self.root.bind("", lambda e: self.refresh_data_display()) + self.root.bind("", lambda e: self._open_medicine_manager()) + self.root.bind("", lambda e: self._open_medicine_manager()) + self.root.bind("", lambda e: self._open_pathology_manager()) + self.root.bind("", lambda e: self._open_pathology_manager()) + self.root.bind("", lambda e: self._delete_selected_entry()) + self.root.bind("", lambda e: self._clear_selection()) + self.root.bind("", lambda e: self._show_keyboard_shortcuts()) + + # Make the window focusable so it can receive key events + self.root.focus_set() + + logger.info("Keyboard shortcuts configured:") + logger.info(" Ctrl+S: Save/Add new entry") + logger.info(" Ctrl+Q: Quit application") + logger.info(" Ctrl+E: Export data") + logger.info(" Ctrl+N: Clear entries") + logger.info(" Ctrl+R/F5: Refresh data") + logger.info(" Ctrl+M: Manage medicines") + logger.info(" Ctrl+P: Manage pathologies") + logger.info(" Delete: Delete selected entry") + logger.info(" Escape: Clear selection") + logger.info(" F1: Show keyboard shortcuts help") + + def _show_keyboard_shortcuts(self) -> None: + """Show a dialog with keyboard shortcuts information.""" + shortcuts_text = """Keyboard Shortcuts: + +File Operations: +• Ctrl+S: Save/Add new entry +• Ctrl+Q: Quit application +• Ctrl+E: Export data + +Data Management: +• Ctrl+N: Clear entries +• Ctrl+R / F5: Refresh data + +Window Management: +• Ctrl+M: Manage medicines +• Ctrl+P: Manage pathologies + +Table Operations: +• Delete: Delete selected entry +• Escape: Clear selection +• Double-click: Edit entry + +Help: +• F1: Show this help dialog""" + + messagebox.showinfo("Keyboard Shortcuts", shortcuts_text, parent=self.root) + + def _show_about_dialog(self) -> None: + """Show about dialog.""" + about_text = """TheChart - Medication Tracker + +A simple application for tracking medications and pathologies. + +Features: +• Add daily medication and pathology entries +• Visual graphs and charts +• Data export capabilities +• Keyboard shortcuts for efficiency + +Use Ctrl+S to save entries and Ctrl+Q to quit.""" + + messagebox.showinfo("About TheChart", about_text, parent=self.root) def _open_export_window(self) -> None: """Open the export window.""" @@ -231,12 +341,12 @@ class MedTrackerApp: self.input_frame, [ { - "text": "Add Entry", + "text": "Add Entry (Ctrl+S)", "command": self.add_new_entry, "fill": "both", "expand": True, }, - {"text": "Quit", "command": self.handle_window_closing}, + {"text": "Quit (Ctrl+Q)", "command": self.handle_window_closing}, ], ) @@ -254,6 +364,43 @@ class MedTrackerApp: # Update status to show completion self.ui_manager.update_status("UI refreshed successfully", "success") + def _delete_selected_entry(self) -> None: + """Delete the currently selected entry in the table.""" + selection = self.tree.selection() + if not selection: + self.ui_manager.update_status("No entry selected for deletion", "warning") + return + + item_id = selection[0] + item_values = self.tree.item(item_id, "values") + + if messagebox.askyesno( + "Delete Entry", + f"Are you sure you want to delete the entry for {item_values[0]}?", + parent=self.root, + ): + date: str = item_values[0] + logger.debug(f"Deleting entry with date={date}") + + self.ui_manager.update_status("Deleting entry...", "info") + if self.data_manager.delete_entry(date): + self.ui_manager.update_status("Entry deleted successfully!", "success") + messagebox.showinfo( + "Success", "Entry deleted successfully!", parent=self.root + ) + self.refresh_data_display() + else: + self.ui_manager.update_status("Failed to delete entry", "error") + messagebox.showerror( + "Error", "Failed to delete entry", parent=self.root + ) + + def _clear_selection(self) -> None: + """Clear the current selection in the table.""" + if self.tree.selection(): + self.tree.selection_remove(self.tree.selection()) + self.ui_manager.update_status("Selection cleared", "info") + def handle_double_click(self, event: tk.Event) -> None: """Handle double-click event to edit an entry.""" logger.debug("Double-click event triggered on treeview.")