supervertaler 1.9.189__py3-none-any.whl → 1.9.196__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 +842 -214
- modules/keyboard_shortcuts_widget.py +76 -8
- modules/llm_clients.py +58 -33
- modules/quicktrans.py +670 -0
- modules/shortcut_manager.py +19 -5
- modules/statuses.py +2 -2
- modules/superlookup.py +3 -3
- modules/unified_prompt_manager_qt.py +22 -1
- {supervertaler-1.9.189.dist-info → supervertaler-1.9.196.dist-info}/METADATA +1 -1
- {supervertaler-1.9.189.dist-info → supervertaler-1.9.196.dist-info}/RECORD +14 -13
- {supervertaler-1.9.189.dist-info → supervertaler-1.9.196.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.189.dist-info → supervertaler-1.9.196.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.189.dist-info → supervertaler-1.9.196.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.189.dist-info → supervertaler-1.9.196.dist-info}/top_level.txt +0 -0
Supervertaler.py
CHANGED
|
@@ -32,9 +32,9 @@ License: MIT
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
# Version Information.
|
|
35
|
-
__version__ = "1.9.
|
|
35
|
+
__version__ = "1.9.196"
|
|
36
36
|
__phase__ = "0.9"
|
|
37
|
-
__release_date__ = "2026-02-
|
|
37
|
+
__release_date__ = "2026-02-02"
|
|
38
38
|
__edition__ = "Qt"
|
|
39
39
|
|
|
40
40
|
import sys
|
|
@@ -2298,10 +2298,15 @@ class ReadOnlyGridTextEditor(QTextEdit):
|
|
|
2298
2298
|
|
|
2299
2299
|
# Superlookup search action
|
|
2300
2300
|
if self.textCursor().hasSelection():
|
|
2301
|
-
superlookup_action = QAction("🔍 Search in
|
|
2301
|
+
superlookup_action = QAction("🔍 Search in SuperLookup (Ctrl+K)", self)
|
|
2302
2302
|
superlookup_action.triggered.connect(self._handle_superlookup_search)
|
|
2303
2303
|
menu.addAction(superlookup_action)
|
|
2304
|
-
|
|
2304
|
+
|
|
2305
|
+
# MT Quick Lookup action
|
|
2306
|
+
mt_lookup_action = QAction("⚡ QuickTrans (Ctrl+M)", self)
|
|
2307
|
+
mt_lookup_action.triggered.connect(self._handle_mt_quick_lookup)
|
|
2308
|
+
menu.addAction(mt_lookup_action)
|
|
2309
|
+
menu.addSeparator()
|
|
2305
2310
|
|
|
2306
2311
|
# QuickMenu (prompt-based actions)
|
|
2307
2312
|
try:
|
|
@@ -2355,7 +2360,7 @@ class ReadOnlyGridTextEditor(QTextEdit):
|
|
|
2355
2360
|
"""Handle Ctrl+Alt+N: Add selected text to active non-translatable list(s)"""
|
|
2356
2361
|
# Get selected text
|
|
2357
2362
|
selected_text = self.textCursor().selectedText().strip()
|
|
2358
|
-
|
|
2363
|
+
|
|
2359
2364
|
if not selected_text:
|
|
2360
2365
|
from PyQt6.QtWidgets import QMessageBox
|
|
2361
2366
|
QMessageBox.warning(
|
|
@@ -2364,14 +2369,14 @@ class ReadOnlyGridTextEditor(QTextEdit):
|
|
|
2364
2369
|
"Please select text in the Source cell before adding to non-translatables."
|
|
2365
2370
|
)
|
|
2366
2371
|
return
|
|
2367
|
-
|
|
2372
|
+
|
|
2368
2373
|
# Find main window and call add_to_nt method
|
|
2369
2374
|
table = self.table_ref if hasattr(self, 'table_ref') else self.parent()
|
|
2370
2375
|
if table:
|
|
2371
2376
|
main_window = table.parent()
|
|
2372
2377
|
while main_window and not hasattr(main_window, 'add_text_to_non_translatables'):
|
|
2373
2378
|
main_window = main_window.parent()
|
|
2374
|
-
|
|
2379
|
+
|
|
2375
2380
|
if main_window and hasattr(main_window, 'add_text_to_non_translatables'):
|
|
2376
2381
|
main_window.add_text_to_non_translatables(selected_text)
|
|
2377
2382
|
else:
|
|
@@ -2382,6 +2387,16 @@ class ReadOnlyGridTextEditor(QTextEdit):
|
|
|
2382
2387
|
"Non-translatables functionality not available."
|
|
2383
2388
|
)
|
|
2384
2389
|
|
|
2390
|
+
def _handle_mt_quick_lookup(self):
|
|
2391
|
+
"""Handle right-click: Open MT Quick Lookup popup for selected text or full source"""
|
|
2392
|
+
# Get selected text (if any)
|
|
2393
|
+
selected_text = self.textCursor().selectedText().strip() if self.textCursor().hasSelection() else None
|
|
2394
|
+
|
|
2395
|
+
# Find main window and call show_mt_quick_popup
|
|
2396
|
+
main_window = self._get_main_window()
|
|
2397
|
+
if main_window and hasattr(main_window, 'show_mt_quick_popup'):
|
|
2398
|
+
main_window.show_mt_quick_popup(text_override=selected_text)
|
|
2399
|
+
|
|
2385
2400
|
def set_background_color(self, color: str):
|
|
2386
2401
|
"""Set the background color for this text editor (for alternating row colors)"""
|
|
2387
2402
|
self.setStyleSheet(f"""
|
|
@@ -2991,10 +3006,15 @@ class EditableGridTextEditor(QTextEdit):
|
|
|
2991
3006
|
|
|
2992
3007
|
# Superlookup search action
|
|
2993
3008
|
if self.textCursor().hasSelection():
|
|
2994
|
-
superlookup_action = QAction("🔍 Search in
|
|
3009
|
+
superlookup_action = QAction("🔍 Search in SuperLookup (Ctrl+K)", self)
|
|
2995
3010
|
superlookup_action.triggered.connect(self._handle_superlookup_search)
|
|
2996
3011
|
menu.addAction(superlookup_action)
|
|
2997
|
-
|
|
3012
|
+
|
|
3013
|
+
# MT Quick Lookup action
|
|
3014
|
+
mt_lookup_action = QAction("⚡ QuickTrans (Ctrl+M)", self)
|
|
3015
|
+
mt_lookup_action.triggered.connect(self._handle_mt_quick_lookup)
|
|
3016
|
+
menu.addAction(mt_lookup_action)
|
|
3017
|
+
menu.addSeparator()
|
|
2998
3018
|
|
|
2999
3019
|
# QuickMenu (prompt-based actions)
|
|
3000
3020
|
try:
|
|
@@ -3507,6 +3527,24 @@ class EditableGridTextEditor(QTextEdit):
|
|
|
3507
3527
|
"Non-translatables functionality not available."
|
|
3508
3528
|
)
|
|
3509
3529
|
|
|
3530
|
+
def _handle_mt_quick_lookup(self):
|
|
3531
|
+
"""Handle right-click: Open MT Quick Lookup popup for selected text or full source"""
|
|
3532
|
+
# Get selected text (if any) - prefer from target, then try source
|
|
3533
|
+
selected_text = self.textCursor().selectedText().strip() if self.textCursor().hasSelection() else None
|
|
3534
|
+
|
|
3535
|
+
if not selected_text and self.table and self.row >= 0:
|
|
3536
|
+
# Try getting selected text from source cell
|
|
3537
|
+
source_widget = self.table.cellWidget(self.row, 2)
|
|
3538
|
+
if source_widget and hasattr(source_widget, 'textCursor'):
|
|
3539
|
+
cursor = source_widget.textCursor()
|
|
3540
|
+
if cursor.hasSelection():
|
|
3541
|
+
selected_text = cursor.selectedText().strip()
|
|
3542
|
+
|
|
3543
|
+
# Find main window and call show_mt_quick_popup
|
|
3544
|
+
main_window = self._get_main_window()
|
|
3545
|
+
if main_window and hasattr(main_window, 'show_mt_quick_popup'):
|
|
3546
|
+
main_window.show_mt_quick_popup(text_override=selected_text)
|
|
3547
|
+
|
|
3510
3548
|
def _insert_next_tag_or_wrap_selection(self):
|
|
3511
3549
|
"""
|
|
3512
3550
|
Insert the next memoQ tag, HTML tag, or CafeTran pipe symbol from source, or wrap selection.
|
|
@@ -6435,7 +6473,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
6435
6473
|
|
|
6436
6474
|
# Restore Termview under grid visibility state
|
|
6437
6475
|
if hasattr(self, 'bottom_tabs'):
|
|
6438
|
-
termview_visible = general_settings.get('termview_under_grid_visible',
|
|
6476
|
+
termview_visible = general_settings.get('termview_under_grid_visible', False)
|
|
6439
6477
|
self.bottom_tabs.setVisible(termview_visible)
|
|
6440
6478
|
if hasattr(self, 'termview_visible_action'):
|
|
6441
6479
|
self.termview_visible_action.setChecked(termview_visible)
|
|
@@ -7283,7 +7321,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
7283
7321
|
|
|
7284
7322
|
# Alt+K - Open QuickMenu directly
|
|
7285
7323
|
create_shortcut("editor_open_quickmenu", "Alt+K", self.open_quickmenu)
|
|
7286
|
-
|
|
7324
|
+
|
|
7325
|
+
# Ctrl+Shift+Q - MT Quick Lookup (GT4T-style popup)
|
|
7326
|
+
mt_quick_shortcut = create_shortcut("mt_quick_lookup", "Ctrl+Shift+Q", self.show_mt_quick_popup)
|
|
7327
|
+
# Use ApplicationShortcut context so it works even when focus is in QTextEdit widgets
|
|
7328
|
+
mt_quick_shortcut.setContext(Qt.ShortcutContext.ApplicationShortcut)
|
|
7329
|
+
|
|
7287
7330
|
def focus_segment_notes(self):
|
|
7288
7331
|
"""Switch to Segment Note tab and focus the notes editor so user can start typing immediately"""
|
|
7289
7332
|
if not hasattr(self, 'right_tabs'):
|
|
@@ -7355,7 +7398,105 @@ class SupervertalerQt(QMainWindow):
|
|
|
7355
7398
|
|
|
7356
7399
|
except Exception as e:
|
|
7357
7400
|
self.log(f"❌ Error opening QuickMenu: {e}")
|
|
7358
|
-
|
|
7401
|
+
|
|
7402
|
+
def show_mt_quick_popup(self, text_override: str = None):
|
|
7403
|
+
"""Show GT4T-style MT Quick Lookup popup with translations from all enabled MT engines.
|
|
7404
|
+
|
|
7405
|
+
Triggered by Ctrl+Shift+Q or right-click menu. Shows machine translation
|
|
7406
|
+
suggestions from all configured and enabled MT providers in a popup window.
|
|
7407
|
+
|
|
7408
|
+
Args:
|
|
7409
|
+
text_override: Optional text to translate. If None, uses selected text
|
|
7410
|
+
in the current cell, or falls back to the full source text.
|
|
7411
|
+
|
|
7412
|
+
Features:
|
|
7413
|
+
- Displays source text at top
|
|
7414
|
+
- Shows numbered list of MT suggestions from each provider
|
|
7415
|
+
- Press 1-9 to quickly insert a translation
|
|
7416
|
+
- Arrow keys to navigate, Enter to insert selected
|
|
7417
|
+
- Escape to dismiss
|
|
7418
|
+
"""
|
|
7419
|
+
try:
|
|
7420
|
+
# Get current segment
|
|
7421
|
+
current_row = self.table.currentRow()
|
|
7422
|
+
if current_row < 0:
|
|
7423
|
+
self.log("⚠️ No segment selected")
|
|
7424
|
+
return
|
|
7425
|
+
|
|
7426
|
+
# Determine what text to translate
|
|
7427
|
+
text_to_translate = text_override
|
|
7428
|
+
|
|
7429
|
+
if not text_to_translate:
|
|
7430
|
+
# Check for selected text in the currently focused widget
|
|
7431
|
+
focus_widget = QApplication.focusWidget()
|
|
7432
|
+
if focus_widget and hasattr(focus_widget, 'textCursor'):
|
|
7433
|
+
cursor = focus_widget.textCursor()
|
|
7434
|
+
if cursor.hasSelection():
|
|
7435
|
+
text_to_translate = cursor.selectedText().strip()
|
|
7436
|
+
|
|
7437
|
+
if not text_to_translate:
|
|
7438
|
+
# Fall back to full source text
|
|
7439
|
+
source_widget = self.table.cellWidget(current_row, 2)
|
|
7440
|
+
if not source_widget or not hasattr(source_widget, 'toPlainText'):
|
|
7441
|
+
self.log("⚠️ Could not get source text")
|
|
7442
|
+
return
|
|
7443
|
+
text_to_translate = source_widget.toPlainText().strip()
|
|
7444
|
+
|
|
7445
|
+
if not text_to_translate:
|
|
7446
|
+
self.log("⚠️ No text to translate")
|
|
7447
|
+
return
|
|
7448
|
+
|
|
7449
|
+
# Import and create the popup
|
|
7450
|
+
from modules.quicktrans import MTQuickPopup
|
|
7451
|
+
|
|
7452
|
+
# Create popup
|
|
7453
|
+
popup = MTQuickPopup(
|
|
7454
|
+
parent_app=self,
|
|
7455
|
+
source_text=text_to_translate,
|
|
7456
|
+
source_lang=getattr(self, 'source_language', 'en'),
|
|
7457
|
+
target_lang=getattr(self, 'target_language', 'nl'),
|
|
7458
|
+
parent=self
|
|
7459
|
+
)
|
|
7460
|
+
|
|
7461
|
+
# Connect signal to insert translation into target cell
|
|
7462
|
+
def insert_translation(translation: str):
|
|
7463
|
+
# Get the target widget
|
|
7464
|
+
target_widget = self.table.cellWidget(current_row, 3)
|
|
7465
|
+
if not target_widget or not hasattr(target_widget, 'toPlainText'):
|
|
7466
|
+
return
|
|
7467
|
+
|
|
7468
|
+
# Check if there was a selection in the target - replace just that
|
|
7469
|
+
focus_widget = QApplication.focusWidget()
|
|
7470
|
+
if focus_widget == target_widget and hasattr(focus_widget, 'textCursor'):
|
|
7471
|
+
cursor = focus_widget.textCursor()
|
|
7472
|
+
if cursor.hasSelection():
|
|
7473
|
+
# Replace selection only
|
|
7474
|
+
cursor.insertText(translation)
|
|
7475
|
+
self.log(f"✅ Replaced selection with MT translation")
|
|
7476
|
+
else:
|
|
7477
|
+
# No selection in target, replace entire target
|
|
7478
|
+
target_widget.setPlainText(translation)
|
|
7479
|
+
self.log(f"✅ Inserted MT translation")
|
|
7480
|
+
else:
|
|
7481
|
+
# Focus was elsewhere, replace entire target
|
|
7482
|
+
target_widget.setPlainText(translation)
|
|
7483
|
+
self.log(f"✅ Inserted MT translation")
|
|
7484
|
+
|
|
7485
|
+
# Mark segment as modified
|
|
7486
|
+
if hasattr(self, 'segments') and current_row < len(self.segments):
|
|
7487
|
+
self.segments[current_row].target = target_widget.toPlainText()
|
|
7488
|
+
self.mark_segment_modified(current_row)
|
|
7489
|
+
|
|
7490
|
+
popup.translation_selected.connect(insert_translation)
|
|
7491
|
+
|
|
7492
|
+
# Show the popup (it positions itself near cursor)
|
|
7493
|
+
popup.show()
|
|
7494
|
+
|
|
7495
|
+
except ImportError as e:
|
|
7496
|
+
self.log(f"❌ MT Quick Popup module not found: {e}")
|
|
7497
|
+
except Exception as e:
|
|
7498
|
+
self.log(f"❌ Error showing MT Quick Popup: {e}")
|
|
7499
|
+
|
|
7359
7500
|
def refresh_shortcut_enabled_states(self):
|
|
7360
7501
|
"""Refresh enabled/disabled states and key bindings of all global shortcuts from shortcut manager.
|
|
7361
7502
|
|
|
@@ -7991,7 +8132,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
7991
8132
|
edit_menu.addSeparator()
|
|
7992
8133
|
|
|
7993
8134
|
# Superlookup
|
|
7994
|
-
superlookup_action = QAction("🔍 &
|
|
8135
|
+
superlookup_action = QAction("🔍 &SuperLookup...", self)
|
|
7995
8136
|
superlookup_action.setShortcut("Ctrl+Alt+L")
|
|
7996
8137
|
# Tab indices: Grid=0, Project resources=1, Tools=2, Settings=3
|
|
7997
8138
|
superlookup_action.triggered.connect(lambda: self._go_to_superlookup() if hasattr(self, 'main_tabs') else None) # Navigate to Superlookup
|
|
@@ -8098,7 +8239,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
8098
8239
|
# Termview visibility toggle
|
|
8099
8240
|
self.termview_visible_action = QAction("🔍 &Termview Under Grid", self)
|
|
8100
8241
|
self.termview_visible_action.setCheckable(True)
|
|
8101
|
-
self.termview_visible_action.setChecked(
|
|
8242
|
+
self.termview_visible_action.setChecked(False) # Default: hidden (restored from settings if enabled)
|
|
8102
8243
|
self.termview_visible_action.triggered.connect(self.toggle_termview_under_grid)
|
|
8103
8244
|
self.termview_visible_action.setToolTip("Show/hide the Termview panel under the grid")
|
|
8104
8245
|
view_menu.addAction(self.termview_visible_action)
|
|
@@ -10138,7 +10279,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
10138
10279
|
|
|
10139
10280
|
# Create detached window
|
|
10140
10281
|
self.lookup_detached_window = QDialog(self)
|
|
10141
|
-
self.lookup_detached_window.setWindowTitle("🔍
|
|
10282
|
+
self.lookup_detached_window.setWindowTitle("🔍 SuperLookup - Supervertaler")
|
|
10142
10283
|
self.lookup_detached_window.setMinimumSize(600, 700)
|
|
10143
10284
|
self.lookup_detached_window.resize(700, 800)
|
|
10144
10285
|
|
|
@@ -10192,7 +10333,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
10192
10333
|
# Header with reattach button
|
|
10193
10334
|
header_layout = QVBoxLayout()
|
|
10194
10335
|
|
|
10195
|
-
header_title = QLabel("🔍
|
|
10336
|
+
header_title = QLabel("🔍 SuperLookup")
|
|
10196
10337
|
header_title.setStyleSheet("font-size: 16px; font-weight: bold; color: #333;")
|
|
10197
10338
|
header_layout.addWidget(header_title)
|
|
10198
10339
|
|
|
@@ -10346,7 +10487,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
10346
10487
|
|
|
10347
10488
|
lookup_tab = SuperlookupTab(self, user_data_path=self.user_data_path)
|
|
10348
10489
|
self.lookup_tab = lookup_tab # Store reference for later use
|
|
10349
|
-
modules_tabs.addTab(lookup_tab, "🔍
|
|
10490
|
+
modules_tabs.addTab(lookup_tab, "🔍 SuperLookup")
|
|
10350
10491
|
|
|
10351
10492
|
# Supervoice - Voice Commands & Dictation
|
|
10352
10493
|
supervoice_tab = self._create_voice_dictation_settings_tab()
|
|
@@ -14995,7 +15136,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
14995
15136
|
|
|
14996
15137
|
# Delete selected term button
|
|
14997
15138
|
delete_term_btn = QPushButton("🗑️ Delete Selected Term")
|
|
14998
|
-
delete_term_btn.setStyleSheet("background-color: #f44336; color: white; font-weight: bold;")
|
|
15139
|
+
delete_term_btn.setStyleSheet("background-color: #f44336; color: white; font-weight: bold; padding: 3px 5px;")
|
|
14999
15140
|
def delete_selected_term():
|
|
15000
15141
|
selected_row = terms_table.currentRow()
|
|
15001
15142
|
if selected_row < 0:
|
|
@@ -15669,8 +15810,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
15669
15810
|
# ===== TAB 4: MT Settings =====
|
|
15670
15811
|
mt_tab = self._create_mt_settings_tab()
|
|
15671
15812
|
settings_tabs.addTab(scroll_area_wrapper(mt_tab), "🌐 MT Settings")
|
|
15672
|
-
|
|
15673
|
-
# ===== TAB 5:
|
|
15813
|
+
|
|
15814
|
+
# ===== TAB 5: MT Quick Lookup Settings =====
|
|
15815
|
+
mt_quick_tab = self._create_mt_quick_lookup_settings_tab()
|
|
15816
|
+
settings_tabs.addTab(scroll_area_wrapper(mt_quick_tab), "⚡ QuickTrans")
|
|
15817
|
+
self.mt_quick_lookup_tab_index = settings_tabs.count() - 1 # Store index for opening
|
|
15818
|
+
|
|
15819
|
+
# ===== TAB 6: View Settings =====
|
|
15674
15820
|
view_tab = self._create_view_settings_tab()
|
|
15675
15821
|
settings_tabs.addTab(scroll_area_wrapper(view_tab), "🔍 View Settings")
|
|
15676
15822
|
|
|
@@ -16478,9 +16624,199 @@ class SupervertalerQt(QMainWindow):
|
|
|
16478
16624
|
layout.addWidget(save_btn)
|
|
16479
16625
|
|
|
16480
16626
|
layout.addStretch()
|
|
16481
|
-
|
|
16627
|
+
|
|
16482
16628
|
return tab
|
|
16483
|
-
|
|
16629
|
+
|
|
16630
|
+
def _create_mt_quick_lookup_settings_tab(self):
|
|
16631
|
+
"""Create MT Quick Lookup settings tab content"""
|
|
16632
|
+
from PyQt6.QtWidgets import QCheckBox, QGroupBox, QPushButton, QComboBox
|
|
16633
|
+
|
|
16634
|
+
tab = QWidget()
|
|
16635
|
+
layout = QVBoxLayout(tab)
|
|
16636
|
+
layout.setContentsMargins(20, 20, 20, 20)
|
|
16637
|
+
layout.setSpacing(15)
|
|
16638
|
+
|
|
16639
|
+
# Load current settings
|
|
16640
|
+
general_settings = self.load_general_settings()
|
|
16641
|
+
mt_quick_settings = general_settings.get('mt_quick_lookup', {})
|
|
16642
|
+
api_keys = self.load_api_keys()
|
|
16643
|
+
enabled_providers = self.load_provider_enabled_states()
|
|
16644
|
+
|
|
16645
|
+
# Header info
|
|
16646
|
+
header_info = QLabel(
|
|
16647
|
+
"⚡ <b>QuickTrans</b> - Configure which providers appear in the QuickTrans popup (Ctrl+M / Ctrl+Alt+M).<br>"
|
|
16648
|
+
"Enable MT engines and/or LLMs to get instant translation suggestions."
|
|
16649
|
+
)
|
|
16650
|
+
header_info.setTextFormat(Qt.TextFormat.RichText)
|
|
16651
|
+
header_info.setStyleSheet("font-size: 9pt; color: #444; padding: 10px; background-color: #E3F2FD; border-radius: 4px;")
|
|
16652
|
+
header_info.setWordWrap(True)
|
|
16653
|
+
layout.addWidget(header_info)
|
|
16654
|
+
|
|
16655
|
+
# ===== MT Providers Group =====
|
|
16656
|
+
mt_group = QGroupBox("🌐 Machine Translation Providers")
|
|
16657
|
+
mt_layout = QVBoxLayout()
|
|
16658
|
+
|
|
16659
|
+
mt_info = QLabel("Select which MT engines to query. Only enabled providers with valid API keys are shown.")
|
|
16660
|
+
mt_info.setWordWrap(True)
|
|
16661
|
+
mt_info.setStyleSheet("font-size: 8pt; color: #666; padding-bottom: 8px;")
|
|
16662
|
+
mt_layout.addWidget(mt_info)
|
|
16663
|
+
|
|
16664
|
+
# MT provider checkboxes
|
|
16665
|
+
self._mtql_checkboxes = {}
|
|
16666
|
+
|
|
16667
|
+
mt_providers = [
|
|
16668
|
+
("gt", "Google Translate", "mt_google_translate", "google_translate"),
|
|
16669
|
+
("dl", "DeepL", "mt_deepl", "deepl"),
|
|
16670
|
+
("ms", "Microsoft Translator", "mt_microsoft", "microsoft_translate"),
|
|
16671
|
+
("at", "Amazon Translate", "mt_amazon", "amazon_translate"),
|
|
16672
|
+
("mmt", "ModernMT", "mt_modernmt", "modernmt"),
|
|
16673
|
+
("mm", "MyMemory (Free)", "mt_mymemory", None),
|
|
16674
|
+
]
|
|
16675
|
+
|
|
16676
|
+
for code, name, enabled_key, api_key_name in mt_providers:
|
|
16677
|
+
# Check if provider is available (has API key or doesn't need one)
|
|
16678
|
+
has_key = api_key_name is None or bool(api_keys.get(api_key_name))
|
|
16679
|
+
is_enabled_globally = enabled_providers.get(enabled_key, True)
|
|
16680
|
+
|
|
16681
|
+
checkbox = CheckmarkCheckBox(name)
|
|
16682
|
+
# Default: use global MT enabled state
|
|
16683
|
+
checkbox.setChecked(mt_quick_settings.get(f"mtql_{code}", is_enabled_globally and has_key))
|
|
16684
|
+
checkbox.setEnabled(has_key)
|
|
16685
|
+
|
|
16686
|
+
if not has_key:
|
|
16687
|
+
checkbox.setToolTip(f"API key not configured for {name}")
|
|
16688
|
+
checkbox.setStyleSheet("color: #999;")
|
|
16689
|
+
else:
|
|
16690
|
+
checkbox.setToolTip(f"Include {name} in QuickTrans results")
|
|
16691
|
+
|
|
16692
|
+
self._mtql_checkboxes[f"mtql_{code}"] = checkbox
|
|
16693
|
+
mt_layout.addWidget(checkbox)
|
|
16694
|
+
|
|
16695
|
+
mt_group.setLayout(mt_layout)
|
|
16696
|
+
layout.addWidget(mt_group)
|
|
16697
|
+
|
|
16698
|
+
# ===== LLM Providers Group =====
|
|
16699
|
+
llm_group = QGroupBox("🤖 AI/LLM Providers")
|
|
16700
|
+
llm_layout = QVBoxLayout()
|
|
16701
|
+
|
|
16702
|
+
llm_info = QLabel(
|
|
16703
|
+
"Enable AI models for translation suggestions. LLMs may provide more context-aware translations but are slower.<br>"
|
|
16704
|
+
"<b>Note:</b> LLM calls cost more than MT APIs. Use sparingly for quick lookups."
|
|
16705
|
+
)
|
|
16706
|
+
llm_info.setTextFormat(Qt.TextFormat.RichText)
|
|
16707
|
+
llm_info.setWordWrap(True)
|
|
16708
|
+
llm_info.setStyleSheet("font-size: 8pt; color: #666; padding-bottom: 8px;")
|
|
16709
|
+
llm_layout.addWidget(llm_info)
|
|
16710
|
+
|
|
16711
|
+
# LLM provider checkboxes with model selection
|
|
16712
|
+
self._mtql_llm_combos = {}
|
|
16713
|
+
|
|
16714
|
+
llm_providers = [
|
|
16715
|
+
("claude", "Claude", "claude", [
|
|
16716
|
+
("claude-sonnet-4-5-20250929", "Claude Sonnet 4.5 (Recommended)"),
|
|
16717
|
+
("claude-haiku-4-5-20251001", "Claude Haiku 4.5 (Fast)"),
|
|
16718
|
+
("claude-opus-4-1-20250924", "Claude Opus 4.1 (Premium)"),
|
|
16719
|
+
]),
|
|
16720
|
+
("openai", "OpenAI", "openai", [
|
|
16721
|
+
("gpt-4o", "GPT-4o (Recommended)"),
|
|
16722
|
+
("gpt-4o-mini", "GPT-4o Mini (Fast)"),
|
|
16723
|
+
("gpt-4-turbo", "GPT-4 Turbo"),
|
|
16724
|
+
("o1", "o1 (Reasoning)"),
|
|
16725
|
+
]),
|
|
16726
|
+
("gemini", "Gemini", "gemini", [
|
|
16727
|
+
("gemini-2.5-flash", "Gemini 2.5 Flash (Recommended)"),
|
|
16728
|
+
("gemini-2.5-pro", "Gemini 2.5 Pro"),
|
|
16729
|
+
("gemini-2.0-flash", "Gemini 2.0 Flash"),
|
|
16730
|
+
]),
|
|
16731
|
+
]
|
|
16732
|
+
|
|
16733
|
+
for code, name, api_key_name, models in llm_providers:
|
|
16734
|
+
has_key = bool(api_keys.get(api_key_name))
|
|
16735
|
+
|
|
16736
|
+
# Container for checkbox and model combo
|
|
16737
|
+
llm_row = QHBoxLayout()
|
|
16738
|
+
|
|
16739
|
+
checkbox = CheckmarkCheckBox(name)
|
|
16740
|
+
# Default: disabled (LLMs are opt-in)
|
|
16741
|
+
checkbox.setChecked(mt_quick_settings.get(f"mtql_{code}", False))
|
|
16742
|
+
checkbox.setEnabled(has_key)
|
|
16743
|
+
|
|
16744
|
+
if not has_key:
|
|
16745
|
+
checkbox.setToolTip(f"API key not configured for {name}. Add it in AI Settings.")
|
|
16746
|
+
checkbox.setStyleSheet("color: #999;")
|
|
16747
|
+
else:
|
|
16748
|
+
checkbox.setToolTip(f"Include {name} translations in QuickTrans")
|
|
16749
|
+
|
|
16750
|
+
self._mtql_checkboxes[f"mtql_{code}"] = checkbox
|
|
16751
|
+
llm_row.addWidget(checkbox)
|
|
16752
|
+
|
|
16753
|
+
# Model selection combo
|
|
16754
|
+
model_combo = QComboBox()
|
|
16755
|
+
model_combo.setMinimumWidth(200)
|
|
16756
|
+
for model_id, model_name in models:
|
|
16757
|
+
model_combo.addItem(model_name, model_id)
|
|
16758
|
+
|
|
16759
|
+
# Restore saved model selection
|
|
16760
|
+
saved_model = mt_quick_settings.get(f"mtql_{code}_model")
|
|
16761
|
+
if saved_model:
|
|
16762
|
+
idx = model_combo.findData(saved_model)
|
|
16763
|
+
if idx >= 0:
|
|
16764
|
+
model_combo.setCurrentIndex(idx)
|
|
16765
|
+
|
|
16766
|
+
model_combo.setEnabled(has_key)
|
|
16767
|
+
self._mtql_llm_combos[f"mtql_{code}_model"] = model_combo
|
|
16768
|
+
llm_row.addWidget(model_combo)
|
|
16769
|
+
|
|
16770
|
+
llm_row.addStretch()
|
|
16771
|
+
llm_layout.addLayout(llm_row)
|
|
16772
|
+
|
|
16773
|
+
llm_group.setLayout(llm_layout)
|
|
16774
|
+
layout.addWidget(llm_group)
|
|
16775
|
+
|
|
16776
|
+
# Save button
|
|
16777
|
+
save_btn = QPushButton("💾 Save QuickTrans Settings")
|
|
16778
|
+
save_btn.setStyleSheet("font-weight: bold; padding: 8px;")
|
|
16779
|
+
save_btn.clicked.connect(self._save_mt_quick_lookup_settings)
|
|
16780
|
+
layout.addWidget(save_btn)
|
|
16781
|
+
|
|
16782
|
+
layout.addStretch()
|
|
16783
|
+
|
|
16784
|
+
return tab
|
|
16785
|
+
|
|
16786
|
+
def _save_mt_quick_lookup_settings(self):
|
|
16787
|
+
"""Save MT Quick Lookup settings"""
|
|
16788
|
+
general_settings = self.load_general_settings()
|
|
16789
|
+
|
|
16790
|
+
mt_quick_settings = {}
|
|
16791
|
+
|
|
16792
|
+
# Save MT provider states
|
|
16793
|
+
for key, checkbox in self._mtql_checkboxes.items():
|
|
16794
|
+
mt_quick_settings[key] = checkbox.isChecked()
|
|
16795
|
+
|
|
16796
|
+
# Save LLM model selections
|
|
16797
|
+
for key, combo in self._mtql_llm_combos.items():
|
|
16798
|
+
mt_quick_settings[key] = combo.currentData()
|
|
16799
|
+
|
|
16800
|
+
general_settings['mt_quick_lookup'] = mt_quick_settings
|
|
16801
|
+
self.save_general_settings(general_settings)
|
|
16802
|
+
|
|
16803
|
+
self.log("✓ QuickTrans settings saved")
|
|
16804
|
+
QMessageBox.information(self, "Settings Saved", "QuickTrans settings have been saved.")
|
|
16805
|
+
|
|
16806
|
+
def open_mt_quick_lookup_settings(self):
|
|
16807
|
+
"""Open Settings and navigate to MT Quick Lookup tab"""
|
|
16808
|
+
# Switch to Settings tab
|
|
16809
|
+
if hasattr(self, 'main_tabs'):
|
|
16810
|
+
# Find Settings tab index
|
|
16811
|
+
for i in range(self.main_tabs.count()):
|
|
16812
|
+
if "Settings" in self.main_tabs.tabText(i):
|
|
16813
|
+
self.main_tabs.setCurrentIndex(i)
|
|
16814
|
+
break
|
|
16815
|
+
|
|
16816
|
+
# Navigate to MT Quick Lookup sub-tab
|
|
16817
|
+
if hasattr(self, 'settings_tabs') and hasattr(self, 'mt_quick_lookup_tab_index'):
|
|
16818
|
+
self.settings_tabs.setCurrentIndex(self.mt_quick_lookup_tab_index)
|
|
16819
|
+
|
|
16484
16820
|
def _find_autohotkey_for_settings(self):
|
|
16485
16821
|
"""Find AutoHotkey executable for settings display (doesn't modify state)"""
|
|
16486
16822
|
# Standard installation paths
|
|
@@ -17971,14 +18307,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
17971
18307
|
|
|
17972
18308
|
def _create_voice_dictation_settings_tab(self):
|
|
17973
18309
|
"""Create Supervoice Settings tab content with Voice Commands"""
|
|
17974
|
-
from PyQt6.QtWidgets import (QGroupBox, QPushButton, QComboBox, QSpinBox,
|
|
18310
|
+
from PyQt6.QtWidgets import (QGroupBox, QPushButton, QComboBox, QSpinBox,
|
|
17975
18311
|
QTableWidget, QTableWidgetItem, QHeaderView,
|
|
17976
|
-
QAbstractItemView, QCheckBox)
|
|
18312
|
+
QAbstractItemView, QCheckBox, QSplitter)
|
|
18313
|
+
from modules.keyboard_shortcuts_widget import CheckmarkCheckBox
|
|
17977
18314
|
|
|
17978
18315
|
tab = QWidget()
|
|
17979
|
-
|
|
17980
|
-
|
|
17981
|
-
|
|
18316
|
+
main_layout = QVBoxLayout(tab)
|
|
18317
|
+
main_layout.setContentsMargins(20, 20, 20, 20)
|
|
18318
|
+
main_layout.setSpacing(15)
|
|
17982
18319
|
|
|
17983
18320
|
# Load current dictation settings
|
|
17984
18321
|
dictation_settings = self.load_dictation_settings()
|
|
@@ -17991,19 +18328,33 @@ class SupervertalerQt(QMainWindow):
|
|
|
17991
18328
|
header_info.setTextFormat(Qt.TextFormat.RichText)
|
|
17992
18329
|
header_info.setStyleSheet("font-size: 9pt; color: #444; padding: 10px; background-color: #E3F2FD; border-radius: 4px;")
|
|
17993
18330
|
header_info.setWordWrap(True)
|
|
17994
|
-
|
|
18331
|
+
main_layout.addWidget(header_info)
|
|
17995
18332
|
|
|
17996
|
-
# ===== Voice Commands
|
|
17997
|
-
|
|
17998
|
-
|
|
18333
|
+
# ===== Two-column layout: Left = Settings, Right = Voice Commands Table =====
|
|
18334
|
+
columns_layout = QHBoxLayout()
|
|
18335
|
+
columns_layout.setSpacing(15)
|
|
18336
|
+
|
|
18337
|
+
# --- LEFT COLUMN: Settings ---
|
|
18338
|
+
left_column = QVBoxLayout()
|
|
18339
|
+
left_column.setSpacing(15)
|
|
17999
18340
|
|
|
18000
|
-
# Enable voice commands checkbox
|
|
18001
|
-
voice_cmd_enabled =
|
|
18341
|
+
# Enable voice commands checkbox (green checkmark style)
|
|
18342
|
+
voice_cmd_enabled = CheckmarkCheckBox("Enable voice commands (spoken phrases trigger actions)")
|
|
18002
18343
|
voice_cmd_enabled.setChecked(dictation_settings.get('voice_commands_enabled', True))
|
|
18003
18344
|
voice_cmd_enabled.setToolTip("When enabled, spoken phrases like 'confirm' or 'next segment' will execute commands instead of being inserted as text")
|
|
18004
|
-
|
|
18345
|
+
left_column.addWidget(voice_cmd_enabled)
|
|
18005
18346
|
self.voice_commands_enabled_checkbox = voice_cmd_enabled
|
|
18006
18347
|
|
|
18348
|
+
# Create a layout variable for settings sections to be added below
|
|
18349
|
+
layout = left_column
|
|
18350
|
+
|
|
18351
|
+
# --- RIGHT COLUMN: Voice Commands Table ---
|
|
18352
|
+
right_column = QVBoxLayout()
|
|
18353
|
+
right_column.setSpacing(10)
|
|
18354
|
+
|
|
18355
|
+
commands_group = QGroupBox("🗣️ Voice Commands (Talon-style)")
|
|
18356
|
+
commands_layout = QVBoxLayout()
|
|
18357
|
+
|
|
18007
18358
|
commands_info = QLabel(
|
|
18008
18359
|
"Voice commands let you control Supervertaler by voice. Say a phrase to execute an action.\n"
|
|
18009
18360
|
"If no command matches, the spoken text is inserted as dictation."
|
|
@@ -18022,38 +18373,47 @@ class SupervertalerQt(QMainWindow):
|
|
|
18022
18373
|
self.voice_commands_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
|
|
18023
18374
|
self.voice_commands_table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
18024
18375
|
self.voice_commands_table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
|
18025
|
-
self.voice_commands_table.setMinimumHeight(
|
|
18026
|
-
|
|
18027
|
-
|
|
18376
|
+
self.voice_commands_table.setMinimumHeight(350)
|
|
18377
|
+
|
|
18028
18378
|
# Populate table with current commands
|
|
18029
18379
|
self._populate_voice_commands_table()
|
|
18030
18380
|
commands_layout.addWidget(self.voice_commands_table)
|
|
18031
18381
|
|
|
18032
18382
|
# Command buttons
|
|
18033
18383
|
cmd_btn_layout = QHBoxLayout()
|
|
18034
|
-
|
|
18035
|
-
add_cmd_btn = QPushButton("➕ Add
|
|
18384
|
+
|
|
18385
|
+
add_cmd_btn = QPushButton("➕ Add")
|
|
18036
18386
|
add_cmd_btn.clicked.connect(self._add_voice_command)
|
|
18037
18387
|
cmd_btn_layout.addWidget(add_cmd_btn)
|
|
18038
|
-
|
|
18039
|
-
edit_cmd_btn = QPushButton("✏️ Edit
|
|
18388
|
+
|
|
18389
|
+
edit_cmd_btn = QPushButton("✏️ Edit")
|
|
18040
18390
|
edit_cmd_btn.clicked.connect(self._edit_voice_command)
|
|
18041
18391
|
cmd_btn_layout.addWidget(edit_cmd_btn)
|
|
18042
|
-
|
|
18043
|
-
remove_cmd_btn = QPushButton("🗑️ Remove
|
|
18392
|
+
|
|
18393
|
+
remove_cmd_btn = QPushButton("🗑️ Remove")
|
|
18044
18394
|
remove_cmd_btn.clicked.connect(self._remove_voice_command)
|
|
18045
18395
|
cmd_btn_layout.addWidget(remove_cmd_btn)
|
|
18046
|
-
|
|
18396
|
+
|
|
18047
18397
|
cmd_btn_layout.addStretch()
|
|
18048
|
-
|
|
18049
|
-
reset_cmd_btn = QPushButton("🔄 Reset
|
|
18398
|
+
|
|
18399
|
+
reset_cmd_btn = QPushButton("🔄 Reset")
|
|
18050
18400
|
reset_cmd_btn.clicked.connect(self._reset_voice_commands)
|
|
18051
18401
|
cmd_btn_layout.addWidget(reset_cmd_btn)
|
|
18052
|
-
|
|
18402
|
+
|
|
18053
18403
|
commands_layout.addLayout(cmd_btn_layout)
|
|
18054
18404
|
|
|
18055
18405
|
commands_group.setLayout(commands_layout)
|
|
18056
|
-
|
|
18406
|
+
right_column.addWidget(commands_group)
|
|
18407
|
+
right_column.addStretch()
|
|
18408
|
+
|
|
18409
|
+
# Add columns to the two-column layout
|
|
18410
|
+
left_widget = QWidget()
|
|
18411
|
+
left_widget.setLayout(left_column)
|
|
18412
|
+
right_widget = QWidget()
|
|
18413
|
+
right_widget.setLayout(right_column)
|
|
18414
|
+
|
|
18415
|
+
columns_layout.addWidget(left_widget, stretch=1)
|
|
18416
|
+
columns_layout.addWidget(right_widget, stretch=1)
|
|
18057
18417
|
|
|
18058
18418
|
# ===== Always-On Mode Section =====
|
|
18059
18419
|
alwayson_group = QGroupBox("🎧 Always-On Listening Mode")
|
|
@@ -18216,7 +18576,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
18216
18576
|
ahk_group.setLayout(ahk_layout)
|
|
18217
18577
|
layout.addWidget(ahk_group)
|
|
18218
18578
|
|
|
18219
|
-
#
|
|
18579
|
+
# Add stretch to left column to push content up
|
|
18580
|
+
layout.addStretch()
|
|
18581
|
+
|
|
18582
|
+
# Add two-column layout to main layout
|
|
18583
|
+
main_layout.addLayout(columns_layout, stretch=1)
|
|
18584
|
+
|
|
18585
|
+
# Save button (full width, below the two columns)
|
|
18220
18586
|
save_btn = QPushButton("💾 Save Supervoice Settings")
|
|
18221
18587
|
save_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 10px; border: none; outline: none;")
|
|
18222
18588
|
save_btn.clicked.connect(lambda: self._save_voice_settings(
|
|
@@ -18225,15 +18591,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
18225
18591
|
lang_combo.currentText(),
|
|
18226
18592
|
voice_cmd_enabled.isChecked()
|
|
18227
18593
|
))
|
|
18228
|
-
|
|
18594
|
+
main_layout.addWidget(save_btn)
|
|
18229
18595
|
|
|
18230
18596
|
# Store references
|
|
18231
18597
|
self.dictation_model_combo = model_combo
|
|
18232
18598
|
self.dictation_duration_spin = duration_spin
|
|
18233
18599
|
self.dictation_lang_combo = lang_combo
|
|
18234
18600
|
|
|
18235
|
-
layout.addStretch()
|
|
18236
|
-
|
|
18237
18601
|
return tab
|
|
18238
18602
|
|
|
18239
18603
|
def _populate_voice_commands_table(self):
|
|
@@ -18487,7 +18851,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
18487
18851
|
background-color: #2E7D32;
|
|
18488
18852
|
color: white;
|
|
18489
18853
|
font-weight: bold;
|
|
18490
|
-
padding:
|
|
18854
|
+
padding: 3px 5px;
|
|
18491
18855
|
border-radius: 3px;
|
|
18492
18856
|
}
|
|
18493
18857
|
QPushButton:checked {
|
|
@@ -18501,7 +18865,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
18501
18865
|
background-color: #C62828;
|
|
18502
18866
|
color: white;
|
|
18503
18867
|
font-weight: bold;
|
|
18504
|
-
padding:
|
|
18868
|
+
padding: 3px 5px;
|
|
18505
18869
|
border-radius: 3px;
|
|
18506
18870
|
}
|
|
18507
18871
|
QPushButton:checked {
|
|
@@ -18515,7 +18879,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
18515
18879
|
background-color: #F57C00;
|
|
18516
18880
|
color: white;
|
|
18517
18881
|
font-weight: bold;
|
|
18518
|
-
padding:
|
|
18882
|
+
padding: 3px 5px;
|
|
18519
18883
|
border-radius: 3px;
|
|
18520
18884
|
}
|
|
18521
18885
|
QPushButton:checked {
|
|
@@ -18530,7 +18894,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
18530
18894
|
background-color: #757575;
|
|
18531
18895
|
color: white;
|
|
18532
18896
|
font-weight: bold;
|
|
18533
|
-
padding:
|
|
18897
|
+
padding: 3px 5px;
|
|
18534
18898
|
border-radius: 3px;
|
|
18535
18899
|
}
|
|
18536
18900
|
QPushButton:checked {
|
|
@@ -19864,6 +20228,27 @@ class SupervertalerQt(QMainWindow):
|
|
|
19864
20228
|
grid_font_family_combo=None, termview_font_family_combo=None, termview_font_spin=None, termview_bold_check=None,
|
|
19865
20229
|
border_color_btn=None, border_thickness_spin=None, badge_text_color_btn=None, tabs_above_check=None):
|
|
19866
20230
|
"""Save view settings from UI"""
|
|
20231
|
+
# CRITICAL: Suppress TM saves during view settings update
|
|
20232
|
+
# Grid operations (setStyleSheet, rehighlight, etc.) can trigger textChanged events
|
|
20233
|
+
# which would cause mass TM saves for all confirmed segments
|
|
20234
|
+
previous_suppression = getattr(self, '_suppress_target_change_handlers', False)
|
|
20235
|
+
self._suppress_target_change_handlers = True
|
|
20236
|
+
|
|
20237
|
+
try:
|
|
20238
|
+
self._save_view_settings_from_ui_impl(
|
|
20239
|
+
grid_spin, match_spin, compare_spin, show_tags_check, tag_color_btn,
|
|
20240
|
+
alt_colors_check, even_color_btn, odd_color_btn, invisible_char_color_btn,
|
|
20241
|
+
grid_font_family_combo, termview_font_family_combo, termview_font_spin, termview_bold_check,
|
|
20242
|
+
border_color_btn, border_thickness_spin, badge_text_color_btn, tabs_above_check
|
|
20243
|
+
)
|
|
20244
|
+
finally:
|
|
20245
|
+
self._suppress_target_change_handlers = previous_suppression
|
|
20246
|
+
|
|
20247
|
+
def _save_view_settings_from_ui_impl(self, grid_spin, match_spin, compare_spin, show_tags_check=None, tag_color_btn=None,
|
|
20248
|
+
alt_colors_check=None, even_color_btn=None, odd_color_btn=None, invisible_char_color_btn=None,
|
|
20249
|
+
grid_font_family_combo=None, termview_font_family_combo=None, termview_font_spin=None, termview_bold_check=None,
|
|
20250
|
+
border_color_btn=None, border_thickness_spin=None, badge_text_color_btn=None, tabs_above_check=None):
|
|
20251
|
+
"""Implementation of save view settings (called with TM saves suppressed)"""
|
|
19867
20252
|
general_settings = {
|
|
19868
20253
|
'restore_last_project': self.load_general_settings().get('restore_last_project', False),
|
|
19869
20254
|
'auto_propagate_exact_matches': self.auto_propagate_exact_matches, # Keep existing value
|
|
@@ -20034,8 +20419,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
20034
20419
|
if invisible_char_color_btn and hasattr(self, 'table') and self.table is not None:
|
|
20035
20420
|
invisible_char_color = invisible_char_color_btn.property('selected_color')
|
|
20036
20421
|
if invisible_char_color:
|
|
20037
|
-
# Update all cell highlighters
|
|
20422
|
+
# Update all cell highlighters (with processEvents to keep UI responsive)
|
|
20038
20423
|
for row in range(self.table.rowCount()):
|
|
20424
|
+
if row % 50 == 0:
|
|
20425
|
+
QApplication.processEvents()
|
|
20039
20426
|
for col in [2, 3]: # Source and target columns
|
|
20040
20427
|
widget = self.table.cellWidget(row, col)
|
|
20041
20428
|
if widget and hasattr(widget, 'highlighter'):
|
|
@@ -20047,8 +20434,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
20047
20434
|
border_color = EditableGridTextEditor.focus_border_color
|
|
20048
20435
|
border_thickness = EditableGridTextEditor.focus_border_thickness
|
|
20049
20436
|
self.log(f"Applying focus border: color={border_color}, thickness={border_thickness}px")
|
|
20050
|
-
|
|
20437
|
+
|
|
20051
20438
|
for row in range(self.table.rowCount()):
|
|
20439
|
+
if row % 50 == 0:
|
|
20440
|
+
QApplication.processEvents()
|
|
20052
20441
|
widget = self.table.cellWidget(row, 3) # Target column
|
|
20053
20442
|
if widget and isinstance(widget, EditableGridTextEditor):
|
|
20054
20443
|
# Update the stylesheet with new border settings
|
|
@@ -20154,7 +20543,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20154
20543
|
filter_layout.setSpacing(10)
|
|
20155
20544
|
|
|
20156
20545
|
# Source filter
|
|
20157
|
-
source_filter_label = QLabel("
|
|
20546
|
+
source_filter_label = QLabel("Source:")
|
|
20158
20547
|
self.source_filter = self._ensure_shared_filter(
|
|
20159
20548
|
'source_filter',
|
|
20160
20549
|
"Type to filter source segments...",
|
|
@@ -20163,7 +20552,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20163
20552
|
)
|
|
20164
20553
|
|
|
20165
20554
|
# Target filter
|
|
20166
|
-
target_filter_label = QLabel("
|
|
20555
|
+
target_filter_label = QLabel("Target:")
|
|
20167
20556
|
self.target_filter = self._ensure_shared_filter(
|
|
20168
20557
|
'target_filter',
|
|
20169
20558
|
"Type to filter target segments...",
|
|
@@ -20175,11 +20564,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
20175
20564
|
clear_filters_btn = QPushButton("Clear Filters")
|
|
20176
20565
|
clear_filters_btn.clicked.connect(self.clear_filters)
|
|
20177
20566
|
clear_filters_btn.setMaximumWidth(100)
|
|
20567
|
+
clear_filters_btn.setStyleSheet("padding: 3px 5px;")
|
|
20178
20568
|
|
|
20179
20569
|
# Show Invisibles button with dropdown menu
|
|
20180
20570
|
show_invisibles_btn = QPushButton("¶ Show Invisibles")
|
|
20181
20571
|
show_invisibles_btn.setMaximumWidth(140)
|
|
20182
|
-
show_invisibles_btn.setStyleSheet("background-color: #607D8B; color: white; font-weight: bold;")
|
|
20572
|
+
show_invisibles_btn.setStyleSheet("background-color: #607D8B; color: white; font-weight: bold; padding: 3px 5px;")
|
|
20183
20573
|
show_invisibles_menu = QMenu(show_invisibles_btn)
|
|
20184
20574
|
|
|
20185
20575
|
# Create checkable actions for each invisible character type
|
|
@@ -20304,7 +20694,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20304
20694
|
filter_layout.setSpacing(10)
|
|
20305
20695
|
|
|
20306
20696
|
# Source filter
|
|
20307
|
-
source_filter_label = QLabel("
|
|
20697
|
+
source_filter_label = QLabel("Source:")
|
|
20308
20698
|
self.source_filter = self._ensure_shared_filter(
|
|
20309
20699
|
'source_filter',
|
|
20310
20700
|
"Type to filter source segments... (Press Enter or click Filter)",
|
|
@@ -20312,7 +20702,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20312
20702
|
)
|
|
20313
20703
|
|
|
20314
20704
|
# Target filter
|
|
20315
|
-
target_filter_label = QLabel("
|
|
20705
|
+
target_filter_label = QLabel("Target:")
|
|
20316
20706
|
self.target_filter = self._ensure_shared_filter(
|
|
20317
20707
|
'target_filter',
|
|
20318
20708
|
"Type to filter target segments... (Press Enter or click Filter)",
|
|
@@ -20323,17 +20713,18 @@ class SupervertalerQt(QMainWindow):
|
|
|
20323
20713
|
apply_filter_btn = QPushButton("Filter")
|
|
20324
20714
|
apply_filter_btn.clicked.connect(self.apply_filters)
|
|
20325
20715
|
apply_filter_btn.setMaximumWidth(80)
|
|
20326
|
-
apply_filter_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold;")
|
|
20716
|
+
apply_filter_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 3px 5px;")
|
|
20327
20717
|
|
|
20328
20718
|
# Clear filters button
|
|
20329
20719
|
clear_filters_btn = QPushButton("Clear Filters")
|
|
20330
20720
|
clear_filters_btn.clicked.connect(self.clear_filters)
|
|
20331
20721
|
clear_filters_btn.setMaximumWidth(100)
|
|
20722
|
+
clear_filters_btn.setStyleSheet("padding: 3px 5px;")
|
|
20332
20723
|
|
|
20333
20724
|
# Quick Filters dropdown menu
|
|
20334
20725
|
quick_filter_btn = QPushButton("⚡ Quick Filters")
|
|
20335
20726
|
quick_filter_btn.setMaximumWidth(130)
|
|
20336
|
-
quick_filter_btn.setStyleSheet("background-color: #D84315; color: white; font-weight: bold;")
|
|
20727
|
+
quick_filter_btn.setStyleSheet("background-color: #D84315; color: white; font-weight: bold; padding: 3px 5px;")
|
|
20337
20728
|
quick_filter_menu = QMenu(self)
|
|
20338
20729
|
quick_filter_menu.addAction("🔍 Empty segments", lambda: self.apply_quick_filter("empty"))
|
|
20339
20730
|
quick_filter_menu.addAction("❌ Not translated", lambda: self.apply_quick_filter("not_translated"))
|
|
@@ -20347,12 +20738,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
20347
20738
|
advanced_filter_btn = QPushButton("⚙️ Advanced Filters")
|
|
20348
20739
|
advanced_filter_btn.clicked.connect(self.show_advanced_filters_dialog)
|
|
20349
20740
|
advanced_filter_btn.setMaximumWidth(160)
|
|
20350
|
-
advanced_filter_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold;")
|
|
20741
|
+
advanced_filter_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold; padding: 3px 5px;")
|
|
20351
20742
|
|
|
20352
20743
|
# Sort dropdown button (similar to memoQ)
|
|
20353
20744
|
sort_btn = QPushButton("⇅ Sort")
|
|
20354
20745
|
sort_btn.setMaximumWidth(100)
|
|
20355
|
-
sort_btn.setStyleSheet("background-color: #FF9800; color: white; font-weight: bold;")
|
|
20746
|
+
sort_btn.setStyleSheet("background-color: #FF9800; color: white; font-weight: bold; padding: 3px 5px;")
|
|
20356
20747
|
sort_menu = QMenu(self)
|
|
20357
20748
|
|
|
20358
20749
|
# Initialize sort state if not exists
|
|
@@ -20422,7 +20813,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20422
20813
|
# Show Invisibles button with dropdown menu
|
|
20423
20814
|
show_invisibles_btn_home = QPushButton("¶ Show Invisibles")
|
|
20424
20815
|
show_invisibles_btn_home.setMaximumWidth(140)
|
|
20425
|
-
show_invisibles_btn_home.setStyleSheet("background-color: #607D8B; color: white; font-weight: bold;")
|
|
20816
|
+
show_invisibles_btn_home.setStyleSheet("background-color: #607D8B; color: white; font-weight: bold; padding: 3px 5px;")
|
|
20426
20817
|
show_invisibles_menu_home = QMenu(show_invisibles_btn_home)
|
|
20427
20818
|
|
|
20428
20819
|
# Use the same actions (they're stored as instance variables)
|
|
@@ -20718,12 +21109,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
20718
21109
|
|
|
20719
21110
|
preview_prompt_btn = QPushButton("🧪 Preview Prompts")
|
|
20720
21111
|
preview_prompt_btn.setToolTip("Preview the complete assembled prompt\n(System Prompt + Custom Prompts + current segment)")
|
|
20721
|
-
preview_prompt_btn.setStyleSheet("background-color: #9C27B0; color: white; font-weight: bold; padding:
|
|
21112
|
+
preview_prompt_btn.setStyleSheet("background-color: #9C27B0; color: white; font-weight: bold; padding: 3px 5px; border: none; outline: none;")
|
|
20722
21113
|
preview_prompt_btn.clicked.connect(self._preview_combined_prompt_from_grid)
|
|
20723
21114
|
toolbar_layout.addWidget(preview_prompt_btn)
|
|
20724
21115
|
|
|
20725
21116
|
dictate_btn = QPushButton("🎤 Dictation")
|
|
20726
|
-
dictate_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding:
|
|
21117
|
+
dictate_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 3px 5px; border: none; outline: none;")
|
|
20727
21118
|
dictate_btn.clicked.connect(self.start_voice_dictation)
|
|
20728
21119
|
dictate_btn.setToolTip("Start/stop voice dictation (F9)")
|
|
20729
21120
|
toolbar_layout.addWidget(dictate_btn)
|
|
@@ -20737,7 +21128,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20737
21128
|
background-color: #757575;
|
|
20738
21129
|
color: white;
|
|
20739
21130
|
font-weight: bold;
|
|
20740
|
-
padding:
|
|
21131
|
+
padding: 3px 5px;
|
|
20741
21132
|
border-radius: 3px;
|
|
20742
21133
|
}
|
|
20743
21134
|
QPushButton:checked {
|
|
@@ -20752,7 +21143,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20752
21143
|
toolbar_layout.addStretch()
|
|
20753
21144
|
|
|
20754
21145
|
save_next_btn = QPushButton("✓ Confirm && Next")
|
|
20755
|
-
save_next_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold; padding:
|
|
21146
|
+
save_next_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold; padding: 3px 5px; border: none; outline: none;")
|
|
20756
21147
|
save_next_btn.clicked.connect(self.confirm_selected_or_next)
|
|
20757
21148
|
save_next_btn.setToolTip("Confirm current segment and go to next unconfirmed (Ctrl+Enter)")
|
|
20758
21149
|
toolbar_layout.addWidget(save_next_btn)
|
|
@@ -21361,9 +21752,21 @@ class SupervertalerQt(QMainWindow):
|
|
|
21361
21752
|
# Configure columns
|
|
21362
21753
|
self.table.setColumnCount(5)
|
|
21363
21754
|
self.table.setHorizontalHeaderLabels(["#", "Type", "Source", "Target", "Status"])
|
|
21364
|
-
|
|
21365
|
-
#
|
|
21755
|
+
|
|
21756
|
+
# Explicitly set header font to normal weight (not bold)
|
|
21366
21757
|
header = self.table.horizontalHeader()
|
|
21758
|
+
header_font = QFont(self.default_font_family, self.default_font_size, QFont.Weight.Normal)
|
|
21759
|
+
header.setFont(header_font)
|
|
21760
|
+
|
|
21761
|
+
# Also set font on individual header items through the model (extra insurance)
|
|
21762
|
+
model = self.table.model()
|
|
21763
|
+
if model:
|
|
21764
|
+
for col in range(5):
|
|
21765
|
+
item = model.headerData(col, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole)
|
|
21766
|
+
model.setHeaderData(col, Qt.Orientation.Horizontal, item, Qt.ItemDataRole.DisplayRole)
|
|
21767
|
+
model.setHeaderData(col, Qt.Orientation.Horizontal, header_font, Qt.ItemDataRole.FontRole)
|
|
21768
|
+
|
|
21769
|
+
# Column widths - Source and Target columns stretch to fill space, others are interactive
|
|
21367
21770
|
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Interactive) # ID
|
|
21368
21771
|
header.setSectionResizeMode(1, QHeaderView.ResizeMode.Interactive) # Type
|
|
21369
21772
|
header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) # Source - stretch to fill space
|
|
@@ -21377,7 +21780,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
21377
21780
|
self.table.setColumnWidth(1, 40) # Type - narrower
|
|
21378
21781
|
self.table.setColumnWidth(2, 400) # Source
|
|
21379
21782
|
self.table.setColumnWidth(3, 400) # Target
|
|
21380
|
-
self.table.setColumnWidth(4,
|
|
21783
|
+
self.table.setColumnWidth(4, 50) # Status - compact width
|
|
21381
21784
|
|
|
21382
21785
|
# Enable word wrap in cells (both display and edit mode)
|
|
21383
21786
|
self.table.setWordWrap(True)
|
|
@@ -21407,6 +21810,51 @@ class SupervertalerQt(QMainWindow):
|
|
|
21407
21810
|
QTableWidget::item:last-child {
|
|
21408
21811
|
border-right: none;
|
|
21409
21812
|
}
|
|
21813
|
+
|
|
21814
|
+
/* Narrower scrollbar with visible arrow buttons */
|
|
21815
|
+
QScrollBar:vertical {
|
|
21816
|
+
border: none;
|
|
21817
|
+
background: #F0F0F0;
|
|
21818
|
+
width: 12px;
|
|
21819
|
+
margin: 12px 0 12px 0;
|
|
21820
|
+
}
|
|
21821
|
+
QScrollBar::handle:vertical {
|
|
21822
|
+
background: #C0C0C0;
|
|
21823
|
+
min-height: 20px;
|
|
21824
|
+
border-radius: 2px;
|
|
21825
|
+
}
|
|
21826
|
+
QScrollBar::handle:vertical:hover {
|
|
21827
|
+
background: #A0A0A0;
|
|
21828
|
+
}
|
|
21829
|
+
QScrollBar::add-line:vertical {
|
|
21830
|
+
height: 12px;
|
|
21831
|
+
background: #E0E0E0;
|
|
21832
|
+
subcontrol-position: bottom;
|
|
21833
|
+
subcontrol-origin: margin;
|
|
21834
|
+
}
|
|
21835
|
+
QScrollBar::add-line:vertical:hover {
|
|
21836
|
+
background: #2196F3;
|
|
21837
|
+
}
|
|
21838
|
+
QScrollBar::sub-line:vertical {
|
|
21839
|
+
height: 12px;
|
|
21840
|
+
background: #E0E0E0;
|
|
21841
|
+
subcontrol-position: top;
|
|
21842
|
+
subcontrol-origin: margin;
|
|
21843
|
+
}
|
|
21844
|
+
QScrollBar::sub-line:vertical:hover {
|
|
21845
|
+
background: #2196F3;
|
|
21846
|
+
}
|
|
21847
|
+
/* Arrow images */
|
|
21848
|
+
QScrollBar::up-arrow:vertical {
|
|
21849
|
+
image: url(assets/scrollbar_up.png);
|
|
21850
|
+
width: 8px;
|
|
21851
|
+
height: 8px;
|
|
21852
|
+
}
|
|
21853
|
+
QScrollBar::down-arrow:vertical {
|
|
21854
|
+
image: url(assets/scrollbar_down.png);
|
|
21855
|
+
width: 8px;
|
|
21856
|
+
height: 8px;
|
|
21857
|
+
}
|
|
21410
21858
|
""")
|
|
21411
21859
|
|
|
21412
21860
|
# Simplified editing: Double-click only (no F2 key) - companion tool philosophy
|
|
@@ -21429,8 +21877,8 @@ class SupervertalerQt(QMainWindow):
|
|
|
21429
21877
|
# Debug: Confirm signal connections
|
|
21430
21878
|
self.log("🔌 Table signals connected: currentCellChanged, itemClicked, cellDoubleClicked, itemSelectionChanged")
|
|
21431
21879
|
|
|
21432
|
-
#
|
|
21433
|
-
self.add_precision_scroll_buttons()
|
|
21880
|
+
# Precision scroll buttons removed (user preference)
|
|
21881
|
+
# self.add_precision_scroll_buttons()
|
|
21434
21882
|
|
|
21435
21883
|
def add_precision_scroll_buttons(self):
|
|
21436
21884
|
"""Add precision scroll buttons at top/bottom of scrollbar (memoQ-style)"""
|
|
@@ -21656,10 +22104,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
21656
22104
|
editor_widget.dictate_btn = dictate_btn
|
|
21657
22105
|
|
|
21658
22106
|
save_btn = QPushButton("💾 Save")
|
|
21659
|
-
save_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold;")
|
|
22107
|
+
save_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 3px 5px;")
|
|
21660
22108
|
save_btn.clicked.connect(self.save_tab_segment)
|
|
21661
22109
|
save_next_btn = QPushButton("✓ Confirm && Next (Ctrl+Enter)")
|
|
21662
|
-
save_next_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold;")
|
|
22110
|
+
save_next_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold; padding: 3px 5px;")
|
|
21663
22111
|
save_next_btn.clicked.connect(self.confirm_selected_or_next)
|
|
21664
22112
|
|
|
21665
22113
|
button_layout.addWidget(copy_btn)
|
|
@@ -22003,6 +22451,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
22003
22451
|
# Update UI
|
|
22004
22452
|
self.project_file_path = None
|
|
22005
22453
|
self.project_modified = True # Mark as modified since it hasn't been saved
|
|
22454
|
+
|
|
22455
|
+
# Store original segment order for "Document Order" sort reset
|
|
22456
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
22457
|
+
|
|
22006
22458
|
self.update_window_title()
|
|
22007
22459
|
self.load_segments_to_grid()
|
|
22008
22460
|
self.initialize_tm_database() # Initialize TM for this project
|
|
@@ -22031,16 +22483,16 @@ class SupervertalerQt(QMainWindow):
|
|
|
22031
22483
|
if hasattr(self.lookup_tab, '_ahk') and self.lookup_tab._ahk:
|
|
22032
22484
|
try:
|
|
22033
22485
|
self.lookup_tab._ahk.stop_hotkeys()
|
|
22034
|
-
print("[
|
|
22486
|
+
print("[SuperLookup] ahk library hotkeys stopped")
|
|
22035
22487
|
except Exception as e:
|
|
22036
|
-
print(f"[
|
|
22488
|
+
print(f"[SuperLookup] Error stopping ahk library: {e}")
|
|
22037
22489
|
|
|
22038
22490
|
# Terminate external AutoHotkey process if running (fallback method)
|
|
22039
22491
|
if hasattr(self, 'lookup_tab') and hasattr(self.lookup_tab, 'ahk_process') and self.lookup_tab.ahk_process:
|
|
22040
22492
|
try:
|
|
22041
22493
|
self.lookup_tab.ahk_process.terminate()
|
|
22042
22494
|
self.lookup_tab.ahk_process.wait(timeout=2)
|
|
22043
|
-
print("[
|
|
22495
|
+
print("[SuperLookup] AHK process terminated")
|
|
22044
22496
|
except:
|
|
22045
22497
|
# Force kill if terminate doesn't work
|
|
22046
22498
|
try:
|
|
@@ -22048,7 +22500,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
22048
22500
|
except:
|
|
22049
22501
|
pass
|
|
22050
22502
|
except Exception as e:
|
|
22051
|
-
print(f"[
|
|
22503
|
+
print(f"[SuperLookup] Error terminating AHK: {e}")
|
|
22052
22504
|
|
|
22053
22505
|
# Accept the close event
|
|
22054
22506
|
event.accept()
|
|
@@ -22084,6 +22536,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
22084
22536
|
self.project_file_path = file_path
|
|
22085
22537
|
self.project_modified = False
|
|
22086
22538
|
|
|
22539
|
+
# Store original segment order for "Document Order" sort reset
|
|
22540
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
22541
|
+
|
|
22542
|
+
# Always reset sort state when loading - project should open in document order
|
|
22543
|
+
self.current_sort = None
|
|
22544
|
+
|
|
22087
22545
|
# Sync global language settings with project languages
|
|
22088
22546
|
if self.current_project.source_lang:
|
|
22089
22547
|
self.source_language = self.current_project.source_lang
|
|
@@ -23435,9 +23893,21 @@ class SupervertalerQt(QMainWindow):
|
|
|
23435
23893
|
original_path = getattr(self, 'original_docx', None) or getattr(self, 'current_document_path', None)
|
|
23436
23894
|
if original_path and os.path.exists(original_path):
|
|
23437
23895
|
self.current_project.original_docx_path = original_path
|
|
23438
|
-
|
|
23896
|
+
|
|
23897
|
+
# IMPORTANT: Always save segments in original document order, not sorted order
|
|
23898
|
+
# Store current sort state and temporarily restore original order
|
|
23899
|
+
current_sort_state = getattr(self, 'current_sort', None)
|
|
23900
|
+
current_segments = self.current_project.segments.copy() # Save current (possibly sorted) order
|
|
23901
|
+
|
|
23902
|
+
# Restore original order for saving
|
|
23903
|
+
if hasattr(self, '_original_segment_order') and self._original_segment_order:
|
|
23904
|
+
self.current_project.segments = self._original_segment_order.copy()
|
|
23905
|
+
|
|
23439
23906
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
23440
23907
|
json.dump(self.current_project.to_dict(), f, indent=2, ensure_ascii=False)
|
|
23908
|
+
|
|
23909
|
+
# Restore the current (sorted) order after saving
|
|
23910
|
+
self.current_project.segments = current_segments
|
|
23441
23911
|
|
|
23442
23912
|
self.project_modified = False
|
|
23443
23913
|
self.update_window_title()
|
|
@@ -29152,7 +29622,11 @@ class SupervertalerQt(QMainWindow):
|
|
|
29152
29622
|
def load_segments_to_grid(self):
|
|
29153
29623
|
"""Load segments into the grid with termbase highlighting"""
|
|
29154
29624
|
self.log(f"🔄🔄🔄 load_segments_to_grid CALLED - this will RELOAD grid from segment data!")
|
|
29155
|
-
|
|
29625
|
+
|
|
29626
|
+
# Ensure original segment order is stored (for Document Order sort)
|
|
29627
|
+
if self.current_project and not hasattr(self, '_original_segment_order'):
|
|
29628
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
29629
|
+
|
|
29156
29630
|
# Clear row color settings cache to ensure fresh settings are loaded
|
|
29157
29631
|
if hasattr(self, '_row_color_settings_cached'):
|
|
29158
29632
|
delattr(self, '_row_color_settings_cached')
|
|
@@ -29229,7 +29703,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
29229
29703
|
id_item.setForeground(QColor(segment_num_color))
|
|
29230
29704
|
id_item.setBackground(QColor()) # Default background from theme
|
|
29231
29705
|
# Smaller font for segment numbers
|
|
29232
|
-
seg_num_font = QFont(self.default_font_family, max(
|
|
29706
|
+
seg_num_font = QFont(self.default_font_family, max(9, self.default_font_size - 1))
|
|
29233
29707
|
id_item.setFont(seg_num_font)
|
|
29234
29708
|
self.table.setItem(row, 0, id_item)
|
|
29235
29709
|
|
|
@@ -29321,7 +29795,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
29321
29795
|
type_item.setForeground(QColor("#388E3C")) # Green for list items (works in both themes)
|
|
29322
29796
|
|
|
29323
29797
|
# Smaller font for type symbols
|
|
29324
|
-
type_font = QFont(self.default_font_family, max(
|
|
29798
|
+
type_font = QFont(self.default_font_family, max(9, self.default_font_size - 1))
|
|
29325
29799
|
type_item.setFont(type_font)
|
|
29326
29800
|
|
|
29327
29801
|
self.table.setItem(row, 1, type_item)
|
|
@@ -29771,7 +30245,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
29771
30245
|
if shortcut_badge_tooltip:
|
|
29772
30246
|
badge_label.setToolTip(f"Press {shortcut_badge_tooltip} to insert")
|
|
29773
30247
|
header_layout.addWidget(badge_label)
|
|
29774
|
-
|
|
30248
|
+
|
|
30249
|
+
# Add stretch to push navigation controls to the right (aligned with scrollbar)
|
|
30250
|
+
header_layout.addStretch()
|
|
30251
|
+
|
|
29775
30252
|
nav_label = None
|
|
29776
30253
|
nav_buttons = None
|
|
29777
30254
|
|
|
@@ -29837,8 +30314,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
29837
30314
|
self.theme_aware_arrows.extend([prev_btn, next_btn])
|
|
29838
30315
|
|
|
29839
30316
|
nav_buttons = [prev_btn, next_btn]
|
|
29840
|
-
|
|
29841
|
-
header_layout.addStretch()
|
|
30317
|
+
|
|
29842
30318
|
main_layout.addLayout(header_layout)
|
|
29843
30319
|
|
|
29844
30320
|
# Text area
|
|
@@ -30761,19 +31237,24 @@ class SupervertalerQt(QMainWindow):
|
|
|
30761
31237
|
widget.setToolTip(f"Notes: {segment.notes.strip()}")
|
|
30762
31238
|
|
|
30763
31239
|
status_def = get_status(segment.status)
|
|
30764
|
-
|
|
31240
|
+
|
|
31241
|
+
# Status icons: ✔ (green) and ❌ (naturally red emoji)
|
|
31242
|
+
icon_text = status_def.icon
|
|
31243
|
+
if segment.status == "confirmed":
|
|
31244
|
+
icon_html = f'<font color="#2e7d32" size="2">{icon_text}</font>' # Green checkmark
|
|
31245
|
+
else:
|
|
31246
|
+
icon_html = f'<font size="2">{icon_text}</font>' # Other icons (including ❌ emoji)
|
|
31247
|
+
|
|
31248
|
+
status_label = QLabel(icon_html)
|
|
31249
|
+
status_label.setTextFormat(Qt.TextFormat.RichText) # Enable HTML rendering
|
|
30765
31250
|
status_label.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
|
|
31251
|
+
status_label.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding) # Expand vertically to match row height
|
|
30766
31252
|
status_label.setToolTip(status_def.label)
|
|
30767
|
-
|
|
30768
|
-
|
|
30769
|
-
# Make confirmed checkmark green
|
|
30770
|
-
color = "color: #2e7d32;" if segment.status == "confirmed" else ""
|
|
30771
|
-
|
|
30772
|
-
# Apply orange background highlight to status icon if segment has notes
|
|
31253
|
+
|
|
31254
|
+
# Add orange background if segment has notes (using stylesheet for background only)
|
|
30773
31255
|
if has_notes:
|
|
30774
|
-
status_label.setStyleSheet(
|
|
30775
|
-
|
|
30776
|
-
status_label.setStyleSheet(f"font-size: {font_size}; {color} padding-right: 4px;")
|
|
31256
|
+
status_label.setStyleSheet("padding: 2px 4px; background-color: rgba(255, 152, 0, 0.35); border-radius: 3px;")
|
|
31257
|
+
# Note: No stylesheet for non-notes case to avoid interfering with HTML color
|
|
30777
31258
|
layout.addWidget(status_label)
|
|
30778
31259
|
|
|
30779
31260
|
# Only add match label if there's a match percentage
|
|
@@ -30885,14 +31366,17 @@ class SupervertalerQt(QMainWindow):
|
|
|
30885
31366
|
"""Auto-resize all rows to fit content - Compact version"""
|
|
30886
31367
|
if not hasattr(self, 'table') or not self.table:
|
|
30887
31368
|
return
|
|
30888
|
-
|
|
31369
|
+
|
|
30889
31370
|
# Reduce width slightly to account for padding and prevent text cut-off
|
|
30890
31371
|
width_reduction = 8
|
|
30891
|
-
|
|
31372
|
+
|
|
30892
31373
|
# Manually calculate and set row heights for compact display
|
|
30893
31374
|
for row in range(self.table.rowCount()):
|
|
31375
|
+
# Keep UI responsive during large grid updates
|
|
31376
|
+
if row % 50 == 0:
|
|
31377
|
+
QApplication.processEvents()
|
|
30894
31378
|
self._auto_resize_single_row(row, width_reduction)
|
|
30895
|
-
|
|
31379
|
+
|
|
30896
31380
|
self.log("✓ Auto-resized rows to fit content (compact)")
|
|
30897
31381
|
self._enforce_status_row_heights()
|
|
30898
31382
|
|
|
@@ -30939,26 +31423,30 @@ class SupervertalerQt(QMainWindow):
|
|
|
30939
31423
|
def apply_font_to_grid(self):
|
|
30940
31424
|
"""Apply selected font to all grid cells"""
|
|
30941
31425
|
font = QFont(self.default_font_family, self.default_font_size)
|
|
30942
|
-
|
|
31426
|
+
|
|
30943
31427
|
self.table.setFont(font)
|
|
30944
|
-
|
|
30945
|
-
# Also update header font - same size as grid content,
|
|
30946
|
-
header_font = QFont(self.default_font_family, self.default_font_size, QFont.Weight.
|
|
31428
|
+
|
|
31429
|
+
# Also update header font - same size as grid content, normal weight
|
|
31430
|
+
header_font = QFont(self.default_font_family, self.default_font_size, QFont.Weight.Normal)
|
|
30947
31431
|
self.table.horizontalHeader().setFont(header_font)
|
|
30948
|
-
|
|
31432
|
+
|
|
30949
31433
|
# Update fonts in QTextEdit widgets (source and target columns)
|
|
30950
31434
|
if hasattr(self, 'table') and self.table:
|
|
30951
31435
|
for row in range(self.table.rowCount()):
|
|
31436
|
+
# Keep UI responsive during large grid updates
|
|
31437
|
+
if row % 50 == 0:
|
|
31438
|
+
QApplication.processEvents()
|
|
31439
|
+
|
|
30952
31440
|
# Source column (2) - ReadOnlyGridTextEditor
|
|
30953
31441
|
source_widget = self.table.cellWidget(row, 2)
|
|
30954
31442
|
if source_widget and isinstance(source_widget, ReadOnlyGridTextEditor):
|
|
30955
31443
|
source_widget.setFont(font)
|
|
30956
|
-
|
|
31444
|
+
|
|
30957
31445
|
# Target column (3) - EditableGridTextEditor
|
|
30958
31446
|
target_widget = self.table.cellWidget(row, 3)
|
|
30959
31447
|
if target_widget and isinstance(target_widget, EditableGridTextEditor):
|
|
30960
31448
|
target_widget.setFont(font)
|
|
30961
|
-
|
|
31449
|
+
|
|
30962
31450
|
# Adjust segment number column width based on font size
|
|
30963
31451
|
self._update_segment_column_width()
|
|
30964
31452
|
|
|
@@ -30982,12 +31470,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
30982
31470
|
# Measure the width of the largest number (as string)
|
|
30983
31471
|
text_width = fm.horizontalAdvance(str(max_segment))
|
|
30984
31472
|
|
|
30985
|
-
# Add padding (
|
|
30986
|
-
new_width = text_width +
|
|
30987
|
-
|
|
30988
|
-
# Ensure minimum width for very small numbers
|
|
30989
|
-
new_width = max(30, new_width)
|
|
30990
|
-
|
|
31473
|
+
# Add padding (6px on each side = 12px total)
|
|
31474
|
+
new_width = text_width + 12
|
|
31475
|
+
|
|
31476
|
+
# Ensure minimum width for very small numbers, cap at width for ~1000
|
|
31477
|
+
new_width = max(30, min(new_width, 55))
|
|
31478
|
+
|
|
30991
31479
|
self.table.setColumnWidth(0, new_width)
|
|
30992
31480
|
|
|
30993
31481
|
def set_font_family(self, family_name: str):
|
|
@@ -31019,14 +31507,18 @@ class SupervertalerQt(QMainWindow):
|
|
|
31019
31507
|
"""Refresh tag highlight colors in all grid cells"""
|
|
31020
31508
|
if not hasattr(self, 'table') or not self.table:
|
|
31021
31509
|
return
|
|
31022
|
-
|
|
31510
|
+
|
|
31023
31511
|
for row in range(self.table.rowCount()):
|
|
31512
|
+
# Keep UI responsive during large grid updates
|
|
31513
|
+
if row % 50 == 0:
|
|
31514
|
+
QApplication.processEvents()
|
|
31515
|
+
|
|
31024
31516
|
# Source column (2) - ReadOnlyGridTextEditor
|
|
31025
31517
|
source_widget = self.table.cellWidget(row, 2)
|
|
31026
31518
|
if source_widget and isinstance(source_widget, ReadOnlyGridTextEditor):
|
|
31027
31519
|
if hasattr(source_widget, 'highlighter'):
|
|
31028
31520
|
source_widget.highlighter.set_tag_color(EditableGridTextEditor.tag_highlight_color)
|
|
31029
|
-
|
|
31521
|
+
|
|
31030
31522
|
# Target column (3) - EditableGridTextEditor
|
|
31031
31523
|
target_widget = self.table.cellWidget(row, 3)
|
|
31032
31524
|
if target_widget and isinstance(target_widget, EditableGridTextEditor):
|
|
@@ -31091,18 +31583,22 @@ class SupervertalerQt(QMainWindow):
|
|
|
31091
31583
|
"""Apply alternating row colors to all source and target cells in the grid"""
|
|
31092
31584
|
if not hasattr(self, 'table') or not self.table:
|
|
31093
31585
|
return
|
|
31094
|
-
|
|
31586
|
+
|
|
31095
31587
|
# Clear cached settings to force reload
|
|
31096
31588
|
if hasattr(self, '_row_color_settings_cached'):
|
|
31097
31589
|
delattr(self, '_row_color_settings_cached')
|
|
31098
|
-
|
|
31590
|
+
|
|
31099
31591
|
for row in range(self.table.rowCount()):
|
|
31592
|
+
# Keep UI responsive during large grid updates
|
|
31593
|
+
if row % 50 == 0:
|
|
31594
|
+
QApplication.processEvents()
|
|
31595
|
+
|
|
31100
31596
|
source_widget = self.table.cellWidget(row, 2)
|
|
31101
31597
|
target_widget = self.table.cellWidget(row, 3)
|
|
31102
|
-
|
|
31598
|
+
|
|
31103
31599
|
if source_widget and target_widget:
|
|
31104
31600
|
self._apply_row_color(row, source_widget, target_widget)
|
|
31105
|
-
|
|
31601
|
+
|
|
31106
31602
|
self.log("✓ Alternating row colors applied")
|
|
31107
31603
|
|
|
31108
31604
|
def on_font_changed(self):
|
|
@@ -36976,9 +37472,9 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
36976
37472
|
"""Update spellcheck button style based on enabled state"""
|
|
36977
37473
|
if hasattr(self, 'spellcheck_btn'):
|
|
36978
37474
|
if self.spellcheck_enabled:
|
|
36979
|
-
self.spellcheck_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold;")
|
|
37475
|
+
self.spellcheck_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 3px 5px;")
|
|
36980
37476
|
else:
|
|
36981
|
-
self.spellcheck_btn.setStyleSheet("background-color: #9E9E9E; color: white; font-weight: bold;")
|
|
37477
|
+
self.spellcheck_btn.setStyleSheet("background-color: #9E9E9E; color: white; font-weight: bold; padding: 3px 5px;")
|
|
36982
37478
|
|
|
36983
37479
|
def _toggle_spellcheck(self, checked=None):
|
|
36984
37480
|
"""Toggle spellcheck on/off"""
|
|
@@ -37687,16 +38183,16 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37687
38183
|
if not self.current_project.segments:
|
|
37688
38184
|
return
|
|
37689
38185
|
|
|
37690
|
-
# Show progress dialog
|
|
38186
|
+
# Show progress dialog during sorting
|
|
37691
38187
|
from PyQt6.QtWidgets import QProgressDialog
|
|
37692
38188
|
from PyQt6.QtCore import Qt
|
|
37693
38189
|
|
|
37694
38190
|
progress = QProgressDialog("Sorting segments, please wait...", None, 0, 0, self)
|
|
37695
38191
|
progress.setWindowTitle("Sorting")
|
|
37696
38192
|
progress.setWindowModality(Qt.WindowModality.WindowModal)
|
|
37697
|
-
progress.setMinimumDuration(
|
|
37698
|
-
progress.
|
|
37699
|
-
QApplication.processEvents() #
|
|
38193
|
+
progress.setMinimumDuration(0) # Show immediately
|
|
38194
|
+
progress.show()
|
|
38195
|
+
QApplication.processEvents() # Force UI update
|
|
37700
38196
|
|
|
37701
38197
|
try:
|
|
37702
38198
|
# Store original document order if not already stored
|
|
@@ -37708,7 +38204,12 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37708
38204
|
|
|
37709
38205
|
# If sort_type is None, restore document order
|
|
37710
38206
|
if sort_type is None:
|
|
37711
|
-
|
|
38207
|
+
# Restore document order by sorting by segment ID (original position)
|
|
38208
|
+
# This works even if the stored original order is wrong
|
|
38209
|
+
self.current_project.segments.sort(key=lambda seg: int(seg.id))
|
|
38210
|
+
|
|
38211
|
+
# Update stored original order to this correct order
|
|
38212
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
37712
38213
|
|
|
37713
38214
|
# Set pagination to "All" to show all segments
|
|
37714
38215
|
if hasattr(self, 'page_size_combo') and self._widget_is_alive(self.page_size_combo):
|
|
@@ -43760,23 +44261,58 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43760
44261
|
"""Call DeepL API"""
|
|
43761
44262
|
try:
|
|
43762
44263
|
import deepl
|
|
43763
|
-
|
|
44264
|
+
|
|
43764
44265
|
if not api_key:
|
|
43765
44266
|
api_keys = self.load_api_keys()
|
|
43766
44267
|
api_key = api_keys.get("deepl")
|
|
43767
|
-
|
|
44268
|
+
|
|
43768
44269
|
if not api_key:
|
|
43769
44270
|
return "[DeepL requires API key]"
|
|
43770
|
-
|
|
44271
|
+
|
|
43771
44272
|
translator = deepl.Translator(api_key)
|
|
43772
|
-
|
|
43773
|
-
# Convert language
|
|
44273
|
+
|
|
44274
|
+
# Convert source language code (DeepL uses uppercase, no variant needed for source)
|
|
43774
44275
|
src_code = source_lang.split('-')[0].split('_')[0].upper()
|
|
43775
|
-
|
|
43776
|
-
|
|
44276
|
+
|
|
44277
|
+
# Convert target language code - DeepL requires variants for some languages
|
|
44278
|
+
# Handle full codes like "en-US", "en-GB", "pt-BR", "pt-PT"
|
|
44279
|
+
tgt_upper = target_lang.upper().replace('_', '-')
|
|
44280
|
+
|
|
44281
|
+
# DeepL target language mapping - some require specific variants
|
|
44282
|
+
deepl_target_map = {
|
|
44283
|
+
# English variants (EN alone is deprecated)
|
|
44284
|
+
'EN': 'EN-US', # Default to US English
|
|
44285
|
+
'EN-US': 'EN-US',
|
|
44286
|
+
'EN-GB': 'EN-GB',
|
|
44287
|
+
'EN-AU': 'EN-GB', # Map Australian to British
|
|
44288
|
+
'EN-CA': 'EN-US', # Map Canadian to US
|
|
44289
|
+
# Portuguese variants
|
|
44290
|
+
'PT': 'PT-PT', # Default to European Portuguese
|
|
44291
|
+
'PT-PT': 'PT-PT',
|
|
44292
|
+
'PT-BR': 'PT-BR',
|
|
44293
|
+
# Chinese variants
|
|
44294
|
+
'ZH': 'ZH-HANS', # Default to Simplified
|
|
44295
|
+
'ZH-CN': 'ZH-HANS',
|
|
44296
|
+
'ZH-TW': 'ZH-HANT',
|
|
44297
|
+
'ZH-HANS': 'ZH-HANS',
|
|
44298
|
+
'ZH-HANT': 'ZH-HANT',
|
|
44299
|
+
}
|
|
44300
|
+
|
|
44301
|
+
# Check if full code matches first, then base code
|
|
44302
|
+
if tgt_upper in deepl_target_map:
|
|
44303
|
+
tgt_code = deepl_target_map[tgt_upper]
|
|
44304
|
+
else:
|
|
44305
|
+
# Extract base code and check
|
|
44306
|
+
base_code = tgt_upper.split('-')[0]
|
|
44307
|
+
if base_code in deepl_target_map:
|
|
44308
|
+
tgt_code = deepl_target_map[base_code]
|
|
44309
|
+
else:
|
|
44310
|
+
# Use base code as-is for other languages
|
|
44311
|
+
tgt_code = base_code
|
|
44312
|
+
|
|
43777
44313
|
result = translator.translate_text(text, source_lang=src_code, target_lang=tgt_code)
|
|
43778
44314
|
return result.text
|
|
43779
|
-
|
|
44315
|
+
|
|
43780
44316
|
except ImportError:
|
|
43781
44317
|
return "[DeepL requires: pip install deepl]"
|
|
43782
44318
|
except Exception as e:
|
|
@@ -44222,8 +44758,11 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
44222
44758
|
# Determine segment number color based on theme
|
|
44223
44759
|
is_dark_theme = theme.name == "Dark"
|
|
44224
44760
|
segment_num_color = theme.text if is_dark_theme else "black"
|
|
44225
|
-
|
|
44761
|
+
|
|
44226
44762
|
for row in range(self.table.rowCount()):
|
|
44763
|
+
# Keep UI responsive during large grid updates
|
|
44764
|
+
if row % 50 == 0:
|
|
44765
|
+
QApplication.processEvents()
|
|
44227
44766
|
id_item = self.table.item(row, 0)
|
|
44228
44767
|
if id_item:
|
|
44229
44768
|
# Don't change currently highlighted row (orange background)
|
|
@@ -45312,7 +45851,7 @@ class SuperlookupTab(QWidget):
|
|
|
45312
45851
|
self.main_window = parent # Store reference to main window for database access
|
|
45313
45852
|
self.user_data_path = user_data_path # Store user data path for web cache
|
|
45314
45853
|
|
|
45315
|
-
print("[
|
|
45854
|
+
print("[SuperLookup] SuperlookupTab.__init__ called")
|
|
45316
45855
|
|
|
45317
45856
|
# Get theme manager from main window (try parent first, then parent's parent for dialogs)
|
|
45318
45857
|
self.theme_manager = getattr(parent, 'theme_manager', None)
|
|
@@ -45321,16 +45860,16 @@ class SuperlookupTab(QWidget):
|
|
|
45321
45860
|
parent_parent = getattr(parent, 'parent', lambda: None)()
|
|
45322
45861
|
if parent_parent:
|
|
45323
45862
|
self.theme_manager = getattr(parent_parent, 'theme_manager', None)
|
|
45324
|
-
print(f"[
|
|
45863
|
+
print(f"[SuperLookup] theme_manager: {self.theme_manager is not None}")
|
|
45325
45864
|
|
|
45326
45865
|
# Import lookup engine
|
|
45327
45866
|
try:
|
|
45328
45867
|
from modules.superlookup import SuperlookupEngine, LookupResult
|
|
45329
45868
|
self.SuperlookupEngine = SuperlookupEngine
|
|
45330
45869
|
self.LookupResult = LookupResult
|
|
45331
|
-
print("[
|
|
45870
|
+
print("[SuperLookup] Successfully imported SuperlookupEngine")
|
|
45332
45871
|
except ImportError as e:
|
|
45333
|
-
print(f"[
|
|
45872
|
+
print(f"[SuperLookup] IMPORT ERROR: {e}")
|
|
45334
45873
|
QMessageBox.critical(
|
|
45335
45874
|
self,
|
|
45336
45875
|
"Missing Module",
|
|
@@ -45412,7 +45951,7 @@ class SuperlookupTab(QWidget):
|
|
|
45412
45951
|
if self.db_manager or self.termbase_mgr:
|
|
45413
45952
|
self.populate_language_dropdowns()
|
|
45414
45953
|
self._languages_populated = True
|
|
45415
|
-
print("[
|
|
45954
|
+
print("[SuperLookup] Languages populated on first show")
|
|
45416
45955
|
|
|
45417
45956
|
def init_ui(self):
|
|
45418
45957
|
"""Initialize the UI"""
|
|
@@ -45421,7 +45960,7 @@ class SuperlookupTab(QWidget):
|
|
|
45421
45960
|
layout.setSpacing(5) # Reduced from 10 to 5 for consistency
|
|
45422
45961
|
|
|
45423
45962
|
# Header
|
|
45424
|
-
header = QLabel("🔍
|
|
45963
|
+
header = QLabel("🔍 SuperLookup")
|
|
45425
45964
|
header.setStyleSheet("font-size: 16pt; font-weight: bold; color: #1976D2;")
|
|
45426
45965
|
layout.addWidget(header, 0) # 0 = no stretch, stays compact
|
|
45427
45966
|
|
|
@@ -45915,7 +46454,7 @@ class SuperlookupTab(QWidget):
|
|
|
45915
46454
|
})
|
|
45916
46455
|
|
|
45917
46456
|
except Exception as e:
|
|
45918
|
-
print(f"[
|
|
46457
|
+
print(f"[SuperLookup] MT error ({provider_name}): {e}")
|
|
45919
46458
|
results.append({
|
|
45920
46459
|
'provider': provider_name,
|
|
45921
46460
|
'translation': f"[Error: {str(e)}]",
|
|
@@ -46006,9 +46545,9 @@ class SuperlookupTab(QWidget):
|
|
|
46006
46545
|
self.web_profile = QWebEngineProfile("SuperlookupProfile", self)
|
|
46007
46546
|
self.web_profile.setPersistentStoragePath(storage_path)
|
|
46008
46547
|
self.web_profile.setPersistentCookiesPolicy(QWebEngineProfile.PersistentCookiesPolicy.ForcePersistentCookies)
|
|
46009
|
-
print(f"[
|
|
46548
|
+
print(f"[SuperLookup] QWebEngineView available - embedded browser enabled with persistent storage at {storage_path}")
|
|
46010
46549
|
except ImportError:
|
|
46011
|
-
print("[
|
|
46550
|
+
print("[SuperLookup] QWebEngineView not available - external browser only")
|
|
46012
46551
|
self.QWebEngineView = None
|
|
46013
46552
|
self.QWebEngineProfile = None
|
|
46014
46553
|
|
|
@@ -46460,7 +46999,7 @@ class SuperlookupTab(QWidget):
|
|
|
46460
46999
|
self.web_view_stack.addWidget(web_view)
|
|
46461
47000
|
self.web_views[resource['id']] = web_view
|
|
46462
47001
|
|
|
46463
|
-
print(f"[
|
|
47002
|
+
print(f"[SuperLookup] Created web view for {resource['name']} (lazy load)")
|
|
46464
47003
|
|
|
46465
47004
|
def _get_web_view_index(self, resource_id):
|
|
46466
47005
|
"""Get the stack index for a web view by resource ID"""
|
|
@@ -46477,7 +47016,7 @@ class SuperlookupTab(QWidget):
|
|
|
46477
47016
|
|
|
46478
47017
|
self._update_web_view_for_mode()
|
|
46479
47018
|
self._show_web_welcome_message()
|
|
46480
|
-
print(f"[
|
|
47019
|
+
print(f"[SuperLookup] Web browser mode changed to: {self.web_browser_mode}")
|
|
46481
47020
|
|
|
46482
47021
|
def _update_web_view_for_mode(self):
|
|
46483
47022
|
"""Update the view stack based on current mode"""
|
|
@@ -47110,11 +47649,11 @@ class SuperlookupTab(QWidget):
|
|
|
47110
47649
|
if index == 2:
|
|
47111
47650
|
# Initialize Supermemory when tab is first viewed
|
|
47112
47651
|
if not self.supermemory_engine:
|
|
47113
|
-
print("[
|
|
47652
|
+
print("[SuperLookup] Supermemory tab viewed - initializing engine")
|
|
47114
47653
|
self.init_supermemory()
|
|
47115
47654
|
# Settings tab is at index 5
|
|
47116
47655
|
elif index == 5:
|
|
47117
|
-
print("[
|
|
47656
|
+
print("[SuperLookup] Settings tab viewed - refreshing resource lists")
|
|
47118
47657
|
self.refresh_tm_list()
|
|
47119
47658
|
self.refresh_termbase_list()
|
|
47120
47659
|
self.populate_language_dropdowns()
|
|
@@ -47122,19 +47661,19 @@ class SuperlookupTab(QWidget):
|
|
|
47122
47661
|
def on_tm_search_toggled(self, state):
|
|
47123
47662
|
"""Handle TM search checkbox toggle"""
|
|
47124
47663
|
self.search_tm_enabled = (state == Qt.CheckState.Checked.value)
|
|
47125
|
-
print(f"[
|
|
47664
|
+
print(f"[SuperLookup] TM search {'enabled' if self.search_tm_enabled else 'disabled'}")
|
|
47126
47665
|
|
|
47127
47666
|
def on_termbase_search_toggled(self, state):
|
|
47128
47667
|
"""Handle termbase search checkbox toggle"""
|
|
47129
47668
|
self.search_termbase_enabled = (state == Qt.CheckState.Checked.value)
|
|
47130
|
-
print(f"[
|
|
47669
|
+
print(f"[SuperLookup] Termbase search {'enabled' if self.search_termbase_enabled else 'disabled'}")
|
|
47131
47670
|
|
|
47132
47671
|
def _on_web_resource_checkbox_changed(self, index: int, state: int):
|
|
47133
47672
|
"""Handle web resource checkbox change - show/hide corresponding sidebar button"""
|
|
47134
47673
|
is_checked = (state == Qt.CheckState.Checked.value)
|
|
47135
47674
|
if hasattr(self, 'web_resource_buttons') and index < len(self.web_resource_buttons):
|
|
47136
47675
|
self.web_resource_buttons[index].setVisible(is_checked)
|
|
47137
|
-
print(f"[
|
|
47676
|
+
print(f"[SuperLookup] Web resource {index} {'shown' if is_checked else 'hidden'}")
|
|
47138
47677
|
|
|
47139
47678
|
# If the hidden resource was selected, select the first visible one
|
|
47140
47679
|
if not is_checked and hasattr(self, 'current_web_resource_index') and self.current_web_resource_index == index:
|
|
@@ -47152,18 +47691,18 @@ class SuperlookupTab(QWidget):
|
|
|
47152
47691
|
checkbox.deleteLater()
|
|
47153
47692
|
self.tm_checkboxes.clear()
|
|
47154
47693
|
|
|
47155
|
-
print(f"[
|
|
47156
|
-
print(f"[
|
|
47694
|
+
print(f"[SuperLookup] refresh_tm_list called")
|
|
47695
|
+
print(f"[SuperLookup] main_window exists: {self.main_window is not None}")
|
|
47157
47696
|
|
|
47158
47697
|
# Get TMs from main window's database
|
|
47159
47698
|
if self.main_window and hasattr(self.main_window, 'db_manager') and self.main_window.db_manager:
|
|
47160
47699
|
try:
|
|
47161
|
-
print(f"[
|
|
47700
|
+
print(f"[SuperLookup] db_manager found, querying TMs...")
|
|
47162
47701
|
cursor = self.main_window.db_manager.cursor
|
|
47163
47702
|
cursor.execute("SELECT id, name, tm_id FROM translation_memories ORDER BY name")
|
|
47164
47703
|
tms = cursor.fetchall()
|
|
47165
47704
|
|
|
47166
|
-
print(f"[
|
|
47705
|
+
print(f"[SuperLookup] Query returned {len(tms)} TMs")
|
|
47167
47706
|
|
|
47168
47707
|
for db_id, tm_name, tm_id_str in tms:
|
|
47169
47708
|
checkbox = CheckmarkCheckBox(f"{tm_name} (ID: {db_id})")
|
|
@@ -47174,13 +47713,13 @@ class SuperlookupTab(QWidget):
|
|
|
47174
47713
|
# Insert before the stretch at the end
|
|
47175
47714
|
self.tm_scroll_layout.insertWidget(len(self.tm_checkboxes) - 1, checkbox)
|
|
47176
47715
|
|
|
47177
|
-
print(f"[
|
|
47716
|
+
print(f"[SuperLookup] ✓ Loaded {len(tms)} TMs")
|
|
47178
47717
|
except Exception as e:
|
|
47179
|
-
print(f"[
|
|
47718
|
+
print(f"[SuperLookup] ✗ Error loading TMs: {e}")
|
|
47180
47719
|
import traceback
|
|
47181
47720
|
traceback.print_exc()
|
|
47182
47721
|
else:
|
|
47183
|
-
print(f"[
|
|
47722
|
+
print(f"[SuperLookup] db_manager not available")
|
|
47184
47723
|
# Add placeholder label
|
|
47185
47724
|
placeholder = QLabel("No database connection - TMs unavailable")
|
|
47186
47725
|
placeholder.setStyleSheet("color: #999; font-style: italic;")
|
|
@@ -47194,16 +47733,16 @@ class SuperlookupTab(QWidget):
|
|
|
47194
47733
|
checkbox.deleteLater()
|
|
47195
47734
|
self.tb_checkboxes.clear()
|
|
47196
47735
|
|
|
47197
|
-
print(f"[
|
|
47198
|
-
print(f"[
|
|
47736
|
+
print(f"[SuperLookup] refresh_termbase_list called")
|
|
47737
|
+
print(f"[SuperLookup] main_window exists: {self.main_window is not None}")
|
|
47199
47738
|
|
|
47200
47739
|
# Try termbase_mgr first (preferred method)
|
|
47201
47740
|
if self.main_window and hasattr(self.main_window, 'termbase_mgr') and self.main_window.termbase_mgr:
|
|
47202
47741
|
try:
|
|
47203
|
-
print(f"[
|
|
47742
|
+
print(f"[SuperLookup] termbase_mgr found, querying termbases...")
|
|
47204
47743
|
termbases = self.main_window.termbase_mgr.get_all_termbases()
|
|
47205
47744
|
|
|
47206
|
-
print(f"[
|
|
47745
|
+
print(f"[SuperLookup] get_all_termbases() returned {len(termbases)} termbases")
|
|
47207
47746
|
|
|
47208
47747
|
for tb in termbases:
|
|
47209
47748
|
tb_id = tb.get('id')
|
|
@@ -47215,22 +47754,22 @@ class SuperlookupTab(QWidget):
|
|
|
47215
47754
|
# Insert before the stretch at the end
|
|
47216
47755
|
self.tb_scroll_layout.insertWidget(len(self.tb_checkboxes) - 1, checkbox)
|
|
47217
47756
|
|
|
47218
|
-
print(f"[
|
|
47757
|
+
print(f"[SuperLookup] ✓ Loaded {len(termbases)} termbases via termbase_mgr")
|
|
47219
47758
|
return
|
|
47220
47759
|
except Exception as e:
|
|
47221
|
-
print(f"[
|
|
47760
|
+
print(f"[SuperLookup] ✗ Error loading termbases via termbase_mgr: {e}")
|
|
47222
47761
|
import traceback
|
|
47223
47762
|
traceback.print_exc()
|
|
47224
47763
|
|
|
47225
47764
|
# Fallback to direct database query
|
|
47226
47765
|
if self.main_window and hasattr(self.main_window, 'db_manager') and self.main_window.db_manager:
|
|
47227
47766
|
try:
|
|
47228
|
-
print(f"[
|
|
47767
|
+
print(f"[SuperLookup] db_manager found, querying termbases...")
|
|
47229
47768
|
cursor = self.main_window.db_manager.cursor
|
|
47230
47769
|
cursor.execute("SELECT id, name FROM termbases ORDER BY name")
|
|
47231
47770
|
termbases = cursor.fetchall()
|
|
47232
47771
|
|
|
47233
|
-
print(f"[
|
|
47772
|
+
print(f"[SuperLookup] Query returned {len(termbases)} termbases")
|
|
47234
47773
|
|
|
47235
47774
|
for tb_id, tb_name in termbases:
|
|
47236
47775
|
checkbox = CheckmarkCheckBox(f"{tb_name} (ID: {tb_id})")
|
|
@@ -47240,13 +47779,13 @@ class SuperlookupTab(QWidget):
|
|
|
47240
47779
|
# Insert before the stretch at the end
|
|
47241
47780
|
self.tb_scroll_layout.insertWidget(len(self.tb_checkboxes) - 1, checkbox)
|
|
47242
47781
|
|
|
47243
|
-
print(f"[
|
|
47782
|
+
print(f"[SuperLookup] ✓ Loaded {len(termbases)} termbases via db_manager")
|
|
47244
47783
|
except Exception as e:
|
|
47245
|
-
print(f"[
|
|
47784
|
+
print(f"[SuperLookup] ✗ Error loading termbases via db_manager: {e}")
|
|
47246
47785
|
import traceback
|
|
47247
47786
|
traceback.print_exc()
|
|
47248
47787
|
else:
|
|
47249
|
-
print(f"[
|
|
47788
|
+
print(f"[SuperLookup] Neither termbase_mgr nor db_manager available")
|
|
47250
47789
|
# Add placeholder label
|
|
47251
47790
|
placeholder = QLabel("No database connection - Glossaries unavailable")
|
|
47252
47791
|
placeholder.setStyleSheet("color: #999; font-style: italic;")
|
|
@@ -48057,7 +48596,7 @@ class SuperlookupTab(QWidget):
|
|
|
48057
48596
|
self.status_label.setText(f"Navigated to glossary entry: {source_term}")
|
|
48058
48597
|
|
|
48059
48598
|
except Exception as e:
|
|
48060
|
-
print(f"[
|
|
48599
|
+
print(f"[SuperLookup] Error navigating to glossary: {e}")
|
|
48061
48600
|
self.status_label.setText(f"Error navigating to glossary: {e}")
|
|
48062
48601
|
|
|
48063
48602
|
def _select_first_term_in_table(self, main):
|
|
@@ -48071,7 +48610,7 @@ class SuperlookupTab(QWidget):
|
|
|
48071
48610
|
if item:
|
|
48072
48611
|
table.scrollToItem(item)
|
|
48073
48612
|
except Exception as e:
|
|
48074
|
-
print(f"[
|
|
48613
|
+
print(f"[SuperLookup] Error selecting term: {e}")
|
|
48075
48614
|
|
|
48076
48615
|
def display_mt_results(self, results):
|
|
48077
48616
|
"""Display MT results in the table"""
|
|
@@ -48606,7 +49145,7 @@ class SuperlookupTab(QWidget):
|
|
|
48606
49145
|
if self.main_window and hasattr(self.main_window, 'general_settings'):
|
|
48607
49146
|
saved_path = self.main_window.general_settings.get('autohotkey_path', '')
|
|
48608
49147
|
if saved_path and os.path.exists(saved_path):
|
|
48609
|
-
print(f"[
|
|
49148
|
+
print(f"[SuperLookup] Using saved AutoHotkey path: {saved_path}")
|
|
48610
49149
|
return saved_path, 'saved'
|
|
48611
49150
|
|
|
48612
49151
|
# Standard installation paths
|
|
@@ -48624,7 +49163,7 @@ class SuperlookupTab(QWidget):
|
|
|
48624
49163
|
|
|
48625
49164
|
for path in ahk_paths:
|
|
48626
49165
|
if os.path.exists(path):
|
|
48627
|
-
print(f"[
|
|
49166
|
+
print(f"[SuperLookup] Detected AutoHotkey at: {path}")
|
|
48628
49167
|
return path, 'detected'
|
|
48629
49168
|
|
|
48630
49169
|
return None, None
|
|
@@ -48751,7 +49290,7 @@ class SuperlookupTab(QWidget):
|
|
|
48751
49290
|
if self.main_window and hasattr(self.main_window, 'general_settings'):
|
|
48752
49291
|
self.main_window.general_settings['autohotkey_path'] = file_path
|
|
48753
49292
|
self.main_window.save_general_settings()
|
|
48754
|
-
print(f"[
|
|
49293
|
+
print(f"[SuperLookup] Saved AutoHotkey path: {file_path}")
|
|
48755
49294
|
|
|
48756
49295
|
self._ahk_setup_status.setText(f"✓ Saved: {file_path}\n\nRestart Supervertaler to use this path.")
|
|
48757
49296
|
|
|
@@ -48772,11 +49311,11 @@ class SuperlookupTab(QWidget):
|
|
|
48772
49311
|
Note: AutoHotkey is Windows-only, so skip on Linux/Mac.
|
|
48773
49312
|
"""
|
|
48774
49313
|
global _ahk_process
|
|
48775
|
-
print("[
|
|
49314
|
+
print("[SuperLookup] register_global_hotkey called")
|
|
48776
49315
|
|
|
48777
49316
|
# AutoHotkey is Windows-only - skip on other platforms
|
|
48778
49317
|
if sys.platform != 'win32':
|
|
48779
|
-
print("[
|
|
49318
|
+
print("[SuperLookup] Skipping AutoHotkey registration (not Windows)")
|
|
48780
49319
|
self.hotkey_registered = False
|
|
48781
49320
|
return
|
|
48782
49321
|
|
|
@@ -48790,24 +49329,24 @@ class SuperlookupTab(QWidget):
|
|
|
48790
49329
|
"""
|
|
48791
49330
|
try:
|
|
48792
49331
|
from ahk import AHK
|
|
48793
|
-
print("[
|
|
49332
|
+
print("[SuperLookup] ahk library available, attempting to use it...")
|
|
48794
49333
|
|
|
48795
49334
|
# Find AutoHotkey executable using shared function
|
|
48796
49335
|
ahk_exe, source = self._find_autohotkey_executable()
|
|
48797
49336
|
|
|
48798
49337
|
# Create AHK instance (with executable path if found)
|
|
48799
49338
|
if ahk_exe:
|
|
48800
|
-
print(f"[
|
|
49339
|
+
print(f"[SuperLookup] Using AutoHotkey at: {ahk_exe} (source: {source})")
|
|
48801
49340
|
self._ahk = AHK(executable_path=ahk_exe)
|
|
48802
49341
|
else:
|
|
48803
49342
|
# Let it try to find AHK on PATH (may fail)
|
|
48804
49343
|
self._ahk = AHK()
|
|
48805
|
-
print(f"[
|
|
49344
|
+
print(f"[SuperLookup] AHK instance created: {self._ahk}")
|
|
48806
49345
|
|
|
48807
49346
|
# Define hotkey callback
|
|
48808
49347
|
def on_hotkey():
|
|
48809
49348
|
"""Called when Ctrl+Alt+L is pressed"""
|
|
48810
|
-
print("[
|
|
49349
|
+
print("[SuperLookup] Hotkey triggered via ahk library!")
|
|
48811
49350
|
try:
|
|
48812
49351
|
# Copy selection to clipboard
|
|
48813
49352
|
self._ahk.send('^c') # Ctrl+C
|
|
@@ -48820,7 +49359,7 @@ class SuperlookupTab(QWidget):
|
|
|
48820
49359
|
try:
|
|
48821
49360
|
self._ahk.win_activate('Supervertaler')
|
|
48822
49361
|
except Exception as e:
|
|
48823
|
-
print(f"[
|
|
49362
|
+
print(f"[SuperLookup] win_activate error (non-critical): {e}")
|
|
48824
49363
|
|
|
48825
49364
|
# Trigger lookup in main thread
|
|
48826
49365
|
if text:
|
|
@@ -48828,22 +49367,22 @@ class SuperlookupTab(QWidget):
|
|
|
48828
49367
|
QTimer.singleShot(0, lambda: self.on_ahk_capture(text))
|
|
48829
49368
|
|
|
48830
49369
|
except Exception as e:
|
|
48831
|
-
print(f"[
|
|
49370
|
+
print(f"[SuperLookup] Error in hotkey callback: {e}")
|
|
48832
49371
|
|
|
48833
49372
|
# Register the hotkey
|
|
48834
49373
|
self._ahk.add_hotkey('^!l', callback=on_hotkey) # Ctrl+Alt+L
|
|
48835
49374
|
self._ahk.start_hotkeys()
|
|
48836
49375
|
|
|
48837
|
-
print("[
|
|
49376
|
+
print("[SuperLookup] ✓ Hotkey registered via ahk library: Ctrl+Alt+L")
|
|
48838
49377
|
self.hotkey_registered = True
|
|
48839
49378
|
self._using_ahk_library = True
|
|
48840
49379
|
return True
|
|
48841
49380
|
|
|
48842
49381
|
except ImportError:
|
|
48843
|
-
print("[
|
|
49382
|
+
print("[SuperLookup] ahk library not installed (pip install ahk)")
|
|
48844
49383
|
return False
|
|
48845
49384
|
except Exception as e:
|
|
48846
|
-
print(f"[
|
|
49385
|
+
print(f"[SuperLookup] ahk library method failed: {e}")
|
|
48847
49386
|
# Clean up on failure
|
|
48848
49387
|
if hasattr(self, '_ahk'):
|
|
48849
49388
|
try:
|
|
@@ -48924,11 +49463,13 @@ class SuperlookupTab(QWidget):
|
|
|
48924
49463
|
self.hotkey_registered = False
|
|
48925
49464
|
|
|
48926
49465
|
def start_file_watcher(self):
|
|
48927
|
-
"""Watch for signal
|
|
49466
|
+
"""Watch for signal files from AHK (Superlookup and MT Quick Lookup)"""
|
|
48928
49467
|
self.signal_file = Path(__file__).parent / "lookup_signal.txt"
|
|
48929
49468
|
self.capture_file = Path(__file__).parent / "temp_capture.txt"
|
|
48930
|
-
|
|
48931
|
-
|
|
49469
|
+
self.mt_lookup_signal_file = Path(__file__).parent / "mt_lookup_signal.txt"
|
|
49470
|
+
|
|
49471
|
+
print(f"[SuperLookup] File watcher started, watching: {self.signal_file}")
|
|
49472
|
+
print(f"[QuickTrans] File watcher started, watching: {self.mt_lookup_signal_file}")
|
|
48932
49473
|
|
|
48933
49474
|
# Create timer to check for signal file
|
|
48934
49475
|
self.file_check_timer = QTimer()
|
|
@@ -48937,27 +49478,57 @@ class SuperlookupTab(QWidget):
|
|
|
48937
49478
|
|
|
48938
49479
|
def check_for_signal(self):
|
|
48939
49480
|
"""Check if AHK wrote a signal file"""
|
|
49481
|
+
# Check for Superlookup signal
|
|
48940
49482
|
if self.signal_file.exists():
|
|
48941
|
-
print(f"[
|
|
49483
|
+
print(f"[SuperLookup] Signal file detected!")
|
|
48942
49484
|
try:
|
|
48943
49485
|
# Delete signal file
|
|
48944
49486
|
self.signal_file.unlink()
|
|
48945
|
-
print(f"[
|
|
48946
|
-
|
|
49487
|
+
print(f"[SuperLookup] Signal file deleted")
|
|
49488
|
+
|
|
48947
49489
|
# Get text from clipboard (AHK already copied it)
|
|
48948
49490
|
time.sleep(0.1) # Give clipboard a moment
|
|
48949
49491
|
text = pyperclip.paste()
|
|
48950
|
-
|
|
49492
|
+
|
|
48951
49493
|
# Trigger lookup
|
|
48952
49494
|
if text:
|
|
48953
49495
|
self.on_ahk_capture(text)
|
|
48954
49496
|
except Exception as e:
|
|
48955
|
-
print(f"[
|
|
49497
|
+
print(f"[SuperLookup] Error reading capture: {e}")
|
|
49498
|
+
|
|
49499
|
+
# Check for MT Quick Lookup signal
|
|
49500
|
+
if hasattr(self, 'mt_lookup_signal_file') and self.mt_lookup_signal_file.exists():
|
|
49501
|
+
print(f"[QuickTrans] Signal file detected!")
|
|
49502
|
+
try:
|
|
49503
|
+
# Small delay to let AHK finish writing/close the file
|
|
49504
|
+
time.sleep(0.05)
|
|
49505
|
+
|
|
49506
|
+
# Delete signal file with retry for file lock
|
|
49507
|
+
for attempt in range(3):
|
|
49508
|
+
try:
|
|
49509
|
+
self.mt_lookup_signal_file.unlink()
|
|
49510
|
+
print(f"[QuickTrans] Signal file deleted")
|
|
49511
|
+
break
|
|
49512
|
+
except PermissionError:
|
|
49513
|
+
if attempt < 2:
|
|
49514
|
+
time.sleep(0.05)
|
|
49515
|
+
else:
|
|
49516
|
+
raise
|
|
49517
|
+
|
|
49518
|
+
# Get text from clipboard (AHK already copied it)
|
|
49519
|
+
time.sleep(0.1) # Give clipboard a moment
|
|
49520
|
+
text = pyperclip.paste()
|
|
49521
|
+
|
|
49522
|
+
# Trigger MT Quick Lookup
|
|
49523
|
+
if text:
|
|
49524
|
+
self.on_ahk_mt_lookup_capture(text)
|
|
49525
|
+
except Exception as e:
|
|
49526
|
+
print(f"[QuickTrans] Error reading capture: {e}")
|
|
48956
49527
|
|
|
48957
49528
|
def on_ahk_capture(self, text):
|
|
48958
49529
|
"""Handle text captured by AHK"""
|
|
48959
49530
|
try:
|
|
48960
|
-
print(f"[
|
|
49531
|
+
print(f"[SuperLookup] on_ahk_capture called with text: {text[:50]}...")
|
|
48961
49532
|
|
|
48962
49533
|
# Bring Supervertaler to foreground
|
|
48963
49534
|
main_window = self.window()
|
|
@@ -48987,39 +49558,96 @@ class SuperlookupTab(QWidget):
|
|
|
48987
49558
|
QTimer.singleShot(250, lambda: self.show_superlookup(text))
|
|
48988
49559
|
|
|
48989
49560
|
except Exception as e:
|
|
48990
|
-
print(f"[
|
|
48991
|
-
|
|
49561
|
+
print(f"[SuperLookup] Error handling capture: {e}")
|
|
49562
|
+
|
|
49563
|
+
def on_ahk_mt_lookup_capture(self, text):
|
|
49564
|
+
"""Handle MT Quick Lookup text captured by AHK (Ctrl+Alt+M)"""
|
|
49565
|
+
try:
|
|
49566
|
+
print(f"[QuickTrans] on_ahk_mt_lookup_capture called with text: {text[:50]}...")
|
|
49567
|
+
|
|
49568
|
+
# Show popup directly without bringing Supervertaler to foreground
|
|
49569
|
+
# The popup has WindowStaysOnTopHint so it will appear over any app
|
|
49570
|
+
QTimer.singleShot(100, lambda: self.show_mt_quick_lookup_from_ahk(text))
|
|
49571
|
+
|
|
49572
|
+
except Exception as e:
|
|
49573
|
+
print(f"[QuickTrans] Error handling capture: {e}")
|
|
49574
|
+
|
|
49575
|
+
def show_mt_quick_lookup_from_ahk(self, text):
|
|
49576
|
+
"""Show MT Quick Lookup popup with text from AHK capture"""
|
|
49577
|
+
try:
|
|
49578
|
+
print(f"[QuickTrans] show_mt_quick_lookup_from_ahk called with text: {text[:50]}...")
|
|
49579
|
+
|
|
49580
|
+
# Get main window reference for settings access
|
|
49581
|
+
main_window = self.main_window
|
|
49582
|
+
if not main_window:
|
|
49583
|
+
main_window = self.window()
|
|
49584
|
+
|
|
49585
|
+
if not main_window:
|
|
49586
|
+
print("[QuickTrans] ERROR: Could not find main window")
|
|
49587
|
+
return
|
|
49588
|
+
|
|
49589
|
+
# Get language settings
|
|
49590
|
+
source_lang = getattr(main_window, 'source_language', 'English')
|
|
49591
|
+
target_lang = getattr(main_window, 'target_language', 'Dutch')
|
|
49592
|
+
|
|
49593
|
+
# Import and show MT Quick Lookup popup
|
|
49594
|
+
from modules.quicktrans import MTQuickPopup
|
|
49595
|
+
|
|
49596
|
+
# Create popup without Qt parent so it can appear independently over any app
|
|
49597
|
+
# Pass main_window as parent_app for API access
|
|
49598
|
+
popup = MTQuickPopup(
|
|
49599
|
+
parent_app=main_window,
|
|
49600
|
+
source_text=text,
|
|
49601
|
+
source_lang=source_lang,
|
|
49602
|
+
target_lang=target_lang,
|
|
49603
|
+
parent=None # No Qt parent - allows independent window
|
|
49604
|
+
)
|
|
49605
|
+
|
|
49606
|
+
# Store reference to prevent garbage collection
|
|
49607
|
+
self._ahk_mt_popup = popup
|
|
49608
|
+
|
|
49609
|
+
# Show and ensure it's on top
|
|
49610
|
+
popup.show()
|
|
49611
|
+
popup.raise_()
|
|
49612
|
+
popup.activateWindow()
|
|
49613
|
+
print(f"[QuickTrans] Popup shown for text: {text[:30]}...")
|
|
49614
|
+
|
|
49615
|
+
except Exception as e:
|
|
49616
|
+
print(f"[QuickTrans] Error showing popup: {e}")
|
|
49617
|
+
import traceback
|
|
49618
|
+
traceback.print_exc()
|
|
49619
|
+
|
|
48992
49620
|
def show_superlookup(self, text):
|
|
48993
49621
|
"""Show Superlookup with pre-filled text"""
|
|
48994
49622
|
try:
|
|
48995
|
-
print(f"[
|
|
49623
|
+
print(f"[SuperLookup] show_superlookup called with text: {text[:50]}...")
|
|
48996
49624
|
|
|
48997
49625
|
# Get main window reference
|
|
48998
49626
|
main_window = self.main_window
|
|
48999
49627
|
if not main_window:
|
|
49000
49628
|
main_window = self.window()
|
|
49001
49629
|
|
|
49002
|
-
print(f"[
|
|
49003
|
-
print(f"[
|
|
49004
|
-
print(f"[
|
|
49630
|
+
print(f"[SuperLookup] Main window found: {main_window is not None}")
|
|
49631
|
+
print(f"[SuperLookup] Main window type: {type(main_window).__name__}")
|
|
49632
|
+
print(f"[SuperLookup] Has main_tabs: {hasattr(main_window, 'main_tabs')}")
|
|
49005
49633
|
|
|
49006
49634
|
# Switch to Tools tab (main_tabs index 3)
|
|
49007
49635
|
# Tab structure: Grid=0, Resources=1, QuickMenu=2, Tools=3, Settings=4
|
|
49008
49636
|
if hasattr(main_window, 'main_tabs'):
|
|
49009
|
-
print(f"[
|
|
49637
|
+
print(f"[SuperLookup] Current main_tab index: {main_window.main_tabs.currentIndex()}")
|
|
49010
49638
|
main_window.main_tabs.setCurrentIndex(3) # Tools tab
|
|
49011
|
-
print(f"[
|
|
49639
|
+
print(f"[SuperLookup] Switched to Tools tab (index 2)")
|
|
49012
49640
|
QApplication.processEvents() # Force GUI update
|
|
49013
49641
|
else:
|
|
49014
|
-
print(f"[
|
|
49642
|
+
print(f"[SuperLookup] WARNING: Main window has no main_tabs attribute!")
|
|
49015
49643
|
|
|
49016
49644
|
# Switch to Superlookup within modules_tabs
|
|
49017
49645
|
if hasattr(main_window, 'modules_tabs'):
|
|
49018
|
-
print(f"[
|
|
49646
|
+
print(f"[SuperLookup] Current modules_tab index: {main_window.modules_tabs.currentIndex()}")
|
|
49019
49647
|
for i in range(main_window.modules_tabs.count()):
|
|
49020
49648
|
if "Superlookup" in main_window.modules_tabs.tabText(i):
|
|
49021
49649
|
main_window.modules_tabs.setCurrentIndex(i)
|
|
49022
|
-
print(f"[
|
|
49650
|
+
print(f"[SuperLookup] Switched to Superlookup tab (index {i})")
|
|
49023
49651
|
QApplication.processEvents() # Force GUI update
|
|
49024
49652
|
break
|
|
49025
49653
|
|
|
@@ -49027,23 +49655,23 @@ class SuperlookupTab(QWidget):
|
|
|
49027
49655
|
QTimer.singleShot(100, lambda: self._fill_and_search(text))
|
|
49028
49656
|
|
|
49029
49657
|
except Exception as e:
|
|
49030
|
-
print(f"[
|
|
49658
|
+
print(f"[SuperLookup] Error showing lookup: {e}")
|
|
49031
49659
|
|
|
49032
49660
|
def _fill_and_search(self, text):
|
|
49033
49661
|
"""Fill in text and trigger search (called after tab switching completes)"""
|
|
49034
49662
|
try:
|
|
49035
|
-
print(f"[
|
|
49663
|
+
print(f"[SuperLookup] _fill_and_search called")
|
|
49036
49664
|
# Fill in text and trigger lookup
|
|
49037
49665
|
if hasattr(self, 'source_text'):
|
|
49038
49666
|
self.source_text.setCurrentText(text)
|
|
49039
|
-
print(f"[
|
|
49667
|
+
print(f"[SuperLookup] Text filled in source_text field")
|
|
49040
49668
|
# Trigger lookup by calling perform_lookup directly
|
|
49041
49669
|
self.perform_lookup()
|
|
49042
|
-
print(f"[
|
|
49670
|
+
print(f"[SuperLookup] perform_lookup() called")
|
|
49043
49671
|
else:
|
|
49044
|
-
print(f"[
|
|
49672
|
+
print(f"[SuperLookup] ERROR: source_text widget not found!")
|
|
49045
49673
|
except Exception as e:
|
|
49046
|
-
print(f"[
|
|
49674
|
+
print(f"[SuperLookup] Error in _fill_and_search: {e}")
|
|
49047
49675
|
import traceback
|
|
49048
49676
|
traceback.print_exc()
|
|
49049
49677
|
|