supervertaler 1.9.153__py3-none-any.whl
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.
Potentially problematic release.
This version of supervertaler might be problematic. Click here for more details.
- Supervertaler.py +47886 -0
- modules/__init__.py +10 -0
- modules/ai_actions.py +964 -0
- modules/ai_attachment_manager.py +343 -0
- modules/ai_file_viewer_dialog.py +210 -0
- modules/autofingers_engine.py +466 -0
- modules/cafetran_docx_handler.py +379 -0
- modules/config_manager.py +469 -0
- modules/database_manager.py +1878 -0
- modules/database_migrations.py +417 -0
- modules/dejavurtf_handler.py +779 -0
- modules/document_analyzer.py +427 -0
- modules/docx_handler.py +689 -0
- modules/encoding_repair.py +319 -0
- modules/encoding_repair_Qt.py +393 -0
- modules/encoding_repair_ui.py +481 -0
- modules/feature_manager.py +350 -0
- modules/figure_context_manager.py +340 -0
- modules/file_dialog_helper.py +148 -0
- modules/find_replace.py +164 -0
- modules/find_replace_qt.py +457 -0
- modules/glossary_manager.py +433 -0
- modules/image_extractor.py +188 -0
- modules/keyboard_shortcuts_widget.py +571 -0
- modules/llm_clients.py +1211 -0
- modules/llm_leaderboard.py +737 -0
- modules/llm_superbench_ui.py +1401 -0
- modules/local_llm_setup.py +1104 -0
- modules/model_update_dialog.py +381 -0
- modules/model_version_checker.py +373 -0
- modules/mqxliff_handler.py +638 -0
- modules/non_translatables_manager.py +743 -0
- modules/pdf_rescue_Qt.py +1822 -0
- modules/pdf_rescue_tkinter.py +909 -0
- modules/phrase_docx_handler.py +516 -0
- modules/project_home_panel.py +209 -0
- modules/prompt_assistant.py +357 -0
- modules/prompt_library.py +689 -0
- modules/prompt_library_migration.py +447 -0
- modules/quick_access_sidebar.py +282 -0
- modules/ribbon_widget.py +597 -0
- modules/sdlppx_handler.py +874 -0
- modules/setup_wizard.py +353 -0
- modules/shortcut_manager.py +932 -0
- modules/simple_segmenter.py +128 -0
- modules/spellcheck_manager.py +727 -0
- modules/statuses.py +207 -0
- modules/style_guide_manager.py +315 -0
- modules/superbench_ui.py +1319 -0
- modules/superbrowser.py +329 -0
- modules/supercleaner.py +600 -0
- modules/supercleaner_ui.py +444 -0
- modules/superdocs.py +19 -0
- modules/superdocs_viewer_qt.py +382 -0
- modules/superlookup.py +252 -0
- modules/tag_cleaner.py +260 -0
- modules/tag_manager.py +333 -0
- modules/term_extractor.py +270 -0
- modules/termbase_entry_editor.py +842 -0
- modules/termbase_import_export.py +488 -0
- modules/termbase_manager.py +1060 -0
- modules/termview_widget.py +1172 -0
- modules/theme_manager.py +499 -0
- modules/tm_editor_dialog.py +99 -0
- modules/tm_manager_qt.py +1280 -0
- modules/tm_metadata_manager.py +545 -0
- modules/tmx_editor.py +1461 -0
- modules/tmx_editor_qt.py +2784 -0
- modules/tmx_generator.py +284 -0
- modules/tracked_changes.py +900 -0
- modules/trados_docx_handler.py +430 -0
- modules/translation_memory.py +715 -0
- modules/translation_results_panel.py +2134 -0
- modules/translation_services.py +282 -0
- modules/unified_prompt_library.py +659 -0
- modules/unified_prompt_manager_qt.py +3951 -0
- modules/voice_commands.py +920 -0
- modules/voice_dictation.py +477 -0
- modules/voice_dictation_lite.py +249 -0
- supervertaler-1.9.153.dist-info/METADATA +896 -0
- supervertaler-1.9.153.dist-info/RECORD +85 -0
- supervertaler-1.9.153.dist-info/WHEEL +5 -0
- supervertaler-1.9.153.dist-info/entry_points.txt +2 -0
- supervertaler-1.9.153.dist-info/licenses/LICENSE +21 -0
- supervertaler-1.9.153.dist-info/top_level.txt +2 -0
modules/theme_manager.py
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Theme Manager
|
|
3
|
+
=============
|
|
4
|
+
Manages UI themes and color schemes for Supervertaler Qt.
|
|
5
|
+
Allows users to customize the appearance of the entire application.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- Predefined themes (Light, Dark, Sepia, High Contrast)
|
|
9
|
+
- Custom theme creation and editing
|
|
10
|
+
- Save/load user themes
|
|
11
|
+
- Apply themes to all UI elements
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from PyQt6.QtGui import QColor, QPalette
|
|
15
|
+
from PyQt6.QtWidgets import QApplication
|
|
16
|
+
from dataclasses import dataclass, asdict
|
|
17
|
+
import json
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Dict, Optional
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class Theme:
|
|
24
|
+
"""Theme definition with all UI colors"""
|
|
25
|
+
name: str
|
|
26
|
+
|
|
27
|
+
# Main window colors
|
|
28
|
+
window_bg: str = "#F5F5F5" # Main background
|
|
29
|
+
alternate_bg: str = "#EBEBEB" # Alternate row color
|
|
30
|
+
|
|
31
|
+
# Text colors
|
|
32
|
+
text: str = "#212121" # Primary text
|
|
33
|
+
text_disabled: str = "#9E9E9E" # Disabled text
|
|
34
|
+
text_placeholder: str = "#BDBDBD" # Placeholder text
|
|
35
|
+
|
|
36
|
+
# Control colors
|
|
37
|
+
base: str = "#FFFFFF" # Input fields, text areas
|
|
38
|
+
button: str = "#E0E0E0" # Button background
|
|
39
|
+
button_hover: str = "#D5D5D5" # Button hover
|
|
40
|
+
|
|
41
|
+
# Highlight colors
|
|
42
|
+
highlight: str = "#2196F3" # Selection highlight
|
|
43
|
+
highlight_text: str = "#FFFFFF" # Selected text
|
|
44
|
+
|
|
45
|
+
# Border and separator colors
|
|
46
|
+
border: str = "#CCCCCC" # Borders
|
|
47
|
+
separator: str = "#E0E0E0" # Separators
|
|
48
|
+
|
|
49
|
+
# Status colors
|
|
50
|
+
success: str = "#4CAF50" # Green for success
|
|
51
|
+
warning: str = "#FF9800" # Orange for warnings
|
|
52
|
+
error: str = "#F44336" # Red for errors
|
|
53
|
+
info: str = "#2196F3" # Blue for info
|
|
54
|
+
|
|
55
|
+
# Grid colors
|
|
56
|
+
grid_header: str = "#E8E8E8" # Table headers
|
|
57
|
+
grid_line: str = "#E0E0E0" # Grid lines
|
|
58
|
+
|
|
59
|
+
# Tab colors
|
|
60
|
+
tab_bg: str = "#F5F5F5" # Tab background
|
|
61
|
+
tab_selected: str = "#FFFFFF" # Selected tab
|
|
62
|
+
|
|
63
|
+
# TM match colors (for colored match percentages)
|
|
64
|
+
tm_exact: str = "#C8E6C9" # 100% match (light green)
|
|
65
|
+
tm_high: str = "#FFF9C4" # 95-99% (light yellow)
|
|
66
|
+
tm_medium: str = "#FFE0B2" # 85-94% (light orange)
|
|
67
|
+
tm_low: str = "#F5F5F5" # <85% (default)
|
|
68
|
+
|
|
69
|
+
# Action button colors (for buttons that need specific semantic colors)
|
|
70
|
+
button_success: str = "#4CAF50" # Green for success actions (save, apply, etc.)
|
|
71
|
+
button_info: str = "#2196F3" # Blue for info actions
|
|
72
|
+
button_warning: str = "#FF9800" # Orange for warning actions
|
|
73
|
+
button_danger: str = "#F44336" # Red for danger actions (delete, etc.)
|
|
74
|
+
button_neutral: str = "#607D8B" # Blue-gray for neutral actions
|
|
75
|
+
button_purple: str = "#9C27B0" # Purple for special actions
|
|
76
|
+
|
|
77
|
+
# Panel/info box backgrounds
|
|
78
|
+
panel_info: str = "#F0F7FF" # Light blue info panels
|
|
79
|
+
panel_warning: str = "#FFF3CD" # Light yellow warning panels
|
|
80
|
+
panel_neutral: str = "#F3F4F6" # Gray neutral panels
|
|
81
|
+
panel_preview: str = "#F9F9F9" # Preview areas
|
|
82
|
+
panel_accent: str = "#FFF3E0" # Accent panels
|
|
83
|
+
|
|
84
|
+
# TM results display colors
|
|
85
|
+
tm_source_label: str = "#1976D2" # Blue for source language label
|
|
86
|
+
tm_target_label: str = "#388E3C" # Green for target language label
|
|
87
|
+
tm_highlight_bg: str = "#FFFF00" # Yellow background for search term highlight
|
|
88
|
+
tm_highlight_text: str = "#000000" # Black text for highlighted terms
|
|
89
|
+
|
|
90
|
+
def to_dict(self) -> Dict:
|
|
91
|
+
"""Convert theme to dictionary"""
|
|
92
|
+
return asdict(self)
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def from_dict(cls, data: Dict) -> 'Theme':
|
|
96
|
+
"""Create theme from dictionary"""
|
|
97
|
+
return cls(**data)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class ThemeManager:
|
|
101
|
+
"""Manages application themes"""
|
|
102
|
+
|
|
103
|
+
# Predefined themes
|
|
104
|
+
PREDEFINED_THEMES = {
|
|
105
|
+
"Light (Default)": Theme(
|
|
106
|
+
name="Light (Default)",
|
|
107
|
+
window_bg="#F5F5F5",
|
|
108
|
+
alternate_bg="#EBEBEB",
|
|
109
|
+
text="#212121",
|
|
110
|
+
base="#FFFFFF",
|
|
111
|
+
button="#E0E0E0",
|
|
112
|
+
highlight="#e3f2fd",
|
|
113
|
+
highlight_text="#000000",
|
|
114
|
+
),
|
|
115
|
+
|
|
116
|
+
"Soft Gray": Theme(
|
|
117
|
+
name="Soft Gray",
|
|
118
|
+
window_bg="#E8E8E8",
|
|
119
|
+
alternate_bg="#DEDEDE",
|
|
120
|
+
text="#1A1A1A",
|
|
121
|
+
base="#F8F8F8",
|
|
122
|
+
button="#D5D5D5",
|
|
123
|
+
highlight="#1976D2",
|
|
124
|
+
),
|
|
125
|
+
|
|
126
|
+
"Warm Cream": Theme(
|
|
127
|
+
name="Warm Cream",
|
|
128
|
+
window_bg="#F5F0E8",
|
|
129
|
+
alternate_bg="#EBE6DE",
|
|
130
|
+
text="#3E2723",
|
|
131
|
+
base="#FFFEF8",
|
|
132
|
+
button="#E8DED0",
|
|
133
|
+
highlight="#6D4C41",
|
|
134
|
+
grid_header="#EBE6DE",
|
|
135
|
+
),
|
|
136
|
+
|
|
137
|
+
"Dark": Theme(
|
|
138
|
+
name="Dark",
|
|
139
|
+
window_bg="#2B2B2B",
|
|
140
|
+
alternate_bg="#353535",
|
|
141
|
+
text="#E0E0E0",
|
|
142
|
+
text_disabled="#757575",
|
|
143
|
+
text_placeholder="#616161",
|
|
144
|
+
base="#1E1E1E",
|
|
145
|
+
button="#404040",
|
|
146
|
+
button_hover="#4A4A4A",
|
|
147
|
+
highlight="#0D47A1",
|
|
148
|
+
highlight_text="#FFFFFF",
|
|
149
|
+
border="#505050",
|
|
150
|
+
separator="#404040",
|
|
151
|
+
grid_header="#353535",
|
|
152
|
+
grid_line="#404040",
|
|
153
|
+
tab_bg="#2B2B2B",
|
|
154
|
+
tab_selected="#1E1E1E",
|
|
155
|
+
# TM match colors (darker versions for dark mode)
|
|
156
|
+
tm_exact="#2E5C35", # Dark green
|
|
157
|
+
tm_high="#5C5424", # Dark yellow
|
|
158
|
+
tm_medium="#5C4224", # Dark orange
|
|
159
|
+
tm_low="#2B2B2B", # Match window background
|
|
160
|
+
# Action button colors (keep vibrant for visibility in dark mode)
|
|
161
|
+
button_success="#388E3C", # Darker green
|
|
162
|
+
button_info="#1976D2", # Darker blue
|
|
163
|
+
button_warning="#F57C00", # Darker orange
|
|
164
|
+
button_danger="#D32F2F", # Darker red
|
|
165
|
+
button_neutral="#455A64", # Darker blue-gray
|
|
166
|
+
button_purple="#7B1FA2", # Darker purple
|
|
167
|
+
# Panel/info box backgrounds (dark versions)
|
|
168
|
+
panel_info="#1A2F3A", # Dark blue
|
|
169
|
+
panel_warning="#3A3020", # Dark yellow
|
|
170
|
+
panel_neutral="#323232", # Dark gray
|
|
171
|
+
panel_preview="#252525", # Dark preview
|
|
172
|
+
panel_accent="#3A2F1A", # Dark accent
|
|
173
|
+
# TM results display colors (brighter for visibility in dark mode)
|
|
174
|
+
tm_source_label="#64B5F6", # Brighter blue for source language label
|
|
175
|
+
tm_target_label="#81C784", # Brighter green for target language label
|
|
176
|
+
tm_highlight_bg="#FFD54F", # Softer yellow for dark mode
|
|
177
|
+
tm_highlight_text="#000000", # Black text for highlighted terms
|
|
178
|
+
),
|
|
179
|
+
|
|
180
|
+
"Sepia": Theme(
|
|
181
|
+
name="Sepia",
|
|
182
|
+
window_bg="#F4ECD8",
|
|
183
|
+
alternate_bg="#E8E0CE",
|
|
184
|
+
text="#3E2723",
|
|
185
|
+
base="#FFFEF5",
|
|
186
|
+
button="#E0D8C8",
|
|
187
|
+
highlight="#8D6E63",
|
|
188
|
+
grid_header="#E8E0CE",
|
|
189
|
+
),
|
|
190
|
+
|
|
191
|
+
"High Contrast": Theme(
|
|
192
|
+
name="High Contrast",
|
|
193
|
+
window_bg="#FFFFFF",
|
|
194
|
+
alternate_bg="#F0F0F0",
|
|
195
|
+
text="#000000",
|
|
196
|
+
base="#FFFFFF",
|
|
197
|
+
button="#E0E0E0",
|
|
198
|
+
highlight="#0000FF",
|
|
199
|
+
highlight_text="#FFFFFF",
|
|
200
|
+
border="#000000",
|
|
201
|
+
),
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
def __init__(self, user_data_path: Path):
|
|
205
|
+
"""
|
|
206
|
+
Initialize theme manager
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
user_data_path: Path to user_data folder for saving custom themes
|
|
210
|
+
"""
|
|
211
|
+
self.user_data_path = user_data_path
|
|
212
|
+
self.themes_file = user_data_path / "themes.json"
|
|
213
|
+
self.current_theme: Theme = self.PREDEFINED_THEMES["Light (Default)"]
|
|
214
|
+
self.custom_themes: Dict[str, Theme] = {}
|
|
215
|
+
|
|
216
|
+
# Load custom themes
|
|
217
|
+
self.load_custom_themes()
|
|
218
|
+
|
|
219
|
+
def get_all_themes(self) -> Dict[str, Theme]:
|
|
220
|
+
"""Get all available themes (predefined + custom)"""
|
|
221
|
+
all_themes = self.PREDEFINED_THEMES.copy()
|
|
222
|
+
all_themes.update(self.custom_themes)
|
|
223
|
+
return all_themes
|
|
224
|
+
|
|
225
|
+
def get_theme(self, name: str) -> Optional[Theme]:
|
|
226
|
+
"""Get theme by name"""
|
|
227
|
+
all_themes = self.get_all_themes()
|
|
228
|
+
return all_themes.get(name)
|
|
229
|
+
|
|
230
|
+
def set_theme(self, name: str) -> bool:
|
|
231
|
+
"""
|
|
232
|
+
Set current theme
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
name: Theme name
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
True if theme was found and applied
|
|
239
|
+
"""
|
|
240
|
+
theme = self.get_theme(name)
|
|
241
|
+
if theme:
|
|
242
|
+
self.current_theme = theme
|
|
243
|
+
return True
|
|
244
|
+
return False
|
|
245
|
+
|
|
246
|
+
def save_custom_theme(self, theme: Theme):
|
|
247
|
+
"""Save a custom theme"""
|
|
248
|
+
self.custom_themes[theme.name] = theme
|
|
249
|
+
self._save_themes()
|
|
250
|
+
|
|
251
|
+
def delete_custom_theme(self, name: str) -> bool:
|
|
252
|
+
"""Delete a custom theme"""
|
|
253
|
+
if name in self.custom_themes:
|
|
254
|
+
del self.custom_themes[name]
|
|
255
|
+
self._save_themes()
|
|
256
|
+
return True
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
def load_custom_themes(self):
|
|
260
|
+
"""Load custom themes from file"""
|
|
261
|
+
if self.themes_file.exists():
|
|
262
|
+
try:
|
|
263
|
+
with open(self.themes_file, 'r', encoding='utf-8') as f:
|
|
264
|
+
data = json.load(f)
|
|
265
|
+
for theme_data in data.get('themes', []):
|
|
266
|
+
theme = Theme.from_dict(theme_data)
|
|
267
|
+
self.custom_themes[theme.name] = theme
|
|
268
|
+
|
|
269
|
+
# Load last used theme
|
|
270
|
+
current_theme_name = data.get('current_theme')
|
|
271
|
+
if current_theme_name:
|
|
272
|
+
self.set_theme(current_theme_name)
|
|
273
|
+
except Exception as e:
|
|
274
|
+
print(f"Error loading themes: {e}")
|
|
275
|
+
|
|
276
|
+
def _save_themes(self):
|
|
277
|
+
"""Save custom themes to file"""
|
|
278
|
+
try:
|
|
279
|
+
data = {
|
|
280
|
+
'current_theme': self.current_theme.name,
|
|
281
|
+
'themes': [theme.to_dict() for theme in self.custom_themes.values()]
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
with open(self.themes_file, 'w', encoding='utf-8') as f:
|
|
285
|
+
json.dump(data, f, indent=2)
|
|
286
|
+
except Exception as e:
|
|
287
|
+
print(f"Error saving themes: {e}")
|
|
288
|
+
|
|
289
|
+
def apply_theme(self, app: QApplication):
|
|
290
|
+
"""
|
|
291
|
+
Apply current theme to application
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
app: QApplication instance
|
|
295
|
+
"""
|
|
296
|
+
theme = self.current_theme
|
|
297
|
+
|
|
298
|
+
# Create and apply stylesheet - COLORS ONLY, preserves native sizes/spacing
|
|
299
|
+
stylesheet = f"""
|
|
300
|
+
/* Main window background */
|
|
301
|
+
QMainWindow, QWidget {{
|
|
302
|
+
background-color: {theme.window_bg};
|
|
303
|
+
color: {theme.text};
|
|
304
|
+
}}
|
|
305
|
+
|
|
306
|
+
/* Input fields and text areas */
|
|
307
|
+
QLineEdit, QTextEdit, QPlainTextEdit, QSpinBox, QDoubleSpinBox {{
|
|
308
|
+
background-color: {theme.base};
|
|
309
|
+
color: {theme.text};
|
|
310
|
+
border: 1px solid {theme.border};
|
|
311
|
+
}}
|
|
312
|
+
|
|
313
|
+
QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {{
|
|
314
|
+
border: 1px solid {theme.highlight};
|
|
315
|
+
}}
|
|
316
|
+
|
|
317
|
+
/* Buttons */
|
|
318
|
+
QPushButton {{
|
|
319
|
+
background-color: {theme.button};
|
|
320
|
+
color: {theme.text};
|
|
321
|
+
border: 1px solid {theme.border};
|
|
322
|
+
}}
|
|
323
|
+
|
|
324
|
+
QPushButton:hover {{
|
|
325
|
+
background-color: {theme.button_hover};
|
|
326
|
+
}}
|
|
327
|
+
|
|
328
|
+
QPushButton:pressed {{
|
|
329
|
+
background-color: {theme.highlight};
|
|
330
|
+
color: {theme.highlight_text};
|
|
331
|
+
}}
|
|
332
|
+
|
|
333
|
+
QPushButton:disabled {{
|
|
334
|
+
color: {theme.text_disabled};
|
|
335
|
+
}}
|
|
336
|
+
|
|
337
|
+
/* Combo boxes */
|
|
338
|
+
QComboBox {{
|
|
339
|
+
background-color: {theme.base};
|
|
340
|
+
color: {theme.text};
|
|
341
|
+
border: 1px solid {theme.border};
|
|
342
|
+
}}
|
|
343
|
+
|
|
344
|
+
QComboBox:hover {{
|
|
345
|
+
border: 1px solid {theme.highlight};
|
|
346
|
+
}}
|
|
347
|
+
|
|
348
|
+
/* Tables */
|
|
349
|
+
QTableWidget {{
|
|
350
|
+
background-color: {theme.base};
|
|
351
|
+
alternate-background-color: {theme.alternate_bg};
|
|
352
|
+
color: {theme.text};
|
|
353
|
+
gridline-color: {theme.grid_line};
|
|
354
|
+
border: 1px solid {theme.border};
|
|
355
|
+
}}
|
|
356
|
+
|
|
357
|
+
QTableWidget::item:selected {{
|
|
358
|
+
background-color: {theme.highlight};
|
|
359
|
+
color: {theme.highlight_text};
|
|
360
|
+
}}
|
|
361
|
+
|
|
362
|
+
QHeaderView::section {{
|
|
363
|
+
background-color: {theme.grid_header};
|
|
364
|
+
color: {theme.text};
|
|
365
|
+
border: 1px solid {theme.border};
|
|
366
|
+
}}
|
|
367
|
+
|
|
368
|
+
/* Tabs */
|
|
369
|
+
QTabWidget::pane {{
|
|
370
|
+
border: 1px solid {theme.border};
|
|
371
|
+
background-color: {theme.base};
|
|
372
|
+
}}
|
|
373
|
+
|
|
374
|
+
QTabBar::tab {{
|
|
375
|
+
background-color: {theme.tab_bg};
|
|
376
|
+
color: {theme.text};
|
|
377
|
+
border: 1px solid {theme.border};
|
|
378
|
+
padding: 6px 12px;
|
|
379
|
+
}}
|
|
380
|
+
|
|
381
|
+
QTabBar::tab:selected {{
|
|
382
|
+
background-color: {theme.tab_selected};
|
|
383
|
+
border-bottom: 1px solid {theme.highlight};
|
|
384
|
+
}}
|
|
385
|
+
|
|
386
|
+
QTabBar::tab:hover {{
|
|
387
|
+
background-color: {theme.button_hover};
|
|
388
|
+
}}
|
|
389
|
+
|
|
390
|
+
/* Splitter */
|
|
391
|
+
QSplitter::handle {{
|
|
392
|
+
background-color: {theme.separator};
|
|
393
|
+
}}
|
|
394
|
+
|
|
395
|
+
/* Scrollbars */
|
|
396
|
+
QScrollBar:vertical {{
|
|
397
|
+
background-color: {theme.window_bg};
|
|
398
|
+
}}
|
|
399
|
+
|
|
400
|
+
QScrollBar::handle:vertical {{
|
|
401
|
+
background-color: {theme.button};
|
|
402
|
+
}}
|
|
403
|
+
|
|
404
|
+
QScrollBar::handle:vertical:hover {{
|
|
405
|
+
background-color: {theme.button_hover};
|
|
406
|
+
}}
|
|
407
|
+
|
|
408
|
+
QScrollBar:horizontal {{
|
|
409
|
+
background-color: {theme.window_bg};
|
|
410
|
+
}}
|
|
411
|
+
|
|
412
|
+
QScrollBar::handle:horizontal {{
|
|
413
|
+
background-color: {theme.button};
|
|
414
|
+
}}
|
|
415
|
+
|
|
416
|
+
QScrollBar::handle:horizontal:hover {{
|
|
417
|
+
background-color: {theme.button_hover};
|
|
418
|
+
}}
|
|
419
|
+
|
|
420
|
+
/* Checkboxes and Radio buttons */
|
|
421
|
+
QCheckBox, QRadioButton {{
|
|
422
|
+
color: {theme.text};
|
|
423
|
+
}}
|
|
424
|
+
|
|
425
|
+
QCheckBox::indicator, QRadioButton::indicator {{
|
|
426
|
+
border: 1px solid {theme.border};
|
|
427
|
+
background-color: {theme.base};
|
|
428
|
+
}}
|
|
429
|
+
|
|
430
|
+
QCheckBox::indicator:checked {{
|
|
431
|
+
background-color: {theme.highlight};
|
|
432
|
+
}}
|
|
433
|
+
|
|
434
|
+
/* Menu bar */
|
|
435
|
+
QMenuBar {{
|
|
436
|
+
background-color: {theme.window_bg};
|
|
437
|
+
color: {theme.text};
|
|
438
|
+
}}
|
|
439
|
+
|
|
440
|
+
QMenuBar::item:selected {{
|
|
441
|
+
background-color: {theme.highlight};
|
|
442
|
+
color: {theme.highlight_text};
|
|
443
|
+
}}
|
|
444
|
+
|
|
445
|
+
QMenu {{
|
|
446
|
+
background-color: {theme.base};
|
|
447
|
+
color: {theme.text};
|
|
448
|
+
border: 1px solid {theme.border};
|
|
449
|
+
}}
|
|
450
|
+
|
|
451
|
+
QMenu::item:selected {{
|
|
452
|
+
background-color: {theme.highlight};
|
|
453
|
+
color: {theme.highlight_text};
|
|
454
|
+
}}
|
|
455
|
+
|
|
456
|
+
/* Status bar */
|
|
457
|
+
QStatusBar {{
|
|
458
|
+
background-color: {theme.window_bg};
|
|
459
|
+
color: {theme.text};
|
|
460
|
+
}}
|
|
461
|
+
|
|
462
|
+
/* Group boxes - minimal styling to avoid title rendering issues */
|
|
463
|
+
QGroupBox {{
|
|
464
|
+
color: {theme.text};
|
|
465
|
+
border: 1px solid {theme.border};
|
|
466
|
+
padding: 18px 10px 10px 10px;
|
|
467
|
+
margin-top: 12px;
|
|
468
|
+
}}
|
|
469
|
+
|
|
470
|
+
QGroupBox::title {{
|
|
471
|
+
color: {theme.text};
|
|
472
|
+
subcontrol-origin: margin;
|
|
473
|
+
subcontrol-position: top left;
|
|
474
|
+
padding: 2px 5px;
|
|
475
|
+
background-color: {theme.window_bg};
|
|
476
|
+
}}
|
|
477
|
+
|
|
478
|
+
/* Dialogs */
|
|
479
|
+
QDialog {{
|
|
480
|
+
background-color: {theme.window_bg};
|
|
481
|
+
color: {theme.text};
|
|
482
|
+
}}
|
|
483
|
+
|
|
484
|
+
/* Labels */
|
|
485
|
+
QLabel {{
|
|
486
|
+
color: {theme.text};
|
|
487
|
+
padding: 3px 2px;
|
|
488
|
+
}}
|
|
489
|
+
|
|
490
|
+
/* Form layouts need extra spacing */
|
|
491
|
+
QFormLayout {{
|
|
492
|
+
vertical-spacing: 8px;
|
|
493
|
+
}}
|
|
494
|
+
"""
|
|
495
|
+
|
|
496
|
+
app.setStyleSheet(stylesheet)
|
|
497
|
+
|
|
498
|
+
# Save current theme
|
|
499
|
+
self._save_themes()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TM Editor Dialog - Edit a specific Translation Memory
|
|
3
|
+
|
|
4
|
+
This dialog provides comprehensive editing for a single TM:
|
|
5
|
+
- Browse entries
|
|
6
|
+
- Concordance search
|
|
7
|
+
- Statistics
|
|
8
|
+
- Import/Export (scoped to this TM)
|
|
9
|
+
- Maintenance
|
|
10
|
+
|
|
11
|
+
Similar to TMManagerDialog but scoped to a specific tm_id.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QLabel, QTabWidget, QWidget, QPushButton)
|
|
15
|
+
from PyQt6.QtCore import Qt
|
|
16
|
+
|
|
17
|
+
# Import the existing TM Manager tabs
|
|
18
|
+
from modules.tm_manager_qt import TMManagerDialog
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TMEditorDialog(QDialog):
|
|
22
|
+
"""TM Editor for a specific translation memory"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, parent, db_manager, log_callback, tm_id: str, tm_name: str):
|
|
25
|
+
"""
|
|
26
|
+
Initialize TM Editor
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
parent: Parent widget
|
|
30
|
+
db_manager: DatabaseManager instance
|
|
31
|
+
log_callback: Logging function
|
|
32
|
+
tm_id: The tm_id to edit
|
|
33
|
+
tm_name: Display name of the TM
|
|
34
|
+
"""
|
|
35
|
+
super().__init__(parent)
|
|
36
|
+
self.db_manager = db_manager
|
|
37
|
+
self.log = log_callback
|
|
38
|
+
self.tm_id = tm_id
|
|
39
|
+
self.tm_name = tm_name
|
|
40
|
+
|
|
41
|
+
self.setWindowTitle(f"TM Editor - {tm_name}")
|
|
42
|
+
self.setMinimumSize(1000, 700)
|
|
43
|
+
|
|
44
|
+
self.init_ui()
|
|
45
|
+
|
|
46
|
+
def init_ui(self):
|
|
47
|
+
"""Initialize UI - tabs for editing a specific TM"""
|
|
48
|
+
layout = QVBoxLayout(self)
|
|
49
|
+
|
|
50
|
+
# Header showing which TM is being edited
|
|
51
|
+
header = QLabel(f"๐ Editing: {self.tm_name}")
|
|
52
|
+
header.setStyleSheet("""
|
|
53
|
+
font-size: 16px;
|
|
54
|
+
font-weight: bold;
|
|
55
|
+
padding: 10px;
|
|
56
|
+
background-color: #e3f2fd;
|
|
57
|
+
border-radius: 4px;
|
|
58
|
+
margin-bottom: 10px;
|
|
59
|
+
""")
|
|
60
|
+
layout.addWidget(header)
|
|
61
|
+
|
|
62
|
+
# Info about TM
|
|
63
|
+
from modules.tm_metadata_manager import TMMetadataManager
|
|
64
|
+
tm_metadata_mgr = TMMetadataManager(self.db_manager, self.log)
|
|
65
|
+
tm_info = tm_metadata_mgr.get_tm_by_tm_id(self.tm_id)
|
|
66
|
+
|
|
67
|
+
if tm_info:
|
|
68
|
+
info_text = f"TM ID: {self.tm_id} | Languages: {tm_info['source_lang'] or '?'} โ {tm_info['target_lang'] or '?'} | Entries: {tm_info['entry_count']}"
|
|
69
|
+
info_label = QLabel(info_text)
|
|
70
|
+
info_label.setStyleSheet("color: #666; font-size: 11px; padding: 5px; margin-bottom: 10px;")
|
|
71
|
+
layout.addWidget(info_label)
|
|
72
|
+
|
|
73
|
+
# Create nested TM Manager for this specific TM
|
|
74
|
+
tm_manager = TMManagerDialog(self, self.db_manager, self.log, tm_ids=[self.tm_id])
|
|
75
|
+
|
|
76
|
+
# Create tab widget with only relevant tabs for editing a specific TM
|
|
77
|
+
tabs = QTabWidget()
|
|
78
|
+
|
|
79
|
+
# Tab 1: Browse (this TM only)
|
|
80
|
+
tabs.addTab(tm_manager.browser_tab, "๐ Browse Entries")
|
|
81
|
+
|
|
82
|
+
# Tab 2: Import/Export (this TM only)
|
|
83
|
+
tabs.addTab(tm_manager.import_export_tab, "๐ฅ Import/Export")
|
|
84
|
+
|
|
85
|
+
# Tab 3: Statistics (this TM only)
|
|
86
|
+
tabs.addTab(tm_manager.stats_tab, "๐ Statistics")
|
|
87
|
+
|
|
88
|
+
# Tab 4: Maintenance (this TM only)
|
|
89
|
+
tabs.addTab(tm_manager.maintenance_tab, "๐งน Maintenance")
|
|
90
|
+
|
|
91
|
+
# Store reference to prevent garbage collection
|
|
92
|
+
self._tm_manager = tm_manager
|
|
93
|
+
|
|
94
|
+
layout.addWidget(tabs)
|
|
95
|
+
|
|
96
|
+
# Close button
|
|
97
|
+
close_btn = QPushButton("Close")
|
|
98
|
+
close_btn.clicked.connect(self.accept)
|
|
99
|
+
layout.addWidget(close_btn)
|