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.
- package/LICENSE +21 -0
- package/README.md +680 -0
- package/bin/pomera-ai-commander.js +62 -0
- package/core/__init__.py +66 -0
- package/core/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/__pycache__/app_context.cpython-313.pyc +0 -0
- package/core/__pycache__/async_text_processor.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_recovery_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/content_hash_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/context_menu.cpython-313.pyc +0 -0
- package/core/__pycache__/data_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/database_connection_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_curl_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_promera_ai_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager_interface.cpython-313.pyc +0 -0
- package/core/__pycache__/dialog_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/efficient_line_numbers.cpython-313.pyc +0 -0
- package/core/__pycache__/error_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/error_service.cpython-313.pyc +0 -0
- package/core/__pycache__/event_consolidator.cpython-313.pyc +0 -0
- package/core/__pycache__/memory_efficient_text_widget.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_test_suite.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_find_replace.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_pattern_engine.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_search_highlighter.cpython-313.pyc +0 -0
- package/core/__pycache__/performance_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/persistence_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/progressive_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_library.cpython-313.pyc +0 -0
- package/core/__pycache__/search_operation_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_defaults_registry.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_integrity_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_serializer.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/smart_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/statistics_update_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/stats_config_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/streaming_text_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/task_scheduler.cpython-313.pyc +0 -0
- package/core/__pycache__/visibility_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/widget_cache.cpython-313.pyc +0 -0
- package/core/app_context.py +482 -0
- package/core/async_text_processor.py +422 -0
- package/core/backup_manager.py +656 -0
- package/core/backup_recovery_manager.py +1034 -0
- package/core/content_hash_cache.py +509 -0
- package/core/context_menu.py +313 -0
- package/core/data_validator.py +1067 -0
- package/core/database_connection_manager.py +745 -0
- package/core/database_curl_settings_manager.py +609 -0
- package/core/database_promera_ai_settings_manager.py +447 -0
- package/core/database_schema.py +412 -0
- package/core/database_schema_manager.py +396 -0
- package/core/database_settings_manager.py +1508 -0
- package/core/database_settings_manager_interface.py +457 -0
- package/core/dialog_manager.py +735 -0
- package/core/efficient_line_numbers.py +511 -0
- package/core/error_handler.py +747 -0
- package/core/error_service.py +431 -0
- package/core/event_consolidator.py +512 -0
- package/core/mcp/__init__.py +43 -0
- package/core/mcp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/protocol.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/server_stdio.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/tool_registry.cpython-313.pyc +0 -0
- package/core/mcp/protocol.py +288 -0
- package/core/mcp/schema.py +251 -0
- package/core/mcp/server_stdio.py +299 -0
- package/core/mcp/tool_registry.py +2345 -0
- package/core/memory_efficient_text_widget.py +712 -0
- package/core/migration_manager.py +915 -0
- package/core/migration_test_suite.py +1086 -0
- package/core/migration_validator.py +1144 -0
- package/core/optimized_find_replace.py +715 -0
- package/core/optimized_pattern_engine.py +424 -0
- package/core/optimized_search_highlighter.py +553 -0
- package/core/performance_monitor.py +675 -0
- package/core/persistence_manager.py +713 -0
- package/core/progressive_stats_calculator.py +632 -0
- package/core/regex_pattern_cache.py +530 -0
- package/core/regex_pattern_library.py +351 -0
- package/core/search_operation_manager.py +435 -0
- package/core/settings_defaults_registry.py +1087 -0
- package/core/settings_integrity_validator.py +1112 -0
- package/core/settings_serializer.py +558 -0
- package/core/settings_validator.py +1824 -0
- package/core/smart_stats_calculator.py +710 -0
- package/core/statistics_update_manager.py +619 -0
- package/core/stats_config_manager.py +858 -0
- package/core/streaming_text_handler.py +723 -0
- package/core/task_scheduler.py +596 -0
- package/core/update_pattern_library.py +169 -0
- package/core/visibility_monitor.py +596 -0
- package/core/widget_cache.py +498 -0
- package/mcp.json +61 -0
- package/package.json +57 -0
- package/pomera.py +7483 -0
- package/pomera_mcp_server.py +144 -0
- package/tools/__init__.py +5 -0
- package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/__pycache__/ai_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/ascii_art_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/base64_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/base_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/case_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/column_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/cron_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_history.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_processor.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_settings.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/diff_viewer.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_extraction_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_header_analyzer.cpython-313.pyc +0 -0
- package/tools/__pycache__/extraction_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/find_replace.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter_adapter.cpython-313.pyc +0 -0
- package/tools/__pycache__/generator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/hash_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/html_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/huggingface_helper.cpython-313.pyc +0 -0
- package/tools/__pycache__/jsonxml_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/line_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/list_comparator.cpython-313.pyc +0 -0
- package/tools/__pycache__/markdown_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/mcp_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/notes_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/number_base_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/regex_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/slug_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/sorter_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/string_escape_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_statistics_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_wrapper.cpython-313.pyc +0 -0
- package/tools/__pycache__/timestamp_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/tool_loader.cpython-313.pyc +0 -0
- package/tools/__pycache__/translator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_link_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_parser.cpython-313.pyc +0 -0
- package/tools/__pycache__/whitespace_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/word_frequency_counter.cpython-313.pyc +0 -0
- package/tools/ai_tools.py +2892 -0
- package/tools/ascii_art_generator.py +353 -0
- package/tools/base64_tools.py +184 -0
- package/tools/base_tool.py +511 -0
- package/tools/case_tool.py +309 -0
- package/tools/column_tools.py +396 -0
- package/tools/cron_tool.py +885 -0
- package/tools/curl_history.py +601 -0
- package/tools/curl_processor.py +1208 -0
- package/tools/curl_settings.py +503 -0
- package/tools/curl_tool.py +5467 -0
- package/tools/diff_viewer.py +1072 -0
- package/tools/email_extraction_tool.py +249 -0
- package/tools/email_header_analyzer.py +426 -0
- package/tools/extraction_tools.py +250 -0
- package/tools/find_replace.py +1751 -0
- package/tools/folder_file_reporter.py +1463 -0
- package/tools/folder_file_reporter_adapter.py +480 -0
- package/tools/generator_tools.py +1217 -0
- package/tools/hash_generator.py +256 -0
- package/tools/html_tool.py +657 -0
- package/tools/huggingface_helper.py +449 -0
- package/tools/jsonxml_tool.py +730 -0
- package/tools/line_tools.py +419 -0
- package/tools/list_comparator.py +720 -0
- package/tools/markdown_tools.py +562 -0
- package/tools/mcp_widget.py +1417 -0
- package/tools/notes_widget.py +973 -0
- package/tools/number_base_converter.py +373 -0
- package/tools/regex_extractor.py +572 -0
- package/tools/slug_generator.py +311 -0
- package/tools/sorter_tools.py +459 -0
- package/tools/string_escape_tool.py +393 -0
- package/tools/text_statistics_tool.py +366 -0
- package/tools/text_wrapper.py +431 -0
- package/tools/timestamp_converter.py +422 -0
- package/tools/tool_loader.py +710 -0
- package/tools/translator_tools.py +523 -0
- package/tools/url_link_extractor.py +262 -0
- package/tools/url_parser.py +205 -0
- package/tools/whitespace_tools.py +356 -0
- 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
|