pomera-ai-commander 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +680 -0
  3. package/bin/pomera-ai-commander.js +62 -0
  4. package/core/__init__.py +66 -0
  5. package/core/__pycache__/__init__.cpython-313.pyc +0 -0
  6. package/core/__pycache__/app_context.cpython-313.pyc +0 -0
  7. package/core/__pycache__/async_text_processor.cpython-313.pyc +0 -0
  8. package/core/__pycache__/backup_manager.cpython-313.pyc +0 -0
  9. package/core/__pycache__/backup_recovery_manager.cpython-313.pyc +0 -0
  10. package/core/__pycache__/content_hash_cache.cpython-313.pyc +0 -0
  11. package/core/__pycache__/context_menu.cpython-313.pyc +0 -0
  12. package/core/__pycache__/data_validator.cpython-313.pyc +0 -0
  13. package/core/__pycache__/database_connection_manager.cpython-313.pyc +0 -0
  14. package/core/__pycache__/database_curl_settings_manager.cpython-313.pyc +0 -0
  15. package/core/__pycache__/database_promera_ai_settings_manager.cpython-313.pyc +0 -0
  16. package/core/__pycache__/database_schema.cpython-313.pyc +0 -0
  17. package/core/__pycache__/database_schema_manager.cpython-313.pyc +0 -0
  18. package/core/__pycache__/database_settings_manager.cpython-313.pyc +0 -0
  19. package/core/__pycache__/database_settings_manager_interface.cpython-313.pyc +0 -0
  20. package/core/__pycache__/dialog_manager.cpython-313.pyc +0 -0
  21. package/core/__pycache__/efficient_line_numbers.cpython-313.pyc +0 -0
  22. package/core/__pycache__/error_handler.cpython-313.pyc +0 -0
  23. package/core/__pycache__/error_service.cpython-313.pyc +0 -0
  24. package/core/__pycache__/event_consolidator.cpython-313.pyc +0 -0
  25. package/core/__pycache__/memory_efficient_text_widget.cpython-313.pyc +0 -0
  26. package/core/__pycache__/migration_manager.cpython-313.pyc +0 -0
  27. package/core/__pycache__/migration_test_suite.cpython-313.pyc +0 -0
  28. package/core/__pycache__/migration_validator.cpython-313.pyc +0 -0
  29. package/core/__pycache__/optimized_find_replace.cpython-313.pyc +0 -0
  30. package/core/__pycache__/optimized_pattern_engine.cpython-313.pyc +0 -0
  31. package/core/__pycache__/optimized_search_highlighter.cpython-313.pyc +0 -0
  32. package/core/__pycache__/performance_monitor.cpython-313.pyc +0 -0
  33. package/core/__pycache__/persistence_manager.cpython-313.pyc +0 -0
  34. package/core/__pycache__/progressive_stats_calculator.cpython-313.pyc +0 -0
  35. package/core/__pycache__/regex_pattern_cache.cpython-313.pyc +0 -0
  36. package/core/__pycache__/regex_pattern_library.cpython-313.pyc +0 -0
  37. package/core/__pycache__/search_operation_manager.cpython-313.pyc +0 -0
  38. package/core/__pycache__/settings_defaults_registry.cpython-313.pyc +0 -0
  39. package/core/__pycache__/settings_integrity_validator.cpython-313.pyc +0 -0
  40. package/core/__pycache__/settings_serializer.cpython-313.pyc +0 -0
  41. package/core/__pycache__/settings_validator.cpython-313.pyc +0 -0
  42. package/core/__pycache__/smart_stats_calculator.cpython-313.pyc +0 -0
  43. package/core/__pycache__/statistics_update_manager.cpython-313.pyc +0 -0
  44. package/core/__pycache__/stats_config_manager.cpython-313.pyc +0 -0
  45. package/core/__pycache__/streaming_text_handler.cpython-313.pyc +0 -0
  46. package/core/__pycache__/task_scheduler.cpython-313.pyc +0 -0
  47. package/core/__pycache__/visibility_monitor.cpython-313.pyc +0 -0
  48. package/core/__pycache__/widget_cache.cpython-313.pyc +0 -0
  49. package/core/app_context.py +482 -0
  50. package/core/async_text_processor.py +422 -0
  51. package/core/backup_manager.py +656 -0
  52. package/core/backup_recovery_manager.py +1034 -0
  53. package/core/content_hash_cache.py +509 -0
  54. package/core/context_menu.py +313 -0
  55. package/core/data_validator.py +1067 -0
  56. package/core/database_connection_manager.py +745 -0
  57. package/core/database_curl_settings_manager.py +609 -0
  58. package/core/database_promera_ai_settings_manager.py +447 -0
  59. package/core/database_schema.py +412 -0
  60. package/core/database_schema_manager.py +396 -0
  61. package/core/database_settings_manager.py +1508 -0
  62. package/core/database_settings_manager_interface.py +457 -0
  63. package/core/dialog_manager.py +735 -0
  64. package/core/efficient_line_numbers.py +511 -0
  65. package/core/error_handler.py +747 -0
  66. package/core/error_service.py +431 -0
  67. package/core/event_consolidator.py +512 -0
  68. package/core/mcp/__init__.py +43 -0
  69. package/core/mcp/__pycache__/__init__.cpython-313.pyc +0 -0
  70. package/core/mcp/__pycache__/protocol.cpython-313.pyc +0 -0
  71. package/core/mcp/__pycache__/schema.cpython-313.pyc +0 -0
  72. package/core/mcp/__pycache__/server_stdio.cpython-313.pyc +0 -0
  73. package/core/mcp/__pycache__/tool_registry.cpython-313.pyc +0 -0
  74. package/core/mcp/protocol.py +288 -0
  75. package/core/mcp/schema.py +251 -0
  76. package/core/mcp/server_stdio.py +299 -0
  77. package/core/mcp/tool_registry.py +2345 -0
  78. package/core/memory_efficient_text_widget.py +712 -0
  79. package/core/migration_manager.py +915 -0
  80. package/core/migration_test_suite.py +1086 -0
  81. package/core/migration_validator.py +1144 -0
  82. package/core/optimized_find_replace.py +715 -0
  83. package/core/optimized_pattern_engine.py +424 -0
  84. package/core/optimized_search_highlighter.py +553 -0
  85. package/core/performance_monitor.py +675 -0
  86. package/core/persistence_manager.py +713 -0
  87. package/core/progressive_stats_calculator.py +632 -0
  88. package/core/regex_pattern_cache.py +530 -0
  89. package/core/regex_pattern_library.py +351 -0
  90. package/core/search_operation_manager.py +435 -0
  91. package/core/settings_defaults_registry.py +1087 -0
  92. package/core/settings_integrity_validator.py +1112 -0
  93. package/core/settings_serializer.py +558 -0
  94. package/core/settings_validator.py +1824 -0
  95. package/core/smart_stats_calculator.py +710 -0
  96. package/core/statistics_update_manager.py +619 -0
  97. package/core/stats_config_manager.py +858 -0
  98. package/core/streaming_text_handler.py +723 -0
  99. package/core/task_scheduler.py +596 -0
  100. package/core/update_pattern_library.py +169 -0
  101. package/core/visibility_monitor.py +596 -0
  102. package/core/widget_cache.py +498 -0
  103. package/mcp.json +61 -0
  104. package/package.json +57 -0
  105. package/pomera.py +7483 -0
  106. package/pomera_mcp_server.py +144 -0
  107. package/tools/__init__.py +5 -0
  108. package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  109. package/tools/__pycache__/ai_tools.cpython-313.pyc +0 -0
  110. package/tools/__pycache__/ascii_art_generator.cpython-313.pyc +0 -0
  111. package/tools/__pycache__/base64_tools.cpython-313.pyc +0 -0
  112. package/tools/__pycache__/base_tool.cpython-313.pyc +0 -0
  113. package/tools/__pycache__/case_tool.cpython-313.pyc +0 -0
  114. package/tools/__pycache__/column_tools.cpython-313.pyc +0 -0
  115. package/tools/__pycache__/cron_tool.cpython-313.pyc +0 -0
  116. package/tools/__pycache__/curl_history.cpython-313.pyc +0 -0
  117. package/tools/__pycache__/curl_processor.cpython-313.pyc +0 -0
  118. package/tools/__pycache__/curl_settings.cpython-313.pyc +0 -0
  119. package/tools/__pycache__/curl_tool.cpython-313.pyc +0 -0
  120. package/tools/__pycache__/diff_viewer.cpython-313.pyc +0 -0
  121. package/tools/__pycache__/email_extraction_tool.cpython-313.pyc +0 -0
  122. package/tools/__pycache__/email_header_analyzer.cpython-313.pyc +0 -0
  123. package/tools/__pycache__/extraction_tools.cpython-313.pyc +0 -0
  124. package/tools/__pycache__/find_replace.cpython-313.pyc +0 -0
  125. package/tools/__pycache__/folder_file_reporter.cpython-313.pyc +0 -0
  126. package/tools/__pycache__/folder_file_reporter_adapter.cpython-313.pyc +0 -0
  127. package/tools/__pycache__/generator_tools.cpython-313.pyc +0 -0
  128. package/tools/__pycache__/hash_generator.cpython-313.pyc +0 -0
  129. package/tools/__pycache__/html_tool.cpython-313.pyc +0 -0
  130. package/tools/__pycache__/huggingface_helper.cpython-313.pyc +0 -0
  131. package/tools/__pycache__/jsonxml_tool.cpython-313.pyc +0 -0
  132. package/tools/__pycache__/line_tools.cpython-313.pyc +0 -0
  133. package/tools/__pycache__/list_comparator.cpython-313.pyc +0 -0
  134. package/tools/__pycache__/markdown_tools.cpython-313.pyc +0 -0
  135. package/tools/__pycache__/mcp_widget.cpython-313.pyc +0 -0
  136. package/tools/__pycache__/notes_widget.cpython-313.pyc +0 -0
  137. package/tools/__pycache__/number_base_converter.cpython-313.pyc +0 -0
  138. package/tools/__pycache__/regex_extractor.cpython-313.pyc +0 -0
  139. package/tools/__pycache__/slug_generator.cpython-313.pyc +0 -0
  140. package/tools/__pycache__/sorter_tools.cpython-313.pyc +0 -0
  141. package/tools/__pycache__/string_escape_tool.cpython-313.pyc +0 -0
  142. package/tools/__pycache__/text_statistics_tool.cpython-313.pyc +0 -0
  143. package/tools/__pycache__/text_wrapper.cpython-313.pyc +0 -0
  144. package/tools/__pycache__/timestamp_converter.cpython-313.pyc +0 -0
  145. package/tools/__pycache__/tool_loader.cpython-313.pyc +0 -0
  146. package/tools/__pycache__/translator_tools.cpython-313.pyc +0 -0
  147. package/tools/__pycache__/url_link_extractor.cpython-313.pyc +0 -0
  148. package/tools/__pycache__/url_parser.cpython-313.pyc +0 -0
  149. package/tools/__pycache__/whitespace_tools.cpython-313.pyc +0 -0
  150. package/tools/__pycache__/word_frequency_counter.cpython-313.pyc +0 -0
  151. package/tools/ai_tools.py +2892 -0
  152. package/tools/ascii_art_generator.py +353 -0
  153. package/tools/base64_tools.py +184 -0
  154. package/tools/base_tool.py +511 -0
  155. package/tools/case_tool.py +309 -0
  156. package/tools/column_tools.py +396 -0
  157. package/tools/cron_tool.py +885 -0
  158. package/tools/curl_history.py +601 -0
  159. package/tools/curl_processor.py +1208 -0
  160. package/tools/curl_settings.py +503 -0
  161. package/tools/curl_tool.py +5467 -0
  162. package/tools/diff_viewer.py +1072 -0
  163. package/tools/email_extraction_tool.py +249 -0
  164. package/tools/email_header_analyzer.py +426 -0
  165. package/tools/extraction_tools.py +250 -0
  166. package/tools/find_replace.py +1751 -0
  167. package/tools/folder_file_reporter.py +1463 -0
  168. package/tools/folder_file_reporter_adapter.py +480 -0
  169. package/tools/generator_tools.py +1217 -0
  170. package/tools/hash_generator.py +256 -0
  171. package/tools/html_tool.py +657 -0
  172. package/tools/huggingface_helper.py +449 -0
  173. package/tools/jsonxml_tool.py +730 -0
  174. package/tools/line_tools.py +419 -0
  175. package/tools/list_comparator.py +720 -0
  176. package/tools/markdown_tools.py +562 -0
  177. package/tools/mcp_widget.py +1417 -0
  178. package/tools/notes_widget.py +973 -0
  179. package/tools/number_base_converter.py +373 -0
  180. package/tools/regex_extractor.py +572 -0
  181. package/tools/slug_generator.py +311 -0
  182. package/tools/sorter_tools.py +459 -0
  183. package/tools/string_escape_tool.py +393 -0
  184. package/tools/text_statistics_tool.py +366 -0
  185. package/tools/text_wrapper.py +431 -0
  186. package/tools/timestamp_converter.py +422 -0
  187. package/tools/tool_loader.py +710 -0
  188. package/tools/translator_tools.py +523 -0
  189. package/tools/url_link_extractor.py +262 -0
  190. package/tools/url_parser.py +205 -0
  191. package/tools/whitespace_tools.py +356 -0
  192. package/tools/word_frequency_counter.py +147 -0
@@ -0,0 +1,735 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dialog Manager Module
4
+
5
+ This module provides centralized dialog management with configurable settings for the Pomera application.
6
+ It allows users to control which types of notification and confirmation dialogs are displayed throughout
7
+ the application, providing a better user experience by reducing interruptions while maintaining important
8
+ system communications.
9
+
10
+ The DialogManager acts as a wrapper around tkinter.messagebox functions, evaluating user preferences
11
+ before displaying dialogs and providing fallback logging when dialogs are suppressed.
12
+
13
+ Key Features:
14
+ - Configurable dialog categories (success, warning, confirmation, error)
15
+ - Settings-driven dialog suppression with logging fallback
16
+ - Extensible category registration system
17
+ - Real-time settings updates without application restart
18
+ - Error dialogs always shown (cannot be disabled for safety)
19
+ - Integration with existing application settings system
20
+
21
+ Architecture:
22
+ - DialogManager: Central coordinator for all dialog decisions
23
+ - DialogCategory: Data class representing dialog category configuration
24
+ - Settings integration: Leverages existing settings persistence
25
+ - Logging integration: Provides fallback when dialogs are suppressed
26
+
27
+ Usage Examples:
28
+ Basic usage with settings manager:
29
+ from core.dialog_manager import DialogManager
30
+
31
+ dialog_manager = DialogManager(settings_manager, logger)
32
+ dialog_manager.show_info("Success", "Operation completed successfully")
33
+ result = dialog_manager.ask_yes_no("Confirm", "Are you sure?")
34
+
35
+ Standalone usage without settings:
36
+ dialog_manager = DialogManager() # Uses defaults
37
+ dialog_manager.show_error("Error", "Something went wrong")
38
+
39
+ Custom category registration:
40
+ dialog_manager.register_dialog_type(
41
+ "custom_notifications",
42
+ "Custom application notifications",
43
+ default_enabled=True
44
+ )
45
+
46
+ Requirements Addressed:
47
+ - Requirement 4.4: Error handling covers all edge cases
48
+ - Requirement 6.4: Clear documentation and examples
49
+ - Requirement 8.4: Extensible system with proper documentation
50
+ """
51
+
52
+ import tkinter.messagebox as messagebox
53
+ from typing import Dict, Optional, Any, List
54
+ from dataclasses import dataclass, field
55
+ import logging
56
+
57
+
58
+ @dataclass
59
+ class DialogCategory:
60
+ """
61
+ Represents a dialog category with its configuration and behavior settings.
62
+
63
+ This data class encapsulates all the information needed to manage a specific
64
+ type of dialog, including whether it can be disabled, what it's used for,
65
+ and how it should behave when suppressed.
66
+
67
+ Attributes:
68
+ name (str): Unique identifier for the dialog category (e.g., "success", "warning")
69
+ enabled (bool): Whether dialogs of this category should be shown
70
+ description (str): Human-readable description for settings UI
71
+ locked (bool): If True, category cannot be disabled by users (default: False)
72
+ examples (List[str]): Example messages to help users understand the category
73
+ default_action (str): Default action for confirmations when suppressed ("yes", "no", "show")
74
+
75
+ Examples:
76
+ Success notification category:
77
+ DialogCategory(
78
+ name="success",
79
+ enabled=True,
80
+ description="Success notifications for completed operations",
81
+ examples=["File saved successfully", "Settings applied"]
82
+ )
83
+
84
+ Locked error category:
85
+ DialogCategory(
86
+ name="error",
87
+ enabled=True,
88
+ locked=True, # Cannot be disabled
89
+ description="Critical error messages",
90
+ examples=["File not found", "Network error"]
91
+ )
92
+
93
+ Confirmation with default action:
94
+ DialogCategory(
95
+ name="confirmation",
96
+ enabled=True,
97
+ description="Confirmation dialogs for destructive actions",
98
+ default_action="yes",
99
+ examples=["Delete file?", "Clear all data?"]
100
+ )
101
+ """
102
+ name: str
103
+ enabled: bool
104
+ description: str
105
+ locked: bool = False # Cannot be disabled (for errors)
106
+ examples: List[str] = field(default_factory=list)
107
+ default_action: str = "show" # For confirmations: "yes", "no", "cancel"
108
+
109
+
110
+ class DialogManager:
111
+ """
112
+ Central coordinator for all dialog display decisions in the Pomera application.
113
+
114
+ The DialogManager serves as a configurable wrapper around tkinter.messagebox functions,
115
+ allowing users to control which types of dialogs are shown based on their preferences.
116
+ When dialogs are suppressed, equivalent messages are logged to maintain debugging
117
+ capabilities and system transparency.
118
+
119
+ Core Responsibilities:
120
+ - Evaluate dialog settings before showing dialogs
121
+ - Provide wrapper methods for all messagebox types (info, warning, error, confirmation)
122
+ - Handle logging fallback when dialogs are suppressed
123
+ - Manage dialog type registration and categorization
124
+ - Support real-time settings updates without application restart
125
+ - Ensure error dialogs are always shown for safety
126
+
127
+ Design Patterns:
128
+ - Wrapper Pattern: Wraps tkinter.messagebox with additional logic
129
+ - Strategy Pattern: Different behavior based on dialog category settings
130
+ - Observer Pattern: Responds to settings changes via refresh_settings()
131
+
132
+ Thread Safety:
133
+ This class is not thread-safe. All methods should be called from the main UI thread
134
+ since tkinter.messagebox functions must be called from the main thread.
135
+
136
+ Error Handling Philosophy:
137
+ - Graceful degradation: If dialog display fails, always log the message
138
+ - Safety first: Error dialogs cannot be disabled to ensure critical issues are visible
139
+ - Fallback behavior: Unknown categories default to enabled for safety
140
+ - Settings corruption: Invalid settings are handled gracefully with defaults
141
+
142
+ Integration Points:
143
+ - Settings Manager: Retrieves dialog preferences from application settings
144
+ - Logger: Provides fallback logging when dialogs are suppressed
145
+ - UI Components: Real-time updates when settings change
146
+ - Tool Modules: Consistent dialog behavior across all application components
147
+ """
148
+
149
+ def __init__(self, settings_manager=None, logger=None):
150
+ """
151
+ Initialize DialogManager with references to settings and logging systems.
152
+
153
+ Args:
154
+ settings_manager: Object with get_setting() method for retrieving dialog settings
155
+ logger: Logger instance for fallback logging when dialogs are suppressed
156
+ """
157
+ self.settings_manager = settings_manager
158
+ self.logger = logger or logging.getLogger(__name__)
159
+ self.registered_categories: Dict[str, DialogCategory] = {}
160
+
161
+ # Initialize default dialog categories
162
+ self._initialize_default_categories()
163
+
164
+ # Load current settings from settings manager if available
165
+ if self.settings_manager:
166
+ self.refresh_settings()
167
+
168
+ def _initialize_default_categories(self):
169
+ """Initialize the default dialog categories."""
170
+ default_categories = [
171
+ DialogCategory(
172
+ name="success",
173
+ enabled=True,
174
+ description="Success notifications for completed operations",
175
+ examples=["File saved successfully", "Settings applied", "Export complete"]
176
+ ),
177
+ DialogCategory(
178
+ name="confirmation",
179
+ enabled=True,
180
+ description="Confirmation dialogs for destructive actions",
181
+ examples=["Clear all tabs?", "Delete entry?", "Reset settings?"],
182
+ default_action="yes"
183
+ ),
184
+ DialogCategory(
185
+ name="warning",
186
+ enabled=True,
187
+ description="Warning messages for potential issues",
188
+ examples=["No data specified", "Invalid input detected", "Feature unavailable"]
189
+ ),
190
+ DialogCategory(
191
+ name="error",
192
+ enabled=True,
193
+ locked=True,
194
+ description="Error messages for critical issues (cannot be disabled)",
195
+ examples=["File not found", "Network error", "Invalid configuration"]
196
+ )
197
+ ]
198
+
199
+ for category in default_categories:
200
+ self.registered_categories[category.name] = category
201
+
202
+ def register_dialog_type(self, category: str, description: str, default_enabled: bool = True,
203
+ locked: bool = False, examples: List[str] = None,
204
+ default_action: str = "show"):
205
+ """
206
+ Register new dialog categories for extensibility.
207
+
208
+ Args:
209
+ category: Name of the dialog category
210
+ description: Human-readable description of the category
211
+ default_enabled: Whether this category is enabled by default
212
+ locked: Whether this category can be disabled by users
213
+ examples: List of example messages for this category
214
+ default_action: Default action for confirmation dialogs
215
+ """
216
+ if examples is None:
217
+ examples = []
218
+
219
+ self.registered_categories[category] = DialogCategory(
220
+ name=category,
221
+ enabled=default_enabled,
222
+ description=description,
223
+ locked=locked,
224
+ examples=examples,
225
+ default_action=default_action
226
+ )
227
+
228
+ self.logger.debug(f"Registered dialog category: {category}")
229
+
230
+ def _is_dialog_enabled(self, category: str) -> bool:
231
+ """
232
+ Check if a dialog category is enabled based on current settings.
233
+
234
+ This method implements a multi-layered approach to determine dialog visibility:
235
+ 1. Error dialogs are always enabled (safety requirement)
236
+ 2. Locked categories are always enabled (cannot be disabled)
237
+ 3. Registered categories use their current enabled status
238
+ 4. Fallback to settings manager for unknown categories
239
+ 5. Default to enabled for maximum safety
240
+
241
+ Args:
242
+ category (str): Dialog category name to check
243
+
244
+ Returns:
245
+ bool: True if dialogs of this category should be shown
246
+
247
+ Raises:
248
+ None: This method never raises exceptions, always returns a safe default
249
+
250
+ Edge Cases Handled:
251
+ - None or empty category name: defaults to enabled
252
+ - Corrupted settings data: logs warning and defaults to enabled
253
+ - Missing settings manager: defaults to enabled
254
+ - Unknown category: logs info and defaults to enabled
255
+ """
256
+ # Handle invalid category input
257
+ if not category or not isinstance(category, str):
258
+ self.logger.warning(f"Invalid category provided: {category}, defaulting to enabled")
259
+ return True
260
+
261
+ # Error dialogs are always enabled for safety
262
+ if category == "error":
263
+ return True
264
+
265
+ # Check registered categories first (for immediate updates)
266
+ if category in self.registered_categories:
267
+ try:
268
+ registered_category = self.registered_categories[category]
269
+
270
+ # If category is locked, always return True
271
+ if registered_category.locked:
272
+ return True
273
+
274
+ # For real-time updates, prioritize the registered category's enabled status
275
+ # This allows immediate updates via update_category_setting() to take effect
276
+ return registered_category.enabled
277
+ except (AttributeError, TypeError) as e:
278
+ self.logger.error(f"Corrupted registered category data for {category}: {e}")
279
+ return True # Safe default
280
+
281
+ # Category not registered, check settings manager as fallback
282
+ if self.settings_manager:
283
+ try:
284
+ dialog_settings = self.settings_manager.get_setting("dialog_settings", {})
285
+
286
+ # Validate settings structure
287
+ if not isinstance(dialog_settings, dict):
288
+ self.logger.warning(f"Invalid dialog_settings structure: {type(dialog_settings)}, using defaults")
289
+ return True
290
+
291
+ category_settings = dialog_settings.get(category, {})
292
+
293
+ # Validate category settings structure
294
+ if not isinstance(category_settings, dict):
295
+ self.logger.warning(f"Invalid settings for category {category}: {type(category_settings)}, using defaults")
296
+ return True
297
+
298
+ enabled = category_settings.get("enabled", True)
299
+
300
+ # Validate enabled value
301
+ if not isinstance(enabled, bool):
302
+ self.logger.warning(f"Invalid enabled value for category {category}: {enabled}, defaulting to True")
303
+ return True
304
+
305
+ return enabled
306
+
307
+ except Exception as e:
308
+ self.logger.warning(f"Error checking dialog settings for {category}: {e}")
309
+ return True # Safe default
310
+
311
+ # Log unknown category for debugging
312
+ self.logger.info(f"Unknown dialog category '{category}', defaulting to enabled")
313
+
314
+ # Default to enabled if no other information available (safety first)
315
+ return True
316
+
317
+ def _log_suppressed_dialog(self, level: str, title: str, message: str, category: str):
318
+ """
319
+ Log a message when a dialog is suppressed due to settings.
320
+
321
+ Args:
322
+ level: Log level (info, warning, error)
323
+ title: Dialog title
324
+ message: Dialog message
325
+ category: Dialog category
326
+ """
327
+ log_message = f"[{category.upper()}] {title}: {message}"
328
+
329
+ if level.lower() == "info":
330
+ self.logger.info(log_message)
331
+ elif level.lower() == "warning":
332
+ self.logger.warning(log_message)
333
+ elif level.lower() == "error":
334
+ self.logger.error(log_message)
335
+ else:
336
+ self.logger.info(log_message)
337
+
338
+ def show_info(self, title: str, message: str, category: str = "success", parent=None) -> bool:
339
+ """
340
+ Show info dialog if enabled, return whether dialog was shown.
341
+
342
+ This method provides comprehensive error handling for info dialogs,
343
+ including input validation, display failure recovery, and logging fallback.
344
+
345
+ Args:
346
+ title (str): Dialog title text
347
+ message (str): Dialog message content
348
+ category (str): Dialog category for settings lookup (default: "success")
349
+ parent: Optional parent window for dialog positioning (default: None)
350
+
351
+ Returns:
352
+ bool: True if dialog was shown, False if suppressed or failed
353
+
354
+ Error Handling:
355
+ - Invalid input parameters: Logs warning and uses safe defaults
356
+ - Dialog display failure: Logs error and falls back to logging
357
+ - Category lookup failure: Handled by _is_dialog_enabled method
358
+ - Tkinter unavailable: Graceful fallback to logging only
359
+ """
360
+ # Input validation with safe defaults
361
+ try:
362
+ title = str(title) if title is not None else "Information"
363
+ message = str(message) if message is not None else ""
364
+ category = str(category) if category else "success"
365
+ except Exception as e:
366
+ self.logger.warning(f"Error validating info dialog parameters: {e}")
367
+ title, message, category = "Information", str(message), "success"
368
+
369
+ if self._is_dialog_enabled(category):
370
+ try:
371
+ messagebox.showinfo(title, message, parent=parent)
372
+ self.logger.debug(f"Info dialog shown: {title}")
373
+ return True
374
+ except Exception as e:
375
+ self.logger.error(f"Failed to show info dialog '{title}': {e}")
376
+ self._log_suppressed_dialog("info", title, message, category)
377
+ return False
378
+ else:
379
+ self._log_suppressed_dialog("info", title, message, category)
380
+ return False
381
+
382
+ def show_warning(self, title: str, message: str, category: str = "warning", parent=None) -> bool:
383
+ """
384
+ Show warning dialog if enabled, return whether dialog was shown.
385
+
386
+ This method provides comprehensive error handling for warning dialogs,
387
+ including input validation, display failure recovery, and logging fallback.
388
+
389
+ Args:
390
+ title (str): Dialog title text
391
+ message (str): Dialog message content
392
+ category (str): Dialog category for settings lookup (default: "warning")
393
+ parent: Optional parent window for dialog positioning (default: None)
394
+
395
+ Returns:
396
+ bool: True if dialog was shown, False if suppressed or failed
397
+
398
+ Error Handling:
399
+ - Invalid input parameters: Logs warning and uses safe defaults
400
+ - Dialog display failure: Logs error and falls back to logging
401
+ - Category lookup failure: Handled by _is_dialog_enabled method
402
+ - Tkinter unavailable: Graceful fallback to logging only
403
+ """
404
+ # Input validation with safe defaults
405
+ try:
406
+ title = str(title) if title is not None else "Warning"
407
+ message = str(message) if message is not None else ""
408
+ category = str(category) if category else "warning"
409
+ except Exception as e:
410
+ self.logger.warning(f"Error validating warning dialog parameters: {e}")
411
+ title, message, category = "Warning", str(message), "warning"
412
+
413
+ if self._is_dialog_enabled(category):
414
+ try:
415
+ messagebox.showwarning(title, message, parent=parent)
416
+ self.logger.debug(f"Warning dialog shown: {title}")
417
+ return True
418
+ except Exception as e:
419
+ self.logger.error(f"Failed to show warning dialog '{title}': {e}")
420
+ self._log_suppressed_dialog("warning", title, message, category)
421
+ return False
422
+ else:
423
+ self._log_suppressed_dialog("warning", title, message, category)
424
+ return False
425
+
426
+ def show_error(self, title: str, message: str, parent=None) -> bool:
427
+ """
428
+ Always show error dialogs (cannot be disabled for safety).
429
+
430
+ Error dialogs are critical for user safety and system stability, so they
431
+ cannot be disabled through settings. This method provides robust error
432
+ handling and always logs error messages regardless of display success.
433
+
434
+ Args:
435
+ title (str): Dialog title text
436
+ message (str): Dialog message content
437
+ parent: Optional parent window for dialog positioning (default: None)
438
+
439
+ Returns:
440
+ bool: True if dialog was shown, False if failed to show
441
+
442
+ Safety Features:
443
+ - Cannot be disabled through settings (safety requirement)
444
+ - Always logs error messages for debugging
445
+ - Robust input validation with safe defaults
446
+ - Graceful handling of display failures
447
+
448
+ Error Handling:
449
+ - Invalid input parameters: Uses safe defaults and continues
450
+ - Dialog display failure: Logs critical error but continues
451
+ - Tkinter unavailable: Ensures error is still logged
452
+ """
453
+ # Input validation with safe defaults - errors must always be communicated
454
+ try:
455
+ title = str(title) if title is not None else "Error"
456
+ message = str(message) if message is not None else "An unknown error occurred"
457
+ except Exception as e:
458
+ self.logger.critical(f"Critical error validating error dialog parameters: {e}")
459
+ title, message = "Critical Error", "An error occurred that could not be properly formatted"
460
+
461
+ try:
462
+ messagebox.showerror(title, message, parent=parent)
463
+ # Always log error messages for debugging, even when dialog is shown
464
+ self._log_suppressed_dialog("error", title, message, "error")
465
+ self.logger.debug(f"Error dialog shown: {title}")
466
+ return True
467
+ except Exception as e:
468
+ # Critical: Error dialog failed to display
469
+ self.logger.critical(f"CRITICAL: Failed to show error dialog '{title}': {e}")
470
+ # Ensure error is logged even if dialog fails
471
+ self._log_suppressed_dialog("error", title, message, "error")
472
+ # Also log the display failure itself
473
+ self.logger.critical(f"Error dialog display failure - Original error: {message}")
474
+ return False
475
+
476
+ def ask_yes_no(self, title: str, message: str, category: str = "confirmation", parent=None) -> bool:
477
+ """
478
+ Show confirmation dialog if enabled, return user choice or default action.
479
+
480
+ This method handles confirmation dialogs with comprehensive error handling
481
+ and intelligent default behavior when dialogs are suppressed. It ensures
482
+ that application flow continues even when dialogs cannot be displayed.
483
+
484
+ Args:
485
+ title (str): Dialog title text
486
+ message (str): Dialog message content
487
+ category (str): Dialog category for settings lookup (default: "confirmation")
488
+ parent: Optional parent window for dialog positioning (default: None)
489
+
490
+ Returns:
491
+ bool: User's choice (True for Yes, False for No) or configured default action
492
+
493
+ Default Action Behavior:
494
+ - When dialogs are suppressed, returns the category's default_action
495
+ - Default actions: "yes" -> True, "no" -> False, other -> True
496
+ - Logs the automatic decision for transparency
497
+
498
+ Error Handling:
499
+ - Invalid input parameters: Uses safe defaults and continues
500
+ - Dialog display failure: Falls back to default action
501
+ - Category lookup failure: Uses safe default (True for most cases)
502
+ - Default action determination failure: Uses True as ultimate fallback
503
+ """
504
+ # Input validation with safe defaults
505
+ try:
506
+ title = str(title) if title is not None else "Confirmation"
507
+ message = str(message) if message is not None else "Are you sure?"
508
+ category = str(category) if category else "confirmation"
509
+ except Exception as e:
510
+ self.logger.warning(f"Error validating confirmation dialog parameters: {e}")
511
+ title, message, category = "Confirmation", "Are you sure?", "confirmation"
512
+
513
+ if self._is_dialog_enabled(category):
514
+ try:
515
+ result = messagebox.askyesno(title, message, parent=parent)
516
+ self.logger.debug(f"Confirmation dialog shown: {title}, result: {result}")
517
+ return result
518
+ except Exception as e:
519
+ self.logger.error(f"Failed to show confirmation dialog '{title}': {e}")
520
+ default_action = self._get_default_confirmation_action(category)
521
+ action_text = "Yes" if default_action else "No"
522
+ self._log_suppressed_dialog("info", title, f"{message} [Auto-{action_text} due to display failure]", category)
523
+ return default_action
524
+ else:
525
+ # Log the suppressed confirmation and return default action
526
+ default_action = self._get_default_confirmation_action(category)
527
+ action_text = "Yes" if default_action else "No"
528
+ self._log_suppressed_dialog("info", title, f"{message} [Auto-{action_text}]", category)
529
+ return default_action
530
+
531
+ def _get_default_confirmation_action(self, category: str) -> bool:
532
+ """
533
+ Get the default action for a confirmation dialog when suppressed.
534
+
535
+ This method determines what action to take when a confirmation dialog
536
+ would normally be shown but is suppressed due to user settings. It
537
+ provides intelligent defaults based on category configuration.
538
+
539
+ Args:
540
+ category (str): Dialog category name
541
+
542
+ Returns:
543
+ bool: Default action (True for Yes, False for No)
544
+
545
+ Default Action Logic:
546
+ 1. Check registered category's default_action setting
547
+ 2. "yes" -> True, "no" -> False
548
+ 3. Invalid/unknown -> True (safe default for most operations)
549
+
550
+ Error Handling:
551
+ - Invalid category: Logs warning and returns True
552
+ - Corrupted category data: Logs error and returns True
553
+ - Missing default_action: Uses True as safe default
554
+ """
555
+ try:
556
+ if category and category in self.registered_categories:
557
+ registered_category = self.registered_categories[category]
558
+
559
+ if hasattr(registered_category, 'default_action'):
560
+ default_action = registered_category.default_action
561
+
562
+ if isinstance(default_action, str):
563
+ action_lower = default_action.lower().strip()
564
+ if action_lower == "yes":
565
+ return True
566
+ elif action_lower == "no":
567
+ return False
568
+ else:
569
+ self.logger.debug(f"Unknown default_action '{default_action}' for category {category}, using True")
570
+ return True
571
+ else:
572
+ self.logger.warning(f"Invalid default_action type for category {category}: {type(default_action)}")
573
+ return True
574
+ else:
575
+ self.logger.debug(f"No default_action defined for category {category}, using True")
576
+ return True
577
+ else:
578
+ self.logger.debug(f"Category {category} not found in registered categories, using default True")
579
+ return True
580
+
581
+ except Exception as e:
582
+ self.logger.error(f"Error determining default confirmation action for category {category}: {e}")
583
+ return True # Safe default
584
+
585
+ # Ultimate fallback - should never reach here but ensures method always returns
586
+ return True
587
+
588
+ def get_registered_categories(self) -> Dict[str, DialogCategory]:
589
+ """
590
+ Get all registered dialog categories.
591
+
592
+ Returns:
593
+ Dict[str, DialogCategory]: Dictionary of registered categories
594
+ """
595
+ return self.registered_categories.copy()
596
+
597
+ def is_category_locked(self, category: str) -> bool:
598
+ """
599
+ Check if a dialog category is locked (cannot be disabled).
600
+
601
+ Args:
602
+ category: Dialog category name
603
+
604
+ Returns:
605
+ bool: True if category is locked
606
+ """
607
+ if category in self.registered_categories:
608
+ return self.registered_categories[category].locked
609
+ return False
610
+
611
+ def get_category_description(self, category: str) -> str:
612
+ """
613
+ Get the description for a dialog category.
614
+
615
+ Args:
616
+ category: Dialog category name
617
+
618
+ Returns:
619
+ str: Category description or empty string if not found
620
+ """
621
+ if category in self.registered_categories:
622
+ return self.registered_categories[category].description
623
+ return ""
624
+
625
+ def get_category_examples(self, category: str) -> List[str]:
626
+ """
627
+ Get example messages for a dialog category.
628
+
629
+ Args:
630
+ category: Dialog category name
631
+
632
+ Returns:
633
+ List[str]: List of example messages
634
+ """
635
+ if category in self.registered_categories:
636
+ return self.registered_categories[category].examples.copy()
637
+ return []
638
+
639
+ def refresh_settings(self):
640
+ """
641
+ Refresh dialog settings from the settings manager with comprehensive error handling.
642
+
643
+ This method should be called when dialog settings are updated to ensure the
644
+ DialogManager uses the latest configuration. It handles various edge cases
645
+ including corrupted settings, missing categories, and invalid data types.
646
+
647
+ Error Handling:
648
+ - Corrupted settings: Logs error and maintains current state
649
+ - Invalid data types: Validates and uses safe defaults
650
+ - Missing categories: Preserves existing category settings
651
+ - Settings manager unavailable: Logs warning and continues
652
+
653
+ Side Effects:
654
+ - Updates registered category enabled status
655
+ - Logs all setting changes for debugging
656
+ - Maintains system stability even with corrupted data
657
+ """
658
+ if not self.settings_manager:
659
+ self.logger.warning("No settings manager available for refresh")
660
+ return
661
+
662
+ try:
663
+ # Force a fresh read of dialog settings
664
+ dialog_settings = self.settings_manager.get_setting("dialog_settings", {})
665
+
666
+ # Validate settings structure
667
+ if not isinstance(dialog_settings, dict):
668
+ self.logger.error(f"Invalid dialog_settings structure: {type(dialog_settings)}, skipping refresh")
669
+ return
670
+
671
+ self.logger.debug(f"Refreshed dialog settings: {dialog_settings}")
672
+
673
+ # Update registered categories with current settings
674
+ updated_categories = []
675
+ for category_name, category in self.registered_categories.items():
676
+ try:
677
+ if category_name in dialog_settings:
678
+ category_settings = dialog_settings[category_name]
679
+
680
+ # Validate category settings structure
681
+ if not isinstance(category_settings, dict):
682
+ self.logger.warning(f"Invalid settings structure for category {category_name}: {type(category_settings)}")
683
+ continue
684
+
685
+ # Update enabled status if not locked
686
+ if not category.locked:
687
+ enabled_value = category_settings.get("enabled", category.enabled)
688
+
689
+ # Validate enabled value type
690
+ if not isinstance(enabled_value, bool):
691
+ self.logger.warning(f"Invalid enabled value for category {category_name}: {enabled_value}, keeping current setting")
692
+ continue
693
+
694
+ old_enabled = category.enabled
695
+ category.enabled = enabled_value
696
+
697
+ if old_enabled != category.enabled:
698
+ self.logger.info(f"Dialog category '{category_name}' {'enabled' if category.enabled else 'disabled'}")
699
+ updated_categories.append(category_name)
700
+ else:
701
+ self.logger.debug(f"Skipping locked category '{category_name}' during refresh")
702
+
703
+ except Exception as e:
704
+ self.logger.error(f"Error updating category '{category_name}' during refresh: {e}")
705
+ continue
706
+
707
+ if updated_categories:
708
+ self.logger.info(f"Dialog settings refreshed successfully. Updated categories: {updated_categories}")
709
+ else:
710
+ self.logger.info("Dialog settings refreshed successfully. No category changes.")
711
+
712
+ except Exception as e:
713
+ self.logger.error(f"Critical error refreshing dialog settings: {e}")
714
+ # Don't re-raise - maintain system stability
715
+
716
+ def update_category_setting(self, category: str, enabled: bool):
717
+ """
718
+ Update a specific category's enabled status immediately.
719
+
720
+ Args:
721
+ category: Dialog category name
722
+ enabled: Whether the category should be enabled
723
+ """
724
+ if category in self.registered_categories:
725
+ # Don't allow disabling locked categories (like error)
726
+ if self.registered_categories[category].locked and not enabled:
727
+ self.logger.warning(f"Cannot disable locked category: {category}")
728
+ return False
729
+
730
+ self.registered_categories[category].enabled = enabled
731
+ self.logger.debug(f"Updated category {category} enabled status to {enabled}")
732
+ return True
733
+ else:
734
+ self.logger.warning(f"Unknown category for update: {category}")
735
+ return False