8 """ |
8 """ |
9 |
9 |
10 from PyQt6.QtCore import pyqtSlot, QTemporaryFile |
10 from PyQt6.QtCore import pyqtSlot, QTemporaryFile |
11 from PyQt6.QtWidgets import QWidget |
11 from PyQt6.QtWidgets import QWidget |
12 try: |
12 try: |
13 # TODO: adapt QtMultiMedia usage for Qt 6.2 |
13 from PyQt6.QtMultimedia import QMediaFormat, QMediaPlayer, QAudioOutput |
14 from PyQt6.QtMultimedia import QMediaPlayer, QMediaContent |
|
15 MULTIMEDIA_AVAILABLE = True |
14 MULTIMEDIA_AVAILABLE = True |
16 except ImportError: |
15 except ImportError: |
17 MULTIMEDIA_AVAILABLE = False |
16 MULTIMEDIA_AVAILABLE = False |
18 |
17 |
19 from EricWidgets import EricMessageBox |
18 from EricWidgets import EricMessageBox |
33 """ |
32 """ |
34 def __init__(self, plugin, translator, parent=None): |
33 def __init__(self, plugin, translator, parent=None): |
35 """ |
34 """ |
36 Constructor |
35 Constructor |
37 |
36 |
38 @param plugin reference to the plugin object (TranslatorPlugin) |
37 @param plugin reference to the plugin object |
39 @param translator reference to the translator object (Translator) |
38 @type TranslatorPlugin |
40 @param parent reference to the parent widget (QWidget) |
39 @param translator reference to the translator object |
|
40 @type Translator |
|
41 @param parent reference to the parent widget |
|
42 @type QWidget |
41 """ |
43 """ |
42 super().__init__(parent) |
44 super().__init__(parent) |
43 self.setupUi(self) |
45 self.setupUi(self) |
44 |
46 |
45 self.__plugin = plugin |
47 self.__plugin = plugin |
48 self.__languages = TranslatorLanguagesDb(self) |
50 self.__languages = TranslatorLanguagesDb(self) |
49 |
51 |
50 self.__translatorRequest = None |
52 self.__translatorRequest = None |
51 self.__translationEngine = None |
53 self.__translationEngine = None |
52 |
54 |
|
55 self.__audioOutput = None |
53 self.__mediaPlayer = None |
56 self.__mediaPlayer = None |
54 self.__mediaFile = None |
57 self.__mediaFile = None |
55 |
58 |
56 audioAvailable = (MULTIMEDIA_AVAILABLE and |
59 audioAvailable = False |
57 bool(QMediaPlayer.hasSupport("audio/mpeg"))) |
60 if MULTIMEDIA_AVAILABLE: |
|
61 mediaFormat = QMediaFormat() |
|
62 audioAvailable = ( |
|
63 QMediaFormat.AudioCodec.MP3 in |
|
64 mediaFormat.supportedAudioCodecs( |
|
65 QMediaFormat.ConversionMode.Decode) |
|
66 ) |
58 self.pronounceOrigButton.setVisible(audioAvailable) |
67 self.pronounceOrigButton.setVisible(audioAvailable) |
59 self.pronounceTransButton.setVisible(audioAvailable) |
68 self.pronounceTransButton.setVisible(audioAvailable) |
60 |
69 |
61 self.pronounceOrigButton.setIcon( |
70 self.pronounceOrigButton.setIcon( |
62 self.__translator.getAppIcon("pronounce")) |
71 self.__translator.getAppIcon("pronounce")) |
134 |
143 |
135 def __originalLanguage(self): |
144 def __originalLanguage(self): |
136 """ |
145 """ |
137 Private method to return the code of the selected original language. |
146 Private method to return the code of the selected original language. |
138 |
147 |
139 @return code of the original language (string) |
148 @return code of the original language |
|
149 @rtype str |
140 """ |
150 """ |
141 return self.origLanguageComboBox.itemData( |
151 return self.origLanguageComboBox.itemData( |
142 self.origLanguageComboBox.currentIndex()) |
152 self.origLanguageComboBox.currentIndex()) |
143 |
153 |
144 def __translationLanguage(self): |
154 def __translationLanguage(self): |
145 """ |
155 """ |
146 Private method to return the code of the selected translation language. |
156 Private method to return the code of the selected translation language. |
147 |
157 |
148 @return code of the translation language (string) |
158 @return code of the translation language |
|
159 @rtype str |
149 """ |
160 """ |
150 return self.transLanguageComboBox.itemData( |
161 return self.transLanguageComboBox.itemData( |
151 self.transLanguageComboBox.currentIndex()) |
162 self.transLanguageComboBox.currentIndex()) |
152 |
163 |
153 @pyqtSlot() |
164 @pyqtSlot() |
238 @pyqtSlot(int) |
249 @pyqtSlot(int) |
239 def on_origLanguageComboBox_currentIndexChanged(self, index): |
250 def on_origLanguageComboBox_currentIndexChanged(self, index): |
240 """ |
251 """ |
241 Private slot to handle the selection of the original language. |
252 Private slot to handle the selection of the original language. |
242 |
253 |
243 @param index current index (integer) |
254 @param index current index |
|
255 @type int |
244 """ |
256 """ |
245 self.__plugin.setPreferences( |
257 self.__plugin.setPreferences( |
246 "OriginalLanguage", self.origLanguageComboBox.itemData(index)) |
258 "OriginalLanguage", self.origLanguageComboBox.itemData(index)) |
247 |
259 |
248 supportedTargetCodes = ( |
260 supportedTargetCodes = ( |
274 @pyqtSlot(int) |
286 @pyqtSlot(int) |
275 def on_transLanguageComboBox_currentIndexChanged(self, index): |
287 def on_transLanguageComboBox_currentIndexChanged(self, index): |
276 """ |
288 """ |
277 Private slot to handle the selection of the translation language. |
289 Private slot to handle the selection of the translation language. |
278 |
290 |
279 @param index current index (integer) |
291 @param index current index |
|
292 @type int |
280 """ |
293 """ |
281 self.__plugin.setPreferences( |
294 self.__plugin.setPreferences( |
282 "TranslationLanguage", self.transLanguageComboBox.itemData(index)) |
295 "TranslationLanguage", self.transLanguageComboBox.itemData(index)) |
283 |
296 |
284 @pyqtSlot() |
297 @pyqtSlot() |
367 |
380 |
368 def __translate(self, text, originalLanguage, translationLanguage): |
381 def __translate(self, text, originalLanguage, translationLanguage): |
369 """ |
382 """ |
370 Private method to translate the given text. |
383 Private method to translate the given text. |
371 |
384 |
372 @param text text to be translated (string) |
385 @param text text to be translated |
373 @param originalLanguage language code of the original (string) |
386 @type str |
374 @param translationLanguage language code of the translation (string) |
387 @param originalLanguage language code of the original |
375 @return tuple of translated text (string) and flag indicating |
388 @type str |
376 success (boolean) |
389 @param translationLanguage language code of the translation |
|
390 @type str |
|
391 @return tuple of translated text and flag indicating success |
|
392 @rtype tuple of (str, bool) |
377 """ |
393 """ |
378 if self.__translatorRequest is None: |
394 if self.__translatorRequest is None: |
379 from .TranslatorRequest import TranslatorRequest |
395 from .TranslatorRequest import TranslatorRequest |
380 self.__translatorRequest = TranslatorRequest(self) |
396 self.__translatorRequest = TranslatorRequest(self) |
381 |
397 |
391 |
407 |
392 def __pronounce(self, text, language): |
408 def __pronounce(self, text, language): |
393 """ |
409 """ |
394 Private method to pronounce the given text. |
410 Private method to pronounce the given text. |
395 |
411 |
396 @param text text to be pronounced (string) |
412 @param text text to be pronounced |
397 @param language language code of the text (string) |
413 @type str |
|
414 @param language language code of the text |
|
415 @type str |
398 """ |
416 """ |
399 if not text or not language: |
417 if not text or not language: |
400 return |
418 return |
401 |
419 |
402 if self.__translatorRequest is None: |
420 if self.__translatorRequest is None: |
403 from .TranslatorRequest import TranslatorRequest |
421 from .TranslatorRequest import TranslatorRequest |
404 self.__translatorRequest = TranslatorRequest(self) |
422 self.__translatorRequest = TranslatorRequest(self) |
405 |
423 |
406 if self.__mediaPlayer is None: |
424 if self.__mediaPlayer is None: |
407 self.__mediaPlayer = QMediaPlayer(self) |
425 self.__mediaPlayer = QMediaPlayer(self) |
408 self.__mediaPlayer.stateChanged.connect( |
426 self.__audioOutput = QAudioOutput(self) |
409 self.__mediaPlayerStateChanged) |
427 self.__mediaPlayer.setAudioOutput(self.__audioOutput) |
410 |
428 |
411 if self.__mediaPlayer.state() == QMediaPlayer.State.PlayingState: |
429 self.__mediaPlayer.playbackStateChanged.connect( |
|
430 self.__mediaPlayerPlaybackStateChanged) |
|
431 self.__mediaPlayer.errorOccurred.connect( |
|
432 self.__mediaPlayerError) |
|
433 |
|
434 if ( |
|
435 self.__mediaPlayer.playbackState() == |
|
436 QMediaPlayer.PlaybackState.PlayingState |
|
437 ): |
412 return |
438 return |
413 |
439 |
414 self.__ensureTranslationEngineReady() |
440 self.__ensureTranslationEngineReady() |
415 if self.__translationEngine is not None: |
441 if self.__translationEngine is not None: |
416 if not self.__translationEngine.hasTTS(): |
442 if not self.__translationEngine.hasTTS(): |
426 if ok: |
452 if ok: |
427 self.__mediaFile = QTemporaryFile(self) |
453 self.__mediaFile = QTemporaryFile(self) |
428 self.__mediaFile.open() |
454 self.__mediaFile.open() |
429 self.__mediaFile.setAutoRemove(False) |
455 self.__mediaFile.setAutoRemove(False) |
430 self.__mediaFile.write(data) |
456 self.__mediaFile.write(data) |
|
457 self.__mediaFile.close() |
431 |
458 |
432 self.__mediaPlayer.setMedia(QMediaContent(), self.__mediaFile) |
459 from PyQt6.QtCore import QUrl |
|
460 self.__mediaPlayer.setSource( |
|
461 QUrl.fromLocalFile(self.__mediaFile.fileName())) |
433 self.__mediaPlayer.play() |
462 self.__mediaPlayer.play() |
434 else: |
463 else: |
435 EricMessageBox.critical( |
464 EricMessageBox.critical( |
436 self, |
465 self, |
437 self.tr("Translation Error"), |
466 self.tr("Translation Error"), |
438 data) |
467 data) |
439 |
468 |
440 def __mediaPlayerStateChanged(self, state): |
469 @pyqtSlot(QMediaPlayer.PlaybackState) |
|
470 def __mediaPlayerPlaybackStateChanged(self, state): |
441 """ |
471 """ |
442 Private slot handling changes of the media player state. |
472 Private slot handling changes of the media player state. |
443 |
473 |
444 @param state media player state (QAudio.State) |
474 @param state media player state (QMediaPlayer.PlaybackState) |
445 """ |
475 """ |
446 if state == QMediaPlayer.State.StoppedState: |
476 if state == QMediaPlayer.PlaybackState.StoppedState: |
447 self.__mediaFile.close() |
477 self.__mediaFile.close() |
448 self.__mediaFile.remove() |
478 self.__mediaFile.remove() |
449 self.__mediaFile = None |
479 self.__mediaFile = None |
450 |
480 |
|
481 @pyqtSlot(QMediaPlayer.Error, str) |
|
482 def __mediaPlayerError(self, error, errorString): |
|
483 """ |
|
484 Private slot to handle errors during playback of the data. |
|
485 |
|
486 @param error media player error condition |
|
487 @type QMediaPlayer.Error |
|
488 @param errorString string representation for the error |
|
489 @type str |
|
490 """ |
|
491 if error != QMediaPlayer.Error.NoError: |
|
492 EricMessageBox.warning( |
|
493 self, |
|
494 self.tr("Error playing pronunciation"), |
|
495 self.tr("<p>The received pronunciation could not be played." |
|
496 "</p><p>Reason: {0}</p>") |
|
497 ) |
|
498 |
451 @pyqtSlot() |
499 @pyqtSlot() |
452 def on_preferencesButton_clicked(self): |
500 def on_preferencesButton_clicked(self): |
453 """ |
501 """ |
454 Private slot to open the Translator configuration page. |
502 Private slot to open the Translator configuration page. |
455 """ |
503 """ |