Coverage for main/components/collapsible_info_frame.py: 94%

33 statements  

« prev     ^ index     » next       coverage.py v7.15.0, created at 2026-07-03 15:51 +0000

1from PyQt6.QtCore import QCoreApplication 

2from PyQt6.QtWidgets import QFrame, QVBoxLayout, QPushButton, QLabel 

3 

4 

5class CollapsibleInfoFrame(QFrame): 

6 """ 

7 A collapsible information panel displaying contextual help or configuration instructions. 

8 

9 This widget provides a styled information box with a toggle button that expands 

10 or collapses its content. It’s particularly useful for showing optional user 

11 guidance (e.g., color-coding legends, usage tips, or data selection rules). 

12 

13 --- 

14 **Features** 

15 - Collapsible/expandable content area 

16 - Styled using Qt stylesheets for a clean look 

17 - Supports dynamic translation through Qt's `QCoreApplication.translate` 

18 - Automatically reacts to external language change signals (if provided in `context`) 

19 --- 

20 

21 **Parameters** 

22 - `context (dict | None)`: Optional application context dictionary. 

23 If it includes a `"language_changed"` signal, the frame will update its text automatically when the language changes. 

24 

25 **Example** 

26 ```python 

27 frame = CollapsibleInfoFrame(context) 

28 frame.show() 

29 ``` 

30 """ 

31 

32 def __init__(self, context): 

33 """ 

34 Initialize the collapsible information frame. 

35 

36 Args: 

37 context (dict | None): Optional dictionary providing signal connections 

38 for language translation updates. 

39 """ 

40 super().__init__() 

41 

42 # --- Frame styling --- 

43 self.setObjectName("info_frame") 

44 self.setStyleSheet(""" 

45 QFrame#info_frame { 

46 background-color: #e3f2fd; /* Soft blue background */ 

47 border: 1px solid #2196f3; /* Blue border */ 

48 border-radius: 6px; 

49 margin: 6px 0; 

50 } 

51 """) 

52 

53 # --- Main layout configuration --- 

54 self.layout = QVBoxLayout(self) 

55 self.layout.setContentsMargins(8, 6, 8, 6) 

56 self.layout.setSpacing(4) 

57 

58 # --- Toggle button --- 

59 self.toggle_button = QPushButton("Configuration Instructions") 

60 self.toggle_button.setStyleSheet(""" 

61 QPushButton { 

62 font-size: 14px; 

63 font-weight: bold; 

64 color: #1976d2; 

65 background: none; 

66 border: none; 

67 text-align: left; 

68 padding: 4px 8px; 

69 } 

70 QPushButton:hover { 

71 background-color: #bbdefb; /* Hover highlight */ 

72 border-radius: 4px; 

73 } 

74 """) 

75 self.toggle_button.clicked.connect(self.toggle_content) 

76 self.layout.addWidget(self.toggle_button) 

77 

78 # --- Content area --- 

79 self.content_frame = QFrame() 

80 self.content_layout = QVBoxLayout(self.content_frame) 

81 self.content_layout.setContentsMargins(8, 4, 8, 4) 

82 self.content_layout.setSpacing(4) 

83 

84 # --- Informational text --- 

85 self.info_text = QLabel(""" 

86 <style> 

87 .info-list { margin: 0; padding-left: 1rem; } 

88 .info-list li { margin-bottom: 0.3rem; line-height: 1.3; } 

89 </style> 

90 <ul class="info-list" role="list"> 

91 <li><strong>Yellow frames</strong> indicate patients with <strong>multiple files</strong>.  

92 <br> Requires <strong>medical review</strong> and manual selection.</li> 

93 <li><strong>White frames</strong> show patients with auto-selected files.</li> 

94 </ul> 

95 """) 

96 self.info_text.setStyleSheet(""" 

97 color: #000000; 

98 font-size: 12px; 

99 line-height: 1.4; 

100 padding: 2px 0; 

101 """) 

102 self.info_text.setWordWrap(True) 

103 

104 self.content_layout.addWidget(self.info_text) 

105 self.layout.addWidget(self.content_frame) 

106 

107 # --- Internal state --- 

108 self.is_collapsed = False # Whether the content is hidden 

109 

110 # --- Language translation support --- 

111 self._translate_ui() 

112 if context and "language_changed" in context: 

113 context["language_changed"].connect(self._translate_ui) 

114 

115 # ------------------------------------------------------------------------- 

116 

117 def toggle_content(self): 

118 """ 

119 Toggle the visibility of the content section. 

120 

121 This method inverts the current state of the frame (expanded ↔ collapsed). 

122 It is connected to the toggle button’s `clicked` signal. 

123 """ 

124 self.is_collapsed = not self.is_collapsed 

125 self.content_frame.setVisible(not self.is_collapsed) 

126 

127 # ------------------------------------------------------------------------- 

128 

129 def _translate_ui(self): 

130 """ 

131 Update the text of the UI elements for the current language. 

132 

133 This method is automatically called during initialization and whenever 

134 the `"language_changed"` signal is emitted from the application context. 

135 """ 

136 self.toggle_button.setText(QCoreApplication.translate("Components", "Configuration Instructions")) 

137 self.info_text.setText(QCoreApplication.translate("Components", """ 

138 <style> 

139 .info-list { margin: 0; padding-left: 1rem; } 

140 .info-list li { margin-bottom: 0.3rem; line-height: 1.3; } 

141 </style> 

142 <ul class="info-list" role="list"> 

143 <li><strong>Yellow frames</strong> indicate patients with <strong>multiple files</strong>.  

144 <br> Requires <strong>medical review</strong> and manual selection.</li> 

145 <li><strong>White frames</strong> show patients with auto-selected files.</li> 

146 </ul> 

147 """))