timeline_entry.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. """
  2. Timeline Entry Widget
  3. Widget for displaying a single test result entry in the analysis timeline.
  4. """
  5. from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QPushButton
  6. from PyQt5.QtCore import Qt, pyqtSignal
  7. from PyQt5.QtGui import QFont
  8. class TimelineEntry(QWidget):
  9. """
  10. Timeline entry showing a test result.
  11. Signals:
  12. save_clicked: Emitted when save button is clicked
  13. view_clicked: Emitted when view button is clicked
  14. """
  15. save_clicked = pyqtSignal(int) # test_id
  16. view_clicked = pyqtSignal(int) # test_id
  17. def __init__(self, test_id: int, timestamp: str, classification: str,
  18. confidence: float, processing_time: float, parent=None):
  19. super().__init__(parent)
  20. self.test_id = test_id
  21. self.init_ui(timestamp, classification, confidence, processing_time)
  22. def init_ui(self, timestamp: str, classification: str,
  23. confidence: float, processing_time: float):
  24. """Initialize the timeline entry UI."""
  25. self.setFixedHeight(48)
  26. # Set background color (alternating)
  27. bg_color = "#f8f9fa" if self.test_id % 2 == 0 else "#ffffff"
  28. self.setStyleSheet(f"""
  29. QWidget {{
  30. background-color: {bg_color};
  31. border: 1px solid #ecf0f1;
  32. border-radius: 3px;
  33. }}
  34. """)
  35. layout = QHBoxLayout(self)
  36. layout.setContentsMargins(12, 8, 12, 8)
  37. layout.setSpacing(12)
  38. # Status indicator dot
  39. status_colors = {
  40. "Ripe": "#27ae60",
  41. "Overripe": "#f39c12",
  42. "Unripe": "#95a5a6",
  43. "Overripe": "#e74c3c"
  44. }
  45. color = status_colors.get(classification, "#95a5a6")
  46. status_dot = QLabel("●")
  47. status_dot.setFont(QFont("Arial", 12))
  48. status_dot.setStyleSheet(f"color: {color};")
  49. status_dot.setFixedWidth(15)
  50. layout.addWidget(status_dot)
  51. # Info section
  52. info_layout = QVBoxLayout()
  53. info_layout.setSpacing(2)
  54. # Timestamp and test ID
  55. header_label = QLabel(f"{timestamp} - Test #{self.test_id:04d}")
  56. header_label.setFont(QFont("Arial", 10, QFont.Bold))
  57. header_label.setStyleSheet("color: #2c3e50;")
  58. info_layout.addWidget(header_label)
  59. # Classification and details
  60. details = f"{classification.upper()} ({confidence:.1f}%) - Processing: {processing_time:.2f}s"
  61. details_label = QLabel(details)
  62. details_label.setFont(QFont("Arial", 9))
  63. details_label.setStyleSheet(f"color: {color};")
  64. info_layout.addWidget(details_label)
  65. layout.addLayout(info_layout, 1)
  66. # Action button
  67. if self.test_id == 1: # Most recent - show SAVE button
  68. action_btn = QPushButton("SAVE")
  69. action_btn.clicked.connect(lambda: self.save_clicked.emit(self.test_id))
  70. btn_color = "#27ae60"
  71. else: # Older entries - show VIEW button
  72. action_btn = QPushButton("VIEW")
  73. action_btn.clicked.connect(lambda: self.view_clicked.emit(self.test_id))
  74. btn_color = "#3498db"
  75. action_btn.setFont(QFont("Arial", 8, QFont.Bold))
  76. action_btn.setFixedSize(50, 24)
  77. action_btn.setStyleSheet(f"""
  78. QPushButton {{
  79. background-color: {btn_color};
  80. border: none;
  81. border-radius: 2px;
  82. color: white;
  83. }}
  84. QPushButton:hover {{
  85. opacity: 0.9;
  86. }}
  87. """)
  88. layout.addWidget(action_btn)